├── .clang-format ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── check_format.yml │ ├── cpack-deb-debian.yml │ ├── cpack-deb-ubuntu.yml.bak │ ├── hashfile.yml │ ├── linux-static-qt6.yml │ ├── linux-static.yml │ ├── macos-qt6.yml │ ├── macos.yml │ ├── sourcefile.yml │ ├── watcher_linux.yml │ ├── watcher_macos.yml │ ├── windows-qt6.yml │ └── windows.yml ├── .gitignore ├── .gitmodules ├── AUTHORS ├── BUILD.md ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── LICENSES └── GPL-3.0-or-later.txt ├── README.md ├── TODO ├── assets ├── MacOSXInfo.plist.in ├── icons │ ├── lemon-lime.1024.png │ ├── lemon-lime.128.png │ ├── lemon-lime.150.png │ ├── lemon-lime.16.png │ ├── lemon-lime.192.png │ ├── lemon-lime.22.png │ ├── lemon-lime.24.png │ ├── lemon-lime.256.png │ ├── lemon-lime.310.png │ ├── lemon-lime.32.png │ ├── lemon-lime.36.png │ ├── lemon-lime.44.png │ ├── lemon-lime.48.png │ ├── lemon-lime.512.png │ ├── lemon-lime.64.png │ ├── lemon-lime.72.png │ ├── lemon-lime.96.png │ └── lemon-lime.png ├── js │ └── jquery.slim.min.js ├── lemon-lime.desktop.in ├── lemon-lime.ico ├── lemon-lime.metainfo.xml.in ├── lemon.rc ├── pics │ ├── acrobat.svg │ ├── application-exit.svg │ ├── code-function.svg │ ├── configure.svg │ ├── deletecell.svg │ ├── dialog-cancel.svg │ ├── dialog-ok-apply.svg │ ├── document-close.svg │ ├── document-edit.svg │ ├── document-export.svg │ ├── document-new.svg │ ├── document-save.svg │ ├── edit-clear.svg │ ├── edit-delete.svg │ ├── edit-find-replace.svg │ ├── edit-find.svg │ ├── globe.svg │ ├── go-down.svg │ ├── go-parent-folder.svg │ ├── go-up.svg │ ├── help-about.svg │ ├── layer-new.svg │ ├── list-add.svg │ ├── list-remove.svg │ ├── media-playback-stop.svg │ ├── media-skip-forward.svg │ ├── paint-none.svg │ ├── paint-unknown.svg │ ├── quickopen-file.svg │ ├── splash.png │ ├── splash2.png │ ├── system-help.svg │ ├── view-refresh.svg │ └── view-sort.svg └── x-lemon-contest.xml.in ├── cmake ├── LemonDocs.cmake ├── LemonTranslations.cmake ├── deployment.cmake ├── lemon-base.cmake ├── lemon-core.cmake ├── lemon-ui.cmake └── platforms │ ├── linux.cmake │ ├── macos.cmake │ └── windows.cmake ├── hooks └── pre-commit ├── makespec ├── BUILDVERSION ├── VERSION ├── VERSIONSUFFIX └── lemonlime.spec.in ├── manual ├── .gitignore ├── latexmkrc ├── llmanual.pdf ├── llmanual.tex ├── manual.qrc └── pics │ ├── addcompiler.png │ ├── addcompiler2.png │ ├── addtestcases.png │ ├── compilersettings.png │ ├── compilersettings2.png │ ├── editproblem.png │ ├── edittestcase.png │ ├── exttestcasemodifier.png │ ├── generalsettings.png │ ├── icon.png │ ├── intoexttestcasemodifier.png │ ├── judgingdialog.png │ ├── newcontest.png │ ├── statistics.png │ ├── statistics2.png │ ├── visualmainsettings.png │ ├── visualmainsettings_whenchoosingtheme.png │ └── visualsettings.png ├── resource.qrc ├── src ├── addcompilerwizard.cpp ├── addcompilerwizard.h ├── addtaskdialog.cpp ├── addtaskdialog.h ├── addtestcaseswizard.cpp ├── addtestcaseswizard.h ├── advancedcompilersettingsdialog.cpp ├── advancedcompilersettingsdialog.h ├── base │ ├── LemonApplicationInterface.cpp │ ├── LemonApplicationInterface.hpp │ ├── LemonBase.hpp │ ├── LemonBaseApplication.cpp │ ├── LemonBaseApplication.hpp │ ├── LemonConfig.cpp │ ├── LemonConfig.hpp │ ├── LemonLog.hpp │ ├── LemonMacro.hpp │ ├── LemonTranslator.cpp │ ├── LemonTranslator.hpp │ ├── LemonType.hpp │ ├── LemonUtils.cpp │ ├── LemonUtils.hpp │ ├── compiler.cpp │ ├── compiler.h │ ├── settings.cpp │ └── settings.h ├── compilersettings.cpp ├── compilersettings.h ├── component │ └── exportutil │ │ ├── exportutil.cpp │ │ └── exportutil.h ├── core │ ├── contest.cpp │ ├── contest.h │ ├── contestant.cpp │ ├── contestant.h │ ├── judgesharedvariables.h │ ├── judgingcontroller.cpp │ ├── judgingcontroller.h │ ├── judgingthread.cpp │ ├── judgingthread.h │ ├── subtaskdependencelib.h │ ├── task.cpp │ ├── task.h │ ├── taskjudger.cpp │ ├── taskjudger.h │ ├── testcase.cpp │ └── testcase.h ├── detaildialog.cpp ├── detaildialog.h ├── editvariabledialog.cpp ├── editvariabledialog.h ├── environmentvariablesdialog.cpp ├── environmentvariablesdialog.h ├── exttestcasemodifier.cpp ├── exttestcasemodifier.h ├── exttestcasemodifierdialog.cpp ├── exttestcasemodifierdialog.h ├── exttestcasetable.cpp ├── exttestcasetable.h ├── exttestcaseupdaterdialog.cpp ├── exttestcaseupdaterdialog.h ├── filelineedit.cpp ├── filelineedit.h ├── forms │ ├── addcompilerwizard.ui │ ├── addtaskdialog.ui │ ├── addtestcaseswizard.ui │ ├── advancedcompilersettingsdialog.ui │ ├── compilersettings.ui │ ├── detaildialog.ui │ ├── editvariabledialog.ui │ ├── environmentvariablesdialog.ui │ ├── exttestcasemodifier.ui │ ├── exttestcasemodifierdialog.ui │ ├── exttestcaseupdaterdialog.ui │ ├── generalsettings.ui │ ├── judgingdialog.ui │ ├── lemon.ui │ ├── newcontestdialog.ui │ ├── newcontestwidget.ui │ ├── opencontestdialog.ui │ ├── opencontestwidget.ui │ ├── optionsdialog.ui │ ├── statisticsbrowser.ui │ ├── taskeditwidget.ui │ ├── testcaseeditwidget.ui │ ├── themeeditdialog.ui │ ├── visualmainsettings.ui │ ├── visualsettings.ui │ └── welcomedialog.ui ├── generalsettings.cpp ├── generalsettings.h ├── judgingdialog.cpp ├── judgingdialog.h ├── lemon.cpp ├── lemon.h ├── main.cpp ├── newcontestdialog.cpp ├── newcontestdialog.h ├── newcontestwidget.cpp ├── newcontestwidget.h ├── opencontestdialog.cpp ├── opencontestdialog.h ├── opencontestwidget.cpp ├── opencontestwidget.h ├── optionsdialog.cpp ├── optionsdialog.h ├── pch.h ├── resultviewer.cpp ├── resultviewer.h ├── statisticsbrowser.cpp ├── statisticsbrowser.h ├── summarytree.cpp ├── summarytree.h ├── taskeditwidget.cpp ├── taskeditwidget.h ├── testcaseeditwidget.cpp ├── testcaseeditwidget.h ├── themeeditdialog.cpp ├── themeeditdialog.h ├── visualmainsettings.cpp ├── visualmainsettings.h ├── visualsettings.cpp ├── visualsettings.h ├── welcomedialog.cpp └── welcomedialog.h ├── translations ├── en_US.ts ├── translations.qrc ├── zh_CN.ts └── zh_TW.ts └── unix ├── test ├── CMakeLists.txt ├── add.c ├── hello.c ├── hello.sh ├── mle_static.c ├── re.c ├── scripts │ ├── mle_static.py │ ├── redirect.py │ ├── run.py │ ├── run_sh.py │ ├── runtimeerr.py │ ├── space.py │ ├── symlink_abs.py │ ├── symlink_rel.py │ ├── tle.py │ └── unlimit.py └── tle.c ├── watcher.qrc ├── watcher_linux.cpp ├── watcher_macos.mm └── watcher_unix.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | BreakBeforeBraces: Attach 3 | IndentWidth: 4 4 | TabWidth: 4 5 | UseTab: ForIndentation 6 | ColumnLimit: 110 7 | 8 | ContinuationIndentWidth: 4 9 | IndentCaseLabels: true 10 | NamespaceIndentation: All 11 | SpaceAfterLogicalNot: true 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.txt text eof=lf 2 | *.cpp text eof=lf 3 | *.hpp text eof=lf 4 | *.h text eof=lf 5 | *.qrc text eof=lf 6 | *.cmake text eof=lf 7 | *.in text eof=lf 8 | *.ui text eof=lf 9 | *.md text eof=lf 10 | *.tex text eof=lf 11 | *.ts text eof=lf 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve | 汇报一个错误让工作人员处理 4 | title: "[BUG]" 5 | labels: 整叉劈了 | Bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | **描述一下这个 Bug** 12 | A clear and concise description of what the bug is. 清楚简明地描述这个 bug 是啥。 13 | 14 | **To Reproduce** 15 | **如何复现** 16 | Steps to reproduce the behavior: 像下面这样写出重现 Bug 的步骤: 17 | 1. Go to '...' 去 "…" 18 | 2. Click on '....' 点击 "…" 19 | 3. Scroll down to '....' 滚动到 "…" 20 | 4. See error 哦唷,崩溃啦! 21 | 22 | **Expected behavior** 23 | **期望获得的结果** 24 | A clear and concise description of what you expected to happen. 清楚简明地描述你认为程序应该做的事情。 25 | 26 | **Screenshots** 27 | **有截图吗?** 28 | If applicable, add screenshots to help explain your problem. 如果可以的话,附上屏幕截图来帮助表现 bug。 29 | 30 | **Environment:** 31 | **环境:** 32 | - Version: (e.g. 0.2.2) 版本代号:(比如 0.2.2) 33 | - OS: 系统: 34 | - \[ \] Windows (Which version? 哪个版本啊?) 35 | - \[ \] macOS 36 | - \[ \] Linux (Which edition and version? 哪个发行版和版本?) 37 | 38 | **Additional context** 39 | **其他信息** 40 | Add any other context about the problem here. 如果,你还有想说的话…… 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project | 对这个项目提个建议 4 | title: "[Feature]" 5 | labels: 想要点新功能 | Feature Request 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | **你的功能请求是否与某些问题有关?请描述。** 12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when \[...\] 对这些问题的清晰而简明的描述。比如:我想改进 \[…\] 13 | 14 | **Describe the solution you'd like** 15 | **描述您想要的解决方案** 16 | (Optional) A clear and concise description of what you want to happen. 清晰而简明地描述你想要的解决方案。(没有也可) 17 | 18 | **Additional context** 19 | **补充内容** 20 | Add any other context or screenshots about the feature request here. 如果,你还有想说的话…… 21 | -------------------------------------------------------------------------------- /.github/workflows/check_format.yml: -------------------------------------------------------------------------------- 1 | name: "Check Clang Format" 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | format: 7 | name: "Check Clang Format" 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - name: "Install clang-format" 12 | run: | 13 | sudo apt-get update 14 | sudo apt-get install clang-format 15 | - name: "Format Codes" 16 | run: clang-format -i src/*.cpp src/*.h src/**/*.cpp src/**/*.h src/**/**/*.cpp src/**/**/*.h src/**/*.hpp 17 | - name: Check diff 18 | run: git diff --exit-code HEAD 19 | - name: Create Pull Request 20 | if: failure() 21 | uses: peter-evans/create-pull-request@v3 22 | with: 23 | commit-message: "style: format codes" 24 | title: "Format codes for ${{ github.ref }}" 25 | labels: "style" 26 | assignees: "${{ github.actor }}" 27 | reviewers: "${{ github.actor }}" 28 | branch: "auto-pr/clang-format/${{ github.ref }}" 29 | -------------------------------------------------------------------------------- /.github/workflows/cpack-deb-debian.yml: -------------------------------------------------------------------------------- 1 | name: CPack - DEB - Debian 2 | 3 | on: 4 | # push代码时触发workflow 5 | push: 6 | # 忽略README.md 7 | paths-ignore: 8 | - "README.md" 9 | - "LICENSE" 10 | - "BUILD.md" 11 | # pull_request时触发workflow 12 | pull_request: 13 | # 忽略README.md 14 | paths-ignore: 15 | - "README.md" 16 | - "LICENSE" 17 | - "BUILD.md" 18 | release: 19 | types: [published] 20 | 21 | jobs: 22 | check_commit_msg: 23 | outputs: 24 | commit_message: ${{ steps.get_message.outputs.message }} 25 | name: Check if the workflow has been disabled. 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v4 29 | - name: Get commit message 30 | id: get_message 31 | run: | 32 | echo "message=$(git log --format=%B -n 1 ${{ github.event.after }})" >> $GITHUB_OUTPUT 33 | linux: 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | #distro: [stable, testing, sid] 38 | build_type: [Release, RelWithDebInfo] 39 | distro: [testing, sid] 40 | needs: check_commit_msg 41 | if: ${{ !contains( needs.check_commit_msg.outputs.commit_message, 'NO_DEB') }} 42 | name: Debian ${{ matrix.distro }} 43 | runs-on: ubuntu-latest 44 | container: debian:${{ matrix.distro }} 45 | 46 | steps: 47 | - name: Install git 48 | run: | 49 | apt-get update 50 | apt-get install -y git 51 | - name: Get the version 52 | id: get_version 53 | shell: bash 54 | run: echo "VERSION=$(echo $GITHUB_REF | cut -d / -f 3)" >> $GITHUB_OUTPUT 55 | - name: Checking out sources 56 | uses: actions/checkout@v4 57 | with: 58 | submodules: "recursive" 59 | - name: Install build dependencies 60 | run: | 61 | apt-get install -y build-essential ninja-build qtbase5-dev qttools5-dev cmake pkgconf bash libspdlog-dev 62 | - name: Build 63 | run: | 64 | mkdir build 65 | cd build 66 | cmake .. -GNinja -DEMBED_TRANSLATIONS=OFF -DEMBED_DOCS=OFF -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBUILD_DEB=ON -DLEMON_BUILD_INFO="Build for Debian" -DLEMON_BUILD_EXTRA_INFO="Build on $(uname -sr)" 67 | cmake --build . --target package --parallel $(nproc) 68 | - name: Get package name 69 | shell: bash 70 | id: get_package 71 | run: | 72 | echo "NAME=$(basename build/LemonLime-*.deb)" >> $GITHUB_OUTPUT 73 | - name: Upload artifact 74 | uses: actions/upload-artifact@v4 75 | with: 76 | name: LemonLime-${{ steps.get_version.outputs.VERSION }}-debian-${{ matrix.distro }}-${{ matrix.build_type }}.deb 77 | path: build/${{ steps.get_package.outputs.NAME }} 78 | - name: Upload binaries to release 79 | uses: svenstaro/upload-release-action@v2 80 | if: startsWith(github.event.ref, 'refs/tags/') 81 | with: 82 | repo_token: ${{ secrets.GITHUB_TOKEN }} 83 | file: build/${{ steps.get_package.outputs.NAME }} 84 | asset_name: LemonLime-${{ steps.get_version.outputs.VERSION }}-debian-${{ matrix.distro }}-${{ matrix.build_type }}.deb 85 | tag: ${{ github.ref }} 86 | overwrite: true 87 | -------------------------------------------------------------------------------- /.github/workflows/hashfile.yml: -------------------------------------------------------------------------------- 1 | name: Update release files hash 2 | 3 | on: 4 | release: 5 | types: [edited] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - run: echo "VERSION=\"$(echo $GITHUB_REF | cut -d / -f 3)\"" >> $GITHUB_ENV 13 | shell: bash 14 | - run: echo "REPOSITORY_NAME=\"$(echo \"$GITHUB_REPOSITORY\" | awk -F / '{print $2}')\"" >> $GITHUB_ENV 15 | shell: bash 16 | - name: Checking out sources 17 | uses: actions/checkout@v4 18 | with: 19 | ref: master 20 | - name: Hash File 21 | shell: bash 22 | run: | 23 | wget -O release.info https://api.github.com/repos/iotang/${REPOSITORY_NAME}/releases/tags/${VERSION} 24 | cat ./release.info | jq -r ".assets | .[] | .browser_download_url" > download.list 25 | cat ./release.info | jq -r ".assets | .[] | { uploader_id: .uploader.login, asset_name: .name }" > assets.info.json 26 | mkdir files 27 | cd files 28 | for x in $(cat ../download.list); do 29 | wget "$x"; 30 | done; 31 | rm assets.info.json || true 32 | rm sha256.list || true 33 | sha256sum ./* > ../sha256.list 34 | - name: Upload metadata to release 35 | uses: svenstaro/upload-release-action@v2 36 | with: 37 | repo_token: ${{ secrets.GITHUB_TOKEN }} 38 | file: assets.info.json 39 | asset_name: assets.info.json 40 | tag: ${{ github.ref }} 41 | overwrite: true 42 | - name: Upload metadata to release 43 | uses: svenstaro/upload-release-action@v2 44 | with: 45 | repo_token: ${{ secrets.GITHUB_TOKEN }} 46 | file: sha256.list 47 | asset_name: sha256.list 48 | tag: ${{ github.ref }} 49 | overwrite: true 50 | -------------------------------------------------------------------------------- /.github/workflows/macos-qt6.yml: -------------------------------------------------------------------------------- 1 | name: MacOS Qt6 2 | on: 3 | push: 4 | paths-ignore: 5 | - "README.md" 6 | - "LICENSE" 7 | - "BUILD.md" 8 | pull_request: 9 | paths-ignore: 10 | - "README.md" 11 | - "LICENSE" 12 | - "BUILD.md" 13 | release: 14 | types: [published] 15 | jobs: 16 | build: 17 | name: Build 18 | runs-on: ${{ matrix.os }} 19 | strategy: 20 | matrix: 21 | os: [macos-latest] 22 | build_type: [Release, RelWithDebInfo] 23 | arch: [x86_64, arm64] 24 | qt_ver: [6.7.2] 25 | qt_arch: [clang_64] 26 | env: 27 | targetName: lemon 28 | steps: 29 | - name: Install Qt 30 | uses: jurplel/install-qt-action@v3 31 | with: 32 | version: ${{ matrix.qt_ver }} 33 | cached: ${{ steps.MacosCacheQt.outputs.cache-hit }} 34 | 35 | - uses: actions/checkout@v4 36 | with: 37 | submodules: true 38 | - name: macOS - ${{ matrix.qt_version }} - Build preparation - Install Packages 39 | run: | 40 | brew install ninja pkg-config 41 | - name: build macos 42 | run: | 43 | cmake . \ 44 | -GNinja \ 45 | -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ 46 | -DLEMON_QT6=ON \ 47 | -DLEMON_BUILD_INFO="Build for macOS" \ 48 | -DLEMON_BUILD_EXTRA_INFO="Build on $(uname -sr)" \ 49 | -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 \ 50 | -DCMAKE_OSX_ARCHITECTURES="${{ matrix.arch }}" 51 | cmake --build . --parallel $(sysctl -n hw.logicalcpu) 52 | # tag 打包 53 | - name: package 54 | env: 55 | Qt6_DIR: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 56 | run: | 57 | # 拷贝依赖 58 | #mv ${targetName} ${targetName}.app 59 | export PATH=$Qt6_DIR/bin:$PATH 60 | macdeployqt ${targetName}.app -qmldir=. -verbose=1 -dmg 61 | - name: Upload artifact 62 | uses: actions/upload-artifact@v4 63 | with: 64 | name: ${{ env.targetName }}-Qt${{ matrix.qt_ver }}-${{ matrix.build_type }}-${{ matrix.arch }}.dmg 65 | path: ${{ env.targetName }}.dmg 66 | - name: uploadRelease 67 | if: startsWith(github.event.ref, 'refs/tags/') 68 | uses: svenstaro/upload-release-action@v2 69 | with: 70 | repo_token: ${{ secrets.GITHUB_TOKEN }} 71 | file: ./${{ env.targetName }}.dmg 72 | asset_name: ${{ env.targetName }}-Qt${{ matrix.qt_ver }}-${{ matrix.build_type }}-${{ matrix.arch }}.dmg 73 | tag: ${{ github.ref }} 74 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: MacOS 2 | on: 3 | push: 4 | paths-ignore: 5 | - "README.md" 6 | - "LICENSE" 7 | - "BUILD.md" 8 | pull_request: 9 | paths-ignore: 10 | - "README.md" 11 | - "LICENSE" 12 | - "BUILD.md" 13 | release: 14 | types: [published] 15 | jobs: 16 | build: 17 | name: Build 18 | runs-on: ${{ matrix.os }} 19 | strategy: 20 | matrix: 21 | os: [macos-13] 22 | build_type: [Release, RelWithDebInfo] 23 | qt_ver: [5.15.2] 24 | qt_arch: [clang_64] 25 | env: 26 | targetName: lemon 27 | steps: 28 | - name: cacheQt 29 | id: MacosCacheQt 30 | uses: actions/cache@v4 31 | with: 32 | path: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 33 | key: ${{ runner.os }}-Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 34 | # - name: setupQt 35 | # if: steps.MacosCacheQt.outputs.cache-hit == 'true' 36 | # shell: bash 37 | # env: 38 | # QtPath: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 39 | # run: | 40 | # qt_Path=${env:QtPath} 41 | # echo "Qt5_DIR=\"$QtPath\"" >> $GITHUB_ENV 42 | # echo "${qt_Path}/bin" >> $GITHUB_PATH 43 | - name: Install Qt 44 | if: steps.MacosCacheQt.outputs.cache-hit != 'true' 45 | uses: jurplel/install-qt-action@v3 46 | with: 47 | version: ${{ matrix.qt_ver }} 48 | 49 | - uses: actions/checkout@v4 50 | with: 51 | submodules: true 52 | - name: macOS - ${{ matrix.qt_version }} - Build preparation - Install Packages 53 | run: | 54 | brew install ninja pkg-config 55 | - name: build macos 56 | env: 57 | Qt5_DIR: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 58 | run: | 59 | cmake . -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DLEMON_BUILD_INFO="Build for macOS" -DLEMON_BUILD_EXTRA_INFO="Build on $(uname -sr)" -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 60 | cmake --build . --parallel $(sysctl -n hw.logicalcpu) 61 | # tag 打包 62 | - name: package 63 | env: 64 | Qt5_DIR: ../Qt/${{matrix.qt_ver}}/${{matrix.qt_arch}} 65 | run: | 66 | # 拷贝依赖 67 | #mv ${targetName} ${targetName}.app 68 | export PATH=$Qt5_DIR/bin:$PATH 69 | macdeployqt ${targetName}.app -qmldir=. -verbose=1 -dmg 70 | - name: Upload artifact 71 | uses: actions/upload-artifact@v4 72 | with: 73 | name: ${{ env.targetName }}-${{ matrix.build_type }}.dmg 74 | path: ${{ env.targetName }}.dmg 75 | - name: uploadRelease 76 | if: startsWith(github.event.ref, 'refs/tags/') 77 | uses: svenstaro/upload-release-action@v2 78 | with: 79 | repo_token: ${{ secrets.GITHUB_TOKEN }} 80 | file: ./${{ env.targetName }}.dmg 81 | asset_name: ${{ env.targetName }}-${{ matrix.build_type }}.dmg 82 | tag: ${{ github.ref }} 83 | -------------------------------------------------------------------------------- /.github/workflows/sourcefile.yml: -------------------------------------------------------------------------------- 1 | name: All Source Files 2 | 3 | on: 4 | push: 5 | release: 6 | types: [published, edited] 7 | 8 | jobs: 9 | check_commit_msg: 10 | outputs: 11 | commit_message: ${{ steps.get_message.outputs.message }} 12 | name: Check if the workflow has been disabled. 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Get commit message 17 | id: get_message 18 | run: | 19 | echo "message=$(git log --format=%B -n 1 ${{ github.event.after }})" >> $GITHUB_OUTPUT 20 | linux: 21 | needs: check_commit_msg 22 | name: All Source Files 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - name: Install git 27 | run: | 28 | sudo apt-get update 29 | sudo apt-get install -y git 30 | - name: Get the version 31 | id: get_version 32 | shell: bash 33 | run: echo "VERSION=$(echo $GITHUB_REF | cut -d / -f 3)" >> $GITHUB_OUTPUT 34 | - name: Checking out sources 35 | uses: actions/checkout@v4 36 | with: 37 | submodules: "recursive" 38 | - name: Create 7z Release 39 | uses: DuckSoft/create-7z-action@v1.0 40 | with: 41 | pathSource: ./ 42 | pathTarget: ./Lemon-${{ steps.get_version.outputs.VERSION }}-source-all.7z 43 | - name: Upload artifact 44 | uses: actions/upload-artifact@v4 45 | with: 46 | name: Lemon-${{ steps.get_version.outputs.VERSION }}-source-all.7z 47 | path: Lemon-${{ steps.get_version.outputs.VERSION }}-source-all.7z 48 | - name: Upload binaries to release 49 | uses: svenstaro/upload-release-action@v2 50 | if: startsWith(github.event.ref, 'refs/tags/') 51 | with: 52 | repo_token: ${{ secrets.GITHUB_TOKEN }} 53 | file: Lemon-${{ steps.get_version.outputs.VERSION }}-source-all.7z 54 | asset_name: Lemon-${{ steps.get_version.outputs.VERSION }}-source-all.7z 55 | tag: ${{ github.ref }} 56 | overwrite: true 57 | -------------------------------------------------------------------------------- /.github/workflows/watcher_linux.yml: -------------------------------------------------------------------------------- 1 | name: Watcher for Linux Test 2 | 3 | on: 4 | push: 5 | branches: ["master"] 6 | paths: ["unix/**"] 7 | pull_request: 8 | branches: ["master"] 9 | paths: ["unix/**"] 10 | workflow_dispatch: 11 | 12 | env: 13 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 14 | BUILD_TYPE: Release 15 | 16 | jobs: 17 | build: 18 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 19 | # You can convert this to a matrix build if you need cross-platform coverage. 20 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Configure CMake 27 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 28 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 29 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} unix/test 30 | 31 | - name: Build 32 | # Build your program with the given configuration 33 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 34 | 35 | - name: Test 36 | working-directory: ${{github.workspace}}/build 37 | # Execute tests defined by the CMake configuration. 38 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 39 | run: ctest --verbose -C ${{env.BUILD_TYPE}} 40 | -------------------------------------------------------------------------------- /.github/workflows/watcher_macos.yml: -------------------------------------------------------------------------------- 1 | name: Watcher for MacOS Test 2 | 3 | on: 4 | push: 5 | branches: ["master"] 6 | paths: ["unix/**"] 7 | pull_request: 8 | branches: ["master"] 9 | paths: ["unix/**"] 10 | workflow_dispatch: 11 | 12 | env: 13 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 14 | BUILD_TYPE: Release 15 | 16 | jobs: 17 | build: 18 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 19 | # You can convert this to a matrix build if you need cross-platform coverage. 20 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 21 | runs-on: macos-13 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Configure CMake 27 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 28 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 29 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} unix/test 30 | 31 | - name: Build 32 | # Build your program with the given configuration 33 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 34 | 35 | - name: Test 36 | working-directory: ${{github.workspace}}/build 37 | # Execute tests defined by the CMake configuration. 38 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 39 | run: ctest --verbose -C ${{env.BUILD_TYPE}} 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Qt 35 | moc_*.cpp 36 | moc_*.h 37 | ui_*.cpp 38 | ui_*.h 39 | qrc_resource.cpp 40 | lemon.pro.user 41 | 42 | # CMake 43 | .ninja_deps 44 | .ninja_log 45 | CMakeCache.txt 46 | CMakeFiles/ 47 | CMakeLists.txt.user 48 | build.ninja 49 | cmake_install.cmake 50 | lemon 51 | *_autogen/ 52 | watcher_unix 53 | CPackConfig.cmake 54 | CPackSourceConfig.cmake 55 | _CPack_Packages/ 56 | install_manifest.txt 57 | lemon-*-Linux.sh 58 | lemon-*-Linux.tar.Z 59 | lemon-*-Linux.tar.gz 60 | 61 | # KDevelop 62 | .kdev4/ 63 | *.kdev4 64 | .cache/ 65 | 66 | # Extra 67 | build/ 68 | build-debug/ 69 | .idea/ 70 | cmake-build-debug/ 71 | 72 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rdparty/SingleApplication"] 2 | path = 3rdparty/SingleApplication 3 | url = https://github.com/itay-grudev/SingleApplication.git 4 | [submodule "assets/Testlib-for-Lemons"] 5 | path = assets/Testlib-for-Lemons 6 | url = https://github.com/GitPinkRabbit/Testlib-for-Lemons.git 7 | [submodule "3rdparty/spdlog"] 8 | path = 3rdparty/spdlog 9 | url = https://github.com/gabime/spdlog/ 10 | branch = v1.x 11 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Current maintainer: 2 | * Coelacanthus 3 | * iotang <> 4 | 5 | Original author: 6 | * Zhipeng Jia 7 | 8 | Contributors: 9 | * iotang <> 10 | * Coelacanthus 11 | * Dust1404 <> 12 | * swift-zym (Yiming Zhang) <> 13 | * memset0 14 | * Alphagocc 15 | * Xeonacid <> 16 | 17 | Image: 18 | * files assets/icons/lemon-lime.png 19 | copyright: iotang <> 20 | license: GPLv3 21 | 22 | Translations authors: 23 | * files: translations/*.ts 24 | * file: assets/lemon-lime.desktop 25 | copyright: 26 | - Chinese (Simplified): iotang <> and Coelacanthus 27 | - Chinese (Traditional): Coelacanthus and KunoiSayami <> 28 | - English: iotang <> and Coelacanthus 29 | license: GPLv3 30 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Thw master branch is develop branch, 2 | x.y.z branch is the maintenance branch. 3 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Improve: 2 | * config: 3 | - refactor to store config in same format on different platform (#69) 4 | 5 | * judge: 6 | - rewrite (maybe a sandbox) (#64) 7 | - WSL support (#81) 8 | - Scorer Support 9 | 10 | * UI: 11 | - tui/cli support (#67) 12 | - QML GUI 13 | 14 | 15 | 16 | Bugfix: 17 | * platform dependent 18 | - crash on macOS Big Sur (#72) 19 | 20 | -------------------------------------------------------------------------------- /assets/MacOSXInfo.plist.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleInfoDictionaryVersion 8 | 6.0 9 | CFBundlePackageType 10 | APPL 11 | 12 | CFBundleName 13 | ${MACOSX_BUNDLE_BUNDLE_NAME} 14 | CFBundleExecutable 15 | ${MACOSX_BUNDLE_EXECUTABLE_NAME} 16 | NSHumanReadableCopyright 17 | ${MACOSX_BUNDLE_COPYRIGHT} 18 | 19 | CFBundleVersion 20 | ${MACOSX_BUNDLE_BUNDLE_VERSION} 21 | CFBundleLongVersionString 22 | ${MACOSX_BUNDLE_LONG_VERSION_STRING} 23 | CFBundleShortVersionString 24 | ${MACOSX_BUNDLE_SHORT_VERSION_STRING} 25 | 26 | CFBundleIdentifier 27 | ${MACOSX_BUNDLE_GUI_IDENTIFIER} 28 | 29 | 30 | NSPrincipalClass 31 | NSApplication 32 | NSHighResolutionCapable 33 | True 34 | 35 | 36 | -------------------------------------------------------------------------------- /assets/icons/lemon-lime.1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.1024.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.128.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.150.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.16.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.192.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.22.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.24.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.256.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.310.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.32.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.36.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.44.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.48.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.512.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.64.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.72.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.96.png -------------------------------------------------------------------------------- /assets/icons/lemon-lime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/icons/lemon-lime.png -------------------------------------------------------------------------------- /assets/lemon-lime.desktop.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env xdg-open 2 | [Desktop Entry] 3 | Version=1.0 4 | Name=LemonLime 5 | Type=Application 6 | GenericName=A tiny judging environment for OI contest 7 | GenericName[zh_CN]=为了 OI 比赛而生的轻量评测系统 8 | GenericName[zh_TW]=為了 OI 比賽而生的輕量評測系統 9 | GenericName[ja]=OI競争のための軽量評価システム 10 | Comment=A tiny judging environment for OI contest based on Project_LemonPlus 11 | Comment[zh_CN]=为了 OI 比赛而生的基于 Lemon + LemonPlus 的轻量评测系统 12 | Comment[zh_TW]=為了 OI 比賽而生的基於 Lemon + LemonPlus 的輕量評測系統 13 | Comment[ja]=Lemon + LemonPlusに基づくOI競争用の軽量評価システム 14 | Keywords=OI;Qt;Judge; 15 | Keywords[zh_CN]=OI;Qt;评测; 16 | Keywords[zh_TW]=OI;Qt;評測; 17 | Keywords[ja]=OI;Qt;評価; 18 | Categories=Utility;Education;Competition; 19 | Terminal=false 20 | Path=/usr/bin 21 | Exec=lemon 22 | Icon=lemon-lime 23 | MimeType=application/x-lemon-contest; 24 | -------------------------------------------------------------------------------- /assets/lemon-lime.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/lemon-lime.ico -------------------------------------------------------------------------------- /assets/lemon-lime.metainfo.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.lemonlime.LemonLime 4 | GPL-3.0+ 5 | GPL-3.0+ 6 | LemonLime 7 | A tiny judging environment for OI contest 8 | 9 |

10 | A tiny judging environment for OI contest based on Project_LemonPlus and Lemon 11 |

12 |
13 | https://github.com/Project-LemonLime/Project_LemonLime 14 | https://github.com/Project-LemonLime/Project_LemonLime/issues 15 | 16 | Development 17 | Education 18 | Competition 19 | 20 | 21 | 22 | https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/master/assets/icons/lemon-lime.png 23 | 24 | 25 | 26 | lemon 27 | 28 | 29 | 30 | 31 |
32 | -------------------------------------------------------------------------------- /assets/lemon.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "lemon-lime.ico" 2 | -------------------------------------------------------------------------------- /assets/pics/acrobat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/pics/application-exit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /assets/pics/code-function.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/configure.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/deletecell.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /assets/pics/dialog-cancel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/dialog-ok-apply.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/document-close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /assets/pics/document-edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/document-export.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/document-new.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/document-save.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/edit-clear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/edit-delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /assets/pics/edit-find-replace.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/edit-find.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/go-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /assets/pics/go-parent-folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/go-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /assets/pics/help-about.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/layer-new.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/list-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/list-remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/media-playback-stop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/media-skip-forward.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /assets/pics/paint-none.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /assets/pics/paint-unknown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/quickopen-file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/pics/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/pics/splash.png -------------------------------------------------------------------------------- /assets/pics/splash2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/assets/pics/splash2.png -------------------------------------------------------------------------------- /assets/pics/system-help.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /assets/pics/view-refresh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /assets/pics/view-sort.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/x-lemon-contest.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Lemon Contest File 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cmake/LemonDocs.cmake: -------------------------------------------------------------------------------- 1 | # ================================================================================== 2 | # Lemon Documents 3 | # ================================================================================== 4 | 5 | if(EMBED_DOCS) 6 | add_definitions(-DLEMON_EMBED_DOCS) 7 | set(LEMON_EMBED_DOC_QRC ${CMAKE_SOURCE_DIR}/manual/manual.qrc) 8 | endif() 9 | -------------------------------------------------------------------------------- /cmake/LemonTranslations.cmake: -------------------------------------------------------------------------------- 1 | # ================================================================================== 2 | # Lemon Translations 3 | # ================================================================================== 4 | 5 | find_package(${LEMON_QT_LIBNAME} COMPONENTS LinguistTools REQUIRED) 6 | set(TRANSLATIONS_DIR ${CMAKE_SOURCE_DIR}/translations) 7 | file(GLOB TRANSLATIONS_TS ${TRANSLATIONS_DIR}/**.ts) 8 | qt_add_translation(QM_FILES ${TRANSLATIONS_TS}) 9 | -------------------------------------------------------------------------------- /cmake/deployment.cmake: -------------------------------------------------------------------------------- 1 | # Packaging 2 | set(CPACK_PACKAGE_NAME "LemonLime") 3 | set(CPACK_PACKAGE_VENDOR "Project LemonLime Developers") 4 | set(CPACK_PACKAGE_DESCRIPTION "A tiny judging environment for OI contest based on Lemon + LemonPlus.") 5 | set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/Project-LemonLime/Project_LemonLime") 6 | set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/assets/lemon-lime.ico") 7 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSES") 8 | 9 | SET(COMMON_IGNORE_FILES "/CMakeFiles/" "_CPack_Packages/" "/Testing/" 10 | ".cmake$" ".directory$" "CMakeCache.txt" 11 | "/.svn/" "/CVS/" "~$" ".swp$" ".log$" ".gz$" 12 | "/src/config.h$") 13 | 14 | SET(CPACK_PACKAGE_IGNORE_FILES ${PRJ_COMMON_IGNORE_FILES} ) 15 | 16 | if(UNIX) 17 | if(BUILD_DEB) 18 | set(CPACK_GENERATOR "DEB") 19 | set(CPACK_DEBIAN_PACKAGE_NAME "LemonLime") 20 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Project LemonLime Developers") 21 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "qtbase5-dev, qttools5-dev, libspdlog") 22 | endif() 23 | 24 | if(BUILD_RPM) 25 | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/makespec/lemonlime.spec.in" "${CMAKE_CURRENT_BINARY_DIR}/lemonlime.spec" @ONLY IMMEDIATE) 26 | #set(CPACK_RPM_USER_BINARY_SPECFILE "${CMAKE_CURRENT_BINARY_DIR}/lemonlime.spec") 27 | set(CPACK_GENERATOR "RPM") 28 | set(CPACK_RPM_PACKAGE_NAME "LemonLime") 29 | set(CPACK_RPM_PACKAGE_VENDOR "Project LemonLime Developers") 30 | if(LSB_RELEASE_ID_SHORT EQUAL "openSUSE") 31 | set(CPACK_RPM_BUILDREQUIRES "cmake >= 3.9, libqt5-qtbase-common-devel >= 5.15, libQt5Core-devel, libQt5Gui-devel, libQt5Network-devel, libQt5Widgets-devel, libQt5Concurrent-devel, libqt5-linguist-devel, libqt5-qtsvg-devel, update-desktop-files, ninja, spdlog-devel") 32 | else() 33 | set(CPACK_RPM_BUILDREQUIRES "cmake >= 3.9, qt5-qtbase-devel >= 5.15, qt5-linguist, qt5-qtsvg-devel, desktop-file-utils, ninja-build, spdlog") 34 | endif() 35 | set(CPACK_RPM_PACKAGE_LICENSE "GPL-3.0-or-later") 36 | endif() 37 | endif() 38 | 39 | # Must Here 40 | include(CPack) 41 | -------------------------------------------------------------------------------- /cmake/lemon-base.cmake: -------------------------------------------------------------------------------- 1 | # ================================================================================== 2 | # Lemon Base 3 | # ================================================================================== 4 | 5 | set(LEMON_BASEDIR_BASE ${CMAKE_SOURCE_DIR}/src/base) 6 | 7 | aux_source_directory(${LEMON_BASEDIR_BASE} LEMON_BASE_SOURCES) 8 | 9 | add_library(lemon-base STATIC 10 | ${LEMON_BASE_SOURCES} 11 | ${SINGLEAPPLICATION_SOURCES} 12 | ) 13 | 14 | target_precompile_headers(lemon-base PUBLIC ${CMAKE_SOURCE_DIR}/src/pch.h) 15 | 16 | target_link_libraries(lemon-base 17 | ${LEMON_QT_LIBS} 18 | ${SINGLEAPPLICATION_LIBRARY} 19 | ) 20 | 21 | target_include_directories(lemon-base PUBLIC 22 | ${CMAKE_BINARY_DIR} 23 | ${LEMON_BASEDIR_BASE} 24 | ${SINGLEAPPLICATION_DIR} 25 | ${spdlog_DIR}/include 26 | ${CMAKE_CURRENT_SOURCE_DIR} 27 | ${CMAKE_CURRENT_SOURCE_DIR}/src 28 | ) 29 | -------------------------------------------------------------------------------- /cmake/lemon-core.cmake: -------------------------------------------------------------------------------- 1 | # ================================================================================== 2 | # Lemon Core 3 | # ================================================================================== 4 | 5 | set(LEMON_BASEDIR_CORE ${CMAKE_SOURCE_DIR}/src/core) 6 | 7 | aux_source_directory(${LEMON_BASEDIR_CORE} LEMON_CORE_SOURCES) 8 | 9 | add_library(lemon-core STATIC 10 | ${LEMON_CORE_SOURCES} 11 | ${SINGLEAPPLICATION_SOURCES} 12 | ) 13 | 14 | target_precompile_headers(lemon-core PUBLIC ${CMAKE_SOURCE_DIR}/src/pch.h) 15 | 16 | target_link_libraries(lemon-core 17 | lemon-base 18 | ${LEMON_QT_LIBS} 19 | ${SINGLEAPPLICATION_LIBRARY} 20 | ) 21 | 22 | target_include_directories(lemon-core PUBLIC 23 | ${CMAKE_BINARY_DIR} 24 | ${LEMON_BASEDIR_CORE} 25 | ${SINGLEAPPLICATION_DIR} 26 | ${spdlog_DIR}/include 27 | ${CMAKE_CURRENT_SOURCE_DIR} 28 | ${CMAKE_CURRENT_SOURCE_DIR}/src 29 | ) 30 | -------------------------------------------------------------------------------- /cmake/lemon-ui.cmake: -------------------------------------------------------------------------------- 1 | # ================================================================================== 2 | # Lemon UI 3 | # ================================================================================== 4 | 5 | set(LEMON_BASEDIR_UI ${CMAKE_SOURCE_DIR}/src) 6 | 7 | aux_source_directory(${LEMON_BASEDIR_UI} LEMON_UI_SOURCES) 8 | 9 | list(APPEND LEMON_UI_SOURCES ${LEMON_BASEDIR_UI}/component/exportutil/exportutil.cpp) 10 | list(APPEND LEMON_UI_SOURCES ${LEMON_BASEDIR_UI}/component/exportutil/exportutil.h) 11 | 12 | set(LEMON_UI_FORMS 13 | ${LEMON_BASEDIR_UI}/forms/lemon.ui 14 | ${LEMON_BASEDIR_UI}/forms/exttestcasemodifierdialog.ui 15 | ${LEMON_BASEDIR_UI}/forms/exttestcasemodifier.ui 16 | ${LEMON_BASEDIR_UI}/forms/exttestcaseupdaterdialog.ui 17 | ${LEMON_BASEDIR_UI}/forms/taskeditwidget.ui 18 | ${LEMON_BASEDIR_UI}/forms/testcaseeditwidget.ui 19 | ${LEMON_BASEDIR_UI}/forms/generalsettings.ui 20 | ${LEMON_BASEDIR_UI}/forms/compilersettings.ui 21 | ${LEMON_BASEDIR_UI}/forms/addtestcaseswizard.ui 22 | ${LEMON_BASEDIR_UI}/forms/judgingdialog.ui 23 | ${LEMON_BASEDIR_UI}/forms/optionsdialog.ui 24 | ${LEMON_BASEDIR_UI}/forms/detaildialog.ui 25 | ${LEMON_BASEDIR_UI}/forms/newcontestwidget.ui 26 | ${LEMON_BASEDIR_UI}/forms/opencontestwidget.ui 27 | ${LEMON_BASEDIR_UI}/forms/newcontestdialog.ui 28 | ${LEMON_BASEDIR_UI}/forms/opencontestdialog.ui 29 | ${LEMON_BASEDIR_UI}/forms/visualmainsettings.ui 30 | ${LEMON_BASEDIR_UI}/forms/visualsettings.ui 31 | ${LEMON_BASEDIR_UI}/forms/themeeditdialog.ui 32 | ${LEMON_BASEDIR_UI}/forms/welcomedialog.ui 33 | ${LEMON_BASEDIR_UI}/forms/addtaskdialog.ui 34 | ${LEMON_BASEDIR_UI}/forms/advancedcompilersettingsdialog.ui 35 | ${LEMON_BASEDIR_UI}/forms/environmentvariablesdialog.ui 36 | ${LEMON_BASEDIR_UI}/forms/editvariabledialog.ui 37 | ${LEMON_BASEDIR_UI}/forms/addcompilerwizard.ui 38 | ${LEMON_BASEDIR_UI}/forms/statisticsbrowser.ui 39 | ) 40 | -------------------------------------------------------------------------------- /cmake/platforms/linux.cmake: -------------------------------------------------------------------------------- 1 | install(TARGETS lemon RUNTIME DESTINATION bin) 2 | 3 | include(GNUInstallDirs) 4 | 5 | set(LEMON_LINUX_ICON_DIMENSIONS 16 22 24 32 36 44 48 64 72 96 128 150 192 256 310 512 1024) 6 | install(FILES assets/lemon-lime.metainfo.xml.in DESTINATION "${CMAKE_INSTALL_DATADIR}/metainfo" RENAME lemon-lime.metainfo.xml) 7 | install(FILES assets/x-lemon-contest.xml.in DESTINATION "${CMAKE_INSTALL_DATADIR}/mime/application" RENAME x-lemon-contest.xml) 8 | install(FILES assets/lemon-lime.desktop.in DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" RENAME lemon-lime.desktop) 9 | #install(FILES assets/icons/lemon-lime.svg DESTINATION "${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps") 10 | foreach(LEMON_LINUX_ICON_DIMENSION ${LEMON_LINUX_ICON_DIMENSIONS}) 11 | install(FILES assets/icons/lemon-lime.${LEMON_LINUX_ICON_DIMENSION}.png DESTINATION "${CMAKE_INSTALL_DATADIR}/icons/hicolor/${LEMON_LINUX_ICON_DIMENSION}x${LEMON_LINUX_ICON_DIMENSION}/apps" RENAME lemon-lime.png) 12 | endforeach(LEMON_LINUX_ICON_DIMENSION) 13 | if(NOT EMBED_TRANSLATIONS) 14 | install(FILES ${QM_FILES} DESTINATION "${CMAKE_INSTALL_DATADIR}/lemon-lime/lang") 15 | endif() 16 | if(NOT EMBED_DOCS) 17 | install(FILES manual/llmanual.pdf DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/lemon-lime") 18 | endif() 19 | install(FILES assets/Testlib-for-Lemons/testlib.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} RENAME testlib_for_lemons.h) 20 | -------------------------------------------------------------------------------- /cmake/platforms/macos.cmake: -------------------------------------------------------------------------------- 1 | set_target_properties(lemon 2 | PROPERTIES 3 | MACOSX_BUNDLE TRUE 4 | MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/assets/MacOSXInfo.plist.in" 5 | MACOSX_BUNDLE_BUNDLE_NAME "LemonLime" 6 | MACOSX_BUNDLE_COPYRIGHT "Copyright (c) 2019-2024 Project LemonLime" 7 | MACOSX_BUNDLE_BUNDLE_VERSION ${VERSION_STRING} 8 | MACOSX_BUNDLE_LONG_VERSION_STRING ${VERSION_STRING} 9 | MACOSX_BUNDLE_SHORT_VERSION_STRING ${VERSION_STRING} 10 | MACOSX_BUNDLE_GUI_IDENTIFIER "com.github.lemonlime" 11 | ) 12 | -------------------------------------------------------------------------------- /cmake/platforms/windows.cmake: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | STAGE_FILES=$(git diff --cached --name-only --diff-filter=ACM -- 'makespec/BUILDVERSION') 3 | #echo $STAGE_FILES 4 | if test ${#STAGE_FILES} -gt 0 5 | then 6 | echo 'BUILDVERSION already changed, not touching' 7 | else 8 | echo 'Increasing BUILDVERSION' 9 | expr $(cat ./makespec/BUILDVERSION) + 1 > ./makespec/BUILDVERSION 10 | cat ./makespec/BUILDVERSION 11 | git add ./makespec/BUILDVERSION 12 | fi 13 | -------------------------------------------------------------------------------- /makespec/BUILDVERSION: -------------------------------------------------------------------------------- 1 | 271 2 | -------------------------------------------------------------------------------- /makespec/VERSION: -------------------------------------------------------------------------------- 1 | 0.3.5 -------------------------------------------------------------------------------- /makespec/VERSIONSUFFIX: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/makespec/VERSIONSUFFIX -------------------------------------------------------------------------------- /makespec/lemonlime.spec.in: -------------------------------------------------------------------------------- 1 | # disable debug packages, use explicit glibc-langpack follow openSUSE:Tools/obs-service-tar_scm 2 | %if 0%{?fedora_version} || 0%{?centos_version} || 0%{?rhel_version} 3 | %global debug_package %{nil} 4 | %define locale_package glibc-langpack-en 5 | %endif 6 | %define interface_version 3 7 | 8 | Name: LemonLime 9 | Version: @CPACK_PACKAGE_VERSION@ 10 | Release: 0 11 | Summary: A tiny judging environment for OI contest based on Lemon + LemonPlus 12 | License: GPL-3.0-only 13 | Url: https://github.com/Project-LemonLime/Project_LemonLime 14 | Source0: https://github.com/Project-LemonLime/Project_LemonLime/releases/download/@CPACK_PACKAGE_VERSION@/Lemon-@CPACK_PACKAGE_VERSION@-source-all.7z 15 | %if 0%{?suse_version} 16 | # for openSUSE 17 | BuildRequires: cmake >= 3.9 18 | BuildRequires: libqt5-qtbase-common-devel >= 5.15 19 | BuildRequires: libQt5Core-devel 20 | BuildRequires: libQt5Gui-devel 21 | BuildRequires: libQt5Network-devel 22 | BuildRequires: libQt5Widgets-devel 23 | BuildRequires: libQt5Concurrent-devel 24 | BuildRequires: libqt5-linguist-devel 25 | BuildRequires: libqt5-qtsvg-devel 26 | BuildRequires: update-desktop-files 27 | BuildRequires: ninja 28 | BuildRequires: spdlog-devel 29 | %else 30 | # for Fedora/CentOS/ ... 31 | %if 0%{?rhel} 32 | BuildRequires: epel-rpm-macros 33 | %endif 34 | BuildRequires: cmake >= 3.9 35 | BuildRequires: qt5-qtbase-devel >= 5.15 36 | BuildRequires: qt5-linguist 37 | BuildRequires: qt5-qtsvg-devel 38 | #BuildRequires: %{locale_package} 39 | BuildRequires: desktop-file-utils 40 | BuildRequires: ninja-build 41 | BuildRequires: spdlog 42 | %endif 43 | 44 | 45 | %description 46 | A tiny judging environment for OI contest based on Lemon + LemonPlus. 47 | 48 | 49 | %prep 50 | #%setup -qn Lemon-%{version} 51 | %define INSTALL_PREFIX %{buildroot}/usr 52 | %define BUILD_SOURCE %{_builddir}/LemonLime-%{version} 53 | %define BUILD_DIR %{_builddir}/LemonLime-%{version}/build 54 | mkdir -p %{BUILD_DIR} 55 | 56 | %build 57 | # build 58 | export _LEMON_BUILD_INFO_="LemonLime built by openSUSE Build Service" 59 | export _LEMON_BUILD_EXTRA_INFO_="(Official Build) $(uname -a | cut -d ' ' -f3,13), Qt $(pkg-config --modversion Qt5Core)" 60 | 61 | %if 0%{?centos_version} 62 | cd %{BUILD_DIR} 63 | cmake .. \ 64 | %else 65 | cmake -S %{BUILD_SOURCE} -B %{BUILD_DIR} \ 66 | %endif 67 | -DCMAKE_INSTALL_PREFIX="%{INSTALL_PREFIX}" \ 68 | -DCMAKE_BUILD_TYPE=Release \ 69 | -GNinja 70 | ninja -C %{BUILD_DIR} 71 | 72 | %install 73 | ninja -C %{BUILD_DIR} install 74 | 75 | %post 76 | %postun 77 | 78 | %files 79 | %license LICENSE 80 | %doc README.md 81 | %{_bindir}/lemon-lime 82 | %{_datadir}/applications/lemon-lime.desktop 83 | %{_datadir}/icons/hicolor 84 | #%{_datadir}/metainfo/lemon-lime.metainfo.xml 85 | %{_datadir}/lemon-lime/lang/*.qm 86 | %dir %{_datadir}/lemon-lime 87 | %dir %{_datadir}/lemon-lime/lang 88 | 89 | %changelog 90 | -------------------------------------------------------------------------------- /manual/.gitignore: -------------------------------------------------------------------------------- 1 | *.aux 2 | *.log 3 | *.out 4 | *.toc 5 | *.xdv 6 | *.fdb_latexmk 7 | *.fls 8 | *.pyg 9 | -------------------------------------------------------------------------------- /manual/latexmkrc: -------------------------------------------------------------------------------- 1 | $pdf_mode = 5; 2 | 3 | $pdflatex = "pdflatex -file-line-error -halt-on-error -interaction=nonstopmode -synctex=1 %O %S"; 4 | $xelatex = "xelatex -8bit -shell-escape -file-line-error -halt-on-error -interaction=nonstopmode -no-pdf %O %S"; 5 | $xdvipdfmx = "xdvipdfmx -q -E -o %D %O %S"; 6 | -------------------------------------------------------------------------------- /manual/llmanual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/llmanual.pdf -------------------------------------------------------------------------------- /manual/manual.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | llmanual.pdf 4 | 5 | 6 | -------------------------------------------------------------------------------- /manual/pics/addcompiler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/addcompiler.png -------------------------------------------------------------------------------- /manual/pics/addcompiler2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/addcompiler2.png -------------------------------------------------------------------------------- /manual/pics/addtestcases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/addtestcases.png -------------------------------------------------------------------------------- /manual/pics/compilersettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/compilersettings.png -------------------------------------------------------------------------------- /manual/pics/compilersettings2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/compilersettings2.png -------------------------------------------------------------------------------- /manual/pics/editproblem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/editproblem.png -------------------------------------------------------------------------------- /manual/pics/edittestcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/edittestcase.png -------------------------------------------------------------------------------- /manual/pics/exttestcasemodifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/exttestcasemodifier.png -------------------------------------------------------------------------------- /manual/pics/generalsettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/generalsettings.png -------------------------------------------------------------------------------- /manual/pics/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/icon.png -------------------------------------------------------------------------------- /manual/pics/intoexttestcasemodifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/intoexttestcasemodifier.png -------------------------------------------------------------------------------- /manual/pics/judgingdialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/judgingdialog.png -------------------------------------------------------------------------------- /manual/pics/newcontest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/newcontest.png -------------------------------------------------------------------------------- /manual/pics/statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/statistics.png -------------------------------------------------------------------------------- /manual/pics/statistics2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/statistics2.png -------------------------------------------------------------------------------- /manual/pics/visualmainsettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/visualmainsettings.png -------------------------------------------------------------------------------- /manual/pics/visualmainsettings_whenchoosingtheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/visualmainsettings_whenchoosingtheme.png -------------------------------------------------------------------------------- /manual/pics/visualsettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-LemonLime/Project_LemonLime/ca50c29921377b752a2503e200c099c1a13af37d/manual/pics/visualsettings.png -------------------------------------------------------------------------------- /resource.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | assets/pics/splash2.png 4 | 5 | 6 | makespec/VERSION 7 | makespec/VERSIONSUFFIX 8 | makespec/BUILDVERSION 9 | assets/lemon-lime.ico 10 | 11 | 12 | assets/icons/lemon-lime.png 13 | assets/pics/code-function.svg 14 | assets/pics/configure.svg 15 | assets/pics/dialog-cancel.svg 16 | assets/pics/dialog-ok-apply.svg 17 | assets/pics/document-edit.svg 18 | assets/pics/edit-clear.svg 19 | assets/pics/edit-delete.svg 20 | assets/pics/edit-find-replace.svg 21 | assets/pics/edit-find.svg 22 | assets/pics/go-down.svg 23 | assets/pics/go-up.svg 24 | assets/pics/list-add.svg 25 | assets/pics/list-remove.svg 26 | assets/pics/media-playback-stop.svg 27 | assets/pics/media-skip-forward.svg 28 | assets/pics/paint-none.svg 29 | assets/pics/view-refresh.svg 30 | assets/pics/view-sort.svg 31 | assets/pics/application-exit.svg 32 | assets/pics/deletecell.svg 33 | assets/pics/document-close.svg 34 | assets/pics/document-export.svg 35 | assets/pics/document-new.svg 36 | assets/pics/document-save.svg 37 | assets/pics/globe.svg 38 | assets/pics/go-parent-folder.svg 39 | assets/pics/help-about.svg 40 | assets/pics/layer-new.svg 41 | assets/pics/paint-unknown.svg 42 | assets/pics/quickopen-file.svg 43 | assets/pics/system-help.svg 44 | assets/pics/acrobat.svg 45 | 46 | 47 | assets/js/jquery.slim.min.js 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/addcompilerwizard.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 3 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | * 7 | */ 8 | 9 | #pragma once 10 | // 11 | 12 | #include 13 | #include 14 | 15 | namespace Ui { 16 | class AddCompilerWizard; 17 | } 18 | 19 | class Compiler; 20 | 21 | class AddCompilerWizard : public QWizard { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit AddCompilerWizard(QWidget *parent = nullptr); 26 | ~AddCompilerWizard(); 27 | void accept(); 28 | const QList &getCompilerList() const; 29 | 30 | private: 31 | Ui::AddCompilerWizard *ui; 32 | QList compilerList; 33 | int nextId() const; 34 | bool validateCurrentPage(); 35 | 36 | private slots: 37 | void compilerTypeChanged(); 38 | void selectCompilerLocation(); 39 | void selectInterpreterLocation(); 40 | void selectGccPath(); 41 | void selectGppPath(); 42 | void selectFpcPath(); 43 | void selectFbcPath(); 44 | void selectJavacPath(); 45 | void selectJavaPath(); 46 | void selectPythonPath(); 47 | }; 48 | -------------------------------------------------------------------------------- /src/addtaskdialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include "addtaskdialog.h" 11 | #include "ui_addtaskdialog.h" 12 | // 13 | #include "base/settings.h" 14 | // 15 | 16 | AddTaskDialog::AddTaskDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AddTaskDialog) { 17 | ui->setupUi(this); 18 | ui->fullScore->setValidator(new QIntValidator(1, Settings::upperBoundForFullScore() * 100, this)); 19 | ui->timeLimit->setValidator(new QIntValidator(1, Settings::upperBoundForTimeLimit(), this)); 20 | ui->memoryLimit->setValidator(new QIntValidator(1, Settings::upperBoundForMemoryLimit(), this)); 21 | connect(ui->taskBox, qOverload(&QComboBox::currentIndexChanged), this, 22 | &AddTaskDialog::taskBoxIndexChanged); 23 | connect(ui->fullScore, &QLineEdit::textChanged, this, &AddTaskDialog::fullScoreChanged); 24 | connect(ui->timeLimit, &QLineEdit::textChanged, this, &AddTaskDialog::timeLimitChanged); 25 | connect(ui->memoryLimit, &QLineEdit::textChanged, this, &AddTaskDialog::memoryLimitChanged); 26 | } 27 | 28 | AddTaskDialog::~AddTaskDialog() { delete ui; } 29 | 30 | void AddTaskDialog::addTask(const QString &title, int _fullScore, int _timeLimit, int _memoryLimit) { 31 | fullScore.append(_fullScore); 32 | timeLimit.append(_timeLimit); 33 | memoryLimit.append(_memoryLimit); 34 | ui->taskBox->addItem(title); 35 | ui->taskBox->setCurrentIndex(0); 36 | } 37 | 38 | auto AddTaskDialog::getFullScore(int index) const -> int { 39 | if (0 <= index && index < fullScore.size()) { 40 | return fullScore[index]; 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | auto AddTaskDialog::getTimeLimit(int index) const -> int { 47 | if (0 <= index && index < timeLimit.size()) { 48 | return timeLimit[index]; 49 | } 50 | 51 | return 0; 52 | } 53 | 54 | auto AddTaskDialog::getMemoryLimit(int index) const -> int { 55 | if (0 <= index && index < memoryLimit.size()) { 56 | return memoryLimit[index]; 57 | } 58 | 59 | return 0; 60 | } 61 | 62 | void AddTaskDialog::taskBoxIndexChanged() { 63 | int index = ui->taskBox->currentIndex(); 64 | ui->fullScore->setText(QString("%1").arg(fullScore[index])); 65 | ui->timeLimit->setText(QString("%1").arg(timeLimit[index])); 66 | ui->memoryLimit->setText(QString("%1").arg(memoryLimit[index])); 67 | } 68 | 69 | void AddTaskDialog::fullScoreChanged() { 70 | int index = ui->taskBox->currentIndex(); 71 | fullScore[index] = ui->fullScore->text().toInt(); 72 | } 73 | 74 | void AddTaskDialog::timeLimitChanged() { 75 | int index = ui->taskBox->currentIndex(); 76 | timeLimit[index] = ui->timeLimit->text().toInt(); 77 | } 78 | 79 | void AddTaskDialog::memoryLimitChanged() { 80 | int index = ui->taskBox->currentIndex(); 81 | memoryLimit[index] = ui->memoryLimit->text().toInt(); 82 | } 83 | -------------------------------------------------------------------------------- /src/addtaskdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | 15 | namespace Ui { 16 | class AddTaskDialog; 17 | } 18 | 19 | class AddTaskDialog : public QDialog { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit AddTaskDialog(QWidget *parent = nullptr); 24 | ~AddTaskDialog(); 25 | void addTask(const QString &, int, int, int); 26 | int getFullScore(int) const; 27 | int getTimeLimit(int) const; 28 | int getMemoryLimit(int) const; 29 | 30 | private: 31 | Ui::AddTaskDialog *ui; 32 | QList fullScore; 33 | QList timeLimit; 34 | QList memoryLimit; 35 | 36 | private slots: 37 | void taskBoxIndexChanged(); 38 | void fullScoreChanged(); 39 | void timeLimitChanged(); 40 | void memoryLimitChanged(); 41 | }; 42 | -------------------------------------------------------------------------------- /src/addtestcaseswizard.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace Ui { 19 | class AddTestCasesWizard; 20 | } 21 | 22 | class Settings; 23 | 24 | class AddTestCasesWizard : public QWizard { 25 | Q_OBJECT 26 | 27 | public: 28 | explicit AddTestCasesWizard(QWidget *parent = nullptr); 29 | ~AddTestCasesWizard(); 30 | void setSettings(Settings *, bool); 31 | int getFullScore() const; 32 | int getTimeLimit() const; 33 | int getMemoryLimit() const; 34 | const QList &getMatchedInputFiles() const; 35 | const QList &getMatchedOutputFiles() const; 36 | 37 | private: 38 | Ui::AddTestCasesWizard *ui; 39 | Settings *settings{}; 40 | int fullScore{}; 41 | int timeLimit{}; 42 | int memoryLimit{}; 43 | QString inputFilesPattern; 44 | QString outputFilesPattern; 45 | QList matchedInputFiles; 46 | QList matchedOutputFiles; 47 | void refreshButtonState(); 48 | void getFiles(const QString &, const QString &, QStringList &); 49 | QString getFullRegExp(const QString &); 50 | QStringList getMatchedPart(const QString &, const QString &); 51 | void searchMatchedFiles(); 52 | bool validateCurrentPage(); 53 | static bool compareFileName(const QString &, const QString &); 54 | 55 | private slots: 56 | void fullScoreChanged(const QString &); 57 | void timeLimitChanged(const QString &); 58 | void memoryLimitChanged(const QString &); 59 | void inputFilesPatternChanged(const QString &); 60 | void outputFilesPatternChanged(const QString &); 61 | void addArgument(); 62 | void deleteArgument(); 63 | }; 64 | -------------------------------------------------------------------------------- /src/advancedcompilersettingsdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | 15 | class Compiler; 16 | 17 | namespace Ui { 18 | class AdvancedCompilerSettingsDialog; 19 | } 20 | 21 | class AdvancedCompilerSettingsDialog : public QDialog { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit AdvancedCompilerSettingsDialog(QWidget *parent = nullptr); 26 | ~AdvancedCompilerSettingsDialog(); 27 | void resetEditCompiler(Compiler *); 28 | Compiler *getEditCompiler() const; 29 | 30 | private: 31 | Ui::AdvancedCompilerSettingsDialog *ui; 32 | Compiler *editCompiler; 33 | int configCount{}; 34 | 35 | private slots: 36 | void okayButtonClicked(); 37 | void compilerTypeChanged(); 38 | void compilerLocationChanged(); 39 | void interpreterLocationChanged(); 40 | void selectCompilerLocation(); 41 | void selectInterpreterLocation(); 42 | void bytecodeExtensionsChanged(); 43 | void timeLimitRatioChanged(); 44 | void memoryLimitRatioChanged(); 45 | void disableMemoryLimitCheckChanged(); 46 | void configurationIndexChanged(); 47 | void configurationTextChanged(); 48 | void deleteConfiguration(); 49 | void compilerArgumentsChanged(); 50 | void interpreterArgumentsChanged(); 51 | void environmentVariablesButtonClicked(); 52 | }; 53 | -------------------------------------------------------------------------------- /src/base/LemonApplicationInterface.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #include "LemonApplicationInterface.hpp" 9 | // 10 | #include "base/LemonBase.hpp" 11 | #include "base/LemonLog.hpp" 12 | #include "base/LemonTranslator.hpp" 13 | #include "base/settings.h" // TODO: Config Refactor 14 | // 15 | #include 16 | #include 17 | // 18 | #define LEMON_MODULE_NAME "LemonApplicationInterface" 19 | 20 | using namespace Lemon; 21 | 22 | LemonApplicationInterface::LemonApplicationInterface() { 23 | // ConfigObject = new LemonConfigObject; 24 | LemonCoreApplication = this; 25 | LOG("LemonLime", LEMON_VERSION_STRING, "on", QSysInfo::prettyProductName(), 26 | QSysInfo::currentCpuArchitecture()); 27 | DEBUG("LemonLime Start Time: ", QTime::currentTime().msecsSinceStartOfDay()); 28 | DEBUG(LEMON_BUILD_INFO); 29 | DEBUG(LEMON_BUILD_EXTRA_INFO); 30 | } 31 | 32 | LemonApplicationInterface::~LemonApplicationInterface() { 33 | // delete ConfigObject; 34 | LemonCoreApplication = nullptr; 35 | } 36 | -------------------------------------------------------------------------------- /src/base/LemonApplicationInterface.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | #include 11 | #include 12 | #include 13 | 14 | namespace Lemon { 15 | struct LemonStartupArguments { 16 | enum Argument { 17 | NORMAL = 0, 18 | EXIT = 1, 19 | LEMON_LINK = 2 // Maybe support URL... 20 | }; 21 | QList arguments; 22 | QString version; 23 | int buildVersion; 24 | QString data; 25 | QList links; 26 | QList fullArgs; 27 | // 28 | bool debugLog; 29 | bool exitLemon; 30 | }; 31 | 32 | class LemonApplicationInterface { 33 | 34 | public: 35 | explicit LemonApplicationInterface(); 36 | ~LemonApplicationInterface(); 37 | 38 | Lemon::LemonStartupArguments StartupArguments; 39 | }; 40 | 41 | inline LemonApplicationInterface *LemonCoreApplication = nullptr; 42 | } // namespace Lemon 43 | -------------------------------------------------------------------------------- /src/base/LemonBase.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define LEMON_BUILD_INFO QString(LEMON_BUILD_INFO_STR) 22 | #define LEMON_BUILD_EXTRA_INFO QString(LEMON_BUILD_EXTRA_INFO_STR) 23 | 24 | namespace Lemon { 25 | inline QStringList LemonAssetsPaths(const QString &dirName) { 26 | #define makeAbs(p) QDir(p).absolutePath() 27 | // Configuration Path 28 | QStringList list; 29 | 30 | // This is the default behavior on Windows 31 | list << makeAbs(QCoreApplication::applicationDirPath() + "/" + dirName); 32 | #ifdef LEMON_CONFIG_DIR 33 | list << makeAbs(LEMON_CONFIG_DIR + dirName); 34 | #endif 35 | list << ":/" + dirName; 36 | // 37 | list << QStandardPaths::locateAll(QStandardPaths::AppDataLocation, dirName, 38 | QStandardPaths::LocateDirectory); 39 | list << QStandardPaths::locateAll(QStandardPaths::AppConfigLocation, dirName, 40 | QStandardPaths::LocateDirectory); 41 | 42 | #ifdef Q_OS_LINUX 43 | // Linux platform directories. 44 | list << makeAbs("/lib/lemon-lime/" + dirName); 45 | list << makeAbs("/usr/lib/lemon-lime/" + dirName); 46 | list << makeAbs("/usr/local/lib/lemon-lime/" + dirName); 47 | // 48 | list << makeAbs("/usr/share/lemon-lime/" + dirName); 49 | list << makeAbs("/usr/local/share/lemon-lime/" + dirName); 50 | // For Snap 51 | if (qEnvironmentVariableIsSet("SNAP")) { 52 | list << makeAbs(qEnvironmentVariable("SNAP") + "/usr/share/lemon-lime/" + dirName); 53 | } 54 | if (qEnvironmentVariableIsSet("APPIMAGE")) 55 | list << makeAbs(QCoreApplication::applicationDirPath() + "/../share/lemon-lime/" + dirName); 56 | #elif defined(Q_OS_MAC) 57 | // macOS platform directories. 58 | list << QDir(QCoreApplication::applicationDirPath() + "/../Resources/" + dirName).absolutePath(); 59 | #endif 60 | list.removeDuplicates(); 61 | return list; 62 | #undef makeAbs 63 | } 64 | 65 | } // namespace Lemon 66 | -------------------------------------------------------------------------------- /src/base/LemonBaseApplication.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #include "LemonBaseApplication.hpp" 9 | // 10 | #include "base/LemonLog.hpp" 11 | #include "base/LemonTranslator.hpp" 12 | #include "base/settings.h" // TODO: Config Refactor 13 | // 14 | #include 15 | #include 16 | 17 | // 18 | #define LEMON_MODULE_NAME "LemonBaseApplication" 19 | 20 | using namespace Lemon; 21 | 22 | auto LemonBaseApplication::Initialize() -> bool { 23 | QString errorMessage; 24 | bool canContinue; 25 | const auto hasError = parseCommandLine(&canContinue, &errorMessage); 26 | if (hasError) { 27 | LOG("Command line: " GEN_PAIR(errorMessage)); 28 | if (! canContinue) { 29 | LOG("Fatal Error, LemonLime cannot continue."); 30 | return false; 31 | } else { 32 | LOG("Non-fatal error, LemonLime will continue starting up."); 33 | } 34 | } 35 | 36 | // Load Translations 37 | Settings *settings = new Settings; 38 | settings->loadSettings(); 39 | LemonLimeTranslator = std::make_unique(); 40 | const auto allTranslations = LemonLimeTranslator->GetAvailableLanguages(); 41 | const auto osLanguage = QLocale::system().name(); 42 | if (! allTranslations.contains(settings->getUiLanguage())) { 43 | // If we need to reset the language. 44 | if (allTranslations.contains(osLanguage)) { 45 | settings->setUiLanguage(osLanguage); 46 | } else if (! allTranslations.isEmpty()) { 47 | settings->setUiLanguage(allTranslations.first()); 48 | } 49 | } 50 | LemonLimeTranslator->InstallTranslation(settings->getUiLanguage()); 51 | 52 | return true; 53 | } 54 | 55 | auto LemonBaseApplication::parseCommandLine(bool *canContinue, QString *errorMessage) -> bool { 56 | *canContinue = true; 57 | QStringList filteredArgs; 58 | for (const auto &arg : arguments()) { 59 | #ifdef Q_OS_MACOS 60 | if (arg.contains("-psn")) 61 | continue; 62 | #endif 63 | filteredArgs << arg; 64 | } 65 | QCommandLineParser parser; 66 | // 67 | QCommandLineOption debugLogOption("debug", QObject::tr("Enable debug output")); 68 | // 69 | parser.setApplicationDescription(QObject::tr("LemonLime - A tiny judging environment for OI contest.")); 70 | parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); 71 | // 72 | parser.addOption(debugLogOption); 73 | // 74 | const auto helpOption = parser.addHelpOption(); 75 | const auto versionOption = parser.addVersionOption(); 76 | 77 | if (! parser.parse(filteredArgs)) { 78 | *canContinue = true; 79 | *errorMessage = parser.errorText(); 80 | return false; 81 | } 82 | 83 | if (parser.isSet(versionOption)) { 84 | parser.showVersion(); 85 | return true; 86 | } 87 | 88 | if (parser.isSet(helpOption)) { 89 | parser.showHelp(); 90 | return true; 91 | } 92 | 93 | #define ProcessExtraStartupOptions(option) \ 94 | DEBUG("Startup Options:" GEN_PAIR(parser.isSet(option##Option))); \ 95 | StartupArguments.option = parser.isSet(option##Option); 96 | 97 | ProcessExtraStartupOptions(debugLog); 98 | return true; 99 | } 100 | -------------------------------------------------------------------------------- /src/base/LemonBaseApplication.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | #include 11 | // 12 | #include "base/LemonApplicationInterface.hpp" 13 | 14 | namespace Lemon { 15 | class LemonBaseApplication : public SingleApplication, public LemonApplicationInterface { 16 | Q_OBJECT 17 | 18 | public: 19 | LemonBaseApplication(int &argc, char *argv[]) 20 | : SingleApplication(argc, argv, true, User | ExcludeAppPath | ExcludeAppVersion), 21 | LemonApplicationInterface(){}; 22 | virtual ~LemonBaseApplication(){}; 23 | 24 | virtual bool Initialize() final; 25 | 26 | private: 27 | bool parseCommandLine(bool *canContinue, QString *errorMessage); 28 | }; 29 | } // namespace Lemon 30 | -------------------------------------------------------------------------------- /src/base/LemonConfig.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #include "LemonConfig.hpp" 9 | // 10 | #include "base/LemonUtils.hpp" 11 | #include "base/compiler.h" 12 | 13 | namespace Lemon::base::config { 14 | 15 | int LemonConfigJudge::read(const QJsonObject &json) { 16 | READ_JSON(json, defaultFullScore); 17 | READ_JSON(json, defaultTimeLimit); 18 | READ_JSON(json, defaultMemoryLimit); 19 | READ_JSON(json, compileTimeLimit); 20 | READ_JSON(json, specialJudgeTimeLimit); 21 | READ_JSON(json, fileSizeLimit); 22 | READ_JSON(json, rejudgeTimes); 23 | READ_JSON(json, maxJudgingThreads); 24 | 25 | READ_JSON(json, defaultInputFileExtension); 26 | READ_JSON(json, defaultOutputFileExtension); 27 | READ_JSON(json, diffPath); 28 | 29 | READ_JSON(json, inputFileExtensions); 30 | READ_JSON(json, outputFileExtensions); 31 | READ_JSON(json, recentContest); 32 | 33 | // CompilerList 34 | if (json.contains("compilerList") && json["compilerList"].isArray()) { 35 | QJsonArray _compilerList = json["compilerList"].toArray(); 36 | compilerList.clear(); 37 | compilerList.reserve(_compilerList.size()); 38 | for (int i = 0; i < _compilerList.size(); ++i) { 39 | QJsonObject compilerObject = _compilerList[i].toObject(); 40 | Compiler *compiler = new Compiler; 41 | if (compiler->read(compilerObject) == -1) 42 | return -1; 43 | compilerList.append(compiler); 44 | } 45 | } else 46 | return -1; 47 | return 0; 48 | } 49 | 50 | void LemonConfigJudge::write(QJsonObject &json) const { 51 | WRITE_JSON(json, defaultFullScore); 52 | WRITE_JSON(json, defaultTimeLimit); 53 | WRITE_JSON(json, defaultMemoryLimit); 54 | WRITE_JSON(json, compileTimeLimit); 55 | WRITE_JSON(json, specialJudgeTimeLimit); 56 | WRITE_JSON(json, fileSizeLimit); 57 | WRITE_JSON(json, rejudgeTimes); 58 | WRITE_JSON(json, maxJudgingThreads); 59 | 60 | WRITE_JSON(json, defaultInputFileExtension); 61 | WRITE_JSON(json, defaultOutputFileExtension); 62 | WRITE_JSON(json, diffPath); 63 | 64 | WRITE_JSON(json, inputFileExtensions); 65 | WRITE_JSON(json, outputFileExtensions); 66 | WRITE_JSON(json, recentContest); 67 | 68 | QJsonArray compilerList; 69 | for (const auto compiler : this->compilerList) { 70 | QJsonObject obj; 71 | compiler->write(obj); 72 | compilerList.append(obj); 73 | } 74 | WRITE_JSON(json, compilerList); 75 | } 76 | 77 | } // namespace Lemon::base::config 78 | -------------------------------------------------------------------------------- /src/base/LemonConfig.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | #include 12 | // 13 | #include 14 | 15 | class Compiler; 16 | 17 | namespace Lemon::base::config { 18 | 19 | class LemonConfigJudge { 20 | private: 21 | QList compilerList; 22 | int defaultFullScore{}; 23 | int defaultTimeLimit{}; 24 | int defaultMemoryLimit{}; 25 | int compileTimeLimit{}; 26 | int specialJudgeTimeLimit{}; 27 | int fileSizeLimit{}; 28 | int rejudgeTimes{}; 29 | int maxJudgingThreads{}; 30 | QString defaultInputFileExtension; 31 | QString defaultOutputFileExtension; 32 | QStringList inputFileExtensions; 33 | QStringList outputFileExtensions; 34 | QStringList recentContest; 35 | QString diffPath; 36 | 37 | public: 38 | int read(const QJsonObject &json); 39 | void write(QJsonObject &json) const; 40 | }; 41 | 42 | class LemonConfigUI { 43 | private: 44 | QString language = "en_US"; 45 | // Prepare for theme setting 46 | // QString theme = ; 47 | public: 48 | int read(const QJsonObject &json); 49 | void write(QJsonObject &json) const; 50 | }; 51 | 52 | class LemonConfig { 53 | private: 54 | LemonConfigJudge judgeConfig; 55 | LemonConfigUI uiConfig; 56 | int splashTime{}; 57 | 58 | public: 59 | enum SaveFormat { Json, Binary, Yaml }; 60 | void read(const QJsonObject &json); 61 | void write(QJsonObject &json) const; 62 | bool loadConfig(SaveFormat saveFormat); 63 | bool saveConfig(SaveFormat saveFormat) const; 64 | }; 65 | 66 | } // namespace Lemon::base::config 67 | -------------------------------------------------------------------------------- /src/base/LemonLog.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019-2020 Qv2ray Development Group 3 | * 2020-2022 Project LemonLime 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | * 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | // 16 | #include 17 | #include 18 | 19 | #include "spdlog/spdlog.h" 20 | 21 | #define NEWLINE "\r\n" 22 | #define ___LOG_EXPAND(___x) , QPair(std::string(#___x), [&] { return ___x; }()) 23 | 24 | // Generate pairs for each variable passed as args to use in the log. 25 | // with line 73: QTextStream &operator<<(QTextStream &stream, const std::pair &pair) 26 | #define GEN_PAIR(...) FOREACH_CALL_FUNC(___LOG_EXPAND, __VA_ARGS__) 27 | 28 | #ifdef QT_DEBUG 29 | #define LEMON_IS_DEBUG true 30 | // __FILE__ ":" QT_STRINGIFY(__LINE__), 31 | // https://doc.qt.io/qt-5/qtglobal.html#Q_FUNC_INFO 32 | #define LEMON_LOG_PREPEND_CONTENT Q_FUNC_INFO, 33 | #else 34 | #define LEMON_IS_DEBUG false 35 | #define LEMON_LOG_PREPEND_CONTENT 36 | #endif 37 | 38 | // prepend module name in log 39 | #define _LOG_ARG_(...) "[" LEMON_MODULE_NAME "]", LEMON_LOG_PREPEND_CONTENT __VA_ARGS__ 40 | 41 | #define WARN(...) Lemon::base::log_concat(_LOG_ARG_(__VA_ARGS__)) 42 | #define LOG(...) Lemon::base::log_concat(_LOG_ARG_(__VA_ARGS__)) 43 | #define DEBUG(...) Lemon::base::log_concat(_LOG_ARG_(__VA_ARGS__)) 44 | 45 | enum LemonLogType { LEMON_LOG_WARN, LEMON_LOG_NORMAL, LEMON_LOG_DEBUG }; 46 | 47 | Q_DECLARE_METATYPE(const char *) 48 | 49 | namespace Lemon::base { 50 | inline std::shared_ptr logger; 51 | inline QString tempBuffer; 52 | inline QTextStream tempStream{&tempBuffer}; 53 | 54 | template inline void log_concat(T... v) { 55 | ((tempStream << v << " "), ...); 56 | 57 | const auto logString = tempStream.readAll().toStdString(); 58 | 59 | if constexpr (t == LEMON_LOG_DEBUG) { 60 | if (LemonCoreApplication && ! LemonCoreApplication->StartupArguments.debugLog) 61 | return; 62 | logger->debug(logString); 63 | } else if constexpr (t == LEMON_LOG_NORMAL) { 64 | logger->info(logString); 65 | } else if constexpr (t == LEMON_LOG_WARN) { 66 | logger->warn(logString); 67 | } 68 | } 69 | } // namespace Lemon::base 70 | 71 | template 72 | QTextStream &operator<<(QTextStream &stream, const QPair &pair) { 73 | return stream << pair.first << ": " << pair.second; 74 | } 75 | 76 | inline QTextStream &operator<<(QTextStream &stream, const std::string &ss) { return stream << ss.data(); } 77 | 78 | template 79 | QTextStream &operator<<(QTextStream &stream, const QMap &map) { 80 | stream << "{ "; 81 | for (const auto &[k, v] : map.toStdMap()) 82 | stream << QPair(k, v) << "; "; 83 | stream << "}"; 84 | return stream; 85 | } 86 | 87 | template 88 | QTextStream &operator<<(QTextStream &stream, const std::initializer_list &init_list) { 89 | for (const auto &x : init_list) 90 | stream << x; 91 | return stream; 92 | } 93 | -------------------------------------------------------------------------------- /src/base/LemonMacro.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | 10 | #define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2) 11 | #define CONCATENATE2(arg1, arg2) arg1##arg2 12 | #define CONCATENATE(x, y) x##y 13 | 14 | #define EXPAND(...) __VA_ARGS__ 15 | #define FOR_EACH_1(what, x, ...) what(x) 16 | #define FOR_EACH_2(what, x, ...) what(x) EXPAND(FOR_EACH_1(what, __VA_ARGS__)) 17 | #define FOR_EACH_3(what, x, ...) what(x) EXPAND(FOR_EACH_2(what, __VA_ARGS__)) 18 | #define FOR_EACH_4(what, x, ...) what(x) EXPAND(FOR_EACH_3(what, __VA_ARGS__)) 19 | #define FOR_EACH_5(what, x, ...) what(x) EXPAND(FOR_EACH_4(what, __VA_ARGS__)) 20 | #define FOR_EACH_6(what, x, ...) what(x) EXPAND(FOR_EACH_5(what, __VA_ARGS__)) 21 | #define FOR_EACH_7(what, x, ...) what(x) EXPAND(FOR_EACH_6(what, __VA_ARGS__)) 22 | #define FOR_EACH_8(what, x, ...) what(x) EXPAND(FOR_EACH_7(what, __VA_ARGS__)) 23 | #define FOR_EACH_9(what, x, ...) what(x) EXPAND(FOR_EACH_8(what, __VA_ARGS__)) 24 | #define FOR_EACH_10(what, x, ...) what(x) EXPAND(FOR_EACH_9(what, __VA_ARGS__)) 25 | #define FOR_EACH_11(what, x, ...) what(x) EXPAND(FOR_EACH_10(what, __VA_ARGS__)) 26 | #define FOR_EACH_12(what, x, ...) what(x) EXPAND(FOR_EACH_11(what, __VA_ARGS__)) 27 | #define FOR_EACH_13(what, x, ...) what(x) EXPAND(FOR_EACH_12(what, __VA_ARGS__)) 28 | #define FOR_EACH_14(what, x, ...) what(x) EXPAND(FOR_EACH_13(what, __VA_ARGS__)) 29 | #define FOR_EACH_15(what, x, ...) what(x) EXPAND(FOR_EACH_14(what, __VA_ARGS__)) 30 | #define FOR_EACH_16(what, x, ...) what(x) EXPAND(FOR_EACH_15(what, __VA_ARGS__)) 31 | 32 | #define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N()) 33 | #define FOR_EACH_NARG_(...) EXPAND(FOR_EACH_ARG_N(__VA_ARGS__)) 34 | #define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N 35 | #define FOR_EACH_RSEQ_N() 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 36 | 37 | #define FOR_EACH_(N, what, ...) EXPAND(CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__)) 38 | #define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__) 39 | #define FOREACH_CALL_FUNC(func, ...) FOR_EACH(func, __VA_ARGS__) 40 | -------------------------------------------------------------------------------- /src/base/LemonTranslator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019-2020 Qv2ray Development Group 3 | * 2020-2022 Project LemonLime 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | * 7 | */ 8 | 9 | #include "LemonTranslator.hpp" 10 | // 11 | #include 12 | #include 13 | #include 14 | // 15 | 16 | #define LEMON_MODULE_NAME "Translator" 17 | 18 | using namespace Lemon; 19 | 20 | // path searching list. 21 | auto getLanguageSearchPaths() -> QStringList { 22 | // Configuration Path 23 | QStringList list = LemonAssetsPaths("lang"); 24 | #ifdef LEMON_EMBED_TRANSLATIONS 25 | // If the translations have been embedded. 26 | list << QString(":/translation/"); 27 | #endif 28 | #ifdef LEMON_TRANSLATION_PATH 29 | // Platform-specific dir, if specified. 30 | list << QString(LEMON_TRANSLATION_PATH); 31 | #endif 32 | return list; 33 | } 34 | 35 | namespace Lemon::common { 36 | LemonTranslator::LemonTranslator() { refreshTranslations(); } 37 | 38 | void LemonTranslator::refreshTranslations() { 39 | searchPaths = getLanguageSearchPaths(); 40 | languages.clear(); 41 | for (const auto &path : qAsConst(searchPaths)) { 42 | languages << QDir(path).entryList({"*.qm"}, QDir::Hidden | QDir::Files); 43 | } 44 | std::transform(languages.begin(), languages.end(), languages.begin(), 45 | [](QString &fileName) { return fileName.replace(".qm", ""); }); 46 | languages.removeDuplicates(); 47 | DEBUG("Found translations: " + languages.join(" ")); 48 | } 49 | 50 | auto LemonTranslator::InstallTranslation(const QString &code) -> bool { 51 | for (const auto &path : qAsConst(searchPaths)) { 52 | if (FileExistsIn(QDir(path), code + ".qm")) { 53 | DEBUG("Found " + code + " in folder: " + path); 54 | QTranslator *translatorNew = new QTranslator(); 55 | bool success = translatorNew->load(code + ".qm", path); 56 | if (! success) { 57 | LOG("Cannot load translation: " + code); 58 | } 59 | if (pTranslator) { 60 | LOG("Removed translations"); 61 | qApp->removeTranslator(pTranslator.get()); 62 | } 63 | this->pTranslator.reset(translatorNew); 64 | qApp->installTranslator(pTranslator.get()); 65 | LOG("Successfully installed a translator for " + code); 66 | return true; 67 | } 68 | } 69 | return false; 70 | } 71 | } // namespace Lemon::common 72 | -------------------------------------------------------------------------------- /src/base/LemonTranslator.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019-2020 Qv2ray Development Group 3 | * 2020-2022 Project LemonLime 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | * 7 | */ 8 | 9 | #pragma once 10 | // 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace Lemon::common { 17 | class LemonTranslator { 18 | public: 19 | explicit LemonTranslator(); 20 | 21 | public: 22 | /** 23 | * @brief get the available languages. 24 | * @return (if available) languages (zh_CN, en_US, ...) 25 | */ 26 | const inline QStringList GetAvailableLanguages() const { return languages; } 27 | /** 28 | * @brief reload the translation from file 29 | * @param code eg: zh_CN, ... 30 | */ 31 | bool InstallTranslation(const QString &); 32 | 33 | private: 34 | QStringList languages; 35 | QStringList searchPaths; 36 | std::unique_ptr pTranslator; 37 | void refreshTranslations(); 38 | }; 39 | inline std::unique_ptr LemonLimeTranslator; 40 | } // namespace Lemon::common 41 | 42 | using namespace Lemon::common; 43 | -------------------------------------------------------------------------------- /src/base/LemonType.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | enum CompileState { 12 | CompileSuccessfully, 13 | NoValidSourceFile, 14 | CompileError, 15 | CompileTimeLimitExceeded, 16 | InvalidCompiler, 17 | NoValidGraderFile 18 | }; 19 | 20 | enum ResultState { 21 | CorrectAnswer, 22 | WrongAnswer, 23 | PartlyCorrect, 24 | TimeLimitExceeded, 25 | MemoryLimitExceeded, 26 | CannotStartProgram, 27 | FileError, 28 | RunTimeError, 29 | InvalidSpecialJudge, 30 | SpecialJudgeTimeLimitExceeded, 31 | SpecialJudgeRunTimeError, 32 | Skipped, 33 | InteractorError, 34 | PresentationError, 35 | OutputLimitExceeded, 36 | LastResultState 37 | }; 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | /* struct TaskResult { 44 | CompileState compileState; 45 | QString compileMessage; 46 | QString sourceFile; 47 | QList> resultState; 48 | QList resultMessage; 49 | QList> scores; 50 | QList> timeUsed; 51 | QList> memoryUsed; 52 | QList inputFiles; 53 | }; */ -------------------------------------------------------------------------------- /src/base/LemonUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #include "LemonUtils.hpp" 9 | // 10 | 11 | namespace Lemon::common { 12 | 13 | auto GetFileList(const QDir &dir) -> QStringList { 14 | return dir.entryList(QStringList{"*", "*.*"}, QDir::Hidden | QDir::Files); 15 | } 16 | 17 | auto FileExistsIn(const QDir &dir, const QString &fileName) -> bool { 18 | return GetFileList(dir).contains(fileName); 19 | } 20 | 21 | } // namespace Lemon::common 22 | -------------------------------------------------------------------------------- /src/base/compiler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | 16 | class Compiler : public QObject { 17 | Q_OBJECT 18 | public: 19 | enum CompilerType { Typical, InterpretiveWithByteCode, InterpretiveWithoutByteCode }; 20 | Q_ENUM(CompilerType) 21 | 22 | explicit Compiler(QObject *parent = nullptr); 23 | 24 | CompilerType getCompilerType() const; 25 | const QString &getCompilerName() const; 26 | const QStringList &getSourceExtensions() const; 27 | const QString &getCompilerLocation() const; 28 | const QString &getInterpreterLocation() const; 29 | const QStringList &getBytecodeExtensions() const; 30 | const QStringList &getConfigurationNames() const; 31 | const QStringList &getCompilerArguments() const; 32 | const QStringList &getInterpreterArguments() const; 33 | const QProcessEnvironment &getEnvironment() const; 34 | double getTimeLimitRatio() const; 35 | double getMemoryLimitRatio() const; 36 | bool getDisableMemoryLimitCheck() const; 37 | 38 | void setCompilerType(CompilerType); 39 | void setCompilerName(const QString &); 40 | void setSourceExtensions(const QString &); 41 | void setCompilerLocation(const QString &); 42 | void setInterpreterLocation(const QString &); 43 | void setBytecodeExtensions(const QString &); 44 | void setEnvironment(const QProcessEnvironment &); 45 | void setTimeLimitRatio(double); 46 | void setMemoryLimitRatio(double); 47 | void setDisableMemoryLimitCheck(bool); 48 | 49 | void addConfiguration(const QString &, const QString &, const QString &); 50 | void setConfigName(int, const QString &); 51 | void setCompilerArguments(int, const QString &); 52 | void setInterpreterArguments(int, const QString &); 53 | void deleteConfiguration(int); 54 | 55 | void copyFrom(Compiler *); 56 | 57 | int read(const QJsonObject &json); 58 | void write(QJsonObject &json) const; 59 | 60 | private: 61 | CompilerType compilerType; 62 | QString compilerName; 63 | QStringList sourceExtensions; 64 | QString compilerLocation; 65 | QString interpreterLocation; 66 | QStringList bytecodeExtensions; 67 | QStringList configurationNames; 68 | QStringList compilerArguments; 69 | QStringList interpreterArguments; 70 | QProcessEnvironment environment; 71 | double timeLimitRatio; 72 | double memoryLimitRatio; 73 | bool disableMemoryLimitCheck; 74 | }; 75 | -------------------------------------------------------------------------------- /src/compilersettings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | 16 | namespace Ui { 17 | class CompilerSettings; 18 | } 19 | 20 | class Settings; 21 | class Compiler; 22 | 23 | class CompilerSettings : public QWidget { 24 | Q_OBJECT 25 | 26 | public: 27 | explicit CompilerSettings(QWidget *parent = nullptr); 28 | ~CompilerSettings(); 29 | void resetEditSettings(Settings *); 30 | bool checkValid(); 31 | 32 | private: 33 | Ui::CompilerSettings *ui; 34 | Settings *editSettings{}; 35 | Compiler *curCompiler{}; 36 | QAction *deleteCompilerKeyAction; 37 | void setCurrentCompiler(Compiler *); 38 | void refreshItemState(); 39 | 40 | private slots: 41 | void moveUpCompiler(); 42 | void moveDownCompiler(); 43 | void addCompiler(); 44 | void deleteCompiler(); 45 | void compilerNameChanged(const QString &); 46 | void sourceExtensionsChanged(const QString &); 47 | void compilerListCurrentRowChanged(); 48 | void advancedButtonClicked(); 49 | }; 50 | -------------------------------------------------------------------------------- /src/component/exportutil/exportutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * 2018-2019 Project LemonPlus, Dust1404 4 | * 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include "base/LemonType.hpp" 14 | #include 15 | 16 | #ifdef ENABLE_XLS_EXPORT 17 | #include 18 | #endif 19 | 20 | class Contest; 21 | class Contestant; 22 | 23 | class ExportUtil : public QObject { 24 | Q_OBJECT 25 | public: 26 | explicit ExportUtil(QObject *parent = nullptr); 27 | static void exportResult(QWidget *, Contest *); 28 | 29 | private: 30 | static QString getContestantHtmlCode(Contest *, Contestant *, int); 31 | static QString getSmallerContestantHtmlCode(Contest *, Contestant *); 32 | static void exportHtml(QWidget *, Contest *, const QString &); 33 | static void exportSmallerHtml(QWidget *, Contest *, const QString &); 34 | static void exportCsv(QWidget *, Contest *, const QString &); 35 | #ifdef ENABLE_XLS_EXPORT 36 | static void exportXls(QWidget *, Contest *, const QString &); 37 | #endif 38 | signals: 39 | 40 | public slots: 41 | }; 42 | -------------------------------------------------------------------------------- /src/core/contest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * 2018-2019 Project LemonPlus, Dust1404 4 | * 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include "base/LemonType.hpp" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define MagicNumber 0x20111127 21 | 22 | class Task; 23 | class Settings; 24 | class Contestant; 25 | class JudgingController; 26 | 27 | class Contest : public QObject { 28 | Q_OBJECT 29 | public: 30 | explicit Contest(QObject *parent = nullptr); 31 | void setSettings(Settings *); 32 | void copySettings(Settings &); 33 | void setContestTitle(const QString &); 34 | const QString &getContestTitle() const; 35 | Task *getTask(int) const; 36 | void swapTask(int, int); 37 | const QList &getTaskList() const; 38 | Contestant *getContestant(const QString &) const; 39 | QList getContestantList() const; 40 | int getTotalTimeLimit() const; 41 | int getTotalScore() const; 42 | void addTask(Task *); 43 | void deleteTask(int); 44 | void refreshContestantList(); 45 | void deleteContestant(const QString &); 46 | void writeToJson(QJsonObject &); 47 | void readFromStream(QDataStream &); 48 | int readFromJson(const QJsonObject &); 49 | 50 | private: 51 | QString contestTitle; 52 | Settings *settings{}; 53 | QList taskList; 54 | QMap contestantList; 55 | bool stopJudging{}; 56 | void judge(Contestant *); 57 | void judge(const QVector> &); 58 | void clearPath(const QString &); 59 | JudgingController *controller; 60 | 61 | public slots: 62 | void judge(const QList>> &); 63 | void judgeAll(); 64 | // void judgeFinished(); 65 | void stopJudgingSlot(); 66 | 67 | signals: 68 | void taskAddedForContestant(); 69 | void taskDeletedForContestant(int); 70 | void taskAddedForViewer(); 71 | void taskDeletedForViewer(int); 72 | void problemTitleChanged(); 73 | void dialogAlert(QString); 74 | void singleCaseFinished(QString, int, int, int, int, int, int, int); 75 | void singleSubtaskDependenceFinished(int, int, int); 76 | void taskJudgingStarted(QString); 77 | void taskJudgingFinished(); 78 | void taskJudgedDisplay(const QString &, const QList> &, const int); 79 | void contestantJudgingStart(QString); 80 | void contestantJudgingFinished(); 81 | void contestantJudgedDisplay(const QString &, const int, const int); 82 | void compileError(int, int); 83 | void stopJudgingSignal(); 84 | }; 85 | -------------------------------------------------------------------------------- /src/core/contestant.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * 2018-2019 Project LemonPlus, Dust1404 4 | * 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | #include "base/LemonType.hpp" 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class Contestant : public QObject { 19 | Q_OBJECT 20 | public: 21 | explicit Contestant(QObject *parent = nullptr); 22 | 23 | const QString &getContestantName() const; 24 | bool getCheckJudged(int) const; 25 | CompileState getCompileState(int) const; 26 | const QString &getSourceFile(int) const; 27 | const QString &getCompileMessage(int) const; 28 | const QList &getInputFiles(int) const; 29 | const QList> &getResult(int) const; 30 | const QList &getMessage(int) const; 31 | const QList> &getScore(int) const; 32 | const QList> &getTimeUsed(int) const; 33 | const QList> &getMemoryUsed(int) const; 34 | QDateTime getJudingTime() const; 35 | int getTaskScore(int) const; 36 | int getTotalScore() const; 37 | int getTotalUsedTime() const; 38 | 39 | void setContestantName(const QString &); 40 | void setCheckJudged(int, bool); 41 | void setCompileState(int, CompileState); 42 | void setSourceFile(int, const QString &); 43 | void setCompileMessage(int, const QString &); 44 | void setInputFiles(int, const QList &); 45 | void setResult(int, const QList> &); 46 | void setMessage(int, const QList &); 47 | void setScore(int, const QList> &); 48 | void setTimeUsed(int, const QList> &); 49 | void setMemoryUsed(int, const QList> &); 50 | void setJudgingTime(QDateTime); 51 | 52 | int writeToJson(QJsonObject &); 53 | int readFromJson(const QJsonObject &); 54 | void readFromStream(QDataStream &); 55 | 56 | private: 57 | QString contestantName; 58 | QList checkJudged; 59 | QList compileState; 60 | QStringList sourceFile; 61 | QStringList compileMesaage; 62 | QList> inputFiles; 63 | QList>> result; 64 | QList> message; 65 | QList>> score; 66 | QList>> timeUsed; 67 | QList>> memoryUsed; 68 | QDateTime judgingTime; 69 | 70 | // QList taskResults; 71 | signals: 72 | 73 | public slots: 74 | void addTask(); 75 | void deleteTask(int); 76 | void swapTask(int, int); 77 | }; 78 | -------------------------------------------------------------------------------- /src/core/judgesharedvariables.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | extern bool skipEnabled; 12 | -------------------------------------------------------------------------------- /src/core/judgingcontroller.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #include "judgingcontroller.h" 9 | #include "core/contestant.h" 10 | 11 | #include 12 | 13 | #define LEMON_MODULE_NAME "JudgingController" 14 | 15 | JudgingController::JudgingController(Settings *settings, QObject *parent) : QObject(parent) { 16 | isJudging = false; 17 | maxThreads = qMax(1, settings->getMaxJudgingThreads()); 18 | } 19 | 20 | void JudgingController::assign() { 21 | if (! isJudging) { 22 | return; 23 | } 24 | if (queuingTasks.empty()) 25 | return; 26 | QThread *thread = new QThread; 27 | auto *taskJudger = queuingTasks.front(); 28 | queuingTasks.pop_front(); 29 | taskJudger->moveToThread(thread); 30 | connect(taskJudger, &TaskJudger::judgingFinished, this, &JudgingController::taskFinished); 31 | runningTasks[taskJudger] = thread; 32 | thread->start(); 33 | QMetaObject::invokeMethod(taskJudger, &TaskJudger::judgeIt); 34 | } 35 | 36 | void JudgingController::taskFinished() { 37 | auto *taskJudger = qobject_cast(sender()); 38 | if (taskJudger == nullptr) { 39 | return; 40 | } 41 | if (runningTasks.count(taskJudger)) { 42 | auto *thread = runningTasks[taskJudger]; 43 | thread->quit(); 44 | thread->wait(); 45 | delete thread; 46 | runningTasks.remove(taskJudger); 47 | delete taskJudger; 48 | } 49 | assign(); 50 | if (runningTasks.empty()) { 51 | isJudging = false; 52 | emit judgeFinished(); 53 | } 54 | } 55 | void JudgingController::start() { 56 | if (queuingTasks.size() == 0) { 57 | emit judgeFinished(); 58 | return; 59 | } 60 | isJudging = true; 61 | while (! queuingTasks.empty() && runningTasks.size() < maxThreads) { 62 | assign(); 63 | } 64 | } 65 | void JudgingController::stop() { 66 | if (! isJudging) 67 | return; 68 | isJudging = false; 69 | for (auto [taskJudger, thread] : runningTasks.toStdMap()) { 70 | QMetaObject::invokeMethod(taskJudger, &TaskJudger::stop); 71 | } 72 | // emit judgeFinished(); 73 | } 74 | void JudgingController::addTask(TaskJudger *taskJudger) { queuingTasks.push_back(taskJudger); } 75 | -------------------------------------------------------------------------------- /src/core/judgingcontroller.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | #pragma once 8 | 9 | #include "base/LemonType.hpp" 10 | #include "base/settings.h" 11 | #include "taskjudger.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | class JudgingController : public QObject { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit JudgingController(Settings *settings, QObject *parent = nullptr); 24 | void addTask(TaskJudger *judger); 25 | 26 | private: 27 | QQueue queuingTasks; 28 | QMap runningTasks; 29 | bool isJudging; 30 | int maxThreads; 31 | public slots: 32 | void stop(); 33 | void taskFinished(); 34 | void assign(); 35 | void start(); 36 | 37 | signals: 38 | void judgeFinished(); 39 | }; 40 | -------------------------------------------------------------------------------- /src/core/judgingthread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * 2018-2019 Project LemonPlus, Dust1404 4 | * 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include "base/LemonType.hpp" 14 | #include 15 | #include 16 | 17 | class Task; 18 | 19 | class JudgingThread : public QThread { 20 | Q_OBJECT 21 | public: 22 | explicit JudgingThread(QObject *parent = nullptr); 23 | // void setCheckRejudgeMode(bool); 24 | void setExtraTimeRatio(double); 25 | void setEnvironment(const QProcessEnvironment &); 26 | void setWorkingDirectory(const QString &); 27 | void setSpecialJudgeTimeLimit(int); 28 | void setExecutableFile(const QString &); 29 | void setArguments(const QString &); 30 | void setAnswerFile(const QString &); 31 | void setInputFile(const QString &); 32 | void setOutputFile(const QString &); 33 | void setDiffPath(const QString &); 34 | void setTask(Task *); 35 | void setFullScore(int); 36 | void setTimeLimit(int); 37 | void setMemoryLimit(int); 38 | int getTimeUsed() const; 39 | int getMemoryUsed() const; 40 | int getScore() const; 41 | int getFullScore() const; 42 | int getJudgeTimes() const; 43 | ResultState getResult() const; 44 | const QString &getMessage() const; 45 | bool getNeedRejudge() const; 46 | void run(); 47 | 48 | private: 49 | // bool checkRejudgeMode; 50 | 51 | bool needRejudge; 52 | // Control some extra time program used, like kernel time, judge system fluctuation 53 | double extraTimeRatio{}; 54 | QProcessEnvironment environment; 55 | QString workingDirectory; 56 | QString executableFile; 57 | QString arguments; 58 | QString answerFile; 59 | QString inputFile; 60 | QString outputFile; 61 | QString diffPath; 62 | Task *task{}; 63 | int specialJudgeTimeLimit{}; 64 | int fullScore{}; 65 | int timeLimit{}; 66 | int memoryLimit{}; 67 | int timeUsed; 68 | int memoryUsed; 69 | int score{}; 70 | int judgedTimes; 71 | ResultState result; 72 | QString message; 73 | bool stopJudging; 74 | void compareLineByLine(const QString &); 75 | void compareIgnoreSpaces(const QString &); 76 | void compareWithDiff(const QString &); 77 | void compareRealNumbers(const QString &); 78 | void specialJudge(const QString &); 79 | void runProgram(); 80 | void judgeOutput(); 81 | void judgeTraditionalTask(); 82 | void judgeAnswersOnlyTask(); 83 | // void judgeInteractionTask(); 84 | 85 | public slots: 86 | void stopJudgingSlot(); 87 | }; 88 | -------------------------------------------------------------------------------- /src/core/subtaskdependencelib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | #include "base/LemonType.hpp" 12 | #include 13 | #include 14 | 15 | const int maxDependValue = 1000000; 16 | 17 | inline int stateToStatus(ResultState in, int score, int maxScore) { 18 | if (in == CorrectAnswer) 19 | return maxDependValue; 20 | 21 | if (in == PartlyCorrect && maxScore == 0) 22 | return maxDependValue; 23 | 24 | if (score <= 0) 25 | return -1; 26 | 27 | return 1ll * maxDependValue * score / maxScore; 28 | } 29 | 30 | inline int statusToScore(int ratio, int maxScore) { return 1ll * maxScore * ratio / maxDependValue; } 31 | 32 | inline QString statusRankingText(int ratio) { 33 | if (ratio >= maxDependValue) 34 | return QObject::tr("Pure"); 35 | 36 | if (ratio < 0) 37 | return QObject::tr("Lost"); 38 | 39 | return QString::number(100.00 * ratio / maxDependValue, 'f', 3) + "%"; 40 | } 41 | -------------------------------------------------------------------------------- /src/core/taskjudger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | 10 | #include "base/LemonType.hpp" 11 | #include "core/judgingthread.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | class Contestant; 21 | class Settings; 22 | class Task; 23 | 24 | class TaskJudger : public QObject { 25 | Q_OBJECT 26 | public: 27 | TaskJudger(QObject *parent = nullptr); 28 | // void setCheckRejudgeMode(bool); 29 | void setNeedRejudge(const QList> &); 30 | void setSettings(Settings *); 31 | void setTask(Task *); 32 | void setTaskId(int); 33 | void setContestant(Contestant *); 34 | Contestant *getContestant() const; 35 | CompileState getCompileState() const; 36 | // const QList< std::pair >& getNeedRejudge() const; 37 | 38 | private: 39 | // bool checkRejudgeMode; 40 | 41 | const QString commExecGrader = "grader"; 42 | bool interpreterFlag{}; 43 | Settings *settings{}; 44 | Task *task{}; 45 | Contestant *contestant; 46 | CompileState compileState; 47 | QString compileMessage; 48 | QString sourceFile; 49 | QString executableFile; 50 | QString arguments; 51 | QString diffPath; 52 | double compilerTimeLimitRatio{}; 53 | double compilerMemoryLimitRatio{}; 54 | bool disableMemoryLimitCheck{}; 55 | QProcessEnvironment environment; 56 | QList overallStatus; 57 | QList> timeUsed; 58 | QList> memoryUsed; 59 | QList> score; 60 | QList> result; 61 | QList message; 62 | QList inputFiles; 63 | 64 | QList testCaseScore; 65 | bool isJudging; 66 | int taskId; 67 | bool traditionalTaskPrepare(); 68 | void assign(); 69 | void taskSkipped(const std::pair &); 70 | void makeDialogAlert(QString); 71 | int judge(); 72 | 73 | QTemporaryDir temporaryDir; 74 | 75 | public: 76 | void judgeIt(); 77 | public slots: 78 | void stop(); 79 | signals: 80 | void judgingStarted(QString); 81 | void judgingFinished(); 82 | void dialogAlert(QString); 83 | void singleCaseFinished(QString, int, int, int, int, int, int, int); 84 | void singleSubtaskDependenceFinished(int, int, int); 85 | void compileError(int, int); 86 | void stopJudgingSignal(); 87 | }; -------------------------------------------------------------------------------- /src/core/testcase.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * 2018-2019 Project LemonPlus, Dust1404 4 | * 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | 15 | class TestCase { 16 | public: 17 | explicit TestCase(); 18 | int getFullScore() const; 19 | int getTimeLimit() const; 20 | int getMemoryLimit() const; 21 | const QStringList &getInputFiles() const; 22 | const QStringList &getOutputFiles() const; 23 | const QList &getDependenceSubtask() const; 24 | void setIndex(int); 25 | void setFullScore(int); 26 | void setTimeLimit(int); 27 | void setMemoryLimit(int); 28 | void setInputFiles(int, const QString &); 29 | void setOutputFiles(int, const QString &); 30 | void setDependenceSubtask(const QStringList &); 31 | void setDependenceSubtask(const QList &); 32 | void setDependenceSubtask(const QSet &); 33 | bool checkDependenceSubtask(const QStringList &) const; 34 | void addSingleCase(const QString &, const QString &); 35 | void deleteSingleCase(int); 36 | int writeToJson(QJsonObject &out); 37 | void readFromStream(QDataStream &); 38 | int readFromJson(const QJsonObject &); 39 | void clearDependenceSubtask(); 40 | void swapFiles(int, int); 41 | 42 | private: 43 | QStringList inputFiles; 44 | QStringList outputFiles; 45 | QList dependenceSubtask; 46 | int index{}; 47 | int fullScore{}; 48 | int timeLimit{}; 49 | int memoryLimit{}; 50 | }; 51 | -------------------------------------------------------------------------------- /src/detaildialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | 16 | class Contestant; 17 | class Contest; 18 | 19 | namespace Ui { 20 | class DetailDialog; 21 | } 22 | 23 | class DetailDialog : public QDialog { 24 | Q_OBJECT 25 | 26 | public: 27 | explicit DetailDialog(QWidget *parent = nullptr); 28 | ~DetailDialog(); 29 | void refreshViewer(Contest *, Contestant *); 30 | void showDialog(); 31 | 32 | private: 33 | Ui::DetailDialog *ui; 34 | Contest *contest{}; 35 | Contestant *contestant{}; 36 | 37 | private slots: 38 | void anchorClicked(const QUrl &); 39 | 40 | signals: 41 | void rejudgeSignal(); 42 | }; 43 | -------------------------------------------------------------------------------- /src/editvariabledialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include "editvariabledialog.h" 11 | #include "ui_editvariabledialog.h" 12 | // 13 | #include 14 | 15 | EditVariableDialog::EditVariableDialog(QWidget *parent) : QDialog(parent), ui(new Ui::EditVariableDialog) { 16 | ui->setupUi(this); 17 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 18 | connect(ui->variableName, &QLineEdit::textChanged, this, &EditVariableDialog::textChanged); 19 | connect(ui->variableValue, &QLineEdit::textChanged, this, &EditVariableDialog::textChanged); 20 | } 21 | 22 | EditVariableDialog::~EditVariableDialog() { delete ui; } 23 | 24 | void EditVariableDialog::setVariableName(const QString &variable) { ui->variableName->setText(variable); } 25 | 26 | void EditVariableDialog::setVariableValue(const QString &value) { ui->variableValue->setText(value); } 27 | 28 | auto EditVariableDialog::getVariableName() const -> QString { return ui->variableName->text(); } 29 | 30 | auto EditVariableDialog::getVariableValue() const -> QString { return ui->variableValue->text(); } 31 | 32 | void EditVariableDialog::textChanged() { 33 | if (! ui->variableName->text().isEmpty() && ! ui->variableValue->text().isEmpty()) { 34 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 35 | } else { 36 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/editvariabledialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | 16 | namespace Ui { 17 | class EditVariableDialog; 18 | } 19 | 20 | class EditVariableDialog : public QDialog { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit EditVariableDialog(QWidget *parent = nullptr); 25 | ~EditVariableDialog(); 26 | void setVariableName(const QString &); 27 | void setVariableValue(const QString &); 28 | QString getVariableName() const; 29 | QString getVariableValue() const; 30 | 31 | private: 32 | Ui::EditVariableDialog *ui; 33 | 34 | private slots: 35 | void textChanged(); 36 | }; 37 | -------------------------------------------------------------------------------- /src/environmentvariablesdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | 16 | namespace Ui { 17 | class EnvironmentVariablesDialog; 18 | } 19 | 20 | class EnvironmentVariablesDialog : public QDialog { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit EnvironmentVariablesDialog(QWidget *parent = nullptr); 25 | ~EnvironmentVariablesDialog(); 26 | void setProcessEnvironment(const QProcessEnvironment &); 27 | QProcessEnvironment getProcessEnvironment() const; 28 | 29 | private: 30 | Ui::EnvironmentVariablesDialog *ui; 31 | 32 | private slots: 33 | void addButtonClicked(); 34 | void editButtonClicked(); 35 | void deleteButtonClicked(); 36 | void viewerSelectionChanged(); 37 | }; 38 | -------------------------------------------------------------------------------- /src/exttestcasemodifier.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | #include 12 | 13 | namespace Ui { 14 | class ExtTestCaseModifier; 15 | } 16 | 17 | class Task; 18 | class Settings; 19 | 20 | class ExtTestCaseModifier : public QWidget { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit ExtTestCaseModifier(QWidget *parent = nullptr); 25 | ~ExtTestCaseModifier(); 26 | 27 | void refresh(); 28 | void init(Task *, const Settings *); 29 | 30 | private: 31 | Ui::ExtTestCaseModifier *ui; 32 | 33 | Task *editTask{}; 34 | const Settings *editSettings{}; 35 | 36 | private slots: 37 | void whenTestCaseSelectionChanged(); 38 | 39 | void modifySelected(); 40 | void moveUpSelected(); 41 | void moveDownSelected(); 42 | void removeSelected(); 43 | void mergeSelected(); 44 | void splitSelected(); 45 | 46 | void appendNewSub(); 47 | void appendNewCase(); 48 | }; 49 | -------------------------------------------------------------------------------- /src/exttestcasemodifierdialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #include "exttestcasemodifierdialog.h" 9 | #include "ui_exttestcasemodifierdialog.h" 10 | // 11 | #include "core/task.h" 12 | // 13 | #include 14 | 15 | ExtTestCaseModifierDialog::ExtTestCaseModifierDialog(QWidget *parent) 16 | : QDialog(parent), ui(new Ui::ExtTestCaseModifierDialog) { 17 | ui->setupUi(this); 18 | setWindowTitle(QString(tr("Advanced Test Case Modifier"))); 19 | connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, 20 | &ExtTestCaseModifierDialog::accept); 21 | connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, 22 | &ExtTestCaseModifierDialog::reject); 23 | } 24 | 25 | ExtTestCaseModifierDialog::~ExtTestCaseModifierDialog() { delete ui; } 26 | 27 | void ExtTestCaseModifierDialog::init(Task *theTask, const Settings *theSettings) { 28 | editTask = new Task; 29 | 30 | theTask->copyTo(editTask); 31 | 32 | ui->widget->init(editTask, theSettings); 33 | } 34 | 35 | auto ExtTestCaseModifierDialog::getEditTask() -> Task * { return editTask; } 36 | -------------------------------------------------------------------------------- /src/exttestcasemodifierdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | #include 12 | 13 | namespace Ui { 14 | class ExtTestCaseModifierDialog; 15 | } 16 | 17 | class Task; 18 | class Settings; 19 | 20 | class ExtTestCaseModifierDialog : public QDialog { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit ExtTestCaseModifierDialog(QWidget *parent = nullptr); 25 | ~ExtTestCaseModifierDialog(); 26 | 27 | void init(Task *, const Settings *); 28 | Task *getEditTask(); 29 | 30 | private: 31 | Ui::ExtTestCaseModifierDialog *ui; 32 | 33 | Task *editTask{}; 34 | }; 35 | -------------------------------------------------------------------------------- /src/exttestcasetable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | #include 12 | 13 | class Task; 14 | class TestCase; 15 | 16 | class ExtTestCaseTable : public QTableWidget { 17 | Q_OBJECT 18 | 19 | public: 20 | ExtTestCaseTable(QWidget *parent); 21 | 22 | void refreshTask(Task *); 23 | 24 | bool canModify() const; 25 | bool canAddSub() const; 26 | bool canAddCase() const; 27 | bool canRemove() const; 28 | bool canUp() const; 29 | bool canDown() const; 30 | bool canMerge() const; 31 | bool canSplit() const; 32 | 33 | QList getSelectedHaveSub() const; 34 | QList>> getSelectedResSub() const; 35 | std::pair getSelectRange() const; 36 | void modifySelected(int, int); 37 | 38 | private: 39 | Task *editTask{}; 40 | 41 | void addItem(int row, int column, const QString &text); 42 | void addItem(int row, int column, const QString &text, const QString &tipText); 43 | 44 | QList haveSub; 45 | QList>> resSub; 46 | 47 | bool isCanModify; 48 | bool isCanAddSub; 49 | bool isCanAddCase; 50 | bool isCanRemove; 51 | bool isCanUp; 52 | bool isCanDown; 53 | bool isCanMerge; 54 | bool isCanSplit; 55 | int selectMi{}; 56 | int selectMx{}; 57 | bool noDfs; 58 | 59 | private slots: 60 | void whenItemSelectionChanged(); 61 | 62 | signals: 63 | void testCaseSelectionChanged(); 64 | }; 65 | -------------------------------------------------------------------------------- /src/exttestcaseupdaterdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | #include 12 | 13 | namespace Ui { 14 | class ExtTestCaseUpdaterDialog; 15 | } 16 | 17 | class Task; 18 | class Settings; 19 | 20 | const int NO_EDIT = -400; 21 | const int MAY_EDIT = -300; 22 | const int EDIT_WITH_DEFAULT = -200; 23 | 24 | class ExtTestCaseUpdaterDialog : public QDialog { 25 | Q_OBJECT 26 | 27 | public: 28 | explicit ExtTestCaseUpdaterDialog(QWidget *parent = nullptr, Task *nowTask = nullptr, 29 | const Settings *nowSettings = nullptr, int nowCaseNumber = 0, 30 | int editScore = NO_EDIT, int editData = NO_EDIT, int editTime = NO_EDIT, 31 | int editMemory = NO_EDIT, int editDepend = NO_EDIT, 32 | QList tempDepends = QList()); 33 | ~ExtTestCaseUpdaterDialog(); 34 | 35 | int getScore() const; 36 | QString getInput() const; 37 | QString getOutput() const; 38 | int getTimeLimit() const; 39 | int getMemoryLimit() const; 40 | QStringList getDepends() const; 41 | 42 | int checkDepends(); 43 | 44 | protected: 45 | virtual void accept() override; 46 | 47 | private: 48 | Ui::ExtTestCaseUpdaterDialog *ui; 49 | Task *nowTask; 50 | const Settings *nowSettings; 51 | int nowCaseNumber; 52 | int editScore; 53 | int editData; 54 | int editTime; 55 | int editMemory; 56 | int editDepend; 57 | 58 | int score; 59 | QString input, output; 60 | int timeLimit, memoryLimit; 61 | QStringList depends; 62 | 63 | int defScore, defTimeLimit, defMemoryLimit; 64 | 65 | private slots: 66 | 67 | void whenButtonFindInputClicked(); 68 | void whenButtonFindOutputClicked(); 69 | void fullScoreChanged(const QString &); 70 | void timeLimitChanged(const QString &); 71 | void memoryLimitChanged(const QString &); 72 | void inputFileChanged(const QString &); 73 | void outputFileChanged(const QString &); 74 | void dependsChanged(const QString &); 75 | }; 76 | -------------------------------------------------------------------------------- /src/filelineedit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include "filelineedit.h" 11 | // 12 | #include "base/settings.h" 13 | 14 | FileLineEdit::FileLineEdit(QWidget *parent) : QLineEdit(parent) { completer = nullptr; } 15 | 16 | void FileLineEdit::getFiles(const QString &curDir, const QString &prefix, QStringList &files) { 17 | QDir dir(curDir); 18 | 19 | if (! nameFilters.isEmpty()) { 20 | dir.setNameFilters(nameFilters); 21 | } 22 | 23 | QStringList fileList = dir.entryList(filters); 24 | 25 | for (auto &f : fileList) 26 | f = prefix + f; 27 | 28 | files.append(fileList); 29 | 30 | // Get file in Child dir 31 | QStringList dirList = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); 32 | 33 | for (auto &&d : dirList) { 34 | getFiles(curDir + d + QDir::separator(), prefix + d + QDir::separator(), files); 35 | } 36 | } 37 | 38 | void FileLineEdit::setFilters(QDir::Filters _filters) { filters = _filters; } 39 | 40 | void FileLineEdit::setFileExtensions(const QStringList &extensions) { 41 | nameFilters.clear(); 42 | 43 | for (int i = 0; i < extensions.size(); i++) { 44 | nameFilters.append("*." + extensions[i]); 45 | } 46 | 47 | refreshFileList(); 48 | } 49 | 50 | void FileLineEdit::refreshFileList() { 51 | QStringList files; 52 | getFiles(Settings::dataPath(), "", files); 53 | delete completer; 54 | completer = new QCompleter(files, this); 55 | setCompleter(completer); 56 | } 57 | -------------------------------------------------------------------------------- /src/filelineedit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class FileLineEdit : public QLineEdit { 19 | Q_OBJECT 20 | public: 21 | explicit FileLineEdit(QWidget *parent = nullptr); 22 | void setFilters(QDir::Filters); 23 | void setFileExtensions(const QStringList &); 24 | void getFiles(const QString &, const QString &, QStringList &); 25 | 26 | private: 27 | QCompleter *completer; 28 | QStringList nameFilters; 29 | QDir::Filters filters; 30 | 31 | public slots: 32 | void refreshFileList(); 33 | }; 34 | -------------------------------------------------------------------------------- /src/forms/detaildialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DetailDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 709 10 | 520 11 | 12 | 13 | 14 | Details 15 | 16 | 17 | 18 | 19 | 20 | 21 | 10 22 | 23 | 24 | 25 | Qt::LinksAccessibleByMouse 26 | 27 | 28 | false 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | Qt::Horizontal 38 | 39 | 40 | 41 | 40 42 | 20 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 10 52 | 53 | 54 | 55 | &Close 56 | 57 | 58 | 59 | :/icon/paint-none.svg:/icon/paint-none.svg 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | closeButton 73 | clicked() 74 | DetailDialog 75 | accept() 76 | 77 | 78 | 650 79 | 493 80 | 81 | 82 | 354 83 | 259 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/forms/exttestcasemodifierdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ExtTestCaseModifierDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 512 11 | 12 | 13 | 14 | 15 | 800 16 | 0 17 | 18 | 19 | 20 | Dialog 21 | 22 | 23 | 24 | :/icon/icon.png:/icon/icon.png 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 10 35 | 36 | 37 | 38 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ExtTestCaseModifier 47 | QWidget 48 |
exttestcasemodifier.h
49 | 1 50 |
51 |
52 | 53 | 54 |
55 | -------------------------------------------------------------------------------- /src/forms/newcontestdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | NewContestDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 450 10 | 320 11 | 12 | 13 | 14 | 15 | 450 16 | 320 17 | 18 | 19 | 20 | New Contest 21 | 22 | 23 | 24 | 25 | 26 | 27 | 10 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 10 37 | 38 | 39 | 40 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | NewContestWidget 49 | QWidget 50 |
newcontestwidget.h
51 | 1 52 |
53 |
54 | 55 | 56 | 57 | buttonBox 58 | accepted() 59 | NewContestDialog 60 | accept() 61 | 62 | 63 | 224 64 | 294 65 | 66 | 67 | 224 68 | 159 69 | 70 | 71 | 72 | 73 | buttonBox 74 | rejected() 75 | NewContestDialog 76 | reject() 77 | 78 | 79 | 224 80 | 294 81 | 82 | 83 | 224 84 | 159 85 | 86 | 87 | 88 | 89 |
90 | -------------------------------------------------------------------------------- /src/forms/opencontestdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenContestDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 450 10 | 320 11 | 12 | 13 | 14 | 15 | 450 16 | 320 17 | 18 | 19 | 20 | Open an Existing Contest 21 | 22 | 23 | 24 | 25 | 26 | 27 | 10 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 10 37 | 38 | 39 | 40 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | OpenContestWidget 49 | QWidget 50 |
opencontestwidget.h
51 | 1 52 |
53 |
54 | 55 | 56 | 57 | buttonBox 58 | accepted() 59 | OpenContestDialog 60 | accept() 61 | 62 | 63 | 224 64 | 294 65 | 66 | 67 | 224 68 | 159 69 | 70 | 71 | 72 | 73 | buttonBox 74 | rejected() 75 | OpenContestDialog 76 | reject() 77 | 78 | 79 | 224 80 | 294 81 | 82 | 83 | 224 84 | 159 85 | 86 | 87 | 88 | 89 |
90 | -------------------------------------------------------------------------------- /src/forms/optionsdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | OptionsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 533 10 | 437 11 | 12 | 13 | 14 | 15 | 533 16 | 437 17 | 18 | 19 | 20 | Options 21 | 22 | 23 | 24 | 25 | 26 | 27 | 10 28 | 29 | 30 | 31 | 0 32 | 33 | 34 | 35 | General 36 | 37 | 38 | 39 | 40 | Compiler 41 | 42 | 43 | 44 | 45 | Visual 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 10 55 | 56 | 57 | 58 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | GeneralSettings 67 | QWidget 68 |
generalsettings.h
69 | 1 70 |
71 | 72 | CompilerSettings 73 | QWidget 74 |
compilersettings.h
75 | 1 76 |
77 | 78 | VisualMainSettings 79 | QWidget 80 |
visualmainsettings.h
81 | 1 82 |
83 |
84 | 85 | tabWidget 86 | 87 | 88 | 89 | 90 | buttonBox 91 | rejected() 92 | OptionsDialog 93 | reject() 94 | 95 | 96 | 176 97 | 414 98 | 99 | 100 | 176 101 | 219 102 | 103 | 104 | 105 | 106 |
107 | -------------------------------------------------------------------------------- /src/forms/statisticsbrowser.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | StatisticsBrowser 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 21 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 22 | p, li { white-space: pre-wrap; } 23 | </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> 24 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/forms/themeeditdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ThemeEditDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Qt::Horizontal 24 | 25 | 26 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | VisualSettings 35 | QWidget 36 |
visualsettings.h
37 | 1 38 |
39 |
40 | 41 | 42 | 43 | buttonBox 44 | accepted() 45 | ThemeEditDialog 46 | accept() 47 | 48 | 49 | 248 50 | 254 51 | 52 | 53 | 157 54 | 274 55 | 56 | 57 | 58 | 59 | buttonBox 60 | rejected() 61 | ThemeEditDialog 62 | reject() 63 | 64 | 65 | 316 66 | 260 67 | 68 | 69 | 286 70 | 274 71 | 72 | 73 | 74 | 75 |
76 | -------------------------------------------------------------------------------- /src/generalsettings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | 15 | namespace Ui { 16 | class GeneralSettings; 17 | } 18 | 19 | class Settings; 20 | 21 | class GeneralSettings : public QWidget { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit GeneralSettings(QWidget *parent = nullptr); 26 | ~GeneralSettings(); 27 | void resetEditSettings(Settings *); 28 | bool checkValid(); 29 | 30 | private: 31 | Ui::GeneralSettings *ui; 32 | Settings *editSettings{}; 33 | 34 | private slots: 35 | void defaultFullScoreChanged(const QString &); 36 | void defaultTimeLimitChanged(const QString &); 37 | void defaultExtraTimeRatioChanged(const QString &); 38 | void defaultMemoryLimitChanged(const QString &); 39 | void compileTimeLimitChanged(const QString &); 40 | void specialJudgeTimeLimitChanged(const QString &); 41 | void fileSizeLimitChanged(const QString &); 42 | void rejudgeTimesChanged(const QString &); 43 | void maxJudgingThreadsChanged(const QString &); 44 | void inputFileExtensionsChanged(const QString &); 45 | void outputFileExtensionsChanged(const QString &); 46 | void onLanguageComboBoxChanged(const QString &); 47 | }; 48 | -------------------------------------------------------------------------------- /src/judgingdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include "base/LemonType.hpp" 14 | #include 15 | #include 16 | 17 | class Contest; 18 | 19 | namespace Ui { 20 | class JudgingDialog; 21 | } 22 | 23 | class JudgingDialog : public QDialog { 24 | Q_OBJECT 25 | 26 | public: 27 | explicit JudgingDialog(QWidget *parent = nullptr); 28 | ~JudgingDialog(); 29 | void setContest(Contest *); 30 | void judge(const QList>> &); 31 | void judgeAll(); 32 | void reject(); 33 | 34 | private slots: 35 | void stopJudgingSlot(); 36 | static void skipJudging(); 37 | void sendNotify(QString, QString); 38 | 39 | private: 40 | Ui::JudgingDialog *ui; 41 | Contest *curContest{}; 42 | QTextCursor *cursor; 43 | bool stopJudging{}; 44 | 45 | public slots: 46 | void dialogAlert(const QString &); 47 | void singleCaseFinished(QString, int, int, int, int, int, int, int); 48 | void singleSubtaskDependenceFinished(int, int, int); 49 | void taskJudgingStarted(const QString &); 50 | void taskJudgedDisplay(const QString &, const QList> &, const int); 51 | void contestantJudgingStart(const QString &); 52 | void contestantJudgingFinished(); 53 | void contestantJudgedDisplay(const QString &, const int, const int); 54 | void compileError(int, int); 55 | 56 | signals: 57 | void stopJudgingSignal(); 58 | }; 59 | -------------------------------------------------------------------------------- /src/lemon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | 16 | namespace Ui { 17 | class LemonLime; 18 | } 19 | 20 | class Contest; 21 | class Settings; 22 | class OptionsDialog; 23 | 24 | class LemonLime : public QMainWindow { 25 | Q_OBJECT 26 | 27 | public: 28 | explicit LemonLime(QWidget *parent = nullptr); 29 | ~LemonLime(); 30 | void changeEvent(QEvent *); 31 | void closeEvent(QCloseEvent *); 32 | int getSplashTime(); 33 | void welcome(); 34 | 35 | private: 36 | Ui::LemonLime *ui; 37 | Contest *curContest; 38 | Settings *settings; 39 | QFileSystemWatcher *dataDirWatcher; 40 | QString curFile; 41 | QSignalMapper *signalMapper; 42 | QMenu *TaskMenu; 43 | QList TaskList; 44 | QTimer autoSaveTimer; 45 | void judgeExtButtonFlip(bool); 46 | void loadUiLanguage(); 47 | void insertWatchPath(const QString &, QFileSystemWatcher *); 48 | void newContest(const QString &, const QString &, const QString &); 49 | void saveContest(const QString &); 50 | void loadContest(const QString &); 51 | static void getFiles(const QString &, const QStringList &, QMap &); 52 | void addTask(const QString &, const QList> &, int, int, int); 53 | void addTaskWithScoreScale(const QString &, const QList> &, int, int, int); 54 | static bool compareFileName(const std::pair &, const std::pair &); 55 | 56 | private slots: 57 | void summarySelectionChanged(); 58 | void refreshSummary(); 59 | void resetDataWatcher(); 60 | void showOptionsDialog(); 61 | void refreshButtonClicked(); 62 | void cleanupButtonClicked(); 63 | void tabIndexChanged(int); 64 | void moveUpTask(); 65 | void moveDownTask(); 66 | void viewerSelectionChanged(); 67 | void contestantDeleted(); 68 | void newAction(); 69 | void saveAction(); 70 | static void openFolderAction(); 71 | void closeAction(); 72 | void loadAction(); 73 | void addTasksAction(); 74 | void exportResult(); 75 | void exportStatstics(); 76 | void changeContestName(); 77 | void aboutLemon(); 78 | void actionManual(); 79 | static void actionMore(); 80 | 81 | signals: 82 | void dataPathChanged(); 83 | }; 84 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include "lemon.h" 11 | #include "spdlog/sinks/stdout_color_sinks.h" 12 | // 13 | #include "base/LemonBase.hpp" 14 | #include "base/LemonBaseApplication.hpp" 15 | #include "base/LemonLog.hpp" 16 | #include "spdlog/sinks/daily_file_sink.h" 17 | // 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #define LEMON_MODULE_NAME "Main" 24 | 25 | void initLogger() { 26 | auto console_sink = std::make_shared(); 27 | console_sink->set_level(spdlog::level::warn); 28 | QDir logDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QDir::separator() + 29 | "logs"); 30 | logDir.mkpath("."); 31 | // retain last 30 days logs 32 | auto file_sink = std::make_shared( 33 | (logDir.path() + QDir::separator() + "lemonlime-log.txt").toStdString(), 0, 0, false, 30); 34 | file_sink->set_level(spdlog::level::trace); 35 | Lemon::base::logger = 36 | std::make_shared(spdlog::logger("lemonlime", {console_sink, file_sink})); 37 | spdlog::flush_every(std::chrono::seconds(5)); 38 | } 39 | 40 | int main(int argc, char *argv[]) { 41 | 42 | #ifndef LEMON_QT6 43 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // High DPI supported 44 | QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); 45 | QApplication::setHighDpiScaleFactorRoundingPolicy( 46 | Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); // Qt 6 compatibility 47 | #endif 48 | 49 | QCoreApplication::setApplicationName("Lemonlime"); 50 | 51 | initLogger(); 52 | 53 | Lemon::LemonBaseApplication app(argc, argv); 54 | 55 | app.Initialize(); 56 | 57 | if (app.sendMessage("")) { 58 | app.activeWindow(); 59 | return 0; 60 | } 61 | 62 | #ifdef Q_OS_LINUX 63 | // fonts.setFamily("Noto Sans CJK SC"); 64 | #endif 65 | #ifdef Q_OS_WIN32 66 | QFont fonts; 67 | fonts.setFamily("Microsoft YaHei"); 68 | fonts.setHintingPreference(QFont::PreferNoHinting); 69 | SingleApplication::setFont(fonts); 70 | #endif 71 | #ifdef Q_OS_MAC 72 | // fonts.setFamily("PingFangSC-Regular"); 73 | #endif 74 | Q_INIT_RESOURCE(resource); 75 | QPixmap pixmap(":/logo/splash2.png"); 76 | QSplashScreen screen(pixmap.scaled(450, 191, Qt::KeepAspectRatio, Qt::SmoothTransformation)); 77 | LemonLime w; 78 | qint64 startTime = QDateTime::currentMSecsSinceEpoch(); 79 | int splashTime = w.getSplashTime(); 80 | 81 | if (splashTime > 0) { 82 | screen.show(); 83 | 84 | do { 85 | SingleApplication::processEvents(); 86 | } while (QDateTime::currentMSecsSinceEpoch() - startTime <= splashTime); 87 | 88 | screen.finish(&w); 89 | } 90 | 91 | w.activateWindow(); 92 | w.show(); 93 | w.welcome(); 94 | return app.exec(); 95 | } 96 | -------------------------------------------------------------------------------- /src/newcontestdialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include "newcontestdialog.h" 11 | #include "ui_newcontestdialog.h" 12 | // 13 | #include 14 | 15 | NewContestDialog::NewContestDialog(QWidget *parent) : QDialog(parent), ui(new Ui::NewContestDialog) { 16 | ui->setupUi(this); 17 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 18 | connect(ui->newContestWidget, &NewContestWidget::informationChanged, this, 19 | &NewContestDialog::informationChanged); 20 | } 21 | 22 | NewContestDialog::~NewContestDialog() { delete ui; } 23 | 24 | auto NewContestDialog::getContestTitle() -> QString { return ui->newContestWidget->getContestTitle(); } 25 | 26 | auto NewContestDialog::getSavingName() -> QString { return ui->newContestWidget->getSavingName(); } 27 | 28 | auto NewContestDialog::getContestPath() -> QString { return ui->newContestWidget->getContestPath(); } 29 | 30 | void NewContestDialog::informationChanged() { 31 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ui->newContestWidget->checkReady()); 32 | } 33 | -------------------------------------------------------------------------------- /src/newcontestdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | 16 | namespace Ui { 17 | class NewContestDialog; 18 | } 19 | 20 | class NewContestDialog : public QDialog { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit NewContestDialog(QWidget *parent = nullptr); 25 | ~NewContestDialog(); 26 | QString getContestTitle(); 27 | QString getSavingName(); 28 | QString getContestPath(); 29 | 30 | private: 31 | Ui::NewContestDialog *ui; 32 | 33 | private slots: 34 | void informationChanged(); 35 | }; 36 | -------------------------------------------------------------------------------- /src/newcontestwidget.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include "newcontestwidget.h" 11 | #include "ui_newcontestwidget.h" 12 | // 13 | #include 14 | 15 | NewContestWidget::NewContestWidget(QWidget *parent) : QWidget(parent), ui(new Ui::NewContestWidget) { 16 | ui->setupUi(this); 17 | connect(ui->selectButton, &QToolButton::clicked, this, &NewContestWidget::selectContestPath); 18 | connect(ui->savingName, &QLineEdit::textChanged, this, &NewContestWidget::savingNameChanged); 19 | connect(ui->contestTitle, &QLineEdit::textChanged, this, &NewContestWidget::informationChanged); 20 | connect(ui->savingName, &QLineEdit::textChanged, this, &NewContestWidget::informationChanged); 21 | connect(ui->contestPath, &QLineEdit::textChanged, this, &NewContestWidget::informationChanged); 22 | } 23 | 24 | NewContestWidget::~NewContestWidget() { delete ui; } 25 | 26 | auto NewContestWidget::getContestTitle() -> QString { return ui->contestTitle->text(); } 27 | 28 | auto NewContestWidget::getSavingName() -> QString { return ui->savingName->text(); } 29 | 30 | auto NewContestWidget::getContestPath() -> QString { return ui->contestPath->text(); } 31 | 32 | auto NewContestWidget::checkReady() const -> bool { 33 | return ! ui->contestTitle->text().isEmpty() && ! ui->contestPath->text().isEmpty() && 34 | ! ui->savingName->text().isEmpty(); 35 | } 36 | 37 | void NewContestWidget::selectContestPath() { 38 | QString path = QFileDialog::getExistingDirectory(this, tr("Select Contest Path"), QDir::homePath()); 39 | 40 | if (! path.isEmpty()) 41 | ui->contestPath->setText(QDir::toNativeSeparators(path)); 42 | } 43 | 44 | void NewContestWidget::savingNameChanged() { 45 | QString path = QDir::homePath(); 46 | path = QDir::toNativeSeparators(path); 47 | path += QDir::separator(); 48 | path += ui->savingName->text(); 49 | ui->contestPath->setText(path); 50 | } 51 | -------------------------------------------------------------------------------- /src/newcontestwidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | 15 | namespace Ui { 16 | class NewContestWidget; 17 | } 18 | 19 | class NewContestWidget : public QWidget { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit NewContestWidget(QWidget *parent = nullptr); 24 | ~NewContestWidget(); 25 | QString getContestTitle(); 26 | QString getSavingName(); 27 | QString getContestPath(); 28 | bool checkReady() const; 29 | 30 | private: 31 | Ui::NewContestWidget *ui; 32 | 33 | signals: 34 | void informationChanged(); 35 | 36 | private slots: 37 | void selectContestPath(); 38 | void savingNameChanged(); 39 | }; 40 | -------------------------------------------------------------------------------- /src/opencontestdialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include "opencontestdialog.h" 11 | #include "ui_opencontestdialog.h" 12 | // 13 | #include 14 | 15 | OpenContestDialog::OpenContestDialog(QWidget *parent) : QDialog(parent), ui(new Ui::OpenContestDialog) { 16 | ui->setupUi(this); 17 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 18 | connect(ui->openContestWidget, &OpenContestWidget::selectionChanged, this, 19 | &OpenContestDialog::selectionChanged); 20 | connect(ui->openContestWidget, &OpenContestWidget::rowDoubleClicked, this, &OpenContestDialog::accept); 21 | } 22 | 23 | OpenContestDialog::~OpenContestDialog() { delete ui; } 24 | 25 | void OpenContestDialog::setRecentContest(const QStringList &list) { 26 | ui->openContestWidget->setRecentContest(list); 27 | } 28 | 29 | void OpenContestDialog::selectionChanged() { 30 | if (ui->openContestWidget->getCurrentRow() != -1) { 31 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 32 | } else { 33 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 34 | } 35 | } 36 | 37 | auto OpenContestDialog::getRecentContest() const -> const QStringList & { 38 | return ui->openContestWidget->getRecentContest(); 39 | } 40 | 41 | auto OpenContestDialog::getSelectedContest() -> QString { 42 | return ui->openContestWidget->getRecentContest().at(ui->openContestWidget->getCurrentRow()); 43 | } 44 | -------------------------------------------------------------------------------- /src/opencontestdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace Ui { 18 | class OpenContestDialog; 19 | } 20 | 21 | class OpenContestDialog : public QDialog { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit OpenContestDialog(QWidget *parent = nullptr); 26 | ~OpenContestDialog(); 27 | void setRecentContest(const QStringList &); 28 | const QStringList &getRecentContest() const; 29 | QString getSelectedContest(); 30 | 31 | private: 32 | Ui::OpenContestDialog *ui; 33 | 34 | private slots: 35 | void selectionChanged(); 36 | }; 37 | -------------------------------------------------------------------------------- /src/opencontestwidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace Ui { 18 | class OpenContestWidget; 19 | } 20 | 21 | class OpenContestWidget : public QWidget { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit OpenContestWidget(QWidget *parent = nullptr); 26 | ~OpenContestWidget(); 27 | void setRecentContest(const QStringList &); 28 | const QStringList &getRecentContest() const; 29 | int getCurrentRow() const; 30 | 31 | private: 32 | Ui::OpenContestWidget *ui; 33 | QStringList recentContest; 34 | void refreshContestList(); 35 | 36 | private slots: 37 | void addContest(); 38 | void deleteContest(); 39 | void currentRowChanged(); 40 | 41 | signals: 42 | void selectionChanged(); 43 | void rowDoubleClicked(); 44 | }; 45 | -------------------------------------------------------------------------------- /src/optionsdialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include "optionsdialog.h" 11 | #include "ui_optionsdialog.h" 12 | // 13 | #include "base/LemonLog.hpp" 14 | #include "base/settings.h" 15 | // 16 | #include 17 | #define LEMON_MODULE_NAME "OptionsDialog" 18 | 19 | OptionsDialog::OptionsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::OptionsDialog) { 20 | ui->setupUi(this); 21 | editSettings = new Settings(); 22 | connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, 23 | &OptionsDialog::okayButtonClicked); 24 | } 25 | 26 | OptionsDialog::~OptionsDialog() { delete ui; } 27 | 28 | auto OptionsDialog::getEditSettings() -> Settings * { return editSettings; } 29 | 30 | void OptionsDialog::resetEditSettings(Settings *settings) { 31 | editSettings->copyFrom(settings); 32 | ui->generalSettings->resetEditSettings(editSettings); 33 | ui->compilerSettings->resetEditSettings(editSettings); 34 | ui->visualMainSettings->resetEditSettings(editSettings); 35 | ui->tabWidget->setCurrentIndex(0); 36 | } 37 | 38 | void OptionsDialog::okayButtonClicked() { 39 | ui->tabWidget->setCurrentIndex(0); 40 | 41 | if (! ui->generalSettings->checkValid()) 42 | return; 43 | 44 | ui->tabWidget->setCurrentIndex(1); 45 | 46 | if (! ui->compilerSettings->checkValid()) 47 | return; 48 | 49 | accept(); 50 | } 51 | -------------------------------------------------------------------------------- /src/optionsdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | 15 | namespace Ui { 16 | class OptionsDialog; 17 | } 18 | 19 | class Settings; 20 | 21 | class OptionsDialog : public QDialog { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit OptionsDialog(QWidget *parent = nullptr); 26 | ~OptionsDialog(); 27 | void resetEditSettings(Settings *); 28 | Settings *getEditSettings(); 29 | 30 | private: 31 | Ui::OptionsDialog *ui; 32 | Settings *editSettings; 33 | 34 | private slots: 35 | void okayButtonClicked(); 36 | }; 37 | -------------------------------------------------------------------------------- /src/pch.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include -------------------------------------------------------------------------------- /src/resultviewer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | 15 | class Contest; 16 | 17 | class ResultViewer : public QTableWidget { 18 | Q_OBJECT 19 | public: 20 | explicit ResultViewer(QWidget *parent = nullptr); 21 | void changeEvent(QEvent *); 22 | void contextMenuEvent(QContextMenuEvent *); 23 | void setContest(Contest *); 24 | 25 | public slots: 26 | void refreshViewer(); 27 | void judgeSelected(); 28 | void judgeAll(); 29 | void judgeUnjudged(); 30 | void judgeGrey(); 31 | void judgeMagenta(); 32 | 33 | private: 34 | Contest *curContest; 35 | QAction *deleteContestantAction; 36 | QAction *detailInformationAction; 37 | QAction *judgeSelectedAction; 38 | QAction *deleteContestantKeyAction; 39 | void clearPath(const QString &); 40 | 41 | private slots: 42 | void deleteContestant(); 43 | void detailInformation(); 44 | 45 | signals: 46 | void contestantDeleted(); 47 | }; 48 | -------------------------------------------------------------------------------- /src/statisticsbrowser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | #include "base/LemonType.hpp" 12 | #include "core/contestant.h" 13 | #include "core/task.h" 14 | #include "core/testcase.h" 15 | #include 16 | 17 | namespace Ui { 18 | class StatisticsBrowser; 19 | } 20 | 21 | class Contest; 22 | class TestCase; 23 | 24 | static QString nowBrowserText; 25 | 26 | class StatisticsBrowser : public QWidget { 27 | Q_OBJECT 28 | 29 | public: 30 | explicit StatisticsBrowser(QWidget *parent = nullptr); 31 | void setContest(Contest *); 32 | static void exportStatstics(QWidget *, Contest *); 33 | ~StatisticsBrowser(); 34 | 35 | public slots: 36 | void refresh(); 37 | 38 | private: 39 | Ui::StatisticsBrowser *ui; 40 | Contest *curContest; 41 | static bool checkValid(QList, const QList &); 42 | static QString getScoreNormalChart(const QMap &, int, int); 43 | static QString getTestcaseScoreChart(QList, QList>>, 44 | QList>>); 45 | static void exportStatsticsHtml(QWidget *, const QString &); 46 | }; 47 | -------------------------------------------------------------------------------- /src/summarytree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | class Settings; 20 | class Contest; 21 | 22 | class SummaryTree : public QTreeWidget { 23 | Q_OBJECT 24 | public: 25 | explicit SummaryTree(QWidget *parent = nullptr); 26 | void changeEvent(QEvent *) override; 27 | void setContest(Contest *); 28 | void setSettings(Settings *); 29 | void contextMenuEvent(QContextMenuEvent *) override; 30 | 31 | private: 32 | int addCount; 33 | Contest *curContest; 34 | Settings *settings{}; 35 | QAction *addTaskAction; 36 | QAction *addTestCaseAction; 37 | QAction *addTestCasesAction; 38 | QAction *addTaskKeyAction; 39 | QAction *addTestCaseKeyAction; 40 | QAction *deleteTaskAction; 41 | QAction *deleteTestCaseAction; 42 | QAction *deleteTaskKeyAction; 43 | QAction *deleteTestCaseKeyAction; 44 | QAction *ExtTestCaseModifierAction; 45 | 46 | private slots: 47 | void addTask(); 48 | void addTestCase(); 49 | void addTestCases(); 50 | void deleteTask(); 51 | void deleteTestCase(); 52 | void selectionChanged(); 53 | void itemChanged(QTreeWidgetItem *); 54 | void titleChanged(const QString &); 55 | void launchExtTestCaseModifier(); 56 | 57 | signals: 58 | void taskChanged(); 59 | }; 60 | -------------------------------------------------------------------------------- /src/taskeditwidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | 15 | namespace Ui { 16 | class TaskEditWidget; 17 | } 18 | 19 | class Settings; 20 | class Task; 21 | 22 | class TaskEditWidget : public QWidget { 23 | Q_OBJECT 24 | 25 | public: 26 | explicit TaskEditWidget(QWidget *parent = nullptr); 27 | ~TaskEditWidget(); 28 | void changeEvent(QEvent *); 29 | void setEditTask(Task *); 30 | void setSettings(Settings *); 31 | 32 | private: 33 | Ui::TaskEditWidget *ui; 34 | Settings *settings{}; 35 | Task *editTask; 36 | void refreshWidgetState(); 37 | void addSourceFiles(const QString &, const QString &); 38 | void addGraderFiles(const QString &, const QString &); 39 | void rmSourceFilesAt(int); 40 | void rmGraderFilesAt(int); 41 | void multiFilesRefresh(); 42 | 43 | private slots: 44 | void problemTitleChanged(const QString &); 45 | void setToTraditional(bool); 46 | void setToAnswersOnly(bool); 47 | void setToInteraction(bool); 48 | void setToCommunication(bool); 49 | void setToCommunicationExec(bool); 50 | void sourceFileNameChanged(const QString &); 51 | void subFolderCheckChanged(); 52 | void inputFileNameChanged(const QString &); 53 | void outputFileNameChanged(const QString &); 54 | void standardInputCheckChanged(); 55 | void standardOutputCheckChanged(); 56 | void comparisonModeChanged(); 57 | void diffArgumentsChanged(const QString &); 58 | void realPrecisionChanged(int); 59 | void specialJudgeChanged(const QString &); 60 | void interactorChanged(const QString &); 61 | void interactorNameChanged(const QString &); 62 | void graderChanged(const QString &); 63 | void refreshProblemTitle(const QString &); 64 | void refreshCompilerConfiguration(); 65 | void compilerSelectionChanged(); 66 | void configurationSelectionChanged(); 67 | void answerFileExtensionChanged(const QString &); 68 | void addSourceFileClicked(); 69 | void addGraderFileClicked(); 70 | void rmSourceFileClicked(); 71 | void rmGraderFileClicked(); 72 | 73 | signals: 74 | void dataPathChanged(); 75 | }; 76 | -------------------------------------------------------------------------------- /src/testcaseeditwidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace Ui { 19 | class TestCaseEditWidget; 20 | } 21 | 22 | class Settings; 23 | class TestCase; 24 | 25 | class TestCaseEditWidget : public QWidget { 26 | Q_OBJECT 27 | 28 | public: 29 | explicit TestCaseEditWidget(QWidget *parent = nullptr); 30 | ~TestCaseEditWidget(); 31 | void changeEvent(QEvent *); 32 | void setEditTestCase(TestCase *, bool); 33 | void setSettings(Settings *); 34 | 35 | private: 36 | Ui::TestCaseEditWidget *ui; 37 | TestCase *editTestCase; 38 | Settings *settings{}; 39 | QAction *deleteAction; 40 | void refreshFileList(); 41 | 42 | private slots: 43 | void addSingleCase(); 44 | void deleteSingleCase(); 45 | void fullScoreChanged(const QString &); 46 | void timeLimitChanged(const QString &); 47 | void memoryLimitChanged(const QString &); 48 | void subtaskDependenceChanged(); 49 | void subtaskDependenceClear(); 50 | void fileListSelectionChanged(); 51 | void fileListItemChanged(QTableWidgetItem *); 52 | 53 | signals: 54 | void dataPathChanged(); 55 | }; 56 | -------------------------------------------------------------------------------- /src/themeeditdialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #include "themeeditdialog.h" 9 | #include "settings.h" 10 | #include "ui_themeeditdialog.h" 11 | #include "visualsettings.h" 12 | #include 13 | 14 | ThemeEditDialog::ThemeEditDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ThemeEditDialog) { 15 | ui->setupUi(this); 16 | editTheme = nullptr; 17 | connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, 18 | &ThemeEditDialog::okayButtonClicked); 19 | } 20 | 21 | ThemeEditDialog::~ThemeEditDialog() { delete ui; } 22 | 23 | void ThemeEditDialog::resetEditTheme(ColorTheme *colorTheme) { 24 | editTheme = colorTheme; 25 | ui->ThemeEdit->resetColorTheme(editTheme); 26 | } 27 | 28 | ColorTheme *ThemeEditDialog::getEditTheme() { return editTheme; } 29 | 30 | void ThemeEditDialog::okayButtonClicked() { 31 | ui->ThemeEdit->refresh(); 32 | accept(); 33 | } 34 | -------------------------------------------------------------------------------- /src/themeeditdialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #ifndef THEMEEDITDIALOG_H 9 | #define THEMEEDITDIALOG_H 10 | 11 | #include 12 | 13 | namespace Ui { 14 | class ThemeEditDialog; 15 | } 16 | 17 | class ColorTheme; 18 | 19 | class ThemeEditDialog : public QDialog { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit ThemeEditDialog(QWidget *parent = nullptr); 24 | void resetEditTheme(ColorTheme *); 25 | ColorTheme *getEditTheme(); 26 | 27 | ~ThemeEditDialog(); 28 | 29 | private: 30 | Ui::ThemeEditDialog *ui; 31 | ColorTheme *editTheme{}; 32 | 33 | private slots: 34 | void okayButtonClicked(); 35 | }; 36 | 37 | #endif // THEMEEDITDIALOG_H 38 | -------------------------------------------------------------------------------- /src/visualmainsettings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #include "visualmainsettings.h" 9 | #include "themeeditdialog.h" 10 | #include "ui_visualmainsettings.h" 11 | // 12 | #include "base/LemonLog.hpp" 13 | #include "base/settings.h" 14 | // 15 | #include 16 | // 17 | #define LEMON_MODULE_NAME "VisualMainSettings" 18 | 19 | VisualMainSettings::VisualMainSettings(QWidget *parent) : QWidget(parent), ui(new Ui::VisualMainSettings) { 20 | ui->setupUi(this); 21 | 22 | ui->splashTimeEdit->setValidator(new QIntValidator(0, 3000, this)); 23 | 24 | connect(ui->splashTimeEdit, &QLineEdit::textChanged, this, &VisualMainSettings::splashTimeChanged); 25 | connect(ui->editThemeButton, &QPushButton::clicked, this, &VisualMainSettings::whenThemeEdit); 26 | connect(ui->themeComboBox, qOverload(&QComboBox::currentIndexChanged), this, 27 | &VisualMainSettings::themeChanged); 28 | connect(ui->addThemeButton, &QToolButton::clicked, this, &VisualMainSettings::whenThemeAdd); 29 | connect(ui->deleteThemeButton, &QToolButton::clicked, this, &VisualMainSettings::whenThemeDelete); 30 | } 31 | 32 | void VisualMainSettings::resetEditSettings(Settings *settings) { 33 | editSettings = settings; 34 | int index = editSettings->getCurrentColorThemeIndex(); 35 | 36 | ui->themeComboBox->clear(); 37 | 38 | auto themeList = editSettings->getColorThemeList(); 39 | 40 | for (auto i : themeList) { 41 | ui->themeComboBox->addItem(i->getName()); 42 | } 43 | 44 | ui->themeComboBox->setCurrentIndex(index); 45 | 46 | ui->splashTimeEdit->setText(QString("%1").arg(editSettings->getSplashTime())); 47 | } 48 | 49 | void VisualMainSettings::splashTimeChanged(const QString &x) { editSettings->setSplashTime(x.toInt()); } 50 | 51 | void VisualMainSettings::themeChanged(const int x) { editSettings->setCurrentColorThemeIndex(x); } 52 | 53 | void VisualMainSettings::whenThemeEdit() { 54 | int index = ui->themeComboBox->currentIndex(); 55 | auto *dialog = new ThemeEditDialog(this); 56 | 57 | ColorTheme *temp = new ColorTheme; 58 | temp->copyFrom(editSettings->getColorTheme(index)); 59 | 60 | dialog->resetEditTheme(temp); 61 | 62 | if (dialog->exec() == QDialog::Accepted) { 63 | editSettings->setColorTheme(dialog->getEditTheme(), index); 64 | } 65 | 66 | delete dialog; 67 | 68 | resetEditSettings(editSettings); 69 | ui->themeComboBox->setCurrentIndex(index); 70 | } 71 | 72 | void VisualMainSettings::whenThemeAdd() { 73 | ColorTheme *temp = new ColorTheme(); 74 | temp->setName(tr("New Theme")); 75 | editSettings->addColorTheme(temp); 76 | resetEditSettings(editSettings); 77 | ui->themeComboBox->setCurrentIndex(editSettings->getColorThemeList().size() - 1); 78 | } 79 | 80 | void VisualMainSettings::whenThemeDelete() { 81 | if (editSettings->getColorThemeList().size() <= 1) 82 | return; 83 | int index = ui->themeComboBox->currentIndex(); 84 | editSettings->deleteColorTheme(index); 85 | if (index >= editSettings->getColorThemeList().size()) 86 | index--; 87 | ui->themeComboBox->setCurrentIndex(index); 88 | resetEditSettings(editSettings); 89 | } 90 | 91 | VisualMainSettings::~VisualMainSettings() { delete ui; } 92 | -------------------------------------------------------------------------------- /src/visualmainsettings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #ifndef VISUALMAINSETTINGS_H 9 | #define VISUALMAINSETTINGS_H 10 | 11 | #include 12 | 13 | namespace Ui { 14 | class VisualMainSettings; 15 | } 16 | 17 | class Settings; 18 | 19 | class VisualMainSettings : public QWidget { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit VisualMainSettings(QWidget *parent = nullptr); 24 | ~VisualMainSettings(); 25 | void resetEditSettings(Settings *); 26 | 27 | private: 28 | Ui::VisualMainSettings *ui; 29 | Settings *editSettings{}; 30 | 31 | private slots: 32 | void splashTimeChanged(const QString &); 33 | void themeChanged(const int); 34 | void whenThemeEdit(); 35 | void whenThemeAdd(); 36 | void whenThemeDelete(); 37 | }; 38 | 39 | #endif // VISUALMAINSETTINGS_H 40 | -------------------------------------------------------------------------------- /src/visualsettings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #include "visualsettings.h" 9 | #include "ui_visualsettings.h" 10 | // 11 | #include "base/LemonLog.hpp" 12 | #include "base/settings.h" 13 | #define LEMON_MODULE_NAME "VisualSettings" 14 | 15 | VisualSettings::VisualSettings(QWidget *parent) : QWidget(parent), ui(new Ui::VisualSettings) { 16 | ui->setupUi(this); 17 | 18 | editColorTheme = nullptr; 19 | connect(ui->themeName, &QLineEdit::textChanged, this, &VisualSettings::themeNameChanged); 20 | } 21 | 22 | void VisualSettings::resetColorTheme(ColorTheme *colorTheme) { 23 | editColorTheme = colorTheme; 24 | 25 | ui->themeName->setText(editColorTheme->getName()); 26 | ui->spinBoxMxH->setValue(editColorTheme->getMxColor().h); 27 | ui->doubleSpinBoxMxS->setValue(editColorTheme->getMxColor().s); 28 | ui->doubleSpinBoxMxL->setValue(editColorTheme->getMxColor().l); 29 | ui->spinBoxMiH->setValue(editColorTheme->getMiColor().h); 30 | ui->doubleSpinBoxMiS->setValue(editColorTheme->getMiColor().s); 31 | ui->doubleSpinBoxMiL->setValue(editColorTheme->getMiColor().l); 32 | ui->spinBoxNfH->setValue(editColorTheme->getNfColor().h); 33 | ui->doubleSpinBoxNfS->setValue(editColorTheme->getNfColor().s); 34 | ui->doubleSpinBoxNfL->setValue(editColorTheme->getNfColor().l); 35 | ui->spinBoxCeH->setValue(editColorTheme->getCeColor().h); 36 | ui->doubleSpinBoxCeS->setValue(editColorTheme->getCeColor().s); 37 | ui->doubleSpinBoxCeL->setValue(editColorTheme->getCeColor().l); 38 | 39 | ui->grandCompH->setValue(editColorTheme->getGrandComp().h); 40 | ui->grandCompS->setValue(editColorTheme->getGrandComp().s); 41 | ui->grandCompL->setValue(editColorTheme->getGrandComp().l); 42 | ui->grandRateH->setValue(editColorTheme->getGrandRate().h); 43 | ui->grandRateS->setValue(editColorTheme->getGrandRate().s); 44 | ui->grandRateL->setValue(editColorTheme->getGrandRate().l); 45 | } 46 | 47 | void VisualSettings::themeNameChanged(const QString &x) { editColorTheme->setName(x); } 48 | 49 | void VisualSettings::refresh() { 50 | editColorTheme->setColor( 51 | hslTuple(ui->spinBoxMxH->value(), ui->doubleSpinBoxMxS->value(), ui->doubleSpinBoxMxL->value()), 52 | hslTuple(ui->spinBoxMiH->value(), ui->doubleSpinBoxMiS->value(), ui->doubleSpinBoxMiL->value()), 53 | hslTuple(ui->spinBoxNfH->value(), ui->doubleSpinBoxNfS->value(), ui->doubleSpinBoxNfL->value()), 54 | hslTuple(ui->spinBoxCeH->value(), ui->doubleSpinBoxCeS->value(), ui->doubleSpinBoxCeL->value()), 55 | dddTuple(ui->grandCompH->value(), ui->grandCompS->value(), ui->grandCompL->value()), 56 | dddTuple(ui->grandRateH->value(), ui->grandRateS->value(), ui->grandRateL->value())); 57 | } 58 | 59 | VisualSettings::~VisualSettings() { delete ui; } 60 | -------------------------------------------------------------------------------- /src/visualsettings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 3 | * 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | */ 7 | 8 | #pragma once 9 | // 10 | 11 | #include 12 | 13 | namespace Ui { 14 | class VisualSettings; 15 | } 16 | 17 | class ColorTheme; 18 | 19 | class VisualSettings : public QWidget { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit VisualSettings(QWidget *parent = nullptr); 24 | void resetColorTheme(ColorTheme *); 25 | void refresh(); 26 | ~VisualSettings(); 27 | 28 | private: 29 | Ui::VisualSettings *ui; 30 | ColorTheme *editColorTheme{}; 31 | 32 | private slots: 33 | void themeNameChanged(const QString &); 34 | }; 35 | -------------------------------------------------------------------------------- /src/welcomedialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include "welcomedialog.h" 11 | #include "ui_welcomedialog.h" 12 | // 13 | #include 14 | 15 | WelcomeDialog::WelcomeDialog(QWidget *parent) : QDialog(parent), ui(new Ui::WelcomeDialog) { 16 | ui->setupUi(this); 17 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 18 | connect(ui->openContestWidget, &OpenContestWidget::selectionChanged, this, 19 | &WelcomeDialog::selectionChanged); 20 | connect(ui->newContestWidget, &NewContestWidget::informationChanged, this, 21 | &WelcomeDialog::informationChanged); 22 | connect(ui->tabWidget, &QTabWidget::currentChanged, this, &WelcomeDialog::tabIndexChanged); 23 | connect(ui->openContestWidget, &OpenContestWidget::rowDoubleClicked, this, &WelcomeDialog::accept); 24 | } 25 | 26 | WelcomeDialog::~WelcomeDialog() { delete ui; } 27 | 28 | void WelcomeDialog::setRecentContest(const QStringList &list) { 29 | ui->openContestWidget->setRecentContest(list); 30 | } 31 | 32 | auto WelcomeDialog::getContestTitle() -> QString { return ui->newContestWidget->getContestTitle(); } 33 | 34 | auto WelcomeDialog::getSavingName() -> QString { return ui->newContestWidget->getSavingName(); } 35 | 36 | auto WelcomeDialog::getContestPath() -> QString { return ui->newContestWidget->getContestPath(); } 37 | 38 | auto WelcomeDialog::getRecentContest() const -> const QStringList & { 39 | return ui->openContestWidget->getRecentContest(); 40 | } 41 | 42 | auto WelcomeDialog::getSelectedContest() -> QString { 43 | return ui->openContestWidget->getRecentContest().at(ui->openContestWidget->getCurrentRow()); 44 | } 45 | 46 | auto WelcomeDialog::getCurrentTab() const -> int { return ui->tabWidget->currentIndex(); } 47 | 48 | void WelcomeDialog::selectionChanged() { 49 | if (ui->openContestWidget->getCurrentRow() != -1) { 50 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 51 | } else { 52 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 53 | } 54 | } 55 | 56 | void WelcomeDialog::informationChanged() { 57 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ui->newContestWidget->checkReady()); 58 | } 59 | 60 | void WelcomeDialog::tabIndexChanged(int index) { 61 | if (index == 0) { 62 | selectionChanged(); 63 | } else { 64 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ui->newContestWidget->checkReady()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/welcomedialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2018 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2018-2019 Project LemonPlus, Dust1404 4 | * SPDX-FileCopyrightText: 2019-2022 Project LemonLime 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #pragma once 11 | // 12 | 13 | #include 14 | 15 | namespace Ui { 16 | class WelcomeDialog; 17 | } 18 | 19 | class WelcomeDialog : public QDialog { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit WelcomeDialog(QWidget *parent = nullptr); 24 | ~WelcomeDialog(); 25 | void setRecentContest(const QStringList &); 26 | QString getContestTitle(); 27 | QString getSavingName(); 28 | QString getContestPath(); 29 | const QStringList &getRecentContest() const; 30 | QString getSelectedContest(); 31 | int getCurrentTab() const; 32 | 33 | private: 34 | Ui::WelcomeDialog *ui; 35 | 36 | private slots: 37 | void selectionChanged(); 38 | void informationChanged(); 39 | void tabIndexChanged(int); 40 | }; 41 | -------------------------------------------------------------------------------- /translations/translations.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | zh_CN.qm 4 | zh_TW.qm 5 | en_US.qm 6 | 7 | 8 | -------------------------------------------------------------------------------- /unix/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.0) 2 | 3 | project(lemon_watcher_unix_test) 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | if(APPLE) 10 | add_executable(watcher_unix ${CMAKE_CURRENT_SOURCE_DIR}/../watcher_unix.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../watcher_macos.mm) 11 | else() 12 | add_executable(watcher_unix ${CMAKE_CURRENT_SOURCE_DIR}/../watcher_unix.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../watcher_linux.cpp) 13 | endif() 14 | 15 | add_executable(hello hello.c) 16 | add_executable(mle_static mle_static.c) 17 | file(COPY hello.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 18 | add_executable(tle tle.c) 19 | add_executable(add add.c) 20 | add_executable(re re.c) 21 | 22 | file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/scripts DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 23 | 24 | enable_testing() 25 | add_test(NAME watcher_run_c_test COMMAND python3 scripts/run.py) 26 | add_test(NAME watcher_run_sh_test COMMAND python3 scripts/run_sh.py) 27 | add_test(NAME watcher_MLE_static_test COMMAND python3 scripts/mle_static.py) 28 | add_test(NAME watcher_unlimit_memory_test COMMAND python3 scripts/unlimit.py) 29 | add_test(NAME watcher_TLE_test COMMAND python3 scripts/tle.py) 30 | add_test(NAME watcher_filename_with_space_test COMMAND python3 scripts/space.py) 31 | add_test(NAME watcher_symlink_abs_test COMMAND python3 scripts/symlink_abs.py) 32 | add_test(NAME watcher_symlink_rel_test COMMAND python3 scripts/symlink_rel.py) 33 | add_test(NAME watcher_redirect_IO_test COMMAND python3 scripts/redirect.py) 34 | add_test(NAME watcher_RE_test COMMAND python3 scripts/runtimeerr.py) 35 | -------------------------------------------------------------------------------- /unix/test/add.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int a, b; 5 | 6 | scanf("%d%d", &a, &b); 7 | printf("%d\n", a + b); 8 | 9 | return 0; 10 | } -------------------------------------------------------------------------------- /unix/test/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | printf("Hello World!\n"); 5 | 6 | return 0; 7 | } -------------------------------------------------------------------------------- /unix/test/hello.sh: -------------------------------------------------------------------------------- 1 | echo "Hello World!" -------------------------------------------------------------------------------- /unix/test/mle_static.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int a[100000000]; 4 | // 400 MB 5 | 6 | int main() { 7 | puts("Hello World!"); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /unix/test/re.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int *x = (void *)0; 3 | return *x; 4 | } -------------------------------------------------------------------------------- /unix/test/scripts/mle_static.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | cmd = "\"%s\" %s" % ("./mle_static", "") 4 | p = subprocess.Popen(["./watcher_unix", cmd, "", "", "_tmperr", "1000", "380"], shell=False, stdout=subprocess.PIPE) 5 | 6 | stdout, _ = p.communicate() 7 | 8 | assert(p.wait() == 0) 9 | assert(stdout[0] == 48) -------------------------------------------------------------------------------- /unix/test/scripts/redirect.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | import time 4 | 5 | with open('_tmpin', 'w') as f: 6 | f.writelines(['1 1']) 7 | 8 | cmd = "\"%s\" %s" % ("./add", "") 9 | p = subprocess.Popen(["./watcher_unix", cmd, "_tmpin", "_tmpout", "_tmperr", "1000", "100"], shell=False) 10 | 11 | time.sleep(2) 12 | p.kill() 13 | 14 | assert(p.returncode == 0) 15 | 16 | assert(os.path.exists('_tmpout')) 17 | with open('_tmpout', 'r') as f: 18 | assert(f.read() == "2\n") 19 | -------------------------------------------------------------------------------- /unix/test/scripts/run.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | cmd = "\"%s\" %s" % ("./hello", "") 4 | p = subprocess.Popen(["./watcher_unix", cmd, "", "", "_tmperr", "1000", "100"], shell=False, stdout=subprocess.PIPE) 5 | 6 | stdout, _ = p.communicate() 7 | 8 | assert(p.wait() == 0) 9 | out_str = stdout.decode() 10 | assert(out_str.split('\n')[0] == 'Hello World!') -------------------------------------------------------------------------------- /unix/test/scripts/run_sh.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | cmd = "\"%s\" %s" % ("/bin/bash", "hello.sh") 4 | p = subprocess.Popen(["./watcher_unix", cmd, "", "", "_tmperr", "1000", "100"], shell=False, stdout=subprocess.PIPE) 5 | 6 | stdout, _ = p.communicate() 7 | 8 | assert(p.wait() == 0) 9 | out_str = stdout.decode() 10 | assert(out_str.split('\n')[0] == 'Hello World!') -------------------------------------------------------------------------------- /unix/test/scripts/runtimeerr.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import time 3 | 4 | cmd = "\"%s\" %s" % ("./re", "") 5 | p = subprocess.Popen(["./watcher_unix", cmd, "", "", "_tmperr", "1000", "100"], shell=False) 6 | 7 | assert(p.wait() == 2) 8 | -------------------------------------------------------------------------------- /unix/test/scripts/space.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import shutil 3 | 4 | shutil.copy("./hello", "./he llo") 5 | 6 | cmd = "\"%s\" %s" % ("./he llo", "") 7 | p = subprocess.Popen(["./watcher_unix", cmd, "", "", "_tmperr", "1000", "100"], shell=False, stdout=subprocess.PIPE) 8 | 9 | stdout, _ = p.communicate() 10 | 11 | assert(p.wait() == 0) 12 | out_str = stdout.decode() 13 | assert(out_str.split('\n')[0] == 'Hello World!') -------------------------------------------------------------------------------- /unix/test/scripts/symlink_abs.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | 4 | if os.path.exists("hello_s_abs"): 5 | os.remove("hello_s_abs") 6 | 7 | os.symlink(os.path.join(os.getcwd(), "hello"), "hello_s_abs") 8 | 9 | cmd = "\"%s\" %s" % ("./hello_s_abs", "") 10 | p = subprocess.Popen(["./watcher_unix", cmd, "", "", "_tmperr", "1000", "100"], shell=False, stdout=subprocess.PIPE) 11 | 12 | stdout, _ = p.communicate() 13 | 14 | assert(p.wait() == 0) 15 | out_str = stdout.decode() 16 | assert(out_str.split('\n')[0] == 'Hello World!') -------------------------------------------------------------------------------- /unix/test/scripts/symlink_rel.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | 4 | if os.path.exists("hello_s_rel"): 5 | os.remove("hello_s_rel") 6 | 7 | os.symlink("hello", "hello_s_rel") 8 | 9 | cmd = "\"%s\" %s" % ("./hello_s_rel", "") 10 | p = subprocess.Popen(["./watcher_unix", cmd, "", "", "_tmperr", "1000", "100"], shell=False, stdout=subprocess.PIPE) 11 | 12 | stdout, _ = p.communicate() 13 | 14 | assert(p.wait() == 0) 15 | out_str = stdout.decode() 16 | assert(out_str.split('\n')[0] == 'Hello World!') -------------------------------------------------------------------------------- /unix/test/scripts/tle.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import time 3 | 4 | cmd = "\"%s\" %s" % ("./tle", "") 5 | p = subprocess.Popen(["./watcher_unix", cmd, "", "", "_tmperr", "1000", "100"], shell=False) 6 | 7 | time.sleep(5) 8 | p.kill() 9 | 10 | assert(p.returncode == 3) 11 | -------------------------------------------------------------------------------- /unix/test/scripts/unlimit.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | cmd = "\"%s\" %s" % ("./mle_static", "") 4 | p = subprocess.Popen(["./watcher_unix", cmd, "", "", "_tmperr", "1000", "-1"], shell=False, stdout=subprocess.PIPE) 5 | 6 | stdout, _ = p.communicate() 7 | 8 | assert(p.wait() == 0) 9 | out_str = stdout.decode() 10 | assert(out_str.split('\n')[0] == 'Hello World!') -------------------------------------------------------------------------------- /unix/test/tle.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | while (1) 3 | ; 4 | return 0; 5 | } -------------------------------------------------------------------------------- /unix/watcher.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | watcher_unix 4 | 5 | 6 | -------------------------------------------------------------------------------- /unix/watcher_linux.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011-2019 Project Lemon, Zhipeng Jia 3 | * SPDX-FileCopyrightText: 2019-2023 Project LemonLime 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | * 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | static auto read_elf_ident(int fd, char *e_ident) -> bool { 24 | if (read(fd, e_ident, EI_NIDENT) != EI_NIDENT) { 25 | return false; 26 | } 27 | if (strncmp(e_ident, "\177ELF", 4) != 0) { 28 | return false; 29 | } 30 | return true; 31 | } 32 | 33 | template static auto calculateStaticMemoryUsage(int fd) -> ssize_t { 34 | ssize_t res = 0; 35 | 36 | Ehdr elf_header; 37 | if (lseek64(fd, 0, SEEK_SET) < 0) { 38 | return -1; 39 | } 40 | if (read(fd, &elf_header, sizeof(Ehdr)) != sizeof(Ehdr)) { 41 | return -1; 42 | } 43 | // gcc with PIE will set executable as ET_DYN 44 | // https://stackoverflow.com/questions/34519521 45 | if (elf_header.e_type != ET_EXEC && elf_header.e_type != ET_DYN) { 46 | return -1; 47 | } 48 | if (elf_header.e_phoff == 0) { 49 | return -1; // no program header, not executable 50 | } 51 | if (elf_header.e_phentsize != sizeof(Phdr)) { 52 | return -1; 53 | } 54 | 55 | if (lseek64(fd, elf_header.e_phoff, SEEK_SET) < 0) { 56 | return -1; 57 | } 58 | Phdr program_header; 59 | for (int i = 0; i < elf_header.e_phnum; ++i) { 60 | if (read(fd, &program_header, sizeof(Phdr)) != sizeof(Phdr)) { 61 | return -1; 62 | } 63 | if (program_header.p_type == PT_LOAD) { 64 | res += program_header.p_memsz; 65 | } 66 | } 67 | 68 | return res; 69 | } 70 | 71 | void initWatcher() { return; } 72 | 73 | ssize_t calculateStaticMemoryUsage(const std::string &fileName) { 74 | char e_ident[EI_NIDENT]; 75 | ssize_t staticMemoryUsage = 0; 76 | int fd = open(fileName.c_str(), O_RDONLY); 77 | if (fd < 0) { 78 | return -1; 79 | } 80 | 81 | if (read_elf_ident(fd, e_ident) == false) { 82 | return -1; 83 | } 84 | if (e_ident[EI_CLASS] == ELFCLASS32) { 85 | staticMemoryUsage = calculateStaticMemoryUsage(fd); 86 | } else if (e_ident[EI_CLASS] == ELFCLASS64) { 87 | staticMemoryUsage = calculateStaticMemoryUsage(fd); 88 | } else { 89 | staticMemoryUsage = -1; 90 | } 91 | close(fd); 92 | 93 | return staticMemoryUsage; 94 | } 95 | 96 | ssize_t getMemoryRLimit(ssize_t memoryLimitInMB) { return memoryLimitInMB * 1024 * 1024; } 97 | 98 | size_t getMaxRSSInByte(long ru_maxrss) { return ru_maxrss * 1024; } 99 | --------------------------------------------------------------------------------