pax_global_header00006660000000000000000000000064151647265120014523gustar00rootroot0000000000000052 comment=ff1cbea1d4f89032b10d63fec8614bc179fc1558 seer-2.7/000077500000000000000000000000001516472651200123315ustar00rootroot00000000000000seer-2.7/.github/000077500000000000000000000000001516472651200136715ustar00rootroot00000000000000seer-2.7/.github/workflows/000077500000000000000000000000001516472651200157265ustar00rootroot00000000000000seer-2.7/.github/workflows/build-latest.yml000066400000000000000000000032121516472651200210400ustar00rootroot00000000000000name: build-latest Development Build on: workflow_dispatch: push: branches: [ main ] pull_request: branches: [ main ] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Update Ubuntu run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.6 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` seer-2.7/.github/workflows/contributor-map.yml000066400000000000000000000004451516472651200216010ustar00rootroot00000000000000name: Create Contributor Map on: workflow_dispatch: jobs: build-and-push-image: runs-on: ubuntu-latest steps: - name: Contributor Map uses: tunaitis/contributor-map@v1 with: repository: epasveer/seer output: images/contributor-map.svg seer-2.7/.github/workflows/debian-latest.yml000066400000000000000000000042651516472651200211740ustar00rootroot00000000000000name: debian-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: debian-latest steps: - uses: actions/checkout@v3 - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.* install-deps: 'true' modules: 'qtcharts' - name: Update debian run: | sudo apt-get update sudo apt list --installed | grep mesa - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build Debian Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "debian-latest" prerelease: true title: "Debian Development Release" files: | src/build/seergdb.tar.gz seer-2.7/.github/workflows/debian-package.yml000066400000000000000000000046551516472651200212760ustar00rootroot00000000000000name: debian-latest Package Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Update Ubuntu run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.6 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: List Results run: | cd src ls -l build/ debian-pkg: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install build dependencies run: | sudo apt-get update sudo apt-get -y install devscripts build-essential dpkg-dev equivs sudo mk-build-deps --install --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control - name: Build Debian package run: dpkg-buildpackage --unsigned-source --unsigned-changes - name: Upload debian package Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "debian-pkg-latest" prerelease: true title: "Debian Package Release" files: | ../seergdb_*_amd64.deb seer-2.7/.github/workflows/flatpak-latest.yml000066400000000000000000000025441516472651200213720ustar00rootroot00000000000000name: flatpak-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: flatpak: name: Build Flatpak runs-on: ubuntu-latest container: image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.10 options: --privileged steps: - name: Where Am I run: | pwd ls -l lscpu - name: Checkout code uses: actions/checkout@v4 - name: Create/update tag uses: rickstaa/action-create-tag@v1 with: tag: flatpak-latest message: Tag from latest ${{ github.ref_name }} branch. force_push_tag: true - name: Build Flatpak uses: flatpak/flatpak-github-actions/flatpak-builder@v6 with: branch: main bundle: seer.flatpak manifest-path: src/resources/flathub/io.github.epasveer.seer.github.yml # Always uses 'main'! cache-key: flatpak-builder-${{ github.sha }} - name: Create Release uses: softprops/action-gh-release@v2 with: name: Flatpak Development Release body: Build from latest ${{ github.ref_name }} branch. files: | seer.flatpak tag_name: flatpak-latest draft: false prerelease: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} seer-2.7/.github/workflows/macos-latest.yml000066400000000000000000000050161516472651200210470ustar00rootroot00000000000000name: macos-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: macos-latest steps: - uses: actions/checkout@v3 - name: Install dependencies run: | export \ HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 \ HOMEBREW_NO_INSTALL_CLEANUP=1 brew update > /dev/null brew install \ cmake ninja - name: Setup ccache uses: Chocobo1/setup-ccache-action@v1 with: update_packager_index: false - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.* install-deps: 'true' modules: 'qtcharts' - name: Where am I run: | pwd ls -l - name: Tool versions run: | g++ --version cmake --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel 4 - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build MacOS Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "macos-latest" prerelease: true title: "MacOS Development Release" files: | src/build/seergdb.tar.gz seer-2.7/.github/workflows/mint-latest.yml000066400000000000000000000041761516472651200207220ustar00rootroot00000000000000name: mint-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Update Mint run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.4.2 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build Mint Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "mint-latest" prerelease: true title: "Mint Development Release" files: | src/build/seergdb.tar.gz seer-2.7/.github/workflows/stargazers-map.yml000066400000000000000000000017431516472651200214160ustar00rootroot00000000000000name: Create Stargazer Map on: workflow_dispatch: jobs: generate-stargazer-map: runs-on: ubuntu-latest name: Generate Stargazer World Map steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install dependencies run: pip install requests plotly pandas kaleido - name: Generate stargazer map env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} run: python .github/scripts/generate_stargazer_map.py - name: Commit and push map run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add images/stargazer-map.svg images/stargazer-map.html git diff --staged --quiet || git commit -m "🌍 Update stargazer world map [skip ci]" git push seer-2.7/.github/workflows/ubuntu-arm64-latest.yml000066400000000000000000000042431516472651200222170ustar00rootroot00000000000000name: ubuntu-arm64-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-24.04-arm64 steps: - uses: actions/checkout@v3 - name: Update Ubuntu ARM64 run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.6 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build Ubuntu Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "ubuntu-arm64-latest" prerelease: true title: "Ubuntu ARM64 Development Release" files: | src/build/seergdb.tar.gz seer-2.7/.github/workflows/ubuntu-latest.yml000066400000000000000000000056471516472651200213010ustar00rootroot00000000000000name: ubuntu-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Update Ubuntu run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.6 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build Ubuntu Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "ubuntu-latest" prerelease: true title: "Ubuntu Development Release" files: | src/build/seergdb.tar.gz debian-pkg: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install build dependencies run: | sudo apt-get update sudo apt-get -y install devscripts build-essential dpkg-dev equivs sudo mk-build-deps --install --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control - name: Build Debian package run: dpkg-buildpackage --unsigned-source --unsigned-changes - name: Upload debian package Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "debian-pkg-latest" prerelease: true title: "Debian Package Release" files: | ../seergdb_*_amd64.deb seer-2.7/.github/workflows/windows-latest.yml000066400000000000000000000060051516472651200214360ustar00rootroot00000000000000name: windows-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: runs-on: windows-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup WSL uses: Vampire/setup-wsl@v3 with: distribution: Ubuntu-22.04 - name: Update ubuntu shell: wsl-bash {0} run: | sudo apt update sudo apt search qt6 sudo apt install -y \ build-essential \ cmake \ ninja-build \ pkg-config \ qt6-base-dev \ qt6-base-dev-tools \ libqt6charts6-dev \ libqt6svg6-dev \ libgl1-mesa-dev \ libxkbcommon-dev \ libxcb-xinerama0-dev \ libxcb-cursor-dev sudo ldconfig /usr/lib/x86_64-linux-gnu sudo ldconfig - name: Set Qt6 environment variables shell: wsl-bash {0} run: | # Find Qt6 installation path QT6_PATH=$(dpkg -L qt6-base-dev | grep -E 'lib.*cmake.*Qt6$' | head -1 | sed 's|/lib.*||') echo "Qt6 found at: $QT6_PATH" # Set environment variables for the session echo "export Qt6_DIR=$QT6_PATH" > /tmp/env.sh echo "export CMAKE_PREFIX_PATH=/usr/lib/x86_64-linux-gnu/cmake/Qt6:$QT6_PATH" >> /tmp/env.sh echo "export QT_QPA_PLATFORM_PLUGIN_PATH=$QT6_PATH/lib/qt6/plugins/platforms" >> /tmp/env.sh echo "export QML_IMPORT_PATH=$QT6_PATH/lib/qt6/qml" >> /tmp/env.sh echo "export QT_PLUGIN_PATH=$QT6_PATH/lib/qt6/plugins" >> /tmp/env.sh # Source the updated env.sh cat /tmp/env.sh source /tmp/env.sh # Print environment for debugging echo "SHELL: $SHELL" echo "Qt6_DIR: $Qt6_DIR" dpkg -L qt6-base-dev dpkg -L libqt6charts6 ldconfig -p - name: Where Am I shell: wsl-bash {0} run: | pwd ls -l lscpu - name: Versions shell: wsl-bash {0} run: g++ --version - name: Configure CMake shell: wsl-bash {0} run: | source /tmp/env.sh cd src/build cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DQTVERSION=QT6 \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH=$Qt6_DIR \ -DQt6_DIR=$Qt6_DIR/lib/cmake/Qt6 pwd ls -l - name: Build shell: wsl-bash {0} run: | source /tmp/env.sh cd src/build pwd ls -l make -j$(nproc) - name: Tar shell: wsl-bash {0} run: | source /tmp/env.sh cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results shell: wsl-bash {0} run: | source /tmp/env.sh cd src ls -l build/ seer-2.7/CHANGELOG.md000066400000000000000000000414071516472651200141500ustar00rootroot00000000000000 # Seer Change Log ## [2.7] - 2026-04-06 * Starting version 2.7 development cycle. * SyntaxHighlighting: Refactored syntax highlighting code. Supports C/C++/Rust/Odin. (Thanks RaphGL!) * VariableTracker: Add 'deleteselect' and 'deleteall' to RMB context menu. * VariableLogger: Add 'deleteselect' and 'deleteall' to RMB context menu. * EditorConfig: Show syntax highlighting for C/C++, Rust, and Odin. * Editor: ^F to focus on text search ^L to focus on line search. * Editor: ESC to hide search panel. * Editor: ^B to toggle breakpoint on current line. * Editor: Show cursor all the time. * Breakpoints: Allow multiple filename:line entries for the --break-source option. * Control: Add ^D to toggle record playback direction for RR, Undo, and gdb's Record. * Control: Add SHIFT+F5 (etal) to reverse step (etc.) during record playback for RR, Undo, and gdb's Record. * GDB: Add Seer config to set gdb architecture. * GDB: Add an optional 'launcher' program to start gdb. eg: flatpak-spawn. * Build: Add flatpak generation to github actions. * Assemby: An option to show assembly tab when there is no source file. * Signals: Add an window to show how GDB handles signals. And to set that behavior. * Macros: Add 10 macros for custom commands that are executed by clicking a button (or a hot key). ## [2.6] - 2025-10-07 * Watchpoints: Fixed regression when adding commands to a watchpoint. * Console: Create console once per Seer session. Instead of constant create/destroy. * EditorManager: Fixed regression when ignoring files to be opened in the EditorManager. * MessageTabs: Fixed regression when order of message tabs not being preserved between sessions. * RemoteMode: Connect mode to a gdb server now supports 'remote' and 'extended-remote'. * ConnectMode: Connect mode's 'pre' commands are executed before the 'target connect'. * MessageTabs: Optionally add a timestamp to the Seer and Gdb log widgets. * ConnectMode: Add 'gdbserver debug' checkbox to Connect launch tab. For showing gdb and gdbserver communication debug information in gdb tab. * Skips: Manage gdb skip commands via a new Skip Browser. * LaunchMode: Revamp the "run/start" buttons on the menu bar to be a predominate "terminate" that switches to a "restart". * VariableTracker: Fixed bug when adding variable to tracker. Sometimes would not refresh value. * VariableTracker: Raise Logger or Tracker tab when new variable is added. * CheckpointMode: Implment gdb's "checkpoint" feature. As simple time-travel feature. * Undo: Add preliminary support for Undo's udb time-traveling debugger. * CheckpointMode: Add support for remaining Catchpoint types. * Visualizers: Add a Matrix Visualizer for viewing 2D arrays. * Breakpoints: Add breakpoints from the Function tab. * DefaultProject: When using the Debug dialog, save the debug settings so they can be fast loaded the next time the Debug dialog is used. Kind of a default project. * RR: When using the Debug dialog, check a couple standard locations for the RR trace directory. * ObjectiveC: Add support for printing ObjectiveC object via a '(objc)' pretext. * Registers: Fix bug handling register names of "" in gdb's register list. ## [2.5] - 2024-12-24 * Console now supports a subset of ANSI color codes. * Console can be started in these modes: - Detached - Detached and minimized - Attached in Seer's tab view (with gdb logs and seer logs). * Improved handling of \n \t and other escaped characters in gdb log window. * Show breakpoint info as a tooltip if the breakpoint icon is clicked with LMB and held down. * Show stack as a hex dump, with options to view as short, int, long, ascii, ... * The "go to address" in the Assembly view now works if address it outside current assembly view. * Visualizers can take a gdb expression for input fields for length/size of something. The visualizers are: - ArrayVisualizer - ImageVisualizer - MemoryVisualizer * Fixed regression when setting/saving the editor font setting. * Fixed bug when the Basic Struct visualizer display simple variable types (non-structs). * Source all files in ~/.config/seergdb/scripts/ on startup. * Fixed regression handling ignoring of system header files. * Fixed regression when adding commands to a breakpoint. * Refactored/improved Printpoints. Added 'help' to the Printpoint create dialog. * Fixed regression when display variable value when hovering over the text in the editor window. ## [2.4] - 2024-03-18 * Changed main icon to a more license friendly one. All icons are now GPLv3, CC3.0, or CC4.0 * Fixed string compares for breakpoint conditions (#184) * Added '--bs' command line option to specify a breakpoint at a source.cpp:lineno * Fixed long tooltips text by restricting them to 100 characters. (#189) The text in the various viewing dialogs is still the full length. The 100 limit probably needs to be configurable. * Added register profiles to show only interesting/relevant registers. * Added UTF-8,16,32 support in the Memory Visualizer. * Added an internal "dark" and "light" theme via the View->Style menu. * Added option to open the current source file in an external editor. * Fixed saving of RR parameters in config dialog. * Sped up some visualization views. ## [2.3] - 2023-11-19 * In the margins of the source windows, allow CTRL+DoubleClick to do a quick RunToLine or RunToAddress. * Add --gdb-program and --gdb-arguments to command line to override settings from Seer's config. * Fixed a rare bug with blank lines from gdb causing a segv in GdbMonitor. * Fixed bug specifying path to "rr" debugger. * Add option to reload source file if it changes. * Tighten up the layout by removing some needless whitespace. * Move gdb messages to a tab in the breakpoints window. - Options to raise on every message, never, or important messages. * Add C++ level (11 or 17) depending on qt5 or qt6 compile. * Fixed up column resizing for the Variable logger (#173) * Use monspace font, where it makes sense (#175) * Allow copy to clipboard (#176) * Fixed hovering a variable name and value (#179) * Add nested struct viewing in "locals", "arguments", "logger", and "tracker" tabs. (#180) ## [2.2] - 2023-09-07 * Fixed infinite loop when starting with RR mode. * Reworked RR mode to directly run 'rr replay'. No need to start a 'rr server' and connect to it. https://github.com/epasveer/seer/wiki/RR-and-Seer * Fixed Source handling in source browser. Qt5 mode was broken. Qt6 works. Directory paths need a tailing "/*" ## [2.1] - 2023-08-23 * Add Execution dialog to record breakpoint events. This solves the problem of too many break/error dialogs to "swat away" as the program is debugged. * Add a method to add/change gdb commands to execute when a breakpoint (breakpoint, watchpoint, catchpoint) is reached. * Add a method to add/change a breakpoint's condition command. * Add a method to add/change a breakpoint's ignore count. * Add a method to add/change a breakpoint's command list. * Debug dialog for "attach" mode now detects executable name and path from /proc//exe. * Commandline for "attach" mode now detects executable name and path from /proc//exe. ## [2.0] - 2023-03-06 * Seer is Qt6 based. Still compiles with Qt5. * See Seer's Wiki page for compile instructions. https://github.com/epasveer/seer/wiki ## [1.17] - 2023-04-23 * Add support for the RR debugger. https://github.com/epasveer/seer/wiki/RR-and-Seer * Add a dialog when a breakpoint is reached. ## [1.16] - 2023-04-07 * Add pid to main window and console title bars. * The Pending flag is automatically supplied to the breakpoint function in the Debug dialog for the Run mode. Some apps use deferred loading of code with dlopen(). * Fixed bug when restoring from project file with 'start' mode. * ADA: Improve visualizers for Ada arrays. "(system.address) 0x7fffffffcf10" * ADA: Add Ada task browser. * ADA: Add Ada specific catchpoints. * ADA: Add Ada exception brower. * Add a Shortcut (CTRL-I) to interrupt the running program. ## [1.15] - 2023-03-04 * Revamp Debug dialog. Move debug modes into "tabs". * Add "help" icon to each debug mode in Debug dialog. * Add 'pre' and 'post' gdb commands that can be executed just before and just after the program is loaded into gdb. * Add the concept of 'project' files that can be created and loaded. Project files contain all settings available in the Debug dialog. * Assembly view can now be shown in 2 modes. See "Settings->Configure->Assembly" - Function. The view shows all assembly in the function the $PC is in. - Length. The view shows N bytes of assembly after the $PC. Used for code that is pure assembly or has no debug information. * Minor fixes when debugging corefiles. * Fixed breakpoints with conditional statements. * Fixed up icons and Debian "copyright" file for Debian Intent-To-Package. * Double-clicking on a breakpoint in the source window will delete it. Previously it would disable it. * Assembly Tab - show only Nexti and Stepi buttons. Source tabs - show only Next and Step buttons. * Hide certains buttons (Run, Start, ...) depending on Debug mode (run, attach, connect, etc...) * Save state of tabs (tab order and current tab). So next session will get them. ## [1.14] - 2023-01-02 * Happy New Year! * Add 'tabsize' property to Source Editors to properly display source files containing tab characters. Default is 4. Can be changed by the Editor config page. * Fixed '\t' character returned by some flavors of gdb that display the disassembly. * Remove whitespace from C/C++ lines in the Assembly tab. * Allow assembly code to have its own font format. See Config->Editor->AssemblyText. * Add Nexti and Stepi toolbar buttons if Assembly tab is shown. * Add PC, SP, FLAGS status bar to Assembly tab. * Re-added the original struct visualizers as "Basic Struct Visualizer". The advanced version is called "Struct Visualizer". * Moved selection of visualizers into a sub menu called "Visualizers" on the menu bar. * Added alternate file to load symbols from (instead of the debugee executable. ## [1.13] - 2022-12-02 * Improve specifying an alternate directory if the source has moved. Fewer mouse clicks. * Add new Image Visualizer. - View RGB888 and RGBA8888 images. * Assembly Tab can show source lines along with assembly. * Add CRC16 checksum to Memory Visualizer. * Add help for the main window's tab bar. ## [1.12] - 2022-10-22 * Added Gdb's Reverse Debugging mode. - Turn on/off gdb instruction recording. - Set play-back direction. * Added Gdb's Non-Stop mode. - https://sourceware.org/gdb/onlinedocs/gdb/Non_002dStop-Mode.html - A new --non-stop-mode command line flag - A new entry in the Debug dialog. - A new entry in Seer's config dialog under the gdb section. * Added support for the older QT5.12 library. - Expect rendering problems with the builtin help system. - Urge to move to QT5.15 library. * Main execute buttons. - Add '--all threads' for main execute buttons. - run/start/next/step/finish/continue/interrupt. - Individual threads can be managed by the Thread Manager. * Thread Manager changes. - Thread Frame browser. - Allow multiple threads to be select. Selecting 1 thread will select stack frame. - Add next/step/finish/continue/interrupt for selected thread(s). - Thread Id browser. - Allow multiple threads to be select. Selecting 1 thread will select stack frame. - Add next/step/finish/continue/interrupt for selected thread(s). - Thread Group browser. - Allow multiple thread groups to be select. - Add continue/interrupt for selected thread group(s). - Add run/start for selected thread group(s). Disabled for now. * Assembly view changes. - Showing Address, Offset, and Opcodes columns are configuable from the Config Dialog. - ^F in the Assembly editor can do quick changes. * Changing the Qt Style can be saved using Settings->Save Configuration. * Added valgrind support. - https://github.com/epasveer/seer/wiki/Valgrind-and-Seer. ## [1.11] - 2022-09-26 * Thread/Process manager. - Add a fork/vfork mode. Follow: - Parent process. - Child process. - Both (switchable via thread manager) - (see gdb's follow-fork-mode and detach-on-fork modes) - Add thread execution mode. Execute: - Selected thread only. - All threads - (see gdb's scheduler-locking mode) - Add multi-process execution mode. - Execute selected process. - Execute all processes. - (see gdb's schedule-multiple mode) * Add Help to Thread/Process browser. * Add Help to Stack Frame browser. * Add Help to Variable/Register browser. * Add Help to Source/Symbol/Library browser. * Add Help to Struct Visualizer. * Add Help to Memory Visualizer. * Add Help to Array Visualizer. * Add Help to Code Manager. * Add Help to Breakpoint/Gdb log Manager. * Add RMB menu to progress indicator to select indicator type. ## [1.10] - 2022-09-22 * New Struct Visualizer. - Built apon gdb's -var-obj framework. - Can recursively show the contents of a struct/class. - Show datatype of each member. (Value or pointer) - Can modify values of simple datatypes. * Improve Source Browsing. - See new options in 'Source' config page. - Ignore opening files from a list of directories. Like system directories that don't exist. - Better sorting of program's files into "Source", "Header", and "Misc" folders in the SourceBrowser by having a list of filename patterns for each folder. * The list of C/C++ file suffixes for syntax highlighting is configurable. * Changed to CreativeCommons and GPLv3 icons. - Friendlier license to use icons. - Breeze Icon set for most things. (GPLv3) - Icons from these sites that require CreativeCommon license. (Simple attribution). icon-icons.com thenounproject.com ## [1.9] - 2022-08-30 * Rename 'seer' binary to 'seergdb'. The name conflicts with another opensource project. * Prepare for better Debian (and other distros) packaging and releasing. * Add history (up/down arrows) to all line input fields. - Variable logger, tracker browsers. - Source, function, types, statics, library browsers. - Struct, memory, array visualizers. - Code and assembly editors. - Console. * Add StructVisualizer to source/assembly editors and stack arguments/locals browsers. * Add a RMB to launch Memory/Array/Struct viewer from a running Struct viewer. * Change 'detachtab' to use RMB context menu instead of a double-click. * Allow filenames with spaces when setting breakpoints. ## [1.8] - 2022-08-08 * Add StructVisualizer - New visualizer to view the contents of a C/C++ struct or a C++ class in a tree. - Click on the "StructVisualizer" in the menubar or "View -> Struct Visualizer". - Enter the name of the variable in the text section. - examples: "*this" "mystruct" "mystruct.member" - The variable text section has a history. So you can use the UP and DOWN arrows to select previous entries. - Manually refresh the view or click on "Auto" to refresh the view at each stopping point (after a step/next/breakpoint). * Add Dark theme option for Seer's code editor. Set in Seer config page. - Works for C/C++ source tabs and the assembly tab. * Register browser. - Can now edit register values. - Either by double-clicking the register value or by RMB context menu to bring up a dialog. - Add format selector for register values. - Improve detection of changed register values from previous stopping point. * Assembly support. - Add assembly config page for certain assembly settings. - assembly style - C++ symbol demangling. - Keep assembly tab on top. - Show assembly tab on Seer startup. - Launch MemoryVisualizer and ArrayVisualizer from the Assembly tab on highlighter text. * Debug options for launching program. - No break on program start. - Break in "main". - Break in function. - Break at address. - Randomize program's start address. * ArrayVisualizer and MemoryVisualizer now allow an address as the variable name. * A menu to experiment setting Seer with different Qt gui styles. - See "View -> Styles" * Bugs fixes. - Fixed double refresh bug in code editor. - Fixed bug when displaying assembly for the first time. It wasn't showing the current line. - Fixed background color problem in MemoryVisualizer for disassembly. ## [1.7] - 2022-07-04 * Add an assembly tab, along side the source tabs in the Code Manager. - Shows the program's assembly. - Enable with "View -> Assembly View" - Can set and show breakpoints. - Highlight the current instruction. - Step by instruction (Nexti and Stepi). - Double-clicking on entries in the "Breakpoints" tab and the "Stack frames" tab will show the assembly for those addresses. - ^F to bring up search bar in Assembly tab. * Fix some minor bugs. seer-2.7/CONTRIBUTING.md000066400000000000000000000001771516472651200145670ustar00rootroot00000000000000Contributions are welcomed as a Pull Request. Features and bug reports as GitHub issues or a simple email to epasveer@att.net. seer-2.7/LICENSE000066400000000000000000001045151516472651200133440ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . seer-2.7/README.md000066400000000000000000000223431516472651200136140ustar00rootroot00000000000000Introduction ============ Seer - a gui frontend to gdb for Linux. (Ernie Pasveer epasveer@att.net) This project is actively worked on. The aim is a simple, yet pleasing gui to gdb. Please report any bugs or desired features to my email or create a [task](https://github.com/epasveer/seer/issues) in my GitHub project page. Installation ============ Seer can be installed either from a package manager or from source. > [!NOTE] > Make sure the requirements are met before installing. Requirements --------- * Linux * C++17 * gdb with "mi" interpreter (check by running: `gdb --interpreter=mi`) * CMake (3.5.0 or newer) * QT6 * When building Seer from source, you will need the QT6 "devel" packages installed on your system for your distribution. * Core * Gui * Widgets * PrintSupport * Charts * Svg * Qt6 build instructions are here: https://github.com/epasveer/seer/wiki/Building-Seer---Qt6 * QT5 * **Seer no longer compiles with Qt5.** The 2.3 source tree is the last one that does. * Qt5 build instructions are here: https://github.com/epasveer/seer/wiki/Building-Seer---Qt5 Install from package --------- Available through the following package managers: ### Pamac (Manjaro) $ pamac install seer ### zypper (openSUSE Tumbleweed) $ zypper install seergdb ### Flathub Flathub website. [Here](https://flathub.org/en/apps/io.github.epasveer.seer) $ flatpak install flathub io.github.epasveer.seer ### Flatpak Beta Seer versions. [Seer's release page](https://github.com/epasveer/seer/releases/tag/flatpak-latest) on github. **Important**: `flatpak-spawn --host`, needed in `GDB Launcher` to run gdb. See https://github.com/epasveer/seer/issues/377#issuecomment-3620844808. Download ```seer.flatpak```. Install it: $ flatpak install -y --bundle --user seer.flatpak Install from source --------- (Recommended) Seer can be built with Qt6 by following the instructions below. https://github.com/epasveer/seer/wiki/Building-Seer---Qt6 It can still be built with Qt5, for the time being by following the instructions below. https://github.com/epasveer/seer/wiki/Building-Seer---Qt5 NEWS ==== Check out [Seer's Wiki page](https://github.com/epasveer/seer/wiki) on github. * Version v1.17 will be the last Qt5 release. * The next release will be v2.0 and will be Qt6 based. However, for the time being, it's still able to be compiled with Qt5. * If you want the latest stable Qt5 source, grab v1.17 from here: https://github.com/epasveer/seer/releases/tag/v1.17 Starting Seer ============= Seer is meant to easily start the program to debug from the command line. gdb has multiple methods for debugging a program. So Seer naturally does too. Go to the Wiki to see all the ways to run Seer. https://github.com/epasveer/seer/wiki/Starting-Seer GUI overview ============ Examples of the various Seer views and dialogs. Main View --------- The main view for Seer looks like this: ![](images/mainview.png) * Source/Function/Types/Variables/Libraries * The list of source/header files that were used in the program. * Search for Functions, Types, and Static Variables. Dobule clicking will open the source file. * The list of shared libraries referenced by the program. * The list of source/header files can be searched. This will "shrink" the list of files shown. * Double clicking on a file will open it in the Code Manager. * Variable/Register Info * Show variable and register values. * "Logger" - log the value of a variable. Manually enter it or double click on the variable in the file that is opened in the code manager. * "Tracker" - create a list of variables to show the value for whenever gdb reaches a stopping point (step, next, finish, etc.). When the stopping point is reached, all variables in the list will show their potentially new value. * "Registers" - show the values of all cpu registers. * Code Manager. * The large area of the middle part of the Seer gui. * Source files are opened in this view. * Text in a file can be seached for with ^F. * Variables can be added to the "Logger" by double clicking the variable name. Double click with CTLR key pressed will prepend variable with "*". Double click with SHIFT key pressed will prepend variable with "&". Double click with CTRL+SHIFT key pressed will prepend variable with "*&". * Variables can be added to the "Tracker" by selecting the variable name and RMB and select "Add variable to Tracker". * Variables can be added to the "Memory Visualizer" by selecting the variable name and RMB and select "Add variable to Memory Visualizer". * A breakpoint/printpoint can be created by RMB on a specific line. * Can execute to a specific line by RMB on a specific line. * Tabs in this view can be detached by double-clicking a tab. * Breakpoints, Watchpoints, Catchpoints, Printpoints, manual gdb commands, and logs. * The area below the Code Manager. * Manual commands. Manually enter a gdb or gdbmi command. The commands are remembered for the next Seer use. * Breakpoint manager. Create and manage breakpoints. * Watchpoint manager. Create and manage watchpoints. A watchpoint monitors when a variable is accessed (read, write, read/write). * Catchpoint manager. Create and manage catchpoints. A catchpoint stops execution on a C++ throw/rethrow/catch call. * Printpoint manager. Create and manage printpoints. A printpoint is like a breakpoint but it allows you to print variables at that printpoint. See gdb's 'dprintf' call. * GDB output. A log of any output from the gdb program itself. * Seer output. A log of any output from the Seer program itself. As diagnostics. * Tabs in this view can be detached by double-clicking a tab. * Stack frame information. * Stack frame list. A frame can be double clicked to change the scope (the current function). * Stack frame arguments. For each frame, print the arguments passed to each function. * Stack locals. For the current function, print the values of the local variables. * Thread information. * Thread ids. A list of all threads. Double click on a thread id to change the scope (the current thread). * Thread frames. For each thread, list its stack frames. * Supports Gdb's Reverse Debugging mode. * Turn instruction recording on or off. * Set playback direction to forward or reverse. Open Dialog ----------- When the open executable dialog is invoked, it looks like this: ![](images/opendialog.png) Seer Console ------------ All text output from the executable will go to the Seer console. Text input for the executable can be entered via the console too. ![](images/console.png) Assembly View ------------- Normally Seer will just show the source code as tabs in the Code Manager. The program's assembly can also be show as a tab. Select "View->Assembly View" and an extra tab will be shown alongside the source code tabs that shows the current assembly being executed. Here is an example. ![](images/mainview_assemby.png ) Like the source code tabs, breakpoints can be set in the assembly tab. The current instruction is highlighted. Double-clicking on entries in the "Breakpoints" tab and the "Stack frames" tab will show the assembly for those addresses. There are "Nexti" and "Stepi" hot-keys, as defined by your config settings. Normally "Ctrl+F5" and "CTRL+F6". Using "^F" in the assembly tab will show a powerful search bar. **The assembly feature in Seer is new. Feel free to suggest changes/features.** Memory Visualizer ----------------- When looking at the contents of raw memory in the Memory Visualizer, it looks like this : Memory | Disassembly --- | --- ![](images/memoryvisualizer.png) | ![](images/memoryvisualizer_asm.png) Array Visualizer ----------------- When looking at the contents of arrays in the Array Visualizer, it looks like this : Normal | Spline | Scatter --- | --- | --- ![](images/arrayvisualizer.png) | ![](images/arrayvisualizer_spline.png) | ![](images/arrayvisualizer_scatter.png) Two arrays can be used as an X-Y plot. For example, this simple 'points' array forms the X-Y outline of a shape. ``` int main() { int points[] = {50,1,20,91,97,35,2,35,79,91,50,1}; return 0; } ``` X values | Y values | XY Values --- | --- | --- ![](images/arrayvisualizer_x.png) | ![](images/arrayvisualizer_y.png) | ![](images/arrayvisualizer_xy.png) Struct Visualizer ----------------- When looking at the contents of a C/C++ struct or a C++ class in the Struct Visualizer, it looks like this. This example shows the contents of "*this" for the current C++ class that Seer is in. All structure members that are basic types can be edited. ![](images/structvisualizer.png) There is also a **Basic Struct Visualizer** that is more light weight, but can not follow pointers and can not be edited. Image Visualizer ----------------- When looking at the contents of raw memory that is an image, the Image Visualizer can be used. ![](images/imagevisualizer.png) Support/Contact =============== Send an email to epasveer@att.net for any bugs or features. Or create a [task](https://github.com/epasveer/seer/issues) in my GitHub project page. Stargazers ========== It's a wonderful world. ![](images/stargazer-map.svg) seer-2.7/src/000077500000000000000000000000001516472651200131205ustar00rootroot00000000000000seer-2.7/src/CMakeLists.txt000066400000000000000000000273351516472651200156720ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.10.0) project(seergdb VERSION 2.7 LANGUAGES CXX) set(PROJECT_NAME seergdb) if(NOT DEFINED QTVERSION) set(QTVERSION "QT6" CACHE STRING "" FORCE) endif() if(${QTVERSION} STREQUAL "QT6") message("-- Compile with QT6") elseif(${QTVERSION} STREQUAL "QT5") message("-- Compile with QT5") else() message(FATAL_ERROR "-- Use -DQTVERSION=QT5|QT6 not \"${QTVERSION}\"") endif() # Find includes in the build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_PREFIX_PATH ${QTDIR}) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) if(${QTVERSION} STREQUAL "QT6") find_package(Qt6 COMPONENTS REQUIRED Core) find_package(Qt6 COMPONENTS REQUIRED Gui) find_package(Qt6 COMPONENTS REQUIRED Widgets) find_package(Qt6 COMPONENTS REQUIRED PrintSupport) find_package(Qt6 COMPONENTS REQUIRED Charts) find_package(Qt6 COMPONENTS REQUIRED Svg) find_package(Qt6 COMPONENTS REQUIRED OpenGL) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) elseif(${QTVERSION} STREQUAL "QT5") find_package(Qt5 COMPONENTS REQUIRED Core) find_package(Qt5 COMPONENTS REQUIRED Gui) find_package(Qt5 COMPONENTS REQUIRED Widgets) find_package(Qt5 COMPONENTS REQUIRED PrintSupport) find_package(Qt5 COMPONENTS REQUIRED Charts) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) endif() # Define the source location of header files set(HEADER_FILES GdbMonitor.h QProcessInfo.h QProcessInfoWidget.h QProgressIndicator.h QColorButton.h QColorSwatch.h QDetachTabWidget.h QZoomChartView.h QZoomChart.h QClearLineEdit.h QIndexTreeWidget.h QStringPair.h QHistoryLineEdit.h QEditDelegate.h QHContainerWidget.h QImageViewer.h QAnsiTextEdit.h SeerUtl.h SeerArgumentsDialog.h SeerBreakpointCreateDialog.h SeerMessagesBrowserWidget.h SeerBreakpointsBrowserWidget.h SeerCatchpointCreateDialog.h SeerCatchpointsBrowserWidget.h SeerPrintpointCreateDialog.h SeerPrintpointsBrowserWidget.h SeerCheckpointsBrowserWidget.h SeerCommandLogsWidget.h SeerSeerLogWidget.h SeerConsoleWidget.h SeerConfigDialog.h SeerGdbConfigPage.h SeerRRConfigPage.h SeerEditorConfigPage.h SeerSourceConfigPage.h SeerAssemblyConfigPage.h SeerSeerConfigPage.h SeerKeysConfigPage.h SeerCloseSourceDialog.h SeerDebugDialog.h SeerDirectoryFilterProxyModel.h SeerEditorManagerEntry.h SeerEditorManagerWidget.h SeerEditorWidgetSource.h SeerEditorWidgetAssembly.h SeerExecutableFilterProxyModel.h SeerGdbWidget.h SeerHexWidget.h SeerAsmWidget.h SeerArrayWidget.h SeerMarixWidget.h SeerLogWidget.h SeerMainWindow.h SeerArrayVisualizerWidget.h SeerMatrixVisualizerWidget.h SeerMemoryVisualizerWidget.h SeerStructVisualizerWidget.h SeerVarVisualizerWidget.h SeerImageVisualizerWidget.h SeerRegisterValuesBrowserWidget.h SeerRegisterEditValueDialog.h SeerRegisterProfileDialog.h SeerRegisterTreeWidgetItem.h SeerSignalValuesBrowserWidget.h SeerSignalProfileDialog.h SeerSignalEditValueDialog.h SeerRunStatusIndicator.h SeerLibraryBrowserWidget.h SeerSourceBrowserWidget.h SeerFunctionBrowserWidget.h SeerTypeBrowserWidget.h SeerStaticBrowserWidget.h SeerSkipBrowserWidget.h SeerSkipCreateDialog.h SeerSourceSymbolLibraryManagerWidget.h SeerStackArgumentsBrowserWidget.h SeerStackFramesBrowserWidget.h SeerStackLocalsBrowserWidget.h SeerStackDumpBrowserWidget.h SeerStackDumpSettingsDialog.h SeerStackManagerWidget.h SeerThreadFramesBrowserWidget.h SeerThreadIdsBrowserWidget.h SeerThreadGroupsBrowserWidget.h SeerAdaTasksBrowserWidget.h SeerAdaExceptionsBrowserWidget.h SeerThreadManagerWidget.h SeerGdbLogWidget.h SeerTildeLogWidget.h SeerVariableLoggerBrowserWidget.h SeerVariableManagerWidget.h SeerVariableTrackerBrowserWidget.h SeerWatchpointCreateDialog.h SeerWatchpointsBrowserWidget.h SeerSourceHighlighter.h SeerCppSourceHighlighter.h SeerOdinSourceHighlighter.h SeerRustSourceHighlighter.h SeerAboutDialog.h SeerSlashProcDialog.h SeerHighlighterSettings.h SeerKeySettings.h SeerPlainTextEdit.h SeerHelpPageDialog.h SeerProgressIndicator.h SeerMessagesDialog.h SeerAssemblyPreferenceDialog.h SeerHistoryLineEdit.h SeerMacroEditorDialog.h SeerMacroToolButton.h ) # Define the source location of source files set(SOURCE_FILES GdbMonitor.cpp QProcessInfo.cpp QProcessInfoWidget.cpp QProgressIndicator.cpp QColorButton.cpp QColorSwatch.cpp QDetachTabWidget.cpp QZoomChartView.cpp QZoomChart.cpp QClearLineEdit.cpp QIndexTreeWidget.cpp QHistoryLineEdit.cpp QEditDelegate.cpp QHContainerWidget.cpp QImageViewer.cpp QAnsiTextEdit.cpp SeerUtl.cpp SeerArgumentsDialog.cpp SeerBreakpointCreateDialog.cpp SeerMessagesBrowserWidget.cpp SeerBreakpointsBrowserWidget.cpp SeerCatchpointCreateDialog.cpp SeerCatchpointsBrowserWidget.cpp SeerPrintpointCreateDialog.cpp SeerPrintpointsBrowserWidget.cpp SeerCheckpointsBrowserWidget.cpp SeerCommandLogsWidget.cpp SeerSeerLogWidget.cpp SeerConsoleWidget.cpp SeerConfigDialog.cpp SeerGdbConfigPage.cpp SeerRRConfigPage.cpp SeerEditorConfigPage.cpp SeerSourceConfigPage.cpp SeerAssemblyConfigPage.cpp SeerSeerConfigPage.cpp SeerKeysConfigPage.cpp SeerCloseSourceDialog.cpp SeerDebugDialog.cpp SeerEditorManagerWidget.cpp SeerEditorWidgetSource.cpp SeerEditorWidgetSourceAreas.cpp SeerEditorWidgetAssembly.cpp SeerEditorWidgetAssemblyAreas.cpp SeerGdbWidget.cpp SeerHexWidget.cpp SeerAsmWidget.cpp SeerArrayWidget.cpp SeerMatrixWidget.cpp SeerLogWidget.cpp SeerMainWindow.cpp SeerArrayVisualizerWidget.cpp SeerMatrixVisualizerWidget.cpp SeerMemoryVisualizerWidget.cpp SeerStructVisualizerWidget.cpp SeerVarVisualizerWidget.cpp SeerImageVisualizerWidget.cpp SeerRegisterValuesBrowserWidget.cpp SeerRegisterEditValueDialog.cpp SeerRegisterProfileDialog.cpp SeerRegisterTreeWidgetItem.cpp SeerSignalValuesBrowserWidget.cpp SeerSignalProfileDialog.cpp SeerSignalEditValueDialog.cpp SeerRunStatusIndicator.cpp SeerLibraryBrowserWidget.cpp SeerSourceBrowserWidget.cpp SeerFunctionBrowserWidget.cpp SeerTypeBrowserWidget.cpp SeerStaticBrowserWidget.cpp SeerSkipBrowserWidget.cpp SeerSkipCreateDialog.cpp SeerSourceSymbolLibraryManagerWidget.cpp SeerStackArgumentsBrowserWidget.cpp SeerStackFramesBrowserWidget.cpp SeerStackLocalsBrowserWidget.cpp SeerStackDumpBrowserWidget.cpp SeerStackDumpSettingsDialog.cpp SeerStackManagerWidget.cpp SeerThreadFramesBrowserWidget.cpp SeerThreadIdsBrowserWidget.cpp SeerThreadGroupsBrowserWidget.cpp SeerAdaTasksBrowserWidget.cpp SeerAdaExceptionsBrowserWidget.cpp SeerThreadManagerWidget.cpp SeerGdbLogWidget.cpp SeerTildeLogWidget.cpp SeerVariableLoggerBrowserWidget.cpp SeerVariableManagerWidget.cpp SeerVariableTrackerBrowserWidget.cpp SeerWatchpointCreateDialog.cpp SeerWatchpointsBrowserWidget.cpp SeerSourceHighlighter.cpp SeerCppSourceHighlighter.cpp SeerOdinSourceHighlighter.cpp SeerRustSourceHighlighter.cpp SeerAboutDialog.cpp SeerSlashProcDialog.cpp SeerHighlighterSettings.cpp SeerKeySettings.cpp SeerPlainTextEdit.cpp SeerHelpPageDialog.cpp SeerProgressIndicator.cpp SeerMessagesDialog.cpp SeerAssemblyPreferenceDialog.cpp SeerHistoryLineEdit.cpp SeerMacroEditorDialog.cpp SeerMacroToolButton.cpp seergdb.cpp ) if(${QTVERSION} STREQUAL "QT6") qt6_add_resources(SOURCE_FILES resource.qrc resources/qdarkstyle/dark/darkstyle.qrc resources/qdarkstyle/light/lightstyle.qrc) elseif(${QTVERSION} STREQUAL "QT5") qt5_add_resources(SOURCE_FILES resource.qrc resources/qdarkstyle/dark/darkstyle.qrc resources/qdarkstyle/light/lightstyle.qrc) endif() # Set non-Debug build as GUI application. # Debug build remains consle application. if(NOT CMAKE_BUILD_TYPE MATCHES Debug) #Release, RelWithDebInfo and MinSizeRel if(WIN32) # Check if we are on Windows set(SYSTEM_TYPE WIN32) endif() message("-- System type is " ${SYSTEM_TYPE}) endif() # for Linux, BSD, Solaris, Minix if(UNIX AND NOT APPLE) add_compile_options(-Wall -Wextra -Wunused-result -pedantic) # -Werror -Wdeprecated-copy endif() add_definitions(-DQT_DISABLE_DEPRECATED_UP_TO=0x060300) add_executable(${PROJECT_NAME} ${SYSTEM_TYPE} ${SOURCE_FILES}) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) if(${QTVERSION} STREQUAL "QT6") target_link_libraries(${PROJECT_NAME} Qt6::Widgets Qt6::Gui Qt6::Core Qt6::PrintSupport Qt6::Charts Qt6::Svg Qt6::OpenGL) elseif(${QTVERSION} STREQUAL "QT5") target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::Gui Qt5::Core Qt5::PrintSupport Qt5::Charts) endif() # Handle gdb logout debugging. Turn CONFIG_SEER_GDB_LOGOUT=1 to enable gdb logout # -DCONFIG_SEER_GDB_LOGOUT=1 if(NOT DEFINED CONFIG_SEER_GDB_LOGOUT) set(CONFIG_SEER_GDB_LOGOUT 0) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE SEER_GDB_LOGOUT=${CONFIG_SEER_GDB_LOGOUT} ) # Handle default gdb binary name and location. # -DCONFIG_SEER_GDB_NAME=/app/bin/gdb if(NOT DEFINED CONFIG_SEER_GDB_NAME) set(CONFIG_SEER_GDB_NAME "/usr/bin/gdb") endif() target_compile_definitions(${PROJECT_NAME} PRIVATE SEER_GDB_NAME=${CONFIG_SEER_GDB_NAME} ) # Handle default gdb binary launcher (for flatpak, et al) # -DCONFIG_SEER_GDB_LAUNCHER="flatpak-spawn --host" if(NOT DEFINED CONFIG_SEER_GDB_LAUNCHER) set(CONFIG_SEER_GDB_LAUNCHER "") endif() target_compile_definitions(${PROJECT_NAME} PRIVATE SEER_GDB_LAUNCHER=${CONFIG_SEER_GDB_LAUNCHER} ) # Install icons to standard XDG icon directories # -DCONFIG_SEER_INSTALL_ICONS=1 if(CONFIG_SEER_INSTALL_ICONS) message("-- Will install icons to system") install(FILES "${CMAKE_SOURCE_DIR}/resources/icons/hicolor/32x32/seergdb.png" DESTINATION "share/icons/hicolor/32x32/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/icons/hicolor/64x64/seergdb.png" DESTINATION "share/icons/hicolor/64x64/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/icons/hicolor/128x128/seergdb.png" DESTINATION "share/icons/hicolor/128x128/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/icons/hicolor/256x256/seergdb.png" DESTINATION "share/icons/hicolor/256x256/apps") endif() # Install flathub icons to standard XDG icon directories # -DCONFIG_SEER_INSTALL_FLATHUB_FILES=1 if(CONFIG_SEER_INSTALL_FLATHUB_FILES) message("-- Will install flathub icons+files to system") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/icons/hicolor/32x32/io.github.epasveer.seer.png" DESTINATION "share/icons/hicolor/32x32/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/icons/hicolor/64x64/io.github.epasveer.seer.png" DESTINATION "share/icons/hicolor/64x64/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/icons/hicolor/128x128/io.github.epasveer.seer.png" DESTINATION "share/icons/hicolor/128x128/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/icons/hicolor/256x256/io.github.epasveer.seer.png" DESTINATION "share/icons/hicolor/256x256/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/io.github.epasveer.seer.metainfo.xml" DESTINATION "share/metainfo") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/io.github.epasveer.seer.desktop" DESTINATION "share/applications") endif() seer-2.7/src/GdbMonitor.cpp000066400000000000000000000110661516472651200156740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "GdbMonitor.h" #include #include #include #include #include static QLoggingCategory LC("seer.gdbmonitor"); GdbMonitor::GdbMonitor (QObject* parent) : QObject(parent) { _process = 0; } GdbMonitor::~GdbMonitor () { } void GdbMonitor::handleErrorOccurred (QProcess::ProcessError error) { Q_UNUSED(error); qCDebug(LC) << error; qApp->exit(); } void GdbMonitor::handleFinished (int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode); Q_UNUSED(exitStatus); qCDebug(LC) << exitCode << exitStatus; qApp->exit(); } void GdbMonitor::handleReadyReadStandardError () { qCDebug(LC) << "Ready to read stderr"; QProcess* p = (QProcess*)sender(); // Read a line at a time. while (p->canReadLine()) { QByteArray buf = p->readLine(); // Chop off trailing RETURN character. if (buf[buf.size()-1] == '\n') { buf.chop(1); } // Convert to a string. QString text(buf); qCDebug(LC) << text; // Start broadcasting it around. emit allTextOutput(text); } } void GdbMonitor::handleReadyReadStandardOutput () { qCDebug(LC) << "Ready to read stdout"; QProcess* p = (QProcess*)sender(); // Read a line at a time. while (p->canReadLine()) { QByteArray buf = p->readLine(); // Chop off trailing RETURN character. if (buf[buf.size()-1] == '\n') { buf.chop(1); } if (buf.size() == 0) { // Ignore empty lines. continue; } // Convert to a string. QString text(buf); //qDebug() << "Read buffer" << buf.size() << (int)buf[buf.size()-1] << text; qCDebug(LC) << text; #if SEER_GDB_LOGOUT == 1 // Start broadcasting it around. For debugging emit allTextOutput("From GdbMonitor: " + text + "\n"); #endif if (text[0] == '~') { emit tildeTextOutput(text); }else if (text[0] == '=') { emit equalTextOutput(text); }else if (text[0] == '*') { emit astrixTextOutput(text); }else if (text[0] == '^') { emit caretTextOutput(text); }else if (text[0] == '&') { emit ampersandTextOutput(text); }else if (text[0] == '@') { emit atsignTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\~"))) { emit tildeTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\="))) { emit equalTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\*"))) { emit astrixTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\^"))) { emit caretTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\&"))) { emit ampersandTextOutput(text); }else{ emit textOutput(text); } } qCDebug(LC) << "Finished reading stdout"; } void GdbMonitor::handleTextOutput (QString text) { qCDebug(LC) << "Ready to handle text output"; qCDebug(LC) << text; emit allTextOutput(text); if (text[0] == '~') { emit tildeTextOutput(text); }else if (text[0] == '=') { emit equalTextOutput(text); }else if (text[0] == '*') { emit astrixTextOutput(text); }else if (text[0] == '^') { emit caretTextOutput(text); }else if (text[0] == '&') { emit ampersandTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\~"))) { emit tildeTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\="))) { emit equalTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\*"))) { emit astrixTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\^"))) { emit caretTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\&"))) { emit ampersandTextOutput(text); }else{ emit textOutput(text); } qCDebug(LC) << "Finished handling text output"; } void GdbMonitor::handleStarted() { qCDebug(LC); } void GdbMonitor::handleStateChanged(QProcess::ProcessState newState) { Q_UNUSED(newState); qCDebug(LC) << newState; } void GdbMonitor::setProcess (QProcess* process) { _process = process; } QProcess* GdbMonitor::process () { return _process; } seer-2.7/src/GdbMonitor.h000066400000000000000000000033321516472651200153360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #ifndef GdbMonitor_H #define GdbMonitor_H #include #include class GdbMonitor : public QObject { Q_OBJECT public: explicit GdbMonitor (QObject* parent = 0); virtual ~GdbMonitor (); void setProcess (QProcess* process); QProcess* process (); signals: void allTextOutput (const QString& text); void tildeTextOutput (const QString& text); void equalTextOutput (const QString& text); void astrixTextOutput (const QString& text); void caretTextOutput (const QString& text); void ampersandTextOutput (const QString& text); void atsignTextOutput (const QString& text); void textOutput (const QString& text); public slots: void handleErrorOccurred (QProcess::ProcessError error); void handleFinished (int exitCode, QProcess::ExitStatus exitStatus); void handleReadyReadStandardError (); void handleReadyReadStandardOutput (); void handleStarted (); void handleStateChanged (QProcess::ProcessState newState); void handleTextOutput (QString text); private: QProcess* _process; }; #endif seer-2.7/src/QAnsiTextEdit.cpp000066400000000000000000000350551516472651200163220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QAnsiTextEdit.h" #include // // // QAnsiTextEditFormattedText::QAnsiTextEditFormattedText(const QString& txt, const QTextCharFormat& fmt) { text = txt; format = fmt; } // // // QList QAnsiTextEditEscapeCodeHandler::parseText (const QAnsiTextEditFormattedText& input) { enum AnsiEscapeCodes { ResetFormat = 0, BoldText = 1, UnderLinedText = 4, TextColorStart = 30, TextColorEnd = 37, RgbTextColor = 38, DefaultTextColor = 39, BackgroundColorStart = 40, BackgroundColorEnd = 47, RgbBackgroundColor = 48, DefaultBackgroundColor = 49 }; const QString escape = "\x1b["; const QChar semicolon = ';'; const QChar colorTerminator = 'm'; const QChar eraseToEol = 'K'; QList outputData; QTextCharFormat charFormat = _previousFormatClosed ? input.format : _previousFormat; QString strippedText; if (_pendingText.isEmpty()) { strippedText = input.text; }else{ strippedText = _pendingText.append(input.text); _pendingText.clear(); } while (!strippedText.isEmpty()) { if (_waitingForTerminator) { // We ignore all escape codes taking string arguments. QString terminator = "\x1b\\"; int terminatorPos = strippedText.indexOf(terminator); if (terminatorPos == -1 && !_alternateTerminator.isEmpty()) { terminator = _alternateTerminator; terminatorPos = strippedText.indexOf(terminator); } if (terminatorPos == -1) { _pendingText = strippedText; break; } _waitingForTerminator = false; _alternateTerminator.clear(); strippedText.remove(0, terminatorPos + terminator.length()); if (strippedText.isEmpty()) { break; } } const int escapePos = strippedText.indexOf(escape.at(0)); if (escapePos < 0) { outputData << QAnsiTextEditFormattedText(strippedText, charFormat); break; }else if (escapePos != 0) { outputData << QAnsiTextEditFormattedText(strippedText.left(escapePos), charFormat); strippedText.remove(0, escapePos); } while (!strippedText.isEmpty() && escape.at(0) == strippedText.at(0)) { if (escape.startsWith(strippedText)) { // control secquence is not complete _pendingText += strippedText; strippedText.clear(); break; } if (!strippedText.startsWith(escape)) { switch (strippedText.at(1).toLatin1()) { case '\\': // Unexpected terminator sequence. Q_FALLTHROUGH(); case 'N': case 'O': // Ignore unsupported single-character sequences. strippedText.remove(0, 2); break; case ']': _alternateTerminator = QChar(7); Q_FALLTHROUGH(); case 'P': case 'X': case '^': case '_': strippedText.remove(0, 2); _waitingForTerminator = true; break; default: // not a control sequence _pendingText.clear(); outputData << QAnsiTextEditFormattedText(strippedText.left(1), charFormat); strippedText.remove(0, 1); continue; } break; } _pendingText += strippedText.mid(0, escape.length()); strippedText.remove(0, escape.length()); // \e[K is not supported. Just strip it. if (strippedText.startsWith(eraseToEol)) { _pendingText.clear(); strippedText.remove(0, 1); continue; } // get the number QString strNumber; QStringList numbers; while (!strippedText.isEmpty()) { if (strippedText.at(0).isDigit()) { strNumber += strippedText.at(0); }else{ if (!strNumber.isEmpty()) { numbers << strNumber; } if (strNumber.isEmpty() || strippedText.at(0) != semicolon) { break; } strNumber.clear(); } _pendingText += strippedText.mid(0, 1); strippedText.remove(0, 1); } if (strippedText.isEmpty()) { break; } // remove terminating char if (!strippedText.startsWith(colorTerminator)) { _pendingText.clear(); strippedText.remove(0, 1); break; } // got consistent control sequence, ok to clear pending text _pendingText.clear(); strippedText.remove(0, 1); if (numbers.isEmpty()) { charFormat = input.format; endFormatScope(); } for (int i = 0; i < numbers.size(); ++i) { const uint code = numbers.at(i).toUInt(); if (code >= TextColorStart && code <= TextColorEnd) { //qDebug() << "TextColorStart/TextColorEnd called"; charFormat.setForeground(ansiColor(code - TextColorStart)); setFormatScope(charFormat); }else if (code >= BackgroundColorStart && code <= BackgroundColorEnd) { //qDebug() << "BackgroundColorStart/BackgroundColorEnd called"; charFormat.setBackground(ansiColor(code - BackgroundColorStart)); setFormatScope(charFormat); }else{ switch (code) { case ResetFormat: //qDebug() << "ResetFormat called"; charFormat.setFontWeight(QFont::Normal); charFormat.setFontUnderline(false); charFormat.setForeground(input.format.foreground()); charFormat.setBackground(input.format.background()); setFormatScope(charFormat); endFormatScope(); break; case BoldText: //qDebug() << "BoldText called"; charFormat.setFontWeight(QFont::ExtraBold); setFormatScope(charFormat); break; case UnderLinedText: //qDebug() << "UnderLinedText called"; charFormat.setFontUnderline(true); setFormatScope(charFormat); break; case DefaultTextColor: //qDebug() << "DefaultTextColor called"; charFormat.setForeground(input.format.foreground()); setFormatScope(charFormat); break; case DefaultBackgroundColor: //qDebug() << "DefaultBackgroundColor called"; charFormat.setBackground(input.format.background()); setFormatScope(charFormat); break; case RgbTextColor: case RgbBackgroundColor: //qDebug() << "RgbTextColor/RgbBackgroundColor called"; // See http://en.wikipedia.org/wiki/ANSI_escape_code#Colors if (++i >= numbers.size()) { break; } switch (numbers.at(i).toInt()) { case 2: // RGB set with format: 38;2;;; if ((i + 3) < numbers.size()) { (code == RgbTextColor) ? charFormat.setForeground(QColor(numbers.at(i + 1).toInt(), numbers.at(i + 2).toInt(), numbers.at(i + 3).toInt())) : charFormat.setBackground(QColor(numbers.at(i + 1).toInt(), numbers.at(i + 2).toInt(), numbers.at(i + 3).toInt())); setFormatScope(charFormat); } i += 3; break; case 5: // 256 color mode with format: 38;5; uint index = numbers.at(i + 1).toUInt(); QColor color; if (index < 8) { // The first 8 colors are standard low-intensity ANSI colors. color = ansiColor(index); }else if (index < 16) { // The next 8 colors are standard high-intensity ANSI colors. color = ansiColor(index - 8).lighter(150); }else if (index < 232) { // The next 216 colors are a 6x6x6 RGB cube. uint o = index - 16; color = QColor((o / 36) * 51, ((o / 6) % 6) * 51, (o % 6) * 51); }else{ // The last 24 colors are a greyscale gradient. int grey = int((index - 232) * 11); color = QColor(grey, grey, grey); } if (code == RgbTextColor) { charFormat.setForeground(color); }else{ charFormat.setBackground(color); } setFormatScope(charFormat); ++i; break; } break; default: qDebug() << "Unkown code:" << code; break; } } } } } return outputData; } void QAnsiTextEditEscapeCodeHandler::endFormatScope () { _previousFormatClosed = true; } void QAnsiTextEditEscapeCodeHandler::setFormatScope (const QTextCharFormat& charFormat) { _previousFormat = charFormat; _previousFormatClosed = false; } QTextCharFormat QAnsiTextEditEscapeCodeHandler::formatScope () const { return _previousFormat; } QColor QAnsiTextEditEscapeCodeHandler::ansiColor(uint code) { const int red = code & 1 ? 170 : 0; const int green = code & 2 ? 170 : 0; const int blue = code & 4 ? 170 : 0; return QColor(red, green, blue); } // // // QAnsiTextEdit::QAnsiTextEdit (QWidget* parent) : QPlainTextEdit(parent) { } QAnsiTextEdit::QAnsiTextEdit (const QString& text, QWidget* parent) : QPlainTextEdit(parent) { setAnsiText(text); } QAnsiTextEdit::~QAnsiTextEdit () { } void QAnsiTextEdit::dumpCharFormat (QString string, QTextCharFormat format) { qDebug() << "dumpCharFormat" << string << "Font" << format.font().toString(); qDebug() << "dumpCharFormat" << string << "Color" << format.foreground().color(); qDebug() << "dumpCharFormat" << string << "FontWeight" << format.fontWeight(); qDebug() << "dumpCharFormat" << string << "UnderLined" << format.fontUnderline(); qDebug() << ""; } void QAnsiTextEdit::setAnsiText (const QString& text) { // Reset the text edit clear(); // Use append method. appendAnsiText(text); } void QAnsiTextEdit::appendAnsiText (const QString& text) { // // Use the 'append' method for the first sub text, then // the 'insert' method for every sub text after that. // // Save current TextCharFormat QTextCharFormat saveFormat = currentCharFormat(); // Create the default text object; QAnsiTextEditFormattedText ftext; ftext.text = text; ftext.format = currentCharFormat(); // Parse it. A list of sub text objects is created. QList ftexts = _escapeCodeHandler.parseText(ftext); // Print each sub text object. Each one has its own text format. bool first = true; for (const QAnsiTextEditFormattedText& ftext : ftexts) { QTextCharFormat format = ftext.format; setCurrentCharFormat(format); if (first) { appendPlainText(ftext.text); first = false; }else{ insertPlainText(ftext.text); } } // Restore current TextCharFormat setCurrentCharFormat(saveFormat); } void QAnsiTextEdit::insertAnsiText (const QString& text) { // // Use the 'insert' method for every sub text. // // Save current TextCharFormat QTextCharFormat saveFormat = currentCharFormat(); // Create the default text object; QAnsiTextEditFormattedText ftext; ftext.text = text; ftext.format = currentCharFormat(); // Parse it. A list of sub text objects is created. QList ftexts = _escapeCodeHandler.parseText(ftext); // Print each sub text object. Each one has its own text format. for (const QAnsiTextEditFormattedText& ftext : ftexts) { QTextCharFormat format = ftext.format; setCurrentCharFormat(format); insertPlainText(ftext.text); } // Restore current TextCharFormat setCurrentCharFormat(saveFormat); } seer-2.7/src/QAnsiTextEdit.h000066400000000000000000000037541516472651200157700ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include class QAnsiTextEditFormattedText { public: QAnsiTextEditFormattedText() = default; QAnsiTextEditFormattedText(const QString& txt, const QTextCharFormat& fmt = QTextCharFormat()); QString text; QTextCharFormat format; }; class QAnsiTextEditEscapeCodeHandler { public: QList parseText (const QAnsiTextEditFormattedText& input); void endFormatScope (); void setFormatScope (const QTextCharFormat& charFormat); QTextCharFormat formatScope () const; private: QColor ansiColor (uint code); bool _previousFormatClosed = true; bool _waitingForTerminator = false; QString _alternateTerminator; QTextCharFormat _previousFormat; QString _pendingText; }; class QAnsiTextEdit : public QPlainTextEdit { Q_OBJECT public: explicit QAnsiTextEdit(QWidget* parent = 0); explicit QAnsiTextEdit(const QString& text, QWidget* parent = 0); ~QAnsiTextEdit(); public: void dumpCharFormat (QString string, QTextCharFormat format); public slots: void setAnsiText (const QString& text); void appendAnsiText (const QString& text); void insertAnsiText (const QString& text); private: QAnsiTextEditEscapeCodeHandler _escapeCodeHandler; }; seer-2.7/src/QClearLineEdit.cpp000066400000000000000000000020271516472651200164120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QClearLineEdit.h" #include QClearLineEdit::QClearLineEdit (const QString& contents, QWidget* parent) : QLineEdit(contents, parent) { enableReturnPressedOnClear(); } QClearLineEdit::QClearLineEdit (QWidget* parent) : QLineEdit(parent) { enableReturnPressedOnClear(); } QClearLineEdit::~QClearLineEdit () { } void QClearLineEdit::enableReturnPressedOnClear() { for (int i=0; i (children().at(i))); if (myClearAction) { //qDebug() << myClearAction->objectName(); // Look for only the QLineEdit clear action. // This name could change or be different. if (myClearAction->objectName() == "_q_qlineeditclearaction") { connect(myClearAction, &QAction::triggered, this, &QLineEdit::returnPressed, Qt::QueuedConnection); } } } } seer-2.7/src/QClearLineEdit.h000066400000000000000000000007551516472651200160650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include class QClearLineEdit : public QLineEdit { public: QClearLineEdit (const QString& contents, QWidget* parent = nullptr); QClearLineEdit (QWidget* parent = nullptr); ~QClearLineEdit (); void enableReturnPressedOnClear (); public slots: protected: private: }; seer-2.7/src/QColorButton.cpp000066400000000000000000000022271516472651200162220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QColorButton.h" #include #include #include #include QColorButton::QColorButton(QWidget* parent) : QFrame(parent) { // Construct the UI. setupUi(this); setColor(palette().color(QPalette::Window)); } QColorButton::QColorButton(const QColor& color, QWidget* parent) : QFrame(parent) { // Construct the UI. setupUi(this); // Create color swatch setColor(color); } QColorButton::~QColorButton() { } void QColorButton::mouseDoubleClickEvent (QMouseEvent* e) { Q_UNUSED(e) // Open a color dialog if someone double-clicked. QColor c = QColorDialog::getColor(color(), this); if (c.isValid()) { setColor(c); } } QColor QColorButton::color () const { // Return the current color. return colorSwatch->color(); } void QColorButton::setColor (const QColor& color) { // Save the new color. colorSwatch->setColor(color); colorSwatch->update(); // Notify others that are listening. emit colorChanged(); } seer-2.7/src/QColorButton.h000066400000000000000000000014551516472651200156710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include "ui_QColorButton.h" class QColorButton : public QFrame, protected Ui::QColorButtonForm { Q_OBJECT public: QColorButton(QWidget* parent = 0); QColorButton(const QColor& color, QWidget* parent = 0); ~QColorButton(); void setColor (const QColor& color); QColor color () const; signals: void colorChanged (); protected: void mouseDoubleClickEvent (QMouseEvent* e); }; seer-2.7/src/QColorButton.ui000066400000000000000000000022651516472651200160570ustar00rootroot00000000000000 QColorButtonForm 0 0 400 300 Color Button QFrame::NoFrame QFrame::Plain 0 0 0 0 QColorSwatch QWidget
QColorSwatch.h
1
seer-2.7/src/QColorSwatch.cpp000066400000000000000000000014731516472651200162020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QColorSwatch.h" #include #include #include QColorSwatch::QColorSwatch(QWidget* parent) : QWidget(parent) { setColor(palette().color(QPalette::Window)); } QColorSwatch::QColorSwatch(const QColor& color, QWidget* parent) : QWidget(parent) { setColor(color); } QColorSwatch::~QColorSwatch() { } void QColorSwatch::setColor (const QColor& color) { _color = color; } QColor QColorSwatch::color () const { return _color; } void QColorSwatch::paintEvent(QPaintEvent* e) { Q_UNUSED(e) // Draw the color to the widget. QPainter painter(this); painter.setPen(Qt::NoPen); painter.setBrush(color()); painter.drawRect(rect()); } seer-2.7/src/QColorSwatch.h000066400000000000000000000012561516472651200156460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include class QColorSwatch : public QWidget { public: QColorSwatch(QWidget* parent = 0); QColorSwatch(const QColor& color, QWidget* parent = 0); ~QColorSwatch(); void setColor (const QColor& color); QColor color () const; protected: void paintEvent (QPaintEvent* e); private: QColor _color; }; seer-2.7/src/QDetachTabWidget.cpp000066400000000000000000000200021516472651200167220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QDetachTabWidget.h" #include #include #include #include #include #include #include #include QDetachTabWidget::QDetachTabWidget(QWidget* parent) : QTabWidget(parent) { tabBar()->setContextMenuPolicy(Qt::CustomContextMenu); QObject::connect(tabBar(), &QTabBar::customContextMenuRequested, this, &QDetachTabWidget::handleShowContextMenu); QObject::connect(this, &QTabWidget::tabCloseRequested, this, &QDetachTabWidget::handleTabClosedRequested); } bool QDetachTabWidget::isDetached (int tabIndex) const { // Get the tab the user selected. QWidget* w = widget(tabIndex); if (w == nullptr) { return false; } // If it's the 'placeholder' it is detached. if (w->objectName() == "QDetachTabWidgetPlaceholder") { return true; } // Otherwise, it's still attached. return false; } QWidget* QDetachTabWidget::tabWidget (int tabIndex) const { if (tabIndex < 0 || tabIndex > _tabInfo.size()) { return nullptr; } return _tabInfo[tabIndex]._widget; } void QDetachTabWidget::detachTab (int tabIndex, bool minimized) { // Get the tab the user selected. QWidget* w = widget(tabIndex); if (w == nullptr) { return; } // It can't be a 'placeholder' as it was already detached. if (w->objectName() == "QDetachTabWidgetPlaceholder") { return; } // Create a blank 'placeholder' tab. QDetachTabWidgetPlaceholder* placeholder = new QDetachTabWidgetPlaceholder(tabIndex); // Create an entry for the tab cache. Remember the real tab and the 'placeholder' tab. Plus the tab title. QDetachTabInfo tabinfo(tabText(tabIndex), w, placeholder); _tabInfo.append(tabinfo); // Remove the real tab. removeTab(tabIndex); // Insert the 'placeholder' in the same position. insertTab(tabIndex, placeholder, tabinfo._title); // Tweak the detached tab to make sure it can't be destroyed as it is now a normal window. w->setParent(0); Qt::WindowFlags flags = w->windowFlags(); Qt::WindowFlags closeFlag = Qt::WindowCloseButtonHint; flags = flags & (~closeFlag); w->setWindowFlags(flags); w->setWindowTitle(tabinfo._title); w->setWindowIcon(windowIcon()); if (minimized) { w->showMinimized(); }else{ w->showNormal(); } // Connect the placeholder's 'reattach' signal to the slot. QObject::connect(placeholder, &QDetachTabWidgetPlaceholder::reattach, this, &QDetachTabWidget::handleTabClosedRequested); // Notify listeners the tab was detached. emit tabDetached(tabIndex); emit tabDetached(w); } void QDetachTabWidget::reattachTab (int tabIndex) { // Get the tab the user selected to re-attach. QWidget* w = widget(tabIndex); if (w == nullptr) { return; } // It must be a 'placeholder' if (w->objectName() != "QDetachTabWidgetPlaceholder") { return; } // Look for the 'placeholder' tab in the tab cache. // Note, we do a scan of the cache because a QTabWidget can have isMovable() enabled. // Using 'tabindex' is not always reliable. QList::iterator it = findPlaceholderWidget(w); if (it == _tabInfo.end()) { return; } // Remove the 'placeholder' tab. removeTab(tabIndex); delete w; // Insert the real tab in the same position. insertTab(tabIndex, it->_widget, it->_title); // Save the real tab's widget before we delete the entry. w = it->_widget; // Delete the entry from the tab cache. _tabInfo.erase(it); // Notify listeners the tab was reattached. emit tabReattached(tabIndex); emit tabReattached(w); } void QDetachTabWidget::closeEvent (QCloseEvent* e) { auto it = _tabInfo.begin(); while (it != _tabInfo.end()) { delete it->_widget; it = _tabInfo.erase(it); // Erase current tab and point to the next one. } QTabWidget::closeEvent(e); } void QDetachTabWidget::handleShowContextMenu (const QPoint& point) { // Don't do anything. if (point.isNull()) { return; } // Get the tab index at the RMB click point. int tabIndex = tabBar()->tabAt(point); // Create the menu. QMenu menu("Window Action", this); QAction* detachAction = menu.addAction(tr("Detach")); QAction* detachMinimizedAction = menu.addAction(tr("Detach Minimized")); QAction* reattachAction = menu.addAction(tr("Reattach")); // Enable/disable depending if it was already detached. QWidget* w = widget(tabIndex); if (w->objectName() == "QDetachTabWidgetPlaceholder") { detachAction->setEnabled(false); detachMinimizedAction->setEnabled(false); reattachAction->setEnabled(true); }else{ detachAction->setEnabled(true); detachMinimizedAction->setEnabled(true); reattachAction->setEnabled(false); } // Exec the menue QAction* action = menu.exec(QCursor::pos()); // // Handle detaching a tab. // if (action == detachAction) { // Detach the tab. detachTab(tabIndex, false); // Set the tabwidget to the placeholder tab. setCurrentIndex(tabIndex); } // // Handle detaching a tab. // if (action == detachMinimizedAction) { // Detach the tab. detachTab(tabIndex, true); // Set the tabwidget to the placeholder tab. setCurrentIndex(tabIndex); } // // Handle reattaching a tab. // if (action == reattachAction) { // Reattach the tab. reattachTab(tabIndex); // Set the tabwidget to the real tab. setCurrentIndex(tabIndex); } } // // The QDetachTabWidget listens for 'tabCloseRequests'. Only to // reattach the widget, if necessary. Normally, you derive from // QDetachTabWidget and add signal/connect to do the same. I'm // counting on mine happening first. // void QDetachTabWidget::handleTabClosedRequested (int tabIndex) { // Reattach the tab. reattachTab(tabIndex); // Set the tabwidget to the real tab. setCurrentIndex(tabIndex); } // // Look for the real widget in the tab cache. // QList::iterator QDetachTabWidget::findWidget (QWidget* widget) { QList::iterator it = _tabInfo.begin(); while (it != _tabInfo.end()) { if (it->_widget == widget) { return it; } it++; } return it; } // // Look for the 'placeholder' widget in the tab cache. // QList::iterator QDetachTabWidget::findPlaceholderWidget (QWidget* widget) { QList::iterator it = _tabInfo.begin(); while (it != _tabInfo.end()) { if (it->_placeholderWidget == widget) { return it; } it++; } return it; } // // A placeholder widget that has a 'reattach' pushbutton. // QDetachTabWidgetPlaceholder::QDetachTabWidgetPlaceholder(int tabIndex, QWidget* parent) : QWidget(parent) { // This the placeholder's object name. Users of this object can focus // on this name if they need too. setObjectName("QDetachTabWidgetPlaceholder"); // Create the 'Reattach' button and add a layout to it. _reattachPushButton = new QPushButton("Reattach", this); _reattachPushButton->setIcon(QIcon(":/qt-project.org/styles/commonstyle/images/right-16.png")); _tabIndex = tabIndex; QHBoxLayout* layout = new QHBoxLayout; layout->addStretch(); layout->addWidget(_reattachPushButton); layout->addStretch(); setLayout(layout); // We'll handle the 'click' signal. QObject::connect(_reattachPushButton, &QPushButton::clicked, this, &QDetachTabWidgetPlaceholder::handlePushButtonClicked); } // Handle the pushbutton 'click' by emitting the 'reattach' signal. void QDetachTabWidgetPlaceholder::handlePushButtonClicked () { emit reattach(_tabIndex); } seer-2.7/src/QDetachTabWidget.h000066400000000000000000000045501516472651200164010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include struct QDetachTabInfo { QString _title; QWidget* _widget; QWidget* _placeholderWidget; QDetachTabInfo(QString title, QWidget* widget, QWidget* placeholderWidget) : _title(title), _widget(widget), _placeholderWidget(placeholderWidget) {} }; class QDetachTabWidget : public QTabWidget { Q_OBJECT public: QDetachTabWidget(QWidget* parent = 0); bool isDetached (int tabIndex) const; QWidget* tabWidget (int tabIndex) const; public slots: void detachTab (int tabIndex, bool minimized=false); void reattachTab (int tabIndex); signals: void tabDetached (int tabIndex); void tabDetached (QWidget* widget); void tabReattached (int tabIndex); void tabReattached (QWidget* widget); protected: void closeEvent (QCloseEvent* e); protected slots: void handleShowContextMenu (const QPoint& point); void handleTabClosedRequested (int tabIndex); private: QList::iterator findWidget (QWidget* widget); QList::iterator findPlaceholderWidget (QWidget* widget); QList _tabInfo; }; class QDetachTabWidgetPlaceholder : public QWidget { Q_OBJECT public: QDetachTabWidgetPlaceholder(int tabIndex, QWidget* parent = 0); signals: void reattach (int tabIndex); protected slots: void handlePushButtonClicked (); private: QPushButton* _reattachPushButton; int _tabIndex; }; seer-2.7/src/QEditDelegate.cpp000066400000000000000000000020031516472651200162600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QEditDelegate.h" // // QAllowEditDelegate enables a custom editor for a QTreeView column. // QAllowEditDelegate::QAllowEditDelegate(QObject* parent) : QStyledItemDelegate(parent) { } void QAllowEditDelegate::setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { emit editingStarted(index); QStyledItemDelegate::setModelData(editor, model, index); emit editingFinished(index); } // // QNoEditDelegate disables editing in a QTreeView for a column. // It does this by returning a 'null' editor when QTreeView calls QStyledItemDelegate::createEditor() for the cell. // QNoEditDelegate::QNoEditDelegate(QObject* parent) : QStyledItemDelegate(parent) { } QWidget* QNoEditDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_UNUSED(parent); Q_UNUSED(option); Q_UNUSED(index); return 0; } seer-2.7/src/QEditDelegate.h000066400000000000000000000016401516472651200157330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include class QAllowEditDelegate : public QStyledItemDelegate { Q_OBJECT public: QAllowEditDelegate(QObject* parent = nullptr); virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; signals: void editingStarted (const QModelIndex& index) const; void editingFinished (const QModelIndex& index) const; }; class QNoEditDelegate : public QStyledItemDelegate { public: QNoEditDelegate(QObject* parent = nullptr); virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; seer-2.7/src/QHContainerWidget.cpp000066400000000000000000000012151516472651200171420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QHContainerWidget.h" QHContainerWidget::QHContainerWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets // Connect things. } QHContainerWidget::~QHContainerWidget () { } void QHContainerWidget::setSpacing (int spacing) { horizontalLayout->setSpacing(spacing); } void QHContainerWidget::addWidget (QWidget* widget) { horizontalLayout->addWidget(widget); } void QHContainerWidget::removeWidget (QWidget* widget) { horizontalLayout->removeWidget(widget); } seer-2.7/src/QHContainerWidget.h000066400000000000000000000011461516472651200166120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include "ui_QHContainerWidget.h" class QHContainerWidget : public QWidget, protected Ui::QHContainerWidgetForm { Q_OBJECT public: explicit QHContainerWidget (QWidget* parent = 0); ~QHContainerWidget (); void setSpacing (int spacing); void addWidget (QWidget* widget); void removeWidget (QWidget* widget); private: }; seer-2.7/src/QHContainerWidget.ui000066400000000000000000000015221516472651200167760ustar00rootroot00000000000000 QHContainerWidgetForm 0 0 580 145 QHContainerWidgetForm 0 0 0 0 seer-2.7/src/QHistoryLineEdit.cpp000066400000000000000000000216471516472651200170360ustar00rootroot00000000000000/** * \file * * \author Mattia Basaglia * * \copyright Copyright (C) 2012-2020 Mattia Basaglia * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include "QHistoryLineEdit.h" #include #include #include #include #include #include #include QHistoryLineEdit::QHistoryLineEdit (const QString& contents, QWidget* parent) : QLineEdit(contents, parent), _currentLine(0), _completer(0), _completionMinchars(1), _completionMax(0) { enableReturnPressedOnClear(); QObject::connect(this, &QLineEdit::returnPressed, this, &QHistoryLineEdit::execute); } QHistoryLineEdit::QHistoryLineEdit (QWidget* parent) : QLineEdit(parent), _currentLine(0), _completer(0), _completionMinchars(1), _completionMax(0) { enableReturnPressedOnClear(); QObject::connect(this, &QLineEdit::returnPressed, this, &QHistoryLineEdit::execute); } /** * \brief Enable "return press" signal on Clear action. */ void QHistoryLineEdit::enableReturnPressedOnClear() { for (int i=0; i (children().at(i))); if (myClearAction) { //qDebug() << myClearAction->objectName(); // Look for only the QLineEdit clear action. // This name could change or be different. if (myClearAction->objectName() == "_q_qlineeditclearaction") { connect(myClearAction, &QAction::triggered, this, &QLineEdit::returnPressed, Qt::QueuedConnection); } } } } /** * \brief Number of available lines */ int QHistoryLineEdit::lineCount () const { return _lines.size(); } /** * \brief Overwrite the line history */ void QHistoryLineEdit::setHistory (const QStringList& history) { _lines = history; _currentLine = _lines.size(); } /** * \brief Stored history */ QStringList QHistoryLineEdit::history () const { return _lines; } /** * \brief Sets the completer used on a per-word completion * * Unlike setCompleter(), this suggests completion at every entered word * * If \c completer is null it will remove the current completer */ void QHistoryLineEdit::setWordCompleter (QCompleter* comp) { if ( _completer ) { QObject::disconnect(_completer, 0, this, 0); _completer->setWidget(0); } _completer = comp; if ( comp ) { /// \todo should set these only when on focus QObject::connect(_completer, QOverload::of(&QCompleter::activated), this, &QHistoryLineEdit::autoComplete); QObject::connect(_completer, QOverload::of(&QCompleter::highlighted), this, &QHistoryLineEdit::autoComplete); _completer->setWidget(this); } } /** * \brief Sets a prefix that is ignored by the word completer */ void QHistoryLineEdit::setWordCompleterPrefix (const QString& prefix) { _completionPrefix = prefix; } /** * \brief Sets the minimum number of characters required to display the word completer */ void QHistoryLineEdit::setWordCompleterMinChars (int minChars) { _completionMinchars = minChars; } /** * \brief Sets the maximum number of suggestions that the completer should show. * * If more than this many suggestions are found the completer isn't shown */ void QHistoryLineEdit::setWordCompleterMaxSuggestions (int max) { _completionMax = max; } /** * \brief Executes the current line */ void QHistoryLineEdit::execute () { // Ignore blank lines. if (text() == "") { return; } // Add the line if it doesn't equal the previous (that is store in the history). if ( _lines.empty() || _lines.back() != text() ) { _lines << text(); } // Set our current position in the history list. _currentLine = _lines.size(); // If it wants to, the calling widget should clear the text line. // clear(); // Emit the entered text. emit lineExecuted(_lines.back()); } void QHistoryLineEdit::keyPressEvent (QKeyEvent* ev) { if ( ev->key() == Qt::Key_Up ) { previousLine(); return; } else if ( ev->key() == Qt::Key_Down ) { nextLine(); return; } else if (_completer && _completer->popup() && _completer->popup()->isVisible()) { switch (ev->key()) { case Qt::Key_Enter: case Qt::Key_Return: case Qt::Key_F4: case Qt::Key_Select: _completer->popup()->hide(); return; } } if ( ev->key() == Qt::Key_Escape ) { emit escapePressed(); } QLineEdit::keyPressEvent(ev); if (_completer) { QString current = current_word(); _completer->setCompletionPrefix(current); if ( current.size() < _completionMinchars || _completer->completionCount() == 0 || (_completionMax > 0 && _completer->completionCount() > _completionMax) ) { _completer->popup()->hide(); } else { // Get the selection status int sel = selectionStart(); int sellength = selectedText().size(); // Get the current cursor position int c = cursorPosition(); // Get the start of the current word setCursorPosition(_wordStart()); // Get the cursor rectangle at the beginning of the current word QRect rect = cursorRect(); // Restore cursor position (clears the selection) setCursorPosition(c); // If we had a selection if ( sel != -1 ) { // If the selection started at the cursor, // it needs to start at the far end and go back // (otherwise it moves the cursor at the end) if ( sel == c ) setSelection(sel+sellength, -sellength); else setSelection(sel, sellength); } // Set the rectangle to the appropriate width rect.setWidth( _completer->popup()->sizeHintForColumn(0) + _completer->popup()->verticalScrollBar()->sizeHint().width()); // Display the _completer under the rectangle _completer->complete(rect); } } } void QHistoryLineEdit::wheelEvent (QWheelEvent* ev) { if ( ev->angleDelta().y() > 0 ) { previousLine(); }else{ nextLine(); } } void QHistoryLineEdit::focusOutEvent (QFocusEvent* ev) { QLineEdit::focusOutEvent(ev); emit lostFocus(); } void QHistoryLineEdit::focusInEvent (QFocusEvent* ev) { QLineEdit::focusInEvent(ev); emit gainedFocus(); } void QHistoryLineEdit::previousLine () { if ( _lines.empty() ) { return; } if ( !text().isEmpty() && ( _currentLine >= _lines.size() || text() != _lines[_currentLine] ) ) { _unfinished = text(); } if ( _currentLine > 0 ) { _currentLine--; } setText(_lines[_currentLine]); } void QHistoryLineEdit::nextLine () { if ( _lines.empty() ) { return; } _currentLine++; if ( _currentLine >= _lines.size() ) { setText(_unfinished); _unfinished = ""; _currentLine = _lines.size(); } else { setText(_lines[_currentLine]); } } /** * \brief Current word being edited (used to fire the completer) */ QString QHistoryLineEdit::current_word () const { int completion_index = _wordStart(); return text().mid(completion_index, cursorPosition() - completion_index); } /** * \brief Autocompletes the current word */ void QHistoryLineEdit::autoComplete (const QString& completion) { int completion_index = _wordStart(); setText(text().replace( completion_index, cursorPosition() - completion_index, completion)); setCursorPosition(completion_index+completion.size()); } /** * \brief Returns the index of the character starting the currently edited word */ int QHistoryLineEdit::_wordStart () const { // lastIndexOf returns the index of the last space or -1 if there are no spaces // so that + 1 returns the index of the character starting the word or 0 int after_space = text().left(cursorPosition()).lastIndexOf(' ') + 1; if ( text().right(text().size()-after_space).startsWith(_completionPrefix) ) { after_space += _completionPrefix.size(); } return after_space; } seer-2.7/src/QHistoryLineEdit.h000066400000000000000000000056551516472651200165040ustar00rootroot00000000000000/** * \file * * \author Mattia Basaglia * * \copyright Copyright (C) 2012-2020 Mattia Basaglia * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #pragma once #include /** * \brief Line edit providing a history of entered text */ class QHistoryLineEdit : public QLineEdit { Q_OBJECT public: QHistoryLineEdit(const QString& contents, QWidget* parent = 0); QHistoryLineEdit(QWidget* parent = 0); void enableReturnPressedOnClear (); int lineCount () const; void setHistory (const QStringList& history); QStringList history() const; void setWordCompleter (QCompleter* completer); void setWordCompleterPrefix (const QString& prefix); void setWordCompleterMinChars (int minChars); void setWordCompleterMaxSuggestions (int max); public slots: void execute (); signals: void lineExecuted (QString text); void lostFocus (); void gainedFocus (); void escapePressed (); protected: void keyPressEvent (QKeyEvent* event) Q_DECL_OVERRIDE; void wheelEvent (QWheelEvent* event) Q_DECL_OVERRIDE; void focusOutEvent (QFocusEvent* event) Q_DECL_OVERRIDE; void focusInEvent (QFocusEvent* event) Q_DECL_OVERRIDE; void previousLine (); void nextLine (); QString current_word () const; private slots: void autoComplete (const QString& completion); private: int _wordStart () const; int _currentLine; QStringList _lines; QString _unfinished; QCompleter* _completer; QString _completionPrefix; int _completionMinchars; int _completionMax; }; seer-2.7/src/QImageViewer.cpp000066400000000000000000000074711516472651200161620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QImageViewer.h" #include #include #include #include #include #include #include #include // // https://doc.qt.io/qt-5/qtwidgets-widgets-imageviewer-example.html // https://stackoverflow.com/questions/53193010/how-to-resize-a-qlabel-with-pixmap-inside-a-qscrollarea // QImageViewer::QImageViewer (QWidget* parent) : QWidget(parent) { _zoomFactor = 1.0; // Setup the widgets QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); _imageLabel = new QLabel(); _imageLabel->setBackgroundRole(QPalette::Base); _imageLabel->setScaledContents(true); _scrollArea = new QScrollArea(this); _scrollArea->setBackgroundRole(QPalette::Dark); _scrollArea->setWidget(_imageLabel); _scrollArea->setWidgetResizable(false); layout->addWidget(_scrollArea); _imageLabel->setPixmap(QPixmap::fromImage(_image)); } QImageViewer::~QImageViewer () { } bool QImageViewer::loadFile (const QString& file) { QImageReader reader(file); reader.setAutoTransform(true); QImage image = reader.read(); if (image.isNull()) { return false; } setImage(image); return true; } bool QImageViewer::saveFile (const QString& file) { if (file.isEmpty() == true) { return false; } QImageWriter writer(file); bool f = writer.write(_image); if (f == false) { qDebug() << writer.errorString(); } return f; } bool QImageViewer::saveFileDialog (const QString& file) { QString fileName = QFileDialog::getSaveFileName(this, tr("Save Image File"), file, tr("Image Files (*.png *.jpg *.bmp)"), nullptr, QFileDialog::DontUseNativeDialog); return saveFile(fileName); } void QImageViewer::setImage (const QImage& image) { //qDebug() << image; _image = image.copy(); _zoomFactor = 1.0; _imageLabel->setPixmap(QPixmap::fromImage(_image)); zoomReset(); } const QImage& QImageViewer::image () const { return _image; } void QImageViewer::setText (const QString& text) { _imageLabel->setText(text); } double QImageViewer::zoomFactor () const { return _zoomFactor; } void QImageViewer::zoom (double factor) { _zoomFactor = factor; _imageLabel->resize(_zoomFactor * _imageLabel->pixmap(Qt::ReturnByValue).size()); } void QImageViewer::zoomIn () { zoom(zoomFactor() * 1.25); } void QImageViewer::zoomOut () { zoom(zoomFactor() * 0.8); } void QImageViewer::zoomReset () { zoom(1.0); } void QImageViewer::print () { QPrintDialog dialog(&_printer, this); if (dialog.exec()) { QPainter painter(&_printer); QRect rect = painter.viewport(); QSize size = _imageLabel->pixmap(Qt::ReturnByValue).size(); size.scale(rect.size(), Qt::KeepAspectRatio); painter.setViewport(rect.x(), rect.y(), size.width(), size.height()); painter.setWindow(_imageLabel->pixmap(Qt::ReturnByValue).rect()); painter.drawPixmap(0, 0, _imageLabel->pixmap(Qt::ReturnByValue)); } } void QImageViewer::keyPressEvent (QKeyEvent* event) { //qDebug() << "Key =" << event->key(); switch (event->key()) { case Qt::Key_Escape: zoomReset(); break; case Qt::Key_Plus: zoomIn(); break; case Qt::Key_Minus: zoomOut(); break; default: QWidget::keyPressEvent(event); break; } } void QImageViewer::enterEvent (QEvent* event) { Q_UNUSED(event); setFocus(); } void QImageViewer::leaveEvent (QEvent* event) { Q_UNUSED(event); } seer-2.7/src/QImageViewer.h000066400000000000000000000033651516472651200156250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include class QImageViewer : public QWidget { Q_OBJECT public: explicit QImageViewer (QWidget* parent = 0); ~QImageViewer (); bool loadFile (const QString& file); bool saveFile (const QString& file); bool saveFileDialog (const QString& file); void setImage (const QImage& image); const QImage& image () const; void setText (const QString& text); double zoomFactor () const; public slots: void zoom (double factor); void zoomIn (); void zoomOut (); void zoomReset (); void print (); protected slots: void keyPressEvent (QKeyEvent* event); void enterEvent (QEvent* event); void leaveEvent (QEvent* event); private: QImage _image; QScrollArea* _scrollArea; QLabel* _imageLabel; double _zoomFactor; QPrinter _printer; }; seer-2.7/src/QIndexTreeWidget.cpp000066400000000000000000000005741516472651200170060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QIndexTreeWidget.h" QIndexTreeWidget::QIndexTreeWidget (QWidget* parent) : QTreeWidget(parent) { } QIndexTreeWidget::~QIndexTreeWidget () { } QTreeWidgetItem* QIndexTreeWidget::getItemFromIndex (const QModelIndex& index) const { return itemFromIndex(index); } seer-2.7/src/QIndexTreeWidget.h000066400000000000000000000007461516472651200164540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include class QIndexTreeWidget : public QTreeWidget { public: QIndexTreeWidget(QWidget* parent = nullptr); ~QIndexTreeWidget(); QTreeWidgetItem* getItemFromIndex (const QModelIndex& index) const; }; seer-2.7/src/QProcessInfo.cpp000066400000000000000000000110241516472651200161750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 Baldur Karlsson // SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QProcessInfo.h" #include #include #include #include #include #include #include #include #include #include #include QProcessInfo QProcessInfo::populate(uint32_t pid) { QProcessInfo info; info.setPid(pid); QDir processDir(QStringLiteral("/proc/") + QString::number(pid)); // default to the exe symlink if valid QFileInfo exe(processDir.absoluteFilePath(QStringLiteral("exe"))); exe = QFileInfo(exe.symLinkTarget()); info.setName(exe.completeBaseName()); info.setPath(exe.absolutePath()); // if we didn't get a name from the symlink, check in the status file if (info.name().isEmpty()) { QFile status(processDir.absoluteFilePath(QStringLiteral("status"))); if (status.open(QIODevice::ReadOnly)) { QByteArray contents = status.readAll(); QTextStream in(&contents); while(!in.atEnd()) { QString line = in.readLine(); if (line.startsWith(QStringLiteral("Name:"))) { line.remove(0, 5); // if we're using this name, surround with []s to indicate it's not a file info.setName(QStringLiteral("[%1]").arg(line.trimmed())); info.setPath(""); break; } } status.close(); } } // Get the username. QFile status(processDir.absoluteFilePath(QStringLiteral("status"))); if (status.open(QIODevice::ReadOnly)) { QByteArray contents = status.readAll(); QTextStream in(&contents); while(!in.atEnd()) { QString line = in.readLine(); if (line.startsWith(QStringLiteral("Uid:"))) { info.setUsername(line.split(QRegularExpression("\\s+")).at(1)); break; } } status.close(); struct passwd* pw = getpwuid(info.username().toULong()); if (pw) { info.setUsername(pw->pw_name); } } // Get the command line QFile cmdline(processDir.absoluteFilePath(QStringLiteral("cmdline"))); if (cmdline.open(QIODevice::ReadOnly)) { QByteArray contents = cmdline.readAll(); int nullIdx = contents.indexOf('\0'); if (nullIdx > 0) { QString firstparam = QString::fromUtf8(contents.data(), nullIdx); // if name is a truncated form of a filename, replace it if (firstparam.endsWith(info.name()) && QFileInfo::exists(firstparam)) { info.setName(QFileInfo(firstparam).completeBaseName()); info.setPath(QFileInfo(firstparam).absolutePath()); } // if we don't have a name, replace it but with []s if (info.name().isEmpty()) { info.setName(QStringLiteral("[%1]").arg(firstparam)); info.setPath(""); } contents.replace('\0', ' '); } info.setCommandLine(QString::fromUtf8(contents).trimmed()); cmdline.close(); } return info; } QProcessList QProcessInfo::populate() { QProcessList ret; QDir proc(QStringLiteral("/proc")); QStringList files = proc.entryList(); for (const QString& f : files) { bool ok = false; uint32_t pid = f.toUInt(&ok); if (ok) { // Get process info for pid. QProcessInfo info = QProcessInfo::populate(pid); // Add the process to the list. ret.push_back(info); } } return ret; } QProcessInfo::QProcessInfo() { _pid = 0; } uint32_t QProcessInfo::pid() const { return _pid; } void QProcessInfo::setPid(uint32_t pid) { _pid = pid; } const QString& QProcessInfo::username() const { return _username; } void QProcessInfo::setUsername(const QString& username) { _username = username; } const QString& QProcessInfo::name() const { return _name; } void QProcessInfo::setName(const QString& name) { _name = name; } const QString& QProcessInfo::path() const { return _path; } void QProcessInfo::setPath(const QString& path) { _path = path; } const QString& QProcessInfo::commandLine() const { return _cmdLine; } void QProcessInfo::setCommandLine(const QString& cmd) { _cmdLine = cmd; } seer-2.7/src/QProcessInfo.h000066400000000000000000000022721516472651200156470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include class QProcessInfo; typedef QList QProcessList; class QProcessInfo { public: QProcessInfo(); static QProcessList populate(); static QProcessInfo populate(uint32_t pid); uint32_t pid () const; void setPid (uint32_t pid); const QString& username () const; void setUsername (const QString& username); const QString& name () const; void setName (const QString& name); const QString& path () const; void setPath (const QString& path); const QString& commandLine () const; void setCommandLine (const QString& cmd); private: uint32_t _pid; QString _username; QString _name; QString _path; QString _cmdLine; }; seer-2.7/src/QProcessInfoWidget.cpp000066400000000000000000000165631516472651200173560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QProcessInfoWidget.h" #include "QProcessInfo.h" #include #include #include #include #include #include // // Custom tree item with numeric ordering on column 0. // class QProcessInfoWidgetItem : public QTreeWidgetItem { public: QProcessInfoWidgetItem(QTreeWidget* parent = 0) : QTreeWidgetItem(parent) { } private: bool operator< (const QTreeWidgetItem& other) const { int column = treeWidget()->sortColumn(); if (column == 0) { return text(column).toLong() < other.text(column).toLong(); } return text(column) < other.text(column); } }; // // The main widget starts here. // QProcessInfoWidget::QProcessInfoWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets processTreeWidget->setMouseTracking(true); processTreeWidget->resizeColumnToContents(0); // PID processTreeWidget->resizeColumnToContents(1); // User name processTreeWidget->resizeColumnToContents(2); // Path name processTreeWidget->resizeColumnToContents(3); // Program name //processTreeWidget->resizeColumnToContents(4); // Command line processTreeWidget->setSortingEnabled(true); processTreeWidget->clear(); systemProcessesCheckBox->setChecked(false); // Connect things. QObject::connect(programNameLineEdit, &QLineEdit::textChanged, this, &QProcessInfoWidget::refreshView); QObject::connect(userNameLineEdit, &QLineEdit::textChanged, this, &QProcessInfoWidget::refreshView); QObject::connect(systemProcessesCheckBox, &QCheckBox::clicked, this, &QProcessInfoWidget::refreshView); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &QProcessInfoWidget::refreshList); QObject::connect(processTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QProcessInfoWidget::handleDoubleClicked); // Give focus to the program line edit. programNameLineEdit->setFocus(Qt::OtherFocusReason); // Load the initial process list. refreshList(); } QProcessInfoWidget::~QProcessInfoWidget () { } int QProcessInfoWidget::selectedPid () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return -1; } return items[0]->text(0).toLong(); } QString QProcessInfoWidget::selectedUsername () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return ""; } return items[0]->text(1); } QString QProcessInfoWidget::selectedName () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return ""; } return items[0]->text(3); } QString QProcessInfoWidget::selectedFullname () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return ""; } return items[0]->text(2) + "/" + items[0]->text(3); } QString QProcessInfoWidget::selectedCommandLine () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return ""; } return items[0]->text(4); } void QProcessInfoWidget::refreshList () { QApplication::setOverrideCursor(Qt::BusyCursor); // Scan the /proc file system. QProcessList list = QProcessInfo::populate(); // Loop through each entry and add it to our view. processTreeWidget->clear(); for (const QProcessInfo& info : list) { QTreeWidgetItem* item = new QProcessInfoWidgetItem; item->setText(0, QString::number(info.pid())); item->setText(1, info.username()); item->setText(2, info.path()); item->setText(3, info.name()); item->setText(4, info.commandLine()); processTreeWidget->addTopLevelItem(item); } // Adjust the column widths. processTreeWidget->clearSelection(); processTreeWidget->resizeColumnToContents(0); processTreeWidget->resizeColumnToContents(1); processTreeWidget->resizeColumnToContents(2); processTreeWidget->resizeColumnToContents(3); //processTreeWidget->resizeColumnToContents(4); // Don't clear the line edits. // programNameLineEdit->clear(); // userNameLineEdit->clear(); refreshView(); QApplication::restoreOverrideCursor(); } void QProcessInfoWidget::refreshView () { // Get this list of program name matches. Or all if there is no program name provided. QList programNameMatches; if (programNameLineEdit->text() == "") { programNameMatches = processTreeWidget->findItems("*", Qt::MatchWildcard | Qt::MatchRecursive, 3); }else{ if (programNameLineEdit->text().contains('*')) { programNameMatches = processTreeWidget->findItems(programNameLineEdit->text(), Qt::MatchWildcard | Qt::MatchRecursive, 3); }else{ programNameMatches = processTreeWidget->findItems(programNameLineEdit->text(), Qt::MatchStartsWith | Qt::MatchRecursive, 3); } } // Get this list of user name matches. Or all if there is no user name provided. QList userNameMatches; if (userNameLineEdit->text() == "") { userNameMatches = processTreeWidget->findItems("*", Qt::MatchWildcard | Qt::MatchRecursive, 1); }else{ if (userNameLineEdit->text().contains('*')) { userNameMatches = processTreeWidget->findItems(userNameLineEdit->text(), Qt::MatchWildcard | Qt::MatchRecursive, 1); }else{ userNameMatches = processTreeWidget->findItems(userNameLineEdit->text(), Qt::MatchStartsWith | Qt::MatchRecursive, 1); } } // Get this list of process matches. Include one's with [xxx]) or not. QList processMatches; if (systemProcessesCheckBox->isChecked() == true) { processMatches = processTreeWidget->findItems("*", Qt::MatchWildcard | Qt::MatchRecursive, 3); //qDebug() << "Checkbox is on." << processMatches.size(); }else{ // To find [xxx] processes : "^(\\[).*(\\])$" // To exclude [xxx] processes: "^(?!\\[).*(?!\\])$" processMatches = processTreeWidget->findItems("^(?!\\[).*(?!\\])$", Qt::MatchRegularExpression | Qt::MatchRecursive, 3); //qDebug() << "Checkbox is off." << processMatches.size(); } // Go through each item in the tree. If it's in the user, program, and process matches, show it. // Otherwise, hide it. QTreeWidgetItemIterator it(processTreeWidget); while (*it) { if (programNameMatches.contains(*it) && userNameMatches.contains(*it) && processMatches.contains(*it)) { (*it)->setHidden(false); }else{ (*it)->setHidden(true); } ++it; } // Resize the columns. processTreeWidget->resizeColumnToContents(0); processTreeWidget->resizeColumnToContents(1); processTreeWidget->resizeColumnToContents(2); processTreeWidget->resizeColumnToContents(3); //processTreeWidget->resizeColumnToContents(4); } void QProcessInfoWidget::handleDoubleClicked () { emit pidSelected(selectedPid()); } seer-2.7/src/QProcessInfoWidget.h000066400000000000000000000021171516472651200170110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include "ui_QProcessInfoWidget.h" class QProcessInfoWidget : public QWidget, protected Ui::QProcessInfoWidget { Q_OBJECT public: explicit QProcessInfoWidget (QWidget* parent = 0); ~QProcessInfoWidget (); int selectedPid () const; QString selectedUsername () const; QString selectedName () const; QString selectedFullname () const; QString selectedCommandLine () const; signals: void pidSelected (int pid); public slots: protected slots: void refreshList (); void refreshView (); void handleDoubleClicked (); protected: private: }; seer-2.7/src/QProcessInfoWidget.ui000066400000000000000000000065201516472651200172010ustar00rootroot00000000000000 QProcessInfoWidget 0 0 770 488 System Process Browser Show system processes or hide them. System Processes false Refresh the list of processes. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg true 5 PID User Name Program Path Program Name Command Line Search program name in the list of processes. "*" is allowed. Search Program Name... true Search user name in the list of processes. "*" is allowed. Search User Name... true programNameLineEdit userNameLineEdit systemProcessesCheckBox refreshToolButton processTreeWidget seer-2.7/src/QProgressIndicator.cpp000066400000000000000000000152411516472651200174110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QProgressIndicator.h" #include #include #include #include #include #define SPIN_INTERVAL 100 // Set timer to wake up every 100ms. QProgressIndicator::QProgressIndicator(QWidget* parent) : QWidget(parent) { _type = QProgressIndicator::line_rotate; _interval = SPIN_INTERVAL; _angle = 0; _scale = 0.0f; _color = Qt::black; setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setFocusPolicy(Qt::NoFocus); _timer = new QTimer(); connect(_timer, SIGNAL(timeout()), this, SLOT(onTimeout())); update(); } QProgressIndicator::~QProgressIndicator() { stop(); delete _timer; } void QProgressIndicator::paintEvent(QPaintEvent* e) { Q_UNUSED(e) if (!_timer->isActive()) { _angle = 0; _scale = 0.0f; } QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); switch (_type) { case QProgressIndicator::line_rotate: drawRotateLine(&painter); break; case QProgressIndicator::line_scale: drawScaleLine((&painter)); break; case QProgressIndicator::ball_rotate: drawRotateBall(&painter); break; case QProgressIndicator::circle_rotate: drawRotateCircle(&painter); break; } } void QProgressIndicator::start() { _timer->start(_interval); } void QProgressIndicator::stop() { _timer->stop(); update(); // Force an update to erase the indicator from the view. } int QProgressIndicator::type () const { return _type; } QString QProgressIndicator::typeName () const { if (_type == line_rotate) { return "LineRotate"; }else if (_type == line_scale) { return "LineScale"; }else if (_type == ball_rotate) { return "BallRotate"; }else if (_type == circle_rotate) { return "CircleRotate"; } return "BallRotate"; } void QProgressIndicator::setType (int type) { _type = type; } void QProgressIndicator::setType (const QString& type) { if (type == "LineRotate") { setType(line_rotate); }else if (type == "LineScale") { setType(line_scale); }else if (type == "BallRotate") { setType(ball_rotate); }else if (type == "CircleRotate") { setType(circle_rotate); }else{ setType(line_rotate); } update(); } QStringList QProgressIndicator::types () const { QStringList list = {"LineRotate", "LineScale", "BallRotate", "CircleRotate"}; return list; } const QColor& QProgressIndicator::color () { return _color; } void QProgressIndicator::setColor (const QColor& color) { _color = color; } int QProgressIndicator::interval () { return _interval; } void QProgressIndicator::setInterval (int interval) { _interval = interval; } void QProgressIndicator::onTimeout() { switch (_type) { case line_rotate: case ball_rotate: _angle = (_angle + 45) % 360; break; case circle_rotate: _angle = (_angle + 45) % 360; break; case line_scale: _scale += 0.1f; _scale = _scale > .5f ? 0.0f : _scale; break; } update(); } void QProgressIndicator::drawRotateLine(QPainter* painter) { int width = qMin(this->width(), this->height()); int outerRadius = (width - 4) * 0.5f; int innerRadius = outerRadius * 0.42f; int capsuleHeight = outerRadius - innerRadius; int capsuleWidth = (width > 32 ) ? capsuleHeight * .32f : capsuleHeight * .40f; int capsuleRadius = capsuleWidth / 2; for (int i = 0; i < 8; i++) { QColor color = _color; color.setAlphaF(1.0f - (i / 8.0f)); painter->setPen(Qt::NoPen); painter->setBrush(color); painter->save(); painter->translate(rect().center()); painter->rotate(_angle - i * 45.0f); painter->drawRoundedRect(-capsuleWidth * 0.5, -(innerRadius + capsuleHeight), capsuleWidth, capsuleHeight, capsuleRadius, capsuleRadius); painter->restore(); } } void QProgressIndicator::drawScaleLine(QPainter* painter) { int height = qMin(this->width(), this->height()); qreal lineWidth = height * 0.15f; qreal lineHeight = height * 0.9f; qreal lineRadius = lineWidth / 2.0f; qreal lineGap = lineWidth; qreal margin = (this->width() - lineWidth * 5 - lineGap * 4) / 2.0f; for (int i = 0; i < 5; i++) { painter->setPen(Qt::NoPen); painter->setBrush(_color); int tmp = _scale * 10 + i + 1; if (tmp > 5) { tmp = 5 - tmp % 5; } qreal scale = 0.5f + tmp * 0.1f; qreal h = lineHeight * scale; painter->save(); painter->translate(QPointF(margin + (lineWidth + lineGap) * i, this->height() / 2)); painter->drawRoundedRect(0, -h / 2.0f, lineWidth, h, lineRadius, lineRadius); painter->restore(); } } void QProgressIndicator::drawRotateBall(QPainter* painter) { int width = qMin(this->width(), this->height()); int outerRadius = (width - 4) * 0.5f; int innerRadius = outerRadius * 0.78f; int capsuleRadius = (outerRadius - innerRadius) / 2; for (int i = 0; i < 8; i++) { QColor color = _color; color.setAlphaF(1.0f - (i / 8.0f)); painter->setPen(Qt::NoPen); painter->setBrush(color); qreal radius = capsuleRadius * (1.0f - (i / 16.0f)); painter->save(); painter->translate(rect().center()); painter->rotate(_angle - i * 45.0f); QPointF centre = QPointF(-capsuleRadius, -(innerRadius + capsuleRadius)); painter->drawEllipse(centre, radius * 2, radius * 2); painter->restore(); } } void QProgressIndicator::drawRotateCircle(QPainter* painter) { // My version is based on ProgressInfiniteBar from : https://github.com/przemek83/wble int width = qMin(this->width(), this->height()); int offset = qAbs(this->width() - this->height()) / 2; int penwidth = 3; QRectF r = QRect(offset+penwidth,0+penwidth, width-(2*penwidth),width-(2*penwidth)); QPen pen(_color); pen.setWidth(penwidth); pen.setCapStyle(Qt::RoundCap); painter->setPen(pen); painter->setBrush(_color); int startAngle = 0.0; int spanAngle = 45 * 16; startAngle = (0.0 + _angle) * 16; painter->drawArc(r, -startAngle, -spanAngle); startAngle = (120.0 + _angle) * 16; painter->drawArc(r, -startAngle, -spanAngle); startAngle = (240.0 + _angle) * 16; painter->drawArc(r, -startAngle, -spanAngle); } seer-2.7/src/QProgressIndicator.h000066400000000000000000000037261516472651200170630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include class QProgressIndicator : public QWidget { Q_OBJECT Q_PROPERTY(int _type READ type WRITE setType) Q_PROPERTY(QColor _color READ color WRITE setColor) Q_PROPERTY(int _interval READ interval WRITE setInterval) public: QProgressIndicator(QWidget* parent = 0); ~QProgressIndicator(); enum { line_rotate, line_scale, ball_rotate, circle_rotate }; void paintEvent (QPaintEvent* e); void start (); void stop (); int type () const; QString typeName () const; void setType (int type); void setType (const QString& type); QStringList types () const; const QColor& color (); void setColor (const QColor &color); int interval (); void setInterval (int interval); private slots: void onTimeout (); private: void drawRotateLine (QPainter* painter); void drawScaleLine (QPainter* painter); void drawRotateBall (QPainter* painter); void drawRotateCircle (QPainter* painter); private: int _type; int _interval; QColor _color; int _angle; qreal _scale; QTimer* _timer; }; seer-2.7/src/QStringPair.h000066400000000000000000000003231516472651200154720ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include typedef QPair QStringPair; seer-2.7/src/QZoomChart.cpp000066400000000000000000000025211516472651200156530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QZoomChart.h" #include #include #include #include QZoomChart::QZoomChart(QGraphicsItem* parent, Qt::WindowFlags wFlags) : QChart(QChart::ChartTypeCartesian, parent, wFlags) { // Seems that QGraphicsView (QChartView) does not grab gestures. // They can only be grabbed here in the QGraphicsWidget (QChart). grabGesture(Qt::PanGesture); grabGesture(Qt::PinchGesture); } QZoomChart::~QZoomChart() { } bool QZoomChart::sceneEvent(QEvent* event) { if (event->type() == QEvent::Gesture) { return gestureEvent(static_cast(event)); } return QChart::event(event); } bool QZoomChart::gestureEvent(QGestureEvent* event) { if (QGesture* gesture = event->gesture(Qt::PanGesture)) { QPanGesture* pan = static_cast(gesture); QChart::scroll(-(pan->delta().x()), pan->delta().y()); } if (QGesture* gesture = event->gesture(Qt::PinchGesture)) { QPinchGesture* pinch = static_cast(gesture); if (pinch->changeFlags() & QPinchGesture::ScaleFactorChanged) { QChart::zoom(pinch->scaleFactor()); } } return true; } seer-2.7/src/QZoomChart.h000066400000000000000000000010331516472651200153150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #if QT_VERSION < 0x060000 using namespace QtCharts; #endif class QGestureEvent; class QZoomChart : public QChart { public: QZoomChart(QGraphicsItem* parent = nullptr, Qt::WindowFlags wFlags = {}); ~QZoomChart(); protected: bool sceneEvent (QEvent* event); private: bool gestureEvent (QGestureEvent* event); private: }; seer-2.7/src/QZoomChartView.cpp000066400000000000000000000105711516472651200165120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QZoomChartView.h" #include #include #include #include #include #include QZoomChartView::QZoomChartView (QWidget* parent) : QChartView(parent) { _isDragging = false; setRubberBand(QChartView::RectangleRubberBand); } QZoomChartView::QZoomChartView (QChart* chart, QWidget* parent) : QChartView(chart, parent) { _isDragging = false; setRubberBand(QChartView::RectangleRubberBand); } void QZoomChartView::printView () { QPrinter printer; if (QPrintDialog(&printer).exec() == QDialog::Accepted) { QPainter painter(&printer); painter.setRenderHint(QPainter::Antialiasing); render(&painter); } } bool QZoomChartView::viewportEvent (QEvent* event) { // Disable ToolTip events in the ChartView. They interfer with the 'length' arguments // of the QToolTip::showText() function. // https://bugreports.qt.io/browse/QTBUG-56427 switch (event->type()) { case QEvent::ToolTip: return false; default: break; } return QChartView::viewportEvent(event); } void QZoomChartView::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { _keyboardModifiers = QGuiApplication::keyboardModifiers(); if (_keyboardModifiers == Qt::ShiftModifier) { QApplication::setOverrideCursor(QCursor(Qt::SizeAllCursor)); setRubberBand(QChartView::NoRubberBand); _lastMousePos = event->pos(); _isDragging = true; event->accept(); }else{ setRubberBand(QChartView::RectangleRubberBand); } } QChartView::mousePressEvent(event); } void QZoomChartView::mouseMoveEvent (QMouseEvent* event) { // pan the chart with a left mouse drag if (event->buttons() & Qt::LeftButton) { if (_keyboardModifiers == Qt::ShiftModifier) { auto dPos = event->pos() - _lastMousePos; chart()->scroll(-dPos.x(), dPos.y()); chart()->update(); _lastMousePos = event->pos(); event->accept(); } } QChartView::mouseMoveEvent(event); } void QZoomChartView::mouseReleaseEvent (QMouseEvent* event) { if (_isDragging) { QApplication::restoreOverrideCursor(); _isDragging = false; } QChartView::mouseReleaseEvent(event); } void QZoomChartView::wheelEvent (QWheelEvent* event) { // https://stackoverflow.com/questions/48623595/scale-x-axis-of-qchartview-using-mouse-wheel qreal factor = event->angleDelta().y() > 0 ? 0.5 : 2.0; chart()->zoom(factor); chart()->update(); event->accept(); QChartView::wheelEvent(event); } void QZoomChartView::keyPressEvent (QKeyEvent* event) { switch (event->key()) { case Qt::Key_Plus: chart()->zoomIn(); chart()->update(); break; case Qt::Key_Minus: chart()->zoomOut(); chart()->update(); break; case Qt::Key_Escape: chart()->zoomReset(); chart()->zoom(.9); chart()->update(); break; case Qt::Key_Left: chart()->scroll(-10, 0); chart()->update(); break; case Qt::Key_Right: chart()->scroll(10, 0); chart()->update(); break; case Qt::Key_Up: chart()->scroll(0, 10); chart()->update(); break; case Qt::Key_Down: chart()->scroll(0, -10); chart()->update(); break; case Qt::Key_R: { if (event->modifiers() == Qt::ControlModifier) { chart()->update(); } } break; case Qt::Key_P: { if (event->modifiers() == Qt::ControlModifier) { printView(); } } break; default: QGraphicsView::keyPressEvent(event); break; } } void QZoomChartView::enterEvent (QEvent* event) { Q_UNUSED(event); setFocus(); } void QZoomChartView::leaveEvent (QEvent* event) { Q_UNUSED(event); } seer-2.7/src/QZoomChartView.h000066400000000000000000000025261516472651200161600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #if QT_VERSION < 0x060000 using namespace QtCharts; #endif class QZoomChartView : public QChartView { public: QZoomChartView (QWidget* parent = 0); QZoomChartView (QChart* chart, QWidget* parent = 0); public slots: void printView (); protected: bool viewportEvent (QEvent* event); void mousePressEvent (QMouseEvent* event); void mouseMoveEvent (QMouseEvent* event); void mouseReleaseEvent (QMouseEvent* event); void wheelEvent (QWheelEvent* event); void keyPressEvent (QKeyEvent* event); void enterEvent (QEvent* event); void leaveEvent (QEvent* event); private: bool _isDragging; QPointF _lastMousePos; Qt::KeyboardModifiers _keyboardModifiers; }; seer-2.7/src/SeerAboutDialog.cpp000066400000000000000000000023231516472651200166350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAboutDialog.h" #include "SeerUtl.h" #include #include #include #include #include SeerAboutDialog::SeerAboutDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Get the About text from the resource. QFile file(":/seer/resources/ABOUT.md"); bool f = file.open(QFile::ReadOnly | QFile::Text); if (f == false) { return; } QTextStream stream(&file); QString text = stream.readAll(); // Substitute the text holder with the version number. text.replace("VERSIONNUMBER", Seer::version()); // Put the About text in as markdown. Move back to the begining. textBrowser->setMarkdown(text); textBrowser->moveCursor (QTextCursor::Start); // Set the TextBrowser's background to the same as the window's. QColor windowColor = palette().color(QWidget::backgroundRole()); QPalette p = textBrowser->palette(); p.setColor(QPalette::Base, windowColor); textBrowser->setPalette(p); } SeerAboutDialog::~SeerAboutDialog () { } seer-2.7/src/SeerAboutDialog.h000066400000000000000000000006711516472651200163060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerAboutDialog.h" class SeerAboutDialog : public QDialog, protected Ui::SeerAboutDialogForm { Q_OBJECT public: explicit SeerAboutDialog (QWidget* parent = 0); ~SeerAboutDialog (); public slots: private: }; seer-2.7/src/SeerAboutDialog.ui000066400000000000000000000072061516472651200164750ustar00rootroot00000000000000 SeerAboutDialogForm 0 0 563 556 About Seer false :/seer/resources/icons/hicolor/256x256/seergdb.png false Qt::AlignCenter QFrame::NoFrame QFrame::Plain Qt::ScrollBarAsNeeded QTextEdit::WidgetWidth true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> true Qt::Horizontal QDialogButtonBox::Ok buttonBox accepted() SeerAboutDialogForm accept() 248 254 157 274 buttonBox rejected() SeerAboutDialogForm reject() 316 260 286 274 seer-2.7/src/SeerAdaExceptionsBrowserWidget.cpp000066400000000000000000000134631516472651200217110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAdaExceptionsBrowserWidget.h" #include "SeerCatchpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerAdaExceptionsBrowserWidget::SeerAdaExceptionsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets adaExceptionsSearchLineEdit->setPlaceholderText("Search regex..."); adaExceptionsSearchLineEdit->setClearButtonEnabled(true); adaExceptionsTreeWidget->resizeColumnToContents(0); adaExceptionsTreeWidget->resizeColumnToContents(1); adaExceptionsTreeWidget->clear(); // Connect things. QObject::connect(adaExceptionsSearchLineEdit, &QLineEdit::textChanged, this, &SeerAdaExceptionsBrowserWidget::handleSearchLineEdit); QObject::connect(addCatchpointToolButton, &QToolButton::clicked, this, &SeerAdaExceptionsBrowserWidget::handleAddCatchpointToolButtonClicked); } SeerAdaExceptionsBrowserWidget::~SeerAdaExceptionsBrowserWidget () { } void SeerAdaExceptionsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,ada-exceptions={") && text.endsWith("}")) { adaExceptionsTreeWidget->clear(); // -info-ada-exceptions aint // ^done,ada-exceptions={ // nr_rows="2", // nr_cols="2", // hdr=[ // {width="1",alignment="-1",col_name="name",colhdr="Name"}, // {width="1",alignment="-1",col_name="address",colhdr="Address"} // ], // body=[ // {name="constraint_error",address="0x0000000000613da0"}, // {name="const.aint_global_e",address="0x0000000000613b00"} // ] // } QString body_text = Seer::parseFirst(text, "body=", '[', ']', false); //qDebug() << body_text; QStringList exceptions_list = Seer::parse(body_text, "", '{', '}', false); for ( const auto& entry_text : exceptions_list ) { QString name_text = Seer::parseFirst(entry_text, "name=", '"', '"', false); QString address_text = Seer::parseFirst(entry_text, "address=", '"', '"', false); // Add the file to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, name_text); item->setText(1, address_text); adaExceptionsTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } adaExceptionsTreeWidget->resizeColumnToContents(0); adaExceptionsTreeWidget->resizeColumnToContents(1); adaExceptionsSearchLineEdit->clear(); QApplication::restoreOverrideCursor(); } void SeerAdaExceptionsBrowserWidget::handleSessionTerminated () { // Delete previous contents. adaExceptionsTreeWidget->clear(); } void SeerAdaExceptionsBrowserWidget::handleSearchLineEdit (const QString& text) { // Set everything to a normal font. If there is no search text, unhide everything. // If there is search text, hide everything so the matching ones can be unhidden later on. QTreeWidgetItemIterator it(adaExceptionsTreeWidget); if (*it) { QFont f0 = (*it)->font(0); f0.setBold(false); if (text == "") { while (*it) { (*it)->setHidden(false); // No search text, unhide everything. (*it)->setFont(0,f0); ++it; } }else{ while (*it) { (*it)->setHidden(true); // Has search text, hide everything. Matching items to be unhidden below. (*it)->setFont(0,f0); ++it; } } } // Set selected items to a bold font and unhidden. Move to the first match. if (text != "") { QList matches; matches = adaExceptionsTreeWidget->findItems(text, Qt::MatchRegularExpression | Qt::MatchRecursive, 0); QList::const_iterator it = matches.begin(); QList::const_iterator e = matches.end(); if (it != e) { adaExceptionsTreeWidget->setCurrentItem(*it); QFont f0 = (*it)->font(0); f0.setBold(true); while (it != e) { (*it)->setHidden(false); (*it)->setFont(0,f0); it++; } } //qDebug() << text << matches.size(); } adaExceptionsTreeWidget->resizeColumnToContents(0); adaExceptionsTreeWidget->resizeColumnToContents(1); } void SeerAdaExceptionsBrowserWidget::handleAddCatchpointToolButtonClicked () { SeerCatchpointCreateDialog dlg(this); dlg.setType("exception"); QTreeWidgetItem* item = adaExceptionsTreeWidget->currentItem(); if (item != 0) { dlg.setArguments(item->text(0)); } int ret = dlg.exec(); if (ret == 0) { return; } // Build a catchpoint specification. QString catchpointParameters = dlg.catchpointText(); // If nothing, just return. if (catchpointParameters == "") { return; } // Otherwise send the command to create the catchpoint. emit insertCatchpoint(catchpointParameters); } void SeerAdaExceptionsBrowserWidget::refresh () { emit refreshAdaExceptions(); } void SeerAdaExceptionsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } seer-2.7/src/SeerAdaExceptionsBrowserWidget.h000066400000000000000000000023001516472651200213420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerAdaExceptionsBrowserWidget.h" class SeerAdaExceptionsBrowserWidget : public QWidget, protected Ui::SeerAdaExceptionsBrowserWidgetForm { Q_OBJECT public: explicit SeerAdaExceptionsBrowserWidget (QWidget* parent = 0); ~SeerAdaExceptionsBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (const QString& text); void handleAddCatchpointToolButtonClicked (); signals: void refreshAdaExceptions (); void insertCatchpoint (QString catchpoint); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerAdaExceptionsBrowserWidget.ui000066400000000000000000000042721516472651200215420ustar00rootroot00000000000000 SeerAdaExceptionsBrowserWidgetForm 0 0 730 698 Ada Exceptions Browser Search in the list of exceptions. "*" is allowed. Search regex... Add a catchpoint for an Ada exception. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg 2 Name Address QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerAdaTasksBrowserWidget.cpp000066400000000000000000000155431516472651200206560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAdaTasksBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerAdaTasksBrowserWidget::SeerAdaTasksBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets adaTaskTreeWidget->setMouseTracking(true); adaTaskTreeWidget->setSortingEnabled(false); adaTaskTreeWidget->resizeColumnToContents(0); // current adaTaskTreeWidget->resizeColumnToContents(1); // id adaTaskTreeWidget->resizeColumnToContents(2); // taskid adaTaskTreeWidget->resizeColumnToContents(3); // threadid adaTaskTreeWidget->resizeColumnToContents(4); // parentid adaTaskTreeWidget->resizeColumnToContents(5); // priority adaTaskTreeWidget->resizeColumnToContents(6); // state adaTaskTreeWidget->resizeColumnToContents(7); // name adaTaskTreeWidget->clear(); // Connect things. QObject::connect(adaTaskTreeWidget, &QTreeWidget::itemClicked, this, &SeerAdaTasksBrowserWidget::handleItemClicked); } SeerAdaTasksBrowserWidget::~SeerAdaTasksBrowserWidget () { } void SeerAdaTasksBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,tasks={")) { // -ada-task-info [ task-id ] // ^done,tasks={ // nr_rows="3", // nr_cols="8", // hdr=[ // { // width="1",alignment="-1",col_name="current",colhdr="" // }, // { // width="3",alignment="1",col_name="id",colhdr="ID" // }, // { // width="9",alignment="1",col_name="task-id",colhdr="TID" // }, // { // width="4",alignment="1",col_name="thread-id",colhdr="" // }, // { // width="4",alignment="1",col_name="parent-id",colhdr="P-ID" // }, // { // width="3",alignment="1",col_name="priority",colhdr="Pri" // }, // { // width="22",alignment="-1",col_name="state",colhdr="State" // }, // { // width="1",alignment="2",col_name="name",colhdr="Name" // } // ], // body=[ // { // id="1",task-id="45d030",thread-id="1",priority="48",state="Waiting on RV with 2 ",name="main_task" // }, // { // current="*",id="2",task-id="45de30",thread-id="2",parent-id="1",priority="48",state="Runnable",name="task_a" // }, // { // id="3",task-id="461460",thread-id="3",parent-id="1",priority="48",state="Delay Sleep",name="task_b" // } // ] // } //qDebug() << text; adaTaskTreeWidget->clear(); QString body_text = Seer::parseFirst(text, "body=", '[', ']', false); //qDebug() << threads_text; if (body_text != "") { QStringList tasks_list = Seer::parse(body_text, "", '{', '}', false); for ( const auto& task_text : tasks_list ) { QString current_text = Seer::parseFirst(task_text, "current=", '"', '"', false); QString id_text = Seer::parseFirst(task_text, "id=", '"', '"', false); QString taskid_text = Seer::parseFirst(task_text, "task-id=", '"', '"', false); QString threadid_text = Seer::parseFirst(task_text, "thread-id=", '"', '"', false); QString parentid_text = Seer::parseFirst(task_text, "parent-id=", '"', '"', false); QString priority_text = Seer::parseFirst(task_text, "priority=", '"', '"', false); QString state_text = Seer::parseFirst(task_text, "state=", '"', '"', false); QString name_text = Seer::parseFirst(task_text, "name=", '"', '"', false); // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, current_text); item->setText(1, id_text); item->setText(2, taskid_text); item->setText(3, threadid_text); item->setText(4, parentid_text); item->setText(5, priority_text); item->setText(6, state_text); item->setText(7, name_text); // Add the frame to the tree. adaTaskTreeWidget->addTopLevelItem(item); } } // Clear the selection and select the one for the current thread-id. adaTaskTreeWidget->clearSelection(); QList matches = adaTaskTreeWidget->findItems("*", Qt::MatchExactly, 0); if (matches.size() > 0) { adaTaskTreeWidget->setCurrentItem(matches.first()); } }else{ // Ignore others. } adaTaskTreeWidget->resizeColumnToContents(0); adaTaskTreeWidget->resizeColumnToContents(1); adaTaskTreeWidget->resizeColumnToContents(2); adaTaskTreeWidget->resizeColumnToContents(3); adaTaskTreeWidget->resizeColumnToContents(4); adaTaskTreeWidget->resizeColumnToContents(5); adaTaskTreeWidget->resizeColumnToContents(6); adaTaskTreeWidget->resizeColumnToContents(7); QApplication::restoreOverrideCursor(); } void SeerAdaTasksBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } refresh(); } void SeerAdaTasksBrowserWidget::handleSessionTerminated () { // Delete previous contents. adaTaskTreeWidget->clear(); } void SeerAdaTasksBrowserWidget::handleItemClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedThread(item->text(3).toInt()); } void SeerAdaTasksBrowserWidget::refresh () { emit refreshAdaTasks(); } void SeerAdaTasksBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } seer-2.7/src/SeerAdaTasksBrowserWidget.h000066400000000000000000000021571516472651200203200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerAdaTasksBrowserWidget.h" class SeerAdaTasksBrowserWidget : public QWidget, protected Ui::SeerAdaTasksBrowserWidgetForm { Q_OBJECT public: explicit SeerAdaTasksBrowserWidget (QWidget* parent = 0); ~SeerAdaTasksBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemClicked (QTreeWidgetItem* item, int column); signals: void refreshAdaTasks (); void selectedThread (int threadid); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerAdaTasksBrowserWidget.ui000066400000000000000000000032311516472651200205000ustar00rootroot00000000000000 SeerAdaTasksBrowserWidgetForm 0 0 794 528 Form QAbstractItemView::SingleSelection 8 Active Id Task Id Thread Id Parent Id Priority State Name seer-2.7/src/SeerArgumentsDialog.cpp000066400000000000000000000012271516472651200175320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerArgumentsDialog.h" SeerArgumentsDialog::SeerArgumentsDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setExecutableArguments(""); // Connect things. } SeerArgumentsDialog::~SeerArgumentsDialog () { } void SeerArgumentsDialog::setExecutableArguments (const QString& executableArguments) { executableArgumentsLineEdit->setText(executableArguments); } QString SeerArgumentsDialog::executableArguments () { return executableArgumentsLineEdit->text(); } seer-2.7/src/SeerArgumentsDialog.h000066400000000000000000000012001516472651200171660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerArgumentsDialog.h" class SeerArgumentsDialog : public QDialog, protected Ui::SeerArgumentsDialogForm { Q_OBJECT public: explicit SeerArgumentsDialog (QWidget* parent = 0); ~SeerArgumentsDialog (); void setExecutableArguments (const QString& executableArguments); QString executableArguments (); public slots: private: }; seer-2.7/src/SeerArgumentsDialog.ui000066400000000000000000000037221516472651200173670ustar00rootroot00000000000000 SeerArgumentsDialogForm 0 0 375 121 Select Executable Arguments to Use Executable Arguments Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerArgumentsDialogForm accept() 187 97 187 60 buttonBox rejected() SeerArgumentsDialogForm reject() 187 97 187 60 seer-2.7/src/SeerArrayVisualizerWidget.cpp000066400000000000000000001172251516472651200207530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerArrayVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SeerArrayVisualizerWidget::SeerArrayVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _aVariableId = Seer::createID(); // Create id's for A queries. _aMemoryId = Seer::createID(); _aLengthId = Seer::createID(); _aOffsetId = Seer::createID(); _aStrideId = Seer::createID(); _bVariableId = Seer::createID(); // Create id's for B queries. _bMemoryId = Seer::createID(); _bLengthId = Seer::createID(); _bOffsetId = Seer::createID(); _bStrideId = Seer::createID(); _aSeries = 0; _bSeries = 0; // Set up UI. setupUi(this); // Setup the widgets setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer Array Visualizer"); setAttribute(Qt::WA_DeleteOnClose); arrayTableWidget->setAAxis(aAxisComboBox->currentText()); arrayTableWidget->setBAxis(bAxisComboBox->currentText()); lineRadioButton->setChecked(true); aArrayDisplayFormatComboBox->setCurrentIndex(0); bArrayDisplayFormatComboBox->setCurrentIndex(0); handleaArrayDisplayFormatComboBox(0); handlebArrayDisplayFormatComboBox(0); aVariableNameLineEdit->enableReturnPressedOnClear(); bVariableNameLineEdit->enableReturnPressedOnClear(); // A single series chart. QChart* chart = new QChart; chart->legend()->hide(); chart->createDefaultAxes(); chart->legend()->setVisible(true); chart->legend()->setAlignment(Qt::AlignBottom); arrayChartView->setRenderHint(QPainter::Antialiasing); arrayChartView->setChart(chart); arrayChartView->setFocusPolicy(Qt::StrongFocus); // Connect things. QObject::connect(aRefreshToolButton, &QToolButton::clicked, this, &SeerArrayVisualizerWidget::handleaRefreshButton); QObject::connect(bRefreshToolButton, &QToolButton::clicked, this, &SeerArrayVisualizerWidget::handlebRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerArrayVisualizerWidget::handleHelpButton); QObject::connect(aVariableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleaVariableNameLineEdit); QObject::connect(aVariableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleaVariableNameLineEdit); QObject::connect(aArrayLengthLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleaRefreshButton); QObject::connect(aArrayLengthLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleaElementLengthLineEdit); QObject::connect(aArrayOffsetLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleaRefreshButton); QObject::connect(aArrayOffsetLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleaElementOffsetLineEdit); QObject::connect(aArrayStrideLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleaRefreshButton); QObject::connect(aArrayStrideLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleaElementStrideLineEdit); QObject::connect(aArrayDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerArrayVisualizerWidget::handleaArrayDisplayFormatComboBox); QObject::connect(aAxisComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerArrayVisualizerWidget::handleaAxisComboBox); QObject::connect(bVariableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handlebVariableNameLineEdit); QObject::connect(bVariableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handlebVariableNameLineEdit); QObject::connect(bArrayLengthLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handlebRefreshButton); QObject::connect(bArrayLengthLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handlebElementLengthLineEdit); QObject::connect(bArrayOffsetLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handlebRefreshButton); QObject::connect(bArrayOffsetLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handlebElementOffsetLineEdit); QObject::connect(bArrayStrideLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handlebRefreshButton); QObject::connect(bArrayStrideLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handlebElementStrideLineEdit); QObject::connect(bArrayDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerArrayVisualizerWidget::handlebArrayDisplayFormatComboBox); QObject::connect(bAxisComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerArrayVisualizerWidget::handlebAxisComboBox); QObject::connect(arrayTableWidget, &SeerArrayWidget::dataChanged, this, &SeerArrayVisualizerWidget::handleDataChanged); QObject::connect(splitter, &QSplitter::splitterMoved, this, &SeerArrayVisualizerWidget::handleSplitterMoved); QObject::connect(titleLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleTitleLineEdit); QObject::connect(titleLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleTitleLineEdit); QObject::connect(pointsCheckBox, &QCheckBox::clicked, this, &SeerArrayVisualizerWidget::handlePointsCheckBox); QObject::connect(labelsCheckBox, &QCheckBox::clicked, this, &SeerArrayVisualizerWidget::handleLabelsCheckBox); QObject::connect(lineTypeButtonGroup, QOverload::of(&QButtonGroup::idClicked), this, &SeerArrayVisualizerWidget::handleLineTypeButtonGroup); QObject::connect(printPushButton, &QPushButton::clicked, arrayChartView, &QZoomChartView::printView); // Restore window settings. readSettings(); } SeerArrayVisualizerWidget::~SeerArrayVisualizerWidget () { } void SeerArrayVisualizerWidget::setAVariableName (const QString& name) { setWindowTitle("Seer Array Visualizer - '" + name + "'"); aVariableNameLineEdit->setText(name); if (aVariableNameLineEdit->text() == "") { aVariableAddressLineEdit->setText(""); aArrayLengthLineEdit->setText(""); aArrayOffsetLineEdit->setText(""); aArrayStrideLineEdit->setText(""); arrayTableWidget->setAData("deleted", 0); return; } setAVariableAddress(""); // Clear old contents. QByteArray array; bool ok; arrayTableWidget->setAData(name, new SeerArrayWidget::DataStorageArray(array)); if (aArrayOffsetLineEdit->text() != "") { arrayTableWidget->setAAddressOffset(aArrayOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << aArrayOffsetLineEdit->text(); } }else{ arrayTableWidget->setAAddressOffset(0); } if (aArrayStrideLineEdit->text() != "") { arrayTableWidget->setAAddressStride(aArrayStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << aArrayStrideLineEdit->text(); } }else{ arrayTableWidget->setAAddressStride(1); } // Send signal to get variable address. emit evaluateVariableExpression(_aVariableId, aVariableNameLineEdit->text()); } QString SeerArrayVisualizerWidget::aVariableName () const { return aVariableNameLineEdit->text(); } void SeerArrayVisualizerWidget::setAVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; if (address == "") { aVariableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { aVariableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { aVariableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } if (ok == false) { aVariableAddressLineEdit->setText("not an address"); offset = 0; } } arrayTableWidget->setAAddressOffset(0); } QString SeerArrayVisualizerWidget::aVariableAddress () const { return aVariableAddressLineEdit->text(); } void SeerArrayVisualizerWidget::setAVariableLength (const QString& length) { aArrayLengthLineEdit->setText(length); } QString SeerArrayVisualizerWidget::aVariableLength () const { return aArrayLengthLineEdit->text(); } void SeerArrayVisualizerWidget::setAVariableOffset (const QString& offset) { aArrayOffsetLineEdit->setText(offset); } QString SeerArrayVisualizerWidget::aVariableOffset () const { return aArrayOffsetLineEdit->text(); } void SeerArrayVisualizerWidget::setAVariableStride (const QString& stride) { aArrayStrideLineEdit->setText(stride); } QString SeerArrayVisualizerWidget::aVariableStride () const { return aArrayStrideLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableName (const QString& name) { setWindowTitle("Seer Array Visualizer - '" + name + "'"); bVariableNameLineEdit->setText(name); if (bVariableNameLineEdit->text() == "") { bVariableAddressLineEdit->setText(""); bArrayLengthLineEdit->setText(""); bArrayOffsetLineEdit->setText(""); bArrayStrideLineEdit->setText(""); arrayTableWidget->setBData("deleted", 0); return; } setBVariableAddress(""); // Clear old contents. QByteArray array; bool ok; arrayTableWidget->setBData(name, new SeerArrayWidget::DataStorageArray(array)); if (bArrayOffsetLineEdit->text() != "") { arrayTableWidget->setBAddressOffset(bArrayOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << bArrayOffsetLineEdit->text(); } }else{ arrayTableWidget->setBAddressOffset(0); } if (bArrayStrideLineEdit->text() != "") { arrayTableWidget->setBAddressStride(bArrayStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << bArrayStrideLineEdit->text(); } }else{ arrayTableWidget->setBAddressStride(1); } // Send signal to get variable address. emit evaluateVariableExpression(_bVariableId, bVariableNameLineEdit->text()); } QString SeerArrayVisualizerWidget::bVariableName () const { return bVariableNameLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; if (address == "") { bVariableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { bVariableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { bVariableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } if (ok == false) { bVariableAddressLineEdit->setText("not an address"); offset = 0; } } arrayTableWidget->setBAddressOffset(0); } QString SeerArrayVisualizerWidget::bVariableAddress () const { return bVariableAddressLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableLength (const QString& length) { bArrayLengthLineEdit->setText(length); } QString SeerArrayVisualizerWidget::bVariableLength () const { return bArrayLengthLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableOffset (const QString& offset) { bArrayOffsetLineEdit->setText(offset); } QString SeerArrayVisualizerWidget::bVariableOffset () const { return bArrayOffsetLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableStride (const QString& stride) { bArrayStrideLineEdit->setText(stride); } QString SeerArrayVisualizerWidget::bVariableStride () const { return bArrayStrideLineEdit->text(); } void SeerArrayVisualizerWidget::handleText (const QString& text) { //qDebug() << text; if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 11^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _aVariableId) { QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString address = ""; // Look for an address in the value. if (address == "") { QRegularExpression re("0[xX][0-9a-fA-F]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Look for a number in the value. if (address == "") { QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Set the variable address. setAVariableAddress(address); } if (id_text.toInt() == _aLengthId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setAVariableLength(value_text); handleaRefreshButton(); } if (id_text.toInt() == _aOffsetId) { // Set the memory offset. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setAVariableOffset(value_text); handleaRefreshButton(); } if (id_text.toInt() == _aStrideId) { // Set the memory stride. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setAVariableStride(value_text); handleaRefreshButton(); } if (id_text.toInt() == _bVariableId) { QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString address = ""; // Look for an address in the value. if (address == "") { QRegularExpression re("0[xX][0-9a-fA-F]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Look for a number in the value. if (address == "") { QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Set the variable address. setBVariableAddress(address); } if (id_text.toInt() == _bLengthId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setBVariableLength(value_text); handlebRefreshButton(); } if (id_text.toInt() == _bOffsetId) { // Set the memory offset. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setBVariableOffset(value_text); handlebRefreshButton(); } if (id_text.toInt() == _bStrideId) { // Set the memory stride. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setBVariableStride(value_text); handlebRefreshButton(); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { // 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}] // 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}] QString id_text = text.section('^', 0,0); if (id_text.toInt() == _aMemoryId) { QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetAData(arrayTableWidget->aLabel(), new SeerArrayWidget::DataStorageArray(array)); if (aArrayOffsetLineEdit->text() != "") { arrayTableWidget->setAAddressOffset(aArrayOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << aArrayOffsetLineEdit->text(); } }else{ arrayTableWidget->setAAddressOffset(0); } if (aArrayStrideLineEdit->text() != "") { arrayTableWidget->setAAddressStride(aArrayStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << aArrayStrideLineEdit->text(); } }else{ arrayTableWidget->setAAddressStride(1); } break; // Take just the first range for now. } } if (id_text.toInt() == _bMemoryId) { QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetBData(arrayTableWidget->bLabel(), new SeerArrayWidget::DataStorageArray(array)); if (bArrayOffsetLineEdit->text() != "") { arrayTableWidget->setBAddressOffset(bArrayOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << bArrayOffsetLineEdit->text(); } }else{ arrayTableWidget->setBAddressOffset(0); } if (bArrayStrideLineEdit->text() != "") { arrayTableWidget->setBAddressStride(bArrayStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << bArrayStrideLineEdit->text(); } }else{ arrayTableWidget->setBAddressStride(1); } break; // Take just the first range for now. } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." // 3^error,msg="Unable to read memory." QString id_text = text.section('^', 0,0); if (id_text.toInt() == _aVariableId) { aVariableAddressLineEdit->setText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); } if (id_text.toInt() == _aMemoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } } if (id_text.toInt() == _aLengthId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); aArrayLengthLineEdit->setText(""); aArrayLengthLineEdit->setFocus(); } if (id_text.toInt() == _aOffsetId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); aArrayOffsetLineEdit->setText(""); aArrayOffsetLineEdit->setFocus(); } if (id_text.toInt() == _aStrideId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); aArrayStrideLineEdit->setText(""); aArrayStrideLineEdit->setFocus(); } if (id_text.toInt() == _bVariableId) { bVariableAddressLineEdit->setText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); } if (id_text.toInt() == _bMemoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } } if (id_text.toInt() == _bLengthId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); bArrayLengthLineEdit->setText(""); bArrayLengthLineEdit->setFocus(); } if (id_text.toInt() == _bOffsetId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); bArrayOffsetLineEdit->setText(""); bArrayOffsetLineEdit->setFocus(); } if (id_text.toInt() == _bStrideId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); bArrayStrideLineEdit->setText(""); bArrayStrideLineEdit->setFocus(); } }else{ // Ignore anything else. } } void SeerArrayVisualizerWidget::handleaRefreshButton () { if (aVariableNameLineEdit->text() == "") { return; } if (aVariableAddressLineEdit->text() == "") { return; } if (aVariableAddressLineEdit->text() == "not an address") { return; } int bytes = aArrayLengthLineEdit->text().toInt() * Seer::typeBytes(aArrayDisplayFormatComboBox->currentText()); //qDebug() << _aMemoryId << aVariableAddressLineEdit->text() << aArrayLengthLineEdit->text() << aArrayDisplayFormatComboBox->currentText() << bytes; emit evaluateMemoryExpression(_aMemoryId, aVariableAddressLineEdit->text(), bytes); } void SeerArrayVisualizerWidget::handlebRefreshButton () { if (bVariableNameLineEdit->text() == "") { return; } if (bVariableAddressLineEdit->text() == "") { return; } if (bVariableAddressLineEdit->text() == "not an address") { return; } int bytes = bArrayLengthLineEdit->text().toInt() * Seer::typeBytes(bArrayDisplayFormatComboBox->currentText()); //qDebug() << _bMemoryId << bVariableAddressLineEdit->text() << bArrayLengthLineEdit->text() << bArrayDisplayFormatComboBox->currentText() << bytes; emit evaluateMemoryExpression(_bMemoryId, bVariableAddressLineEdit->text(), bytes); } void SeerArrayVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/ArrayVisualizer.md"); help->show(); help->raise(); } void SeerArrayVisualizerWidget::handleaVariableNameLineEdit () { setAVariableName (aVariableNameLineEdit->text()); } void SeerArrayVisualizerWidget::handlebVariableNameLineEdit () { setBVariableName (bVariableNameLineEdit->text()); } void SeerArrayVisualizerWidget::handleaElementLengthLineEdit () { if (aVariableLength() == "") { return; } emit evaluateVariableExpression(_aLengthId, aVariableLength()); } void SeerArrayVisualizerWidget::handleaElementOffsetLineEdit () { if (aVariableOffset() == "") { return; } emit evaluateVariableExpression(_aOffsetId, aVariableOffset()); } void SeerArrayVisualizerWidget::handleaElementStrideLineEdit () { if (aVariableStride() == "") { return; } emit evaluateVariableExpression(_aStrideId, aVariableStride()); } void SeerArrayVisualizerWidget::handlebElementLengthLineEdit () { if (bVariableLength() == "") { return; } emit evaluateVariableExpression(_bLengthId, bVariableLength()); } void SeerArrayVisualizerWidget::handlebElementOffsetLineEdit () { if (bVariableOffset() == "") { return; } emit evaluateVariableExpression(_bOffsetId, bVariableOffset()); } void SeerArrayVisualizerWidget::handlebElementStrideLineEdit () { if (bVariableStride() == "") { return; } emit evaluateVariableExpression(_bStrideId, bVariableStride()); } void SeerArrayVisualizerWidget::handleaArrayDisplayFormatComboBox (int index) { //qDebug() << index; if (index == 0) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Int16ArrayMode); }else if (index == 1) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Int32ArrayMode); }else if (index == 2) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Int64ArrayMode); }else if (index == 3) { arrayTableWidget->setAArrayMode(SeerArrayWidget::UInt16ArrayMode); }else if (index == 4) { arrayTableWidget->setAArrayMode(SeerArrayWidget::UInt32ArrayMode); }else if (index == 5) { arrayTableWidget->setAArrayMode(SeerArrayWidget::UInt64ArrayMode); }else if (index == 6) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Float32ArrayMode); }else if (index == 7) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Float64ArrayMode); }else{ // Do nothing. } handleaRefreshButton(); } void SeerArrayVisualizerWidget::handlebArrayDisplayFormatComboBox (int index) { //qDebug() << index; if (index == 0) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Int16ArrayMode); }else if (index == 1) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Int32ArrayMode); }else if (index == 2) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Int64ArrayMode); }else if (index == 3) { arrayTableWidget->setBArrayMode(SeerArrayWidget::UInt16ArrayMode); }else if (index == 4) { arrayTableWidget->setBArrayMode(SeerArrayWidget::UInt32ArrayMode); }else if (index == 5) { arrayTableWidget->setBArrayMode(SeerArrayWidget::UInt64ArrayMode); }else if (index == 6) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Float32ArrayMode); }else if (index == 7) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Float64ArrayMode); }else{ // Do nothing. } handlebRefreshButton(); } void SeerArrayVisualizerWidget::handleaAxisComboBox (int index) { arrayTableWidget->setAAxis(aAxisComboBox->itemText(index)); handleDataChanged(); } void SeerArrayVisualizerWidget::handlebAxisComboBox (int index) { arrayTableWidget->setBAxis(bAxisComboBox->itemText(index)); handleDataChanged(); } void SeerArrayVisualizerWidget::handleDataChanged () { // Delete old series. if (_aSeries) { arrayChartView->chart()->removeSeries(_aSeries); arrayChartView->chart()->update(); delete _aSeries; _aSeries = 0; } if (_bSeries) { arrayChartView->chart()->removeSeries(_bSeries); arrayChartView->chart()->update(); delete _bSeries; _bSeries = 0; } // If only the first array is defined, create a series for it. // Handle the X and Y axis. if (arrayTableWidget->aSize() > 0 && arrayTableWidget->bSize() == 0) { createASeries(); // If only the second array is defined, create a series for it. // Handle the X and Y axis. }else if (arrayTableWidget->aSize() == 0 && arrayTableWidget->bSize() > 0) { createBSeries(); } else if (arrayTableWidget->aSize() > 0 && arrayTableWidget->bSize() > 0) { // If the axis is the same for the two arrays, plot them as // two unique series. if (arrayTableWidget->aAxis() == arrayTableWidget->bAxis()) { createASeries(); createBSeries(); // Otherwise, we have an X and Y axis. // Plot one series using the two arrays as an X and as a Y. }else{ if (scatterRadioButton->isChecked()) { QScatterSeries* scatter = new QScatterSeries; scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); scatter->setMarkerSize(7); _aSeries = scatter; }else if (lineRadioButton->isChecked()) { QLineSeries* line = new QLineSeries; _aSeries = line; }else if (splineRadioButton->isChecked()) { QSplineSeries* line = new QSplineSeries; _aSeries = line; }else{ qWarning() << "Invalid line type."; return; } _aSeries->setPointsVisible(false); _aSeries->setPointLabelsVisible(false); _aSeries->setPointLabelsClipping(true); const QVector& xvalues = arrayTableWidget->aArrayValues(); const QVector& yvalues = arrayTableWidget->bArrayValues(); if (arrayTableWidget->aAxis() == "Y" && arrayTableWidget->bAxis() == "X") { for (int i = 0; i < std::min(xvalues.size(),yvalues.size()); ++i) { _aSeries->append(xvalues[i], yvalues[i]); } }else if (arrayTableWidget->aAxis() == "X" && arrayTableWidget->bAxis() == "Y") { for (int i = 0; i < std::min(xvalues.size(),yvalues.size()); ++i) { _aSeries->append(yvalues[i], xvalues[i]); } }else{ qWarning() << "Invalid axis type of '" << arrayTableWidget->aAxis() << "'. Not 'X' or 'Y'."; } _aSeries->setName(aVariableName() + "/" + bVariableName()); _aSeries->setName(QString("%1:%2:%3 | %4:%5:%6") .arg(arrayTableWidget->aLabel()).arg(arrayTableWidget->aAddressOffset()).arg(arrayTableWidget->aAddressStride()) .arg(arrayTableWidget->bLabel()).arg(arrayTableWidget->bAddressOffset()).arg(arrayTableWidget->bAddressStride())); } } if (_aSeries) { QObject::connect(_aSeries, &QLineSeries::hovered, this, &SeerArrayVisualizerWidget::handleSeriesHovered); arrayChartView->chart()->addSeries(_aSeries); arrayChartView->chart()->createDefaultAxes(); } if (_bSeries) { QObject::connect(_bSeries, &QLineSeries::hovered, this, &SeerArrayVisualizerWidget::handleSeriesHovered); arrayChartView->chart()->addSeries(_bSeries); arrayChartView->chart()->createDefaultAxes(); } // Zoom out slightly to allow for text label at edges. arrayChartView->chart()->zoomReset(); arrayChartView->chart()->zoom(.9); arrayChartView->chart()->update(); // Check for points or labels to be shown. handlePointsCheckBox(); handleLabelsCheckBox(); } void SeerArrayVisualizerWidget::writeSettings() { QSettings settings; settings.beginGroup("arrayvisualizerwindow"); { settings.setValue("size", size()); settings.setValue("splitter", splitter->saveState()); } settings.endGroup(); } void SeerArrayVisualizerWidget::readSettings() { QSettings settings; settings.beginGroup("arrayvisualizerwindow"); { resize(settings.value("size", QSize(800, 400)).toSize()); splitter->restoreState(settings.value("splitter").toByteArray()); } settings.endGroup(); } void SeerArrayVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } void SeerArrayVisualizerWidget::handleSplitterMoved (int pos, int index) { Q_UNUSED(pos); Q_UNUSED(index); writeSettings(); } void SeerArrayVisualizerWidget::handleSeriesHovered (const QPointF& point, bool state) { //qDebug() << "QPointF=" << point << "State=" << state << "MapToPosition=" << arrayChartView->chart()->mapToPosition(point) << "MapFromScene=" << arrayChartView->mapFromScene(arrayChartView->chart()->mapToPosition(point)); if (state) { QToolTip::showText(arrayChartView->mapToGlobal(arrayChartView->mapFromScene(arrayChartView->chart()->mapToPosition(point))), QString("%1 / %2").arg(point.x()).arg(point.y()), this, QRect(), 10000); }else{ QToolTip::hideText(); } } void SeerArrayVisualizerWidget::handleTitleLineEdit () { arrayChartView->chart()->setTitle(titleLineEdit->text()); titleLineEdit->setText(""); } void SeerArrayVisualizerWidget::handlePointsCheckBox () { if (_aSeries) { _aSeries->setPointsVisible(pointsCheckBox->isChecked()); arrayChartView->chart()->update(); } if (_bSeries) { _bSeries->setPointsVisible(pointsCheckBox->isChecked()); arrayChartView->chart()->update(); } } void SeerArrayVisualizerWidget::handleLabelsCheckBox () { if (_aSeries) { _aSeries->setPointLabelsVisible(labelsCheckBox->isChecked()); arrayChartView->chart()->update(); } if (_bSeries) { _bSeries->setPointLabelsVisible(labelsCheckBox->isChecked()); arrayChartView->chart()->update(); } } void SeerArrayVisualizerWidget::handleLineTypeButtonGroup () { handleDataChanged(); } void SeerArrayVisualizerWidget::createASeries() { if (scatterRadioButton->isChecked()) { QScatterSeries* scatter = new QScatterSeries; scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); scatter->setMarkerSize(7); _aSeries = scatter; }else if (lineRadioButton->isChecked()) { QLineSeries* line = new QLineSeries; _aSeries = line; }else if (splineRadioButton->isChecked()) { QSplineSeries* line = new QSplineSeries; _aSeries = line; }else{ qWarning() << "Invalid line type."; return; } _aSeries->setPointsVisible(false); _aSeries->setPointLabelsVisible(false); _aSeries->setPointLabelsClipping(true); const QVector& values = arrayTableWidget->aArrayValues(); if (arrayTableWidget->aAxis() == "Y") { for (int i = 0; i < values.size(); ++i) { _aSeries->append(i, values[i]); } }else if (arrayTableWidget->aAxis() == "X") { for (int i = 0; i < values.size(); ++i) { _aSeries->append(values[i], i); } }else{ qWarning() << "Invalid axis type of '" << arrayTableWidget->aAxis() << "'. Not 'X' or 'Y'."; } _aSeries->setName(QString("%1:%2:%3").arg(arrayTableWidget->aLabel()).arg(arrayTableWidget->aAddressOffset()).arg(arrayTableWidget->aAddressStride())); } void SeerArrayVisualizerWidget::createBSeries() { if (scatterRadioButton->isChecked()) { QScatterSeries* scatter = new QScatterSeries; scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); scatter->setMarkerSize(7); _bSeries = scatter; }else if (lineRadioButton->isChecked()) { QLineSeries* line = new QLineSeries; _bSeries = line; }else if (splineRadioButton->isChecked()) { QSplineSeries* line = new QSplineSeries; _bSeries = line; }else{ qWarning() << "Invalid line type."; return; } _bSeries->setPointsVisible(false); _bSeries->setPointLabelsVisible(false); _bSeries->setPointLabelsClipping(true); const QVector& values = arrayTableWidget->bArrayValues(); if (arrayTableWidget->bAxis() == "Y") { for (int i = 0; i < values.size(); ++i) { _bSeries->append(i, values[i]); } }else if (arrayTableWidget->bAxis() == "X") { for (int i = 0; i < values.size(); ++i) { _bSeries->append(values[i], i); } }else{ qWarning() << "Invalid axis type of '" << arrayTableWidget->bAxis() << "'. Not 'X' or 'Y'."; } _bSeries->setName(QString("%1:%2:%3").arg(arrayTableWidget->bLabel()).arg(arrayTableWidget->bAddressOffset()).arg(arrayTableWidget->bAddressStride())); } seer-2.7/src/SeerArrayVisualizerWidget.h000066400000000000000000000114711516472651200204140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerArrayVisualizerWidget.h" class SeerArrayVisualizerWidget : public QWidget, protected Ui::SeerArrayVisualizerWidgetForm { Q_OBJECT public: explicit SeerArrayVisualizerWidget (QWidget* parent = 0); ~SeerArrayVisualizerWidget (); void setAVariableName (const QString& name); QString aVariableName () const; void setAVariableAddress (const QString& address); QString aVariableAddress () const; void setAVariableLength (const QString& length); QString aVariableLength () const; void setAVariableOffset (const QString& offset); QString aVariableOffset () const; void setAVariableStride (const QString& stride); QString aVariableStride () const; void setBVariableName (const QString& name); QString bVariableName () const; void setBVariableAddress (const QString& address); QString bVariableAddress () const; void setBVariableLength (const QString& length); QString bVariableLength () const; void setBVariableOffset (const QString& offset); QString bVariableOffset () const; void setBVariableStride (const QString& stride); QString bVariableStride () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void evaluateMemoryExpression (int expressionid, QString address, int count); public slots: void handleText (const QString& text); protected slots: void handleaRefreshButton (); void handlebRefreshButton (); void handleHelpButton (); void handleaVariableNameLineEdit (); void handlebVariableNameLineEdit (); void handleaElementLengthLineEdit (); void handlebElementLengthLineEdit (); void handleaElementOffsetLineEdit (); void handlebElementOffsetLineEdit (); void handleaElementStrideLineEdit (); void handlebElementStrideLineEdit (); void handleaArrayDisplayFormatComboBox (int index); void handlebArrayDisplayFormatComboBox (int index); void handleaAxisComboBox (int index); void handlebAxisComboBox (int index); void handleDataChanged (); void handleSplitterMoved (int pos, int index); void handleSeriesHovered (const QPointF& point, bool state); void handleTitleLineEdit (); void handlePointsCheckBox (); void handleLabelsCheckBox (); void handleLineTypeButtonGroup (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: void createASeries (); void createBSeries (); QXYSeries* _aSeries; QXYSeries* _bSeries; int _aVariableId; int _bVariableId; int _aMemoryId; int _aLengthId; int _aOffsetId; int _aStrideId; int _bMemoryId; int _bLengthId; int _bOffsetId; int _bStrideId; }; seer-2.7/src/SeerArrayVisualizerWidget.ui000066400000000000000000000412231516472651200206000ustar00rootroot00000000000000 SeerArrayVisualizerWidgetForm 0 0 972 704 Form Element stride between values. (default=1) Array stride true Array data type. int16 int32 int64 uint16 uint32 uint64 float32 float64 Element stride between values. (default=1) Array stride true Total number of elements in array. # elements true Variable name or expression. Variable name true Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Element offset into array. (default=0) Array offset true Total number of elements in array. # elements true Array data type. int16 int32 int64 uint16 uint32 uint64 float32 float64 Variable address. true Variable address false Element offset into array. (default=0) Array offset true Variable address. true Variable address false Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Variable name or expression. Variable name true Variable axis type. Y Y X Variable axis type. Y Y X 0 0 Qt::Horizontal 1 0 QLayout::SetDefaultConstraint 100 0 0 0 Set chart title. chart title true Qt::Vertical Line lineTypeButtonGroup Spline lineTypeButtonGroup Scatter lineTypeButtonGroup Qt::Vertical Show chart data points. Points Show chart data labels. Labels Qt::Vertical Print the chart. :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Help on Array Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg SeerArrayWidget QTableWidget
SeerArrayWidget.h
QZoomChartView QGraphicsView
QZoomChartView.h
SeerHistoryLineEdit QLineEdit
SeerHistoryLineEdit.h
aAxisComboBox aVariableNameLineEdit aVariableAddressLineEdit aArrayLengthLineEdit aArrayOffsetLineEdit aArrayStrideLineEdit aArrayDisplayFormatComboBox aRefreshToolButton bAxisComboBox bVariableNameLineEdit bVariableAddressLineEdit bArrayLengthLineEdit bArrayOffsetLineEdit bArrayStrideLineEdit bArrayDisplayFormatComboBox bRefreshToolButton arrayTableWidget arrayChartView titleLineEdit lineRadioButton splineRadioButton scatterRadioButton pointsCheckBox labelsCheckBox printPushButton helpToolButton
seer-2.7/src/SeerArrayWidget.cpp000066400000000000000000000351721516472651200166750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerArrayWidget.h" #include "SeerUtl.h" #include #include #include SeerArrayWidget::SeerArrayWidget(QWidget* parent) : QTableWidget(parent) { QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); setFont(font); setFocusPolicy(Qt::StrongFocus); setEditTriggers(QAbstractItemView::NoEditTriggers); horizontalHeader()->setDefaultAlignment(Qt::AlignRight); _aData = 0; _aAxis = "Y"; _aArrayMode = SeerArrayWidget::UnknownArrayMode; _aAddressOffset = 0; _aAddressStride = 1; _bData = 0; _bAxis = "X"; _bArrayMode = SeerArrayWidget::UnknownArrayMode; _bAddressOffset = 0; _bAddressStride = 1; setAAddressOffset(0); setAAddressStride(1); setBAddressOffset(0); setBAddressStride(1); } SeerArrayWidget::~SeerArrayWidget() { if (_aData) { delete _aData; } if (_bData) { delete _bData; } } int SeerArrayWidget::elementsPerLine () const { return 1; } const QString& SeerArrayWidget::aAxis () const { return _aAxis; } void SeerArrayWidget::setAAxis (const QString& axis) { _aAxis = axis; } const QString& SeerArrayWidget::aLabel () const { return _aLabel; } void SeerArrayWidget::setAAddressOffset (unsigned long offset) { _aAddressOffset = offset; // Repaint the widget. create(); } unsigned long SeerArrayWidget::aAddressOffset () const { return _aAddressOffset; } void SeerArrayWidget::setAAddressStride (unsigned long stride) { if (stride < 1) { qWarning() << "Stride is not valid." << stride; stride = 1; } _aAddressStride = stride; // Repaint the widget. create(); } unsigned long SeerArrayWidget::aAddressStride () const { return _aAddressStride; } unsigned long SeerArrayWidget::aSize () const { if (_aData) { return _aData->size(); } return 0; } unsigned long SeerArrayWidget::aElementSize () const { if (aArrayMode() == SeerArrayWidget::Int16ArrayMode) { return 2; }else if (aArrayMode() == SeerArrayWidget::UInt16ArrayMode) { return 2; }else if (aArrayMode() == SeerArrayWidget::Int32ArrayMode) { return 4; }else if (aArrayMode() == SeerArrayWidget::UInt32ArrayMode) { return 4; }else if (aArrayMode() == SeerArrayWidget::Int64ArrayMode) { return 8; }else if (aArrayMode() == SeerArrayWidget::UInt64ArrayMode) { return 8; }else if (aArrayMode() == SeerArrayWidget::Float32ArrayMode) { return 4; }else if (aArrayMode() == SeerArrayWidget::Float64ArrayMode) { return 8; } return 0; } void SeerArrayWidget::setAArrayMode (SeerArrayWidget::ArrayMode arrayMode) { _aArrayMode = arrayMode; // This repaints the widget with the new array mode create(); } SeerArrayWidget::ArrayMode SeerArrayWidget::aArrayMode () const { return _aArrayMode; } QString SeerArrayWidget::aArrayModeString () const { if (aArrayMode() == SeerArrayWidget::Int16ArrayMode) { return "int8"; }else if (aArrayMode() == SeerArrayWidget::UInt16ArrayMode) { return "uint16"; }else if (aArrayMode() == SeerArrayWidget::Int32ArrayMode) { return "int32"; }else if (aArrayMode() == SeerArrayWidget::UInt32ArrayMode) { return "uint32"; }else if (aArrayMode() == SeerArrayWidget::Int64ArrayMode) { return "int64"; }else if (aArrayMode() == SeerArrayWidget::UInt64ArrayMode) { return "uint64"; }else if (aArrayMode() == SeerArrayWidget::Float32ArrayMode) { return "float32"; }else if (aArrayMode() == SeerArrayWidget::Float64ArrayMode) { return "float64"; } return "???"; } const QVector& SeerArrayWidget::aArrayValues () const { return _aArrayValues; } const QString& SeerArrayWidget::bAxis () const { return _bAxis; } void SeerArrayWidget::setBAxis (const QString& axis) { _bAxis = axis; } const QString& SeerArrayWidget::bLabel () const { return _bLabel; } void SeerArrayWidget::setBAddressOffset (unsigned long offset) { _bAddressOffset = offset; // Repaint the widget. create(); } unsigned long SeerArrayWidget::bAddressOffset () const { return _bAddressOffset; } void SeerArrayWidget::setBAddressStride (unsigned long stride) { if (stride < 1) { qWarning() << "Stride is not valid." << stride; stride = 1; } _bAddressStride = stride; // Repaint the widget. create(); } unsigned long SeerArrayWidget::bAddressStride () const { return _bAddressStride; } unsigned long SeerArrayWidget::bSize () const { if (_bData) { return _bData->size(); } return 0; } unsigned long SeerArrayWidget::bElementSize () const { if (bArrayMode() == SeerArrayWidget::Int16ArrayMode) { return 2; }else if (bArrayMode() == SeerArrayWidget::UInt16ArrayMode) { return 2; }else if (bArrayMode() == SeerArrayWidget::Int32ArrayMode) { return 4; }else if (bArrayMode() == SeerArrayWidget::UInt32ArrayMode) { return 4; }else if (bArrayMode() == SeerArrayWidget::Int64ArrayMode) { return 8; }else if (bArrayMode() == SeerArrayWidget::UInt64ArrayMode) { return 8; }else if (bArrayMode() == SeerArrayWidget::Float32ArrayMode) { return 4; }else if (bArrayMode() == SeerArrayWidget::Float64ArrayMode) { return 8; } return 0; } void SeerArrayWidget::setBArrayMode (SeerArrayWidget::ArrayMode arrayMode) { _bArrayMode = arrayMode; // This repaints the widget with the new array mode create(); } SeerArrayWidget::ArrayMode SeerArrayWidget::bArrayMode () const { return _bArrayMode; } QString SeerArrayWidget::bArrayModeString () const { if (bArrayMode() == SeerArrayWidget::Int16ArrayMode) { return "int8"; }else if (bArrayMode() == SeerArrayWidget::UInt16ArrayMode) { return "uint16"; }else if (bArrayMode() == SeerArrayWidget::Int32ArrayMode) { return "int32"; }else if (bArrayMode() == SeerArrayWidget::UInt32ArrayMode) { return "uint32"; }else if (bArrayMode() == SeerArrayWidget::Int64ArrayMode) { return "int64"; }else if (bArrayMode() == SeerArrayWidget::UInt64ArrayMode) { return "uint64"; }else if (bArrayMode() == SeerArrayWidget::Float32ArrayMode) { return "float32"; }else if (bArrayMode() == SeerArrayWidget::Float64ArrayMode) { return "float64"; } return "???"; } const QVector& SeerArrayWidget::bArrayValues () const { return _bArrayValues; } void SeerArrayWidget::setAData(const QString& label, SeerArrayWidget::DataStorage* pData) { if (_aData) { delete _aData; } _aLabel = label; _aData = pData; // Repaint the widget. create(); } void SeerArrayWidget::setBData(const QString& label, SeerArrayWidget::DataStorage* pData) { if (_bData) { delete _bData; } _bLabel = label; _bData = pData; // Repaint the widget. create(); } void SeerArrayWidget::create () { // Clear the table. We're going to recreate it. clear(); setRowCount(0); if (_aData && _bData) { setColumnCount(2); _aColumnId = 0; _bColumnId = 1; }else if (_aData) { setColumnCount(1); _aColumnId = 0; _bColumnId = -1; }else if (_bData) { setColumnCount(1); _aColumnId = -1; _bColumnId = 0; }else{ setColumnCount(0); _aColumnId = -1; _bColumnId = -1; } // Clear the values. _aArrayValues.resize(0); _bArrayValues.resize(0); // If there's no data, do nothing. if (!_aData && !_bData) { emit dataChanged(); return; } if (aElementSize() < 1 && bElementSize() < 1) { emit dataChanged(); return; } if (_aData) { //qDebug() << "_aData" << aElementSize() << aAddressOffset() << aAddressStride() << _aData->size(); setHorizontalHeaderItem(_aColumnId, new QTableWidgetItem(QString("%1:%2:%3").arg(aLabel()).arg(aAddressOffset()).arg(aAddressStride()))); int row = 0; for (int i=aElementSize()*aAddressOffset(); i<_aData->size(); i+=aElementSize()*aAddressStride()) { // Add new row if we need to. Set its label. if (row == rowCount()) { //qDebug() << "Adding row" << row << "for _aData"; insertRow(rowCount()); QTableWidgetItem* rowHeaderitem = new QTableWidgetItem(QString::number(row)); rowHeaderitem->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); setVerticalHeaderItem(row, rowHeaderitem); } QTableWidgetItem* item = new QTableWidgetItem; item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); QByteArray element = _aData->getData(i, aElementSize()); double val = 0.0; if (aArrayMode() == SeerArrayWidget::Int16ArrayMode) { short v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::UInt16ArrayMode) { unsigned short v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::Int32ArrayMode) { int v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::UInt32ArrayMode) { unsigned int v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::Int64ArrayMode) { long v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::UInt64ArrayMode) { unsigned long v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::Float32ArrayMode) { float v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::Float64ArrayMode) { double v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else{ qWarning() << "Unknown data type."; val = 0.0; } //qDebug() << "Adding item" << row << 0 << "for _aData"; setItem(row, _aColumnId, item); _aArrayValues.push_back(val); row++; } } if (_bData) { //qDebug() << "_bData" << bElementSize() << bAddressOffset() << bAddressStride() << _bData->size(); setHorizontalHeaderItem(_bColumnId, new QTableWidgetItem(QString("%1:%2:%3").arg(bLabel()).arg(bAddressOffset()).arg(bAddressStride()))); int row = 0; for (int i=bElementSize()*bAddressOffset(); i<_bData->size(); i+=bElementSize()*bAddressStride()) { // Add new row if we need to. Set its label. if (row == rowCount()) { //qDebug() << "Adding row" << row << "for _bData"; insertRow(rowCount()); QTableWidgetItem* rowHeaderitem = new QTableWidgetItem(QString::number(row)); rowHeaderitem->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); setVerticalHeaderItem(row, rowHeaderitem); } QTableWidgetItem* item = new QTableWidgetItem; item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); QByteArray element = _bData->getData(i, bElementSize()); double val = 0.0; if (bArrayMode() == SeerArrayWidget::Int16ArrayMode) { short v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::UInt16ArrayMode) { unsigned short v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::Int32ArrayMode) { int v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::UInt32ArrayMode) { unsigned int v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::Int64ArrayMode) { long v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::UInt64ArrayMode) { unsigned long v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::Float32ArrayMode) { float v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::Float64ArrayMode) { double v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else{ qWarning() << "Unknown data type."; val = 0.0; } //qDebug() << "Adding item" << row << 0 << "for _bData"; setItem(row, _bColumnId, item); _bArrayValues.push_back(val); row++; } } emit dataChanged(); } SeerArrayWidget::DataStorageArray::DataStorageArray(const QByteArray& arr) { _data = arr; } QByteArray SeerArrayWidget::DataStorageArray::getData(int position, int length) { return _data.mid(position, length); } int SeerArrayWidget::DataStorageArray::size() { return _data.size(); } seer-2.7/src/SeerArrayWidget.h000066400000000000000000000105651516472651200163410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerArrayWidget: public QTableWidget { Q_OBJECT public: class DataStorage { public: virtual ~DataStorage() {}; virtual QByteArray getData(int position, int length) = 0; virtual int size() = 0; }; class DataStorageArray: public DataStorage { public: DataStorageArray(const QByteArray& arr); virtual QByteArray getData(int position, int length); virtual int size(); private: QByteArray _data; }; enum ArrayMode { UnknownArrayMode = 0, Int16ArrayMode = 1, UInt16ArrayMode = 2, Int32ArrayMode = 3, UInt32ArrayMode = 4, Int64ArrayMode = 5, UInt64ArrayMode = 6, Float32ArrayMode = 7, Float64ArrayMode = 8 }; SeerArrayWidget(QWidget* parent = 0); ~SeerArrayWidget(); int elementsPerLine () const; const QString& aAxis () const; void setAAxis (const QString& axis); const QString& aLabel () const; void setAAddressOffset (unsigned long offset); unsigned long aAddressOffset () const; void setAAddressStride (unsigned long stride); unsigned long aAddressStride () const; unsigned long aSize () const; unsigned long aElementSize () const; void setAArrayMode (SeerArrayWidget::ArrayMode arrayMode); SeerArrayWidget::ArrayMode aArrayMode () const; QString aArrayModeString () const; const QVector& aArrayValues () const; const QString& bAxis () const; void setBAxis (const QString& axis); const QString& bLabel () const; void setBAddressOffset (unsigned long offset); unsigned long bAddressOffset () const; void setBAddressStride (unsigned long stride); unsigned long bAddressStride () const; unsigned long bSize () const; unsigned long bElementSize () const; void setBArrayMode (SeerArrayWidget::ArrayMode arrayMode); SeerArrayWidget::ArrayMode bArrayMode () const; QString bArrayModeString () const; const QVector& bArrayValues () const; signals: void dataChanged (); public slots: void setAData (const QString& label, DataStorage* pData); void setBData (const QString& label, DataStorage* pData); protected: private: void create (); QString _aAxis; QString _aLabel; int _aColumnId; DataStorage* _aData; unsigned long _aAddressOffset; unsigned long _aAddressStride; SeerArrayWidget::ArrayMode _aArrayMode; QVector _aArrayValues; QString _bAxis; QString _bLabel; int _bColumnId; DataStorage* _bData; unsigned long _bAddressOffset; unsigned long _bAddressStride; SeerArrayWidget::ArrayMode _bArrayMode; QVector _bArrayValues; }; seer-2.7/src/SeerAsmWidget.cpp000066400000000000000000000103521516472651200163300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAsmWidget.h" #include "SeerUtl.h" #include #include SeerAsmWidget::SeerAsmWidget(QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); plainTextEdit->setFont(font); plainTextEdit->setFocusPolicy(Qt::StrongFocus); plainTextEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse); plainTextEdit->setWordWrapMode(QTextOption::NoWrap); // Set text formats. _defaultFormat = plainTextEdit->currentCharFormat(); _grayFormat = _defaultFormat; _grayFormat.setBackground(QBrush(Qt::lightGray)); // Connect things. } SeerAsmWidget::~SeerAsmWidget() { } QTextDocument* SeerAsmWidget::document () { return plainTextEdit->document(); } QString SeerAsmWidget::toPlainText () { return plainTextEdit->toPlainText(); } void SeerAsmWidget::setData (const QString& data) { // ^done,asm_insns=[ // {address="0x000000000040093c",func-name="main()",offset="362",inst="mov $0x400aa9,%edi"}, // {address="0x0000000000400941",func-name="main()",offset="367",inst="call 0x400680 "}, // {address="0x0000000000400946",func-name="main()",offset="372",inst="mov -0x30(%rbp),%rax"} // ] // Clear the document. plainTextEdit->clear(); // Get a cursor QTextCursor cursor(plainTextEdit->textCursor()); cursor.movePosition(QTextCursor::Start); // Prepare the 'data' for parsing. QString asm_insns_text = Seer::parseFirst(data, "asm_insns=", '[', ']', false); QStringList asm_list = Seer::parse(asm_insns_text, "", '{', '}', false); // Loop through the asm list to get maximum field widths. int address_width = QString("Address").length(); int opcode_width = QString("Opcode").length(); int inst_width = QString("Assembly").length(); for ( const auto& asm_text : asm_list ) { QString address_text = Seer::parseFirst(asm_text, "address=", '"', '"', false); QString opcodes_text = Seer::parseFirst(asm_text, "opcodes=", '"', '"', false); QString inst_text = Seer::parseFirst(asm_text, "inst=", '"', '"', false); address_width = std::max((qsizetype)address_width, (qsizetype)address_text.length()); opcode_width = std::max((qsizetype)opcode_width, (qsizetype)opcodes_text.length()); inst_width = std::max((qsizetype)inst_width, (qsizetype)inst_text.length()); } // Write header. cursor.insertText (QString("Address").leftJustified(address_width, ' ', true), _grayFormat); cursor.insertText (QString(" "), _defaultFormat); cursor.insertText (QString("Opcodes").leftJustified(opcode_width, ' ', true), _defaultFormat); cursor.insertText (QString(" | "), _defaultFormat); cursor.insertText (QString("Assembly"), _defaultFormat); cursor.insertText (QString("\n"), _defaultFormat); // Loop through the asm list and print each line. for ( const auto& asm_text : asm_list ) { // Get the strings, with padding. QString address_text = Seer::parseFirst(asm_text, "address=", '"', '"', false).leftJustified(address_width, ' ', true); QString opcodes_text = Seer::parseFirst(asm_text, "opcodes=", '"', '"', false).leftJustified(opcode_width, ' ', true); QString inst_text = Seer::parseFirst(asm_text, "inst=", '"', '"', false).leftJustified(inst_width, ' ', true); // Write the text, with spacers. cursor.insertText (address_text, _grayFormat); cursor.insertText (QString(" "), _defaultFormat); cursor.insertText (opcodes_text, _defaultFormat); cursor.insertText (QString(" | "), _defaultFormat); cursor.insertText (inst_text, _defaultFormat); // Write eol to document. cursor.insertText (QString("\n"), _defaultFormat); } // Move to the start of the document. cursor.movePosition(QTextCursor::Start); plainTextEdit->setTextCursor(cursor); } seer-2.7/src/SeerAsmWidget.h000066400000000000000000000013751516472651200160020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerAsmWidget.h" class SeerAsmWidget: public QWidget, protected Ui::SeerAsmWidgetForm { Q_OBJECT public: SeerAsmWidget(QWidget* parent = 0); ~SeerAsmWidget(); QTextDocument* document (); QString toPlainText (); signals: public slots: void setData (const QString& data); protected: protected slots: private: QTextCharFormat _defaultFormat; QTextCharFormat _grayFormat; }; seer-2.7/src/SeerAsmWidget.ui000066400000000000000000000016641516472651200161710ustar00rootroot00000000000000 SeerAsmWidgetForm 0 0 907 643 Form 0 100 true Qt::NoTextInteraction seer-2.7/src/SeerAssemblyConfigPage.cpp000066400000000000000000000100551516472651200201460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAssemblyConfigPage.h" #include #include SeerAssemblyConfigPage::SeerAssemblyConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Setup the widgets reset(); // Connect things. } SeerAssemblyConfigPage::~SeerAssemblyConfigPage() { } QString SeerAssemblyConfigPage::showAssemblyTabOnStartupMode () const { return showAssemblyTabComboBox->currentText(); } bool SeerAssemblyConfigPage::keepAssemblyTabOnTop () const { return assemblyTabOnTopCheckBox->isChecked(); } QString SeerAssemblyConfigPage::disassemblyFlavor () const { if (attFlavorRadioButton->isChecked()) { return "att"; }else if (intelFlavorRadioButton->isChecked()) { return "intel"; }else{ return ""; } } QString SeerAssemblyConfigPage::symbolDemagling () const { if (demanglingOnRadioButton->isChecked()) { return "on"; }else if (demanglingOffRadioButton->isChecked()) { return "off"; }else{ return ""; } } bool SeerAssemblyConfigPage::showAddressColumn () const { return showAddressCheckBox->isChecked(); } bool SeerAssemblyConfigPage::showOffsetColumn () const { return showOffsetCheckBox->isChecked(); } bool SeerAssemblyConfigPage::showOpcodeColumn () const { return showOpcodeCheckBox->isChecked(); } bool SeerAssemblyConfigPage::showSourceLines () const { return showSourceCheckBox->isChecked(); } QString SeerAssemblyConfigPage::registerFormat () const { return registerFormatComboBox->currentText(); } QString SeerAssemblyConfigPage::disassemblyMode () const { if (pcFunctionRadioButton->isChecked()) { return "function"; }else if (pcLengthRadioButton->isChecked()) { return "length"; }else{ return "unknown"; } } int SeerAssemblyConfigPage::disassemblyBytes () const { return pcLengthSpinBox->value(); } void SeerAssemblyConfigPage::setShowAssemblyTabOnStartupMode (const QString& mode) { showAssemblyTabComboBox->setCurrentText(mode); } void SeerAssemblyConfigPage::setKeepAssemblyTabOnTop (bool flag) { assemblyTabOnTopCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setDisassemblyFlavor (const QString& flavor) { if (flavor == "att") { attFlavorRadioButton->setChecked(true); }else if (flavor == "intel") { intelFlavorRadioButton->setChecked(true); }else{ } } void SeerAssemblyConfigPage::setSymbolDemagling (const QString& onoff) { if (onoff == "on") { demanglingOnRadioButton->setChecked(true); }else if (onoff == "off") { demanglingOffRadioButton->setChecked(true); }else{ } } void SeerAssemblyConfigPage::setShowAddressColumn (bool flag) { showAddressCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setShowOffsetColumn (bool flag) { showOffsetCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setShowOpcodeColumn (bool flag) { showOpcodeCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setShowSourceLines (bool flag) { showSourceCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setRegisterFormat (const QString& format) { registerFormatComboBox->setCurrentText(format); } void SeerAssemblyConfigPage::setDisassemblyMode (const QString& mode, int bytes) { if (mode == "function") { pcFunctionRadioButton->setChecked(true); }else if (mode == "length") { pcLengthRadioButton->setChecked(true); }else{ pcFunctionRadioButton->setChecked(true); } pcLengthSpinBox->setValue(bytes); } void SeerAssemblyConfigPage::reset () { setShowAssemblyTabOnStartupMode("never"); setKeepAssemblyTabOnTop(true); setDisassemblyFlavor("att"); setSymbolDemagling("on"); setShowAddressColumn(true); setShowOffsetColumn(false); setShowOpcodeColumn(false); setShowSourceLines(false); setRegisterFormat("Natural"); setDisassemblyMode("function", 256); } seer-2.7/src/SeerAssemblyConfigPage.h000066400000000000000000000047141516472651200176200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerAssemblyConfigPage.h" class SeerAssemblyConfigPage : public QWidget, protected Ui::SeerAssemblyConfigPage { Q_OBJECT public: explicit SeerAssemblyConfigPage (QWidget* parent = 0); ~SeerAssemblyConfigPage (); QString showAssemblyTabOnStartupMode () const; bool keepAssemblyTabOnTop () const; QString disassemblyFlavor () const; QString symbolDemagling () const; bool showAddressColumn () const; bool showOffsetColumn () const; bool showOpcodeColumn () const; bool showSourceLines () const; QString registerFormat () const; QString disassemblyMode () const; int disassemblyBytes () const; void setShowAssemblyTabOnStartupMode (const QString& mode); void setKeepAssemblyTabOnTop (bool flag); void setDisassemblyFlavor (const QString& flavor); void setSymbolDemagling (const QString& onoff); void setShowAddressColumn (bool flag); void setShowOffsetColumn (bool flag); void setShowOpcodeColumn (bool flag); void setShowSourceLines (bool flag); void setRegisterFormat (const QString& format); void setDisassemblyMode (const QString& mode, int bytes); void reset (); protected slots: }; seer-2.7/src/SeerAssemblyConfigPage.ui000066400000000000000000000570261516472651200200120ustar00rootroot00000000000000 SeerAssemblyConfigPage 0 0 926 901 SeerAssemblyConfigPage Assembly Settings Show Assembly tab on startup Qt::Horizontal QSizePolicy::Fixed 27 20 never always auto Qt::Horizontal 616 20 Keep Assembly tab on top Qt::Horizontal 616 20 Qt::Vertical QSizePolicy::Fixed 20 20 Disassembly Flavor Qt::Horizontal QSizePolicy::Fixed 27 20 att disassemblyFlavorButtonGroup intel disassemblyFlavorButtonGroup Qt::Horizontal QSizePolicy::Preferred 616 20 Symbol Demangling Qt::Horizontal QSizePolicy::Fixed 27 20 on assemblyDemangleButtonGroup off assemblyDemangleButtonGroup Qt::Horizontal QSizePolicy::Preferred 616 20 Show Columns in Editor Qt::Horizontal 40 20 Address Offset Opcode Source Register Format Qt::Horizontal QSizePolicy::Fixed 27 20 Natural Hex Octal Binary Decimal Raw Qt::Horizontal QSizePolicy::Preferred 616 20 Disassembly Mode Qt::Horizontal QSizePolicy::Fixed 38 20 Start and end address is defined by current function. Function disassemblyModeButtonGroup <html><head/><body><p>End address is defined by N bytes after current $PC</p></body></html> Length disassemblyModeButtonGroup Number of bytes after current $PC 9999 100 Qt::Horizontal QSizePolicy::Expanding 373 20 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Set various Assembly and Register settings.</span></p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Seer can show the program's assembly as a tab in the Code Manager. The Assembly tab can be shown automatically when Seer starts. There are these start up modes.</span></p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Never. Seer won't show the assembly tab at start up.</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Always. Seer will always show the assembly tab.</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Auto. Seer will show the the assembly tab if there is no source file to show.</li></ul> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">The assembly tab can always be shown with:</span></p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Monospace';"> View-&gt;Assembly View</span></p> <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; font-family:'Monospace';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">When enabled, the Assembly tab will tend to stay in the background (ie:hidden by any Source tabs) as the program is stepped through. If set, the Assembly tab can be forced to always stay on top, even while stepping through the program. Manually clicking on the tabs will still raise them, though.</span></p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">When presenting the assembly, there are 2 flavors. 'att' and 'intel'.</span></p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Monospace';"> att: mov 0xc(%ebp),%eax<br /> intel: mov eax, DWORDPTR [ebp+0xc]</span></p> <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; font-family:'Monospace';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">When printing certain symbols, the mangled or demangled symbol names can be printed.</span></p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Monospace';"> mangled: callq 0x4007b8 &lt;_ZNSolsEPFRSoS_E@plt&gt;<br /> demanlged: callq 0x4007b8 &lt;std::ostream::operator&lt;&lt;(std::ostream&amp;(*)(std::ostream&amp;))@plt&gt;</span></p> <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; font-family:'Monospace';"><br /></p> <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; font-family:'Monospace';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Monospace';">The Assembly Editor can show different columns along side the assembly. These can be quickly changed in the Assembly Editor using ^F.</span></p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Offset</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Opcode</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Source</li></ul> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Assembly Editor does its best to show relevant assembly. This means setting the 'start' and 'end' address of the disassembly. There are two modes.</p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Function - The start and end address is defined by the function the current $PC is in. Needs debug information. Otherwise, a blank editor is shown.</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Length - A number of bytes after the current $PC is shown.</li></ul> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">In the Register browser, register values can be shown in various formats:</span></p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Natural (A predefined format, based on the register name)</span></li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hex</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Octal</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Binary</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decimal</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Raw</li></ul></body></html> textBrowser printPointGroupBox assemblyTabOnTopCheckBox attFlavorRadioButton intelFlavorRadioButton demanglingOnRadioButton demanglingOffRadioButton showAddressCheckBox showOffsetCheckBox showOpcodeCheckBox registerFormatComboBox textBrowser seer-2.7/src/SeerAssemblyPreferenceDialog.cpp000066400000000000000000000055551516472651200213530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAssemblyPreferenceDialog.h" #include #include SeerAssemblyPreferenceDialog::SeerAssemblyPreferenceDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets // Connect things. // Restore window settings. readSettings(); } SeerAssemblyPreferenceDialog::~SeerAssemblyPreferenceDialog () { } void SeerAssemblyPreferenceDialog::setRegiserNamePC (const QString& name) { pcLineEdit->setText(name); } QString SeerAssemblyPreferenceDialog::regiserNamePC () const { return pcLineEdit->text(); } void SeerAssemblyPreferenceDialog::setRegiserNameFLAGS (const QString& name) { flagsLineEdit->setText(name); } QString SeerAssemblyPreferenceDialog::regiserNameFLAGS () const { return flagsLineEdit->text(); } void SeerAssemblyPreferenceDialog::setRegiserNameSP (const QString& name) { spLineEdit->setText(name); } QString SeerAssemblyPreferenceDialog::regiserNameSP () const { return spLineEdit->text(); } void SeerAssemblyPreferenceDialog::setShowAssemblyAddress (bool flag) { showAddressCheckBox->setChecked(flag); } bool SeerAssemblyPreferenceDialog::showAssemblyAddress () const { return showAddressCheckBox->isChecked(); } void SeerAssemblyPreferenceDialog::setShowAssemblyOffset (bool flag) { showOffsetCheckBox->setChecked(flag); } bool SeerAssemblyPreferenceDialog::showAssemblyOffset () const { return showOffsetCheckBox->isChecked(); } void SeerAssemblyPreferenceDialog::setShowAssemblyOpcode (bool flag) { showOpcodeCheckBox->setChecked(flag); } bool SeerAssemblyPreferenceDialog::showAssemblyOpcode () const { return showOpcodeCheckBox->isChecked(); } void SeerAssemblyPreferenceDialog::setShowAssemblySource (bool flag) { showSourceCheckBox->setChecked(flag); } bool SeerAssemblyPreferenceDialog::showAssemblySource () const { return showSourceCheckBox->isChecked(); } void SeerAssemblyPreferenceDialog::setConvertUppercase (bool flag) { convertUppercaseRadioButton->setChecked(flag); } bool SeerAssemblyPreferenceDialog::convertUppercase () const { return convertUppercaseRadioButton->isChecked(); } void SeerAssemblyPreferenceDialog::writeSettings() { QSettings settings; settings.beginGroup("registerpreferencedialog"); { settings.setValue("size", size()); }settings.endGroup(); } void SeerAssemblyPreferenceDialog::readSettings() { QSettings settings; settings.beginGroup("registerpreferencedialog"); { resize(settings.value("size", QSize(350, 300)).toSize()); } settings.endGroup(); } void SeerAssemblyPreferenceDialog::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QWidget::resizeEvent(event); } seer-2.7/src/SeerAssemblyPreferenceDialog.h000066400000000000000000000037651516472651200210210ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerAssemblyPreferenceDialog.h" class SeerAssemblyPreferenceDialog : public QDialog, protected Ui::SeerAssemblyPreferenceDialogForm { Q_OBJECT public: explicit SeerAssemblyPreferenceDialog (QWidget* parent = 0); ~SeerAssemblyPreferenceDialog (); void setRegiserNamePC (const QString& name); QString regiserNamePC () const; void setRegiserNameFLAGS (const QString& name); QString regiserNameFLAGS () const; void setRegiserNameSP (const QString& name); QString regiserNameSP () const; void setShowAssemblyAddress (bool flag); bool showAssemblyAddress () const; void setShowAssemblyOffset (bool flag); bool showAssemblyOffset () const; void setShowAssemblyOpcode (bool flag); bool showAssemblyOpcode () const; void setShowAssemblySource (bool flag); bool showAssemblySource () const; void setConvertUppercase (bool flag); bool convertUppercase () const; public slots: private slots: protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: }; seer-2.7/src/SeerAssemblyPreferenceDialog.ui000066400000000000000000000151561516472651200212040ustar00rootroot00000000000000 SeerAssemblyPreferenceDialogForm 0 0 357 368 Seer - Assembly Preferences Editor CPU Registers PC PC register name PC register name ($pc) true FLAGS CPU flags register name CPU Flags register name ($ps) true SP SP register name SP register name ($sp) true Assembly Details Show assembly address. Address Show assembly offset. Offset Show assembly opcodes. Opcode Show original source code. Source Qt::Horizontal 66 20 Assembly Text Convert Assembly text to uppercase letters. Convert To Uppercase Qt::Vertical 20 27 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok groupBox_2 buttonBox groupBox_1 groupBox_3 pcLineEdit flagsLineEdit spLineEdit showAddressCheckBox showOffsetCheckBox showOpcodeCheckBox showSourceCheckBox buttonBox accepted() SeerAssemblyPreferenceDialogForm accept() 248 254 157 274 buttonBox rejected() SeerAssemblyPreferenceDialogForm reject() 316 260 286 274 seer-2.7/src/SeerBreakpointCreateDialog.cpp000066400000000000000000000137701516472651200210150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerBreakpointCreateDialog.h" #include SeerBreakpointCreateDialog::SeerBreakpointCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setFilename(""); setFunctionName(""); setLabelName(""); setLineNumber(""); setAddress(""); setTemporaryEnabled (false); setHardwareEnabled (false); setPendingEnabled (false); setDisabledEnabled (false); setConditionalEnabled (false); setIgnoreCountEnabled (false); setThreadIdEnabled (false); setConditionalText (""); setIgnoreCountText (""); setThreadIdText (""); filenameLineEdit->setFocus(); // Connect things. QObject::connect(conditionalCheckBox, &QCheckBox::clicked, conditionalLineEdit, &QLineEdit::setEnabled); QObject::connect(ignoreCountCheckBox, &QCheckBox::clicked, ignoreCountLineEdit, &QLineEdit::setEnabled); QObject::connect(threadIdCheckBox, &QCheckBox::clicked, threadIdLineEdit, &QLineEdit::setEnabled); } SeerBreakpointCreateDialog::~SeerBreakpointCreateDialog () { } void SeerBreakpointCreateDialog::setFilename (const QString& text) { filenameLineEdit->setText(text); } void SeerBreakpointCreateDialog::setFunctionName (const QString& text) { functionLineEdit->setText(text); } void SeerBreakpointCreateDialog::setLabelName (const QString& text) { labelLineEdit->setText(text); } void SeerBreakpointCreateDialog::setLineNumber (const QString& text) { lineNumberLineEdit->setText(text); } void SeerBreakpointCreateDialog::setAddress (const QString& text) { addressLineEdit->setText(text); } QString SeerBreakpointCreateDialog::filenameText () const { return filenameLineEdit->text(); } QString SeerBreakpointCreateDialog::functionNameText () const { return functionLineEdit->text(); } QString SeerBreakpointCreateDialog::labelNameText () const { return labelLineEdit->text(); } QString SeerBreakpointCreateDialog::lineNumberText () const { return lineNumberLineEdit->text(); } QString SeerBreakpointCreateDialog::addressText () const { return addressLineEdit->text(); } void SeerBreakpointCreateDialog::setTemporaryEnabled (bool flag) { temporaryCheckBox->setChecked(flag); } void SeerBreakpointCreateDialog::setHardwareEnabled (bool flag) { hardwareCheckBox->setChecked(flag); } void SeerBreakpointCreateDialog::setPendingEnabled (bool flag) { pendingCheckBox->setChecked(flag); } void SeerBreakpointCreateDialog::setDisabledEnabled (bool flag) { disabledCheckBox->setChecked(flag); } void SeerBreakpointCreateDialog::setConditionalEnabled (bool flag) { conditionalCheckBox->setChecked(flag); conditionalLineEdit->setEnabled(flag); } void SeerBreakpointCreateDialog::setIgnoreCountEnabled (bool flag) { ignoreCountCheckBox->setChecked(flag); ignoreCountLineEdit->setEnabled(flag); } void SeerBreakpointCreateDialog::setThreadIdEnabled (bool flag) { threadIdCheckBox->setChecked(flag); threadIdLineEdit->setEnabled(flag); } void SeerBreakpointCreateDialog::setConditionalText (const QString& text) { conditionalLineEdit->setText(text); } void SeerBreakpointCreateDialog::setIgnoreCountText (const QString& text) { ignoreCountLineEdit->setText(text); } void SeerBreakpointCreateDialog::setThreadIdText (const QString& text) { threadIdLineEdit->setText(text); } bool SeerBreakpointCreateDialog::temporaryEnabled () const { return temporaryCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::hardwareEnabled () const { return hardwareCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::pendingEnabled () const { return pendingCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::disabledEnabled () const { return disabledCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::conditionalEnabled () const { return conditionalCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::ignoreCountEnabled () const { return ignoreCountCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::threadIdEnabled () const { return threadIdCheckBox->isChecked(); } QString SeerBreakpointCreateDialog::conditionalText () const { return conditionalLineEdit->text(); } QString SeerBreakpointCreateDialog::ignoreCountText () const { return ignoreCountLineEdit->text(); } QString SeerBreakpointCreateDialog::threadIdText () const { return threadIdLineEdit->text(); } QString SeerBreakpointCreateDialog::breakpointText () const { // Build a breakpoint specification. QString breakpointParameters; if (temporaryEnabled()) { breakpointParameters += " -t"; } if (hardwareEnabled()) { breakpointParameters += " -h"; } if (pendingEnabled()) { breakpointParameters += " -f"; } if (disabledEnabled()) { breakpointParameters += " -d"; } if (conditionalEnabled()) { if (conditionalText() != "") { QString str = conditionalText().replace('"', "\\\""); // Quote " characters. breakpointParameters += " -c \"" + str + "\""; } } if (ignoreCountEnabled()) { if (ignoreCountText() != "") { breakpointParameters += " -i " + ignoreCountText(); } } if (threadIdEnabled()) { if (threadIdText() != "") { breakpointParameters += " -p " + threadIdText(); } } if (filenameText() != "") { breakpointParameters += " --source \"" + filenameText() + "\""; } if (functionNameText() != "") { breakpointParameters += " --function \"" + functionNameText() + "\""; } if (labelNameText() != "") { breakpointParameters += " --label " + labelNameText(); } if (lineNumberText() != "") { breakpointParameters += " --line " + lineNumberText(); } if (addressText() != "") { breakpointParameters += " *" + addressText(); } return breakpointParameters; } seer-2.7/src/SeerBreakpointCreateDialog.h000066400000000000000000000047661516472651200204670ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerBreakpointCreateDialog.h" class SeerBreakpointCreateDialog : public QDialog, protected Ui::SeerBreakpointCreateDialogForm { Q_OBJECT public: explicit SeerBreakpointCreateDialog (QWidget* parent = 0); ~SeerBreakpointCreateDialog (); void setFilename (const QString& text); void setFunctionName (const QString& text); void setLabelName (const QString& text); void setLineNumber (const QString& text); void setAddress (const QString& text); QString filenameText () const; QString functionNameText () const; QString labelNameText () const; QString lineNumberText () const; QString addressText () const; void setTemporaryEnabled (bool flag); void setHardwareEnabled (bool flag); void setPendingEnabled (bool flag); void setDisabledEnabled (bool flag); void setConditionalEnabled (bool flag); void setIgnoreCountEnabled (bool flag); void setThreadIdEnabled (bool flag); void setConditionalText (const QString& text); void setIgnoreCountText (const QString& text); void setThreadIdText (const QString& text); bool temporaryEnabled () const; bool hardwareEnabled () const; bool pendingEnabled () const; bool disabledEnabled () const; bool conditionalEnabled () const; bool ignoreCountEnabled () const; bool threadIdEnabled () const; QString conditionalText () const; QString ignoreCountText () const; QString threadIdText () const; QString breakpointText () const; public slots: private: }; seer-2.7/src/SeerBreakpointCreateDialog.ui000066400000000000000000000175361516472651200206540ustar00rootroot00000000000000 SeerBreakpointCreateDialogForm 0 0 525 429 Create a Breakpoint Breakpoint Location Filename true Line number true Qt::Horizontal 40 20 Function true Label true Qt::Horizontal 40 20 Address true Qt::Horizontal 243 20 Breakpoint Type Temporary Condition if: true Hardware Ignore Count true Qt::Horizontal 131 20 Pending Thread Id true Qt::Horizontal 131 20 Disabled Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerBreakpointCreateDialogForm accept() 248 254 157 274 buttonBox rejected() SeerBreakpointCreateDialogForm reject() 316 260 286 274 seer-2.7/src/SeerBreakpointsBrowserWidget.cpp000066400000000000000000000406171516472651200214440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerBreakpointsBrowserWidget.h" #include "SeerBreakpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerBreakpointsBrowserWidget::SeerBreakpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets breakpointsTreeWidget->clear(); breakpointsTreeWidget->setSortingEnabled(false); breakpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); breakpointsTreeWidget->resizeColumnToContents(0); // number breakpointsTreeWidget->resizeColumnToContents(1); // type breakpointsTreeWidget->resizeColumnToContents(2); // disp breakpointsTreeWidget->resizeColumnToContents(3); // enabled breakpointsTreeWidget->resizeColumnToContents(4); // addr //breakpointsTreeWidget->resizeColumnToContents(5); // func Too long to show breakpointsTreeWidget->resizeColumnToContents(6); // file //breakpointsTreeWidget->resizeColumnToContents(7); // fullname Too long to show breakpointsTreeWidget->resizeColumnToContents(8); // line breakpointsTreeWidget->resizeColumnToContents(9); // thread-groups breakpointsTreeWidget->resizeColumnToContents(10); // cond breakpointsTreeWidget->resizeColumnToContents(11); // times breakpointsTreeWidget->resizeColumnToContents(12); // ignore //breakpointsTreeWidget->resizeColumnToContents(13); // script Too long to show breakpointsTreeWidget->resizeColumnToContents(14); // original-location /* breakpointsTreeWidget->setColumnHidden(1, true); // ??? Hide or have a config to hide/show columns. breakpointsTreeWidget->setColumnHidden(6, true); */ // Connect things. QObject::connect(breakpointsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerBreakpointsBrowserWidget::handleItemDoubleClicked); QObject::connect(refreshBreakpointsToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addBreakpointToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleAddToolButton); QObject::connect(deleteBreakpointsToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleDeleteToolButton); QObject::connect(enableBreakpointsToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleEnableToolButton); QObject::connect(disableBreakpointsToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleDisableToolButton); QObject::connect(conditionBreakpointToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleConditionToolButton); QObject::connect(ignoreBreakpointToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleIgnoreToolButton); QObject::connect(commandsBreakpointToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleCommandsToolButton); } SeerBreakpointsBrowserWidget::~SeerBreakpointsBrowserWidget () { } bool SeerBreakpointsBrowserWidget::isEmpty() const { return (breakpointsTreeWidget->topLevelItemCount() == 0); } QStringList SeerBreakpointsBrowserWidget::breakpoints () const { return QStringList(); } void SeerBreakpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { breakpointsTreeWidget->clear(); // // ^done,BreakpointTable={ // nr_rows="2",nr_cols="6", // // hdr=[ // {width="7",alignment="-1",col_name="number",colhdr="Num"}, // {width="14",alignment="-1",col_name="type",colhdr="Type"}, // {width="4",alignment="-1",col_name="disp",colhdr="Disp"}, // {width="3",alignment="-1",col_name="enabled",colhdr="Enb"}, // {width="18",alignment="-1",col_name="addr",colhdr="Address"}, // {width="40",alignment="2",col_name="what",colhdr="What"} // ], // // body=[ // bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="0x0000000000400c17",func="main(int, char**)",file="helloworld.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp",line="8",thread-groups=["i1"],times="0",original-location="main"}, // bkpt={number="3", // type="breakpoint", // disp="keep", // enabled="y", // addr="0x0000000000400d72", // func="function1(std::__cxx11::basic_string, std::allocator > const&)", // file="function1.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp", // line="7", // thread-groups=["i1"], // cond="1 == 1", // times="0", // script={"print i argc"}, // original-location="function1"} // ] // } // //qDebug().noquote() << bkpt_list; QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(text, "body=", '[', ']', false); if (body_text != "") { QStringList bkpt_list = Seer::parse(newtext, "bkpt=", '{', '}', false); for (const auto& bkpt_text : bkpt_list) { // // A different way (better?) of parsing the table output // // Divide test into a list, delimited by a ','. // Then morph that list into a map, delimited by a '='. // Remove bookends. // QStringList items = Seer::parseCommaList(bkpt_text, '[', ']'); QMap keyValueMap = Seer::createKeyValueMap(items, '='); QString number_text = Seer::filterBookends(keyValueMap["number"], '"', '"'); QString type_text = Seer::filterBookends(keyValueMap["type"], '"', '"'); QString disp_text = Seer::filterBookends(keyValueMap["disp"], '"', '"'); QString enabled_text = Seer::filterBookends(keyValueMap["enabled"], '"', '"'); QString addr_text = Seer::filterBookends(keyValueMap["addr"], '"', '"'); QString func_text = Seer::filterBookends(keyValueMap["func"], '"', '"'); QString file_text = Seer::filterBookends(keyValueMap["file"], '"', '"'); QString fullname_text = Seer::filterBookends(keyValueMap["fullname"], '"', '"'); QString line_text = Seer::filterBookends(keyValueMap["line"], '"', '"'); QString thread_groups_text = Seer::filterBookends(keyValueMap["thread-groups"], '[', ']'); QString cond_text = Seer::filterBookends(keyValueMap["cond"], '"', '"'); QString times_text = Seer::filterBookends(keyValueMap["times"], '"', '"'); QString ignore_text = Seer::filterBookends(keyValueMap["ignore"], '"', '"'); QString script_text = Seer::filterBookends(keyValueMap["script"], '[', ']'); QString original_location_text = Seer::filterBookends(keyValueMap["original-location"], '"', '"'); // Only look for 'breakpoint' type break points. if (type_text != "breakpoint") { continue; } script_text = Seer::filterBookends(Seer::parseCommaList(script_text, '{', '}'), '"', '"').join('\n'); // Add the level to the tree. QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, number_text); topItem->setText(1, type_text); topItem->setText(2, disp_text); topItem->setText(3, enabled_text); topItem->setText(4, addr_text); topItem->setText(5, func_text); topItem->setText(6, QFileInfo(file_text).fileName()); topItem->setText(7, fullname_text); topItem->setText(8, line_text); topItem->setText(9, thread_groups_text); topItem->setText(10, cond_text); topItem->setText(11, times_text); topItem->setText(12, ignore_text); topItem->setText(13, script_text); topItem->setText(14, original_location_text); for (int i=0; icolumnCount(); i++) { topItem->setTextAlignment(i, Qt::AlignLeft|Qt::AlignTop); } breakpointsTreeWidget->addTopLevelItem(topItem); } } }else{ // Ignore others. } breakpointsTreeWidget->resizeColumnToContents(0); breakpointsTreeWidget->resizeColumnToContents(1); breakpointsTreeWidget->resizeColumnToContents(2); breakpointsTreeWidget->resizeColumnToContents(3); breakpointsTreeWidget->resizeColumnToContents(4); //breakpointsTreeWidget->resizeColumnToContents(5); breakpointsTreeWidget->resizeColumnToContents(6); //breakpointsTreeWidget->resizeColumnToContents(7); breakpointsTreeWidget->resizeColumnToContents(8); breakpointsTreeWidget->resizeColumnToContents(9); breakpointsTreeWidget->resizeColumnToContents(10); breakpointsTreeWidget->resizeColumnToContents(11); breakpointsTreeWidget->resizeColumnToContents(12); //breakpointsTreeWidget->resizeColumnToContents(13); breakpointsTreeWidget->resizeColumnToContents(14); QApplication::restoreOverrideCursor(); } void SeerBreakpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshBreakpointsList(); } void SeerBreakpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. breakpointsTreeWidget->clear(); } void SeerBreakpointsBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); int lineno = item->text(8).toInt(); emit selectedFile(item->text(6), item->text(7), lineno); emit maybeSelectedAddress(item->text(6), item->text(7), item->text(4)); } void SeerBreakpointsBrowserWidget::handleRefreshToolButton () { emit refreshBreakpointsList(); } void SeerBreakpointsBrowserWidget::handleAddToolButton () { SeerBreakpointCreateDialog dlg(this); int ret = dlg.exec(); if (ret == 0) { return; } // Build a breakpoint specification. QString breakpointParameters = dlg.breakpointText(); // If nothing, just return. if (breakpointParameters == "") { return; } // Otherwise send the command to create the breakpoint. emit insertBreakpoint(breakpointParameters); } void SeerBreakpointsBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = breakpointsTreeWidget->selectedItems(); // Build a string that is a list of breakpoints. QString breakpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { breakpoints += " "; } breakpoints += (*i)->text(0); } // Don't do anything if the list of breakpoints is empty. if (breakpoints == "") { return; } // Send the signal. emit deleteBreakpoints(breakpoints); } void SeerBreakpointsBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = breakpointsTreeWidget->selectedItems(); // Build a string that is a list of breakpoints. QString breakpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { breakpoints += " "; } breakpoints += (*i)->text(0); } // Don't do anything if the list of breakpoints is empty. if (breakpoints == "") { return; } // Send the signal. emit enableBreakpoints(breakpoints); } void SeerBreakpointsBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = breakpointsTreeWidget->selectedItems(); // Build a string that is a list of breakpoints. QString breakpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { breakpoints += " "; } breakpoints += (*i)->text(0); } // Don't do anything if the list of breakpoints is empty. if (breakpoints == "") { return; } // Send the signal. emit disableBreakpoints(breakpoints); } void SeerBreakpointsBrowserWidget::handleConditionToolButton () { // Get selected tree items. Only allow one. QList items = breakpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one breakpoint when adding a condition.", QMessageBox::Ok); return; } // Get the condition text. bool ok; QString condition = QInputDialog::getText(this, "Seer", "Enter the condition for this breakpoint.\nA blank condition will remove an existing one.\n\nif:", QLineEdit::Normal, items.front()->text(10), &ok); if (ok == false) { return; } // Get the selected breakpoint number. QString breakpoint = items.front()->text(0); // Send the signal. emit addBreakpointCondition(breakpoint, condition); } void SeerBreakpointsBrowserWidget::handleIgnoreToolButton () { // Get selected tree items. Only allow one. QList items = breakpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one breakpoint when adding an ignore count.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; int count = QInputDialog::getInt(this, "Seer", "Enter the ignore count for this breakpoint.\nA count of 0 will remove an existing one.", items.front()->text(12).toInt(), 0, 2147483647, 1, &ok); if (ok == false) { return; } // Get the selected breakpoint number. QString breakpoint = items.front()->text(0); // Send the signal. emit addBreakpointIgnore(breakpoint, QString::number(count)); } void SeerBreakpointsBrowserWidget::handleCommandsToolButton () { // Get selected tree items. Only allow one. QList items = breakpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one breakpoint when adding commands.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; QString commandstr = QInputDialog::getMultiLineText(this, "Seer", "Enter the commands to execute for this breakpoint.\nA blank list will remove existing ones.", items.front()->text(13), &ok); if (ok == false) { return; } // Get the selected breakpoint number. QString breakpoint = items.front()->text(0); QStringList commands = Seer::quoteChars(commandstr.split('\n', Qt::SkipEmptyParts), "\""); // Send the signal. emit addBreakpointCommands(breakpoint, commands); } void SeerBreakpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshBreakpointsList(); } seer-2.7/src/SeerBreakpointsBrowserWidget.h000066400000000000000000000047241516472651200211100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerBreakpointsBrowserWidget.h" class SeerBreakpointsBrowserWidget : public QWidget, protected Ui::SeerBreakpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerBreakpointsBrowserWidget (QWidget* parent = 0); ~SeerBreakpointsBrowserWidget (); bool isEmpty () const; QStringList breakpoints () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleConditionToolButton (); void handleIgnoreToolButton (); void handleCommandsToolButton (); signals: void refreshBreakpointsList (); void deleteBreakpoints (QString breakpoints); void enableBreakpoints (QString breakpoints); void disableBreakpoints (QString breakpoints); void addBreakpointCondition (QString breakpoint, QString condition); void addBreakpointIgnore (QString breakpoint, QString count); void addBreakpointCommands (QString breakpoint, QStringList commands); void insertBreakpoint (QString breakpoint); void selectedFile (QString file, QString fullname, int lineno); void selectedAddress (QString address); void maybeSelectedAddress (QString file, QString fullname, QString address); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerBreakpointsBrowserWidget.ui000066400000000000000000000156061516472651200212770ustar00rootroot00000000000000 SeerBreakpointsBrowserWidgetForm 0 0 1162 625 Form 15 Number Type Disposition Enabled Address Function File Fullname Line Thread Groups Condition Times Ignore Commands Original Location Add a new breakpoint. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of breakpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Enable selected breakpoints. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected breakpoints. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Add condition to selected breakpoint. ? Add ignore count to selected breakpoint. # Add commands to selected breakpoint. ... :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Delete selected breakpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 seer-2.7/src/SeerCatchpointCreateDialog.cpp000066400000000000000000000116101516472651200210020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCatchpointCreateDialog.h" #include SeerCatchpointCreateDialog::SeerCatchpointCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setType(""); setArguments(""); setTemporaryEnabled(false); setDisabledEnabled(false); throwRadioButton->setFocus(); // Connect things. } SeerCatchpointCreateDialog::~SeerCatchpointCreateDialog () { } void SeerCatchpointCreateDialog::setType (const QString& text) { if (text == "throw") { throwRadioButton->setChecked(true); }else if (text == "rethrow") { rethrowRadioButton->setChecked(true); }else if (text == "catch") { catchRadioButton->setChecked(true); }else if (text == "load") { loadRadioButton->setChecked(true); }else if (text == "unload") { unloadRadioButton->setChecked(true); }else if (text == "assert") { adaAssertRadioButton->setChecked(true); }else if (text == "exception") { adaExceptionRadioButton->setChecked(true); }else if (text == "handlers") { adaHandlersRadioButton->setChecked(true); }else if (text == "signal") { signalRadioButton->setChecked(true); }else if (text == "fork") { forkRadioButton->setChecked(true); }else if (text == "vfork") { vforkRadioButton->setChecked(true); }else if (text == "exec") { execRadioButton->setChecked(true); }else if (text == "syscall") { syscallRadioButton->setChecked(true); }else{ throwRadioButton->setChecked(true); } } QString SeerCatchpointCreateDialog::typeText () const { if (throwRadioButton->isChecked()) { return "throw"; }else if (rethrowRadioButton->isChecked()) { return "rethrow"; }else if (catchRadioButton->isChecked()) { return "catch"; }else if (loadRadioButton->isChecked()) { return "load"; }else if (unloadRadioButton->isChecked()) { return "unload"; }else if (adaAssertRadioButton->isChecked()) { return "assert"; }else if (adaExceptionRadioButton->isChecked()) { return "exception"; }else if (adaHandlersRadioButton->isChecked()) { return "handlers"; }else if (signalRadioButton->isChecked()) { return "signal"; }else if (forkRadioButton->isChecked()) { return "fork"; }else if (vforkRadioButton->isChecked()) { return "vfork"; }else if (execRadioButton->isChecked()) { return "exec"; }else if (syscallRadioButton->isChecked()) { return "syscall"; }else{ return "throw"; } } void SeerCatchpointCreateDialog::setTemporaryEnabled (bool flag) { temporaryCheckBox->setChecked(flag); } void SeerCatchpointCreateDialog::setDisabledEnabled (bool flag) { disabledCheckBox->setChecked(flag); } void SeerCatchpointCreateDialog::setArguments (const QString& text) { argumentsLineEdit->setText(text); } QString SeerCatchpointCreateDialog::arguments () const { return argumentsLineEdit->text(); } bool SeerCatchpointCreateDialog::temporaryEnabled () const { return temporaryCheckBox->isChecked(); } bool SeerCatchpointCreateDialog::disabledEnabled () const { return disabledCheckBox->isChecked(); } QString SeerCatchpointCreateDialog::catchpointText () const { // Build a catchpoint specification. QString catchpointParameters = typeText(); if (temporaryEnabled()) { catchpointParameters += " -t"; } if (disabledEnabled()) { catchpointParameters += " -d"; } if (typeText() == "assert") { // Handle Ada 'assert'. Nothing to add here. }else if (typeText() == "exception") { // Handle Ada 'exception'. if (arguments() != "") { catchpointParameters += " -e " + arguments(); } }else if (typeText() == "handlers") { // Handle Ada 'handlers'. if (arguments() != "") { catchpointParameters += " -e " + arguments(); } }else if (typeText() == "load") { // Handle library 'load'. Must have a name. catchpointParameters += " " + arguments(); }else if (typeText() == "unload") { // Handle library 'unload'. Must have a name. catchpointParameters += " " + arguments(); }else if (typeText() == "signal") { // Handle library 'unload'. Must have a name. catchpointParameters += " " + arguments(); }else if (typeText() == "syscall") { // Handle library 'unload'. Must have a name. catchpointParameters += " " + arguments(); }else{ // C++ throw, rethrow, catch. These require '-r', but only if there is a name. if (arguments() != "") { catchpointParameters += " -r " + arguments(); } } // qDebug() << catchpointParameters; return catchpointParameters; } seer-2.7/src/SeerCatchpointCreateDialog.h000066400000000000000000000023031516472651200204460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerCatchpointCreateDialog.h" class SeerCatchpointCreateDialog : public QDialog, protected Ui::SeerCatchpointCreateDialogForm { Q_OBJECT public: explicit SeerCatchpointCreateDialog (QWidget* parent = 0); ~SeerCatchpointCreateDialog (); void setType (const QString& text); QString typeText () const; void setTemporaryEnabled (bool flag); bool temporaryEnabled () const; void setDisabledEnabled (bool flag); bool disabledEnabled () const; void setNameEnabled (bool flag); bool nameEnabled () const; void setArguments (const QString& text); QString arguments () const; QString catchpointText () const; public slots: private: }; seer-2.7/src/SeerCatchpointCreateDialog.ui000066400000000000000000000211521516472651200206370ustar00rootroot00000000000000 SeerCatchpointCreateDialogForm 0 0 543 403 Create a Catchpoint Catchpoint Type Catch on 'throw' typeButtonGroup Catch on library 'load' typeButtonGroup Catch on Ada 'assert' typeButtonGroup Catch on 'rethrow' typeButtonGroup Catch on library 'unload' typeButtonGroup Catch on Ada 'exception' typeButtonGroup Catch on 'catch' typeButtonGroup Catch on Ada 'handlers' typeButtonGroup Catch on 'signal' typeButtonGroup Catch on 'fork' typeButtonGroup Catch on 'exec' typeButtonGroup Catch on 'syscall' typeButtonGroup Catch on 'vfork' typeButtonGroup Catchpoint Details Create a temporary catchpoint. Temporary Create a disabled catchpoint. Disabled Qt::Horizontal 40 20 Arguments Optional arguments for selected Catchpoint type. true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok throwRadioButton loadRadioButton adaAssertRadioButton rethrowRadioButton unloadRadioButton adaExceptionRadioButton catchRadioButton adaHandlersRadioButton signalRadioButton forkRadioButton execRadioButton syscallRadioButton vforkRadioButton temporaryCheckBox disabledCheckBox argumentsLineEdit buttonBox accepted() SeerCatchpointCreateDialogForm accept() 257 393 157 274 buttonBox rejected() SeerCatchpointCreateDialogForm reject() 325 393 286 274 seer-2.7/src/SeerCatchpointsBrowserWidget.cpp000066400000000000000000000426221516472651200214400ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCatchpointsBrowserWidget.h" #include "SeerCatchpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include SeerCatchpointsBrowserWidget::SeerCatchpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets catchpointsTreeWidget->clear(); catchpointsTreeWidget->setSortingEnabled(false); catchpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); catchpointsTreeWidget->resizeColumnToContents(0); // number catchpointsTreeWidget->resizeColumnToContents(1); // type catchpointsTreeWidget->resizeColumnToContents(2); // disp catchpointsTreeWidget->resizeColumnToContents(3); // enabled catchpointsTreeWidget->resizeColumnToContents(4); // what catchpointsTreeWidget->resizeColumnToContents(5); // catch-type catchpointsTreeWidget->resizeColumnToContents(6); // name catchpointsTreeWidget->resizeColumnToContents(7); // thread-groups catchpointsTreeWidget->resizeColumnToContents(8); // cond catchpointsTreeWidget->resizeColumnToContents(9); // times catchpointsTreeWidget->resizeColumnToContents(10); // ignore //catchpointsTreeWidget->resizeColumnToContents(11); // script Too long to show catchpointsTreeWidget->setColumnHidden(12, true); // Hide the 'used' column. catchpointsTreeWidget->clear(); // Connect things. QObject::connect(refreshCatchpointsToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addCatchpointToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleAddToolButton); QObject::connect(deleteCatchpointsToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleDeleteToolButton); QObject::connect(enableCatchpointsToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleEnableToolButton); QObject::connect(disableCatchpointsToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleDisableToolButton); QObject::connect(conditionCatchpointToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleConditionToolButton); QObject::connect(ignoreCatchpointToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleIgnoreToolButton); QObject::connect(commandsCatchpointToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleCommandsToolButton); } SeerCatchpointsBrowserWidget::~SeerCatchpointsBrowserWidget () { } bool SeerCatchpointsBrowserWidget::isEmpty() const { return (catchpointsTreeWidget->topLevelItemCount() == 0); } QStringList SeerCatchpointsBrowserWidget::breakpoints () const { return QStringList(); } void SeerCatchpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } //qDebug() << text; QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { // ^done,BreakpointTable={ // nr_rows="3", nr_cols="6", // // hdr=[ // {width="7",alignment="-1",col_name="number",colhdr="Num"}, // {width="14",alignment="-1",col_name="type",colhdr="Type"}, // {width="4",alignment="-1",col_name="disp",colhdr="Disp"}, // {width="3",alignment="-1",col_name="enabled",colhdr="Enb"}, // {width="18",alignment="-1",col_name="addr",colhdr="Address"}, // {width="40",alignment="2",col_name="what",colhdr="What"} // ], // // body=[ // bkpt={number="2",type="catchpoint",disp="keep",enabled="y",what="exception catch",catch-type="catch",thread-groups=["i1"],times="0"}, // bkpt={number="3", // type="catchpoint", // disp="keep", // enabled="y", // what="exception throw", // catch-type="throw", // thread-groups=["i1"], // regexp="Exception*", // times="0"} // ] // // body=[ // bkpt={number="2", // type="catchpoint", // disp="keep", // enabled="y", // what="", // catch-type="signal", // thread-groups=["i1"], // times="1"} // ] // QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(newtext, "body=", '[', ']', false); //qDebug() << body_text; // No rows? Just clear the tree. if (body_text == "") { catchpointsTreeWidget->clear(); // Otherwise, populate it. }else{ // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(catchpointsTreeWidget); while (*it) { (*it)->setText(12, "unused"); ++it; } QStringList bkpt_list = Seer::parse(newtext, "bkpt=", '{', '}', false); for ( const auto& bkpt_text : bkpt_list ) { QString number_text = Seer::parseFirst(bkpt_text, "number=", '"', '"', false); QString type_text = Seer::parseFirst(bkpt_text, "type=", '"', '"', false); QString disp_text = Seer::parseFirst(bkpt_text, "disp=", '"', '"', false); QString enabled_text = Seer::parseFirst(bkpt_text, "enabled=", '"', '"', false); QString what_text = Seer::parseFirst(bkpt_text, "what=", '"', '"', false); QString catch_type_text = Seer::parseFirst(bkpt_text, "catch-type=", '"', '"', false); QString name_text = Seer::parseFirst(bkpt_text, "regexp=", '"', '"', false); QString thread_groups_text = Seer::parseFirst(bkpt_text, "thread-groups=", '[', ']', false); QString cond_text = Seer::parseFirst(bkpt_text, "cond=", '"', '"', false); QString times_text = Seer::parseFirst(bkpt_text, "times=", '"', '"', false); QString ignore_text = Seer::parseFirst(bkpt_text, "ignore=", '"', '"', false); QString script_text = Seer::parseFirst(bkpt_text, "script=", '{', '}', false); // Only look for 'catchpoint' type break points. if (type_text != "catchpoint") { continue; } script_text = Seer::filterBookends(Seer::parseCommaList(script_text, '{', '}'), '"', '"').join('\n'); // Hack for library 'load' and 'unload' catchpoints. // Unlike 'catch' catchpoints, the "regexp" field is blank. The // name is buried in the "what" field. So extract it. // // what="load of library matching libSampVar.so" // what="unload of library matching libSampVar.so" // if (name_text == "") { QString loadsearch("load of library matching "); QString unloadsearch("unload of library matching "); if (what_text.startsWith(loadsearch)) { name_text = what_text.mid(loadsearch.length()); } if (what_text.startsWith(unloadsearch)) { name_text = what_text.mid(unloadsearch.length()); } } // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. QList matches = catchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); // No matches. So can't reuse. Add the new entry. if (matches.size() == 0) { // Add the level to the tree. QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, number_text); topItem->setText(1, type_text); topItem->setText(2, disp_text); topItem->setText(3, enabled_text); topItem->setText(4, what_text); topItem->setText(5, catch_type_text); topItem->setText(6, name_text); topItem->setText(7, thread_groups_text); topItem->setText(8, cond_text); topItem->setText(9, times_text); topItem->setText(10, ignore_text); topItem->setText(11, script_text); topItem->setText(12, "new"); for (int i=0; icolumnCount(); i++) { topItem->setTextAlignment(i, Qt::AlignLeft|Qt::AlignTop); } catchpointsTreeWidget->addTopLevelItem(topItem); // Found a match. Reuse it. }else{ QTreeWidgetItem* topItem = matches.takeFirst(); topItem->setText(0, number_text); topItem->setText(1, type_text); topItem->setText(2, disp_text); topItem->setText(3, enabled_text); topItem->setText(4, what_text); topItem->setText(5, catch_type_text); topItem->setText(6, name_text); topItem->setText(7, thread_groups_text); topItem->setText(8, cond_text); topItem->setText(9, times_text); topItem->setText(10, ignore_text); topItem->setText(11, script_text); topItem->setText(12, "reused"); } } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. QList matches = catchpointsTreeWidget->findItems("unused", Qt::MatchExactly, 12); qDeleteAll(matches); } }else{ // Ignore others. } catchpointsTreeWidget->resizeColumnToContents(0); catchpointsTreeWidget->resizeColumnToContents(1); catchpointsTreeWidget->resizeColumnToContents(2); catchpointsTreeWidget->resizeColumnToContents(3); catchpointsTreeWidget->resizeColumnToContents(4); catchpointsTreeWidget->resizeColumnToContents(5); catchpointsTreeWidget->resizeColumnToContents(6); catchpointsTreeWidget->resizeColumnToContents(7); catchpointsTreeWidget->resizeColumnToContents(8); catchpointsTreeWidget->resizeColumnToContents(9); catchpointsTreeWidget->resizeColumnToContents(10); //catchpointsTreeWidget->resizeColumnToContents(11); catchpointsTreeWidget->resizeColumnToContents(12); QApplication::restoreOverrideCursor(); } void SeerCatchpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshCatchpointsList(); } void SeerCatchpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. catchpointsTreeWidget->clear(); } void SeerCatchpointsBrowserWidget::handleRefreshToolButton () { emit refreshCatchpointsList(); } void SeerCatchpointsBrowserWidget::handleAddToolButton () { SeerCatchpointCreateDialog dlg(this); int ret = dlg.exec(); if (ret == 0) { return; } // Build a catchpoint specification. QString catchpointParameters = dlg.catchpointText(); // If nothing, just return. if (catchpointParameters == "") { return; } // Otherwise send the command to create the catchpoint. emit insertCatchpoint(catchpointParameters); } void SeerCatchpointsBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = catchpointsTreeWidget->selectedItems(); // Build a string that is a list of catchpoints. QString catchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { catchpoints += " "; } catchpoints += (*i)->text(0); } // Don't do anything if the list of catchpoints is empty. if (catchpoints == "") { return; } // Send the signal. emit deleteCatchpoints(catchpoints); } void SeerCatchpointsBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = catchpointsTreeWidget->selectedItems(); // Build a string that is a list of catchpoints. QString catchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { catchpoints += " "; } catchpoints += (*i)->text(0); } // Don't do anything if the list of catchpoints is empty. if (catchpoints == "") { return; } // Send the signal. emit enableCatchpoints(catchpoints); } void SeerCatchpointsBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = catchpointsTreeWidget->selectedItems(); // Build a string that is a list of catchpoints. QString catchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { catchpoints += " "; } catchpoints += (*i)->text(0); } // Don't do anything if the list of catchpoints is empty. if (catchpoints == "") { return; } // Send the signal. emit disableCatchpoints(catchpoints); } void SeerCatchpointsBrowserWidget::handleConditionToolButton () { // Get selected tree items. Only allow one. QList items = catchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one catchpoint when adding a condition.", QMessageBox::Ok); return; } // Get the condition text. bool ok; QString condition = QInputDialog::getText(this, "Seer", "Enter the condition for this catchpoint.\nA blank condition will remove an existing one.", QLineEdit::Normal, items.front()->text(8), &ok); if (ok == false) { return; } // Get the selected catchpoint number. QString catchpoint = items.front()->text(0); // Send the signal. emit addBreakpointCondition(catchpoint, condition); } void SeerCatchpointsBrowserWidget::handleIgnoreToolButton () { // Get selected tree items. Only allow one. QList items = catchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one catchpoint when adding an ignore count.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; int count = QInputDialog::getInt(this, "Seer", "Enter the ignore count for this catchpoint.\nA count of 0 will remove an existing one.", items.front()->text(10).toInt(), 0, 2147483647, 1, &ok); if (ok == false) { return; } // Get the selected catchpoint number. QString catchpoint = items.front()->text(0); // Send the signal. emit addBreakpointIgnore(catchpoint, QString::number(count)); } void SeerCatchpointsBrowserWidget::handleCommandsToolButton () { // Get selected tree items. Only allow one. QList items = catchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one watcpoint when adding commands.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; QString commandstr = QInputDialog::getMultiLineText(this, "Seer", "Enter the commands to execute for this catchpoint.\nA blank list will remove existing ones.", items.front()->text(11), &ok); if (ok == false) { return; } // Get the selected catchpoint number. QString catchpoint = items.front()->text(0); QStringList commands = Seer::quoteChars(commandstr.split('\n', Qt::SkipEmptyParts), "\""); // Send the signal. emit addBreakpointCommands(catchpoint, commands); } void SeerCatchpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshCatchpointsList(); } seer-2.7/src/SeerCatchpointsBrowserWidget.h000066400000000000000000000041331516472651200211000ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerCatchpointsBrowserWidget.h" class SeerCatchpointsBrowserWidget : public QWidget, protected Ui::SeerCatchpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerCatchpointsBrowserWidget (QWidget* parent = 0); ~SeerCatchpointsBrowserWidget (); bool isEmpty () const; QStringList breakpoints () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleConditionToolButton (); void handleIgnoreToolButton (); void handleCommandsToolButton (); signals: void refreshCatchpointsList (); void deleteCatchpoints (QString catchpoints); void enableCatchpoints (QString catchpoints); void disableCatchpoints (QString catchpoints); void addBreakpointCondition (QString catchpoint, QString condition); void addBreakpointIgnore (QString catchpoint, QString count); void addBreakpointCommands (QString catchpoint, QStringList commands); void insertCatchpoint (QString catchpoint); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerCatchpointsBrowserWidget.ui000066400000000000000000000152411516472651200212700ustar00rootroot00000000000000 SeerCatchpointsBrowserWidgetForm 0 0 1052 485 Form 13 Number Type Disposition Enabled What Catch Type Name Thread Groups Condtion Times Ignore Commands Used Add a new catchpoint. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of catchpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Enable selected catchpoints. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected catchpoints. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Add condition to selected catchpoint. ? Add ignore count to selected catchpoint. # Add commands to selected catchpoint. ... :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Delete selected catchpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 seer-2.7/src/SeerCheckpointsBrowserWidget.cpp000066400000000000000000000164201516472651200214300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCheckpointsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerCheckpointsBrowserWidget::SeerCheckpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets checkpointsTreeWidget->clear(); checkpointsTreeWidget->setSortingEnabled(false); checkpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); checkpointsTreeWidget->resizeColumnToContents(0); // state checkpointsTreeWidget->resizeColumnToContents(1); // number checkpointsTreeWidget->resizeColumnToContents(2); // process checkpointsTreeWidget->resizeColumnToContents(3); // file checkpointsTreeWidget->resizeColumnToContents(4); // line // Connect things. QObject::connect(checkpointsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerCheckpointsBrowserWidget::handleItemDoubleClicked); QObject::connect(refreshCheckpointsToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addCheckpointToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleAddToolButton); QObject::connect(deleteCheckpointsToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleDeleteToolButton); QObject::connect(selectCheckpointToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleSelectToolButton); } SeerCheckpointsBrowserWidget::~SeerCheckpointsBrowserWidget () { } void SeerCheckpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } if (text.startsWith("^done,checkpoints=[") && text.endsWith("]")) { // // "^done,checkpoints=[ // {id="0",state="*",process="Thread 0x7ffff7e7f740 (LWP 31803) (main process) at 0x0",file="",line=""}, // {id="1",state=" ",process="process 31806 at 0x55555555513f",file="hellostruct.cpp",line="49"}, // {id="2",state=" ",process="process 31807 at 0x5555555552a0",file="hellostruct.cpp",line="62"} // ] // checkpointsTreeWidget->clear(); checkpointsTreeWidget->setSortingEnabled(false); checkpointsTreeWidget->sortByColumn(-1, Qt::AscendingOrder); QString checkpoints_text = Seer::parseFirst(text, "checkpoints=", '[', ']', false); QStringList checkpoints_list = Seer::parse(checkpoints_text, "", '{', '}', false); for (const auto& checkpoint_entry : checkpoints_list) { QString id_text = Seer::parseFirst(checkpoint_entry, "id=", '"', '"', false); QString state_text = Seer::parseFirst(checkpoint_entry, "state=", '"', '"', false); QString process_text = Seer::parseFirst(checkpoint_entry, "process=", '"', '"', false); QString file_text = Seer::parseFirst(checkpoint_entry, "file=", '"', '"', false); QString line_text = Seer::parseFirst(checkpoint_entry, "line=", '"', '"', false); // Add the function to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, state_text); item->setText(1, id_text); item->setText(2, process_text); item->setText(3, file_text); item->setText(4, line_text); checkpointsTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } checkpointsTreeWidget->resizeColumnToContents(0); checkpointsTreeWidget->resizeColumnToContents(1); checkpointsTreeWidget->resizeColumnToContents(2); checkpointsTreeWidget->resizeColumnToContents(3); checkpointsTreeWidget->resizeColumnToContents(4); QApplication::restoreOverrideCursor(); } void SeerCheckpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshCheckpointsList(); } void SeerCheckpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. checkpointsTreeWidget->clear(); } void SeerCheckpointsBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectCheckpoint(item->text(1)); } void SeerCheckpointsBrowserWidget::handleRefreshToolButton () { emit refreshCheckpointsList(); } void SeerCheckpointsBrowserWidget::handleAddToolButton () { // Otherwise send the command to create the checkpoint. emit insertCheckpoint(); } void SeerCheckpointsBrowserWidget::handleSelectToolButton () { // Any items in the tree? if (checkpointsTreeWidget->topLevelItemCount() == 0) { QMessageBox::warning(this, "Seer", QString("There are no checkpoints to switch to."), QMessageBox::Ok, QMessageBox::Ok); return; } // Get selected tree items. QList items = checkpointsTreeWidget->selectedItems(); if (items.count() == 0) { QMessageBox::warning(this, "Seer", QString("Selected a checkpoint to switch to."), QMessageBox::Ok, QMessageBox::Ok); return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", QString("Select only 1 checkpoint to switch to."), QMessageBox::Ok, QMessageBox::Ok); return; } // Build a string that is a list of checkpoints. QString checkpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { checkpoints += " "; } checkpoints += (*i)->text(1); } // Don't do anything if the list of checkpoints is empty. if (checkpoints == "") { return; } // Send the signal. emit selectCheckpoint(checkpoints); } void SeerCheckpointsBrowserWidget::handleDeleteToolButton () { // Any items in the tree? if (checkpointsTreeWidget->topLevelItemCount() == 0) { QMessageBox::warning(this, "Seer", QString("There are no checkpoints to delete."), QMessageBox::Ok, QMessageBox::Ok); return; } // Get selected tree items. QList items = checkpointsTreeWidget->selectedItems(); if (items.count() == 0) { QMessageBox::warning(this, "Seer", QString("Select checkpoints to delete."), QMessageBox::Ok, QMessageBox::Ok); return; } // Build a string that is a list of checkpoints. QString checkpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { checkpoints += " "; } checkpoints += (*i)->text(1); } // Don't do anything if the list of checkpoints is empty. if (checkpoints == "") { return; } // Send the signal. emit deleteCheckpoints(checkpoints); } void SeerCheckpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshCheckpointsList(); } seer-2.7/src/SeerCheckpointsBrowserWidget.h000066400000000000000000000026771516472651200211060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerCheckpointsBrowserWidget.h" class SeerCheckpointsBrowserWidget : public QWidget, protected Ui::SeerCheckpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerCheckpointsBrowserWidget (QWidget* parent = 0); ~SeerCheckpointsBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleSelectToolButton (); signals: void refreshCheckpointsList (); void insertCheckpoint (); void selectCheckpoint (QString checkpoint); void deleteCheckpoints (QString checkpoints); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerCheckpointsBrowserWidget.ui000066400000000000000000000102321516472651200212560ustar00rootroot00000000000000 SeerCheckpointsBrowserWidgetForm 0 0 1162 625 Form 5 Active Number Process File Line Add a new checkpoint at the current spot in the program. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of checkpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Switch to the selected breakpoint. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Delete selected checkpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 seer-2.7/src/SeerCloseSourceDialog.cpp000066400000000000000000000047031516472651200200150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCloseSourceDialog.h" #include #include #include #include SeerCloseSourceDialog::SeerCloseSourceDialog(QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets // Connect things. // Restore window settings. readSettings(); } SeerCloseSourceDialog::~SeerCloseSourceDialog() { } void SeerCloseSourceDialog::setFiles (const SeerEditorManagerFiles& files) { for (int i=0; isetText(0, files[i].file); topItem->setText(1, files[i].fullname); filenamesTreeWidget->addTopLevelItem(topItem); } filenamesTreeWidget->resizeColumnToContents(0); filenamesTreeWidget->resizeColumnToContents(1); } SeerEditorManagerFiles SeerCloseSourceDialog::files () const { SeerEditorManagerFiles files; QList items = filenamesTreeWidget->findItems(QString("*"), Qt::MatchWrap|Qt::MatchWildcard|Qt::MatchRecursive); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { SeerEditorManagerFile f; f.file = (*i)->text(0); f.fullname = (*i)->text(1); files.push_back(f); } return files; } SeerEditorManagerFiles SeerCloseSourceDialog::selectedFiles () const { SeerEditorManagerFiles files; QList items = filenamesTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { SeerEditorManagerFile f; f.file = (*i)->text(0); f.fullname = (*i)->text(1); files.push_back(f); } return files; } void SeerCloseSourceDialog::writeSettings() { QSettings settings; settings.beginGroup("closesourcedialog"); { settings.setValue("size", size()); } settings.endGroup(); //qDebug() << size(); } void SeerCloseSourceDialog::readSettings() { QSettings settings; settings.beginGroup("closesourcedialog"); { resize(settings.value("size", QSize(400, 300)).toSize()); } settings.endGroup(); //qDebug() << size(); } void SeerCloseSourceDialog::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } seer-2.7/src/SeerCloseSourceDialog.h000066400000000000000000000017511516472651200174620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerEditorManagerEntry.h" #include #include #include "ui_SeerCloseSourceDialog.h" class SeerCloseSourceDialog : public QDialog, public Ui::SeerCloseSourceDialogForm { Q_OBJECT public: explicit SeerCloseSourceDialog (QWidget* parent = 0); ~SeerCloseSourceDialog (); void setFiles (const SeerEditorManagerFiles& files); SeerEditorManagerFiles files () const; SeerEditorManagerFiles selectedFiles () const; protected slots: protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: }; seer-2.7/src/SeerCloseSourceDialog.ui000066400000000000000000000044461516472651200176540ustar00rootroot00000000000000 SeerCloseSourceDialogForm 0 0 400 300 Seer - Select files to close Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok Select the files to close. QAbstractItemView::NoEditTriggers QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows true File Full Name buttonBox accepted() SeerCloseSourceDialogForm accept() 248 254 157 274 buttonBox rejected() SeerCloseSourceDialogForm reject() 316 260 286 274 seer-2.7/src/SeerCommandLogsWidget.cpp000066400000000000000000000561421516472651200200220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCommandLogsWidget.h" #include "SeerMacroToolButton.h" #include "SeerLogWidget.h" #include "SeerHelpPageDialog.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include #include #include #include SeerCommandLogsWidget::SeerCommandLogsWidget (QWidget* parent) : QWidget(parent) { _consoleWidget = 0; _consoleIndex = -1; _consoleScrollLines = 1000; _rememberManualCommandCount = 10; _aboutToQuit = false; setupUi(this); // Setup the widgets QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); m1ToolButton->setMacroName("M1"); m2ToolButton->setMacroName("M2"); m3ToolButton->setMacroName("M3"); m4ToolButton->setMacroName("M4"); m5ToolButton->setMacroName("M5"); m6ToolButton->setMacroName("M6"); m7ToolButton->setMacroName("M7"); m8ToolButton->setMacroName("M8"); m9ToolButton->setMacroName("M9"); m0ToolButton->setMacroName("M0"); _messagesBrowserWidget = new SeerMessagesBrowserWidget(this); _breakpointsBrowserWidget = new SeerBreakpointsBrowserWidget(this); _watchpointsBrowserWidget = new SeerWatchpointsBrowserWidget(this); _catchpointsBrowserWidget = new SeerCatchpointsBrowserWidget(this); _printpointsBrowserWidget = new SeerPrintpointsBrowserWidget(this); _checkpointsBrowserWidget = new SeerCheckpointsBrowserWidget(this); _gdbOutputLog = new SeerGdbLogWidget(this); _seerOutputLog = new SeerSeerLogWidget(this); _gdbOutputLog->setPlaceholderText("[gdb output]"); _seerOutputLog->setPlaceholderText("[seer output]"); logsTabWidget->clear(); logsTabWidget->addTab(_messagesBrowserWidget, "Messages"); logsTabWidget->addTab(_breakpointsBrowserWidget, "Breakpoints"); logsTabWidget->addTab(_watchpointsBrowserWidget, "Watchpoints"); logsTabWidget->addTab(_catchpointsBrowserWidget, "Catchpoints"); logsTabWidget->addTab(_printpointsBrowserWidget, "Printpoints"); logsTabWidget->addTab(_checkpointsBrowserWidget, "Checkpoints"); logsTabWidget->addTab(_gdbOutputLog, "GDB output"); logsTabWidget->addTab(_seerOutputLog, "Seer output"); logsTabWidget->setCurrentIndex(0); QToolButton* tabsContextMenuButton = new QToolButton(logsTabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); logsTabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Create the console tab. // Each RUN method will create and connect to the console's terminal. createConsole(); // Set manual command settings. manualCommandComboBox->setFont(font); manualCommandComboBox->setEditable(true); manualCommandComboBox->lineEdit()->setPlaceholderText("Manually enter a gdb/mi command..."); manualCommandComboBox->lineEdit()->setToolTip("Manually enter a gdb/mi command."); manualCommandComboBox->lineEdit()->setClearButtonEnabled(true); // Restore tab ordering and manual command history. readSettings(); readHistorySettings(); readLogSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerCommandLogsWidget::handleTabsContextMenuButtonClicked); QObject::connect(logsTabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerCommandLogsWidget::handleLogsTabMoved); QObject::connect(logsTabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerCommandLogsWidget::handleLogsTabChanged); QObject::connect(manualCommandComboBox->lineEdit(), &QLineEdit::returnPressed, this, &SeerCommandLogsWidget::handleManualCommandExecute); QObject::connect(manualCommandComboBox, QOverload::of(&QComboBox::activated), this, &SeerCommandLogsWidget::handleManualCommandChanged); QObject::connect(_messagesBrowserWidget, &SeerMessagesBrowserWidget::showMessages, this, &SeerCommandLogsWidget::handleRaiseMessageTab); QObject::connect(_gdbOutputLog, &SeerLogWidget::logEnabledChanged, this, &SeerCommandLogsWidget::handleLogOutputChanged); QObject::connect(_gdbOutputLog, &SeerLogWidget::logTimeStampChanged, this, &SeerCommandLogsWidget::handleLogOutputChanged); QObject::connect(_seerOutputLog, &SeerLogWidget::logEnabledChanged, this, &SeerCommandLogsWidget::handleLogOutputChanged); QObject::connect(_seerOutputLog, &SeerLogWidget::logTimeStampChanged, this, &SeerCommandLogsWidget::handleLogOutputChanged); QObject::connect(breakpointsLoadToolButton, &QToolButton::clicked, this, &SeerCommandLogsWidget::handleGdbLoadBreakpoints); QObject::connect(breakpointsSaveToolButton, &QToolButton::clicked, this, &SeerCommandLogsWidget::handleGdbSaveBreakpoints); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerCommandLogsWidget::handleHelpToolButtonClicked); QObject::connect(macroButtonGroup, &QButtonGroup::buttonClicked, this, &SeerCommandLogsWidget::handleMacroToolButtonClicked); QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &SeerCommandLogsWidget::handleAboutToQuit); } SeerCommandLogsWidget::~SeerCommandLogsWidget () { deleteConsole(); } SeerMessagesBrowserWidget* SeerCommandLogsWidget::messagesBrowser () { return _messagesBrowserWidget; } SeerBreakpointsBrowserWidget* SeerCommandLogsWidget::breakpointsBrowser () { return _breakpointsBrowserWidget; } SeerWatchpointsBrowserWidget* SeerCommandLogsWidget::watchpointsBrowser () { return _watchpointsBrowserWidget; } SeerCatchpointsBrowserWidget* SeerCommandLogsWidget::catchpointsBrowser () { return _catchpointsBrowserWidget; } SeerPrintpointsBrowserWidget* SeerCommandLogsWidget::printpointsBrowser () { return _printpointsBrowserWidget; } SeerCheckpointsBrowserWidget* SeerCommandLogsWidget::checkpointsBrowser () { return _checkpointsBrowserWidget; } SeerGdbLogWidget* SeerCommandLogsWidget::gdbOutputLog () { return _gdbOutputLog; } SeerSeerLogWidget* SeerCommandLogsWidget::seerOutputLog () { return _seerOutputLog; } SeerConsoleWidget* SeerCommandLogsWidget::console () { return _consoleWidget; } void SeerCommandLogsWidget::createConsole () { if (_consoleWidget == 0) { _consoleWidget = new SeerConsoleWidget(0); // The console needs to know when it's detached or reattached. QObject::connect(logsTabWidget, qOverload(&QDetachTabWidget::tabDetached), _consoleWidget, &SeerConsoleWidget::handleTabDetached); QObject::connect(logsTabWidget, qOverload(&QDetachTabWidget::tabReattached), _consoleWidget, &SeerConsoleWidget::handleTabReattached); _consoleIndex = logsTabWidget->addTab(_consoleWidget, "Console output"); QObject::connect(_consoleWidget, &SeerConsoleWidget::newTextAdded, this, &SeerCommandLogsWidget::handleConsoleNewTextAdded); QObject::connect(_consoleWidget, &SeerConsoleWidget::newTextViewed, this, &SeerCommandLogsWidget::handleConsoleNewTextViewed); setConsoleMode(consoleMode()); setConsoleScrollLines(consoleScrollLines()); } } void SeerCommandLogsWidget::deleteConsole () { if (_consoleWidget) { if (_consoleIndex >= 0) { logsTabWidget->removeTab(_consoleIndex); } delete _consoleWidget; _consoleWidget = 0; _consoleIndex = -1; } } void SeerCommandLogsWidget::reattachConsole () { if (_consoleIndex < 0) { return; } if (_consoleWidget == nullptr) { return; } _consoleMode = "attached"; logsTabWidget->reattachTab(_consoleIndex); } void SeerCommandLogsWidget::setConsoleMode (const QString& mode) { _consoleMode = mode; handleConsoleModeChanged(); } QString SeerCommandLogsWidget::consoleMode () const { return _consoleMode; } void SeerCommandLogsWidget::setConsoleScrollLines (int count) { _consoleScrollLines = count; if (_consoleWidget) { _consoleWidget->setScrollLines(_consoleScrollLines); } } int SeerCommandLogsWidget::consoleScrollLines () const { return _consoleScrollLines; } void SeerCommandLogsWidget::setManualCommands (const QStringList& commands) { manualCommandComboBox->clear(); manualCommandComboBox->addItems(commands); // Point to last one. if (manualCommandComboBox->count() > 0) { manualCommandComboBox->setCurrentIndex(manualCommandComboBox->count()-1); } } QStringList SeerCommandLogsWidget::manualCommands(int count) const { // Select all if a zero. if (count == 0) { count = manualCommandComboBox->count(); } // No more than count. if (count > manualCommandComboBox->count()) { count = manualCommandComboBox->count(); } // Calculate starting position in list. int index = manualCommandComboBox->count() - count; // Get the list. QStringList list; for (; indexitemText(index); } return list; } void SeerCommandLogsWidget::setRememberManualCommandCount (int count) { _rememberManualCommandCount = count; } int SeerCommandLogsWidget::rememberManualCommandCount () const { return _rememberManualCommandCount; } void SeerCommandLogsWidget::clearManualCommandHistory () { // Zap the entries in the combobox. manualCommandComboBox->clear(); // Write the history settings. writeHistorySettings(); } void SeerCommandLogsWidget::handleLogsTabMoved (int to, int from) { Q_UNUSED(from); Q_UNUSED(to); // Keep track of console tab if it moved. if (_consoleIndex == from) { _consoleIndex = to; } // Don't handle anything here if Seer is exiting. if (_aboutToQuit) { return; } writeSettings(); } void SeerCommandLogsWidget::handleLogsTabChanged (int index) { Q_UNUSED(index); // Don't handle anything here if Seer is exiting. if (_aboutToQuit) { return; } writeSettings(); } void SeerCommandLogsWidget::handleRaiseMessageTab () { int idx = logsTabWidget->indexOf(_messagesBrowserWidget); if (idx < 0) { return; } logsTabWidget->setCurrentIndex(idx); } void SeerCommandLogsWidget::handleConsoleModeChanged () { if (_consoleIndex < 0) { return; } if (_consoleWidget == nullptr) { return; } if (_consoleMode == "detached") { logsTabWidget->detachTab(_consoleIndex, false); _consoleWidget->raise(); _consoleWidget->resetSize(); }else if (_consoleMode == "detachedminimized") { logsTabWidget->detachTab(_consoleIndex, true); _consoleWidget->resetSize(); }else if (_consoleMode == "attached") { logsTabWidget->reattachTab(_consoleIndex); }else{ logsTabWidget->reattachTab(_consoleIndex); } } void SeerCommandLogsWidget::handleConsoleNewTextAdded () { if (_consoleIndex >= 0) { logsTabWidget->setTabIcon(_consoleIndex, QIcon(":/seer/resources/RelaxLightIcons/data-information.svg")); } } void SeerCommandLogsWidget::handleConsoleNewTextViewed () { if (_consoleIndex >= 0) { logsTabWidget->setTabIcon(_consoleIndex, QIcon()); } } void SeerCommandLogsWidget::handleManualCommandExecute () { // Get new command. QString command = manualCommandComboBox->currentText(); // Do nothing if it is blank. if (command == "") { return; } // Remove the second to last line, if it is blank. if (manualCommandComboBox->count() >= 2) { QString lastCommand = manualCommandComboBox->itemText(manualCommandComboBox->count()-2); if (lastCommand == "") { manualCommandComboBox->removeItem(manualCommandComboBox->count()-2); } } // Remove the last line, if it is blank. if (manualCommandComboBox->count() >= 1) { QString lastCommand = manualCommandComboBox->itemText(manualCommandComboBox->count()-1); if (lastCommand == "") { manualCommandComboBox->removeItem(manualCommandComboBox->count()-1); } } // Add entered command to the end of the list as long as it's not // already there. if (manualCommandComboBox->count() > 0) { QString lastCommand = manualCommandComboBox->itemText(manualCommandComboBox->count()-1); if (lastCommand != command) { manualCommandComboBox->addItem(command); } } // Add a blank entry. It will be removed when the next manual command is entered. manualCommandComboBox->addItem(""); // Point to last one. manualCommandComboBox->setCurrentIndex(manualCommandComboBox->count()-1); // Execute it. emit executeGdbCommand(command); writeHistorySettings(); } void SeerCommandLogsWidget::handleManualCommandChanged () { writeHistorySettings(); } void SeerCommandLogsWidget::handleLogOutputChanged () { writeLogSettings(); } void SeerCommandLogsWidget::handleGdbLoadBreakpoints () { QFileDialog dialog(this, "Seer - Load Breakpoints from a file.", "./", "Breakpoints (*.seer);;All files (*.*)"); dialog.setOptions(QFileDialog::DontUseNativeDialog); dialog.setAcceptMode(QFileDialog::AcceptOpen); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("seer"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QString fname = files[0]; emit executeGdbCommand("source -v " + fname); emit refreshBreakpointsList(); QMessageBox::information(this, "Seer", "Loaded."); } void SeerCommandLogsWidget::handleGdbSaveBreakpoints () { if (breakpointsBrowser()->isEmpty() && watchpointsBrowser()->isEmpty() && catchpointsBrowser()->isEmpty() && printpointsBrowser()->isEmpty()) { QMessageBox::information(this, "Seer", "No breakpoints of any kind to save."); return; } QFileDialog dialog(this, "Seer - Save Breakpoints to a file.", "./", "Breakpoints (*.seer);;All files (*.*)"); dialog.setOptions(QFileDialog::DontUseNativeDialog); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("seer"); dialog.selectFile("breakpoints.seer"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QString fname = files[0]; emit executeGdbCommand("save breakpoints " + fname); QMessageBox::information(this, "Seer", "Saved."); } void SeerCommandLogsWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/BreakpointGdbSeerManager.md"); help->show(); help->raise(); } void SeerCommandLogsWidget::handleMacroToolButtonClicked (QAbstractButton* button) { if (button == nullptr) { return; } SeerMacroToolButton* tb = qobject_cast(button); QString macroFileName = tb->macroFileName(); if (macroFileName == "") { return; } emit executeGdbCommand("source -v " + macroFileName); } void SeerCommandLogsWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(logsTabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(logsTabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = logsTabWidget->tabBar()->tabText(logsTabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Write settings. QSettings settings; settings.beginGroup("logsmanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerCommandLogsWidget::readSettings () { QSettings settings; // Read tab order from settings. QStringList tabs; QStringList visible; QString current; settings.beginGroup("logsmanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (logsTabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { logsTabWidget->tabBar()->moveTab(tb, i); } } // Find the console tab index. _consoleIndex = -1; for (int i=0; itabBar()->count(); i++) { if (logsTabWidget->tabBar()->tabText(i) == "Console output") { _consoleIndex = i; break; } } if (_consoleIndex < 0) { qDebug() << "The console tab index is not in the settings."; } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { logsTabWidget->setTabVisible(i,false); }else{ logsTabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (logsTabWidget->tabBar()->tabText(i) == current) { logsTabWidget->setCurrentIndex(i); break; } } }else{ logsTabWidget->setCurrentIndex(0); } } void SeerCommandLogsWidget::writeHistorySettings () { QSettings settings; // Write the manual command history. settings.beginWriteArray("manualgdbcommandshistory"); { QStringList commands = manualCommands(rememberManualCommandCount()); if (commands.size() > 0) { for (int i = 0; i < commands.size(); ++i) { settings.setArrayIndex(i); settings.setValue("command", commands[i]); } } } settings.endArray(); } void SeerCommandLogsWidget::readHistorySettings () { QSettings settings; // Read the manual command history. int size = settings.beginReadArray("manualgdbcommandshistory"); { QStringList commands; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); commands << settings.value("command").toString(); } setManualCommands(commands); } settings.endArray(); } void SeerCommandLogsWidget::writeLogSettings () { QSettings settings; // Write log settings. settings.beginGroup("gdboutputlog"); { settings.setValue("enabled", _gdbOutputLog->isLogEnabled()); settings.setValue("timestamp", _gdbOutputLog->isTimeStampEnabled()); } settings.endGroup(); settings.beginGroup("seeroutputlog"); { settings.setValue("enabled", _seerOutputLog->isLogEnabled()); settings.setValue("timestamp", _seerOutputLog->isTimeStampEnabled()); } settings.endGroup(); } void SeerCommandLogsWidget::readLogSettings () { QSettings settings; // Read log settings. settings.beginGroup("gdboutputlog"); { _gdbOutputLog->setLogEnabled(settings.value("enabled", true).toBool()); _gdbOutputLog->setTimeStampEnabled(settings.value("timestamp", false).toBool()); } settings.endGroup(); settings.beginGroup("seeroutputlog"); { _seerOutputLog->setLogEnabled(settings.value("enabled", true).toBool()); _seerOutputLog->setTimeStampEnabled(settings.value("timestamp", false).toBool()); } settings.endGroup(); } void SeerCommandLogsWidget::handleAboutToQuit () { _aboutToQuit = true; } void SeerCommandLogsWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < logsTabWidget->count(); i++) { QString title = logsTabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(logsTabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (logsTabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { logsTabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ logsTabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } seer-2.7/src/SeerCommandLogsWidget.h000066400000000000000000000124631516472651200174650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerConsoleWidget.h" #include "SeerGdbLogWidget.h" #include "SeerSeerLogWidget.h" #include "SeerMessagesBrowserWidget.h" #include "SeerBreakpointsBrowserWidget.h" #include "SeerWatchpointsBrowserWidget.h" #include "SeerCatchpointsBrowserWidget.h" #include "SeerPrintpointsBrowserWidget.h" #include "SeerCheckpointsBrowserWidget.h" #include #include "ui_SeerCommandLogsWidget.h" class SeerCommandLogsWidget : public QWidget, protected Ui::SeerCommandLogsWidgetForm { Q_OBJECT public: explicit SeerCommandLogsWidget (QWidget* parent = 0); ~SeerCommandLogsWidget (); SeerMessagesBrowserWidget* messagesBrowser (); SeerBreakpointsBrowserWidget* breakpointsBrowser (); SeerWatchpointsBrowserWidget* watchpointsBrowser (); SeerCatchpointsBrowserWidget* catchpointsBrowser (); SeerPrintpointsBrowserWidget* printpointsBrowser (); SeerCheckpointsBrowserWidget* checkpointsBrowser (); SeerGdbLogWidget* gdbOutputLog (); SeerSeerLogWidget* seerOutputLog (); void createConsole (); void deleteConsole (); void reattachConsole (); SeerConsoleWidget* console (); void setConsoleMode (const QString& mode); QString consoleMode () const; void setConsoleScrollLines (int count); int consoleScrollLines () const; void setManualCommands (const QStringList& commands); QStringList manualCommands (int count) const; void setRememberManualCommandCount (int count); int rememberManualCommandCount () const; void clearManualCommandHistory (); protected slots: void handleLogsTabMoved (int to, int from); void handleLogsTabChanged (int index); void handleRaiseMessageTab (); void handleConsoleModeChanged (); void handleConsoleNewTextAdded (); void handleConsoleNewTextViewed (); void handleManualCommandExecute (); void handleManualCommandChanged (); void handleLogOutputChanged (); void handleGdbLoadBreakpoints (); void handleGdbSaveBreakpoints (); void handleHelpToolButtonClicked (); void handleMacroToolButtonClicked (QAbstractButton* button); void handleAboutToQuit (); void handleTabsContextMenuButtonClicked (); signals: void executeGdbCommand (QString command); void refreshBreakpointsList (); protected: void writeSettings (); void readSettings (); void writeHistorySettings (); void readHistorySettings (); void writeLogSettings (); void readLogSettings (); private: SeerConsoleWidget* _consoleWidget; int _consoleIndex; QString _consoleMode; int _consoleScrollLines; int _rememberManualCommandCount; bool _aboutToQuit; SeerMessagesBrowserWidget* _messagesBrowserWidget; SeerBreakpointsBrowserWidget* _breakpointsBrowserWidget; SeerWatchpointsBrowserWidget* _watchpointsBrowserWidget; SeerCatchpointsBrowserWidget* _catchpointsBrowserWidget; SeerPrintpointsBrowserWidget* _printpointsBrowserWidget; SeerCheckpointsBrowserWidget* _checkpointsBrowserWidget; SeerGdbLogWidget* _gdbOutputLog; SeerSeerLogWidget* _seerOutputLog; }; seer-2.7/src/SeerCommandLogsWidget.ui000066400000000000000000000200211516472651200176400ustar00rootroot00000000000000 SeerCommandLogsWidgetForm 0 0 975 384 Seer - Commands and Logs 0 0 0 0 M1 macro. Click to execute. Hold down to edit. M1 Qt::NoArrow macroButtonGroup M2 macro. Click to execute. Hold down to edit. M2 macroButtonGroup M3 macro. Click to execute. Hold down to edit. M3 macroButtonGroup M4 macro. Click to execute. Hold down to edit. M4 macroButtonGroup M5 macro. Click to execute. Hold down to edit. M5 macroButtonGroup M6 macro. Click to execute. Hold down to edit. M6 macroButtonGroup M7 macro. Click to execute. Hold down to edit. M7 macroButtonGroup M8 macro. Click to execute. Hold down to edit. M8 macroButtonGroup M9 macro. Click to execute. Hold down to edit. M9 macroButtonGroup M0 macro. Click to execute. Hold down to edit. M0 macroButtonGroup Qt::Horizontal 578 20 Load previously saved breakpoints. ... :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Save breakpoints to a file. ... :/seer/resources/RelaxLightIcons/document-save.svg:/seer/resources/RelaxLightIcons/document-save.svg Help on Breakpoint/Logs/Commands information. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg false 0 true Tab 1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
SeerMacroToolButton QToolButton
SeerMacroToolButton.h
seer-2.7/src/SeerConfigDialog.cpp000066400000000000000000000376141516472651200170030ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerConfigDialog.h" #include #include #include #include #include #include #include #include SeerConfigDialog::SeerConfigDialog(QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets QSize size(96, 84); int spacing = 12; contentsListWidget->setViewMode(QListView::IconMode); contentsListWidget->setIconSize(size); contentsListWidget->setMovement(QListView::Static); contentsListWidget->setSpacing(spacing); contentsListWidget->setFixedWidth(size.width()+(spacing*3)); contentsListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QPushButton* resetButton = buttonBox->button(QDialogButtonBox::Reset); if (resetButton) { resetButton->setToolTip("Reset configuration for the current page to initial settings."); } QPushButton* okButton = buttonBox->button(QDialogButtonBox::Ok); if (okButton) { okButton->setToolTip("Accept configuration changes to all pages."); } QPushButton* cancelButton = buttonBox->button(QDialogButtonBox::Cancel); if (cancelButton) { cancelButton->setToolTip("Discard configuration changes to all pages."); } // Create pages. _seerConfigPage = new SeerSeerConfigPage; _gdbConfigPage = new SeerGdbConfigPage; _editorConfigPage = new SeerEditorConfigPage; _sourceConfigPage = new SeerSourceConfigPage; _assemblyConfigPage = new SeerAssemblyConfigPage; _keysConfigPage = new SeerKeysConfigPage; _rrConfigPage = new SeerRRConfigPage; // Add the pages to the stacked widget. pagesStackedWidget->addWidget(_seerConfigPage); pagesStackedWidget->addWidget(_gdbConfigPage); pagesStackedWidget->addWidget(_editorConfigPage); pagesStackedWidget->addWidget(_sourceConfigPage); pagesStackedWidget->addWidget(_assemblyConfigPage); pagesStackedWidget->addWidget(_keysConfigPage); pagesStackedWidget->addWidget(_rrConfigPage); // Create icons. QListWidgetItem* configSeerButton = new QListWidgetItem(contentsListWidget); configSeerButton->setIcon(QIcon(":/seer/resources/icons/hicolor/128x128/seergdb.png")); configSeerButton->setText(tr("Seer")); configSeerButton->setTextAlignment(Qt::AlignHCenter); configSeerButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configGdbButton = new QListWidgetItem(contentsListWidget); configGdbButton->setIcon(QIcon(":/seer/resources/icons-icons/gdb.png")); configGdbButton->setText(tr("GDB")); configGdbButton->setTextAlignment(Qt::AlignHCenter); configGdbButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configEditorButton = new QListWidgetItem(contentsListWidget); configEditorButton->setIcon(QIcon(":/seer/resources/icons-icons/editor.png")); configEditorButton->setText(tr("Editor")); configEditorButton->setTextAlignment(Qt::AlignHCenter); configEditorButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configSourceButton = new QListWidgetItem(contentsListWidget); configSourceButton->setIcon(QIcon(":/seer/resources/thenounproject/source.svg")); configSourceButton->setText(tr("Source")); configSourceButton->setTextAlignment(Qt::AlignHCenter); configSourceButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configAssemblyButton = new QListWidgetItem(contentsListWidget); configAssemblyButton->setIcon(QIcon(":/seer/resources/thenounproject/assembly.svg")); configAssemblyButton->setText(tr("Assembly")); configAssemblyButton->setTextAlignment(Qt::AlignHCenter); configAssemblyButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configKeysButton = new QListWidgetItem(contentsListWidget); configKeysButton->setIcon(QIcon(":/seer/resources/thenounproject/keyboard.svg")); configKeysButton->setText(tr("Keys")); configKeysButton->setTextAlignment(Qt::AlignHCenter); configKeysButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configRRButton = new QListWidgetItem(contentsListWidget); configRRButton->setIcon(QIcon(":/seer/resources/icons/hicolor/256x256/rr.png")); configRRButton->setText(tr("RR")); configRRButton->setTextAlignment(Qt::AlignHCenter); configRRButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); // Connect things. connect(contentsListWidget, &QListWidget::currentItemChanged, this, &SeerConfigDialog::handleChangePage); connect(buttonBox, &QDialogButtonBox::clicked, this, &SeerConfigDialog::handleButtonClicked); // Set to first page. contentsListWidget->setCurrentRow(0); } SeerConfigDialog::~SeerConfigDialog() { } void SeerConfigDialog::setSeerConsoleMode (const QString& mode) { _seerConfigPage->setConsoleMode(mode); } QString SeerConfigDialog::seerConsoleMode () const { return _seerConfigPage->consoleMode(); } void SeerConfigDialog::setSeerConsoleScrollLines (int count) { _seerConfigPage->setConsoleScrollLines(count); } int SeerConfigDialog::seerConsoleScrollLines () const { return _seerConfigPage->consoleScrollLines(); } void SeerConfigDialog::setSeerRememberWindowSizes (bool flag) { _seerConfigPage->setRememberWindowSizes(flag); } bool SeerConfigDialog::seerRememberWindowSizes () const { return _seerConfigPage->rememberWindowSizes(); } void SeerConfigDialog::setSeerRememberManualCommandCount (int count) { _seerConfigPage->setRememberManualCommandCount(count); } int SeerConfigDialog::seerRememberManualCommandCount () const { return _seerConfigPage->rememberManualCommandCount(); } void SeerConfigDialog::setSeerClearManualCommandHistory (bool flag) { _seerConfigPage->setClearManualCommandHistory(flag); } bool SeerConfigDialog::seerClearManualCommandHistory () const { return _seerConfigPage->clearManualCommandHistory(); } void SeerConfigDialog::setGdbLauncher (const QString& launcher) { _gdbConfigPage->setGdbLauncher(launcher); } QString SeerConfigDialog::gdbLauncher () const { return _gdbConfigPage->gdbLauncher(); } void SeerConfigDialog::setGdbProgram (const QString& program) { _gdbConfigPage->setGdbProgram(program); } QString SeerConfigDialog::gdbProgram () const { return _gdbConfigPage->gdbProgram(); } void SeerConfigDialog::setGdbArguments (const QString& arguments) { _gdbConfigPage->setGdbArguments(arguments); } QString SeerConfigDialog::gdbArguments () const { return _gdbConfigPage->gdbArguments(); } void SeerConfigDialog::setGdbAsyncMode (bool flag) { _gdbConfigPage->setGdbAsyncMode(flag); } bool SeerConfigDialog::gdbAsyncMode () const { return _gdbConfigPage->gdbAsyncMode(); } void SeerConfigDialog::setGdbNonStopMode (bool flag) { _gdbConfigPage->setGdbNonStopMode(flag); } bool SeerConfigDialog::gdbNonStopMode () const { return _gdbConfigPage->gdbNonStopMode(); } void SeerConfigDialog::setGdbHandleTerminatingException (bool flag) { _gdbConfigPage->setGdbHandleTerminatingException(flag); } bool SeerConfigDialog::gdbHandleTerminatingException () const { return _gdbConfigPage->gdbHandleTerminatingException(); } void SeerConfigDialog::setGdbRandomizeStartAddress (bool flag) { _gdbConfigPage->setGdbRandomizeStartAddress(flag); } bool SeerConfigDialog::gdbRandomizeStartAddress () const { return _gdbConfigPage->gdbRandomizeStartAddress(); } void SeerConfigDialog::setGdbEnablePrettyPrinting (bool flag) { _gdbConfigPage->setGdbEnablePrettyPrinting(flag); } bool SeerConfigDialog::gdbEnablePrettyPrinting () const { return _gdbConfigPage->gdbEnablePrettyPrinting(); } void SeerConfigDialog::setGdbRemoteTargetType (const QString& type) { _gdbConfigPage->setGdbRemoteTargetType(type); } QString SeerConfigDialog::gdbRemoteTargetType () const { return _gdbConfigPage->gdbRemoteTargetType(); } void SeerConfigDialog::setGdbArchitectureType (const QString& type) { _gdbConfigPage->setGdbArchitectureType(type); } QString SeerConfigDialog::gdbArchitectureType () const { return _gdbConfigPage->gdbArchitectureType(); } void SeerConfigDialog::setEditorFont (const QFont& font) { _editorConfigPage->setEditorFont(font); } const QFont& SeerConfigDialog::editorFont () const { return _editorConfigPage->editorFont(); } void SeerConfigDialog::setEditorTabSize (int spaces) { _editorConfigPage->setEditorTabSize(spaces); } int SeerConfigDialog::editorTabSize () const { return _editorConfigPage->editorTabSize(); } void SeerConfigDialog::setEditorHighlighterSettings (const SeerHighlighterSettings& settings) { _editorConfigPage->setHighlighterSettings(settings); } const SeerHighlighterSettings& SeerConfigDialog::editorHighlighterSettings () const { return _editorConfigPage->highlighterSettings(); } void SeerConfigDialog::setEditorHighlighterEnabled (bool flag) { _editorConfigPage->setHighlighterEnabled(flag); } bool SeerConfigDialog::editorHighlighterEnabled () const { return _editorConfigPage->highlighterEnabled(); } void SeerConfigDialog::setExternalEditorCommand (const QString& externalEditorCommand) { _editorConfigPage->setExternalEditorCommand(externalEditorCommand); } QString SeerConfigDialog::externalEditorCommand () const { return _editorConfigPage->externalEditorCommand(); } void SeerConfigDialog::setEditorAutoSourceReload (bool flag) { _editorConfigPage->setAutoSourceReload(flag); } bool SeerConfigDialog::editorAutoSourceReload () const { return _editorConfigPage->autoSourceReload(); } void SeerConfigDialog::setSourceAlternateDirectories (const QStringList& alternateDirectories) { _sourceConfigPage->setAlternateDirectories(alternateDirectories); } QStringList SeerConfigDialog::sourceAlternateDirectories () const { return _sourceConfigPage->alternateDirectories(); } void SeerConfigDialog::setSourceIgnoreFilePatterns (const QStringList& filePatterns) { _sourceConfigPage->setIgnoreFilePatterns(filePatterns); } QStringList SeerConfigDialog::sourceIgnoreFilePatterns () const { return _sourceConfigPage->ignoreFilePatterns(); } void SeerConfigDialog::setSourceMiscFilePatterns (const QStringList& filePatterns) { _sourceConfigPage->setMiscFilePatterns(filePatterns); } QStringList SeerConfigDialog::sourceMiscFilePatterns () const { return _sourceConfigPage->miscFilePatterns(); } void SeerConfigDialog::setSourceSourceFilePatterns (const QStringList& filePatterns) { _sourceConfigPage->setSourceFilePatterns(filePatterns); } QStringList SeerConfigDialog::sourceSourceFilePatterns () const { return _sourceConfigPage->sourceFilePatterns(); } void SeerConfigDialog::setSourceHeaderFilePatterns (const QStringList& filePatterns) { _sourceConfigPage->setHeaderFilePatterns(filePatterns); } QStringList SeerConfigDialog::sourceHeaderFilePatterns () const { return _sourceConfigPage->headerFilePatterns(); } void SeerConfigDialog::setAssemblyShowAssemblyTabOnStartupMode (const QString& mode) { _assemblyConfigPage->setShowAssemblyTabOnStartupMode(mode); } QString SeerConfigDialog::assemblyShowAssemblyTabOnStartupMode () const { return _assemblyConfigPage->showAssemblyTabOnStartupMode(); } void SeerConfigDialog::setAssemblyKeepAssemblyTabOnTop (bool flag) { _assemblyConfigPage->setKeepAssemblyTabOnTop(flag); } bool SeerConfigDialog::assemblyKeepAssemblyTabOnTop () const { return _assemblyConfigPage->keepAssemblyTabOnTop(); } void SeerConfigDialog::setAssemblyDisassemblyFlavor (const QString& flavor) { _assemblyConfigPage->setDisassemblyFlavor(flavor); } QString SeerConfigDialog::assemblyDisassemblyFlavor () const { return _assemblyConfigPage->disassemblyFlavor(); } void SeerConfigDialog::setAssemblySymbolDemagling (const QString& onoff) { _assemblyConfigPage->setSymbolDemagling(onoff); } QString SeerConfigDialog::assemblySymbolDemagling () const { return _assemblyConfigPage->symbolDemagling(); } void SeerConfigDialog::setAssemblyShowAddressColumn (bool flag) { _assemblyConfigPage->setShowAddressColumn(flag); } bool SeerConfigDialog::assemblyShowAddressColumn () const { return _assemblyConfigPage->showAddressColumn(); } void SeerConfigDialog::setAssemblyShowOffsetColumn (bool flag) { _assemblyConfigPage->setShowOffsetColumn(flag); } bool SeerConfigDialog::assemblyShowOffsetColumn () const { return _assemblyConfigPage->showOffsetColumn(); } void SeerConfigDialog::setAssemblyShowOpcodeColumn (bool flag) { _assemblyConfigPage->setShowOpcodeColumn(flag); } bool SeerConfigDialog::assemblyShowOpcodeColumn () const { return _assemblyConfigPage->showOpcodeColumn(); } void SeerConfigDialog::setAssemblyShowSourceLines (bool flag) { _assemblyConfigPage->setShowSourceLines(flag); } bool SeerConfigDialog::assemblyShowSourceLines () const { return _assemblyConfigPage->showSourceLines(); } void SeerConfigDialog::setAssemblyRegisterFormat (const QString& format) { _assemblyConfigPage->setRegisterFormat(format); } QString SeerConfigDialog::assemblyRegisterFormat () const { return _assemblyConfigPage->registerFormat(); } void SeerConfigDialog::setAssemblyDisassemblyMode (const QString& mode, int bytes) { _assemblyConfigPage->setDisassemblyMode(mode, bytes); } QString SeerConfigDialog::assemblyDisassemblyMode () const { return _assemblyConfigPage->disassemblyMode(); } int SeerConfigDialog::assemblyDisassemblyBytes () const { return _assemblyConfigPage->disassemblyBytes(); } void SeerConfigDialog::setKeySettings (const SeerKeySettings& settings) { _keysConfigPage->setKeySettings(settings); } SeerKeySettings SeerConfigDialog::keySettings () const { return _keysConfigPage->keySettings(); } void SeerConfigDialog::setRRProgram (const QString& program) { _rrConfigPage->setRRProgram(program); } QString SeerConfigDialog::rrProgram () const { return _rrConfigPage->rrProgram(); } void SeerConfigDialog::setRRArguments (const QString& arguments) { _rrConfigPage->setRRArguments(arguments); } QString SeerConfigDialog::rrArguments () const { return _rrConfigPage->rrArguments(); } void SeerConfigDialog::setRRGdbArguments (const QString& arguments) { _rrConfigPage->setGdbArguments(arguments); } QString SeerConfigDialog::rrGdbArguments () const { return _rrConfigPage->gdbArguments(); } void SeerConfigDialog::handleChangePage(QListWidgetItem* current, QListWidgetItem* previous) { if (!current) { current = previous; } pagesStackedWidget->setCurrentIndex(contentsListWidget->row(current)); } void SeerConfigDialog::handleButtonClicked (QAbstractButton* button) { // Handle resetting the config pages if "Reset" is clicked. if (buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) { QString itemLabel = contentsListWidget->currentItem()->text(); int result = QMessageBox::warning(this, "Seer", QString("Reset settings for the '") + itemLabel + "' tab?", QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel); if (result != QMessageBox::Ok) { return; } if (itemLabel == "GDB") { _gdbConfigPage->reset(); }else if (itemLabel == "Editor") { _editorConfigPage->reset(); }else if (itemLabel == "Source") { _sourceConfigPage->reset(); }else if (itemLabel == "Assembly") { _assemblyConfigPage->reset(); }else if (itemLabel == "Keys") { _keysConfigPage->reset(); }else if (itemLabel == "Seer") { _seerConfigPage->reset(); }else if (itemLabel == "RR") { _rrConfigPage->reset(); } } } seer-2.7/src/SeerConfigDialog.h000066400000000000000000000243631516472651200164450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerGdbConfigPage.h" #include "SeerRRConfigPage.h" #include "SeerEditorConfigPage.h" #include "SeerSourceConfigPage.h" #include "SeerAssemblyConfigPage.h" #include "SeerKeysConfigPage.h" #include "SeerSeerConfigPage.h" #include #include "ui_SeerConfigDialog.h" class QListWidget; class QListWidgetItem; class QStackedWidget; class SeerConfigDialog : public QDialog, protected Ui::SeerConfigDialogForm { Q_OBJECT public: explicit SeerConfigDialog (QWidget* parent = 0); ~SeerConfigDialog (); // Seer settings. void setSeerConsoleMode (const QString& mode); QString seerConsoleMode () const; void setSeerConsoleScrollLines (int count); int seerConsoleScrollLines () const; void setSeerRememberWindowSizes (bool flag); bool seerRememberWindowSizes () const; void setSeerRememberManualCommandCount (int count); int seerRememberManualCommandCount () const; void setSeerClearManualCommandHistory (bool flag); bool seerClearManualCommandHistory () const; // Gdb settings. // Program to launch gdb, rr, etc. Can be blank. Needed by flatpak. void setGdbLauncher (const QString& launcher); QString gdbLauncher () const; void setGdbProgram (const QString& program); QString gdbProgram () const; void setGdbArguments (const QString& arguments); QString gdbArguments () const; void setGdbAsyncMode (bool flag); bool gdbAsyncMode () const; void setGdbNonStopMode (bool flag); bool gdbNonStopMode () const; void setGdbHandleTerminatingException (bool flag); bool gdbHandleTerminatingException () const; void setGdbRandomizeStartAddress (bool flag); bool gdbRandomizeStartAddress () const; void setGdbEnablePrettyPrinting (bool flag); bool gdbEnablePrettyPrinting () const; void setGdbRemoteTargetType (const QString& type); QString gdbRemoteTargetType () const; void setGdbArchitectureType (const QString& type); QString gdbArchitectureType () const; // Editor settings. void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setEditorHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& editorHighlighterSettings () const; void setEditorHighlighterEnabled (bool flag); bool editorHighlighterEnabled () const; void setExternalEditorCommand (const QString& externalEditorCommand); QString externalEditorCommand () const; void setEditorAutoSourceReload (bool flag); bool editorAutoSourceReload () const; // Source settings. void setSourceAlternateDirectories (const QStringList& alternateDirectories); QStringList sourceAlternateDirectories () const; void setSourceIgnoreFilePatterns (const QStringList& filePatterns); QStringList sourceIgnoreFilePatterns () const; void setSourceMiscFilePatterns (const QStringList& filePatterns); QStringList sourceMiscFilePatterns () const; void setSourceSourceFilePatterns (const QStringList& filePatterns); QStringList sourceSourceFilePatterns () const; void setSourceHeaderFilePatterns (const QStringList& filePatterns); QStringList sourceHeaderFilePatterns () const; // Assembly settings. void setAssemblyShowAssemblyTabOnStartupMode (const QString& mode); QString assemblyShowAssemblyTabOnStartupMode () const; void setAssemblyKeepAssemblyTabOnTop (bool flag); bool assemblyKeepAssemblyTabOnTop () const; void setAssemblyDisassemblyFlavor (const QString& flavor); QString assemblyDisassemblyFlavor () const; void setAssemblySymbolDemagling (const QString& onoff); QString assemblySymbolDemagling () const; void setAssemblyShowAddressColumn (bool flag); bool assemblyShowAddressColumn () const; void setAssemblyShowOffsetColumn (bool flag); bool assemblyShowOffsetColumn () const; void setAssemblyShowOpcodeColumn (bool flag); bool assemblyShowOpcodeColumn () const; void setAssemblyShowSourceLines (bool flag); bool assemblyShowSourceLines () const; void setAssemblyRegisterFormat (const QString& format); QString assemblyRegisterFormat () const; void setAssemblyDisassemblyMode (const QString& mode, int bytes); QString assemblyDisassemblyMode () const; int assemblyDisassemblyBytes () const; // Key settings. void setKeySettings (const SeerKeySettings& settings); SeerKeySettings keySettings () const; // RR settings. void setRRProgram (const QString& program); QString rrProgram () const; void setRRArguments (const QString& arguments); QString rrArguments () const; void setRRGdbArguments (const QString& arguments); QString rrGdbArguments () const; public slots: void handleChangePage (QListWidgetItem* current, QListWidgetItem* previous); void handleButtonClicked (QAbstractButton* button); private: SeerGdbConfigPage* _gdbConfigPage; SeerRRConfigPage* _rrConfigPage; SeerEditorConfigPage* _editorConfigPage; SeerSourceConfigPage* _sourceConfigPage; SeerAssemblyConfigPage* _assemblyConfigPage; SeerKeysConfigPage* _keysConfigPage; SeerSeerConfigPage* _seerConfigPage; }; seer-2.7/src/SeerConfigDialog.ui000066400000000000000000000044101516472651200166220ustar00rootroot00000000000000 SeerConfigDialogForm 0 0 736 569 Seer - Configuration 25 0 75 0 1 -1 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset buttonBox accepted() SeerConfigDialogForm accept() 248 254 157 274 buttonBox rejected() SeerConfigDialogForm reject() 316 260 286 274 seer-2.7/src/SeerConsoleWidget.cpp000066400000000000000000000337651516472651200172270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerConsoleWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SeerConsoleWidget::SeerConsoleWidget (QWidget* parent) : QWidget(parent) { // Init variables. _terminalDeviceName = ""; _ttyFD = -1; _ttyListener = 0; _enableStdout = false; _enableWrap = false; // Set up UI. setupUi(this); // Setup the widgets setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer Console"); textEdit->setReadOnly(true); textEdit->setTextInteractionFlags(textEdit->textInteractionFlags() | Qt::TextSelectableByKeyboard); // Show cursor textEdit->setLineWrapMode(QPlainTextEdit::NoWrap); // No wrap // Default font. QFont font; font.setFamily("monospace"); font.setStyleHint(QFont::Monospace); font.setFixedPitch(true); // Set the widget's font. QTextCharFormat format = textEdit->currentCharFormat(); format.setFont(font); textEdit->setCurrentCharFormat(format); textEdit->setFont(font); wrapTextCheckBox->setCheckState(Qt::Unchecked); // No wrap // Connect things. QObject::connect(clearButton, &QPushButton::clicked, this, &SeerConsoleWidget::handleClearButton); QObject::connect(printButton, &QPushButton::clicked, this, &SeerConsoleWidget::handlePrintButton); QObject::connect(saveButton, &QPushButton::clicked, this, &SeerConsoleWidget::handleSaveButton); QObject::connect(fontButton, &QPushButton::clicked, this, &SeerConsoleWidget::handleFontButton); QObject::connect(wrapTextCheckBox, &QCheckBox::clicked, this, &SeerConsoleWidget::handleWrapTextCheckBox); QObject::connect(stdoutCheckBox, &QCheckBox::clicked, this, &SeerConsoleWidget::handleStdoutCheckBox); QObject::connect(stdinLineEdit, &QLineEdit::returnPressed, this, &SeerConsoleWidget::handleStdinLineEdit); // Restore window settings. readSettings(); } SeerConsoleWidget::~SeerConsoleWidget () { deleteTerminal(); // Will disconnect terminal first befor deleting. } void SeerConsoleWidget::handleText (const char* buffer, int count) { if (count < 1) { return; } // Write text to stdout on terminal that started Seer.. // Ignore errors. if (isStdoutEnabled()) { ssize_t n = ::write (STDOUT_FILENO, buffer, count); if (n < count) { qDebug("Can't write stdout to terminal"); } } // Write text to Ansi widget. QString str = QString::fromLatin1(buffer, count); textEdit->insertAnsiText(str); textEdit->ensureCursorVisible(); // Send signal of new text if this widget is not visable. if (isVisible() == false) { emit newTextAdded(); } return; } void SeerConsoleWidget::handleChangeWindowTitle (QString title) { if (title == "") { setWindowTitle("Seer Console"); }else{ setWindowTitle("Seer Console - '" + title + "'"); } } void SeerConsoleWidget::handleTabDetached (QWidget* widget) { if (widget != (QWidget*)this) { return; } // Resize the detached console with the size from // the settings. QSettings settings; settings.beginGroup("consolewindow"); { resize(settings.value("size", QSize(800, 600)).toSize()); } settings.endGroup(); } void SeerConsoleWidget::handleTabReattached (QWidget* widget) { // Do nothing for now. Q_UNUSED(widget); } void SeerConsoleWidget::handleClearButton () { textEdit->clear(); } void SeerConsoleWidget::handlePrintButton () { QPrinter printer; QPrintDialog* dlg = new QPrintDialog(&printer, this); if (dlg->exec() != QDialog::Accepted) { return; } QTextDocument* document = textEdit->document(); document->print(&printer); } void SeerConsoleWidget::handleSaveButton () { QFileDialog dialog(this, "Seer log file", "./", "Logs (*.log);;Text files (*.txt);;All files (*.*)"); dialog.setOptions(QFileDialog::DontUseNativeDialog); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("log"); dialog.selectFile("gdboutput.log"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); stream << textEdit->toPlainText(); file.flush(); file.close(); }else{ QMessageBox::critical(this, tr("Error"), tr("Cannot save log to file.")); return; } } void SeerConsoleWidget::handleFontButton () { // Get current format for the font name. bool ok; QFont font = QFontDialog::getFont(&ok, textEdit->font().toString(), this, "Seer - Select Console Font", QFontDialog::DontUseNativeDialog|QFontDialog::MonospacedFonts); if (ok == false) { return; } // Set the widget's font. QTextCharFormat format = textEdit->currentCharFormat(); format.setFont(font); textEdit->setCurrentCharFormat(format); textEdit->setFont(font); writeFontSettings(); } void SeerConsoleWidget::handleWrapTextCheckBox () { if (wrapTextCheckBox->checkState() == Qt::Unchecked) { textEdit->setLineWrapMode(QPlainTextEdit::NoWrap); // No wrap _enableWrap = false; }else{ textEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth); // Wrap at end of widget _enableWrap = true; } writeSettings(); } void SeerConsoleWidget::handleStdoutCheckBox () { // Don't write text to the terminal's stdout. if (stdoutCheckBox->checkState() == Qt::Unchecked) { enableStdout(false); writeSettings(); return; } // If stdout is not valid, don't set it. if (fcntl(STDOUT_FILENO, F_GETFD) == -1) { QMessageBox::critical(this, tr("Error"), tr("stdout file descriptor is not valid.\nDisabling writing to stdout.")); enableStdout(false); writeSettings(); return; } // All good to write to stdout enableStdout(true); writeSettings(); } void SeerConsoleWidget::handleStdinLineEdit () { QString str = stdinLineEdit->text(); stdinLineEdit->clear(); str += '\n'; std::string s = str.toStdString(); if (isTerminalCreated() == false) { return; } int n = write(_ttyFD, s.c_str(), s.length()); if (n != (signed long int)s.length()) { qWarning() << "Not able to process stdin of" << s.length() << "bytes."; } fsync(_ttyFD); } void SeerConsoleWidget::handleTerminalOutput (int socketfd) { if (isTerminalCreated() == false) { return; } Q_UNUSED(socketfd); char buffer[1024]; while (1) { int n = read(_ttyFD, buffer, sizeof(buffer)); if (n < 0) { if (errno == EAGAIN) { break; } if (errno == EIO) { // Disconnect terminal if tty has an I/O error. // Can be reconnected later just before gdb restarts it's target program. disconnectTerminal(); break; } break; } handleText(buffer, n); break; } } void SeerConsoleWidget::createTerminal () { // Is terminal already created? if (isTerminalCreated()) { qDebug() << "Terminal already created!"; return; } // Create tty and its permissions. _ttyFD = posix_openpt(O_RDWR | O_NOCTTY); if (_ttyFD < 0) { qDebug() << "Failed to create tty" << strerror(errno); return; } if (grantpt(_ttyFD)) { qDebug() << "Failed to grant pt" << strerror(errno); ::close(_ttyFD); _ttyFD = -1; return; } if (unlockpt(_ttyFD)) { qDebug() << "Failed to unlock pt" << strerror(errno); ::close(_ttyFD); _ttyFD = -1; return; } // Turn off blocking. fcntl(_ttyFD, F_SETFL, O_NDELAY); // Set window size struct winsize term_winsize; term_winsize.ws_col = 80; term_winsize.ws_row = 20; term_winsize.ws_xpixel = 80 * 8; term_winsize.ws_ypixel = 20 * 8; if (ioctl(_ttyFD, TIOCSWINSZ, &term_winsize) < 0) { qDebug() << "ioctl TIOCSWINSZ failed" << strerror(errno); } // Set controlling if (ioctl(_ttyFD, TIOCSCTTY, (char *)0) < 0) { // Seems to work even though this fails. // qDebug() << "ioctl TIOCSCTTY failed" << strerror(errno); } // Save the device name. _terminalDeviceName = ptsname(_ttyFD); // Set maximum blocks to 0 (unlimited). // The createTerminal can be followed with a setScrollLines() call. setScrollLines(0); } void SeerConsoleWidget::deleteTerminal () { disconnectTerminal(); _terminalDeviceName = ""; if (isTerminalCreated() == false) { return; } ::close(_ttyFD); _ttyFD = -1; } void SeerConsoleWidget::connectTerminal () { if (isTerminalConnected()) { //qDebug() << "Terminal is already connected!"; return; } if (isTerminalCreated() == false) { qDebug() << "Can't connect Terminal. No _ttyFD!"; return; } _ttyListener = new QSocketNotifier(_ttyFD, QSocketNotifier::Read); QObject::connect(_ttyListener, &QSocketNotifier::activated, this, &SeerConsoleWidget::handleTerminalOutput); } void SeerConsoleWidget::disconnectTerminal () { if (isTerminalConnected() == false) { //qDebug() << "Terminal is already disconnected!"; return; } QObject::disconnect(_ttyListener, &QSocketNotifier::activated, this, &SeerConsoleWidget::handleTerminalOutput); delete _ttyListener; _ttyListener = 0; } bool SeerConsoleWidget::isTerminalCreated () const { if (_ttyFD >= 0) { return true; } return false; } bool SeerConsoleWidget::isTerminalConnected () const { if (_ttyListener != nullptr) { return true; } return false; } void SeerConsoleWidget::resetTerminal () { if (isTerminalConnected()) { disconnectTerminal(); } if (isTerminalCreated() == true) { deleteTerminal(); } createTerminal(); } const QString& SeerConsoleWidget::terminalDeviceName () const { return _terminalDeviceName; } void SeerConsoleWidget::setScrollLines (int count) { textEdit->setMaximumBlockCount(count); } int SeerConsoleWidget::scrollLines () const { return textEdit->maximumBlockCount(); } void SeerConsoleWidget::enableStdout (bool flag) { _enableStdout = flag; stdoutCheckBox->setChecked(_enableStdout); } bool SeerConsoleWidget::isStdoutEnabled () const { return _enableStdout; } void SeerConsoleWidget::enableWrap (bool flag) { _enableWrap = flag; wrapTextCheckBox->setChecked(_enableWrap); } bool SeerConsoleWidget::isWrapEnabled () const { return _enableWrap; } void SeerConsoleWidget::resetSize () { // If there's a parent, don't reset the size. // This means the console is attached in the // tab bar and its size has been shrunk. We // only want to resize if the console // has been detached, ie: no parent. if (parent() != 0) { return; } QSettings settings; settings.beginGroup("consolewindow"); { resize(settings.value("size", QSize(800, 600)).toSize()); } settings.endGroup(); } void SeerConsoleWidget::writeSettings() { QSettings settings; settings.beginGroup("consolewindow"); { settings.setValue("stdout", isStdoutEnabled()); settings.setValue("wrap", isWrapEnabled()); }settings.endGroup(); } void SeerConsoleWidget::writeFontSettings() { QSettings settings; settings.beginGroup("consolewindow"); { settings.setValue("font", textEdit->font().toString()); }settings.endGroup(); } void SeerConsoleWidget::writeSizeSettings() { // If there's a parent, don't save the size. // This means the console is attached in the // tab bar and its size has been shrunk. We // only want to save resizes if the console // has been detached, ie: no parent. if (parent() != 0) { return; } QSettings settings; settings.beginGroup("consolewindow"); { settings.setValue("size", size()); }settings.endGroup(); } void SeerConsoleWidget::readSettings() { QSettings settings; settings.beginGroup("consolewindow"); { resize(settings.value("size", QSize(800, 600)).toSize()); enableStdout(settings.value("stdout", false).toBool()); enableWrap(settings.value("wrap", false).toBool()); QFont f; if (settings.contains("font")) { f.fromString(settings.value("font").toString()); }else{ f = QFont("monospace", 10); } // Get current format for the font name. QTextCharFormat format = textEdit->currentCharFormat(); format.setFont(f); textEdit->setCurrentCharFormat(format); textEdit->setFont(f); } settings.endGroup(); } void SeerConsoleWidget::resizeEvent (QResizeEvent* event) { // Write window settings. writeSizeSettings(); QWidget::resizeEvent(event); } void SeerConsoleWidget::showEvent (QShowEvent* event) { // Handle the event as normal. QWidget::showEvent(event); // Set focus on the text input. stdinLineEdit->setFocus(); // Announce we are now visable. emit newTextViewed(); } seer-2.7/src/SeerConsoleWidget.h000066400000000000000000000060631516472651200166630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include #include "ui_SeerConsoleWidget.h" class SeerConsoleWidget : public QWidget, protected Ui::SeerConsoleWidgetForm { Q_OBJECT public: explicit SeerConsoleWidget (QWidget* parent = 0); ~SeerConsoleWidget (); void createTerminal (); void deleteTerminal (); void connectTerminal (); void disconnectTerminal (); bool isTerminalCreated () const; bool isTerminalConnected () const; void resetTerminal (); const QString& terminalDeviceName () const; void setScrollLines (int count); int scrollLines () const; void enableStdout (bool flag); bool isStdoutEnabled () const; void enableWrap (bool flag); bool isWrapEnabled () const; void resetSize (); signals: void newTextAdded (); void newTextViewed (); public slots: void handleChangeWindowTitle (QString title); void handleTabDetached (QWidget* widget); void handleTabReattached (QWidget* widget); protected slots: void handleClearButton (); void handlePrintButton (); void handleSaveButton (); void handleFontButton (); void handleWrapTextCheckBox (); void handleStdoutCheckBox (); void handleStdinLineEdit (); void handleTerminalOutput (int socketfd); protected: void handleText (const char* buffer, int count); void writeSettings (); void writeFontSettings (); void writeSizeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); void showEvent (QShowEvent* event); private: QString _terminalDeviceName; int _ttyFD; QSocketNotifier* _ttyListener; bool _enableStdout; bool _enableWrap; }; seer-2.7/src/SeerConsoleWidget.ui000066400000000000000000000106611516472651200170500ustar00rootroot00000000000000 SeerConsoleWidgetForm 0 0 891 589 Seer Console Save the log output to a file. :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Clear the log output. :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg QPlainTextEdit::NoWrap false [program output text] Print the log output. :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg 100 0 [stdin input text] true Wrap long lines to the next line. Wrap Select the log output font. :/seer/resources/icons-icons/font.png:/seer/resources/icons-icons/font.png Send output to stdout as well. stdout QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
QAnsiTextEdit QPlainTextEdit
QAnsiTextEdit.h
seer-2.7/src/SeerCppSourceHighlighter.cpp000066400000000000000000000154761516472651200205420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCppSourceHighlighter.h" SeerCppSourceHighlighter::SeerCppSourceHighlighter (QTextDocument* parent) : SeerSourceHighlighter(parent) { // Set to default formats. setHighlighterSettings(SeerHighlighterSettings::populate("")); } void SeerCppSourceHighlighter::setHighlighterSettings (const SeerHighlighterSettings& settings) { _highlighterSettings = settings; _classFormat = _highlighterSettings.get("Class"); _quotationFormat = _highlighterSettings.get("Quotation"); _functionFormat = _highlighterSettings.get("Function"); _singleLineCommentFormat = _highlighterSettings.get("Comment"); _multiLineCommentFormat = _highlighterSettings.get("Multiline Comment"); _keywordFormat = _highlighterSettings.get("Keyword"); /* List from QT example. const QString keywordPatterns[] = { QStringLiteral("\\bchar\\b"), QStringLiteral("\\bclass\\b"), QStringLiteral("\\bconst\\b"), QStringLiteral("\\bdouble\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bexplicit\\b"), QStringLiteral("\\bfriend\\b"), QStringLiteral("\\binline\\b"), QStringLiteral("\\bint\\b"), QStringLiteral("\\blong\\b"), QStringLiteral("\\bnamespace\\b"), QStringLiteral("\\boperator\\b"), QStringLiteral("\\bprivate\\b"), QStringLiteral("\\bprotected\\b"), QStringLiteral("\\bpublic\\b"), QStringLiteral("\\bshort\\b"), QStringLiteral("\\bsignals\\b"), QStringLiteral("\\bsigned\\b"), QStringLiteral("\\bslots\\b"), QStringLiteral("\\bstatic\\b"), QStringLiteral("\\bstruct\\b"), QStringLiteral("\\btemplate\\b"), QStringLiteral("\\btypedef\\b"), QStringLiteral("\\btypename\\b"), QStringLiteral("\\bunion\\b"), QStringLiteral("\\bunsigned\\b"), QStringLiteral("\\bvirtual\\b"), QStringLiteral("\\bvoid\\b"), QStringLiteral("\\bvolatile\\b"), QStringLiteral("\\bbool\\b") }; */ // List from the kdbg debugger. const QString keywordPatterns[] = { QStringLiteral("\\balignas\\b"), QStringLiteral("\\balignof\\b"), QStringLiteral("\\band\\b"), QStringLiteral("\\band_eq\\b"), QStringLiteral("\\basm\\b"), QStringLiteral("\\bauto\\b"), QStringLiteral("\\bbitand\\b"), QStringLiteral("\\bbitor\\b"), QStringLiteral("\\bbool\\b"), QStringLiteral("\\bbreak\\b"), QStringLiteral("\\bcase\\b"), QStringLiteral("\\bcatch\\b"), QStringLiteral("\\bchar\\b"), QStringLiteral("\\bchar16_t\\b"), QStringLiteral("\\bchar32_t\\b"), QStringLiteral("\\bclass\\b"), QStringLiteral("\\bcompl\\b"), QStringLiteral("\\bconst\\b"), QStringLiteral("\\bconst_cast\\b"), QStringLiteral("\\bconstexpr\\b"), QStringLiteral("\\bcontinue\\b"), QStringLiteral("\\bdecltype\\b"), QStringLiteral("\\bdefault\\b"), QStringLiteral("\\bdelete\\b"), QStringLiteral("\\bdo\\b"), QStringLiteral("\\bdouble\\b"), QStringLiteral("\\bdynamic_cast\\b"), QStringLiteral("\\belse\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bexplicit\\b"), QStringLiteral("\\bexport\\b"), QStringLiteral("\\bextern\\b"), QStringLiteral("\\bfalse\\b"), QStringLiteral("\\bfloat\\b"), QStringLiteral("\\bfor\\b"), QStringLiteral("\\bfriend\\b"), QStringLiteral("\\bgoto\\b"), QStringLiteral("\\bif\\b"), QStringLiteral("\\binline\\b"), QStringLiteral("\\bint\\b"), QStringLiteral("\\blong\\b"), QStringLiteral("\\bmutable\\b"), QStringLiteral("\\bnamespace\\b"), QStringLiteral("\\bnew\\b"), QStringLiteral("\\bnoexcept\\b"), QStringLiteral("\\bnot\\b"), QStringLiteral("\\bnot_eq\\b"), QStringLiteral("\\bnullptr\\b"), QStringLiteral("\\boperator\\b"), QStringLiteral("\\bor\\b"), QStringLiteral("\\bor_eq\\b"), QStringLiteral("\\bprivate\\b"), QStringLiteral("\\bprotected\\b"), QStringLiteral("\\bpublic\\b"), QStringLiteral("\\bregister\\b"), QStringLiteral("\\breinterpret_cast\\b"), QStringLiteral("\\breturn\\b"), QStringLiteral("\\bshort\\b"), QStringLiteral("\\bsigned\\b"), QStringLiteral("\\bsizeof\\b"), QStringLiteral("\\bstatic\\b"), QStringLiteral("\\bstatic_assert\\b"), QStringLiteral("\\bstatic_cast\\b"), QStringLiteral("\\bstruct\\b"), QStringLiteral("\\bswitch\\b"), QStringLiteral("\\btemplate\\b"), QStringLiteral("\\bthis\\b"), QStringLiteral("\\bthread_local\\b"), QStringLiteral("\\bthrow\\b"), QStringLiteral("\\btrue\\b"), QStringLiteral("\\btry\\b"), QStringLiteral("\\btypedef\\b"), QStringLiteral("\\btypeid\\b"), QStringLiteral("\\btypename\\b"), QStringLiteral("\\bunion\\b"), QStringLiteral("\\bunsigned\\b"), QStringLiteral("\\busing\\b"), QStringLiteral("\\bvirtual\\b"), QStringLiteral("\\bvoid\\b"), QStringLiteral("\\bvolatile\\b"), QStringLiteral("\\bwchar_t\\b"), QStringLiteral("\\bwhile\\b"), QStringLiteral("\\bxor\\b"), QStringLiteral("\\bxor_eq\\b"), QStringLiteral("\\bslots\\b"), QStringLiteral("\\bsignals\\b") }; _highlightingRules.clear(); // Clear old rules. HighlightingRule rule; // Set class format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\bQ[A-Za-z]+\\b")); rule.format = _classFormat; _highlightingRules.append(rule); // Set quote format and expression. rule.pattern = QRegularExpression(QStringLiteral("\".*\"")); rule.format = _quotationFormat; _highlightingRules.append(rule); // Set function format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_]+(?=\\s*\\()")); rule.format = _functionFormat; _highlightingRules.append(rule); // Set keywords format and expression (must have precedence over functions) for (const QString& pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern); rule.format = _keywordFormat; _highlightingRules.append(rule); } // Set single line comment format and expression. rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*")); rule.format = _singleLineCommentFormat; _highlightingRules.append(rule); // Set multi-line comment expression. Format is defined later. _commentStartExpression = QRegularExpression(QStringLiteral("/\\*")); _commentEndExpression = QRegularExpression(QStringLiteral("\\*/")); } seer-2.7/src/SeerCppSourceHighlighter.h000066400000000000000000000007261516472651200201770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include "SeerSourceHighlighter.h" class SeerCppSourceHighlighter : public SeerSourceHighlighter { Q_OBJECT public: SeerCppSourceHighlighter(QTextDocument *parent = 0); virtual void setHighlighterSettings (const SeerHighlighterSettings &settings) override; }; seer-2.7/src/SeerCxxSourceHighlighter.cpp000066400000000000000000000131561516472651200205530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCxxSourceHighlighter.h" #include // // This C++ syntax highlighter is based on the one in the kdbg debugger. // However, it doesn't work well. // // I'll leave it in the Seer source directory for reference purposes. // // Instead, the SeerCppSourceHighlighter is used. // SeerCxxSourceHighlighter::SeerCxxSourceHighlighter (QTextDocument* parent) : QSyntaxHighlighter(parent) { } enum HLState { hlCommentLine = 1, hlCommentBlock, hlIdent, hlString }; static const QString ckw[] = { "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "const", "const_cast", "constexpr", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this", "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq" }; void SeerCxxSourceHighlighter::highlightBlock (const QString& text) { int state = previousBlockState(); state = highlight(text, state); setCurrentBlockState(state); } int SeerCxxSourceHighlighter::highlight (const QString& text, int state) { if (state == -2) // initial state state = 0; // check for preprocessor line if (state == 0 && text.trimmed().startsWith("#")) { setFormat(0, text.length(), QColor("darkgreen")); return 0; } // a font for keywords QTextCharFormat identFont; identFont.setFontWeight(QFont::Bold); int start = 0; while (start < text.length()) { int end; switch (state) { case hlCommentLine: end = text.length(); state = 0; setFormat(start, end-start, QColor("gray")); break; case hlCommentBlock: end = text.indexOf("*/", start); if (end >= 0) { end += 2, state = 0; }else{ end = text.length(); } setFormat(start, end-start, QColor("gray")); break; case hlString: for (end = start+1; end < int(text.length()); end++) { if (text[end] == '\\') { if (end < int(text.length())) { ++end; } }else if (text[end] == text[start]) { ++end; break; } } state = 0; setFormat(start, end-start, QColor("darkred")); break; case hlIdent: for (end = start+1; end < int(text.length()); end++) { if (!text[end].isLetterOrNumber() && text[end] != '_') { break; } } state = 0; if (isCppKeyword(text.mid(start, end-start))) { setFormat(start, end-start, identFont); }else{ //setFormat(start, end-start, Normal Format); } break; default: for (end = start; end < int(text.length()); end++) { if (text[end] == '/') { if (end+1 < int(text.length())) { if (text[end+1] == '/') { state = hlCommentLine; break; }else if (text[end+1] == '*') { state = hlCommentBlock; break; } } }else if (text[end] == '"' || text[end] == '\'') { state = hlString; break; }else if ((text[end] >= 'A' && text[end] <= 'Z') || (text[end] >= 'a' && text[end] <= 'z') || text[end] == '_') { state = hlIdent; break; } } //setFormat(start, end-start, Normal Format); } start = end; } return state; } bool SeerCxxSourceHighlighter::isCppKeyword (const QString& word) { // std::binary_search requires the search list to be sorted static bool keyword_order_verified = false; if (keyword_order_verified == false) { for (size_t i = 1; i < sizeof(ckw)/sizeof(ckw[0]); ++i) { if (ckw[i-1] > ckw[i]) { qDebug("\"%s\" > \"%s\"", qPrintable(ckw[i-1]), qPrintable(ckw[i])); assert(0); } } keyword_order_verified = true; } return std::binary_search(ckw, ckw + sizeof(ckw)/sizeof(ckw[0]), word); } seer-2.7/src/SeerCxxSourceHighlighter.h000066400000000000000000000013521516472651200202130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include class SeerCxxSourceHighlighter : public QSyntaxHighlighter { Q_OBJECT public: SeerCxxSourceHighlighter (QTextDocument* parent = 0); protected: void highlightBlock (const QString& text) override; int highlight (const QString& text, int state); static bool isCppKeyword (const QString& word); }; seer-2.7/src/SeerDebugDialog.cpp000066400000000000000000001065211516472651200166160ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerDebugDialog.h" #include "SeerExecutableFilterProxyModel.h" #include "SeerDirectoryFilterProxyModel.h" #include "SeerSlashProcDialog.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include #include #include #include #include SeerDebugDialog::SeerDebugDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); buttonBox->button(QDialogButtonBox::Ok)->setText("Launch"); buttonBox->button(QDialogButtonBox::Reset)->setText("Clear"); // Setup the widgets reset(); // Create editor options bar. QToolButton* loadProjectToolButton = new QToolButton(runModeTabWidget); loadProjectToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/document-open.svg")); loadProjectToolButton->setToolTip("Load a Seer project file."); QToolButton* saveProjectToolButton = new QToolButton(runModeTabWidget); saveProjectToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/document-save.svg")); saveProjectToolButton->setToolTip("Save a Seer project file."); QToolButton* helpModeToolButton = new QToolButton(runModeTabWidget); helpModeToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpModeToolButton->setToolTip("Help on the debug launch modes."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(loadProjectToolButton); hcontainer->addWidget(saveProjectToolButton); hcontainer->addWidget(helpModeToolButton); runModeTabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Connect things. QObject::connect(executableNameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleExecutableNameToolButton); QObject::connect(executableSymbolNameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleExecutableSymbolNameToolButton); QObject::connect(executableWorkingDirectoryToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleExecutableWorkingDirectoryToolButton); QObject::connect(loadBreakpointsFilenameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadBreakpointsFilenameToolButton); QObject::connect(rrLoadTraceDirectoryToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadRRTraceDirectoryToolButton); QObject::connect(rrLoadBreakpointsFilenameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadBreakpointsFilenameToolButton); QObject::connect(loadCoreFilenameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadCoreFilenameToolButton); QObject::connect(breakpointInFunctionLineEdit, &QLineEdit::textChanged, this, &SeerDebugDialog::handleBreakpointInFunctionLineEdit); QObject::connect(attachProgramPidToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleProgramPidToolButton); QObject::connect(loadProjectToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadProjectToolButton); QObject::connect(saveProjectToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleSaveProjectToolButton); QObject::connect(helpModeToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpModeToolButtonClicked); QObject::connect(helpRunToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpRunToolButtonClicked); QObject::connect(helpAttachToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpAttachToolButtonClicked); QObject::connect(helpConnectToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpConnectToolButtonClicked); QObject::connect(helpRRToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpRRToolButtonClicked); QObject::connect(helpCorefileToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpCorefileToolButtonClicked); QObject::connect(runModeTabWidget, &QTabWidget::currentChanged, this, &SeerDebugDialog::handleRunModeChanged); QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &SeerDebugDialog::handleLaunchButtonClicked); QObject::connect(buttonBox, &QDialogButtonBox::clicked, this, &SeerDebugDialog::handleResetButtonClicked); // Set initial run mode. handleRunModeChanged(0); // Restore window settings. readSettings(); // Read default project settings, if any. loadDefaultProjectSettings(); } SeerDebugDialog::~SeerDebugDialog () { } void SeerDebugDialog::reset () { // At least retain the launch mode. QString launchmode = launchMode(); // Reset everything else. setExecutableName(""); setExecutableSymbolName(""); setExecutableWorkingDirectory(""); setExecutableArguments(""); setBreakpointsFilename(""); setBreakpointFunctionName(""); setBreakpointSourceName(""); setBreakpointMode("inmain"); setShowAssemblyTabMode("never"); setRandomizeStartAddress(false); setNonStopMode(false); setPreGdbCommands(QStringList()); setPostGdbCommands(QStringList()); setAttachPid(0); setConnectHostPort(""); setConnectRemoteTargetType("remote"); setConnectGdbserverDebug(false); setRRTraceDirectory(""); setCoreFilename(""); setLaunchMode(launchmode); setProjectFilename(""); } void SeerDebugDialog::setExecutableName (const QString& executableName) { executableNameLineEdit->setText(executableName); } QString SeerDebugDialog::executableName () const { if (executableNameLineEdit->isEnabled()) { return executableNameLineEdit->text(); } return ""; } void SeerDebugDialog::setExecutableSymbolName (const QString& executableSymbolName) { executableSymbolNameLineEdit->setText(executableSymbolName); } QString SeerDebugDialog::executableSymbolName () const { if (executableSymbolNameLineEdit->isEnabled()) { return executableSymbolNameLineEdit->text(); } return ""; } void SeerDebugDialog::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) { executableWorkingDirectoryLineEdit->setText(executableWorkingDirectory); } QString SeerDebugDialog::executableWorkingDirectory () const { if (executableWorkingDirectoryLineEdit->isEnabled()) { return executableWorkingDirectoryLineEdit->text(); } return ""; } void SeerDebugDialog::setExecutableArguments (const QString& executableArguments) { runProgramArgumentsLineEdit->setText(executableArguments); } QString SeerDebugDialog::executableArguments () const { return runProgramArgumentsLineEdit->text(); } void SeerDebugDialog::setBreakpointsFilename (const QString& breakpointsFilename) { // Try to keep these in sync. Arg! loadBreakpointsFilenameLineEdit->setText(breakpointsFilename); rrLoadBreakpointsFilenameLineEdit->setText(breakpointsFilename); } QString SeerDebugDialog::breakpointsFilename () const { return loadBreakpointsFilenameLineEdit->text(); } void SeerDebugDialog::setBreakpointMode (const QString& mode) { if (mode == "none") { noBreakpointRadioButton->setChecked(true); return; }else if (mode == "inmain") { breakpointInMainRadioButton->setChecked(true); return; }else if (mode == "infunction") { breakpointInFunctionRadioButton->setChecked(true); return; }else if (mode == "insource") { breakpointAtSourceRadioButton->setChecked(true); return; } // Default of "inmain". breakpointInMainRadioButton->setChecked(true); } QString SeerDebugDialog::breakpointMode () const { if (noBreakpointRadioButton->isChecked()) { return "none"; }else if (breakpointInMainRadioButton->isChecked()) { return "inmain"; }else if (breakpointInFunctionRadioButton->isChecked()) { return "infunction"; }else if (breakpointAtSourceRadioButton->isChecked()) { return "insource"; } return "inmain"; } void SeerDebugDialog::setBreakpointFunctionName (const QString& nameoraddress) { breakpointInFunctionLineEdit->setText(nameoraddress); if (nameoraddress != "") { breakpointInFunctionRadioButton->setChecked(true); } } QString SeerDebugDialog::breakpointFunctionName () const { return breakpointInFunctionLineEdit->text(); } void SeerDebugDialog::setBreakpointSourceName (const QString& sourceFilenameAndLineno) { breakpointAtSourceLineEdit->setText(sourceFilenameAndLineno); if (sourceFilenameAndLineno != "") { breakpointAtSourceRadioButton->setChecked(true); } } QString SeerDebugDialog::breakpointSourceName () const { return breakpointAtSourceLineEdit->text(); } void SeerDebugDialog::setShowAssemblyTabMode (const QString& mode) { showAssemblyTabComboBox->setCurrentText(mode); } QString SeerDebugDialog::showAssemblyTabMode () const { return showAssemblyTabComboBox->currentText(); } void SeerDebugDialog::setRandomizeStartAddress (bool flag) { randomizeStartAddressCheckBox->setChecked(flag); } bool SeerDebugDialog::randomizeStartAddress () const { return randomizeStartAddressCheckBox->isChecked(); } void SeerDebugDialog::setNonStopMode (bool flag) { nonStopModeCheckBox->setChecked(flag); } bool SeerDebugDialog::nonStopMode () const { return nonStopModeCheckBox->isChecked(); } void SeerDebugDialog::setPreGdbCommands (const QStringList& preGdbCommands) { preCommandsPlainTextEdit->setPlainText(preGdbCommands.join("\n")); } QStringList SeerDebugDialog::preGdbCommands () const { return preCommandsPlainTextEdit->toPlainText().split("\n"); } void SeerDebugDialog::setPostGdbCommands (const QStringList& postGdbCommands) { postCommandsPlainTextEdit->setPlainText(postGdbCommands.join("\n")); } QStringList SeerDebugDialog::postGdbCommands () const { return postCommandsPlainTextEdit->toPlainText().split("\n"); } void SeerDebugDialog::setCoreFilename (const QString& coreFilename) { loadCoreFilenameLineEdit->setText(coreFilename); } QString SeerDebugDialog::coreFilename () const { return loadCoreFilenameLineEdit->text(); } void SeerDebugDialog::setAttachPid (int pid) { if (pid < 1) { attachProgramPidLineEdit->setText(""); }else{ attachProgramPidLineEdit->setText(QString::number(pid)); } } int SeerDebugDialog::attachPid () const { return attachProgramPidLineEdit->text().toInt(); } void SeerDebugDialog::setConnectHostPort (const QString& connectHostPort) { connectProgramHostPortLineEdit->setText(connectHostPort); } QString SeerDebugDialog::connectHostPort () const { return connectProgramHostPortLineEdit->text(); } void SeerDebugDialog::setConnectRemoteTargetType (const QString& type) { connectRemoteTargetTypeCombo->setCurrentText(type); } QString SeerDebugDialog::connectRemoteTargetType () const { return connectRemoteTargetTypeCombo->currentText(); } void SeerDebugDialog::setConnectGdbserverDebug (bool enable) { connectGdbserverDebugCheckBox->setChecked(enable); } bool SeerDebugDialog::connectGdbserverDebug () const { return connectGdbserverDebugCheckBox->isChecked(); } void SeerDebugDialog::setRRTraceDirectory (const QString& rrTraceDirectory) { rrTraceDirectoryLineEdit->setText(rrTraceDirectory); } QString SeerDebugDialog::rrTraceDirectory () const { return rrTraceDirectoryLineEdit->text(); } void SeerDebugDialog::setLaunchMode (const QString& mode) { if (mode == "start") { runModeTabWidget->setCurrentIndex(0); setBreakpointMode(breakpointMode()); }else if (mode == "run") { runModeTabWidget->setCurrentIndex(0); setBreakpointMode(breakpointMode()); }else if (mode == "attach") { runModeTabWidget->setCurrentIndex(1); }else if (mode == "connect") { runModeTabWidget->setCurrentIndex(2); }else if (mode == "rr") { runModeTabWidget->setCurrentIndex(3); }else if (mode == "corefile") { runModeTabWidget->setCurrentIndex(4); }else if (mode == "") { runModeTabWidget->setCurrentIndex(0); setBreakpointMode("inmain"); }else{ qWarning() << "Unknown launch mode of:" << mode; runModeTabWidget->setCurrentIndex(0); setBreakpointMode("inmain"); } } QString SeerDebugDialog::launchMode () const { if (runModeTabWidget->currentIndex() == 0) { if (breakpointMode() == "inmain") { return "start"; }else if (breakpointMode() == "infunction") { return "run"; }else if (breakpointMode() == "none") { return "run"; }else{ return "run"; } }else if (runModeTabWidget->currentIndex() == 1) { return "attach"; }else if (runModeTabWidget->currentIndex() == 2) { return "connect"; }else if (runModeTabWidget->currentIndex() == 3) { return "rr"; }else if (runModeTabWidget->currentIndex() == 4) { return "corefile"; } qWarning() << "Unknown launch mode of:" << runModeTabWidget->currentIndex(); return ""; } void SeerDebugDialog::setProjectFilename (const QString& filename) { _projectFilename = filename; if (_projectFilename != "") { loadProject(_projectFilename, false); } } QString SeerDebugDialog::projectFilename () const { return _projectFilename; } void SeerDebugDialog::handleExecutableNameToolButton () { QString name = QFileDialog::getOpenFileName(this, "Select an Executable to debug.", executableName(), "", nullptr, QFileDialog::DontUseNativeDialog); if (name != "") { setExecutableName(name); } } void SeerDebugDialog::handleExecutableSymbolNameToolButton () { QString name = QFileDialog::getOpenFileName(this, "Select a Symbol File for the executable.", executableSymbolName(), "", nullptr, QFileDialog::DontUseNativeDialog); if (name != "") { setExecutableSymbolName(name); } } void SeerDebugDialog::handleExecutableWorkingDirectoryToolButton () { QString name = QFileDialog::getExistingDirectory(this, "Select a Working Directory to run in.", executableWorkingDirectory(), QFileDialog::ShowDirsOnly|QFileDialog::DontUseNativeDialog); if (name != "") { setExecutableWorkingDirectory(name); } } void SeerDebugDialog::handleBreakpointInFunctionLineEdit () { breakpointInFunctionRadioButton->setChecked(true); } void SeerDebugDialog::handleLoadRRTraceDirectoryToolButton () { QString name = QFileDialog::getExistingDirectory(this, "Select a RR trace-directory to load.", rrTraceDirectory(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (name != "") { setRRTraceDirectory(name); } } void SeerDebugDialog::handleLoadBreakpointsFilenameToolButton () { QString name = QFileDialog::getOpenFileName(this, "Select a breakpoints file to load.", breakpointsFilename(), "Breakpoints (*.seer);;All files (*.*)", nullptr, QFileDialog::DontUseNativeDialog); if (name != "") { setBreakpointsFilename(name); } } void SeerDebugDialog::handleLoadCoreFilenameToolButton () { QString name = QFileDialog::getOpenFileName(this, "Select a core file to debug.", coreFilename(), "Core Files (core core.* *.core)", nullptr, QFileDialog::DontUseNativeDialog); if (name != "") { setCoreFilename(name); } } void SeerDebugDialog::handleProgramPidToolButton () { SeerSlashProcDialog dlg(this); // Execute the dialog and get the result. if (dlg.exec()) { setAttachPid(dlg.selectedPid()); if (executableName() == "") { setExecutableName(dlg.selectedFullname()); } } } void SeerDebugDialog::handleLoadProjectToolButton () { // Get the filename to load from. QString fname = QFileDialog::getOpenFileName(this, "Load a project file.", "project.seer", "Projects (*.seer);;All files (*.*)", nullptr, QFileDialog::DontUseNativeDialog); if (fname == "") { return; } loadProject(fname, true); } void SeerDebugDialog::loadProject (const QString& filename, bool notify) { // Look for the mainwindow to place possible QMessageBox on. QWidget* p = this; if (isHidden() == true) { foreach (QWidget* w, qApp->topLevelWidgets()) { if (QMainWindow* mainWin = qobject_cast(w)) { p = mainWin; break; } } } // Open the project file. QFile loadFile(filename);; bool f = loadFile.open(QIODevice::ReadOnly); if (f == false) { QMessageBox::critical(p, "Error", QString("Can't open the Seer project file '%1'.").arg(filename)); return; } // Populate the JSON document from the project file. QJsonDocument jsonDoc = QJsonDocument::fromJson(loadFile.readAll()); f = loadJsonDoc(jsonDoc, filename); if (f == false) { return; } if (notify) { QMessageBox::information(p, "Success", QString("Loaded the Seer project file '%1'.").arg(filename)); } } QJsonDocument SeerDebugDialog::makeJsonDoc() const { // Build the JSON document. QJsonDocument jsonDoc; QJsonObject rootJson; QJsonObject seerProjectJson; QJsonArray preConnectCommands; QJsonArray postConnectCommands; // Save pre/post gdb commands. QStringList preCommands = preGdbCommands(); QStringList postCommands = postGdbCommands(); for (const auto& i : preCommands) { preConnectCommands.push_back(QJsonValue(i)); } for (const auto& i : postCommands) { postConnectCommands.push_back(QJsonValue(i)); } seerProjectJson["executable"] = QJsonValue(executableNameLineEdit->text()); seerProjectJson["symbolfile"] = QJsonValue(executableSymbolNameLineEdit->text()); seerProjectJson["workingdirectory"] = QJsonValue(executableWorkingDirectoryLineEdit->text()); seerProjectJson["pregdbcommands"] = preConnectCommands; seerProjectJson["postgdbcommands"] = postConnectCommands; // Save RUN project. if (launchMode() == "run") { QJsonObject modeJson; modeJson["arguments"] = runProgramArgumentsLineEdit->text(); modeJson["breakpointsfile"] = loadBreakpointsFilenameLineEdit->text(); modeJson["nobreak"] = noBreakpointRadioButton->isChecked(); modeJson["breakinmain"] = breakpointInMainRadioButton->isChecked(); modeJson["breakinfunction"] = breakpointInFunctionRadioButton->isChecked(); modeJson["breakinfunctionname"] = breakpointInFunctionLineEdit->text(); modeJson["showassemblytabmode"] = showAssemblyTabComboBox->currentText(); modeJson["nonstopmode"] = nonStopModeCheckBox->isChecked(); modeJson["randomizestartaddress"] = randomizeStartAddressCheckBox->isChecked(); seerProjectJson["runmode"] = modeJson; } // Save START project. if (launchMode() == "start") { QJsonObject modeJson; modeJson["arguments"] = runProgramArgumentsLineEdit->text(); modeJson["breakpointsfile"] = loadBreakpointsFilenameLineEdit->text(); modeJson["nobreak"] = noBreakpointRadioButton->isChecked(); modeJson["breakinmain"] = breakpointInMainRadioButton->isChecked(); modeJson["breakinfunction"] = breakpointInFunctionRadioButton->isChecked(); modeJson["breakinfunctionname"] = breakpointInFunctionLineEdit->text(); modeJson["showassemblytabmode"] = showAssemblyTabComboBox->currentText(); modeJson["nonstopmode"] = nonStopModeCheckBox->isChecked(); modeJson["randomizestartaddress"] = randomizeStartAddressCheckBox->isChecked(); seerProjectJson["startmode"] = modeJson; } // Save ATTACH project. if (launchMode() == "attach") { QJsonObject modeJson; modeJson["pid"] = attachProgramPidLineEdit->text(); seerProjectJson["attachmode"] = modeJson; } // Save CONNECT project. if (launchMode() == "connect") { QJsonObject modeJson; modeJson["gdbserver"] = connectProgramHostPortLineEdit->text(); modeJson["targettype"] = connectRemoteTargetTypeCombo->currentText(); modeJson["gdbserverdebug"] = connectGdbserverDebugCheckBox->isChecked(); seerProjectJson["connectmode"] = modeJson; } // Save RR project. if (launchMode() == "rr") { QJsonObject modeJson; modeJson["tracedirectory"] = rrTraceDirectoryLineEdit->text(); modeJson["breakpointsfile"] = rrLoadBreakpointsFilenameLineEdit->text(); seerProjectJson["rrmode"] = modeJson; } // Save COREFILE project. if (launchMode() == "corefile") { QJsonObject modeJson; modeJson["corefile"] = loadCoreFilenameLineEdit->text(); seerProjectJson["corefilemode"] = modeJson; } rootJson["seerproject"] = seerProjectJson; jsonDoc.setObject(rootJson); return jsonDoc; } bool SeerDebugDialog::loadJsonDoc (const QJsonDocument& jsonDoc, const QString& filename) { // Look for the mainwindow to place possible QMessageBox on. QWidget* p = this; if (isHidden() == true) { foreach (QWidget* w, qApp->topLevelWidgets()) { if (QMainWindow* mainWin = qobject_cast(w)) { p = mainWin; break; } } } QJsonObject rootJson; QJsonObject seerProjectJson; QJsonObject runModeJson; QJsonObject startModeJson; QJsonObject attachModeJson; QJsonObject connectModeJson; QJsonObject rrModeJson; QJsonObject corefileModeJson; QJsonArray preConnectCommands; QJsonArray postConnectCommands; if (jsonDoc.isObject() == false) { QMessageBox::critical(p, "Error", QString("'%1' is not a Seer project file (bad Json format).").arg(filename)); return false; } rootJson = jsonDoc.object(); seerProjectJson = rootJson.value("seerproject").toObject(); runModeJson = seerProjectJson.value("runmode").toObject(); startModeJson = seerProjectJson.value("startmode").toObject(); attachModeJson = seerProjectJson.value("attachmode").toObject(); connectModeJson = seerProjectJson.value("connectmode").toObject(); rrModeJson = seerProjectJson.value("rrmode").toObject(); corefileModeJson = seerProjectJson.value("corefilemode").toObject(); preConnectCommands = seerProjectJson.value("pregdbcommands").toArray(); postConnectCommands = seerProjectJson.value("postgdbcommands").toArray(); if (seerProjectJson.isEmpty() == true) { QMessageBox::critical(p, "Error", QString("'%1' is not a Seer project file (missing 'seerproject' section).").arg(filename)); return false; } // Load executable/symbol/working directory. executableNameLineEdit->setText(seerProjectJson["executable"].toString()); executableSymbolNameLineEdit->setText(seerProjectJson["symbolfile"].toString()); executableWorkingDirectoryLineEdit->setText(seerProjectJson["workingdirectory"].toString()); // Load pre/post gdb commands. Good for all modes. QStringList preCommands; QStringList postCommands; for (const auto& i : preConnectCommands) { preCommands.push_back(i.toString()); } for (const auto& i : postConnectCommands) { postCommands.push_back(i.toString()); } setPreGdbCommands(preCommands); setPostGdbCommands(postCommands); // Load RUN/START project. if (runModeJson.isEmpty() == false || startModeJson.isEmpty() == false) { if (runModeJson.isEmpty() == false) { runProgramArgumentsLineEdit->setText(runModeJson["arguments"].toString()); loadBreakpointsFilenameLineEdit->setText(runModeJson["breakpointsfile"].toString()); rrLoadBreakpointsFilenameLineEdit->setText(startModeJson["breakpointsfile"].toString()); if (runModeJson["nobreak"].toBool()) { noBreakpointRadioButton->setChecked(true); } if (runModeJson["breakinmain"].toBool()) { breakpointInMainRadioButton->setChecked(true); } if (runModeJson["breakinfunction"].toBool()) { breakpointInFunctionRadioButton->setChecked(true); } breakpointInFunctionLineEdit->setText(runModeJson["breakinfunctionname"].toString()); showAssemblyTabComboBox->setCurrentText(runModeJson["showassemblytabmode"].toString()); nonStopModeCheckBox->setChecked(runModeJson["nonstopmode"].toBool()); randomizeStartAddressCheckBox->setChecked(runModeJson["randomizestartaddress"].toBool()); setLaunchMode("run"); }else if (startModeJson.isEmpty() == false) { runProgramArgumentsLineEdit->setText(startModeJson["arguments"].toString()); loadBreakpointsFilenameLineEdit->setText(startModeJson["breakpointsfile"].toString()); rrLoadBreakpointsFilenameLineEdit->setText(startModeJson["breakpointsfile"].toString()); if (startModeJson["nobreak"].toBool()) { noBreakpointRadioButton->setChecked(true); } if (startModeJson["breakinmain"].toBool()) { breakpointInMainRadioButton->setChecked(true); } if (startModeJson["breakinfunction"].toBool()) { breakpointInFunctionRadioButton->setChecked(true); } breakpointInFunctionLineEdit->setText(startModeJson["breakinfunctionname"].toString()); showAssemblyTabComboBox->setCurrentText(startModeJson["showassemblytabmode"].toString()); nonStopModeCheckBox->setChecked(startModeJson["nonstopmode"].toBool()); randomizeStartAddressCheckBox->setChecked(startModeJson["randomizestartaddress"].toBool()); setLaunchMode("start"); }else{ setLaunchMode(""); } } // Load ATTACH project. if (attachModeJson.isEmpty() == false) { attachProgramPidLineEdit->setText(attachModeJson["pid"].toString()); setLaunchMode("attach"); } // Load CONNECT project. if (connectModeJson.isEmpty() == false) { connectProgramHostPortLineEdit->setText(connectModeJson["gdbserver"].toString()); if (connectModeJson.contains("targettype")) { connectRemoteTargetTypeCombo->setCurrentText(connectModeJson["targettype"].toString()); } if (connectModeJson.contains("gdbserverdebug")) { connectGdbserverDebugCheckBox->setChecked(connectModeJson["gdbserverdebug"].toBool()); } setLaunchMode("connect"); } // Load RR project. if (rrModeJson.isEmpty() == false) { rrTraceDirectoryLineEdit->setText(rrModeJson["tracedirectory"].toString()); loadBreakpointsFilenameLineEdit->setText(rrModeJson["breakpointsfile"].toString()); rrLoadBreakpointsFilenameLineEdit->setText(rrModeJson["breakpointsfile"].toString()); setLaunchMode("rr"); } // Load COREFILE project. if (corefileModeJson.isEmpty() == false) { loadCoreFilenameLineEdit->setText(corefileModeJson["corefile"].toString()); setLaunchMode("corefile"); } return true; } void SeerDebugDialog::handleSaveProjectToolButton () { // Get the filename to save to. QString fname = QFileDialog::getSaveFileName(this, "Save to a project file.", "project.seer", "Projects (*.seer);;All files (*.*)", nullptr, QFileDialog::DontUseNativeDialog); if (fname == "") { return; } // Make the json document for the debug dialog settings. QJsonDocument jsonDoc = makeJsonDoc(); // Write the JSON document to the project file. QFile saveFile(fname); if (saveFile.open(QIODevice::WriteOnly) == false) { QMessageBox::critical(this, "Error", QString("Can't create the Seer project file '%1'.").arg(fname)); return; } saveFile.write(jsonDoc.toJson()); QMessageBox::information(this, "Success", QString("Created the Seer project file '%1'.").arg(fname)); } void SeerDebugDialog::handleRunModeChanged (int id) { // // Disable all important widgets. // executableNameLineEdit->setEnabled(false); executableNameToolButton->setEnabled(false); executableSymbolNameLineEdit->setEnabled(false); executableSymbolNameToolButton->setEnabled(false); executableWorkingDirectoryLineEdit->setEnabled(false); executableWorkingDirectoryToolButton->setEnabled(false); preCommandsPlainTextEdit->setPlaceholderText(""); postCommandsPlainTextEdit->setPlaceholderText(""); // // Enable the newly selected one. // // ID == 0 RUN/START if (id == 0) { executableNameLineEdit->setEnabled(true); executableNameToolButton->setEnabled(true); executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); executableWorkingDirectoryLineEdit->setEnabled(true); executableWorkingDirectoryToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before \"run\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after \"run\""); } // ID == 1 ATTACH if (id == 1) { executableNameLineEdit->setEnabled(true); executableNameToolButton->setEnabled(true); executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); executableWorkingDirectoryLineEdit->setEnabled(true); executableWorkingDirectoryToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before \"attach\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after \"attach\""); } // ID == 2 CONNECT if (id == 2) { executableNameLineEdit->setEnabled(true); executableNameToolButton->setEnabled(true); executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); executableWorkingDirectoryLineEdit->setEnabled(true); executableWorkingDirectoryToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before \"connect\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after \"connect\""); } // ID == 3 RR if (id == 3) { executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before \"RR trace-directory load\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after \"RR trace-directory load\""); // Set default if we can. Otherwise, leave it blank. // if (rrTraceDirectoryLineEdit->text() == "") { QStringList searchPaths = { "$_RR_TRACE_DIR/latest-trace", "$XDG_DATA_HOME/rr/latest-trace", "$HOME/.local/share/rr/latest-trace" }; QString defaultPath = ""; bool f; for (const auto& path : searchPaths) { defaultPath = Seer::expandEnv(path, &f); if (f == false) { continue; } if (QFile::exists(defaultPath)) { setRRTraceDirectory(defaultPath); break; } } } } // ID == 4 COREFILE if (id == 4) { executableNameLineEdit->setEnabled(true); executableNameToolButton->setEnabled(true); executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before loading \"corefile\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after loading \"corefile\""); } } void SeerDebugDialog::handleLaunchButtonClicked () { QJsonDocument document = makeJsonDoc(); writeDefaultProjectSettings(document); } void SeerDebugDialog::handleResetButtonClicked (QAbstractButton* button) { // Was the Reset button clicked? QAbstractButton* resetButton = buttonBox->button(QDialogButtonBox::Reset); if (button != resetButton) { return; } // Reset all parameters. reset(); } void SeerDebugDialog::handleHelpModeToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/DebugModes.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpRunToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/RunDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpAttachToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/AttachDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpConnectToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/ConnectDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpRRToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/RRDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpCorefileToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/CorefileDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::writeSettings() { QSettings settings; settings.beginGroup("debugdialog"); { settings.setValue("size", size()); } settings.endGroup(); } void SeerDebugDialog::readSettings() { QSettings settings; settings.beginGroup("debugdialog"); { resize(settings.value("size", QSize(800, 600)).toSize()); } settings.endGroup(); } void SeerDebugDialog::writeDefaultProjectSettings (const QJsonDocument& document) { QSettings settings; settings.beginGroup("debugdialog"); { settings.setValue("defaultproject", document.toJson(QJsonDocument::Compact)); } settings.endGroup(); } void SeerDebugDialog::loadDefaultProjectSettings () { QSettings settings; settings.beginGroup("debugdialog"); { QVariant variantData = settings.value("defaultproject"); if (variantData.isValid()) { QJsonDocument jsonDoc = QJsonDocument::fromJson(variantData.toByteArray()); loadJsonDoc(jsonDoc, "defaultproject"); } } settings.endGroup(); } void SeerDebugDialog::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QWidget::resizeEvent(event); } seer-2.7/src/SeerDebugDialog.h000066400000000000000000000172701516472651200162650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include "ui_SeerDebugDialog.h" class SeerDebugDialog : public QDialog, protected Ui::SeerDebugDialogForm { Q_OBJECT public: explicit SeerDebugDialog (QWidget* parent = 0); ~SeerDebugDialog (); // Reset all void reset (); // For any run mode. void setExecutableName (const QString& executableName); QString executableName () const; void setExecutableSymbolName (const QString& executableSymbolName); QString executableSymbolName () const; void setExecutableWorkingDirectory (const QString& executableWorkingDirectory); QString executableWorkingDirectory () const; // Run or start executable. "run" or "start". void setExecutableArguments (const QString& executableArguments); QString executableArguments () const; void setBreakpointsFilename (const QString& breakpointsFilename); QString breakpointsFilename () const; void setBreakpointMode (const QString& mode); QString breakpointMode () const; void setBreakpointFunctionName (const QString& nameoraddress); QString breakpointFunctionName () const; void setBreakpointSourceName (const QString& sourceFilenameAndLineno); QString breakpointSourceName () const; void setShowAssemblyTabMode (const QString& mode); QString showAssemblyTabMode () const; void setRandomizeStartAddress (bool flag); bool randomizeStartAddress () const; void setNonStopMode (bool flag); bool nonStopMode () const; void setPreGdbCommands (const QStringList& preGdbCommands); QStringList preGdbCommands () const; void setPostGdbCommands (const QStringList& postGdbCommands); QStringList postGdbCommands () const; // Attach to a running process. "attach". void setAttachPid (int pid); int attachPid () const; // Connectect to a GDB server. "connect". void setConnectHostPort (const QString& connectHostPort); QString connectHostPort () const; void setConnectRemoteTargetType (const QString& type); QString connectRemoteTargetType () const; void setConnectGdbserverDebug (bool enable); bool connectGdbserverDebug () const; // Connectect to a RR server. "rr". void setRRTraceDirectory (const QString& rrTraceDirectory); QString rrTraceDirectory () const; QString rrBreakpointsFilename () const; // Load a core file. "corefile". void setCoreFilename (const QString& coreFilename); QString coreFilename () const; // Get the launch mode. void setLaunchMode (const QString& mode); QString launchMode () const; // Get the project filename. void setProjectFilename (const QString& filename); QString projectFilename () const; void loadProject (const QString& filename, bool notify); void loadDefaultProjectSettings (); // Make a json document of the current debug dialog settings. QJsonDocument makeJsonDoc () const; bool loadJsonDoc (const QJsonDocument& jsonDoc, const QString& filename); protected slots: void handleExecutableNameToolButton (); void handleExecutableSymbolNameToolButton (); void handleExecutableWorkingDirectoryToolButton (); void handleLoadBreakpointsFilenameToolButton (); void handleBreakpointInFunctionLineEdit (); void handleLoadRRTraceDirectoryToolButton (); void handleLoadCoreFilenameToolButton (); void handleProgramPidToolButton (); void handleLoadProjectToolButton (); void handleSaveProjectToolButton (); void handleRunModeChanged (int id); void handleLaunchButtonClicked (); void handleResetButtonClicked (QAbstractButton* button); private slots: void handleHelpModeToolButtonClicked (); void handleHelpRunToolButtonClicked (); void handleHelpAttachToolButtonClicked (); void handleHelpConnectToolButtonClicked (); void handleHelpRRToolButtonClicked (); void handleHelpCorefileToolButtonClicked (); protected: void writeSettings (); void readSettings (); void writeDefaultProjectSettings (const QJsonDocument& document); void resizeEvent (QResizeEvent* event); private: QString _projectFilename; }; seer-2.7/src/SeerDebugDialog.ui000066400000000000000000001222171516472651200164510ustar00rootroot00000000000000 SeerDebugDialogForm 0 0 758 849 Select Executable to Debug 0 100 Launch Method 0 10 0 0 0 Run Run and debug an executable. Qt::Horizontal 40 20 Help for Run launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Arguments 100 0 The arguments to pass to the program. optional program arguments true Breakpoints file 100 0 A file containing previously saved breakpoints. breakpoints.seer true Open a dialog to select a breakpoints file. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Set a breakpoint in "main". Break in "main" breakpointButtonGroup Set a breakpoint in a function or at an address. Break in breakpointButtonGroup The breakpoint function or address. _function or 0xaddress true Set a breakpoint at a line number in a source file. Break at breakpointButtonGroup The breakpoint using filename and lineno. sourcefile.cpp:line true No initial breakpoint. No breakpoint true breakpointButtonGroup Allow other threads to continue if any thread reaches a breakpoint. Non-stop mode Randomize the process start address. Randomize start address Qt::Horizontal 258 20 0 0 Show Assembly tab on startup 0 0 never always auto Qt::Horizontal QSizePolicy::Expanding 385 23 Attach Attach and debug a running process on the local machine. Qt::Horizontal 40 20 Help for Attach launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Process PID 100 0 The process pid. 9999999 pid true Open a dialog to select a pid on the local system. ... Qt::Vertical 20 192 Connect Connect to a gdbserver (or similar) session. Qt::Horizontal 248 20 Help for Connect launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Gdbserver 100 0 How to access the gdbserver. host:port or /dev/serialport true Remote target type 0 0 Select the type of remote target connection. remote extended-remote Qt::Horizontal QSizePolicy::Expanding 308 23 Enable debug communication between gdb and the gdbserver. Gdbserver debug Qt::Horizontal QSizePolicy::Expanding 408 23 Qt::Vertical 20 151 RR Load a RR trace session. Qt::Horizontal 248 20 Help for RR launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg RR trace directory 100 0 How to access the RR trace session. /path/to/rr/trace/directory true Open a dialog to load a RR trace-directory. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Breakpoints file 100 0 A file containing previously saved breakpoints. breakpoints.seer true Open a dialog to select a breakpoints file. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Qt::Vertical 20 113 Corefile Analyze a corefile. Qt::Horizontal 40 20 Help for Corefile launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Core file 100 0 The path and name of a core file. The path and name of the core file. true Open a dialog to select a core file. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Qt::Vertical 20 478 0 40 0 40 Working Directory Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop The working directory path to tell GDB. Default current directory. The working directory path to tell GDB. Default current directory. true Open a dialog to select a path. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Executable Name Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop false 0 0 The path and name of an executable to debug. The path and name of an executable to debug. true 0 0 Open a dialog to select an executable. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset Symbol File Name Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop false 0 0 Optional path and name of a symbol file for the executable. Optional path and name of a symbol file for the executable. true 0 0 Open a dialog to select the symbol file for the executable. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg executableNameGroupBox buttonBox executableSymbolNameGroupBox executableWorkingDirectoryGroupBox launchMethodGroupBox executableNameLineEdit executableNameToolButton executableSymbolNameLineEdit executableSymbolNameToolButton executableWorkingDirectoryLineEdit executableWorkingDirectoryToolButton runModeTabWidget helpRunToolButton runProgramArgumentsLineEdit loadBreakpointsFilenameLineEdit loadBreakpointsFilenameToolButton breakpointInMainRadioButton breakpointInFunctionRadioButton breakpointInFunctionLineEdit breakpointAtSourceRadioButton breakpointAtSourceLineEdit noBreakpointRadioButton nonStopModeCheckBox randomizeStartAddressCheckBox preCommandsPlainTextEdit postCommandsPlainTextEdit helpAttachToolButton attachProgramPidLineEdit attachProgramPidToolButton helpConnectToolButton helpRRToolButton rrTraceDirectoryLineEdit rrLoadTraceDirectoryToolButton rrLoadBreakpointsFilenameLineEdit rrLoadBreakpointsFilenameToolButton helpCorefileToolButton loadCoreFilenameLineEdit loadCoreFilenameToolButton buttonBox accepted() SeerDebugDialogForm accept() 248 254 157 274 buttonBox rejected() SeerDebugDialogForm reject() 316 260 286 274 seer-2.7/src/SeerDirectoryFilterProxyModel.h000066400000000000000000000012741516472651200212510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerDirectoryFilterProxyModel : public QSortFilterProxyModel { bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { QFileSystemModel* fileModel = qobject_cast(sourceModel()); QFileInfo file(fileModel->filePath(sourceModel()->index(sourceRow, 0, sourceParent))); if (file.isDir() == true || file.isHidden()) { return true; }else{ return false; } } }; seer-2.7/src/SeerEditorConfigPage.cpp000066400000000000000000000347111516472651200176220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorConfigPage.h" #include "QColorButton.h" #include #include #include #include #include #include SeerEditorConfigPage::SeerEditorConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // // Setup the widgets // // Connect things. QObject::connect(fontMonoRadioButton, &QRadioButton::clicked, this, &SeerEditorConfigPage::handleFontMonoChanged); QObject::connect(fontSizeComboBox, &QComboBox::currentTextChanged, this, &SeerEditorConfigPage::handleFontSizeChanged); QObject::connect(fontNameComboBox, &QFontComboBox::currentFontChanged, this, &SeerEditorConfigPage::handleFontChanged); QObject::connect(fontDialogButton, &QToolButton::clicked, this, &SeerEditorConfigPage::handleFontDialog); QObject::connect(highlighterEnabledCheckBox, &QToolButton::clicked, this, &SeerEditorConfigPage::handleEnabledChanged); QObject::connect(cppSuffixesLineEdit, &QHistoryLineEdit::lostFocus, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(rustSuffixesLineEdit, &QHistoryLineEdit::lostFocus, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(odinSuffixesLineEdit, &QHistoryLineEdit::lostFocus, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(cppSuffixesLineEdit, &QHistoryLineEdit::gainedFocus, this, &SeerEditorConfigPage::handleCppSuffixFocusIn); QObject::connect(rustSuffixesLineEdit, &QHistoryLineEdit::gainedFocus, this, &SeerEditorConfigPage::handleRustSuffixFocusIn); QObject::connect(odinSuffixesLineEdit, &QHistoryLineEdit::gainedFocus, this, &SeerEditorConfigPage::handleOdinSuffixFocusIn); QObject::connect(themeApplyToolButton, &QToolButton::clicked, this, &SeerEditorConfigPage::handleApplyTheme); // Set the defaults. reset(); // Fill in the available theme names. themeComboBox->addItems(SeerHighlighterSettings::themeNames()); // Set example text. handleCppSuffixFocusIn(); } SeerEditorConfigPage::~SeerEditorConfigPage() { } void SeerEditorConfigPage::setEditorFont (const QFont& font) { handleFontChanged(font); } const QFont& SeerEditorConfigPage::editorFont () const { return _font; } void SeerEditorConfigPage::setEditorTabSize (int spaces) { tabSpinBox->setValue(spaces); } int SeerEditorConfigPage::editorTabSize () const { return tabSpinBox->value(); } void SeerEditorConfigPage::setHighlighterSettings (const SeerHighlighterSettings& settings) { _highlighterSettings = settings; // Clear the table contents. highlighterTableWidget->setRowCount(0); // Get a list of keys from the highlighter. QStringList keys = _highlighterSettings.keys(); // Loop through each key and get its info. // Construct a table entry. for (int r=0; rinsertRow(r); // Insert the font weight. QComboBox* fontWeightBox = new QComboBox; fontWeightBox->addItem("Normal"); fontWeightBox->addItem("Bold"); if (format.fontWeight() == QFont::Normal) { fontWeightBox->setCurrentText("Normal"); }else if (format.fontWeight() == QFont::Bold) { fontWeightBox->setCurrentText("Bold"); }else{ fontWeightBox->setCurrentText("Normal"); } highlighterTableWidget->setCellWidget(r, 0, fontWeightBox); // Insert the font italic. QComboBox* fontItalicBox = new QComboBox; fontItalicBox->addItem("Normal"); fontItalicBox->addItem("Italic"); if (format.fontItalic() == false) { fontItalicBox->setCurrentText("Normal"); }else if (format.fontItalic() == true) { fontItalicBox->setCurrentText("Italic"); }else{ fontItalicBox->setCurrentText("Normal"); } highlighterTableWidget->setCellWidget(r, 1, fontItalicBox); // Insert the font color. QColorButton* foregroundColorButton = new QColorButton; foregroundColorButton->setColor(format.foreground().color()); QColorButton* backgroundColorButton = new QColorButton; backgroundColorButton->setColor(format.background().color()); highlighterTableWidget->setCellWidget(r, 2, foregroundColorButton); highlighterTableWidget->setCellWidget(r, 3, backgroundColorButton); // Connect things to watch for changes. QObject::connect(fontWeightBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(fontItalicBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(foregroundColorButton, &QColorButton::colorChanged, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(backgroundColorButton, &QColorButton::colorChanged, this, &SeerEditorConfigPage::handleHighlighterChanged); } highlighterTableWidget->setVerticalHeaderLabels(keys); highlighterTableWidget->resizeColumnToContents(0); // Weight highlighterTableWidget->resizeColumnToContents(1); // Italic highlighterTableWidget->resizeColumnToContents(2); // Foreground color highlighterTableWidget->resizeColumnToContents(3); // Background color cppSuffixesLineEdit->setText(_highlighterSettings.cppSourceSuffixes()); cppSuffixesLineEdit->setCursorPosition(0); rustSuffixesLineEdit->setText(_highlighterSettings.rustSourceSuffixes()); rustSuffixesLineEdit->setCursorPosition(0); odinSuffixesLineEdit->setText(_highlighterSettings.odinSourceSuffixes()); odinSuffixesLineEdit->setCursorPosition(0); // Update our sample editor. editorWidget->sourceArea()->setHighlighterSettings(highlighterSettings()); editorWidget->sourceArea()->setCurrentLine(0); } const SeerHighlighterSettings& SeerEditorConfigPage::highlighterSettings() const { return _highlighterSettings; } void SeerEditorConfigPage::setHighlighterEnabled (bool flag) { highlighterEnabledCheckBox->setChecked(flag); editorWidget->sourceArea()->setHighlighterEnabled(flag); } bool SeerEditorConfigPage::highlighterEnabled () const { return editorWidget->sourceArea()->highlighterEnabled(); } void SeerEditorConfigPage::setExternalEditorCommand (const QString& externalEditorCommand) { externalEditorCommandLineEdit->setText(externalEditorCommand); } QString SeerEditorConfigPage::externalEditorCommand () const { return externalEditorCommandLineEdit->text(); } void SeerEditorConfigPage::setAutoSourceReload (bool flag) { autoReloadSourceFileCheckBox->setChecked(flag); } bool SeerEditorConfigPage::autoSourceReload () const { return autoReloadSourceFileCheckBox->isChecked(); } void SeerEditorConfigPage::reset () { setEditorFont(QFont("monospace", 10)); setEditorTabSize(4); setHighlighterSettings(SeerHighlighterSettings::populate("")); setHighlighterEnabled(true); setExternalEditorCommand(""); setAutoSourceReload(false); } void SeerEditorConfigPage::handleFontMonoChanged () { if (fontMonoRadioButton->isChecked()) { fontNameComboBox->setFontFilters(QFontComboBox::MonospacedFonts); }else{ fontNameComboBox->setFontFilters(QFontComboBox::AllFonts); } } void SeerEditorConfigPage::handleFontSizeChanged (const QString& text) { // Convert the text size to a number. int size = text.toInt(); // Guard against a bad size. if (size <= 0) { return; } // Set its size. _font.setPointSize(size); // Display our example text with the new font. editorWidget->sourceArea()->setFont(_font); } void SeerEditorConfigPage::handleFontChanged (const QFont& font) { // Clear the font size list. QStringList sizes; fontSizeComboBox->clear(); // Populate the font size list from the given font. foreach (int points, QFontDatabase::smoothSizes(font.family(), font.styleName())) { sizes.append(QString::number(points)); } fontSizeComboBox->addItems(sizes); // Set the current font size in the list. fontSizeComboBox->setCurrentText(QString::number(font.pointSize())); // Set the current font family in the list. fontNameComboBox->setCurrentFont(font); // Display our example text with the new font. editorWidget->sourceArea()->setFont(font); // Save the new font. _font = font; } void SeerEditorConfigPage::handleFontDialog () { bool ok; QFont font; if (fontMonoRadioButton->isChecked()) { font = QFontDialog::getFont(&ok, _font, this, "Select a font for the editors", QFontDialog::MonospacedFonts); }else{ font = QFontDialog::getFont(&ok, _font, this, "Select a font for the editors"); } if (ok) { handleFontChanged(font); } } void SeerEditorConfigPage::handleHighlighterChanged () { SeerHighlighterSettings languageSettings; for (int r=0; rrowCount(); r++) { // Get the key (label) for this row. QString key = highlighterTableWidget->verticalHeaderItem(r)->text(); // Get widgets for this row. QComboBox* fontWeightBox = dynamic_cast(highlighterTableWidget->cellWidget(r,0)); QComboBox* fontItalicBox = dynamic_cast(highlighterTableWidget->cellWidget(r,1)); QColorButton* foregroundColorButton = dynamic_cast(highlighterTableWidget->cellWidget(r,2)); QColorButton* backgroundColorButton = dynamic_cast(highlighterTableWidget->cellWidget(r,3)); // Create an empty format. QTextCharFormat format; // Set the font weight. if (fontWeightBox->currentText() == "Normal") { format.setFontWeight(QFont::Normal); }else if (fontWeightBox->currentText() == "Bold") { format.setFontWeight(QFont::Bold); }else{ format.setFontWeight(QFont::Normal); } // Set the font italic. if (fontItalicBox->currentText() == "Normal") { format.setFontItalic(false); }else if (fontItalicBox->currentText() == "Italic") { format.setFontItalic(true); }else{ format.setFontItalic(false); } // Set the font color. format.setForeground(foregroundColorButton->color()); format.setBackground(backgroundColorButton->color()); // Add the format to our settings. languageSettings.add(key, format); } // Get list of source suffixes. languageSettings.setCppSourceSuffixes(cppSuffixesLineEdit->text()); languageSettings.setRustSourceSuffixes(rustSuffixesLineEdit->text()); languageSettings.setOdinSourceSuffixes(odinSuffixesLineEdit->text()); // Update our view. setHighlighterSettings(languageSettings); } void SeerEditorConfigPage::handleEnabledChanged () { setHighlighterEnabled(highlighterEnabledCheckBox->isChecked()); } void SeerEditorConfigPage::handleApplyTheme () { setHighlighterSettings(SeerHighlighterSettings::populate(themeComboBox->currentText())); } void SeerEditorConfigPage::handleCppSuffixFocusIn () { // Set example text. editorWidget->sourceArea()->openText("/*\n" " * Seer, Copyright 2021 (c)\n" " * Ernie Pasveer (epasveer@att.net)\n" " * C/C++ example\n" " */\n" "\n" "// This is the main function.\n" "int main(int argc, char* argv[]) {\n" "\n" " std::cout << \"Hello, Seer!\"; // Greetings\n" "\n" " return 0;\n" "}", "sample.cpp"); editorWidget->sourceArea()->setCurrentLine(0); } void SeerEditorConfigPage::handleRustSuffixFocusIn () { // Set example text. editorWidget->sourceArea()->openText("/*\n" " * Seer, Copyright 2021 (c)\n" " * Ernie Pasveer (epasveer@att.net)\n" " * Rust example\n" " */\n" "\n" "// This is the main function.\n" "fn main() {\n" " // Print text to the console.\n" " println!(\"Hello World!\");\n" "}", "sample.rs"); editorWidget->sourceArea()->setCurrentLine(0); } void SeerEditorConfigPage::handleOdinSuffixFocusIn () { // Set example text. editorWidget->sourceArea()->openText("/*\n" " * Seer, Copyright 2021 (c)\n" " * Ernie Pasveer (epasveer@att.net)\n" " * Odin example\n" " */\n" "package main\n" "\n" "import \"core:fmt\"\n" "\n" "// This is the main function.\n" "main :: proc() {\n" " fmt.println(\"Hello, World!\")\n" "}", "sample.odin"); editorWidget->sourceArea()->setCurrentLine(0); } seer-2.7/src/SeerEditorConfigPage.h000066400000000000000000000051341516472651200172640ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include #include #include "ui_SeerEditorConfigPage.h" class SeerEditorConfigPage : public QWidget, public Ui::SeerEditorConfigPage { Q_OBJECT public: explicit SeerEditorConfigPage (QWidget* parent = 0); ~SeerEditorConfigPage (); void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& highlighterSettings () const; void setHighlighterEnabled (bool flag); bool highlighterEnabled () const; void setExternalEditorCommand (const QString& externalEditorCommand); QString externalEditorCommand () const; void setAutoSourceReload (bool flag); bool autoSourceReload () const; void reset (); protected slots: void handleFontMonoChanged (); void handleFontSizeChanged (const QString& text); void handleFontChanged (const QFont& font); void handleFontDialog (); void handleHighlighterChanged (); void handleEnabledChanged (); void handleApplyTheme (); void handleCppSuffixFocusIn (); void handleRustSuffixFocusIn (); void handleOdinSuffixFocusIn (); private: QFont _font; SeerHighlighterSettings _highlighterSettings; }; seer-2.7/src/SeerEditorConfigPage.ui000066400000000000000000000377371516472651200174700ustar00rootroot00000000000000 SeerEditorConfigPage 0 0 660 861 SeerEditorConfigPage 50 0 QFontComboBox::MonospacedFonts :/seer/resources/icons-icons/font.png:/seer/resources/icons-icons/font.png Show only Mono Spaced fonts. Mono true Theme Select Light or Dark theme. 0 0 Apply Qt::Vertical Tab Size Set tab width, in spaces, for Editors. 1 10 4 Qt::Vertical Enable or disable highlighting for supported languages' files. Syntax highlighting. Qt::Horizontal 40 20 C/C++ C/C++ source suffixes. Separated by '|'. C/C++ source suffixes. true Rust Rust source suffixes. Separated by '|'. Rust source suffixes. true Odin Odin source suffixes. Separated by '|'. Odin source suffixes. true 0 50 0 50 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded 0 false false true false Weight Style Foreground Background Auto Source Reload External Editor Command Command to launch external editor. myeditor --line %{line} "%{file}" true Automatically reload source files if they are externally modified. 0 50 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify font and syntax highlighting colors for the code editor.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These formats apply only when highlighting is enabled and if the file is one of the listed source suffixes.</p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Class</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Comment</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Multiline Comment</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Function</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Keyword</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Quotation</li></ul> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These formats apply for any type of file. </p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Margin</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Text</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Assembly Text</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current Line</li></ul> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A note about fonts. Sometimes Qt will not list some Mono Spaced fonts even though they are. If this is the case for you, disable the Mono button. All fonts will then be listed.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Syntax highlighting can be enabled or disabled. The list of suffixes for supported source files can be changed. For example, C/C++ source files:</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&quot;.h|.cpp|.c&quot;</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The tab size, in spaces, can be set to properly display source files that contain tab characters.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You can specify a command to launch an external editor. While in a source window, you can use the RMB menu to launch the external editor on the current file. However, these changes are not recognized by Seer. When specifying the command, you have these two variables. One for the name of the source file, and one for the line number to tell the editor to go to. Here are a few examples:</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'monospace';">geany &quot;%{file}&quot;:%{line}<br />kate --line %{line} &quot;%{file}&quot;<br />gedit &quot;%{file}&quot; +%{line}<br />konsole -e vim &quot;%{file}&quot; +%{line}<br /><br /></span>Seer detects if the underlining source file is modified externally. Seer can automatically reload the file or prompt you to reload it.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You may need to close and reopen the source files for changes to take effect.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Seer detects if the underlining source file is modified. Seer can automatically reload the file or prompt you to reload it.</p> <p style="-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> SeerEditorWidgetSource QWidget
SeerEditorWidgetSource.h
1
QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerEditorManagerEntry.h000066400000000000000000000011611516472651200176520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerEditorWidgetSource.h" #include #include #include struct SeerEditorManagerEntry { QString fullname; QString file; SeerEditorWidgetSource* widget; }; typedef QMap SeerEditorManagerEntries; struct SeerEditorManagerFile { QString fullname; QString file; }; typedef QVector SeerEditorManagerFiles; seer-2.7/src/SeerEditorManagerWidget.cpp000066400000000000000000001755401516472651200203440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorManagerWidget.h" #include "SeerEditorWidgetSource.h" #include "SeerEditorWidgetAssembly.h" #include "SeerCloseSourceDialog.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include SeerEditorManagerWidget::SeerEditorManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data _editorFont = QFont("monospace", 10); // Default font. _editorHighlighterSettings = SeerHighlighterSettings::populate(""); // Default syntax highlighting. _editorHighlighterEnabled = true; _editorKeySettings = SeerKeySettings::populate(); // Default key settings. _editorTabSize = 4; _editorExternalEditorCommand = ""; _editorAutoSourceReload = false; _assemblyWidget = 0; _showAssemblyTabOnStartupMode = "never"; _keepAssemblyTabOnTop = true; _showAddressColumn = true; _showOffsetColumn = false; _showOpcodeColumn = false; _showSourceLines = false; _notifyAssemblyTabShown = true; _idFunctionDefinition = Seer::createID(); _idVariableDefinition = Seer::createID(); _idTypeDefinition = Seer::createID(); // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(true); // Create editor options bar. QToolButton* fileOpenToolButton = new QToolButton(tabWidget); fileOpenToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/document-open.svg")); fileOpenToolButton->setToolTip("Open a file."); QToolButton* fileCloseToolButton = new QToolButton(tabWidget); fileCloseToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg")); fileCloseToolButton->setToolTip("Close opened files."); QToolButton* textSearchToolButton = new QToolButton(tabWidget); textSearchToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/edit-find.svg")); textSearchToolButton->setToolTip("Show search bar."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on the code manager."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(fileOpenToolButton); hcontainer->addWidget(fileCloseToolButton); hcontainer->addWidget(textSearchToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Create a place holder tab with a special name of "". createEditorWidgetTab("", ""); // Connect things. QObject::connect(tabWidget, &QTabWidget::tabCloseRequested, this, &SeerEditorManagerWidget::handleTabCloseRequested); QObject::connect(tabWidget, &QTabWidget::currentChanged, this, &SeerEditorManagerWidget::handleTabCurrentChanged); QObject::connect(fileOpenToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleFileOpenToolButtonClicked); QObject::connect(fileCloseToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleFileCloseToolButtonClicked); QObject::connect(textSearchToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleTextSearchToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleHelpToolButtonClicked); // Add combination shortcut for re-open closed file (Ctrl + Shift + T) QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+Shift+T"), this); QObject::connect(shortcut, &QShortcut::activated, [this] () { if (!_stackClosedFiles.empty()) { SeerEditorWidgetSourceArea::SeerCurrentFile topValue = _stackClosedFiles.top(); // read the top _stackClosedFiles.pop(); handleOpenFileWithDetails(topValue.file, topValue.fullname, topValue.cursorRow, topValue.cursorCol, topValue.firstDisplayLine); } } ); } SeerEditorManagerWidget::~SeerEditorManagerWidget () { _notifyAssemblyTabShown = false; deleteAssemblyWidgetTab(); } SeerEditorManagerEntries& SeerEditorManagerWidget::entries() { return _entries; } const SeerEditorManagerEntries& SeerEditorManagerWidget::entries() const { return _entries; } void SeerEditorManagerWidget::dumpEntries () const { qDebug(); SeerEditorManagerEntries::const_iterator b = beginEntry(); SeerEditorManagerEntries::const_iterator e = endEntry(); qDebug() << "Start"; while (b != e) { qDebug() << "\tFullname:" << b->fullname << "File:" << b->file; b++; } qDebug() << "End"; } bool SeerEditorManagerWidget::hasEntry (const QString& fullname) const { if (_entries.find(fullname) != _entries.end()) { return true; } return false; } SeerEditorManagerEntries::iterator SeerEditorManagerWidget::addEntry (const QString& fullname, const QString& file) { //qDebug() << "Add entry:" << fullname << file; SeerEditorManagerEntry entry; entry.fullname = fullname; entry.file = file; entry.widget = 0; return _entries.insert(fullname, entry); } SeerEditorManagerEntries::iterator SeerEditorManagerWidget::findEntry (const QString& fullname) { return _entries.find(fullname); } SeerEditorManagerEntries::const_iterator SeerEditorManagerWidget::findEntry (const QString& fullname) const { return _entries.find(fullname); } SeerEditorManagerEntries::iterator SeerEditorManagerWidget::beginEntry () { return _entries.begin(); } SeerEditorManagerEntries::const_iterator SeerEditorManagerWidget::beginEntry () const { return _entries.begin(); } SeerEditorManagerEntries::iterator SeerEditorManagerWidget::endEntry () { return _entries.end(); } SeerEditorManagerEntries::const_iterator SeerEditorManagerWidget::endEntry () const { return _entries.end(); } void SeerEditorManagerWidget::deleteEntry (SeerEditorManagerEntries::iterator i) { _entries.erase(i); } void SeerEditorManagerWidget::maybeShowAssembly () { if (showAssemblyTabOnStartupMode() == "always") { showAssembly(); } } void SeerEditorManagerWidget::showAssembly () { // Create and show the assembly widget if it isn't already. if (assemblyWidgetTab() == 0) { createAssemblyWidgetTab(); } assemblyWidgetTab()->assemblyArea()->setAddress("$pc"); assemblyWidgetTab()->reloadRegisters(); } SeerEditorWidgetAssembly* SeerEditorManagerWidget::assemblyWidgetTab () { return _assemblyWidget; } void SeerEditorManagerWidget::setKeepAssemblyTabOnTop (bool flag) { _keepAssemblyTabOnTop = flag; } bool SeerEditorManagerWidget::keepAssemblyTabOnTop () const { return _keepAssemblyTabOnTop; } void SeerEditorManagerWidget::setShowAssemblyTabOnStartupMode (const QString& mode) { _showAssemblyTabOnStartupMode = mode; } QString SeerEditorManagerWidget::showAssemblyTabOnStartupMode () const { return _showAssemblyTabOnStartupMode; } void SeerEditorManagerWidget::setAssemblyShowAddressColumn (bool flag) { _showAddressColumn = flag; if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->setShowAddressColumn(_showAddressColumn); } } bool SeerEditorManagerWidget::assemblyShowAddressColumn () const { return _showAddressColumn; } void SeerEditorManagerWidget::setAssemblyShowOffsetColumn (bool flag) { _showOffsetColumn = flag; if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->setShowOffsetColumn(_showOffsetColumn); } } bool SeerEditorManagerWidget::assemblyShowOffsetColumn () const { return _showOffsetColumn; } void SeerEditorManagerWidget::setAssemblyShowOpcodeColumn (bool flag) { _showOpcodeColumn = flag; if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->setShowOpcodeColumn(_showOpcodeColumn); } } bool SeerEditorManagerWidget::assemblyShowOpcodeColumn () const { return _showOpcodeColumn; } void SeerEditorManagerWidget::setAssemblyShowSourceLines (bool flag) { _showSourceLines = flag; if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->setShowSourceLines(_showSourceLines); } } bool SeerEditorManagerWidget::assemblyShowSourceLines () const { return _showSourceLines; } SeerEditorManagerFiles SeerEditorManagerWidget::openedFiles () const { SeerEditorManagerFiles files; SeerEditorManagerEntries::const_iterator b = beginEntry(); SeerEditorManagerEntries::const_iterator e = endEntry(); while (b != e) { SeerEditorManagerFile f; f.file = b->file; f.fullname = b->fullname; files.push_back(f); b++; } return files; } void SeerEditorManagerWidget::setEditorFont (const QFont& font) { _editorFont = font; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setEditorFont(editorFont()); b++; } // Don't forget about the assembly widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->setEditorFont(editorFont()); } } const QFont& SeerEditorManagerWidget::editorFont () const { return _editorFont; } void SeerEditorManagerWidget::setEditorHighlighterSettings (const SeerHighlighterSettings& settings) { _editorHighlighterSettings = settings; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setHighlighterSettings(_editorHighlighterSettings); b++; } // Don't forget about the assembly widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->setHighlighterSettings(editorHighlighterSettings()); } } const SeerHighlighterSettings& SeerEditorManagerWidget::editorHighlighterSettings () const { return _editorHighlighterSettings; } void SeerEditorManagerWidget::setEditorHighlighterEnabled (bool flag) { _editorHighlighterEnabled = flag; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setHighlighterEnabled(_editorHighlighterEnabled); b++; } // Don't forget about the assembly widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->setHighlighterEnabled(editorHighlighterEnabled()); } } bool SeerEditorManagerWidget::editorHighlighterEnabled () const { return _editorHighlighterEnabled; } void SeerEditorManagerWidget::setEditorAlternateDirectories (const QStringList alternateDirectories) { _editorAlternateDirectories = alternateDirectories; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setAlternateDirectories(_editorAlternateDirectories); b++; } } const QStringList& SeerEditorManagerWidget::editorAlternateDirectories () const { return _editorAlternateDirectories; } void SeerEditorManagerWidget::setEditorIgnoreDirectories (const QStringList ignoreDirectories) { _editorIgnoreDirectories = ignoreDirectories; } const QStringList& SeerEditorManagerWidget::editorIgnoreDirectories () const { return _editorIgnoreDirectories; } void SeerEditorManagerWidget::setEditorKeySettings (const SeerKeySettings& settings) { _editorKeySettings = settings; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->setKeySettings(_editorKeySettings); b++; } // Don't forget about the assembly widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->setKeySettings(editorKeySettings()); } } const SeerKeySettings& SeerEditorManagerWidget::editorKeySettings () const { return _editorKeySettings; } void SeerEditorManagerWidget::setEditorTabSize (int spaces) { _editorTabSize = spaces; } int SeerEditorManagerWidget::editorTabSize () const { return _editorTabSize; } void SeerEditorManagerWidget::setEditorExternalEditorCommand (const QString& externalEditorCommand) { _editorExternalEditorCommand = externalEditorCommand; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setExternalEditorCommand(_editorExternalEditorCommand); b++; } } const QString& SeerEditorManagerWidget::editorExternalEditorCommand () const { return _editorExternalEditorCommand; } void SeerEditorManagerWidget::setEditorAutoSourceReload (bool flag) { _editorAutoSourceReload = flag; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setAutoSourceReload(_editorAutoSourceReload); b++; } } bool SeerEditorManagerWidget::editorAutoSourceReload () const { return _editorAutoSourceReload; } void SeerEditorManagerWidget::handleText (const QString& text) { // Update the current line. if (text.startsWith("*stopped")) { //qDebug() << ":stopped:" << text; QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "frame=", '{', '}', false); if (frame_text == "") { return; } QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); //qDebug() << frame_text; //qDebug() << fullname_text << file_text << line_text; // If there is a file to open, open it. if (fullname_text != "" && file_text != "") { // Get the EditorWidget for the file. Create one if needed. SeerEditorWidgetSource* editorWidget = editorWidgetTab(fullname_text); if (editorWidget == 0) { editorWidget = createEditorWidgetTab(fullname_text, file_text, text); } // Can still be null, if the file is ignored. if (editorWidget == 0) { return; } // Push this tab to the top only if the current one in not the "Assembly" tab. QString tabtext = ""; if (tabWidget->currentIndex() >= 0) { tabtext = tabWidget->tabText(tabWidget->currentIndex()); } if (keepAssemblyTabOnTop() && tabtext == "Assembly") { // Do nothing. The "Assembly" tab is already on top. }else{ tabWidget->setCurrentWidget(editorWidget); } // Give the EditorWidget the command text (read file, set line number, etc.). editorWidget->sourceArea()->handleText(text); } // Get the AssemblyWidget, if there is one. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } // Handle certain reasons uniquely. QString reason_text = Seer::parseFirst(newtext, "reason=", '"', '"', false); if (reason_text == "breakpoint-hit") { QString disp_text = Seer::parseFirst(newtext, "disp=", '"', '"', false); // Ask for the breakpoint list to be resent, in case the encountered breakpoint was temporary. if (disp_text == "del") { emit refreshBreakpointsList(); } } return; // Refresh the breakpoints for all opened files. }else if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { // // See SeerBreakpointsBrowserWidget.cpp // // ^done,BreakpointTable={ // ... // } // // We have a breakpoint table. Start by clearing all breakpoints // in the editor widgets that are opened. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->clearBreakpoints(); b++; } // Tell the assembly widget to clear its breakpoints. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->clearBreakpoints(); } // Now parse the table and re-add the breakpoints. QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(newtext, "body=", '[', ']', false); //qDebug() << body_text; if (body_text != "") { QStringList bkpt_list = Seer::parse(newtext, "bkpt=", '{', '}', false); for ( const auto& bkpt_text : bkpt_list ) { QString number_text = Seer::parseFirst(bkpt_text, "number=", '"', '"', false); QString type_text = Seer::parseFirst(bkpt_text, "type=", '"', '"', false); QString disp_text = Seer::parseFirst(bkpt_text, "disp=", '"', '"', false); QString enabled_text = Seer::parseFirst(bkpt_text, "enabled=", '"', '"', false); QString addr_text = Seer::parseFirst(bkpt_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(bkpt_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(bkpt_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(bkpt_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(bkpt_text, "line=", '"', '"', false); QString thread_groups_text = Seer::parseFirst(bkpt_text, "thread-groups=", '[', ']', false); QString times_text = Seer::parseFirst(bkpt_text, "times=", '"', '"', false); QString original_location_text = Seer::parseFirst(bkpt_text, "original-location=", '"', '"', false); // Find the appropriate source file and update its breakpoints SeerEditorManagerEntries::iterator i = findEntry(fullname_text); SeerEditorManagerEntries::iterator e = endEntry(); if (i != e) { i->widget->sourceArea()->addBreakpoint(number_text.toInt(), line_text.toInt(), (enabled_text == "y" ? true : false)); } // Tell the assembly widget about the breakpoint. If the address is in its range, it will add it. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->addBreakpoint(number_text.toInt(), addr_text, (enabled_text == "y" ? true : false)); } } } // Send the info for an individual breakpoint to all opened files. // Each opened file can accept it (or reject it) to display the // info as a ToolTip. }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,BreakpointTable={")) && text.endsWith("}")) { // // See SeerBreakpointsBrowserWidget.cpp // // 7^done,BreakpointTable={ // ... // } // // Loop through each opened file and forward the text. SeerEditorManagerEntries::iterator i = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (i != e) { i->widget->sourceArea()->handleText(text); i++; } // Forward the text to the assembly widget, if there is one. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); } }else if (text.startsWith("^done,stack=[") && text.endsWith("]")) { //qDebug() << ":stack:" << text; // // See SeerStackFramesBrowserWidget.cpp // ^done,stack=[ // ... // ] // // Now parse the table and re-add the breakpoints. QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString stack_text = Seer::parseFirst(newtext, "stack=", '[', ']', false); if (stack_text != "") { // Clear current lines in all opened editor widgets. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { //b->widget->setCurrentLine(0); b->widget->sourceArea()->clearCurrentLines(); b++; } // Parse through the frame list and set the current lines that are in the frame list. QStringList frame_list = Seer::parse(newtext, "frame=", '{', '}', false); _lastFrameList = frame_list; SeerEditorManagerEntries::iterator i_later=endEntry(); int lineToPrintLater = -1; for ( const auto& frame_text : frame_list ) { QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(frame_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); QString arch_text = Seer::parseFirst(frame_text, "arch=", '"', '"', false); SeerEditorManagerEntries::iterator i = findEntry(fullname_text); SeerEditorManagerEntries::iterator e = endEntry(); if (level_text.toInt() == 0) // if current line level = 0, save command and paint it later, fix recursive painting { i_later = i; lineToPrintLater = line_text.toInt(); continue; } if (i != e) { i->widget->sourceArea()->addCurrentLine(line_text.toInt(), level_text.toInt()); } } if (i_later != endEntry() && lineToPrintLater != -1) { i_later->widget->sourceArea()->addCurrentLine(lineToPrintLater, 0); } } // Get the AssemblyWidget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } }else if (text.startsWith("^done,asm_insns=")) { // Get the AssemblyWidget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } }else if (text.startsWith("^error,msg=\"-data-disassemble:")) { // Get the AssemblyWidget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } }else if (text.startsWith("^error,msg=\"No registers.\"")) { //qDebug() << text; // Clear current lines in all opened editor widgets. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setCurrentLine(0); b++; } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 10^done,value="1" // 11^done,value="0x7fffffffd538" QWidget* w = tabWidget->currentWidget(); if (w) { static_cast(w)->sourceArea()->handleText(text); } SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." QWidget* w = tabWidget->currentWidget(); if (w) { static_cast(w)->sourceArea()->handleText(text); } }else if (text.startsWith("*running")) { // target / program is running, should erase 'yellow' color is for the current line // _lastFrameList is invoked to erase previously "colored" line for ( const auto& frame_text : _lastFrameList ) { QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); SeerEditorManagerEntries::iterator i = findEntry(fullname_text); SeerEditorManagerEntries::iterator e = endEntry(); if (i != e) { i->widget->sourceArea()->eraseColorCurrentLine(line_text.toInt()); } } }else if ( text.contains(QRegularExpression("^([0-9]+)\\^done,symbols={"))) { if (text.startsWith(QString::number(_idTypeDefinition) + "^done,symbols={") || text.startsWith(QString::number(_idFunctionDefinition) + "^done,symbols={") || text.startsWith(QString::number(_idVariableDefinition) + "^done,symbols={")) { // Handle Go to Definition //^10done,symbols={debug=[{filename=" ",fullname=" ", // symbols=[{line=" ",name="uwTick",type="volatile uint32_t",description="volatile uint32_t uwTick;"},}]}] QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false); QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false); for (const auto& filename_entry : filenames_list) { QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false); QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false); QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false); QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false); for (const auto& symbol_entry : symbols_list) { QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false); QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false); // name_text may be st like: function_name(params...) , so only extract function_name part name_text = name_text.section('(', 0, 0).trimmed(); if (name_text == _gotoDefIdentifier) { // you found it! Open file handleOpenFile(filename_text, fullname_text, line_text.toInt()); } } } } }else{ // Ignore others. return; } } void SeerEditorManagerWidget::handleTabCloseRequested (int index) { //qDebug() << index << tabWidget->count() << tabWidget->tabText(0); // If it is the place holder, don't delete it. if (tabWidget->tabText(index) == "") { return; } // Push to _stackClosedFiles before deleting QString fullname = tabWidget->tabToolTip(index).section(" : ", 1, 1); if (fullname != "") { // Don't push place holder or Assembly tab SeerEditorManagerEntries::iterator i = findEntry(fullname); SeerEditorWidgetSourceArea::SeerCurrentFile current = i->widget->sourceArea()->readCurrentPosition(); _stackClosedFiles.push(current); } // Delete the tab. deleteEditorWidgetTab(index); // If there are no tabs left, create a place holder. if (tabWidget->count() == 0) { createEditorWidgetTab("", ""); } } void SeerEditorManagerWidget::handleTabCurrentChanged (int index) { if (_notifyAssemblyTabShown == false) { return; } if (tabWidget->tabText(index) == "Assembly") { emit assemblyTabShown(true); }else{ emit assemblyTabShown(false); } } void SeerEditorManagerWidget::handleOpenFile (const QString& file, const QString& fullname, int lineno) { // Open file and scroll to lineno handleOpenFileWithDetails(file, fullname, lineno, 0, 0); } void SeerEditorManagerWidget::handleOpenFileWithDetails (const QString& file, const QString& fullname, int cursorRow, int cursorCol, int firstDisplayLine) { // Must have a valid filename. if (file == "" || fullname == "") { return; } // Get the EditorWidget for the file. Create one if needed. SeerEditorWidgetSource* editorWidget = editorWidgetTab(fullname); if (editorWidget == 0) { editorWidget = createEditorWidgetTab(fullname, file); } // Can still be null, if the file is ignored. if (editorWidget == 0) { return; } // Push this tab to the top only if the current one in not the "Assembly" tab. QString tabtext = ""; if (tabWidget->currentIndex() >= 0) { tabtext = tabWidget->tabText(tabWidget->currentIndex()); } if (keepAssemblyTabOnTop() && tabtext == "Assembly") { // Do nothing. The "Assembly" tab is already on top. }else{ tabWidget->setCurrentWidget(editorWidget); } if (firstDisplayLine > 0) { // firstDisplayLine is always > 0 // this means the function is handling open closed files, set cursor position and first display line QPlainTextEdit* textEdit = editorWidget->sourceArea(); // Create a small helper lambda that does the actual restoration auto restoreView = [textEdit, cursorRow, cursorCol, firstDisplayLine, this]() { QTextDocument* doc = textEdit->document(); int lineIndex = cursorRow - 1; // 0-based if (lineIndex >= doc->lineCount()) { return; } QTextBlock block = doc->findBlockByLineNumber(lineIndex); if (!block.isValid()) { return; } QTextCursor cursor(block); cursor.setPosition(block.position() + qMax(0, cursorCol - 1)); textEdit->setTextCursor(cursor); if (firstDisplayLine > 0) { QScrollBar* sb = textEdit->verticalScrollBar(); sb->setValue(firstDisplayLine * sb->singleStep() - sb->singleStep()/2 - 1); } }; QTimer::singleShot(0, textEdit, restoreView); } else { // otherwise, just open file and scroll to cursorRow if (cursorRow > 0) { editorWidget->sourceArea()->scrollToLine(cursorRow); } } handleAddToMouseNavigation({file, fullname, cursorRow, 1, editorWidget->sourceArea()->firstDisplayLine()}); // Ask for the breakpoint list to be resent, in case this file has breakpoints. emit refreshBreakpointsList(); // Ask for the stackframe list to be resent, in case this file has currently executing lines. emit refreshStackFrames(); } void SeerEditorManagerWidget::handleOpenAddress (const QString& address) { // Must have a valid address. if (address == "") { return; } // Get the AssemblyWidget so the address can be loaded. Return if there is no widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); // Create assembly widget, if allowed. if (assemblyWidget == 0) { assemblyWidget = createAssemblyWidgetTab(); } // No assembly widget, return. if (assemblyWidget == 0) { return; } // Update assembly widget. assemblyWidget->assemblyArea()->setAddress(address); assemblyWidget->reloadRegisters(); } void SeerEditorManagerWidget::handleMaybeOpenAddress (const QString& file, const QString& fullname, const QString& address) { // Must have a valid address. if (address == "") { return; } // Don't open the assembly tab if told not to. if (showAssemblyTabOnStartupMode() == "never") { return; } // Open the assembly tab. if (showAssemblyTabOnStartupMode() == "always") { handleOpenAddress(address); return; } // If the mode is 'auto', open the assembly tab if there's no source file for the address. if (showAssemblyTabOnStartupMode() == "auto") { if (file != "" && fullname != "") { return; } handleOpenAddress(address); } } SeerEditorWidgetSource* SeerEditorManagerWidget::currentEditorWidgetTab () { QWidget* w = tabWidget->currentWidget(); if (w == 0) { return 0; } return dynamic_cast(w); } SeerEditorWidgetSource* SeerEditorManagerWidget::editorWidgetTab (const QString& fullname) { // Do we have an entry for 'fullname'? SeerEditorManagerEntries::iterator i = findEntry(fullname); if (i == endEntry()) { return 0; } // Return the editor widget. return i->widget; } SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QString& fullname, const QString& file, const QString& text) { //qDebug() << "1:" << fullname << file << tabWidget->count() << tabWidget->tabText(0); //dumpEntries(); // Are we asked to ignore this file? if (Seer::matchesWildcard(editorIgnoreDirectories(), fullname) == true) { emit showMessage(QString("Ignored opening of: '%1'").arg(fullname), 3000); return 0; } // Remove the place holder tab, if present. if (tabWidget->count() == 1 && tabWidget->tabText(0) == "") { deleteEditorWidgetTab(0); } // Create the Editor widget and add it to the tab. SeerEditorWidgetSource* editorWidget = new SeerEditorWidgetSource(this); editorWidget->sourceArea()->setEditorFont(editorFont()); editorWidget->sourceArea()->setEditorTabSize(editorTabSize()); editorWidget->sourceArea()->setExternalEditorCommand(editorExternalEditorCommand()); editorWidget->sourceArea()->setAutoSourceReload(editorAutoSourceReload()); editorWidget->sourceArea()->setHighlighterSettings(editorHighlighterSettings()); editorWidget->sourceArea()->setHighlighterEnabled(editorHighlighterEnabled()); editorWidget->sourceArea()->setAlternateDirectories(editorAlternateDirectories()); editorWidget->setKeySettings(editorKeySettings()); // Set the tooltip for the tab. int tabno = tabWidget->addTab(editorWidget, QFileInfo(file).fileName()); tabWidget->setTabToolTip(tabno, QFileInfo(file).fileName() + " : " + fullname); // Connect signals. QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::insertBreakpoint, this, &SeerEditorManagerWidget::handleInsertBreakpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::insertPrintpoint, this, &SeerEditorManagerWidget::handleInsertPrintpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::deleteBreakpoints, this, &SeerEditorManagerWidget::handleDeleteBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::enableBreakpoints, this, &SeerEditorManagerWidget::handleEnableBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::disableBreakpoints, this, &SeerEditorManagerWidget::handleDisableBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::infoBreakpoint, this, &SeerEditorManagerWidget::handleInfoBreakpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::refreshBreakpointsStackFrames, this, &SeerEditorManagerWidget::handleRefreshBreakpointsStackFrames); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::runToLine, this, &SeerEditorManagerWidget::handleRunToLine); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addVariableLoggerExpression, this, &SeerEditorManagerWidget::handleAddVariableLoggerExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addVariableTrackerExpression, this, &SeerEditorManagerWidget::handleAddVariableTrackerExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::refreshVariableTrackerValues, this, &SeerEditorManagerWidget::handleRefreshVariableTrackerValues); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::evaluateVariableExpression, this, &SeerEditorManagerWidget::handleEvaluateVariableExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMemoryVisualizer, this, &SeerEditorManagerWidget::handleAddMemoryVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addArrayVisualizer, this, &SeerEditorManagerWidget::handleAddArrayVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer); QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addToMouseNavigation, this, &SeerEditorManagerWidget::handleAddToMouseNavigation); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::signalGotoDefinition, this, &SeerEditorManagerWidget::gotoDefinitionForwarder); // Send the Editor widget the command to load the file. ??? Do better than this. editorWidget->sourceArea()->handleText(text); // Add an entry to our table. SeerEditorManagerEntries::iterator i = addEntry(fullname, QFileInfo(file).fileName()); i->widget = editorWidget; // Return the editor widget. return i->widget; } SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QString& fullname, const QString& file) { //qDebug() << "2:" << fullname << file << tabWidget->count() << tabWidget->tabText(0); //dumpEntries(); // Are we asked to ignore this file? if (Seer::matchesWildcard(editorIgnoreDirectories(), fullname) == true) { emit showMessage(QString("Ignored opening of: '%1'").arg(fullname), 3000); return 0; } // Remove the place holder tab, if present. if (tabWidget->count() == 1 && tabWidget->tabText(0) == "") { deleteEditorWidgetTab(0); } // Create the Editor widget and add it to the tab. SeerEditorWidgetSource* editorWidget = new SeerEditorWidgetSource(this); editorWidget->sourceArea()->setEditorFont(editorFont()); editorWidget->sourceArea()->setEditorTabSize(editorTabSize()); editorWidget->sourceArea()->setExternalEditorCommand(editorExternalEditorCommand()); editorWidget->sourceArea()->setAutoSourceReload(editorAutoSourceReload()); editorWidget->sourceArea()->setHighlighterSettings(editorHighlighterSettings()); editorWidget->sourceArea()->setHighlighterEnabled(editorHighlighterEnabled()); editorWidget->sourceArea()->setAlternateDirectories(editorAlternateDirectories()); editorWidget->setKeySettings(editorKeySettings()); // Set the tooltip for the tab. int tabno = tabWidget->addTab(editorWidget, QFileInfo(file).fileName()); tabWidget->setTabToolTip(tabno, QFileInfo(file).fileName() + " : " + fullname); // Connect signals. QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::insertBreakpoint, this, &SeerEditorManagerWidget::handleInsertBreakpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::insertPrintpoint, this, &SeerEditorManagerWidget::handleInsertPrintpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::deleteBreakpoints, this, &SeerEditorManagerWidget::handleDeleteBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::enableBreakpoints, this, &SeerEditorManagerWidget::handleEnableBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::disableBreakpoints, this, &SeerEditorManagerWidget::handleDisableBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::infoBreakpoint, this, &SeerEditorManagerWidget::handleInfoBreakpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::refreshBreakpointsStackFrames, this, &SeerEditorManagerWidget::handleRefreshBreakpointsStackFrames); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::runToLine, this, &SeerEditorManagerWidget::handleRunToLine); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addVariableLoggerExpression, this, &SeerEditorManagerWidget::handleAddVariableLoggerExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addVariableTrackerExpression, this, &SeerEditorManagerWidget::handleAddVariableTrackerExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::refreshVariableTrackerValues, this, &SeerEditorManagerWidget::handleRefreshVariableTrackerValues); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::evaluateVariableExpression, this, &SeerEditorManagerWidget::handleEvaluateVariableExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMemoryVisualizer, this, &SeerEditorManagerWidget::handleAddMemoryVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addArrayVisualizer, this, &SeerEditorManagerWidget::handleAddArrayVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer); QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addToMouseNavigation, this, &SeerEditorManagerWidget::handleAddToMouseNavigation); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::signalGotoDefinition, this, &SeerEditorManagerWidget::gotoDefinitionForwarder); // Load the file. editorWidget->sourceArea()->open(fullname, QFileInfo(file).fileName()); // Add an entry to our table. SeerEditorManagerEntries::iterator i = addEntry(fullname, QFileInfo(file).fileName()); i->widget = editorWidget; // Return the editor widget. return i->widget; } void SeerEditorManagerWidget::deleteEditorWidgetTab (int index) { //qDebug() << index << tabWidget->count() << tabWidget->tabText(index); // Get the editor widget. Try as a SeerEditorWidgetSource. SeerEditorWidgetSource* editorWidget = dynamic_cast(tabWidget->widget(index)); if (editorWidget != 0) { // Look for the matching entry for the EditorWidget. // If found, delete it and clean up the map. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { if (editorWidget == b->widget) { deleteEntry(b); // Delete the entry from the map. tabWidget->removeTab(index); // Remove the tab. delete editorWidget; // Delete the actual EditorWidget break; } b++; } return; } // Get the editor widget. Try as a SeerEditorWidgetAssembly. SeerEditorWidgetAssembly* assemblyWidget = dynamic_cast(tabWidget->widget(index)); if (assemblyWidget != 0) { deleteAssemblyWidgetTab(); return; } } SeerEditorWidgetAssembly* SeerEditorManagerWidget::createAssemblyWidgetTab () { // Does it already exist? if (assemblyWidgetTab() != 0) { return assemblyWidgetTab(); } //qDebug() << tabWidget->count() << tabWidget->tabText(0); // Remove the place holder tab, if present. if (tabWidget->count() == 1 && tabWidget->tabText(0) == "") { deleteEditorWidgetTab(0); } // Create the Editor widget and add it to the tab. // Raise it to the top. SeerEditorWidgetAssembly* assemblyWidget = new SeerEditorWidgetAssembly(this); assemblyWidget->assemblyArea()->setEditorFont(editorFont()); assemblyWidget->assemblyArea()->setEditorTabSize(editorTabSize()); assemblyWidget->assemblyArea()->setHighlighterSettings(editorHighlighterSettings()); assemblyWidget->assemblyArea()->setHighlighterEnabled(editorHighlighterEnabled()); assemblyWidget->setShowAddressColumn(assemblyShowAddressColumn()); assemblyWidget->setShowOffsetColumn(assemblyShowOffsetColumn()); assemblyWidget->setShowOpcodeColumn(assemblyShowOpcodeColumn()); assemblyWidget->setShowSourceLines(assemblyShowSourceLines()); _assemblyIndex= tabWidget->addTab(assemblyWidget, "Assembly"); tabWidget->setCurrentWidget(assemblyWidget); // Set the tooltip for the tab. tabWidget->setTabToolTip(_assemblyIndex, "Assembly"); // Connect signals. QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::insertBreakpoint, this, &SeerEditorManagerWidget::handleInsertBreakpoint); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::deleteBreakpoints, this, &SeerEditorManagerWidget::handleDeleteBreakpoints); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::enableBreakpoints, this, &SeerEditorManagerWidget::handleEnableBreakpoints); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::disableBreakpoints, this, &SeerEditorManagerWidget::handleDisableBreakpoints); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::refreshBreakpointsStackFrames, this, &SeerEditorManagerWidget::handleRefreshBreakpointsStackFrames); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::runToAddress, this, &SeerEditorManagerWidget::handleRunToAddress); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::requestAssembly, this, &SeerEditorManagerWidget::handleRequestAssembly); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::requestSourceAndAssembly, this, &SeerEditorManagerWidget::handleRequestSourceAndAssembly); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::addMemoryVisualizer, this, &SeerEditorManagerWidget::handleAddMemoryVisualizer); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::addArrayVisualizer, this, &SeerEditorManagerWidget::handleAddArrayVisualizer); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer); QObject::connect(assemblyWidget, &SeerEditorWidgetAssembly::evaluateVariableExpression, this, &SeerEditorManagerWidget::handleEvaluateVariableExpression); // Load the file. assemblyWidget->assemblyArea()->setPlainText(""); // Add an entry to our table. _assemblyWidget = assemblyWidget; // Send a signal to enable the Nexti/Stepi buttons. emit assemblyTabShown(true); // Return the editor widget. return assemblyWidget; } void SeerEditorManagerWidget::deleteAssemblyWidgetTab () { if (_assemblyWidget == 0) { return; } //qDebug() << "Delete AssemblyWidget"; tabWidget->removeTab(_assemblyIndex); // Remove the tab. delete _assemblyWidget; // Delete the actual EditorWidget _assemblyWidget = 0; // Send a signal to disable the Nexti/Stepi buttons. if (_notifyAssemblyTabShown) { emit assemblyTabShown(false); } } void SeerEditorManagerWidget::handleFileOpenToolButtonClicked () { QString filename = QFileDialog::getOpenFileName(this, tr("Open Source File"), "./", tr("Source files (*.*)"), nullptr, QFileDialog::DontUseNativeDialog); if (filename == "") { return; } QFileInfo info(filename); info.makeAbsolute(); handleOpenFile(info.fileName(), info.filePath(), 0); } void SeerEditorManagerWidget::handleFileCloseToolButtonClicked () { SeerCloseSourceDialog dlg(this); dlg.setFiles(openedFiles()); int ret = dlg.exec(); if (ret == 0) { return; } SeerEditorManagerFiles files = dlg.selectedFiles(); for (int i=0; iindexOf(w); if (idx < 0) { qWarning() << "Can't find tab index for:" << files[i].fullname; continue; } deleteEditorWidgetTab(idx); } // If there are no tabs left, create a place holder. if (tabWidget->count() == 0) { createEditorWidgetTab("", ""); } } void SeerEditorManagerWidget::handleTextSearchToolButtonClicked () { QWidget* tab = tabWidget->currentWidget(); SeerEditorWidgetSource* sourcew = dynamic_cast(tab); if (sourcew != 0) { if (sourcew->isSearchBarShown() == true) { sourcew->showSearchBar(false); }else{ sourcew->showSearchBar(true); } return; } SeerEditorWidgetAssembly* assemblyw = dynamic_cast(tab); if (assemblyw != 0) { if (assemblyw->isSearchBarShown() == true) { assemblyw->showSearchBar(false); }else{ assemblyw->showSearchBar(true); } return; } } void SeerEditorManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/CodeManager.md"); help->show(); help->raise(); } void SeerEditorManagerWidget::handleAddAlternateDirectory (QString path) { // Don't re-add it if it already exists in the list. if (_editorAlternateDirectories.contains(path) == true) { QMessageBox::warning(this, "Note.", "The directory '" + path +"' is already in the alternate directories list."); return; } // Add the new path to our list. _editorAlternateDirectories << path; // Update any open editors. Future editors will get the updated list normally. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setAlternateDirectories(_editorAlternateDirectories); b++; } QMessageBox::information(this, "Note.", "Added '" + path +"' to the alternate directories list."); } void SeerEditorManagerWidget::handleInsertBreakpoint (QString breakpoint) { // rethrow emit insertBreakpoint (breakpoint); } void SeerEditorManagerWidget::handleInsertPrintpoint (QString type, QString function, QString channel, QString parameters) { // rethrow emit insertPrintpoint (type, function, channel, parameters); } void SeerEditorManagerWidget::handleDeleteBreakpoints (QString breakpoints) { // rethrow emit deleteBreakpoints (breakpoints); } void SeerEditorManagerWidget::handleEnableBreakpoints (QString breakpoints) { // rethrow emit enableBreakpoints (breakpoints); } void SeerEditorManagerWidget::handleDisableBreakpoints (QString breakpoints) { // rethrow emit disableBreakpoints (breakpoints); } void SeerEditorManagerWidget::handleInfoBreakpoint (int breakpointid, QString breakpoint) { // rethrow emit infoBreakpoint (breakpointid, breakpoint); } void SeerEditorManagerWidget::handleRefreshBreakpointsStackFrames () { // Ask for the breakpoint list to be resent, in case files have breakpoints. emit refreshBreakpointsList(); // Ask for the stackframe list to be resent, in case files have currently executing lines. emit refreshStackFrames(); } void SeerEditorManagerWidget::handleRunToLine (QString fullname, int lineno) { // rethrow emit runToLine (fullname, lineno); } void SeerEditorManagerWidget::handleRunToAddress (QString address) { // rethrow if (address != "") { emit runToAddress (address); } } void SeerEditorManagerWidget::handleRunToSelectedLine () { SeerEditorWidgetSource* sourceTab = currentEditorWidgetTab(); SeerEditorWidgetAssembly* assemblyTab = assemblyWidgetTab(); if (sourceTab) { emit runToLine (sourceTab->sourceArea()->fullname(), sourceTab->sourceArea()->currentLine()); } if (assemblyTab) { QString address = assemblyTab->assemblyArea()->currentLine(); if (address != "") { emit runToAddress (address); } } } void SeerEditorManagerWidget::handleAddVariableLoggerExpression (QString expression) { // rethrow emit addVariableLoggerExpression (expression); } void SeerEditorManagerWidget::handleAddVariableTrackerExpression (QString expression) { // rethrow emit addVariableTrackerExpression (expression); } void SeerEditorManagerWidget::handleRefreshVariableTrackerValues () { // rethrow emit refreshVariableTrackerValues (); } void SeerEditorManagerWidget::handleEvaluateVariableExpression (int expressionid, QString expression) { // rethrow emit evaluateVariableExpression (expressionid, expression); } void SeerEditorManagerWidget::handleAddMemoryVisualizer (QString expression) { // rethrow emit addMemoryVisualizer (expression); } void SeerEditorManagerWidget::handleAddArrayVisualizer (QString expression) { // rethrow emit addArrayVisualizer (expression); } void SeerEditorManagerWidget::handleAddMatrixVisualizer (QString expression) { // rethrow emit addMatrixVisualizer (expression); } void SeerEditorManagerWidget::handleAddStructVisualizer (QString expression) { // rethrow emit addStructVisualizer (expression); } void SeerEditorManagerWidget::handleRequestAssembly (QString address) { // rethrow emit requestAssembly (address); // Ask for the stackframe list to be resent, this will highlight current line when the // assembly tab is shown for the first time. emit refreshStackFrames(); } void SeerEditorManagerWidget::handleRequestSourceAndAssembly (QString address) { // rethrow emit requestSourceAndAssembly (address); // Ask for the stackframe list to be resent, this will highlight current line when the // assembly tab is shown for the first time. emit refreshStackFrames(); } void SeerEditorManagerWidget::handleAssemblyConfigChanged () { // Tell the assembly tab to refresh. if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->reloadAssembly(); } } void SeerEditorManagerWidget::handleSessionTerminated () { // Clear current editors. for (auto entry : entries()) { entry.widget->sourceArea()->clearCurrentLines(); } // Clear assembly editor. if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->assemblyArea()->clearCurrentLines(); } } // Clear the stack of recently closed files backward/forward list whenever a new gdb session starts void SeerEditorManagerWidget::handleGdbStateChanged() { while (!_stackClosedFiles.empty()) { _stackClosedFiles.pop(); } _listForwardFiles.clear(); _forwardFilesIndex = -1; } /*********************************************************************************************************************** * Function for handling mouse navigation **********************************************************************************************************************/ void SeerEditorManagerWidget::handleAddToMouseNavigation(const SeerEditorWidgetSourceArea::SeerCurrentFile& currentFile) { // Record this file in the forward list. if (currentFile.file != "") { // Check if the last added file is the same as currentFile if (!_listForwardFiles.empty()) { const SeerEditorWidgetSourceArea::SeerCurrentFile& lastFile = _listForwardFiles[_listForwardFiles.size() -1]; if (currentFile == lastFile) { return; } } // if _forwardFilesIndex is at the end of the list, just append if (_forwardFilesIndex >= _listForwardFiles.size() - 1) { _listForwardFiles.append(currentFile); _forwardFilesIndex ++; } else // else remove all entries after _forwardFilesIndex and then append { int removeCount = _listForwardFiles.size() - 1 - _forwardFilesIndex; if ((currentFile == _listForwardFiles[_listForwardFiles.size() -1]) || (currentFile == _listForwardFiles[0]) || (currentFile == _listForwardFiles[_listForwardFiles.size() - 1 - removeCount]) ) { return; } for (int i=0; i < removeCount; i++) { _listForwardFiles.removeLast(); } _listForwardFiles.append(currentFile); _forwardFilesIndex = _listForwardFiles.size() -1; } } } void SeerEditorManagerWidget::handleOpenForwardBackward(const SeerEditorWidgetSourceArea::SeerCurrentFile& fileInfo) { // Get the EditorWidget for the file. Create one if needed. SeerEditorWidgetSource* editorWidget = editorWidgetTab(fileInfo.fullname); if (editorWidget == 0) { editorWidget = createEditorWidgetTab(fileInfo.fullname, fileInfo.file); } // Can still be null, if the file is ignored. if (editorWidget == 0) { return; } // Push this tab to the top only if the current one in not the "Assembly" tab. QString tabtext = ""; if (tabWidget->currentIndex() >= 0) { tabtext = tabWidget->tabText(tabWidget->currentIndex()); } if (keepAssemblyTabOnTop() && tabtext == "Assembly") { // Do nothing. The "Assembly" tab is already on top. }else{ tabWidget->setCurrentWidget(editorWidget); } if (fileInfo.firstDisplayLine > 0) { // scroll to the previous first display line QScrollBar *scrollBar = editorWidget->sourceArea()->verticalScrollBar(); int step = scrollBar->singleStep(); scrollBar->setValue(fileInfo.firstDisplayLine * step - 1); // Set cursor position QTextBlock block = editorWidget->sourceArea()->document()->findBlockByLineNumber(fileInfo.cursorRow-1); QTextCursor cursor = editorWidget->sourceArea()->textCursor(); cursor.setPosition(block.position() + fileInfo.cursorCol - 1); editorWidget->sourceArea()->setTextCursor(cursor); } } // Handle mouse press events for navigation void SeerEditorManagerWidget::mousePressEvent(QMouseEvent *event) { // Back button (XButton1) clicked if (event->button() == Qt::XButton1) { if (_forwardFilesIndex - 1 < 0) return; --_forwardFilesIndex; const SeerEditorWidgetSourceArea::SeerCurrentFile &info = _listForwardFiles.at(_forwardFilesIndex); handleOpenForwardBackward(info); } // Forward button (XButton2) clicked else if (event->button() == Qt::XButton2) { if (_forwardFilesIndex + 1 > _listForwardFiles.size() - 1) return; ++ _forwardFilesIndex; const SeerEditorWidgetSourceArea::SeerCurrentFile &info = _listForwardFiles.at(_forwardFilesIndex); handleOpenForwardBackward(info); } else { QWidget::mousePressEvent(event); } } /*********************************************************************************************************************** * Functions for handling tracing identifier * **********************************************************************************************************************/ void SeerEditorManagerWidget::gotoDefinitionForwarder(const QString& identifier) { _gotoDefIdentifier = identifier; // Ask for identifier matches for Functions, Variables, and Types. // // Sometimes symbols have or don't have arguments. // Searching for: "^functionName(.*)$" "^functionName$". // Searching for: "^functionName$". // emit refreshFunctionList(_idFunctionDefinition, "^" + _gotoDefIdentifier + "$"); emit refreshFunctionList(_idFunctionDefinition, "^" + _gotoDefIdentifier + "\\(.*\\)$"); emit refreshVariableList(_idVariableDefinition, _gotoDefIdentifier, ""); emit refreshTypeList(_idTypeDefinition, _gotoDefIdentifier); } seer-2.7/src/SeerEditorManagerWidget.h000066400000000000000000000404161516472651200200020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerEditorWidgetAssembly.h" #include "SeerEditorManagerEntry.h" #include "SeerHighlighterSettings.h" #include "SeerKeySettings.h" #include #include #include #include #include #include #include "ui_SeerEditorManagerWidget.h" class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerWidgetForm { Q_OBJECT public: explicit SeerEditorManagerWidget (QWidget* parent = 0); ~SeerEditorManagerWidget (); void dumpEntries () const; SeerEditorManagerEntries& entries (); const SeerEditorManagerEntries& entries () const; bool hasEntry (const QString& fullname) const; SeerEditorManagerEntries::iterator addEntry (const QString& fullname, const QString& file); SeerEditorManagerEntries::iterator findEntry (const QString& fullname); SeerEditorManagerEntries::const_iterator findEntry (const QString& fullname) const; SeerEditorManagerEntries::iterator beginEntry (); SeerEditorManagerEntries::const_iterator beginEntry () const; SeerEditorManagerEntries::iterator endEntry (); SeerEditorManagerEntries::const_iterator endEntry () const; void deleteEntry (SeerEditorManagerEntries::iterator i); void maybeShowAssembly (); void showAssembly (); SeerEditorWidgetAssembly* assemblyWidgetTab (); void setKeepAssemblyTabOnTop (bool flag); bool keepAssemblyTabOnTop () const; void setShowAssemblyTabOnStartupMode (const QString& mode); QString showAssemblyTabOnStartupMode () const; void setAssemblyShowAddressColumn (bool flag); bool assemblyShowAddressColumn () const; void setAssemblyShowOffsetColumn (bool flag); bool assemblyShowOffsetColumn () const; void setAssemblyShowOpcodeColumn (bool flag); bool assemblyShowOpcodeColumn () const; void setAssemblyShowSourceLines (bool flag); bool assemblyShowSourceLines () const; SeerEditorManagerFiles openedFiles () const; void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& editorHighlighterSettings () const; void setEditorHighlighterEnabled (bool flag); bool editorHighlighterEnabled () const; void setEditorAlternateDirectories (const QStringList alternateDirectories); const QStringList& editorAlternateDirectories () const; void setEditorIgnoreDirectories (const QStringList ignoreDirectories); const QStringList& editorIgnoreDirectories () const; void setEditorKeySettings (const SeerKeySettings& settings); const SeerKeySettings& editorKeySettings () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setEditorExternalEditorCommand (const QString& externalEditorCommand); const QString& editorExternalEditorCommand () const; void setEditorAutoSourceReload (bool flag); bool editorAutoSourceReload () const; public slots: void handleText (const QString& text); void handleTabCloseRequested (int index); void handleTabCurrentChanged (int index); void handleOpenFile (const QString& file, const QString& fullname, int lineno); void handleOpenAddress (const QString& address); void handleMaybeOpenAddress (const QString& file, const QString& fullname, const QString& address); void handleInsertBreakpoint (QString breakpoint); void handleInsertPrintpoint (QString type, QString function, QString channel, QString parameters); void handleDeleteBreakpoints (QString breakpoints); void handleEnableBreakpoints (QString breakpoints); void handleDisableBreakpoints (QString breakpoints); void handleInfoBreakpoint (int breakpointid, QString breakpoint); void handleRefreshBreakpointsStackFrames (); void handleRunToLine (QString fullname, int lineno); void handleRunToAddress (QString address); void handleRunToSelectedLine (); void handleAddVariableLoggerExpression (QString expression); void handleAddVariableTrackerExpression (QString expression); void handleRefreshVariableTrackerValues (); void handleEvaluateVariableExpression (int expressionid, QString expression); void handleAddMemoryVisualizer (QString expression); void handleAddArrayVisualizer (QString expression); void handleAddMatrixVisualizer (QString expression); void handleAddStructVisualizer (QString expression); void handleRequestAssembly (QString address); void handleRequestSourceAndAssembly (QString address); void handleAssemblyConfigChanged (); void handleSessionTerminated (); void handleGdbStateChanged (); void handleAddToMouseNavigation (const SeerEditorWidgetSourceArea::SeerCurrentFile& currentFile); protected: void mousePressEvent (QMouseEvent *event) override; private slots: void handleFileOpenToolButtonClicked (); void handleFileCloseToolButtonClicked (); void handleTextSearchToolButtonClicked (); void handleHelpToolButtonClicked (); void handleAddAlternateDirectory (QString path); void gotoDefinitionForwarder (const QString& identifier); signals: void refreshBreakpointsList (); void refreshStackFrames (); void insertBreakpoint (QString breakpoint); void insertPrintpoint (QString type, QString function, QString channel, QString parameters); void deleteBreakpoints (QString breakpoints); void enableBreakpoints (QString breakpoints); void disableBreakpoints (QString breakpoints); void infoBreakpoint (int breakpointid, QString breakpoint); void runToLine (QString file, int lineno); void runToAddress (QString address); void addVariableLoggerExpression (QString expression); void addVariableTrackerExpression (QString expression); void refreshVariableTrackerValues (); void evaluateVariableExpression (int expressionid, QString expression); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void requestAssembly (QString address); void requestSourceAndAssembly (QString address); void showMessage (QString message, int time); void assemblyTabShown (bool shown); void gotoDefinitionForward (const QString& identifier, bool ignoreErrors = false); void refreshFunctionList (int id, const QString& functionRegex); void refreshVariableList (int id, const QString& staticNameRegex, const QString& staticTypeRegex); void refreshTypeList (int id, const QString& typeRegex); private: SeerEditorWidgetSource* currentEditorWidgetTab (); SeerEditorWidgetSource* editorWidgetTab (const QString& fullname); SeerEditorWidgetSource* createEditorWidgetTab (const QString& fullname, const QString& file, const QString& text); SeerEditorWidgetSource* createEditorWidgetTab (const QString& fullname, const QString& file); void deleteEditorWidgetTab (int index); SeerEditorWidgetAssembly* createAssemblyWidgetTab (); void deleteAssemblyWidgetTab (); void handleOpenFileWithDetails (const QString& file, const QString& fullname, int cursorRow, int cursorCol, int firstDisplayLine); void handleOpenForwardBackward (const SeerEditorWidgetSourceArea::SeerCurrentFile& fileInfo); SeerEditorManagerEntries _entries; SeerHighlighterSettings _editorHighlighterSettings; bool _editorHighlighterEnabled; QFont _editorFont; QStringList _editorAlternateDirectories; QStringList _editorIgnoreDirectories; SeerKeySettings _editorKeySettings; int _editorTabSize; QString _editorExternalEditorCommand; bool _editorAutoSourceReload; SeerEditorWidgetAssembly* _assemblyWidget; int _assemblyIndex; QString _showAssemblyTabOnStartupMode; bool _keepAssemblyTabOnTop; bool _showAddressColumn; bool _showOffsetColumn; bool _showOpcodeColumn; bool _showSourceLines; bool _notifyAssemblyTabShown; QStringList _lastFrameList; // variable for saving previous backtrace // list of recently closed files (Ctrl + Shift + T) QStack _stackClosedFiles; // list of cursor positions for mouse navigation (back/forward) QList _listForwardFiles; int _forwardFilesIndex = -1; // _id of identifier for Go to definition int _idFunctionDefinition; int _idVariableDefinition; int _idTypeDefinition; QString _gotoDefIdentifier; }; seer-2.7/src/SeerEditorManagerWidget.ui000066400000000000000000000023421516472651200201640ustar00rootroot00000000000000 SeerEditorManagerWidgetForm 0 0 854 571 Form 0 0 0 0 3 -1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
seer-2.7/src/SeerEditorWidgetAssembly.cpp000066400000000000000000000463301516472651200205430ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorWidgetAssembly.h" #include "SeerAssemblyPreferenceDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SeerEditorWidgetAssembly::SeerEditorWidgetAssembly(QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Set the widgets. assemblyArea()->show(); searchTextLineEdit->enableReturnPressedOnClear(); showSearchBar(false); // Hide the search bar. ctrl+F to show it again. setSearchMatchCase(true); // Search with case sensitivity. _textSearchShortcut = new QShortcut(QKeySequence(tr("Ctrl+F")), this); _textSearchNextShortcut = new QShortcut(QKeySequence(tr("Ctrl+G")), this); _textSearchPrevShortcut = new QShortcut(QKeySequence(tr("Ctrl+Shift+G")), this); _lineSearchShortcut = new QShortcut(QKeySequence(tr("Ctrl+L")), this); _toggleBreakpointShortcut = new QShortcut(QKeySequence(tr("Ctrl+B")), this); setKeySettings(SeerKeySettings::populate()); _pcId = Seer::createID(); _spId = Seer::createID(); _flagsId = Seer::createID(); // Clear PC, SP, and FLAGS. pcLineEdit->clear(); spLineEdit->clear(); flagsLineEdit->clear(); // Preference menu. QMenu* menu = new QMenu(); _editPreferencesAction = menu->addAction("Assembly preferences"); preferencesToolButton->setMenu(menu); preferencesToolButton->setPopupMode(QToolButton::InstantPopup); // Connect things. QObject::connect(searchTextLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetAssembly::handleSearchTextLineEdit); QObject::connect(searchTextLineEdit, &QHistoryLineEdit::escapePressed, this, &SeerEditorWidgetAssembly::handleEscapePressed); #if QT_VERSION >= 0x060900 QObject::connect(matchCaseCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleSearchTextLineEdit); #else QObject::connect(matchCaseCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleSearchTextLineEdit); #endif QObject::connect(searchDownToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::handleSearchDownToolButton); QObject::connect(searchUpToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::handleSearchUpToolButton); QObject::connect(searchLineNumberLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetAssembly::handleSearchLineNumberLineEdit); QObject::connect(searchLineNumberLineEdit, &QHistoryLineEdit::escapePressed, this, &SeerEditorWidgetAssembly::handleEscapePressed); QObject::connect(searchCloseToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::handleSearchCloseToolButton); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::reloadAssembly); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::reloadRegisters); #if QT_VERSION >= 0x060900 QObject::connect(showAddressCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleShowAddressColumn); QObject::connect(showOffsetCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleShowOffsetColumn); QObject::connect(showOpcodeCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleShowOpcodeColumn); QObject::connect(showSourceCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleShowSourceLines); #else QObject::connect(showAddressCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleShowAddressColumn); QObject::connect(showOffsetCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleShowOffsetColumn); QObject::connect(showOpcodeCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleShowOpcodeColumn); QObject::connect(showSourceCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleShowSourceLines); #endif QObject::connect(assemblyWidget, &SeerEditorWidgetAssemblyArea::showSearchBar, this, qOverload(&SeerEditorWidgetAssembly::showSearchBar)); QObject::connect(_textSearchShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleTextSearchShortcut); QObject::connect(_textSearchNextShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleSearchDownToolButton); QObject::connect(_textSearchPrevShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleSearchUpToolButton); QObject::connect(_lineSearchShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleLineSearchShortcut); QObject::connect(_toggleBreakpointShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleToggleBreakpointShortcut); QObject::connect(_editPreferencesAction, &QAction::triggered, this, &SeerEditorWidgetAssembly::handleEditPreferences); // Set defaults. setShowAddressColumn(true); setShowOffsetColumn(false); setShowOpcodeColumn(false); setShowSourceLines(false); setConvertUppercase(false); setRegiserNamePC("$pc"); setRegiserNameSP("$sp"); setRegiserNameFLAGS("$ps"); readSettings(); } SeerEditorWidgetAssembly::~SeerEditorWidgetAssembly () { } SeerEditorWidgetAssemblyArea* SeerEditorWidgetAssembly::assemblyArea () { return assemblyWidget; } const SeerEditorWidgetAssemblyArea* SeerEditorWidgetAssembly::assemblyArea () const { return assemblyWidget; } bool SeerEditorWidgetAssembly::isSearchBarShown () const { return searchBarWidget->isVisible(); } bool SeerEditorWidgetAssembly::searchMatchCase () const { return matchCaseCheckBox->isChecked(); } bool SeerEditorWidgetAssembly::showAddressColumn () const { return showAddressCheckBox->isChecked(); } bool SeerEditorWidgetAssembly::showOffsetColumn () const { return showOffsetCheckBox->isChecked(); } bool SeerEditorWidgetAssembly::showOpcodeColumn () const { return showOpcodeCheckBox->isChecked(); } bool SeerEditorWidgetAssembly::showSourceLines () const { return showSourceCheckBox->isChecked(); } QString SeerEditorWidgetAssembly::regiserNamePC () const { return _pcName; } QString SeerEditorWidgetAssembly::regiserNameFLAGS () const { return _flagsName; } QString SeerEditorWidgetAssembly::regiserNameSP () const { return _spName; } bool SeerEditorWidgetAssembly::convertUppercase () const { return assemblyArea()->convertUppercase(); } void SeerEditorWidgetAssembly::setKeySettings (const SeerKeySettings& settings) { _keySettings = settings; if (_keySettings.has("SearchText") == true) { _textSearchShortcut->setKey(_keySettings.get("SearchText")._sequence); } if (_keySettings.has("SearchTextNext") == true) { _textSearchNextShortcut->setKey(_keySettings.get("SearchTextNext")._sequence); } if (_keySettings.has("SearchTextPrev") == true) { _textSearchPrevShortcut->setKey(_keySettings.get("SearchTextPrev")._sequence); } if (_keySettings.has("ToggleBreakpoint") == true) { _toggleBreakpointShortcut->setKey(_keySettings.get("ToggleBreakpoint")._sequence); } } const SeerKeySettings& SeerEditorWidgetAssembly::keySettings () const { return _keySettings; } void SeerEditorWidgetAssembly::reloadAssembly () { QString addr = assemblyArea()->address(); assemblyArea()->setAddress(addr, true); pcLineEdit->clear(); spLineEdit->clear(); flagsLineEdit->clear(); // Get the PC, SP, and FLAGS if (regiserNamePC() != "") { emit evaluateVariableExpression(_pcId, regiserNamePC()); } if (regiserNameSP() != "") { emit evaluateVariableExpression(_spId, regiserNameSP()); } if (regiserNameFLAGS() != "") { emit evaluateVariableExpression(_flagsId, regiserNameFLAGS()); } } void SeerEditorWidgetAssembly::reloadRegisters () { pcLineEdit->clear(); spLineEdit->clear(); flagsLineEdit->clear(); // Get the PC, SP, and FLAGS if (regiserNamePC() != "") { emit evaluateVariableExpression(_pcId, regiserNamePC()); } if (regiserNameSP() != "") { emit evaluateVariableExpression(_spId, regiserNameSP()); } if (regiserNameFLAGS() != "") { emit evaluateVariableExpression(_flagsId, regiserNameFLAGS()); } } void SeerEditorWidgetAssembly::showSearchBar (bool flag) { showSearchBar(flag, ""); } void SeerEditorWidgetAssembly::showSearchBar (bool flag, QString field) { searchBarWidget->setVisible(flag); // If 'show', give the searchTextLineEdit or the searchTextLineEdit the focus. if (flag) { if (field == "text") { searchTextLineEdit->setFocus(Qt::MouseFocusReason); }else if (field == "line") { searchLineNumberLineEdit->setFocus(Qt::MouseFocusReason); }else{ searchTextLineEdit->setFocus(Qt::MouseFocusReason); } } } void SeerEditorWidgetAssembly::setSearchMatchCase (bool flag) { matchCaseCheckBox->setChecked(flag); } void SeerEditorWidgetAssembly::setShowAddressColumn (bool flag) { showAddressCheckBox->setChecked(flag); handleShowAddressColumn(); } void SeerEditorWidgetAssembly::setShowOffsetColumn (bool flag) { showOffsetCheckBox->setChecked(flag); handleShowOffsetColumn(); } void SeerEditorWidgetAssembly::setShowOpcodeColumn (bool flag) { showOpcodeCheckBox->setChecked(flag); handleShowOpcodeColumn(); } void SeerEditorWidgetAssembly::setShowSourceLines (bool flag) { showSourceCheckBox->setChecked(flag); handleShowSourceLines(); } void SeerEditorWidgetAssembly::setRegiserNamePC (const QString& name) { _pcName = name; } void SeerEditorWidgetAssembly::setRegiserNameFLAGS (const QString& name) { _flagsName = name; } void SeerEditorWidgetAssembly::setRegiserNameSP (const QString& name) { _spName = name; } void SeerEditorWidgetAssembly::setConvertUppercase (bool flag) { assemblyArea()->setConvertUppercase(flag); } void SeerEditorWidgetAssembly::handleText (const QString& text) { if (text.startsWith("*stopped")) { //qDebug() << text; // *stopped, // // reason="end-stepping-range", // // frame={addr="0x0000000000400b45", // func="main", // args=[{name="argc",value="1"},{name="argv",value="0x7fffffffd5b8"}], // file="helloworld.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp", // line="7", // arch="i386:x86-64"}, // // thread-id="1", // stopped-threads="all", // core="6" QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "frame=", '{', '}', false); if (frame_text == "") { return; } // Get the PC, SP, and FLAGS if (regiserNamePC() != "") { emit evaluateVariableExpression(_pcId, regiserNamePC()); } if (regiserNameSP() != "") { emit evaluateVariableExpression(_spId, regiserNameSP()); } if (regiserNameFLAGS() != "") { emit evaluateVariableExpression(_flagsId, regiserNameFLAGS()); } return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); if (id_text == QString::number(_pcId)) { pcLineEdit->setText(Seer::filterEscapes(value_text)); return; } if (id_text == QString::number(_spId)) { spLineEdit->setText(Seer::filterEscapes(value_text)); return; } if (id_text == QString::number(_flagsId)) { flagsLineEdit->setText(Seer::filterEscapes(value_text)); return; } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "value=", '"', '"', false); if (id_text == QString::number(_pcId)) { pcLineEdit->setText(Seer::filterEscapes(msg_text)); return; } if (id_text == QString::number(_spId)) { spLineEdit->setText(Seer::filterEscapes(msg_text)); return; } if (id_text == QString::number(_flagsId)) { flagsLineEdit->setText(Seer::filterEscapes(msg_text)); return; } }else if (text.startsWith("^error,msg=\"No registers.\"")) { // Clear PC, SP, and FLAGS. pcLineEdit->clear(); spLineEdit->clear(); flagsLineEdit->clear(); }else{ // Ignore others. } } void SeerEditorWidgetAssembly::handleSearchLineNumberLineEdit () { QString address = searchLineNumberLineEdit->text(); if (address == "") { showSearchBar(false); return; } searchLineNumberLineEdit->clear(); // Will emit the load signal, if 'address' is not already loaded. assemblyArea()->setAddress(address); assemblyArea()->setCurrentLine(address); } void SeerEditorWidgetAssembly::handleSearchTextLineEdit () { QString str = searchTextLineEdit->text(); matchesLabel->setText(""); if (str == "") { assemblyArea()->clearFindText(); showSearchBar(false); return; } int nMatches = assemblyArea()->findText(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags())); matchesLabel->setText(QString("(%1)").arg(nMatches)); } void SeerEditorWidgetAssembly::handleSearchDownToolButton () { QString str = searchTextLineEdit->text(); if (str == "") { return; } assemblyArea()->find(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags())); } void SeerEditorWidgetAssembly::handleSearchUpToolButton () { QString str = searchTextLineEdit->text(); if (str == "") { return; } assemblyArea()->find(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags()) | QTextDocument::FindBackward); } void SeerEditorWidgetAssembly::handleSearchCloseToolButton () { showSearchBar(false); } void SeerEditorWidgetAssembly::handleTextSearchShortcut () { if (isSearchBarShown() == true) { showSearchBar(false, ""); }else{ showSearchBar(true, "text"); } } void SeerEditorWidgetAssembly::handleLineSearchShortcut () { if (isSearchBarShown() == true) { showSearchBar(false, ""); }else{ showSearchBar(true, "line"); } } void SeerEditorWidgetAssembly::handleToggleBreakpointShortcut () { assemblyArea()->breakpointToggle(); } void SeerEditorWidgetAssembly::handleShowAddressColumn () { assemblyArea()->enableLineNumberArea(showAddressColumn()); } void SeerEditorWidgetAssembly::handleShowOffsetColumn () { assemblyArea()->enableOffsetArea(showOffsetColumn()); } void SeerEditorWidgetAssembly::handleShowOpcodeColumn () { assemblyArea()->enableOpcodeArea(showOpcodeColumn()); } void SeerEditorWidgetAssembly::handleShowSourceLines () { assemblyArea()->enableSourceLines(showSourceLines()); } void SeerEditorWidgetAssembly::handleEditPreferences () { // Bring up the register profile dialog. SeerAssemblyPreferenceDialog dlg(this); dlg.setRegiserNamePC(regiserNamePC()); dlg.setRegiserNameFLAGS(regiserNameFLAGS()); dlg.setRegiserNameSP(regiserNameSP()); dlg.setShowAssemblyAddress(showAddressColumn()); dlg.setShowAssemblyOffset(showOffsetColumn()); dlg.setShowAssemblyOpcode(showOpcodeColumn()); dlg.setShowAssemblySource(showSourceLines()); dlg.setConvertUppercase(convertUppercase()); if (dlg.exec()) { setRegiserNamePC(dlg.regiserNamePC()); setRegiserNameFLAGS(dlg.regiserNameFLAGS()); setRegiserNameSP(dlg.regiserNameSP()); setShowAddressColumn(dlg.showAssemblyAddress()); setShowOffsetColumn(dlg.showAssemblyOffset()); setShowOpcodeColumn(dlg.showAssemblyOpcode()); setShowSourceLines(dlg.showAssemblySource()); setConvertUppercase(dlg.convertUppercase()); reloadRegisters(); writeSettings(); } } void SeerEditorWidgetAssembly::handleEscapePressed () { showSearchBar(false, ""); } void SeerEditorWidgetAssembly::writeSettings () { QSettings settings; settings.beginGroup("assembly"); { settings.setValue("assemblyregisternamepc", regiserNamePC()); settings.setValue("assemblyregisternameflags", regiserNameFLAGS()); settings.setValue("assemblyregisternamesp", regiserNameSP()); settings.setValue("assemblyshowaddresscolumn", showAddressColumn()); settings.setValue("assemblyshowoffsetcolumn", showOffsetColumn()); settings.setValue("assemblyshowopcodecolumn", showOpcodeColumn()); settings.setValue("assemblyshowsourcelines", showSourceLines()); settings.setValue("assemblyconvertuppercase", convertUppercase()); } settings.endGroup(); } void SeerEditorWidgetAssembly::readSettings () { QSettings settings; settings.beginGroup("assembly"); { setRegiserNamePC (settings.value("assemblyregisternamepc", "$pc").toString()); setRegiserNameFLAGS (settings.value("assemblyregisternameflags", "$ps").toString()); setRegiserNameSP (settings.value("assemblyregisternamesp", "$sp").toString()); setShowAddressColumn (settings.value("assemblyshowaddresscolumn", true).toBool()); setShowOffsetColumn (settings.value("assemblyshowoffsetcolumn", false).toBool()); setShowOpcodeColumn (settings.value("assemblyshowopcodecolumn", false).toBool()); setShowSourceLines (settings.value("assemblyshowsourcelines", false).toBool()); setConvertUppercase (settings.value("assemblyconvertuppercase", false).toBool()); } settings.endGroup(); } seer-2.7/src/SeerEditorWidgetAssembly.h000066400000000000000000000511601516472651200202050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerCppSourceHighlighter.h" #include "SeerKeySettings.h" #include "SeerPlainTextEdit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class SeerEditorWidgetAssemblyLineNumberArea; class SeerEditorWidgetAssemblyOffsetArea; class SeerEditorWidgetAssemblyBreakPointArea; class SeerEditorWidgetAssemblyOpcodeArea; class SeerEditorWidgetAssemblyArea : public SeerPlainTextEdit { Q_OBJECT public: SeerEditorWidgetAssemblyArea (QWidget* parent = 0); void enableLineNumberArea (bool flag); bool lineNumberAreaEnabled () const; void enableOffsetArea (bool flag); bool offsetAreaEnabled () const; void enableBreakPointArea (bool flag); bool breakPointAreaEnabled () const; void enableOpcodeArea (bool flag); bool opcodeAreaEnabled () const; void enableSourceLines (bool flag); bool sourceLinesEnabled () const; void lineNumberAreaPaintEvent (QPaintEvent* event); int lineNumberAreaWidth (); void offsetAreaPaintEvent (QPaintEvent* event); int offsetAreaWidth (); void breakPointAreaPaintEvent (QPaintEvent* event); int breakPointAreaWidth (); void opcodeAreaPaintEvent (QPaintEvent* event); int opcodeAreaWidth (); void setAddress (const QString& address, bool force=false); const QString& address () const; bool setCurrentLine (const QString& address); const QString currentLine () const; void scrollToLine (const QString& address); void clearCurrentLines (); int findText (const QString& text, QTextDocument::FindFlags flags); void clearFindText (); void clearBreakpoints (); void addBreakpoint (int number, const QString& address, bool enabled); bool hasBreakpointNumber (int number) const; bool hasBreakpointAddress (const QString& address) const; const QVector& breakpointNumbers () const; const QVector& breakpointAddresses () const; const QVector& breakpointEnableds () const; int breakpointAddressToNumber (const QString& address) const; bool breakpointAddressEnabled (const QString& address) const; void breakpointToggle (); void showContextMenu (QMouseEvent* event); void showContextMenu (QContextMenuEvent* event); void showContextMenu (const QPoint& pos, const QPointF& globalPos); void setQuickBreakpoint (QMouseEvent* event); void setQuickRunToAddress (QMouseEvent* event); void setHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& highlighterSettings () const; void setHighlighterEnabled (bool flag); bool highlighterEnabled () const; QString sourceForLine (const QString& fullname, const QString& file, int line); void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setConvertUppercase (bool flag); bool convertUppercase () const; signals: void insertBreakpoint (QString breakpoint); void insertPrintpoint (QString printpoint); void deleteBreakpoints (QString breakpoints); void enableBreakpoints (QString breakpoints); void disableBreakpoints (QString breakpoints); void refreshBreakpointsStackFrames (); void runToAddress (QString address); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void requestAssembly (QString address); void requestSourceAndAssembly (QString address); void showSearchBar (bool flag); void highlighterSettingsChanged (); public slots: void handleText (const QString& text); void handleHighlighterSettingsChanged (); protected: void resizeEvent (QResizeEvent* event); void contextMenuEvent (QContextMenuEvent* event); private slots: void refreshExtraSelections (); void updateTextArea (); void updateMarginAreasWidth (int newBlockCount); void updateLineNumberArea (const QRect& rect, int dy); void updateOffsetArea (const QRect& rect, int dy); void updateBreakPointArea (const QRect& rect, int dy); void updateOpcodeArea (const QRect& rect, int dy); private: bool _enableLineNumberArea; bool _enableOffsetArea; bool _enableBreakPointArea; bool _enableOpcodeArea; bool _enableSourceLines; QVector _breakpointsNumbers; QVector _breakpointsAddresses; QVector _breakpointsEnableds; QList _findExtraSelections; QList _currentLinesExtraSelections; QList _sourceLinesExtraSelections; SeerEditorWidgetAssemblyLineNumberArea* _lineNumberArea; SeerEditorWidgetAssemblyOffsetArea* _offsetArea; SeerEditorWidgetAssemblyBreakPointArea* _breakPointArea; SeerEditorWidgetAssemblyOpcodeArea* _opcodeArea; SeerHighlighterSettings _sourceHighlighterSettings; bool _sourceHighlighterEnabled; QString _currentAddress; QMap _addressLineMap; QMap _offsetLineMap; QMap _lineAddressMap; QMap _lineOffsetMap; QMap _lineOpcodeMap; // Text from asm_insns command. QString _asm_insns_text; // Source lines for assembly file. QStringList _fileLines; QString _fileFullname; QString _fileName; int _sourceTabSize; bool _convertUppercase; }; class SeerEditorWidgetAssemblyLineNumberArea : public QWidget { Q_OBJECT public: SeerEditorWidgetAssemblyLineNumberArea (SeerEditorWidgetAssemblyArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetAssemblyArea* _editorWidget; }; class SeerEditorWidgetAssemblyOffsetArea : public QWidget { Q_OBJECT public: SeerEditorWidgetAssemblyOffsetArea (SeerEditorWidgetAssemblyArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetAssemblyArea* _editorWidget; }; class SeerEditorWidgetAssemblyBreakPointArea : public QWidget { Q_OBJECT public: SeerEditorWidgetAssemblyBreakPointArea (SeerEditorWidgetAssemblyArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetAssemblyArea* _editorWidget; }; class SeerEditorWidgetAssemblyOpcodeArea : public QWidget { Q_OBJECT public: SeerEditorWidgetAssemblyOpcodeArea (SeerEditorWidgetAssemblyArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetAssemblyArea* _editorWidget; }; #include "ui_SeerEditorWidgetAssembly.h" class SeerEditorWidgetAssembly : public QWidget, protected Ui::SeerEditorWidgetAssemblyForm { Q_OBJECT public: explicit SeerEditorWidgetAssembly (QWidget* parent = 0); ~SeerEditorWidgetAssembly (); SeerEditorWidgetAssemblyArea* assemblyArea (); const SeerEditorWidgetAssemblyArea* assemblyArea () const; bool isSearchBarShown () const; bool searchMatchCase () const; bool showAddressColumn () const; bool showOffsetColumn () const; bool showOpcodeColumn () const; bool showSourceLines () const; QString regiserNamePC () const; QString regiserNameFLAGS () const; QString regiserNameSP () const; bool convertUppercase () const; void setKeySettings (const SeerKeySettings& settings); const SeerKeySettings& keySettings () const; public slots: void reloadAssembly (); void reloadRegisters (); void showSearchBar (bool flag); void showSearchBar (bool flag, QString field); void setSearchMatchCase (bool flag); void setShowAddressColumn (bool flag); void setShowOffsetColumn (bool flag); void setShowOpcodeColumn (bool flag); void setShowSourceLines (bool flag); void setRegiserNamePC (const QString& name); void setRegiserNameFLAGS (const QString& name); void setRegiserNameSP (const QString& name); void setConvertUppercase (bool flag); void handleText (const QString& text); private slots: void handleSearchLineNumberLineEdit (); void handleSearchTextLineEdit (); void handleSearchDownToolButton (); void handleSearchUpToolButton (); void handleSearchCloseToolButton (); void handleTextSearchShortcut (); void handleLineSearchShortcut (); void handleToggleBreakpointShortcut (); void handleShowAddressColumn (); void handleShowOffsetColumn (); void handleShowOpcodeColumn (); void handleShowSourceLines (); void handleEditPreferences (); void handleEscapePressed (); signals: void evaluateVariableExpression (int expressionid, QString expression); protected: void writeSettings (); void readSettings (); private: int _pcId; int _spId; int _flagsId; SeerKeySettings _keySettings; QShortcut* _textSearchShortcut; QShortcut* _textSearchNextShortcut; QShortcut* _textSearchPrevShortcut; QShortcut* _lineSearchShortcut; QShortcut* _toggleBreakpointShortcut; QAction* _editPreferencesAction; QString _pcName; QString _spName; QString _flagsName; }; seer-2.7/src/SeerEditorWidgetAssembly.ui000066400000000000000000000260661516472651200204020ustar00rootroot00000000000000 SeerEditorWidgetAssemblyForm 0 0 788 574 SeerEditorWidgetAssemblyForm 0 100 PC 40 0 Program counter true Program counter FLAGS 20 0 Processor flags true Processor flags SP 20 0 Stack pointer true Stack pointer Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg 0 0 0 0 50 0 Enter text to search for. Enter search text true Match Case Search for the next occurance. ... :/seer/resources/RelaxLightIcons/go-down.svg:/seer/resources/RelaxLightIcons/go-down.svg Search for the previous occurance. ... :/seer/resources/RelaxLightIcons/go-up.svg:/seer/resources/RelaxLightIcons/go-up.svg Qt::Vertical 50 0 Scroll to a specific 0xAddress, +Offset, or line#. Go to 0xAddress, +Offset, or line#. true Qt::Vertical Close the search bar. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Refresh the Assembly view. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Show assembly address. Address Show assembly offset. Offset Show assembly opcodes. Opcode Show original source code. Source Qt::Horizontal 40 20 SeerEditorWidgetAssemblyArea QWidget
SeerEditorWidgetAssembly.h
1
QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
searchTextLineEdit matchCaseCheckBox searchDownToolButton searchUpToolButton searchLineNumberLineEdit searchCloseToolButton refreshToolButton showAddressCheckBox showOffsetCheckBox showOpcodeCheckBox showSourceCheckBox
seer-2.7/src/SeerEditorWidgetAssemblyAreas.cpp000066400000000000000000001572701516472651200215250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorWidgetAssembly.h" #include "SeerPlainTextEdit.h" #include "SeerBreakpointCreateDialog.h" #include "SeerPrintpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // // Assembly Area // SeerEditorWidgetAssemblyArea::SeerEditorWidgetAssemblyArea(QWidget* parent) : SeerPlainTextEdit(parent) { _enableLineNumberArea = false; _enableOffsetArea = false; _enableBreakPointArea = false; _enableOpcodeArea = false; _enableSourceLines = false; _sourceTabSize = 4; _convertUppercase = false; _addressLineMap.clear(); _offsetLineMap.clear(); _lineAddressMap.clear(); _lineOffsetMap.clear(); _lineOpcodeMap.clear(); QFont font("monospace"); font.setStyleHint(QFont::Monospace); setFont(font); setReadOnly(true); setTextInteractionFlags(textInteractionFlags() | Qt::TextSelectableByKeyboard); setLineWrapMode(QPlainTextEdit::NoWrap); _lineNumberArea = new SeerEditorWidgetAssemblyLineNumberArea(this); _offsetArea = new SeerEditorWidgetAssemblyOffsetArea(this); _breakPointArea = new SeerEditorWidgetAssemblyBreakPointArea(this); _opcodeArea = new SeerEditorWidgetAssemblyOpcodeArea(this); enableLineNumberArea(true); enableOffsetArea(true); enableBreakPointArea(true); enableOpcodeArea(true); enableSourceLines(true); setConvertUppercase(false); QObject::connect(this, &SeerEditorWidgetAssemblyArea::blockCountChanged, this, &SeerEditorWidgetAssemblyArea::updateMarginAreasWidth); QObject::connect(this, &SeerEditorWidgetAssemblyArea::updateRequest, this, &SeerEditorWidgetAssemblyArea::updateLineNumberArea); QObject::connect(this, &SeerEditorWidgetAssemblyArea::updateRequest, this, &SeerEditorWidgetAssemblyArea::updateOffsetArea); QObject::connect(this, &SeerEditorWidgetAssemblyArea::updateRequest, this, &SeerEditorWidgetAssemblyArea::updateBreakPointArea); QObject::connect(this, &SeerEditorWidgetAssemblyArea::updateRequest, this, &SeerEditorWidgetAssemblyArea::updateOpcodeArea); QObject::connect(this, &SeerEditorWidgetAssemblyArea::highlighterSettingsChanged, this, &SeerEditorWidgetAssemblyArea::handleHighlighterSettingsChanged); setCurrentLine(""); updateMarginAreasWidth(0); // Forward the scroll events in the various areas to the text edit. SeerPlainTextWheelEventForwarder* lineNumberAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* offsetAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* breakPointAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* opcodeAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); _lineNumberArea->installEventFilter(lineNumberAreaWheelForwarder); _offsetArea->installEventFilter(offsetAreaWheelForwarder); _breakPointArea->installEventFilter(breakPointAreaWheelForwarder); _opcodeArea->installEventFilter(opcodeAreaWheelForwarder); // Calling close() will clear the text document. close(); } void SeerEditorWidgetAssemblyArea::enableLineNumberArea (bool flag) { _enableLineNumberArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetAssemblyArea::lineNumberAreaEnabled () const { return _enableLineNumberArea; } void SeerEditorWidgetAssemblyArea::enableOffsetArea (bool flag) { _enableOffsetArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetAssemblyArea::offsetAreaEnabled () const { return _enableOffsetArea; } void SeerEditorWidgetAssemblyArea::enableBreakPointArea (bool flag) { _enableBreakPointArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetAssemblyArea::breakPointAreaEnabled () const { return _enableBreakPointArea; } void SeerEditorWidgetAssemblyArea::enableOpcodeArea (bool flag) { _enableOpcodeArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetAssemblyArea::opcodeAreaEnabled () const { return _enableOpcodeArea; } void SeerEditorWidgetAssemblyArea::enableSourceLines (bool flag) { _enableSourceLines = flag; QString addr = address(); setAddress(addr, true); } bool SeerEditorWidgetAssemblyArea::sourceLinesEnabled () const { return _enableSourceLines; } void SeerEditorWidgetAssemblyArea::updateTextArea () { // // ^done,asm_insns=[ // src_and_asm_line={ // line="72", // file="helloarray.cpp", // fullname="/home/erniep/Development/Peak/src/seer/tests/helloarray/helloarray.cpp", // line_asm_insn=[ // {address="0x000000000040093c",func-name="main()",offset="362",opcodes="bf a9 0a 40 00",inst="mov $0x400aa9,%edi"}, // {address="0x0000000000400941",func-name="main()",offset="367",opcodes="e8 3a fd ff ff",inst="call 0x400680 "} // ] // }, // src_and_asm_line={ // line="73", // file="helloarray.cpp", // fullname="/home/erniep/Development/Peak/src/seer/tests/helloarray/helloarray.cpp", // line_asm_insn=[ // ] // }, // QApplication::setOverrideCursor(Qt::BusyCursor); // Clear the existing document. document()->clear(); // Clear mappings. _addressLineMap.clear(); _offsetLineMap.clear(); _lineAddressMap.clear(); _lineOffsetMap.clear(); _lineOpcodeMap.clear(); // Clear 'source line' selections. _sourceLinesExtraSelections.clear(); // Get the list of source and assembly lines. QString asm_insns_text = Seer::parseFirst(_asm_insns_text, "asm_insns=", '[', ']', false); QStringList src_and_asm_list = Seer::parse(asm_insns_text, "src_and_asm_line=", '{', '}', false); QStringList asm_list = Seer::parse(asm_insns_text, "", '{', '}', false); if (src_and_asm_list.size() > 0) { //qDebug() << "src_and_asm_text mode."; // Loop through the asm list and print each line. int lineno = 1; for ( const auto& src_and_asm_text : src_and_asm_list ) { // Get the strings, with padding. QString line_text = Seer::parseFirst(src_and_asm_text, "line=", '"', '"', false); QString file_text = Seer::parseFirst(src_and_asm_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(src_and_asm_text, "fullname=", '"', '"', false); // Print source line? if (sourceLinesEnabled() == true) { // Get source for 'line' QString sourceLine = sourceForLine(fullname_text, file_text, line_text.toInt()); sourceLine = Seer::expandTabs(sourceLine, editorTabSize(), false); // Expand tabs. sourceLine = sourceLine.simplified(); // Remove blank spaces at front and end of line. // Write source line to the document. if (convertUppercase()) { appendPlainText(sourceLine.toUpper()); }else{ appendPlainText(sourceLine); } // Highlight it. QTextCharFormat sourceLinesFormat = highlighterSettings().get("Text"); QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); QTextEdit::ExtraSelection selection; selection.format.setForeground(sourceLinesFormat.foreground()); selection.format.setBackground(sourceLinesFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _sourceLinesExtraSelections.append(selection); lineno++; } // Get the list of assembly lines. QString asm_insns_text = Seer::parseFirst(src_and_asm_text, "line_asm_insn=", '[', ']', false); QStringList asm_list = Seer::parse(asm_insns_text, "", '{', '}', false); for ( const auto& asm_text : asm_list ) { // Get the strings, with padding. QString address_text = Seer::parseFirst(asm_text, "address=", '"', '"', false); QString funcname_text = Seer::parseFirst(asm_text, "func-name=", '"', '"', false); QString offset_num = Seer::parseFirst(asm_text, "offset=", '"', '"', false); QString opcodes_text = Seer::parseFirst(asm_text, "opcodes=", '"', '"', false); QString inst_text = Seer::parseFirst(asm_text, "inst=", '"', '"', false); inst_text = Seer::expandTabs(inst_text, editorTabSize(), true); // Expand tabs. // Write assembly line to the document. if (convertUppercase()) { appendPlainText(inst_text.toUpper()); }else{ appendPlainText(inst_text); } // Highlight it. QTextCharFormat sourceLinesFormat = highlighterSettings().get("Assembly Text"); QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); QTextEdit::ExtraSelection selection; selection.format.setForeground(sourceLinesFormat.foreground()); selection.format.setBackground(sourceLinesFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _sourceLinesExtraSelections.append(selection); // Add to maps _addressLineMap.insert(address_text.toULongLong(0,0), lineno); _offsetLineMap.insert(offset_num.toULongLong(0,0), lineno); _lineAddressMap.insert(lineno, address_text); _lineOffsetMap.insert(lineno, offset_num.toULongLong(0,0)); _lineOpcodeMap.insert(lineno, opcodes_text); lineno++; } } }else if (asm_list.size() > 0) { //qDebug() << "asm_text mode."; // Loop through the asm list and print each line. int lineno = 1; for ( const auto& asm_text : asm_list ) { // Get the strings, with padding. QString address_text = Seer::parseFirst(asm_text, "address=", '"', '"', false); QString offset_num = Seer::parseFirst(asm_text, "offset=", '"', '"', false); QString opcodes_text = Seer::parseFirst(asm_text, "opcodes=", '"', '"', false); QString inst_text = Seer::parseFirst(asm_text, "inst=", '"', '"', false); inst_text = Seer::expandTabs(inst_text, editorTabSize(), true); // Expand tabs. // Write assembly line to the document. qDebug() << "Convert to Uppercase?" << convertUppercase(); if (convertUppercase()) { appendPlainText(QString(" ") + inst_text.toUpper()); }else{ appendPlainText(QString(" ") + inst_text); } // Highlight it. QTextCharFormat sourceLinesFormat = highlighterSettings().get("Assembly Text"); QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); QTextEdit::ExtraSelection selection; selection.format.setForeground(sourceLinesFormat.foreground()); selection.format.setBackground(sourceLinesFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _sourceLinesExtraSelections.append(selection); // Add to maps _addressLineMap.insert(address_text.toULongLong(0,0), lineno); _offsetLineMap.insert(offset_num.toULongLong(0,0), lineno); _lineAddressMap.insert(lineno, address_text); _lineOffsetMap.insert(lineno, offset_num.toULongLong(0,0)); _lineOpcodeMap.insert(lineno, opcodes_text); lineno++; } }else{ qDebug() << "src_and_asm_text and asm_text are both empty."; } // Refresh all the extra selections. refreshExtraSelections(); // Move to the start of the document as a default. moveCursor(QTextCursor::Start); // Move to the line that has our address. setCurrentLine(_currentAddress); // Set the cursor back. QApplication::restoreOverrideCursor(); } void SeerEditorWidgetAssemblyArea::updateMarginAreasWidth (int newBlockCount) { Q_UNUSED(newBlockCount); int leftMarginWidth = lineNumberAreaWidth() + offsetAreaWidth() + breakPointAreaWidth() + opcodeAreaWidth(); int rightMarginWidth = 0; setViewportMargins(leftMarginWidth, 0, rightMarginWidth, 0); } int SeerEditorWidgetAssemblyArea::lineNumberAreaWidth () { if (lineNumberAreaEnabled() == false) { return 0; } int chars = 1; QMap::iterator b = _lineAddressMap.begin(); QMap::iterator e = _lineAddressMap.end(); while (b != e) { chars = qMax(chars, b->length()); b++; } int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * chars; return space; } int SeerEditorWidgetAssemblyArea::offsetAreaWidth () { if (offsetAreaEnabled() == false) { return 0; } qulonglong offset = 0; QMap::iterator b = _lineOffsetMap.begin(); QMap::iterator e = _lineOffsetMap.end(); while (b != e) { offset = qMax(offset, b.value()); b++; } QString tmp = QString("<+%1>").arg(offset); int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * tmp.length(); return space; } int SeerEditorWidgetAssemblyArea::breakPointAreaWidth () { if (breakPointAreaEnabled() == false) { return 0; } int space = 3 + 20; return space; } int SeerEditorWidgetAssemblyArea::opcodeAreaWidth () { if (opcodeAreaEnabled() == false) { return 0; } int chars = 1; QMap::iterator b = _lineOpcodeMap.begin(); QMap::iterator e = _lineOpcodeMap.end(); while (b != e) { chars = qMax(chars, b->length()); b++; } int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * chars; return space; } void SeerEditorWidgetAssemblyArea::updateLineNumberArea (const QRect& rect, int dy) { if (lineNumberAreaEnabled() == false) { return; } if (dy) { _lineNumberArea->scroll(0, dy); }else{ _lineNumberArea->update(0, rect.y(), _lineNumberArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetAssemblyArea::updateOffsetArea (const QRect& rect, int dy) { if (offsetAreaEnabled() == false) { return; } if (dy) { _offsetArea->scroll(0, dy); }else{ _offsetArea->update(0, rect.y(), _offsetArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetAssemblyArea::updateBreakPointArea (const QRect& rect, int dy) { if (breakPointAreaEnabled() == false) { return; } if (dy) { _breakPointArea->scroll(0, dy); }else{ _breakPointArea->update(0, rect.y(), _breakPointArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetAssemblyArea::updateOpcodeArea (const QRect& rect, int dy) { if (opcodeAreaEnabled() == false) { return; } if (dy) { _opcodeArea->scroll(0, dy); }else{ _opcodeArea->update(0, rect.y(), _opcodeArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetAssemblyArea::lineNumberAreaPaintEvent (QPaintEvent* event) { if (lineNumberAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_lineNumberArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString address; if (_lineAddressMap.contains(blockNumber+1)) { if (convertUppercase()) { address = _lineAddressMap[blockNumber+1].toUpper(); }else{ address = _lineAddressMap[blockNumber+1]; } } painter.drawText(0, top, _lineNumberArea->width(), fontMetrics().height(), Qt::AlignLeft, address); } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetAssemblyArea::offsetAreaPaintEvent (QPaintEvent* event) { if (offsetAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_offsetArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString offset; if (_lineOffsetMap.contains(blockNumber+1)) { offset = QString("<+%1>").arg(_lineOffsetMap[blockNumber+1]); } painter.drawText(0, top, _offsetArea->width(), fontMetrics().height(), Qt::AlignRight, offset); } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetAssemblyArea::breakPointAreaPaintEvent (QPaintEvent* event) { if (breakPointAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_breakPointArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString address = _lineAddressMap[blockNumber+1]; if (address != "" && hasBreakpointAddress(address) == true) { if (breakpointAddressEnabled(address)) { QRect rect(_breakPointArea->width() - 20, top, fontMetrics().height(), fontMetrics().height()); QPainterPath path; path.addEllipse(rect); QPointF bias = QPointF(rect.width() * .25 * 1.0, rect.height() * .25 * -1.0); QRadialGradient gradient(rect.center(), rect.width() / 2.0, rect.center() + bias); gradient.setColorAt(0.0, QColor(Qt::white)); gradient.setColorAt(0.9, QColor(Qt::red)); gradient.setColorAt(1.0, QColor(Qt::transparent)); painter.fillPath(path,QBrush(gradient)); }else{ QRect rect(_breakPointArea->width() - 20, top, fontMetrics().height(), fontMetrics().height()); QPainterPath path; path.addEllipse(rect); QPointF bias = QPointF(rect.width() * .25 * 1.0, rect.height() * .25 * -1.0); QRadialGradient gradient(rect.center(), rect.width() / 2.0, rect.center() + bias); gradient.setColorAt(0.0, QColor(Qt::white)); gradient.setColorAt(0.9, QColor(Qt::darkGray)); gradient.setColorAt(1.0, Qt::transparent); painter.fillPath(path,QBrush(gradient)); } } } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetAssemblyArea::opcodeAreaPaintEvent (QPaintEvent* event) { if (opcodeAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Assembly Text"); QPainter painter(_opcodeArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString opcode; if (_lineOpcodeMap.contains(blockNumber+1)) { if (convertUppercase()) { opcode = _lineOpcodeMap[blockNumber+1].toUpper(); }else{ opcode = _lineOpcodeMap[blockNumber+1]; } } painter.drawText(0, top, _opcodeArea->width(), fontMetrics().height(), Qt::AlignLeft, opcode); } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetAssemblyArea::resizeEvent (QResizeEvent* e) { QPlainTextEdit::resizeEvent(e); QRect cr = contentsRect(); int leftbias = 0; if (lineNumberAreaEnabled()) { _lineNumberArea->setGeometry (QRect(cr.left() + leftbias, cr.top(), lineNumberAreaWidth(), cr.height())); leftbias += lineNumberAreaWidth(); } if (offsetAreaEnabled()) { _offsetArea->setGeometry (QRect(cr.left() + leftbias, cr.top(), offsetAreaWidth(), cr.height())); leftbias += offsetAreaWidth(); } if (breakPointAreaEnabled()) { _breakPointArea->setGeometry (QRect(cr.left() + leftbias, cr.top(), breakPointAreaWidth(), cr.height())); leftbias += breakPointAreaWidth(); } if (opcodeAreaEnabled()) { _opcodeArea->setGeometry (QRect(cr.left() + leftbias, cr.top(), opcodeAreaWidth(), cr.height())); leftbias += opcodeAreaWidth(); } } void SeerEditorWidgetAssemblyArea::contextMenuEvent (QContextMenuEvent* event) { showContextMenu(event); } void SeerEditorWidgetAssemblyArea::refreshExtraSelections () { // // Merge all the extra selections into one. // // The current line(s) // The searched text. // // Create an empty list of selections. QList extraSelections; // Append the 'source lines' extra selections. extraSelections.append(_sourceLinesExtraSelections); // Append the 'current lines' extra selections. extraSelections.append(_currentLinesExtraSelections); // Append the 'searched text' extra selections. extraSelections.append(_findExtraSelections); // Give the editor the list of selections. // This will remove the old selections and select the new ones. setExtraSelections(extraSelections); } void SeerEditorWidgetAssemblyArea::setAddress (const QString& address, bool force) { // Emit the signal to load the assembly for address 'address' if // it's not already loaded. if (_addressLineMap.contains(address.toULongLong(0,0)) == false || force == true) { // Hack to keep track of address when the assembly hasn't been loaded yet. _currentAddress = address; emit requestSourceAndAssembly(address); } } const QString& SeerEditorWidgetAssemblyArea::address () const { return _currentAddress; } bool SeerEditorWidgetAssemblyArea::setCurrentLine (const QString& address) { // Clear current line selections. _currentLinesExtraSelections.clear(); // See scrollToLine(). // // Initial lineno. bool ok = false; int lineno = 0; // Try parsing as an address. if (ok == false && address.startsWith("0x") == true) { qulonglong addr = address.toULongLong(&ok, 0); // Try it as an '0x.....'. if (ok) { if (_addressLineMap.contains(addr)) { lineno = _addressLineMap[addr]; }else{ ok = false; } } } // Try parsing as an offset. if (ok == false && address.startsWith("+") == true) { qulonglong offset = address.toULongLong(&ok, 0); // Try it as an '+.....'. if (ok) { if (_offsetLineMap.contains(offset)) { lineno = _offsetLineMap[offset]; }else{ ok = false; } } } // Try parsing as an integer. if (ok == false && address.startsWith("0x") == false && address.startsWith("+") == false) { lineno = address.toInt(&ok, 10); // Try it as an 'int'. lineno == 0 on error. } // Stop if no valid lineno. if (ok == false || lineno < 1) { //qDebug() << "address is not in current assembly: '" << address << "'"; return false; } // Highlight if a valid line number is selected. QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); _currentLinesExtraSelections.clear(); QTextCharFormat currentLineFormat = highlighterSettings().get("Current Line"); QTextEdit::ExtraSelection selection; selection.format.setForeground(currentLineFormat.foreground()); selection.format.setBackground(currentLineFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _currentLinesExtraSelections.append(selection); // Scroll to the line. scrollToLine(address); // Refresh all the extra selections. refreshExtraSelections(); return true; } const QString SeerEditorWidgetAssemblyArea::currentLine () const { // Get current lineno. int lineno = textCursor().blockNumber() + 1; QString address = _lineAddressMap[lineno]; return address; } void SeerEditorWidgetAssemblyArea::scrollToLine (const QString& address) { // Just return. if (address == "") { return; } // // 'address' can be one of these forms: // // 0xdeadbeef An address // +1000 An offset // 10 A linenumber // // Test for which one and convert it to a linenumber using the maps: // // _addressLineMap // _offsetLineMap // // Or just go to the line# // // Initial lineno. bool ok = false; int lineno = 0; // Try parsing as an address. if (ok == false && address.startsWith("0x") == true) { qulonglong addr = address.toULongLong(&ok, 0); // Try it as an '0x.....'. if (ok) { if (_addressLineMap.contains(addr)) { lineno = _addressLineMap[addr]; }else{ ok = false; } } } // Try parsing as an offset. if (ok == false && address.startsWith("+") == true) { qulonglong offset = address.toULongLong(&ok, 0); // Try it as an '+.....'. if (ok) { if (_offsetLineMap.contains(offset)) { lineno = _offsetLineMap[offset]; }else{ ok = false; } } } // Try parsing as an integer. if (ok == false && address.startsWith("0x") == false && address.startsWith("+") == false) { lineno = address.toInt(&ok, 10); // Try it as an 'int'. lineno == 0 on error. } // 'address' is meaningless. Just return. if (ok == false) { if (_currentAddress == "") { // Hack when the assembly hasn't been loaded yet. QMessageBox::warning(this, "Warning.", "Address/offset '" + address + "' not found."); } return; } // Scroll to the first line if we went before it. if (lineno < 1) { lineno = 1; } // Scroll to the last line if we went past it. if (lineno > document()->blockCount()) { lineno = document()->blockCount(); } QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); centerCursor(); } void SeerEditorWidgetAssemblyArea::clearCurrentLines () { _currentLinesExtraSelections.clear(); refreshExtraSelections(); } int SeerEditorWidgetAssemblyArea::findText (const QString& text, QTextDocument::FindFlags flags) { _findExtraSelections.clear(); if (document()) { QTextCharFormat matchFormat = highlighterSettings().get("Match"); // Build a list of highlights for all matches. QTextCursor cursor(document()); cursor = document()->find(text, cursor, flags); while (cursor.isNull() == false) { QTextEdit::ExtraSelection extra; extra.format = matchFormat; extra.cursor = cursor; _findExtraSelections.append(extra); cursor = document()->find(text, cursor, flags); } // Move to the next match after out current position. find(text, flags); } refreshExtraSelections(); return _findExtraSelections.size(); } void SeerEditorWidgetAssemblyArea::clearFindText () { _findExtraSelections.clear(); refreshExtraSelections(); } void SeerEditorWidgetAssemblyArea::clearBreakpoints () { _breakpointsNumbers.clear(); _breakpointsAddresses.clear(); _breakpointsEnableds.clear(); repaint(); } void SeerEditorWidgetAssemblyArea::addBreakpoint (int number, const QString& address, bool enabled) { _breakpointsNumbers.push_back(number); _breakpointsAddresses.push_back(address); _breakpointsEnableds.push_back(enabled); repaint(); } bool SeerEditorWidgetAssemblyArea::hasBreakpointNumber (int number) const { return _breakpointsNumbers.contains(number); } bool SeerEditorWidgetAssemblyArea::hasBreakpointAddress (const QString& address) const { return _breakpointsAddresses.contains(address); } const QVector& SeerEditorWidgetAssemblyArea::breakpointNumbers () const { return _breakpointsNumbers; } const QVector& SeerEditorWidgetAssemblyArea::breakpointAddresses () const { return _breakpointsAddresses; } const QVector& SeerEditorWidgetAssemblyArea::breakpointEnableds () const { return _breakpointsEnableds; } int SeerEditorWidgetAssemblyArea::breakpointAddressToNumber (const QString& address) const { // Map address to breakpoint number. int i = _breakpointsAddresses.indexOf(address); if (i < 0) { return 0; } return _breakpointsNumbers[i]; } bool SeerEditorWidgetAssemblyArea::breakpointAddressEnabled (const QString& address) const { // Look for the address and get its index. int i = _breakpointsAddresses.indexOf(address); // Not found, return false. if (i < 0) { return false; } // Otherwise, return the proper status. return _breakpointsEnableds[i]; } void SeerEditorWidgetAssemblyArea::breakpointToggle () { // Get current lineno. int lineno = textCursor().blockNumber() + 1; QString address = _lineAddressMap[lineno]; if (address == "") { return; } // If there is a breakpoint on the line, toggle it. if (hasBreakpointAddress(address)) { // Toggle the breakpoint. // Enable if disabled. Disable if enabled. if (breakpointAddressEnabled(address) == false) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); }else{ // Emit the disable breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); } // Otherwise, do a quick create of a new breakpoint. }else{ emit insertBreakpoint(QString("-f *%1").arg(address)); } } void SeerEditorWidgetAssemblyArea::showContextMenu (QMouseEvent* event) { #if QT_VERSION >= 0x060000 showContextMenu(event->pos(), event->globalPosition()); #else showContextMenu(event->pos(), event->globalPos()); #endif } void SeerEditorWidgetAssemblyArea::showContextMenu (QContextMenuEvent* event) { showContextMenu(event->pos(), event->globalPos()); } void SeerEditorWidgetAssemblyArea::showContextMenu (const QPoint& pos, const QPointF& globalPos) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(pos); int lineno = cursor.blockNumber()+1; QString address = _lineAddressMap[lineno]; // Create the menu actions. QAction* runToAddressAction; QAction* createBreakpointAction; QAction* deleteAction; QAction* enableAction; QAction* disableAction; QAction* addMemoryAddressVisualizerAction; QAction* addArrayAddressVisualizerAction; QAction* addMatrixAddressVisualizerAction; QAction* addStructAddressVisualizerAction; // Enable/disable them depending if the breakpoint already exists. if (hasBreakpointAddress(address) == true) { int breakno = breakpointAddressToNumber(address); runToAddressAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg"), QString("Run to address %1").arg(address), this); createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint on address %1").arg(address), this); deleteAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/edit-delete.svg"), QString("Delete breakpoint %1 on address %2").arg(breakno).arg(address), this); enableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg"), QString("Enable breakpoint %1 on address %2").arg(breakno).arg(address), this); disableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg"), QString("Disable breakpoint %1 on address %2").arg(breakno).arg(address), this); runToAddressAction->setEnabled(true); createBreakpointAction->setEnabled(false); deleteAction->setEnabled(true); enableAction->setEnabled(true); disableAction->setEnabled(true); }else{ runToAddressAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg"), QString("Run to address %1").arg(address), this); createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint on address %1").arg(address), this); deleteAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/edit-delete.svg"), QString("Delete breakpoint on address %1").arg(address), this); enableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg"), QString("Enable breakpoint on address %1").arg(address), this); disableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg"), QString("Disable breakpoint on address %1").arg(address), this); runToAddressAction->setEnabled(true); createBreakpointAction->setEnabled(true); deleteAction->setEnabled(false); enableAction->setEnabled(false); disableAction->setEnabled(false); } addMemoryAddressVisualizerAction = new QAction(QString("\"%1\"").arg(textCursor().selectedText())); addArrayAddressVisualizerAction = new QAction(QString("\"%1\"").arg(textCursor().selectedText())); addMatrixAddressVisualizerAction = new QAction(QString("\"%1\"").arg(textCursor().selectedText())); addStructAddressVisualizerAction = new QAction(QString("\"%1\"").arg(textCursor().selectedText())); QMenu menu("Breakpoints", this); menu.setTitle("Breakpoints"); menu.addAction(runToAddressAction); menu.addAction(createBreakpointAction); menu.addAction(deleteAction); menu.addAction(enableAction); menu.addAction(disableAction); QMenu memoryVisualizerMenu("Add address to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryAddressVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add address to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayAddressVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add address to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixAddressVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu structVisualizerMenu("Add address to a Struct Visualizer"); structVisualizerMenu.addAction(addStructAddressVisualizerAction); menu.addMenu(&structVisualizerMenu); // Enable/disable items based on something being selected or not. if (textCursor().selectedText() == "") { addMemoryAddressVisualizerAction->setEnabled(false); addArrayAddressVisualizerAction->setEnabled(false); addMatrixAddressVisualizerAction->setEnabled(false); addStructAddressVisualizerAction->setEnabled(false); }else{ addMemoryAddressVisualizerAction->setEnabled(true); addArrayAddressVisualizerAction->setEnabled(true); addMatrixAddressVisualizerAction->setEnabled(true); addStructAddressVisualizerAction->setEnabled(true); } // Launch the menu. Get the response. QAction* action = menu.exec(globalPos.toPoint()); // Do nothing. if (action == 0) { return; } // Handle running to an address. if (action == runToAddressAction) { // Emit the runToLine signal. emit runToAddress(address); return; } // Handle creating a new breakpoint. if (action == createBreakpointAction) { SeerBreakpointCreateDialog dlg(this); dlg.setAddress(address); int ret = dlg.exec(); if (ret == 0) { return; } // Emit the create breakpoint signal. emit insertBreakpoint(dlg.breakpointText()); return; } // Handle deleting a breakpoint. if (action == deleteAction) { // Emit the delete breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); return; } // Handle enabling a breakpoint. if (action == enableAction) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); return; } // Handle disabling a breakpoint. if (action == disableAction) { // Emit the disable breakpoint signal. emit disableBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); return; } // Handle adding memory to visualize. if (action == addMemoryAddressVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMemoryVisualizer(textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addArrayAddressVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addArrayVisualizer(textCursor().selectedText()); } return; } // Handle adding matrix to visualize. if (action == addMatrixAddressVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMatrixVisualizer(textCursor().selectedText()); } return; } // Handle adding struct to visualize. if (action == addStructAddressVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addStructVisualizer(textCursor().selectedText()); } return; } } void SeerEditorWidgetAssemblyArea::setQuickBreakpoint (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; QString address = _lineAddressMap[lineno]; // If there is a breakpoint on the line, toggle it. if (hasBreakpointAddress(address)) { // Toggle the breakpoint. // Enable if disabled. Disable if enabled. if (breakpointAddressEnabled(address) == false) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); }else{ // Emit the disable breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); } // Otherwise, do a quick create of a new breakpoint. }else{ emit insertBreakpoint(QString("-f *%1").arg(address)); } } void SeerEditorWidgetAssemblyArea::setQuickRunToAddress (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; QString address = _lineAddressMap[lineno]; //qDebug() << "runToAddress" << address; // Emit the runToAddress signal. if (address != "") { emit runToAddress(address); } return; } void SeerEditorWidgetAssemblyArea::setHighlighterSettings (const SeerHighlighterSettings& settings) { _sourceHighlighterSettings = settings; emit highlighterSettingsChanged(); } const SeerHighlighterSettings& SeerEditorWidgetAssemblyArea::highlighterSettings () const { return _sourceHighlighterSettings; } void SeerEditorWidgetAssemblyArea::setHighlighterEnabled (bool flag) { _sourceHighlighterEnabled = flag; emit highlighterSettingsChanged(); } bool SeerEditorWidgetAssemblyArea::highlighterEnabled () const { return _sourceHighlighterEnabled; } QString SeerEditorWidgetAssemblyArea::sourceForLine (const QString& fullname, const QString& file, int line) { // A new file? Zap the previously cached file. if (fullname != _fileFullname || file != _fileName) { _fileLines = QStringList(); _fileFullname = ""; _fileName = ""; } // Nothing in cache? Open the file and read it. if (_fileFullname == "" || _fileName == "") { _fileFullname = fullname; _fileName = file; bool f = Seer::readFile(_fileFullname, _fileLines); if (f == false) { qDebug() << "Can't read:" << _fileFullname; } } // Return the requested line. // 'line' is 1 based. We want it to be 0 based. line --; if (line < 0 || line >= _fileLines.size()) { return ""; } return _fileLines[line]; } void SeerEditorWidgetAssemblyArea::setEditorFont (const QFont& font) { setFont(font); // See: SeerEditorSourceArea::setEditorFont() } const QFont& SeerEditorWidgetAssemblyArea::editorFont () const { return font(); } void SeerEditorWidgetAssemblyArea::setEditorTabSize (int spaces) { _sourceTabSize = spaces; } int SeerEditorWidgetAssemblyArea::editorTabSize () const { return _sourceTabSize; } void SeerEditorWidgetAssemblyArea::setConvertUppercase (bool flag) { _convertUppercase = flag; } bool SeerEditorWidgetAssemblyArea::convertUppercase () const { return _convertUppercase; } void SeerEditorWidgetAssemblyArea::handleText (const QString& text) { if (text.startsWith("*stopped")) { // *stopped, // // reason="end-stepping-range", // // frame={addr="0x0000000000400b45", // func="main", // args=[{name="argc",value="1"},{name="argv",value="0x7fffffffd5b8"}], // file="helloworld.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp", // line="7", // arch="i386:x86-64"}, // // thread-id="1", // stopped-threads="all", // core="6" QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "frame=", '{', '}', false); if (frame_text == "") { return; } QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); //qDebug() << frame_text; //qDebug() << addr_text << fullname_text << file_text << line_text; // Will emit the load signal, if 'addr_text' is not already loaded. setAddress(addr_text); // Set to the line number. setCurrentLine(addr_text); return; }else if (text.startsWith("^done,stack=[") && text.endsWith("]")) { //qDebug() << ":stack:" << text; // // See SeerStackFramesBrowserWidget.cpp // ^done,stack=[ // ... // ] // // Now parse the table and re-add the current line, if possible. QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString stack_text = Seer::parseFirst(newtext, "stack=", '[', ']', false); if (stack_text != "") { // Parse through the frame list and set the current lines that are in the frame list. QStringList frame_list = Seer::parse(newtext, "frame=", '{', '}', false); for ( const auto& frame_text : frame_list ) { QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(frame_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); QString arch_text = Seer::parseFirst(frame_text, "arch=", '"', '"', false); // If the 'addr' works for the currently loaded assembly, then stop. bool f = setCurrentLine(addr_text); if (f == true) { break; } } } }else if (text.startsWith("^done,asm_insns=")) { _asm_insns_text = text; updateTextArea(); // This function does all the work on _asm_insns_text. }else if (text.startsWith("^error,msg=\"-data-disassemble:")) { QString error_text = Seer::parseFirst(text, "msg=", '"', '"', false); QMessageBox::warning(this, "Warning.", error_text); } } void SeerEditorWidgetAssemblyArea::handleHighlighterSettingsChanged () { // Set base color for background and text color. // Use the palette to do this. Some people say to use the stylesheet. // But the palettle method works (for now). QTextCharFormat format = highlighterSettings().get("Text"); QPalette p = palette(); p.setColor(QPalette::Base, format.background().color()); p.setColor(QPalette::Text, format.foreground().color()); setPalette(p); // Note. The margins are automatically updated by their own paint events. // The new highlighter settings will be used. } // // LineNumber Area. // SeerEditorWidgetAssemblyLineNumberArea::SeerEditorWidgetAssemblyLineNumberArea(SeerEditorWidgetAssemblyArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetAssemblyLineNumberArea::sizeHint () const { return QSize(_editorWidget->lineNumberAreaWidth(), 0); } void SeerEditorWidgetAssemblyLineNumberArea::paintEvent (QPaintEvent* event) { _editorWidget->lineNumberAreaPaintEvent(event); } void SeerEditorWidgetAssemblyLineNumberArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToAddress(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetAssemblyLineNumberArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetAssemblyLineNumberArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetAssemblyLineNumberArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } // // Offset Area. // SeerEditorWidgetAssemblyOffsetArea::SeerEditorWidgetAssemblyOffsetArea(SeerEditorWidgetAssemblyArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetAssemblyOffsetArea::sizeHint () const { return QSize(_editorWidget->offsetAreaWidth(), 0); } void SeerEditorWidgetAssemblyOffsetArea::paintEvent (QPaintEvent* event) { _editorWidget->offsetAreaPaintEvent(event); } void SeerEditorWidgetAssemblyOffsetArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToAddress(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetAssemblyOffsetArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetAssemblyOffsetArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetAssemblyOffsetArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } // // Breakpoint Area. // SeerEditorWidgetAssemblyBreakPointArea::SeerEditorWidgetAssemblyBreakPointArea(SeerEditorWidgetAssemblyArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetAssemblyBreakPointArea::sizeHint () const { return QSize(_editorWidget->breakPointAreaWidth(), 0); } void SeerEditorWidgetAssemblyBreakPointArea::paintEvent (QPaintEvent* event) { _editorWidget->breakPointAreaPaintEvent(event); } void SeerEditorWidgetAssemblyBreakPointArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToAddress(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetAssemblyBreakPointArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetAssemblyBreakPointArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetAssemblyBreakPointArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } // // Opcode Area. // SeerEditorWidgetAssemblyOpcodeArea::SeerEditorWidgetAssemblyOpcodeArea(SeerEditorWidgetAssemblyArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetAssemblyOpcodeArea::sizeHint () const { return QSize(_editorWidget->opcodeAreaWidth(), 0); } void SeerEditorWidgetAssemblyOpcodeArea::paintEvent (QPaintEvent* event) { _editorWidget->opcodeAreaPaintEvent(event); } void SeerEditorWidgetAssemblyOpcodeArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToAddress(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetAssemblyOpcodeArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetAssemblyOpcodeArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetAssemblyOpcodeArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } seer-2.7/src/SeerEditorWidgetSource.cpp000066400000000000000000000337231516472651200202260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorWidgetSource.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SeerEditorWidgetSource::SeerEditorWidgetSource(QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Set the widgets. sourceArea()->show(); searchTextLineEdit->enableReturnPressedOnClear(); showSearchBar(false); // Hide the search bar. ctrl+F to show it again. showAlternateBar(false); // Hide the alternate bar. ctrl+O to show it again. showReloadBar(false); // Hide the reload file bar. Automatically shown if file gets updated. setSearchMatchCase(true); // Search with case sensitivity. _textSearchShortcut = new QShortcut(QKeySequence(tr("Ctrl+F")), this); _textSearchNextShortcut = new QShortcut(QKeySequence(tr("Ctrl+G")), this); _textSearchPrevShortcut = new QShortcut(QKeySequence(tr("Ctrl+Shift+G")), this); _textSearchReloadShortcut = new QShortcut(QKeySequence(tr("Ctrl+R")), this); _lineSearchShortcut = new QShortcut(QKeySequence(tr("Ctrl+L")), this); _alternateDirShortcut = new QShortcut(QKeySequence(tr("Ctrl+O")), this); _toggleBreakpointShortcut = new QShortcut(QKeySequence(tr("Ctrl+B")), this); _gotoDefinitionShortcut = new QShortcut(QKeySequence(tr("F12")), this); setKeySettings(SeerKeySettings::populate()); // Connect things. QObject::connect(searchTextLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetSource::handleSearchTextLineEdit); QObject::connect(searchTextLineEdit, &QHistoryLineEdit::escapePressed, this, &SeerEditorWidgetSource::handleEscapePressed); #if QT_VERSION >= 0x060900 QObject::connect(matchCaseCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetSource::handleSearchTextLineEdit); #else QObject::connect(matchCaseCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetSource::handleSearchTextLineEdit); #endif QObject::connect(searchDownToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleSearchDownToolButton); QObject::connect(searchUpToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleSearchUpToolButton); QObject::connect(searchLineNumberLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetSource::handleSearchLineNumberLineEdit); QObject::connect(searchLineNumberLineEdit, &QHistoryLineEdit::escapePressed, this, &SeerEditorWidgetSource::handleEscapePressed); QObject::connect(searchReloadToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleReloadToolButton); QObject::connect(searchCloseToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleSearchCloseToolButton); QObject::connect(alternateCloseToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleAlternateCloseToolButton); QObject::connect(alternateFileOpenToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleAlternateFileOpenToolButton); QObject::connect(alternateLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetSource::handleAlternateLineEdit); QObject::connect(reloadToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleReloadToolButton); QObject::connect(reloadCloseToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleReloadCloseToolButton); QObject::connect(sourceWidget, &SeerEditorWidgetSourceArea::showSearchBar, this, qOverload(&SeerEditorWidgetSource::showSearchBar)); QObject::connect(sourceWidget, &SeerEditorWidgetSourceArea::showAlternateBar, this, &SeerEditorWidgetSource::showAlternateBar); QObject::connect(sourceWidget, &SeerEditorWidgetSourceArea::showReloadBar, this, &SeerEditorWidgetSource::showReloadBar); QObject::connect(_textSearchShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleTextSearchShortcut); QObject::connect(_textSearchNextShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleSearchDownToolButton); QObject::connect(_textSearchPrevShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleSearchUpToolButton); QObject::connect(_textSearchReloadShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleReloadToolButton); QObject::connect(_lineSearchShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleLineSearchShortcut); QObject::connect(_alternateDirShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleAlternateDirectoryShortcut); QObject::connect(_toggleBreakpointShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleToggleBreakpointShortcut); QObject::connect(_gotoDefinitionShortcut, &QShortcut::activated, sourceArea(), &SeerEditorWidgetSourceArea::handleGotoDefinition); } SeerEditorWidgetSource::~SeerEditorWidgetSource () { } SeerEditorWidgetSourceArea* SeerEditorWidgetSource::sourceArea () { return sourceWidget; } bool SeerEditorWidgetSource::isSearchBarShown () const { return searchBarWidget->isVisible(); } bool SeerEditorWidgetSource::searchMatchCase () const { return matchCaseCheckBox->isChecked(); } bool SeerEditorWidgetSource::isAlternateBarShown () const { return alternateBarWidget->isVisible(); } void SeerEditorWidgetSource::setKeySettings (const SeerKeySettings& settings) { _keySettings = settings; if (_keySettings.has("SearchText") == true) { _textSearchShortcut->setKey(_keySettings.get("SearchText")._sequence); } if (_keySettings.has("SearchTextNext") == true) { _textSearchNextShortcut->setKey(_keySettings.get("SearchTextNext")._sequence); } if (_keySettings.has("SearchTextPrev") == true) { _textSearchPrevShortcut->setKey(_keySettings.get("SearchTextPrev")._sequence); } if (_keySettings.has("AlternateDir") == true) { _alternateDirShortcut->setKey(_keySettings.get("AlternateDir")._sequence); } if (_keySettings.has("ToggleBreakpoint") == true) { _toggleBreakpointShortcut->setKey(_keySettings.get("ToggleBreakpoint")._sequence); } if (_keySettings.has("GoToDefinition") == true) { _gotoDefinitionShortcut->setKey(_keySettings.get("GoToDefinition")._sequence); } } const SeerKeySettings& SeerEditorWidgetSource::keySettings () const { return _keySettings; } void SeerEditorWidgetSource::showSearchBar (bool flag) { showSearchBar(flag, ""); } void SeerEditorWidgetSource::showSearchBar (bool flag, QString field) { searchBarWidget->setVisible(flag); // If 'show', give the searchTextLineEdit or the searchTextLineEdit the focus. if (flag) { if (field == "text") { searchTextLineEdit->setFocus(Qt::MouseFocusReason); }else if (field == "line") { searchLineNumberLineEdit->setFocus(Qt::MouseFocusReason); }else{ searchTextLineEdit->setFocus(Qt::MouseFocusReason); } } } void SeerEditorWidgetSource::setSearchMatchCase (bool flag) { matchCaseCheckBox->setChecked(flag); } void SeerEditorWidgetSource::showAlternateBar (bool flag) { alternateBarWidget->setVisible(flag); if (flag) { originalLineEdit->setText(sourceArea()->fullname()); // Set the original text. rememberAlternateCheckBox->setChecked(true); // Set the default remember setting. alternateLineEdit->setFocus(Qt::MouseFocusReason); // If 'show', give the alternateLineEdit the focus. } } void SeerEditorWidgetSource::showReloadBar (bool flag) { reloadBarWidget->setVisible(flag); reloadBarWidget->setStyleSheet("QWidget { background-color : #00AA00; color : #FFFF00; }"); if (flag) { int elideLength = 50; if (sourceArea()->autoSourceReload()) { reloadFilenameLabel->setText("The file \"" + Seer::elideText(sourceArea()->file(),Qt::ElideLeft,elideLength) + "\" has changed on disk. RELOADING..."); reloadFilenameLabel->setToolTip(sourceArea()->file()); reloadToolButton->setFocus(Qt::MouseFocusReason); // Give the reload button the focus. // Schedule the reload. QTimer::singleShot(1000, this, &SeerEditorWidgetSource::handleReloadToolButton); }else{ reloadFilenameLabel->setText("The file \"" + Seer::elideText(sourceArea()->file(),Qt::ElideLeft,elideLength) + "\" has changed on disk."); reloadFilenameLabel->setToolTip(sourceArea()->file()); reloadToolButton->setFocus(Qt::MouseFocusReason); // Give the reload button the focus. } }else{ reloadFilenameLabel->setText(""); reloadFilenameLabel->setToolTip(""); } } void SeerEditorWidgetSource::handleSearchLineNumberLineEdit () { QString str = searchLineNumberLineEdit->text(); if (str == "") { showSearchBar(false); return; } int lineno = str.toInt(); if (lineno < 1) { return; } searchLineNumberLineEdit->clear(); sourceArea()->scrollToLine(lineno); } void SeerEditorWidgetSource::handleSearchTextLineEdit () { QString str = searchTextLineEdit->text(); matchesLabel->setText(""); if (str == "") { sourceArea()->clearFindText(); showSearchBar(false); return; } int nMatches = sourceArea()->findText(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags())); matchesLabel->setText(QString("(%1)").arg(nMatches)); } void SeerEditorWidgetSource::handleSearchDownToolButton () { QString str = searchTextLineEdit->text(); if (str == "") { return; } sourceArea()->find(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags())); } void SeerEditorWidgetSource::handleSearchUpToolButton () { QString str = searchTextLineEdit->text(); if (str == "") { return; } sourceArea()->find(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags()) | QTextDocument::FindBackward); } void SeerEditorWidgetSource::handleSearchCloseToolButton () { showSearchBar(false); } void SeerEditorWidgetSource::handleAlternateCloseToolButton () { showAlternateBar(false); } void SeerEditorWidgetSource::handleAlternateFileOpenToolButton () { //qDebug() << "fullname =" << sourceArea()->fullname(); //qDebug() << "file =" << sourceArea()->file(); QString filename = QFileDialog::getOpenFileName(this, "Locate File", sourceArea()->fullname(), QString("File (%1)").arg(sourceArea()->file()), nullptr, QFileDialog::DontUseNativeDialog); //qDebug() << "location =" << filename; //qDebug() << "directory=" << QFileInfo(filename).absolutePath(); if (filename != "") { alternateLineEdit->setText(QFileInfo(filename).absolutePath()); } handleAlternateLineEdit(); } void SeerEditorWidgetSource::handleAlternateLineEdit () { showAlternateBar(false); // Get the base path. QString dirname = alternateLineEdit->text(); if (dirname == "") { return; } //qDebug() << "alternate dirname=" << dirname; // Attempt to open the file. sourceArea()->open(sourceArea()->fullname(), sourceArea()->file(), dirname); // Add to global alternate list. if (rememberAlternateCheckBox->isChecked()) { emit addAlternateDirectory(dirname); } } void SeerEditorWidgetSource::handleTextSearchShortcut () { if (isSearchBarShown() == true) { showSearchBar(false, ""); }else{ showSearchBar(true, "text"); } } void SeerEditorWidgetSource::handleLineSearchShortcut () { if (isSearchBarShown() == true) { showSearchBar(false, ""); }else{ showSearchBar(true, "line"); } } void SeerEditorWidgetSource::handleAlternateDirectoryShortcut () { if (isAlternateBarShown() == true) { showAlternateBar(false); }else{ showAlternateBar(true); } } void SeerEditorWidgetSource::handleToggleBreakpointShortcut () { sourceArea()->breakpointToggle(); } void SeerEditorWidgetSource::handleReloadToolButton () { showReloadBar(false); sourceArea()->reload(); } void SeerEditorWidgetSource::handleReloadCloseToolButton () { showReloadBar(false); } void SeerEditorWidgetSource::handleEscapePressed () { showSearchBar(false, ""); } seer-2.7/src/SeerEditorWidgetSource.h000066400000000000000000000517751516472651200177020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerSourceHighlighter.h" #include "SeerKeySettings.h" #include "SeerPlainTextEdit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include class SeerEditorWidgetSourceLineNumberArea; class SeerEditorWidgetSourceBreakPointArea; class SeerEditorWidgetSourceArea : public SeerPlainTextEdit { Q_OBJECT public: struct SeerCurrentFile { QString file; QString fullname; int cursorRow; // line to set the cursor to int cursorCol; // column to set the cursor to int firstDisplayLine; // line to display at top bool operator==(const SeerCurrentFile& other) const { return (fullname == other.fullname) && (cursorRow == other.cursorRow) && (cursorCol == other.cursorCol) && (firstDisplayLine == other.firstDisplayLine); } bool operator!=(const SeerCurrentFile& other) const { return (fullname != other.fullname) | (cursorRow != other.cursorRow) | (cursorCol != other.cursorCol) | (firstDisplayLine != other.firstDisplayLine); } }; SeerEditorWidgetSourceArea (QWidget* parent = 0); void enableLineNumberArea (bool flag); bool lineNumberAreaEnabled () const; void enableBreakPointArea (bool flag); bool breakPointAreaEnabled () const; void lineNumberAreaPaintEvent (QPaintEvent* event); int lineNumberAreaWidth (); void breakPointAreaPaintEvent (QPaintEvent* event); int breakPointAreaWidth (); bool isOpen () const; void open (const QString& fullname, const QString& file, const QString& alternateDirectory=""); void openText (const QString& text, const QString& file); void close (); void reload (); const QString& fullname () const; const QString& file () const; void setAlternateDirectory (const QString& alternateDirectory); const QString& alternateDirectory () const; void setAlternateDirectories (const QStringList& alternateDirectories); const QStringList& alternateDirectories () const; QString findFile (const QString& file, const QString& fullname, const QString& alternateDirectory, const QStringList& alternateDirectories); void setCurrentLine (int lineno); void setCurrentColumn (int colno); int currentLine () const; int currentColumn () const; int firstDisplayLine () const; void scrollToLine (int lineno); void clearCurrentLines (); void addCurrentLine (int lineno, int level); int findText (const QString& text, QTextDocument::FindFlags flags); void clearFindText (); void clearBreakpoints (); void addBreakpoint (int number, int lineno, bool enabled); bool hasBreakpointNumber (int number) const; bool hasBreakpointLine (int lineno) const; const QVector& breakpointNumbers () const; const QVector& breakpointLines () const; const QVector& breakpointEnableds () const; int breakpointLineToNumber (int lineno) const; bool breakpointLineEnabled (int lineno) const; void breakpointToggle (); void runToSelectedLine (); void showContextMenu (QMouseEvent* event); void showContextMenu (QContextMenuEvent* event); void showContextMenu (const QPoint& pos, const QPointF& globalPos); void setQuickBreakpoint (QMouseEvent* event); void setQuickRunToLine (QMouseEvent* event); void showBreakpointToolTip (QMouseEvent* event); void clearExpression (); void setHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& highlighterSettings () const; void setHighlighterEnabled (bool flag); bool highlighterEnabled () const; void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setExternalEditorCommand (const QString& externalEditorCommand); const QString& externalEditorCommand (); void setAutoSourceReload (bool flag); bool autoSourceReload () const; SeerCurrentFile readCurrentPosition (); void eraseColorCurrentLine (int lineno); signals: void insertBreakpoint (QString breakpoint); void insertPrintpoint (QString type, QString function, QString channel, QString parameters); void deleteBreakpoints (QString breakpoints); void enableBreakpoints (QString breakpoints); void disableBreakpoints (QString breakpoints); void infoBreakpoint (int breakpointid, QString breakpoint); void refreshBreakpointsStackFrames (); void runToLine (QString fullname, int lineno); void addVariableLoggerExpression (QString expression); void addVariableTrackerExpression (QString expression); void refreshVariableTrackerValues (); void evaluateVariableExpression (int expressionid, QString expression); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void showSearchBar (bool flag); void showAlternateBar (bool flag); void showReloadBar (bool flag); void highlighterSettingsChanged (); void addToMouseNavigation (const SeerCurrentFile& currentFile); void signalGotoDefinition (const QString& identifier); public slots: void handleText (const QString& text); void handleHighlighterSettingsChanged (); void handleWatchFileModified (const QString& path); void handleBreakpointToolTip (QPoint pos, const QString& text); void handleGotoDefinition (); protected: void resizeEvent (QResizeEvent* event); void contextMenuEvent (QContextMenuEvent* event); void mouseReleaseEvent (QMouseEvent* event); bool event (QEvent* event); void showExpressionTooltip (); void hideExpressionTooltip (); void mousePressEvent (QMouseEvent *event) override; void keyPressEvent (QKeyEvent* event) override; void keyReleaseEvent (QKeyEvent* event) override; private slots: void refreshExtraSelections (); void updateMarginAreasWidth (int newBlockCount); void updateLineNumberArea (const QRect& rect, int dy); void updateBreakPointArea (const QRect& rect, int dy); private: void handleCursorPositionChanged (); void updateCursor (const QPoint &pos); bool isOverWord (const QPoint &pos); QString wordUnderCursor (const QPoint &pos) const; bool isValidIdentifier (const QString& text); QString _fullname; QString _file; QString _alternateDirectory; QStringList _alternateDirectories; QFileSystemWatcher* _fileWatcher; bool _enableLineNumberArea; bool _enableBreakPointArea; QVector _breakpointsNumbers; QVector _breakpointsLineNumbers; QVector _breakpointsEnableds; QList _findExtraSelections; QList _currentLinesExtraSelections; QTextCursor _selectedExpressionCursor; QPoint _selectedExpressionPosition; int _selectedExpressionId; QString _selectedExpressionName; QString _selectedExpressionValue; QPoint _selectedBreakpointPosition; int _selectedBreakpointId; SeerEditorWidgetSourceLineNumberArea* _lineNumberArea; SeerEditorWidgetSourceBreakPointArea* _breakPointArea; SeerSourceHighlighter* _sourceHighlighter; SeerHighlighterSettings _sourceHighlighterSettings; bool _sourceHighlighterEnabled; int _sourceTabSize; QString _externalEditorCommand; bool _autoSourceReload; int _ignoreThumbMouseEvent = 0; // Variables for Goto Definition (Alt + Click) static QTimer* _altHeldTimer; static bool _altHeld; QString _wordUnderCursor; }; class SeerEditorWidgetSourceLineNumberArea : public QWidget { Q_OBJECT public: SeerEditorWidgetSourceLineNumberArea (SeerEditorWidgetSourceArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetSourceArea* _editorWidget; }; class SeerEditorWidgetSourceBreakPointArea : public QWidget { Q_OBJECT public: SeerEditorWidgetSourceBreakPointArea (SeerEditorWidgetSourceArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetSourceArea* _editorWidget; }; #include "ui_SeerEditorWidgetSource.h" class SeerEditorWidgetSource : public QWidget, protected Ui::SeerEditorWidgetSourceForm { Q_OBJECT public: explicit SeerEditorWidgetSource (QWidget* parent = 0); ~SeerEditorWidgetSource (); SeerEditorWidgetSourceArea* sourceArea (); bool isSearchBarShown () const; bool searchMatchCase () const; bool isAlternateBarShown () const; void setKeySettings (const SeerKeySettings& settings); const SeerKeySettings& keySettings () const; public slots: void showSearchBar (bool flag); void showSearchBar (bool flag, QString field); void setSearchMatchCase (bool flag); void showAlternateBar (bool flag); void showReloadBar (bool flag); private slots: void handleSearchLineNumberLineEdit (); void handleSearchTextLineEdit (); void handleSearchDownToolButton (); void handleSearchUpToolButton (); void handleSearchCloseToolButton (); void handleAlternateCloseToolButton (); void handleAlternateFileOpenToolButton (); void handleAlternateLineEdit (); void handleTextSearchShortcut (); void handleLineSearchShortcut (); void handleAlternateDirectoryShortcut (); void handleToggleBreakpointShortcut (); void handleReloadToolButton (); void handleReloadCloseToolButton (); void handleEscapePressed (); signals: void addAlternateDirectory (QString path); private: SeerKeySettings _keySettings; QShortcut* _textSearchShortcut; QShortcut* _textSearchNextShortcut; QShortcut* _textSearchPrevShortcut; QShortcut* _textSearchReloadShortcut; QShortcut* _lineSearchShortcut; QShortcut* _alternateDirShortcut; QShortcut* _toggleBreakpointShortcut; QShortcut* _gotoDefinitionShortcut; }; seer-2.7/src/SeerEditorWidgetSource.ui000066400000000000000000000257171516472651200200650ustar00rootroot00000000000000 SeerEditorWidgetSourceForm 0 0 838 720 SeerEditorWidgetSourceForm 0 0 0 0 Looking for: Original path location. true Alternate path: Enter path for alternate location. Enter /path/to/alternate/location true Open file dialog for alternate location. ... :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Add path to global list of alternate directories. Remember Close the alternate bar. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg 0 0 0 0 Reload source file. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Close the reload bar. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg 0 100 0 0 0 0 50 0 Enter text to search for. Enter search text true Match Case Search for the next occurance. ... :/seer/resources/RelaxLightIcons/go-down.svg:/seer/resources/RelaxLightIcons/go-down.svg Search for the previous occurance. ... :/seer/resources/RelaxLightIcons/go-up.svg:/seer/resources/RelaxLightIcons/go-up.svg Qt::Vertical 50 0 Scroll to a specific line. Go to line # Qt::Vertical Reload source file. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Qt::Vertical Close the search bar. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg SeerEditorWidgetSourceArea QWidget
SeerEditorWidgetSource.h
1
QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
alternateLineEdit alternateFileOpenToolButton rememberAlternateCheckBox alternateCloseToolButton searchTextLineEdit matchCaseCheckBox searchDownToolButton searchUpToolButton searchLineNumberLineEdit searchCloseToolButton
seer-2.7/src/SeerEditorWidgetSourceAreas.cpp000066400000000000000000002244421516472651200212020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorWidgetSource.h" #include "SeerHighlighterSettings.h" #include "SeerPlainTextEdit.h" #include "SeerBreakpointCreateDialog.h" #include "SeerPrintpointCreateDialog.h" #include "SeerSourceHighlighter.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool SeerEditorWidgetSourceArea::_altHeld = false; QTimer* SeerEditorWidgetSourceArea::_altHeldTimer = new QTimer(); SeerEditorWidgetSourceArea::SeerEditorWidgetSourceArea(QWidget* parent) : SeerPlainTextEdit(parent) { _fileWatcher = 0; _enableLineNumberArea = false; _enableBreakPointArea = false; _sourceHighlighter = 0; _sourceHighlighterEnabled = true; _sourceTabSize = 4; _autoSourceReload = false; _selectedExpressionId = Seer::createID(); _selectedBreakpointId = Seer::createID(); QFont font("monospace"); font.setStyleHint(QFont::Monospace); setEditorFont(font); setEditorTabSize(4); setExternalEditorCommand(""); setReadOnly(true); setTextInteractionFlags(textInteractionFlags() | Qt::TextSelectableByKeyboard); setLineWrapMode(QPlainTextEdit::NoWrap); _lineNumberArea = new SeerEditorWidgetSourceLineNumberArea(this); _breakPointArea = new SeerEditorWidgetSourceBreakPointArea(this); _breakPointArea->setMouseTracking(true); enableLineNumberArea(true); enableBreakPointArea(true); _altHeldTimer->setInterval(40); // 40 ms interval = 25Hz update rate QObject::connect(_altHeldTimer, &QTimer::timeout, this, [this]() { updateCursor(QCursor::pos()); }); QObject::connect(this, &SeerEditorWidgetSourceArea::blockCountChanged, this, &SeerEditorWidgetSourceArea::updateMarginAreasWidth); QObject::connect(this, &SeerEditorWidgetSourceArea::updateRequest, this, &SeerEditorWidgetSourceArea::updateLineNumberArea); QObject::connect(this, &SeerEditorWidgetSourceArea::updateRequest, this, &SeerEditorWidgetSourceArea::updateBreakPointArea); QObject::connect(this, &SeerEditorWidgetSourceArea::highlighterSettingsChanged, this, &SeerEditorWidgetSourceArea::handleHighlighterSettingsChanged); // Connect cursor position changed signal. QObject::connect(this, &QPlainTextEdit::cursorPositionChanged, this, &SeerEditorWidgetSourceArea::handleCursorPositionChanged); setCurrentLine(0); updateMarginAreasWidth(0); // Forward the scroll events in the various areas to the text edit. SeerPlainTextWheelEventForwarder* lineNumberAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* breakPointAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); _lineNumberArea->installEventFilter(lineNumberAreaWheelForwarder); _breakPointArea->installEventFilter(breakPointAreaWheelForwarder); _altHeldTimer->start(); // Calling close() will clear the text document. close(); } void SeerEditorWidgetSourceArea::enableLineNumberArea (bool flag) { _enableLineNumberArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetSourceArea::lineNumberAreaEnabled () const { return _enableLineNumberArea; } void SeerEditorWidgetSourceArea::enableBreakPointArea (bool flag) { _enableBreakPointArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetSourceArea::breakPointAreaEnabled () const { return _enableBreakPointArea; } void SeerEditorWidgetSourceArea::updateMarginAreasWidth (int newBlockCount) { Q_UNUSED(newBlockCount); int leftMarginWidth = lineNumberAreaWidth() + breakPointAreaWidth(); int rightMarginWidth = 0; setViewportMargins(leftMarginWidth, 0, rightMarginWidth, 0); } int SeerEditorWidgetSourceArea::lineNumberAreaWidth () { if (lineNumberAreaEnabled() == false) { return 0; } int digits = 1; int max = qMax(1, blockCount()); while (max >= 10) { max /= 10; digits++; } int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits; return space; } int SeerEditorWidgetSourceArea::breakPointAreaWidth () { if (breakPointAreaEnabled() == false) { return 0; } int space = 3 + 20; return space; } void SeerEditorWidgetSourceArea::updateLineNumberArea (const QRect& rect, int dy) { if (lineNumberAreaEnabled() == false) { return; } if (dy) { _lineNumberArea->scroll(0, dy); }else{ _lineNumberArea->update(0, rect.y(), _lineNumberArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetSourceArea::updateBreakPointArea (const QRect& rect, int dy) { if (breakPointAreaEnabled() == false) { return; } if (dy) { _breakPointArea->scroll(0, dy); }else{ _breakPointArea->update(0, rect.y(), _breakPointArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetSourceArea::lineNumberAreaPaintEvent (QPaintEvent* event) { if (lineNumberAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_lineNumberArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString number = QString::number(blockNumber + 1); painter.drawText(0, top, _lineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, number); } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetSourceArea::breakPointAreaPaintEvent (QPaintEvent* event) { if (breakPointAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_breakPointArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { if (hasBreakpointLine(blockNumber+1)) { if (breakpointLineEnabled(blockNumber+1)) { QRect rect(_breakPointArea->width() - 20, top, fontMetrics().height(), fontMetrics().height()); QPainterPath path; path.addEllipse(rect); QPointF bias = QPointF(rect.width() * .25 * 1.0, rect.height() * .25 * -1.0); QRadialGradient gradient(rect.center(), rect.width() / 2.0, rect.center() + bias); gradient.setColorAt(0.0, QColor(Qt::white)); gradient.setColorAt(0.9, QColor(Qt::red)); gradient.setColorAt(1.0, QColor(Qt::transparent)); painter.fillPath(path,QBrush(gradient)); }else{ QRect rect(_breakPointArea->width() - 20, top, fontMetrics().height(), fontMetrics().height()); QPainterPath path; path.addEllipse(rect); QPointF bias = QPointF(rect.width() * .25 * 1.0, rect.height() * .25 * -1.0); QRadialGradient gradient(rect.center(), rect.width() / 2.0, rect.center() + bias); gradient.setColorAt(0.0, QColor(Qt::white)); gradient.setColorAt(0.9, QColor(Qt::darkGray)); gradient.setColorAt(1.0, Qt::transparent); painter.fillPath(path,QBrush(gradient)); } } } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetSourceArea::resizeEvent (QResizeEvent* e) { QPlainTextEdit::resizeEvent(e); QRect cr = contentsRect(); if (lineNumberAreaEnabled()) { _lineNumberArea->setGeometry (QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); } if (breakPointAreaEnabled()) { _breakPointArea->setGeometry (QRect(cr.left() + lineNumberAreaWidth(), cr.top(), breakPointAreaWidth(), cr.height())); } } void SeerEditorWidgetSourceArea::contextMenuEvent (QContextMenuEvent* event) { showContextMenu(event); } void SeerEditorWidgetSourceArea::mouseReleaseEvent (QMouseEvent* event) { QPlainTextEdit::mouseReleaseEvent(event); if (textCursor().selectedText() == "") { // Nothing selected, clear current expression. clearExpression(); return; } _selectedExpressionCursor = textCursor(); _selectedExpressionPosition = event->pos(); _selectedExpressionValue = ""; // Look for a keyboard modifier to prepend a '*', '&', or '*&'. Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers(); if (modifiers == Qt::ControlModifier) { _selectedExpressionName = QString("*") + textCursor().selectedText(); }else if (modifiers == Qt::ShiftModifier) { _selectedExpressionName = QString("&") + textCursor().selectedText(); }else if (modifiers == (Qt::ShiftModifier | Qt::ControlModifier)) { _selectedExpressionName = QString("*&") + textCursor().selectedText(); }else{ _selectedExpressionName = textCursor().selectedText(); } emit addVariableLoggerExpression(_selectedExpressionName); // For the variable logger. } bool SeerEditorWidgetSourceArea::event(QEvent* event) { // Handle the ToolTip event. if (event->type() == QEvent::ToolTip) { while (1) { // Create a region of the code that does one pass. // Convert the event to a Help event. QHelpEvent* helpEvent = static_cast(event); // Massage the event location to account for the linenumber and breakpoint widgets. QPoint pos = QPoint(helpEvent->pos().x() - _lineNumberArea->width() - _breakPointArea->width(), helpEvent->pos().y()); // Create a cursor at the position so we can get the text underneath at the cursor. QTextCursor cursor = cursorForPosition(pos); cursor.select(QTextCursor::WordUnderCursor); // If the hover text is empty, do nothing. Reset things. Exit this function. QString word = cursor.selectedText(); if (word.isEmpty() == true) { hideExpressionTooltip(); break; } // Is our cursor the same as the previous. if (cursor == _selectedExpressionCursor) { // Same word as before? Display the tooltip value. if (word == _selectedExpressionName) { // If the tooltip is already visible, refreshen it with // the same value, possibly at a new postion. if (QToolTip::isVisible()) { _selectedExpressionPosition = helpEvent->globalPos(); showExpressionTooltip(); // If not already visible, refreshen its value. }else{ emit evaluateVariableExpression(_selectedExpressionId, _selectedExpressionName); // For the tooltip. } // Otherwise, hide any old one. }else{ hideExpressionTooltip(); } // Otherwise it's a different spot. Create a new request to get the variable's value. }else{ hideExpressionTooltip(); _selectedExpressionCursor = cursor; _selectedExpressionPosition = helpEvent->globalPos(); _selectedExpressionName = word; _selectedExpressionValue = ""; emit evaluateVariableExpression(_selectedExpressionId, _selectedExpressionName); // For the tooltip. } break; } return true; } // Pass any others to the base class. return QPlainTextEdit::event(event); } void SeerEditorWidgetSourceArea::showExpressionTooltip () { // qDebug() << "Tooltip:" << _selectedExpressionPosition << _selectedExpressionName << _selectedExpressionValue; QToolTip::hideText(); QToolTip::showText(_selectedExpressionPosition, _selectedExpressionName + ": " + Seer::elideText(_selectedExpressionValue, Qt::ElideRight, 100)); } void SeerEditorWidgetSourceArea::hideExpressionTooltip () { QToolTip::hideText(); _selectedExpressionCursor = QTextCursor(); _selectedExpressionPosition = QPoint(); _selectedExpressionName = ""; _selectedExpressionValue = ""; } void SeerEditorWidgetSourceArea::refreshExtraSelections () { // // Merge all the extra selections into one. // // The current line(s) // The searched text. // // Create an empty list of selections. QList extraSelections; // Append the 'current lines' extra selections. extraSelections.append(_currentLinesExtraSelections); // Append the 'searched text' extra selections. extraSelections.append(_findExtraSelections); // Give the editor the list of selections. // This will remove the old selections and select the new ones. setExtraSelections(extraSelections); } bool SeerEditorWidgetSourceArea::isOpen () const { if (_fullname != "") { return true; } return false; } void SeerEditorWidgetSourceArea::open (const QString& fullname, const QString& file, const QString& alternateDirectory) { // Delete old file watcher, if any. if (_fileWatcher) { delete _fileWatcher; _fileWatcher = 0; } // Close the previous file, if any. if (isOpen()) { close(); } // Save the filename. _fullname = fullname; _file = file; _alternateDirectory = alternateDirectory; setDocumentTitle(_fullname); // If the filename or file is null, it's a placeholder // widget. Show the Seer icon! if (_fullname == "" || _file == "") { setStyleSheet("QPlainTextEdit {" "background: url(:/seer/resources/icons/hicolor/512x512/seergdb.png) center no-repeat;" "border: none;" "}"); return; } // // Open the file. // // See findFile() to see the search paths and order. // QString filename = findFile(_file, _fullname, _alternateDirectory, _alternateDirectories); if (filename == "") { QMessageBox::critical(this, "Can't find source file.", "Can't find : " + _file + "\nIts location may have changed."); emit showAlternateBar(true); return; } QFile inputFile(filename); bool f = inputFile.open(QIODevice::ReadOnly); if (f == false) { QMessageBox::critical(this, "Can't read source file.", "Can't read : " + filename + "\nThe file is there but can't be opened."); emit showAlternateBar(true); return; } // Read the file. QTextStream stream(&inputFile); QString line = stream.readLine(); QString text; while (!line.isNull()) { // Expand tabs line = Seer::expandTabs(line, editorTabSize(), false); // Build up text for file. text += line + "\n"; // Read next line, if available. line = stream.readLine(); }; // Put the contents in the editor. openText(text, _fullname); // Watch the file. _fileWatcher = new QFileSystemWatcher(this); _fileWatcher->addPath(filename); QObject::connect(_fileWatcher, &QFileSystemWatcher::fileChanged, this, &SeerEditorWidgetSourceArea::handleWatchFileModified); } void SeerEditorWidgetSourceArea::openText (const QString& text, const QString& file) { // Put the contents in the editor. setPlainText(text); // Set the text cursor to the first line. QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1); setTextCursor(cursor); // Add a syntax highlighter. if (_sourceHighlighter) { delete _sourceHighlighter; _sourceHighlighter = 0; } _file = file; SeerSourceHighlighter* highlighter = SeerSourceHighlighter::getSourceHighlighter(_file, _sourceHighlighterSettings); if (highlighter) { _sourceHighlighter = highlighter; if (highlighterEnabled()) { _sourceHighlighter->setDocument(document()); }else{ _sourceHighlighter->setDocument(0); } _sourceHighlighter->setHighlighterSettings(_sourceHighlighterSettings); _sourceHighlighter->rehighlight(); } } void SeerEditorWidgetSourceArea::reload () { // Open the same file again. QString fullname = _fullname; QString file = _file; QString alternateDirectory = _alternateDirectory; if (fullname == "") return; if (file == "") return; // Save old cursor and scroll position. int blockno = textCursor().blockNumber(); int posinblock = textCursor().positionInBlock(); int vscrollpos = verticalScrollBar()->value(); // Reload file. open(fullname, file, alternateDirectory); // Restore to old cursor and scroll position. QTextCursor c = textCursor(); c.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1); c.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, blockno); c.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, posinblock); setTextCursor(c); ensureCursorVisible(); verticalScrollBar()->setValue(vscrollpos); // Refresh any breakpoints or current lines in the stackframes. emit refreshBreakpointsStackFrames(); } void SeerEditorWidgetSourceArea::close () { setDocumentTitle(""); setPlainText(""); clearExpression(); // Delete old file watcher, if any. if (_fileWatcher) { delete _fileWatcher; _fileWatcher = 0; } } const QString& SeerEditorWidgetSourceArea::fullname () const { return _fullname; } const QString& SeerEditorWidgetSourceArea::file () const { return _file; } void SeerEditorWidgetSourceArea::setAlternateDirectory (const QString& alternateDirectory) { _alternateDirectory = alternateDirectory; } const QString& SeerEditorWidgetSourceArea::alternateDirectory () const { return _alternateDirectory; } void SeerEditorWidgetSourceArea::setAlternateDirectories (const QStringList& alternateDirectories) { _alternateDirectories = alternateDirectories; } const QStringList& SeerEditorWidgetSourceArea::alternateDirectories () const { return _alternateDirectories; } QString SeerEditorWidgetSourceArea::findFile (const QString& file, const QString& fullname, const QString& alternateDirectory, const QStringList& alternateDirectories) { // // This function returns the filename to use to load the source file. // // 'file' is the short version of the filename. eg: 'source.cpp' // 'fullname' is the long version. eg: '/path/to/locate/source.cpp' // 'alternateDirectory' is the alternate directory to use if 'fullname' is not found. // 'alternateDirectories' is a list of alternate directories if 'fullname' is not found // and if 'file' is not in 'alternateDirectory'. // // 'alternateDirectory' can be blank ("") and usually is. If it isn't blank, then it // takes presedence over 'fullname' and 'alternateDirectories'. // // 'alternateDirectories' is a list of directory locations. It defines the search order. // Once a location has the 'file', the search stops and that directory is used. // // If the 'file' can't be found in any of the locations, a "" is returned. // // One note about 'fullname'. This is the path that gdb knows of. Gdb extracts the path // from the debug information in the executable when it was compiled and linked. // // Use 'alternateDirectory', if provided. if (alternateDirectory != "") { QString filename = alternateDirectory + "/" + file; if (QFileInfo::exists(filename) == false) { return ""; } return filename; } // Handle 'fullname'. if (QFileInfo::exists(fullname) == true) { return fullname; } // Handle 'alternateDirectories'. QStringListIterator iter(alternateDirectories); while (iter.hasNext()) { QString filename = iter.next() + "/" + file; if (QFileInfo::exists(filename) == true) { return filename; } } // Not found anywhere. return ""; } void SeerEditorWidgetSourceArea::setCurrentLine (int lineno) { // Clear current line selections. _currentLinesExtraSelections.clear(); // Highlight if a valid line number is selected. if (lineno >= 1) { QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); _currentLinesExtraSelections.clear(); QTextCharFormat lineFormat = highlighterSettings().get("Current Line"); QTextEdit::ExtraSelection selection; selection.format.setForeground(lineFormat.foreground()); selection.format.setBackground(lineFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _currentLinesExtraSelections.append(selection); } // Refresh all the extra selections. refreshExtraSelections(); } void SeerEditorWidgetSourceArea::setCurrentColumn (int colno) { QTextCursor cursor = textCursor(); int lineStartPos = cursor.block().position(); int newPos = lineStartPos + (colno - 1); cursor.setPosition(newPos); setTextCursor(cursor); } int SeerEditorWidgetSourceArea::currentLine () const { QTextCursor cursor = textCursor(); return cursor.blockNumber() + 1;; } int SeerEditorWidgetSourceArea::currentColumn () const { QTextCursor cursor = textCursor(); return cursor.positionInBlock() + 1; } int SeerEditorWidgetSourceArea::firstDisplayLine () const { QTextBlock block = firstVisibleBlock(); return block.blockNumber() + 1; } void SeerEditorWidgetSourceArea::scrollToLine (int lineno) { // Scroll to the first line if we went before it. if (lineno < 1) { lineno = 1; } // Scroll to the last line if we went past it. if (lineno > document()->blockCount()) { lineno = document()->blockCount(); } QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); centerCursor(); } void SeerEditorWidgetSourceArea::clearCurrentLines () { _currentLinesExtraSelections.clear(); refreshExtraSelections(); } void SeerEditorWidgetSourceArea::addCurrentLine (int lineno, int level) { // Any line will be highlighted with a yellow line. // The 'yellow' color is for the current line of the most recent stack frame. // The 'grey' color is for older stack frames. QTextCharFormat lineFormat; if (level == 0) { lineFormat = highlighterSettings().get("Current Line"); }else{ lineFormat = highlighterSettings().get("Calling Line"); } // Create a selection at the cursor. QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); QTextEdit::ExtraSelection selection; selection.format.setForeground(lineFormat.foreground()); selection.format.setBackground(lineFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = cursor; selection.cursor.clearSelection(); // Add it to the extra selection list. _currentLinesExtraSelections.append(selection); // Refresh all the extra selections. refreshExtraSelections(); } int SeerEditorWidgetSourceArea::findText (const QString& text, QTextDocument::FindFlags flags) { _findExtraSelections.clear(); if (document()) { QTextCharFormat matchFormat = highlighterSettings().get("Match"); // Build a list of highlights for all matches. QTextCursor cursor(document()); cursor = document()->find(text, cursor, flags); while (cursor.isNull() == false) { QTextEdit::ExtraSelection extra; extra.format = matchFormat; extra.cursor = cursor; _findExtraSelections.append(extra); cursor = document()->find(text, cursor, flags); } // Move to the next match after out current position. find(text, flags); } refreshExtraSelections(); return _findExtraSelections.size(); } void SeerEditorWidgetSourceArea::clearFindText () { _findExtraSelections.clear(); refreshExtraSelections(); } void SeerEditorWidgetSourceArea::clearBreakpoints () { _breakpointsLineNumbers.clear(); _breakpointsNumbers.clear(); _breakpointsEnableds.clear(); repaint(); } void SeerEditorWidgetSourceArea::addBreakpoint (int number, int lineno, bool enabled) { _breakpointsNumbers.push_back(number); _breakpointsLineNumbers.push_back(lineno); _breakpointsEnableds.push_back(enabled); repaint(); } bool SeerEditorWidgetSourceArea::hasBreakpointNumber (int number) const { return _breakpointsNumbers.contains(number); } bool SeerEditorWidgetSourceArea::hasBreakpointLine (int lineno) const { return _breakpointsLineNumbers.contains(lineno); } const QVector& SeerEditorWidgetSourceArea::breakpointNumbers () const { return _breakpointsNumbers; } const QVector& SeerEditorWidgetSourceArea::breakpointLines () const { return _breakpointsLineNumbers; } const QVector& SeerEditorWidgetSourceArea::breakpointEnableds () const { return _breakpointsEnableds; } int SeerEditorWidgetSourceArea::breakpointLineToNumber (int lineno) const { // Map lineno to breakpoint number. int i = _breakpointsLineNumbers.indexOf(lineno); if (i < 0) { return 0; } return _breakpointsNumbers[i]; } bool SeerEditorWidgetSourceArea::breakpointLineEnabled (int lineno) const { // Look for the lineno and get its index. int i = _breakpointsLineNumbers.indexOf(lineno); // Not found, return false. if (i < 0) { return false; } // Otherwise, return the proper status. return _breakpointsEnableds[i]; } void SeerEditorWidgetSourceArea::breakpointToggle () { // Get current lineno. int lineno = textCursor().blockNumber() + 1; // If there is a breakpoint on the line, toggle it. if (hasBreakpointLine(lineno)) { // Toggle the breakpoint. // Enable if disabled. Disable if enabled. if (breakpointLineEnabled(lineno) == false) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); }else{ // Emit the disable breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); } // Otherwise, do a quick create of a new breakpoint. }else{ emit insertBreakpoint(QString("-f --source \"%1\" --line %2").arg(fullname()).arg(lineno)); } } void SeerEditorWidgetSourceArea::runToSelectedLine () { // Emit the runToLine signal. emit runToLine(fullname(), currentLine()); } void SeerEditorWidgetSourceArea::showContextMenu (QMouseEvent* event) { #if QT_VERSION >= 0x060000 showContextMenu(event->pos(), event->globalPosition()); #else showContextMenu(event->pos(), event->globalPos()); #endif } void SeerEditorWidgetSourceArea::showContextMenu (QContextMenuEvent* event) { showContextMenu(event->pos(), event->globalPos()); } void SeerEditorWidgetSourceArea::showContextMenu (const QPoint& pos, const QPointF& globalPos) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(pos); int lineno = cursor.blockNumber()+1; // Create the menu actions. QAction* createBreakpointAction; QAction* createPrintpointAction; QAction* deleteAction; QAction* enableAction; QAction* disableAction; QAction* runToLineAction; QAction* openExternalEditor; QAction* addVariableLoggerExpressionAction; QAction* addVariableLoggerAsteriskExpressionAction; QAction* addVariableLoggerAmpersandExpressionAction; QAction* addVariableLoggerAsteriskAmpersandExpressionAction; QAction* addVariableLoggerObjcExpressionAction; QAction* addVariableTrackerExpressionAction; QAction* addVariableTrackerAsteriskExpressionAction; QAction* addVariableTrackerAmpersandExpressionAction; QAction* addVariableTrackerAsteriskAmpersandExpressionAction; QAction* addVariableTrackerObjcExpressionAction; QAction* addMemoryVisualizerAction; QAction* addMemoryAsteriskVisualizerAction; QAction* addMemoryAmpersandVisualizerAction; QAction* addArrayVisualizerAction; QAction* addArrayAsteriskVisualizerAction; QAction* addArrayAmpersandVisualizerAction; QAction* addMatrixVisualizerAction; QAction* addMatrixAsteriskVisualizerAction; QAction* addMatrixAmpersandVisualizerAction; QAction* addStructVisualizerAction; QAction* addStructAsteriskVisualizerAction; QAction* addStructAmpersandVisualizerAction; // Enable/disable them depending if the breakpoint already exists. if (hasBreakpointLine(lineno) == true) { int breakno = breakpointLineToNumber(lineno); runToLineAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg"), QString("Run to line %1").arg(lineno), this); createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint on line %1").arg(lineno), this); createPrintpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create printpoint on line %1").arg(lineno), this); deleteAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/edit-delete.svg"), QString("Delete breakpoint %1 on line %2").arg(breakno).arg(lineno), this); enableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg"), QString("Enable breakpoint %1 on line %2").arg(breakno).arg(lineno), this); disableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg"), QString("Disable breakpoint %1 on line %2").arg(breakno).arg(lineno), this); openExternalEditor = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Open external editor on line %1").arg(lineno), this); runToLineAction->setEnabled(true); createBreakpointAction->setEnabled(false); createPrintpointAction->setEnabled(false); deleteAction->setEnabled(true); enableAction->setEnabled(true); disableAction->setEnabled(true); openExternalEditor->setEnabled(true); }else{ runToLineAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg"), QString("Run to line %1").arg(lineno), this); createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint on line %1").arg(lineno), this); createPrintpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create printpoint on line %1").arg(lineno), this); deleteAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/edit-delete.svg"), QString("Delete breakpoint on line %1").arg(lineno), this); enableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg"), QString("Enable breakpoint on line %1").arg(lineno), this); disableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg"), QString("Disable breakpoint on line %1").arg(lineno), this); openExternalEditor = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Open file in external editor"), this); runToLineAction->setEnabled(true); createBreakpointAction->setEnabled(true); createPrintpointAction->setEnabled(true); deleteAction->setEnabled(false); enableAction->setEnabled(false); disableAction->setEnabled(false); openExternalEditor->setEnabled(true); } addVariableLoggerExpressionAction = new QAction(QString("%1").arg(textCursor().selectedText())); addVariableLoggerAsteriskExpressionAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addVariableLoggerAmpersandExpressionAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addVariableLoggerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(textCursor().selectedText())); addVariableLoggerObjcExpressionAction = new QAction(QString("(objc)%1").arg(textCursor().selectedText())); addVariableTrackerExpressionAction = new QAction(QString("%1").arg(textCursor().selectedText())); addVariableTrackerAsteriskExpressionAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addVariableTrackerAmpersandExpressionAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addVariableTrackerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(textCursor().selectedText())); addVariableTrackerObjcExpressionAction = new QAction(QString("(objc)%1").arg(textCursor().selectedText())); addMemoryVisualizerAction = new QAction(QString("%1").arg(textCursor().selectedText())); addMemoryAsteriskVisualizerAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addMemoryAmpersandVisualizerAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addArrayVisualizerAction = new QAction(QString("%1").arg(textCursor().selectedText())); addArrayAsteriskVisualizerAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addArrayAmpersandVisualizerAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addMatrixVisualizerAction = new QAction(QString("%1").arg(textCursor().selectedText())); addMatrixAsteriskVisualizerAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addMatrixAmpersandVisualizerAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addStructVisualizerAction = new QAction(QString("%1").arg(textCursor().selectedText())); addStructAsteriskVisualizerAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addStructAmpersandVisualizerAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); QMenu menu("Breakpoints", this); menu.setTitle("Breakpoints"); menu.addAction(runToLineAction); menu.addAction(createBreakpointAction); menu.addAction(createPrintpointAction); menu.addAction(deleteAction); menu.addAction(enableAction); menu.addAction(disableAction); menu.addAction(openExternalEditor); QMenu loggerMenu("Add variable to Logger"); loggerMenu.addAction(addVariableLoggerExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskExpressionAction); loggerMenu.addAction(addVariableLoggerAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerObjcExpressionAction); menu.addMenu(&loggerMenu); QMenu trackerMenu("Add variable to Tracker"); trackerMenu.addAction(addVariableTrackerExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskExpressionAction); trackerMenu.addAction(addVariableTrackerAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerObjcExpressionAction); menu.addMenu(&trackerMenu); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Enable/disable items based on something being selected or not. if (textCursor().selectedText() == "") { addVariableLoggerExpressionAction->setEnabled(false); addVariableLoggerAsteriskExpressionAction->setEnabled(false); addVariableLoggerAmpersandExpressionAction->setEnabled(false); addVariableLoggerAsteriskAmpersandExpressionAction->setEnabled(false); addVariableLoggerObjcExpressionAction->setEnabled(false); addVariableTrackerExpressionAction->setEnabled(false); addVariableTrackerAsteriskExpressionAction->setEnabled(false); addVariableTrackerAmpersandExpressionAction->setEnabled(false); addVariableTrackerAsteriskAmpersandExpressionAction->setEnabled(false); addMemoryVisualizerAction->setEnabled(false); addMemoryAsteriskVisualizerAction->setEnabled(false); addMemoryAmpersandVisualizerAction->setEnabled(false); addArrayVisualizerAction->setEnabled(false); addArrayAsteriskVisualizerAction->setEnabled(false); addArrayAmpersandVisualizerAction->setEnabled(false); addMatrixVisualizerAction->setEnabled(false); addMatrixAsteriskVisualizerAction->setEnabled(false); addMatrixAmpersandVisualizerAction->setEnabled(false); addStructVisualizerAction->setEnabled(false); addStructAsteriskVisualizerAction->setEnabled(false); addStructAmpersandVisualizerAction->setEnabled(false); }else{ addVariableLoggerExpressionAction->setEnabled(true); addVariableLoggerAsteriskExpressionAction->setEnabled(true); addVariableLoggerAmpersandExpressionAction->setEnabled(true); addVariableLoggerAsteriskAmpersandExpressionAction->setEnabled(true); addVariableLoggerObjcExpressionAction->setEnabled(true); addVariableTrackerExpressionAction->setEnabled(true); addVariableTrackerAsteriskExpressionAction->setEnabled(true); addVariableTrackerAmpersandExpressionAction->setEnabled(true); addVariableTrackerAsteriskAmpersandExpressionAction->setEnabled(true); addMemoryVisualizerAction->setEnabled(true); addMemoryAsteriskVisualizerAction->setEnabled(true); addMemoryAmpersandVisualizerAction->setEnabled(true); addArrayVisualizerAction->setEnabled(true); addArrayAsteriskVisualizerAction->setEnabled(true); addArrayAmpersandVisualizerAction->setEnabled(true); addMatrixVisualizerAction->setEnabled(true); addMatrixAsteriskVisualizerAction->setEnabled(true); addMatrixAmpersandVisualizerAction->setEnabled(true); addStructVisualizerAction->setEnabled(true); addStructAsteriskVisualizerAction->setEnabled(true); addStructAmpersandVisualizerAction->setEnabled(true); } // Launch the menu. Get the response. QAction* action = menu.exec(globalPos.toPoint()); // Do nothing. if (action == 0) { return; } // Handle running to a line number. if (action == runToLineAction) { // Emit the runToLine signal. emit runToLine(fullname(), lineno); return; } // Handle creating a new breakpoint. if (action == createBreakpointAction) { SeerBreakpointCreateDialog dlg(this); dlg.setFilename(fullname()); dlg.setLineNumber(QString("%1").arg(lineno)); int ret = dlg.exec(); if (ret == 0) { return; } // Emit the create breakpoint signal. emit insertBreakpoint(dlg.breakpointText()); return; } // Handle creating a new printpoint. if (action == createPrintpointAction) { SeerPrintpointCreateDialog dlg(this); dlg.setFilename(fullname()); dlg.setLineNumber(QString("%1").arg(lineno)); int ret = dlg.exec(); if (ret == 0) { return; } // Build a printpoint specification. QString type = dlg.dprintfType(); QString function = dlg.dprintfFunction(); QString channel = dlg.dprintfChannel(); QString parameters = dlg.printpointParameters(); // If nothing, just return. if (parameters == "" || type == "") { return; } // Emit the create breakpoint signal. emit insertPrintpoint(type, function, channel, parameters); return; } // Handle deleting a breakpoint. if (action == deleteAction) { // Emit the delete breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); return; } // Handle enabling a breakpoint. if (action == enableAction) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); return; } // Handle disabling a breakpoint. if (action == disableAction) { // Emit the disable breakpoint signal. emit disableBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); return; } // Handle open code editor at a line number. if (action == openExternalEditor) { // External editor examples: // $ export SEERGDB_CustomCodeEditor='geany "%{file}":%{line}' // $ export SEERGDB_CustomCodeEditor='kate --line %{line} "%{file}"' // $ export SEERGDB_CustomCodeEditor='gedit "%{file}" +%{line}' // $ export SEERGDB_CustomCodeEditor='konsole -e vim "%{file}" +%{line}' // QString codeEditorCmd = []() { const char* pc = std::getenv("SEERGDB_CustomCodeEditor"); if(pc) return pc; return ""; } (); QString codeEditorCmd = externalEditorCommand(); if (codeEditorCmd == "") { QMessageBox::critical(this, "Error!", "External editor not set.\n\nSee the Editor Config page to set the editor to use."); return; } // Mark cursor as busy. QApplication::setOverrideCursor(Qt::BusyCursor); codeEditorCmd.replace("%{file}", fullname()); codeEditorCmd.replace("%{line}", QString::number(lineno)); QProcess* process = new QProcess(this); process->startCommand(codeEditorCmd); bool f = process->waitForStarted(5000); // Set the cursor back. QApplication::restoreOverrideCursor(); if (f == false) { QMessageBox::critical(this, "Error!", "Launching external editor failed.\n\nCommand: '" + codeEditorCmd + "'"); qDebug().nospace() << "Launching external editor failed. Command: '" << codeEditorCmd << "'"; qDebug().nospace() << "Error: '" << process->error() << "'"; } return; } // Handle adding a variable to log. if (action == addVariableLoggerExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(textCursor().selectedText()); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(QString("*") + textCursor().selectedText()); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAmpersandExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(QString("&") + textCursor().selectedText()); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskAmpersandExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(QString("*&") + textCursor().selectedText()); } return; } // Handle adding a variable to log. if (action == addVariableLoggerObjcExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(QString("(objc)") + textCursor().selectedText()); } return; } // Handle adding a variable to track. if (action == addVariableTrackerExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(QString("*") + textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAmpersandExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(QString("&") + textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskAmpersandExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(QString("*&") + textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerObjcExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(QString("(objc)") + textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMemoryVisualizer(textCursor().selectedText()); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMemoryVisualizer(QString("*") + textCursor().selectedText()); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMemoryVisualizer(QString("&") + textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addArrayVisualizer(textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addArrayVisualizer(QString("*") + textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addArrayVisualizer(QString("&") + textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMatrixVisualizer(textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMatrixVisualizer(QString("*") + textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMatrixVisualizer(QString("&") + textCursor().selectedText()); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addStructVisualizer(textCursor().selectedText()); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addStructVisualizer(QString("*") + textCursor().selectedText()); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addStructVisualizer(QString("&") + textCursor().selectedText()); } return; } } void SeerEditorWidgetSourceArea::setQuickBreakpoint (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; // If there is a breakpoint on the line, toggle it. if (hasBreakpointLine(lineno)) { // Toggle the breakpoint. // Enable if disabled. Disable if enabled. if (breakpointLineEnabled(lineno) == false) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); }else{ // Emit the disable breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); } // Otherwise, do a quick create of a new breakpoint. }else{ emit insertBreakpoint(QString("-f --source \"%1\" --line %2").arg(fullname()).arg(lineno)); } } void SeerEditorWidgetSourceArea::setQuickRunToLine (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; // Emit the runToLine signal. emit runToLine(fullname(), lineno); return; } void SeerEditorWidgetSourceArea::showBreakpointToolTip (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; // If there is a breakpoint on the line, ask for its information. if (hasBreakpointLine(lineno)) { _selectedBreakpointPosition = event->pos(); // Emit the info breakpoint signal. emit infoBreakpoint(_selectedBreakpointId, QString("%1").arg(breakpointLineToNumber(lineno))); }else{ _selectedBreakpointPosition = QPoint(); } } void SeerEditorWidgetSourceArea::clearExpression() { _selectedExpressionCursor = QTextCursor(); _selectedExpressionPosition = QPoint(); _selectedExpressionName = ""; _selectedExpressionValue = ""; _selectedBreakpointPosition = QPoint(); } void SeerEditorWidgetSourceArea::setHighlighterSettings (const SeerHighlighterSettings& settings) { _sourceHighlighterSettings = settings; emit highlighterSettingsChanged(); } const SeerHighlighterSettings& SeerEditorWidgetSourceArea::highlighterSettings () const { return _sourceHighlighterSettings; } void SeerEditorWidgetSourceArea::setHighlighterEnabled (bool flag) { _sourceHighlighterEnabled = flag; emit highlighterSettingsChanged(); } bool SeerEditorWidgetSourceArea::highlighterEnabled () const { return _sourceHighlighterEnabled; } void SeerEditorWidgetSourceArea::setEditorFont (const QFont& font) { setFont(font); /* * None of the tabstops work. Setting tabstops never look the same * as replacing tabs with spaces. Not sure why. * Tried setTabStopDistance() and setTabArray(). Same problem. * Zooming in and out in QPlainTextEdit will also result in bad * tabstops. QFont f = font; f.setLetterSpacing(QFont::PercentageSpacing, 100); f.setWordSpacing(0.0); f.setFixedPitch(true); f.setKerning(false); setFont(f); qreal tabspace = fontMetrics().horizontalAdvance(QLatin1Char(' ')) * 4; //setTabStopDistance(tabspace); QList tabstops; qreal tabpos = 0.0; for (int i=0; i<100; i++) { tabstops.append(tabpos); tabpos += tabspace; } QTextOption opt = document()->defaultTextOption(); opt.setFlags(QTextOption::ShowTabsAndSpaces); opt.setTabArray(tabstops); document()->setDefaultTextOption(opt); */ } const QFont& SeerEditorWidgetSourceArea::editorFont () const { return font(); } void SeerEditorWidgetSourceArea::setEditorTabSize (int spaces) { _sourceTabSize = spaces; } int SeerEditorWidgetSourceArea::editorTabSize () const { return _sourceTabSize; } void SeerEditorWidgetSourceArea::setExternalEditorCommand (const QString& externalEditorCommand) { _externalEditorCommand = externalEditorCommand; } const QString& SeerEditorWidgetSourceArea::externalEditorCommand () { return _externalEditorCommand; } void SeerEditorWidgetSourceArea::setAutoSourceReload (bool flag) { _autoSourceReload = flag; } bool SeerEditorWidgetSourceArea::autoSourceReload () const { return _autoSourceReload; } void SeerEditorWidgetSourceArea::eraseColorCurrentLine (int lineno) { // Erase color of this line QTextCharFormat lineFormat; lineFormat = highlighterSettings().get("Text"); // Create a selection at the cursor. QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); QTextEdit::ExtraSelection selection; selection.format.setForeground(lineFormat.foreground()); selection.format.setBackground(lineFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = cursor; selection.cursor.clearSelection(); // Add it to the extra selection list. _currentLinesExtraSelections.append(selection); // Refresh all the extra selections. refreshExtraSelections(); } // Read current position in the source area: file name, line, column of cursor and first displayed line SeerEditorWidgetSourceArea::SeerCurrentFile SeerEditorWidgetSourceArea::readCurrentPosition() { SeerCurrentFile info; info.file = QFileInfo(file()).fileName(); // extract file name from full path info.fullname = fullname(); info.cursorRow = currentLine(); info.cursorCol = currentColumn(); info.firstDisplayLine = firstDisplayLine(); return info; } void SeerEditorWidgetSourceArea::handleText (const QString& text) { if (text.startsWith("*stopped")) { // *stopped, // // reason="end-stepping-range", // // frame={addr="0x0000000000400b45", // func="main", // args=[{name="argc",value="1"},{name="argv",value="0x7fffffffd5b8"}], // file="helloworld.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp", // line="7", // arch="i386:x86-64"}, // // thread-id="1", // stopped-threads="all", // core="6" QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "frame=", '{', '}', false); if (frame_text == "") { return; } QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); // Read the file if it hasn't been read before or if we are reading a different file. if (fullname_text != fullname()) { open(fullname_text, QFileInfo(file_text).fileName()); } // Move to the line number. setCurrentLine(line_text.toInt()); return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 10^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _selectedExpressionId) { _selectedExpressionValue = Seer::filterEscapes(Seer::parseFirst(text, "value=", '"', '"', false)); showExpressionTooltip(); } return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,BreakpointTable="))) { // 11^done,BreakpointTable={...} QString id_text = text.section('^', 0,0); if (id_text.toInt() == _selectedBreakpointId && _selectedBreakpointPosition != QPoint()) { handleBreakpointToolTip(_selectedBreakpointPosition, text); } return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." QString id_text = text.section('^', 0,0); if (id_text.toInt() == _selectedExpressionId) { _selectedExpressionValue = Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)); // Refresh the tooltip event. QHelpEvent* event = new QHelpEvent(QEvent::ToolTip, _selectedExpressionPosition, this->mapToGlobal(_selectedExpressionPosition)); QCoreApplication::postEvent(this, event); } if (id_text.toInt() == _selectedBreakpointId && _selectedBreakpointPosition != QPoint()) { qDebug() << "Error displaying breakpoint info as a ToolTip"; } return; }else{ // Ignore others. return; } } void SeerEditorWidgetSourceArea::handleHighlighterSettingsChanged () { // Set base color for background and text color. // Use the palette to do this. Some people say to use the stylesheet. // But the palettle method works (for now). QTextCharFormat format = highlighterSettings().get("Text"); QPalette p = palette(); p.setColor(QPalette::Base, format.background().color()); p.setColor(QPalette::Text, format.foreground().color()); setPalette(p); // Update the syntax highlighter. _sourceHighlighter = SeerSourceHighlighter::getSourceHighlighter(_file, _sourceHighlighterSettings); if (_sourceHighlighter) { if (highlighterEnabled()) { _sourceHighlighter->setDocument(document()); }else{ _sourceHighlighter->setDocument(0); } _sourceHighlighter->setHighlighterSettings(highlighterSettings()); _sourceHighlighter->rehighlight(); } // Note. The margins are automatically updated by their own paint events. // The new highlighter settings will be used. } void SeerEditorWidgetSourceArea::handleWatchFileModified (const QString& path) { Q_UNUSED(path); emit showReloadBar(true); } void SeerEditorWidgetSourceArea::handleBreakpointToolTip (QPoint pos, const QString& text) { // 11^7^done,BreakpointTable={...} // 7^done,BreakpointTable={ // nr_rows="1", // nr_cols="6", // hdr=[], // body=[ // bkpt={ // number="2", // type="breakpoint", // disp="keep", // enabled="y", // addr="0x0000000000400ccd", // func="main(int, char**)", // file="helloworld.cpp", // fullname="/nas/erniep/Development/seer/tests/helloworld/helloworld.cpp", // line="30", // thread-groups=["i1"], // times="1", // original-location="-source /nas/erniep/Development/seer/tests/helloworld/helloworld.cpp -line 30" // } // ] // } QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString tooltiptext; // // Parse 'body' text. // QString body_text = Seer::parseFirst(newtext, "body=", '[', ']', false); if (body_text != "") { QStringList bkpt_list = Seer::parse(body_text, "bkpt=", '{', '}', false); // Construct the tooltip. tooltiptext += "Breakpoint information\n\n"; for (const auto& bkpt_text : bkpt_list) { QStringList item_list = Seer::parseCommaList(bkpt_text); for (const auto& item_text : item_list) { tooltiptext += item_text + "\n"; } break; // Take the first breakpoint in case, somehow, more are returned. } } QToolTip::showText(mapToGlobal(pos), tooltiptext); } // // LineNumber area. // SeerEditorWidgetSourceLineNumberArea::SeerEditorWidgetSourceLineNumberArea(SeerEditorWidgetSourceArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetSourceLineNumberArea::sizeHint () const { return QSize(_editorWidget->lineNumberAreaWidth(), 0); } void SeerEditorWidgetSourceLineNumberArea::paintEvent (QPaintEvent* event) { _editorWidget->lineNumberAreaPaintEvent(event); } void SeerEditorWidgetSourceLineNumberArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToLine(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetSourceLineNumberArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetSourceLineNumberArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetSourceLineNumberArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } // // Breakpoints Area. // SeerEditorWidgetSourceBreakPointArea::SeerEditorWidgetSourceBreakPointArea(SeerEditorWidgetSourceArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetSourceBreakPointArea::sizeHint () const { return QSize(_editorWidget->breakPointAreaWidth(), 0); } void SeerEditorWidgetSourceBreakPointArea::paintEvent (QPaintEvent* event) { _editorWidget->breakPointAreaPaintEvent(event); } void SeerEditorWidgetSourceBreakPointArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToLine(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetSourceBreakPointArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetSourceBreakPointArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else if (event->button() == Qt::LeftButton) { _editorWidget->showBreakpointToolTip(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetSourceBreakPointArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } /*********************************************************************************************************************** * Functions for mouse navigation feature * **********************************************************************************************************************/ void SeerEditorWidgetSourceArea::mousePressEvent(QMouseEvent *event) { // This part is for mouse navigation feature if (event->button() == Qt::XButton1 || event->button() == Qt::XButton2) { // Avoid the default back/forward action _ignoreThumbMouseEvent ++; SeerCurrentFile firstInfo = readCurrentPosition(); // _ignoreThumbMouseEvent will incremented in mousePressEvent when thumb mouse button is pressed but it may not be decremented // if user just click the thumb mouse button without moving the cursor. So here we check if the position is the same as last time, // which means cursor didn't move, then we reset _ignoreThumbMouseEvent to 0 to avoid blocking future events. QTimer::singleShot(30, this, [this, firstInfo]() { // let's give 30 ms for cursor to move to new position SeerCurrentFile secondInfo = readCurrentPosition(); if (firstInfo == secondInfo) { // cursor didn't move _ignoreThumbMouseEvent = 0; // reset to 0 } } ); } // This part is for Go to definition (Ctrl + Click) feature if (event->button() == Qt::LeftButton && _altHeld) { if (_wordUnderCursor != "") { QApplication::restoreOverrideCursor(); signalGotoDefinition(_wordUnderCursor); event->ignore(); // If we don't ignore the event, the cursor will move to that position, which is not desired return; } } QPlainTextEdit::mousePressEvent(event); } void SeerEditorWidgetSourceArea::handleCursorPositionChanged() { // Emit signal to SeerEditorManagerWidget.cpp and save position // Read current position, deploy a timer SeerCurrentFile firstInfo = readCurrentPosition(); if (_ignoreThumbMouseEvent > 0) { _ignoreThumbMouseEvent --; return; } QTimer::singleShot(2000, this, [this, firstInfo]() { SeerCurrentFile secondInfo = readCurrentPosition(); if (firstInfo == secondInfo) { emit addToMouseNavigation(firstInfo); } } ); } /*********************************************************************************************************************** * Go to definition (F12) feature * **********************************************************************************************************************/ void SeerEditorWidgetSourceArea::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Alt) { _altHeld = true; } QPlainTextEdit::keyPressEvent(event); } void SeerEditorWidgetSourceArea::keyReleaseEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Alt) { _altHeld = false; } QPlainTextEdit::keyReleaseEvent(event); } bool SeerEditorWidgetSourceArea::isOverWord(const QPoint &pos) { QTextCursor cursor = cursorForPosition(pos); cursor.select(QTextCursor::WordUnderCursor); return !cursor.selectedText().isEmpty(); } QString SeerEditorWidgetSourceArea::wordUnderCursor(const QPoint &pos) const { int leftMarginOffset = 0; QMargins margins = viewportMargins(); QPoint adjustedPos = pos; // The correct position to get the word under cursor should subtract the left margin // offset (breakpoint area and line number area) leftMarginOffset = margins.left(); adjustedPos.setX(pos.x() - leftMarginOffset); QTextCursor cursor = cursorForPosition(adjustedPos); cursor.select(QTextCursor::WordUnderCursor); return cursor.selectedText(); } void SeerEditorWidgetSourceArea::updateCursor(const QPoint &pos) { // Why not QApplication::setOverrideCursor()? Because QApplication::setOverrideCursor uses internal stack // It causes delay and sometimes the cursor won't change back to normal when we want it to. // In short, QApplication::setOverrideCursor is global and not real time // In contrary, viewport()->setCursor() is local and real time, apply only for that widget, in this case, the text area QPoint localPos = mapFromGlobal(pos); if (!_altHeld) { viewport()->setCursor(Qt::IBeamCursor); _wordUnderCursor = ""; return; } if (!hasFocus()) return; _wordUnderCursor = wordUnderCursor(localPos); if (isValidIdentifier(_wordUnderCursor)) { viewport()->setCursor(Qt::PointingHandCursor); } else { viewport()->setCursor(Qt::IBeamCursor); _wordUnderCursor = ""; } } // Check text and decide if that text is valid identifier (function, variable, type name) bool SeerEditorWidgetSourceArea::isValidIdentifier(const QString& text) { static const QSet keywords = { // Add your C and C++ keywords as QString literals here "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local", "alignas", "alignof", "and", "and_eq", "asm", "bitand", "bitor", "bool", "catch", "char16_t", "char32_t", "class", "compl", "const_cast", "constexpr", "decltype", "delete", "dynamic_cast", "explicit", "export", "false", "friend", "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "reinterpret_cast", "static_assert", "static_cast", "template", "this", "thread_local", "throw", "true", "try", "typeid", "typename", "using", "virtual", "wchar_t", "xor", "xor_eq" }; if (text.isEmpty()) return false; if (keywords.contains(text)) return false; QChar firstChar = text[0]; if (!firstChar.isLetter() && firstChar != '_') return false; for (int i = 1; i < text.size(); ++i) { QChar ch = text[i]; if (!ch.isLetterOrNumber() && ch != '_') return false; } return true; } // When F12 is pressed, try to look for the word under cursor, if it's a valid identifier then emit signalGotoDefinition void SeerEditorWidgetSourceArea::handleGotoDefinition() { QTextCursor cursor = textCursor(); cursor.select(QTextCursor::WordUnderCursor); QString wordUnderCursor = cursor.selectedText(); if (isValidIdentifier(wordUnderCursor)) { emit signalGotoDefinition(wordUnderCursor); } } seer-2.7/src/SeerExecutableFilterProxyModel.h000066400000000000000000000014401516472651200213610ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerExecutableFilterProxyModel : public QSortFilterProxyModel { bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { QFileSystemModel* fileModel = qobject_cast(sourceModel()); QFileInfo file(fileModel->filePath(sourceModel()->index(sourceRow, 0, sourceParent))); /* if (fileModel != NULL) { return false; } */ if (file.isExecutable() == true || file.isHidden()) { return true; }else{ return false; } } }; seer-2.7/src/SeerFunctionBrowserWidget.cpp000066400000000000000000000246651516472651200207550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerFunctionBrowserWidget.h" #include "SeerBreakpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include SeerFunctionBrowserWidget::SeerFunctionBrowserWidget (QWidget* parent) : QWidget(parent) { // Set the state. _id = Seer::createID(); // Construct the UI. setupUi(this); // Setup the widgets functionSearchLineEdit->setPlaceholderText("Search regex..."); functionSearchLineEdit->setClearButtonEnabled(true); functionTreeWidget->setMouseTracking(true); functionTreeWidget->setSortingEnabled(false); functionTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); //functionTreeWidget->resizeColumnToContents(0); // Name functionTreeWidget->resizeColumnToContents(1); // Filename functionTreeWidget->resizeColumnToContents(2); // Line number functionTreeWidget->resizeColumnToContents(3); // Fullname functionTreeWidget->resizeColumnToContents(4); // Type functionTreeWidget->resizeColumnToContents(5); // Description functionTreeWidget->clear(); // Connect things. QObject::connect(functionTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerFunctionBrowserWidget::handleItemDoubleClicked); QObject::connect(functionTreeWidget, &QTreeWidget::itemEntered, this, &SeerFunctionBrowserWidget::handleItemEntered); QObject::connect(functionTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerFunctionBrowserWidget::handleContextMenu); QObject::connect(functionSearchLineEdit, &QLineEdit::returnPressed, this, &SeerFunctionBrowserWidget::handleSearchLineEdit); } SeerFunctionBrowserWidget::~SeerFunctionBrowserWidget () { } void SeerFunctionBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith(QString::number(_id) + "^done,symbols={") && text.endsWith("}")) { functionTreeWidget->clear(); functionTreeWidget->setSortingEnabled(false); functionTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // -symbol-info-functions // ^done,symbols={ // debug=[ // { // filename="elf-init.c", // fullname="/home/abuild/rpmbuild/BUILD/glibc-2.31/csu/elf-init.c", // symbols=[ // { // line="95", // name="__libc_csu_fini", // type="void (void)", // description="void __libc_csu_fini(void);" // }, // { // line="67", // name="__libc_csu_init", // type="void (int, char **, char **)", // description="void __libc_csu_init(int, char **, char **);" // } // ] // }, // ... // ] // } QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false); QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false); for (const auto& filename_entry : filenames_list) { QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false); QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false); QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false); QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false); for (const auto& symbol_entry : symbols_list) { QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false); QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false); QString type_text = Seer::parseFirst(symbol_entry, "type=", '"', '"', false); QString description_text = Seer::parseFirst(symbol_entry, "type=", '"', '"', false); // Skip function entries that have no line number. if (line_text == "") { continue; } // Add the function to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; QFont f0 = item->font(0); f0.setBold(true); item->setFont(0,f0); item->setText(0, name_text); item->setText(1, filename_text); item->setText(2, line_text); item->setText(3, fullname_text); item->setText(4, type_text); item->setText(5, description_text); functionTreeWidget->addTopLevelItem(item); } } // ---- // -symbol-info-functions // ^done,symbols={ // nondebug=[ // {address="0x0000555555554720",name="putchar@plt"}, // {address="0x00007ffff7c40031",name="putchar[cold]"}, // {address="0x00007ffff7c9561e",name="putchar"}, // {address="0x00007ffff7c9579e",name="putchar_unlocked"} // ] // } QString nondebug_text = Seer::parseFirst(text, "nondebug=", '[', ']', false); QStringList nondebug_list = Seer::parse(nondebug_text, "", '{', '}', false); for (const auto& nondebug_entry : nondebug_list) { QString address_text = Seer::parseFirst(nondebug_entry, "address=", '"', '"', false); QString name_text = Seer::parseFirst(nondebug_entry, "name=", '"', '"', false); // Add the function to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; QFont f0 = item->font(0); f0.setBold(true); item->setFont(0,f0); item->setText(0, name_text); item->setText(1, address_text); functionTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } //functionTreeWidget->resizeColumnToContents(0); functionTreeWidget->resizeColumnToContents(1); functionTreeWidget->resizeColumnToContents(2); functionTreeWidget->resizeColumnToContents(3); functionTreeWidget->resizeColumnToContents(4); functionTreeWidget->resizeColumnToContents(5); functionTreeWidget->sortByColumn(0, Qt::AscendingOrder); functionTreeWidget->setSortingEnabled(true); QApplication::restoreOverrideCursor(); } void SeerFunctionBrowserWidget::handleSessionTerminated () { // Delete previous contents. functionTreeWidget->clear(); } void SeerFunctionBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedFile(item->text(1), item->text(3), item->text(2).toInt()); } void SeerFunctionBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QString tip = QString("Function: %1\nFile: %2\nLine: %3\nFullname: %4\nType: %5\nDescription: %6").arg(item->text(0)).arg(item->text(1)).arg(item->text(2)).arg(item->text(3)).arg(item->text(4)).arg(item->text(5)); item->setToolTip(0, tip); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerFunctionBrowserWidget::handleSearchLineEdit () { functionTreeWidget->clear(); functionTreeWidget->setSortingEnabled(false); functionTreeWidget->sortByColumn(-1, Qt::AscendingOrder); //functionTreeWidget->resizeColumnToContents(0); functionTreeWidget->resizeColumnToContents(1); functionTreeWidget->resizeColumnToContents(2); functionTreeWidget->resizeColumnToContents(3); functionTreeWidget->resizeColumnToContents(4); functionTreeWidget->resizeColumnToContents(5); if (functionSearchLineEdit->text() != "") { emit refreshFunctionList(_id, functionSearchLineEdit->text()); } } void SeerFunctionBrowserWidget::refresh () { handleSearchLineEdit(); } void SeerFunctionBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = functionTreeWidget->itemAt(pos); if (item == 0) { return; } // Create the menu actions. QAction* createBreakpointAction; QAction* createSkipAction; createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint in function: \"%1\"").arg(item->text(0)), this); createSkipAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create skip for function: \"%1\"").arg(item->text(0)), this); QMenu menu("Breakpoints", this); menu.setTitle("Breakpoints"); menu.addAction(createBreakpointAction); menu.addAction(createSkipAction); // Launch the menu. Get the response. QAction* action = menu.exec(functionTreeWidget->mapToGlobal(pos + QPoint(0,20))); // Do nothing. if (action == 0) { return; } if (action == createBreakpointAction) { SeerBreakpointCreateDialog dlg(this); dlg.setFunctionName(item->text(0)); dlg.setLineNumber(item->text(2)); dlg.setFilename(item->text(3)); int ret = dlg.exec(); if (ret == 0) { return; } // Emit the create breakpoint signal. emit insertBreakpoint(dlg.breakpointText()); return; } if (action == createSkipAction) { // Emit the create skip signal. emit addSkip("function", item->text(0)); return; } } seer-2.7/src/SeerFunctionBrowserWidget.h000066400000000000000000000027161516472651200204130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerFunctionBrowserWidget.h" class SeerFunctionBrowserWidget : public QWidget, protected Ui::SeerFunctionBrowserWidgetForm { Q_OBJECT public: explicit SeerFunctionBrowserWidget (QWidget* parent = 0); ~SeerFunctionBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (); void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); void handleContextMenu (const QPoint& pos); signals: void refreshFunctionList (int id, const QString& functionRegex); void selectedFile (QString file, QString fullname, int lineno); void insertBreakpoint (QString breakpoint); void addSkip (const QString& skipMode, const QString& skipParameters); protected: private: int _id; }; seer-2.7/src/SeerFunctionBrowserWidget.ui000066400000000000000000000035241516472651200205770ustar00rootroot00000000000000 SeerFunctionBrowserWidgetForm 0 0 730 698 Function Browser 6 Function File/Address Line Full Name Type Description Search in the list of functions. "*" is allowed. QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerGdbConfigPage.cpp000066400000000000000000000073161516472651200170710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerGdbConfigPage.h" #include "SeerUtl.h" #include #include #include SeerGdbConfigPage::SeerGdbConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Connect things. QObject::connect(gdbProgramToolButton, &QToolButton::clicked, this, &SeerGdbConfigPage::handleGdbProgramToolButton); // Setup the defaults. reset(); } SeerGdbConfigPage::~SeerGdbConfigPage() { } QString SeerGdbConfigPage::gdbProgram () const { return gdbProgramLineEdit->text(); } QString SeerGdbConfigPage::gdbLauncher () const { return gdbLauncherLineEdit->text(); } QString SeerGdbConfigPage::gdbArguments () const { return gdbArgumentsLineEdit->text(); } bool SeerGdbConfigPage::gdbAsyncMode () const { return gdbAsyncModeCheckBox->isChecked(); } bool SeerGdbConfigPage::gdbNonStopMode () const { return gdbNonStopModeCheckBox->isChecked(); } bool SeerGdbConfigPage::gdbHandleTerminatingException () const { return gdbHandleTerminateExceptionCheckBox->isChecked(); } bool SeerGdbConfigPage::gdbRandomizeStartAddress () const { return gdbRandomizeStartAddressCheckBox->isChecked(); } bool SeerGdbConfigPage::gdbEnablePrettyPrinting () const { return gdbEnablePrettyPrintingCheckBox->isChecked(); } QString SeerGdbConfigPage::gdbRemoteTargetType () const { return gdbRemoteTargetTypeCombo->currentText(); } QString SeerGdbConfigPage::gdbArchitectureType () const { QString type = gdbArchitectureLineEdit->text(); if (type == "") type = "auto"; return type; } void SeerGdbConfigPage::setGdbProgram (const QString& program) { gdbProgramLineEdit->setText(program); } void SeerGdbConfigPage::setGdbLauncher (const QString& launcher) { return gdbLauncherLineEdit->setText(launcher); } void SeerGdbConfigPage::setGdbArguments (const QString& arguments) { gdbArgumentsLineEdit->setText(arguments); } void SeerGdbConfigPage::setGdbAsyncMode (bool flag) { gdbAsyncModeCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbNonStopMode (bool flag) { gdbNonStopModeCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbHandleTerminatingException (bool flag) { gdbHandleTerminateExceptionCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbRandomizeStartAddress (bool flag) { gdbRandomizeStartAddressCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbEnablePrettyPrinting (bool flag) { gdbEnablePrettyPrintingCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbRemoteTargetType (const QString& type) { gdbRemoteTargetTypeCombo->setCurrentText(type); } void SeerGdbConfigPage::setGdbArchitectureType (const QString& type) { gdbArchitectureLineEdit->setText(type); } void SeerGdbConfigPage::reset () { #ifdef SEER_GDB_NAME setGdbProgram(STRINGIFY(SEER_GDB_NAME)); #else setGdbProgram("/usr/bin/gdb"; #endif #ifdef SEER_GDB_LAUNCHER setGdbLauncher(STRINGIFY(SEER_GDB_LAUNCHER)); #else setGdbLauncher(""); #endif setGdbArguments("--interpreter=mi"); setGdbAsyncMode(true); setGdbNonStopMode(false); setGdbHandleTerminatingException(true); setGdbRandomizeStartAddress(false); setGdbEnablePrettyPrinting(true); setGdbRemoteTargetType("extended-remote"); setGdbArchitectureType("auto"); } void SeerGdbConfigPage::handleGdbProgramToolButton () { QString program = QFileDialog::getOpenFileName(this, "Select a gdb program to use as the debugger.", gdbProgram(), "", nullptr, QFileDialog::DontUseNativeDialog); if (program != "") { setGdbProgram(program); } } seer-2.7/src/SeerGdbConfigPage.h000066400000000000000000000046521516472651200165360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerGdbConfigPage.h" class SeerGdbConfigPage : public QWidget, protected Ui::SeerGdbConfigPage { Q_OBJECT public: explicit SeerGdbConfigPage (QWidget* parent = 0); ~SeerGdbConfigPage (); QString gdbProgram () const; QString gdbLauncher () const; QString gdbArguments () const; bool gdbAsyncMode () const; bool gdbNonStopMode () const; bool gdbHandleTerminatingException () const; bool gdbRandomizeStartAddress () const; bool gdbEnablePrettyPrinting () const; QString gdbRemoteTargetType () const; QString gdbArchitectureType () const; void setGdbProgram (const QString& program); void setGdbLauncher (const QString& launcher); void setGdbArguments (const QString& arguments); void setGdbAsyncMode (bool flag); void setGdbNonStopMode (bool flag); void setGdbHandleTerminatingException (bool flag); void setGdbRandomizeStartAddress (bool flag); void setGdbEnablePrettyPrinting (bool flag); void setGdbRemoteTargetType (const QString& type); void setGdbArchitectureType (const QString& type); void reset (); protected slots: void handleGdbProgramToolButton (); }; seer-2.7/src/SeerGdbConfigPage.ui000066400000000000000000000373041516472651200167240ustar00rootroot00000000000000 SeerGdbConfigPage 0 0 788 881 SeerGdbConfigPage Gdb Settings GDB program Specify the path and name of the gdb debugger. true Open a file dialog to locate the gdb debugger. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg GDB arguments Arguments to pass to the gdb debugger. true GDB launcher The program, if needed, to launch the gdb binary. false If needed, program and arguments to launch gdb. true Turn gdb 'async' mode on or off. Async mode Allow other threads to continue if any thread reaches a breakpoint. Non-stop mode Randomize the process start address. Randomize start address Handle terminating exceptions when calling functions. Handle terminating-exception Show variables with gdb's 'pretty-printing' system. Enable pretty-printing Remote target type Select the type of remote target connection. remote extended-remote Qt::Horizontal 385 20 Architecture type Executable architecture type. true Qt::Horizontal 385 20 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify an alternate gdb program and alternate gdb flags. </span></p> <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; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Changing many of these require saving the new configuration and restarting Seer to take effect</span>.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Note, Seer relies on the &quot;mi&quot; interpreter that is built into gdb. If a different debugger is used, it must provide that. So, usually, the &quot;--interpreter=mi&quot; argument is a must.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sometimes gdb needs to be launched by another program. For example, under flatpak, gdb needs to be launched by flatpak-spawn. This can be defined when compiling Seer. See the CMakefile.txt file. Or manually set here. Normally, this does not need to be set. This launcher is also used for launching RR.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Async mode allows all gdb actions to happen in the background. This allows interrupting of a running program possible. Note, this is disabled for 'connect' mode as background commands may overwhelm the gdbserver.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Non-stop mode, when turned on, will allow other threads to continue to run while another thread reaches a breakpoint.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The gdb debugger normally starts the process at the same address each time. The program's start address can be randomized.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A terminating-exception can happen when gdb is asked to call a function in your program. Like printing the return value from a function. If the function throws an exception, gdb can handle it by suppressing the exception or allowing the program to terminate. See:</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace'; color:#24292f; background-color:transparent;"> unwind-on-terminating-exception on|off</span></p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enabling pretty-printing allows gdb to present certain variables (like std::string) in a pleasing way. Otherwise, the contents of the variables are presented in their full description. (See gdb 'pretty-printing'). Once enabled, it can not be turned off for the Seer session.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When connecting to a gdbserver (or the like), you can set gdb's remote target type to:</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">* remote</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">* extended-remote</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Extended remote is generally suggested but may not be supported by all gdbserver programs. If you experience a slowness starting Seer, try &quot;remote&quot;.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Architecture Type sets the target's architecture type. The value can be &quot;auto&quot;, in addition of one of the support architectures your version of gdb supports.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Run this command in gdb to see a full list of architectures supported by your version of gdb.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> (gdb) set architecture</p> <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> <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> seer-2.7/src/SeerGdbLogWidget.cpp000066400000000000000000000034341516472651200167510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerGdbLogWidget.h" #include "SeerUtl.h" #include #include #include #include SeerGdbLogWidget::SeerGdbLogWidget (QWidget* parent) : SeerLogWidget(parent) { } SeerGdbLogWidget::~SeerGdbLogWidget () { } void SeerGdbLogWidget::processText (const QString& text) { QString str; // Remove leading "~" // Remove leading "&" // Remove leading "@" switch (text.front().unicode()) { case QChar('~').unicode(): case QChar('&').unicode(): case QChar('@').unicode(): str = text.mid(1); // Remove leading """ if (str.front() == '"') { str = str.mid(1); } // Remove trailing """ if (str.back() == '"') { str.chop(1); } break; default: str = text; } // https://github.com/epasveer/seer/issues/238 str = Seer::unescape(str); // Add timestamp. if (isTimeStampEnabled()) { QString text = QString("[") + QTime::currentTime().toString("hh:mm:ss.zz") + QString("] ") + str; // Write the string to the log. textEdit->insertPlainText(text); }else{ // Write the string to the log. textEdit->insertPlainText(str); } // If there is breakpoint message (via a manual command), ask // for the breakpoint list to be refreshed. // // Breakpoint 2 at 0x403a40: file explorer.cpp, line 78. // if (str.contains(QRegularExpression("^Breakpoint ([0-9]+) at (0[xX][0-9a-fA-F]+): file (.*\\,) (line) ([0-9]+)"))) { emit refreshBreakpointsList(); } } seer-2.7/src/SeerGdbLogWidget.h000066400000000000000000000007331516472651200164150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerLogWidget.h" class SeerGdbLogWidget : public SeerLogWidget { Q_OBJECT public: explicit SeerGdbLogWidget (QWidget* parent = 0); ~SeerGdbLogWidget (); void processText (const QString& text); signals: void refreshBreakpointsList (); }; seer-2.7/src/SeerGdbWidget.cpp000066400000000000000000005254511516472651200163170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerGdbWidget.h" #include "SeerLogWidget.h" #include "SeerMemoryVisualizerWidget.h" #include "SeerArrayVisualizerWidget.h" #include "SeerMatrixVisualizerWidget.h" #include "SeerStructVisualizerWidget.h" #include "SeerVarVisualizerWidget.h" #include "SeerImageVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static QLoggingCategory LC("seer.gdbwidget"); SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) { _executableName = ""; _executableArguments = ""; _executableWorkingDirectory = ""; _executableBreakpointsFilename = ""; _executableBreakpointFunctionName = ""; _executableConnectHostPort = ""; _executableRRTraceDirectory = ""; _executableCoreFilename = ""; _executablePid = 0; _gdbMonitor = 0; _gdbProcess = 0; #ifdef SEER_GDB_NAME _gdbProgram = STRINGIFY(SEER_GDB_NAME); #else _gdbProgram = "/usr/bin/gdb"; #endif #ifdef SEER_GDB_LAUNCHER _gdbLauncher = STRINGIFY(SEER_GDB_LAUNCHER); #else _gdbLauncher = ""; #endif _gdbArguments = "--interpreter=mi"; _gdbASyncMode = true; _gdbNonStopMode = false; _gdbServerDebug = false; _assemblyDisassemblyFlavor = "att"; _gdbHandleTerminatingException = true; _gdbRandomizeStartAddress = false; _gdbEnablePrettyPrinting = true; _gdbRemoteTargetType = "extended-remote"; _gdbRecordMode = ""; _gdbRecordDirection = ""; setIsQuitting(false); setNewExecutableFlag(true); setupUi(this); // Create the gdb process. _gdbProcess = new QProcess(this); // Create the gdb monitor. _gdbMonitor = new GdbMonitor(this); _gdbMonitor->setProcess(_gdbProcess); // Handle the app's 'quit' event, in case we want to do things before exiting. QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &SeerGdbWidget::handleAboutToQuit); // Connect things. QObject::connect(commandLogsWidget, &SeerCommandLogsWidget::executeGdbCommand, this, &SeerGdbWidget::handleManualCommandExecute); QObject::connect(_gdbProcess, &QProcess::readyReadStandardOutput, _gdbMonitor, &GdbMonitor::handleReadyReadStandardOutput); QObject::connect(_gdbProcess, &QProcess::readyReadStandardError, _gdbMonitor, &GdbMonitor::handleReadyReadStandardError); QObject::connect(_gdbProcess, static_cast(&QProcess::finished), this, &SeerGdbWidget::handleGdbProcessFinished); // ??? Do we care about the gdb process ending? For now, terminate Seer. QObject::connect(_gdbProcess, static_cast(&QProcess::errorOccurred), this, &SeerGdbWidget::handleGdbProcessErrored); QObject::connect(_gdbMonitor, &GdbMonitor::tildeTextOutput, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::ampersandTextOutput, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::atsignTextOutput, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, commandLogsWidget->seerOutputLog(), &SeerSeerLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->seerOutputLog(), &SeerSeerLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, commandLogsWidget->seerOutputLog(), &SeerSeerLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, editorManagerWidget, &SeerEditorManagerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, editorManagerWidget, &SeerEditorManagerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->typeBrowserWidget(), &SeerTypeBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->staticBrowserWidget(), &SeerStaticBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->libraryBrowserWidget(), &SeerLibraryBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->adaExceptionsBrowserWidget(), &SeerAdaExceptionsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget, &SeerStackManagerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, this, &SeerGdbWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, this, &SeerGdbWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::tildeTextOutput, this, &SeerGdbWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::handleText); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshStackFrames, this, &SeerGdbWidget::handleGdbStackListFrames); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::insertBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInsert); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::insertPrintpoint, this, &SeerGdbWidget::handleGdbPrintpointInsert); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::deleteBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDelete); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::enableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointEnable); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::disableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDisable); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::infoBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInfo); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::runToLine, this, &SeerGdbWidget::handleGdbRunToLine); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::runToAddress, this, &SeerGdbWidget::handleGdbRunToAddress); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addVariableLoggerExpression, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addVariableExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addVariableTrackerExpression, this, &SeerGdbWidget::handleGdbDataAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshVariableTrackerValues, this, &SeerGdbWidget::handleGdbDataListValues); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::evaluateVariableExpression, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::handleEvaluateVariableExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::requestAssembly, this, &SeerGdbWidget::handleGdbGetAssembly); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::requestSourceAndAssembly, this, &SeerGdbWidget::handleGdbGetSourceAndAssembly); QObject::connect(sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::refreshSourceList, this, &SeerGdbWidget::handleGdbExecutableSources); QObject::connect(sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::refreshFunctionList, this, &SeerGdbWidget::handleGdbExecutableFunctions); QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::insertBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInsert); QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::addSkip, this, &SeerGdbWidget::handleGdbSkipAdd); QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(sourceLibraryManagerWidget->typeBrowserWidget(), &SeerTypeBrowserWidget::refreshTypeList, this, &SeerGdbWidget::handleGdbExecutableTypes); QObject::connect(sourceLibraryManagerWidget->typeBrowserWidget(), &SeerTypeBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(sourceLibraryManagerWidget->staticBrowserWidget(), &SeerStaticBrowserWidget::refreshVariableList, this, &SeerGdbWidget::handleGdbExecutableVariables); QObject::connect(sourceLibraryManagerWidget->staticBrowserWidget(), &SeerStaticBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(sourceLibraryManagerWidget->libraryBrowserWidget(), &SeerLibraryBrowserWidget::refreshLibraryList, this, &SeerGdbWidget::handleGdbExecutableLibraries); QObject::connect(sourceLibraryManagerWidget->adaExceptionsBrowserWidget(), &SeerAdaExceptionsBrowserWidget::refreshAdaExceptions, this, &SeerGdbWidget::handleGdbAdaListExceptions); QObject::connect(sourceLibraryManagerWidget->adaExceptionsBrowserWidget(), &SeerAdaExceptionsBrowserWidget::insertCatchpoint, this, &SeerGdbWidget::handleGdbCatchpointInsert); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::refreshSkipList, this, &SeerGdbWidget::handleGdbSkipList); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::addSkip, this, &SeerGdbWidget::handleGdbSkipAdd); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::deleteSkips, this, &SeerGdbWidget::handleGdbSkipDelete); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::enableSkips, this, &SeerGdbWidget::handleGdbSkipEnable); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::disableSkips, this, &SeerGdbWidget::handleGdbSkipDisable); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::refreshStackFrames, this, &SeerGdbWidget::handleGdbStackListFrames); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::selectedFrame, this, &SeerGdbWidget::handleGdbStackSelectFrame); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::selectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleOpenAddress); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::maybeSelectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleMaybeOpenAddress); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::refreshStackArguments, this, &SeerGdbWidget::handleGdbStackListArguments); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addVariableLoggerExpression, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addVariableExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addVariableTrackerExpression, this, &SeerGdbWidget::handleGdbDataAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::refreshVariableTrackerValues, this, &SeerGdbWidget::handleGdbDataListExpressions); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::refreshStackLocals, this, &SeerGdbWidget::handleGdbStackListLocals); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addVariableLoggerExpression, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addVariableExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addVariableTrackerExpression, this, &SeerGdbWidget::handleGdbDataAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::refreshVariableTrackerValues, this, &SeerGdbWidget::handleGdbDataListExpressions); QObject::connect(stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::refreshStackPointer, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::refreshStackDump, this, QOverload::of(&SeerGdbWidget::handleGdbMemoryEvaluateExpression)); QObject::connect(stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(stackManagerWidget, &SeerStackManagerWidget::refreshThreadFrames, this, &SeerGdbWidget::handleGdbThreadListFrames); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::refreshVariableTrackerNames, this, &SeerGdbWidget::handleGdbDataListExpressions); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::refreshVariableTrackerValues, this, &SeerGdbWidget::handleGdbDataListValues); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addVariableExpression, this, &SeerGdbWidget::handleGdbDataAddExpression); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::deleteVariableExpressions, this, &SeerGdbWidget::handleGdbDataDeleteExpressions); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::refreshRegisterNames, this, &SeerGdbWidget::handleGdbRegisterListNames); QObject::connect(variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::refreshRegisterValues, this, &SeerGdbWidget::handleGdbRegisterListValues); QObject::connect(variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::setRegisterValue, this, &SeerGdbWidget::handleGdbRegisterSetValue); QObject::connect(variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::refreshSignalNames, this, &SeerGdbWidget::handleGdbSignalListNames); QObject::connect(variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::refreshSignalValues, this, &SeerGdbWidget::handleGdbSignalListValues); QObject::connect(variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::setSignalValue, this, &SeerGdbWidget::handleGdbSignalSetValue); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::refreshThreadIds, this, &SeerGdbWidget::handleGdbThreadListIds); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::refreshThreadFrames, this, &SeerGdbWidget::handleGdbThreadListFrames); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::selectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleOpenAddress); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::maybeSelectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleMaybeOpenAddress); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::selectedThread, this, &SeerGdbWidget::handleGdbThreadSelectId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::nextThreadId, this, &SeerGdbWidget::handleGdbNextThreadId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::stepThreadId, this, &SeerGdbWidget::handleGdbStepThreadId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::finishThreadId, this, &SeerGdbWidget::handleGdbFinishThreadId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::continueThreadId, this, &SeerGdbWidget::handleGdbContinueThreadId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::interruptThreadId, this, &SeerGdbWidget::handleGdbInterruptThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::refreshThreadIds, this, &SeerGdbWidget::handleGdbThreadListIds); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::selectedThread, this, &SeerGdbWidget::handleGdbThreadSelectId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::nextThreadId, this, &SeerGdbWidget::handleGdbNextThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::stepThreadId, this, &SeerGdbWidget::handleGdbStepThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::finishThreadId, this, &SeerGdbWidget::handleGdbFinishThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::continueThreadId, this, &SeerGdbWidget::handleGdbContinueThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::interruptThreadId, this, &SeerGdbWidget::handleGdbInterruptThreadId); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::refreshThreadGroups, this, &SeerGdbWidget::handleGdbThreadListGroups); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::runThreadGroup, this, &SeerGdbWidget::handleGdbRunThreadGroup); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::startThreadGroup, this, &SeerGdbWidget::handleGdbStartThreadGroup); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::continueThreadGroup, this, &SeerGdbWidget::handleGdbContinueThreadGroup); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::interruptThreadGroup, this, &SeerGdbWidget::handleGdbInterruptThreadGroup); QObject::connect(threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::refreshAdaTasks, this, &SeerGdbWidget::handleGdbAdaListTasks); QObject::connect(threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::selectedThread, this, &SeerGdbWidget::handleGdbThreadSelectId); QObject::connect(threadManagerWidget, &SeerThreadManagerWidget::schedulerLockingModeChanged, this, &SeerGdbWidget::handleGdbSchedulerLockingMode); QObject::connect(threadManagerWidget, &SeerThreadManagerWidget::scheduleMultipleModeChanged, this, &SeerGdbWidget::handleGdbScheduleMultipleMode); QObject::connect(threadManagerWidget, &SeerThreadManagerWidget::forkFollowsModeChanged, this, &SeerGdbWidget::handleGdbForkFollowMode); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::deleteBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDelete); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::enableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointEnable); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::disableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDisable); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::insertBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInsert); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::addBreakpointCondition, this, &SeerGdbWidget::handleGdbBreakpointCondition); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::addBreakpointIgnore, this, &SeerGdbWidget::handleGdbBreakpointIgnore); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::addBreakpointCommands, this, &SeerGdbWidget::handleGdbBreakpointCommands); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::selectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleOpenAddress); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::maybeSelectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleMaybeOpenAddress); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::refreshWatchpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::deleteWatchpoints, this, &SeerGdbWidget::handleGdbWatchpointDelete); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::enableWatchpoints, this, &SeerGdbWidget::handleGdbWatchpointEnable); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::disableWatchpoints, this, &SeerGdbWidget::handleGdbWatchpointDisable); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::insertWatchpoint, this, &SeerGdbWidget::handleGdbWatchpointInsert); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::addBreakpointCondition, this, &SeerGdbWidget::handleGdbBreakpointCondition); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::addBreakpointIgnore, this, &SeerGdbWidget::handleGdbBreakpointIgnore); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::addBreakpointCommands, this, &SeerGdbWidget::handleGdbBreakpointCommands); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::refreshCatchpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::deleteCatchpoints, this, &SeerGdbWidget::handleGdbCatchpointDelete); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::enableCatchpoints, this, &SeerGdbWidget::handleGdbCatchpointEnable); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::disableCatchpoints, this, &SeerGdbWidget::handleGdbCatchpointDisable); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::insertCatchpoint, this, &SeerGdbWidget::handleGdbCatchpointInsert); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::addBreakpointCondition, this, &SeerGdbWidget::handleGdbBreakpointCondition); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::addBreakpointIgnore, this, &SeerGdbWidget::handleGdbBreakpointIgnore); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::addBreakpointCommands, this, &SeerGdbWidget::handleGdbBreakpointCommands); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::refreshPrintpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::deletePrintpoints, this, &SeerGdbWidget::handleGdbPrintpointDelete); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::enablePrintpoints, this, &SeerGdbWidget::handleGdbPrintpointEnable); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::disablePrintpoints, this, &SeerGdbWidget::handleGdbPrintpointDisable); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::insertPrintpoint, this, &SeerGdbWidget::handleGdbPrintpointInsert); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::addBreakpointCondition, this, &SeerGdbWidget::handleGdbBreakpointCondition); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::addBreakpointIgnore, this, &SeerGdbWidget::handleGdbBreakpointIgnore); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::addBreakpointCommand, this, &SeerGdbWidget::handleGdbBreakpointCommand); QObject::connect(commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::refreshCheckpointsList, this, &SeerGdbWidget::handleGdbCheckpointList); QObject::connect(commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::insertCheckpoint, this, &SeerGdbWidget::handleGdbCheckpointInsert); QObject::connect(commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::selectCheckpoint, this, &SeerGdbWidget::handleGdbCheckpointSelect); QObject::connect(commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::deleteCheckpoints, this, &SeerGdbWidget::handleGdbCheckpointDelete); QObject::connect(this, &SeerGdbWidget::assemblyConfigChanged, editorManagerWidget, &SeerEditorManagerWidget::handleAssemblyConfigChanged); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget, &SeerStackManagerWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::sessionTerminated, editorManagerWidget, &SeerEditorManagerWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->staticBrowserWidget(), &SeerStaticBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->libraryBrowserWidget(), &SeerLibraryBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->adaExceptionsBrowserWidget(), &SeerAdaExceptionsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget, &SeerStackManagerWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::handleSessionTerminated); QObject::connect(leftCenterRightSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved); QObject::connect(sourceLibraryVariableManagerSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved); QObject::connect(sourceCommandLogsSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved); QObject::connect(stackThreadManagerSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved); QObject::connect(commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshFunctionList, this, &SeerGdbWidget::handleGdbExecutableFunctions); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshVariableList, this, &SeerGdbWidget::handleGdbExecutableVariables); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshTypeList, this, &SeerGdbWidget::handleGdbExecutableTypes); #if SEER_GDB_LOGOUT == 1 // Direct all GdbWidget and GdbMonitor log to GDB Log, for debugging QObject::connect(this, &SeerGdbWidget::gdbCommandLogout, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::allTextOutput, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); #endif QObject::connect(this, &SeerGdbWidget::stateChanged, editorManagerWidget, &SeerEditorManagerWidget::handleGdbStateChanged); // Restore window settings. readSettings(); } SeerGdbWidget::~SeerGdbWidget () { commandLogsWidget->deleteConsole(); if (_gdbMonitor) { delete _gdbMonitor; } if (_gdbProcess) { _gdbProcess->kill(); _gdbProcess->waitForFinished(); delete _gdbProcess; } } GdbMonitor* SeerGdbWidget::gdbMonitor () { return _gdbMonitor; } QProcess* SeerGdbWidget::gdbProcess () { return _gdbProcess; } void SeerGdbWidget::setExecutableName (const QString& executableName) { _executableName = executableName; setNewExecutableFlag(true); } const QString& SeerGdbWidget::executableName () const { return _executableName; } void SeerGdbWidget::setExecutableSymbolName (const QString& executableSymbolName) { _executableSymbolName = executableSymbolName; setNewExecutableFlag(true); } const QString& SeerGdbWidget::executableSymbolName () const { return _executableSymbolName; } void SeerGdbWidget::setNewExecutableFlag (bool flag) { _newExecutableFlag = flag; } bool SeerGdbWidget::newExecutableFlag () const { return _newExecutableFlag; } void SeerGdbWidget::setExecutableArguments (const QString& executableArguments) { _executableArguments = executableArguments; } const QString& SeerGdbWidget::executableArguments () const { return _executableArguments; } void SeerGdbWidget::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) { _executableWorkingDirectory = executableWorkingDirectory; } const QString& SeerGdbWidget::executableWorkingDirectory () const { return _executableWorkingDirectory; } void SeerGdbWidget::setExecutableBreakpointsFilename (const QString& breakpointsFilename) { _executableBreakpointsFilename = breakpointsFilename; } const QString& SeerGdbWidget::executableBreakpointsFilename () const { return _executableBreakpointsFilename; } void SeerGdbWidget::setExecutableBreakpointFunctionName (const QString& nameoraddress) { _executableBreakpointFunctionName = nameoraddress; } const QString& SeerGdbWidget::executableBreakpointFunctionName () const { return _executableBreakpointFunctionName; } void SeerGdbWidget::setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno) { _executableBreakpointSourceName = sourceFilenameAndLineno; } const QString& SeerGdbWidget::executableBreakpointSourceName () const { return _executableBreakpointSourceName; } void SeerGdbWidget::setExecutablePid (int pid) { _executablePid = pid; } int SeerGdbWidget::executablePid () const { return _executablePid; } void SeerGdbWidget::setExecutableConnectHostPort (const QString& connectHostPort) { _executableConnectHostPort = connectHostPort; } const QString& SeerGdbWidget::executableConnectHostPort () const { return _executableConnectHostPort; } void SeerGdbWidget::setExecutableRRTraceDirectory (const QString& rrTraceDirectory) { _executableRRTraceDirectory = rrTraceDirectory; } const QString& SeerGdbWidget::executableRRTraceDirectory () const { return _executableRRTraceDirectory; } void SeerGdbWidget::setExecutableCoreFilename (const QString& coreFilename) { _executableCoreFilename = coreFilename; } const QString& SeerGdbWidget::executableCoreFilename () const { return _executableCoreFilename; } void SeerGdbWidget::setExecutablePreGdbCommands (const QStringList& preGdbCommands) { _executablePreGdbCommands = preGdbCommands; } const QStringList& SeerGdbWidget::executablePreGdbCommands () const { return _executablePreGdbCommands; } void SeerGdbWidget::setExecutablePostGdbCommands (const QStringList& postGdbCommands) { _executablePostGdbCommands = postGdbCommands; } const QStringList& SeerGdbWidget::executablePostGdbCommands () const { return _executablePostGdbCommands; } void SeerGdbWidget::setExecutableLaunchMode (const QString& launchMode) { _executableLaunchMode = launchMode; } const QString& SeerGdbWidget::executableLaunchMode () const { return _executableLaunchMode; } const QString& SeerGdbWidget::executableBreakMode () const { return _executableBreakMode; } void SeerGdbWidget::saveLaunchMode() { _executableLaunchModeBackup = _executableLaunchMode; _executableBreakModeBackup = _executableBreakMode; } void SeerGdbWidget::restoreLaunchMode() { _executableLaunchMode = _executableLaunchModeBackup; _executableBreakMode = _executableBreakModeBackup; } bool SeerGdbWidget::hasBackupLaunchMode () const { if (_executableLaunchModeBackup == "") { return false; } return true; } void SeerGdbWidget::clearBackupLaunchMode () { _executableLaunchModeBackup = ""; _executableBreakModeBackup = ""; } const QString& SeerGdbWidget::backupLaunchMode () const { return _executableLaunchModeBackup; } void SeerGdbWidget::setGdbProgram (const QString& program) { _gdbProgram = program; } QString SeerGdbWidget::gdbProgram () const { return _gdbProgram; } void SeerGdbWidget::setGdbLauncher (const QString& launchProgram) { _gdbLauncher = launchProgram; } QString SeerGdbWidget::gdbLauncher () const { return _gdbLauncher; } void SeerGdbWidget::setGdbArguments (const QString& arguments) { _gdbArguments = arguments; } QString SeerGdbWidget::gdbArguments () const { return _gdbArguments; } void SeerGdbWidget::setGdbProgramOverride (const QString& program) { _gdbProgramOverride = program; } QString SeerGdbWidget::gdbProgramOverride () const { return _gdbProgramOverride; } void SeerGdbWidget::setGdbArgumentsOverride (const QString& arguments) { _gdbArgumentsOverride = arguments; } QString SeerGdbWidget::gdbArgumentsOverride () const { return _gdbArgumentsOverride; } void SeerGdbWidget::setRRProgram (const QString& program) { _gdbRRProgram = program; } QString SeerGdbWidget::rrProgram () const { return _gdbRRProgram; } void SeerGdbWidget::setRRArguments (const QString& arguments) { _gdbRRArguments = arguments; } QString SeerGdbWidget::rrArguments () const { return _gdbRRArguments; } void SeerGdbWidget::setRRGdbArguments (const QString& arguments) { _gdbRRGdbArguments = arguments; } QString SeerGdbWidget::rrGdbArguments () const { return _gdbRRGdbArguments; } void SeerGdbWidget::setGdbAsyncMode (bool flag) { _gdbASyncMode = flag; } bool SeerGdbWidget::gdbAsyncMode () const { return _gdbASyncMode; } void SeerGdbWidget::setGdbNonStopMode (bool flag) { _gdbNonStopMode = flag; } bool SeerGdbWidget::gdbNonStopMode () const { return _gdbNonStopMode; } void SeerGdbWidget::setGdbServerDebug (bool flag) { _gdbServerDebug = flag; } bool SeerGdbWidget::gdbServerDebug () const { return _gdbServerDebug; } void SeerGdbWidget::setGdbHandleTerminatingException (bool flag) { _gdbHandleTerminatingException = flag; } bool SeerGdbWidget::gdbHandleTerminatingException () const { return _gdbHandleTerminatingException; } void SeerGdbWidget::setGdbRandomizeStartAddress (bool flag) { _gdbRandomizeStartAddress = flag; } bool SeerGdbWidget::gdbRandomizeStartAddress () const { return _gdbRandomizeStartAddress; } void SeerGdbWidget::setGdbEnablePrettyPrinting (bool flag) { _gdbEnablePrettyPrinting = flag; } bool SeerGdbWidget::gdbEnablePrettyPrinting () const { return _gdbEnablePrettyPrinting; } void SeerGdbWidget::setGdbRemoteTargetType (const QString& type) { _gdbRemoteTargetType = type; } QString SeerGdbWidget::gdbRemoteTargetType () const { return _gdbRemoteTargetType; } void SeerGdbWidget::setGdbArchitectureType (const QString& type) { _gdbArchitectureType = type; } QString SeerGdbWidget::gdbArchitectureType () const { return _gdbArchitectureType; } void SeerGdbWidget::setGdbRecordMode(const QString& mode) { if (mode == "auto") { if (gdbProgram().contains("udb")) { _gdbRecordMode = "udb"; }else{ _gdbRecordMode = ""; } }else{ _gdbRecordMode = mode; } if (_gdbRecordMode != "rr" && _gdbRecordMode != "udb" && _gdbRecordMode != "") { handleGdbCommand("record " + _gdbRecordMode); } emit recordSettingsChanged(); } QString SeerGdbWidget::gdbRecordMode () const { return _gdbRecordMode; } void SeerGdbWidget::setGdbRecordDirection (const QString& direction) { _gdbRecordDirection = direction; emit recordSettingsChanged(); } QString SeerGdbWidget::gdbRecordDirection () const { return _gdbRecordDirection; } SeerEditorManagerWidget* SeerGdbWidget::editorManager () { return editorManagerWidget; } const SeerEditorManagerWidget* SeerGdbWidget::editorManager () const { return editorManagerWidget; } void SeerGdbWidget::addMessage (const QString& message, QMessageBox::Icon messageType) { commandLogsWidget->messagesBrowser()->addMessage(message, messageType); } void SeerGdbWidget::handleText (const QString& text) { if (text.startsWith("*running,thread-id=\"all\"")) { // Probably a better way to handle all these types of stops. }else if (text.startsWith("*stopped")) { emit stoppingPointReached(); }else if (text.startsWith("=breakpoint-created,")) { handleGdbGenericpointList(); }else if (text.startsWith("=thread-group-started,")) { // =thread-group-started,id="i1",pid="30916" QString pid_text = Seer::parseFirst(text, "pid=", '"', '"', false); //qDebug() << "Inferior pid = " << pid_text; setExecutablePid(pid_text.toLong()); }else if (text.startsWith("=thread-group-exited,")) { handleGdbTerminateExecutable(false); // Scan the output for magic text to refresh the Signal tab. }else if (text.startsWith("~\"@refresh-signal-values\"")) { handleGdbSignalListValues("all"); }else{ // All other text is ignored by this widget. } } void SeerGdbWidget::handleManualCommandExecute (QString command) { // Do nothing if it is blank. if (command == "") { return; } // Execute it. handleGdbCommand(command); } void SeerGdbWidget::handleGdbCommand (const QString& command, bool ignoreErrors) { qCDebug(LC) << "Command=" << command; if (_gdbProcess->state() == QProcess::NotRunning) { if (ignoreErrors == false) { QMessageBox::warning(this, "Seer", QString("The executable has not been started yet or has already exited.\n\n") + "(" + command + ")", QMessageBox::Ok); } return; } QString str = command + "\n"; // Ensure there's a trailing RETURN. QByteArray bytes = str.toUtf8(); // 8-bit Unicode Transformation Format #if SEER_GDB_LOGOUT == 1 // Broadcast this log. For debugging emit gdbCommandLogout("From Widget:" + str); #endif _gdbProcess->write(bytes); // Send the data into the stdin stream of the bash child process } void SeerGdbWidget::handleGdbCommands (const QStringList& commands) { // This may not be as good as using "source file.gdb" because it doesn't // stop on errors. // // Leaving it here, though. for (auto command : commands) { handleGdbCommand(command, true); } } void SeerGdbWidget::handleGdbExit () { handleGdbCommand("-gdb-exit"); } void SeerGdbWidget::handleGdbRunExecutable (const QString& breakMode, bool loadSessionBreakpoints) { qCDebug(LC) << "Starting 'gdb run/start':" << breakMode; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { // Has a executable name been provided? if (executableName() == "") { QMessageBox::warning(this, "Seer", QString("The executable name has not been provided.\n\nUse File->Debug..."), QMessageBox::Ok); break; } _executableBreakMode = breakMode; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Delete the old gdb if there is a new executable. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdb(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } if (gdbAsyncMode()) { handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen. } if (gdbNonStopMode()) { handleGdbCommand("-gdb-set pagination off"); handleGdbCommand("-gdb-set non-stop on"); }else{ handleGdbCommand("-gdb-set non-stop off"); } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. handleGdbTerminalDeviceName(); setExecutableLaunchMode("run"); saveLaunchMode(); setGdbRecordMode("auto"); setExecutablePid(0); // Load the executable, if needed. if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbExecutableLoadBreakpoints(); // Set the program's breakpoints (if any) before running. if (loadSessionBreakpoints) { handleGdbSessionLoadBreakpoints(); } setNewExecutableFlag(false); } // Set or reset some things. handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); if (gdbHandleTerminatingException()) { handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions. }else{ handleGdbCommand("-gdb-set unwind-on-terminating-exception off"); } if (gdbRandomizeStartAddress()) { handleGdbCommand("-gdb-set disable-randomization off"); // Turn on randomization of starting address for process. } if (gdbEnablePrettyPrinting()) { handleGdbCommand("-enable-pretty-printing"); // Turn on pretty-printing. Can not be turned off. } // Set the program's arguments before running. handleGdbExecutableArguments(); // Set a breakpoint for start up if "infunction". if (_executableBreakMode == "infunction" && executableBreakpointFunctionName() != "") { if (executableBreakpointFunctionName().contains(QRegularExpression("^0[xX][0-9a-fA-F]+"))) { handleGdbBreakpointInsert("*" + executableBreakpointFunctionName()); }else{ handleGdbBreakpointInsert("-f --function " + executableBreakpointFunctionName()); } } // Set breakpoints for start up if "insource". if (_executableBreakMode == "insource" && executableBreakpointSourceName() != "") { handleGdbBreakpointsInsert(executableBreakpointSourceName()); } // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // Run the executable. if (_executableBreakMode == "inmain") { handleGdbCommand("-exec-run --all --start"); // Stop in main }else{ handleGdbCommand("-exec-run --all"); // Do not stop in main. But honor other breakpoints that may have been previously set. } // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableName()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb run/start'."; } void SeerGdbWidget::handleGdbAttachExecutable (bool loadSessionBreakpoints) { qCDebug(LC) << "Starting 'gdb attach'."; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { // Has a executable name been provided? if (executableName() == "") { QMessageBox::warning(this, "Seer", QString("The executable name has not been provided.\n\nUse File->Debug..."), QMessageBox::Ok); break; } _executableBreakMode = ""; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Delete the old gdb if there is a new executable. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. // No need to connect to the console in this mode. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdb(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } if (gdbAsyncMode()) { handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen. } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. // Not really needed for 'attach' mode, but do it anyway. handleGdbTerminalDeviceName(); // No console for 'attach' mode but make sure it's reattached. setExecutableLaunchMode("attach"); saveLaunchMode(); setGdbRecordMode("auto"); commandLogsWidget->reattachConsole(); // Load the executable, if needed. if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbExecutableLoadBreakpoints(); // Set the program's breakpoints (if any) before running. if (loadSessionBreakpoints) { handleGdbSessionLoadBreakpoints(); } setNewExecutableFlag(false); } // Set or reset some things. handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); if (gdbHandleTerminatingException()) { handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions. }else{ handleGdbCommand("-gdb-set unwind-on-terminating-exception off"); } // Attach to the executable's pid. handleGdbCommand(QString("-target-attach %1").arg(executablePid())); // Set breakpoints for start up if "insource". if (executableBreakpointSourceName() != "") { handleGdbBreakpointsInsert(executableBreakpointSourceName()); } // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableName()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb attach'."; } void SeerGdbWidget::handleGdbConnectExecutable (bool loadSessionBreakpoints) { qCDebug(LC) << "Starting 'gdb connect'."; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { _executableBreakMode = ""; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Disconnect from the terminal and delete the old gdb if there is a new executable. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdb(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. // Not really needed for 'connect' mode, but do it anyway. handleGdbTerminalDeviceName(); // No console for 'connect' mode but make sure it's reattached. setExecutableLaunchMode("connect"); saveLaunchMode(); setGdbRecordMode("auto"); setExecutablePid(0); commandLogsWidget->reattachConsole(); // Load any 'pre' commands. if (newExecutableFlag() == true) { if (gdbServerDebug()) { handleGdbCommand("-gdb-set debug remote 1"); // Turn on gdbserver debug }else{ handleGdbCommand("-gdb-set debug remote 0"); } handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. } // Connect to the remote gdbserver using the proper remote type. handleGdbCommand(QString("-target-select %1 %2").arg(gdbRemoteTargetType()).arg(executableConnectHostPort())); // Load the executable, if needed. if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbExecutableLoadBreakpoints(); // Set the program's breakpoints (if any) before running. if (loadSessionBreakpoints) { handleGdbSessionLoadBreakpoints(); } setNewExecutableFlag(false); } // Set or reset some things. handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); if (gdbHandleTerminatingException()) { handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions. }else{ handleGdbCommand("-gdb-set unwind-on-terminating-exception off"); } // Set breakpoints for start up if "insource". if (executableBreakpointSourceName() != "") { handleGdbBreakpointsInsert(executableBreakpointSourceName()); } // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableConnectHostPort()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb connect'."; } void SeerGdbWidget::handleGdbRRExecutable (bool loadSessionBreakpoints) { qCDebug(LC) << "Starting 'gdb direct rr'."; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { // Has a executable name been provided? if (executableName() != "") { QMessageBox::warning(this, "Seer", QString("The executable name can't be provided for 'rr' mode."), QMessageBox::Ok); break; } _executableBreakMode = ""; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Disconnect from the console and delete the old gdb, then reconnect. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdbRR(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. handleGdbTerminalDeviceName(); // Set the launch mode. setExecutableLaunchMode("rr"); saveLaunchMode(); setGdbRecordMode("rr"); setGdbRecordDirection(""); setExecutablePid(0); // Load the executable, if needed. // For RR, this will start it. if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbExecutableLoadBreakpoints(); // Set the program's breakpoints (if any) before running. if (loadSessionBreakpoints) { handleGdbSessionLoadBreakpoints(); } setNewExecutableFlag(false); } // Set or reset some things. handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); if (gdbHandleTerminatingException()) { handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions. }else{ handleGdbCommand("-gdb-set unwind-on-terminating-exception off"); } if (gdbEnablePrettyPrinting()) { handleGdbCommand("-enable-pretty-printing"); // Turn on pretty-printing. Can not be turned off. } // Set breakpoints for start up if "insource". if (executableBreakpointSourceName() != "") { handleGdbBreakpointsInsert(executableBreakpointSourceName()); } // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableRRTraceDirectory()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb rr'."; } void SeerGdbWidget::handleGdbCoreFileExecutable () { qCDebug(LC) << "Starting 'gdb corefile'."; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { // Has a executable name been provided? if (executableName() == "") { QMessageBox::warning(this, "Seer", QString("The executable name has not been provided.\n\nUse File->Debug..."), QMessageBox::Ok); break; } _executableBreakMode = ""; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Disconnect from the console and delete the old gdb. No need to reconnect. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. // No need to connect to the console in this mode. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdb(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } if (gdbAsyncMode()) { handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen. } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. // Not really needed for 'core' mode, but do it anyway. handleGdbTerminalDeviceName(); // No console for 'core' mode but make sure it's reattached. setExecutableLaunchMode("corefile"); saveLaunchMode(); setGdbRecordMode("auto"); setExecutablePid(0); commandLogsWidget->reattachConsole(); if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); } setNewExecutableFlag(false); // Load the executable's core file. handleGdbCommand(QString("-target-select core %1").arg(executableCoreFilename())); // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // This is needed for 'core' mode to refresh the stack frame, for some reason. handleGdbStackListFrames(); // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableName()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb corefile'."; } void SeerGdbWidget::handleGdbTerminateExecutable (bool confirm) { while (1) { // Do you really want to restart? if (isGdbRuning() == true) { if (confirm) { int result = QMessageBox::warning(this, "Seer", QString("Terminate current session?"), QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel); if (result == QMessageBox::Cancel) { break; } } handleGdbCommand(QString("save breakpoints /tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid()), true); delay(2); // Give the gdb and 'exit' command. // This should handle detaching from an attached pid. handleGdbCommand("-exec-kill", true); // Kill the gdb. killGdb(); // Print a message. addMessage("Program terminated.", QMessageBox::Warning); // Alert listeners the session has been terminated. emit sessionTerminated(); // Notify the state of the GdbWidget has changed. emit stateChanged(); } break; } } void SeerGdbWidget::handleGdbShutdown () { // Remove session breakpoint file, if any. QFile::remove(QString("/tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid())); // Do nothing if there's not gdb running. if (isGdbRuning() == false) { return; } // We are in no mode now. setExecutableLaunchMode(""); setGdbRecordMode(""); // Give the gdb and 'exit' command. // This should handle detaching from an attached pid. handleGdbExit(); // Kill the gdb. killGdb(); } void SeerGdbWidget::handleGdbRunToLine (QString fullname, int lineno) { if (executableLaunchMode() == "") { return; } QString command = "-exec-until " + fullname + ":" + QString::number(lineno); handleGdbCommand(command); } void SeerGdbWidget::handleGdbRunToAddress (QString address) { if (executableLaunchMode() == "") { return; } QString command = "-exec-until *" +address; handleGdbCommand(command); } void SeerGdbWidget::handleGdbNext () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-next %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbNexti () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-next-instruction %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbStep () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-step %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbStepi () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-step-instruction %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbFinish () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-finish %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbContinue () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-continue %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbReverseNext () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-next --reverse"); } void SeerGdbWidget::handleGdbReverseNexti () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-next-instruction --reverse"); } void SeerGdbWidget::handleGdbReverseStep () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-step --reverse"); } void SeerGdbWidget::handleGdbReverseStepi () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-step-instruction --reverse"); } void SeerGdbWidget::handleGdbReverseFinish () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-finish --reverse"); } void SeerGdbWidget::handleGdbReverseContinue () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-continue --reverse"); } void SeerGdbWidget::handleGdbRecordStart () { if (executableLaunchMode() == "") { return; } if (executableLaunchMode() == "rr" || executableLaunchMode() == "udb") { QMessageBox::warning(this, "Seer", QString("Record 'Start' not available in RR or UDB mode."), QMessageBox::Ok); return; } setGdbRecordMode("full"); setGdbRecordDirection(""); } void SeerGdbWidget::handleGdbRecordStop () { if (executableLaunchMode() == "") { return; } if (executableLaunchMode() == "rr" || executableLaunchMode() == "udb") { QMessageBox::warning(this, "Seer", QString("Record 'Stop' not available in RR or UDB mode."), QMessageBox::Ok); return; } setGdbRecordMode("stop"); setGdbRecordDirection(""); } void SeerGdbWidget::handleGdbRecordForward () { setGdbRecordDirection(""); } void SeerGdbWidget::handleGdbRecordReverse () { setGdbRecordDirection("--reverse"); } void SeerGdbWidget::handleGdbRecordStartStopToggle () { if (gdbRecordMode() == "stop" || gdbRecordMode() == "") { setGdbRecordMode("full"); setGdbRecordDirection(""); }else if (gdbRecordMode() == "full") { setGdbRecordMode("stop"); setGdbRecordDirection(""); }else if (gdbRecordMode() == "rr") { // Don't do anthing. }else if (gdbRecordMode() == "udb") { // Don't do anthing. }else{ setGdbRecordMode("stop"); setGdbRecordDirection(""); } } void SeerGdbWidget::handleGdbRecordDirectionToggle () { if (gdbRecordDirection() == "") { setGdbRecordDirection("--reverse"); }else if (gdbRecordDirection() == "--reverse") { setGdbRecordDirection(""); }else{ setGdbRecordDirection(""); } } void SeerGdbWidget::handleGdbInterrupt () { sendGdbInterrupt(-1); } void SeerGdbWidget::handleGdbInterruptSIGINT () { sendGdbInterrupt(SIGINT); } void SeerGdbWidget::handleGdbInterruptSIGKILL () { sendGdbInterrupt(SIGKILL); } void SeerGdbWidget::handleGdbInterruptSIGFPE () { sendGdbInterrupt(SIGFPE); } void SeerGdbWidget::handleGdbInterruptSIGSEGV () { sendGdbInterrupt(SIGSEGV); } void SeerGdbWidget::handleGdbInterruptSIGUSR1 () { sendGdbInterrupt(SIGUSR1); } void SeerGdbWidget::handleGdbInterruptSIGUSR2 () { sendGdbInterrupt(SIGUSR2); } void SeerGdbWidget::handleGdbRunThreadGroup (QString threadGroup) { if (executableLaunchMode() == "") { return; } if (threadGroup == "") { return; } handleGdbCommand(QString("-exec-run --thread-group %1").arg(threadGroup)); } void SeerGdbWidget::handleGdbStartThreadGroup (QString threadGroup) { if (executableLaunchMode() == "") { return; } if (threadGroup == "") { return; } handleGdbCommand(QString("-exec-run --thread-group %1 --start").arg(threadGroup)); } void SeerGdbWidget::handleGdbContinueThreadGroup (QString threadGroup) { if (executableLaunchMode() == "") { return; } if (threadGroup == "") { return; } handleGdbCommand(QString("-exec-continue %1 --thread-group %2").arg(gdbRecordDirection()).arg(threadGroup)); } void SeerGdbWidget::handleGdbInterruptThreadGroup (QString threadGroup) { if (executableLaunchMode() == "") { return; } if (threadGroup == "") { return; } handleGdbCommand(QString("-exec-interrupt --thread-group %1").arg(threadGroup)); } void SeerGdbWidget::handleGdbNextThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-next --thread %1 %2").arg(threadid).arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbStepThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-step %1 --thread %2").arg(gdbRecordDirection()).arg(threadid)); } void SeerGdbWidget::handleGdbFinishThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-finish %1 --thread %2").arg(gdbRecordDirection()).arg(threadid)); } void SeerGdbWidget::handleGdbContinueThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-continue %1 --thread %2").arg(gdbRecordDirection()).arg(threadid)); } void SeerGdbWidget::handleGdbInterruptThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-interrupt --thread %1").arg(threadid)); } void SeerGdbWidget::handleGdbExecutableSources () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-file-list-exec-source-files"); } void SeerGdbWidget::handleGdbExecutableFunctions (int id, const QString& functionRegex) { if (executableLaunchMode() == "") { return; } if (id <= 0) { return; } if (functionRegex == "") { return; } QApplication::setOverrideCursor(Qt::BusyCursor); handleGdbCommand(QString("%1-symbol-info-functions --include-nondebug --name %2").arg(id).arg(functionRegex)); QApplication::restoreOverrideCursor(); } void SeerGdbWidget::handleGdbExecutableTypes (int id, const QString& typeRegex) { if (executableLaunchMode() == "") { return; } if (id <= 0) { return; } if (typeRegex == "") { return; } //qDebug() << id << typeRegex; handleGdbCommand(QString("%1-symbol-info-types --name %2").arg(id).arg(typeRegex)); } void SeerGdbWidget::handleGdbExecutableVariables (int id, const QString& variableNameRegex, const QString& variableTypeRegex) { if (executableLaunchMode() == "") { return; } if (id <= 0) { return; } if (variableNameRegex == "" && variableTypeRegex == "") { return; } QString command = QString("%1-symbol-info-variables").arg(id); if (variableNameRegex != "") { command += QString(" --name %1").arg(variableNameRegex); } if (variableTypeRegex != "") { command += QString(" --type %1").arg(variableTypeRegex); } handleGdbCommand(command); } void SeerGdbWidget::handleGdbExecutableLibraries () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-file-list-shared-libraries"); } void SeerGdbWidget::handleGdbExecutableName () { if (executableLaunchMode() == "") { return; } //qDebug() << executableName(); //qDebug() << executableSymbolName(); // executableName() is expected to be non-blank. // An executable and no symbol file? Symbols are expected in the executable. if (executableName() != "" && executableSymbolName() == "") { handleGdbCommand(QString("-file-exec-and-symbols \"") + executableName() + "\""); // An executable and a symbol file? Open the executable and symbol files separately. }else if (executableName() != "" && executableSymbolName() != "") { handleGdbCommand(QString("-file-exec-file \"") + executableName() + "\""); handleGdbCommand(QString("-file-symbol-file \"") + executableSymbolName() + "\""); // No executable and a symbol file? Open the symbol files only. }else if (executableName() == "" && executableSymbolName() != "") { handleGdbCommand(QString("-file-symbol-file \"") + executableSymbolName() + "\""); } } void SeerGdbWidget::handleGdbExecutableArguments () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-arguments ") + executableArguments()); } void SeerGdbWidget::handleGdbExecutableWorkingDirectory () { if (executableLaunchMode() == "") { return; } if (executableWorkingDirectory() != "") { handleGdbCommand(QString("-environment-cd \"") + executableWorkingDirectory() + "\""); } } void SeerGdbWidget::handleGdbExecutableLoadBreakpoints () { if (executableBreakpointsFilename() == "") { return; } handleGdbCommand("source -v " + executableBreakpointsFilename()); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbExecutablePreCommands () { for (const auto& i : _executablePreGdbCommands) { handleGdbCommand(i); } } void SeerGdbWidget::handleGdbExecutablePostCommands () { for (const auto& i : _executablePostGdbCommands) { handleGdbCommand(i); } } void SeerGdbWidget::handleGdbSessionLoadBreakpoints () { handleGdbCommand(QString("source -v /tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid())); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbSessionSaveBreakpoints () { handleGdbCommand(QString("source -v /tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid())); } void SeerGdbWidget::handleGdbTerminalDeviceName () { if (commandLogsWidget->console()->terminalDeviceName() != "") { handleGdbCommand(QString("-inferior-tty-set ") + commandLogsWidget->console()->terminalDeviceName()); }else{ qWarning() << "Can't set TTY name because the name is blank."; } } void SeerGdbWidget::handleGdbStackListFrames () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-stack-list-frames"); } void SeerGdbWidget::handleGdbStackSelectFrame (int frameno) { if (executableLaunchMode() == "") { return; } // This is not supported anymore with gdbmi. // handleGdbCommand(QString("-stack-select-frame %1").arg(frameno)); // So resort to calling the non-gdbmi version. handleGdbCommand(QString("frame %1").arg(frameno)); emit stoppingPointReached(); } void SeerGdbWidget::handleGdbStackListLocals () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-stack-list-variables --all-values"); } void SeerGdbWidget::handleGdbStackListArguments () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-stack-list-arguments --all-values"); } void SeerGdbWidget::handleGdbGenericpointList () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-list"); } void SeerGdbWidget::handleGdbBreakpointDelete (QString breakpoints) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-delete " + breakpoints); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointEnable (QString breakpoints) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-enable " + breakpoints); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointDisable (QString breakpoints) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-disable " + breakpoints); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointInfo (int breakpointid, QString breakpoint) { if (executableLaunchMode() == "") { return; } QString str = QString("%1-break-info %2").arg(breakpointid).arg(breakpoint); handleGdbCommand(str); } void SeerGdbWidget::handleGdbBreakpointsInsert (QString breakpoints) { if (executableLaunchMode() == "") { return; } QStringList breakpointlist = breakpoints.split(','); for (const QString& breakpoint : breakpointlist) { handleGdbBreakpointInsert(breakpoint); } handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointInsert (QString breakpoint) { qDebug() << breakpoint; if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-insert " + breakpoint); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointCondition (QString breakpoint, QString condition) { if (executableLaunchMode() == "") { return; } QString str = condition.replace('"', "\\\""); // Quote " characters. handleGdbCommand("-break-condition " + breakpoint + " \"" + condition + "\""); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointIgnore (QString breakpoint, QString count) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-after " + breakpoint + " " + count); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointCommand (QString breakpoint, QString command) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-commands " + breakpoint + " \"" + command + "\""); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointCommands (QString breakpoint, QStringList commands) { if (executableLaunchMode() == "") { return; } QString commandstext; for (int i=0; ihandleTextOutput(text); } void SeerGdbWidget::handleGdbDataAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } // Is this one already present? // ??? Emit an error? if (_dataExpressionName.indexOf(expression) >= 0) { return; } // Add it to our list of variables. _dataExpressionName.push_back(expression); _dataExpressionId.push_back(Seer::createID()); // ^done,DataExpressionAdded={ // id="2", // expression="a" // } QString text = QString("^done,DataExpressionAdded={id=\"%1\",expression=\"%2\"}").arg(_dataExpressionId.back()).arg(_dataExpressionName.back()); //qDebug() << text; gdbMonitor()->handleTextOutput(text); } void SeerGdbWidget::handleGdbDataDeleteExpressions (QString expressionids) { if (executableLaunchMode() == "") { // Clear expression list. _dataExpressionId.clear(); _dataExpressionName.clear(); return; } // ^done,DataExpressionDeleted={ // entry={id="2", expression="a"}, // entry={id="3", expression="a"} // } QString text; text += "^done,DataExpressionDeleted={"; if (expressionids == "*") { bool first = true; for (int i=0; i<_dataExpressionId.size(); i++) { if (first == false) { text += ","; } text += "entry={id=\"" + QString::number(_dataExpressionId[i]) + "\",expression=\"" + _dataExpressionName[i] + "\"}"; first = false; } _dataExpressionId.clear(); _dataExpressionName.clear(); }else{ QStringList ids = expressionids.split(' ', Qt::SkipEmptyParts); bool first = true; for (int i=0; ihandleTextOutput(text); } void SeerGdbWidget::handleGdbMemoryAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerMemoryVisualizerWidget* w = new SeerMemoryVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerMemoryVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerMemoryVisualizerWidget::handleText); QObject::connect(w, &SeerMemoryVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerMemoryVisualizerWidget::evaluateMemoryExpression, this, QOverload::of(&SeerGdbWidget::handleGdbMemoryEvaluateExpression)); QObject::connect(w, &SeerMemoryVisualizerWidget::evaluateAsmExpression, this, &SeerGdbWidget::handleGdbAsmEvaluateExpression); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbArrayAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerArrayVisualizerWidget* w = new SeerArrayVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerArrayVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerArrayVisualizerWidget::handleText); QObject::connect(w, &SeerArrayVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerArrayVisualizerWidget::evaluateMemoryExpression, this, &SeerGdbWidget::handleGdbArrayEvaluateExpression); // Tell the visualizer what variable to use. w->setAVariableName(expression); } void SeerGdbWidget::handleGdbMatrixAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerMatrixVisualizerWidget* w = new SeerMatrixVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerMatrixVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerMatrixVisualizerWidget::handleText); QObject::connect(w, &SeerMatrixVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerMatrixVisualizerWidget::evaluateMemoryExpression, this, &SeerGdbWidget::handleGdbArrayEvaluateExpression); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbStructAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerStructVisualizerWidget* w = new SeerStructVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerStructVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerStructVisualizerWidget::handleText); QObject::connect(w, &SeerStructVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerStructVisualizerWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(w, &SeerStructVisualizerWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(w, &SeerStructVisualizerWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(w, &SeerStructVisualizerWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbStructAddExpression); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbVarAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerVarVisualizerWidget* w = new SeerVarVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerVarVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerVarVisualizerWidget::handleText); QObject::connect(w, &SeerVarVisualizerWidget::varObjCreate, this, &SeerGdbWidget::handleGdbVarObjCreate); QObject::connect(w, &SeerVarVisualizerWidget::varObjListChildren, this, &SeerGdbWidget::handleGdbVarObjListChildren); QObject::connect(w, &SeerVarVisualizerWidget::varObjUpdate, this, &SeerGdbWidget::handleGdbVarObjUpdate); QObject::connect(w, &SeerVarVisualizerWidget::varObjAssign, this, &SeerGdbWidget::handleGdbVarObjAssign); QObject::connect(w, &SeerVarVisualizerWidget::varObjDelete, this, &SeerGdbWidget::handleGdbVarObjDelete); QObject::connect(w, &SeerVarVisualizerWidget::varObjAttributes, this, &SeerGdbWidget::handleGdbVarObjAttributes); QObject::connect(w, &SeerVarVisualizerWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(w, &SeerVarVisualizerWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(w, &SeerVarVisualizerWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(w, &SeerVarVisualizerWidget::addVarVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbImageAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerImageVisualizerWidget* w = new SeerImageVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerImageVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerImageVisualizerWidget::handleText); QObject::connect(w, &SeerImageVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerImageVisualizerWidget::evaluateMemoryExpression, this, QOverload::of(&SeerGdbWidget::handleGdbMemoryEvaluateExpression)); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbMemoryEvaluateExpression (int expressionid, QString address, int count) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes " + address + " " + QString::number(count)); } void SeerGdbWidget::handleGdbMemoryEvaluateExpression (int expressionid, QString address, int offset, int count) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes -o " + QString::number(offset) + " " + address + " " + QString::number(count)); } void SeerGdbWidget::handleGdbAsmEvaluateExpression (int expressionid, QString address, int count, int mode) { // -data-disassemble -s $pc -e "$pc + 96" -- 2 if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("%1-data-disassemble -s \"%2 - %3\" -e \"%4 + %5\" -- %6").arg(expressionid).arg(address).arg(0).arg(address).arg(count).arg(mode)); } void SeerGdbWidget::handleGdbArrayEvaluateExpression (int expressionid, QString address, int count) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes " + address + " " + QString::number(count)); } void SeerGdbWidget::handleGdbGetAssembly (QString address) { if (executableLaunchMode() == "") { return; } //qDebug() << "Getting assembly for address" << address << "for mode" << assemblyDisassemblyMode(); QString command; if (assemblyDisassemblyMode() == "length") { command = QString("-data-disassemble -s \"%1\" -e \"%1 + %2\" -- 2").arg(address).arg(assemblyDisassemblyBytes()); }else if (assemblyDisassemblyMode() == "function") { command = QString("-data-disassemble -a \"%1\" -- 2").arg(address); }else{ command = QString("-data-disassemble -a \"%1\" -- 2").arg(address); } //qDebug() << command; handleGdbCommand(command); } void SeerGdbWidget::handleGdbGetSourceAndAssembly (QString address) { if (executableLaunchMode() == "") { return; } //qDebug() << "Getting source and assembly for address" << address << "for mode" << assemblyDisassemblyMode(); QString command; if (assemblyDisassemblyMode() == "length") { command = QString("-data-disassemble -s \"%1\" -e \"%1 + %2\" -- 5").arg(address).arg(assemblyDisassemblyBytes()); }else if (assemblyDisassemblyMode() == "function") { command = QString("-data-disassemble -a \"%1\" -- 5").arg(address); }else{ command = QString("-data-disassemble -a \"%1\" -- 5").arg(address); } //qDebug() << command; handleGdbCommand(command); } void SeerGdbWidget::handleGdbMemoryVisualizer () { handleGdbMemoryAddExpression(""); } void SeerGdbWidget::handleGdbArrayVisualizer () { handleGdbArrayAddExpression(""); } void SeerGdbWidget::handleGdbMatrixVisualizer () { handleGdbMatrixAddExpression(""); } void SeerGdbWidget::handleGdbStructVisualizer () { handleGdbStructAddExpression(""); } void SeerGdbWidget::handleGdbVarVisualizer () { handleGdbVarAddExpression(""); } void SeerGdbWidget::handleGdbImageVisualizer () { handleGdbImageAddExpression(""); } void SeerGdbWidget::handleSplitterMoved (int pos, int index) { Q_UNUSED(pos); Q_UNUSED(index); //qDebug() << "Splitter moved to " << pos << index; writeSettings(); } void SeerGdbWidget::handleGdbAssemblyDisassemblyFlavor () { if (_assemblyDisassemblyFlavor != "") { handleGdbCommand(QString("-gdb-set disassembly-flavor ") + _assemblyDisassemblyFlavor); } } void SeerGdbWidget::handleGdbAssemblySymbolDemangling () { if (_assemblySymbolDemangling != "") { handleGdbCommand(QString("-gdb-set print asm-demangle ") + _assemblySymbolDemangling); } } void SeerGdbWidget::handleGdbProcessFinished (int exitCode, QProcess::ExitStatus exitStatus) { //qDebug() << "Gdb process finished. Exit code =" << exitCode << "Exit status =" << exitStatus; // Warn if gdb exits only if we are in some kind of run mode. if (executableLaunchMode() != "") { QMessageBox::warning(this, "Seer", QString("The GDB program exited unexpectedly.\n\n") + QString("Exit code=%1 Exit status=%2").arg(exitCode).arg(exitStatus) + "\n\n" + QString("'%1 %2'").arg(_gdbProcess->program()).arg(_gdbProcess->arguments().join(' ')) + "\n\n" + QString("Please restart Seer."), QMessageBox::Ok); } } void SeerGdbWidget::handleGdbProcessErrored (QProcess::ProcessError errorStatus) { //qDebug() << "Error launching gdb process. Error =" << errorStatus; if (errorStatus == QProcess::FailedToStart) { QMessageBox::warning(this, "Seer", QString("Unable to launch the GDB program.\n\n") + QString("'%1 %2'").arg(_gdbProcess->program()).arg(_gdbProcess->arguments().join(' ')) + "\n\n" + QString("Error status=%1").arg(errorStatus), QMessageBox::Ok); } } void SeerGdbWidget::handleAboutToQuit () { // Detect if we're exiting Seer. setIsQuitting(true); } void SeerGdbWidget::writeSettings () { //qDebug() << "Write Settings"; QSettings settings; settings.beginGroup("mainwindowsplitters"); { settings.setValue("leftCenterRightSplitter", leftCenterRightSplitter->saveState()); settings.setValue("sourceCommandLogsSplitter", sourceCommandLogsSplitter->saveState()); settings.setValue("sourceLibraryVariableManagerSplitter", sourceLibraryVariableManagerSplitter->saveState()); settings.setValue("stackThreadManagerSplitter", stackThreadManagerSplitter->saveState()); } settings.endGroup(); settings.beginGroup("consolewindow"); { settings.setValue("mode", consoleMode()); settings.setValue("scrolllines", consoleScrollLines()); }settings.endGroup(); settings.beginWriteArray("sourcealternatedirectories"); { QStringList directories = sourceAlternateDirectories(); for (int i = 0; i < directories.size(); ++i) { settings.setArrayIndex(i); settings.setValue("directory", directories[i]); } } settings.endArray(); settings.beginWriteArray("sourceignorefilepatters"); { QStringList patterns = sourceIgnoreFilePatterns(); for (int i = 0; i < patterns.size(); ++i) { settings.setArrayIndex(i); settings.setValue("pattern", patterns[i]); } } settings.endArray(); settings.beginWriteArray("sourcemiscfilepatterns"); { QStringList patterns = sourceMiscFilePatterns(); for (int i = 0; i < patterns.size(); ++i) { settings.setArrayIndex(i); settings.setValue("pattern", patterns[i]); } } settings.endArray(); settings.beginWriteArray("sourcesourcefilepatterns"); { QStringList patterns = sourceSourceFilePatterns(); for (int i = 0; i < patterns.size(); ++i) { settings.setArrayIndex(i); settings.setValue("pattern", patterns[i]); } } settings.endArray(); settings.beginWriteArray("sourceheaderfilepatterns"); { QStringList patterns = sourceHeaderFilePatterns(); for (int i = 0; i < patterns.size(); ++i) { settings.setArrayIndex(i); settings.setValue("pattern", patterns[i]); } } settings.endArray(); settings.beginGroup("assembly"); { settings.setValue("showassemblytabonstartupmode", assemblyShowAssemblyTabOnStartupMode()); settings.setValue("keepassemblytabontop", assemblyKeepAssemblyTabOnTop()); settings.setValue("assemblydisassemblyflavor", assemblyDisassemblyFlavor()); settings.setValue("assemblysymboldemagling", assemblySymbolDemagling()); settings.setValue("assemblyregisterformat", assemblyRegisterFormat()); settings.setValue("assemblyshowaddresscolumn", assemblyShowAddressColumn()); settings.setValue("assemblyshowoffsetcolumn", assemblyShowOffsetColumn()); settings.setValue("assemblyshowopcodecolumn", assemblyShowOpcodeColumn()); settings.setValue("assemblyshowsourcelines", assemblyShowSourceLines()); settings.setValue("assemblydisassemblymode", assemblyDisassemblyMode()); settings.setValue("assemblydisassemblybytes", assemblyDisassemblyBytes()); } settings.endGroup(); } void SeerGdbWidget::readSettings () { QSettings settings; int size; settings.beginGroup("mainwindowsplitters"); { leftCenterRightSplitter->restoreState(settings.value("leftCenterRightSplitter").toByteArray()); sourceCommandLogsSplitter->restoreState(settings.value("sourceCommandLogsSplitter").toByteArray()); sourceLibraryVariableManagerSplitter->restoreState(settings.value("sourceLibraryVariableManagerSplitter").toByteArray()); stackThreadManagerSplitter->restoreState(settings.value("stackThreadManagerSplitter").toByteArray()); } settings.endGroup(); settings.beginGroup("consolewindow"); { setConsoleMode(settings.value("mode", "attached").toString()); setConsoleScrollLines(settings.value("scrolllines", 1000).toInt()); } settings.endGroup(); size = settings.beginReadArray("sourcealternatedirectories"); { QStringList directories; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); directories << settings.value("directory").toString(); } setSourceAlternateDirectories(directories); } settings.endArray(); size = settings.beginReadArray("sourceignorefilepatters"); { QStringList patterns; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); patterns << settings.value("pattern").toString(); } setSourceIgnoreFilePatterns(patterns); } settings.endArray(); if (settings.childGroups().contains("sourcemiscfilepatterns")) { size = settings.beginReadArray("sourcemiscfilepatterns"); { QStringList patterns; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); patterns << settings.value("pattern").toString(); } setSourceMiscFilePatterns(patterns); } settings.endArray(); } if (settings.childGroups().contains("sourcesourcefilepatterns")) { size = settings.beginReadArray("sourcesourcefilepatterns"); { QStringList patterns; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); patterns << settings.value("pattern").toString(); } setSourceSourceFilePatterns(patterns); } settings.endArray(); } if (settings.childGroups().contains("sourceheaderfilepatterns")) { size = settings.beginReadArray("sourceheaderfilepatterns"); { QStringList patterns; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); patterns << settings.value("pattern").toString(); } setSourceHeaderFilePatterns(patterns); } settings.endArray(); } settings.beginGroup("assembly"); { setAssemblyShowAssemblyTabOnStartupMode( settings.value("showassemblytabonstartupmode", "never").toString()); setAssemblyKeepAssemblyTabOnTop( settings.value("keepassemblytabontop", true).toBool()); setAssemblyDisassemblyFlavor( settings.value("assemblydisassemblyflavor", "att").toString()); setAssemblySymbolDemagling( settings.value("assemblysymboldemagling", "on").toString()); setAssemblyRegisterFormat( settings.value("assemblyregisterformat", "Natural").toString()); setAssemblyShowAddressColumn( settings.value("assemblyshowaddresscolumn", true).toBool()); setAssemblyShowOffsetColumn( settings.value("assemblyshowoffsetcolumn", false).toBool()); setAssemblyShowOpcodeColumn( settings.value("assemblyshowopcodecolumn", false).toBool()); setAssemblyShowSourceLines( settings.value("assemblyshowsourcelines", false).toBool()); setAssemblyDisassemblyMode( settings.value("assemblydisassemblymode", "function").toString(), settings.value("assemblydisassemblybytes", "256").toInt()); } settings.endGroup(); } bool SeerGdbWidget::isQuitting () const { return _isQuitting; } void SeerGdbWidget::setIsQuitting (bool f) { _isQuitting = f; } bool SeerGdbWidget::isGdbRuning () const { if (_gdbProcess->state() == QProcess::NotRunning) { return false; } return true; } bool SeerGdbWidget::startGdb () { // Don't do anything, if already running. if (isGdbRuning()) { qWarning() << "Already running"; return false; } // Build the raw command to launch the gdb program. // Later the raw command will be broken into individual strings (via ' ') // that the QProcess object expects. QString rawcommand; // Is a 'launcher' being used? Like 'flatpak-spawn'. if (gdbLauncher() != "") { rawcommand += gdbLauncher() + " "; } // Set the gdb program name to use. if (gdbProgramOverride() != "") { rawcommand += gdbProgramOverride() + " "; }else{ rawcommand += gdbProgram() + " "; } // Build the gdb argument list. if (gdbArgumentsOverride() != "") { rawcommand += gdbArgumentsOverride() + " "; }else{ rawcommand += gdbArguments() + " "; } // Now expand any $VAR environment variables. bool ok; QString expandedcommand = Seer::expandEnv(rawcommand, &ok); //qDebug() << "Raw command : " << rawcommand; //qDebug() << "Expanded command: " << expandedcommand; if (ok == false) { QMessageBox::critical(this, "Error", QString("Can't resolve all environment variables in command to launch gdb:\n'%1'").arg(rawcommand)); return false; } // Split string into words, handling "double quoted" words. QStringList args = Seer::split(expandedcommand); // Extract the program name and create a list of arguments. QString program = args.front(); args.pop_front(); // Give the gdb process the program and the argument list. _gdbProcess->setProgram(program); _gdbProcess->setArguments(args); // We need to set the C language, otherwise the MI interface is translated and our message // filters will not work. QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("LANG", "C"); _gdbProcess->setProcessEnvironment(env); // Start the gdb process. _gdbProcess->start(); //qDebug() << _gdbProcess->state(); return true; } bool SeerGdbWidget::startGdbRR () { // Don't do anything, if already running. if (isGdbRuning()) { qWarning() << "Already running"; return false; } // Does the RR trace directory exist? if (QFile::exists(executableRRTraceDirectory()) == false) { QMessageBox::critical(this, "Seer", QString("The RR trace-directory '" + executableRRTraceDirectory() + "' doesn't exist."), QMessageBox::Ok); return false; } // Build the raw command to launch the RR program. // Later the raw command will be broken into individual strings (via ' ') // that the QProcess object expects. QString rawcommand; // Is a 'launcher' being used? Like 'flatpak-spawn'. if (gdbLauncher() != "") { rawcommand += gdbLauncher() + " "; } // Set the RR program name to use. rawcommand += rrProgram() + " "; rawcommand += rrArguments() + " --tty " + commandLogsWidget->console()->terminalDeviceName() + " " + executableRRTraceDirectory() + " "; // Set any extra gdb arguments that RR may want. if (rrGdbArguments() != "") { rawcommand += "-- " + rrGdbArguments() + " "; } // Now expand any $VAR environment variables. bool ok; QString expandedcommand = Seer::expandEnv(rawcommand, &ok); //qDebug() << "Raw command : " << rawcommand; //qDebug() << "Expanded command: " << expandedcommand; if (ok == false) { QMessageBox::critical(this, "Error", QString("Can't resolve all environment variables in command to launch RR:\n'%1'").arg(rawcommand)); return false; } // Split string into words, handling "double quoted" words. QStringList args = Seer::split(expandedcommand); // Extract the program name and create a list of arguments. QString program = args.front(); args.pop_front(); // Give the gdb process the program and the argument list. _gdbProcess->setProgram(program); _gdbProcess->setArguments(args); // We need to set the C language, otherwise the MI interface is translated and our message // filters will not work. QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("LANG", "C"); _gdbProcess->setProcessEnvironment(env); // Start the gdb process. _gdbProcess->start(); //qDebug() << _gdbProcess->state(); return true; } void SeerGdbWidget::killGdb () { // Don't do anything, if isn't running. if (isGdbRuning() == false) { return; } // Clear the launch mode. setExecutableLaunchMode(""); setGdbRecordMode(""); // Kill the process. _gdbProcess->kill(); // Wait for it to end. _gdbProcess->waitForFinished(); // Sanity check. if (isGdbRuning()) { qWarning() << "Is running but shouldn't be."; } } SeerConsoleWidget* SeerGdbWidget::console () { return commandLogsWidget->console(); } void SeerGdbWidget::setConsoleMode (const QString& mode) { commandLogsWidget->setConsoleMode(mode); } QString SeerGdbWidget::consoleMode () const { return commandLogsWidget->consoleMode(); } void SeerGdbWidget::setConsoleScrollLines (int count) { commandLogsWidget->setConsoleScrollLines(count); } int SeerGdbWidget::consoleScrollLines () const { return commandLogsWidget->consoleScrollLines(); } void SeerGdbWidget::setRememberManualCommandCount (int count) { commandLogsWidget->setRememberManualCommandCount(count); } int SeerGdbWidget::rememberManualCommandCount () const { return commandLogsWidget->rememberManualCommandCount(); } void SeerGdbWidget::clearManualCommandHistory () { commandLogsWidget->clearManualCommandHistory(); } const QStringList& SeerGdbWidget::sourceAlternateDirectories() const { return editorManager()->editorAlternateDirectories(); } void SeerGdbWidget::setSourceAlternateDirectories (const QStringList& alternateDirectories) { editorManager()->setEditorAlternateDirectories(alternateDirectories); } void SeerGdbWidget::setSourceMiscFilePatterns (const QStringList& filePatterns) { sourceLibraryManagerWidget->sourceBrowserWidget()->setMiscFilePatterns(filePatterns); } const QStringList& SeerGdbWidget::sourceMiscFilePatterns () const { return sourceLibraryManagerWidget->sourceBrowserWidget()->miscFilePatterns(); } void SeerGdbWidget::setSourceSourceFilePatterns (const QStringList& filePatterns) { sourceLibraryManagerWidget->sourceBrowserWidget()->setSourceFilePatterns(filePatterns); } const QStringList& SeerGdbWidget::sourceSourceFilePatterns () const { return sourceLibraryManagerWidget->sourceBrowserWidget()->sourceFilePatterns(); } void SeerGdbWidget::setSourceHeaderFilePatterns (const QStringList& filePatterns) { sourceLibraryManagerWidget->sourceBrowserWidget()->setHeaderFilePatterns(filePatterns); } const QStringList& SeerGdbWidget::sourceHeaderFilePatterns () const { return sourceLibraryManagerWidget->sourceBrowserWidget()->headerFilePatterns(); } void SeerGdbWidget::setSourceIgnoreFilePatterns (const QStringList& filePatterns) { _ignoreFilePatterns = filePatterns; sourceLibraryManagerWidget->sourceBrowserWidget()->setIgnoreFilePatterns(sourceIgnoreFilePatterns()); editorManager()->setEditorIgnoreDirectories(sourceIgnoreFilePatterns()); } const QStringList& SeerGdbWidget::sourceIgnoreFilePatterns () const { return _ignoreFilePatterns; } void SeerGdbWidget::setAssemblyShowAssemblyTabOnStartupMode (const QString& mode) { editorManager()->setShowAssemblyTabOnStartupMode(mode); } QString SeerGdbWidget::assemblyShowAssemblyTabOnStartupMode () const { return editorManager()->showAssemblyTabOnStartupMode(); } void SeerGdbWidget::setAssemblyKeepAssemblyTabOnTop (bool flag) { editorManager()->setKeepAssemblyTabOnTop(flag); } bool SeerGdbWidget::assemblyKeepAssemblyTabOnTop () const { return editorManager()->keepAssemblyTabOnTop(); } void SeerGdbWidget::setAssemblyDisassemblyFlavor (const QString& flavor) { _assemblyDisassemblyFlavor = flavor; if (isGdbRuning()) { handleGdbAssemblyDisassemblyFlavor(); emit assemblyConfigChanged(); } } QString SeerGdbWidget::assemblyDisassemblyFlavor () const { return _assemblyDisassemblyFlavor; } void SeerGdbWidget::setAssemblySymbolDemagling (const QString& onoff) { _assemblySymbolDemangling = onoff; if (isGdbRuning()) { handleGdbAssemblySymbolDemangling(); emit assemblyConfigChanged(); } } void SeerGdbWidget::handleGdbSchedulerLockingMode (QString mode) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-gdb-set scheduler-locking %1").arg(mode)); } void SeerGdbWidget::handleGdbScheduleMultipleMode (QString mode) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-gdb-set schedule-multiple %1").arg(mode)); } void SeerGdbWidget::handleGdbForkFollowMode (QString mode) { if (executableLaunchMode() == "") { return; } if (mode == "parent") { handleGdbCommand("-gdb-set follow-fork-mode parent"); handleGdbCommand("-gdb-set detach-on-fork on"); }else if (mode == "child") { handleGdbCommand("-gdb-set follow-fork-mode child"); handleGdbCommand("-gdb-set detach-on-fork on"); }else if (mode == "both") { handleGdbCommand("-gdb-set follow-fork-mode parent"); handleGdbCommand("-gdb-set detach-on-fork off"); }else{ qWarning() << "Invalid 'ForkFollowMode' of '" << mode << "'"; } } void SeerGdbWidget::handleGdbLoadMICommands () { // Don't do anything, if isn't running. if (isGdbRuning() == false) { return; } // Path the MI files in the resources. QString miPath = ":/seer/resources/mi-python/"; // Resource file path QDir miDirectory(miPath); if (!miDirectory.exists()) { qDebug() << "Directory does not exist:" << miPath; return; } // Get list of MI files. QFileInfoList miList = miDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries); // Print the list. qDebug() << "Sourcing scripts from:" << miPath; foreach (QFileInfo miInfo, miList) { // Open the source file from resources. QFile miFile(miInfo.absoluteFilePath()); if (!miFile.exists()) { qDebug().nospace().noquote() << "Resource file '" << miInfo << "' does not exist!"; continue; } // Destination file path in /tmp. QString destinationPath = "/tmp/" + miInfo.fileName(); // Delete possible old temp version, if it exists. if (QFile::exists(destinationPath)) { bool f = QFile::remove(destinationPath); if (f == false) { qDebug().nospace().noquote() << "Old temp Resource file '" << destinationPath << "' can not be deleted!"; continue; } } // Copy to temp. bool f = miFile.copy(destinationPath); if (f == false) { qDebug().nospace().noquote() << "Resource file '" << miInfo << "' can not be copied to '" << destinationPath << "'!"; continue; } // Source it. if (QFile::exists(destinationPath) == false) { qDebug().nospace().noquote() << "Temp Resource file '" << destinationPath << "' does not exist!"; continue; } qDebug() << "source " + miInfo.absoluteFilePath(); QString command = "source " + destinationPath; handleGdbCommand(command); } qDebug() << "Done."; } void SeerGdbWidget::handleGdbSourceScripts () { // Don't do anything, if isn't running. if (isGdbRuning() == false) { return; } // Get setting's config path. QSettings settings; QString configFile = settings.fileName(); if (configFile == "") { return; } QFileInfo configFileInfo(configFile); QString configDirectory = configFileInfo.absolutePath(); // Get a list of files in the "scripts" folder. QString scriptsDirectory = configDirectory + "/scripts"; QDir dir(scriptsDirectory); QStringList scripts = dir.entryList(QDir::Files, QDir::Name); // Source each one. qDebug() << "Sourcing scripts from:" << scriptsDirectory; for (const QString& script : scripts) { QString command = "source " + scriptsDirectory + "/" + script; qDebug() << command; handleGdbCommand(command); } qDebug() << "Done."; } void SeerGdbWidget::handleGdbLoadSkips () { // Don't do anything, if isn't running. if (isGdbRuning() == false) { return; } // Guard agains the remote possibility of no Skip browser if (sourceLibraryManagerWidget->skipBrowserWidget() == nullptr) { return; } sourceLibraryManagerWidget->skipBrowserWidget()->loadSkips(); } void SeerGdbWidget::handleGdbSetArchitectureType () { if (gdbArchitectureType() != "") { handleGdbCommand(QString("set architecture ") + gdbArchitectureType()); } } QString SeerGdbWidget::assemblySymbolDemagling () const { return _assemblySymbolDemangling; } void SeerGdbWidget::setAssemblyShowAddressColumn (bool flag) { editorManager()->setAssemblyShowAddressColumn(flag); } bool SeerGdbWidget::assemblyShowAddressColumn () const { return editorManager()->assemblyShowAddressColumn(); } void SeerGdbWidget::setAssemblyShowOffsetColumn (bool flag) { editorManager()->setAssemblyShowOffsetColumn(flag); } bool SeerGdbWidget::assemblyShowOffsetColumn () const { return editorManager()->assemblyShowOffsetColumn(); } void SeerGdbWidget::setAssemblyShowOpcodeColumn (bool flag) { editorManager()->setAssemblyShowOpcodeColumn(flag); } bool SeerGdbWidget::assemblyShowOpcodeColumn () const { return editorManager()->assemblyShowOpcodeColumn(); } void SeerGdbWidget::setAssemblyShowSourceLines (bool flag) { editorManager()->setAssemblyShowSourceLines(flag); } bool SeerGdbWidget::assemblyShowSourceLines () const { return editorManager()->assemblyShowSourceLines(); } void SeerGdbWidget::setAssemblyRegisterFormat (const QString& format) { _assemblyRegisterFormat = format; variableManagerWidget->registerValuesBrowserWidget()->setRegisterFormat(_assemblyRegisterFormat); } QString SeerGdbWidget::assemblyRegisterFormat () const { return _assemblyRegisterFormat; } void SeerGdbWidget::setAssemblyDisassemblyMode (const QString& mode, int bytes) { _assemblyDisassemblyMode = mode; _assemblyDisassemblyBytes = bytes; } QString SeerGdbWidget::assemblyDisassemblyMode () const { return _assemblyDisassemblyMode; } int SeerGdbWidget::assemblyDisassemblyBytes () const { return _assemblyDisassemblyBytes; } void SeerGdbWidget::sendGdbInterrupt (int signal) { //qDebug() << "Sending an interrupt to the program. Signal =" << signal; if (executableLaunchMode() == "") { return; } if (executablePid() < 1) { QMessageBox::warning(this, "Seer", QString("No executable is running or I don't know the PID of the process."), QMessageBox::Ok); return; } // Use kill() to send the signal to the inferior. // -exec-interrupt does not work for -exec-until when the line // number is not in the current function. In this case, -exec-until // behaves like -exec-continue but -exec-interrupt has no effect. :^( // We do have the ability to use a different signal, though. :^) if (signal < 0) { handleGdbCommand("-exec-interrupt"); }else{ int stat = kill(executablePid(), signal); if (stat < 0) { QMessageBox::warning(this, "Seer", QString("Unable to send signal '%1' to pid %2.\nError = '%3'").arg(strsignal(signal)).arg(executablePid()).arg(strerror(errno)), QMessageBox::Ok); } } } // Deleay N seconds by executing Qt's even loop a bunch of times. // This gives time for certain gdb commands to finish. Like saving the breakpoints before exit. void SeerGdbWidget::delay (int seconds) { QTime dieTime = QTime::currentTime().addSecs(seconds); while (QTime::currentTime() < dieTime) { QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } } seer-2.7/src/SeerGdbWidget.h000066400000000000000000001032771516472651200157620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerConsoleWidget.h" #include "SeerEditorWidgetSource.h" #include "SeerGdbLogWidget.h" #include "SeerSeerLogWidget.h" #include "SeerMessagesBrowserWidget.h" #include "SeerBreakpointsBrowserWidget.h" #include "SeerWatchpointsBrowserWidget.h" #include "SeerCatchpointsBrowserWidget.h" #include "SeerPrintpointsBrowserWidget.h" #include "SeerCheckpointsBrowserWidget.h" #include "GdbMonitor.h" #include #include #include #include "ui_SeerGdbWidget.h" class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { Q_OBJECT public: explicit SeerGdbWidget (QWidget* parent = 0); ~SeerGdbWidget (); GdbMonitor* gdbMonitor (); QProcess* gdbProcess (); void setExecutableName (const QString& executableName); const QString& executableName () const; void setExecutableSymbolName (const QString& executableSymbolName); const QString& executableSymbolName () const; void setNewExecutableFlag (bool flag); bool newExecutableFlag () const; void setExecutableArguments (const QString& executableArguments); const QString& executableArguments () const; void setExecutableWorkingDirectory (const QString& executableWorkingDirectory); const QString& executableWorkingDirectory () const; void setExecutableBreakpointsFilename (const QString& breakpointsFilename); const QString& executableBreakpointsFilename () const; void setExecutableBreakpointFunctionName (const QString& nameoraddress); const QString& executableBreakpointFunctionName () const; void setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno); const QString& executableBreakpointSourceName () const; void setExecutablePid (int pid); int executablePid () const; void setExecutableConnectHostPort (const QString& connectHostPort); const QString& executableConnectHostPort () const; void setExecutableRRTraceDirectory (const QString& rrTraceDirectory); const QString& executableRRTraceDirectory () const; void setExecutableCoreFilename (const QString& coreFilename); const QString& executableCoreFilename () const; void setExecutablePreGdbCommands (const QStringList& preGdbCommands); const QStringList& executablePreGdbCommands () const; void setExecutablePostGdbCommands (const QStringList& postGdbCommands); const QStringList& executablePostGdbCommands () const; void setExecutableLaunchMode (const QString& launchMode); const QString& executableLaunchMode () const; const QString& executableBreakMode () const; // Gdb settings. void setGdbLauncher (const QString& launchProgram); QString gdbLauncher () const; void setGdbProgram (const QString& program); QString gdbProgram () const; void setGdbArguments (const QString& arguments); QString gdbArguments () const; void setGdbProgramOverride (const QString& program); QString gdbProgramOverride () const; void setGdbArgumentsOverride (const QString& arguments); QString gdbArgumentsOverride () const; void setGdbAsyncMode (bool flag); bool gdbAsyncMode () const; void setGdbNonStopMode (bool flag); bool gdbNonStopMode () const; void setGdbServerDebug (bool flag); bool gdbServerDebug () const; void setGdbHandleTerminatingException (bool flag); bool gdbHandleTerminatingException () const; void setGdbRandomizeStartAddress (bool flag); bool gdbRandomizeStartAddress () const; void setGdbEnablePrettyPrinting (bool flag); bool gdbEnablePrettyPrinting () const; void setGdbRemoteTargetType (const QString& type); QString gdbRemoteTargetType () const; void setGdbArchitectureType (const QString& type); QString gdbArchitectureType () const; void setGdbRecordMode (const QString& mode); QString gdbRecordMode () const; void setGdbRecordDirection (const QString& direction); QString gdbRecordDirection () const; SeerConsoleWidget* console (); void setConsoleMode (const QString& mode); QString consoleMode () const; void setConsoleScrollLines (int count); int consoleScrollLines () const; void setRememberManualCommandCount (int count); int rememberManualCommandCount () const; void clearManualCommandHistory (); void setSourceAlternateDirectories (const QStringList& alternateDirectories); const QStringList& sourceAlternateDirectories () const; void setSourceMiscFilePatterns (const QStringList& filePatterns); const QStringList& sourceMiscFilePatterns () const; void setSourceSourceFilePatterns (const QStringList& filePatterns); const QStringList& sourceSourceFilePatterns () const; void setSourceHeaderFilePatterns (const QStringList& filePatterns); const QStringList& sourceHeaderFilePatterns () const; void setSourceIgnoreFilePatterns (const QStringList& filePatterns); const QStringList& sourceIgnoreFilePatterns () const; void setAssemblyShowAssemblyTabOnStartupMode (const QString& mode); QString assemblyShowAssemblyTabOnStartupMode () const; void setAssemblyKeepAssemblyTabOnTop (bool flag); bool assemblyKeepAssemblyTabOnTop () const; void setAssemblyDisassemblyFlavor (const QString& flavor); QString assemblyDisassemblyFlavor () const; void setAssemblySymbolDemagling (const QString& onoff); QString assemblySymbolDemagling () const; void setAssemblyShowAddressColumn (bool flag); bool assemblyShowAddressColumn () const; void setAssemblyShowOffsetColumn (bool flag); bool assemblyShowOffsetColumn () const; void setAssemblyShowOpcodeColumn (bool flag); bool assemblyShowOpcodeColumn () const; void setAssemblyShowSourceLines (bool flag); bool assemblyShowSourceLines () const; void setAssemblyRegisterFormat (const QString& format); QString assemblyRegisterFormat () const; void setAssemblyDisassemblyMode (const QString& mode, int bytes); QString assemblyDisassemblyMode () const; int assemblyDisassemblyBytes () const; // RR settings. void setRRProgram (const QString& program); QString rrProgram () const; void setRRArguments (const QString& arguments); QString rrArguments () const; void setRRGdbArguments (const QString& arguments); QString rrGdbArguments () const; // Editor manager. SeerEditorManagerWidget* editorManager (); const SeerEditorManagerWidget* editorManager () const; // Messages void addMessage (const QString& message, QMessageBox::Icon messageType); // Settings void writeSettings (); void readSettings (); // Gdb bool isGdbRuning () const; void restoreLaunchMode (); void saveLaunchMode (); bool hasBackupLaunchMode () const; void clearBackupLaunchMode (); const QString& backupLaunchMode () const; public slots: void handleText (const QString& text); void handleManualCommandExecute (QString command); void handleGdbCommand (const QString& command, bool ignoreErrors=false); void handleGdbCommands (const QStringList& commands); void handleGdbExit (); void handleGdbRunExecutable (const QString& breakMode, bool loadSessionBreakpoints); void handleGdbAttachExecutable (bool loadSessionBreakpoints); void handleGdbConnectExecutable (bool loadSessionBreakpoints); void handleGdbRRExecutable (bool loadSessionBreakpoints); void handleGdbCoreFileExecutable (); void handleGdbTerminateExecutable (bool confirm=true); void handleGdbShutdown (); void handleGdbRunToLine (QString fullname, int lineno); void handleGdbRunToAddress (QString address); void handleGdbNext (); void handleGdbNexti (); void handleGdbStep (); void handleGdbStepi (); void handleGdbFinish (); void handleGdbContinue (); void handleGdbReverseNext (); void handleGdbReverseNexti (); void handleGdbReverseStep (); void handleGdbReverseStepi (); void handleGdbReverseFinish (); void handleGdbReverseContinue (); void handleGdbRecordStart (); void handleGdbRecordStop (); void handleGdbRecordForward (); void handleGdbRecordReverse (); void handleGdbRecordStartStopToggle (); void handleGdbRecordDirectionToggle (); void handleGdbInterrupt (); void handleGdbInterruptSIGINT (); void handleGdbInterruptSIGKILL (); void handleGdbInterruptSIGFPE (); void handleGdbInterruptSIGSEGV (); void handleGdbInterruptSIGUSR1 (); void handleGdbInterruptSIGUSR2 (); void handleGdbRunThreadGroup (QString threadGroup); void handleGdbStartThreadGroup (QString threadGroup); void handleGdbContinueThreadGroup (QString threadGroup); void handleGdbInterruptThreadGroup (QString threadGroup); void handleGdbNextThreadId (int threadid); void handleGdbStepThreadId (int threadid); void handleGdbFinishThreadId (int threadid); void handleGdbContinueThreadId (int threadid); void handleGdbInterruptThreadId (int threadid); void handleGdbExecutableSources (); void handleGdbExecutableFunctions (int id, const QString& functionRegex); void handleGdbExecutableTypes (int id, const QString& typeRegex); void handleGdbExecutableVariables (int id, const QString& variableNameRegex, const QString& variableTypeRegex); void handleGdbExecutableLibraries (); void handleGdbExecutableName (); void handleGdbExecutableArguments (); void handleGdbExecutableWorkingDirectory (); void handleGdbExecutableLoadBreakpoints (); void handleGdbExecutablePreCommands (); void handleGdbExecutablePostCommands (); void handleGdbSessionLoadBreakpoints (); void handleGdbSessionSaveBreakpoints (); void handleGdbTerminalDeviceName (); void handleGdbStackListFrames (); void handleGdbStackSelectFrame (int frameno); void handleGdbStackListLocals (); void handleGdbStackListArguments (); void handleGdbGenericpointList (); void handleGdbBreakpointDelete (QString breakpoints); void handleGdbBreakpointEnable (QString breakpoints); void handleGdbBreakpointDisable (QString breakpoints); void handleGdbBreakpointInfo (int breakpointid, QString breakpoint); void handleGdbBreakpointsInsert (QString breakpoints); void handleGdbBreakpointInsert (QString breakpoint); void handleGdbBreakpointCondition (QString breakpoint, QString condition); void handleGdbBreakpointIgnore (QString breakpoint, QString count); void handleGdbBreakpointCommand (QString breakpoint, QString commands); void handleGdbBreakpointCommands (QString breakpoint, QStringList commands); void handleGdbBreakpointReload (QStringList breakpointsText); void handleGdbWatchpointReload (QStringList watchpointsText); void handleGdbCatchpointReload (QStringList catchpointsText); void handleGdbWatchpointDelete (QString watchpoints); void handleGdbWatchpointEnable (QString watchpoints); void handleGdbWatchpointDisable (QString watchpoints); void handleGdbWatchpointInsert (QString watchpoint); void handleGdbCatchpointDelete (QString catchpoints); void handleGdbCatchpointEnable (QString catchpoints); void handleGdbCatchpointDisable (QString catchpoints); void handleGdbCatchpointInsert (QString catchpoint); void handleGdbPrintpointDelete (QString breakpoints); void handleGdbPrintpointEnable (QString breakpoints); void handleGdbPrintpointDisable (QString breakpoints); void handleGdbPrintpointInsert (QString type, QString function, QString channel, QString parameters); void handleGdbThreadListFrames (); void handleGdbThreadListIds (); void handleGdbThreadListGroups (); void handleGdbThreadSelectId (int threadid); void handleGdbAdaListTasks (); void handleGdbAdaListExceptions (); void handleGdbSkipList (); void handleGdbSkipAdd (QString skipmode, QString skipparameters); void handleGdbSkipDelete (QString skipids); void handleGdbSkipEnable (QString skipids); void handleGdbSkipDisable (QString skipids); void handleGdbCheckpointList (); void handleGdbCheckpointInsert (); void handleGdbCheckpointSelect (QString id); void handleGdbCheckpointDelete (QString ids); void handleGdbRegisterListNames (); void handleGdbRegisterListValues (QString fmt); void handleGdbRegisterSetValue (QString fmt, QString name, QString value); void handleGdbSignalListNames (); void handleGdbSignalListValues (QString names); void handleGdbSignalSetValue (QString name, QString stop, QString print, QString pass); void handleGdbDataEvaluateExpression (int expressionid, QString expression); void handleGdbVarObjCreate (int expressionid, QString expression); void handleGdbVarObjListChildren (int expressionid, QString objname); void handleGdbVarObjUpdate (int expressionid, QString objname); void handleGdbVarObjAssign (int expressionid, QString objname, QString value); void handleGdbVarObjDelete (int expressionid, QString objname); void handleGdbVarObjAttributes (int objid, QString objname); void handleGdbDataListValues (); void handleGdbDataListExpressions (); void handleGdbDataAddExpression (QString expression); void handleGdbDataDeleteExpressions (QString expressionids); void handleGdbMemoryAddExpression (QString expression); void handleGdbArrayAddExpression (QString expression); void handleGdbMatrixAddExpression (QString expression); void handleGdbStructAddExpression (QString expression); void handleGdbVarAddExpression (QString expression); void handleGdbImageAddExpression (QString expression); void handleGdbMemoryEvaluateExpression (int expressionid, QString address, int count); void handleGdbMemoryEvaluateExpression (int expressionid, QString address, int offset, int count); void handleGdbAsmEvaluateExpression (int expressionid, QString address, int count, int mode); void handleGdbArrayEvaluateExpression (int expressionid, QString address, int count); void handleGdbGetAssembly (QString address); void handleGdbGetSourceAndAssembly (QString address); void handleGdbMemoryVisualizer (); void handleGdbArrayVisualizer (); void handleGdbMatrixVisualizer (); void handleGdbStructVisualizer (); void handleGdbVarVisualizer (); void handleGdbImageVisualizer (); void handleSplitterMoved (int pos, int index); void handleGdbAssemblyDisassemblyFlavor (); void handleGdbAssemblySymbolDemangling (); void handleGdbSchedulerLockingMode (QString mode); void handleGdbScheduleMultipleMode (QString mode); void handleGdbForkFollowMode (QString mode); void handleGdbLoadMICommands (); void handleGdbSourceScripts (); void handleGdbLoadSkips (); void handleGdbSetArchitectureType (); void handleGdbProcessFinished (int exitCode, QProcess::ExitStatus exitStatus); void handleGdbProcessErrored (QProcess::ProcessError errorStatus); void handleAboutToQuit (); signals: void stoppingPointReached (); void sessionTerminated (); void changeWindowTitle (QString title); void assemblyConfigChanged (); void recordSettingsChanged (); void stateChanged (); void gdbCommandLogout (const QString& text); protected: private: bool isQuitting () const; void setIsQuitting (bool f); bool startGdb (); bool startGdbRR (); void killGdb (); void sendGdbInterrupt (int signal); void delay (int seconds); bool _isQuitting; QString _gdbLauncher; QString _gdbProgram; QString _gdbArguments; QString _gdbProgramOverride; QString _gdbArgumentsOverride; QString _gdbRRProgram; QString _gdbRRArguments; QString _gdbRRGdbArguments; bool _gdbASyncMode; bool _gdbNonStopMode; bool _gdbServerDebug; bool _gdbHandleTerminatingException; bool _gdbRandomizeStartAddress; bool _gdbEnablePrettyPrinting; QString _gdbRecordMode; QString _gdbRecordDirection; QString _gdbRemoteTargetType; QString _gdbArchitectureType; QString _assemblyDisassemblyFlavor; QString _assemblySymbolDemangling; QString _assemblyRegisterFormat; QString _assemblyDisassemblyMode; int _assemblyDisassemblyBytes; QString _executableName; QString _executableSymbolName; QString _executableArguments; QString _executableWorkingDirectory; QString _executableBreakpointsFilename; QString _executableBreakpointFunctionName; QString _executableBreakpointSourceName; int _executablePid; QString _executableConnectHostPort; QString _executableRRTraceDirectory; QString _executableCoreFilename; QString _executableLaunchMode; QString _executableBreakMode; QString _executableLaunchModeBackup; QString _executableBreakModeBackup; QStringList _executablePreGdbCommands; QStringList _executablePostGdbCommands; bool _newExecutableFlag; GdbMonitor* _gdbMonitor; QProcess* _gdbProcess; QVector _dataExpressionId; QVector _dataExpressionName; QStringList _ignoreFilePatterns; }; seer-2.7/src/SeerGdbWidget.ui000066400000000000000000000114241516472651200161400ustar00rootroot00000000000000 SeerGdbWidgetForm 0 0 997 567 Form Qt::Horizontal false 10 0 Qt::Vertical false 50 50 50 50 Qt::Vertical false 20 75 30 0 Qt::Vertical false 50 50 50 50 SeerEditorManagerWidget QWidget
SeerEditorManagerWidget.h
1
SeerSourceSymbolLibraryManagerWidget QWidget
SeerSourceSymbolLibraryManagerWidget.h
1
SeerStackManagerWidget QWidget
SeerStackManagerWidget.h
1
SeerThreadManagerWidget QWidget
SeerThreadManagerWidget.h
1
SeerVariableManagerWidget QWidget
SeerVariableManagerWidget.h
1
SeerCommandLogsWidget QWidget
SeerCommandLogsWidget.h
1
seer-2.7/src/SeerHelpPageDialog.cpp000066400000000000000000000047131516472651200172550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerHelpPageDialog.h" #include #include #include #include #include #include #include SeerHelpPageDialog::SeerHelpPageDialog(QDialog* parent) : QDialog(parent) { // Construct the UI. setupUi(this); // Setup the widgets setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer Help"); textBrowser->setOpenExternalLinks(true); // Connect things. QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerHelpPageDialog::handlePrintToolButton); QObject::connect(okPushButton, &QPushButton::clicked, this, &SeerHelpPageDialog::handleOkPushButton); // Restore window settings. readSettings(); } SeerHelpPageDialog::~SeerHelpPageDialog() { } void SeerHelpPageDialog::loadFile (const QString& filename) { // Get the Help text from the file. QFile file(filename); bool f = file.open(QFile::ReadOnly|QFile::Text); if (f == false) { return; } QTextStream stream(&file); QString text = stream.readAll(); // Load it into the browser. loadText(text); } void SeerHelpPageDialog::loadText (const QString& text) { // Put the Help text in as markdown. Move back to the begining. textBrowser->setMarkdown(text); textBrowser->moveCursor(QTextCursor::Start); } void SeerHelpPageDialog::handlePrintToolButton () { QPrinter printer; QPrintDialog* dlg = new QPrintDialog(&printer, this); if (dlg->exec() != QDialog::Accepted) { return; } QTextDocument* document = textBrowser->document(); document->print(&printer); } void SeerHelpPageDialog::handleOkPushButton () { done(QDialog::Accepted); } void SeerHelpPageDialog::writeSettings() { QSettings settings; settings.beginGroup("helpwindow"); { settings.setValue("size", size()); }settings.endGroup(); } void SeerHelpPageDialog::readSettings() { QSettings settings; settings.beginGroup("helpwindow"); { resize(settings.value("size", QSize(600, 600)).toSize()); }settings.endGroup(); } void SeerHelpPageDialog::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QDialog::resizeEvent(event); } seer-2.7/src/SeerHelpPageDialog.h000066400000000000000000000020111516472651200167070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerHelpPageDialog.h" class SeerHelpPageDialog: public QDialog, protected Ui::SeerHelpPageDialogForm { Q_OBJECT public: SeerHelpPageDialog(QDialog* parent = 0); ~SeerHelpPageDialog(); void loadFile (const QString& filename); void loadText (const QString& text); signals: public slots: protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); protected slots: void handlePrintToolButton (); void handleOkPushButton (); private: }; seer-2.7/src/SeerHelpPageDialog.ui000066400000000000000000000042201516472651200171010ustar00rootroot00000000000000 SeerHelpPageDialogForm 0 0 592 352 Dialog 0 100 Print Help page. :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Qt::Horizontal 40 20 Dismiss Help page. OK seer-2.7/src/SeerHexWidget.cpp000066400000000000000000000575221516472651200163460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerHexWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #define byteArrayToType( data, order, precision, type ) \ QDataStream stream( data ); \ stream.setByteOrder( order ); \ stream.setFloatingPointPrecision( precision ); \ type t; \ stream >> t; \ return t; qint8 toQInt8 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, qint8) } quint8 toQUInt8 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, quint8) } qint16 toQInt16 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, qint16) } quint16 toQUInt16 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, quint16) } qint32 toQInt32 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, qint32) } quint32 toQUInt32 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, quint32) } qint64 toQInt64 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, qint64) } quint64 toQUInt64 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, quint64) } float toQFloat32 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, float) } double toQFloat64 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::DoublePrecision, double) } SeerHexWidget::SeerHexWidget(QWidget* parent) : QWidget(parent), _pdata(NULL) { // Construct the UI. setupUi(this); // Setup the widgets QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); plainTextEdit->setFont(font); plainTextEdit->setFocusPolicy(Qt::StrongFocus); plainTextEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse); plainTextEdit->setWordWrapMode(QTextOption::NoWrap); _memoryMode = SeerHexWidget::HexMemoryMode; _charMode = SeerHexWidget::AsciiCharMode; _addressOffset = 0; _charWidth = plainTextEdit->fontMetrics().horizontalAdvance(QLatin1Char('9')); _charHeight = plainTextEdit->fontMetrics().height(); _gapAddrHex = 10; // Gap between address and hex fields. _gapHexAscii = 16; // Gap between hex and ascii fields. _highlightByte = -1; setBytesPerLine(16); // Connect things. QObject::connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(showAsLittleEndianCheckBox, &QCheckBox::clicked, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(showUnsignedFloatAsHexCheckBox, &QCheckBox::clicked, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(this, &SeerHexWidget::byteOffsetChanged, this, &SeerHexWidget::handleByteOffsetChanged); } SeerHexWidget::~SeerHexWidget() { if (_pdata) { delete _pdata; } } void SeerHexWidget::setBytesPerLine (int count) { // 3 = 'a0 ' // 4 = '007 ' // 9 = '00011010 ' // 4 = ' 10 ' if (memoryMode() == SeerHexWidget::HexMemoryMode) { _hexCharsPerByte = 3; }else if (memoryMode() == SeerHexWidget::OctalMemoryMode) { _hexCharsPerByte = 4; }else if (memoryMode() == SeerHexWidget::BinaryMemoryMode) { _hexCharsPerByte = 9; }else if (memoryMode() == SeerHexWidget::DecimalMemoryMode) { _hexCharsPerByte = 4; }else{ _hexCharsPerByte = 3; } _bytesPerLine = count; _hexCharsPerLine = _bytesPerLine * _hexCharsPerByte - 1; int posHex = SeerHexWidget::HexFieldWidth * _charWidth + gapAddrHex(); // x position of hex field. int posAscii = posHex + hexCharsPerLine() * _charWidth + gapHexAscii(); // x position of ascii field. setMinimumWidth(posAscii + (bytesPerLine() * _charWidth)); // x position after the ascii field. // Repaint the widget. create(); } int SeerHexWidget::bytesPerLine () const { return _bytesPerLine; } int SeerHexWidget::hexCharsPerLine () const { return _hexCharsPerLine; } int SeerHexWidget::hexCharsPerByte () const { return _hexCharsPerByte; } int SeerHexWidget::nLines () const { return plainTextEdit->blockCount(); } int SeerHexWidget::gapAddrHex () const { return _gapAddrHex; } int SeerHexWidget::gapHexAscii () const { return _gapHexAscii; } void SeerHexWidget::setAddressOffset (unsigned long offset) { _addressOffset = offset; // Repaint the widget. create(); } unsigned long SeerHexWidget::addressOffset () const { return _addressOffset; } unsigned long SeerHexWidget::size () const { if (_pdata) { return _pdata->size(); } return 0; } void SeerHexWidget::setMemoryMode (SeerHexWidget::MemoryMode memoryMode) { _memoryMode = memoryMode; // This repaints the widget with the new memory mode setBytesPerLine(bytesPerLine()); } SeerHexWidget::MemoryMode SeerHexWidget::memoryMode () const { return _memoryMode; } QString SeerHexWidget::memoryModeString () const { if (memoryMode() == SeerHexWidget::HexMemoryMode) { return "hex"; }else if (memoryMode() == SeerHexWidget::OctalMemoryMode) { return "octal"; }else if (memoryMode() == SeerHexWidget::BinaryMemoryMode) { return "binary"; }else if (memoryMode() == SeerHexWidget::DecimalMemoryMode) { return "decimal"; } return "???"; } void SeerHexWidget::setCharMode (SeerHexWidget::CharMode charMode) { _charMode = charMode; // Repaint the widget. create(); } SeerHexWidget::CharMode SeerHexWidget::charMode() const { return _charMode; } QString SeerHexWidget::charModeString () const { if (charMode() == SeerHexWidget::AsciiCharMode) { return "ascii"; }else if (charMode() == SeerHexWidget::Utf8Mode) { return "utf8"; }else if (charMode() == SeerHexWidget::Utf16Mode) { return "utf16"; }else if (charMode() == SeerHexWidget::Utf32Mode) { return "utf32"; }else if (charMode() == SeerHexWidget::EbcdicCharMode) { return "ebcdic"; } return "???"; } QTextDocument* SeerHexWidget::document () { return plainTextEdit->document(); } QString SeerHexWidget::toPlainText () { return plainTextEdit->toPlainText(); } void SeerHexWidget::setData(SeerHexWidget::DataStorage* pData) { if (_pdata) { delete _pdata; } _pdata = pData; // Repaint the widget. create(); } void SeerHexWidget::handleCursorPositionChanged () { // Get the current cursor position. QTextCursor cursor = plainTextEdit->textCursor(); // Is it before the hex values? (address region) if (cursor.positionInBlock() < SeerHexWidget::HexFieldWidth) { emit byteOffsetChanged(-1); return; } // Is is after the hex values? (ascii/utf/ebcdic region) if (cursor.positionInBlock() > SeerHexWidget::HexFieldWidth + hexCharsPerLine()) { emit byteOffsetChanged(-1); return; } int line = cursor.blockNumber(); int col = cursor.positionInBlock() - SeerHexWidget::HexFieldWidth; int byte = (col / hexCharsPerByte()) + (line * bytesPerLine()); _highlightByte = byte; emit byteOffsetChanged(byte); } void SeerHexWidget::handleByteOffsetChanged (int byte) { // Clear all fields. lineEdit_1->setText(""); lineEdit_2->setText(""); lineEdit_3->setText(""); lineEdit_4->setText(""); lineEdit_5->setText(""); lineEdit_6->setText(""); lineEdit_7->setText(""); lineEdit_8->setText(""); lineEdit_9->setText(""); lineEdit_10->setText(""); lineEdit_11->setText(""); lineEdit_12->setText(""); lineEdit_13->setText(""); lineEdit_14->setText(""); // Remove previous highlight. plainTextEdit->setExtraSelections(QList()); // Invalid byte number, do nothing. if (byte < 0) { return; } // If there's no data, do nothing. if (!_pdata) { return; } // Byte past the end, do nothing. if ((unsigned int)byte >= size()) { return; } // Calculate line and position in line. int line = (byte / bytesPerLine()); int pos = byte - (line * bytesPerLine()); int pos_s = SeerHexWidget::HexFieldWidth + (pos * hexCharsPerByte()); int pos_e = pos_s + hexCharsPerByte() - 1; int pos_a = SeerHexWidget::HexFieldWidth + hexCharsPerLine() + pos + 4; // 4 == ' ' .... ' | ' // Highlight the text in the hex region and the ascii region. QList extraSelections; { // Get a cursor to the current line. QTextBlock block = plainTextEdit->document()->findBlockByLineNumber(line); QTextCursor cursor = QTextCursor(block); // Highlight the current hex value. cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, pos_s); cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, pos_e - pos_s + 1); // Add it to the extra selections. QTextEdit::ExtraSelection extra_byte; extra_byte.format.setBackground(plainTextEdit->palette().highlight().color()); extra_byte.cursor = cursor; extraSelections.append(extra_byte); // Highlight the current ascii value. // For Ascii and Ebcdic only. No UTF as it can be variable length encoding. if (charMode() == SeerHexWidget::AsciiCharMode || charMode() == SeerHexWidget::EbcdicCharMode) { cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, pos_a); cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1); // Add it to the extra selections. QTextEdit::ExtraSelection extra_ascii; extra_ascii.format.setBackground(plainTextEdit->palette().highlight().color()); extra_ascii.cursor = cursor; extraSelections.append(extra_ascii); } } plainTextEdit->setExtraSelections(extraSelections); // Set the endian default. QDataStream::ByteOrder byteOrder = QDataStream::BigEndian; if (showAsLittleEndianCheckBox->isChecked()) { byteOrder = QDataStream::LittleEndian; } // Set the 'AsHex' default. bool unsignedAndFloatAsHex = false; if (showUnsignedFloatAsHexCheckBox->isChecked()) { unsignedAndFloatAsHex = true; } // Go through each one and display the value. { QByteArray arr = _pdata->getData(byte, sizeof(char)); // Extract a bytearray from the data for the size of the value we are after. if (arr.size() == sizeof(char)) { // If not the right size, skip it. Near the end of the data. lineEdit_1->setText(QString::number(toQInt8(arr, byteOrder))); // Fill in the signed value. if (unsignedAndFloatAsHex) { // Show unsigned value as hex? if (byteOrder == QDataStream::LittleEndian) { // Swap bytes to handle endianess. std::reverse(arr.begin(), arr.end()); } lineEdit_2->setText("0x"+QString(arr.toHex())); // Print value as hex. }else{ lineEdit_2->setText(QString::number(toQUInt8(arr, byteOrder))); // Print value as a value. } } } { QByteArray arr = _pdata->getData(byte, sizeof(short)); if (arr.size() == sizeof(short)) { lineEdit_3->setText(QString::number(toQInt16(arr, byteOrder))); if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_4->setText("0x"+QString(arr.toHex())); }else{ lineEdit_4->setText(QString::number(toQUInt16(arr, byteOrder))); } } } { QByteArray arr = _pdata->getData(byte, sizeof(float)); if (arr.size() == sizeof(float)) { if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_5->setText("0x"+QString(arr.toHex())); }else{ lineEdit_5->setText(QString::number(toQFloat32(arr, byteOrder))); } } } { QByteArray arr = _pdata->getData(byte, sizeof(int)); if (arr.size() == sizeof(int)) { lineEdit_6->setText(QString::number(toQInt32(arr, byteOrder))); if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_7->setText("0x"+QString(arr.toHex())); }else{ lineEdit_7->setText(QString::number(toQUInt32(arr, byteOrder))); } } } { QByteArray arr = _pdata->getData(byte, sizeof(long int)); if (arr.size() == sizeof(long int)) { lineEdit_8->setText(QString::number(toQInt64(arr, byteOrder))); if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_9->setText("0x"+QString(arr.toHex())); }else{ lineEdit_9->setText(QString::number(toQUInt64(arr, byteOrder))); } } } { QByteArray arr = _pdata->getData(byte, sizeof(double)); if (arr.size() == sizeof(double)) { if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_10->setText("0x"+QString(arr.toHex())); }else{ lineEdit_10->setText(QString::number(toQFloat64(arr, byteOrder))); } } } { QString val; QByteArray arr = _pdata->getData(byte, 4); for (int i=0; isetText(val); } { QString val; QByteArray arr = _pdata->getData(byte, 4); for (int i=0; isetText(val); } { QString val; QByteArray arr = _pdata->getData(byte, 4); for (int i=0; isetText(val); } { QString val; QByteArray arr = _pdata->getData(byte, 4); // Print N bytes in their char value. if (charMode() == SeerHexWidget::AsciiCharMode) { for (int i=0; isetText(val); } } void SeerHexWidget::create () { // Ignore changing of cursor positions. QObject::disconnect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); // Clear the current document. We're going to recreate it. plainTextEdit->clear(); // Clear the checksum. lineEdit_15->setText(""); // If there's no data, do nothing. if (!_pdata) { // Re-enable notification of changing of cursor positions. QObject::connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); return; } // Convert the data to a 'text' string. QString textString = ""; QByteArray data = _pdata->getData(); if (charMode() == SeerHexWidget::AsciiCharMode) { for (int b=0; bcurrentCharFormat(); QTextCharFormat grayFormat = defaultFormat; grayFormat.setBackground(QBrush(Qt::lightGray)); QTextCharFormat greenFormat = defaultFormat; greenFormat.setBackground(QBrush(Qt::green)); // Get a cursor QTextCursor cursor(plainTextEdit->textCursor()); cursor.movePosition(QTextCursor::Start); // Go through the data, one byte at a time. for (int i=0; isetText(crc16str); } handleByteOffsetChanged(_highlightByte); // Re-enable notification of changing of cursor positions. QObject::connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); } SeerHexWidget::DataStorageArray::DataStorageArray(const QByteArray& arr) { _data = arr; } QByteArray SeerHexWidget::DataStorageArray::getData(int position, int length) { return _data.mid(position, length); } QByteArray SeerHexWidget::DataStorageArray::getData() { return _data; } int SeerHexWidget::DataStorageArray::size() { return _data.size(); } seer-2.7/src/SeerHexWidget.h000066400000000000000000000103121516472651200157750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerHexWidget.h" // // Hex Memory viewer widget. // Based on virinext/ QHexView // https://github.com/virinext/QHexView // // MIT License. // class SeerHexWidget: public QWidget, protected Ui::SeerHexWidgetForm { Q_OBJECT public: class DataStorage { public: virtual ~DataStorage() {}; virtual QByteArray getData(int position, int length) = 0; virtual QByteArray getData() = 0; virtual int size() = 0; }; class DataStorageArray: public DataStorage { public: DataStorageArray(const QByteArray& arr); virtual QByteArray getData(int position, int length); virtual QByteArray getData(); virtual int size(); private: QByteArray _data; }; enum MemoryMode { UnknownMemoryMode = 0, HexMemoryMode = 1, OctalMemoryMode = 2, BinaryMemoryMode = 3, DecimalMemoryMode = 4, }; enum CharMode { UnknownCharMode = 0, AsciiCharMode = 1, Utf8Mode = 2, Utf16Mode = 3, Utf32Mode = 4, EbcdicCharMode = 5 }; enum MagicNumbers { HexFieldWidth = 18 }; SeerHexWidget(QWidget* parent = 0); ~SeerHexWidget(); void setBytesPerLine (int count); int bytesPerLine () const; int hexCharsPerLine () const; int hexCharsPerByte () const; int nLines () const; int gapAddrHex () const; int gapHexAscii () const; void setAddressOffset (unsigned long offset); unsigned long addressOffset () const; unsigned long size () const; void setMemoryMode (SeerHexWidget::MemoryMode memoryMode); SeerHexWidget::MemoryMode memoryMode () const; QString memoryModeString () const; void setCharMode (SeerHexWidget::CharMode charMode); SeerHexWidget::CharMode charMode () const; QString charModeString () const; QTextDocument* document (); QString toPlainText (); signals: void byteOffsetChanged (int byte); public slots: void setData (DataStorage* pData); protected: protected slots: void handleCursorPositionChanged (); void handleByteOffsetChanged (int byte); private: void create (); DataStorage* _pdata; int _charWidth; int _charHeight; int _highlightByte; int _bytesPerLine; int _hexCharsPerLine; int _hexCharsPerByte; int _gapAddrHex; int _gapHexAscii; unsigned long _addressOffset; SeerHexWidget::MemoryMode _memoryMode; SeerHexWidget::CharMode _charMode; }; seer-2.7/src/SeerHexWidget.ui000066400000000000000000000231531516472651200161720ustar00rootroot00000000000000 SeerHexWidgetForm 0 0 907 643 Form 0 100 true Qt::NoTextInteraction Signed 8 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Signed 32 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Hexadecimal Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Unsigned 8 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Unsigned 32 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Octal Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Signed 16 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Signed 64 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Binary Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Unsigned 16 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Unsigned 64 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Text Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Float 32 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Float 64 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true CRC16 Sum Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Show Little Endian Decoding true Show Unsigned and Float as Hexidecimal seer-2.7/src/SeerHighlighterSettings.cpp000066400000000000000000000204441516472651200204260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerHighlighterSettings.h" SeerHighlighterSettings::SeerHighlighterSettings () { } SeerHighlighterSettings::SeerHighlighterSettings (const SeerHighlighterSettings& other) { *this = other; } SeerHighlighterSettings::~SeerHighlighterSettings () { } SeerHighlighterSettings& SeerHighlighterSettings::operator= (const SeerHighlighterSettings& rhs) { _keys = rhs._keys; _formats = rhs._formats; _cppSourceSuffixes = rhs._cppSourceSuffixes; _rustSourceSuffixes = rhs._rustSourceSuffixes; _odinSourceSuffixes = rhs._odinSourceSuffixes; return *this; } QStringList SeerHighlighterSettings::keys () const { return _keys; } bool SeerHighlighterSettings::has (const QString& name) const { int i = _keys.indexOf(name); if (i < 0) { return false; } return true; } QTextCharFormat SeerHighlighterSettings::get (const QString& name) const { int i = _keys.indexOf(name); if (i < 0) { return QTextCharFormat(); } return _formats[i]; } void SeerHighlighterSettings::add (const QString& name, QTextCharFormat& format) { int i = _keys.indexOf(name); if (i < 0) { _keys.append(name); _formats.append(format); return; } _formats[i] = format; } int SeerHighlighterSettings::count () const { return _keys.size(); } void SeerHighlighterSettings::setCppSourceSuffixes (const QString& suffixes) { _cppSourceSuffixes = suffixes; } void SeerHighlighterSettings::setOdinSourceSuffixes (const QString& suffixes) { _odinSourceSuffixes = suffixes; } void SeerHighlighterSettings::setRustSourceSuffixes (const QString& suffixes) { _rustSourceSuffixes = suffixes; } const QString& SeerHighlighterSettings::cppSourceSuffixes () { return _cppSourceSuffixes; } const QString& SeerHighlighterSettings::odinSourceSuffixes () { return _odinSourceSuffixes; } const QString& SeerHighlighterSettings::rustSourceSuffixes () { return _rustSourceSuffixes; } QStringList SeerHighlighterSettings::themeNames() { QStringList names; names << "light" << "dark"; return names; } SeerHighlighterSettings SeerHighlighterSettings::populate (const QString& themeName) { if (themeName == "light") { return SeerHighlighterSettings::populate_light(); }else if (themeName == "dark") { return SeerHighlighterSettings::populate_dark(); } return SeerHighlighterSettings::populate_light(); } SeerHighlighterSettings SeerHighlighterSettings::populate_light () { SeerHighlighterSettings languageSettings; QTextCharFormat f; f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#ffffff")); languageSettings.add("Text", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#c0c0c0")); f.setBackground(QColor("#ffffff")); languageSettings.add("Assembly Text", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#c0c0c0")); languageSettings.add("Margin", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#ffff99")); languageSettings.add("Current Line", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#c0c0c0")); languageSettings.add("Calling Line", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#c0c0c0")); languageSettings.add("Match", f); f = QTextCharFormat(); f.setFontWeight(QFont::Bold); f.setFontItalic(false); f.setForeground(QColor("#800080")); f.setBackground(QColor("#ffffff")); languageSettings.add("Class", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#008000")); f.setBackground(QColor("#ffffff")); languageSettings.add("Quotation", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(true); f.setForeground(QColor("#0000ff")); f.setBackground(QColor("#ffffff")); languageSettings.add("Function", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#ff0000")); f.setBackground(QColor("#ffffff")); languageSettings.add("Comment", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#ff0000")); f.setBackground(QColor("#ffffff")); languageSettings.add("Multiline Comment", f); f = QTextCharFormat(); f.setFontWeight(QFont::Bold); f.setFontItalic(false); f.setForeground(QColor("#000080")); f.setBackground(QColor("#ffffff")); languageSettings.add("Keyword", f); languageSettings.setCppSourceSuffixes(".c|.C|.cpp|.CPP|.cxx|.CXX|.h|.H|.hpp|.hxx|.Hxx|.HXX"); languageSettings.setOdinSourceSuffixes(".odin"); languageSettings.setRustSourceSuffixes(".rs"); return languageSettings; } SeerHighlighterSettings SeerHighlighterSettings::populate_dark () { SeerHighlighterSettings languageSettings; QTextCharFormat f; f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#b2b2b2")); f.setBackground(QColor("#232629")); languageSettings.add("Text", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#32ae48")); f.setBackground(QColor("#232629")); languageSettings.add("Assembly Text", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#7c7f81")); f.setBackground(QColor("#31363b")); languageSettings.add("Margin", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#c7fa54")); f.setBackground(QColor("#8ea82f")); languageSettings.add("Current Line", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#c7fa54")); f.setBackground(QColor("#737373")); languageSettings.add("Calling Line", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#737373")); languageSettings.add("Match", f); f = QTextCharFormat(); f.setFontWeight(QFont::Bold); f.setFontItalic(false); f.setForeground(QColor("#32ae48")); f.setBackground(QColor("#232629")); languageSettings.add("Class", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#f453de")); f.setBackground(QColor("#232629")); languageSettings.add("Quotation", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(true); f.setForeground(QColor("#736a59")); f.setBackground(QColor("#232629")); languageSettings.add("Function", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#52f8f8")); f.setBackground(QColor("#232629")); languageSettings.add("Comment", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#52f8f8")); f.setBackground(QColor("#232629")); languageSettings.add("Multiline Comment", f); f = QTextCharFormat(); f.setFontWeight(QFont::Bold); f.setFontItalic(false); f.setForeground(QColor("#d9f743")); f.setBackground(QColor("#232629")); languageSettings.add("Keyword", f); languageSettings.setCppSourceSuffixes(".c|.C|.cpp|.CPP|.cxx|.CXX|.h|.H|.hpp|.hxx|.Hxx|.HXX"); languageSettings.setOdinSourceSuffixes(".odin"); languageSettings.setRustSourceSuffixes(".rs"); return languageSettings; } seer-2.7/src/SeerHighlighterSettings.h000066400000000000000000000042171516472651200200730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include class SeerHighlighterSettings { public: SeerHighlighterSettings (); SeerHighlighterSettings (const SeerHighlighterSettings& other); ~SeerHighlighterSettings (); SeerHighlighterSettings& operator= (const SeerHighlighterSettings& rhs); QStringList keys () const; bool has (const QString& name) const; QTextCharFormat get (const QString& name) const; void add (const QString& name, QTextCharFormat& format); int count () const; void setCppSourceSuffixes (const QString& suffixes); void setOdinSourceSuffixes (const QString& suffixes); void setRustSourceSuffixes (const QString& suffixes); const QString& cppSourceSuffixes (); const QString& odinSourceSuffixes (); const QString& rustSourceSuffixes (); static QStringList themeNames (); static SeerHighlighterSettings populate (const QString& themeName); static SeerHighlighterSettings populate_light (); static SeerHighlighterSettings populate_dark (); private: QList _keys; QList _formats; QString _cppSourceSuffixes; QString _odinSourceSuffixes; QString _rustSourceSuffixes; }; seer-2.7/src/SeerHistoryLineEdit.cpp000066400000000000000000000010631516472651200175220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerHistoryLineEdit.h" SeerHistoryLineEdit::SeerHistoryLineEdit (const QString& contents, QWidget* parent) : QHistoryLineEdit(contents, parent) { QObject::connect(this, &QHistoryLineEdit::lostFocus, this, &QHistoryLineEdit::execute); } SeerHistoryLineEdit::SeerHistoryLineEdit (QWidget* parent) : QHistoryLineEdit(parent) { QObject::connect(this, &QHistoryLineEdit::lostFocus, this, &QHistoryLineEdit::execute); } seer-2.7/src/SeerHistoryLineEdit.h000066400000000000000000000010231516472651200171630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "QHistoryLineEdit.h" // // Extends QHistoryLineEdit to connect the 'lostFocus' signal with the // 'execute' slot. This adds the current text to the history when // focus is lost. // class SeerHistoryLineEdit : public QHistoryLineEdit { Q_OBJECT public: SeerHistoryLineEdit(const QString& contents, QWidget* parent = 0); SeerHistoryLineEdit(QWidget* parent = 0); }; seer-2.7/src/SeerImageVisualizerWidget.cpp000066400000000000000000000320551516472651200207140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerImageVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerImageVisualizerWidget::SeerImageVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create two id's for queries. _memoryId = Seer::createID(); _imageWidthId = Seer::createID(); _imageHeightId = Seer::createID(); _formatName = ""; _format = QImage::Format_Invalid; _width = 0; _height = 0; _bytes = 0; // Set up UI. setupUi(this); // Setup the widgets setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer Image Visualizer"); setAttribute(Qt::WA_DeleteOnClose); // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleHelpButton); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerImageVisualizerWidget::handleVariableNameLineEdit); QObject::connect(widthLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleRefreshButton); QObject::connect(widthLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerImageVisualizerWidget::handleWidthLineEdit); QObject::connect(heightLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleRefreshButton); QObject::connect(heightLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerImageVisualizerWidget::handleHeightLineEdit); QObject::connect(formatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerImageVisualizerWidget::handleFormatComboBox); QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handlePrintButton); QObject::connect(saveToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleSaveButton); // Restore window settings. readSettings(); } SeerImageVisualizerWidget::~SeerImageVisualizerWidget () { } void SeerImageVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer Image Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); setVariableAddress(""); if (variableNameLineEdit->text() == "") { return; } // Clear old contents. QByteArray array; imageViewer->setImage(QImage()); // Send signal to get variable address. emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } QString SeerImageVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerImageVisualizerWidget::setVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; bool refresh = false; if (address == "") { variableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); refresh = true; } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); refresh = true; } } if (ok == false) { variableAddressLineEdit->setText("not an address"); offset = 0; } } imageViewer->setImage(QImage()); // Show results immediately. if (refresh) { handleRefreshButton(); } } QString SeerImageVisualizerWidget::variableAddress () const { return variableAddressLineEdit->text(); } void SeerImageVisualizerWidget::setImageWidth (const QString& width) { widthLineEdit->setText(width); } QString SeerImageVisualizerWidget::imageWidth () const { return widthLineEdit->text(); } void SeerImageVisualizerWidget::setImageHeight (const QString& height) { heightLineEdit->setText(height); } QString SeerImageVisualizerWidget::imageHeight () const { return heightLineEdit->text(); } void SeerImageVisualizerWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); //qDebug() << text; if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 10^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { QStringList words = Seer::filterEscapes(Seer::parseFirst(text, "value=", '"', '"', false)).split(' ', Qt::SkipEmptyParts); setVariableAddress(words.first()); }else if (id_text.toInt() == _imageWidthId) { // Set the image width. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setImageWidth(value_text); handleRefreshButton(); }else if (id_text.toInt() == _imageHeightId) { // Set the image height. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setImageHeight(value_text); handleRefreshButton(); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { // 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}] // 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}] QString id_text = text.section('^', 0,0); if (id_text.toInt() == _memoryId) { //qDebug() << text; QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); } if (id_text.toInt() == _memoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } } // At a stopping point, refresh. }else if (text.startsWith("*stopped,reason=\"")) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } QApplication::restoreOverrideCursor(); } void SeerImageVisualizerWidget::handleRefreshButton () { // Clear the status. messageLineEdit->setText(""); if (variableNameLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "not an address") { return; } if (widthLineEdit->text() == "") { return; } if (heightLineEdit->text() == "") { return; } // Get image dimensions. int w = widthLineEdit->text().toInt(); int h = heightLineEdit->text().toInt(); if (w < 1 || h < 1) { return; } // Get image format. QString format = formatComboBox->currentText(); // Validate the image dimensions vs. the data size. _formatName = ""; _format = QImage::Format_Invalid; _width = w; _height = h; _bytes = 0; if (format == "RGBA8888") { _formatName = format; _format = QImage::Format_RGBA8888; _bytes = _width * _height * 4; }else if (format == "RGB888") { _formatName = format; _format = QImage::Format_RGB888; _bytes = _width * _height * 3; } // Unknown format. if (_bytes <= 0) { _formatName = ""; _format = QImage::Format_Invalid; _width = w; _height = h; _bytes = 0; messageLineEdit->setText("Unknown image format of '" + format + "."); return; } emit evaluateMemoryExpression(_memoryId, variableAddressLineEdit->text(), _bytes); } void SeerImageVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/ImageVisualizer.md"); help->show(); help->raise(); } void SeerImageVisualizerWidget::handleVariableNameLineEdit () { setVariableName (variableNameLineEdit->text()); } void SeerImageVisualizerWidget::handleWidthLineEdit () { if (widthLineEdit->text() == "") { return; } emit evaluateVariableExpression(_imageWidthId, widthLineEdit->text()); } void SeerImageVisualizerWidget::handleHeightLineEdit () { if (heightLineEdit->text() == "") { return; } emit evaluateVariableExpression(_imageHeightId, heightLineEdit->text()); } void SeerImageVisualizerWidget::handleFormatComboBox (int index) { Q_UNUSED(index); handleRefreshButton(); } void SeerImageVisualizerWidget::handlePrintButton () { imageViewer->print(); } void SeerImageVisualizerWidget::handleSaveButton () { imageViewer->saveFileDialog(variableNameLineEdit->text() + ".png"); } void SeerImageVisualizerWidget::handleCreateImage (const QByteArray& array) { // Clear the status. messageLineEdit->setText(""); // Nothing to do? if (_bytes == 0) { return; } if (_format == QImage::Format_Invalid) { return; } // Data is not large enough for requested image dimensions. if (_bytes > array.size()) { messageLineEdit->setText(QString("%1 memory bytes is not enough for the '%2' image (%3x%4). Need at least %5 bytes.").arg(array.size()) .arg(_formatName) .arg(_width) .arg(_height) .arg(_bytes)); return; } // Construct image. QImage image = QImage((const uchar*)array.data(), _width, _height, _format); imageViewer->setImage(image); } void SeerImageVisualizerWidget::writeSettings() { QSettings settings; settings.beginGroup("imagevisualizerwindow"); settings.setValue("size", size()); settings.endGroup(); } void SeerImageVisualizerWidget::readSettings() { QSettings settings; settings.beginGroup("imagevisualizerwindow"); resize(settings.value("size", QSize(800, 400)).toSize()); settings.endGroup(); } void SeerImageVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } seer-2.7/src/SeerImageVisualizerWidget.h000066400000000000000000000052041516472651200203550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerImageVisualizerWidget.h" class SeerImageVisualizerWidget : public QWidget, protected Ui::SeerImageVisualizerWidgetForm { Q_OBJECT public: explicit SeerImageVisualizerWidget (QWidget* parent = 0); ~SeerImageVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; void setVariableAddress (const QString& address); QString variableAddress () const; void setImageWidth (const QString& width); QString imageWidth () const; void setImageHeight (const QString& height); QString imageHeight () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void evaluateMemoryExpression (int expressionid, QString address, int count); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleVariableNameLineEdit (); void handleWidthLineEdit (); void handleHeightLineEdit (); void handleFormatComboBox (int index); void handlePrintButton (); void handleSaveButton (); void handleCreateImage (const QByteArray& array); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: int _variableId; int _memoryId; int _imageWidthId; int _imageHeightId; QString _formatName; QImage::Format _format; int _width; int _height; int _bytes; }; seer-2.7/src/SeerImageVisualizerWidget.ui000066400000000000000000000145171516472651200205520ustar00rootroot00000000000000 SeerImageVisualizerWidgetForm 0 0 899 683 Seer Image Visualizer Variable expression resulting in an address. Starting address true Memory address. true Memory address Qt::Vertical RGBA8888 RGB888 The image width (pixels) width true The image height (pixels) height true Qt::Vertical Print the display. ... :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Save the display to a file. ... :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Qt::Vertical Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Qt::Vertical Help on Image Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg 0 100 true true SeerHistoryLineEdit QLineEdit
SeerHistoryLineEdit.h
QImageViewer QWidget
QImageViewer.h
1
seer-2.7/src/SeerKeySettings.cpp000066400000000000000000000144301516472651200167160ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerKeySettings.h" #include SeerKeySettings::SeerKeySettings () { } SeerKeySettings::SeerKeySettings (const SeerKeySettings& other) { *this = other; } SeerKeySettings::~SeerKeySettings () { } SeerKeySettings& SeerKeySettings::operator= (const SeerKeySettings& rhs) { _keys = rhs._keys; return *this; } QStringList SeerKeySettings::keys () const { QList keylist = _keys.keys(); QStringList keys; for (int i=0; i // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include struct SeerKeySetting { SeerKeySetting(QString action, QKeySequence sequence, QString description) : _action(action), _sequence(sequence), _description(description) {} SeerKeySetting() {}; QString _action; QKeySequence _sequence; QString _description; }; class SeerKeySettings { public: SeerKeySettings (); SeerKeySettings (const SeerKeySettings& other); ~SeerKeySettings (); SeerKeySettings& operator= (const SeerKeySettings& rhs); QStringList keys () const; bool has (const QString& action) const; SeerKeySetting get (const QString& action) const; void add (const QString& action, const SeerKeySetting& setting); int count () const; static SeerKeySettings populate (); private: QMap _keys; }; seer-2.7/src/SeerKeysConfigPage.cpp000066400000000000000000000053131516472651200173030ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerKeysConfigPage.h" #include #include #include #include SeerKeysConfigPage::SeerKeysConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Connect things. // Setup the widgets reset(); } SeerKeysConfigPage::~SeerKeysConfigPage() { } void SeerKeysConfigPage::setKeySettings (const SeerKeySettings& settings) { // Clear the table contents. keysTableWidget->setRowCount(0); // Get a list of keys from the highlighter. QStringList keys = settings.keys(); // Loop through each key and get its info. // Construct a table entry. for (int r=0; rinsertRow(r); // Insert the KeySequence editor. QKeySequenceEdit* keySequenceEdit = new QKeySequenceEdit; keySequenceEdit->setKeySequence(setting._sequence); keysTableWidget->setCellWidget(r, 0, keySequenceEdit); // Insert the Description. QLabel* descriptionLabel = new QLabel(setting._description); keysTableWidget->setCellWidget(r, 1, descriptionLabel); } keysTableWidget->setVerticalHeaderLabels(keys); keysTableWidget->resizeColumnToContents(0); // KeySequence keysTableWidget->resizeColumnToContents(1); // Description } SeerKeySettings SeerKeysConfigPage::keySettings() const { SeerKeySettings settings; for (int r=0; rrowCount(); r++) { // Get the key (label) for this row. QString key = keysTableWidget->verticalHeaderItem(r)->text(); // Get widgets for this row. QKeySequenceEdit* keySequenceEdit = dynamic_cast(keysTableWidget->cellWidget(r,0)); QLabel* descriptionLabel = dynamic_cast(keysTableWidget->cellWidget(r,1)); // Create key setting. if (keySequenceEdit != 0 && descriptionLabel != 0) { SeerKeySetting setting(key, keySequenceEdit->keySequence(), descriptionLabel->text()); // Add the setting to our settings. settings.add(key, setting); }else{ if (keySequenceEdit == 0) { qDebug() << "QKeySequenceEdit for row" << r << "is null!"; } if (descriptionLabel == 0) { qDebug() << "QLabel for row" << r << "is null!"; } } } return settings; } void SeerKeysConfigPage::reset () { setKeySettings(SeerKeySettings::populate()); } seer-2.7/src/SeerKeysConfigPage.h000066400000000000000000000012751516472651200167530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerKeySettings.h" #include #include "ui_SeerKeysConfigPage.h" class SeerKeysConfigPage : public QWidget, protected Ui::SeerKeysConfigPage { Q_OBJECT public: explicit SeerKeysConfigPage (QWidget* parent = 0); ~SeerKeysConfigPage (); void setKeySettings (const SeerKeySettings& settings); SeerKeySettings keySettings () const; void reset (); protected slots: private: }; seer-2.7/src/SeerKeysConfigPage.ui000066400000000000000000000070141516472651200171360ustar00rootroot00000000000000 SeerKeysConfigPage 0 0 901 652 SeerKeysConfigPage 0 0 0 25 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify key bindings for important Seer operations.</span></p> <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; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click on the shortcut cell for the key operation you want to change. Then enter the new key sequence.</p> <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> <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> <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> 0 75 Gdb and Editor Keys Shortcut Description seer-2.7/src/SeerLibraryBrowserWidget.cpp000066400000000000000000000142161516472651200205630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerLibraryBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerLibraryBrowserWidget::SeerLibraryBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets librarySearchLineEdit->setPlaceholderText("Search regex..."); librarySearchLineEdit->setClearButtonEnabled(true); libraryTreeWidget->resizeColumnToContents(0); libraryTreeWidget->resizeColumnToContents(1); libraryTreeWidget->resizeColumnToContents(2); libraryTreeWidget->resizeColumnToContents(3); libraryTreeWidget->resizeColumnToContents(4); libraryTreeWidget->resizeColumnToContents(5); libraryTreeWidget->clear(); libraryTreeWidget->setSortingEnabled(false); // Connect things. QObject::connect(librarySearchLineEdit, &QLineEdit::textChanged, this, &SeerLibraryBrowserWidget::handleSearchLineEdit); } SeerLibraryBrowserWidget::~SeerLibraryBrowserWidget () { } void SeerLibraryBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,shared-libraries=[") && text.endsWith("]")) { libraryTreeWidget->clear(); libraryTreeWidget->setSortingEnabled(false); libraryTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // -file-list-shared-libraries // ^done,shared-libraries=[ // {id="/lib/libfoo.so",target-name="/lib/libfoo.so",host-name="/lib/libfoo.so",symbols-loaded="1",thread-group="i1",ranges=[{from="0x72815989",to="0x728162c0"}]}, // {id="/lib/libbar.so",target-name="/lib/libbar.so",host-name="/lib/libbar.so",symbols-loaded="1",thread-group="i1",ranges=[{from="0x76ee48c0",to="0x76ee9160"}]} // ] QString libraries_text = Seer::parseFirst(text, "shared-libraries=", '[', ']', false); //qDebug() << libraries_text; QStringList libraries_list = Seer::parse(libraries_text, "", '{', '}', false); for ( const auto& entry_text : libraries_list ) { QString id_text = Seer::parseFirst(entry_text, "id=", '"', '"', false); QString target_name_text = Seer::parseFirst(entry_text, "target-name=", '"', '"', false); QString host_name_text = Seer::parseFirst(entry_text, "host-name=", '"', '"', false); QString symbols_loaded_text = Seer::parseFirst(entry_text, "symbols-loaded=", '"', '"', false); QString thread_group_text = Seer::parseFirst(entry_text, "thread-group=", '"', '"', false); QString ranges_text = Seer::parseFirst(entry_text, "ranges=", '[', ']', false); // Add the file to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, id_text); item->setText(1, target_name_text); item->setText(2, host_name_text); item->setText(3, symbols_loaded_text); item->setText(4, thread_group_text); item->setText(5, ranges_text); libraryTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } libraryTreeWidget->resizeColumnToContents(0); libraryTreeWidget->resizeColumnToContents(1); libraryTreeWidget->resizeColumnToContents(2); libraryTreeWidget->resizeColumnToContents(3); libraryTreeWidget->resizeColumnToContents(4); libraryTreeWidget->resizeColumnToContents(5); libraryTreeWidget->sortByColumn(0, Qt::AscendingOrder); libraryTreeWidget->setSortingEnabled(true); librarySearchLineEdit->clear(); QApplication::restoreOverrideCursor(); } void SeerLibraryBrowserWidget::handleSessionTerminated () { // Delete previous contents. libraryTreeWidget->clear(); } void SeerLibraryBrowserWidget::handleSearchLineEdit (const QString& text) { // Set everything to a normal font. If there is no search text, unhide everything. // If there is search text, hide everything so the matching ones can be unhidden later on. QTreeWidgetItemIterator it(libraryTreeWidget); if (*it) { QFont f0 = (*it)->font(0); f0.setBold(false); if (text == "") { while (*it) { (*it)->setHidden(false); // No search text, unhide everything. (*it)->setFont(0,f0); ++it; } }else{ while (*it) { (*it)->setHidden(true); // Has search text, hide everything. Matching items to be unhidden below. (*it)->setFont(0,f0); ++it; } } } // Set selected items to a bold font and unhidden. Move to the first match. if (text != "") { QList matches; matches = libraryTreeWidget->findItems(text, Qt::MatchRegularExpression | Qt::MatchRecursive, 0); QList::const_iterator it = matches.begin(); QList::const_iterator e = matches.end(); if (it != e) { libraryTreeWidget->setCurrentItem(*it); QFont f0 = (*it)->font(0); f0.setBold(true); while (it != e) { (*it)->setHidden(false); (*it)->setFont(0,f0); it++; } } //qDebug() << text << matches.size(); } libraryTreeWidget->resizeColumnToContents(0); libraryTreeWidget->resizeColumnToContents(1); libraryTreeWidget->resizeColumnToContents(2); libraryTreeWidget->resizeColumnToContents(3); libraryTreeWidget->resizeColumnToContents(4); libraryTreeWidget->resizeColumnToContents(5); } void SeerLibraryBrowserWidget::refresh () { emit refreshLibraryList(); } void SeerLibraryBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } seer-2.7/src/SeerLibraryBrowserWidget.h000066400000000000000000000016701516472651200202300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerLibraryBrowserWidget.h" class SeerLibraryBrowserWidget : public QWidget, protected Ui::SeerLibraryBrowserWidgetForm { Q_OBJECT public: explicit SeerLibraryBrowserWidget (QWidget* parent = 0); ~SeerLibraryBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (const QString& text); signals: void refreshLibraryList (); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerLibraryBrowserWidget.ui000066400000000000000000000035251516472651200204170ustar00rootroot00000000000000 SeerLibraryBrowserWidgetForm 0 0 730 698 Library Browser 6 Id Target-Name Host-Name Symbols Loaded Thread Group Ranges Search in the list of libraries. "*" is allowed. QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerLogWidget.cpp000066400000000000000000000106351516472651200163350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerLogWidget.h" #include #include #include #include #include #include #include #include #include #include #include SeerLogWidget::SeerLogWidget (QWidget* parent) : QWidget(parent) { setupUi(this); // Setup the widgets QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); textEdit->setReadOnly(true); textEdit->setFont(font); textEdit->setLineWrapMode(QTextEdit::NoWrap); // No wrap wrapTextCheckBox->setCheckState(Qt::Unchecked); // No wrap // Connect things. QObject::connect(clearButton, &QPushButton::clicked, this, &SeerLogWidget::handleClearButton); QObject::connect(printButton, &QPushButton::clicked, this, &SeerLogWidget::handlePrintButton); QObject::connect(saveButton, &QPushButton::clicked, this, &SeerLogWidget::handleSaveButton); QObject::connect(wrapTextCheckBox, &QCheckBox::clicked, this, &SeerLogWidget::handleWrapTextCheckBox); QObject::connect(enableCheckBox, &QCheckBox::clicked, this, &SeerLogWidget::handleEnableCheckBox); QObject::connect(timeStampCheckBox, &QCheckBox::clicked, this, &SeerLogWidget::handleTimeStampCheckBox); } SeerLogWidget::~SeerLogWidget () { } void SeerLogWidget::processText (const QString& text) { // Add text to the end of the document. textEdit->append(text); } bool SeerLogWidget::isLogEnabled () const { return enableCheckBox->isChecked(); } void SeerLogWidget::setLogEnabled (bool flag) { enableCheckBox->setChecked(flag); } bool SeerLogWidget::isTimeStampEnabled () const { return timeStampCheckBox->isChecked(); } void SeerLogWidget::setTimeStampEnabled (bool flag) { timeStampCheckBox->setChecked(flag); } void SeerLogWidget::moveToEnd () { textEdit->verticalScrollBar()->setValue(textEdit->verticalScrollBar()->maximum()); } void SeerLogWidget::setPlaceholderText (const QString& text) { textEdit->setPlaceholderText(text); } void SeerLogWidget::handleText (const QString& text) { // Don't do anything if we're not enabled. if (isLogEnabled() == false) { return; } // Process the text. processText(text); // Move to the end of the document. moveToEnd(); } void SeerLogWidget::handleClearButton () { textEdit->clear(); } void SeerLogWidget::handlePrintButton () { QPrinter printer; QPrintDialog* dlg = new QPrintDialog(&printer, this); if (dlg->exec() != QDialog::Accepted) { return; } QTextDocument* document = textEdit->document(); document->print(&printer); } void SeerLogWidget::handleSaveButton () { QFileDialog dialog(this, "Seer log file", "./", "Logs (*.log);;Text files (*.txt);;All files (*.*)"); dialog.setOptions(QFileDialog::DontUseNativeDialog); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("log"); dialog.selectFile("gdboutput.log"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); stream << textEdit->toPlainText(); file.flush(); file.close(); }else{ QMessageBox::critical(this, tr("Error"), tr("Cannot save log to file.")); return; } } void SeerLogWidget::handleWrapTextCheckBox () { if (wrapTextCheckBox->checkState() == Qt::Unchecked) { textEdit->setLineWrapMode(QTextEdit::NoWrap); // No wrap }else{ textEdit->setLineWrapMode(QTextEdit::WidgetWidth); // Wrap at end of widget } } void SeerLogWidget::handleEnableCheckBox () { emit logEnabledChanged(enableCheckBox->isChecked()); } void SeerLogWidget::handleTimeStampCheckBox () { emit logTimeStampChanged(timeStampCheckBox->isChecked()); } seer-2.7/src/SeerLogWidget.h000066400000000000000000000027511516472651200160020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerLogWidget.h" class SeerLogWidget : public QWidget, protected Ui::SeerLogWidgetForm { Q_OBJECT public: explicit SeerLogWidget (QWidget* parent = 0); ~SeerLogWidget (); virtual void processText (const QString& text); bool isLogEnabled () const; void setLogEnabled (bool flag); bool isTimeStampEnabled () const; void setTimeStampEnabled (bool flag); void moveToEnd (); void setPlaceholderText (const QString& text); signals: void logEnabledChanged (bool flag); void logTimeStampChanged (bool flag); public slots: void handleText (const QString& text); void handleClearButton (); void handlePrintButton (); void handleSaveButton (); void handleWrapTextCheckBox (); void handleTimeStampCheckBox (); void handleEnableCheckBox (); protected: }; seer-2.7/src/SeerLogWidget.ui000066400000000000000000000135561516472651200161750ustar00rootroot00000000000000 SeerLogWidgetForm 0 0 615 361 Seer Log 100 0 QTextEdit::NoWrap false [gdb output] 0 Print the log output. :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Save the log output to a file. :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Qt::Horizontal 0 20 0 Clear the log output. :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 0 20 Enable/Disable output to this log. Enable true 0 0 Wrap long lines to the next line. Wrap Add a timestamp to each line. TStamp Qt::Vertical 28 28 seer-2.7/src/SeerMacroEditorDialog.cpp000066400000000000000000000016731516472651200200020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMacroEditorDialog.h" #include SeerMacroEditorDialog::SeerMacroEditorDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setWindowFlags(Qt::Tool); // lightweight tool window setModal(false); // Connect things. } SeerMacroEditorDialog::~SeerMacroEditorDialog () { } void SeerMacroEditorDialog::setMacroName (const QString& name) { setWindowTitle("Seer - Macro Editor for '" + name + "'"); } void SeerMacroEditorDialog::setCommands (const QStringList& commands) { textEditor->clear(); textEditor->setPlainText(commands.join('\n')); textEditor->moveCursor(QTextCursor::Start); textEditor->setFocus(); } QStringList SeerMacroEditorDialog::commands () const { return textEditor->toPlainText().split('\n'); } seer-2.7/src/SeerMacroEditorDialog.h000066400000000000000000000012751516472651200174450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerMacroEditorDialog.h" class SeerMacroEditorDialog : public QDialog, protected Ui::SeerMacroEditorDialog { Q_OBJECT public: explicit SeerMacroEditorDialog (QWidget* parent = 0); ~SeerMacroEditorDialog (); void setMacroName (const QString& name); void setCommands (const QStringList& commands); QStringList commands () const; public slots: private: }; seer-2.7/src/SeerMacroEditorDialog.ui000066400000000000000000000036331516472651200176330ustar00rootroot00000000000000 SeerMacroEditorDialog 0 0 400 300 Seer - Macro Editor :/seer/resources/icons/hicolor/32x32/seergdb.png:/seer/resources/icons/hicolor/32x32/seergdb.png Insert gdb commands on multiple lines Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerMacroEditorDialog accept() 248 254 157 274 buttonBox rejected() SeerMacroEditorDialog reject() 316 260 286 274 seer-2.7/src/SeerMacroToolButton.cpp000066400000000000000000000074651516472651200175520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMacroToolButton.h" #include "SeerMacroEditorDialog.h" #include #include #include #include #include #include #include #include #include #include SeerMacroToolButton::SeerMacroToolButton(QWidget* parent) : QToolButton(parent) { _holdTimer = new QTimer(this); _holdTimer->setSingleShot(true); _holdTimer->setInterval(500); // 500ms hold time // Create the menu _menu = new QMenu(this); _menu->addAction("Edit Macro", this, &SeerMacroToolButton::handleEditMacro); connect(_holdTimer, &QTimer::timeout, this, &SeerMacroToolButton::handleHoldTriggered); } void SeerMacroToolButton::setMacroName (const QString& name) { // Set the macro name. If it's "", nullify our state. _macroName = name; if (_macroName == "") { _macroFileName = ""; return; } // Add combination shortcut for re-open closed file (Ctrl + Shift + T) QShortcut* shortcut = new QShortcut(QKeySequence(QString("Ctrl+Shift+")+_macroName[1]), this); QObject::connect(shortcut, &QShortcut::activated, this, &QToolButton::click); // Create the macro filename where the macro is to be written. QSettings settings; QFileInfo fileInfo(settings.fileName()); _macroFileName = fileInfo.absolutePath() + "/macros/" + _macroName + ".macro"; // Read settings now we have a proper macro name. readMacro(); } const QString& SeerMacroToolButton::macroName () const { return _macroName; } const QString& SeerMacroToolButton::macroFileName () const { return _macroFileName; } void SeerMacroToolButton::setCommands (const QStringList& commands) { _commands = commands; } const QStringList& SeerMacroToolButton::commands () const { return _commands; } void SeerMacroToolButton::writeMacro () { // No macro filename, don't save. if (macroFileName() == "") { return; } // Get the absolute path of the filename. QFileInfo fileInfo(macroFileName()); QString path = fileInfo.absolutePath(); // Create the directory. QDir().mkpath(path); // Create the macro file and write the lines to it. QFile file(macroFileName()); if (file.open(QFile::WriteOnly|QFile::Text|QFile::Truncate)) { QTextStream out(&file); for (const QString& line : commands()) { out << line << "\n"; } file.close(); } } void SeerMacroToolButton::readMacro () { if (macroFileName() == "") { return; } QFile file(macroFileName()); if (file.open(QFile::ReadOnly|QFile::Text)) { QStringList lines; QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); lines.append(line); } file.close(); setCommands(lines); } } void SeerMacroToolButton::mousePressEvent (QMouseEvent* event) { QToolButton::mousePressEvent(event); _pressPos = event->pos(); _holdTimer->start(); } void SeerMacroToolButton::mouseReleaseEvent (QMouseEvent* event) { QToolButton::mouseReleaseEvent(event); _holdTimer->stop(); } void SeerMacroToolButton::handleHoldTriggered () { // Show menu at button position QPoint globalPos = mapToGlobal(QPoint(0, height())); _menu->exec(globalPos); // Reset button to unpressed state setDown(false); } void SeerMacroToolButton::handleEditMacro () { SeerMacroEditorDialog dlg; dlg.setMacroName(macroName()); dlg.setCommands(commands()); if (dlg.exec()) { setCommands(dlg.commands()); writeMacro(); } } seer-2.7/src/SeerMacroToolButton.h000066400000000000000000000026751516472651200172150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerMacroToolButton : public QToolButton { Q_OBJECT public: explicit SeerMacroToolButton(QWidget* parent = nullptr); void setMacroName (const QString& name); const QString& macroName () const; const QString& macroFileName () const; void setCommands (const QStringList& commands); const QStringList& commands () const; void writeMacro (); void readMacro (); protected: void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; signals: private slots: void handleHoldTriggered (); void handleEditMacro (); private: QTimer* _holdTimer; QMenu* _menu; QPoint _pressPos; QString _macroName; QString _macroFileName; QStringList _commands; }; seer-2.7/src/SeerMainWindow.cpp000066400000000000000000002515031516472651200165250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMainWindow.h" #include "SeerDebugDialog.h" #include "SeerConfigDialog.h" #include "SeerArgumentsDialog.h" #include "SeerAboutDialog.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { // // Set up UI. // setupUi(this); // // Set up other parts of the UI. // // Add status bar indicator. SeerRunStatusIndicator* runStatus = new SeerRunStatusIndicator(this); statusBar()->addPermanentWidget(runStatus); // Add progress spin widget. QWidget* spacerWidget = new QWidget(this); spacerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); spacerWidget->setStyleSheet("background-color:transparent"); // Need this for QToolBar StyleSheets to work. toolBar->addWidget(spacerWidget); _progressIndicator = new SeerProgressIndicator(this); _progressIndicator->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); _progressIndicator->setFixedWidth(96); _progressIndicator->setColor(palette().color(QPalette::WindowText)); toolBar->addWidget(_progressIndicator); // Add help button. QToolButton* helpToolButton = new QToolButton(this); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on Seer main window."); toolBar->addWidget(helpToolButton); // Set up Styles menu. _styleMenuActionGroup = new QActionGroup(this); _styleMenuActionGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive); _styleMenuActionGroup->setEnabled(true); _styleMenuActionGroup->setVisible(true); QAction* lightStyleAction = menuStyles->addAction("light"); lightStyleAction->setCheckable(true); _styleMenuActionGroup->addAction(lightStyleAction); QAction* darkStyleAction = menuStyles->addAction("dark"); darkStyleAction->setCheckable(true); _styleMenuActionGroup->addAction(darkStyleAction); QStringList styles = QStyleFactory::keys(); for (int i = 0; i < styles.size(); i++) { QAction* styleAction = menuStyles->addAction(styles.at(i)); styleAction->setCheckable(true); _styleMenuActionGroup->addAction(styleAction); } // Hide Nexti and Stepi. Enabled/disabled by SeerEditorManagerWidget. actionGdbNext->setVisible(true); actionGdbNexti->setVisible(false); actionGdbStep->setVisible(true); actionGdbStepi->setVisible(false); actionGdbFinish->setVisible(true); // Set up Interrupt menu. QMenu* menuInterrupt = new QMenu(this); _interruptAction = menuInterrupt->addAction("Interrupt"); menuInterrupt->addSeparator(); QAction* interruptActionSIGINT = menuInterrupt->addAction("SIGINT"); QAction* interruptActionSIGKILL = menuInterrupt->addAction("SIGKILL"); QAction* interruptActionSIGFPE = menuInterrupt->addAction("SIGFPE"); QAction* interruptActionSIGSEGV = menuInterrupt->addAction("SIGSEGV"); QAction* interruptActionSIGUSR1 = menuInterrupt->addAction("SIGUSR1"); QAction* interruptActionSIGUSR2 = menuInterrupt->addAction("SIGUSR2"); actionInterruptProcess->setMenu(menuInterrupt); // Set up Visualizer menu. QMenu* menuVisualizer = new QMenu(this); QAction* visualizerMemoryAction = menuVisualizer->addAction("Memory"); menuVisualizer->addSeparator(); QAction* visualizerArrayAction = menuVisualizer->addAction("Array"); QAction* visualizerMatrixAction = menuVisualizer->addAction("Matrix"); QAction* visualizerVarAction = menuVisualizer->addAction("Struct"); QAction* visualizerStructAction = menuVisualizer->addAction("Basic Struct"); QAction* visualizerImageAction = menuVisualizer->addAction("Image"); actionVisualizers->setMenu(menuVisualizer); // Set up control menu for recording. QActionGroup* recordDirectionActionGroup = new QActionGroup(this); recordDirectionActionGroup->addAction(actionControlRecordForward); recordDirectionActionGroup->addAction(actionControlRecordReverse); // Set the inital key settings. setKeySettings(SeerKeySettings::populate()); setProjectFilename(""); // Set the default shotcut key to toggle record direction. actionRecordDirection->setShortcut(QKeySequence::fromString("Ctrl+D")); // // Set up signals/slots. // QObject::connect(actionFileDebug, &QAction::triggered, this, &SeerMainWindow::handleFileDebugWithOutDefaultProject); QObject::connect(actionFileArguments, &QAction::triggered, this, &SeerMainWindow::handleFileArguments); QObject::connect(actionFileQuit, &QAction::triggered, this, &SeerMainWindow::handleFileQuit); QObject::connect(actionViewMemoryVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewMemoryVisualizer); QObject::connect(actionViewArrayVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewArrayVisualizer); QObject::connect(actionViewMatrixVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewMatrixVisualizer); QObject::connect(actionViewStructVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewVarVisualizer); QObject::connect(actionViewBasicStructVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewStructVisualizer); QObject::connect(actionViewImageVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewImageVisualizer); QObject::connect(actionViewAssembly, &QAction::triggered, this, &SeerMainWindow::handleViewAssembly); QObject::connect(actionConsoleAttached, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleAttached); QObject::connect(actionConsoleDetached, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleDetached); QObject::connect(actionConsoleDetachedMinimized, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleDetachedMinimized); QObject::connect(actionHelpAbout, &QAction::triggered, this, &SeerMainWindow::handleHelpAbout); QObject::connect(actionControlRestart, &QAction::triggered, this, &SeerMainWindow::handleRestartExecutable); QObject::connect(actionControlTerminate, &QAction::triggered, this, &SeerMainWindow::handleTerminateExecutable); QObject::connect(actionControlContinue, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbContinue); QObject::connect(actionControlNext, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbNext); QObject::connect(actionControlStep, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStep); QObject::connect(actionControlNexti, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbNexti); QObject::connect(actionControlStepi, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStepi); QObject::connect(actionControlFinish, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbFinish); QObject::connect(actionControlRunToLine, &QAction::triggered, gdbWidget->editorManager(), &SeerEditorManagerWidget::handleRunToSelectedLine); QObject::connect(actionControlReverseContinue, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseContinue); QObject::connect(actionControlReverseNext, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseNext); QObject::connect(actionControlReverseStep, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseStep); QObject::connect(actionControlReverseNexti, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseNexti); QObject::connect(actionControlReverseStepi, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseStepi); QObject::connect(actionControlReverseFinish, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseFinish); QObject::connect(actionControlRecordStart, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordStart); QObject::connect(actionControlRecordForward, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordForward); QObject::connect(actionControlRecordReverse, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordReverse); QObject::connect(actionControlRecordStop, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordStop); QObject::connect(actionControlInterrupt, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterrupt); QObject::connect(actionSettingsConfiguration, &QAction::triggered, this, &SeerMainWindow::handleSettingsConfiguration); QObject::connect(actionSettingsSaveConfiguration, &QAction::triggered, this, &SeerMainWindow::handleSettingsSaveConfiguration); QObject::connect(actionGdbLaunch, &QAction::triggered, this, &SeerMainWindow::handleFileDebugWithOutDefaultProject); QObject::connect(actionGdbTerminate, &QAction::triggered, this, &SeerMainWindow::handleTerminateExecutable); QObject::connect(actionGdbRestart, &QAction::triggered, this, &SeerMainWindow::handleRestartExecutable); QObject::connect(_styleMenuActionGroup, &QActionGroup::triggered, this, &SeerMainWindow::handleStyleMenuChanged); QObject::connect(actionGdbContinue, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbContinue); QObject::connect(actionGdbNext, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbNext); QObject::connect(actionGdbStep, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStep); QObject::connect(actionGdbNexti, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbNexti); QObject::connect(actionGdbStepi, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStepi); QObject::connect(actionGdbFinish, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbFinish); QObject::connect(actionRecordProcess, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordStartStopToggle); QObject::connect(actionRecordDirection, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordDirectionToggle); QObject::connect(actionInterruptProcess, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterrupt); QObject::connect(_interruptAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterrupt); QObject::connect(interruptActionSIGINT, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGINT); QObject::connect(interruptActionSIGKILL, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGKILL); QObject::connect(interruptActionSIGFPE, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGFPE); QObject::connect(interruptActionSIGSEGV, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGSEGV); QObject::connect(interruptActionSIGUSR1, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGUSR1); QObject::connect(interruptActionSIGUSR2, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGUSR2); QObject::connect(actionVisualizers, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbMemoryVisualizer); QObject::connect(visualizerMemoryAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbMemoryVisualizer); QObject::connect(visualizerArrayAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbArrayVisualizer); QObject::connect(visualizerMatrixAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbMatrixVisualizer); QObject::connect(visualizerVarAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbVarVisualizer); QObject::connect(visualizerStructAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStructVisualizer); QObject::connect(visualizerImageAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbImageVisualizer); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, runStatus, &SeerRunStatusIndicator::handleText); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::equalTextOutput, runStatus, &SeerRunStatusIndicator::handleText); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, this, &SeerMainWindow::handleText); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::caretTextOutput, this, &SeerMainWindow::handleText); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::equalTextOutput, this, &SeerMainWindow::handleText); QObject::connect(gdbWidget->editorManager(), &SeerEditorManagerWidget::showMessage, this, &SeerMainWindow::handleShowMessage); QObject::connect(gdbWidget->editorManager(), &SeerEditorManagerWidget::assemblyTabShown, this, &SeerMainWindow::handleViewAssemblyShown); QObject::connect(gdbWidget, &SeerGdbWidget::recordSettingsChanged, this, &SeerMainWindow::handleRecordSettingsChanged); QObject::connect(gdbWidget, &SeerGdbWidget::changeWindowTitle, this, &SeerMainWindow::handleChangeWindowTitle); QObject::connect(gdbWidget, &SeerGdbWidget::stateChanged, this, &SeerMainWindow::handleGdbStateChanged); QObject::connect(runStatus, &SeerRunStatusIndicator::statusChanged, this, &SeerMainWindow::handleRunStatusChanged); QObject::connect(qApp, &QApplication::aboutToQuit, gdbWidget, &SeerGdbWidget::handleGdbShutdown); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerMainWindow::handleHelpToolButtonClicked); QObject::connect(gdbWidget, &SeerGdbWidget::sessionTerminated, runStatus, &SeerRunStatusIndicator::handleSessionTerminated); // This handle button state when target state changes QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, this, &SeerMainWindow::handleStatusChanged); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::caretTextOutput, this, &SeerMainWindow::handleStatusChanged); handleRecordSettingsChanged(); // // Initialize contents. // // Restore window settings. readSettings(); // Restore configuration settings. readConfigSettings(); // Show the main window. show(); handleShowMessage("Welcome to Seer. The All Knowing...", 3000); } SeerMainWindow::~SeerMainWindow() { } void SeerMainWindow::setExecutableName (const QString& executableName) { gdbWidget->setExecutableName(executableName); } const QString& SeerMainWindow::executableName () const { return gdbWidget->executableName(); } void SeerMainWindow::setExecutableSymbolName (const QString& executableSymbolName) { gdbWidget->setExecutableSymbolName(executableSymbolName); } const QString& SeerMainWindow::executableSymbolName () const { return gdbWidget->executableSymbolName(); } void SeerMainWindow::setExecutableArguments (const QString& executableArguments) { gdbWidget->setExecutableArguments(executableArguments); } void SeerMainWindow::setExecutableArguments (const QStringList& executableArguments) { // // Convert the list of arguments into a single argument string. // Be careful of arguments that contain a space. These need to be surrounded by // a "'" character to retain the argument grouping. // // ie: myprog 42.0 "This is a multi-worded argument" // // Has 2 arguments. Not 6. // QString arguments; for (auto arg : executableArguments) { if (arg.contains(' ')) { arg = "'" + arg + "'"; } if (arguments == "") { arguments = arg; }else{ arguments += " " + arg; } } setExecutableArguments(arguments); } const QString& SeerMainWindow::executableArguments () const { return gdbWidget->executableArguments(); } void SeerMainWindow::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) { gdbWidget->setExecutableWorkingDirectory(executableWorkingDirectory); } const QString& SeerMainWindow::executableWorkingDirectory () const { return gdbWidget->executableWorkingDirectory(); } void SeerMainWindow::setExecutableBreakpointsFilename (const QString& breakpointsFilename) { gdbWidget->setExecutableBreakpointsFilename(breakpointsFilename); } const QString& SeerMainWindow::executableBreakpointsFilename () const { return gdbWidget->executableBreakpointsFilename(); } void SeerMainWindow::setExecutableBreakpointFunctionName (const QString& nameoraddress) { gdbWidget->setExecutableBreakpointFunctionName(nameoraddress); } const QString& SeerMainWindow::executableBreakpointFunctionName () const { return gdbWidget->executableBreakpointFunctionName(); } void SeerMainWindow::setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno) { gdbWidget->setExecutableBreakpointSourceName(sourceFilenameAndLineno); } const QString& SeerMainWindow::executableBreakpointSourceName () const { return gdbWidget->executableBreakpointSourceName(); } void SeerMainWindow::setExecutableShowAssemblyTabMode (const QString& mode) { gdbWidget->setAssemblyShowAssemblyTabOnStartupMode(mode); } QString SeerMainWindow::executableShowAssemblyTabMode () const { return gdbWidget->assemblyShowAssemblyTabOnStartupMode(); } void SeerMainWindow::setExecutableRandomizeStartAddress (bool flag) { gdbWidget->setGdbRandomizeStartAddress(flag); } bool SeerMainWindow::executableRandomizeStartAddress () const { return gdbWidget->gdbRandomizeStartAddress(); } void SeerMainWindow::setExecutableNonStopMode (bool flag) { gdbWidget->setGdbNonStopMode(flag); } bool SeerMainWindow::executableNonStopMode () const { return gdbWidget->gdbNonStopMode(); } void SeerMainWindow::setExecutablePid (int pid) { gdbWidget->setExecutablePid(pid); } int SeerMainWindow::executablePid () const { return gdbWidget->executablePid(); } void SeerMainWindow::setExecutableConnectHostPort (const QString& executableConnectHostPort) { gdbWidget->setExecutableConnectHostPort(executableConnectHostPort); } const QString& SeerMainWindow::executableConnectHostPort () const { return gdbWidget->executableConnectHostPort(); } void SeerMainWindow::setExecutableConnectRemoteTargetType (const QString& type) { gdbWidget->setGdbRemoteTargetType(type); } QString SeerMainWindow::executableConnectRemoteTargetType () const { return gdbWidget->gdbRemoteTargetType(); } void SeerMainWindow::setExecutableConnectGdbserverDebug (bool enable) { gdbWidget->setGdbServerDebug(enable); } bool SeerMainWindow::executableConnectGdbserverDebug () const { return gdbWidget->gdbServerDebug(); } void SeerMainWindow::setExecutableRRTraceDirectory (const QString& executableRRTraceDirectory) { gdbWidget->setExecutableRRTraceDirectory(executableRRTraceDirectory); } const QString& SeerMainWindow::executableRRTraceDirectory () const { return gdbWidget->executableRRTraceDirectory(); } void SeerMainWindow::setExecutableCoreFilename (const QString& executableCoreFilename) { gdbWidget->setExecutableCoreFilename(executableCoreFilename); } const QString& SeerMainWindow::executableCoreFilename () const { return gdbWidget->executableCoreFilename(); } void SeerMainWindow::setExecutablePreGdbCommands (const QStringList& preGdbCommands) { gdbWidget->setExecutablePreGdbCommands(preGdbCommands); } const QStringList& SeerMainWindow::executablePreGdbCommands() const { return gdbWidget->executablePreGdbCommands(); } void SeerMainWindow::setExecutablePostGdbCommands (const QStringList& postGdbCommands) { gdbWidget->setExecutablePostGdbCommands(postGdbCommands); } const QStringList& SeerMainWindow::executablePostGdbCommands() const { return gdbWidget->executablePostGdbCommands(); } void SeerMainWindow::setProjectFilename (const QString& projectFilename) { _projectFile = projectFilename; } const QString& SeerMainWindow::projectFilename () const { return _projectFile; } void SeerMainWindow::setGdbProgramOverride (const QString& gdbProgram) { gdbWidget->setGdbProgramOverride(gdbProgram); } QString SeerMainWindow::gdbProgramOverride () const { return gdbWidget->gdbProgramOverride(); } void SeerMainWindow::setGdbArgumentsOverride (const QString& gdbArguments) { gdbWidget->setGdbArgumentsOverride(gdbArguments); } QString SeerMainWindow::gdbArgumentsOverride () const { return gdbWidget->gdbArgumentsOverride(); } void SeerMainWindow::launchExecutable (const QString& launchMode, const QString& breakMode) { // Show all buttons by default. Turn some off depending on debug mode. actionGdbContinue->setVisible(true); actionGdbNext->setVisible(true); actionGdbNexti->setVisible(true); actionGdbStep->setVisible(true); actionGdbStepi->setVisible(true); actionGdbFinish->setVisible(true); actionInterruptProcess->setVisible(true); actionRecordProcess->setVisible(true); actionRecordDirection->setVisible(true); actionGdbRestart->setVisible(false); actionGdbTerminate->setVisible(false); actionGdbLaunch->setVisible(false); actionControlRestart->setVisible(true); actionControlTerminate->setVisible(true); actionControlInterrupt->setVisible(true); if (launchMode == "run") { gdbWidget->handleGdbRunExecutable(breakMode, false); }else if (launchMode == "start") { gdbWidget->handleGdbRunExecutable(breakMode, false); }else if (launchMode == "attach") { gdbWidget->handleGdbAttachExecutable(false); }else if (launchMode == "connect") { gdbWidget->handleGdbConnectExecutable(false); }else if (launchMode == "rr") { gdbWidget->handleGdbRRExecutable(false); }else if (launchMode == "corefile") { actionGdbContinue->setVisible(false); actionGdbNext->setVisible(false); actionGdbNexti->setVisible(false); actionGdbStep->setVisible(false); actionGdbStepi->setVisible(false); actionGdbFinish->setVisible(false); actionInterruptProcess->setVisible(false); actionRecordProcess->setVisible(false); actionRecordDirection->setVisible(false); gdbWidget->handleGdbCoreFileExecutable(); }else if (launchMode == "project") { actionGdbLaunch->setVisible(true); // If no mode, schedule the opening of the debug dialog. QTimer::singleShot(200, this, &SeerMainWindow::handleFileDebugWithDefaultProject); }else if (launchMode == "none") { actionGdbLaunch->setVisible(true); // If no mode, schedule the opening of the debug dialog. QTimer::singleShot(200, this, &SeerMainWindow::handleFileDebugWithDefaultProject); }else if (launchMode == "configdialog") { actionGdbLaunch->setVisible(true); // Launch the config dialog. QTimer::singleShot(200, this, &SeerMainWindow::handleSettingsConfiguration); }else{ qDebug() << "UNKNOWN launch mode:" << launchMode; } } const QString& SeerMainWindow::executableLaunchMode () const { return gdbWidget->executableLaunchMode(); } const QString& SeerMainWindow::executableBreakMode () const { return gdbWidget->executableBreakMode(); } void SeerMainWindow::setStyleName (const QString& name) { // Check for Dark/Light style from Seer's resource tree. if (name == "dark" || name == "light") { QFile s(":qdarkstyle/" + name + "/" + name + "style.qss"); if (s.exists() == false) { qDebug() << "Stylesheet '" + name + "' doesn't exist!"; return; } bool f = s.open(QFile::ReadOnly | QFile::Text); if (f == false) { qDebug() << "Can't open Stylesheet '" + name + "'!"; return; } QTextStream ts(&s); qApp->setStyleSheet(ts.readAll()); _styleName = name; // Otherwise, a system installed one or Qt internal one. }else{ QApplication::setStyle(name); _styleName = name; } } const QString& SeerMainWindow::styleName () { return _styleName; } void SeerMainWindow::handleFileDebugWithDefaultProject () { handleFileDebug(true); } void SeerMainWindow::handleFileDebugWithOutDefaultProject () { handleFileDebug(false); } void SeerMainWindow::handleFileDebug (bool loadDefaultProject) { SeerDebugDialog dlg(this); dlg.setExecutableName(executableName()); dlg.setExecutableSymbolName(executableSymbolName()); dlg.setExecutableWorkingDirectory(executableWorkingDirectory()); dlg.setExecutableArguments(executableArguments()); dlg.setLaunchMode(executableLaunchMode()); dlg.setBreakpointMode(executableBreakMode()); dlg.setBreakpointsFilename(executableBreakpointsFilename()); dlg.setBreakpointFunctionName(executableBreakpointFunctionName()); dlg.setBreakpointSourceName(executableBreakpointSourceName()); dlg.setShowAssemblyTabMode(executableShowAssemblyTabMode()); dlg.setRandomizeStartAddress(executableRandomizeStartAddress()); dlg.setNonStopMode(executableNonStopMode()); dlg.setAttachPid(executablePid()); dlg.setConnectHostPort(executableConnectHostPort()); dlg.setConnectRemoteTargetType(executableConnectRemoteTargetType()); dlg.setConnectGdbserverDebug(executableConnectGdbserverDebug()); dlg.setRRTraceDirectory(executableRRTraceDirectory()); dlg.setCoreFilename(executableCoreFilename()); dlg.setPreGdbCommands(executablePreGdbCommands()); dlg.setPostGdbCommands(executablePostGdbCommands()); // If there's a project, use it. if (projectFilename() != "") { dlg.setProjectFilename(projectFilename()); // Otherwise use the default project, if there is one. }else{ if (loadDefaultProject) { dlg.loadDefaultProjectSettings(); } } setProjectFilename(""); // Clear project name here. No need to have it anymore. int ret = dlg.exec(); if (ret == 0) { return; } QString launchMode = dlg.launchMode(); QString breakMode = dlg.breakpointMode(); if (launchMode == "") { return; } setExecutableName(dlg.executableName()); setExecutableSymbolName(dlg.executableSymbolName()); setExecutableWorkingDirectory(dlg.executableWorkingDirectory()); setExecutableArguments(dlg.executableArguments()); setExecutableBreakpointsFilename(dlg.breakpointsFilename()); setExecutableBreakpointFunctionName(dlg.breakpointFunctionName()); setExecutableBreakpointSourceName(dlg.breakpointSourceName()); setExecutableShowAssemblyTabMode(dlg.showAssemblyTabMode()); setExecutableRandomizeStartAddress(dlg.randomizeStartAddress()); setExecutableNonStopMode(dlg.nonStopMode()); setExecutablePid(dlg.attachPid()); setExecutableConnectHostPort(dlg.connectHostPort()); setExecutableConnectRemoteTargetType(dlg.connectRemoteTargetType()); setExecutableConnectGdbserverDebug(dlg.connectGdbserverDebug()); setExecutableRRTraceDirectory(dlg.rrTraceDirectory()); setExecutableCoreFilename(dlg.coreFilename()); setExecutablePreGdbCommands(dlg.preGdbCommands()); setExecutablePostGdbCommands(dlg.postGdbCommands()); launchExecutable(launchMode, breakMode); } void SeerMainWindow::handleFileArguments () { SeerArgumentsDialog dlg(this); dlg.setExecutableArguments(executableArguments()); int ret = dlg.exec(); if (ret == 0) { return; } setExecutableArguments(dlg.executableArguments()); } void SeerMainWindow::handleFileQuit () { gdbWidget->handleGdbShutdown(); QCoreApplication::exit(0); } void SeerMainWindow::handleViewMemoryVisualizer () { gdbWidget->handleGdbMemoryVisualizer(); } void SeerMainWindow::handleViewArrayVisualizer () { gdbWidget->handleGdbArrayVisualizer(); } void SeerMainWindow::handleViewMatrixVisualizer () { gdbWidget->handleGdbMatrixVisualizer(); } void SeerMainWindow::handleViewStructVisualizer () { gdbWidget->handleGdbStructVisualizer(); } void SeerMainWindow::handleViewVarVisualizer () { gdbWidget->handleGdbVarVisualizer(); } void SeerMainWindow::handleViewImageVisualizer () { gdbWidget->handleGdbImageVisualizer(); } void SeerMainWindow::handleViewAssembly () { gdbWidget->editorManager()->showAssembly(); } void SeerMainWindow::handleViewAssemblyShown (bool shown) { // Corefile always have them off. if (executableLaunchMode() == "corefile") { actionGdbNext->setVisible(false); actionGdbNexti->setVisible(false); actionGdbStep->setVisible(false); actionGdbStepi->setVisible(false); actionGdbFinish->setVisible(false); // Toggle regular and instruction buttons. }else{ actionGdbNext->setVisible(!shown); actionGdbNexti->setVisible(shown); actionGdbStep->setVisible(!shown); actionGdbStepi->setVisible(shown); actionGdbFinish->setVisible(!shown); } } void SeerMainWindow::handleViewConsoleAttached () { gdbWidget->setConsoleMode("attached"); } void SeerMainWindow::handleViewConsoleDetached () { gdbWidget->setConsoleMode("detached"); } void SeerMainWindow::handleViewConsoleDetachedMinimized () { gdbWidget->setConsoleMode("detachedminimized"); } void SeerMainWindow::handleSettingsConfiguration () { SeerConfigDialog dlg(this); dlg.setSeerConsoleMode(gdbWidget->consoleMode()); dlg.setSeerConsoleScrollLines(gdbWidget->consoleScrollLines()); dlg.setSeerRememberManualCommandCount(gdbWidget->rememberManualCommandCount()); dlg.setGdbLauncher(gdbWidget->gdbLauncher()); dlg.setGdbProgram(gdbWidget->gdbProgram()); dlg.setGdbArguments(gdbWidget->gdbArguments()); dlg.setGdbAsyncMode(gdbWidget->gdbAsyncMode()); dlg.setGdbNonStopMode(gdbWidget->gdbNonStopMode()); dlg.setGdbHandleTerminatingException(gdbWidget->gdbHandleTerminatingException()); dlg.setGdbRandomizeStartAddress(gdbWidget->gdbRandomizeStartAddress()); dlg.setGdbEnablePrettyPrinting(gdbWidget->gdbEnablePrettyPrinting()); dlg.setGdbRemoteTargetType(gdbWidget->gdbRemoteTargetType()); dlg.setGdbArchitectureType(gdbWidget->gdbArchitectureType()); dlg.setEditorFont(gdbWidget->editorManager()->editorFont()); dlg.setEditorTabSize(gdbWidget->editorManager()->editorTabSize()); dlg.setEditorHighlighterSettings(gdbWidget->editorManager()->editorHighlighterSettings()); dlg.setEditorHighlighterEnabled(gdbWidget->editorManager()->editorHighlighterEnabled()); dlg.setEditorHighlighterEnabled(gdbWidget->editorManager()->editorHighlighterEnabled()); dlg.setExternalEditorCommand(gdbWidget->editorManager()->editorExternalEditorCommand()); dlg.setEditorAutoSourceReload(gdbWidget->editorManager()->editorAutoSourceReload()); dlg.setSourceAlternateDirectories(gdbWidget->sourceAlternateDirectories()); dlg.setSourceIgnoreFilePatterns(gdbWidget->sourceIgnoreFilePatterns()); dlg.setSourceMiscFilePatterns(gdbWidget->sourceMiscFilePatterns()); dlg.setSourceSourceFilePatterns(gdbWidget->sourceSourceFilePatterns()); dlg.setSourceHeaderFilePatterns(gdbWidget->sourceHeaderFilePatterns()); dlg.setAssemblyShowAssemblyTabOnStartupMode(gdbWidget->assemblyShowAssemblyTabOnStartupMode()); dlg.setAssemblyKeepAssemblyTabOnTop(gdbWidget->assemblyKeepAssemblyTabOnTop()); dlg.setAssemblyDisassemblyFlavor(gdbWidget->assemblyDisassemblyFlavor()); dlg.setAssemblySymbolDemagling(gdbWidget->assemblySymbolDemagling()); dlg.setAssemblyShowAddressColumn(gdbWidget->assemblyShowAddressColumn()); dlg.setAssemblyShowOffsetColumn(gdbWidget->assemblyShowOffsetColumn()); dlg.setAssemblyShowOpcodeColumn(gdbWidget->assemblyShowOpcodeColumn()); dlg.setAssemblyShowSourceLines(gdbWidget->assemblyShowSourceLines()); dlg.setAssemblyRegisterFormat(gdbWidget->assemblyRegisterFormat()); dlg.setAssemblyDisassemblyMode(gdbWidget->assemblyDisassemblyMode(), gdbWidget->assemblyDisassemblyBytes()); dlg.setKeySettings(keySettings()); dlg.setRRProgram(gdbWidget->rrProgram()); dlg.setRRArguments(gdbWidget->rrArguments()); dlg.setRRGdbArguments(gdbWidget->rrGdbArguments()); int ret = dlg.exec(); if (ret == 0) { return; } // Update the GdbWidget with the new settings. gdbWidget->setConsoleMode(dlg.seerConsoleMode()); gdbWidget->setConsoleScrollLines(dlg.seerConsoleScrollLines()); gdbWidget->setRememberManualCommandCount(dlg.seerRememberManualCommandCount()); gdbWidget->setGdbLauncher(dlg.gdbLauncher()); gdbWidget->setGdbProgram(dlg.gdbProgram()); gdbWidget->setGdbArguments(dlg.gdbArguments()); gdbWidget->setGdbAsyncMode(dlg.gdbAsyncMode()); gdbWidget->setGdbNonStopMode(dlg.gdbNonStopMode()); gdbWidget->setGdbHandleTerminatingException(dlg.gdbHandleTerminatingException()); gdbWidget->setGdbRandomizeStartAddress(dlg.gdbRandomizeStartAddress()); gdbWidget->setGdbEnablePrettyPrinting(dlg.gdbEnablePrettyPrinting()); gdbWidget->setGdbRemoteTargetType(dlg.gdbRemoteTargetType()); gdbWidget->setGdbArchitectureType(dlg.gdbArchitectureType()); gdbWidget->editorManager()->setEditorFont(dlg.editorFont()); gdbWidget->editorManager()->setEditorTabSize(dlg.editorTabSize()); gdbWidget->editorManager()->setEditorHighlighterSettings(dlg.editorHighlighterSettings()); gdbWidget->editorManager()->setEditorHighlighterEnabled(dlg.editorHighlighterEnabled()); gdbWidget->editorManager()->setEditorExternalEditorCommand(dlg.externalEditorCommand()); gdbWidget->editorManager()->setEditorAutoSourceReload(dlg.editorAutoSourceReload()); gdbWidget->setSourceAlternateDirectories(dlg.sourceAlternateDirectories()); gdbWidget->setSourceIgnoreFilePatterns(dlg.sourceIgnoreFilePatterns()); gdbWidget->setSourceMiscFilePatterns(dlg.sourceMiscFilePatterns()); gdbWidget->setSourceSourceFilePatterns(dlg.sourceSourceFilePatterns()); gdbWidget->setSourceHeaderFilePatterns(dlg.sourceHeaderFilePatterns()); gdbWidget->setAssemblyShowAssemblyTabOnStartupMode(dlg.assemblyShowAssemblyTabOnStartupMode()); gdbWidget->setAssemblyKeepAssemblyTabOnTop(dlg.assemblyKeepAssemblyTabOnTop()); gdbWidget->setAssemblyDisassemblyFlavor(dlg.assemblyDisassemblyFlavor()); gdbWidget->setAssemblySymbolDemagling(dlg.assemblySymbolDemagling()); gdbWidget->setAssemblyShowAddressColumn(dlg.assemblyShowAddressColumn()); gdbWidget->setAssemblyShowOffsetColumn(dlg.assemblyShowOffsetColumn()); gdbWidget->setAssemblyShowOpcodeColumn(dlg.assemblyShowOpcodeColumn()); gdbWidget->setAssemblyShowSourceLines(dlg.assemblyShowSourceLines()); gdbWidget->setAssemblyRegisterFormat(dlg.assemblyRegisterFormat()); gdbWidget->setAssemblyDisassemblyMode(dlg.assemblyDisassemblyMode(), dlg.assemblyDisassemblyBytes()); gdbWidget->setRRProgram(dlg.rrProgram()); gdbWidget->setRRArguments(dlg.rrArguments()); gdbWidget->setRRGdbArguments(dlg.rrGdbArguments()); // Clear history, if we need to. bool clearManualCommandHistory = dlg.seerClearManualCommandHistory(); if (clearManualCommandHistory) { gdbWidget->clearManualCommandHistory(); } // Set the key shortcuts. setKeySettings(dlg.keySettings()); } void SeerMainWindow::handleSettingsSaveConfiguration () { writeConfigSettings(); gdbWidget->writeSettings(); QMessageBox m(QMessageBox::Information, "Seer", "Configuration saved!"); m.setStandardButtons(QMessageBox::NoButton); QTimer::singleShot(1000, &m, SLOT(hide())); m.exec(); } void SeerMainWindow::handleHelpAbout () { SeerAboutDialog dlg(this); dlg.exec(); } void SeerMainWindow::handleTerminateExecutable () { if (gdbWidget->isGdbRuning() == true) { QSettings settings; bool prompt = true; settings.beginGroup("mainwindow"); { prompt = settings.value("promptterminate", prompt).toBool(); } settings.endGroup(); if (prompt) { QMessageBox msgBox(this); msgBox.setWindowTitle("Seer"); msgBox.setText("Terminate current session?"); msgBox.setIcon(QMessageBox::Question); // Add "Don't ask again" checkbox QCheckBox* dontAskAgainBox = new QCheckBox("Don't ask again", &msgBox); msgBox.setCheckBox(dontAskAgainBox); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Ok); int result = msgBox.exec(); // Save preference if checked if (dontAskAgainBox->isChecked()) { settings.beginGroup("mainwindow"); { settings.setValue("promptterminate", false); } settings.endGroup(); } if (result == QMessageBox::Cancel) { return; } } gdbWidget->handleGdbTerminateExecutable(false); } } void SeerMainWindow::handleRestartExecutable () { // Prompt if there's already a gdb running. if (gdbWidget->isGdbRuning() == true) { QSettings settings; bool prompt = true; settings.beginGroup("mainwindow"); { prompt = settings.value("promptrestart", prompt).toBool(); } settings.endGroup(); if (prompt) { // This QMessageBox with a checkbox and load/save from QSettings // is begging for a helper object! QMessageBox msgBox(this); msgBox.setWindowTitle("Seer"); msgBox.setText("Restart current session?"); msgBox.setIcon(QMessageBox::Question); // Add "Don't ask again" checkbox QCheckBox* dontAskAgainBox = new QCheckBox("Don't ask again", &msgBox); msgBox.setCheckBox(dontAskAgainBox); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Ok); int result = msgBox.exec(); // Save preference if checked if (dontAskAgainBox->isChecked()) { settings.beginGroup("mainwindow"); { settings.setValue("promptrestart", false); } settings.endGroup(); } if (result == QMessageBox::Cancel) { return; } } } if (gdbWidget->isGdbRuning() == true) { gdbWidget->handleGdbTerminateExecutable(false); } if (gdbWidget->isGdbRuning() == false && gdbWidget->hasBackupLaunchMode()) { gdbWidget->restoreLaunchMode(); } if (gdbWidget->executableLaunchMode() == "run" || gdbWidget->executableLaunchMode() == "start") { QString breakfunction = gdbWidget->executableBreakpointFunctionName(); QString breaksource = gdbWidget->executableBreakpointSourceName(); // Stop in function? if (breakfunction != "") { gdbWidget->handleGdbRunExecutable("infunction", true); // Stop at source:line? }else if (breaksource != "") { gdbWidget->handleGdbRunExecutable("insource", true); // Otherwise, attempt to stop in "main". }else{ gdbWidget->handleGdbRunExecutable("inmain", true); } }else if (gdbWidget->executableLaunchMode() == "attach") { gdbWidget->handleGdbAttachExecutable(true); }else if (gdbWidget->executableLaunchMode() == "connect") { gdbWidget->handleGdbConnectExecutable(true); }else if (gdbWidget->executableLaunchMode() == "rr") { gdbWidget->handleGdbRRExecutable(true); }else if (gdbWidget->executableLaunchMode() == "corefile") { gdbWidget->handleGdbCoreFileExecutable(); }else{ qDebug() << "UNKNOWN launch mode:" << gdbWidget->executableLaunchMode(); } } void SeerMainWindow::handleStyleMenuChanged () { QAction* action = _styleMenuActionGroup->checkedAction(); if (action == 0) { return; } setStyleName(action->text()); } void SeerMainWindow::handleShowMessage (QString message, int time) { statusBar()->showMessage(message, time); } void SeerMainWindow::handleGdbStateChanged () { // qDebug() << "MODE:" << gdbWidget->executableLaunchMode() << "GDBRUNNING:" << gdbWidget->isGdbRuning() << "HASBACKUPLAUNCH:" << gdbWidget->hasBackupLaunchMode(); // // We are currently debugging a program. Allow for Terminate/Detach/Disconnect... // // mode: "run" gdbrunning: true hasbackuplaunch: false // terminate: show debug: hide retart: hide // // mode: "run" gdbrunning: true hasbackuplaunch: true // terminate: show debug: hide retart: hide // if (gdbWidget->executableLaunchMode() != "" && gdbWidget->isGdbRuning() == true) { // Launch and Restart. Applies to all. actionGdbLaunch->setVisible(false); actionGdbRestart->setVisible(true); actionControlRestart->setVisible(true); actionControlTerminate->setVisible(true); // Get the hotkey for the Terminate button. QString hotkey = ""; if (_keySettings.has("Terminate")) { SeerKeySetting setting = _keySettings.get("Terminate"); hotkey = " (" + setting._sequence.toString() + ")"; } // Run mode if (gdbWidget->executableLaunchMode() == "run" || gdbWidget->executableLaunchMode() == "start" || gdbWidget->executableLaunchMode() == "rr" || gdbWidget->executableLaunchMode() == "corefile") { // Terminate actionGdbTerminate->setVisible(true); actionGdbTerminate->setText("Terminate" + hotkey); actionGdbTerminate->setToolTip("Terminate the current debugging session."); actionControlTerminate->setText("Terminate"); actionControlTerminate->setToolTip("Terminate the current debugging session."); // Attach mode }else if (gdbWidget->executableLaunchMode() == "attach") { // Detach actionGdbTerminate->setVisible(true); actionGdbTerminate->setText("Detach" + hotkey); actionGdbTerminate->setToolTip("Detach from the current debugging session."); actionControlTerminate->setText("Detach"); actionControlTerminate->setToolTip("Detach from the current debugging session."); // Connect mode }else if (gdbWidget->executableLaunchMode() == "connect") { // Disconnect actionGdbTerminate->setVisible(true); actionGdbTerminate->setText("Disconnect" + hotkey); actionGdbTerminate->setToolTip("Disconnect from the current debugging session."); actionControlTerminate->setText("Disconnect"); actionControlTerminate->setToolTip("Disconnect from the current debugging session."); }else{ qDebug() << "UNKNOWN launch mode:" << gdbWidget->executableLaunchMode(); } return; } // // We are debugging a program but gdb has been killed. Allow for Launch and for Restart/Reattach/Reconnect... // // mode: "" gdbrunning: false hasbackuplaunch: true // terminate: hide debug: show retart: show // if (gdbWidget->executableLaunchMode() == "" && gdbWidget->isGdbRuning() == false && gdbWidget->hasBackupLaunchMode() == true) { // Allow a new debugging session. actionGdbLaunch->setVisible(true); actionGdbLaunch->setToolTip("Start a new debugging session."); // Hide terminate. Applies to all. actionGdbTerminate->setVisible(false); actionControlRestart->setVisible(true); actionControlTerminate->setVisible(true); // Get the hotkey for the Restart button. QString hotkey = ""; if (_keySettings.has("Restart")) { SeerKeySetting setting = _keySettings.get("Restart"); hotkey = " (" + setting._sequence.toString() + ")"; } // Run mode if (gdbWidget->backupLaunchMode() == "run" || gdbWidget->backupLaunchMode() == "start" || gdbWidget->backupLaunchMode() == "rr" || gdbWidget->backupLaunchMode() == "corefile") { // Restart actionGdbRestart->setVisible(true); actionGdbRestart->setText("Restart" + hotkey); actionGdbRestart->setToolTip("Restart the current debugging session."); actionControlRestart->setText("Restart"); actionControlRestart->setToolTip("Restart the current debugging session."); // Attach mode }else if (gdbWidget->backupLaunchMode() == "attach") { // Reattach actionGdbRestart->setVisible(true); actionGdbRestart->setText("Reattach" + hotkey); actionGdbRestart->setToolTip("Reattach the current debugging session."); actionControlRestart->setText("Reattach"); actionControlRestart->setToolTip("Reattach the current debugging session."); // Connect mode }else if (gdbWidget->backupLaunchMode() == "connect") { // Reconnect actionGdbRestart->setVisible(true); actionGdbRestart->setText("Reconnect" + hotkey); actionGdbRestart->setToolTip("Reconnect the current debugging session."); actionControlRestart->setText("Reconnect"); actionControlRestart->setToolTip("Reconnect the current debugging session."); }else{ qDebug() << "UNKNOWN launch mode:" << gdbWidget->backupLaunchMode(); } return; } qDebug() << "BAD STATE!"; } void SeerMainWindow::handleText (const QString& text) { if (text.startsWith("^error,msg=") || text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // ^error,msg="The program is not being run." // ^error,msg="ptrace: No such process." // 3^error,msg="Undefined MI command: symbol-info-variables",code="undefined-command" // 5^error,msg="No symbol "delta" in current context." // 5^error,msg="A syntax error in expression, near `'." QString newtext = Seer::filterEscapes(text); // Filter escaped characters. // Filter out less important errors. if (newtext.contains("^error,msg=\"No registers.\"")) { return; } if (newtext.contains("^error,msg=\"Selected thread is running.\"")) { return; } if (newtext.contains("^error,msg=\"Cannot inspect Ada tasks when program is not running\"")) { return; } if (newtext.contains("^error,msg=\"The current thread has terminated\"")) { return; } if (newtext.contains("^error,msg=\"A syntax error in expression, near ")) { return; } if (newtext.contains("^error,msg=\"No symbol \"")) { return; } // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text == "") { return; } // Show error on status bar. handleShowMessage(Seer::filterBookends(msg_text, '"', '"'), 3000); // Break early for certain errors. if (msg_text == "No symbol \"disassembly\" in current context.") { return; } if (msg_text == "\"-data-disassemble: No function contains specified address\"") { return; } if (msg_text == "\"No symbol \"disassembly\" in current context.\"") { return; } if (msg_text.startsWith("\"A syntax error in expression, near")) { return; } if (msg_text.startsWith("\"Invalid character ")) { return; } if (msg_text.startsWith("\"No symbol ")) { return; } if (msg_text.startsWith("\"Problem parsing arguments: data-evaluate-expression")) { return; } if (msg_text == "\"Attempt to use a type name as an expression\"") { return; } gdbWidget->addMessage(Seer::filterEscapes(msg_text), QMessageBox::Warning); return; }else if (text == "^running") { // Swallow this message. return; }else if (text == "^done") { return; }else if (text.startsWith("^done,files=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,shared-libraries=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,stack=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,variables=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,stack-args=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,bkpt={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,hw-awpt={")) { return; }else if (text.startsWith("^done,hw-rwpt={")) { return; }else if (text.startsWith("^done,wpt={")) { return; }else if (text.startsWith("^done,thread-ids={")) { return; }else if (text.startsWith("^done,new-thread-id=")) { return; }else if (text.startsWith("^done,threads=[")) { return; }else if (text.startsWith("^done,groups=[")) { return; }else if (text.startsWith("^done,register-names=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,register-values=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,DataExpressionAdded={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,DataExpressionDeleted={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,DataExpressionTable={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,symbols={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,asm_insns=[")) { return; }else if (text.startsWith("^done,ada-exceptions={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,skips=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,signal-values=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,signal-names=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,checkpoints=[") && text.endsWith("]")) { return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done"))) { return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { return; }else if (text == "^exit") { return; }else if (text.startsWith("*running,thread-id=\"")) { QString threadid_text = Seer::parseFirst(text, "thread-id=", '"', '"', false); handleShowMessage("Program started. Thread id: " + threadid_text, 3000); return; }else if (text == "^connected") { //^connected return; }else if (text.startsWith("^connected,frame=")) { //^connected,frame={level=\"0\",addr=\"0x00007f48351f80c1\",func=\"read\",args=[],from=\"/lib64/libc.so.6\",arch=\"i386:x86-64\"}" return; }else if (text.startsWith("*stopped")) { QString reason_text = Seer::parseFirst(text, "reason=", '"', '"', false); if (reason_text == "") { reason_text = "unknown"; } handleShowMessage("Program stopped. Reason: " + reason_text, 3000); if (reason_text == "signal-received") { //*stopped,reason="signal-received",signal-name="SIGSEGV",signal-meaning="Segmentation fault", ... QString signalname_text = Seer::parseFirst(text, "signal-name=", '"', '"', false); gdbWidget->addMessage("Program encountered a '" + signalname_text + "' signal.", QMessageBox::Warning); }else if (reason_text == "breakpoint-hit") { QString bkptno_text = Seer::parseFirst(text, "bkptno=", '"', '"', false); QString disp_text = Seer::parseFirst(text, "disp=", '"', '"', false); if (disp_text == "del") { gdbWidget->addMessage("Program reached temporary breakpoint '" + bkptno_text + "'.", QMessageBox::Information); }else{ gdbWidget->addMessage("Program reached breakpoint '" + bkptno_text + "'.", QMessageBox::Information); } }else if (reason_text == "watchpoint-trigger") { //*stopped,reason="watchpoint-trigger",wpt={number="3",exp="i"},value={old="32767",new="42"},frame={addr="0x0000000000400d79",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="9",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="0" QString wpt_text = Seer::parseFirst(text, "wpt=", '{', '}', false); QString number_text = Seer::parseFirst(wpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(wpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false); QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false); gdbWidget->addMessage(QString("Watchpoint triggered.\n\nNumber: %1\nExpression: %2\nOld value: %3\nNew value: %4").arg(number_text).arg(exp_text).arg(old_text).arg(new_text), QMessageBox::Information); }else if (reason_text == "read-watchpoint-trigger") { //*stopped,reason="read-watchpoint-trigger",hw-rwpt={number="5",exp="i"},value={value="42"},frame={addr="0x0000000000400d9a",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="11",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="4" QString hwwpt_text = Seer::parseFirst(text, "hw-rwpt=", '{', '}', false); QString number_text = Seer::parseFirst(hwwpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(hwwpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString value_text2 = Seer::parseFirst(value_text, "value=", '"', '"', false); gdbWidget->addMessage(QString("Watchpoint triggered.\n\nNumber: %1\nExpression: %2\nValue: %3").arg(number_text).arg(exp_text).arg(value_text2), QMessageBox::Information); }else if (reason_text == "access-watchpoint-trigger") { //*stopped,reason="access-watchpoint-trigger",hw-awpt={number="3",exp="v"},value={old="1",new="11"},frame={addr="0x000000000040059a",func="bar",args=[{name="v",value="11"}],file="helloonefile.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloonefile/helloonefile.cpp",line="15",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="3" QString hwawpt_text = Seer::parseFirst(text, "hw-awpt=", '{', '}', false); QString number_text = Seer::parseFirst(hwawpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(hwawpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false); QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false); gdbWidget->addMessage(QString("Watchpoint triggered.\n\nNumber: %1\nExpression: %2\nOld value: %3\nNew value: %4").arg(number_text).arg(exp_text).arg(old_text).arg(new_text), QMessageBox::Information); }else if (reason_text == "watchpoint-scope") { //*stopped,reason="watchpoint-scope",wpnum="5", frame={func="callee3",args=[{name="strarg", value="0x11940 \"A string argument.\""}], file="../../../devo/gdb/testsuite/gdb.mi/basics.c", fullname="/home/foo/bar/devo/gdb/testsuite/gdb.mi/basics.c",line="18"} QString wpnum_text = Seer::parseFirst(text, "wpnum=", '"', '"', false); gdbWidget->addMessage(QString("Watchpoint went out of scope. Will be deleted.\n\nNumber: %1").arg(wpnum_text), QMessageBox::Information); }else if (reason_text == "exited-normally") { //*stopped,reason="exited-normally" gdbWidget->addMessage("Program exited normally.", QMessageBox::Information); }else if (reason_text == "exited") { //*stopped,reason="exited",exit-code="01" QString exitcode_text = Seer::parseFirst(text, "exit-code=", '"', '"', false); gdbWidget->addMessage("Program exited with code '" + exitcode_text +"'", QMessageBox::Information); }else if (reason_text == "exited-signalled") { //*stopped,reason="exited-signalled",signal-name="SIGSEGV",signal-meaning="Segmentation fault" QString signalname_text = Seer::parseFirst(text, "signal-name=", '"', '"', false); gdbWidget->addMessage("Program exited abnormally.\nIt encountered a '" + signalname_text + "' signal.", QMessageBox::Warning); }else if (reason_text == "unknown") { // Don't bother showing this. // Attaching to a pid will generate an unknown *stopped message that is useless. // qDebug() << "Text=" << text; // qDebug() << "Reason=" << reason_text; // gdbWidget->addMessage("Program encountered an unknown problem. See the Gdb output tab for messages.", QMessageBox::Warning); } return; }else if (text.startsWith("=thread-group-started,")) { // =thread-group-started,id="i1",pid="30916" QString pid_text = Seer::parseFirst(text, "pid=", '"', '"', false); //qDebug() << "Inferior pid = " << pid_text; gdbWidget->addMessage("Program started. (pid=" + pid_text +")", QMessageBox::Information); return; }else if (text.startsWith("=")) { // Suppress all other '=' messages. return; } // Leave in for stray error messages. qDebug() << text; } void SeerMainWindow::handleRunStatusChanged (SeerRunStatusIndicator::RunStatus status) { if (status == SeerRunStatusIndicator::RunStatus::Idle) { _progressIndicator->stop(); }else if (status == SeerRunStatusIndicator::RunStatus::Stopped) { _progressIndicator->stop(); }else if (status == SeerRunStatusIndicator::RunStatus::Running) { _progressIndicator->start(); }else{ _progressIndicator->stop(); } } void SeerMainWindow::handleRecordSettingsChanged () { if (gdbWidget->gdbRecordMode() == "stop" || gdbWidget->gdbRecordMode() == "") { // Menu Control actionControlRecordStart->setEnabled(true); actionControlRecordStop->setEnabled(false); actionControlRecordForward->setEnabled(false); actionControlRecordReverse->setEnabled(false); actionControlRecordForward->setChecked(false); actionControlRecordReverse->setChecked(false); actionControlReverseContinue->setEnabled(false); actionControlReverseNext->setEnabled(false); actionControlReverseStep->setEnabled(false); actionControlReverseFinish->setEnabled(false); actionControlReverseNexti->setEnabled(false); actionControlReverseStepi->setEnabled(false); // Toolbar actionRecordProcess->setText("Record"); actionRecordProcess->setToolTip("Toggle Record mode."); actionRecordProcess->setEnabled(true); actionRecordDirection->setEnabled(false); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); }else if (gdbWidget->gdbRecordMode() == "full") { // Menu Control actionControlRecordStart->setEnabled(false); actionControlRecordStop->setEnabled(true); actionControlRecordForward->setEnabled(true); actionControlRecordReverse->setEnabled(true); actionControlReverseContinue->setEnabled(true); actionControlReverseNext->setEnabled(true); actionControlReverseStep->setEnabled(true); actionControlReverseFinish->setEnabled(true); actionControlReverseNexti->setEnabled(true); actionControlReverseStepi->setEnabled(true); if (gdbWidget->gdbRecordDirection() == "") { actionControlRecordForward->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); }else if (gdbWidget->gdbRecordDirection() == "--reverse") { actionControlRecordReverse->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-previous.svg")); }else{ actionControlRecordForward->setChecked(false); actionControlRecordReverse->setChecked(false); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); qDebug() << "Bad record direction of '" << gdbWidget->gdbRecordDirection() << "'"; } // Toolbar actionRecordProcess->setText("Recording"); actionRecordProcess->setToolTip("Toggle Record mode."); actionRecordProcess->setEnabled(true); actionRecordDirection->setEnabled(true); }else if (gdbWidget->gdbRecordMode() == "rr") { // Menu Control actionControlRecordStart->setEnabled(false); actionControlRecordStop->setEnabled(false); actionControlRecordForward->setEnabled(true); actionControlRecordReverse->setEnabled(true); actionControlReverseContinue->setEnabled(true); actionControlReverseNext->setEnabled(true); actionControlReverseStep->setEnabled(true); actionControlReverseFinish->setEnabled(true); actionControlReverseNexti->setEnabled(true); actionControlReverseStepi->setEnabled(true); if (gdbWidget->gdbRecordDirection() == "") { actionControlRecordForward->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); }else if (gdbWidget->gdbRecordDirection() == "--reverse") { actionControlRecordReverse->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-previous.svg")); }else{ actionControlRecordForward->setChecked(false); actionControlRecordReverse->setChecked(false); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); qDebug() << "Bad record direction of '" << gdbWidget->gdbRecordDirection() << "'"; } // Toolbar actionRecordProcess->setText("RR"); actionRecordProcess->setToolTip("Using RR debugger."); actionRecordProcess->setEnabled(true); actionRecordDirection->setEnabled(true); }else if (gdbWidget->gdbRecordMode() == "udb") { // Menu Control actionControlRecordStart->setEnabled(false); actionControlRecordStop->setEnabled(false); actionControlRecordForward->setEnabled(true); actionControlRecordReverse->setEnabled(true); actionControlReverseContinue->setEnabled(true); actionControlReverseNext->setEnabled(true); actionControlReverseStep->setEnabled(true); actionControlReverseFinish->setEnabled(true); actionControlReverseNexti->setEnabled(true); actionControlReverseStepi->setEnabled(true); if (gdbWidget->gdbRecordDirection() == "") { actionControlRecordForward->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); }else if (gdbWidget->gdbRecordDirection() == "--reverse") { actionControlRecordReverse->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-previous.svg")); }else{ actionControlRecordForward->setChecked(false); actionControlRecordReverse->setChecked(false); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); qDebug() << "Bad record direction of '" << gdbWidget->gdbRecordDirection() << "'"; } // Toolbar actionRecordProcess->setText("UDB"); actionRecordProcess->setToolTip("Using UDB debugger."); actionRecordProcess->setEnabled(true); actionRecordDirection->setEnabled(true); }else{ qDebug() << "Bad record mode of:" << gdbWidget->gdbRecordMode(); } } void SeerMainWindow::handleChangeWindowTitle (QString title) { if (title == "") { setWindowTitle("Seer Debugger"); }else{ setWindowTitle("Seer Debugger - '" + title + "'"); } } void SeerMainWindow::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/MainWindow.md"); help->show(); help->raise(); } void SeerMainWindow::writeSettings() { QSettings settings; settings.beginGroup("mainwindow"); { settings.setValue("size", size()); } settings.endGroup(); } void SeerMainWindow::readSettings() { QSettings settings; settings.beginGroup("mainwindow"); { resize(settings.value("size", QSize(1250, 1000)).toSize()); } settings.endGroup(); } void SeerMainWindow::writeConfigSettings () { QSettings settings; settings.beginGroup("mainwindow"); { settings.setValue("qtstyle", styleName()); } settings.endGroup(); settings.beginGroup("gdb"); { settings.setValue("launcher", gdbWidget->gdbLauncher()); settings.setValue("program", gdbWidget->gdbProgram()); settings.setValue("arguments", gdbWidget->gdbArguments()); settings.setValue("asyncmode", gdbWidget->gdbAsyncMode()); settings.setValue("nonstopmode", gdbWidget->gdbNonStopMode()); settings.setValue("handleterminatingexception", gdbWidget->gdbHandleTerminatingException()); settings.setValue("randomizestartaddress", gdbWidget->gdbRandomizeStartAddress()); settings.setValue("enableprettyprinting", gdbWidget->gdbEnablePrettyPrinting()); settings.setValue("remotetargettype", gdbWidget->gdbRemoteTargetType()); settings.setValue("architecturetype", gdbWidget->gdbArchitectureType()); } settings.endGroup(); settings.beginGroup("rr"); { settings.setValue("program", gdbWidget->rrProgram()); settings.setValue("arguments", gdbWidget->rrArguments()); settings.setValue("gdbarguments", gdbWidget->rrGdbArguments()); } settings.endGroup(); settings.beginGroup("editor"); { settings.setValue("font", gdbWidget->editorManager()->editorFont().toString()); settings.setValue("tabsize", gdbWidget->editorManager()->editorTabSize()); settings.setValue("externaleditorcommand", gdbWidget->editorManager()->editorExternalEditorCommand()); settings.setValue("autosourcereload", gdbWidget->editorManager()->editorAutoSourceReload()); settings.beginGroup("highlighter"); { settings.setValue("enabled", gdbWidget->editorManager()->editorHighlighterEnabled()); SeerHighlighterSettings highlighter = gdbWidget->editorManager()->editorHighlighterSettings(); QStringList keys = highlighter.keys(); for (int i=0; irememberManualCommandCount()); } settings.endGroup(); settings.beginWriteArray("shortcuts"); { SeerKeySettings keysettings = keySettings(); QStringList keys = keysettings.keys(); for (int i=0; isetGdbLauncher(settings.value("launcher", STRINGIFY(SEER_GDB_LAUNCHER)).toString()); #else gdbWidget->setGdbLauncher(settings.value("launcher", "").toString()); #endif #ifdef SEER_GDB_NAME gdbWidget->setGdbProgram(settings.value("program", STRINGIFY(SEER_GDB_NAME)).toString()); #else gdbWidget->setGdbProgram(settings.value("program", "/usr/bin/gdb").toString()); #endif gdbWidget->setGdbArguments(settings.value("arguments", "--interpreter=mi").toString()); gdbWidget->setGdbAsyncMode(settings.value("asyncmode", true).toBool()); gdbWidget->setGdbNonStopMode(settings.value("nonstopmode", false).toBool()); gdbWidget->setGdbHandleTerminatingException(settings.value("handleterminatingexception", true).toBool()); gdbWidget->setGdbRandomizeStartAddress(settings.value("randomizestartaddress", false).toBool()); gdbWidget->setGdbEnablePrettyPrinting(settings.value("enableprettyprinting", true).toBool()); gdbWidget->setGdbRemoteTargetType(settings.value("remotetargettype", "extended-remote").toString()); gdbWidget->setGdbArchitectureType(settings.value("architecturetype", "auto").toString()); } settings.endGroup(); settings.beginGroup("rr"); { gdbWidget->setRRProgram(settings.value("program", "/usr/bin/rr").toString()); gdbWidget->setRRArguments(settings.value("arguments", "replay --interpreter=mi").toString()); gdbWidget->setRRGdbArguments(settings.value("gdbarguments", "").toString()); } settings.endGroup(); settings.beginGroup("editor"); { QFont f; if (settings.contains("font")) { f.fromString(settings.value("font").toString()); }else{ f = QFont("monospace", 10); } gdbWidget->editorManager()->setEditorFont(f); gdbWidget->editorManager()->setEditorTabSize(settings.value("tabsize", 4).toInt()); gdbWidget->editorManager()->setEditorExternalEditorCommand(settings.value("externaleditorcommand").toString()); gdbWidget->editorManager()->setEditorAutoSourceReload(settings.value("autosourcereload").toBool()); settings.beginGroup("highlighter"); { gdbWidget->editorManager()->setEditorHighlighterEnabled(settings.value("enabled",true).toBool()); SeerHighlighterSettings highlighter = gdbWidget->editorManager()->editorHighlighterSettings(); QStringList keys = highlighter.keys(); for (int i=0; i()); } if (settings.contains("backgroundcolor")) { f.setBackground(settings.value("backgroundcolor").value()); } highlighter.add(keys[i], f); } settings.endGroup(); } if (settings.contains("cppsuffixes")) highlighter.setCppSourceSuffixes(settings.value("cppsuffixes").toString()); if (settings.contains("odinsuffixes")) highlighter.setOdinSourceSuffixes(settings.value("odinsuffixes").toString()); if (settings.contains("rustsuffixes")) highlighter.setRustSourceSuffixes(settings.value("rustsuffixes").toString()); gdbWidget->editorManager()->setEditorHighlighterSettings(highlighter); } settings.endGroup(); } settings.endGroup(); settings.beginGroup("manualgdbcommands"); { gdbWidget->setRememberManualCommandCount(settings.value("remembercount", 10).toInt()); } settings.endGroup(); int size = settings.beginReadArray("shortcuts"); { SeerKeySettings keysettings = keySettings(); // Start with defaults. The add() will overwrite. for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); QString name = settings.value("action").toString(); QKeySequence key = QKeySequence::fromString(settings.value("key").toString()); QString help = settings.value("help").toString(); keysettings.add(name, SeerKeySetting(name, key, help)); } setKeySettings(keysettings); } settings.endArray(); } void SeerMainWindow::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QMainWindow::resizeEvent(event); } void SeerMainWindow::closeEvent (QCloseEvent* event) { event->accept(); QCoreApplication::exit(0); } void SeerMainWindow::setKeySettings (const SeerKeySettings& settings) { _keySettings = settings; refreshShortCuts(); } const SeerKeySettings SeerMainWindow::keySettings () const { return _keySettings; } void SeerMainWindow::refreshShortCuts () { // Dynamically change tool tip for 'Restart' depending on debug mode. if (_keySettings.has("Restart")) { SeerKeySetting setting = _keySettings.get("Restart"); actionGdbRestart->setToolTip(setting._description); actionGdbRestart->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlRestart->setShortcut(setting._sequence); } if (_keySettings.has("Terminate")) { SeerKeySetting setting = _keySettings.get("Terminate"); actionGdbTerminate->setToolTip(setting._description); actionGdbTerminate->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlTerminate->setShortcut(setting._sequence); } if (_keySettings.has("Next")) { SeerKeySetting setting = _keySettings.get("Next"); actionGdbNext->setToolTip(setting._description); actionGdbNext->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlNext->setShortcut(setting._sequence); } if (_keySettings.has("Nexti")) { SeerKeySetting setting = _keySettings.get("Nexti"); actionGdbNexti->setToolTip(setting._description); actionGdbNexti->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlNexti->setShortcut(setting._sequence); } if (_keySettings.has("Step")) { SeerKeySetting setting = _keySettings.get("Step"); actionGdbStep->setToolTip(setting._description); actionGdbStep->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlStep->setShortcut(setting._sequence); } if (_keySettings.has("Stepi")) { SeerKeySetting setting = _keySettings.get("Stepi"); actionGdbStepi->setToolTip(setting._description); actionGdbStepi->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlStepi->setShortcut(setting._sequence); } if (_keySettings.has("Finish")) { SeerKeySetting setting = _keySettings.get("Finish"); actionGdbFinish->setToolTip(setting._description); actionGdbFinish->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlFinish->setShortcut(setting._sequence); } if (_keySettings.has("Continue")) { SeerKeySetting setting = _keySettings.get("Continue"); actionGdbContinue->setToolTip(setting._description); actionGdbContinue->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlContinue->setShortcut(setting._sequence); } if (_keySettings.has("ReverseNext")) { SeerKeySetting setting = _keySettings.get("ReverseNext"); actionControlReverseNext->setShortcut(setting._sequence); } if (_keySettings.has("ReverseNexti")) { SeerKeySetting setting = _keySettings.get("ReverseNexti"); actionControlReverseNexti->setShortcut(setting._sequence); } if (_keySettings.has("ReverseStep")) { SeerKeySetting setting = _keySettings.get("ReverseStep"); actionControlReverseStep->setShortcut(setting._sequence); } if (_keySettings.has("ReverseStepi")) { SeerKeySetting setting = _keySettings.get("ReverseStepi"); actionControlReverseStepi->setShortcut(setting._sequence); } if (_keySettings.has("ReverseFinish")) { SeerKeySetting setting = _keySettings.get("ReverseFinish"); actionControlReverseFinish->setShortcut(setting._sequence); } if (_keySettings.has("ReverseContinue")) { SeerKeySetting setting = _keySettings.get("ReverseContinue"); actionControlReverseContinue->setShortcut(setting._sequence); } if (_keySettings.has("Interrupt")) { SeerKeySetting setting = _keySettings.get("Interrupt"); _interruptAction->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlInterrupt->setShortcut(setting._sequence); } if (_keySettings.has("Debug")) { SeerKeySetting setting = _keySettings.get("Debug"); actionFileDebug->setShortcut(setting._sequence); } if (_keySettings.has("Arguments")) { SeerKeySetting setting = _keySettings.get("Arguments"); actionFileArguments->setShortcut(setting._sequence); } if (_keySettings.has("Quit")) { SeerKeySetting setting = _keySettings.get("Quit"); actionFileQuit->setShortcut(setting._sequence); } if (_keySettings.has("ToggleRecordDirection")) { SeerKeySetting setting = _keySettings.get("ToggleRecordDirection"); actionRecordDirection->setText(QString("Direction") + " (" + setting._sequence.toString() + ")"); actionRecordDirection->setShortcut(setting._sequence); actionControlDirectionMenu->setTitle(QString("Direction") + " (Toggle " + setting._sequence.toString() + ")"); } if (_keySettings.has("RunToLine")) { SeerKeySetting setting = _keySettings.get("RunToLine"); actionControlRunToLine->setShortcut(setting._sequence); } // Notify the editor manager of changes. gdbWidget->editorManager()->setEditorKeySettings(keySettings()); } /*********************************************************************************************************************** * Change action button availability when status change **********************************************************************************************************************/ void SeerMainWindow::handleStatusChanged(QString message) { // target halt if (message.startsWith("*stopped,reason=") || message.startsWith("^done,stack=[frame=")) { handleGdbTargetInterrupt(); } else if (message.startsWith("*running")) // target is running { handleGdbTargetRunning(); } } // Disable some button while target is running void SeerMainWindow::handleGdbTargetRunning() { // Control Menu actionControlInterrupt->setEnabled(true); actionControlContinue->setEnabled(false); actionControlNext->setEnabled(false); actionControlStep->setEnabled(false); actionControlFinish->setEnabled(false); actionControlNexti->setEnabled(false); actionControlStepi->setEnabled(false); actionControlRunToLine->setEnabled(false); // Action buttons actionInterruptProcess->setEnabled(true); actionGdbContinue->setEnabled(false); actionGdbNext->setEnabled(false); actionGdbStep->setEnabled(false); actionGdbFinish->setEnabled(false); actionGdbNexti->setEnabled(false); actionGdbStepi->setEnabled(false); } // Enable some button while target is interrupted void SeerMainWindow::handleGdbTargetInterrupt() { // Control Menu actionControlInterrupt->setEnabled(false); actionControlContinue->setEnabled(true); actionControlNext->setEnabled(true); actionControlStep->setEnabled(true); actionControlFinish->setEnabled(true); actionControlNexti->setEnabled(true); actionControlStepi->setEnabled(true); actionControlRunToLine->setEnabled(true); // Action buttons actionInterruptProcess->setEnabled(false); actionGdbContinue->setEnabled(true); actionGdbNext->setEnabled(true); actionGdbStep->setEnabled(true); actionGdbFinish->setEnabled(true); actionGdbNexti->setEnabled(true); actionGdbStepi->setEnabled(true); } seer-2.7/src/SeerMainWindow.h000066400000000000000000000217201516472651200161660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerMainWindow.h" #include "SeerRunStatusIndicator.h" #include "SeerKeySettings.h" #include "SeerProgressIndicator.h" #include #include #include #include #include #include #include class SeerMainWindow : public QMainWindow, protected Ui::SeerMainWindowForm { Q_OBJECT public: SeerMainWindow (QWidget* parent = 0); ~SeerMainWindow (); void setExecutableName (const QString& executableName); const QString& executableName () const; void setExecutableSymbolName (const QString& executableSymbolName); const QString& executableSymbolName () const; void setExecutableArguments (const QString& executableArguments); void setExecutableArguments (const QStringList& executableArguments); const QString& executableArguments () const; void setExecutableWorkingDirectory (const QString& executableWorkingDirectory); const QString& executableWorkingDirectory () const; void setExecutableBreakpointsFilename (const QString& breakpointsFilename); const QString& executableBreakpointsFilename () const; void setExecutableBreakpointFunctionName (const QString& nameoraddress); const QString& executableBreakpointFunctionName () const; void setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno); const QString& executableBreakpointSourceName () const; void setExecutableShowAssemblyTabMode (const QString& mode); QString executableShowAssemblyTabMode () const; void setExecutableRandomizeStartAddress (bool flag); bool executableRandomizeStartAddress () const; void setExecutableNonStopMode (bool flag); bool executableNonStopMode () const; void setExecutablePid (int pid); int executablePid () const; void setExecutableConnectHostPort (const QString& executableConnectHostPort); const QString& executableConnectHostPort () const; void setExecutableConnectRemoteTargetType (const QString& type); QString executableConnectRemoteTargetType () const; void setExecutableConnectGdbserverDebug (bool enable); bool executableConnectGdbserverDebug () const; void setExecutableRRTraceDirectory (const QString& executableRRTraceDirectory); const QString& executableRRTraceDirectory () const; void setExecutableCoreFilename (const QString& executableCoreFilename); const QString& executableCoreFilename () const; void setExecutablePreGdbCommands (const QStringList& preGdbCommands); const QStringList& executablePreGdbCommands () const; void setExecutablePostGdbCommands (const QStringList& postGdbCommands); const QStringList& executablePostGdbCommands () const; void setProjectFilename (const QString& projectFilename); const QString& projectFilename () const; void setGdbProgramOverride (const QString& gdbProgram); QString gdbProgramOverride () const; void setGdbArgumentsOverride (const QString& gdbProgram); QString gdbArgumentsOverride () const; void launchExecutable (const QString& launchMode, const QString& breakMode); const QString& executableLaunchMode () const; const QString& executableBreakMode () const; void setStyleName (const QString& name); const QString& styleName (); private slots: void handleFileDebugWithDefaultProject (); void handleFileDebugWithOutDefaultProject (); void handleFileDebug (bool loadDefaultProject); void handleFileArguments (); void handleFileQuit (); void handleViewMemoryVisualizer (); void handleViewArrayVisualizer (); void handleViewMatrixVisualizer (); void handleViewStructVisualizer (); void handleViewVarVisualizer (); void handleViewImageVisualizer (); void handleViewAssembly (); void handleViewAssemblyShown (bool shown); void handleViewConsoleAttached (); void handleViewConsoleDetached (); void handleViewConsoleDetachedMinimized (); void handleSettingsConfiguration (); void handleSettingsSaveConfiguration (); void handleHelpAbout (); void handleText (const QString& text); void handleRunStatusChanged (SeerRunStatusIndicator::RunStatus status); void handleRecordSettingsChanged (); void handleChangeWindowTitle (QString title); void handleHelpToolButtonClicked (); void handleTerminateExecutable (); void handleRestartExecutable (); void handleStyleMenuChanged (); void handleShowMessage (QString message, int time); void handleGdbStateChanged (); void handleGdbTargetRunning (); void handleGdbTargetInterrupt (); void handleStatusChanged (QString message); protected: void writeSettings (); void readSettings (); void writeConfigSettings (); void readConfigSettings (); void resizeEvent (QResizeEvent* event); void closeEvent (QCloseEvent* event); void setKeySettings (const SeerKeySettings& settings); const SeerKeySettings keySettings () const; void refreshShortCuts (); private: QActionGroup* _styleMenuActionGroup; QString _styleName; QAction* _interruptAction; SeerProgressIndicator* _progressIndicator; SeerKeySettings _keySettings; QString _projectFile; }; seer-2.7/src/SeerMainWindow.ui000066400000000000000000000716351516472651200163660ustar00rootroot00000000000000 SeerMainWindowForm 0 0 1206 726 Qt::NoContextMenu Seer Debugger 0 0 1206 23 File Edit View Console :/seer/resources/icons-icons/console.png:/seer/resources/icons-icons/console.png Styles :/seer/resources/icons-icons/style.png:/seer/resources/icons-icons/style.png Settings Help Control Set Record mode. Record :/seer/resources/RelaxLightIcons/tools-media-optical-burn-image.svg:/seer/resources/RelaxLightIcons/tools-media-optical-burn-image.svg Set Playback direction. Direction :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Reverse toolBar Qt::ToolButtonTextBesideIcon TopToolBarArea false :/seer/resources/icons-icons/exit.png:/seer/resources/icons-icons/exit.png Quit Quit Quit the Seer debugger. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Next :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Step :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Finish :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Continue :/seer/resources/thenounproject/fortune-teller.svg:/seer/resources/thenounproject/fortune-teller.svg Debug... Debug Load an executable to debug. :/seer/resources/icons-icons/arguments.png:/seer/resources/icons-icons/arguments.png Arguments... Arguments Specify new arguments to the current executable. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Interrupt Send a 'Terminate' signal to the process.<br/><br/>Hold down for alternate signals. :/seer/resources/icons/hicolor/32x32/seergdb.png:/seer/resources/icons/hicolor/32x32/seergdb.png About Seer About Seer :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Memory Visualizer Launch a blank Memory Visualizer. :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Array Visualizer Launch a blank Array Visualizer. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Restart Restart the debugging session Restart the debugging session. Honor breakpoints, if any. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Continue Continue Continue executing the program. Stop at any breakpoints, or when the program exits. :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Next Next Execute next step, step over functions. :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Step Step Execute next step, step into functions. :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Finish Finish Execute the remaining function, stop after it exits. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Interrupt Interrupt Send a 'Terminate' signal to the process. :/seer/resources/thenounproject/configure.svg:/seer/resources/thenounproject/configure.svg Configuration... Configure Seer. :/seer/resources/RelaxLightIcons/document-save.svg:/seer/resources/RelaxLightIcons/document-save.svg Save Configuration... Save the configurations so future Seer sessions will use them. :/seer/resources/icons-icons/attach.png:/seer/resources/icons-icons/attach.png Attached Show the console window in Seer's tabs. Show the console window in Seer's tabs. :/seer/resources/icons-icons/maximize.png:/seer/resources/icons-icons/maximize.png Detached Detach the console into it's own window. Detach the console into it's own window. :/seer/resources/icons-icons/minimize.png:/seer/resources/icons-icons/minimize.png Detached Minimized Detach the console into it's own minimaize window. Detach the console into it's own minimaize window. :/seer/resources/RelaxLightIcons/debug-step-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-instruction.svg Nexti Execute next instruction, step over functions. :/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg Stepi Execute next instruction, step into functions. :/seer/resources/thenounproject/assembly.svg:/seer/resources/thenounproject/assembly.svg Assembly View View the program's assembly. :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Struct Visualizer Launch a blank Struct Visualizer. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Stop Stop Record mode. true :/seer/resources/RelaxLightIcons/go-previous.svg:/seer/resources/RelaxLightIcons/go-previous.svg Reverse Set Gdb Playback to reverse. :/seer/resources/RelaxLightIcons/tools-media-optical-burn-image.svg:/seer/resources/RelaxLightIcons/tools-media-optical-burn-image.svg Record Toggle Record mode. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Start Start Record mode. true :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Forward Set Gdb Playback to forward. :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Direction Toggle Playback direction. :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Image Visualizer Launch a blank Image Visualizer. :/seer/resources/RelaxLightIcons/debug-step-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-instruction.svg Nexti Nexti :/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg Stepi Stepi :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Visualizers Launch a Memory visualizer.<br/><br/>Hold down for alternate visualizers. :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Basic Struct Visualizer Launch a blank Basic Struct Visualizer. Execution Messages View the program's execution messages. :/seer/resources/RelaxLightIcons/system-shutdown.svg:/seer/resources/RelaxLightIcons/system-shutdown.svg QAction::NoRole :/seer/resources/thenounproject/fortune-teller.svg:/seer/resources/thenounproject/fortune-teller.svg Debug Launch a debugging session. QAction::NoRole :/seer/resources/RelaxLightIcons/system-shutdown.svg:/seer/resources/RelaxLightIcons/system-shutdown.svg Terminate Terminate the debugging session Terminate the debugging session. QAction::NoRole :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Matrix Visualizer Launch a blank Matrix Visualizer. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Reverse Continue :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Reverse Next :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Reverse Step :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Reverse Finish :/seer/resources/RelaxLightIcons/debug-step-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-instruction.svg Reverse Nexti :/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg Reverse Stepi :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Run To Line Run to the currently selected line. Stop at any breakpoints, or when the program exits. QAction::NoRole SeerGdbWidget QWidget
SeerGdbWidget.h
1
seer-2.7/src/SeerMatrixVisualizerWidget.cpp000066400000000000000000000522751516472651200211440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMatrixVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include SeerMatrixVisualizerWidget::SeerMatrixVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create id's for queries. _memoryId = Seer::createID(); _rowsId = Seer::createID(); _columnsId = Seer::createID(); _offsetId = Seer::createID(); _strideId = Seer::createID(); // Set up UI. setupUi(this); // Setup the widgets setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer Matrix Visualizer"); setAttribute(Qt::WA_DeleteOnClose); matrixDisplayFormatComboBox->setCurrentIndex(0); handleMatrixDisplayFormatComboBox(0); variableNameLineEdit->enableReturnPressedOnClear(); // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerMatrixVisualizerWidget::handleHelpButton); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleVariableNameLineEdit); QObject::connect(matrixRowsLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(matrixRowsLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementRowsLineEdit); QObject::connect(matrixColumnsLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(matrixColumnsLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementColumnsLineEdit); QObject::connect(matrixOffsetLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(matrixOffsetLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementOffsetLineEdit); QObject::connect(matrixStrideLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(matrixStrideLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementStrideLineEdit); QObject::connect(matrixDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerMatrixVisualizerWidget::handleMatrixDisplayFormatComboBox); QObject::connect(matrixTableWidget, &SeerMatrixWidget::dataChanged, this, &SeerMatrixVisualizerWidget::handleDataChanged); // Restore window settings. readSettings(); } SeerMatrixVisualizerWidget::~SeerMatrixVisualizerWidget () { } void SeerMatrixVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer Matrix Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); if (variableNameLineEdit->text() == "") { variableAddressLineEdit->setText(""); matrixRowsLineEdit->setText(""); matrixColumnsLineEdit->setText(""); matrixOffsetLineEdit->setText(""); matrixStrideLineEdit->setText(""); matrixTableWidget->setData(0); return; } setVariableAddress(""); // Clear old contents. QByteArray array; bool ok; matrixTableWidget->setData(new SeerMatrixWidget::DataStorageArray(array)); if (matrixOffsetLineEdit->text() != "") { matrixTableWidget->setAddressOffset(matrixOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << matrixOffsetLineEdit->text(); } }else{ matrixTableWidget->setAddressOffset(0); } if (matrixStrideLineEdit->text() != "") { matrixTableWidget->setAddressStride(matrixStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << matrixStrideLineEdit->text(); } }else{ matrixTableWidget->setAddressStride(1); } // Send signal to get variable address. emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } QString SeerMatrixVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; if (address == "") { variableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } if (ok == false) { variableAddressLineEdit->setText("not an address"); offset = 0; } } matrixTableWidget->setAddressOffset(0); } QString SeerMatrixVisualizerWidget::variableAddress () const { return variableAddressLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableRows (const QString& rows) { matrixRowsLineEdit->setText(rows); } QString SeerMatrixVisualizerWidget::variableRows () const { return matrixRowsLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableColumns (const QString& columns) { matrixColumnsLineEdit->setText(columns); } QString SeerMatrixVisualizerWidget::variableColumns () const { return matrixColumnsLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableOffset (const QString& offset) { matrixOffsetLineEdit->setText(offset); } QString SeerMatrixVisualizerWidget::variableOffset () const { return matrixOffsetLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableStride (const QString& stride) { matrixStrideLineEdit->setText(stride); } QString SeerMatrixVisualizerWidget::variableStride () const { return matrixStrideLineEdit->text(); } void SeerMatrixVisualizerWidget::handleText (const QString& text) { //qDebug() << text; if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 11^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString address = ""; // Look for an address in the value. if (address == "") { QRegularExpression re("0[xX][0-9a-fA-F]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Look for a number in the value. if (address == "") { QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Set the variable address. setVariableAddress(address); } if (id_text.toInt() == _rowsId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setVariableRows(value_text); handleRefreshButton(); } if (id_text.toInt() == _columnsId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setVariableColumns(value_text); handleRefreshButton(); } if (id_text.toInt() == _offsetId) { // Set the memory offset. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setVariableOffset(value_text); handleRefreshButton(); } if (id_text.toInt() == _strideId) { // Set the memory stride. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setVariableStride(value_text); handleRefreshButton(); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { // 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}] // 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}] QString id_text = text.section('^', 0,0); if (id_text.toInt() == _memoryId) { QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetData(new SeerMatrixWidget::DataStorageArray(array)); if (matrixOffsetLineEdit->text() != "") { matrixTableWidget->setAddressOffset(matrixOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << matrixOffsetLineEdit->text(); } }else{ matrixTableWidget->setAddressOffset(0); } if (matrixStrideLineEdit->text() != "") { matrixTableWidget->setAddressStride(matrixStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << matrixStrideLineEdit->text(); } }else{ matrixTableWidget->setAddressStride(1); } // Set the dimension of the matrix table. if (matrixRowsLineEdit->text() != "" && matrixColumnsLineEdit->text() != "") { int rows = matrixRowsLineEdit->text().toInt(&ok); if (ok == false) { qWarning() << "Invalid string for number of rows." << matrixRowsLineEdit->text(); rows = 0; } int columns = matrixColumnsLineEdit->text().toInt(&ok); if (ok == false) { qWarning() << "Invalid string for number of columns." << matrixColumnsLineEdit->text(); columns = 0; } matrixTableWidget->setDimensions(rows,columns); }else{ matrixTableWidget->setDimensions(0,0); } break; // Take just the first range for now. } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." // 3^error,msg="Unable to read memory." QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { variableAddressLineEdit->setText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); } if (id_text.toInt() == _memoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } } if (id_text.toInt() == _rowsId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); matrixRowsLineEdit->setText(""); matrixRowsLineEdit->setFocus(); } if (id_text.toInt() == _columnsId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); matrixColumnsLineEdit->setText(""); matrixColumnsLineEdit->setFocus(); } if (id_text.toInt() == _offsetId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); matrixOffsetLineEdit->setText(""); matrixOffsetLineEdit->setFocus(); } if (id_text.toInt() == _strideId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); matrixStrideLineEdit->setText(""); matrixStrideLineEdit->setFocus(); } }else{ // Ignore anything else. } } void SeerMatrixVisualizerWidget::handleRefreshButton () { if (variableNameLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "not an address") { return; } int bytes = matrixRowsLineEdit->text().toInt() * matrixColumnsLineEdit->text().toInt() * Seer::typeBytes(matrixDisplayFormatComboBox->currentText()); // qDebug() << "Asking for" << bytes << "bytes of matrix data."; emit evaluateMemoryExpression(_memoryId, variableAddressLineEdit->text(), bytes); } void SeerMatrixVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/MatrixVisualizer.md"); help->show(); help->raise(); } void SeerMatrixVisualizerWidget::handleVariableNameLineEdit () { setVariableName (variableNameLineEdit->text()); } void SeerMatrixVisualizerWidget::handleElementRowsLineEdit () { // Nothing set? Return. if (variableRows() == "") { return; } // A regular integer? Return. QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(variableRows()); if (match.hasMatch()) { return; } // Send for the value of the variable. emit evaluateVariableExpression(_rowsId, variableRows()); } void SeerMatrixVisualizerWidget::handleElementColumnsLineEdit () { // Nothing set? Return. if (variableColumns() == "") { return; } // A regular integer? Return. QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(variableColumns()); if (match.hasMatch()) { return; } // Send for the value of the variable. emit evaluateVariableExpression(_columnsId, variableColumns()); } void SeerMatrixVisualizerWidget::handleElementOffsetLineEdit () { // Nothing set? Return. if (variableOffset() == "") { return; } // A regular integer? Return. QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(variableOffset()); if (match.hasMatch()) { return; } emit evaluateVariableExpression(_offsetId, variableOffset()); } void SeerMatrixVisualizerWidget::handleElementStrideLineEdit () { // Nothing set? Return. if (variableStride() == "") { return; } // A regular integer? Return. QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(variableRows()); if (match.hasMatch()) { return; } // Send for the value of the variable. emit evaluateVariableExpression(_strideId, variableStride()); } void SeerMatrixVisualizerWidget::handleMatrixDisplayFormatComboBox (int index) { //qDebug() << index; if (index == 0) { matrixTableWidget->setDataType(SeerMatrixWidget::Int16MatrixType); }else if (index == 1) { matrixTableWidget->setDataType(SeerMatrixWidget::Int32MatrixType); }else if (index == 2) { matrixTableWidget->setDataType(SeerMatrixWidget::Int64MatrixType); }else if (index == 3) { matrixTableWidget->setDataType(SeerMatrixWidget::UInt16MatrixType); }else if (index == 4) { matrixTableWidget->setDataType(SeerMatrixWidget::UInt32MatrixType); }else if (index == 5) { matrixTableWidget->setDataType(SeerMatrixWidget::UInt64MatrixType); }else if (index == 6) { matrixTableWidget->setDataType(SeerMatrixWidget::Float32MatrixType); }else if (index == 7) { matrixTableWidget->setDataType(SeerMatrixWidget::Float64MatrixType); }else{ // Do nothing. } handleRefreshButton(); } void SeerMatrixVisualizerWidget::handleDataChanged () { // Update the meta information. // Clear everything. countLineEdit->setText(""); rowsLineEdit->setText(""); columnsLineEdit->setText(""); minimumLineEdit->setText(""); maximumLineEdit->setText(""); sumLineEdit->setText(""); averageLineEdit->setText(""); medianLineEdit->setText(""); rmsLineEdit->setText(""); // If there's nothing to show, just return. if (matrixTableWidget->dataCount() <= 0) { return; } if (matrixTableWidget->dataValues().count() <= 0) { return; } // Make a copy of the values for us to play with. QVector values = matrixTableWidget->dataValues(); // Fill in counts. countLineEdit->setText(QString::number(matrixTableWidget->dataCount())); rowsLineEdit->setText(QString::number(matrixTableWidget->dataRows())); columnsLineEdit->setText(QString::number(matrixTableWidget->dataColumns())); // Calculate statistics. double val = 0.0; double min = 0.0; double max = 0.0; double sum = 0.0; double sum2 = 0.0; double avg = 0.0; double med = 0.0; double rms = 0.0; for (int i=0; isetText(QString::number(min)); maximumLineEdit->setText(QString::number(max)); sumLineEdit->setText(QString::number(sum)); averageLineEdit->setText(QString::number(avg)); rmsLineEdit->setText(QString::number(rms)); // For median, we need to sort the values. So do this last. std::sort(values.begin(), values.end()); // If the number of elements is odd, the median is the middle element if (values.size() % 2 != 0) { med = values[values.size() / 2]; }else{ double mid1 = values[values.size() / 2 - 1]; double mid2 = values[values.size() / 2]; med = (mid1 + mid2) / 2.0; } medianLineEdit->setText(QString::number(med)); return; } void SeerMatrixVisualizerWidget::writeSettings() { QSettings settings; settings.beginGroup("matrixvisualizerwindow"); { settings.setValue("size", size()); } settings.endGroup(); } void SeerMatrixVisualizerWidget::readSettings() { QSettings settings; settings.beginGroup("matrixvisualizerwindow"); { resize(settings.value("size", QSize(800, 400)).toSize()); } settings.endGroup(); } void SeerMatrixVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } seer-2.7/src/SeerMatrixVisualizerWidget.h000066400000000000000000000057121516472651200206030ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerMatrixVisualizerWidget.h" class SeerMatrixVisualizerWidget : public QWidget, protected Ui::SeerMatrixVisualizerWidgetForm { Q_OBJECT public: explicit SeerMatrixVisualizerWidget (QWidget* parent = 0); ~SeerMatrixVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; void setVariableAddress (const QString& address); QString variableAddress () const; void setVariableRows (const QString& rows); QString variableRows () const; void setVariableColumns (const QString& columns); QString variableColumns () const; void setVariableOffset (const QString& offset); QString variableOffset () const; void setVariableStride (const QString& stride); QString variableStride () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void evaluateMemoryExpression (int expressionid, QString address, int count); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleVariableNameLineEdit (); void handleElementRowsLineEdit (); void handleElementColumnsLineEdit (); void handleElementOffsetLineEdit (); void handleElementStrideLineEdit (); void handleMatrixDisplayFormatComboBox (int index); void handleDataChanged (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: int _variableId; int _memoryId; int _rowsId; int _columnsId; int _offsetId; int _strideId; }; seer-2.7/src/SeerMatrixVisualizerWidget.ui000066400000000000000000000336431516472651200207750ustar00rootroot00000000000000 SeerMatrixVisualizerWidgetForm 0 0 855 622 Form Variable name or expression. Variable name true Variable address. true Variable address false Total number of rows in the matrix. # rows true Total number of columns in the matrix. # columns true Element offset into matrix. (default=0) offset true Element stride between values. (default=1) stride true Matrix data type. int16 int32 int64 uint16 uint32 uint64 float32 float64 Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Help on Memory Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg 1 0 Count Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter # values in matrix true # values in matrix Rows Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter # rows in matrix true # rows in matrix Columns Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter # columns in matrix true # columns in matrix Minimum Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Minimum value in matrix true Minimum value in matrix Maximum Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Maximum value in matrix true Maximum value in matrix Qt::Horizontal 40 20 Sum Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Sum of all matrix values true Sum of all matrix values Average Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Average of all matrix values true Average of all matrix values Median Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Median of all matrix values true Median of all matrix values RMS Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter RMS of all matrix values true RMS of all matrix values Qt::Horizontal 40 20 SeerMatrixWidget QTableWidget
SeerMatrixWidget.h
SeerHistoryLineEdit QLineEdit
SeerHistoryLineEdit.h
variableNameLineEdit variableAddressLineEdit matrixRowsLineEdit matrixColumnsLineEdit matrixOffsetLineEdit matrixStrideLineEdit matrixDisplayFormatComboBox refreshToolButton helpToolButton matrixTableWidget countLineEdit rowsLineEdit columnsLineEdit minimumLineEdit maximumLineEdit sumLineEdit averageLineEdit medianLineEdit rmsLineEdit
seer-2.7/src/SeerMatrixWidget.cpp000066400000000000000000000212501516472651200170530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMatrixWidget.h" #include "SeerUtl.h" #include #include #include SeerMatrixWidget::SeerMatrixWidget(QWidget* parent) : QTableWidget(parent) { QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); setFont(font); setFocusPolicy(Qt::StrongFocus); setEditTriggers(QAbstractItemView::NoEditTriggers); horizontalHeader()->setDefaultAlignment(Qt::AlignRight); _data = 0; _dataRows = 0; _dataColumns = 0; _dataType = SeerMatrixWidget::UnknownMatrixType; _addressOffset = 0; _addressStride = 1; setAddressOffset(0); setAddressStride(1); } SeerMatrixWidget::~SeerMatrixWidget() { if (_data) { delete _data; } } void SeerMatrixWidget::setAddressOffset (unsigned long offset) { _addressOffset = offset; // Repaint the widget. create(); } unsigned long SeerMatrixWidget::addressOffset () const { return _addressOffset; } void SeerMatrixWidget::setAddressStride (unsigned long stride) { if (stride < 1) { qWarning() << "Stride is not valid." << stride; stride = 1; } _addressStride = stride; // Repaint the widget. create(); } unsigned long SeerMatrixWidget::addressStride () const { return _addressStride; } int SeerMatrixWidget::dataRows () const { return _dataRows; } int SeerMatrixWidget::dataColumns () const { return _dataColumns; } unsigned long SeerMatrixWidget::dataSize () const { if (_data) { return _data->size(); } return 0; } int SeerMatrixWidget::dataCount () const { if (_data == 0) { return 0; } if (elementSize() < 1) { return 0; } return _data->size() / elementSize(); } unsigned long SeerMatrixWidget::elementSize () const { if (dataType() == SeerMatrixWidget::Int16MatrixType) { return 2; }else if (dataType() == SeerMatrixWidget::UInt16MatrixType) { return 2; }else if (dataType() == SeerMatrixWidget::Int32MatrixType) { return 4; }else if (dataType() == SeerMatrixWidget::UInt32MatrixType) { return 4; }else if (dataType() == SeerMatrixWidget::Int64MatrixType) { return 8; }else if (dataType() == SeerMatrixWidget::UInt64MatrixType) { return 8; }else if (dataType() == SeerMatrixWidget::Float32MatrixType) { return 4; }else if (dataType() == SeerMatrixWidget::Float64MatrixType) { return 8; } return 0; } void SeerMatrixWidget::setDataType (SeerMatrixWidget::MatrixType dataType) { _dataType = dataType; // This repaints the widget with the new matrix mode create(); } SeerMatrixWidget::MatrixType SeerMatrixWidget::dataType () const { return _dataType; } QString SeerMatrixWidget::dataTypeString () const { if (dataType() == SeerMatrixWidget::Int16MatrixType) { return "int8"; }else if (dataType() == SeerMatrixWidget::UInt16MatrixType) { return "uint16"; }else if (dataType() == SeerMatrixWidget::Int32MatrixType) { return "int32"; }else if (dataType() == SeerMatrixWidget::UInt32MatrixType) { return "uint32"; }else if (dataType() == SeerMatrixWidget::Int64MatrixType) { return "int64"; }else if (dataType() == SeerMatrixWidget::UInt64MatrixType) { return "uint64"; }else if (dataType() == SeerMatrixWidget::Float32MatrixType) { return "float32"; }else if (dataType() == SeerMatrixWidget::Float64MatrixType) { return "float64"; } return "???"; } const QVector& SeerMatrixWidget::dataValues () const { return _dataValues; } void SeerMatrixWidget::setData(SeerMatrixWidget::DataStorage* pData) { if (_data) { delete _data; } /* if (pData == 0) { qDebug() << "Setting new data with no size. Dimensions are reset. Assign new data and set them again!"; }else{ qDebug() << "Setting new data with size of" << pData->size() << ". Dimensions are reset. Set them again!"; } */ _data = pData; _dataRows = 0; _dataColumns = 0; // Repaint the widget. create(); } void SeerMatrixWidget::setDimensions (int rows, int colums) { // qDebug() << "Setting dimensions to" << rows << "x" << colums; _dataRows = rows; _dataColumns = colums; // Repaint the widget. create(); } void SeerMatrixWidget::create () { // Clear the table. We're going to recreate it. clear(); setRowCount(0); setColumnCount(0); if (_data) { // qDebug() << "Row:" << dataRows() << "Cols:" << dataColumns(); setRowCount(dataRows()); setColumnCount(dataColumns()); } // If the number of rows/columns have not been assigned, return. if (dataRows() < 1 || dataColumns() < 1) { // qDebug() << "Zero rows or cols. Row:" << dataRows() << "Cols:" << dataColumns(); emit dataChanged(); return; } // Clear the values. _dataValues.resize(0); // If there's no data, do nothing. if (!_data) { // qDebug() << "No _data"; emit dataChanged(); return; } if (elementSize() < 1) { // qDebug() << "Bad element size." << elementSize(); emit dataChanged(); return; } if (_data) { int row = 0; int col = 0; // setHorizontalHeaderItem(_aColumnId, new QTableWidgetItem(QString("%1:%2:%3").arg(aLabel()).arg(aAddressOffset()).arg(aAddressStride()))); for (int i=elementSize()*addressOffset(); i<_data->size(); i+=elementSize()*addressStride()) { // qDebug() << "Displaying element" << i; // Set column header if we need to. Set its label. if (row == 0) { for (int c=0; c < dataColumns(); c++) { QTableWidgetItem* colHeaderitem = new QTableWidgetItem(QString::number(c)); colHeaderitem->setTextAlignment(Qt::AlignRight|Qt::AlignHCenter); setHorizontalHeaderItem(c, colHeaderitem); } } // Set row header if we need to. Set its label. if (col == 0) { QTableWidgetItem* rowHeaderitem = new QTableWidgetItem(QString::number(row)); rowHeaderitem->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); setVerticalHeaderItem(row, rowHeaderitem); } // Set cell item. QTableWidgetItem* item = new QTableWidgetItem; item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); QByteArray element = _data->getData(i, elementSize()); double val = 0.0; if (dataType() == SeerMatrixWidget::Int16MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::UInt16MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::Int32MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::UInt32MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::Int64MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::UInt64MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::Float32MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::Float64MatrixType) { val = *reinterpret_cast(element.data()); }else{ qWarning() << "Unknown data type."; val = 0.0; } item->setText(QString::number(val)); item->setToolTip(QString("(%1,%2) = %3").arg(row).arg(col).arg(item->text())); setItem(row, col, item); _dataValues.push_back(val); col++; if (col == dataColumns()) { col = 0; row++; } } } emit dataChanged(); } SeerMatrixWidget::DataStorageArray::DataStorageArray(const QByteArray& arr) { _data = arr; } QByteArray SeerMatrixWidget::DataStorageArray::getData(int position, int length) { return _data.mid(position, length); } int SeerMatrixWidget::DataStorageArray::size() { return _data.size(); } seer-2.7/src/SeerMatrixWidget.h000066400000000000000000000057331516472651200165300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerMatrixWidget: public QTableWidget { Q_OBJECT public: class DataStorage { public: virtual ~DataStorage() {}; virtual QByteArray getData(int position, int length) = 0; virtual int size() = 0; }; class DataStorageArray: public DataStorage { public: DataStorageArray(const QByteArray& arr); virtual QByteArray getData(int position, int length); virtual int size(); private: QByteArray _data; }; enum MatrixType { UnknownMatrixType = 0, Int16MatrixType = 1, UInt16MatrixType = 2, Int32MatrixType = 3, UInt32MatrixType = 4, Int64MatrixType = 5, UInt64MatrixType = 6, Float32MatrixType = 7, Float64MatrixType = 8 }; SeerMatrixWidget(QWidget* parent = 0); ~SeerMatrixWidget(); void setAddressOffset (unsigned long offset); unsigned long addressOffset () const; void setAddressStride (unsigned long stride); unsigned long addressStride () const; unsigned long elementSize () const; void setDataType (SeerMatrixWidget::MatrixType dataType); SeerMatrixWidget::MatrixType dataType () const; QString dataTypeString () const; const QVector& dataValues () const; int dataRows () const; int dataColumns () const; unsigned long dataSize () const; int dataCount () const; signals: void dataChanged (); public slots: void setData (DataStorage* pData); void setDimensions (int rows, int colums); protected: private: void create (); unsigned long _addressOffset; unsigned long _addressStride; DataStorage* _data; int _dataRows; int _dataColumns; SeerMatrixWidget::MatrixType _dataType; QVector _dataValues; }; seer-2.7/src/SeerMemoryVisualizerWidget.cpp000066400000000000000000000416111516472651200211400ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMemoryVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include SeerMemoryVisualizerWidget::SeerMemoryVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create id's for queries. _memoryId = Seer::createID(); _memoryLengthId = Seer::createID(); _asmId = Seer::createID(); // Set up UI. setupUi(this); // Setup the widgets setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer Memory Visualizer"); setAttribute(Qt::WA_DeleteOnClose); columnCountSpinBox->setValue(memoryHexEditor->bytesPerLine()); if (memoryHexEditor->memoryMode() == SeerHexWidget::HexMemoryMode) { memoryDisplayFormatComboBox->setCurrentIndex(0); }else if (memoryHexEditor->memoryMode() == SeerHexWidget::OctalMemoryMode) { memoryDisplayFormatComboBox->setCurrentIndex(1); }else if (memoryHexEditor->memoryMode() == SeerHexWidget::BinaryMemoryMode) { memoryDisplayFormatComboBox->setCurrentIndex(2); }else if (memoryHexEditor->memoryMode() == SeerHexWidget::DecimalMemoryMode) { memoryDisplayFormatComboBox->setCurrentIndex(3); }else{ memoryDisplayFormatComboBox->setCurrentIndex(0); } if (memoryHexEditor->charMode() == SeerHexWidget::AsciiCharMode) { charDisplayFormatComboBox->setCurrentIndex(0); }else if (memoryHexEditor->charMode() == SeerHexWidget::Utf8Mode) { charDisplayFormatComboBox->setCurrentIndex(1); }else if (memoryHexEditor->charMode() == SeerHexWidget::Utf16Mode) { charDisplayFormatComboBox->setCurrentIndex(2); }else if (memoryHexEditor->charMode() == SeerHexWidget::Utf32Mode) { charDisplayFormatComboBox->setCurrentIndex(3); }else if (memoryHexEditor->charMode() == SeerHexWidget::EbcdicCharMode) { charDisplayFormatComboBox->setCurrentIndex(4); }else{ charDisplayFormatComboBox->setCurrentIndex(0); } // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handleHelpButton); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMemoryVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMemoryVisualizerWidget::handleVariableNameLineEdit); QObject::connect(memoryLengthLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMemoryVisualizerWidget::handleRefreshButton); QObject::connect(memoryLengthLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMemoryVisualizerWidget::handleMemoryLengthLineEdit); QObject::connect(memoryDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerMemoryVisualizerWidget::handleMemoryDisplayFormatComboBox); QObject::connect(charDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerMemoryVisualizerWidget::handleCharDisplayFormatComboBox); QObject::connect(columnCountSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &SeerMemoryVisualizerWidget::handleColumnCountSpinBox); QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handlePrintButton); QObject::connect(saveToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handleSaveButton); // Restore window settings. readSettings(); } SeerMemoryVisualizerWidget::~SeerMemoryVisualizerWidget () { } void SeerMemoryVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer Memory Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); setVariableAddress(""); // Clear old contents. QByteArray array; memoryHexEditor->setData(new SeerHexWidget::DataStorageArray(array)); memoryAsmEditor->setData(""); // Do nothing if there's no variable name. if (variableNameLineEdit->text() == "") { return; } // Send signal to get variable address. emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } QString SeerMemoryVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerMemoryVisualizerWidget::setVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; bool refresh = false; if (address == "") { variableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); refresh = true; } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); refresh = true; } } if (ok == false) { variableAddressLineEdit->setText("not an address"); offset = 0; } } memoryHexEditor->setAddressOffset(offset); // Show results immediately. if (refresh) { handleRefreshButton(); } } QString SeerMemoryVisualizerWidget::variableAddress () const { return variableAddressLineEdit->text(); } void SeerMemoryVisualizerWidget::setMemoryLength (const QString& length) { memoryLengthLineEdit->setText(length); } QString SeerMemoryVisualizerWidget::memoryLength () const { return memoryLengthLineEdit->text(); } void SeerMemoryVisualizerWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 11^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString address = ""; // Look for an address in the value. if (address == "") { QRegularExpression re("0[xX][0-9a-fA-F]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Look for a number in the value. if (address == "") { QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Set the variable address. setVariableAddress(address); }else if (id_text.toInt() == _memoryLengthId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setMemoryLength(value_text); handleRefreshButton(); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { // 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}] // 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}] QString id_text = text.section('^', 0,0); if (id_text.toInt() == _memoryId) { QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetData(new SeerHexWidget::DataStorageArray(array)); break; // Take just the first range for now. } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,asm_insns="))) { QString id_text = text.section('^', 0,0); if (id_text.toInt() == _asmId) { memoryAsmEditor->setData(text); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." // 3^error,msg="Unable to read memory." QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { variableAddressLineEdit->setText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); variableAddressLineEdit->setFocus(); } if (id_text.toInt() == _memoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); /* XXX if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } */ } if (id_text.toInt() == _memoryLengthId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); memoryLengthLineEdit->setText(""); memoryLengthLineEdit->setFocus(); } // At a stopping point, refresh. }else if (text.startsWith("*stopped,reason=\"")) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } QApplication::restoreOverrideCursor(); } void SeerMemoryVisualizerWidget::handleRefreshButton () { if (variableNameLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "not an address") { return; } int nbytes = 256; if (memoryLengthLineEdit->text() != "") { nbytes = memoryLengthLineEdit->text().toInt(); } if (nbytes < 1) { return; } emit evaluateMemoryExpression(_memoryId, variableAddressLineEdit->text(), nbytes); emit evaluateAsmExpression(_asmId, variableAddressLineEdit->text(), nbytes, 2); } void SeerMemoryVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/MemoryVisualizer.md"); help->show(); help->raise(); } void SeerMemoryVisualizerWidget::handleVariableNameLineEdit () { setVariableName (variableNameLineEdit->text()); } void SeerMemoryVisualizerWidget::handleMemoryLengthLineEdit () { if (memoryLengthLineEdit->text() == "") { return; } emit evaluateVariableExpression(_memoryLengthId, memoryLengthLineEdit->text()); } void SeerMemoryVisualizerWidget::handleMemoryDisplayFormatComboBox (int index) { if (index == 0) { memoryHexEditor->setMemoryMode(SeerHexWidget::HexMemoryMode); }else if (index == 1) { memoryHexEditor->setMemoryMode(SeerHexWidget::OctalMemoryMode); }else if (index == 2) { memoryHexEditor->setMemoryMode(SeerHexWidget::BinaryMemoryMode); }else if (index == 3) { memoryHexEditor->setMemoryMode(SeerHexWidget::DecimalMemoryMode); }else{ // Do nothing. } } void SeerMemoryVisualizerWidget::handleCharDisplayFormatComboBox (int index) { if (index == 0) { memoryHexEditor->setCharMode(SeerHexWidget::AsciiCharMode); }else if (index == 1) { memoryHexEditor->setCharMode(SeerHexWidget::Utf8Mode); }else if (index == 2) { memoryHexEditor->setCharMode(SeerHexWidget::Utf16Mode); }else if (index == 3) { memoryHexEditor->setCharMode(SeerHexWidget::Utf32Mode); }else if (index == 4) { memoryHexEditor->setCharMode(SeerHexWidget::EbcdicCharMode); }else{ // Do nothing. } } void SeerMemoryVisualizerWidget::handleColumnCountSpinBox (int value) { memoryHexEditor->setBytesPerLine(value); } void SeerMemoryVisualizerWidget::handlePrintButton () { QPrinter printer; QPrintDialog dialog(&printer, this); if (dialog.exec() != QDialog::Accepted) { return; } // Make a copy so we can temporarily add a header. QTextDocument* clone = 0; if (tabWidget->currentWidget()->objectName() == "hex_tab") { clone = memoryHexEditor->document()->clone(this); }else if (tabWidget->currentWidget()->objectName() == "asm_tab") { clone = memoryAsmEditor->document()->clone(this); }else{ clone = new QTextDocument("NO TAB SELECTED!!!\n"); } QTextCursor cursor(clone); QTextCharFormat format = cursor.charFormat(); format.setBackground(QBrush(Qt::transparent)); cursor.insertText("\n", format); cursor.insertText("name=" + variableName() + " address=" + variableAddress() + " bytesPerLine=" + QString::number(memoryHexEditor->bytesPerLine()) + " bytes=" + QString::number(memoryHexEditor->size()) + " memory=" + memoryHexEditor->memoryModeString() + " char=" + memoryHexEditor->charModeString() + "\n", format); cursor.insertText("\n", format); clone->print(&printer); delete clone; } void SeerMemoryVisualizerWidget::handleSaveButton () { QFileDialog dialog(this, "Seer Visualizer File", "./", "Logs (*.log);;Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("log"); dialog.selectFile("memory.log"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); stream << "\n"; stream << "name=" << variableName() << " address=" << variableAddress() << " bytesPerLine=" << memoryHexEditor->bytesPerLine() << " bytes=" << memoryHexEditor->size() << " memory=" << memoryHexEditor->memoryModeString() << " char=" << memoryHexEditor->charModeString() << "\n"; stream << "\n"; if (tabWidget->currentWidget()->objectName() == "hex_tab") { stream << memoryHexEditor->toPlainText(); }else if (tabWidget->currentWidget()->objectName() == "asm_tab") { stream << memoryAsmEditor->toPlainText(); }else{ stream << "NO TAB SELECTED!!!\n"; } stream << "\n"; file.flush(); file.close(); }else{ QMessageBox::critical(this, tr("Error"), tr("Cannot save display to file.")); return; } } void SeerMemoryVisualizerWidget::writeSettings() { QSettings settings; settings.beginGroup("memoryvisualizerwindow"); settings.setValue("size", size()); settings.endGroup(); } void SeerMemoryVisualizerWidget::readSettings() { QSettings settings; settings.beginGroup("memoryvisualizerwindow"); resize(settings.value("size", QSize(800, 400)).toSize()); settings.endGroup(); } void SeerMemoryVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } seer-2.7/src/SeerMemoryVisualizerWidget.h000066400000000000000000000046321516472651200206070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerMemoryVisualizerWidget.h" class SeerMemoryVisualizerWidget : public QWidget, protected Ui::SeerMemoryVisualizerWidgetForm { Q_OBJECT public: explicit SeerMemoryVisualizerWidget (QWidget* parent = 0); ~SeerMemoryVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; void setVariableAddress (const QString& address); QString variableAddress () const; void setMemoryLength (const QString& length); QString memoryLength () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void evaluateMemoryExpression (int expressionid, QString address, int count); void evaluateAsmExpression (int expressionid, QString address, int count, int mode); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleVariableNameLineEdit (); void handleMemoryLengthLineEdit (); void handleMemoryDisplayFormatComboBox (int index); void handleCharDisplayFormatComboBox (int index); void handleColumnCountSpinBox (int value); void handlePrintButton (); void handleSaveButton (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: int _variableId; int _memoryId; int _memoryLengthId; int _asmId; }; seer-2.7/src/SeerMemoryVisualizerWidget.ui000066400000000000000000000202001516472651200207620ustar00rootroot00000000000000 SeerMemoryVisualizerWidgetForm 0 0 899 683 Form Variable expression resulting in an address. Starting address true Memory address. true Memory address Number of bytes to display. # Bytes (default 256) true Memory display format. hex octal binary decimal Character display format. ascii utf8 utf16 utf32 ebcdic Number of columns in display. 1 10 Print the display. ... :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Save the display to a file. ... :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Qt::Vertical Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Qt::Vertical Help on Memory Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg 0 Memory 0 100 Disassembly 0 100 SeerHexWidget QWidget
SeerHexWidget.h
1
SeerAsmWidget QWidget
SeerAsmWidget.h
1
SeerHistoryLineEdit QLineEdit
SeerHistoryLineEdit.h
seer-2.7/src/SeerMessagesBrowserWidget.cpp000066400000000000000000000140261516472651200207250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMessagesBrowserWidget.h" #include #include #include #include #include SeerMessagesBrowserWidget::SeerMessagesBrowserWidget (QWidget* parent) : QWidget(parent) { _raiseMode = "any"; // Default. Raise message tab on any message. _raiseMenu = 0; // Construct the UI. setupUi(this); // Setup the widgets QString style = "QTreeWidget::item:!selected " // Items in tree widget will have a border. "{ " "border: 1px solid gainsboro; " "border-left: none; " "border-top: none; " "}" "QTreeWidget::item:selected {}"; messagesTreeWidget->setRootIsDecorated(false); messagesTreeWidget->setStyleSheet(style); messagesTreeWidget->setSortingEnabled(false); messagesTreeWidget->resizeColumnToContents(0); // timestamp messagesTreeWidget->resizeColumnToContents(1); // message type icon messagesTreeWidget->resizeColumnToContents(2); // message _raiseMenu = new QMenu("Raise Messages Tab"); QMenu* menu = new QMenu(); menu->addMenu(_raiseMenu); _anyMessageAction = _raiseMenu->addAction("Any message"); _importanMessagesAction = _raiseMenu->addAction("Important messages"); _neverMessagesAction = _raiseMenu->addAction("Never"); preferencesToolButton->setMenu(menu); preferencesToolButton->setPopupMode(QToolButton::InstantPopup); // Get icons. _informationIcon = QIcon(":/seer/resources/RelaxLightIcons/data-information.svg"); _warningIcon = QIcon(":/seer/resources/RelaxLightIcons/data-warning.svg"); _criticalIcon = QIcon(":/seer/resources/RelaxLightIcons/data-error.svg"); _questionIcon = QIcon(":/seer/resources/RelaxLightIcons/dialog-question.svg"); // Connect things. QObject::connect(deleteMessagesToolButton, &QToolButton::clicked, this, &SeerMessagesBrowserWidget::handleDeleteToolButton); QObject::connect(_raiseMenu, &QMenu::aboutToShow, this, &SeerMessagesBrowserWidget::handleRaiseMenuShow); QObject::connect(_raiseMenu, &QMenu::triggered, this, &SeerMessagesBrowserWidget::handleRaiseMenuTriggered); // Clear messages clearMessages(); // Read the default settings. readSettings(); } SeerMessagesBrowserWidget::~SeerMessagesBrowserWidget () { } void SeerMessagesBrowserWidget::addMessage (const QString& message, QMessageBox::Icon messageType) { // Create an entry with our message. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, QTime::currentTime().toString(Qt::TextDate)); switch (messageType) { case QMessageBox::NoIcon: item->setIcon(1, _noIcon); break; case QMessageBox::Information: item->setIcon(1, _informationIcon); break; case QMessageBox::Warning: item->setIcon(1, _warningIcon); break; case QMessageBox::Critical: item->setIcon(1, _criticalIcon); break; case QMessageBox::Question: item->setIcon(1, _questionIcon); break; default: item->setIcon(1, _noIcon); break; } item->setText(2, message); // Insert the entry (at the end). messagesTreeWidget->addTopLevelItem(item); // Re-adjust column sizes. messagesTreeWidget->resizeColumnToContents(0); messagesTreeWidget->resizeColumnToContents(1); messagesTreeWidget->resizeColumnToContents(2); // Scroll to the bottom. QTreeWidgetItem* lastItem = messagesTreeWidget->topLevelItem(messagesTreeWidget->topLevelItemCount()-1); if (lastItem) { messagesTreeWidget->scrollToItem(lastItem); messagesTreeWidget->clearSelection(); lastItem->setSelected(true); } // Signal that a message was added, depending on the 'raise' mode. if (_raiseMode == "any") { emit showMessages(); }else if (_raiseMode == "important") { if (messageType == QMessageBox::Warning || messageType == QMessageBox::Critical || messageType == QMessageBox::Question) { emit showMessages(); }else if (message.startsWith("Program started")) { emit showMessages(); }else if (message.startsWith("Program exited")) { emit showMessages(); } }else if (_raiseMode == "never") { // Do nothing. } } void SeerMessagesBrowserWidget::clearMessages () { messagesTreeWidget->clear(); } void SeerMessagesBrowserWidget::writeSettings () { QSettings settings; settings.beginGroup("executionmessages"); { settings.setValue("raisetabmode", _raiseMode); }settings.endGroup(); } void SeerMessagesBrowserWidget::readSettings () { QSettings settings; settings.beginGroup("executionmessages"); { _raiseMode = settings.value("raisetabmode", "any").toString(); } settings.endGroup(); } void SeerMessagesBrowserWidget::handleDeleteToolButton () { // Delete all messages. clearMessages(); } void SeerMessagesBrowserWidget::handleRaiseMenuShow () { if (_raiseMode == "any") { _raiseMenu->setDefaultAction(_anyMessageAction); }else if (_raiseMode == "important") { _raiseMenu->setDefaultAction(_importanMessagesAction); }else if (_raiseMode == "never") { _raiseMenu->setDefaultAction(_neverMessagesAction); }else{ _raiseMenu->setDefaultAction(_anyMessageAction); } } void SeerMessagesBrowserWidget::handleRaiseMenuTriggered (QAction* action) { if (action == _anyMessageAction) { _raiseMode = "any"; }else if (action == _importanMessagesAction) { _raiseMode = "important"; }else if (action == _neverMessagesAction) { _raiseMode = "never"; }else{ _raiseMode = "any"; } writeSettings(); } seer-2.7/src/SeerMessagesBrowserWidget.h000066400000000000000000000031371516472651200203730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include #include "ui_SeerMessagesBrowserWidget.h" class SeerMessagesBrowserWidget : public QWidget, protected Ui::SeerMessagesBrowserWidgetForm { Q_OBJECT public: explicit SeerMessagesBrowserWidget (QWidget* parent = 0); ~SeerMessagesBrowserWidget (); public slots: void addMessage (const QString& message, QMessageBox::Icon messageType); void clearMessages (); private slots: void handleDeleteToolButton (); void handleRaiseMenuShow (); void handleRaiseMenuTriggered (QAction* action); signals: void showMessages (); protected: void writeSettings (); void readSettings (); private: QString _raiseMode; QMenu* _raiseMenu; QAction* _anyMessageAction; QAction* _importanMessagesAction; QAction* _neverMessagesAction; QIcon _noIcon; QIcon _informationIcon; QIcon _warningIcon; QIcon _criticalIcon; QIcon _questionIcon; }; seer-2.7/src/SeerMessagesBrowserWidget.ui000066400000000000000000000054171516472651200205640ustar00rootroot00000000000000 SeerMessagesBrowserWidgetForm 0 0 1162 625 Form QAbstractItemView::NoEditTriggers Timestamp Type AlignLeading|AlignVCenter Message Delete all messages. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg Qt::Vertical 20 40 seer-2.7/src/SeerMessagesDialog.cpp000066400000000000000000000117031516472651200173340ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMessagesDialog.h" #include #include #include #include #include #include SeerMessagesDialog::SeerMessagesDialog (QWidget* parent) : QDialog(parent) { _closePushButton = 0; _clearPushButton = 0; // Construct the UI. setupUi(this); setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer Execution Messages"); // Setup the widgets. QString style = "QTreeWidget::item:!selected " // Items in tree widget will have a border. "{ " "border: 1px solid gainsboro; " "border-left: none; " "border-top: none; " "}" "QTreeWidget::item:selected {}"; messageTreeWidget->setRootIsDecorated(false); messageTreeWidget->setStyleSheet(style); messageTreeWidget->setSortingEnabled(false); messageTreeWidget->resizeColumnToContents(0); // timestamp messageTreeWidget->resizeColumnToContents(1); // message type icon messageTreeWidget->resizeColumnToContents(2); // message // Add a "CLEAR" button to the dialog's buttonbox. // Make sure the CLOSE has the default action still. QDialogButtonBox* buttonBox = findChild("buttonBox"); if (buttonBox) { _clearPushButton = buttonBox->addButton("Clear", QDialogButtonBox::ActionRole); QObject::connect(_clearPushButton, &QPushButton::clicked, this, &SeerMessagesDialog::clearMessages); _closePushButton = buttonBox->button(QDialogButtonBox::Close); } resetDefaultButton(); // Get icons. _informationIcon = QIcon(":/seer/resources/RelaxLightIcons/data-information.svg"); _warningIcon = QIcon(":/seer/resources/RelaxLightIcons/data-warning.svg"); _criticalIcon = QIcon(":/seer/resources/RelaxLightIcons/data-error.svg"); _questionIcon = QIcon(":/seer/resources/RelaxLightIcons/dialog-question.svg"); // Connect things. // Clear messages clearMessages(); // Restore window settings. readSettings(); // Hide right away. hide(); } SeerMessagesDialog::~SeerMessagesDialog () { } void SeerMessagesDialog::addMessage (const QString& message, QMessageBox::Icon messageType) { // Give this dialog the focus. //setFocus(Qt::OtherFocusReason); // Show messages any time a messaged is added. showMessages(); // Create an entry with our message. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, QTime::currentTime().toString(Qt::TextDate)); switch (messageType) { case QMessageBox::NoIcon: item->setIcon(1, _noIcon); break; case QMessageBox::Information: item->setIcon(1, _informationIcon); break; case QMessageBox::Warning: item->setIcon(1, _warningIcon); break; case QMessageBox::Critical: item->setIcon(1, _criticalIcon); break; case QMessageBox::Question: item->setIcon(1, _questionIcon); break; default: item->setIcon(1, _noIcon); break; } item->setText(2, message); // Insert the entry (at the end). messageTreeWidget->addTopLevelItem(item); // Re-adjust column sizes. messageTreeWidget->resizeColumnToContents(0); messageTreeWidget->resizeColumnToContents(1); messageTreeWidget->resizeColumnToContents(2); // Scroll to the bottom. QTreeWidgetItem* lastItem = messageTreeWidget->topLevelItem(messageTreeWidget->topLevelItemCount()-1); if (lastItem) { messageTreeWidget->scrollToItem(lastItem); messageTreeWidget->clearSelection(); lastItem->setSelected(true); } resetDefaultButton(); } void SeerMessagesDialog::clearMessages () { messageTreeWidget->clear(); resetDefaultButton(); } void SeerMessagesDialog::showMessages () { // Show the dialog. show(); resetDefaultButton(); } void SeerMessagesDialog::writeSettings () { QSettings settings; settings.beginGroup("executionmessagesdialog"); { settings.setValue("size", size()); }settings.endGroup(); } void SeerMessagesDialog::readSettings () { QSettings settings; settings.beginGroup("executionmessagesdialog"); { resize(settings.value("size", QSize(425, 150)).toSize()); } settings.endGroup(); } void SeerMessagesDialog::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QDialog::resizeEvent(event); } void SeerMessagesDialog::resetDefaultButton () { if (_clearPushButton) { _clearPushButton->setDefault(false); } if (_closePushButton) { _closePushButton->setDefault(true); } } seer-2.7/src/SeerMessagesDialog.h000066400000000000000000000026071516472651200170040ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include "ui_SeerMessagesDialog.h" class SeerMessagesDialog : public QDialog, protected Ui::SeerMessagesDialog { Q_OBJECT public: explicit SeerMessagesDialog (QWidget* parent = 0); ~SeerMessagesDialog (); signals: public slots: void addMessage (const QString& message, QMessageBox::Icon messageType); void clearMessages (); void showMessages (); protected slots: protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); void resetDefaultButton (); private: QIcon _noIcon; QIcon _informationIcon; QIcon _warningIcon; QIcon _criticalIcon; QIcon _questionIcon; QPushButton* _closePushButton; QPushButton* _clearPushButton; }; seer-2.7/src/SeerMessagesDialog.ui000066400000000000000000000040631516472651200171700ustar00rootroot00000000000000 SeerMessagesDialog 0 0 425 150 Seer Execution Messages QAbstractItemView::NoEditTriggers Timestamp Type AlignLeading|AlignVCenter Message Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() SeerMessagesDialog accept() 248 254 157 274 buttonBox rejected() SeerMessagesDialog reject() 316 260 286 274 seer-2.7/src/SeerOdinSourceHighlighter.cpp000066400000000000000000000113761516472651200207040ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerOdinSourceHighlighter.h" SeerOdinSourceHighlighter::SeerOdinSourceHighlighter (QTextDocument* parent) : SeerSourceHighlighter(parent) { // Set to default formats. setHighlighterSettings(SeerHighlighterSettings::populate("")); } void SeerOdinSourceHighlighter::setHighlighterSettings (const SeerHighlighterSettings& settings) { _highlighterSettings = settings; _classFormat = _highlighterSettings.get("Class"); _quotationFormat = _highlighterSettings.get("Quotation"); _functionFormat = _highlighterSettings.get("Function"); _singleLineCommentFormat = _highlighterSettings.get("Comment"); _multiLineCommentFormat = _highlighterSettings.get("Multiline Comment"); _keywordFormat = _highlighterSettings.get("Keyword"); const QString keywordPatterns[] = { QStringLiteral("\\bpackage\\b"), QStringLiteral("\\bimport\\b"), QStringLiteral("\\bforeign\\b"), QStringLiteral("\\bproc\\b"), QStringLiteral("\\breturn\\b"), QStringLiteral("\\bif\\b"), QStringLiteral("\\belse\\b"), QStringLiteral("\\bswitch\\b"), QStringLiteral("\\bcase\\b"), QStringLiteral("\\bbreak\\b"), QStringLiteral("\\bcontinue\\b"), QStringLiteral("\\bfallthrough\\b"), QStringLiteral("\\bfor\\b"), QStringLiteral("\\bdo\\b"), QStringLiteral("\\bin\\b"), QStringLiteral("\\bnot_in\\b"), QStringLiteral("\\bdefer\\b"), QStringLiteral("\\bdynamic\\b"), QStringLiteral("\\bconst\\b"), QStringLiteral("\\bwhere\\b"), QStringLiteral("\\busing\\b"), QStringLiteral("\\bor_else\\b"), QStringLiteral("\\bor_break\\b"), QStringLiteral("\\bor_continue\\b"), QStringLiteral("\\bor_return\\b"), QStringLiteral("\\basm\\b"), QStringLiteral("\\bdistinct\\b"), QStringLiteral("\\bcontext\\b"), QStringLiteral("\\bnil\\b"), QStringLiteral("\\btrue\\b"), QStringLiteral("\\bfalse\\b"), QStringLiteral("\\bstruct\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bunion\\b"), QStringLiteral("\\bmap\\b"), QStringLiteral("\\bbit_set\\b"), QStringLiteral("\\bbit_field\\b"), QStringLiteral("\\bcast\\b"), QStringLiteral("\\btransmute\\b"), QStringLiteral("\\bauto_cast\\b"), QStringLiteral("\\bwhen\\b"), // builtin types QStringLiteral("\\b(i8|i16|i32|i64|i128|int)\\b"), QStringLiteral("\\b(u8|u16|u32|u64|u128|uint|uintptr)\\b"), QStringLiteral("\\b(f16|f32|f64|f128)\\b"), QStringLiteral("\\bf16le|f32le|f64le|f128le\\b"), QStringLiteral("\\b(f16be|f32be|f64be|f128be)\\b"), QStringLiteral("\\b(complex32|complex64|complex128)\\b"), QStringLiteral("\\b(quaternion64|quaternion128|quaternion256)\\b"), QStringLiteral("\\b(bool|b8|b16|b32|b64)\\b"), QStringLiteral("\\b(string|cstring|rune)\\b"), QStringLiteral("\\b(rawptr)\\b"), QStringLiteral("\\b(any|typeid)\\b"), QStringLiteral("\\b(byte)\\b"), QStringLiteral("\\b(u16le|u32le|u64le|u128le|i16le|i32le|i64le|i128le)\\b"), QStringLiteral("\\b(i16be|i32be|i64be|i128be|u16be|u32be|u64be|u128be)\\b"), // matches all the #+ and # compiler directives/builtins QStringLiteral("#([^\\s\\(]+)(\\([^\\)]*\\))?"), // matches all attributes like @(attribute) with optional parentheses QStringLiteral("@(\\([^\\)]*\\)|\\w+)"), }; _highlightingRules.clear(); // Clear old rules. HighlightingRule rule; // Set class format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Z][A-Z0-9_]*\\b")); rule.format = _classFormat; _highlightingRules.append(rule); // Set quote format and expression. rule.pattern = QRegularExpression(QStringLiteral("\".*\"")); rule.format = _quotationFormat; _highlightingRules.append(rule); // Set function format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_]+(?=\\s*\\()")); rule.format = _functionFormat; _highlightingRules.append(rule); // Set keywords format and expression (must have precedence over functions) for (const QString& pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern); rule.format = _keywordFormat; _highlightingRules.append(rule); } // Set single line comment format and expression. rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*")); rule.format = _singleLineCommentFormat; _highlightingRules.append(rule); // Set multi-line comment expression. Format is defined later. _commentStartExpression = QRegularExpression(QStringLiteral("/\\*")); _commentEndExpression = QRegularExpression(QStringLiteral("\\*/")); } seer-2.7/src/SeerOdinSourceHighlighter.h000066400000000000000000000007241516472651200203440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include "SeerSourceHighlighter.h" class SeerOdinSourceHighlighter : public SeerSourceHighlighter { Q_OBJECT public: SeerOdinSourceHighlighter(QTextDocument *parent = 0); virtual void setHighlighterSettings (SeerHighlighterSettings const &settings) override; }; seer-2.7/src/SeerPlainTextEdit.cpp000066400000000000000000000061231516472651200171630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include #include "SeerPlainTextEdit.h" #include #include #include #include #include SeerPlainTextEdit::SeerPlainTextEdit(const QString& text, QWidget* parent) : QPlainTextEdit(text, parent) { // Turn off the widget's cursor. We'll do our own in the paintEvent. setCursorWidth(0); _cursorVisible = true; _cursorTimer = new QTimer(this); QObject::connect(_cursorTimer, &QTimer::timeout, this, &SeerPlainTextEdit::blinkCursor); QObject::connect(this, &QPlainTextEdit::cursorPositionChanged, this, &SeerPlainTextEdit::handleCursorPositionChanged); _cursorTimer->start(500); } SeerPlainTextEdit::SeerPlainTextEdit(QWidget* parent) : QPlainTextEdit(parent) { // Turn off the widget's cursor. We'll do our own in the paintEvent. setCursorWidth(0); _cursorVisible = true; _cursorTimer = new QTimer(this); QObject::connect(_cursorTimer, &QTimer::timeout, this, &SeerPlainTextEdit::blinkCursor); QObject::connect(this, &QPlainTextEdit::cursorPositionChanged, this, &SeerPlainTextEdit::handleCursorPositionChanged); _cursorTimer->start(500); } SeerPlainTextEdit::~SeerPlainTextEdit () { } void SeerPlainTextEdit::forwardViewportEvent(QEvent* event) { viewportEvent(event); } void SeerPlainTextEdit::blinkCursor() { _cursorVisible = !_cursorVisible; viewport()->update(); // Trigger a repaint of the viewport } void SeerPlainTextEdit::paintEvent(QPaintEvent* event) { // First, let the standard QPlainTextEdit handle its painting. QPlainTextEdit::paintEvent(event); // Get our painter. QPainter painter(viewport()); // Draw the cursor manually. if (_cursorVisible) { QRect r = cursorRect(); r.setWidth(CURSOR_WIDTH); painter.fillRect(r, palette().text().color()); } // Add margin highlight for current line QTextCursor cursor = textCursor(); QTextBlock block = cursor.block(); // Get the rectangle of the current line (block) QRectF rect = blockBoundingGeometry(block).translated(contentOffset()); // Optional: add a few pixels margin around the block rect.adjust(-2, 0, 2, 0); // Draw a visible border QPen pen(QColor(200, 200, 200), 0.5); painter.setPen(pen); painter.drawRect(rect); } // Add margin highlight for current line void SeerPlainTextEdit::handleCursorPositionChanged() { viewport()->update(); } // // // SeerPlainTextWheelEventForwarder::SeerPlainTextWheelEventForwarder (SeerPlainTextEdit* target ) : QObject(), _target(target) { } SeerPlainTextWheelEventForwarder::~SeerPlainTextWheelEventForwarder() { _target = NULL; } bool SeerPlainTextWheelEventForwarder::eventFilter (QObject* obj, QEvent* event) { Q_UNUSED(obj); if (_target == 0) { return false; } if (event->type() == QEvent::Wheel) { _target->forwardViewportEvent(event); } // do not filter the event return false; } seer-2.7/src/SeerPlainTextEdit.h000066400000000000000000000025521516472651200166320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include class SeerPlainTextEdit : public QPlainTextEdit { Q_OBJECT public: explicit SeerPlainTextEdit (const QString& text, QWidget* parent = 0); explicit SeerPlainTextEdit (QWidget* parent = 0); ~SeerPlainTextEdit (); void forwardViewportEvent (QEvent* event); protected: void paintEvent (QPaintEvent* event); private slots: void blinkCursor (); void handleCursorPositionChanged (); private: constexpr static int CURSOR_WIDTH = 2; QTimer* _cursorTimer; bool _cursorVisible; }; class SeerPlainTextWheelEventForwarder : public QObject { Q_OBJECT public: explicit SeerPlainTextWheelEventForwarder (SeerPlainTextEdit* target); ~SeerPlainTextWheelEventForwarder(); bool eventFilter (QObject* obj, QEvent* event); private: SeerPlainTextEdit* _target; }; seer-2.7/src/SeerPrintpointCreateDialog.cpp000066400000000000000000000214671516472651200210670ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerPrintpointCreateDialog.h" #include "SeerHelpPageDialog.h" #include SeerPrintpointCreateDialog::SeerPrintpointCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setFilename(""); setFunctionName(""); setLabelName(""); setLineNumber(""); setTemporaryEnabled (false); setPendingEnabled (false); setDisabledEnabled (false); setConditionalEnabled (false); setIgnoreCountEnabled (false); setThreadIdEnabled (false); setConditionalText (""); setIgnoreCountText (""); setThreadIdText (""); setFormat(""); setArguments(""); setDPrintfType ("gdb"); setDPrintfFunction (""); setDPrintfChannel (""); filenameLineEdit->setFocus(); // Connect things. QObject::connect(conditionalCheckBox, &QCheckBox::clicked, conditionalLineEdit, &QLineEdit::setEnabled); QObject::connect(ignoreCountCheckBox, &QCheckBox::clicked, ignoreCountLineEdit, &QLineEdit::setEnabled); QObject::connect(threadIdCheckBox, &QCheckBox::clicked, threadIdLineEdit, &QLineEdit::setEnabled); QObject::connect(typeButtonGroup, &QButtonGroup::buttonClicked, this, &SeerPrintpointCreateDialog::handleDprintfTypeChanged); QObject::connect(typeHelpToolButton, &QToolButton::clicked, this, &SeerPrintpointCreateDialog::handleHelpToolButtonClicked); } SeerPrintpointCreateDialog::~SeerPrintpointCreateDialog () { } void SeerPrintpointCreateDialog::setFilename (const QString& text) { filenameLineEdit->setText(text); } void SeerPrintpointCreateDialog::setFunctionName (const QString& text) { functionLineEdit->setText(text); } void SeerPrintpointCreateDialog::setLabelName (const QString& text) { labelLineEdit->setText(text); } void SeerPrintpointCreateDialog::setLineNumber (const QString& text) { lineNumberLineEdit->setText(text); } QString SeerPrintpointCreateDialog::filenameText () const { return filenameLineEdit->text(); } QString SeerPrintpointCreateDialog::functionNameText () const { return functionLineEdit->text(); } QString SeerPrintpointCreateDialog::labelNameText () const { return labelLineEdit->text(); } QString SeerPrintpointCreateDialog::lineNumberText () const { return lineNumberLineEdit->text(); } void SeerPrintpointCreateDialog::setTemporaryEnabled (bool flag) { temporaryCheckBox->setChecked(flag); } void SeerPrintpointCreateDialog::setPendingEnabled (bool flag) { pendingCheckBox->setChecked(flag); } void SeerPrintpointCreateDialog::setDisabledEnabled (bool flag) { disabledCheckBox->setChecked(flag); } void SeerPrintpointCreateDialog::setConditionalEnabled (bool flag) { conditionalCheckBox->setChecked(flag); conditionalLineEdit->setEnabled(flag); } void SeerPrintpointCreateDialog::setIgnoreCountEnabled (bool flag) { ignoreCountCheckBox->setChecked(flag); ignoreCountLineEdit->setEnabled(flag); } void SeerPrintpointCreateDialog::setThreadIdEnabled (bool flag) { threadIdCheckBox->setChecked(flag); threadIdLineEdit->setEnabled(flag); } void SeerPrintpointCreateDialog::setConditionalText (const QString& text) { conditionalLineEdit->setText(text); } void SeerPrintpointCreateDialog::setIgnoreCountText (const QString& text) { ignoreCountLineEdit->setText(text); } void SeerPrintpointCreateDialog::setThreadIdText (const QString& text) { threadIdLineEdit->setText(text); } bool SeerPrintpointCreateDialog::temporaryEnabled () const { return temporaryCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::pendingEnabled () const { return pendingCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::disabledEnabled () const { return disabledCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::conditionalEnabled () const { return conditionalCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::ignoreCountEnabled () const { return ignoreCountCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::threadIdEnabled () const { return threadIdCheckBox->isChecked(); } QString SeerPrintpointCreateDialog::conditionalText () const { return conditionalLineEdit->text(); } QString SeerPrintpointCreateDialog::ignoreCountText () const { return ignoreCountLineEdit->text(); } QString SeerPrintpointCreateDialog::threadIdText () const { return threadIdLineEdit->text(); } void SeerPrintpointCreateDialog::setFormat (const QString& text) { formatLineEdit->setText(text); } void SeerPrintpointCreateDialog::setArguments (const QString& text) { argumentsLineEdit->setText(text); } QString SeerPrintpointCreateDialog::format () const { return formatLineEdit->text(); } QString SeerPrintpointCreateDialog::arguments () const { return argumentsLineEdit->text(); } QString SeerPrintpointCreateDialog::dprintfType () const { if (typeGdbRadioButton->isChecked()) { return "gdb"; }else if (typeCallRadioButton->isChecked()) { return "call"; }else if (typeAgentRadioButton->isChecked()) { return "agent"; } // Default. return "gdb"; } QString SeerPrintpointCreateDialog::dprintfFunction () const { if (dprintfType() == "gdb") { return ""; } return dprintfFunctionLineEdit->text(); } QString SeerPrintpointCreateDialog::dprintfChannel () const { if (dprintfType() == "gdb") { return ""; } return dprintfChannelLineEdit->text(); } void SeerPrintpointCreateDialog::setDPrintfType (const QString& text) { if (text == "gdb") { typeGdbRadioButton->setChecked(true); dprintfFunctionLineEdit->setEnabled(false); dprintfChannelLineEdit->setEnabled(false); return; }else if (text == "call") { typeCallRadioButton->setChecked(true); dprintfFunctionLineEdit->setEnabled(true); dprintfChannelLineEdit->setEnabled(true); return; }else if (text == "agent") { typeAgentRadioButton->setChecked(true); dprintfFunctionLineEdit->setEnabled(false); dprintfChannelLineEdit->setEnabled(false); return; } // Default. typeGdbRadioButton->setChecked(true); dprintfFunctionLineEdit->setEnabled(false); dprintfChannelLineEdit->setEnabled(false); } void SeerPrintpointCreateDialog::setDPrintfFunction (const QString& text) { dprintfFunctionLineEdit->setText(text); } void SeerPrintpointCreateDialog::setDPrintfChannel (const QString& text) { dprintfChannelLineEdit->setText(text); } QString SeerPrintpointCreateDialog::printpointParameters () const { // Build a printpoint specification. // // -dprintf-insert [ -t ] [ -f ] [ -d ] [ --qualified ] // [ -c condition ] [--force-condition] [ -i ignore-count ] // [ -p thread-id ] [ location ] // [ format ] [ argument ] QString printpointParameters; if (temporaryEnabled()) { printpointParameters += " -t"; } if (pendingEnabled()) { printpointParameters += " -f"; } if (disabledEnabled()) { printpointParameters += " -d"; } if (conditionalEnabled()) { if (conditionalText() != "") { printpointParameters += " -c \"" + conditionalText() + "\""; } } if (ignoreCountEnabled()) { if (ignoreCountText() != "") { printpointParameters += " -i " + ignoreCountText(); } } if (threadIdEnabled()) { if (threadIdText() != "") { printpointParameters += " -p " + threadIdText(); } } if (filenameText() != "") { printpointParameters += " --source \"" + filenameText() +"\""; } if (functionNameText() != "") { printpointParameters += " --function " + functionNameText(); } if (labelNameText() != "") { printpointParameters += " --label " + labelNameText(); } if (lineNumberText() != "") { printpointParameters += " --line " + lineNumberText(); } // Build the format string, ensuring a \" at the beginning and end of the string. printpointParameters += " "; if (format().front() != QString("\"")) { printpointParameters += "\""; } printpointParameters += format(); if (format().back() != QString("\"")) { printpointParameters += "\""; } // Add the arguments to the string. printpointParameters += " " + arguments(); return printpointParameters; } void SeerPrintpointCreateDialog::handleDprintfTypeChanged () { setDPrintfType(dprintfType()); } void SeerPrintpointCreateDialog::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/Printpoints.md"); help->show(); help->raise(); } seer-2.7/src/SeerPrintpointCreateDialog.h000066400000000000000000000061411516472651200205240ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerPrintpointCreateDialog.h" class SeerPrintpointCreateDialog : public QDialog, protected Ui::SeerPrintpointCreateDialogForm { Q_OBJECT public: explicit SeerPrintpointCreateDialog (QWidget* parent = 0); ~SeerPrintpointCreateDialog (); void setFilename (const QString& text); void setFunctionName (const QString& text); void setLabelName (const QString& text); void setLineNumber (const QString& text); QString filenameText () const; QString functionNameText () const; QString labelNameText () const; QString lineNumberText () const; void setTemporaryEnabled (bool flag); void setPendingEnabled (bool flag); void setDisabledEnabled (bool flag); void setConditionalEnabled (bool flag); void setIgnoreCountEnabled (bool flag); void setThreadIdEnabled (bool flag); void setConditionalText (const QString& text); void setIgnoreCountText (const QString& text); void setThreadIdText (const QString& text); bool temporaryEnabled () const; bool hardwareEnabled () const; bool pendingEnabled () const; bool disabledEnabled () const; bool conditionalEnabled () const; bool ignoreCountEnabled () const; bool threadIdEnabled () const; QString conditionalText () const; QString ignoreCountText () const; QString threadIdText () const; void setFormat (const QString& text); void setArguments (const QString& text); QString format () const; QString arguments () const; QString dprintfType () const; QString dprintfFunction () const; QString dprintfChannel () const; void setDPrintfType (const QString& text); void setDPrintfFunction (const QString& text); void setDPrintfChannel (const QString& text); QString printpointParameters () const; public slots: void handleDprintfTypeChanged (); private slots: void handleHelpToolButtonClicked (); private: }; seer-2.7/src/SeerPrintpointCreateDialog.ui000066400000000000000000000324201516472651200207110ustar00rootroot00000000000000 SeerPrintpointCreateDialogForm 0 0 607 635 Create a Printpoint Printpoint Location Filename true Line number true Qt::Horizontal 40 20 Function true Label true Qt::Horizontal 40 20 Printpoint Conditions Temporary Qt::Horizontal 40 20 Conditional true Pending Qt::Horizontal 40 20 Ignore Count true Thread Id true Disabled Qt::Horizontal 40 20 Printpoint Parameters Format A printf() style format string. Don't forget the '\n'. true Arguments List of variables to print, separated by a space. true Printpoint Type Type Printpoint output goes the Gdb Ouput tab. gdb typeButtonGroup Printpoint output goes to the Seer Console. call typeButtonGroup Printpoint output is handled by the gdbserver. agent typeButtonGroup Qt::Horizontal 561 20 Help about Printpoints. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Function The name of a function in your program to use. true Channel The channel variable, if required by the function. true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok filenameLineEdit lineNumberLineEdit functionLineEdit labelLineEdit temporaryCheckBox conditionalCheckBox conditionalLineEdit pendingCheckBox ignoreCountCheckBox ignoreCountLineEdit disabledCheckBox threadIdCheckBox threadIdLineEdit formatLineEdit argumentsLineEdit typeGdbRadioButton typeCallRadioButton typeAgentRadioButton typeHelpToolButton dprintfFunctionLineEdit dprintfChannelLineEdit buttonBox accepted() SeerPrintpointCreateDialogForm accept() 248 254 157 274 buttonBox rejected() SeerPrintpointCreateDialogForm reject() 316 260 286 274 seer-2.7/src/SeerPrintpointsBrowserWidget.cpp000066400000000000000000000372761516472651200215230ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerPrintpointsBrowserWidget.h" #include "SeerPrintpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerPrintpointsBrowserWidget::SeerPrintpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets printpointsTreeWidget->clear(); printpointsTreeWidget->setSortingEnabled(false); printpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); printpointsTreeWidget->resizeColumnToContents(0); // number printpointsTreeWidget->resizeColumnToContents(1); // type printpointsTreeWidget->resizeColumnToContents(2); // disp printpointsTreeWidget->resizeColumnToContents(3); // enabled printpointsTreeWidget->resizeColumnToContents(4); // addr //printpointsTreeWidget->resizeColumnToContents(5); // func Too long to show printpointsTreeWidget->resizeColumnToContents(6); // file //printpointsTreeWidget->resizeColumnToContents(7); // fullname Too long to show printpointsTreeWidget->resizeColumnToContents(8); // line //printpointsTreeWidget->resizeColumnToContents(9); // script Too long to show printpointsTreeWidget->resizeColumnToContents(10); // thread-groups printpointsTreeWidget->resizeColumnToContents(11); // cond printpointsTreeWidget->resizeColumnToContents(12); // times printpointsTreeWidget->resizeColumnToContents(13); // ignore printpointsTreeWidget->resizeColumnToContents(14); // original-location /* printpointsTreeWidget->setColumnHidden(1, true); // ??? Hide or have a config to hide/show columns. printpointsTreeWidget->setColumnHidden(6, true); */ // Connect things. QObject::connect(printpointsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerPrintpointsBrowserWidget::handleItemDoubleClicked); QObject::connect(refreshPrintpointsToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addPrintpointToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleAddToolButton); QObject::connect(deletePrintpointsToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleDeleteToolButton); QObject::connect(enablePrintpointsToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleEnableToolButton); QObject::connect(disablePrintpointsToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleDisableToolButton); QObject::connect(conditionBreakpointToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleConditionToolButton); QObject::connect(ignoreBreakpointToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleIgnoreToolButton); QObject::connect(commandBreakpointToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleCommandToolButton); } SeerPrintpointsBrowserWidget::~SeerPrintpointsBrowserWidget () { } bool SeerPrintpointsBrowserWidget::isEmpty() const { return (printpointsTreeWidget->topLevelItemCount() == 0); } QStringList SeerPrintpointsBrowserWidget::breakpoints () const { return QStringList(); } void SeerPrintpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { printpointsTreeWidget->clear(); // // ^done,BreakpointTable={ // nr_rows="1",nr_cols="6", // // hdr=[ // {width="7",alignment="-1",col_name="number",colhdr="Num"}, // {width="14",alignment="-1",col_name="type",colhdr="Type"}, // {width="4",alignment="-1",col_name="disp",colhdr="Disp"}, // {width="3",alignment="-1",col_name="enabled",colhdr="Enb"}, // {width="18",alignment="-1",col_name="addr",colhdr="Address"}, // {width="40",alignment="2",col_name="what",colhdr="What"} // ], // // body=[ // bkpt={number="3", // type="dprintf", // disp="keep", // enabled="y", // addr="0x0000000000403a78", // func="main(int, char**)", // file="explorer.cpp", // fullname="/home/erniep/Development/Peak/src/Apps/Explorer/explorer.cpp", // line="84", // thread-groups=["i1"], // times="0", // script={"printf "i=%d argc=%d\n",i,argc"}, // original-location="-source /home/erniep/Development/Peak/src/Apps/Explorer/explorer.cpp -line 84"} // ] // } // Don't filter characters. It messes up \n in the the dprintf_text. // QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(text, "body=", '[', ']', false); if (body_text != "") { QStringList bkpt_list = Seer::parse(text, "bkpt=", '{', '}', false); for ( const auto& bkpt_text : bkpt_list ) { QString number_text = Seer::parseFirst(bkpt_text, "number=", '"', '"', false); QString type_text = Seer::parseFirst(bkpt_text, "type=", '"', '"', false); QString disp_text = Seer::parseFirst(bkpt_text, "disp=", '"', '"', false); QString enabled_text = Seer::parseFirst(bkpt_text, "enabled=", '"', '"', false); QString addr_text = Seer::parseFirst(bkpt_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(bkpt_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(bkpt_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(bkpt_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(bkpt_text, "line=", '"', '"', false); QString script_text = Seer::parseFirst(bkpt_text, "script=", '[', ']', false); QString thread_groups_text = Seer::parseFirst(bkpt_text, "thread-groups=", '[', ']', false); QString cond_text = Seer::parseFirst(bkpt_text, "cond=", '"', '"', false); QString times_text = Seer::parseFirst(bkpt_text, "times=", '"', '"', false); QString ignore_text = Seer::parseFirst(bkpt_text, "ignore=", '"', '"', false); QString original_location_text = Seer::parseFirst(bkpt_text, "original-location=", '"', '"', false); // Only look for 'breakpoint' type dprintf points. if (type_text != "dprintf") { continue; } // Remove '"' bookends and then remove one level of escapes. script_text = Seer::filterBookends (script_text, '"', '"'); script_text = Seer::filterEscapes(script_text); // Add the level to the tree. QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, number_text); topItem->setText(1, type_text); topItem->setText(2, disp_text); topItem->setText(3, enabled_text); topItem->setText(4, addr_text); topItem->setText(5, func_text); topItem->setText(6, QFileInfo(file_text).fileName()); topItem->setText(7, fullname_text); topItem->setText(8, line_text); topItem->setText(9, script_text); topItem->setText(10, thread_groups_text); topItem->setText(11, cond_text); topItem->setText(12, times_text); topItem->setText(13, ignore_text); topItem->setText(14, original_location_text); for (int i=0; icolumnCount(); i++) { topItem->setTextAlignment(i, Qt::AlignLeft|Qt::AlignTop); } printpointsTreeWidget->addTopLevelItem(topItem); } } }else{ // Ignore others. } printpointsTreeWidget->resizeColumnToContents(0); printpointsTreeWidget->resizeColumnToContents(1); printpointsTreeWidget->resizeColumnToContents(2); printpointsTreeWidget->resizeColumnToContents(3); printpointsTreeWidget->resizeColumnToContents(4); //printpointsTreeWidget->resizeColumnToContents(5); printpointsTreeWidget->resizeColumnToContents(6); //printpointsTreeWidget->resizeColumnToContents(7); printpointsTreeWidget->resizeColumnToContents(8); printpointsTreeWidget->resizeColumnToContents(9); printpointsTreeWidget->resizeColumnToContents(10); printpointsTreeWidget->resizeColumnToContents(11); printpointsTreeWidget->resizeColumnToContents(12); printpointsTreeWidget->resizeColumnToContents(13); printpointsTreeWidget->resizeColumnToContents(14); QApplication::restoreOverrideCursor(); } void SeerPrintpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshPrintpointsList(); } void SeerPrintpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. printpointsTreeWidget->clear(); } void SeerPrintpointsBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); int lineno = item->text(8).toInt(); emit selectedFile(item->text(6), item->text(7), lineno); } void SeerPrintpointsBrowserWidget::handleRefreshToolButton () { emit refreshPrintpointsList(); } void SeerPrintpointsBrowserWidget::handleAddToolButton () { SeerPrintpointCreateDialog dlg(this); int ret = dlg.exec(); if (ret == 0) { return; } // Build a printpoint specification. QString type = dlg.dprintfType(); QString function = dlg.dprintfFunction(); QString channel = dlg.dprintfChannel(); QString parameters = dlg.printpointParameters(); // If nothing, just return. if (parameters == "" || type == "") { return; } // Otherwise send the command to create the printpoint. emit insertPrintpoint(type, function, channel, parameters); } void SeerPrintpointsBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = printpointsTreeWidget->selectedItems(); // Build a string that is a list of printpoints. QString printpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { printpoints += " "; } printpoints += (*i)->text(0); } // Don't do anything if the list of printpoints is empty. if (printpoints == "") { return; } // Send the signal. emit deletePrintpoints(printpoints); } void SeerPrintpointsBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = printpointsTreeWidget->selectedItems(); // Build a string that is a list of printpoints. QString printpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { printpoints += " "; } printpoints += (*i)->text(0); } // Don't do anything if the list of printpoints is empty. if (printpoints == "") { return; } // Send the signal. emit enablePrintpoints(printpoints); } void SeerPrintpointsBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = printpointsTreeWidget->selectedItems(); // Build a string that is a list of printpoints. QString printpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { printpoints += " "; } printpoints += (*i)->text(0); } // Don't do anything if the list of printpoints is empty. if (printpoints == "") { return; } // Send the signal. emit disablePrintpoints(printpoints); } void SeerPrintpointsBrowserWidget::handleConditionToolButton () { // Get selected tree items. Only allow one. QList items = printpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one printpoint when adding a condition.", QMessageBox::Ok); return; } // Get the condition text. bool ok; QString condition = QInputDialog::getText(this, "Seer", "Enter the condition for this printpoint.\nA blank condition will remove an existing one.", QLineEdit::Normal, items.front()->text(11), &ok); if (ok == false) { return; } // Get the selected printpoint number. QString printpoint = items.front()->text(0); // Send the signal. emit addBreakpointCondition(printpoint, condition); } void SeerPrintpointsBrowserWidget::handleIgnoreToolButton () { // Get selected tree items. Only allow one. QList items = printpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one printpoint when adding an ignore count.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; int count = QInputDialog::getInt(this, "Seer", "Enter the ignore count for this printpoint.\nA count of 0 will remove an existing one.", items.front()->text(13).toInt(), 0, 2147483647, 1, &ok); if (ok == false) { return; } // Get the selected printpoint number. QString printpoint = items.front()->text(0); // Send the signal. emit addBreakpointIgnore(printpoint, QString::number(count)); } void SeerPrintpointsBrowserWidget::handleCommandToolButton () { // Get selected tree items. Only allow one. QList items = printpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one printpoint when editing the command.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; QString command = QInputDialog::getText(this, "Seer", "Enter the command to execute for this printpoint.", QLineEdit::Normal, items.front()->text(9), &ok); if (ok == false) { return; } // Get the selected breakpoint number. QString breakpoint = items.front()->text(0); // Send the signal. emit addBreakpointCommand(breakpoint, command); } void SeerPrintpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshPrintpointsList(); } seer-2.7/src/SeerPrintpointsBrowserWidget.h000066400000000000000000000045121516472651200211530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerPrintpointsBrowserWidget.h" class SeerPrintpointsBrowserWidget : public QWidget, protected Ui::SeerPrintpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerPrintpointsBrowserWidget (QWidget* parent = 0); ~SeerPrintpointsBrowserWidget (); bool isEmpty () const; QStringList breakpoints () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleConditionToolButton (); void handleIgnoreToolButton (); void handleCommandToolButton (); signals: void refreshPrintpointsList (); void deletePrintpoints (QString printpoints); void enablePrintpoints (QString printpoints); void disablePrintpoints (QString printpoints); void addBreakpointCondition (QString printpoint, QString condition); void addBreakpointIgnore (QString printpoint, QString count); void addBreakpointCommand (QString breakpoint, QString command); void insertPrintpoint (QString type, QString function, QString channel, QString parameters); void selectedFile (QString file, QString fullname, int lineno); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerPrintpointsBrowserWidget.ui000066400000000000000000000160621516472651200213440ustar00rootroot00000000000000 SeerPrintpointsBrowserWidgetForm 0 0 1173 528 Form 100 100 15 Number Type Disposition Enabled Address Function File Fullname Line Command Thread Groups Condition Times Ignore Original Location Add a new printpoint. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of printpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Enable selected printpoints. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected printpoints. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Add condition to selected breakpoint. ? Add ignore count to selected breakpoint. # Edit command to selected breakpoint. ... :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Delete selected printpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 seer-2.7/src/SeerProgressIndicator.cpp000066400000000000000000000033171516472651200201100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerProgressIndicator.h" #include #include #include #include #include SeerProgressIndicator::SeerProgressIndicator(QWidget* parent) : QProgressIndicator(parent) { setContextMenuPolicy(Qt::CustomContextMenu); QObject::connect(this, &SeerProgressIndicator::customContextMenuRequested, this, &SeerProgressIndicator::handleShowContextMenu); // Read settings. readSettings(); } SeerProgressIndicator::~SeerProgressIndicator() { } void SeerProgressIndicator::writeSettings () { QSettings settings; settings.beginGroup("progressindicator"); { settings.setValue("type", typeName()); } settings.endGroup(); } void SeerProgressIndicator::readSettings () { QSettings settings; settings.beginGroup("progressindicator"); { setType(settings.value("type", QString("BallRotate")).toString()); } settings.endGroup(); } void SeerProgressIndicator::handleShowContextMenu (const QPoint& point) { // Don't do anything. if (point.isNull()) { return; } // Possible indicator types. QStringList typeList = types(); if (typeList.size() == 0) { return; } // Build up menu. QMenu menu("Progress Indicators", this); for (int i=0; itext()); // Save it for next time. writeSettings(); } seer-2.7/src/SeerProgressIndicator.h000066400000000000000000000011421516472651200175470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "QProgressIndicator.h" class SeerProgressIndicator : public QProgressIndicator { Q_OBJECT public: SeerProgressIndicator(QWidget* parent = 0); ~SeerProgressIndicator(); protected: void writeSettings (); void readSettings (); protected slots: void handleShowContextMenu (const QPoint& point); private: }; seer-2.7/src/SeerRRConfigPage.cpp000066400000000000000000000031151516472651200167110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRRConfigPage.h" #include #include #include SeerRRConfigPage::SeerRRConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Connect things. QObject::connect(rrProgramToolButton, &QToolButton::clicked, this, &SeerRRConfigPage::handleRRProgramToolButton); // Setup the defaults. reset(); } SeerRRConfigPage::~SeerRRConfigPage() { } QString SeerRRConfigPage::rrProgram () const { return rrProgramLineEdit->text(); } QString SeerRRConfigPage::rrArguments () const { return rrArgumentsLineEdit->text(); } QString SeerRRConfigPage::gdbArguments () const { return gdbArgumentsLineEdit->text(); } void SeerRRConfigPage::setRRProgram (const QString& program) { rrProgramLineEdit->setText(program); } void SeerRRConfigPage::setRRArguments (const QString& arguments) { rrArgumentsLineEdit->setText(arguments); } void SeerRRConfigPage::setGdbArguments (const QString& arguments) { gdbArgumentsLineEdit->setText(arguments); } void SeerRRConfigPage::reset () { setRRProgram("/usr/bin/rr"); setRRArguments("replay --interpreter=mi"); setGdbArguments(""); } void SeerRRConfigPage::handleRRProgramToolButton () { QString program = QFileDialog::getOpenFileName(this, "Select a RR program to use.", rrProgram(), "", nullptr, QFileDialog::DontUseNativeDialog); if (program != "") { setRRProgram(program); } } seer-2.7/src/SeerRRConfigPage.h000066400000000000000000000022171516472651200163600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerRRConfigPage.h" class SeerRRConfigPage : public QWidget, protected Ui::SeerRRConfigPage { Q_OBJECT public: explicit SeerRRConfigPage (QWidget* parent = 0); ~SeerRRConfigPage (); QString rrProgram () const; QString rrArguments () const; QString gdbArguments () const; void setRRProgram (const QString& program); void setRRArguments (const QString& arguments); void setGdbArguments (const QString& arguments); void reset (); protected slots: void handleRRProgramToolButton (); }; seer-2.7/src/SeerRRConfigPage.ui000066400000000000000000000171111516472651200165450ustar00rootroot00000000000000 SeerRRConfigPage 0 0 794 920 SeerRRConfigPage RR Settings Specify the path and name of the RR debugger. true RR program RR arguments Any extra arguments to pass to the gdb debugger. true Open a file dialog to locate the RR debugger. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Arguments to pass to the RR debugger. true GDB arguments <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify the RR program and location, as well as the RR arguments. </span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Changing many of these require saving the new configuration and restarting Seer to take effect</span>.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"><br />&quot;RR program&quot; points to the path and name of the RR program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">&quot;RR arguments&quot; specifies the arguments to pass to RR. It must minimally have 'replay --interpreter=mi'. And other arguments you may need for RR.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">&quot;GDB arguments&quot; specified the arguments to pass on to gdb. Usually not needed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RR will be started by the launcher specified in the GDB config tab.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">Between these input fields, Seer forms the command:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"> $ /usr/bin/rr replay --interpreter=mi [RR-arguments] [trace-directory] [--tty /dev/pts] [-- gdb-arguments] </span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"><br /></span>Note, Seer relies on the &quot;mi&quot; interpreter that is built into gdb. So, the &quot;--interpreter=mi&quot; argument is a must. This is specified in the &quot;RR arguments&quot; field.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"><br />The &quot;trace-directory&quot; argument is given when you run Seer in the RR mode.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">The &quot;--tty&quot; device is handled automatically by Seer.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"><br />Here's the RR Wiki page for more info on arguments.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">https://github.com/rr-debugger/rr/wiki/Usage<br /><br /></span></p></body></html> seer-2.7/src/SeerRegisterEditValueDialog.cpp000066400000000000000000000015101516472651200211470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRegisterEditValueDialog.h" #include SeerRegisterEditValueDialog::SeerRegisterEditValueDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets set("",""); // Connect things. } SeerRegisterEditValueDialog::~SeerRegisterEditValueDialog () { } void SeerRegisterEditValueDialog::set (const QString& regname, const QString& regvalue) { registerNameLineEdit->setText(regname); registerValueLineEdit->setText(regvalue); } QString SeerRegisterEditValueDialog::nameText () const { return registerNameLineEdit->text(); } QString SeerRegisterEditValueDialog::valueText () const { return registerValueLineEdit->text(); } seer-2.7/src/SeerRegisterEditValueDialog.h000066400000000000000000000013311516472651200206150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerRegisterEditValueDialog.h" class SeerRegisterEditValueDialog : public QDialog, protected Ui::SeerRegisterEditValueDialogForm { Q_OBJECT public: explicit SeerRegisterEditValueDialog (QWidget* parent = 0); ~SeerRegisterEditValueDialog (); void set (const QString& regname, const QString& regvalue); QString nameText () const; QString valueText () const; public slots: private: }; seer-2.7/src/SeerRegisterEditValueDialog.ui000066400000000000000000000057031516472651200210120ustar00rootroot00000000000000 SeerRegisterEditValueDialogForm 0 0 322 164 Seer - Edit a Register Value resources/icons/hicolor/32x32/seergdb.pngresources/icons/hicolor/32x32/seergdb.png Register Edit Name The name of the register to edit. true Value The register's new value. true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerRegisterEditValueDialogForm accept() 248 254 157 274 buttonBox rejected() SeerRegisterEditValueDialogForm reject() 316 260 286 274 seer-2.7/src/SeerRegisterProfileDialog.cpp000066400000000000000000000216501516472651200206740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRegisterProfileDialog.h" #include "SeerRegisterTreeWidgetItem.h" #include #include #include #include #include #include #include SeerRegisterProfileDialog::SeerRegisterProfileDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); registersTreeWidget->setSortingEnabled(true); // We can sort on columns. registersTreeWidget->sortByColumn(0, Qt::AscendingOrder); registersTreeWidget->resizeColumnToContents(0); // index registersTreeWidget->resizeColumnToContents(1); // name registersTreeWidget->resizeColumnToContents(2); // checkbox registersTreeWidget->clear(); // Letters, numbers, space, period, hypen, underscore. QRegularExpressionValidator* validator = new QRegularExpressionValidator(QRegularExpression("[a-zA-Z0-9\\ \\.\\-\\_]+")); profileNameLineEdit->setValidator(validator); // Setup the widgets setRegisters(QStringList(), QVector()); // Connect things. QObject::connect(enablePushButton, &QPushButton::clicked, this, &SeerRegisterProfileDialog::handleEnableSelected); QObject::connect(disablePushButton, &QPushButton::clicked, this, &SeerRegisterProfileDialog::handleDisableSelected); QObject::connect(importPushButton, &QPushButton::clicked, this, &SeerRegisterProfileDialog::handleImportFile); QObject::connect(exportPushButton, &QPushButton::clicked, this, &SeerRegisterProfileDialog::handleExportFile); // Restore window settings. readSettings(); } SeerRegisterProfileDialog::~SeerRegisterProfileDialog () { } void SeerRegisterProfileDialog::setRegisters (const QStringList& registerNames, const QVector& registerEnabled) { registersTreeWidget->clear(); for (int i=0; isetText(0, QString::number(i)); topItem->setText(1, registerNames[i]); if (registerEnabled[i] == true) { topItem->setCheckState(2, Qt::Checked); }else{ topItem->setCheckState(2, Qt::Unchecked); } registersTreeWidget->addTopLevelItem(topItem); } registersTreeWidget->resizeColumnToContents(0); registersTreeWidget->resizeColumnToContents(1); registersTreeWidget->resizeColumnToContents(2); } QStringList SeerRegisterProfileDialog::registerNames () const { QStringList registerNames; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = registersTreeWidget->topLevelItem(i); registerNames.push_back(topItem->text(1)); } return registerNames; } QVector SeerRegisterProfileDialog::registerEnabled () const { QVector registerEnabled; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = registersTreeWidget->topLevelItem(i); if (topItem->checkState(2) == Qt::Checked) { registerEnabled.push_back(true); }else{ registerEnabled.push_back(false); } } return registerEnabled; } void SeerRegisterProfileDialog::setProfileName (const QString& profileName) { profileNameLineEdit->setText(profileName); } QString SeerRegisterProfileDialog::profileName () const { return profileNameLineEdit->text(); } void SeerRegisterProfileDialog::accept () { if (profileNameLineEdit->text() == "") { QMessageBox::warning(this, "Seer", "The register profile name is blank.", QMessageBox::Ok); return; } if (profileNameLineEdit->text() == "allregisters") { QMessageBox::warning(this, "Seer", "The register profile name of 'allregisters' is reserved.\n\nChoose a different name.", QMessageBox::Ok); return; } QDialog::accept(); } void SeerRegisterProfileDialog::handleEnableSelected () { QList selected = registersTreeWidget->selectedItems(); foreach (QTreeWidgetItem* item, selected) { item->setCheckState(2, Qt::Checked); } } void SeerRegisterProfileDialog::handleDisableSelected () { QList selected = registersTreeWidget->selectedItems(); foreach (QTreeWidgetItem* item, selected) { item->setCheckState(2, Qt::Unchecked); } } void SeerRegisterProfileDialog::handleImportFile () { // // Get the name of the file to import. // QFileDialog dialog(this, "Seer Register Profile File", "./", "Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptOpen); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("txt"); dialog.selectFile("registerprofile.txt"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } // // Open the file and read from it. // A simple format of: // // QFile file(files[0]); if (file.open(QIODevice::ReadOnly)) { QStringList registerNames; QVector registerEnabled; QTextStream stream(&file); while (stream.atEnd() == false) { QString line = stream.readLine(); QStringList words = line.split(QRegularExpression("\\s+")); // Ignore empty lines. if (words.count() == 0) { continue; } // Ignore null lines. if (words.count() == 1 && words[0] == "") { continue; } // There should be only two words on each line. if (words.count() != 2) { QMessageBox::critical(this, tr("Error"), tr("Can't load register profile file.\nEncountered a line not the form of:\n\n ")); return; } // The second word must be 'enabled' or 'disabled'. if (words[1] != "enabled" && words[1] != "disabled") { QMessageBox::critical(this, tr("Error"), tr("Can't load register profile file.\nEncountered a line not the form of:\n\n ")); return; } registerNames.push_back(words[0]); registerEnabled.push_back(words[1] == "enabled" ? true : false); } // Populate the list with the imported values. setRegisters (registerNames, registerEnabled); QMessageBox::information(this, "Seer", "Loaded."); }else{ QMessageBox::critical(this, tr("Error"), tr("Can't open register profile file.")); return; } } void SeerRegisterProfileDialog::handleExportFile () { // // Get the name of the file to export. // QFileDialog dialog(this, "Seer Register Profile File", "./", "Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("txt"); dialog.selectFile("registerprofile.txt"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } // // Create the file and write to it. // A simple format of: // // QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); QStringList names = registerNames(); QVector enabled = registerEnabled(); for (int i=0; i // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerRegisterProfileDialog.h" class SeerRegisterProfileDialog : public QDialog, protected Ui::SeerRegisterProfileDialogForm { Q_OBJECT public: explicit SeerRegisterProfileDialog (QWidget* parent = 0); ~SeerRegisterProfileDialog (); void setRegisters (const QStringList& registerNames, const QVector& registerEnabled); QStringList registerNames () const; QVector registerEnabled () const; void setProfileName (const QString& profileName); QString profileName () const; public slots: void accept (); private slots: void handleEnableSelected (); void handleDisableSelected (); void handleImportFile (); void handleExportFile (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: }; seer-2.7/src/SeerRegisterProfileDialog.ui000066400000000000000000000121171516472651200205250ustar00rootroot00000000000000 SeerRegisterProfileDialogForm 0 0 600 601 Seer - Register Profile Editor 100 0 QAbstractItemView::ExtendedSelection true # Name Enabled Profile name (lowercase letters and numbers). Profile name true Enable selected items. Enable Selected Disable selected items. Disable Selected Qt::Vertical QSizePolicy::Fixed 20 40 Import items from a file. Import Export items to a file. Export Qt::Vertical QSizePolicy::Expanding 20 318 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerRegisterProfileDialogForm accept() 248 254 157 274 buttonBox rejected() SeerRegisterProfileDialogForm reject() 316 260 286 274 seer-2.7/src/SeerRegisterTreeWidgetItem.cpp000066400000000000000000000014101516472651200210260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRegisterTreeWidgetItem.h" #include #include #include // // SeerRegisterTreeWidgetItem // bool SeerRegisterTreeWidgetItem::operator< (const QTreeWidgetItem& other) const { int column = treeWidget()->sortColumn(); // If no sort column set, then default to ascending order. if (column < 0) { return true; } // If sort on column 0, then compare numerically. if (column == 0) { return text(column).toInt() < other.text(column).toInt(); } // Otherwise, all other columns are textual. return text(column) < other.text(column); } seer-2.7/src/SeerRegisterTreeWidgetItem.h000066400000000000000000000020611516472651200204760ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include class SeerRegisterTreeWidgetItem : public QTreeWidgetItem { public: /* Do we need to specify the base constructors? QTreeWidgetItem(const QTreeWidgetItem &other) QTreeWidgetItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding, int type = Type) QTreeWidgetItem(QTreeWidgetItem *parent, const QStringList &strings, int type = Type) QTreeWidgetItem(QTreeWidgetItem *parent, int type = Type) QTreeWidgetItem(QTreeWidget *parent, QTreeWidgetItem *preceding, int type = Type) QTreeWidgetItem(QTreeWidget *parent, const QStringList &strings, int type = Type) QTreeWidgetItem(QTreeWidget *parent, int type = Type) QTreeWidgetItem(const QStringList &strings, int type = Type) QTreeWidgetItem(int type = Type) */ virtual bool operator< (const QTreeWidgetItem& other) const; }; seer-2.7/src/SeerRegisterValuesBrowserWidget.cpp000066400000000000000000000564151516472651200221320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRegisterValuesBrowserWidget.h" #include "SeerRegisterEditValueDialog.h" #include "SeerRegisterProfileDialog.h" #include "SeerRegisterTreeWidgetItem.h" #include "SeerUtl.h" #include "QEditDelegate.h" #include #include #include #include #include #include #include #include #include #include SeerRegisterValuesBrowserWidget::SeerRegisterValuesBrowserWidget (QWidget* parent) : QWidget(parent) { _newProfileAction = 0; _deleteProfileAction = 0; // Construct the UI. setupUi(this); // Setup the widgets registersTreeWidget->setMouseTracking(true); registersTreeWidget->sortByColumn(0, Qt::AscendingOrder); registersTreeWidget->setSortingEnabled(true); // We can sort on columns. registersTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); registersTreeWidget->resizeColumnToContents(0); // number registersTreeWidget->resizeColumnToContents(1); // name registersTreeWidget->resizeColumnToContents(2); // value registersTreeWidget->resizeColumnToContents(3); // used registersTreeWidget->setColumnHidden(3, true); // Hide the 'used' column. registersTreeWidget->clear(); registerFormatComboBox->addItem("Natural", QVariant("N")); registerFormatComboBox->addItem("Hex", QVariant("x")); registerFormatComboBox->addItem("Octal", QVariant("o")); registerFormatComboBox->addItem("Binary", QVariant("t")); registerFormatComboBox->addItem("Decimal", QVariant("d")); registerFormatComboBox->addItem("Raw", QVariant("r")); registerProfileComboBox->addItem("allregisters"); _needsRegisterNames = true; // Create edit delegate. QAllowEditDelegate* editDelegate = new QAllowEditDelegate(this); registersTreeWidget->setItemDelegateForColumn(0, new QNoEditDelegate(this)); registersTreeWidget->setItemDelegateForColumn(1, new QNoEditDelegate(this)); registersTreeWidget->setItemDelegateForColumn(2, editDelegate); registersTreeWidget->setItemDelegateForColumn(3, new QNoEditDelegate(this)); // Preference menu. QMenu* menu = new QMenu(); _newProfileAction = menu->addAction("New profile"); _modifyProfileAction = menu->addAction("Modify current profile"); _deleteProfileAction = menu->addAction("Delete current profile"); preferencesToolButton->setMenu(menu); preferencesToolButton->setPopupMode(QToolButton::InstantPopup); // Connect things. QObject::connect(registersTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerRegisterValuesBrowserWidget::handleItemDoubleClicked); QObject::connect(registersTreeWidget, &QTreeWidget::itemEntered, this, &SeerRegisterValuesBrowserWidget::handleItemEntered); QObject::connect(registersTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerRegisterValuesBrowserWidget::handleContextMenu); QObject::connect(editDelegate, &QAllowEditDelegate::editingFinished, this, &SeerRegisterValuesBrowserWidget::handleIndexEditingFinished); QObject::connect(registerFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerRegisterValuesBrowserWidget::handleFormatChanged); QObject::connect(registersTreeWidget->header(), &QHeaderView::sectionClicked, this, &SeerRegisterValuesBrowserWidget::handleColumnSelected); QObject::connect(_newProfileAction, &QAction::triggered, this, &SeerRegisterValuesBrowserWidget::handleNewProfile); QObject::connect(_modifyProfileAction, &QAction::triggered, this, &SeerRegisterValuesBrowserWidget::handleModifyProfile); QObject::connect(_deleteProfileAction, &QAction::triggered, this, &SeerRegisterValuesBrowserWidget::handleDeleteProfile); QObject::connect(registerProfileComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerRegisterValuesBrowserWidget::handleProfileChanged); // Restore settings. readSettings(); } SeerRegisterValuesBrowserWidget::~SeerRegisterValuesBrowserWidget () { } void SeerRegisterValuesBrowserWidget::setRegisterFormat (QString fmt) { registerFormatComboBox->setCurrentText(fmt); } void SeerRegisterValuesBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,register-names=[") && text.endsWith("]")) { // "^done,register-names=[\"rax\",\"rbx\",\"rcx\",\"rdx\",\"rsi\",\"rdi\",\"rbp\",\"rsp\", // \"r8\",\"r9\",\"r10\",\"r11\",\"r12\",\"r13\",\"r14\",\"r15\", // \"rip\",\"eflags\",\"cs\",\"ss\",\"ds\",\"es\",\"fs\",\"gs\", // This recreates the tree. registersTreeWidget->clear(); QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "register-names=", '[', ']', false); QStringList name_list = Seer::parse(frame_text, "", '"', '"', false); int i = 0; for ( const auto& name_text : name_list ) { // Some register names come back as "". Not sure why or how. // We'll skip them but we need to still increment the // register id number. Otherwise we may update the wrong // register because we search for the register by its id. if (name_text != "") { QTreeWidgetItem* topItem = new SeerRegisterTreeWidgetItem; topItem->setFlags(topItem->flags() | Qt::ItemIsEditable); topItem->setText(0, QString::number(i)); topItem->setText(1, name_text); topItem->setText(2, ""); topItem->setText(3, "new"); topItem->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); registersTreeWidget->addTopLevelItem(topItem); } i++; } handleShowHideRegisters(); _needsRegisterNames = false; }else if (text.startsWith("^done,register-values=[") && text.endsWith("]")) { // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(registersTreeWidget); while (*it) { (*it)->setText(3, "unused"); ++it; } // "^done,register-values=[{number=\"0\",value=\"0x4005e7\"},{number=\"1\",value=\"0x0\"},{number=\"2\",value=\"0x100\"}, // {number=\"3\",value=\"0x7fffffffd548\"},{number=\"4\",value=\"0x7fffffffd538\"},{number=\"5\",value=\"0x1\"},... // {number=\"205\",value=\"0x0\"},{number=\"206\",value=\"0x0\"}]" QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "register-values=", '[', ']', false); QStringList registers_list = Seer::parse(frame_text, "", '{', '}', false); for ( const auto& register_text : registers_list ) { QString number_text = Seer::parseFirst(register_text, "number=", '"', '"', false); QString value_text = Seer::parseFirst(register_text, "value=", '"', '"', false); // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. QList matches = registersTreeWidget->findItems(number_text, Qt::MatchExactly, 0); // Found a match. Reuse it. Set the value. // If no matches, do not add this entry. if (matches.size() > 0) { QTreeWidgetItem* item = matches.takeFirst(); bool isDifferent = false; // Flag it as different of the new value is different than the old version _AND_ // the old one isn't "" (like after a refresh). if (item->text(2) != "" && item->text(2) != value_text) { isDifferent = true; } item->setText(2, value_text); item->setText(3, "reused"); QFont f1 = item->font(1); QFont f2 = item->font(2); f1.setBold(isDifferent); f2.setBold(isDifferent); item->setFont(1, f1); item->setFont(2, f2); } } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. QList matches = registersTreeWidget->findItems("unused", Qt::MatchExactly, 3); qDeleteAll(matches); }else{ // Ignore others. } registersTreeWidget->resizeColumnToContents(0); registersTreeWidget->resizeColumnToContents(1); registersTreeWidget->resizeColumnToContents(2); registersTreeWidget->resizeColumnToContents(3); QApplication::restoreOverrideCursor(); } void SeerRegisterValuesBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } if (_needsRegisterNames) { emit refreshRegisterNames(); _needsRegisterNames = false; } // Get the format. QString fmt = registerFormatComboBox->currentData().toString(); // refresh(); // If a stopping point is reached, just refresh the values. // The register names should already be there. emit refreshRegisterValues(fmt); } void SeerRegisterValuesBrowserWidget::handleSessionTerminated () { // Delete previous contents. registersTreeWidget->clear(); _needsRegisterNames = true; } void SeerRegisterValuesBrowserWidget::refresh () { // Force new names. _needsRegisterNames = true; // Get the format. QString fmt = registerFormatComboBox->currentData().toString(); emit refreshRegisterNames(); emit refreshRegisterValues(fmt); } void SeerRegisterValuesBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); _editItem(item); } void SeerRegisterValuesBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(1) + " : " + item->text(2)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerRegisterValuesBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = registersTreeWidget->itemAt(pos); // Construct the menu. QMenu* menu = new QMenu("Options", this); QAction* editAction = menu->addAction("Edit selected"); QAction* copyAction = menu->addAction("Copy selected"); QAction* copyAllAction = menu->addAction("Copy all"); // If no selected item, disable 'selected' copy but allow 'all'. if (item == 0) { editAction->setEnabled(false); copyAction->setEnabled(false); } // Execute the menu. Return if nothing. QAction* action = menu->exec(registersTreeWidget->mapToGlobal(pos)); if (action == 0) { return; } // Do register edit. if (action == editAction) { _editItem(item); } // Get selected tree items. QList items; // Get list of 'select' items. if (action == copyAction) { items = registersTreeWidget->selectedItems(); } // Get list of 'all' items. if (action == copyAllAction) { items = registersTreeWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard); } // Populate the clipboard. if (items.size() == 0) { return; } QClipboard* clipboard = QGuiApplication::clipboard(); QString text; for (int i=0; iisHidden() == true) { continue; } text += items[i]->text(1) + ":" + items[i]->text(2) + '\n'; } clipboard->setText(text, QClipboard::Clipboard); clipboard->setText(text, QClipboard::Selection); } void SeerRegisterValuesBrowserWidget::handleIndexEditingFinished (const QModelIndex& index) { QTreeWidgetItem* item = registersTreeWidget->getItemFromIndex(index); if (item == 0) { return; } // Get the format. QString fmt = registerFormatComboBox->currentData().toString(); // Get the new value; QString value = item->text(2); // Emit the signal to change the register to the new value. emit setRegisterValue(fmt, item->text(1), value); } void SeerRegisterValuesBrowserWidget::handleFormatChanged (int index) { // Get the format. QString fmt = registerFormatComboBox->itemData(index).toString(); // Refresh the register values. emit refreshRegisterValues(fmt); } void SeerRegisterValuesBrowserWidget::handleColumnSelected (int logicalIndex) { Q_UNUSED(logicalIndex); writeSettings(); } void SeerRegisterValuesBrowserWidget::handleNewProfile () { if (registersTreeWidget->topLevelItemCount() == 0) { QMessageBox::warning(this, "Seer", "When creating a profile, Seer needs to be debugging a program.", QMessageBox::Ok); return; } // Build a list of registers. QStringList registerNames; QVector registerEnabled; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* item = registersTreeWidget->topLevelItem(i); registerNames.push_back(item->text(1)); registerEnabled.push_back(true); } // Bring up the register profile dialog. SeerRegisterProfileDialog dlg(this); dlg.setRegisters(registerNames, registerEnabled); if (dlg.exec()) { QString profileName = dlg.profileName(); if (profileName == "") { return; } registerNames = dlg.registerNames(); registerEnabled = dlg.registerEnabled(); registerProfileComboBox->addItem(profileName); registerProfileComboBox->setCurrentText(profileName); writeProfileSettings(profileName, registerNames, registerEnabled); writeSettings(); // Use them. _registerNames = registerNames; _registerEnabled = registerEnabled; handleShowHideRegisters(); } } void SeerRegisterValuesBrowserWidget::handleModifyProfile () { QString profileName = registerProfileComboBox->currentText(); if (profileName == "allregisters") { QMessageBox::warning(this, "Seer", "The profile 'allregisters' is reserved.\n\nIt can't be modified.", QMessageBox::Ok); return; } // Build a list of registers. QStringList registerNames = _registerNames; QVector registerEnabled = _registerEnabled; // Bring up the register profile dialog. SeerRegisterProfileDialog dlg(this); dlg.setProfileName(profileName); dlg.setRegisters(registerNames, registerEnabled); if (dlg.exec()) { // Get the (potenially new) profile name. QString newProfileName = dlg.profileName(); if (newProfileName == "") { return; } registerNames = dlg.registerNames(); registerEnabled = dlg.registerEnabled(); // If it's a new name, add it to the list and switch to it. if (newProfileName != profileName) { registerProfileComboBox->addItem(newProfileName); registerProfileComboBox->setCurrentText(newProfileName); } // Write out the setting changes. writeProfileSettings(newProfileName, registerNames, registerEnabled); writeSettings(); // Use them. _registerNames = registerNames; _registerEnabled = registerEnabled; handleShowHideRegisters(); } } void SeerRegisterValuesBrowserWidget::handleDeleteProfile () { int index = registerProfileComboBox->currentIndex(); if (index < 0) { return; } QString profileName = registerProfileComboBox->itemText(index); if (profileName == "") { return; } if (profileName == "allregisters") { QMessageBox::warning(this, "Seer", "The profile 'allregisters' is reserved.\n\nIt can't be deleted.", QMessageBox::Ok); return; } QMessageBox::StandardButton ans = QMessageBox::question(this, "Seer", "Delete profile '" + profileName + "'?"); if (ans != QMessageBox::Yes) { return; } // Delete the profile from the settings. deleteProfileSettings(profileName); // Delete the profile from the list of profiles. registerProfileComboBox->removeItem(index); // Write the current settings. writeSettings(); // Switch to the next profile in the list of profiles. index = registerProfileComboBox->currentIndex(); if (index < 0) { return; } handleProfileChanged (index); } void SeerRegisterValuesBrowserWidget::handleShowHideRegisters () { // If the list is empty, show all. if (_registerNames.count() == 0 || _registerEnabled.count() == 0) { for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = registersTreeWidget->topLevelItem(i); topItem->setHidden(false); } return; } // There is a list. Hide all, then show which ones are enabled. for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = registersTreeWidget->topLevelItem(i); topItem->setHidden(true); } for (int i=0; i<_registerNames.count(); i++) { if (_registerEnabled[i] == false) { continue; } QString registerName = _registerNames[i]; QList matches = registersTreeWidget->findItems(registerName, Qt::MatchExactly, 1); for (int i=0; isetHidden(false); } } } void SeerRegisterValuesBrowserWidget::handleProfileChanged (int index) { // Get the profile. QString profileName = registerProfileComboBox->itemText(index); // Build a list of registers. QStringList registerNames; QVector registerEnabled; bool f = readProfileSettings(profileName, registerNames, registerEnabled); if (f == false) { return; } // Use them. _registerNames = registerNames; _registerEnabled = registerEnabled; handleShowHideRegisters(); writeSettings(); } void SeerRegisterValuesBrowserWidget::writeSettings () { QSettings settings; QStringList registerprofiles; for (int i=0; icount(); i++) { if (registerProfileComboBox->itemText(i) == "allregisters") { continue; } registerprofiles.push_back(registerProfileComboBox->itemText(i)); } settings.beginGroup("registerwindow"); { settings.setValue("sortcolumn", registersTreeWidget->header()->sortIndicatorSection()); settings.setValue("sortorder", registersTreeWidget->header()->sortIndicatorOrder()); settings.setValue("registerprofile", registerProfileComboBox->currentText()); settings.setValue("registerprofiles", registerprofiles); } settings.endGroup(); } void SeerRegisterValuesBrowserWidget::readSettings () { QSettings settings; settings.beginGroup("registerwindow"); { int column = settings.value("sortcolumn", 0).toInt(); int order = settings.value("sortorder", Qt::AscendingOrder).toInt(); registersTreeWidget->header()->setSortIndicator(column, (Qt::SortOrder)order); QString registerProfileName = settings.value("registerprofile").toString(); QStringList registerProfiles = settings.value("registerprofiles").toStringList(); registerProfileComboBox->addItems(registerProfiles); registerProfileComboBox->setCurrentText(registerProfileName); } settings.endGroup(); } void SeerRegisterValuesBrowserWidget::writeProfileSettings (const QString& profileName, const QStringList& registerNames, const QVector& registerEnabled) { QSettings settings; QStringList registerEnabledFlags; for (int i=0; i& registerEnabled) { if (profileName == "" || profileName == "allregisters") { registerNames.resize(0); registerEnabled.resize(0); return true; } QSettings settings; settings.beginGroup("registerprofile_" + profileName); { QVariant registerNamesVariant = settings.value("registernames"); QVariant registerEnabledVariant = settings.value("registerenabled"); QStringList registerEnabledFlags; // Not found? Return with error. if (registerNamesVariant == QVariant() || registerEnabledVariant == QVariant()) { return false; } // Okay, we found it. Populate the containters. registerNames = registerNamesVariant.toStringList(); registerEnabledFlags = registerEnabledVariant.toStringList(); registerEnabled.resize(0); for (int i=0; itext(1), item->text(2)); int ret = dlg.exec(); if (ret == 0) { return; } // The register name could be changed, as well as the value. QString name = dlg.nameText(); QString value = dlg.valueText(); if (name == "") { return; } if (value == "") { return; } // Get the format. QString fmt = registerFormatComboBox->currentData().toString(); // Emit the signal to change the register to the new value. emit setRegisterValue(fmt, name, value); return; } seer-2.7/src/SeerRegisterValuesBrowserWidget.h000066400000000000000000000067711516472651200215770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerRegisterValuesBrowserWidget.h" #include #include #include #include #include #include class SeerRegisterValuesBrowserWidget : public QWidget, protected Ui::SeerRegisterValuesBrowserWidgetForm { Q_OBJECT public: explicit SeerRegisterValuesBrowserWidget (QWidget* parent = 0); ~SeerRegisterValuesBrowserWidget (); public: void setRegisterFormat (QString fmt); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); void handleContextMenu (const QPoint& pos); void handleIndexEditingFinished (const QModelIndex& index); void handleFormatChanged (int index); void handleColumnSelected (int logicalIndex); void handleNewProfile (); void handleModifyProfile (); void handleDeleteProfile (); void handleShowHideRegisters (); void handleProfileChanged (int index); signals: void refreshRegisterNames (); void refreshRegisterValues (QString fmt); void setRegisterValue (QString fmt, QString name, QString value); protected: void showEvent (QShowEvent* event); void readSettings (); void writeSettings (); bool readProfileSettings (const QString& profileName, QStringList& registerNames, QVector& registerEnabled); void writeProfileSettings (const QString& profileName, const QStringList& registerNames, const QVector& registerEnabled); void deleteProfileSettings (const QString& profileName); private: void _editItem (QTreeWidgetItem* item); bool _needsRegisterNames; QStringList _registerNames; QVector _registerEnabled; QAction* _newProfileAction; QAction* _modifyProfileAction; QAction* _deleteProfileAction; }; seer-2.7/src/SeerRegisterValuesBrowserWidget.ui000066400000000000000000000103641516472651200217560ustar00rootroot00000000000000 SeerRegisterValuesBrowserWidgetForm 0 0 733 528 Form Format 0 0 Register Value Format. Qt::Horizontal 508 23 Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg Profile 50 0 Register Profile Selection. QComboBox::AdjustToContentsOnFirstShow Qt::Horizontal 538 23 4 true # Name Value Used QIndexTreeWidget QTreeWidget
QIndexTreeWidget.h
registerFormatComboBox registerProfileComboBox preferencesToolButton registersTreeWidget
seer-2.7/src/SeerRunStatusIndicator.cpp000066400000000000000000000056641516472651200202630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRunStatusIndicator.h" #include #include #include SeerRunStatusIndicator::SeerRunStatusIndicator(QWidget* parent) : QLabel(parent) { QSize size = fontMetrics().size(Qt::TextSingleLine, "XXXXXXXXXXXXXXXXXX"); setAlignment(Qt::AlignCenter); setFixedWidth(size.width()); setText("Status"); setStyleSheet("background-color: lightgray; color: black; font-weight: bold;"); } SeerRunStatusIndicator::~SeerRunStatusIndicator() { } void SeerRunStatusIndicator::setRunStatus (SeerRunStatusIndicator::RunStatus status) { if (status == RunStatus::Idle) { setText("Session Terminated"); setStyleSheet("background-color: lightgray; color: black; font-weight: bold;"); }else if (status == RunStatus::Stopped) { setText("Stopped"); setStyleSheet("background-color: red; color: black; font-weight: bold;"); }else if (status == RunStatus::Stop_By_Breakpoint) { setText("Stop by breakpoint"); setStyleSheet("background-color: yellow; color: black; font-weight: bold;"); }else if (status == RunStatus::Running) { setText("Running"); setStyleSheet("background-color: green; color: black; font-weight: bold;"); }else{ setText("Unknown"); } emit statusChanged(status); } void SeerRunStatusIndicator::handleText (const QString& text) { if (text.startsWith("*running,thread-id=\"")) { // *running,thread-id="all" // *running,thread-id="2" setRunStatus(SeerRunStatusIndicator::Running); }else if (text.startsWith("*stopped")) { if (text.startsWith("*stopped,reason=\"breakpoint-hit\"")) setRunStatus(SeerRunStatusIndicator::Stop_By_Breakpoint); else //^connected,frame={level=\"0\",addr=\"0x00007f48351f80c1\",func=\"read\",args=[],from=\"/lib64/libc.so.6\",arch=\"i386:x86-64\"}" setRunStatus(SeerRunStatusIndicator::Stopped); }else if (text.startsWith("=thread-exited")) { //=thread-exited,id="1",group-id="i1" setRunStatus(SeerRunStatusIndicator::Stopped); }else if (text.startsWith("=thread-group-exited")) { //=thread-group-exited,id="i1" setRunStatus(SeerRunStatusIndicator::Stopped); } else if (text.startsWith("^done,stack")) { // When finish command is invoked setRunStatus(SeerRunStatusIndicator::Stopped); } else{ // All other text is ignored by this widget. // qDebug() << text; } } // handle when program stop/ killed void SeerRunStatusIndicator::handleSessionTerminated() { setText("Session Terminated"); setStyleSheet("background-color: lightgray; color: black; font-weight: bold;"); // also tell SeerProgressIndicator to stop spinning setRunStatus(SeerRunStatusIndicator::Idle); } seer-2.7/src/SeerRunStatusIndicator.h000066400000000000000000000020611516472651200177140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerRunStatusIndicator : public QLabel { Q_OBJECT public: enum RunStatus { Idle = 0, Stopped = 1, Stop_By_Breakpoint = 2, Running = 3, }; explicit SeerRunStatusIndicator(QWidget* parent = 0); ~SeerRunStatusIndicator (); void setRunStatus (SeerRunStatusIndicator::RunStatus status); SeerRunStatusIndicator::RunStatus runStatus () const; signals: void statusChanged (SeerRunStatusIndicator::RunStatus status); public slots: void handleText (const QString& text); void handleSessionTerminated (); protected: private: }; seer-2.7/src/SeerRustSourceHighlighter.cpp000066400000000000000000000102251516472651200207400ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRustSourceHighlighter.h" SeerRustSourceHighlighter::SeerRustSourceHighlighter(QTextDocument *parent) : SeerSourceHighlighter(parent) { // Set to default formats. setHighlighterSettings(SeerHighlighterSettings::populate("")); } void SeerRustSourceHighlighter::setHighlighterSettings(const SeerHighlighterSettings &settings) { _highlighterSettings = settings; _classFormat = _highlighterSettings.get("Class"); _quotationFormat = _highlighterSettings.get("Quotation"); _functionFormat = _highlighterSettings.get("Function"); _singleLineCommentFormat = _highlighterSettings.get("Comment"); _multiLineCommentFormat = _highlighterSettings.get("Multiline Comment"); _keywordFormat = _highlighterSettings.get("Keyword"); const QString keywordPatterns[] = { QStringLiteral("\\bas\\b"), QStringLiteral("\\bbreak\\b"), QStringLiteral("\\bconst\\b"), QStringLiteral("\\bcontinue\\b"), QStringLiteral("\\bcrate\\b"), QStringLiteral("\\belse\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bextern\\b"), QStringLiteral("\\bfalse\\b"), QStringLiteral("\\bfn\\b"), QStringLiteral("\\bfor\\b"), QStringLiteral("\\bif\\b"), QStringLiteral("\\bimpl\\b"), QStringLiteral("\\bin\\b"), QStringLiteral("\\blet\\b"), QStringLiteral("\\bloop\\b"), QStringLiteral("\\bmatch\\b"), QStringLiteral("\\bmod\\b"), QStringLiteral("\\bmove\\b"), QStringLiteral("\\bmut\\b"), QStringLiteral("\\bpub\\b"), QStringLiteral("\\bref\\b"), QStringLiteral("\\breturn\\b"), QStringLiteral("\\bself\\b"), QStringLiteral("\\bSelf\\b"), QStringLiteral("\\bstatic\\b"), QStringLiteral("\\bstruct\\b"), QStringLiteral("\\bsuper\\b"), QStringLiteral("\\btrait\\b"), QStringLiteral("\\btrue\\b"), QStringLiteral("\\btype\\b"), QStringLiteral("\\bunsafe\\b"), QStringLiteral("\\buse\\b"), QStringLiteral("\\bwhere\\b"), QStringLiteral("\\bwhile\\b"), QStringLiteral("\\basync\\b"), QStringLiteral("\\bawait\\b"), QStringLiteral("\\bdyn\\b"), QStringLiteral("\\babstract\\b"), QStringLiteral("\\bbecome\\b"), QStringLiteral("\\bbox\\b"), QStringLiteral("\\bdo\\b"), QStringLiteral("\\bfinal\\b"), QStringLiteral("\\bmacro\\b"), QStringLiteral("\\boverride\\b"), QStringLiteral("\\bpriv\\b"), QStringLiteral("\\btypeof\\b"), QStringLiteral("\\bunsized\\b"), QStringLiteral("\\bvirtual\\b"), QStringLiteral("\\byield\\b"), QStringLiteral("\\btry\\b"), QStringLiteral("\\bgen\\b"), QStringLiteral("#!?\\[.*\\]"), }; _highlightingRules.clear(); // Clear old rules. HighlightingRule rule; // Set class format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Z][A-z0-9_]*\\b")); rule.format = _classFormat; _highlightingRules.append(rule); // Set quote format and expression. rule.pattern = QRegularExpression(QStringLiteral("\".*\"")); rule.format = _quotationFormat; _highlightingRules.append(rule); // Set function format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_!]+(?=\\s*\\()")); rule.format = _functionFormat; _highlightingRules.append(rule); // Set keywords format and expression (must have precedence over functions) for (const QString &pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern); rule.format = _keywordFormat; _highlightingRules.append(rule); } // Set single line comment format and expression. rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*")); rule.format = _singleLineCommentFormat; _highlightingRules.append(rule); // Set multi-line comment expression. Format is defined later. _commentStartExpression = QRegularExpression(QStringLiteral("/\\*")); _commentEndExpression = QRegularExpression(QStringLiteral("\\*/")); } seer-2.7/src/SeerRustSourceHighlighter.h000066400000000000000000000007241516472651200204100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include "SeerSourceHighlighter.h" class SeerRustSourceHighlighter : public SeerSourceHighlighter { Q_OBJECT public: SeerRustSourceHighlighter(QTextDocument *parent = 0); virtual void setHighlighterSettings (const SeerHighlighterSettings &settings) override; }; seer-2.7/src/SeerSeerConfigPage.cpp000066400000000000000000000043351516472651200172710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSeerConfigPage.h" #include SeerSeerConfigPage::SeerSeerConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Connect things. // Setup the defaults. reset(); } SeerSeerConfigPage::~SeerSeerConfigPage() { } void SeerSeerConfigPage::setConsoleMode (const QString& mode) { if (mode == "attached") { attachedRadioButton->setChecked(true); }else if (mode == "detached") { detachedRadioButton->setChecked(true); }else if (mode == "detachedminimized") { detachedMinimizedRadioButton->setChecked(true); }else{ attachedRadioButton->setChecked(true); } } QString SeerSeerConfigPage::consoleMode () const { if (attachedRadioButton->isChecked()) { return "attached"; }else if (detachedRadioButton->isChecked()) { return "detached"; }else if (detachedMinimizedRadioButton->isChecked()) { return "detachedminimized"; }else{ return "attached"; } } void SeerSeerConfigPage::setConsoleScrollLines (int count) { consoleScrollLinesSpinBox->setValue(count); } int SeerSeerConfigPage::consoleScrollLines () const { return consoleScrollLinesSpinBox->value(); } void SeerSeerConfigPage::setRememberWindowSizes (bool flag) { rememberSizescheckBox->setChecked(flag); } bool SeerSeerConfigPage::rememberWindowSizes () const { return rememberSizescheckBox->isChecked(); } void SeerSeerConfigPage::setRememberManualCommandCount (int count) { rememberGdbCommandsSpinBox->setValue(count); } int SeerSeerConfigPage::rememberManualCommandCount () const { return rememberGdbCommandsSpinBox->value(); } void SeerSeerConfigPage::setClearManualCommandHistory (bool flag) { clearHistoryCheckBox->setChecked(flag); } bool SeerSeerConfigPage::clearManualCommandHistory () const { return clearHistoryCheckBox->isChecked(); } void SeerSeerConfigPage::reset () { setConsoleMode("attached"); setConsoleScrollLines(1000); setRememberWindowSizes(true); setRememberManualCommandCount(10); setClearManualCommandHistory(false); } seer-2.7/src/SeerSeerConfigPage.h000066400000000000000000000025751516472651200167420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerSeerConfigPage.h" class SeerSeerConfigPage : public QWidget, public Ui::SeerSeerConfigPage { Q_OBJECT public: explicit SeerSeerConfigPage (QWidget* parent = 0); ~SeerSeerConfigPage (); void setConsoleMode (const QString& mode); QString consoleMode () const; void setConsoleScrollLines (int count); int consoleScrollLines () const; void setRememberWindowSizes (bool flag); bool rememberWindowSizes () const; void setRememberManualCommandCount (int count); int rememberManualCommandCount () const; void setClearManualCommandHistory (bool flag); bool clearManualCommandHistory () const; void reset (); }; seer-2.7/src/SeerSeerConfigPage.ui000066400000000000000000000205431516472651200171230ustar00rootroot00000000000000 SeerSeerConfigPage 0 0 671 611 SeerSeerConfigPage 0 0 Manual Gdb commands Number of manual commands to rememvber. 0 means all. Clear all manual gdb commands. Clear history Number of manual gdb/mi commands to remember Qt::Horizontal 40 20 Window sizes Remember window sizes. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify general settings for the Seer program itself.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Console is where the output for the program being debugged goes to. On startup, the Console can be shown attached inside Seer's tab windows; detached as a normal window; or detached as a minimized window. Also, the console can limit the number of lines in its scroll history. 0 means all lines.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The window sizes can be remembered if they get changed. On startup, Seer will start with the remembered sizes.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Also, 'N' of the most recent manually entered gdb/mi commands will be remembered. 0 means all.</p> <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> Console mode on startup The console is shown as a normal detached window. Detached modeButtonGroup Qt::Horizontal 218 20 The console is shown attached inside Seer's tabs. Attached modeButtonGroup The console is shown as a normal detached window that is minimize. Detached Minimized modeButtonGroup Maximum number of scroll lines. 0 means unlimited. 99999 1000 Qt::Horizontal 40 20 Number of scroll lines windowSizesGroupBox textBrowser consoleModeGroupBox manualGdbCommandsGroupBox seer-2.7/src/SeerSeerLogWidget.cpp000066400000000000000000000026621516472651200171550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSeerLogWidget.h" #include "SeerUtl.h" #include #include #include #include SeerSeerLogWidget::SeerSeerLogWidget (QWidget* parent) : SeerLogWidget(parent) { } SeerSeerLogWidget::~SeerSeerLogWidget () { } void SeerSeerLogWidget::processText (const QString& text) { // Only log '^', '*', and '=' records. bool selected = false; if (selected == false && text.front() == '^') { selected = true; } if (selected == false && text.front() == '*') { selected = true; } if (selected == false && text.front() == '=') { selected = true; } if (selected == false && text.contains(QRegularExpression("^([0-9]+)\\^")) == true) { selected = true; } if (selected == false && text.contains(QRegularExpression("^([0-9]+)\\*")) == true) { selected = true; } if (selected == false && text.contains(QRegularExpression("^([0-9]+)\\=")) == true) { selected = true; } if (selected == false) { return; } // No filtering. QString str = text; if (isTimeStampEnabled()) { str = QString("[") + QTime::currentTime().toString("hh:mm:ss.zz") + QString("] ") + str; } // Write the string to the log. textEdit->append(str); } seer-2.7/src/SeerSeerLogWidget.h000066400000000000000000000006241516472651200166160ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerLogWidget.h" class SeerSeerLogWidget : public SeerLogWidget { Q_OBJECT public: explicit SeerSeerLogWidget (QWidget* parent = 0); ~SeerSeerLogWidget (); void processText (const QString& text); }; seer-2.7/src/SeerSignalEditValueDialog.cpp000066400000000000000000000037261516472651200206130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSignalEditValueDialog.h" #include SeerSignalEditValueDialog::SeerSignalEditValueDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets set("","","","",""); // Connect things. } SeerSignalEditValueDialog::~SeerSignalEditValueDialog () { } void SeerSignalEditValueDialog::set (const QString& signame, const QString& stopvalue, const QString& printvalue, const QString& passvalue, const QString& description) { signalNameLineEdit->setText(signame); signalDescriptionLineEdit->setText(description); signalStopCheckBox->setCheckState(Qt::Unchecked); signalPrintCheckBox->setCheckState(Qt::Unchecked); signalPassCheckBox->setCheckState(Qt::Unchecked); if (stopvalue == "stop" || stopvalue.compare("Yes", Qt::CaseInsensitive) == 0) { signalStopCheckBox->setCheckState(Qt::Checked); } if (printvalue == "print" || printvalue.compare("Yes", Qt::CaseInsensitive) == 0) { signalPrintCheckBox->setCheckState(Qt::Checked); } if (passvalue == "pass" || passvalue.compare("Yes", Qt::CaseInsensitive) == 0) { signalPassCheckBox->setCheckState(Qt::Checked); } } QString SeerSignalEditValueDialog::nameText () const { return signalNameLineEdit->text(); } QString SeerSignalEditValueDialog::stopText () const { if (signalStopCheckBox->isChecked()) { return "stop"; } return "nostop"; } QString SeerSignalEditValueDialog::printText () const { if (signalPrintCheckBox->isChecked()) { return "print"; } return "noprint"; } QString SeerSignalEditValueDialog::passText () const { if (signalPassCheckBox->isChecked()) { return "pass"; } return "nopass"; } QString SeerSignalEditValueDialog::descriptionText () const { return signalDescriptionLineEdit->text(); } seer-2.7/src/SeerSignalEditValueDialog.h000066400000000000000000000017331516472651200202540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerSignalEditValueDialog.h" class SeerSignalEditValueDialog : public QDialog, protected Ui::SeerSignalEditValueDialogForm { Q_OBJECT public: explicit SeerSignalEditValueDialog (QWidget* parent = 0); ~SeerSignalEditValueDialog (); void set (const QString& signame, const QString& stopvalue, const QString& printvalue, const QString& passvalue, const QString& description); QString nameText () const; QString stopText () const; QString printText () const; QString passText () const; QString descriptionText () const; public slots: private: }; seer-2.7/src/SeerSignalEditValueDialog.ui000066400000000000000000000125301516472651200204370ustar00rootroot00000000000000 SeerSignalEditValueDialogForm 0 0 523 173 Seer - Edit a Signal Value resources/icons/hicolor/32x32/seergdb.pngresources/icons/hicolor/32x32/seergdb.png Signal Edit Name 100 0 The name of the signal to edit. true false Stop your program if GDB sees this signal. Stop Print a message to the "GDB output" tab if GDB sees this signal. Print Pass this signal to your program if GDB sees this signal. Pass Qt::Horizontal QSizePolicy::Preferred 60 20 Description 50 0 The description of the signal. true false Qt::Vertical 20 11 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerSignalEditValueDialogForm accept() 248 254 157 274 buttonBox rejected() SeerSignalEditValueDialogForm reject() 316 260 286 274 seer-2.7/src/SeerSignalProfileDialog.cpp000066400000000000000000000206531516472651200203270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSignalProfileDialog.h" #include #include #include #include #include #include #include SeerSignalProfileDialog::SeerSignalProfileDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); signalsTreeWidget->resizeColumnToContents(0); // name signalsTreeWidget->resizeColumnToContents(1); // checkbox signalsTreeWidget->clear(); // Letters, numbers, space, period, hypen, underscore. QRegularExpressionValidator* validator = new QRegularExpressionValidator(QRegularExpression("[a-zA-Z0-9\\ \\.\\-\\_]+")); profileNameLineEdit->setValidator(validator); // Setup the widgets setSignals(QStringList(), QVector()); // Connect things. QObject::connect(enablePushButton, &QPushButton::clicked, this, &SeerSignalProfileDialog::handleEnableSelected); QObject::connect(disablePushButton, &QPushButton::clicked, this, &SeerSignalProfileDialog::handleDisableSelected); QObject::connect(importPushButton, &QPushButton::clicked, this, &SeerSignalProfileDialog::handleImportFile); QObject::connect(exportPushButton, &QPushButton::clicked, this, &SeerSignalProfileDialog::handleExportFile); // Restore window settings. readSettings(); } SeerSignalProfileDialog::~SeerSignalProfileDialog () { } void SeerSignalProfileDialog::setSignals (const QStringList& signalNames, const QVector& signalEnabled) { signalsTreeWidget->clear(); for (int i=0; isetText(0, signalNames[i]); if (signalEnabled[i] == true) { topItem->setCheckState(1, Qt::Checked); }else{ topItem->setCheckState(1, Qt::Unchecked); } signalsTreeWidget->addTopLevelItem(topItem); } signalsTreeWidget->resizeColumnToContents(0); signalsTreeWidget->resizeColumnToContents(1); } QStringList SeerSignalProfileDialog::signalNames () const { QStringList signalNames; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = signalsTreeWidget->topLevelItem(i); signalNames.push_back(topItem->text(0)); } return signalNames; } QVector SeerSignalProfileDialog::signalEnabled () const { QVector signalEnabled; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = signalsTreeWidget->topLevelItem(i); if (topItem->checkState(1) == Qt::Checked) { signalEnabled.push_back(true); }else{ signalEnabled.push_back(false); } } return signalEnabled; } void SeerSignalProfileDialog::setProfileName (const QString& profileName) { profileNameLineEdit->setText(profileName); } QString SeerSignalProfileDialog::profileName () const { return profileNameLineEdit->text(); } void SeerSignalProfileDialog::accept () { if (profileNameLineEdit->text() == "") { QMessageBox::warning(this, "Seer", "The signal profile name is blank.", QMessageBox::Ok); return; } if (profileNameLineEdit->text() == "allsignals") { QMessageBox::warning(this, "Seer", "The signal profile name of 'allsignals' is reserved.\n\nChoose a different name.", QMessageBox::Ok); return; } QDialog::accept(); } void SeerSignalProfileDialog::handleEnableSelected () { QList selected = signalsTreeWidget->selectedItems(); foreach (QTreeWidgetItem* item, selected) { item->setCheckState(1, Qt::Checked); } } void SeerSignalProfileDialog::handleDisableSelected () { QList selected = signalsTreeWidget->selectedItems(); foreach (QTreeWidgetItem* item, selected) { item->setCheckState(1, Qt::Unchecked); } } void SeerSignalProfileDialog::handleImportFile () { // // Get the name of the file to import. // QFileDialog dialog(this, "Seer Signal Profile File", "./", "Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptOpen); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("txt"); dialog.selectFile("signalprofile.txt"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } // // Open the file and read from it. // A simple format of: // // QFile file(files[0]); if (file.open(QIODevice::ReadOnly)) { QStringList signalNames; QVector signalEnabled; QTextStream stream(&file); while (stream.atEnd() == false) { QString line = stream.readLine(); QStringList words = line.split(QRegularExpression("\\s+")); // Ignore empty lines. if (words.count() == 0) { continue; } // Ignore null lines. if (words.count() == 1 && words[0] == "") { continue; } // There should be only two words on each line. if (words.count() != 2) { QMessageBox::critical(this, tr("Error"), tr("Can't load signal profile file.\nEncountered a line not the form of:\n\n ")); return; } // The second word must be 'enabled' or 'disabled'. if (words[1] != "enabled" && words[1] != "disabled") { QMessageBox::critical(this, tr("Error"), tr("Can't load signal profile file.\nEncountered a line not the form of:\n\n ")); return; } signalNames.push_back(words[0]); signalEnabled.push_back(words[1] == "enabled" ? true : false); } // Populate the list with the imported values. setSignals (signalNames, signalEnabled); QMessageBox::information(this, "Seer", "Loaded."); }else{ QMessageBox::critical(this, tr("Error"), tr("Can't open signal profile file.")); return; } } void SeerSignalProfileDialog::handleExportFile () { // // Get the name of the file to export. // QFileDialog dialog(this, "Seer Signal Profile File", "./", "Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("txt"); dialog.selectFile("signalprofile.txt"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } // // Create the file and write to it. // A simple format of: // // QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); QStringList names = signalNames(); QVector enabled = signalEnabled(); for (int i=0; i // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerSignalProfileDialog.h" class SeerSignalProfileDialog : public QDialog, protected Ui::SeerSignalProfileDialogForm { Q_OBJECT public: explicit SeerSignalProfileDialog (QWidget* parent = 0); ~SeerSignalProfileDialog (); void setSignals (const QStringList& signalNames, const QVector& signalEnabled); QStringList signalNames () const; QVector signalEnabled () const; void setProfileName (const QString& profileName); QString profileName () const; public slots: void accept (); private slots: void handleEnableSelected (); void handleDisableSelected (); void handleImportFile (); void handleExportFile (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: }; seer-2.7/src/SeerSignalProfileDialog.ui000066400000000000000000000117361516472651200201640ustar00rootroot00000000000000 SeerSignalProfileDialogForm 0 0 600 601 Seer - Signal Profile Editor 100 0 QAbstractItemView::ExtendedSelection false Name Enabled Profile name (lowercase letters and numbers). Profile name true Enable selected items. Enable Selected Disable selected items. Disable Selected Qt::Vertical QSizePolicy::Fixed 20 40 Import items from a file. Import Export items to a file. Export Qt::Vertical QSizePolicy::Expanding 20 318 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerSignalProfileDialogForm accept() 248 254 157 274 buttonBox rejected() SeerSignalProfileDialogForm reject() 316 260 286 274 seer-2.7/src/SeerSignalValuesBrowserWidget.cpp000066400000000000000000000471601516472651200215600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSignalValuesBrowserWidget.h" #include "SeerSignalEditValueDialog.h" #include "SeerSignalProfileDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include SeerSignalValuesBrowserWidget::SeerSignalValuesBrowserWidget (QWidget* parent) : QWidget(parent) { _newProfileAction = 0; _deleteProfileAction = 0; // Construct the UI. setupUi(this); // Setup the widgets signalsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); signalsTreeWidget->resizeColumnToContents(0); // name signalsTreeWidget->resizeColumnToContents(1); // stop signalsTreeWidget->resizeColumnToContents(2); // print signalsTreeWidget->resizeColumnToContents(3); // pass signalsTreeWidget->resizeColumnToContents(4); // description signalsTreeWidget->resizeColumnToContents(5); // used signalsTreeWidget->setColumnHidden(5, true); // Hide the 'used' column. signalsTreeWidget->clear(); signalProfileComboBox->addItem("allsignals"); _needsSignalNames = true; // Preference menu. QMenu* menu = new QMenu(); _newProfileAction = menu->addAction("New profile"); _modifyProfileAction = menu->addAction("Modify current profile"); _deleteProfileAction = menu->addAction("Delete current profile"); preferencesToolButton->setMenu(menu); preferencesToolButton->setPopupMode(QToolButton::InstantPopup); // Connect things. QObject::connect(signalsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerSignalValuesBrowserWidget::handleItemDoubleClicked); QObject::connect(signalsTreeWidget, &QTreeWidget::itemEntered, this, &SeerSignalValuesBrowserWidget::handleItemEntered); QObject::connect(signalsTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerSignalValuesBrowserWidget::handleContextMenu); QObject::connect(_newProfileAction, &QAction::triggered, this, &SeerSignalValuesBrowserWidget::handleNewProfile); QObject::connect(_modifyProfileAction, &QAction::triggered, this, &SeerSignalValuesBrowserWidget::handleModifyProfile); QObject::connect(_deleteProfileAction, &QAction::triggered, this, &SeerSignalValuesBrowserWidget::handleDeleteProfile); QObject::connect(signalProfileComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerSignalValuesBrowserWidget::handleProfileChanged); // Restore settings. readSettings(); } SeerSignalValuesBrowserWidget::~SeerSignalValuesBrowserWidget () { } void SeerSignalValuesBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,signal-names=[") && text.endsWith("]")) { // ^done,signal-names=[ // "SIGHUP","SIGINT","SIGQUIT","SIGILL","SIGTRAP","SIGABRT","SIGEMT","SIGFPE","SIGKILL","SIGBUS","SIGSEGV" // ] // This recreates the tree. signalsTreeWidget->clear(); QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "signal-names=", '[', ']', false); QStringList name_list = Seer::parse(frame_text, "", '"', '"', false); for ( const auto& name_text : name_list ) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, name_text); topItem->setText(5, "new"); signalsTreeWidget->addTopLevelItem(topItem); } handleShowHideSignals(); _needsSignalNames = false; } else if (text.startsWith("^done,signal-values=[") && text.endsWith("]")) { // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(signalsTreeWidget); while (*it) { (*it)->setText(5, "unused"); ++it; } // ^done,signal-values=[ // {name="SIGHUP",stop="Yes",print="Yes",pass="Yes",description="Hangup"}, // {name="SIGINT",stop="Yes",print="Yes",pass="No",description="Interrupt"}, // {name="SIGQUIT",stop="Yes",print="Yes",pass="Yes",description="Quit"}, // {name="SIGILL",stop="Yes",print="Yes",pass="Yes",description="Illegal instruction"}, // {name="EXC_EMULATION",stop="Yes",print="Yes",pass="Yes",description="Emulation instruction"}, // {name="EXC_SOFTWARE",stop="Yes",print="Yes",pass="Yes",description="Software generated exception"}, // {name="EXC_BREAKPOINT",stop="Yes",print="Yes",pass="Yes",description="Breakpoint"}, // {name="SIGLIBRT",stop="No",print="No",pass="Yes",description="librt internal signal"} // ] QString signals_text = Seer::parseFirst(text, "signal-values=", '[', ']', false); QStringList signals_list = Seer::parse(signals_text, "", '{', '}', false); for (const auto& signal_entry : signals_list) { QString name_text = Seer::parseFirst(signal_entry, "name=", '"', '"', false); QString stop_text = Seer::parseFirst(signal_entry, "stop=", '"', '"', false); QString print_text = Seer::parseFirst(signal_entry, "print=", '"', '"', false); QString pass_text = Seer::parseFirst(signal_entry, "pass=", '"', '"', false); QString description_text = Seer::parseFirst(signal_entry, "description=", '"', '"', false); // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. QList matches = signalsTreeWidget->findItems(name_text, Qt::MatchExactly, 0); // Found a match. Reuse it. Set the value. // If no matches, do not add this entry. if (matches.size() > 0) { QTreeWidgetItem* item = matches.takeFirst(); item->setText(0, name_text); item->setText(1, stop_text); item->setText(2, print_text); item->setText(3, pass_text); item->setText(4, description_text); item->setText(5, "reused"); } } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. QList matches = signalsTreeWidget->findItems("unused", Qt::MatchExactly, 5); qDeleteAll(matches); }else{ // Ignore others. } signalsTreeWidget->resizeColumnToContents(0); signalsTreeWidget->resizeColumnToContents(1); signalsTreeWidget->resizeColumnToContents(2); signalsTreeWidget->resizeColumnToContents(3); signalsTreeWidget->resizeColumnToContents(4); signalsTreeWidget->resizeColumnToContents(5); QApplication::restoreOverrideCursor(); } void SeerSignalValuesBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } if (_needsSignalNames) { emit refreshSignalNames(); _needsSignalNames = false; } // refresh(); // If a stopping point is reached, just refresh the values. // The signal names should already be there. emit refreshSignalValues("all"); } void SeerSignalValuesBrowserWidget::handleSessionTerminated () { // Delete previous contents. signalsTreeWidget->clear(); _needsSignalNames = true; } void SeerSignalValuesBrowserWidget::refresh () { _needsSignalNames = true; emit refreshSignalNames(); emit refreshSignalValues("all"); } void SeerSignalValuesBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); _editItem(item); } void SeerSignalValuesBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + item->text(4)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerSignalValuesBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = signalsTreeWidget->itemAt(pos); // Construct the menu. QMenu* menu = new QMenu("Options", this); QAction* editAction = menu->addAction("Edit selected"); QAction* copyAction = menu->addAction("Copy selected"); QAction* copyAllAction = menu->addAction("Copy all"); // If no selected item, disable 'selected' copy but allow 'all'. if (item == 0) { editAction->setEnabled(false); copyAction->setEnabled(false); } // Execute the menu. Return if nothing. QAction* action = menu->exec(signalsTreeWidget->mapToGlobal(pos)); if (action == 0) { return; } // Do signal edit. if (action == editAction) { _editItem(item); } // Get selected tree items. QList items; // Get list of 'select' items. if (action == copyAction) { items = signalsTreeWidget->selectedItems(); } // Get list of 'all' items. if (action == copyAllAction) { items = signalsTreeWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard); } // Populate the clipboard. if (items.size() == 0) { return; } QClipboard* clipboard = QGuiApplication::clipboard(); QString text; text += QString("name") + " : " + "stop" + " " + "print" + " " + "pass" + '\n'; for (int i=0; iisHidden() == true) { continue; } text += items[i]->text(0) + " : " + items[i]->text(1) + " " + items[i]->text(2) + " " + items[i] ->text(3) + '\n'; } clipboard->setText(text, QClipboard::Clipboard); clipboard->setText(text, QClipboard::Selection); } void SeerSignalValuesBrowserWidget::handleNewProfile () { if (signalsTreeWidget->topLevelItemCount() == 0) { QMessageBox::warning(this, "Seer", "When creating a profile, Seer needs to be debugging a program.", QMessageBox::Ok); return; } // Build a list of signals. QStringList signalNames; QVector signalEnabled; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* item = signalsTreeWidget->topLevelItem(i); signalNames.push_back(item->text(0)); signalEnabled.push_back(true); } // Bring up the signal profile dialog. SeerSignalProfileDialog dlg(this); dlg.setSignals(signalNames, signalEnabled); if (dlg.exec()) { QString profileName = dlg.profileName(); if (profileName == "") { return; } signalNames = dlg.signalNames(); signalEnabled = dlg.signalEnabled(); signalProfileComboBox->addItem(profileName); signalProfileComboBox->setCurrentText(profileName); writeProfileSettings(profileName, signalNames, signalEnabled); writeSettings(); // Use them. _signalNames = signalNames; _signalEnabled = signalEnabled; handleShowHideSignals(); } } void SeerSignalValuesBrowserWidget::handleModifyProfile () { QString profileName = signalProfileComboBox->currentText(); if (profileName == "allsignals") { QMessageBox::warning(this, "Seer", "The profile 'allsignals' is reserved.\n\nIt can't be modified.", QMessageBox::Ok); return; } // Build a list of signals. QStringList signalNames = _signalNames; QVector signalEnabled = _signalEnabled; // Bring up the signal profile dialog. SeerSignalProfileDialog dlg(this); dlg.setProfileName(profileName); dlg.setSignals(signalNames, signalEnabled); if (dlg.exec()) { // Get the (potenially new) profile name. QString newProfileName = dlg.profileName(); if (newProfileName == "") { return; } signalNames = dlg.signalNames(); signalEnabled = dlg.signalEnabled(); // If it's a new name, add it to the list and switch to it. if (newProfileName != profileName) { signalProfileComboBox->addItem(newProfileName); signalProfileComboBox->setCurrentText(newProfileName); } // Write out the setting changes. writeProfileSettings(newProfileName, signalNames, signalEnabled); writeSettings(); // Use them. _signalNames = signalNames; _signalEnabled = signalEnabled; handleShowHideSignals(); } } void SeerSignalValuesBrowserWidget::handleDeleteProfile () { int index = signalProfileComboBox->currentIndex(); if (index < 0) { return; } QString profileName = signalProfileComboBox->itemText(index); if (profileName == "") { return; } if (profileName == "allsignals") { QMessageBox::warning(this, "Seer", "The profile 'allsignals' is reserved.\n\nIt can't be deleted.", QMessageBox::Ok); return; } QMessageBox::StandardButton ans = QMessageBox::question(this, "Seer", "Delete profile '" + profileName + "'?"); if (ans != QMessageBox::Yes) { return; } // Delete the profile from the settings. deleteProfileSettings(profileName); // Delete the profile from the list of profiles. signalProfileComboBox->removeItem(index); // Write the current settings. writeSettings(); // Switch to the next profile in the list of profiles. index = signalProfileComboBox->currentIndex(); if (index < 0) { return; } handleProfileChanged (index); } void SeerSignalValuesBrowserWidget::handleShowHideSignals () { // If the list is empty, show all. if (_signalNames.count() == 0 || _signalEnabled.count() == 0) { for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = signalsTreeWidget->topLevelItem(i); topItem->setHidden(false); } return; } // There is a list. Hide all, then show which ones are enabled. for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = signalsTreeWidget->topLevelItem(i); topItem->setHidden(true); } for (int i=0; i<_signalNames.count(); i++) { if (_signalEnabled[i] == false) { continue; } QString signalName = _signalNames[i]; QList matches = signalsTreeWidget->findItems(signalName, Qt::MatchExactly, 0); for (int i=0; isetHidden(false); } } } void SeerSignalValuesBrowserWidget::handleProfileChanged (int index) { // Get the profile. QString profileName = signalProfileComboBox->itemText(index); // Build a list of signals. QStringList signalNames; QVector signalEnabled; bool f = readProfileSettings(profileName, signalNames, signalEnabled); if (f == false) { return; } // Use them. _signalNames = signalNames; _signalEnabled = signalEnabled; handleShowHideSignals(); writeSettings(); } void SeerSignalValuesBrowserWidget::writeSettings () { QSettings settings; QStringList signalprofiles; for (int i=0; icount(); i++) { if (signalProfileComboBox->itemText(i) == "allsignals") { continue; } signalprofiles.push_back(signalProfileComboBox->itemText(i)); } settings.beginGroup("signalwindow"); { settings.setValue("signalprofile", signalProfileComboBox->currentText()); settings.setValue("signalprofiles", signalprofiles); } settings.endGroup(); } void SeerSignalValuesBrowserWidget::readSettings () { QSettings settings; settings.beginGroup("signalwindow"); { QString signalProfileName = settings.value("signalprofile").toString(); QStringList signalProfiles = settings.value("signalprofiles").toStringList(); signalProfileComboBox->addItems(signalProfiles); signalProfileComboBox->setCurrentText(signalProfileName); } settings.endGroup(); } void SeerSignalValuesBrowserWidget::writeProfileSettings (const QString& profileName, const QStringList& signalNames, const QVector& signalEnabled) { QSettings settings; QStringList signalEnabledFlags; for (int i=0; i& signalEnabled) { if (profileName == "" || profileName == "allsignals") { signalNames.resize(0); signalEnabled.resize(0); return true; } QSettings settings; settings.beginGroup("signalprofile_" + profileName); { QVariant signalNamesVariant = settings.value("signalnames"); QVariant signalEnabledVariant = settings.value("signalenabled"); QStringList signalEnabledFlags; // Not found? Return with error. if (signalNamesVariant == QVariant() || signalEnabledVariant == QVariant()) { return false; } // Okay, we found it. Populate the containters. signalNames = signalNamesVariant.toStringList(); signalEnabledFlags = signalEnabledVariant.toStringList(); signalEnabled.resize(0); for (int i=0; itext(0), item->text(1), item->text(2), item->text(3), item->text(4)); int ret = dlg.exec(); if (ret == 0) { return; } // The register name could be changed, as well as the value. QString name = dlg.nameText(); QString stop = dlg.stopText(); QString print = dlg.printText(); QString pass = dlg.passText(); if (name == "" || stop == "" || print == "" || pass == "") { return; } // Emit the signal to change the register to the new value. emit setSignalValue(name, stop, print, pass); return; } seer-2.7/src/SeerSignalValuesBrowserWidget.h000066400000000000000000000061661516472651200212260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerSignalValuesBrowserWidget.h" #include #include #include #include #include #include class SeerSignalValuesBrowserWidget : public QWidget, protected Ui::SeerSignalValuesBrowserWidgetForm { Q_OBJECT public: explicit SeerSignalValuesBrowserWidget (QWidget* parent = 0); ~SeerSignalValuesBrowserWidget (); public: public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); void handleContextMenu (const QPoint& pos); void handleNewProfile (); void handleModifyProfile (); void handleDeleteProfile (); void handleShowHideSignals (); void handleProfileChanged (int index); signals: void refreshSignalNames (); void refreshSignalValues (QString names); void setSignalValue (QString name, QString stop, QString print, QString pass); protected: void showEvent (QShowEvent* event); void readSettings (); void writeSettings (); bool readProfileSettings (const QString& profileName, QStringList& signalNames, QVector& signalEnabled); void writeProfileSettings (const QString& profileName, const QStringList& signalNames, const QVector& signalEnabled); void deleteProfileSettings (const QString& profileName); private: void _editItem (QTreeWidgetItem* item); bool _needsSignalNames; QStringList _signalNames; QVector _signalEnabled; QAction* _newProfileAction; QAction* _modifyProfileAction; QAction* _deleteProfileAction; }; seer-2.7/src/SeerSignalValuesBrowserWidget.ui000066400000000000000000000064721516472651200214140ustar00rootroot00000000000000 SeerSignalValuesBrowserWidgetForm 0 0 733 528 Form 0 0 Signal Profile Name. Qt::Horizontal 508 23 Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg Profile 6 false Name Stop Print Pass Description Used QIndexTreeWidget QTreeWidget
QIndexTreeWidget.h
signalProfileComboBox preferencesToolButton signalsTreeWidget
seer-2.7/src/SeerSkipBrowserWidget.cpp000066400000000000000000000216611516472651200200670ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSkipBrowserWidget.h" #include "SeerSkipCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include SeerSkipBrowserWidget::SeerSkipBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets skipTreeWidget->setMouseTracking(true); skipTreeWidget->resizeColumnToContents(0); skipTreeWidget->resizeColumnToContents(1); skipTreeWidget->resizeColumnToContents(2); skipTreeWidget->resizeColumnToContents(3); skipTreeWidget->resizeColumnToContents(4); skipTreeWidget->resizeColumnToContents(5); skipTreeWidget->clear(); skipTreeWidget->setSortingEnabled(false); // Connect things. QObject::connect(skipAddToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleAddToolButton); QObject::connect(skipDeleteToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleDeleteToolButton); QObject::connect(skipEnableToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleEnableToolButton); QObject::connect(skipDisableToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleDisableToolButton); QObject::connect(skipSaveToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleSaveToolButton); QObject::connect(skipLoadToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleLoadToolButton); } SeerSkipBrowserWidget::~SeerSkipBrowserWidget () { } void SeerSkipBrowserWidget::loadSkips () { handleLoadToolButton(false); } void SeerSkipBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,skips=[") && text.endsWith("]")) { skipTreeWidget->clear(); skipTreeWidget->setSortingEnabled(false); skipTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // ^done,skips=[ // {number="1",enable="y",glob="n",file="",re="n",function="std::vector >::back()"}, // {number="2",enable="y",glob="n",file="",re="n",function="std::unique_ptr >::operator*() const"} // ] QString skips_text = Seer::parseFirst(text, "skips=", '[', ']', false); QStringList skips_list = Seer::parse(skips_text, "", '{', '}', false); for (const auto& skip_entry : skips_list) { QString number_text = Seer::parseFirst(skip_entry, "number=", '"', '"', false); QString enable_text = Seer::parseFirst(skip_entry, "enable=", '"', '"', false); QString glob_text = Seer::parseFirst(skip_entry, "glob=", '"', '"', false); QString file_text = Seer::parseFirst(skip_entry, "file=", '"', '"', false); QString re_text = Seer::parseFirst(skip_entry, "re=", '"', '"', false); QString function_text = Seer::parseFirst(skip_entry, "function=", '"', '"', false); // Add the function to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, number_text); item->setText(1, enable_text); item->setText(2, glob_text); item->setText(3, file_text); item->setText(4, re_text); item->setText(5, function_text); skipTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } skipTreeWidget->resizeColumnToContents(0); skipTreeWidget->resizeColumnToContents(1); skipTreeWidget->resizeColumnToContents(2); skipTreeWidget->resizeColumnToContents(3); skipTreeWidget->resizeColumnToContents(4); skipTreeWidget->resizeColumnToContents(5); QApplication::restoreOverrideCursor(); } void SeerSkipBrowserWidget::handleSessionTerminated () { // Delete previous contents. skipTreeWidget->clear(); } void SeerSkipBrowserWidget::handleAddToolButton () { // Create the dialog. SeerSkipCreateDialog dialog(this); // Execute it. if (dialog.exec() != QDialog::Accepted) { return; } // Get result. QString mode = dialog.skipMode(); QString parameters = dialog.skipParameters(); if (mode == "" || parameters == "") { return; } // Send the 'add skip' command. emit addSkip(mode, parameters); } void SeerSkipBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = skipTreeWidget->selectedItems(); // Build ID list. QString ids; for (int i=0; itext(0); } // Send the list of ID's to delete. emit deleteSkips(ids); } void SeerSkipBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = skipTreeWidget->selectedItems(); // Build ID list. QString ids; for (int i=0; itext(0); } // Send the list of ID's to enable. emit enableSkips(ids); } void SeerSkipBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = skipTreeWidget->selectedItems(); // Build ID list. QString ids; for (int i=0; itext(0); } // Send the list of ID's to disable. emit disableSkips(ids); } void SeerSkipBrowserWidget::handleSaveToolButton () { int result = QMessageBox::warning(this, "Seer", QString("Save the skips in the view?\n\nPreviously saved skips will be deleted first."), QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel); if (result == QMessageBox::Cancel) return; QSettings settings; settings.beginWriteArray("gdbskips"); { int i=0; QTreeWidgetItemIterator it(skipTreeWidget); while (*it) { settings.setArrayIndex(i); settings.setValue("number", (*it)->text(0)); settings.setValue("enable", (*it)->text(1)); settings.setValue("glob", (*it)->text(2)); settings.setValue("file", (*it)->text(3)); settings.setValue("re", (*it)->text(4)); settings.setValue("function", (*it)->text(5)); ++i; ++it; } } settings.endArray(); } void SeerSkipBrowserWidget::handleLoadToolButton (bool askIfAlreadyLoaded) { // Warn only if there are existing skips in the view. if (askIfAlreadyLoaded == true && skipTreeWidget->topLevelItemCount() > 0) { int result = QMessageBox::warning(this, "Seer", QString("Load the previously saved skips from settings?\n\nThe existing skips in the view will be deleted first."), QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel); if (result == QMessageBox::Cancel) return; } QSettings settings; if (settings.childGroups().contains("gdbskips")) { emit deleteSkips(""); // Tell gdb to delete all skips. This will update the view. int size = settings.beginReadArray("gdbskips"); for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); QString number = settings.value("number").toString(); QString enable = settings.value("enable").toString(); QString glob = settings.value("glob").toString(); QString file = settings.value("file").toString(); QString re = settings.value("re").toString(); QString function = settings.value("function").toString(); QString mode; QString parameters; // Work on file mode. if (file != "") { if (glob == "y") { parameters = file; mode = "gfile"; }else if (glob == "n") { parameters = file; mode = "file"; } // Work on function mode. } else if (function != "") { if (re == "y") { parameters = function; mode = "rfunction"; }else if (re == "n") { parameters = function; mode = "function"; }else{ continue; } } if (mode == "" || parameters == "") continue; emit addSkip(mode, parameters); } settings.endArray(); } } void SeerSkipBrowserWidget::refresh () { emit refreshSkipList(); } seer-2.7/src/SeerSkipBrowserWidget.h000066400000000000000000000030571516472651200175330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerSkipBrowserWidget.h" class SeerSkipBrowserWidget : public QWidget, protected Ui::SeerSkipBrowserWidgetForm { Q_OBJECT public: explicit SeerSkipBrowserWidget (QWidget* parent = 0); ~SeerSkipBrowserWidget (); void loadSkips (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleSaveToolButton (); void handleLoadToolButton (bool askIfAlreadyLoaded=true); signals: void refreshSkipList (); void addSkip (const QString& skipMode, const QString& skipParameters); void deleteSkips (const QString& skips); void enableSkips (const QString& skips); void disableSkips (const QString& skips); protected: private: }; seer-2.7/src/SeerSkipBrowserWidget.ui000066400000000000000000000116601516472651200177200ustar00rootroot00000000000000 SeerSkipBrowserWidgetForm 0 0 794 528 Form QAbstractItemView::ExtendedSelection 6 Num Enb Glob File RE Function true Add a new skip. :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg true Enable selected skips. :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected skips. :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Delete selected skips. :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 Save skips. ... :/seer/resources/RelaxLightIcons/document-save.svg:/seer/resources/RelaxLightIcons/document-save.svg Load skips. ... :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg seer-2.7/src/SeerSkipCreateDialog.cpp000066400000000000000000000061171516472651200176220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSkipCreateDialog.h" #include "SeerHelpPageDialog.h" #include SeerSkipCreateDialog::SeerSkipCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets fileRadioButton->setChecked(true); fileRadioButton->setFocus(); // Connect things. QObject::connect(modeButtonGroup, QOverload::of(&QButtonGroup::idClicked), this, &SeerSkipCreateDialog::handleModeButtonGroup); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerSkipCreateDialog::handleHelpToolButton); handleModeButtonGroup(); } SeerSkipCreateDialog::~SeerSkipCreateDialog () { } void SeerSkipCreateDialog::handleModeButtonGroup () { // Disable all text fields. We'll enable one later. fileLineEdit->setEnabled(false); fileGlobLineEdit->setEnabled(false); functionLineEdit->setEnabled(false); functionRegexLineEdit->setEnabled(false); // Enable the one that is selected. QAbstractButton* button = modeButtonGroup->checkedButton(); if (button == dynamic_cast(fileRadioButton)) { fileLineEdit->setEnabled(true); fileLineEdit->setFocus(); } else if (button == dynamic_cast(fileGlobRadioButton)) { fileGlobLineEdit->setEnabled(true); fileGlobLineEdit->setFocus(); } else if (button == dynamic_cast(functionRadioButton)) { functionLineEdit->setEnabled(true); functionLineEdit->setFocus(); } else if (button == dynamic_cast(functionRegexRadioButton)) { functionRegexLineEdit->setEnabled(true); functionRegexLineEdit->setFocus(); } } void SeerSkipCreateDialog::handleHelpToolButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/Skips.md"); help->show(); help->raise(); } QString SeerSkipCreateDialog::skipMode () const { // Build a catchpoint specification. QString skipMode; if (fileRadioButton->isChecked()) { skipMode = "file"; }else if (fileGlobRadioButton->isChecked()) { skipMode = "gfile"; }else if (functionRadioButton->isChecked()) { skipMode = "function"; }else if (functionRegexRadioButton->isChecked()) { skipMode = "rfunction"; } qDebug() << skipMode; return skipMode; } QString SeerSkipCreateDialog::skipParameters () const { // Build a catchpoint specification. QString skipParameters; if (fileRadioButton->isChecked()) { skipParameters = fileLineEdit->text(); }else if (fileGlobRadioButton->isChecked()) { skipParameters = fileGlobLineEdit->text(); }else if (functionRadioButton->isChecked()) { skipParameters = functionLineEdit->text(); }else if (functionRegexRadioButton->isChecked()) { skipParameters = functionRegexLineEdit->text(); } qDebug() << skipParameters; return skipParameters; } seer-2.7/src/SeerSkipCreateDialog.h000066400000000000000000000013221516472651200172600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerSkipCreateDialog.h" class SeerSkipCreateDialog : public QDialog, protected Ui::SeerSkipCreateDialogForm { Q_OBJECT public: explicit SeerSkipCreateDialog (QWidget* parent = 0); ~SeerSkipCreateDialog (); QString skipMode () const; QString skipParameters () const; public slots: private slots: void handleModeButtonGroup (); void handleHelpToolButton (); private: }; seer-2.7/src/SeerSkipCreateDialog.ui000066400000000000000000000126561516472651200174620ustar00rootroot00000000000000 SeerSkipCreateDialogForm 0 0 471 253 Create a Skip Specify Skip details. Qt::Horizontal 348 20 :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Filename modeButtonGroup filename Filename (glob) modeButtonGroup filename glob-pattern Function modeButtonGroup function name Function (regex) modeButtonGroup function regex Qt::Vertical 20 17 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok fileRadioButton fileGlobRadioButton functionRadioButton functionRegexRadioButton fileLineEdit fileGlobLineEdit functionLineEdit functionRegexLineEdit helpToolButton buttonBox accepted() SeerSkipCreateDialogForm accept() 248 254 157 274 buttonBox rejected() SeerSkipCreateDialogForm reject() 316 260 286 274 seer-2.7/src/SeerSlashProcDialog.cpp000066400000000000000000000017601516472651200174650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSlashProcDialog.h" SeerSlashProcDialog::SeerSlashProcDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets // Connect things. QObject::connect(processInfoWidget, &QProcessInfoWidget::pidSelected, this, &SeerSlashProcDialog::handlePidSelected); } SeerSlashProcDialog::~SeerSlashProcDialog () { } int SeerSlashProcDialog::selectedPid () const { return processInfoWidget->selectedPid(); } QString SeerSlashProcDialog::selectedName () const { return processInfoWidget->selectedName(); } QString SeerSlashProcDialog::selectedFullname () const { return processInfoWidget->selectedFullname(); } QString SeerSlashProcDialog::selectedCommandLine () const { return processInfoWidget->selectedCommandLine(); } void SeerSlashProcDialog::handlePidSelected() { done(QDialog::Accepted); } seer-2.7/src/SeerSlashProcDialog.h000066400000000000000000000014451516472651200171320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerSlashProcDialog.h" class SeerSlashProcDialog : public QDialog, protected Ui::SeerSlashProcDialogForm { Q_OBJECT public: explicit SeerSlashProcDialog (QWidget* parent = 0); ~SeerSlashProcDialog (); int selectedPid () const; QString selectedName () const; QString selectedFullname () const; QString selectedCommandLine () const; public slots: private slots: void handlePidSelected (); private: }; seer-2.7/src/SeerSlashProcDialog.ui000066400000000000000000000042021516472651200173120ustar00rootroot00000000000000 SeerSlashProcDialogForm 0 0 589 562 Seer - System Processes :/seer/resources/icons/hicolor/32x32/seergdb.png:/seer/resources/icons/hicolor/32x32/seergdb.png Select a process pid. Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok QProcessInfoWidget QWidget
QProcessInfoWidget.h
1
buttonBox accepted() SeerSlashProcDialogForm accept() 248 254 157 274 buttonBox rejected() SeerSlashProcDialogForm reject() 316 260 286 274
seer-2.7/src/SeerSourceBrowserWidget.cpp000066400000000000000000000225101516472651200204130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSourceBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerSourceBrowserWidget::SeerSourceBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets sourceSearchLineEdit->setPlaceholderText("Search regex..."); sourceSearchLineEdit->setClearButtonEnabled(true); _sourceFilesItems = new QTreeWidgetItem; _sourceFilesItems->setText(0, "Source files"); _headerFilesItems = new QTreeWidgetItem; _headerFilesItems->setText(0, "Header files"); _miscFilesItems = new QTreeWidgetItem; _miscFilesItems->setText(0, "Misc files"); sourceTreeWidget->setMouseTracking(true); sourceTreeWidget->addTopLevelItem(_sourceFilesItems); sourceTreeWidget->addTopLevelItem(_headerFilesItems); sourceTreeWidget->addTopLevelItem(_miscFilesItems); sourceTreeWidget->resizeColumnToContents(0); sourceTreeWidget->resizeColumnToContents(1); _sourceFilePatterns = QStringList( {"*.cpp", "*.c", "*.C", "*.f", "*.f90", ".F90", "*.rs", "*.go", "*.ada", "*.adb", "*.s", "*.S"} ); // Default settings. _headerFilePatterns = QStringList( {"*.hpp", "*.h", "*.ads"} ); _miscFilePatterns = QStringList( {"/usr/include/"} ); // Connect things. QObject::connect(sourceTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerSourceBrowserWidget::handleItemDoubleClicked); QObject::connect(sourceTreeWidget, &QTreeWidget::itemEntered, this, &SeerSourceBrowserWidget::handleItemEntered); QObject::connect(sourceSearchLineEdit, &QLineEdit::textChanged, this, &SeerSourceBrowserWidget::handleSearchLineEdit); } SeerSourceBrowserWidget::~SeerSourceBrowserWidget () { } void SeerSourceBrowserWidget::setMiscFilePatterns (const QStringList& patterns) { _miscFilePatterns = patterns; } const QStringList& SeerSourceBrowserWidget::miscFilePatterns () const { return _miscFilePatterns; } void SeerSourceBrowserWidget::setSourceFilePatterns (const QStringList& patterns) { _sourceFilePatterns = patterns; } const QStringList& SeerSourceBrowserWidget::sourceFilePatterns () const { return _sourceFilePatterns; } void SeerSourceBrowserWidget::setHeaderFilePatterns (const QStringList& patterns) { _headerFilePatterns = patterns; } const QStringList& SeerSourceBrowserWidget::headerFilePatterns () const { return _headerFilePatterns; } void SeerSourceBrowserWidget::setIgnoreFilePatterns (const QStringList& patterns) { _ignoreFilePatterns = patterns; } const QStringList& SeerSourceBrowserWidget::ignoreFilePatterns () const { return _ignoreFilePatterns; } void SeerSourceBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,files=[") && text.endsWith("]")) { // ^done,files=[ // {file=\"../sysdeps/x86_64/start.S\",fullname=\"/home/abuild/rpmbuild/BUILD/glibc-2.26/csu/../sysdeps/x86_64/start.S\"}, // {file=\"helloworld.cpp\",fullname=\"/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp\"} // ] // Delete previous files. deleteChildItems(); QString files_text = Seer::parseFirst(text, "files=", '[', ']', false); QStringList files_list = Seer::parse(files_text, "", '{', '}', false); // Set up a map to look for duplicate entries. QMap QMap files; for (const auto& entry_text : files_list) { QString file_text = Seer::parseFirst(entry_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(entry_text, "fullname=", '"', '"', false); //qDebug() << file_text << fullname_text; // Skip duplicates if (files.contains(fullname_text)) { continue; } files.insert(fullname_text, file_text); // Add the file to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, QFileInfo(file_text).fileName()); item->setText(1, fullname_text); // See which pattern the file matches. Put the file under that folder. // If no match, put it in 'misc'. if (Seer::matchesWildcard(ignoreFilePatterns(), fullname_text)) { continue; }else if (Seer::matchesWildcard(miscFilePatterns(), fullname_text)) { _miscFilesItems->addChild(item); }else if (Seer::matchesWildcard(sourceFilePatterns(), fullname_text)) { _sourceFilesItems->addChild(item); }else if (Seer::matchesWildcard(headerFilePatterns(), fullname_text)) { _headerFilesItems->addChild(item); }else{ _miscFilesItems->addChild(item); } } // Always expand the source items. Expanding the other // items are under the user's control. _sourceFilesItems->setExpanded(true); }else{ // Ignore others. } // Sort each item separately. _sourceFilesItems->sortChildren(0, Qt::AscendingOrder); _headerFilesItems->sortChildren(0, Qt::AscendingOrder); _miscFilesItems->sortChildren(0, Qt::AscendingOrder); sourceTreeWidget->resizeColumnToContents(0); sourceTreeWidget->resizeColumnToContents(1); sourceSearchLineEdit->clear(); QApplication::restoreOverrideCursor(); } void SeerSourceBrowserWidget::handleSessionTerminated () { // Delete previous files. deleteChildItems(); } void SeerSourceBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedFile(item->text(0), item->text(1), 0); } void SeerSourceBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); //qDebug() << item->text(0) << column; if (item->text(1) == "") { // Look at the FullName. for (int i=0; icolumnCount(); i++) { // The top-level items do not have a tooltip. item->setToolTip(i, ""); } }else{ item->setToolTip(0, item->text(0) + " : " + item->text(1)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } } void SeerSourceBrowserWidget::handleSearchLineEdit (const QString& text) { // Set everything to a normal font. If there is no search text, unhide everything. // If there is search text, hide everything so the matching ones can be unhidden later on. QTreeWidgetItemIterator it(sourceTreeWidget); if (*it) { QFont f0 = (*it)->font(0); QFont f1 = (*it)->font(1); f0.setBold(false); f1.setBold(false); if (text == "") { while (*it) { (*it)->setHidden(false); // No search text, unhide everything. (*it)->setFont(0,f0); (*it)->setFont(1,f1); ++it; } }else{ while (*it) { (*it)->setHidden(true); // Has serach text, hide everything. Matching items to be unhidden below. (*it)->setFont(0,f0); (*it)->setFont(1,f1); ++it; } } } // Set selected items to a bold font and unhidden. Move to the first match. if (text != "") { _sourceFilesItems->setHidden(false); _headerFilesItems->setHidden(false); _miscFilesItems->setHidden(false); QList matches; matches = sourceTreeWidget->findItems(text, Qt::MatchRegularExpression | Qt::MatchRecursive, 0); QList::const_iterator it = matches.begin(); QList::const_iterator e = matches.end(); if (it != e) { sourceTreeWidget->setCurrentItem(*it); QFont f0 = (*it)->font(0); QFont f1 = (*it)->font(1); f0.setBold(true); f1.setBold(true); while (it != e) { if (*it != _sourceFilesItems && *it != _headerFilesItems && *it != _miscFilesItems) { (*it)->setHidden(false); (*it)->setFont(0,f0); (*it)->setFont(1,f1); } it++; } } // Always expand the source items. Expanding the other // items are under the user's control. _sourceFilesItems->setExpanded(true); //qDebug() << text << matches.size(); } sourceTreeWidget->resizeColumnToContents(0); sourceTreeWidget->resizeColumnToContents(1); } void SeerSourceBrowserWidget::refresh () { emit refreshSourceList(); } void SeerSourceBrowserWidget::deleteChildItems () { // Delete child items. Leave top-level 'Source', 'Header', and 'Misc'. foreach (auto i, _sourceFilesItems->takeChildren()) { delete i; } foreach (auto i, _headerFilesItems->takeChildren()) { delete i; } foreach (auto i, _miscFilesItems->takeChildren()) { delete i; } } seer-2.7/src/SeerSourceBrowserWidget.h000066400000000000000000000045251516472651200200660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerSourceBrowserWidget.h" class SeerSourceBrowserWidget : public QWidget, protected Ui::SeerSourceBrowserWidgetForm { Q_OBJECT public: explicit SeerSourceBrowserWidget (QWidget* parent = 0); ~SeerSourceBrowserWidget (); void setMiscFilePatterns (const QStringList& patterns); const QStringList& miscFilePatterns () const; void setSourceFilePatterns (const QStringList& patterns); const QStringList& sourceFilePatterns () const; void setHeaderFilePatterns (const QStringList& patterns); const QStringList& headerFilePatterns () const; void setIgnoreFilePatterns (const QStringList& patterns); const QStringList& ignoreFilePatterns () const; public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (const QString& text); void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshSourceList (); void selectedFile (QString file, QString fullname, int lineno); protected: void deleteChildItems (); private: QTreeWidgetItem* _sourceFilesItems; QTreeWidgetItem* _headerFilesItems; QTreeWidgetItem* _miscFilesItems; QStringList _sourceFilePatterns; QStringList _headerFilePatterns; QStringList _miscFilePatterns; QStringList _ignoreFilePatterns; }; seer-2.7/src/SeerSourceBrowserWidget.ui000066400000000000000000000026171516472651200202540ustar00rootroot00000000000000 SeerSourceBrowserWidgetForm 0 0 730 698 Source Browser 2 File Full Name Search in the list of files. "*" is allowed. QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerSourceConfigPage.cpp000066400000000000000000000355431516472651200176400ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSourceConfigPage.h" #include #include #include #include #include SeerSourceConfigPage::SeerSourceConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Setup the widgets alternateDirectoriesTreeWidget->clear(); alternateDirectoriesTreeWidget->setSortingEnabled(false); alternateDirectoriesTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); alternateDirectoriesTreeWidget->resizeColumnToContents(0); // directory ignoreFilePatternsTreeWidget->clear(); ignoreFilePatternsTreeWidget->setSortingEnabled(false); ignoreFilePatternsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); ignoreFilePatternsTreeWidget->resizeColumnToContents(0); // file pattern miscFilePatternsTreeWidget->clear(); miscFilePatternsTreeWidget->setSortingEnabled(false); miscFilePatternsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); miscFilePatternsTreeWidget->resizeColumnToContents(0); // file pattern sourceFilePatternsTreeWidget->clear(); sourceFilePatternsTreeWidget->setSortingEnabled(false); sourceFilePatternsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); sourceFilePatternsTreeWidget->resizeColumnToContents(0); // file pattern headerFilePatternsTreeWidget->clear(); headerFilePatternsTreeWidget->setSortingEnabled(false); headerFilePatternsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); headerFilePatternsTreeWidget->resizeColumnToContents(0); // file pattern // Connect things. QObject::connect(addAlternateDirectoryToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddAlternateButtonClicked); QObject::connect(moveUpAlternateDirectoriesToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleUpAlternateButtonClicked); QObject::connect(moveDownAlternateDirectoriesToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDownAlternateButtonClicked); QObject::connect(deleteAlternateDirectoriesToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteAlternateButtonClicked); QObject::connect(addIgnoreFilePatternToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddIgnorePatternButtonClicked); QObject::connect(deleteIgnoreFilePatternesToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteIgnorePatternButtonClicked); QObject::connect(addMiscFilePatternToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddMiscPatternButtonClicked); QObject::connect(deleteMiscFilePatternsToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteMiscPatternButtonClicked); QObject::connect(addSourceFilePatternToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddSourcePatternButtonClicked); QObject::connect(deleteSourceFilePatternsToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteSourcePatternButtonClicked); QObject::connect(addHeaderFilePatternToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddHeaderPatternButtonClicked); QObject::connect(deleteHeaderFilePatternsToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteHeaderPatternButtonClicked); // Setup the defaults. reset(); } SeerSourceConfigPage::~SeerSourceConfigPage() { } void SeerSourceConfigPage::setAlternateDirectories (const QStringList& alternateDirectories) { alternateDirectoriesTreeWidget->clear(); QStringListIterator iter(alternateDirectories); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); alternateDirectoriesTreeWidget->addTopLevelItem(topItem); } alternateDirectoriesTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::alternateDirectories () const { QStringList list; QTreeWidgetItemIterator iter(alternateDirectoriesTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::setIgnoreFilePatterns (const QStringList& filePatterns) { ignoreFilePatternsTreeWidget->clear(); QStringListIterator iter(filePatterns); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); ignoreFilePatternsTreeWidget->addTopLevelItem(topItem); } ignoreFilePatternsTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::ignoreFilePatterns () const { QStringList list; QTreeWidgetItemIterator iter(ignoreFilePatternsTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::setMiscFilePatterns (const QStringList& filePatterns) { miscFilePatternsTreeWidget->clear(); QStringListIterator iter(filePatterns); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); miscFilePatternsTreeWidget->addTopLevelItem(topItem); } miscFilePatternsTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::miscFilePatterns () const { QStringList list; QTreeWidgetItemIterator iter(miscFilePatternsTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::setSourceFilePatterns (const QStringList& filePatterns) { sourceFilePatternsTreeWidget->clear(); QStringListIterator iter(filePatterns); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); sourceFilePatternsTreeWidget->addTopLevelItem(topItem); } sourceFilePatternsTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::sourceFilePatterns () const { QStringList list; QTreeWidgetItemIterator iter(sourceFilePatternsTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::setHeaderFilePatterns (const QStringList& filePatterns) { headerFilePatternsTreeWidget->clear(); QStringListIterator iter(filePatterns); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); headerFilePatternsTreeWidget->addTopLevelItem(topItem); } headerFilePatternsTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::headerFilePatterns () const { QStringList list; QTreeWidgetItemIterator iter(headerFilePatternsTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::reset () { QStringList alternateDirectories; alternateDirectories << "./"; setAlternateDirectories(alternateDirectories); setIgnoreFilePatterns(QStringList()); setMiscFilePatterns( {"/usr/include/*"} ); setSourceFilePatterns( {"*.cpp", "*.c", "*.C", "*.f", "*.f90", "*.F90", "*.rs", "*.go", "*.ada", "*.adb"} ); setHeaderFilePatterns( {"*.hpp", "*.h", "*.ads"} ); } void SeerSourceConfigPage::handleAddAlternateButtonClicked () { // Ask for the alternate directory to add to the list. QString directory = QFileDialog::getExistingDirectory(this, "Seer - Enter an alternate directory", QString(), QFileDialog::ShowDirsOnly|QFileDialog::DontUseNativeDialog); if (directory == "") { return; } // Get the selected items, if any. QList matches = alternateDirectoriesTreeWidget->selectedItems(); // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, directory); // If there is something selected, add the new item before the first selected item. if (matches.count() > 0) { int index = alternateDirectoriesTreeWidget->indexOfTopLevelItem(matches[0]); alternateDirectoriesTreeWidget->insertTopLevelItem(index, topItem); // Otherwise, just add it to the end of the list. }else{ alternateDirectoriesTreeWidget->addTopLevelItem(topItem); } // Resize the columns and select the item we just added. alternateDirectoriesTreeWidget->resizeColumnToContents(0); alternateDirectoriesTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleUpAlternateButtonClicked () { // Get the selected items. QList matches = alternateDirectoriesTreeWidget->selectedItems(); // Loop through them from low to high. for (int i=0; iindexOfTopLevelItem(matches[i]); // Stop if the item is at the top of the list. if (index <= 0) { break; } // Steel it from the treeWidget. QTreeWidgetItem* topItem = alternateDirectoriesTreeWidget->takeTopLevelItem(index); // Re-add it to the moved up position. alternateDirectoriesTreeWidget->insertTopLevelItem(index-1, topItem); } // Re-selected the items. alternateDirectoriesTreeWidget->clearSelection(); for (int i=0; isetSelected(true); } // Resize the columns. alternateDirectoriesTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleDownAlternateButtonClicked () { // Get the selected items. QList matches = alternateDirectoriesTreeWidget->selectedItems(); // Loop through them from high to low. for (int i=matches.count()-1; i>=0; i--) { int index = alternateDirectoriesTreeWidget->indexOfTopLevelItem(matches[i]); // Stop if the item is at the bottom of the list. if (index >= alternateDirectoriesTreeWidget->topLevelItemCount()-1) { break; } // Steel it from the treeWidget. QTreeWidgetItem* topItem = alternateDirectoriesTreeWidget->takeTopLevelItem(index); // Re-add it to the moved down position. alternateDirectoriesTreeWidget->insertTopLevelItem(index+1, topItem); } // Re-selected the items. alternateDirectoriesTreeWidget->clearSelection(); for (int i=0; isetSelected(true); } // Resize the columns. alternateDirectoriesTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleDeleteAlternateButtonClicked () { QList matches = alternateDirectoriesTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. alternateDirectoriesTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleAddIgnorePatternButtonClicked () { // Ask for the ignore directory to add to the list. QString directory = QInputDialog::getText(this, "Seer - Enter a directory to ignore", "Ignore directory:"); if (directory == "") { return; } // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, directory); // Just add it to the end of the list. ignoreFilePatternsTreeWidget->addTopLevelItem(topItem); // Resize the columns and select the item we just added. ignoreFilePatternsTreeWidget->resizeColumnToContents(0); ignoreFilePatternsTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleDeleteIgnorePatternButtonClicked () { QList matches = ignoreFilePatternsTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. ignoreFilePatternsTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleAddMiscPatternButtonClicked () { // Ask for the pattern to add to the list. QString pattern = QInputDialog::getText(this, "Seer - Enter a file pattern", "Misc file pattern:"); if (pattern == "") { return; } // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, pattern); // Just add it to the end of the list. miscFilePatternsTreeWidget->addTopLevelItem(topItem); // Resize the columns and select the item we just added. miscFilePatternsTreeWidget->resizeColumnToContents(0); miscFilePatternsTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleDeleteMiscPatternButtonClicked () { QList matches = miscFilePatternsTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. miscFilePatternsTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleAddSourcePatternButtonClicked () { // Ask for the pattern to add to the list. QString pattern = QInputDialog::getText(this, "Seer - Enter a file pattern", "Source file pattern:"); if (pattern == "") { return; } // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, pattern); // Just add it to the end of the list. sourceFilePatternsTreeWidget->addTopLevelItem(topItem); // Resize the columns and select the item we just added. sourceFilePatternsTreeWidget->resizeColumnToContents(0); sourceFilePatternsTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleDeleteSourcePatternButtonClicked () { QList matches = sourceFilePatternsTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. sourceFilePatternsTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleAddHeaderPatternButtonClicked () { // Ask for the pattern to add to the list. QString pattern = QInputDialog::getText(this, "Seer - Enter a file pattern", "Header file pattern:"); if (pattern == "") { return; } // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, pattern); // Just add it to the end of the list. headerFilePatternsTreeWidget->addTopLevelItem(topItem); // Resize the columns and select the item we just added. headerFilePatternsTreeWidget->resizeColumnToContents(0); headerFilePatternsTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleDeleteHeaderPatternButtonClicked () { QList matches = headerFilePatternsTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. headerFilePatternsTreeWidget->resizeColumnToContents(0); } seer-2.7/src/SeerSourceConfigPage.h000066400000000000000000000052341516472651200172770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerSourceConfigPage.h" class SeerSourceConfigPage : public QWidget, public Ui::SeerSourceConfigPage { Q_OBJECT public: explicit SeerSourceConfigPage (QWidget* parent = 0); ~SeerSourceConfigPage (); void setAlternateDirectories (const QStringList& alternateDirectories); QStringList alternateDirectories () const; void setIgnoreFilePatterns (const QStringList& filePatterns); QStringList ignoreFilePatterns () const; void setMiscFilePatterns (const QStringList& filePatterns); QStringList miscFilePatterns () const; void setSourceFilePatterns (const QStringList& filePatterns); QStringList sourceFilePatterns () const; void setHeaderFilePatterns (const QStringList& filePatterns); QStringList headerFilePatterns () const; void reset (); protected slots: void handleAddAlternateButtonClicked (); void handleUpAlternateButtonClicked (); void handleDownAlternateButtonClicked (); void handleDeleteAlternateButtonClicked (); void handleAddIgnorePatternButtonClicked (); void handleDeleteIgnorePatternButtonClicked (); void handleAddMiscPatternButtonClicked (); void handleDeleteMiscPatternButtonClicked (); void handleAddSourcePatternButtonClicked (); void handleDeleteSourcePatternButtonClicked (); void handleAddHeaderPatternButtonClicked (); void handleDeleteHeaderPatternButtonClicked (); private: }; seer-2.7/src/SeerSourceConfigPage.ui000066400000000000000000000577401516472651200174760ustar00rootroot00000000000000 SeerSourceConfigPage 0 0 804 852 SeerSourceConfigPage Source Lookup 0 0 false Alternate Directories Add a new directory. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Move up selected directories. ... :/seer/resources/RelaxLightIcons/go-up.svg:/seer/resources/RelaxLightIcons/go-up.svg Move down selected directories. ... :/seer/resources/RelaxLightIcons/go-down.svg:/seer/resources/RelaxLightIcons/go-down.svg Delete selected directories. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 0 0 false Ignore Directories/Files Add a new directory. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Delete selected directories. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 Source Browser Filtering 0 0 false Misc Directories/Files Add a new file pattern. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Delete selected file patterns. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 0 0 false Source Directories/Files Add a new file pattern. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Delete selected file patterns. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 0 0 false Header Directories/Files Add a new file pattern. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Delete selected file patterns. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 0 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Source Lookup.</span></p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If Seer can't find the source file in the directory that gdb knows of, then Seer will look in these <span style=" text-decoration: underline;">Alternate</span> directories in the order they appear. If Seer still can't find the source file, it will prompt you to enter the location. If you don't want to be prompted, add the directory path to the list of <span style=" text-decoration: underline;">Ignore</span> directories. Wildcarding is allowed when adding an ignore entry.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Source Browser Filtering.</span></p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These settings affect how Seer sorts all the source and include filenames that a program references. These files appear in the Source Browser in one of three catagegories: <span style=" text-decoration: underline;">Source</span>, <span style=" text-decoration: underline;">Header</span>, or <span style=" text-decoration: underline;">Misc</span>.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Files that match the <span style=" text-decoration: underline;">Ignore</span> list will not be sorted into any catagegory.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">An entry can be a directory path, filename, or filename extension. Wildcarding is allowed and is encouraged for fine control. A directory path must end with &quot;/*&quot;.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Seer looks at the debug information for the program to create a list of all files the program references. Some are applicable to the the program, others are not.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ones that are not, should be sorted into <span style=" text-decoration: underline;">Misc</span>. These can be system header files or system source files. The ones that are, are sorted into <span style=" text-decoration: underline;">Source</span> or <span style=" text-decoration: underline;">Header</span>, depending on the sorting settings.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For each file, it is compared to the sort patterns in the <span style=" text-decoration: underline;">Misc</span> category, then the <span style=" text-decoration: underline;">Source</span>, then the <span style=" text-decoration: underline;">Header</span> category. It is put into the first one that matches. If it doesn't match any, it is put into the <span style=" text-decoration: underline;">Misc</span> category.</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For example, <span style=" text-decoration: underline;">Source</span> should have entries like:</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.cpp</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.c</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.go</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.asm</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline;">Header</span> should have entries like:</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.h</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline;">Misc</span> should have entries like:</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> /usr/include/*</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline;">Ignore</span> should have entries like:</p> <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> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> /home/abuild/*</p> <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> <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> seer-2.7/src/SeerSourceHighlighter.cpp000066400000000000000000000044241516472651200200660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSourceHighlighter.h" #include "SeerOdinSourceHighlighter.h" #include "SeerCppSourceHighlighter.h" #include "SeerRustSourceHighlighter.h" SeerSourceHighlighter::SeerSourceHighlighter (QTextDocument* parent) : QSyntaxHighlighter(parent) {} const SeerHighlighterSettings& SeerSourceHighlighter::highlighterSettings() { return _highlighterSettings; } SeerSourceHighlighter* SeerSourceHighlighter::getSourceHighlighter(QString const& file, SeerHighlighterSettings settings) { QRegularExpression cpp_re("(?:" + settings.cppSourceSuffixes() + ")$"); if (file.contains(cpp_re)) { return new SeerCppSourceHighlighter(0); } QRegularExpression odin_re("(?:" + settings.odinSourceSuffixes() + ")$"); if (file.contains(odin_re)) { return new SeerOdinSourceHighlighter(0); } QRegularExpression rust_re("(?:" + settings.rustSourceSuffixes() + ")$"); if (file.contains(rust_re)) { return new SeerRustSourceHighlighter(0); } return nullptr; } void SeerSourceHighlighter::highlightBlock (const QString& text) { for (const HighlightingRule& rule : std::as_const(_highlightingRules)) { QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); while (matchIterator.hasNext()) { QRegularExpressionMatch match = matchIterator.next(); setFormat(match.capturedStart(), match.capturedLength(), rule.format); } } setCurrentBlockState(0); int startIndex = 0; if (previousBlockState() != 1) { startIndex = text.indexOf(_commentStartExpression); } while (startIndex >= 0) { QRegularExpressionMatch match = _commentEndExpression.match(text, startIndex); int endIndex = match.capturedStart(); int commentLength = 0; if (endIndex == -1) { setCurrentBlockState(1); commentLength = text.length() - startIndex; }else{ commentLength = endIndex - startIndex + match.capturedLength(); } setFormat(startIndex, commentLength, _multiLineCommentFormat); startIndex = text.indexOf(_commentStartExpression, startIndex + commentLength); } } seer-2.7/src/SeerSourceHighlighter.h000066400000000000000000000030111516472651200175220ustar00rootroot00000000000000/* ## Syntax highlighting To add syntax highlighting to a language. Subclass `SeerSourceHighlighter` and then instatiate your highlighter by matching the filename in the `getSourceHighlighter` function. */ #pragma once #include "SeerHighlighterSettings.h" #include #include class SeerSourceHighlighter : public QSyntaxHighlighter { Q_OBJECT public: SeerSourceHighlighter(QTextDocument *parent = 0); const SeerHighlighterSettings& highlighterSettings (); virtual void setHighlighterSettings (SeerHighlighterSettings const& settings) = 0; static SeerSourceHighlighter* getSourceHighlighter (QString const& file, SeerHighlighterSettings settings); protected: virtual void highlightBlock (const QString &text); SeerHighlighterSettings _highlighterSettings; QTextCharFormat _singleLineCommentFormat; QTextCharFormat _multiLineCommentFormat; QRegularExpression _commentStartExpression; QRegularExpression _commentEndExpression; QTextCharFormat _keywordFormat; QTextCharFormat _classFormat; QTextCharFormat _quotationFormat; QTextCharFormat _functionFormat; struct HighlightingRule { QRegularExpression pattern; QTextCharFormat format; }; QVector _highlightingRules{}; }; seer-2.7/src/SeerSourceLoadErrorDialog.ui000066400000000000000000000104501516472651200204700ustar00rootroot00000000000000 Dialog 0 0 638 322 Dialog Error Could not find: /path/to/some/sourcefile. Its location may have changed. How would you like to handle this? :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/HighContrast/document-open.svg For this file, enter an alternate directory to look in. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/HighContrast/document-open.svg /path/that/seer/is/expecting /path/to/an/alternate/directory /path/to/actual/directory For this file and future files, enter a directory mapping between expected and actual. QFrame::Sunken Qt::Horizontal Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() Dialog accept() 248 254 157 274 buttonBox rejected() Dialog reject() 316 260 286 274 seer-2.7/src/SeerSourceSymbolLibraryManagerWidget.cpp000066400000000000000000000231301516472651200230540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSourceSymbolLibraryManagerWidget.h" #include "SeerHelpPageDialog.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include SeerSourceSymbolLibraryManagerWidget::SeerSourceSymbolLibraryManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(false); _sourceBrowserWidget = new SeerSourceBrowserWidget(this); _functionBrowserWidget = new SeerFunctionBrowserWidget(this); _typeBrowserWidget = new SeerTypeBrowserWidget(this); _staticBrowserWidget = new SeerStaticBrowserWidget(this); _libraryBrowserWidget = new SeerLibraryBrowserWidget(this); _adaExceptionsBrowserWidget = new SeerAdaExceptionsBrowserWidget(this); _skipBrowserWidget = new SeerSkipBrowserWidget(this); tabWidget->addTab(_sourceBrowserWidget, "Source"); tabWidget->addTab(_functionBrowserWidget, "Functions"); tabWidget->addTab(_typeBrowserWidget, "Types"); tabWidget->addTab(_staticBrowserWidget, "Statics"); tabWidget->addTab(_libraryBrowserWidget, "Libraries"); tabWidget->addTab(_adaExceptionsBrowserWidget, "AdaExceptions"); tabWidget->addTab(_skipBrowserWidget, "Skips"); QToolButton* tabsContextMenuButton = new QToolButton(tabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QToolButton* refreshToolButton = new QToolButton(tabWidget); refreshToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/view-refresh.svg")); refreshToolButton->setToolTip("Refresh the source/symbol/library information."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on source/symbol/library information."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); hcontainer->addWidget(refreshToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Restore tab ordering. readSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerSourceSymbolLibraryManagerWidget::handleTabsContextMenuButtonClicked); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerSourceSymbolLibraryManagerWidget::handleRefreshToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerSourceSymbolLibraryManagerWidget::handleHelpToolButtonClicked); QObject::connect(tabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerSourceSymbolLibraryManagerWidget::handleTabMoved); QObject::connect(tabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerSourceSymbolLibraryManagerWidget::handleTabChanged); } SeerSourceSymbolLibraryManagerWidget::~SeerSourceSymbolLibraryManagerWidget () { } SeerSourceBrowserWidget* SeerSourceSymbolLibraryManagerWidget::sourceBrowserWidget () { return _sourceBrowserWidget; } SeerFunctionBrowserWidget* SeerSourceSymbolLibraryManagerWidget::functionBrowserWidget () { return _functionBrowserWidget; } SeerTypeBrowserWidget* SeerSourceSymbolLibraryManagerWidget::typeBrowserWidget () { return _typeBrowserWidget; } SeerStaticBrowserWidget* SeerSourceSymbolLibraryManagerWidget::staticBrowserWidget () { return _staticBrowserWidget; } SeerLibraryBrowserWidget* SeerSourceSymbolLibraryManagerWidget::libraryBrowserWidget () { return _libraryBrowserWidget; } SeerAdaExceptionsBrowserWidget* SeerSourceSymbolLibraryManagerWidget::adaExceptionsBrowserWidget () { return _adaExceptionsBrowserWidget; } SeerSkipBrowserWidget* SeerSourceSymbolLibraryManagerWidget::skipBrowserWidget () { return _skipBrowserWidget; } void SeerSourceSymbolLibraryManagerWidget::handleRefreshToolButtonClicked () { sourceBrowserWidget()->refresh(); functionBrowserWidget()->refresh(); typeBrowserWidget()->refresh(); staticBrowserWidget()->refresh(); libraryBrowserWidget()->refresh(); adaExceptionsBrowserWidget()->refresh(); skipBrowserWidget()->refresh(); } void SeerSourceSymbolLibraryManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/SourceSymbolLibraryInfoBrowser.md"); help->show(); help->raise(); } void SeerSourceSymbolLibraryManagerWidget::handleTabMoved (int from, int to) { Q_UNUSED(from); Q_UNUSED(to); writeSettings(); } void SeerSourceSymbolLibraryManagerWidget::handleTabChanged (int index) { Q_UNUSED(index); writeSettings(); } void SeerSourceSymbolLibraryManagerWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(tabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(tabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = tabWidget->tabBar()->tabText(tabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Write settings. QSettings settings; settings.beginGroup("sourcemanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerSourceSymbolLibraryManagerWidget::readSettings () { // Can't move things? if (tabWidget->tabBar()->isMovable() == false) { return; } // Read tab order from settings. QSettings settings; QStringList tabs; QStringList visible; QString current; settings.beginGroup("sourcemanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (tabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { tabWidget->tabBar()->moveTab(tb, i); } } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { tabWidget->setTabVisible(i,false); }else{ tabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (tabWidget->tabBar()->tabText(i) == current) { tabWidget->setCurrentIndex(i); break; } } }else{ tabWidget->setCurrentIndex(0); } } void SeerSourceSymbolLibraryManagerWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < tabWidget->count(); i++) { QString title = tabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(tabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (tabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { tabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ tabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } seer-2.7/src/SeerSourceSymbolLibraryManagerWidget.h000066400000000000000000000054371516472651200225330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerSourceBrowserWidget.h" #include "SeerFunctionBrowserWidget.h" #include "SeerTypeBrowserWidget.h" #include "SeerStaticBrowserWidget.h" #include "SeerLibraryBrowserWidget.h" #include "SeerAdaExceptionsBrowserWidget.h" #include "SeerSkipBrowserWidget.h" #include #include "ui_SeerSourceSymbolLibraryManagerWidget.h" class SeerSourceSymbolLibraryManagerWidget : public QWidget, protected Ui::SeerSourceSymbolLibraryManagerWidgetForm { Q_OBJECT public: explicit SeerSourceSymbolLibraryManagerWidget (QWidget* parent = 0); ~SeerSourceSymbolLibraryManagerWidget (); SeerSourceBrowserWidget* sourceBrowserWidget (); SeerFunctionBrowserWidget* functionBrowserWidget (); SeerTypeBrowserWidget* typeBrowserWidget (); SeerStaticBrowserWidget* staticBrowserWidget (); SeerLibraryBrowserWidget* libraryBrowserWidget (); SeerAdaExceptionsBrowserWidget* adaExceptionsBrowserWidget (); SeerSkipBrowserWidget* skipBrowserWidget (); protected: void writeSettings (); void readSettings (); private slots: void handleRefreshToolButtonClicked (); void handleHelpToolButtonClicked (); void handleTabMoved (int from, int to); void handleTabChanged (int index); void handleTabsContextMenuButtonClicked (); private: SeerSourceBrowserWidget* _sourceBrowserWidget; SeerFunctionBrowserWidget* _functionBrowserWidget; SeerTypeBrowserWidget* _typeBrowserWidget; SeerStaticBrowserWidget* _staticBrowserWidget; SeerLibraryBrowserWidget* _libraryBrowserWidget; SeerAdaExceptionsBrowserWidget* _adaExceptionsBrowserWidget; SeerSkipBrowserWidget* _skipBrowserWidget; QTabWidget* _dumpTab; }; seer-2.7/src/SeerSourceSymbolLibraryManagerWidget.ui000066400000000000000000000031651516472651200227150ustar00rootroot00000000000000 SeerSourceSymbolLibraryManagerWidgetForm 0 0 771 479 Form 0 0 0 0 3 font-weight: bold; Source/Symbol/Library Info Qt::PlainText -1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
seer-2.7/src/SeerStackArgumentsBrowserWidget.cpp000066400000000000000000000572231516472651200221170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackArgumentsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerStackArgumentsBrowserWidget::SeerStackArgumentsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets argumentsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); argumentsTreeWidget->setMouseTracking(true); argumentsTreeWidget->setSortingEnabled(false); argumentsTreeWidget->resizeColumnToContents(0); // level argumentsTreeWidget->resizeColumnToContents(1); // Name argumentsTreeWidget->resizeColumnToContents(2); // Value argumentsTreeWidget->resizeColumnToContents(3); // used argumentsTreeWidget->setColumnHidden(3, true); // Hide the 'used' column. argumentsTreeWidget->clear(); // Connect things. QObject::connect(argumentsTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerStackArgumentsBrowserWidget::handleContextMenu); QObject::connect(argumentsTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerStackArgumentsBrowserWidget::handleItemCollapsed); QObject::connect(argumentsTreeWidget, &QTreeWidget::itemExpanded, this, &SeerStackArgumentsBrowserWidget::handleItemExpanded); QObject::connect(argumentsTreeWidget, &QTreeWidget::itemEntered, this, &SeerStackArgumentsBrowserWidget::handleItemEntered); } SeerStackArgumentsBrowserWidget::~SeerStackArgumentsBrowserWidget () { } void SeerStackArgumentsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,stack-args=[") && text.endsWith("]")) { //argumentsTreeWidget->clear(); // ^done,stack-args=[ // frame={level="0",args=[ // {name="message",value="\"Hello, World!\""} // ]}, // frame={level="1",args=[ // {name="argc",value="1"}, // {name="argv",value="0x7fffffffd5b8"} // ]} // ] // "level=\"0\",args=[{name=\"message\",value=\"\\\"Hello, World!\\\"\"}]", // "level=\"1\",args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\"0x7fffffffd5b8\"}]" QStringList frame_list = Seer::parse(text, "frame=", '{', '}', false); // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(argumentsTreeWidget); while (*it) { (*it)->setText(3, "unused"); ++it; } for ( const auto& frame_text : frame_list ) { QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString args_text = Seer::parseFirst(frame_text, "args=", '[', ']', false); QStringList namevalue_list = Seer::parse(args_text, "", '{', '}', false); QList matches = argumentsTreeWidget->findItems(level_text, Qt::MatchExactly, 0); QTreeWidgetItem* topItem = 0; // Use an existing level. if (matches.count() > 0) { topItem = matches[0]; topItem->setText(3, "reused"); // Add the new level to the tree. }else{ topItem = new QTreeWidgetItem; topItem->setText(0, level_text); topItem->setText(3, "new"); argumentsTreeWidget->addTopLevelItem(topItem); } // Get the argument names and values for the level. for ( const auto& namevalue_text : namevalue_list ) { QString name_text = Seer::parseFirst(namevalue_text, "name=", '"', '"', false); QString value_text = Seer::parseFirst(namevalue_text, "value=", '"', '"', false); // Populate the tree. handleItemCreate(topItem, "", name_text, value_text); } // Expand all items for the level. argumentsTreeWidget->expandItem(topItem); } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. // Don't use qDeleteAll() here. It doesn't work as expected for items that are "found". // Instead, get a list of matches and delete them from the bottom up. QList matches = argumentsTreeWidget->findItems("unused", Qt::MatchExactly|Qt::MatchRecursive, 3); while (matches.isEmpty() == false) { foreach (QTreeWidgetItem* item, matches) { if (item->childCount() == 0) { QTreeWidgetItem* parent = item->parent(); if (parent) { parent->removeChild(item); } bool f = matches.removeOne(item); Q_ASSERT(f != false); delete item; break; } } } }else{ // Ignore others. } argumentsTreeWidget->resizeColumnToContents(0); argumentsTreeWidget->resizeColumnToContents(1); argumentsTreeWidget->resizeColumnToContents(2); argumentsTreeWidget->resizeColumnToContents(3); QApplication::restoreOverrideCursor(); } void SeerStackArgumentsBrowserWidget::handleStoppingPointReached () { refresh(); } void SeerStackArgumentsBrowserWidget::handleSessionTerminated () { // Delete previous contents. argumentsTreeWidget->clear(); } void SeerStackArgumentsBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshStackArguments(); } void SeerStackArgumentsBrowserWidget::handleContextMenu (const QPoint& pos) { QTreeWidgetItem* item = argumentsTreeWidget->itemAt(pos); if (item == 0) { return; } if (item->text(1) == "") { return; } QAction* addVariableLoggerExpressionAction; QAction* addVariableLoggerAsteriskExpressionAction; QAction* addVariableLoggerAmpersandExpressionAction; QAction* addVariableLoggerAsteriskAmpersandExpressionAction; QAction* addVariableLoggerObjcExpressionAction; QAction* addVariableTrackerExpressionAction; QAction* addVariableTrackerAsteriskExpressionAction; QAction* addVariableTrackerAmpersandExpressionAction; QAction* addVariableTrackerAsteriskAmpersandExpressionAction; QAction* addVariableTrackerObjcExpressionAction; QAction* addMemoryVisualizerAction; QAction* addMemoryAsteriskVisualizerAction; QAction* addMemoryAmpersandVisualizerAction; QAction* addArrayVisualizerAction; QAction* addArrayAsteriskVisualizerAction; QAction* addArrayAmpersandVisualizerAction; QAction* addMatrixVisualizerAction; QAction* addMatrixAsteriskVisualizerAction; QAction* addMatrixAmpersandVisualizerAction; QAction* addStructVisualizerAction; QAction* addStructAsteriskVisualizerAction; QAction* addStructAmpersandVisualizerAction; addVariableLoggerExpressionAction = new QAction(QString("%1").arg(item->text(1))); addVariableLoggerAsteriskExpressionAction = new QAction(QString("*%1").arg(item->text(1))); addVariableLoggerAmpersandExpressionAction = new QAction(QString("&&%1").arg(item->text(1))); addVariableLoggerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(item->text(1))); addVariableLoggerObjcExpressionAction = new QAction(QString("(objc)%1").arg(item->text(0))); addVariableTrackerExpressionAction = new QAction(QString("%1").arg(item->text(1))); addVariableTrackerAsteriskExpressionAction = new QAction(QString("*%1").arg(item->text(1))); addVariableTrackerAmpersandExpressionAction = new QAction(QString("&&%1").arg(item->text(1))); addVariableTrackerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(item->text(1))); addVariableTrackerObjcExpressionAction = new QAction(QString("(objc)%1").arg(item->text(0))); addMemoryVisualizerAction = new QAction(QString("%1").arg(item->text(1))); addMemoryAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(1))); addMemoryAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(1))); addArrayVisualizerAction = new QAction(QString("%1").arg(item->text(1))); addArrayAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(1))); addArrayAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(1))); addMatrixVisualizerAction = new QAction(QString("%1").arg(item->text(1))); addMatrixAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(1))); addMatrixAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(1))); addStructVisualizerAction = new QAction(QString("%1").arg(item->text(1))); addStructAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(1))); addStructAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(1))); QMenu menu("Visualizers", this); menu.setTitle("Visualizers"); QMenu loggerMenu("Add variable to Logger"); loggerMenu.addAction(addVariableLoggerExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskExpressionAction); loggerMenu.addAction(addVariableLoggerAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerObjcExpressionAction); menu.addMenu(&loggerMenu); QMenu trackerMenu("Add variable to Tracker"); trackerMenu.addAction(addVariableTrackerExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskExpressionAction); trackerMenu.addAction(addVariableTrackerAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerObjcExpressionAction); menu.addMenu(&trackerMenu); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Launch the menu. Get the response. QAction* action = menu.exec(argumentsTreeWidget->viewport()->mapToGlobal(pos)); // Do nothing. if (action == 0) { return; } // Handle adding a variable to log. if (action == addVariableLoggerExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(item->text(1)); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(QString("*") + item->text(1)); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAmpersandExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(QString("&") + item->text(1)); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskAmpersandExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(QString("*&") + item->text(1)); } return; } // Handle adding a variable to log. if (action == addVariableLoggerObjcExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(QString("(objc)") + item->text(1)); } return; } // Handle adding a variable to track. if (action == addVariableTrackerExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(QString("*") + item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAmpersandExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(QString("&") + item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskAmpersandExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(QString("*&") + item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerObjcExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(QString("(objc)") + item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMemoryVisualizer(item->text(1)); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMemoryVisualizer(QString("*") + item->text(1)); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMemoryVisualizer(QString("&") + item->text(1)); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addArrayVisualizer(item->text(1)); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addArrayVisualizer(QString("*") + item->text(1)); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addArrayVisualizer(QString("&") + item->text(1)); } return; } // Handle adding matrix to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMatrixVisualizer(item->text(1)); } return; } // Handle adding matrix to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMatrixVisualizer(QString("*") + item->text(1)); } return; } // Handle adding matrix to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMatrixVisualizer(QString("&") + item->text(1)); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addStructVisualizer(item->text(1)); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addStructVisualizer(QString("*") + item->text(1)); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addStructVisualizer(QString("&") + item->text(1)); } return; } } void SeerStackArgumentsBrowserWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); argumentsTreeWidget->resizeColumnToContents(0); argumentsTreeWidget->resizeColumnToContents(1); argumentsTreeWidget->resizeColumnToContents(2); argumentsTreeWidget->resizeColumnToContents(3); } void SeerStackArgumentsBrowserWidget::handleItemCollapsed (QTreeWidgetItem* item) { Q_UNUSED(item); argumentsTreeWidget->resizeColumnToContents(0); argumentsTreeWidget->resizeColumnToContents(1); argumentsTreeWidget->resizeColumnToContents(2); argumentsTreeWidget->resizeColumnToContents(3); } void SeerStackArgumentsBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); if (item->text(0) != "") { for (int i=0; icolumnCount(); i++) { // The "level" item does not have a tooltip. item->setToolTip(i, ""); } }else{ QTreeWidgetItem* parent = item->parent(); // Get parent item, which is the level. item->setToolTip(0, parent->text(0) + " : " + item->text(1) + " : " + Seer::elideText(item->text(2), Qt::ElideRight, 100)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } } void SeerStackArgumentsBrowserWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& level_text, const QString& name_text, const QString& value_text) { // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. We start by looking for matches that // may already be there. If there are matches, the code will reuse it. If not, a new item // is created by the code. Note, when searching, we only look at the current level. Not any // children. QList matches; if (parentItem == 0) { Q_ASSERT(parentItem != NULL); return; }else{ for (int i=0; ichildCount(); i++) { if (parentItem->child(i)->text(1) == name_text) { matches.append(parentItem->child(i)); } } } // Parse bookmarks. QString capture0; // With const address. QString capture1; // Without. QRegularExpression withaddress_re("^@0[xX][0-9a-fA-F]+: \\{(.*?)\\}$"); QRegularExpressionMatch withaddress_match = withaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (withaddress_match.hasMatch()) { capture0 = withaddress_match.captured(0); capture1 = withaddress_match.captured(1); }else{ QRegularExpression noaddress_re("^\\{(.*?)\\}$"); QRegularExpressionMatch noaddress_match = noaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (noaddress_match.hasMatch()) { capture0 = noaddress_match.captured(0); capture1 = noaddress_match.captured(1); } } // Add the complex entry to the tree. Reuse, if possible. if (capture0 != "" && capture1 != "") { // Remove bookends QString text = capture1; QTreeWidgetItem* item = 0; // Use the privously created item. Or create a new one. if (matches.size() > 0) { item = matches[0]; item->setText(3, "reused"); }else{ item = new QTreeWidgetItem; item->setText(3, "new"); // If we're dealing with a top-level item, attach it to the tree. // Otherwise, attach it to the parent. if (parentItem) { parentItem->addChild(item); }else{ argumentsTreeWidget->addTopLevelItem(item); } } // Set the flatvalue text. item->setText(0, level_text); item->setText(1, name_text); item->setText(2, Seer::filterEscapes(text)); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); // Convert to a list of name/value pairs. QStringList nv_pairs = Seer::parseCommaList(text, '{', '}'); // Go through each pair and add the name and its value to the tree. for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); handleItemCreate(item, level_text, pair.first, pair.second); } // Add the simple entry to the tree. Reuse, if possible. }else{ QTreeWidgetItem* item = 0; // Use the privously created item. Or create a new one. if (matches.size() > 0) { item = matches[0]; item->setText(3, "reused"); }else{ item = new QTreeWidgetItem; item->setText(3, "new"); // If we're dealing with a top-level item, attach it to the tree. // Otherwise, attach it to the parent. if (parentItem) { parentItem->addChild(item); }else{ argumentsTreeWidget->addTopLevelItem(item); } } // Simple entries don't have children. Delete them. QList children = item->takeChildren(); if (matches.size() > 0) { qDeleteAll(children); } // Populate the item. item->setText(0, level_text); item->setText(1, name_text); item->setText(2, Seer::filterEscapes(value_text)); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); } } void SeerStackArgumentsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } seer-2.7/src/SeerStackArgumentsBrowserWidget.h000066400000000000000000000041331516472651200215540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerStackArgumentsBrowserWidget.h" class SeerStackArgumentsBrowserWidget : public QWidget, protected Ui::SeerStackArgumentsBrowserWidgetForm { Q_OBJECT public: explicit SeerStackArgumentsBrowserWidget (QWidget* parent = 0); ~SeerStackArgumentsBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleContextMenu (const QPoint& pos); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshStackArguments (); void addVariableLoggerExpression (QString expression); void addVariableTrackerExpression (QString expression); void refreshVariableTrackerValues (); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); protected: void handleItemCreate (QTreeWidgetItem* parentItem, const QString& level_text, const QString& name_text, const QString& value_text); void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerStackArgumentsBrowserWidget.ui000066400000000000000000000021411516472651200217370ustar00rootroot00000000000000 SeerStackArgumentsBrowserWidgetForm 0 0 794 528 Form 4 Level Name Value Used seer-2.7/src/SeerStackDumpBrowserWidget.cpp000066400000000000000000000315271516472651200210560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackDumpBrowserWidget.h" #include "SeerStackDumpSettingsDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerStackDumpBrowserWidget::SeerStackDumpBrowserWidget (QWidget* parent) : QWidget(parent) { _spExpressionId = Seer::createID(); _dumpExpressionId = Seer::createID(); // Construct the UI. setupUi(this); // Setup the widgets stackTableWidget->setMouseTracking(true); stackTableWidget->setSortingEnabled(false); stackTableWidget->resizeColumnToContents(0); // 2 byte address stackTableWidget->resizeColumnToContents(1); // 2 byte value stackTableWidget->resizeColumnToContents(2); // 4 byte value stackTableWidget->resizeColumnToContents(3); // 8 byte value stackTableWidget->resizeColumnToContents(4); // N byte ascii stackTableWidget->resizeRowsToContents(); stackTableWidget->clearContents(); // Connect things. QObject::connect(formatComboBox, &QComboBox::currentTextChanged, this, &SeerStackDumpBrowserWidget::handleFormatComboBox); QObject::connect(visualizerToolButton, &QToolButton::clicked, this, &SeerStackDumpBrowserWidget::handleVisualizerToolButton); QObject::connect(preferencesToolButton, &QToolButton::clicked, this, &SeerStackDumpBrowserWidget::handlePreferencesToolButton); QObject::connect(stackTableWidget, &QTableWidget::cellDoubleClicked, this, &SeerStackDumpBrowserWidget::handleCellDoubleClicked); setStackPointerExpression("$sp"); setStackPointerColor(QColor("lightGray")); setBytesBeforeSP(16); setBytesAfterSP(16); setAsciiBytes(8); // Restore settings. readSettings(); } SeerStackDumpBrowserWidget::~SeerStackDumpBrowserWidget () { } void SeerStackDumpBrowserWidget::setStackPointerExpression (const QString& expression) { _stackPointerExpression = expression; spExpressionLabel->setText(_stackPointerExpression); } QString SeerStackDumpBrowserWidget::stackPointerExpression () const { return _stackPointerExpression; } void SeerStackDumpBrowserWidget::setBytesBeforeSP (int nbytes) { _bytesBeforeSP = ceil(nbytes / 8.0) * 8; // Round to 8. } int SeerStackDumpBrowserWidget::bytesBeforeSP () const { return _bytesBeforeSP; } void SeerStackDumpBrowserWidget::setBytesAfterSP (int nbytes) { _bytesAfterSP = ceil(nbytes / 8.0) * 8; // Round to 8. } int SeerStackDumpBrowserWidget::bytesAfterSP () const { return _bytesAfterSP; } void SeerStackDumpBrowserWidget::setAsciiBytes (int nbytes) { _asciiBytes = nbytes; } int SeerStackDumpBrowserWidget::asciiBytes () const { return _asciiBytes; } void SeerStackDumpBrowserWidget::setStackPointerColor (const QColor& color) { _stackPointerColor = color; } QColor SeerStackDumpBrowserWidget::stackPointerColor () const { return _stackPointerColor; } void SeerStackDumpBrowserWidget::handleText (const QString& text) { // -data-read-memory-bytes -o 16 $sp 32 // ^done,memory=[ // { // begin="0x00007fffffffda80", // offset="0x0000000000000000", // end="0x00007fffffffdaa0", // contents="0000000000000000e80300000000000098dcffffff7f0000e803000001000000" // } // ] // // // -data-evaluate-expression $sp // ^done,value="0x7fffffffda90" QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // ^done,value="0x7fffffffda90" QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); if (id_text.toInt() != _spExpressionId) { break; } addressLineEdit->setText(value_text); emit refreshStackDump(_dumpExpressionId, value_text, -bytesBeforeSP(), bytesBeforeSP()+bytesAfterSP()+2); }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { QString id_text = text.section('^', 0,0); if (id_text.toInt() != _dumpExpressionId) { break; } QString begin_text = Seer::parseFirst(text, "begin=", '"', '"', false); QString contents_text = Seer::parseFirst(text, "contents=", '"', '"', false); _populateTable(begin_text, contents_text); }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg=\"No registers.\""))) { addressLineEdit->setText(""); }else{ // Ignore others. } break; } stackTableWidget->resizeColumnToContents(0); stackTableWidget->resizeColumnToContents(1); stackTableWidget->resizeColumnToContents(2); stackTableWidget->resizeColumnToContents(3); stackTableWidget->resizeColumnToContents(4); stackTableWidget->resizeRowsToContents(); QApplication::restoreOverrideCursor(); } void SeerStackDumpBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } refresh(); } void SeerStackDumpBrowserWidget::handleSessionTerminated () { // Delete previous contents. stackTableWidget->clearContents(); } void SeerStackDumpBrowserWidget::handleFormatComboBox (const QString& text) { Q_UNUSED(text); refresh(); } void SeerStackDumpBrowserWidget::handleVisualizerToolButton () { emit addMemoryVisualizer(addressLineEdit->text()); } void SeerStackDumpBrowserWidget::handlePreferencesToolButton () { // Bring up the register edit dialog. SeerStackDumpSettingsDialog dlg(this); dlg.setStackPointerExpression(stackPointerExpression()); dlg.setStackPointerColor(stackPointerColor()); dlg.setBytesBeforeSP(bytesBeforeSP()); dlg.setBytesAfterSP(bytesAfterSP()); dlg.setAsciiBytes(asciiBytes()); //dlg.set(item->text(1), item->text(2)); int ret = dlg.exec(); if (ret == 0) { return; } setStackPointerExpression(dlg.stackPointerExpression()); setStackPointerColor(dlg.stackPointerColor()); setBytesBeforeSP(dlg.bytesBeforeSP()); setBytesAfterSP(dlg.bytesAfterSP()); setAsciiBytes(dlg.asciiBytes()); writeSettings(); refresh(); } void SeerStackDumpBrowserWidget::handleCellDoubleClicked (int row, int col) { Q_UNUSED(col); QTableWidgetItem* item = stackTableWidget->item(row, 0); if (item == 0) { return; } QString address = item->text(); if (address.mid(0,2) != "0x") { address.insert(0,"0x"); } emit addMemoryVisualizer(address); } void SeerStackDumpBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshStackPointer(_spExpressionId, stackPointerExpression()); } void SeerStackDumpBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } void SeerStackDumpBrowserWidget::_populateTable (QString address, QString contents) { QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); // Loop off '0x'. if (address.mid(0,2) == "0x") { address = address.mid(2); } bool ok; quint64 address64 = address.toULongLong(&ok, 16); quint64 pos64 = address64; int nrows = contents.length()/2/2; // Divide by 2 for a "FF" character, then again for 2 bytes per row. // Convert the contents to raw bytes. QVector bytes; for (int pos=0; posclearContents(); stackTableWidget->setRowCount(nrows); int spRow = -1; // Fill in the address column. for (int i=0,r=0; i < contents.length()/2; i+=2,pos64+=2,r++) { QString str = QString::number(pos64, 16); QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (addressLineEdit->text().contains(str)) { item->setBackground(QBrush(stackPointerColor())); spRow = r; } stackTableWidget->setItem(r,0,item); } // Fill in the 2byte column. for (int i=0,r=0; icurrentText() == "hex") { str = Seer::ucharToHex(bytes, i, 2); }else if (formatComboBox->currentText() == "octal") { str = Seer::ucharToOctal(bytes, i, 2); }else if (formatComboBox->currentText() == "uint") { str = Seer::ucharToUShort(bytes, i, 1); }else if (formatComboBox->currentText() == "int") { str = Seer::ucharToShort(bytes, i, 1); } QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (r == spRow) { item->setBackground(QBrush(stackPointerColor())); } stackTableWidget->setItem(r,1,item); } // Fill in the 4byte column. for (int i=0,r=0; i < bytes.size(); i+=2,r++) { QString str; if (formatComboBox->currentText() == "hex") { str = Seer::ucharToHex(bytes, i, 4); }else if (formatComboBox->currentText() == "octal") { str = Seer::ucharToOctal(bytes, i, 4); }else if (formatComboBox->currentText() == "uint") { str = Seer::ucharToUInt(bytes, i, 1); }else if (formatComboBox->currentText() == "int") { str = Seer::ucharToInt(bytes, i, 1); }else if (formatComboBox->currentText() == "float") { str = Seer::ucharToFloat(bytes, i, 1); } QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (r == spRow) { item->setBackground(QBrush(stackPointerColor())); } stackTableWidget->setItem(r,2,item); } // Fill in the 8byte column. for (int i=0,r=0; i < bytes.size(); i+=2,r++) { QString str; if (formatComboBox->currentText() == "hex") { str = Seer::ucharToHex(bytes, i, 8); }else if (formatComboBox->currentText() == "octal") { str = Seer::ucharToOctal(bytes, i, 8); }else if (formatComboBox->currentText() == "uint") { str = Seer::ucharToULong(bytes, i, 1); }else if (formatComboBox->currentText() == "int") { str = Seer::ucharToLong(bytes, i, 1); }else if (formatComboBox->currentText() == "float") { str = Seer::ucharToDouble(bytes, i, 1); } QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (r == spRow) { item->setBackground(QBrush(stackPointerColor())); } stackTableWidget->setItem(r,3,item); } // Fill in the Nbyte ascii column. for (int i=0,r=0; i < bytes.size(); i+=2,r++) { QString str = Seer::ucharToAscii(bytes, i, asciiBytes()); QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (r == spRow) { item->setBackground(QBrush(stackPointerColor())); } stackTableWidget->setItem(r,4,item); } } void SeerStackDumpBrowserWidget::writeSettings () { QSettings settings; settings.beginGroup("stackdumpwindow"); { settings.setValue("stackpointerexpression", stackPointerExpression()); settings.setValue("stackpointercolor", stackPointerColor()); settings.setValue("bytesbeforesp", bytesBeforeSP()); settings.setValue("bytesaftersp", bytesAfterSP()); settings.setValue("asciibytes", asciiBytes()); } settings.endGroup(); } void SeerStackDumpBrowserWidget::readSettings () { QSettings settings; settings.beginGroup("stackdumpwindow"); { setStackPointerExpression(settings.value("stackpointerexpression", "$sp").toString()); QVariant variant = settings.value("stackpointercolor", "lightGray"); QColor color = variant.value(); setStackPointerColor(color); setBytesBeforeSP(settings.value("bytesbeforesp", 32).toInt()); setBytesAfterSP(settings.value("bytesaftersp", 32).toInt()); setAsciiBytes(settings.value("asciibytes", 8).toInt()); } settings.endGroup(); } seer-2.7/src/SeerStackDumpBrowserWidget.h000066400000000000000000000052071516472651200205170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerStackDumpBrowserWidget.h" class SeerStackDumpBrowserWidget : public QWidget, protected Ui::SeerStackDumpBrowserWidgetForm { Q_OBJECT public: explicit SeerStackDumpBrowserWidget (QWidget* parent = 0); ~SeerStackDumpBrowserWidget (); void setStackPointerExpression (const QString& expression); QString stackPointerExpression () const; void setBytesBeforeSP (int nbytes); int bytesBeforeSP () const; void setBytesAfterSP (int nbytes); int bytesAfterSP () const; void setAsciiBytes (int nbytes); int asciiBytes () const; void setStackPointerColor (const QColor& color); QColor stackPointerColor () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleFormatComboBox (const QString& text); void handleVisualizerToolButton (); void handlePreferencesToolButton (); void handleCellDoubleClicked (int row, int col); signals: void refreshStackPointer (int id, QString expression); void refreshStackDump (int id, QString address, int offset, int count); void addMemoryVisualizer (QString expression); protected: void showEvent (QShowEvent* event); void readSettings (); void writeSettings (); private: void _populateTable (QString address, QString contents); int _spExpressionId; int _dumpExpressionId; QString _stackPointerExpression; int _bytesBeforeSP; int _bytesAfterSP; int _asciiBytes; QColor _stackPointerColor; }; seer-2.7/src/SeerStackDumpBrowserWidget.ui000066400000000000000000000131771516472651200207120ustar00rootroot00000000000000 SeerStackDumpBrowserWidgetForm 0 0 794 528 Seer Stack Dump 0 0 $sp 0 0 true address Format 0 0 hex octal int uint float Launch Memory Visualizer :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg Qt::Horizontal QSizePolicy::Expanding 40 20 QAbstractItemView::NoEditTriggers true Qt::SolidLine true false Address AlignLeading|AlignVCenter 2 Byte AlignLeading|AlignVCenter 4 Byte AlignLeading|AlignVCenter 8 Byte AlignLeading|AlignVCenter String AlignLeading|AlignVCenter addressLineEdit formatComboBox stackTableWidget seer-2.7/src/SeerStackDumpSettingsDialog.cpp000066400000000000000000000040151516472651200211770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackDumpSettingsDialog.h" #include "SeerRegisterTreeWidgetItem.h" #include #include #include #include #include #include #include SeerStackDumpSettingsDialog::SeerStackDumpSettingsDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); spHighLightColorButton->setFrameStyle(QFrame::Box|QFrame::Plain); spHighLightColorButton->setLineWidth(1); // Setup the widgets setStackPointerExpression("$sp"); setStackPointerColor(QColor("lightGray")); setBytesBeforeSP(16); setBytesAfterSP(16); setAsciiBytes(8); // Connect things. } SeerStackDumpSettingsDialog::~SeerStackDumpSettingsDialog () { } void SeerStackDumpSettingsDialog::setStackPointerExpression (const QString& expression) { spExpressionLineEdit->setText(expression); } void SeerStackDumpSettingsDialog::setStackPointerColor (const QColor& color) { spHighLightColorButton->setColor(color); } QColor SeerStackDumpSettingsDialog::stackPointerColor () const { return spHighLightColorButton->color(); } QString SeerStackDumpSettingsDialog::stackPointerExpression () const { return spExpressionLineEdit->text(); } void SeerStackDumpSettingsDialog::setBytesBeforeSP (int nbytes) { preBytesSpinBox->setValue(nbytes); } int SeerStackDumpSettingsDialog::bytesBeforeSP () const { return preBytesSpinBox->value(); } void SeerStackDumpSettingsDialog::setBytesAfterSP (int nbytes) { postBytesSpinBox->setValue(nbytes); } int SeerStackDumpSettingsDialog::bytesAfterSP () const { return postBytesSpinBox->value(); } void SeerStackDumpSettingsDialog::setAsciiBytes (int nbytes) { asciiBytesSpinBox->setValue(nbytes); } int SeerStackDumpSettingsDialog::asciiBytes () const { return asciiBytesSpinBox->value(); } seer-2.7/src/SeerStackDumpSettingsDialog.h000066400000000000000000000025061516472651200206470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerStackDumpSettingsDialog.h" class SeerStackDumpSettingsDialog : public QDialog, protected Ui::SeerStackDumpSettingsDialogForm { Q_OBJECT public: explicit SeerStackDumpSettingsDialog (QWidget* parent = 0); ~SeerStackDumpSettingsDialog (); void setStackPointerExpression (const QString& expression); QString stackPointerExpression () const; void setStackPointerColor (const QColor& color); QColor stackPointerColor () const; void setBytesBeforeSP (int nbytes); int bytesBeforeSP () const; void setBytesAfterSP (int nbytes); int bytesAfterSP () const; void setAsciiBytes (int nbytes); int asciiBytes () const; public slots: private slots: protected: private: }; seer-2.7/src/SeerStackDumpSettingsDialog.ui000066400000000000000000000224551516472651200210420ustar00rootroot00000000000000 SeerStackDumpSettingsDialogForm 0 0 699 502 Seer - Stack Dump Settings Stack pointer expression Gdb expression to get the stack pointer. SP expression true Highlight color 0 0 40 0 Select color to highlight SP row. Qt::Horizontal 218 20 Bytes shown before SP Number of bytes shown before the SP. 96 8 16 Qt::Horizontal 448 20 Bytes shown after SP Number of bytes shown after the SP. 96 8 16 Qt::Horizontal 448 20 Ascii bytes shown Number of ascii bytes to show. 96 1 8 Qt::Horizontal 448 20 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The stack pointer (SP) points to where in the stack memory the program is currently at. The settings here control how the memory around the SP is displayed.<br /><br />GDB has the virtual variable called &quot;$sp&quot;, which contains the SP address. It is typical to use this as the SP expression. Some might prefer &quot;$ss*16+$sp&quot;, which is for X86 real mode. Either way, enter a gdb expression that results in an address. In most cases, $sp is enough.<br /><br />Seer can show N bytes before and N bytes after the SP, thus forming a window of bytes. N is rounded up to the next count of 8.<br /><br />The bytes are shown as 2, 4, and 8 byte version of: hex, octal, int, uint, and float values.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Also, Seer will attempt to show the bytes as Ascii characters. The number of Ascii characters to show can be set.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Double clicking on a row will bring up a separate Memory Visualizer for that address.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br />Highlight color is used to highlight the row that contains $SP. Double click on it to bring up a color chooser.</p> <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> <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> Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok QColorButton QWidget
QColorButton.h
1
buttonBox accepted() SeerStackDumpSettingsDialogForm accept() 248 254 157 274 buttonBox rejected() SeerStackDumpSettingsDialogForm reject() 316 260 286 274
seer-2.7/src/SeerStackFramesBrowserWidget.cpp000066400000000000000000000214411516472651200213600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackFramesBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerStackFramesBrowserWidget::SeerStackFramesBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); _previousStackFrameText = ""; // Setup the widgets stackTreeWidget->setMouseTracking(true); stackTreeWidget->setSortingEnabled(false); stackTreeWidget->resizeColumnToContents(0); // level stackTreeWidget->resizeColumnToContents(1); // func stackTreeWidget->resizeColumnToContents(2); // file stackTreeWidget->resizeColumnToContents(3); // line stackTreeWidget->resizeColumnToContents(4); // fullname stackTreeWidget->resizeColumnToContents(5); // addr stackTreeWidget->resizeColumnToContents(6); // arch stackTreeWidget->clear(); // Connect things. QObject::connect(stackTreeWidget, &QTreeWidget::itemClicked, this, &SeerStackFramesBrowserWidget::handleItemClicked); QObject::connect(stackTreeWidget, &QTreeWidget::itemEntered, this, &SeerStackFramesBrowserWidget::handleItemEntered); } SeerStackFramesBrowserWidget::~SeerStackFramesBrowserWidget () { } void SeerStackFramesBrowserWidget::handleText (const QString& text) { // Stackframes is important. Always do it. // // Don't do any work if the widget is hidden. // if (isHidden()) { // return; // } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,stack=[") && text.endsWith("]")) { // ^done,stack=[ // frame={level=\"0\",addr=\"0x0000000000400d72\",func=\"function1\",file=\"function1.cpp\",fullname=\"/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp\",line=\"7\",arch=\"i386:x86-64\"}, // frame={level=\"1\",addr=\"0x0000000000400cc3\",func=\"main\",file=\"helloworld.cpp\",fullname=\"/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp\",line=\"14\",arch=\"i386:x86-64\"} // ] // If we are simply moving up and down the stack (via frame-select) then the text won't change. // If it is different, reconstruct the tree. Select the first frame. if (text != _previousStackFrameText) { _previousStackFrameText = text; stackTreeWidget->clear(); QString stack_text = Seer::parseFirst(text, "stack=", '[', ']', false); if (stack_text != "") { // Parse through the frame list and set the current lines that are in the frame list. QStringList frame_list = Seer::parse(text, "frame=", '{', '}', false); QString firstLiveFrameLevel = ""; QString firstLiveFrameFile = ""; QString firstLiveFrameFullname = ""; QString firstLiveFrameLine = ""; QString firstFrameLevel = ""; QString firstFrameAddr = ""; for ( const auto& frame_text : frame_list ) { QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(frame_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); QString arch_text = Seer::parseFirst(frame_text, "arch=", '"', '"', false); // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, level_text); item->setText(1, func_text); item->setText(2, QFileInfo(file_text).fileName()); item->setText(3, line_text); item->setText(4, fullname_text); item->setText(5, addr_text); item->setText(6, arch_text); // Enable/disable interaction with this row depending if there is a valid file and line number. if (file_text != "" && fullname_text != "" && line_text != "") { item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); // Save the first live frame (that has a valid file and lineno) so we can select it automatically. // This only happens if the stack text is different (a stop point is reached). if (firstLiveFrameLevel == "") { firstLiveFrameLevel = level_text; firstLiveFrameFile = QFileInfo(file_text).fileName(); firstLiveFrameFullname = fullname_text; firstLiveFrameLine = line_text; } }else{ item->setFlags(Qt::NoItemFlags); } // Get the address of the first entry of the frame. if (addr_text != "") { if (firstFrameLevel == "") { firstFrameLevel = level_text; firstFrameAddr = addr_text; } } // Add the frame to the tree. stackTreeWidget->addTopLevelItem(item); } // Automatically bring up the file for the first live frame. if (firstLiveFrameLevel != "") { if (firstLiveFrameFile != "" && firstLiveFrameFullname != "") { emit selectedFile(firstLiveFrameFile, firstLiveFrameFullname, firstLiveFrameLine.toInt()); } } // Automatically bring up the assembly for the first frame. emit maybeSelectedAddress(firstLiveFrameFile, firstLiveFrameFullname, firstFrameAddr); } // Select the first frame level. // ??? Perhaps show the current frame level somehow. stackTreeWidget->clearSelection(); QList matches = stackTreeWidget->findItems("0", Qt::MatchExactly, 0); if (matches.size() > 0) { stackTreeWidget->setCurrentItem(matches.first()); } } }else{ // Ignore others. } stackTreeWidget->resizeColumnToContents(0); stackTreeWidget->resizeColumnToContents(1); stackTreeWidget->resizeColumnToContents(2); stackTreeWidget->resizeColumnToContents(3); stackTreeWidget->resizeColumnToContents(4); stackTreeWidget->resizeColumnToContents(5); stackTreeWidget->resizeColumnToContents(6); QApplication::restoreOverrideCursor(); } void SeerStackFramesBrowserWidget::handleStoppingPointReached () { // Stackframes is important. Always do it. // // Don't do any work if the widget is hidden. // if (isHidden()) { // return; // } refresh(); } void SeerStackFramesBrowserWidget::handleSessionTerminated () { // Delete previous contents and remembered state. stackTreeWidget->clear(); _previousStackFrameText = ""; } void SeerStackFramesBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshStackFrames(); } void SeerStackFramesBrowserWidget::handleItemClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); int lineno = item->text(3).toInt(); // Select frame. emit selectedFrame(item->text(0).toInt()); // Select file if we can. if (item->text(2) != "" && item->text(4) != "") { emit selectedFile(item->text(2), item->text(4), lineno); } // Select address if we can. if (item->text(5) != "") { emit maybeSelectedAddress(item->text(2), item->text(4), item->text(5)); } } void SeerStackFramesBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + item->text(1) + " : " + item->text(2) + " : " + item->text(3)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerStackFramesBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } seer-2.7/src/SeerStackFramesBrowserWidget.h000066400000000000000000000030131516472651200210200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerStackFramesBrowserWidget.h" class SeerStackFramesBrowserWidget : public QWidget, protected Ui::SeerStackFramesBrowserWidgetForm { Q_OBJECT public: explicit SeerStackFramesBrowserWidget (QWidget* parent = 0); ~SeerStackFramesBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshStackFrames (); void selectedFile (QString file, QString fullname, int lineno); void selectedAddress (QString address); void maybeSelectedAddress (QString file, QString fullname, QString address); void selectedFrame (int frameno); protected: void showEvent (QShowEvent* event); private: QString _previousStackFrameText; }; seer-2.7/src/SeerStackFramesBrowserWidget.ui000066400000000000000000000026201516472651200212110ustar00rootroot00000000000000 SeerStackFramesBrowserWidgetForm 0 0 600 700 Form 7 Level Function File Line Fullname Address Arch seer-2.7/src/SeerStackLocalsBrowserWidget.cpp000066400000000000000000000541041516472651200213620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackLocalsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include SeerStackLocalsBrowserWidget::SeerStackLocalsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets localsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); localsTreeWidget->setMouseTracking(true); localsTreeWidget->setSortingEnabled(false); localsTreeWidget->resizeColumnToContents(0); // name localsTreeWidget->resizeColumnToContents(1); // arg localsTreeWidget->resizeColumnToContents(2); // value localsTreeWidget->resizeColumnToContents(3); // used localsTreeWidget->setColumnHidden(3, true); // Hide the 'used' column. localsTreeWidget->clear(); _frameNumber = 0; // Connect things. QObject::connect(localsTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerStackLocalsBrowserWidget::handleContextMenu); QObject::connect(localsTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerStackLocalsBrowserWidget::handleItemCollapsed); QObject::connect(localsTreeWidget, &QTreeWidget::itemExpanded, this, &SeerStackLocalsBrowserWidget::handleItemExpanded); QObject::connect(localsTreeWidget, &QTreeWidget::itemEntered, this, &SeerStackLocalsBrowserWidget::handleItemEntered); } SeerStackLocalsBrowserWidget::~SeerStackLocalsBrowserWidget () { } void SeerStackLocalsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,variables=[") && text.endsWith("]")) { // ^done,variables=[ // {name=\"message\",arg=\"1\",value=\"\\\"Hello, World!\\\"\"}, // {name=\"something\",arg=\"1\",value=\"\\\"Hello, World!\\\"\"} // ] // Parse the text. Create a list of variables. QString frame_text = Seer::parseFirst(text, "variables=", '[', ']', false); QStringList variable_list = Seer::parse(frame_text, "", '{', '}', false); // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(localsTreeWidget); while (*it) { (*it)->setText(3, "unused"); ++it; } // Loop through each variable. for (const auto& variable_text : variable_list) { QString name_text = Seer::parseFirst(variable_text, "name=", '"', '"', false); QString arg_text = Seer::parseFirst(variable_text, "arg=", '"', '"', false); QString value_text = Seer::parseFirst(variable_text, "value=", '"', '"', false); // Morph 'is function argument' from a '1' to 'yes'. arg_text = (arg_text == "1" ? "yes" : ""); // Populate the tree. handleItemCreate(0, name_text, arg_text, value_text); } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. // Don't use qDeleteAll() here. It doesn't work as expected for items that are "found". // Instead, get a list of matches and delete them from the bottom up. QList matches = localsTreeWidget->findItems("unused", Qt::MatchExactly|Qt::MatchRecursive, 3); while (matches.isEmpty() == false) { foreach (QTreeWidgetItem* item, matches) { if (item->childCount() == 0) { QTreeWidgetItem* parent = item->parent(); if (parent) { parent->removeChild(item); } bool f = matches.removeOne(item); Q_ASSERT(f != false); delete item; break; } } } }else{ // Ignore others. } localsTreeWidget->resizeColumnToContents(0); localsTreeWidget->resizeColumnToContents(1); localsTreeWidget->resizeColumnToContents(2); localsTreeWidget->resizeColumnToContents(3); QApplication::restoreOverrideCursor(); } void SeerStackLocalsBrowserWidget::handleStoppingPointReached () { refresh(); } void SeerStackLocalsBrowserWidget::handleSessionTerminated () { // Delete previous contents. localsTreeWidget->clear(); } void SeerStackLocalsBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshStackLocals(); } void SeerStackLocalsBrowserWidget::handleContextMenu (const QPoint& pos) { QTreeWidgetItem* item = localsTreeWidget->itemAt(pos); if (item == 0) { return; } QAction* addVariableLoggerExpressionAction; QAction* addVariableLoggerAsteriskExpressionAction; QAction* addVariableLoggerAmpersandExpressionAction; QAction* addVariableLoggerAsteriskAmpersandExpressionAction; QAction* addVariableLoggerObjcExpressionAction; QAction* addVariableTrackerExpressionAction; QAction* addVariableTrackerAsteriskExpressionAction; QAction* addVariableTrackerAmpersandExpressionAction; QAction* addVariableTrackerAsteriskAmpersandExpressionAction; QAction* addVariableTrackerObjcExpressionAction; QAction* addMemoryVisualizerAction; QAction* addMemoryAsteriskVisualizerAction; QAction* addMemoryAmpersandVisualizerAction; QAction* addArrayVisualizerAction; QAction* addArrayAsteriskVisualizerAction; QAction* addArrayAmpersandVisualizerAction; QAction* addMatrixVisualizerAction; QAction* addMatrixAsteriskVisualizerAction; QAction* addMatrixAmpersandVisualizerAction; QAction* addStructVisualizerAction; QAction* addStructAsteriskVisualizerAction; QAction* addStructAmpersandVisualizerAction; addVariableLoggerExpressionAction = new QAction(QString("%1").arg(item->text(0))); addVariableLoggerAsteriskExpressionAction = new QAction(QString("*%1").arg(item->text(0))); addVariableLoggerAmpersandExpressionAction = new QAction(QString("&&%1").arg(item->text(0))); addVariableLoggerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(item->text(0))); addVariableLoggerObjcExpressionAction = new QAction(QString("(objc)%1").arg(item->text(0))); addVariableTrackerExpressionAction = new QAction(QString("%1").arg(item->text(0))); addVariableTrackerAsteriskExpressionAction = new QAction(QString("*%1").arg(item->text(0))); addVariableTrackerAmpersandExpressionAction = new QAction(QString("&&%1").arg(item->text(0))); addVariableTrackerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(item->text(0))); addVariableTrackerObjcExpressionAction = new QAction(QString("(objc)%1").arg(item->text(0))); addMemoryVisualizerAction = new QAction(QString("%1").arg(item->text(0))); addMemoryAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(0))); addMemoryAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(0))); addArrayVisualizerAction = new QAction(QString("%1").arg(item->text(0))); addArrayAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(0))); addArrayAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(0))); addMatrixVisualizerAction = new QAction(QString("%1").arg(item->text(0))); addMatrixAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(0))); addMatrixAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(0))); addStructVisualizerAction = new QAction(QString("%1").arg(item->text(0))); addStructAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(0))); addStructAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(0))); QMenu menu("Visualizers", this); menu.setTitle("Visualizers"); QMenu loggerMenu("Add variable to Logger"); loggerMenu.addAction(addVariableLoggerExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskExpressionAction); loggerMenu.addAction(addVariableLoggerAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerObjcExpressionAction); menu.addMenu(&loggerMenu); QMenu trackerMenu("Add variable to Tracker"); trackerMenu.addAction(addVariableTrackerExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskExpressionAction); trackerMenu.addAction(addVariableTrackerAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerObjcExpressionAction); menu.addMenu(&trackerMenu); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Launch the menu. Get the response. QAction* action = menu.exec(localsTreeWidget->viewport()->mapToGlobal(pos)); // Do nothing. if (action == 0) { return; } // Build up a variable string, incase it is a nested struct. QTreeWidgetItem* i = item; QString variable = item->text(0); while (i->parent() != 0) { variable = i->parent()->text(0) + "." + variable; i = i->parent(); } // Handle adding a variable to log. if (action == addVariableLoggerExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(variable); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(QString("*") + variable); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAmpersandExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(QString("&") + variable); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskAmpersandExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(QString("*&") + variable); } return; } // Handle adding a variable to log. if (action == addVariableLoggerObjcExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(QString("(objc)") + variable); } return; } // Handle adding a variable to track. if (action == addVariableTrackerExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(variable); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(QString("*") + variable); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAmpersandExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(QString("&") + variable); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskAmpersandExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(QString("*&") + variable); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerObjcExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(QString("(objc)") + variable); emit refreshVariableTrackerValues(); } return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("&") + variable); } return; } } void SeerStackLocalsBrowserWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); localsTreeWidget->resizeColumnToContents(0); localsTreeWidget->resizeColumnToContents(1); localsTreeWidget->resizeColumnToContents(2); localsTreeWidget->resizeColumnToContents(3); } void SeerStackLocalsBrowserWidget::handleItemCollapsed (QTreeWidgetItem* item) { Q_UNUSED(item); localsTreeWidget->resizeColumnToContents(0); localsTreeWidget->resizeColumnToContents(1); localsTreeWidget->resizeColumnToContents(2); localsTreeWidget->resizeColumnToContents(3); } void SeerStackLocalsBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + Seer::elideText(item->text(2), Qt::ElideRight, 100)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerStackLocalsBrowserWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& name_text, const QString& arg_text, const QString& value_text) { // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. We start by looking for matches that // may already be there. If there are matches, the code will reuse it. If not, a new item // is created by the code. Note, when searching, we only look at the current level. Not any // children. QList matches; if (parentItem == 0) { matches = localsTreeWidget->findItems(name_text, Qt::MatchExactly, 0); }else{ for (int i=0; ichildCount(); i++) { if (parentItem->child(i)->text(0) == name_text) { matches.append(parentItem->child(i)); } } } // Parse bookmarks. QString capture0; // With bookends. QString capture1; // Without. QRegularExpression withaddress_re("^@0[xX][0-9a-fA-F]+: \\{(.*?)\\}$"); QRegularExpressionMatch withaddress_match = withaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (withaddress_match.hasMatch()) { capture0 = withaddress_match.captured(0); capture1 = withaddress_match.captured(1); }else{ QRegularExpression noaddress_re("^\\{(.*?)\\}$"); QRegularExpressionMatch noaddress_match = noaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (noaddress_match.hasMatch()) { capture0 = noaddress_match.captured(0); capture1 = noaddress_match.captured(1); } } // Add the complex entry to the tree. Reuse, if possible. if (capture0 != "" && capture1 != "") { // Remove bookends QString text = capture1; QTreeWidgetItem* item = 0; // Use the privously created item. Or create a new one. if (matches.size() > 0) { item = matches[0]; item->setText(3, "reused"); }else{ item = new QTreeWidgetItem; item->setText(3, "new"); // If we're dealing with a top-level item, attach it to the tree. // Otherwise, attach it to the parent. if (parentItem) { parentItem->addChild(item); }else{ localsTreeWidget->addTopLevelItem(item); } } // Set the flatvalue text. item->setText(0, name_text); item->setText(1, arg_text); item->setText(2, Seer::filterEscapes(text)); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); // Convert to a list of name/value pairs. QStringList nv_pairs = Seer::parseCommaList(text, '{', '}'); // Go through each pair and add the name and its value to the tree. for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); handleItemCreate(item, pair.first, arg_text, pair.second); } // Add the simple entry to the tree. Reuse, if possible. }else{ QTreeWidgetItem* item = 0; // Use the privously created item. Or create a new one. if (matches.size() > 0) { item = matches[0]; item->setText(3, "reused"); }else{ item = new QTreeWidgetItem; item->setText(3, "new"); // If we're dealing with a top-level item, attach it to the tree. // Otherwise, attach it to the parent. if (parentItem) { parentItem->addChild(item); }else{ localsTreeWidget->addTopLevelItem(item); } } // Simple entries don't have children. Delete them. QList children = item->takeChildren(); if (matches.size() > 0) { qDeleteAll(children); } // Populate the item. item->setText(0, name_text); item->setText(1, arg_text); item->setText(2, Seer::filterEscapes(value_text)); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); } } void SeerStackLocalsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } seer-2.7/src/SeerStackLocalsBrowserWidget.h000066400000000000000000000041671516472651200210330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerStackLocalsBrowserWidget.h" class SeerStackLocalsBrowserWidget : public QWidget, protected Ui::SeerStackLocalsBrowserWidgetForm { Q_OBJECT public: explicit SeerStackLocalsBrowserWidget (QWidget* parent = 0); ~SeerStackLocalsBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleContextMenu (const QPoint& pos); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshStackLocals (); void addVariableLoggerExpression (QString expression); void addVariableTrackerExpression (QString expression); void refreshVariableTrackerValues (); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); protected: void handleItemCreate (QTreeWidgetItem* parentItem, const QString& name_text, const QString& arg_text, const QString& value_text); void showEvent (QShowEvent* event); private: int _frameNumber; }; seer-2.7/src/SeerStackLocalsBrowserWidget.ui000066400000000000000000000021261516472651200212120ustar00rootroot00000000000000 SeerStackLocalsBrowserWidgetForm 0 0 794 528 Form 4 Name Arg Value Used seer-2.7/src/SeerStackManagerWidget.cpp000066400000000000000000000237101516472651200201520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackManagerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include SeerStackManagerWidget::SeerStackManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(false); _stackFramesBrowserWidget = new SeerStackFramesBrowserWidget(this); _stackArgumentsBrowserWidget = new SeerStackArgumentsBrowserWidget(this); _stackLocalsBrowserWidget = new SeerStackLocalsBrowserWidget(this); _stackDumpBrowserWidget = new SeerStackDumpBrowserWidget(this); tabWidget->addTab(_stackFramesBrowserWidget, "Frames"); tabWidget->addTab(_stackArgumentsBrowserWidget, "Arguments"); tabWidget->addTab(_stackLocalsBrowserWidget, "Locals"); tabWidget->addTab(_stackDumpBrowserWidget, "Stack"); QToolButton* tabsContextMenuButton = new QToolButton(tabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QToolButton* refreshToolButton = new QToolButton(tabWidget); refreshToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/view-refresh.svg")); refreshToolButton->setToolTip("Refresh the stack information."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on stack information."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); hcontainer->addWidget(refreshToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Restore tab ordering. readSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerStackManagerWidget::handleTabsContextMenuButtonClicked); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerStackManagerWidget::handleRefreshToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerStackManagerWidget::handleHelpToolButtonClicked); QObject::connect(tabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerStackManagerWidget::handleTabMoved); QObject::connect(tabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerStackManagerWidget::handleTabChanged); } SeerStackManagerWidget::~SeerStackManagerWidget () { } SeerStackFramesBrowserWidget* SeerStackManagerWidget::stackFramesBrowserWidget () { return _stackFramesBrowserWidget; } SeerStackArgumentsBrowserWidget* SeerStackManagerWidget::stackArgumentsBrowserWidget () { return _stackArgumentsBrowserWidget; } SeerStackLocalsBrowserWidget* SeerStackManagerWidget::stackLocalsBrowserWidget () { return _stackLocalsBrowserWidget; } SeerStackDumpBrowserWidget* SeerStackManagerWidget::stackDumpBrowserWidget () { return _stackDumpBrowserWidget; } void SeerStackManagerWidget::handleRefreshToolButtonClicked () { stackFramesBrowserWidget()->refresh(); stackArgumentsBrowserWidget()->refresh(); stackLocalsBrowserWidget()->refresh(); stackDumpBrowserWidget()->refresh(); refresh(); } void SeerStackManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/StackInfoBrowser.md"); help->show(); help->raise(); } void SeerStackManagerWidget::handleTabMoved (int from, int to) { Q_UNUSED(from); Q_UNUSED(to); writeSettings(); } void SeerStackManagerWidget::handleTabChanged (int index) { Q_UNUSED(index); writeSettings(); } void SeerStackManagerWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(tabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(tabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = tabWidget->tabBar()->tabText(tabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; QSettings settings; settings.beginGroup("stackmanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerStackManagerWidget::readSettings () { // Can't move things? if (tabWidget->tabBar()->isMovable() == false) { return; } // Read tab order from settings. QSettings settings; QStringList tabs; QStringList visible; QString current; settings.beginGroup("stackmanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (tabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { tabWidget->tabBar()->moveTab(tb, i); } } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { tabWidget->setTabVisible(i,false); }else{ tabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (tabWidget->tabBar()->tabText(i) == current) { tabWidget->setCurrentIndex(i); break; } } }else{ tabWidget->setCurrentIndex(0); } } void SeerStackManagerWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,thread-ids={")) { QString newtext = Seer::filterEscapes(text); // Filter escaped characters. // ^done,thread-ids={ // thread-id=\"1\", // thread-id=\"2\" // }, // current-thread-id=\"1\", // number-of-threads=\"2\" QString currentthreadid_text = Seer::parseFirst(newtext, "current-thread-id=", '"', '"', false); if (currentthreadid_text == "") { label->setText("Stack Info - No Thread Selected"); }else{ label->setText("Stack Info - Thread Id " + currentthreadid_text); } stackFramesBrowserWidget()->refresh(); stackArgumentsBrowserWidget()->refresh(); stackLocalsBrowserWidget()->refresh(); stackDumpBrowserWidget()->refresh(); }else{ // Ignore others. } QApplication::restoreOverrideCursor(); } void SeerStackManagerWidget::handleSessionTerminated () { label->setText("Stack Info"); } void SeerStackManagerWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } refresh(); } void SeerStackManagerWidget::refresh () { emit refreshThreadFrames(); } void SeerStackManagerWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < tabWidget->count(); i++) { QString title = tabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(tabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (tabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { tabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ tabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } seer-2.7/src/SeerStackManagerWidget.h000066400000000000000000000050301516472651200176120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerStackFramesBrowserWidget.h" #include "SeerStackArgumentsBrowserWidget.h" #include "SeerStackLocalsBrowserWidget.h" #include "SeerStackDumpBrowserWidget.h" #include #include "ui_SeerStackManagerWidget.h" class SeerStackManagerWidget : public QWidget, protected Ui::SeerStackManagerWidgetForm { Q_OBJECT public: explicit SeerStackManagerWidget (QWidget* parent = 0); ~SeerStackManagerWidget (); SeerStackFramesBrowserWidget* stackFramesBrowserWidget (); SeerStackArgumentsBrowserWidget* stackArgumentsBrowserWidget (); SeerStackLocalsBrowserWidget* stackLocalsBrowserWidget (); SeerStackDumpBrowserWidget* stackDumpBrowserWidget (); signals: void refreshThreadFrames (); protected: void writeSettings (); void readSettings (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); private slots: void handleRefreshToolButtonClicked (); void handleHelpToolButtonClicked (); void handleTabMoved (int from, int to); void handleTabChanged (int index); void handleTabsContextMenuButtonClicked (); private: SeerStackFramesBrowserWidget* _stackFramesBrowserWidget; SeerStackArgumentsBrowserWidget* _stackArgumentsBrowserWidget; SeerStackLocalsBrowserWidget* _stackLocalsBrowserWidget; SeerStackDumpBrowserWidget* _stackDumpBrowserWidget; }; seer-2.7/src/SeerStackManagerWidget.ui000066400000000000000000000031131516472651200200000ustar00rootroot00000000000000 SeerStackManagerWidgetForm 0 0 773 494 Form 0 0 0 0 3 font-weight: bold; Stack Info Qt::PlainText -1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
seer-2.7/src/SeerStaticBrowserWidget.cpp000066400000000000000000000167031516472651200204110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStaticBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerStaticBrowserWidget::SeerStaticBrowserWidget (QWidget* parent) : QWidget(parent) { // Set the state. _id = Seer::createID(); // Construct the UI. setupUi(this); // Setup the widgets staticNameSearchLineEdit->setPlaceholderText("Static name regex..."); staticNameSearchLineEdit->setClearButtonEnabled(true); staticTypeSearchLineEdit->setPlaceholderText("Static type regex..."); staticTypeSearchLineEdit->setClearButtonEnabled(true); staticTreeWidget->setMouseTracking(true); //staticTreeWidget->resizeColumnToContents(0); //staticTreeWidget->resizeColumnToContents(1); staticTreeWidget->resizeColumnToContents(2); staticTreeWidget->resizeColumnToContents(3); staticTreeWidget->resizeColumnToContents(4); staticTreeWidget->resizeColumnToContents(5); staticTreeWidget->clear(); staticTreeWidget->setSortingEnabled(false); // Connect things. QObject::connect(staticTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerStaticBrowserWidget::handleItemDoubleClicked); QObject::connect(staticTreeWidget, &QTreeWidget::itemEntered, this, &SeerStaticBrowserWidget::handleItemEntered); QObject::connect(staticNameSearchLineEdit, &QLineEdit::returnPressed, this, &SeerStaticBrowserWidget::handleSearchLineEdit); QObject::connect(staticTypeSearchLineEdit, &QLineEdit::returnPressed, this, &SeerStaticBrowserWidget::handleSearchLineEdit); } SeerStaticBrowserWidget::~SeerStaticBrowserWidget () { } void SeerStaticBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith(QString::number(_id) + "^done,symbols={") && text.endsWith("}")) { staticTreeWidget->clear(); staticTreeWidget->setSortingEnabled(false); staticTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // -symbol-info-variables // ^done,symbols={ // debug=[ // { // filename="elf-init.c", // fullname="/home/abuild/rpmbuild/BUILD/glibc-2.31/csu/elf-init.c", // symbols=[ // { // line="95", // name="__libc_csu_fini", // type="void (void)", // description="void __libc_csu_fini(void);" // }, // { // line="67", // name="__libc_csu_init", // type="void (int, char **, char **)", // description="void __libc_csu_init(int, char **, char **);" // } // ] // }, // ... // ] // } QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false); QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false); for (const auto& filename_entry : filenames_list) { QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false); QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false); QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false); QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false); for (const auto& symbol_entry : symbols_list) { QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false); QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false); QString type_text = Seer::parseFirst(symbol_entry, "type=", '"', '"', false); QString description_text = Seer::parseFirst(symbol_entry, "type=", '"', '"', false); // Skip variable entries that have no line number. if (line_text == "") { continue; } // Add the variable to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; QFont f0 = item->font(0); f0.setBold(true); item->setFont(0,f0); item->setFont(1,f0); item->setText(0, name_text); item->setText(1, type_text); item->setText(2, filename_text); item->setText(3, line_text); item->setText(4, fullname_text); item->setText(5, description_text); staticTreeWidget->addTopLevelItem(item); } } }else{ // Ignore others. } //staticTreeWidget->resizeColumnToContents(0); // Name //staticTreeWidget->resizeColumnToContents(1); // Type staticTreeWidget->resizeColumnToContents(2); // Filename staticTreeWidget->resizeColumnToContents(3); // Line staticTreeWidget->resizeColumnToContents(4); // Fullname staticTreeWidget->resizeColumnToContents(5); // Description staticTreeWidget->sortByColumn(0, Qt::AscendingOrder); staticTreeWidget->setSortingEnabled(true); QApplication::restoreOverrideCursor(); } void SeerStaticBrowserWidget::handleSessionTerminated () { // Delete previous contents. staticTreeWidget->clear(); } void SeerStaticBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedFile(item->text(2), item->text(4), item->text(3).toInt()); } void SeerStaticBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QString tip = QString("Variable: %1\nType: %2\nFile: %3\nLine: %4\nFullname: %5\nDescription: %6").arg(item->text(0)).arg(item->text(1)).arg(item->text(2)).arg(item->text(3)).arg(item->text(4)).arg(item->text(5)); item->setToolTip(0, tip); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerStaticBrowserWidget::handleSearchLineEdit () { staticTreeWidget->clear(); staticTreeWidget->setSortingEnabled(false); staticTreeWidget->sortByColumn(-1, Qt::AscendingOrder); //staticTreeWidget->resizeColumnToContents(0); //staticTreeWidget->resizeColumnToContents(1); staticTreeWidget->resizeColumnToContents(2); staticTreeWidget->resizeColumnToContents(3); staticTreeWidget->resizeColumnToContents(4); staticTreeWidget->resizeColumnToContents(5); if (staticNameSearchLineEdit->text() != "" || staticTypeSearchLineEdit->text() != "") { emit refreshVariableList(_id, staticNameSearchLineEdit->text(), staticTypeSearchLineEdit->text()); } } void SeerStaticBrowserWidget::refresh () { handleSearchLineEdit(); } seer-2.7/src/SeerStaticBrowserWidget.h000066400000000000000000000023311516472651200200460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerStaticBrowserWidget.h" class SeerStaticBrowserWidget : public QWidget, protected Ui::SeerStaticBrowserWidgetForm { Q_OBJECT public: explicit SeerStaticBrowserWidget (QWidget* parent = 0); ~SeerStaticBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (); void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshVariableList (int id, const QString& staticNameRegex, const QString& staticTypeRegex); void selectedFile (QString file, QString fullname, int lineno); protected: private: int _id; }; seer-2.7/src/SeerStaticBrowserWidget.ui000066400000000000000000000047321516472651200202430ustar00rootroot00000000000000 SeerStaticBrowserWidgetForm 0 0 730 698 Static Browser Search for static variable names. "*" is allowed. Static names true Search for static variable types. "*" is allowed. Static types true 6 Variable Type File Line Full Name Description QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerStructVisualizerWidget.cpp000066400000000000000000000402371516472651200211570ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStructVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include SeerStructVisualizerWidget::SeerStructVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create id for queries. // Set up UI. setupUi(this); // Setup the widgets setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer Basic Struct Visualizer"); setAttribute(Qt::WA_DeleteOnClose); variableTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); variableTreeWidget->setMouseTracking(true); variableTreeWidget->setSortingEnabled(false); variableTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); variableTreeWidget->setRootIsDecorated(true); variableTreeWidget->setItemsExpandable(true); variableTreeWidget->resizeColumnToContents(0); // name variableTreeWidget->resizeColumnToContents(1); // value variableTreeWidget->clear(); // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerStructVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerStructVisualizerWidget::handleHelpButton); QObject::connect(variableNameLineEdit, &QLineEdit::returnPressed, this, &SeerStructVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerStructVisualizerWidget::handleContextMenu); QObject::connect(variableTreeWidget, &QTreeWidget::itemEntered, this, &SeerStructVisualizerWidget::handleItemEntered); QObject::connect(variableTreeWidget, &QTreeWidget::itemExpanded, this, &SeerStructVisualizerWidget::handleItemExpanded); QObject::connect(variableTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerStructVisualizerWidget::handleItemExpanded); // Restore window settings. readSettings(); } SeerStructVisualizerWidget::~SeerStructVisualizerWidget () { } void SeerStructVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer Basic Struct Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); // Create the initial variable in the tree. variableTreeWidget->clear(); if (variableNameLineEdit->text() != "") { QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, name); item->setText(1, ""); variableTreeWidget->addTopLevelItem(item); } // Resize columns. variableTreeWidget->resizeColumnToContents(0); variableTreeWidget->resizeColumnToContents(1); // Send signal to get variable result. if (variableNameLineEdit->text() != "") { emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } } QString SeerStructVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerStructVisualizerWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); if (id_text.toInt() == _variableId) { QTreeWidgetItem* topItem = variableTreeWidget->topLevelItem(0); if (topItem == 0) { return; } // Delete all subitems of the toplevel item. foreach (auto item, topItem->takeChildren()) delete item; // Populate the tree. handleItemCreate(topItem, value_text); // Expand everything if there are children. if (topItem->childCount() > 0) { variableTreeWidget->expandAll(); } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "msg=", '"', '"', false); if (id_text.toInt() == _variableId) { QTreeWidgetItem* topItem = variableTreeWidget->topLevelItem(0); if (topItem == 0) { return; } // Delete all subitems of the toplevel item. foreach (auto item, topItem->takeChildren()) delete item; // Set the error text. topItem->setText(1, Seer::filterEscapes(msg_text)); } }else if (text.startsWith("^error,msg=\"No registers.\"")) { variableTreeWidget->clear(); // At a stopping point, refresh. }else if (text.startsWith("*stopped,reason=\"")) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } // Resize columns. variableTreeWidget->resizeColumnToContents(0); variableTreeWidget->resizeColumnToContents(1); // Set the cursor back. QApplication::restoreOverrideCursor(); } void SeerStructVisualizerWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& value_text) { if (Seer::hasBookends(value_text, '{', '}')) { // Remove bookends QString text = Seer::filterBookends(value_text, '{', '}'); // Set the flatvalue text. parentItem->setText(1, Seer::filterEscapes(text)); // Convert to a list of name/value pairs. QStringList nv_pairs = Seer::parseCommaList(text, '{', '}'); // Go through each pair and add the name and its value to the tree. QTreeWidgetItem* prevItem = 0; for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); // Handle "name = "xxxx", '\\000' , "yyyy" ..., age = 0, salary = 0" // There is a 'first' value but no 'second'. So just concatenate unto the previous item. if (pair.second == "") { if (prevItem) { prevItem->setText(0, prevItem->text(0) + pair.first); prevItem->setText(1, ""); } // Normal case of "name = value". }else{ QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, pair.first); item->setText(1, ""); parentItem->addChild(item); // Handle recursion if value has bookends. if (Seer::hasBookends(pair.second, '{', '}')) { handleItemCreate(item, pair.second); }else{ item->setText(1, Seer::filterEscapes(pair.second)); } prevItem = item; } } parentItem->setExpanded(true); }else{ parentItem->setText(1, Seer::filterEscapes(value_text)); } } void SeerStructVisualizerWidget::handleContextMenu (const QPoint& pos) { QTreeWidgetItem* item = variableTreeWidget->itemAt(pos); if (item == 0) { return; } // Create the variable name. // It's a struct so include its parent names. QString variable; while (item) { if (variable == "") { variable = item->text(0); }else{ variable = item->text(0) + "." + variable; } item = item->parent(); } // Create the menus. QAction* addMemoryVisualizerAction; QAction* addMemoryAsteriskVisualizerAction; QAction* addMemoryAmpersandVisualizerAction; QAction* addArrayVisualizerAction; QAction* addArrayAsteriskVisualizerAction; QAction* addArrayAmpersandVisualizerAction; QAction* addMatrixVisualizerAction; QAction* addMatrixAsteriskVisualizerAction; QAction* addMatrixAmpersandVisualizerAction; QAction* addStructVisualizerAction; QAction* addStructAsteriskVisualizerAction; QAction* addStructAmpersandVisualizerAction; addMemoryVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); addMemoryAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); addMemoryAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); addArrayVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); addArrayAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); addArrayAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); addMatrixVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); addMatrixAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); addMatrixAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); addStructVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); addStructAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); addStructAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); QMenu menu("Visualizers", this); menu.setTitle("Visualizers"); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to an Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Launch the menu. Get the response. QAction* action = menu.exec(variableTreeWidget->viewport()->mapToGlobal(pos)); // Do nothing. if (action == 0) { return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { //qDebug() << "addMemoryVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { //qDebug() << "addMemoryAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { //qDebug() << "addMemoryAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { //qDebug() << "addArrayVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { //qDebug() << "addArrayAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { //qDebug() << "addArrayAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addMatrixVisualizerAction) { //qDebug() << "addMatrixVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addMatrixAsteriskVisualizerAction) { //qDebug() << "addMatrixAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addMatrixAmpersandVisualizerAction) { //qDebug() << "addMatrixAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { //qDebug() << "addStructVisualizer" << variable; // Emit the signals. if (variable != "") { emit addStructVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { //qDebug() << "addStructAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { //qDebug() << "addStructAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("&") + variable); } return; } } void SeerStructVisualizerWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + item->text(1)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerStructVisualizerWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); // Resize columns. variableTreeWidget->resizeColumnToContents(0); variableTreeWidget->resizeColumnToContents(1); } void SeerStructVisualizerWidget::handleRefreshButton () { if (variableNameLineEdit->text() == "") { return; } // Send signal to get variable result. emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } void SeerStructVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/BasicStructVisualizer.md"); help->show(); help->raise(); } void SeerStructVisualizerWidget::handleVariableNameLineEdit () { if (variableNameLineEdit->text() == "") { return; } setVariableName (variableNameLineEdit->text()); } void SeerStructVisualizerWidget::writeSettings () { QSettings settings; settings.beginGroup("structvisualizerwindow"); settings.setValue("size", size()); settings.endGroup(); } void SeerStructVisualizerWidget::readSettings () { QSettings settings; settings.beginGroup("structvisualizerwindow"); resize(settings.value("size", QSize(800, 400)).toSize()); settings.endGroup(); } void SeerStructVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } seer-2.7/src/SeerStructVisualizerWidget.h000066400000000000000000000040461516472651200206220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerStructVisualizerWidget.h" class SeerStructVisualizerWidget : public QWidget, protected Ui::SeerStructVisualizerWidgetForm { Q_OBJECT public: explicit SeerStructVisualizerWidget (QWidget* parent = 0); ~SeerStructVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleVariableNameLineEdit (); void handleContextMenu (const QPoint& pos); void handleItemEntered (QTreeWidgetItem* item, int column); void handleItemExpanded (QTreeWidgetItem* item); protected: void handleItemCreate (QTreeWidgetItem* parentItem, const QString& value_text); void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: int _variableId; }; seer-2.7/src/SeerStructVisualizerWidget.ui000066400000000000000000000063001516472651200210030ustar00rootroot00000000000000 SeerStructVisualizerWidgetForm 0 0 807 683 Form Enter a variable to visualize. Variable name true Qt::Vertical Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Qt::Vertical Help on Struct Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Variable Value QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerThreadFramesBrowserWidget.cpp000066400000000000000000000275241516472651200215320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerThreadFramesBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerThreadFramesBrowserWidget::SeerThreadFramesBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets threadTreeWidget->setMouseTracking(true); threadTreeWidget->setSortingEnabled(false); threadTreeWidget->resizeColumnToContents(0); // active threadTreeWidget->resizeColumnToContents(1); // id threadTreeWidget->resizeColumnToContents(2); // state threadTreeWidget->resizeColumnToContents(3); // target-id threadTreeWidget->resizeColumnToContents(4); // func threadTreeWidget->resizeColumnToContents(5); // file threadTreeWidget->resizeColumnToContents(6); // line threadTreeWidget->resizeColumnToContents(7); // fullname threadTreeWidget->resizeColumnToContents(8); // args threadTreeWidget->resizeColumnToContents(9); // name threadTreeWidget->resizeColumnToContents(10); // level threadTreeWidget->resizeColumnToContents(11); // addr threadTreeWidget->resizeColumnToContents(12); // arch threadTreeWidget->resizeColumnToContents(13); // core threadTreeWidget->clear(); // Connect things. QObject::connect(threadTreeWidget, &QTreeWidget::itemClicked, this, &SeerThreadFramesBrowserWidget::handleItemClicked); QObject::connect(threadTreeWidget, &QTreeWidget::itemEntered, this, &SeerThreadFramesBrowserWidget::handleItemEntered); QObject::connect(gdbNextToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbNextToolButton); QObject::connect(gdbStepToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbStepToolButton); QObject::connect(gdbFinishToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbFinishToolButton); QObject::connect(gdbContinueToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbContinueToolButton); QObject::connect(gdbInterruptToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbInterruptToolButton); } SeerThreadFramesBrowserWidget::~SeerThreadFramesBrowserWidget () { } void SeerThreadFramesBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,threads=[")) { // // ^done,threads=[ // { // id=\"1\", // target-id=\"Thread 0x7ffff7fbd740 (LWP 22356)\", // name=\"hellothreads\", // thread={ // level=\"0\", // addr=\"0x00000000004006bf\", // func=\"main\", // args=[], // file=\"hellothreads.cpp\", // fullname=\"/home/erniep/Development/Peak/src/Seer/hellothreads/hellothreads.cpp\", // line=\"27\", // arch=\"i386:x86-64\" // }, // state=\"stopped\", // core=\"0\" // }, // // { // id=\"2\", // target-id=\"Thread 0x7ffff6ed1700 (LWP 22370)\", // details=\"Exiting\", // name=\"hellothreads\", // frame={ // level=\"0\", // addr=\"0x00007ffff6f0b1c3\", // func=\"__longjmp\", // args=[], // from=\"/lib64/libc.so.6\", // arch=\"i386:x86-64\" // }, // state=\"stopped\", // core=\"6\" // } // ], // current-thread-id=\"1\" // //qDebug() << text; threadTreeWidget->clear(); QString threads_text = Seer::parseFirst(text, "threads=", '[', ']', false); QString currentthreadid_text = Seer::parseFirst(text, "current-thread-id=", '"', '"', false); //qDebug() << threads_text; if (threads_text != "") { QStringList threads_list = Seer::parse(threads_text, "", '{', '}', false); for ( const auto& thread_text : threads_list ) { QString id_text = Seer::parseFirst(thread_text, "id=", '"', '"', false); QString targetid_text = Seer::parseFirst(thread_text, "target-id=", '"', '"', false); QString name_text = Seer::parseFirst(thread_text, "name=", '"', '"', false); QString frame_text = Seer::parseFirst(thread_text, "frame=", '{', '}', false); QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(frame_text, "func=", '"', '"', false); QString args_text = Seer::parseFirst(frame_text, "args=", '[', ']', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); QString arch_text = Seer::parseFirst(frame_text, "arch=", '"', '"', false); QString state_text = Seer::parseFirst(thread_text, "state=", '"', '"', false); QString core_text = Seer::parseFirst(thread_text, "core=", '"', '"', false); //qDebug() << file_text << fullname_text; // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; if (id_text == currentthreadid_text) { item->setText(0, "*"); }else{ item->setText(0, " "); } item->setText(1, id_text); item->setText(2, state_text); item->setText(3, targetid_text); item->setText(4, func_text); item->setText(5, QFileInfo(file_text).fileName()); item->setText(6, line_text); item->setText(7, fullname_text); item->setText(8, args_text); item->setText(9, name_text); item->setText(10, level_text); item->setText(11, addr_text); item->setText(12, arch_text); item->setText(13, core_text); // Add the frame to the tree. threadTreeWidget->addTopLevelItem(item); } // Select the current thread id. threadTreeWidget->clearSelection(); QList matches = threadTreeWidget->findItems(currentthreadid_text, Qt::MatchExactly, 1); if (matches.size() > 0) { threadTreeWidget->setCurrentItem(matches.first()); } } }else if (text.startsWith("*running,thread-id=")) { refresh(); }else if (text.startsWith("=thread-created,id=")) { // =thread-created,id="2",group-id="i2" refresh(); }else if (text.startsWith("=thread-exited,id=")) { // =thread-exited,id="2",group-id="i2" refresh(); }else{ // Ignore others. } threadTreeWidget->resizeColumnToContents(0); threadTreeWidget->resizeColumnToContents(1); threadTreeWidget->resizeColumnToContents(2); threadTreeWidget->resizeColumnToContents(3); //threadTreeWidget->resizeColumnToContents(4); // Don't resize. //threadTreeWidget->resizeColumnToContents(5); // Don't resize. threadTreeWidget->resizeColumnToContents(6); //threadTreeWidget->resizeColumnToContents(7); // Don't resize. //threadTreeWidget->resizeColumnToContents(8); // Don't resize. threadTreeWidget->resizeColumnToContents(9); threadTreeWidget->resizeColumnToContents(10); threadTreeWidget->resizeColumnToContents(11); threadTreeWidget->resizeColumnToContents(12); threadTreeWidget->resizeColumnToContents(13); QApplication::restoreOverrideCursor(); } void SeerThreadFramesBrowserWidget::handleStoppingPointReached () { refresh(); } void SeerThreadFramesBrowserWidget::handleSessionTerminated () { // Delete previous contents. threadTreeWidget->clear(); } void SeerThreadFramesBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshThreadIds(); emit refreshThreadFrames(); } void SeerThreadFramesBrowserWidget::handleItemClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QList items = threadTreeWidget->selectedItems(); if (items.count() == 1) { int lineno = item->text(6).toInt(); // Select thread. emit selectedThread(item->text(1).toInt()); // Select file if we can. if (item->text(5) != "" && item->text(7) != "") { emit selectedFile(item->text(5), item->text(7), lineno); } // Select address if we can. if (item->text(11) != "") { emit maybeSelectedAddress(item->text(5), item->text(7), item->text(11)); } } } void SeerThreadFramesBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); //qDebug() << item->text(1) << column; item->setToolTip(0, item->text(1) + " : " + item->text(2) + " : " + item->text(3) + " : " + item->text(5) + " : " + item->text(6)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerThreadFramesBrowserWidget::handleGdbNextToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit nextThreadId(threadid); } } void SeerThreadFramesBrowserWidget::handleGdbStepToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit stepThreadId(threadid); } } void SeerThreadFramesBrowserWidget::handleGdbFinishToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit finishThreadId(threadid); } } void SeerThreadFramesBrowserWidget::handleGdbContinueToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit continueThreadId(threadid); } } void SeerThreadFramesBrowserWidget::handleGdbInterruptToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit interruptThreadId(threadid); } } void SeerThreadFramesBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } seer-2.7/src/SeerThreadFramesBrowserWidget.h000066400000000000000000000045231516472651200211710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerThreadFramesBrowserWidget.h" class SeerThreadFramesBrowserWidget : public QWidget, protected Ui::SeerThreadFramesBrowserWidgetForm { Q_OBJECT public: explicit SeerThreadFramesBrowserWidget (QWidget* parent = 0); ~SeerThreadFramesBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); void handleGdbNextToolButton (); void handleGdbStepToolButton (); void handleGdbFinishToolButton (); void handleGdbContinueToolButton (); void handleGdbInterruptToolButton (); signals: void refreshThreadFrames (); void refreshThreadIds (); void selectedFile (QString file, QString fullname, int lineno); void selectedAddress (QString address); void maybeSelectedAddress (QString file, QString fullname, QString address); void selectedFrame (int frameno); void selectedThread (int threadid); void nextThreadId (int threadid); void stepThreadId (int threadid); void finishThreadId (int threadid); void continueThreadId (int threadid); void interruptThreadId (int threadid); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerThreadFramesBrowserWidget.ui000066400000000000000000000125201516472651200213530ustar00rootroot00000000000000 SeerThreadFramesBrowserWidgetForm 0 0 794 528 Form Execute the next line for selected threads. Step over functions. :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Execute the next line for selected threads. Step into functions. :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Finish the current function for selected threads. :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Continue execution of selected threads. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Interrupt execution of selected threads. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Qt::Horizontal 40 20 QAbstractItemView::ExtendedSelection 14 Active Thread Id State Target Id Function File Line Fullname Arguments Name Level Address Arch Core seer-2.7/src/SeerThreadGroupsBrowserWidget.cpp000066400000000000000000000152561516472651200215730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerThreadGroupsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerThreadGroupsBrowserWidget::SeerThreadGroupsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets groupTreeWidget->setMouseTracking(true); groupTreeWidget->setSortingEnabled(false); groupTreeWidget->resizeColumnToContents(0); // id groupTreeWidget->resizeColumnToContents(1); // type groupTreeWidget->resizeColumnToContents(2); // pid groupTreeWidget->resizeColumnToContents(3); // executable groupTreeWidget->resizeColumnToContents(4); // cores groupTreeWidget->clear(); // Connect things. QObject::connect(groupTreeWidget, &QTreeWidget::itemEntered, this, &SeerThreadGroupsBrowserWidget::handleItemEntered); QObject::connect(gdbRunToolButton, &QToolButton::clicked, this, &SeerThreadGroupsBrowserWidget::handleGdbRunToolButton); QObject::connect(gdbStartToolButton, &QToolButton::clicked, this, &SeerThreadGroupsBrowserWidget::handleGdbStartToolButton); QObject::connect(gdbContinueToolButton, &QToolButton::clicked, this, &SeerThreadGroupsBrowserWidget::handleGdbContinueToolButton); QObject::connect(gdbInterruptToolButton, &QToolButton::clicked, this, &SeerThreadGroupsBrowserWidget::handleGdbInterruptToolButton); } SeerThreadGroupsBrowserWidget::~SeerThreadGroupsBrowserWidget () { } void SeerThreadGroupsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,groups=[")) { // ^done,groups=[ // { // id="i1", // type="process", // pid="5424", // executable="/home/erniep/Development/Peak/src/seer/tests/helloinferior/helloinferior", // cores=["0"] // }, // { id="i2", // type="process", // pid="5432", // executable="/home/erniep/Development/Peak/src/seer/tests/helloinferior/helloinferior", // cores=["5"] // } // ] //qDebug() << text; groupTreeWidget->clear(); QString groups_text = Seer::parseFirst(text, "groups=", '[', ']', false); //qDebug() << groups_text; if (groups_text != "") { QStringList groups_list = Seer::parse(groups_text, "", '{', '}', false); for ( const auto& group_text : groups_list ) { QString id_text = Seer::parseFirst(group_text, "id=", '"', '"', false); QString type_text = Seer::parseFirst(group_text, "type=", '"', '"', false); QString pid_text = Seer::parseFirst(group_text, "pid=", '"', '"', false); QString exe_text = Seer::parseFirst(group_text, "executable=", '"', '"', false); QString cores_text = Seer::parseFirst(group_text, "cores=", '[', ']', false); // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, id_text); item->setText(1, type_text); item->setText(2, pid_text); item->setText(3, exe_text); item->setText(4, cores_text); // Add the frame to the tree. groupTreeWidget->addTopLevelItem(item); } } }else if (text.startsWith("=thread-created,id=")) { // =thread-created,id="2",group-id="i2" refresh(); }else if (text.startsWith("=thread-exited,id=")) { // =thread-exited,id="2",group-id="i2" refresh(); }else{ // Ignore others. } groupTreeWidget->resizeColumnToContents(0); groupTreeWidget->resizeColumnToContents(1); groupTreeWidget->resizeColumnToContents(2); //groupTreeWidget->resizeColumnToContents(3); // Don't resize. groupTreeWidget->resizeColumnToContents(4); QApplication::restoreOverrideCursor(); } void SeerThreadGroupsBrowserWidget::handleSessionTerminated () { // Delete previous contents. groupTreeWidget->clear(); } void SeerThreadGroupsBrowserWidget::refresh () { emit refreshThreadIds(); emit refreshThreadGroups(); } void SeerThreadGroupsBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); //qDebug() << item->text(0) << column; item->setToolTip(0, item->text(0) + " : " + item->text(1) + " : " + item->text(2) + " : " + item->text(3) + " : " + item->text(4)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerThreadGroupsBrowserWidget::handleGdbRunToolButton () { QList items = groupTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { QString groupid = (*i)->text(0); emit runThreadGroup(groupid); } } void SeerThreadGroupsBrowserWidget::handleGdbStartToolButton () { QList items = groupTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { QString groupid = (*i)->text(0); emit startThreadGroup(groupid); } } void SeerThreadGroupsBrowserWidget::handleGdbContinueToolButton () { QList items = groupTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { QString groupid = (*i)->text(0); emit continueThreadGroup(groupid); } } void SeerThreadGroupsBrowserWidget::handleGdbInterruptToolButton () { QList items = groupTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { QString groupid = (*i)->text(0); emit interruptThreadGroup(groupid); } } void SeerThreadGroupsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } seer-2.7/src/SeerThreadGroupsBrowserWidget.h000066400000000000000000000032031516472651200212250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerThreadGroupsBrowserWidget.h" class SeerThreadGroupsBrowserWidget : public QWidget, protected Ui::SeerThreadGroupsBrowserWidgetForm { Q_OBJECT public: explicit SeerThreadGroupsBrowserWidget (QWidget* parent = 0); ~SeerThreadGroupsBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleItemEntered (QTreeWidgetItem* item, int column); void handleGdbRunToolButton (); void handleGdbStartToolButton (); void handleGdbContinueToolButton (); void handleGdbInterruptToolButton (); signals: void refreshThreadGroups (); void refreshThreadIds (); void runThreadGroup (QString threadGroup); void startThreadGroup (QString threadGroup); void continueThreadGroup (QString threadGroup); void interruptThreadGroup (QString threadGroup); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerThreadGroupsBrowserWidget.ui000066400000000000000000000077741516472651200214340ustar00rootroot00000000000000 SeerThreadGroupsBrowserWidgetForm 0 0 794 528 Form false Run selected inferiors again. Do not break in "main". :/seer/resources/RelaxLightIcons/debug-run.svg:/seer/resources/RelaxLightIcons/debug-run.svg false Run selected inferiors again. Break in "main". :/seer/resources/RelaxLightIcons/debug-run.svg:/seer/resources/RelaxLightIcons/debug-run.svg Continue execution of selected inferiors. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Interrupt execution of selected inferiors. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Qt::Horizontal 40 20 QAbstractItemView::ExtendedSelection 5 Thread Group Id Type Pid Executable Cores seer-2.7/src/SeerThreadIdsBrowserWidget.cpp000066400000000000000000000143441516472651200210300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerThreadIdsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerThreadIdsBrowserWidget::SeerThreadIdsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets idsTreeWidget->setSortingEnabled(false); idsTreeWidget->resizeColumnToContents(0); // state idsTreeWidget->resizeColumnToContents(1); // id idsTreeWidget->clear(); // Connect things. QObject::connect(idsTreeWidget, &QTreeWidget::itemClicked, this, &SeerThreadIdsBrowserWidget::handleItemClicked); QObject::connect(gdbNextToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbNextToolButton); QObject::connect(gdbStepToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbStepToolButton); QObject::connect(gdbFinishToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbFinishToolButton); QObject::connect(gdbContinueToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbContinueToolButton); QObject::connect(gdbInterruptToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbInterruptToolButton); } SeerThreadIdsBrowserWidget::~SeerThreadIdsBrowserWidget () { } void SeerThreadIdsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,thread-ids={")) { QString newtext = Seer::filterEscapes(text); // Filter escaped characters. // ^done,thread-ids={ // thread-id=\"1\", // thread-id=\"2\" // }, // current-thread-id=\"1\", // number-of-threads=\"2\" idsTreeWidget->clear(); QString threadids_text = Seer::parseFirst(newtext, "thread-ids=", '{', '}', false); QStringList threadids_list = Seer::parse(threadids_text, "thread-id=", '"', '"', false); QString currentthreadid_text = Seer::parseFirst(newtext, "current-thread-id=", '"', '"', false); // Add the thread-ids. for ( const auto& threadid_text : threadids_list ) { //qDebug() << threadid_text; // Construct the item QTreeWidgetItem* item = new QTreeWidgetItem; if (threadid_text == currentthreadid_text) { item->setText(0, "*"); }else{ item->setText(0, " "); } item->setText(1, threadid_text); // Set the text to bold if the ID is the same as the CURRENT ID. QFont fnormal = item->font(0); fnormal.setBold(false); QFont fbold = item->font(0); fbold.setBold(true); if (threadid_text == currentthreadid_text) { item->setFont(0, fbold); item->setFont(1, fbold); }else{ item->setFont(0, fnormal); item->setFont(1, fnormal); } // Add the frame to the tree. idsTreeWidget->addTopLevelItem(item); } // Clear the selection and select the one for the current thread-id. idsTreeWidget->clearSelection(); QList matches = idsTreeWidget->findItems(currentthreadid_text, Qt::MatchExactly, 1); if (matches.size() > 0) { idsTreeWidget->setCurrentItem(matches.first()); } }else{ // Ignore others. } idsTreeWidget->resizeColumnToContents(0); idsTreeWidget->resizeColumnToContents(1); QApplication::restoreOverrideCursor(); } void SeerThreadIdsBrowserWidget::handleStoppingPointReached () { refresh(); } void SeerThreadIdsBrowserWidget::handleSessionTerminated () { // Delete previous contents. idsTreeWidget->clear(); } void SeerThreadIdsBrowserWidget::handleItemClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedThread(item->text(1).toInt()); } void SeerThreadIdsBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshThreadIds(); } void SeerThreadIdsBrowserWidget::handleGdbNextToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit nextThreadId(threadid); } } void SeerThreadIdsBrowserWidget::handleGdbStepToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit stepThreadId(threadid); } } void SeerThreadIdsBrowserWidget::handleGdbFinishToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit finishThreadId(threadid); } } void SeerThreadIdsBrowserWidget::handleGdbContinueToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit continueThreadId(threadid); } } void SeerThreadIdsBrowserWidget::handleGdbInterruptToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit interruptThreadId(threadid); } } void SeerThreadIdsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } seer-2.7/src/SeerThreadIdsBrowserWidget.h000066400000000000000000000034601516472651200204720ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerThreadIdsBrowserWidget.h" class SeerThreadIdsBrowserWidget : public QWidget, protected Ui::SeerThreadIdsBrowserWidgetForm { Q_OBJECT public: explicit SeerThreadIdsBrowserWidget (QWidget* parent = 0); ~SeerThreadIdsBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemClicked (QTreeWidgetItem* item, int column); void handleGdbNextToolButton (); void handleGdbStepToolButton (); void handleGdbFinishToolButton (); void handleGdbContinueToolButton (); void handleGdbInterruptToolButton (); signals: void refreshThreadIds (); void selectedThread (int threadid); void nextThreadId (int threadid); void stepThreadId (int threadid); void finishThreadId (int threadid); void continueThreadId (int threadid); void interruptThreadId (int threadid); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerThreadIdsBrowserWidget.ui000066400000000000000000000077251516472651200206700ustar00rootroot00000000000000 SeerThreadIdsBrowserWidgetForm 0 0 794 528 Form Execute the next line for selected threads. Step over functions. :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Execute the next line for selected threads. Step into functions. :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Finish the current function for selected threads. :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Continue execution of selected threads. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Interrupt execution of selected threads. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Qt::Horizontal 40 20 2 Active Thread Id seer-2.7/src/SeerThreadManagerWidget.cpp000066400000000000000000000246021516472651200203150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerThreadManagerWidget.h" #include "SeerHelpPageDialog.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include #include #include SeerThreadManagerWidget::SeerThreadManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(false); _threadFramesBrowserWidget = new SeerThreadFramesBrowserWidget(this); _threadIdsBrowserWidget = new SeerThreadIdsBrowserWidget(this); _threadGroupsBrowserWidget = new SeerThreadGroupsBrowserWidget(this); _adaTasksBrowserWidget = new SeerAdaTasksBrowserWidget(this); tabWidget->addTab(_threadFramesBrowserWidget, "Frames"); tabWidget->addTab(_threadIdsBrowserWidget, "Ids"); tabWidget->addTab(_threadGroupsBrowserWidget, "Groups"); tabWidget->addTab(_adaTasksBrowserWidget, "AdaTasks"); QToolButton* tabsContextMenuButton = new QToolButton(tabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QToolButton* refreshToolButton = new QToolButton(tabWidget); refreshToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/view-refresh.svg")); refreshToolButton->setToolTip("Refresh the thread information."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on thread information."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); hcontainer->addWidget(refreshToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Restore tab ordering. readSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerThreadManagerWidget::handleTabsContextMenuButtonClicked); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerThreadManagerWidget::handleRefreshToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerThreadManagerWidget::handleHelpToolButtonClicked); QObject::connect(schedulerLockingComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerThreadManagerWidget::handleSchedulerLockingComboBox); QObject::connect(scheduleMultipleComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerThreadManagerWidget::handleScheduleMultipleComboBox); QObject::connect(forkFollowsComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerThreadManagerWidget::handleForkFollowComboBox); QObject::connect(tabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerThreadManagerWidget::handleTabMoved); QObject::connect(tabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerThreadManagerWidget::handleTabChanged); } SeerThreadManagerWidget::~SeerThreadManagerWidget () { } SeerThreadFramesBrowserWidget* SeerThreadManagerWidget::threadFramesBrowserWidget () { return _threadFramesBrowserWidget; } SeerThreadIdsBrowserWidget* SeerThreadManagerWidget::threadIdsBrowserWidget () { return _threadIdsBrowserWidget; } SeerThreadGroupsBrowserWidget* SeerThreadManagerWidget::threadGroupsBrowserWidget () { return _threadGroupsBrowserWidget; } SeerAdaTasksBrowserWidget* SeerThreadManagerWidget::adaTasksBrowserWidget () { return _adaTasksBrowserWidget; } void SeerThreadManagerWidget::setSchedulerLockingMode (const QString& mode) { schedulerLockingComboBox->setCurrentText(mode); } QString SeerThreadManagerWidget::schedulerLockingMode () const { return schedulerLockingComboBox->currentText(); } void SeerThreadManagerWidget::setScheduleMultipleMode (const QString& mode) { scheduleMultipleComboBox->setCurrentText(mode); } QString SeerThreadManagerWidget::scheduleMultipleMode () const { return scheduleMultipleComboBox->currentText(); } void SeerThreadManagerWidget::setForkFollowsMode (const QString& mode) { forkFollowsComboBox->setCurrentText(mode); } QString SeerThreadManagerWidget::forkFollowsMode () const { return forkFollowsComboBox->currentText(); } void SeerThreadManagerWidget::handleRefreshToolButtonClicked () { threadFramesBrowserWidget()->refresh(); threadIdsBrowserWidget()->refresh(); threadGroupsBrowserWidget()->refresh(); adaTasksBrowserWidget()->refresh(); } void SeerThreadManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/ThreadProcessInfoBrowser.md"); help->show(); help->raise(); } void SeerThreadManagerWidget::handleSchedulerLockingComboBox (int index) { Q_UNUSED(index); emit schedulerLockingModeChanged(schedulerLockingComboBox->currentText()); } void SeerThreadManagerWidget::handleScheduleMultipleComboBox (int index) { Q_UNUSED(index); emit scheduleMultipleModeChanged(scheduleMultipleComboBox->currentText()); } void SeerThreadManagerWidget::handleForkFollowComboBox (int index) { Q_UNUSED(index); emit forkFollowsModeChanged(forkFollowsComboBox->currentText()); } void SeerThreadManagerWidget::handleTabMoved (int from, int to) { Q_UNUSED(from); Q_UNUSED(to); writeSettings(); } void SeerThreadManagerWidget::handleTabChanged (int index) { Q_UNUSED(index); writeSettings(); } void SeerThreadManagerWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(tabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(tabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = tabWidget->tabBar()->tabText(tabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; QSettings settings; settings.beginGroup("threadmanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerThreadManagerWidget::readSettings () { // Can't move things? if (tabWidget->tabBar()->isMovable() == false) { return; } // Read tab order from settings. QSettings settings; QStringList tabs; QStringList visible; QString current; settings.beginGroup("threadmanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (tabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { tabWidget->tabBar()->moveTab(tb, i); } } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { tabWidget->setTabVisible(i,false); }else{ tabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (tabWidget->tabBar()->tabText(i) == current) { tabWidget->setCurrentIndex(i); break; } } }else{ tabWidget->setCurrentIndex(0); } } void SeerThreadManagerWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < tabWidget->count(); i++) { QString title = tabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(tabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (tabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { tabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ tabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } seer-2.7/src/SeerThreadManagerWidget.h000066400000000000000000000065031516472651200177620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerThreadFramesBrowserWidget.h" #include "SeerThreadIdsBrowserWidget.h" #include "SeerThreadGroupsBrowserWidget.h" #include "SeerAdaTasksBrowserWidget.h" #include #include "ui_SeerThreadManagerWidget.h" class SeerThreadManagerWidget : public QWidget, protected Ui::SeerThreadManagerWidgetForm { Q_OBJECT public: explicit SeerThreadManagerWidget (QWidget* parent = 0); ~SeerThreadManagerWidget (); SeerThreadFramesBrowserWidget* threadFramesBrowserWidget (); SeerThreadIdsBrowserWidget* threadIdsBrowserWidget (); SeerThreadGroupsBrowserWidget* threadGroupsBrowserWidget (); SeerAdaTasksBrowserWidget* adaTasksBrowserWidget (); signals: void schedulerLockingModeChanged (const QString& mode); void scheduleMultipleModeChanged (const QString& mode); void forkFollowsModeChanged (const QString& mode); protected: void writeSettings (); void readSettings (); public slots: void setSchedulerLockingMode (const QString& mode); QString schedulerLockingMode () const; void setScheduleMultipleMode (const QString& mode); QString scheduleMultipleMode () const; void setForkFollowsMode (const QString& mode); QString forkFollowsMode () const; private slots: void handleRefreshToolButtonClicked (); void handleHelpToolButtonClicked (); void handleSchedulerLockingComboBox (int index); void handleScheduleMultipleComboBox (int index); void handleForkFollowComboBox (int index); void handleTabMoved (int from, int to); void handleTabChanged (int index); void handleTabsContextMenuButtonClicked (); private: SeerThreadFramesBrowserWidget* _threadFramesBrowserWidget; SeerThreadIdsBrowserWidget* _threadIdsBrowserWidget; SeerThreadGroupsBrowserWidget* _threadGroupsBrowserWidget; SeerAdaTasksBrowserWidget* _adaTasksBrowserWidget; }; seer-2.7/src/SeerThreadManagerWidget.ui000066400000000000000000000126751516472651200201570ustar00rootroot00000000000000 SeerThreadManagerWidgetForm 0 0 398 520 Form 0 0 0 0 3 font-weight: bold; Thread/Process Info Qt::PlainText -1 50 0 Scheduler locking: 50 0 Schedule multiple: Qt::Vertical 50 0 Fork follows: Qt::Horizontal QSizePolicy::Ignored 0 20 Set the scheduler locking mode. replay off on step Set the mode for allowing threads of multiple processes to be resumed when an execution command is issued. off on Set the debugger response to a program call of fork or vfork. parent child both Qt::Horizontal QSizePolicy::Ignored 0 20 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
seer-2.7/src/SeerTildeLogWidget.cpp000066400000000000000000000012631516472651200173140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerTildeLogWidget.h" #include "SeerUtl.h" #include SeerTildeLogWidget::SeerTildeLogWidget (QWidget* parent) : SeerLogWidget(parent) { } SeerTildeLogWidget::~SeerTildeLogWidget () { } void SeerTildeLogWidget::processText (const QString& text) { QString str = text.mid(1); // Remove leading "~" if (str.front() == '"') { // Remove leading """ str = str.mid(1); } if (str.back() == '"') { // Remove trailing """ str.chop(1); } str = Seer::filterEscapes(str); textEdit->insertPlainText(str); } seer-2.7/src/SeerTildeLogWidget.h000066400000000000000000000006271516472651200167640ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerLogWidget.h" class SeerTildeLogWidget : public SeerLogWidget { Q_OBJECT public: explicit SeerTildeLogWidget (QWidget* parent = 0); ~SeerTildeLogWidget (); void processText (const QString& text); }; seer-2.7/src/SeerTypeBrowserWidget.cpp000066400000000000000000000132771516472651200201060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerTypeBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerTypeBrowserWidget::SeerTypeBrowserWidget (QWidget* parent) : QWidget(parent) { // Set the state. _id = Seer::createID(); // Construct the UI. setupUi(this); // Setup the widgets typeSearchLineEdit->setPlaceholderText("Search regex..."); typeSearchLineEdit->setClearButtonEnabled(true); typeTreeWidget->setMouseTracking(true); //typeTreeWidget->resizeColumnToContents(0); typeTreeWidget->resizeColumnToContents(1); typeTreeWidget->resizeColumnToContents(2); typeTreeWidget->resizeColumnToContents(3); typeTreeWidget->clear(); typeTreeWidget->setSortingEnabled(false); // Connect things. QObject::connect(typeTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerTypeBrowserWidget::handleItemDoubleClicked); QObject::connect(typeTreeWidget, &QTreeWidget::itemEntered, this, &SeerTypeBrowserWidget::handleItemEntered); QObject::connect(typeSearchLineEdit, &QLineEdit::returnPressed, this, &SeerTypeBrowserWidget::handleSearchLineEdit); } SeerTypeBrowserWidget::~SeerTypeBrowserWidget () { } void SeerTypeBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith(QString::number(_id) + "^done,symbols={") && text.endsWith("}")) { typeTreeWidget->clear(); typeTreeWidget->setSortingEnabled(false); typeTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // -symbol-info-types [--name name_regexp] // [--max-results limit] // // ^done,symbols={ // debug=[ // { // filename="/peak/rel/include/CnvLib.h",fullname="/home/erniep/Development/Peak/rel/include/CnvLib.h", // symbols=[ // { // line="8", // name="Cnv" // } // ] // }, // ... // ] // } QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false); QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false); for (const auto& filename_entry : filenames_list) { QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false); QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false); QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false); QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false); for (const auto& symbol_entry : symbols_list) { QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false); QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false); // Skip type entries that have no line number. if (line_text == "") { continue; } // Add the type to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; QFont f0 = item->font(0); f0.setBold(true); item->setFont(0,f0); item->setText(0, name_text); item->setText(1, filename_text); item->setText(2, line_text); item->setText(3, fullname_text); typeTreeWidget->addTopLevelItem(item); } } }else{ // Ignore others. } //typeTreeWidget->resizeColumnToContents(0); typeTreeWidget->resizeColumnToContents(1); typeTreeWidget->resizeColumnToContents(2); typeTreeWidget->resizeColumnToContents(3); typeTreeWidget->sortByColumn(0, Qt::AscendingOrder); typeTreeWidget->setSortingEnabled(true); QApplication::restoreOverrideCursor(); } void SeerTypeBrowserWidget::handleSessionTerminated () { // Delete previous contents. typeTreeWidget->clear(); } void SeerTypeBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedFile(item->text(1), item->text(3), item->text(2).toInt()); } void SeerTypeBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QString tip = QString("Type: %1\nFile: %2\nLine: %3\nFullname: %4").arg(item->text(0)).arg(item->text(1)).arg(item->text(2)).arg(item->text(3)); item->setToolTip(0, tip); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerTypeBrowserWidget::handleSearchLineEdit () { typeTreeWidget->clear(); typeTreeWidget->setSortingEnabled(false); typeTreeWidget->sortByColumn(-1, Qt::AscendingOrder); //typeTreeWidget->resizeColumnToContents(0); typeTreeWidget->resizeColumnToContents(1); typeTreeWidget->resizeColumnToContents(2); typeTreeWidget->resizeColumnToContents(3); if (typeSearchLineEdit->text() != "") { emit refreshTypeList(_id, typeSearchLineEdit->text()); } } void SeerTypeBrowserWidget::refresh () { handleSearchLineEdit(); } seer-2.7/src/SeerTypeBrowserWidget.h000066400000000000000000000022511516472651200175410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerTypeBrowserWidget.h" class SeerTypeBrowserWidget : public QWidget, protected Ui::SeerTypeBrowserWidgetForm { Q_OBJECT public: explicit SeerTypeBrowserWidget (QWidget* parent = 0); ~SeerTypeBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (); void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshTypeList (int id, const QString& typeRegex); void selectedFile (QString file, QString fullname, int lineno); protected: private: int _id; }; seer-2.7/src/SeerTypeBrowserWidget.ui000066400000000000000000000031271516472651200177320ustar00rootroot00000000000000 SeerTypeBrowserWidgetForm 0 0 730 698 Type Browser 4 Type File Line Full Name Search in the list of types. "*" is allowed. QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerUtl.cpp000066400000000000000000001157411516472651200152200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerUtl.h" #include #include #include #include #include #include // Comment out for now. I don't want to include boost because // that would impact people try to compile Seer. Qt6 offer // a 'stacktrace' function. OpenSuse may be slow in adoption. // For now, comment it out and use when needed. // #include #include #include // // Increment this with every release on GitHub. // See scripts/change_versionnumber // #define SEER_VERSION "2.7" namespace Seer { QString version () { return SEER_VERSION + QString(" (Qt") + QT_VERSION_STR + ")"; } QString filterBareNewLines (const QString& str) { // Remove bare (not inside quotes) '\n' substrings. // Maybe extra spaces after '\n'. // "{\n B = 1,\n C = 0,\n D = \"asd\",\n E = std::vector of length 1, capacity 64 = {true}\n}" // "{B = 1, C = 0, D = \"asd\", E = std::vector of length 1, capacity 64 = {true}}" QString tmp; qsizetype anchor=0; qsizetype curr=0; qsizetype end=str.length(); // Loop through string a character at a time. while (curr < end) { // Found a '\n' substring. Deal with it. if (str.mid(curr,2) == "\\n") { // Append the good bits before the '\n'. tmp.append(str.mid(anchor,curr-anchor)); curr += 2; // Skip trailing spaces, if any, after '\n'. while (curr < end) { if (str.at(curr) == ' ') { curr++; }else{ break; } } anchor = curr; // Other character. Skip it. }else{ curr++; } } // Anything left to deal with? if (curr > anchor) { tmp.append(str.mid(anchor,curr-anchor)); anchor = curr; } return tmp; } QString filterEscapes (const QString& str) { // Remove one level of '\'. // value="\"'Treasure' by Lucillius\\n\\n\\tbut theirs.\\n\"" QString tmp; bool escaped = false; for (int i=0; i 0) { r.remove(i, len); r.insert(i, value); }else{ f = false; // Not expanded. break; } } while (true) { QRegularExpressionMatch match = env_re2.match(r); if (match.hasMatch() == false) { break; } qsizetype i = match.capturedStart(); qsizetype len = match.capturedLength(); QString capstr = match.captured(); QString envstr = capstr.mid(1,capstr.length()-1); QByteArray value(qgetenv(envstr.toLatin1().data())); if (value.size() > 0) { r.remove(i, len); r.insert(i, value); }else{ f = false; // Not expanded. break; } } if (ok) { *ok = f; } return r; } QStringList parse (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearchString) { // // str = "^done,stack-args=[frame={level=\"0\",args=[{name=\"message\",value=\"\\\"Hello, World!\\\"\"}]},frame={level=\"1\",args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\"0x7fffffffd5b8\"}]}]" // search = "frame=" // startBracket = '{' // endBracket = '}' // QStringList list; QString searchWord = search + startBracket; // 'frame={' int from = 0; while (1) { // Look for the next occurance of the search word. int index = str.indexOf(searchWord,from); if (index < 0) { // If not found, we're done. break; } // Set things up to look for the matching end bracket. int start = index + search.size() + 1; // Positioned after 'frame={' int end = start + 1; int bracketLevel = 1; // Start with one start bracket already encountered. for (end=start; end= 0) { if (str[end-1] == '\\') { escaped = true; } } if (startBracket != endBracket) { // Do this test if brackets are not the same character. if (str[end] == startBracket && escaped == false) { // Encountered another start bracket, increment the level. bracketLevel++; } } if (str[end] == endBracket && escaped == false) { // Encountered an end bracket, decrement the level. bracketLevel--; if (bracketLevel == 0) { // If the level is 0, we're done. break; } } } // Are things valid? if (bracketLevel != 0) { // No matching bracket. break; } if (end > str.size()) { // The end is past the end of the string. break; } // Build the string. QString tmp; if (includeSearchString) { tmp = search + startBracket + str.mid(start, end-start) + endBracket; }else{ tmp = str.mid(start, end-start); } // Add it to the list. list.append(tmp); // Go back for more from = end + 1; } // Return the list. return list; } QString parseFirst (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearchString) { QStringList list = Seer::parse(str, search, startBracket, endBracket, includeSearchString); if (list.size() == 0) { return QString(); } return list.front(); } QString parseFirst (const QString& str, const QString& search, bool includeSearchString) { QString match; // Look for the next occurance of the search word. int index = str.indexOf(search,0); if (index < 0) { // If not found, we're done. return match; } // Set things up to look for the matching end bracket. int start = index + search.size() + 0; // Position after 'msg=' int end = str.size(); if (includeSearchString) { match = search + str.mid(start, end-start); }else{ match = str.mid(start, end-start); } return match; } bool hasBookends (const QString& str, QChar startBracket, QChar endBracket) { if (str.startsWith(startBracket) && str.endsWith(endBracket)) { return true; } return false; } QString filterBookends (const QString& str, QChar startBracket, QChar endBracket) { // If the string starts with and ends with the bracket characters, then return // the text between the brackets. if (str.startsWith(startBracket) && str.endsWith(endBracket)) { return str.mid(1,str.size()-2); } // Otherwise, return the orginal string. return str; } QStringList filterBookends (const QStringList& strings, QChar startBracket, QChar endBracket) { QStringList list; // For a list of strings, remove the bookends, if possible. for (int i=0; i, \"hildTest 2000-", '0' , "1", '0' , "330324377377377177000000004", '0' , "test\", '000' , \"325377377\", child = {childId = -9864, childString = \"\"}} enum STATE{ START = 0, SCANNING = 1, FOUND = 2, IGNORE = 3, }; QStringList list; int index = 0; int start = 0; int end = 0; int previousComma= 0; STATE state = START; while (index < str.length()) { // Handle "=" if (str[index] == '=') { if (state == SCANNING) // looking for 2nd '=' { // state = FOUND; end = previousComma; QString field = str.mid(start, end-start); list.append(field.trimmed()); start = previousComma + 1; } if (state == START) // looking for 2nd '=' { state = SCANNING; } } if (str[index] == startBracket) { state = IGNORE; } if (str[index] == endBracket) { state = SCANNING; } if (str[index] == ',' && state != IGNORE) { previousComma = index; } // The last if (index == str.length() - 1) { QString field = str.mid(start, index); list.append(field.trimmed()); } index++; } return list; } // // Parse an array, turn it to QList // QStringList parseArray (const QString& parentName, const QString& str) { // Input: {age = 1, name = "1st_child"}, {age = 2, name = "2nd_child"} // Output: QStringList : parentName[0] = {age = 1, name = "1st_child"}, parentName[1] = {age = 1, name = "1st_child"} QStringList list; int index = 0; int cntStartBracket = 0; int cntEndBracket = 0; int start = 0; int cnt = 0; while (index < str.length()) { if (str[index] == '{') { if (cntStartBracket == cntEndBracket) start = index; cntStartBracket++; } if (str[index] == '}') { // Check to see if character after it is ",". Otherwise, it probably trash character. if (index + 1 < str.length()) { if (str[index + 1] == '}' || str[index + 1] == ',' || index + 1 == str.length() ) { cntEndBracket++; if (cntStartBracket == cntEndBracket) { QString field = str.mid(start, index + 1 - start); field = parentName + "[" + QString::number(cnt) + "] = " + field; list.append(field.trimmed()); cntStartBracket = 0; cntEndBracket = 0; cnt++; } } } else if (index + 1 == str.length()) { // The last element cntEndBracket++; if (cntStartBracket == cntEndBracket) { QString field = str.mid(start, index + 1 - start); field = parentName + "[" + QString::number(cnt) + "] = " + field; list.append(field.trimmed()); cntStartBracket = 0; cntEndBracket = 0; cnt++; } } } index ++; } return list; } QMap createKeyValueMap (const QStringList& list, QChar separator) { QMap map; for (const auto& i : list) { QStringPair pair = parseNameValue(i, separator); map[pair.first] = pair.second; } return map; } // // // QStringPair parseNameValue (const QString& str, QChar separator) { // name = "Pasveer, Ernie" // // pair.first = name // pair.second = "Pasveer, Ernie" // QStringPair pair; int index = 0; int state = 0; int start = 0; int end = 0; bool inquotes = false; while (index < str.length()) { // Handle start of field. if (state == 0) { // Start of field. start = index; end = index; state = 1; // Look for end of field (a command or eol). continue; } // Handle end of field. if (state == 1) { // Handle """ if (str[index] == '"') { if (inquotes == false) { inquotes = true; }else{ inquotes = false; } index++; continue; } // Handle "=" separator. if (str[index] == separator) { if (inquotes) { index++; continue; } // Extract the two fields. index is at the "=". end = index; QString one = str.mid(start, end-start); QString two = str.mid(end+1); pair = QStringPair(one.trimmed(),two.trimmed()); state = 0; // Look for the next field. break; } // Handle any other character. index++; continue; } qDebug() << "Bad state!"; index++; continue; } // Handle if no "=" separator. if (state == 1) { pair = QStringPair(str.trimmed(),QString()); } return pair; } // // Quote certain characters in a string. // // "hello" => \"hello\" // QString quoteChars (const QString& str, const QString& chars) { QString string; for (int i=0; i= 0x060000 QRegularExpression re = QRegularExpression::fromWildcard(pattern, Qt::CaseInsensitive, QRegularExpression::UnanchoredWildcardConversion); #else // With Qt5, 'wildcardToRegularExpression' needs a "/*" at the start of 'pattern' // if 'string' start with a "/". //if (string[0] == '/') { // if (pattern[0] != '/') { // pattern = "/*/" + pattern; // } //} // This pattern needs to be converted from a glob to a regex. // All '*' are replaced with '.*' // The pattern is terminated with a '$', if it doesn't have one. pattern.replace("*", ".*"); //if (string[0] != '/') { // if (pattern.back() != '$') { // pattern += '$'; // } //} // qDebug() << pattern << string; // QRegularExpression re = QRegularExpression(QRegularExpression::wildcardToRegularExpression(pattern)); QRegularExpression re = QRegularExpression(pattern); #endif if (re.match(string).hasMatch()) { return true; } } return false; } bool hasWildcards (const QString& str) { return (str.indexOf('*') >= 0) || (str.indexOf('?') >= 0); } QString elideText (const QString& str, Qt::TextElideMode mode, int length) { QString leftElide("... "); QString middleElide(" ... "); QString rightElide(" ..."); // The string is fine. Just return it. if (str.length() <= length) { return str; } // The string is too long but don't add elide. if (mode == Qt::ElideNone) { return str.left(length); } // The string is too long. Add elilde on the left. if (mode == Qt::ElideLeft) { return leftElide + str.right(length); } // The string is too long. Add elilde on the right. if (mode == Qt::ElideRight) { return str.left(length) + rightElide; } // The string is too long. Add elilde in the middle. if (mode == Qt::ElideRight) { int halve = length / 2; return str.left(halve) + middleElide + str.right(halve); } // Bad mode. Just return the string. return str; } // Split a string on words. Double "quoted strings" // act as one word. QStringList split (const QString& str) { QRegularExpression re("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'"); QStringList list; QRegularExpressionMatchIterator i = re.globalMatch(str); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString word; if (match.captured(2) != "") { word = match.captured(2); }else if (match.captured(1) != "") { word = match.captured(1); }else if (match.captured(0) != "") { word = match.captured(0); } if (word != "") { list << word; } } return list; } // // // static int Next_ID = 1; static std::mutex ID_mutex; int createID () { std::lock_guard guard(ID_mutex); int id = Next_ID; Next_ID++; return id; } unsigned char ebcdicToAscii (unsigned char byte) { static const unsigned char ebcdicToAsciiTable[256] = { 46, 46, 46, 46, 46, 46, 46, 46, // 0 46, 46, 46, 46, 46, 46, 46, 46, // 8 46, 46, 46, 46, 46, 46, 46, 46, // 16 46, 46, 46, 46, 46, 46, 46, 46, // 24 46, 46, 46, 46, 46, 46, 46, 46, // 32 46, 46, 46, 46, 46, 46, 46, 46, // 40 46, 46, 46, 46, 46, 46, 46, 46, // 48 46, 46, 46, 46, 46, 46, 46, 46, // 56 32, 46, 46, 46, 46, 46, 46, 46, // 64 46, 46, 91, 46, 60, 40, 43, 33, // 72 38, 46, 46, 46, 46, 46, 46, 46, // 80 46, 46, 33, 36, 42, 41, 59, 94, // 88 45, 47, 46, 46, 46, 46, 46, 46, // 96 46, 46, 124, 44, 37, 95, 62, 63, // 104 46, 46, 46, 46, 46, 46, 46, 46, // 112 46, 96, 58, 35, 64, 39, 61, 34, // 120 46, 97, 98, 99, 100, 101, 102, 103, // 128 104, 105, 46, 46, 46, 46, 46, 46, // 136 46, 106, 107, 108, 109, 110, 111, 112, // 144 113, 114, 46, 46, 46, 46, 46, 46, // 152 46, 126, 115, 116, 117, 118, 119, 120, // 160 121, 122, 46, 46, 46, 46, 46, 46, // 168 46, 46, 46, 46, 46, 46, 46, 46, // 176 46, 46, 46, 46, 46, 46, 46, 46, // 184 123, 65, 66, 67, 68, 69, 70, 71, // 192 72, 73, 46, 46, 46, 46, 46, 46, // 200 125, 74, 75, 76, 77, 78, 79, 80, // 208 81, 82, 46, 46, 46, 46, 46, 46, // 216 92, 46, 83, 84, 85, 86, 87, 88, // 224 89, 90, 46, 46, 46, 46, 46, 46, // 232 48, 49, 50, 51, 52, 53, 54, 55, // 240 56, 57, 46, 46, 46, 46, 46, 46 // 248 }; return ebcdicToAsciiTable[byte]; } unsigned char ucharToAscii (unsigned char byte) { static const unsigned char ucharToAsciiTable[256] = { 46, 46, 46, 46, 46, 46, 46, 46, // 0 46, 46, 46, 46, 46, 46, 46, 46, // 8 46, 46, 46, 46, 46, 46, 46, 46, // 16 46, 46, 46, 46, 46, 46, 46, 46, // 24 32, 33, 34, 35, 36, 37, 38, 39, // 32 40, 41, 42, 43, 44, 45, 46, 47, // 40 48, 49, 50, 51, 52, 53, 54, 55, // 48 56, 57, 58, 59, 60, 61, 62, 63, // 56 64, 65, 66, 67, 68, 69, 70, 71, // 64 72, 73, 74, 75, 76, 77, 78, 79, // 72 80, 81, 82, 83, 84, 85, 86, 87, // 80 88, 89, 90, 91, 92, 93, 94, 95, // 88 96, 97, 98, 99, 100, 101, 102, 103, // 96 104, 105, 106, 107, 108, 109, 110, 111, // 104 112, 113, 114, 115, 116, 117, 118, 119, // 112 120, 121, 122, 123, 124, 125, 126, 46, // 120 46, 46, 46, 46, 46, 46, 46, 46, // 128 46, 46, 46, 46, 46, 46, 46, 46, // 136 46, 46, 46, 46, 46, 46, 46, 46, // 144 46, 46, 46, 46, 46, 46, 46, 46, // 152 46, 46, 46, 46, 46, 46, 46, 46, // 160 46, 46, 46, 46, 46, 46, 46, 46, // 168 46, 46, 46, 46, 46, 46, 46, 46, // 176 46, 46, 46, 46, 46, 46, 46, 46, // 184 46, 46, 46, 46, 46, 46, 46, 46, // 192 46, 46, 46, 46, 46, 46, 46, 46, // 200 46, 46, 46, 46, 46, 46, 46, 46, // 208 46, 46, 46, 46, 46, 46, 46, 46, // 216 46, 46, 46, 46, 46, 46, 46, 46, // 224 46, 46, 46, 46, 46, 46, 46, 46, // 232 46, 46, 46, 46, 46, 46, 46, 46, // 240 46, 46, 46, 46, 46, 46, 46, 46 // 248 }; return ucharToAsciiTable[byte]; } QString ucharToHex (const QVector& bytes, int from, int count) { QString str; str.reserve(count*2+4); for (int i=from; i= bytes.size()) { break; } quint8 decimal = bytes[i]; QString hex = QString("%1").arg(decimal, 2, 16, QLatin1Char('0')); str += hex; } return str; } QString ucharToOctal (const QVector& bytes, int from, int count) { QString str; str.reserve(count*3+4); for (int i=from; i= bytes.size()) { break; } quint8 decimal = bytes[i]; QString octal = QString("%1").arg(decimal, 3, 8, QLatin1Char('0')); str += octal; } return str; } QString ucharToAscii (const QVector& bytes, int from, int count) { QString str; str.reserve(count); for (int i=from; i= bytes.size()) { break; } quint8 decimal = bytes[i]; QString ascii = QChar(Seer::ucharToAscii(decimal)); str += ascii; } return str; } QString ucharToUShort (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } quint16 decimal = *(quint16*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(quint16); } return str; } QString ucharToShort (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } qint16 decimal = *(qint16*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(qint16); } return str; } QString ucharToUInt (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } quint32 decimal = *(quint32*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(quint32); } return str; } QString ucharToInt (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } qint32 decimal = *(qint32*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(qint32); } return str; } QString ucharToULong (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } quint64 decimal = *(quint64*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(quint64); } return str; } QString ucharToLong (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } qint64 decimal = *(qint64*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(qint64); } return str; } QString ucharToFloat (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } float real = *(float*)(bytes.data()+from); QString val = QString("%1").arg(real); if (i != 0) { str += " "; } str += val; from += sizeof(float); } return str; } QString ucharToDouble (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } double real = *(double*)(bytes.data()+from); QString val = QString("%1").arg(real); if (i != 0) { str += " "; } str += val; from += sizeof(double); } return str; } int typeBytes (const QString& type) { if (type == "int8" || type == "uint8") { return 1; }else if (type == "int16" || type == "uint16") { return 2; }else if (type == "int32" || type == "uint32") { return 4; }else if (type == "int64" || type == "uint64") { return 8; }else if (type == "float32") { return 4; }else if (type == "float64") { return 8; }else{ qWarning() << "Bad data type:" << type; return 0; } } bool readFile (const QString& filename, QStringList& lines) { // Empty the list lines = QStringList(); // Open the file. QFile file(filename); if (file.open(QIODevice::ReadOnly) == false) { qDebug() << "Can't open:" << filename; return false; } // Read the file line-by-line and build up the string list. while (file.atEnd() == false) { QString line = file.readLine(); line.chop(1); lines.append(line); } file.close(); // All good. return true; } QString unescape (const QString& str) { QString result; bool quoted = false; // Maybe reserve `str.length()` bytes in result, so that it will not allocate during `push_back()` result.reserve(str.length()); // Loop through each character in 'str'. Look for a '\'. for (int i=0; i= str.length()) { // Nope, just add it. result.push_back(str[i]); break; } // If the following character is another '\', skip the first one. // This removes one level of '\'. if (str[i+1] == QChar('\\')) { continue; } // Treat the following character as an escaped character. // Unescape it. (Is that even a word?) switch(str[i+1].unicode()) { // We don't want to unescape things that are in double quotes. // So keep track of that. (Not the more fool proof implementation). case QChar('\"').unicode(): result.push_back(QChar('\"')); if (quoted) { quoted = false; }else{ quoted = true; } break; case QChar('n').unicode(): if (quoted == false) { result.push_back(QChar('\n')); }else{ result.push_back(QChar('\\')); result.push_back(str[i+1]); } break; case QChar('\'').unicode(): if (quoted == false) { result.push_back(QChar('\'')); }else{ result.push_back(QChar('\\')); result.push_back(str[i+1]); } break; case QChar('\\').unicode(): if (quoted == false) { result.push_back(QChar('\\')); }else{ result.push_back(QChar('\\')); result.push_back(str[i+1]); } break; case QChar('t').unicode(): if (quoted == false) { result.push_back(QChar('\t')); }else{ result.push_back(QChar('\\')); result.push_back(str[i+1]); } break; // and so on for \a, \b, \e, \f, \r, \t, \v // maybe handle octal, hexadecimal ASCII and Unicode forms, but probably in the more distant future // ... default: // unknown escape sequence — do not escape it — I think it is reasonable default result.push_back(QChar('\\')); result.push_back(str[i+1]); break; } i++; // Normal character. Just add it. }else{ result.push_back(str[i]); } } return result; } void printStackTrace () { // Capture and print the stack trace using Boost.Stacktrace. // See comments at top. // std::cout << "Stack trace:\n" << boost::stacktrace::stacktrace() << std::endl; } } seer-2.7/src/SeerUtl.h000066400000000000000000000106611516472651200146600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "QStringPair.h" #include #include #include #include // 1. A helper macro that accepts an argument and stringifies it. #define STRINGIFY_HELPER(x) #x // 2. The main macro that forces expansion of 'x' before passing it to the helper. #define STRINGIFY(x) STRINGIFY_HELPER(x) namespace Seer { QString version (); QString filterBareNewLines (const QString& str); QString filterEscapes (const QString& str); QStringList filterEscapes (const QStringList& strings); QString expandTabs (const QString& str, int tabwidth, bool morph); QString expandEnv (const QString& str, bool* ok = nullptr); QStringList parse (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearch); QString parseFirst (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearch); QString parseFirst (const QString& str, const QString& search, bool includeSearch); bool hasBookends (const QString& str, QChar startBracket, QChar endBracket); QString filterBookends (const QString& str, QChar startBracket, QChar endBracket); QStringList filterBookends (const QStringList& strings, QChar startBracket, QChar endBracket); QStringList parseCommaList (const QString& str); QStringList parseCommaList (const QString& str, QChar startBracket, QChar endBracket); QStringList parseArray (const QString& parentName, const QString& str); QMap createKeyValueMap (const QStringList& list, QChar separator); QStringPair parseNameValue (const QString& str, QChar separator); QString quoteChars (const QString& str, const QString& chars); QStringList quoteChars (const QStringList& strings, const QString& chars); QString varObjParent (const QString& str); bool matchesWildcard (const QStringList& regexpatterns, const QString& string); bool hasWildcards (const QString& str); QString elideText (const QString& str, Qt::TextElideMode mode, int length); QStringList split (const QString& str); QString unescape (const QString& str); int createID (); unsigned char ebcdicToAscii (unsigned char byte); unsigned char ucharToAscii (unsigned char byte); QString ucharToHex (const QVector& bytes, int from, int count); QString ucharToOctal (const QVector& bytes, int from, int count); QString ucharToAscii (const QVector& bytes, int from, int count); QString ucharToUShort (const QVector& bytes, int from, int count); QString ucharToShort (const QVector& bytes, int from, int count); QString ucharToUInt (const QVector& bytes, int from, int count); QString ucharToInt (const QVector& bytes, int from, int count); QString ucharToULong (const QVector& bytes, int from, int count); QString ucharToLong (const QVector& bytes, int from, int count); QString ucharToFloat (const QVector& bytes, int from, int count); QString ucharToDouble (const QVector& bytes, int from, int count); int typeBytes (const QString& type); bool readFile (const QString& filename, QStringList& lines); void printStackTrace (); } seer-2.7/src/SeerVarVisualizerWidget.cpp000066400000000000000000001131161516472651200204200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerVarVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QEditDelegate.h" #include #include #include #include #include #include #include #include #include #include SeerVarVisualizerWidget::SeerVarVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create id for queries. // Set up UI. setupUi(this); // Setup the widgets setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer Struct Visualizer"); setAttribute(Qt::WA_DeleteOnClose); variableNameLineEdit->setFocus(); variableTreeWidget->setMouseTracking(true); variableTreeWidget->setSortingEnabled(false); variableTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); variableTreeWidget->setRootIsDecorated(true); variableTreeWidget->setItemsExpandable(true); variableTreeWidget->resizeColumnToContents(0); // variable variableTreeWidget->resizeColumnToContents(1); // value variableTreeWidget->resizeColumnToContents(2); // type variableTreeWidget->resizeColumnToContents(3); // varobj name variableTreeWidget->resizeColumnToContents(4); // varobj id variableTreeWidget->resizeColumnToContents(5); // exp variableTreeWidget->resizeColumnToContents(6); // numchild variableTreeWidget->resizeColumnToContents(7); // thread-id variableTreeWidget->resizeColumnToContents(8); // has_more variableTreeWidget->resizeColumnToContents(9); // editable variableTreeWidget->clear(); // Show debug columns. debugCheckBox->setChecked(false); debugCheckBox->hide(); // Create edit delegate. // The value column will allow editing of the cell. However, some cells can then // individually disable it again. ie: If the cell is for a node, not a value. // See 'new QTreeWidgetItem' QAllowEditDelegate* editDelegate = new QAllowEditDelegate(this); variableTreeWidget->setItemDelegateForColumn(0, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(1, editDelegate); variableTreeWidget->setItemDelegateForColumn(2, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(3, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(4, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(5, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(6, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(7, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(8, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(9, new QNoEditDelegate(this)); // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerVarVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerVarVisualizerWidget::handleHelpButton); QObject::connect(debugCheckBox, &QCheckBox::clicked, this, &SeerVarVisualizerWidget::handleDebugCheckBox); QObject::connect(variableNameLineEdit, &QLineEdit::returnPressed, this, &SeerVarVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerVarVisualizerWidget::handleContextMenu); QObject::connect(variableTreeWidget, &QTreeWidget::itemEntered, this, &SeerVarVisualizerWidget::handleItemEntered); QObject::connect(variableTreeWidget, &QTreeWidget::itemExpanded, this, &SeerVarVisualizerWidget::handleItemExpanded); QObject::connect(variableTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerVarVisualizerWidget::handleItemCollapsed); QObject::connect(expandSelectedToolButton, &QToolButton::clicked, this, &SeerVarVisualizerWidget::handleExpandSelected); QObject::connect(collapseSelectedToolButton, &QToolButton::clicked, this, &SeerVarVisualizerWidget::handleCollapseSelected); QObject::connect(editDelegate, &QAllowEditDelegate::editingStarted, this, &SeerVarVisualizerWidget::handleIndexEditingStarted); QObject::connect(editDelegate, &QAllowEditDelegate::editingFinished, this, &SeerVarVisualizerWidget::handleIndexEditingFinished); // Show/hide columns. handleDebugCheckBox(); // Restore window settings. readSettings(); } SeerVarVisualizerWidget::~SeerVarVisualizerWidget () { // Send signal to delete variable. if (_variableName != "") { emit varObjDelete(_variableId, _variableName); } } void SeerVarVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer Struct Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); // Send signal to delete old variable. if (_variableName != "") { emit varObjDelete(_variableId, _variableName); _variableName = ""; } // Create the initial variable in the tree. variableTreeWidget->clear(); if (variableNameLineEdit->text() != "") { QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, name); item->setText(1, ""); item->setText(2, ""); item->setText(3, ""); item->setText(4, ""); item->setText(5, ""); item->setText(6, ""); item->setText(7, ""); item->setText(8, ""); item->setText(9, ""); variableTreeWidget->addTopLevelItem(item); } // Resize columns. handleResizeColumns(); // Send signal to get variable result. if (variableNameLineEdit->text() != "") { emit varObjCreate(_variableId, variableNameLineEdit->text()); } } QString SeerVarVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerVarVisualizerWidget::handleText (const QString& text) { if (text.contains(QRegularExpression("^([0-9]+)\\^done,name="))) { // // "-var-create x2112 "*" me" // // "4^done,name=\"seer4\",numchild=\"1\",value=\"{...}\",type=\"Person\",thread-id=\"1\",has_more=\"0\"" // -------------- // QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { //qDebug() << "var-create" << text; QString name_text = Seer::parseFirst(text, "name=", '"', '"', false); QString exp_text = Seer::parseFirst(text, "exp=", '"', '"', false); QString numchild_text = Seer::parseFirst(text, "numchild=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString type_text = Seer::parseFirst(text, "type=", '"', '"', false); QString threadid_text = Seer::parseFirst(text, "thread-id=", '"', '"', false); QString hasmore_text = Seer::parseFirst(text, "has_more=", '"', '"', false); QTreeWidgetItem* topItem = variableTreeWidget->topLevelItem(0); if (topItem == 0) { return; } int varObjID = Seer::createID(); // Create id for queries. topItem->setText(1, Seer::filterEscapes(value_text)); topItem->setText(2, type_text); topItem->setText(3, name_text); topItem->setText(4, QString::number(varObjID)); topItem->setText(5, exp_text); topItem->setText(6, numchild_text); topItem->setText(7, threadid_text); topItem->setText(8, hasmore_text); topItem->setText(9, ""); if (exp_text != "") { topItem->setText(0, exp_text); } //XXX Ask for its editable attributes. //XXX emit varObjAttributes (varObjID, name_text); // If there are children, add a placeholder. if (numchild_text != "0") { if (type_text.endsWith('*')) { if (Seer::filterEscapes(value_text) != "0x0") { // If it is a pointer that is not null, add a placeholder. How universal is this for other languages? QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, name_text); topItem->addChild(child); }else{ deleteItems(topItem->takeChildren()); } }else{ // A non-pointer child, add a placeholder. QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, name_text); topItem->addChild(child); } } // Save the VarObj name. _variableName = name_text; } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,numchild="))) { // // "-var-list-children --all-values x2112.public" // // "4^done,numchild="1", children=[ // ------------ // child={name="x2112.public",exp="public",numchild="4",thread-id="1"} // ], // has_more="0" // QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { //qDebug() << "var-list-children" << text; QString children_text = Seer::parseFirst(text, "children=", '[', ']', false); QStringList child_list = Seer::parse(children_text, "child=", '{', '}', false); QString hasmore_text = Seer::parseFirst(text, "has_more=", '"', '"', false); for (const auto& child_text : child_list) { QString name_text = Seer::parseFirst(child_text, "name=", '"', '"', false); QString exp_text = Seer::parseFirst(child_text, "exp=", '"', '"', false); QString numchild_text = Seer::parseFirst(child_text, "numchild=", '"', '"', false); QString value_text = Seer::parseFirst(child_text, "value=", '"', '"', false); QString type_text = Seer::parseFirst(child_text, "type=", '"', '"', false); QString threadid_text = Seer::parseFirst(child_text, "thread-id=", '"', '"', false); // Do we have an existing item to add to? QTreeWidgetItem* matchItem = findItem(Seer::varObjParent(name_text), Qt::MatchExactly|Qt::MatchRecursive, 3); // No, just add to the top level. if (matchItem == 0) { // This shouldn't really happen. qDebug() << name_text << "from the listchildren does not exist in the tree."; // Yes, add to it. }else{ // See if item has a "{...}" child. If so, remove it and any other siblings. if (matchItem->childCount() > 0) { QTreeWidgetItem* childItem = matchItem->child(0); if (childItem->text(0) == "{...}") { deleteItems(matchItem->takeChildren()); } } // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; int varObjID = Seer::createID(); // Create id for queries. item->setText(0, ""); item->setText(1, Seer::filterEscapes(value_text)); item->setText(2, type_text); item->setText(3, name_text); item->setText(4, QString::number(varObjID)); item->setText(5, exp_text); item->setText(6, numchild_text); item->setText(7, threadid_text); item->setText(8, hasmore_text); item->setText(9, ""); item->setFlags(item->flags() | Qt::ItemIsEditable); //XXX Set item editable if it can. if (exp_text != "") { item->setText(0, exp_text); } //XXX Ask for its editable attributes. //XXX emit varObjAttributes (varObjID, name_text); // If there are children, add a placeholder. bool expandItem = false; if (numchild_text != "0") { if (type_text.endsWith('*')) { if (Seer::filterEscapes(value_text) != "0x0") { // If it is a pointer that is not null, add a placeholder. How universal is this for other languages? QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, name_text); item->addChild(child); }else{ deleteItems(item->takeChildren()); } }else{ // A non-pointer child, add a placeholder. QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, name_text); item->addChild(child); expandItem = true; } } matchItem->addChild(item); if (expandItem == true && expandRecursiveCheckBox->isChecked()) { item->setExpanded(true); } } } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,changelist="))) { //qDebug() << "var-update-children" << text; // // "4^done,changelist=[ // {name=\"seer4.public.age\", value=\"60\", in_scope=\"true\", type_changed=\"false\", has_more=\"0\"}, // {name=\"seer4.public.salary\", value=\"0.25\", in_scope=\"true\", type_changed=\"false\", has_more=\"0\"}, // {name=\"seer4.public.location.public.city\", value=\"\\\"Houston\\\"\", in_scope=\"true\", type_changed=\"false\", displayhint=\"string\", dynamic=\"1\", has_more=\"0\"}, // {name=\"seer4.public.location.public.state\", value=\"\\\"Texas\\\"\", in_scope=\"true\", type_changed=\"false\", displayhint=\"string\", dynamic=\"1\", has_more=\"0\"}, // {name=\"seer4.public.location.public.zip\", value=\"77063\", in_scope=\"true\", type_changed=\"false\", has_more=\"0\"} // ]" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { QString changelist_text = Seer::parseFirst(text, "changelist=", '[', ']', false); QStringList child_list = Seer::parse(changelist_text, "", '{', '}', false); for (const auto& child_text : child_list) { QString name_text = Seer::parseFirst(child_text, "name=", '"', '"', false); QString value_text = Seer::parseFirst(child_text, "value=", '"', '"', false); QString inscope_text = Seer::parseFirst(child_text, "in_scope=", '"', '"', false); QString typechanged_text = Seer::parseFirst(child_text, "type_changed=", '"', '"', false); QString displayhint_text = Seer::parseFirst(child_text, "displayhint=", '"', '"', false); QString dynamic_text = Seer::parseFirst(child_text, "dynamic=", '"', '"', false); QString hasmore_text = Seer::parseFirst(child_text, "has_more=", '"', '"', false); // Do we have an existing item to add to? QTreeWidgetItem* matchItem = findItem(name_text, Qt::MatchExactly|Qt::MatchRecursive, 3); // No, just add to the top level. if (matchItem == 0) { qDebug() << name_text << "from the changelist does not exist in the tree."; // Yes, add to it. }else{ matchItem->setText(1, Seer::filterEscapes(value_text)); matchItem->setText(7, hasmore_text); // If there are children, add a placeholder. if (matchItem->text(5) != "0") { if (matchItem->text(2).endsWith('*')) { if (Seer::filterEscapes(matchItem->text(1)) != "0x0") { // If it is a pointer that is not null, add a placeholder. How universal is this for other languages? QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, matchItem->text(3)); matchItem->addChild(child); }else{ deleteItems(matchItem->takeChildren()); } }else{ // A non-pointer child, add a placeholder. QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, matchItem->text(3)); matchItem->addChild(child); } } // Need to refresh? if (typechanged_text == "true") { handleRefreshButton(); } } } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,attr="))) { //qDebug() << "var-show-attributes" << text; // 4^done,attr="noneditable" // 4^done,attr="editable" QString id_text = text.section('^', 0,0); QString editable_text = Seer::parseFirst(text, "attr=", '"', '"', false); // Do we have any items that match the varobjid? QTreeWidgetItem* matchItem = findItem(id_text, Qt::MatchExactly|Qt::MatchRecursive, 4); if (matchItem) { matchItem->setText(9, editable_text); if (editable_text == "editable") { matchItem->setFlags(matchItem->flags() | Qt::ItemIsEditable); }else{ matchItem->setFlags(matchItem->flags() & ~Qt::ItemIsEditable); } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "msg=", '"', '"', false); if (id_text.toInt() == _variableId) { QMessageBox::warning(this, "Seer", QString("Visualizer Error: '%1'\n").arg(Seer::filterEscapes(msg_text)), QMessageBox::Ok); } if (msg_text.contains("Variable object is not editable")) { if (_previousEditName != "") { QTreeWidgetItem* matchItem = findItem(_previousEditName, Qt::MatchExactly|Qt::MatchRecursive, 3); if (matchItem) { matchItem->setText(1, _previousEditValue); } } } }else if (text.startsWith("^error,msg=\"No registers.\"")) { variableTreeWidget->clear(); // At a stopping point, refresh. }else if (text.startsWith("*stopped,reason=\"")) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } // Resize columns. handleResizeColumns(); } void SeerVarVisualizerWidget::handleContextMenu (const QPoint& pos) { QTreeWidgetItem* item = variableTreeWidget->itemAt(pos); if (item == 0) { return; } // Create the variable name. // If it's a struct, include its parent names. QString variable = fullVariableName(item); // Create the menus. QAction* expandItemAction = new QAction(QString("Expand item")); QAction* collapseItemAction = new QAction(QString("Collapse item")); QAction* addMemoryVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); QAction* addMemoryAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); QAction* addMemoryAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); QAction* addArrayVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); QAction* addArrayAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); QAction* addArrayAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); QAction* addMatrixVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); QAction* addMatrixAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); QAction* addMatrixAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); QAction* addVarVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); QAction* addVarAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); QAction* addVarAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); expandItemAction->setIcon(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg")); collapseItemAction->setIcon(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg")); // Are we on an item that has children? expandItemAction->setEnabled(false); collapseItemAction->setEnabled(false); expandItemAction->setText(QString("Expand item '%1'").arg(item->text(0))); collapseItemAction->setText(QString("Collapse item '%1'").arg(item->text(0))); if (item->childCount() > 0) { if (item->isExpanded() == false) { expandItemAction->setEnabled(true); }else{ collapseItemAction->setEnabled(true); } } // Populate the menu. QMenu menu("Visualizers", this); menu.setTitle("Visualizers"); menu.addAction(expandItemAction); menu.addAction(collapseItemAction); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to an Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addVarVisualizerAction); structVisualizerMenu.addAction(addVarAsteriskVisualizerAction); structVisualizerMenu.addAction(addVarAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Launch the menu. Get the response. QAction* action = menu.exec(variableTreeWidget->viewport()->mapToGlobal(pos)); // Do nothing. if (action == 0) { return; } // Handle expanding the current item. if (action == expandItemAction) { expandItem(item); return; } // Handle collapsing the current item. if (action == collapseItemAction) { collapseItem(item); return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { //qDebug() << "addMemoryVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { //qDebug() << "addMemoryAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { //qDebug() << "addMemoryAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { //qDebug() << "addArrayVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { //qDebug() << "addArrayAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { //qDebug() << "addArrayAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addMatrixVisualizerAction) { //qDebug() << "addMatrixVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addMatrixAsteriskVisualizerAction) { //qDebug() << "addMatrixAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addMatrixAmpersandVisualizerAction) { //qDebug() << "addMatrixAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addVarVisualizerAction) { //qDebug() << "addVarVisualizer" << variable; // Emit the signals. if (variable != "") { emit addVarVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addVarAsteriskVisualizerAction) { //qDebug() << "addVarAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addVarVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addVarAmpersandVisualizerAction) { //qDebug() << "addVarAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addVarVisualizer(QString("&") + variable); } return; } } void SeerVarVisualizerWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QString text = toolTipText(item); if (text != "") { for (int i=0; icolumnCount(); i++) { // Set tooltip to all columns. item->setToolTip(i, text); } // Ask for its editable attributes. if (item->text(4) != "") { //XXX emit varObjAttributes (item->text(4).toInt(), item->text(3)); } } } void SeerVarVisualizerWidget::handleItemExpanded (QTreeWidgetItem* item) { // Ask for the children. emit varObjListChildren(_variableId, item->text(3)); // Resize columns in a sec. // Have to schedule the resize later. Doing it immediatedly messes up the // tree display. Must be a Qt bug. QTimer::singleShot(100, this, &SeerVarVisualizerWidget::handleResizeColumns); } void SeerVarVisualizerWidget::handleItemCollapsed (QTreeWidgetItem* item) { // Delete all children items. deleteItems(item->takeChildren()); // If there are children, add a placeholder. if (item->text(5) != "0") { if (item->text(2).endsWith('*')) { if (Seer::filterEscapes(item->text(1)) != "0x0") { // If it is a pointer that is not null, add a placeholder. How universal is this for other languages? QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, item->text(3)); item->addChild(child); } }else{ // A non-pointer child, add a placeholder. QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, item->text(3)); item->addChild(child); } } // Resize columns in a sec. // Have to schedule the resize later. Doing it immediatedly messes up the // tree display. Must be a Qt bug. QTimer::singleShot(100, this, &SeerVarVisualizerWidget::handleResizeColumns); } void SeerVarVisualizerWidget::handleExpandSelected () { // Expand the current item, if selected. if (variableTreeWidget->currentItem()) { expandItem(variableTreeWidget->currentItem()); return; } // Or the entire tree. if (variableTreeWidget->topLevelItemCount() > 0) { expandItem(variableTreeWidget->topLevelItem(0)); } } void SeerVarVisualizerWidget::handleCollapseSelected () { // Collapse the current item, if selected. if (variableTreeWidget->currentItem()) { collapseItem(variableTreeWidget->currentItem()); return; } // Or the entire tree. if (variableTreeWidget->topLevelItemCount() > 0) { collapseItem(variableTreeWidget->topLevelItem(0)); } } void SeerVarVisualizerWidget::handleResizeColumns () { // Resize columns. variableTreeWidget->resizeColumnToContents(0); variableTreeWidget->resizeColumnToContents(1); variableTreeWidget->resizeColumnToContents(2); variableTreeWidget->resizeColumnToContents(3); variableTreeWidget->resizeColumnToContents(4); variableTreeWidget->resizeColumnToContents(5); variableTreeWidget->resizeColumnToContents(6); variableTreeWidget->resizeColumnToContents(7); variableTreeWidget->resizeColumnToContents(8); variableTreeWidget->resizeColumnToContents(9); } void SeerVarVisualizerWidget::handleHideDebugColumns (bool flag) { variableTreeWidget->setColumnHidden(0, false); variableTreeWidget->setColumnHidden(1, false); variableTreeWidget->setColumnHidden(2, false); variableTreeWidget->setColumnHidden(3, flag); variableTreeWidget->setColumnHidden(4, flag); variableTreeWidget->setColumnHidden(5, flag); variableTreeWidget->setColumnHidden(6, flag); variableTreeWidget->setColumnHidden(7, flag); variableTreeWidget->setColumnHidden(8, flag); variableTreeWidget->setColumnHidden(9, flag); handleResizeColumns(); } void SeerVarVisualizerWidget::handleRefreshButton () { // Send signal to get variable result. if (_variableName != "") { emit varObjUpdate(_variableId, _variableName); } } void SeerVarVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/StructVisualizer.md"); help->show(); help->raise(); } void SeerVarVisualizerWidget::handleDebugCheckBox () { handleHideDebugColumns(!debugCheckBox->isChecked()); } void SeerVarVisualizerWidget::handleVariableNameLineEdit () { if (variableNameLineEdit->text() == "") { return; } setVariableName (variableNameLineEdit->text()); } void SeerVarVisualizerWidget::handleIndexEditingStarted (const QModelIndex& index) { _previousEditName = ""; _previousEditValue = ""; QTreeWidgetItem* item = variableTreeWidget->getItemFromIndex(index); if (item == 0) { return; } // Get the old value; _previousEditName = item->text(3); _previousEditValue = item->text(1); } void SeerVarVisualizerWidget::handleIndexEditingFinished (const QModelIndex& index) { QTreeWidgetItem* item = variableTreeWidget->getItemFromIndex(index); if (item == 0) { return; } // Get the new value; QString value = item->text(1); // If it hasn't changed, we do need to bother. if (value == _previousEditValue) { _previousEditName = ""; _previousEditValue = ""; return; } // Emit the signal to change the varobj to the new value. emit varObjAssign(_variableId, item->text(3), value); } QTreeWidgetItem* SeerVarVisualizerWidget::findItem (const QString& text, Qt::MatchFlags flags, int column) { QList matches = variableTreeWidget->findItems(text, flags, column); if (matches.size() == 0) { return nullptr; } return matches[0]; } void SeerVarVisualizerWidget::writeSettings () { QSettings settings; settings.beginGroup("varvisualizerwindow"); settings.setValue("size", size()); settings.endGroup(); } void SeerVarVisualizerWidget::readSettings () { QSettings settings; settings.beginGroup("varvisualizerwindow"); resize(settings.value("size", QSize(800, 400)).toSize()); settings.endGroup(); } void SeerVarVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } void SeerVarVisualizerWidget::expandItem (QTreeWidgetItem* item) { if (item->childCount() == 0) { return; } if (item->isExpanded() == false) { item->setExpanded(true); } } void SeerVarVisualizerWidget::collapseItem (QTreeWidgetItem* item) { if (item->childCount() == 0) { return; } if (item->isExpanded() == true) { item->setExpanded(false); } } QString SeerVarVisualizerWidget::fullVariableName (QTreeWidgetItem* item) { // If the item has no value or type, then return no variable. if (item->text(1) == "" || item->text(2) == "") { return ""; } // Otherwise traverse up the tree to build up a variable name string, which includes '.' or '->' // depending if the type ends with a '*'. QString name; QTreeWidgetItem* tmp = item; while (tmp) { // Skip items that have no value or type. 'public', 'private', 'protected'. if (tmp->text(1) == "" || tmp->text(2) == "" || (tmp->text(0) == tmp->text(2))) { tmp = tmp->parent(); continue; } // Add the variable part to the variable name. if (tmp->childCount() > 0) { if (tmp->text(2).endsWith('*')) { if (name == "") { name.prepend(tmp->text(0)); }else{ name.prepend(tmp->text(0) + "->"); } }else{ if (name == "") { name.prepend(tmp->text(0)); }else{ name.prepend(tmp->text(0) + "."); } } }else{ name.prepend(tmp->text(0)); } // Move to the parent to get the type, if we can. tmp = tmp->parent(); } return name; } QString SeerVarVisualizerWidget::toolTipText (QTreeWidgetItem* item) { // If the item has no value or type, then return no tooltip. if (item->text(1) == "" || item->text(2) == "") { return ""; } // Get the full variable name. QString name = fullVariableName(item); if (name == "") { return name; } // Tack on the variable value and type. QString text = name + " : " + item->text(1) + " : " + item->text(2); return text; } void SeerVarVisualizerWidget::debug (QString message, QTreeWidgetItem* item) { // 0 variable // 1 value // 2 type // 3 varobj name // 4 varobj id // 5 exp // 6 numchild // 7 thread-id // 8 has_more // 8 editable if (item == 0) { qDebug() << message << "NULL"; }else{ qDebug() << message << item->text(0) << item->text(1) << item->text(2) << item->text(3) << item->text(4) << item->text(5) << item->text(6) << item->text(7) << item->text(8) << item->text(9); } } void SeerVarVisualizerWidget::deleteItems (QList items) { // Loop through the list and delete the items. // Note, the list will still contain pointers, but they will be invalid. foreach (auto item, items) delete item; } seer-2.7/src/SeerVarVisualizerWidget.h000066400000000000000000000075421516472651200200720ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerVarVisualizerWidget.h" class SeerVarVisualizerWidget : public QWidget, protected Ui::SeerVarVisualizerWidgetForm { Q_OBJECT public: explicit SeerVarVisualizerWidget (QWidget* parent = 0); ~SeerVarVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; signals: void varObjCreate (int expressionid, QString expression); void varObjListChildren (int expressionid, QString objname); void varObjUpdate (int expressionid, QString objname); void varObjDelete (int expressionid, QString objname); void varObjAssign (int expressionid, QString objname, QString value); void varObjAttributes (int objid, QString objname); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addVarVisualizer (QString expression); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleDebugCheckBox (); void handleVariableNameLineEdit (); void handleIndexEditingStarted (const QModelIndex& index); void handleIndexEditingFinished (const QModelIndex& index); void handleContextMenu (const QPoint& pos); void handleItemEntered (QTreeWidgetItem* item, int column); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleExpandSelected (); void handleCollapseSelected (); void handleResizeColumns (); void handleHideDebugColumns (bool flag); protected: QTreeWidgetItem* findItem (const QString& text, Qt::MatchFlags flags, int column); void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: void expandItem (QTreeWidgetItem* item); void collapseItem (QTreeWidgetItem* item); QString fullVariableName (QTreeWidgetItem* item); QString toolTipText (QTreeWidgetItem* item); void debug (QString message, QTreeWidgetItem* item); void deleteItems (QList items); int _variableId; QString _variableName; QString _previousEditName; QString _previousEditValue; }; seer-2.7/src/SeerVarVisualizerWidget.ui000066400000000000000000000144671516472651200202640ustar00rootroot00000000000000 SeerVarVisualizerWidgetForm 0 0 798 683 Form Enter a variable to visualize. Variable name true Qt::Vertical Expand items below current selection. :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Collapse items below current selection. :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Show more variable details. Debug Expand recursively. Recursive Qt::Vertical Refresh the list. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Qt::Vertical Help on Struct Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Variable Value Type VarObj VarObjID Exp NumChild ThreadID HasMore Editable QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
QIndexTreeWidget QTreeWidget
QIndexTreeWidget.h
variableNameLineEdit expandSelectedToolButton collapseSelectedToolButton debugCheckBox expandRecursiveCheckBox refreshToolButton autoRefreshCheckBox helpToolButton variableTreeWidget
seer-2.7/src/SeerVariableLoggerBrowserWidget.cpp000066400000000000000000000465531516472651200220550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerVariableLoggerBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include SeerVariableLoggerBrowserWidget::SeerVariableLoggerBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets variablesTreeWidget->setMouseTracking(true); variablesTreeWidget->setSortingEnabled(false); variablesTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); variablesTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); variablesTreeWidget->resizeColumnToContents(0); // timestamp variablesTreeWidget->resizeColumnToContents(1); // name variablesTreeWidget->resizeColumnToContents(2); // value variablesTreeWidget->resizeColumnToContents(3); // id variablesTreeWidget->setColumnHidden(3, true); // Hide the 'id' column. variablesTreeWidget->clear(); // Connect things. QObject::connect(this, &SeerVariableLoggerBrowserWidget::evaluateVariableExpression, this, &SeerVariableLoggerBrowserWidget::handleEvaluateVariableExpression); QObject::connect(variableAddLineEdit, &QLineEdit::returnPressed, this, &SeerVariableLoggerBrowserWidget::handleAddLineEdit); QObject::connect(variableDeleteToolButton, &QToolButton::clicked, this, &SeerVariableLoggerBrowserWidget::handleDeleteToolButton); QObject::connect(variableDeleteAllToolButton, &QToolButton::clicked, this, &SeerVariableLoggerBrowserWidget::handleDeleteAllToolButton); QObject::connect(variablesTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerVariableLoggerBrowserWidget::handleItemCollapsed); QObject::connect(variablesTreeWidget, &QTreeWidget::itemExpanded, this, &SeerVariableLoggerBrowserWidget::handleItemExpanded); QObject::connect(variablesTreeWidget, &QTreeWidget::itemEntered, this, &SeerVariableLoggerBrowserWidget::handleItemEntered); QObject::connect(variablesTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerVariableLoggerBrowserWidget::handleContextMenu); } SeerVariableLoggerBrowserWidget::~SeerVariableLoggerBrowserWidget () { } void SeerVariableLoggerBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // "6^done,value=\"\\\"abc\\\"\"" QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); if (_ids.contains(id_text.toInt()) == false) { break; } // If with brackets (a structure), filter out excess '\n' // in case pretty-print-on is used. if (value_text.front() == '{' && value_text.back() == '}') { value_text = Seer::filterBareNewLines(value_text); } QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 3); if (matches.size() > 0) { QTreeWidgetItem* match = matches[0]; Q_ASSERT(match->parent() == NULL); QString timestamp_text = match->text(0); QString name_text = match->text(1); // Populate the tree. handleItemCreate(match, id_text, timestamp_text, name_text, value_text); emit raiseTab(); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // "1^error,msg=\"No symbol \\\"j\\\" in current context.\"" QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "msg=", '"', '"', false); if (_ids.contains(id_text.toInt()) == true) { QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 3); if (matches.size() > 0) { matches.first()->setText(1, ""); // Overwrite "name" with "" because it's not a valid "name". matches.first()->setText(2, Seer::filterEscapes(msg_text)); } emit raiseTab(); } }else{ // Ignore others. } // Resize columns. variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); // Scroll to the bottom. QTreeWidgetItem* lastItem = variablesTreeWidget->topLevelItem(variablesTreeWidget->topLevelItemCount()-1); if (lastItem) { variablesTreeWidget->scrollToItem(lastItem); } break; } // Set the cursor back. QApplication::restoreOverrideCursor(); } void SeerVariableLoggerBrowserWidget::handleSessionTerminated () { // Delete previous contents. variablesTreeWidget->clear(); } void SeerVariableLoggerBrowserWidget::handleEvaluateVariableExpression (int expressionid, QString expression) { QString id_text = QString::number(expressionid); if (_ids.contains(id_text.toInt()) == false) { return; } // Add new item. Will be filled in by handleText(). QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, QTime::currentTime().toString(Qt::TextDate)); item->setText(1, expression); item->setText(2, ""); item->setText(3, id_text); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); variablesTreeWidget->addTopLevelItem(item); // Resize columns done later in handleText(). } void SeerVariableLoggerBrowserWidget::addVariableExpression (QString expression) { if (expression != "") { int id = Seer::createID(); _ids.insert(id); // Keep track of which ones are entered. emit evaluateVariableExpression(id, expression); } } void SeerVariableLoggerBrowserWidget::handleAddLineEdit () { QString expression = variableAddLineEdit->text(); variableAddLineEdit->clear(); if (expression != "") { int id = Seer::createID(); _ids.insert(id); // Keep track of which ones are entered. emit evaluateVariableExpression(id, expression); } } void SeerVariableLoggerBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = variablesTreeWidget->selectedItems(); // Remove them. for (int i=0; iresizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableLoggerBrowserWidget::handleDeleteAllToolButton () { // Remove all. variablesTreeWidget->clear(); // Resize columns. variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableLoggerBrowserWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableLoggerBrowserWidget::handleItemCollapsed (QTreeWidgetItem* item) { Q_UNUSED(item); variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableLoggerBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + item->text(1) + " : " + Seer::elideText(item->text(2), Qt::ElideRight, 100)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerVariableLoggerBrowserWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& id_text, const QString& timestamp_text, const QString& name_text, const QString& value_text) { // Add the complex entry to the tree. if (Seer::hasBookends(value_text, '{', '}')) { // Remove bookends QString text = Seer::filterBookends(value_text, '{', '}'); // Set the flatvalue text. parentItem->setText(0, timestamp_text); parentItem->setText(1, name_text); parentItem->setText(2, Seer::filterEscapes(text)); parentItem->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); parentItem->setText(3, id_text); // Convert to a list of name/value pairs. QStringList nv_pairs; if (text.startsWith("{")) { // String might describe an array: {a=1, b=1},{a=1, b=1},{a=1, b=1},{a=1, b=1} // parentItem->text(0) is timestamp -> parent name should be parentItem->text(1) nv_pairs = Seer::parseArray(parentItem->text(1), text); } else { nv_pairs = Seer::parseCommaList(text, '{', '}'); } // Go through each pair and add the name and its value to the tree. for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); // Create a new item and attach it to the parent. QTreeWidgetItem* item = new QTreeWidgetItem; handleItemCreate(item, id_text, timestamp_text, pair.first, pair.second); parentItem->addChild(item); } // Add the simple entry to the tree. }else{ parentItem->setText(0, timestamp_text); parentItem->setText(1, name_text); parentItem->setText(2, Seer::filterEscapes(value_text)); parentItem->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); parentItem->setText(3, id_text); } } void SeerVariableLoggerBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = variablesTreeWidget->itemAt(pos); // Construct the menu. QAction* addMemoryVisualizerAction = new QAction(); QAction* addMemoryAsteriskVisualizerAction = new QAction(); QAction* addMemoryAmpersandVisualizerAction = new QAction(); QAction* addArrayVisualizerAction = new QAction(); QAction* addArrayAsteriskVisualizerAction = new QAction(); QAction* addArrayAmpersandVisualizerAction = new QAction(); QAction* addMatrixVisualizerAction = new QAction(); QAction* addMatrixAsteriskVisualizerAction = new QAction(); QAction* addMatrixAmpersandVisualizerAction = new QAction(); QAction* addStructVisualizerAction = new QAction(); QAction* addStructAsteriskVisualizerAction = new QAction(); QAction* addStructAmpersandVisualizerAction = new QAction(); QMenu menu("Options", this); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); QAction* deleteAction = menu.addAction("Delete selected"); QAction* deleteAllAction = menu.addAction("Delete all"); QAction* copyAction = menu.addAction("Copy selected"); QAction* copyValueOnlyAction = menu.addAction("Copy selected value"); QAction* copyAllAction = menu.addAction("Copy all"); QString actionText; if (item != 0) { actionText = item->text(1); } QString variable; if (item != 0) { // Build up a variable string, incase it is a nested struct. QTreeWidgetItem* i = item; variable = item->text(1); while (i->parent() != 0) { variable = i->parent()->text(1) + "." + variable; i = i->parent(); } } // Remove potential '&' and '*' characters at start of string. variable.remove(QRegularExpression("^[\\*\\&]*")); addMemoryVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addMemoryAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addMemoryAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addArrayVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addArrayAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addArrayAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addMatrixVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addMatrixAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addMatrixAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addStructVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addStructAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addStructAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); // If no selected item, disable everything but allow 'copyall' and 'deleteall'. if (item == 0) { memoryVisualizerMenu.setEnabled(false); arrayVisualizerMenu.setEnabled(false); matrixVisualizerMenu.setEnabled(false); structVisualizerMenu.setEnabled(false); deleteAction->setEnabled(false); copyAction->setEnabled(false); } // Execute the menu. Return if nothing. QAction* action = menu.exec(variablesTreeWidget->mapToGlobal(pos)); if (action == 0) { return; } if (action == deleteAction) { handleDeleteToolButton(); } if (action == deleteAllAction) { handleDeleteAllToolButton(); } if (action == copyAction || action == copyAllAction || action == copyValueOnlyAction) { // Get selected tree items. QList items; // Get list of 'select' items. if (action == copyAction || action == copyValueOnlyAction) { items = variablesTreeWidget->selectedItems(); } // Get list of 'all' items. if (action == copyAllAction) { items = variablesTreeWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard); } // Populate the clipboard. if (items.size() == 0) { return; } QClipboard* clipboard = QGuiApplication::clipboard(); QString text; for (int i=0; itext(1) + ":" + items[i]->text(2); } else { text += items[i]->text(2); } } clipboard->setText(text, QClipboard::Clipboard); clipboard->setText(text, QClipboard::Selection); } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("&") + variable); } return; } } seer-2.7/src/SeerVariableLoggerBrowserWidget.h000066400000000000000000000043241516472651200215100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerVariableLoggerBrowserWidget.h" class SeerVariableLoggerBrowserWidget : public QWidget, protected Ui::SeerVariableLoggerBrowserWidgetForm { Q_OBJECT public: explicit SeerVariableLoggerBrowserWidget (QWidget* parent = 0); ~SeerVariableLoggerBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void handleEvaluateVariableExpression (int expressionid, QString expression); void addVariableExpression (QString expression); private slots: void handleAddLineEdit (); void handleDeleteToolButton (); void handleDeleteAllToolButton (); void handleItemEntered (QTreeWidgetItem* item, int column); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleContextMenu (const QPoint& pos); signals: void evaluateVariableExpression (int expressionid, QString expression); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void raiseTab (); protected: void handleItemCreate (QTreeWidgetItem* parentItem, const QString& id_text, const QString& timestamp_text, const QString& name_text, const QString& value_text); private: QSet _ids; }; seer-2.7/src/SeerVariableLoggerBrowserWidget.ui000066400000000000000000000055531516472651200217030ustar00rootroot00000000000000 SeerVariableLoggerBrowserWidgetForm 0 0 794 528 Form Add a variable to the loggger. Enter a variable name to log true Delete selected variables. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Delete all variables. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg 4 Timestamp Name Value ID QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerVariableManagerWidget.cpp000066400000000000000000000226621516472651200206370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerVariableManagerWidget.h" #include "SeerHelpPageDialog.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include SeerVariableManagerWidget::SeerVariableManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(false); _variableLoggerBrowserWidget = new SeerVariableLoggerBrowserWidget(this); _variableTrackerBrowserWidget = new SeerVariableTrackerBrowserWidget(this); _registerValuesBrowserWidget = new SeerRegisterValuesBrowserWidget(this); _signalValuesBrowserWidget = new SeerSignalValuesBrowserWidget(this); tabWidget->addTab(_variableLoggerBrowserWidget, "Logger"); tabWidget->addTab(_variableTrackerBrowserWidget, "Tracker"); tabWidget->addTab(_registerValuesBrowserWidget, "Registers"); tabWidget->addTab(_signalValuesBrowserWidget, "Signals"); QToolButton* tabsContextMenuButton = new QToolButton(tabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QToolButton* refreshToolButton = new QToolButton(tabWidget); refreshToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/view-refresh.svg")); refreshToolButton->setToolTip("Refresh the variable/register/signal information."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on variable/register/signal information."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); hcontainer->addWidget(refreshToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Restore tab ordering. readSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerVariableManagerWidget::handleTabsContextMenuButtonClicked); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerVariableManagerWidget::handleRefreshToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerVariableManagerWidget::handleHelpToolButtonClicked); QObject::connect(tabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerVariableManagerWidget::handleTabMoved); QObject::connect(tabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerVariableManagerWidget::handleTabChanged); QObject::connect(_variableLoggerBrowserWidget, &SeerVariableLoggerBrowserWidget::raiseTab, this, &SeerVariableManagerWidget::handleRaiseLoggerTab); QObject::connect(_variableTrackerBrowserWidget, &SeerVariableTrackerBrowserWidget::raiseTab, this, &SeerVariableManagerWidget::handleRaiseTrackerTab); } SeerVariableManagerWidget::~SeerVariableManagerWidget () { } SeerVariableTrackerBrowserWidget* SeerVariableManagerWidget::variableTrackerBrowserWidget () { return _variableTrackerBrowserWidget; } SeerVariableLoggerBrowserWidget* SeerVariableManagerWidget::variableLoggerBrowserWidget () { return _variableLoggerBrowserWidget; } SeerRegisterValuesBrowserWidget* SeerVariableManagerWidget::registerValuesBrowserWidget () { return _registerValuesBrowserWidget; } SeerSignalValuesBrowserWidget* SeerVariableManagerWidget::signalValuesBrowserWidget () { return _signalValuesBrowserWidget; } void SeerVariableManagerWidget::handleRefreshToolButtonClicked () { variableTrackerBrowserWidget()->refresh(); registerValuesBrowserWidget()->refresh(); signalValuesBrowserWidget()->refresh(); } void SeerVariableManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/VariableRegisterSignalInfoBrowser.md"); help->show(); help->raise(); } void SeerVariableManagerWidget::handleTabMoved (int from, int to) { Q_UNUSED(from); Q_UNUSED(to); writeSettings(); } void SeerVariableManagerWidget::handleTabChanged (int index) { Q_UNUSED(index); writeSettings(); } void SeerVariableManagerWidget::handleRaiseLoggerTab () { int idx = tabWidget->indexOf(_variableLoggerBrowserWidget); if (idx < 0) { return; } tabWidget->setCurrentIndex(idx); } void SeerVariableManagerWidget::handleRaiseTrackerTab () { int idx = tabWidget->indexOf(_variableTrackerBrowserWidget); if (idx < 0) { return; } tabWidget->setCurrentIndex(idx); } void SeerVariableManagerWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(tabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(tabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = tabWidget->tabBar()->tabText(tabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; QSettings settings; settings.beginGroup("variablemanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerVariableManagerWidget::readSettings () { // Can't move things? if (tabWidget->tabBar()->isMovable() == false) { return; } // Read tab order from settings. QSettings settings; QStringList tabs; QStringList visible; QString current; settings.beginGroup("variablemanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (tabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { tabWidget->tabBar()->moveTab(tb, i); } } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { tabWidget->setTabVisible(i,false); }else{ tabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (tabWidget->tabBar()->tabText(i) == current) { tabWidget->setCurrentIndex(i); break; } } }else{ tabWidget->setCurrentIndex(0); } } void SeerVariableManagerWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < tabWidget->count(); i++) { QString title = tabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(tabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (tabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { tabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ tabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } seer-2.7/src/SeerVariableManagerWidget.h000066400000000000000000000043471516472651200203040ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerVariableTrackerBrowserWidget.h" #include "SeerVariableLoggerBrowserWidget.h" #include "SeerRegisterValuesBrowserWidget.h" #include "SeerSignalValuesBrowserWidget.h" #include #include "ui_SeerVariableManagerWidget.h" class SeerVariableManagerWidget : public QWidget, protected Ui::SeerVariableManagerWidgetForm { Q_OBJECT public: explicit SeerVariableManagerWidget (QWidget* parent = 0); ~SeerVariableManagerWidget (); SeerVariableTrackerBrowserWidget* variableTrackerBrowserWidget (); SeerVariableLoggerBrowserWidget* variableLoggerBrowserWidget (); SeerRegisterValuesBrowserWidget* registerValuesBrowserWidget (); SeerSignalValuesBrowserWidget* signalValuesBrowserWidget (); protected: void writeSettings (); void readSettings (); private slots: void handleRefreshToolButtonClicked (); void handleHelpToolButtonClicked (); void handleTabMoved (int from, int to); void handleTabChanged (int index); void handleRaiseLoggerTab (); void handleRaiseTrackerTab (); void handleTabsContextMenuButtonClicked (); private: SeerVariableTrackerBrowserWidget* _variableTrackerBrowserWidget; SeerVariableLoggerBrowserWidget* _variableLoggerBrowserWidget; SeerRegisterValuesBrowserWidget* _registerValuesBrowserWidget; SeerSignalValuesBrowserWidget* _signalValuesBrowserWidget; }; seer-2.7/src/SeerVariableManagerWidget.ui000066400000000000000000000031441516472651200204640ustar00rootroot00000000000000 SeerVariableManagerWidgetForm 0 0 772 469 Form 0 0 0 0 3 font-weight: bold; Variable/Register/Signal Info Qt::PlainText -1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
seer-2.7/src/SeerVariableTrackerBrowserWidget.cpp000066400000000000000000000736121516472651200222250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerVariableTrackerBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include SeerVariableTrackerBrowserWidget::SeerVariableTrackerBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets variablesTreeWidget->setMouseTracking(true); variablesTreeWidget->setSortingEnabled(false); variablesTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); variablesTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); variablesTreeWidget->resizeColumnToContents(0); // name variablesTreeWidget->resizeColumnToContents(1); // value variablesTreeWidget->resizeColumnToContents(2); // id variablesTreeWidget->resizeColumnToContents(3); // used variablesTreeWidget->setColumnHidden(2, true); // Hide the 'id' column. variablesTreeWidget->setColumnHidden(3, true); // Hide the 'used' column. variablesTreeWidget->clear(); // Connect things. QObject::connect(variableAddLineEdit, &QLineEdit::returnPressed, this, &SeerVariableTrackerBrowserWidget::handleAddLineEdit); QObject::connect(variableDeleteToolButton, &QToolButton::clicked, this, &SeerVariableTrackerBrowserWidget::handleDeleteToolButton); QObject::connect(variableDeleteAllToolButton, &QToolButton::clicked, this, &SeerVariableTrackerBrowserWidget::handleDeleteAllToolButton); QObject::connect(variablesTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerVariableTrackerBrowserWidget::handleItemCollapsed); QObject::connect(variablesTreeWidget, &QTreeWidget::itemExpanded, this, &SeerVariableTrackerBrowserWidget::handleItemExpanded); QObject::connect(variablesTreeWidget, &QTreeWidget::itemEntered, this, &SeerVariableTrackerBrowserWidget::handleItemEntered); QObject::connect(variablesTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerVariableTrackerBrowserWidget::handleContextMenu); QObject::connect(variableRememberToolButton, &QToolButton::toggled, this, &SeerVariableTrackerBrowserWidget::handleRememberToolButton); // Read state. readSettings(); } SeerVariableTrackerBrowserWidget::~SeerVariableTrackerBrowserWidget () { } void SeerVariableTrackerBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { if (text.startsWith("^done,DataExpressionTable={") && text.endsWith("}")) { // "^done,DataExpressionTable={ // entry={id=\"1\",expression=\"s\"}, // entry={id=\"2\",expression=\"v\"}, // entry={id=\"4\",expression=\"l\"}, // entry={id=\"5\",expression=\"m\"} // }" QString frame_text = Seer::parseFirst(text, "DataExpressionTable=", '{', '}', false); QStringList entries_list = Seer::parse(frame_text, "entry=", '{', '}', false); for (int i=0; i matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); if (matches.count() == 0) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, expression_text); topItem->setText(1, ""); topItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); topItem->setText(2, id_text); topItem->setText(3, "new"); variablesTreeWidget->addTopLevelItem(topItem); } } }else if (text.startsWith("^done,DataExpressionAdded={") && text.endsWith("}")) { // "^done,DataExpressionAdded={ // id=\"5\", // expression=\"m\" // }" QString frame_text = Seer::parseFirst(text, "DataExpressionAdded=", '{', '}', false); QString id_text = Seer::parseFirst(frame_text, "id=", '"', '"', false); QString expression_text = Seer::parseFirst(frame_text, "expression=", '"', '"', false); QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); if (matches.count() == 0) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, expression_text); topItem->setText(1, ""); topItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); topItem->setText(2, id_text); topItem->setText(3, "new"); variablesTreeWidget->addTopLevelItem(topItem); refreshValues(); emit raiseTab(); } }else if (text.startsWith("^done,DataExpressionDeleted={") && text.endsWith("}")) { // "^done,DataExpressionDeleted={ // entry={id=\"1\",expression=\"s\"}, // entry={id=\"3\",expression=\"vb\"} // }" QString frame_text = Seer::parseFirst(text, "DataExpressionDeleted=", '{', '}', false); QStringList entries_list = Seer::parse(frame_text, "entry=", '{', '}', false); for (int i=0; i matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); qDeleteAll(matches); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // "6^done,value=\"\\\"abc\\\"\"" QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); // If with brackets (a structure), filter out excess '\n' // in case pretty-print-on is used. if (value_text.front() == '{' && value_text.back() == '}') { value_text = Seer::filterBareNewLines(value_text); } // Find the ones that match our 'id'. QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); if (matches.count() == 1) { Q_ASSERT(matches.count() == 1); // There should be only one. QTreeWidgetItem* item = matches[0]; // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator itmark(item); while (*itmark) { (*itmark)->setText(3, "unused"); ++itmark; } QString old_text = item->text(1); old_text.replace("\\\"", "\""); old_text.remove('\\'); value_text.replace("\\\"", "\""); value_text.remove('\\'); if (old_text == "") { // If old_text is empty -> This node is created for the first time. Pass the same text for old and new handleItemCreate (item, value_text, value_text); } else { old_text = Seer::filterBareNewLines(old_text); handleItemCreate (item, value_text, old_text); } emit raiseTab(); // At this point, there are some new entries, some reused entries, and some unused ones. // For now, don't bother deleting 'unused' ones. } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // "1^error,msg=\"No symbol \\\"j\\\" in current context.\"" QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "msg=", '"', '"', false); // Find the ones that match our 'id'. QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); if (matches.count() == 1) { // There should be only one. QTreeWidgetItem* item = matches[0]; // Remove any children. QList children = item->takeChildren(); qDeleteAll(children); // Set the text with the error message. item->setText(1, Seer::filterEscapes(msg_text)); item->setText(3, "used"); } }else{ // Ignore others. } variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); break; } QApplication::restoreOverrideCursor(); } void SeerVariableTrackerBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } refresh(); } void SeerVariableTrackerBrowserWidget::handleSessionTerminated () { // Remember the variable names? if (variableRememberToolButton->isChecked() == true) { return; } // Delete previous contents. variablesTreeWidget->clear(); // Tell the GdbWidget to forget all tracked expressions. emit deleteVariableExpressions("*"); } void SeerVariableTrackerBrowserWidget::refresh () { emit refreshVariableTrackerNames(); emit refreshVariableTrackerValues(); } void SeerVariableTrackerBrowserWidget::refreshValues () { emit refreshVariableTrackerValues(); } void SeerVariableTrackerBrowserWidget::handleAddLineEdit () { QString variable = variableAddLineEdit->text(); variableAddLineEdit->clear(); if (variable != "") { emit addVariableExpression(variable); // After sending the 'add' signal, schedule a 'refresh' 200ms later. QTimer::singleShot(200, this, &SeerVariableTrackerBrowserWidget::refresh); } } void SeerVariableTrackerBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = variablesTreeWidget->selectedItems(); // Build a string that is a list of variable ids. QString variableids; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { variableids += " "; } variableids += (*i)->text(2); } // Don't do anything if the list of variables is empty. if (variableids == "") { return; } // Send the signal. emit deleteVariableExpressions(variableids); } void SeerVariableTrackerBrowserWidget::handleDeleteAllToolButton () { emit deleteVariableExpressions("*"); } void SeerVariableTrackerBrowserWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableTrackerBrowserWidget::handleItemCollapsed (QTreeWidgetItem* item) { Q_UNUSED(item); variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableTrackerBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + Seer::elideText(item->text(1), Qt::ElideRight, 100)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerVariableTrackerBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } void SeerVariableTrackerBrowserWidget::handleItemCreate (QTreeWidgetItem* item, const QString& value_text, const QString& old_text) { handleItemCreate(item, item->text(2), item->text(0), value_text, old_text); } void SeerVariableTrackerBrowserWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& id_text, const QString& name_text, const QString& value_text, const QString& old_text) { // Fill in parent item. Whether is a simple or complex entry. parentItem->setText(0, name_text); parentItem->setText(1, Seer::filterEscapes(value_text)); parentItem->setText(2, id_text); parentItem->setText(3, "reused"); // Look for bookmarks. This indicates a nested structure. // There are two types. With and without an address. QString capture0; // With bookends. QString capture1; // Without. QRegularExpression withaddress_re("^@0[xX][0-9a-fA-F]+: \\{(.*?)\\}$"); QRegularExpressionMatch withaddress_match = withaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (withaddress_match.hasMatch()) { capture0 = withaddress_match.captured(0); capture1 = withaddress_match.captured(1); }else{ QRegularExpression noaddress_re("^\\{(.*?)\\}$"); QRegularExpressionMatch noaddress_match = noaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (noaddress_match.hasMatch()) { capture0 = noaddress_match.captured(0); capture1 = noaddress_match.captured(1); } } // Simple entries don't have children. Delete them. // Then we're done. if (capture0 == "" || capture1 == "") { while (parentItem->childCount() > 0) { QTreeWidgetItem* item = parentItem->child(0); delete item; } } // Do the same for old_text QString captureOld0; // With bookends. QString captureOld1; // Without. QRegularExpressionMatch withaddress_match_Old = withaddress_re.match(old_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (withaddress_match_Old.hasMatch()) { captureOld0 = withaddress_match_Old.captured(0); captureOld1 = withaddress_match_Old.captured(1); }else{ QRegularExpression noaddress_re("^\\{(.*?)\\}$"); QRegularExpressionMatch noaddress_match = noaddress_re.match(old_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (noaddress_match.hasMatch()) { captureOld0 = noaddress_match.captured(0); captureOld1 = noaddress_match.captured(1); } } // Add the complex entry to the tree. Reuse, if possible. // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. We start by looking for matches that // may already be there. If there are matches, the code will reuse it. If not, a new item // is created by the code. Note, when searching, we only look at the current level. Not any // children. // Use the one without bookends. QString text = capture1; // Convert to a list of name/value pairs. QStringList nv_pairs; if (text.startsWith("{")) { // String might describe an array: {a=1, b=1},{a=1, b=1},{a=1, b=1},{a=1, b=1} nv_pairs = Seer::parseArray(parentItem->text(0), text); } else { nv_pairs = Seer::parseCommaList(text, '{', '}'); } QStringList nv_old_pairs; if (text.startsWith("{")) { // String might describe an array: {a=1, b=1},{a=1, b=1},{a=1, b=1},{a=1, b=1} nv_old_pairs = Seer::parseArray(parentItem->text(0), captureOld1); } else { nv_old_pairs = Seer::parseCommaList(captureOld1, '{', '}'); } if (nv_old_pairs.size() != nv_pairs.size()) // Check if variable has changed type or is out of scope { // If sizes don't match, it seems that variables is out of scope or changed type // First, delete all children, otherwise we might have leftovers while (parentItem->childCount() > 0) { QTreeWidgetItem* item = parentItem->child(0); delete item; } // Then, recreate all children for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); // Look for the existing child, if any so we can reuse it. QTreeWidgetItem* childItem = 0; for (int i=0; ichildCount(); i++) { if (parentItem->child(i)->text(0) == pair.first) { childItem = parentItem->child(i); childItem->setText(0, pair.first); childItem->setText(1, pair.second); childItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); childItem->setText(2, id_text); childItem->setText(3, "reused"); break; } } // Otherwise, create a new child. if (childItem == 0) { childItem = new QTreeWidgetItem; childItem->setText(0, pair.first); childItem->setText(1, pair.second); childItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); childItem->setText(2, id_text); childItem->setText(3, "new"); parentItem->addChild(childItem); } handleItemCreate(childItem, id_text, childItem->text(0), childItem->text(1), ""); } return; } QFont parentFont = parentItem->font(0); parentFont.setBold(old_text != value_text); // if value has changed -> set font to bold parentItem->setFont(0, parentFont); parentItem->setFont(1, parentFont); // Go through each pair and add the name and its value to the tree. for (int i = 0; i < nv_pairs.size(); ++i) { QString nv = nv_pairs[i]; QString nv_old = nv_old_pairs[i]; QStringPair pair = Seer::parseNameValue(nv, '='); QStringPair old_pair = Seer::parseNameValue(nv_old, '='); // Look for the existing child, if any so we can reuse it. QTreeWidgetItem* childItem = 0; for (int i=0; ichildCount(); i++) { if (parentItem->child(i)->text(0) == pair.first) { childItem = parentItem->child(i); childItem->setText(0, pair.first); childItem->setText(1, pair.second); childItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); childItem->setText(2, id_text); childItem->setText(3, "reused"); QFont childFontCol0 = childItem->font(0); QFont childFontCol1 = QFontDatabase::systemFont(QFontDatabase::FixedFont); childFontCol0.setBold(pair.second != old_pair.second); childFontCol1.setBold(pair.second != old_pair.second); childItem->setFont(0, childFontCol0); childItem->setFont(1, childFontCol1); break; } } // Otherwise, create a new child. if (childItem == 0) { childItem = new QTreeWidgetItem; childItem->setText(0, pair.first); childItem->setText(1, pair.second); childItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); childItem->setText(2, id_text); childItem->setText(3, "new"); parentItem->addChild(childItem); } handleItemCreate(childItem, id_text, childItem->text(0), childItem->text(1), old_pair.second); } } void SeerVariableTrackerBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = variablesTreeWidget->itemAt(pos); // Construct the menu. QAction* addMemoryVisualizerAction = new QAction(); QAction* addMemoryAsteriskVisualizerAction = new QAction(); QAction* addMemoryAmpersandVisualizerAction = new QAction(); QAction* addArrayVisualizerAction = new QAction(); QAction* addArrayAsteriskVisualizerAction = new QAction(); QAction* addArrayAmpersandVisualizerAction = new QAction(); QAction* addMatrixVisualizerAction = new QAction(); QAction* addMatrixAsteriskVisualizerAction = new QAction(); QAction* addMatrixAmpersandVisualizerAction = new QAction(); QAction* addStructVisualizerAction = new QAction(); QAction* addStructAsteriskVisualizerAction = new QAction(); QAction* addStructAmpersandVisualizerAction = new QAction(); QMenu menu("Options", this); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); QAction* deleteAction = menu.addAction("Delete selected"); QAction* deleteAllAction = menu.addAction("Delete all"); QAction* copyAction = menu.addAction("Copy selected"); QAction* copyValueOnlyAction = menu.addAction("Copy selected value"); QAction* copyAllAction = menu.addAction("Copy all"); QString actionText; if (item != 0) { actionText = item->text(0); } QString variable; if (item != 0) { // Build up a variable string, incase it is a nested struct. QTreeWidgetItem* i = item; variable = item->text(0); while (i->parent() != 0) { variable = i->parent()->text(0) + "." + variable; i = i->parent(); } } // Remove potential '&' and '*' characters at start of string. variable.remove(QRegularExpression("^[\\*\\&]*")); addMemoryVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addMemoryAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addMemoryAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addArrayVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addArrayAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addArrayAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addMatrixVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addMatrixAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addMatrixAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addStructVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addStructAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addStructAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); // If no selected item, disable everything but allow 'copyall' and 'deleteall'. if (item == 0) { memoryVisualizerMenu.setEnabled(false); arrayVisualizerMenu.setEnabled(false); matrixVisualizerMenu.setEnabled(false); structVisualizerMenu.setEnabled(false); deleteAction->setEnabled(false); copyAction->setEnabled(false); } // Execute the menu. Return if nothing. QAction* action = menu.exec(variablesTreeWidget->mapToGlobal(pos)); if (action == 0) { return; } if (action == deleteAction) { handleDeleteToolButton(); } if (action == deleteAllAction) { handleDeleteAllToolButton(); } if (action == copyAction || action == copyAllAction || action == copyValueOnlyAction) { // Get selected tree items. QList items; // Get list of 'select' items. if (action == copyAction || copyValueOnlyAction) { items = variablesTreeWidget->selectedItems(); } // Get list of 'all' items. if (action == copyAllAction) { items = variablesTreeWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard); } // Populate the clipboard. if (items.count() == 0) { return; } QClipboard* clipboard = QGuiApplication::clipboard(); QString text; for (int i=0; itext(0) + ":" + items[i]->text(1); } else { text += items[i]->text(1); } } clipboard->setText(text, QClipboard::Clipboard); clipboard->setText(text, QClipboard::Selection); } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("&") + variable); } return; } } void SeerVariableTrackerBrowserWidget::handleRememberToolButton (bool checked) { Q_UNUSED(checked); writeSettings(); } void SeerVariableTrackerBrowserWidget::readSettings () { QSettings settings; bool remember = false; settings.beginGroup("variabletrackerwindow"); { remember = settings.value("remembervariablenames", remember).toBool(); } settings.endGroup(); variableRememberToolButton->setChecked(remember); } void SeerVariableTrackerBrowserWidget::writeSettings () { QSettings settings; settings.beginGroup("variabletrackerwindow"); { settings.setValue("remembervariablenames", variableRememberToolButton->isChecked()); } settings.endGroup(); } seer-2.7/src/SeerVariableTrackerBrowserWidget.h000066400000000000000000000053051516472651200216640ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerVariableTrackerBrowserWidget.h" class SeerVariableTrackerBrowserWidget : public QWidget, protected Ui::SeerVariableTrackerBrowserWidgetForm { Q_OBJECT public: explicit SeerVariableTrackerBrowserWidget (QWidget* parent = 0); ~SeerVariableTrackerBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); void refreshValues (); private slots: void handleAddLineEdit (); void handleDeleteToolButton (); void handleDeleteAllToolButton (); void handleItemEntered (QTreeWidgetItem* item, int column); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleContextMenu (const QPoint& pos); void handleRememberToolButton (bool checked); signals: void refreshVariableTrackerNames (); void refreshVariableTrackerValues (); void addVariableExpression (QString expression); void deleteVariableExpressions (QString expressionids); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void raiseTab (); protected: void handleItemCreate (QTreeWidgetItem* item, const QString& value_text, const QString& old_text); void handleItemCreate (QTreeWidgetItem* parentItem, const QString& id_text, const QString& name_text, const QString& value_text, const QString& old_text); void showEvent (QShowEvent* event); private: void readSettings (); void writeSettings (); }; seer-2.7/src/SeerVariableTrackerBrowserWidget.ui000066400000000000000000000066751516472651200220650ustar00rootroot00000000000000 SeerVariableTrackerBrowserWidgetForm 0 0 794 528 Form Add a variable to track. Enter a variable name to track true Remember variable names between sessions. ... :/seer/resources/RelaxLightIcons/pin.svg:/seer/resources/RelaxLightIcons/pin.svg true Delete selected variables. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Delete all variables. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg 4 Name Value ID Used QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
seer-2.7/src/SeerWatchpointCreateDialog.cpp000066400000000000000000000042221516472651200210270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerWatchpointCreateDialog.h" #include SeerWatchpointCreateDialog::SeerWatchpointCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); QButtonGroup* accessTypeButtonGroup = new QButtonGroup(this); accessTypeButtonGroup->addButton(writeRadioButton); accessTypeButtonGroup->addButton(readRadioButton); accessTypeButtonGroup->addButton(readWriteRadioButton); // Setup the widgets setExpression(""); setReadAccessEnabled(false); setReadWriteAccessEnabled(false); setWriteAccessEnabled(true); expressionLineEdit->setFocus(); // Connect things. } SeerWatchpointCreateDialog::~SeerWatchpointCreateDialog () { } void SeerWatchpointCreateDialog::setExpression (const QString& text) { expressionLineEdit->setText(text); } QString SeerWatchpointCreateDialog::expressionText () const { return expressionLineEdit->text(); } void SeerWatchpointCreateDialog::setReadAccessEnabled (bool flag) { readRadioButton->setChecked(flag); } void SeerWatchpointCreateDialog::setWriteAccessEnabled (bool flag) { writeRadioButton->setChecked(flag); } void SeerWatchpointCreateDialog::setReadWriteAccessEnabled (bool flag) { readWriteRadioButton->setChecked(flag); } bool SeerWatchpointCreateDialog::readAccessEnabled () const { return readRadioButton->isChecked(); } bool SeerWatchpointCreateDialog::writeAccessEnabled () const { return writeRadioButton->isChecked(); } bool SeerWatchpointCreateDialog::readWriteAccessEnabled () const { return readWriteRadioButton->isChecked(); } QString SeerWatchpointCreateDialog::watchpointText () const { // Build a watchpoint specification. QString watchpointParameters; if (readAccessEnabled()) { watchpointParameters += " -r"; } if (readWriteAccessEnabled()) { watchpointParameters += " -a"; } if (writeAccessEnabled()) { watchpointParameters += ""; } watchpointParameters += " " + expressionText(); return watchpointParameters; } seer-2.7/src/SeerWatchpointCreateDialog.h000066400000000000000000000020711516472651200204740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerWatchpointCreateDialog.h" class SeerWatchpointCreateDialog : public QDialog, protected Ui::SeerWatchpointCreateDialogForm { Q_OBJECT public: explicit SeerWatchpointCreateDialog (QWidget* parent = 0); ~SeerWatchpointCreateDialog (); void setExpression (const QString& text); QString expressionText () const; void setReadAccessEnabled (bool flag); void setWriteAccessEnabled (bool flag); void setReadWriteAccessEnabled (bool flag); bool readAccessEnabled () const; bool writeAccessEnabled () const; bool readWriteAccessEnabled () const; QString watchpointText () const; public slots: private: }; seer-2.7/src/SeerWatchpointCreateDialog.ui000066400000000000000000000067311516472651200206710ustar00rootroot00000000000000 SeerWatchpointCreateDialogForm 0 0 403 256 Create a Watchpoint Watchpoint Location 0 0 Variable/Expression 100 0 true Watchpoint Type Read Access Read/Write Access Write Access Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerWatchpointCreateDialogForm accept() 248 254 157 274 buttonBox rejected() SeerWatchpointCreateDialogForm reject() 316 260 286 274 seer-2.7/src/SeerWatchpointsBrowserWidget.cpp000066400000000000000000000617401516472651200214660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerWatchpointsBrowserWidget.h" #include "SeerWatchpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerWatchpointsBrowserWidget::SeerWatchpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets watchpointsTreeWidget->clear(); watchpointsTreeWidget->setSortingEnabled(false); watchpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); watchpointsTreeWidget->resizeColumnToContents(0); // number watchpointsTreeWidget->resizeColumnToContents(1); // original-location / expression watchpointsTreeWidget->resizeColumnToContents(2); // value watchpointsTreeWidget->resizeColumnToContents(3); // new value watchpointsTreeWidget->resizeColumnToContents(4); // type watchpointsTreeWidget->resizeColumnToContents(5); // disp watchpointsTreeWidget->resizeColumnToContents(6); // enabled watchpointsTreeWidget->resizeColumnToContents(7); // addr //watchpointsTreeWidget->resizeColumnToContents(8); // func Too long to show watchpointsTreeWidget->resizeColumnToContents(9); // file //watchpointsTreeWidget->resizeColumnToContents(10); // fullname Too long to show watchpointsTreeWidget->resizeColumnToContents(11); // line watchpointsTreeWidget->resizeColumnToContents(12); // thread-groups watchpointsTreeWidget->resizeColumnToContents(13); // cond watchpointsTreeWidget->resizeColumnToContents(14); // times watchpointsTreeWidget->resizeColumnToContents(15); // ignore //watchpointsTreeWidget->resizeColumnToContents(16); // script Too long to show watchpointsTreeWidget->resizeColumnToContents(17); // used watchpointsTreeWidget->setColumnHidden(7, true); // Hide the 'addr' column. watchpointsTreeWidget->setColumnHidden(8, true); // Hide the 'func' column. watchpointsTreeWidget->setColumnHidden(17, true); // Hide the 'used' column. watchpointsTreeWidget->clear(); // Connect things. QObject::connect(watchpointsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerWatchpointsBrowserWidget::handleItemDoubleClicked); QObject::connect(refreshWatchpointsToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addWatchpointToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleAddToolButton); QObject::connect(deleteWatchpointsToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleDeleteToolButton); QObject::connect(enableWatchpointsToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleEnableToolButton); QObject::connect(disableWatchpointsToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleDisableToolButton); QObject::connect(conditionWatchpointToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleConditionToolButton); QObject::connect(ignoreWatchpointToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleIgnoreToolButton); QObject::connect(commandsWatchpointToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleCommandsToolButton); } SeerWatchpointsBrowserWidget::~SeerWatchpointsBrowserWidget () { } bool SeerWatchpointsBrowserWidget::isEmpty() const { return (watchpointsTreeWidget->topLevelItemCount() == 0); } QStringList SeerWatchpointsBrowserWidget::breakpoints () const { return QStringList(); } void SeerWatchpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { // // ^done,BreakpointTable={ // nr_rows="2",nr_cols="6", // // hdr=[ // {width="7",alignment="-1",col_name="number",colhdr="Num"}, // {width="14",alignment="-1",col_name="type",colhdr="Type"}, // {width="4",alignment="-1",col_name="disp",colhdr="Disp"}, // {width="3",alignment="-1",col_name="enabled",colhdr="Enb"}, // {width="18",alignment="-1",col_name="addr",colhdr="Address"}, // {width="40",alignment="2",col_name="what",colhdr="What"} // ], // // body=[ // bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="0x0000000000400c17",func="main(int, char**)",file="helloworld.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp",line="8",thread-groups=["i1"],times="0",original-location="main"}, // bkpt={number="3", // type="breakpoint", // disp="keep", // enabled="y", // addr="0x0000000000400d72", // func="function1(std::__cxx11::basic_string, std::allocator > const&)", // file="function1.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp", // line="7", // thread-groups=["i1"], // times="0", // original-location="function1"} // ] // } // QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(newtext, "body=", '[', ']', false); //qDebug() << body_text; // No rows? Just clear the tree. if (body_text == "") { watchpointsTreeWidget->clear(); // Otherwise, populate it. }else{ // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(watchpointsTreeWidget); while (*it) { (*it)->setText(17, "unused"); ++it; } QStringList bkpt_list = Seer::parse(newtext, "bkpt=", '{', '}', false); for ( const auto& bkpt_text : bkpt_list ) { QString number_text = Seer::parseFirst(bkpt_text, "number=", '"', '"', false); QString type_text = Seer::parseFirst(bkpt_text, "type=", '"', '"', false); QString disp_text = Seer::parseFirst(bkpt_text, "disp=", '"', '"', false); QString enabled_text = Seer::parseFirst(bkpt_text, "enabled=", '"', '"', false); QString addr_text = Seer::parseFirst(bkpt_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(bkpt_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(bkpt_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(bkpt_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(bkpt_text, "line=", '"', '"', false); QString thread_groups_text = Seer::parseFirst(bkpt_text, "thread-groups=", '[', ']', false); QString cond_text = Seer::parseFirst(bkpt_text, "cond=", '"', '"', false); QString times_text = Seer::parseFirst(bkpt_text, "times=", '"', '"', false); QString ignore_text = Seer::parseFirst(bkpt_text, "ignore=", '"', '"', false); QString script_text = Seer::parseFirst(bkpt_text, "script=", '[', ']', false); QString original_location_text = Seer::parseFirst(bkpt_text, "original-location=", '"', '"', false); // Only look for 'watchpoint' type break points. if (type_text != "hw watchpoint" && type_text != "watchpoint" && type_text != "read watchpoint" && type_text != "acc watchpoint") { continue; } script_text = Seer::filterBookends(Seer::parseCommaList(script_text, '{', '}'), '"', '"').join('\n'); // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. QList matches = watchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); // No matches. So can't reuse. Add the new entry. if (matches.size() == 0) { // Add the level to the tree. QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, number_text); topItem->setText(1, original_location_text); topItem->setText(2, ""); topItem->setText(3, ""); topItem->setText(4, type_text); topItem->setText(5, disp_text); topItem->setText(6, enabled_text); topItem->setText(7, addr_text); topItem->setText(8, func_text); topItem->setText(9, QFileInfo(file_text).fileName()); topItem->setText(10, fullname_text); topItem->setText(11, line_text); topItem->setText(12, thread_groups_text); topItem->setText(13, cond_text); topItem->setText(14, times_text); topItem->setText(15, ignore_text); topItem->setText(16, script_text); topItem->setText(17, "new"); topItem->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); topItem->setFont(3, QFontDatabase::systemFont(QFontDatabase::FixedFont)); for (int i=0; icolumnCount(); i++) { topItem->setTextAlignment(i, Qt::AlignLeft|Qt::AlignTop); } watchpointsTreeWidget->addTopLevelItem(topItem); // Found a match. Reuse it. // But don't overwrite the file, fullname, line, value, and new value. }else{ QTreeWidgetItem* topItem = matches.takeFirst(); topItem->setText(0, number_text); topItem->setText(1, original_location_text); //topItem->setText(2, ""); //topItem->setText(3, ""); topItem->setText(4, type_text); topItem->setText(5, disp_text); topItem->setText(6, enabled_text); topItem->setText(7, addr_text); topItem->setText(8, func_text); //topItem->setText(9, QFileInfo(file_text).fileName()); //topItem->setText(10, fullname_text); //topItem->setText(11, line_text); topItem->setText(12, thread_groups_text); topItem->setText(13, cond_text); topItem->setText(14, times_text); topItem->setText(15, ignore_text); topItem->setText(16, script_text); topItem->setText(17, "reused"); } } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. QList matches = watchpointsTreeWidget->findItems("unused", Qt::MatchExactly, 17); qDeleteAll(matches); } }else if (text.startsWith("*stopped,reason=\"") || text.startsWith("*stopped,hw-awpt={")) { QString reason_text = Seer::parseFirst(text, "reason=", '"', '"', false); if (reason_text == "watchpoint-trigger") { //*stopped,reason="watchpoint-trigger",wpt={number="3",exp="i"},value={old="32767",new="42"},frame={addr="0x0000000000400d79",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="9",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="0" QString wpt_text = Seer::parseFirst(text, "wpt=", '{', '}', false); QString number_text = Seer::parseFirst(wpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(wpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false); QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false); QString frame_text = Seer::parseFirst(text, "frame=", '{', '}', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); // Find watchpoint number in the tree QList matches = watchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); if (matches.size() > 0) { //qDebug() << text; QTreeWidgetItem* item = matches.first(); item->setText(2, old_text); item->setText(3, new_text); item->setText(9, QFileInfo(file_text).fileName()); item->setText(10, fullname_text); item->setText(11, line_text); } }else if (reason_text == "read-watchpoint-trigger") { //*stopped,reason="read-watchpoint-trigger",hw-rwpt={number="5",exp="i"},value={value="42"},frame={addr="0x0000000000400d9a",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="11",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="4" QString hwwpt_text = Seer::parseFirst(text, "hw-rwpt=", '{', '}', false); QString number_text = Seer::parseFirst(hwwpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(hwwpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString value_text2 = Seer::parseFirst(value_text, "value=", '"', '"', false); QString frame_text = Seer::parseFirst(text, "frame=", '{', '}', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); // Find watchpoint number in the tree QList matches = watchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); if (matches.size() > 0) { //qDebug() << text; QTreeWidgetItem* item = matches.first(); item->setText(2, value_text2); item->setText(3, ""); item->setText(9, QFileInfo(file_text).fileName()); item->setText(10, fullname_text); item->setText(11, line_text); } }else if (reason_text == "access-watchpoint-trigger") { //*stopped,reason="access-watchpoint-trigger",hw-awpt={number="3",exp="v"},value={old="1",new="11"},frame={addr="0x000000000040059a",func="bar",args=[{name="v",value="11"}],file="helloonefile.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloonefile/helloonefile.cpp",line="15",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="3" QString hwawpt_text = Seer::parseFirst(text, "hw-awpt=", '{', '}', false); QString number_text = Seer::parseFirst(hwawpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(hwawpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false); QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false); QString frame_text = Seer::parseFirst(text, "frame=", '{', '}', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); // Find watchpoint number in the tree QList matches = watchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); if (matches.size() > 0) { //qDebug() << text; QTreeWidgetItem* item = matches.first(); item->setText(2, old_text); item->setText(3, new_text); item->setText(9, QFileInfo(file_text).fileName()); item->setText(10, fullname_text); item->setText(11, line_text); } } }else{ // Ignore others. } watchpointsTreeWidget->resizeColumnToContents(0); watchpointsTreeWidget->resizeColumnToContents(1); watchpointsTreeWidget->resizeColumnToContents(2); watchpointsTreeWidget->resizeColumnToContents(3); watchpointsTreeWidget->resizeColumnToContents(4); watchpointsTreeWidget->resizeColumnToContents(5); watchpointsTreeWidget->resizeColumnToContents(6); watchpointsTreeWidget->resizeColumnToContents(7); //watchpointsTreeWidget->resizeColumnToContents(8); watchpointsTreeWidget->resizeColumnToContents(9); //watchpointsTreeWidget->resizeColumnToContents(10); watchpointsTreeWidget->resizeColumnToContents(11); watchpointsTreeWidget->resizeColumnToContents(12); watchpointsTreeWidget->resizeColumnToContents(13); watchpointsTreeWidget->resizeColumnToContents(14); watchpointsTreeWidget->resizeColumnToContents(15); //watchpointsTreeWidget->resizeColumnToContents(16); watchpointsTreeWidget->resizeColumnToContents(17); QApplication::restoreOverrideCursor(); } void SeerWatchpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshWatchpointsList(); } void SeerWatchpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. watchpointsTreeWidget->clear(); } void SeerWatchpointsBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); int lineno = item->text(11).toInt(); emit selectedFile(item->text(9), item->text(10), lineno); } void SeerWatchpointsBrowserWidget::handleRefreshToolButton () { emit refreshWatchpointsList(); } void SeerWatchpointsBrowserWidget::handleAddToolButton () { SeerWatchpointCreateDialog dlg(this); int ret = dlg.exec(); if (ret == 0) { return; } // Build a watchpoint specification. QString watchpointParameters = dlg.watchpointText(); // If nothing, just return. if (watchpointParameters == "") { return; } // Otherwise send the command to create the watchpoint. emit insertWatchpoint(watchpointParameters); } void SeerWatchpointsBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = watchpointsTreeWidget->selectedItems(); // Build a string that is a list of watchpoints. QString watchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { watchpoints += " "; } watchpoints += (*i)->text(0); } // Don't do anything if the list of watchpoints is empty. if (watchpoints == "") { return; } // Send the signal. emit deleteWatchpoints(watchpoints); } void SeerWatchpointsBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = watchpointsTreeWidget->selectedItems(); // Build a string that is a list of watchpoints. QString watchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { watchpoints += " "; } watchpoints += (*i)->text(0); } // Don't do anything if the list of watchpoints is empty. if (watchpoints == "") { return; } // Send the signal. emit enableWatchpoints(watchpoints); } void SeerWatchpointsBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = watchpointsTreeWidget->selectedItems(); // Build a string that is a list of watchpoints. QString watchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { watchpoints += " "; } watchpoints += (*i)->text(0); } // Don't do anything if the list of watchpoints is empty. if (watchpoints == "") { return; } // Send the signal. emit disableWatchpoints(watchpoints); } void SeerWatchpointsBrowserWidget::handleConditionToolButton () { // Get selected tree items. Only allow one. QList items = watchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one watchpoint when adding a condition.", QMessageBox::Ok); return; } // Get the condition text. bool ok; QString condition = QInputDialog::getText(this, "Seer", "Enter the condition for this watchpoint.\nA blank condition will remove an existing one.", QLineEdit::Normal, items.front()->text(13), &ok); if (ok == false) { return; } // Get the selected watchpoint number. QString watchpoint = items.front()->text(0); // Send the signal. emit addBreakpointCondition(watchpoint, condition); } void SeerWatchpointsBrowserWidget::handleIgnoreToolButton () { // Get selected tree items. Only allow one. QList items = watchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one watchpoint when adding an ignore count.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; int count = QInputDialog::getInt(this, "Seer", "Enter the ignore count for this watchpoint.\nA count of 0 will remove an existing one.", items.front()->text(15).toInt(), 0, 2147483647, 1, &ok); if (ok == false) { return; } // Get the selected watchpoint number. QString watchpoint = items.front()->text(0); // Send the signal. emit addBreakpointIgnore(watchpoint, QString::number(count)); } void SeerWatchpointsBrowserWidget::handleCommandsToolButton () { // Get selected tree items. Only allow one. QList items = watchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one watcpoint when adding commands.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; QString commandstr = QInputDialog::getMultiLineText(this, "Seer", "Enter the commands to execute for this watchpoint.\nA blank list will remove existing ones.", items.front()->text(16), &ok); if (ok == false) { return; } // Get the selected watchpoint number. QString watchpoint = items.front()->text(0); QStringList commands = Seer::quoteChars(commandstr.split('\n', Qt::SkipEmptyParts), "\""); // Send the signal. emit addBreakpointCommands(watchpoint, commands); } void SeerWatchpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshWatchpointsList(); } seer-2.7/src/SeerWatchpointsBrowserWidget.h000066400000000000000000000044361516472651200211320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerWatchpointsBrowserWidget.h" class SeerWatchpointsBrowserWidget : public QWidget, protected Ui::SeerWatchpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerWatchpointsBrowserWidget (QWidget* parent = 0); ~SeerWatchpointsBrowserWidget (); bool isEmpty () const; QStringList breakpoints () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleConditionToolButton (); void handleIgnoreToolButton (); void handleCommandsToolButton (); signals: void refreshWatchpointsList (); void deleteWatchpoints (QString watchpoints); void enableWatchpoints (QString watchpoints); void disableWatchpoints (QString watchpoints); void addBreakpointCondition (QString watchpoint, QString condition); void addBreakpointIgnore (QString watchpoint, QString count); void addBreakpointCommands (QString watchpoint, QStringList commands); void insertWatchpoint (QString watchpoint); void selectedFile (QString file, QString fullname, int lineno); protected: void showEvent (QShowEvent* event); private: }; seer-2.7/src/SeerWatchpointsBrowserWidget.ui000066400000000000000000000163001516472651200213110ustar00rootroot00000000000000 SeerWatchpointsBrowserWidgetForm 0 0 1052 528 Form 18 Number Expression Value New Value Type Disposition Enabled Address Function File Fullname Line Thread Groups Condition Times Ignore Commands Used Add a new watchpoint. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of watchpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Enable selected watchpoints. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected watchpoints. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Add condition to selected watchpoint. ? Add ignore count to selected watchpoint. # Add commands to selected watchpoint. ... :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Delete selected watchpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 seer-2.7/src/build/000077500000000000000000000000001516472651200142175ustar00rootroot00000000000000seer-2.7/src/build/README.cmake000066400000000000000000000023631516472651200161620ustar00rootroot00000000000000Notes for building Seer with cmake. % cd seer/src/build % cmake -DCMAKE_BUILD_TYPE=Debug .. # Debug release -g. % cmake -DCMAKE_BUILD_TYPE=Release .. # Optimized release -O. % cmake -DCMAKE_CXX_FLAGS=-Wall .. # With all compile warnings turned on. The above defaults to Qt6. If you want to use Qt5, add the '-DQTVERSION' flag. % cmake -DQTVERSION=QT5 -DCMAKE_BUILD_TYPE=Debug .. Once cmake is run, then just build Seer. % make clean # Clean files. % make seergdb # Build Seer. % sudo make install # Install it. Another way to ask cmake to do the build for you. % cmake --build . --config Release % sudo cmake --install . MacOS may need help finding the cmake config file for Qt6. % cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt6/ -DCMAKE_BUILD_TYPE=Release .. Sometimes you need to specify a newer version of g++/gcc. Your installation may have an old version as the default. % cmake -DCMAKE_CXX_COMPILER=g++-14 -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=Debug .. Checkout the Seer wiki for more build info. https://github.com/epasveer/seer/wiki/Building-Seer---Qt5 https://github.com/epasveer/seer/wiki/Building-Seer---Qt6 seer-2.7/src/build_seerutl/000077500000000000000000000000001516472651200157625ustar00rootroot00000000000000seer-2.7/src/build_seerutl/CMakeLists.txt000066400000000000000000000035041516472651200205240ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.1.0) project(seerutl VERSION 1.0 LANGUAGES CXX) set(PROJECT_NAME seerutl) if(NOT DEFINED QTVERSION) set(QTVERSION "QT6" CACHE STRING "" FORCE) endif() if(${QTVERSION} STREQUAL "QT6") message("-- Compile with QT6") elseif(${QTVERSION} STREQUAL "QT5") message("-- Compile with QT5") else() message(FATAL_ERROR "-- Use -DQTVERSION=QT5|QT6 not \"${QTVERSION}\"") endif() # Find includes in the build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_PREFIX_PATH ${QTDIR}) if(${QTVERSION} STREQUAL "QT6") find_package(Qt6 COMPONENTS REQUIRED Core) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) elseif(${QTVERSION} STREQUAL "QT5") find_package(Qt5 COMPONENTS REQUIRED Core) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) endif() set(HEADER_FILES ../SeerUtl.h ) set(SOURCE_FILES ../seerutl.cpp ../SeerUtl.cpp ) # Set non-Debug build as GUI application. # Debug build remains consle application. if(NOT CMAKE_BUILD_TYPE MATCHES Debug) #Release, RelWithDebInfo and MinSizeRel if(WIN32) # Check if we are on Windows set(SYSTEM_TYPE WIN32) endif() message("-- System type is " ${SYSTEM_TYPE}) endif() # for Linux, BSD, Solaris, Minix if(UNIX AND NOT APPLE) add_compile_options(-Wall -Wextra -Wunused-result -pedantic) # -Werror -Wdeprecated-copy endif() add_definitions(-DQT_DEPRECATED_WARNINGS) add_executable(${PROJECT_NAME} ${SYSTEM_TYPE} ${SOURCE_FILES}) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) if(${QTVERSION} STREQUAL "QT6") target_link_libraries(${PROJECT_NAME} Qt6::Core) elseif(${QTVERSION} STREQUAL "QT5") target_link_libraries(${PROJECT_NAME} Qt5::Core) endif() seer-2.7/src/build_seerutl/README.cmake000066400000000000000000000027411516472651200177250ustar00rootroot00000000000000Notes for building 'seerutl' with cmake. 'seerutl' is a test program for testing the SeerUtl functions. It is used for my developent. It is NOT needed for the average person installing Seergdb from source. # Note the single '.'. The CMakeLists.txt file is local to this build directory. % cd seer/src/build_seerutl % cmake -DCMAKE_BUILD_TYPE=Debug . # Debug release -g. % cmake -DCMAKE_BUILD_TYPE=Release . # Optimized release -O. % cmake -DCMAKE_CXX_FLAGS=-Wall . # With all compile warnings turned on. # Specify a compiler version with debug. % cmake -DCMAKE_CXX_COMPILER=g++-13 -DCMAKE_BUILD_TYPE=Debug . The above defaults to Qt6. If you want to use Qt5, add the '-DQTVERSION' flag. % cmake -DQTVERSION=QT5 -DCMAKE_BUILD_TYPE=Debug . Once cmake is run, then just build 'seerutl'. % make clean # Clean files. % make seerutl # Build 'seerutl'. % sudo make install # Install it. Another way to ask cmake to do the build for you. % cmake --build . --config Release % sudo cmake --install . MacOS may need help finding the cmake config file for Qt6. % cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt6/ -DCMAKE_BUILD_TYPE=Release .. Sometimes you need to specify a newer version of g++/gcc. Your installation may have an old version as the default. % cmake -DCMAKE_C_COMPILER=gcc-13 -DCMAKE_CXX_COMPILER=g++-13 -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=Debug .. seer-2.7/src/resource.qrc000066400000000000000000000120161516472651200154560ustar00rootroot00000000000000 resources/icons/hicolor/32x32/seergdb.png resources/icons/hicolor/64x64/seergdb.png resources/icons/hicolor/128x128/seergdb.png resources/icons/hicolor/256x256/seergdb.png resources/icons/hicolor/512x512/seergdb.png resources/icons/hicolor/256x256/rr.png resources/ABOUT.md resources/thenounproject/memory.svg resources/thenounproject/source.svg resources/thenounproject/assembly.svg resources/thenounproject/keyboard.svg resources/thenounproject/configure.svg resources/thenounproject/stop.svg resources/thenounproject/fortune-teller.svg resources/thenounproject/preferences.svg resources/icons-icons/gdb.png resources/icons-icons/editor.png resources/icons-icons/font.png resources/icons-icons/arguments.png resources/icons-icons/debug.png resources/icons-icons/exit.png resources/icons-icons/console.png resources/icons-icons/hide.png resources/icons-icons/maximize.png resources/icons-icons/minimize.png resources/icons-icons/attach.png resources/icons-icons/style.png resources/RelaxLightIcons/application-menu.svg resources/RelaxLightIcons/document-new.svg resources/RelaxLightIcons/document-open.svg resources/RelaxLightIcons/document-print.svg resources/RelaxLightIcons/document-save-as.svg resources/RelaxLightIcons/document-save.svg resources/RelaxLightIcons/edit-clear.svg resources/RelaxLightIcons/edit-delete.svg resources/RelaxLightIcons/edit-find.svg resources/RelaxLightIcons/go-down.svg resources/RelaxLightIcons/go-up.svg resources/RelaxLightIcons/go-next.svg resources/RelaxLightIcons/go-previous.svg resources/RelaxLightIcons/list-add.svg resources/RelaxLightIcons/list-remove.svg resources/RelaxLightIcons/view-refresh.svg resources/RelaxLightIcons/debug-execute-from-cursor.svg resources/RelaxLightIcons/debug-execute-to-cursor.svg resources/RelaxLightIcons/debug-run-cursor.svg resources/RelaxLightIcons/debug-run.svg resources/RelaxLightIcons/debug-step-instruction.svg resources/RelaxLightIcons/debug-step-into-instruction.svg resources/RelaxLightIcons/debug-step-into.svg resources/RelaxLightIcons/debug-step-out.svg resources/RelaxLightIcons/debug-step-over.svg resources/RelaxLightIcons/help-about.svg resources/RelaxLightIcons/help-whatsthis.svg resources/RelaxLightIcons/tools-media-optical-burn-image.svg resources/RelaxLightIcons/data-error.svg resources/RelaxLightIcons/data-information.svg resources/RelaxLightIcons/data-warning.svg resources/RelaxLightIcons/dialog-question.svg resources/RelaxLightIcons/system-shutdown.svg resources/RelaxLightIcons/pin.svg resources/RelaxLightIcons/lock.svg resources/help/ThreadProcessInfoBrowser.md resources/help/seergdb.hlp resources/help/StructVisualizer.md resources/help/BasicStructVisualizer.md resources/help/MemoryVisualizer.md resources/help/ArrayVisualizer.md resources/help/MatrixVisualizer.md resources/help/ImageVisualizer.md resources/help/StackInfoBrowser.md resources/help/VariableRegisterSignalInfoBrowser.md resources/help/SourceSymbolLibraryInfoBrowser.md resources/help/CodeManager.md resources/help/BreakpointGdbSeerManager.md resources/help/MainWindow.md resources/help/DebugModes.md resources/help/RunDebugMode.md resources/help/AttachDebugMode.md resources/help/ConnectDebugMode.md resources/help/RRDebugMode.md resources/help/CorefileDebugMode.md resources/help/Printpoints.md resources/help/Skips.md resources/mi-python/MIEcho.py resources/mi-python/MISkip.py resources/mi-python/MIKill.py resources/mi-python/MICheckpoint.py resources/mi-python/MICatchpoint.py resources/mi-python/MIObjectiveC.py resources/mi-python/MISignals.py seer-2.7/src/resource_qdarkstylesheet.qrc000066400000000000000000000117411516472651200207560ustar00rootroot00000000000000 resources/icons/hicolor/32x32/seergdb.png resources/icons/hicolor/64x64/seergdb.png resources/icons/hicolor/128x128/seergdb.png resources/icons/hicolor/256x256/seergdb.png resources/icons/hicolor/512x512/seergdb.png resources/icons/hicolor/256x256/rr.png resources/ABOUT.md resources/thenounproject/memory.svg resources/thenounproject/source.svg resources/thenounproject/assembly.svg resources/thenounproject/keyboard.svg resources/thenounproject/configure.svg resources/thenounproject/stop.svg resources/thenounproject/fortune-teller.svg resources/icons-icons/gdb.png resources/icons-icons/editor.png resources/icons-icons/font.png resources/icons-icons/arguments.png resources/icons-icons/debug.png resources/icons-icons/exit.png resources/icons-icons/console.png resources/icons-icons/hide.png resources/icons-icons/maximize.png resources/icons-icons/minimize.png resources/icons-icons/attach.png resources/icons-icons/style.png resources/RelaxLightIcons/application-menu.svg resources/RelaxLightIcons/document-new.svg resources/RelaxLightIcons/document-open.svg resources/RelaxLightIcons/document-print.svg resources/RelaxLightIcons/document-save-as.svg resources/RelaxLightIcons/document-save.svg resources/RelaxLightIcons/edit-clear.svg resources/RelaxLightIcons/edit-delete.svg resources/RelaxLightIcons/edit-find.svg resources/RelaxLightIcons/go-down.svg resources/RelaxLightIcons/go-up.svg resources/RelaxLightIcons/go-next.svg resources/RelaxLightIcons/go-previous.svg resources/RelaxLightIcons/list-add.svg resources/RelaxLightIcons/list-remove.svg resources/RelaxLightIcons/view-refresh.svg resources/RelaxLightIcons/debug-execute-from-cursor.svg resources/RelaxLightIcons/debug-execute-to-cursor.svg resources/RelaxLightIcons/debug-run-cursor.svg resources/RelaxLightIcons/debug-run.svg resources/RelaxLightIcons/debug-step-instruction.svg resources/RelaxLightIcons/debug-step-into-instruction.svg resources/RelaxLightIcons/debug-step-into.svg resources/RelaxLightIcons/debug-step-out.svg resources/RelaxLightIcons/debug-step-over.svg resources/RelaxLightIcons/help-about.svg resources/RelaxLightIcons/help-whatsthis.svg resources/RelaxLightIcons/tools-media-optical-burn-image.svg resources/RelaxLightIcons/data-error.svg resources/RelaxLightIcons/data-information.svg resources/RelaxLightIcons/data-warning.svg resources/RelaxLightIcons/dialog-question.svg resources/RelaxLightIcons/system-shutdown.svg resources/qdarkstyle/light/lightstyle.qrc resources/qdarkstyle/dark/darkstyle.qrc resources/help/ThreadProcessInfoBrowser.md resources/help/seergdb.hlp resources/help/StructVisualizer.md resources/help/BasicStructVisualizer.md resources/help/MemoryVisualizer.md resources/help/ArrayVisualizer.md resources/help/MatrixVisualizer.md resources/help/ImageVisualizer.md resources/help/StackInfoBrowser.md resources/help/VariableRegisterSignalInfoBrowser.md resources/help/SourceSymbolLibraryInfoBrowser.md resources/help/CodeManager.md resources/help/BreakpointGdbSeerManager.md resources/help/MainWindow.md resources/help/DebugModes.md resources/help/RunDebugMode.md resources/help/AttachDebugMode.md resources/help/ConnectDebugMode.md resources/help/RRDebugMode.md resources/help/CorefileDebugMode.md resources/help/Printpoints.md resources/help/Skips.md resources/mi-python/MIEcho.py resources/mi-python/MISkip.py resources/mi-python/MIKill.py resources/mi-python/MICheckpoint.py resources/mi-python/MICatchpoint.py resources/mi-python/MIObjectiveC.py resources/mi-python/MISignals.py seer-2.7/src/resources/000077500000000000000000000000001516472651200151325ustar00rootroot00000000000000seer-2.7/src/resources/ABOUT.md000066400000000000000000000242201516472651200163260ustar00rootroot00000000000000  Version VERSIONNUMBER   Seer, a simple and easy-to-use gui frontend to the GDB debugger, having many features. Copyright (C) 2021-2025    Ernie Pasveer.       [https://github.com/epasveer/seer](https://github.com/epasveer/seer)     [epasveer@att.net](mailto:user@example.com)   Icons used by Seer are the property of the original creators. The main Seer icon and other icons.   | Icon | Creator | License | | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | |Icon fortune_teller.sgv | Created by Toli | (License CC3.0) | |Icons Breeze Icon set | Created by L4ki | (License GPLv3) | |Icon arguments.png | Created by Icon box | (License CC4.0) | |Icon console.png | Created by Icons8 | (License CC4.0) | |Icon debug.png | Created by Carbon Design | (License CC4.0) | |Icon editor.png | Created by Piksart | (License CC4.0) | |Icon exit.png | Created by Nicky Lim | (License CC4.0) | |Icon font.png | Created by Dave Gandy | (License CC4.0) | |Icon gdb.png | Created by John Gardner | (License CC4.0) | |Icon hide.png | Created by ferdi setiadi | (License CC4.0) | |Icon maximize.png | Created by ferdi setiadi | (License CC4.0) | |Icon minimize.png | Created by ferdi setiadi | (License CC4.0) | |Icon attach.png | Created by Unknown | (License CC4.0) | |Icon style.png | Created by Free Icons | (License CC4.0) | |Icon assembly.svg | Created by iyikon | (License CC3.0) | |Icon configuration.sgv | Created by tomas.knopp | (License CC3.0) | |Icon keyboard.sgv | Created by Flowicon | (License CC3.0) | |Icon memory.svg | Created by mudassar.hussain323 | (License CC3.0) | |Icon source.svg | Created by kozinn | (License CC3.0) | |Icon stop.sgv | Created by andre.buand10 | (License CC3.0) | |Icon preferences.sgv | Created by blairwolf | (License CC3.0) |     | Styles/Themes | Creator | License | | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | |Style QDarkStyleSheet | Created by Colin Duquesnoy | (License MIT) | | | | (License CC4.0) |     Credits to kdbg, gede, gdbgui, nemiver, and many other projects for ideas and examples.     seer-2.7/src/resources/README.icons000066400000000000000000000140751516472651200171330ustar00rootroot00000000000000 The main Seer icon is from TheNounProject under the CC3.0 license. The .svg file was converted to .png for better handling of fixed sized .png files. "Toli" is the copyright owner, as mentioned below. Seer uses it under the CC3.0 license. https://thenounproject.com/icon/fortune-teller-3505303/ https://thenounproject.com/tolicon/ thenounproject/fortune-teller.svg CC3.0 seergdb_*.png Some icons are used from "IconsIcons" and "TheNounProject" and are licensed under "CreativeCommons" CC3.0 and CC4.0 licenses. terms of the NetBeans License Agreement. https://icon-icons.com/icon/GDB/132365 https://icon-icons.com/users/AmQJzv5e8DpITUWIRmGPz/icon-sets/ icons-icons/gdb.png CC4.0 https://icon-icons.com/icon/keyboard/122169 https://icon-icons.com/users/z1gHIAw5WHSQk4RJ0exyV/icon-sets/ icons-icons/keyboard.png CC4.0 https://icon-icons.com/icon/web-design-writing-coding-development/220538 https://icon-icons.com/users/14h9fJJJmBr3Dm13gYSpS/icon-sets/ icons-icons/editor.png CC4.0 https://icon-icons.com/icon/font-symbol-of-letter-a/73556 https://icon-icons.com/users/2LUKwJe4QDNsjuhkS98IX/icon-sets/ icons-icons/font.png CC4.0 https://icon-icons.com/icon/setting-configure-repair-support-optimization-google/83447 https://icon-icons.com/users/Nixd2U1fkolfZAGKcPLGu/icon-sets/ icons-icons/configure.png CC4.0 https://icon-icons.com/icon/setting-balance-equalizer/152217 https://icon-icons.com/users/67020lqBmzmzx0F3OH2GE/icon-sets/ icons-icons/arguments.png CC4.0 https://icon-icons.com/icon/debug/215819 https://icon-icons.com/users/7dBLqleqakUowFGJkWLXY/icon-sets/ icons-icons/debug.png CC4.0 https://icon-icons.com/icon/logout-exit/176185 https://icon-icons.com/users/ah334sOoBVVE7GXS94Who/icon-sets/ icons-icons/exit.png CC4.0 https://icon-icons.com/icon/console/5091 https://icon-icons.com/users/Vn6TUStZ7Ng5JKLU3rRHX/icon-sets/ icons-icons/console.png CC4.0 https://icon-icons.com/icon/resize-maximize/175765 https://icon-icons.com/users/sr18GsT8hXb37mrJn4kOU/icon-sets/ icons-icons/maximize.png CC4.0 https://icon-icons.com/icon/minimize-window/175768 https://icon-icons.com/users/sr18GsT8hXb37mrJn4kOU/icon-sets/ icons-icons/minimize.png CC4.0 https://icon-icons.com/icon/attache-attached-attachement-clip-complement/113448 https://icon-icons.com/users/NXDGlLPTpYrqHz13UzsZ4/icon-sets/ icons-icons/attach.png CC4.0 https://icon-icons.com/icon/delete-remove/175783 https://icon-icons.com/users/sr18GsT8hXb37mrJn4kOU/icon-sets/ icons-icons/hide.png CC4.0 https://icon-icons.com/icon/face-glasses-sunglasses/107950 https://icon-icons.com/users/7VZI9qW3el29z8Ka5fjmo/icon-sets/ icons-icons/style.png CC4.0 https://thenounproject.com/icon/asm-file-document-icon-2598539/ https://thenounproject.com/iyikon/ thenounproject/assembly.svg CC3.0 https://thenounproject.com/icon/configuration-1115171/ https://thenounproject.com/tomas.knopp/ thenounproject/configure.svg CC3.0 https://thenounproject.com/icon/keyboard-key-4571629/ https://thenounproject.com/Flowicon/ thenounproject/keyboard.svg CC3.0 https://thenounproject.com/icon/binary-data-search-4065152/ https://thenounproject.com/mudassar.hussain323/ thenounproject/memory.svg CC3.0 https://thenounproject.com/icon/cpp-file-252779/ https://thenounproject.com/kozinn/ thenounproject/source.svg CC3.0 https://thenounproject.com/icon/interruption-4417639/ https://thenounproject.com/andre.buand10/ thenounproject/stop.sgv CC3.0 https://thenounproject.com/icon/preference-2331720/ https://thenounproject.com/creator/blairwolf/ thenounproject/preferences.svg CC3.0 Some icons are used from the RelaxLightIcons set. Licensed under the GPL-3.0+ license. L4ki https://github.com/L4ki RelaxLightIcons/debug-execute-from-cursor.svg RelaxLightIcons/debug-execute-to-cursor.svg RelaxLightIcons/debug-run-cursor.svg RelaxLightIcons/debug-run.svg RelaxLightIcons/debug-step-instruction.svg RelaxLightIcons/debug-step-into-instruction.svg RelaxLightIcons/debug-step-into.svg RelaxLightIcons/debug-step-out.svg RelaxLightIcons/debug-step-over.svg RelaxLightIcons/document-new.svg RelaxLightIcons/document-open.svg RelaxLightIcons/document-print.svg RelaxLightIcons/document-save-as.svg RelaxLightIcons/document-save.svg RelaxLightIcons/edit-clear.svg RelaxLightIcons/edit-delete.svg RelaxLightIcons/edit-find.svg RelaxLightIcons/go-down.svg RelaxLightIcons/go-next.svg RelaxLightIcons/go-previous.svg RelaxLightIcons/go-up.svg RelaxLightIcons/help-about.svg RelaxLightIcons/help-whatsthis.svg RelaxLightIcons/list-add.svg RelaxLightIcons/list-remove.svg RelaxLightIcons/tools-media-optical-burn-image.svg RelaxLightIcons/view-refresh.svg seer-2.7/src/resources/RelaxLightIcons/000077500000000000000000000000001516472651200201715ustar00rootroot00000000000000seer-2.7/src/resources/RelaxLightIcons/application-menu.svg000066400000000000000000000007001516472651200241540ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/data-error.svg000066400000000000000000000010241516472651200227470ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/data-information.svg000066400000000000000000000006661516472651200241560ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/data-warning.svg000066400000000000000000000012271516472651200232700ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/debug-execute-from-cursor.svg000066400000000000000000000007131516472651200257150ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/debug-execute-to-cursor.svg000066400000000000000000000007161516472651200253770ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/debug-run-cursor.svg000066400000000000000000000006761516472651200241260ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/debug-run.svg000066400000000000000000000007011516472651200226000ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/debug-step-instruction.svg000066400000000000000000000103521516472651200253310ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/debug-step-into-instruction.svg000066400000000000000000000101031516472651200262720ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/debug-step-into.svg000066400000000000000000000073551516472651200237320ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/debug-step-out.svg000066400000000000000000000073561516472651200235710ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/debug-step-over.svg000066400000000000000000000073451516472651200237330ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/dialog-question.svg000066400000000000000000000013301516472651200240130ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/document-new.svg000066400000000000000000000011661516472651200233230ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/document-open.svg000066400000000000000000000007301516472651200234670ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/document-print.svg000066400000000000000000000007621516472651200236670ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/document-save-as.svg000066400000000000000000000022331516472651200240650ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/document-save.svg000066400000000000000000000014241516472651200234650ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/edit-clear.svg000066400000000000000000000012271516472651200227250ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/edit-delete.svg000066400000000000000000000006601516472651200231010ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/edit-find.svg000066400000000000000000000013141516472651200225540ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/go-down.svg000066400000000000000000000007661516472651200222750ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/go-next.svg000066400000000000000000000010261516472651200222720ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/go-previous.svg000066400000000000000000000010311516472651200231640ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/go-up.svg000066400000000000000000000006071516472651200217440ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/help-about.svg000066400000000000000000000012531516472651200227530ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/help-whatsthis.svg000066400000000000000000000014131516472651200236550ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/list-add.svg000066400000000000000000000006711516472651200224170ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/list-remove.svg000066400000000000000000000005431516472651200231620ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/lock.svg000066400000000000000000000010561516472651200216440ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/pin.svg000066400000000000000000000006061516472651200215020ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/system-shutdown.svg000066400000000000000000000043071516472651200241130ustar00rootroot00000000000000 image/svg+xml seer-2.7/src/resources/RelaxLightIcons/tools-media-optical-burn-image.svg000066400000000000000000000020061516472651200266020ustar00rootroot00000000000000 seer-2.7/src/resources/RelaxLightIcons/view-refresh.svg000066400000000000000000000012441516472651200233210ustar00rootroot00000000000000 seer-2.7/src/resources/flathub/000077500000000000000000000000001516472651200165575ustar00rootroot00000000000000seer-2.7/src/resources/flathub/BUILD.sh000077500000000000000000000006721516472651200177620ustar00rootroot00000000000000#!/bin/bash # Build the Seergdb flatpak flatpak uninstall -y io.github.epasveer.seer \rm -rf build-dir/ repo/ .flatpak-builder/ seer.flatpak flatpak run org.flatpak.Builder --force-clean build-dir io.github.epasveer.seer.yml flatpak run org.flatpak.Builder --force-clean --repo=repo build-dir io.github.epasveer.seer.yml flatpak build-bundle repo seer.flatpak io.github.epasveer.seer master flatpak install -y --bundle --user seer.flatpak seer-2.7/src/resources/flathub/README000066400000000000000000000041171516472651200174420ustar00rootroot00000000000000$ vim com.github.epasveer.seer.json $ ls -l ~/.local/share/flatpak/app/com.github.epasveer.seer/ $ flatpak update $ flatpak install flathub org.kde.Sdk//6.10 $ flatpak install flathub org.kde.Platform//6.10 $ flatpak list Name Application ID Version Branch Installation Flatpak Builder Flatpak org.flatpak.Builder v0-Flathub stable system ... $ flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo $ flatpak info io.github.epasveer.seer $ flatpak search gdb $ flatpak remove io.github.epasveer.seer $ flatpak-builder --force-clean build-dir ../src/resources/flathub/io.github.epasveer.seer.yml $ flatpak-builder --user --install --force-clean build-dir ../src/resources/flathub/io.github.epasveer.seer.yml $ flatpak run io.github.epasveer.seer -s /nas/erniep/Development/seer/tests/hellostruct/hellostruct $ flatpak run io.github.epasveer.seer --gdb-program=/app/bin/gdb -s /nas/erniep/Development/seer/tests/hellostruct/hellostruct $ flatpak run --command=bash io.github.epasveer.seer $ flatpak run --command=bash org.gnome.Sdk//46 $ flatpak run --command=bash org.freedesktop.Platform.GL.default $ flatpak run --command=bash org.freedesktop.Sdk//24.08 $ flatpak run --command=bash org.freedesktop.Sdk/x86_64/25.08 $ flatpak uninstall -y io.github.epasveer.seer $ \rm -rf build-dir/ repo/ .flatpak-builder/ seer.flatpak $ flatpak run org.flatpak.Builder --force-clean build-dir ../src/resources/flathub/io.github.epasveer.seer.yml $ flatpak run org.flatpak.Builder --force-clean --repo=repo build-dir ../src/resources/flathub/io.github.epasveer.seer.yml $ flatpak build-bundle repo seer.flatpak io.github.epasveer.seer master $ flatpak install -y --bundle --user seer.flatpak $ flatpak run --command=flatpak-builder-lint org.flatpak.Builder repo repo $ flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest ../src/resources/flathub/io.github.epasveer.seer.yml seer-2.7/src/resources/flathub/io.github.epasveer.seer.desktop000066400000000000000000000004551516472651200246140ustar00rootroot00000000000000[Desktop Entry] Version=1.0 Type=Application Name=seer GenericName=GDB Frontend Comment=A GUI frontend to the GDB debugger Icon=io.github.epasveer.seer Exec=seergdb Terminal=false Categories=Development;Debugger;Qt; Keywords=debug;gdb;debugger;qt; StartupNotify=true X-Flatpak=io.github.epasveer.seer seer-2.7/src/resources/flathub/io.github.epasveer.seer.github.yml000066400000000000000000000013021516472651200252150ustar00rootroot00000000000000app-id: io.github.epasveer.seer runtime: org.kde.Platform runtime-version: '6.10' sdk: org.kde.Sdk command: seergdb finish-args: - --socket=fallback-x11 - --socket=wayland - --device=dri - --device=all # Needed for stdout/stdin to debug target - --share=ipc - --filesystem=host # Filesystem access for debugging programs - --talk-name=org.freedesktop.Flatpak # Permission to `flatpak-spawn --host` modules: - name: seergdb buildsystem: cmake-ninja builddir: true subdir: src config-opts: - -DCMAKE_BUILD_TYPE=Release - -DCONFIG_SEER_INSTALL_FLATHUB_FILES=1 sources: - type: git url: https://github.com/epasveer/seer.git branch: main seer-2.7/src/resources/flathub/io.github.epasveer.seer.metainfo.xml000066400000000000000000000026761516472651200255530ustar00rootroot00000000000000 io.github.epasveer.seer CC0-1.0 GPL-3.0-or-later https://github.com/epasveer/seer seer A GUI frontend to GDB debugger io.github.epasveer.seer

Seer is a graphical frontend to the GDB debugger that provides a rich development environment for debugging programs.

Features:

  • Source code browsing and breakpoint management
  • Variable inspection and modification
  • Stack frame navigation
  • Memory inspection
  • Assembly view
  • Register view
io.github.epasveer.seer.desktop Main debugging window https://raw.githubusercontent.com/epasveer/seer/main/images/mainview.png https://github.com/epasveer/seer https://github.com/epasveer/seer/issues Ernie Pasveer
seer-2.7/src/resources/flathub/io.github.epasveer.seer.yml000066400000000000000000000013721516472651200237430ustar00rootroot00000000000000app-id: io.github.epasveer.seer runtime: org.kde.Platform runtime-version: '6.10' sdk: org.kde.Sdk command: seergdb finish-args: - --socket=fallback-x11 - --socket=wayland - --device=dri - --device=all # Needed for stdout/stdin to debug target - --share=ipc - --filesystem=host # Filesystem access for debugging programs - --talk-name=org.freedesktop.Flatpak # Permission to `flatpak-spawn --host` modules: - name: seergdb buildsystem: cmake-ninja builddir: true subdir: src config-opts: - -DCMAKE_BUILD_TYPE=Release - -DCONFIG_SEER_INSTALL_FLATHUB_FILES=1 sources: - type: git url: https://github.com/epasveer/seer.git commit: 6f93e7eca6077faa2152a9130eb16d4b40a856a9 # tag: v2.7 seer-2.7/src/resources/help/000077500000000000000000000000001516472651200160625ustar00rootroot00000000000000seer-2.7/src/resources/help/ArrayVisualizer.md000066400000000000000000000051041516472651200215400ustar00rootroot00000000000000## Array Visualizer ### Introduction The Array Visualizer shows the contents of one or two variables, that are arrays, in a graph/chart view. When providing two arrays, they can be treated as two independant arrays (assigning both to the Y axis) or one array can be the X points and the other array can be the Y points. There are different views of the plot (line, spline, scatter) and the array values can be shown as points and/or labels. The Array Visualizer is made up of 3 main parts: * Input parameters * Values table * Plot area The plot area is a typical graph that has its 'Y' axis on the left side and the 'X' axis across the bottom. ``` ^ | | Y | | | | +---------------------------------> X ``` ### Input parameters This part of the Visualizer specifies the one or two arrays to view. If one array is to be viewed, leave the second entry blank. Otherwise, enter the array details for both arrays. Here are the details for an array. * Axis. Specify what axis the array is for. Can be 'Y' or 'X'. 'Y' is the default. * Variable name. The name name should resolve to an address. * Number of elements. The total length of the array. * Array offset. How many elements to initially skip. Default 0 (start at the begining of the array). * Array stride. How the elements are accessed in the array. Default 1 (use every element). 2 would access every second element. * Array data type. * Refresh. By having array offset and array stride, it's possible to handle the case of a single array containing X/Y points as alternating X and Y values. ### Values table This part of the Visualizer shows the arrays values as one or two columns. The number of rows in the column is the number of elements in the array. Note, the array offset and array stride is taken into account. Each column in the table will have a title, which reflects the variable name and the array offset and stride: ``` &array:0:1 ``` ### Plot area This area shows the plot for the one or two arrays. The plot can be modified with: * Chart title. Add a title to the top of the plot. * Plot mode * Line. Simple line plot. * Spline. Points are plotted using splines. * Scatter. Points are plotted using scatter points. * Annotation * Points. Visually show the points. * Labels. Annotate the value at each point. ### Operation The plot area can be interactive in these way: * '+', '-', mouse scroll button. Zoom in or out of the plot. * LMB drag and hightlight. Zoom in on the selected region. * Shift+LMB. Drag plot around. * 'esc'. Reset plot area. seer-2.7/src/resources/help/AttachDebugMode.md000066400000000000000000000011451516472651200213650ustar00rootroot00000000000000## Attach debug mode ### Introduction This mode allows Seer to debug a locally running process by attaching to the PID. ### Requirements In this mode, Seer needs: * The executable * Optional symbol file if the executable doesn't have debug information * The PID of the process. ### What can you do? In this mode, Seer will attach to the process and immediately interrupt it with a SIGINT. Seer will show the source and line number where the program was interrupted. The program's stack and threads are shown. From this point, you can debug the process as normal (stepping and setting breakpoints, etc...) seer-2.7/src/resources/help/BasicStructVisualizer.md000066400000000000000000000037511516472651200227160ustar00rootroot00000000000000## Basic Struct Visualizer ### Introduction The Struct Visualizer shows the contents of C/C++ structs and classes in a tree view. It is read-only and doesn't follow pointers. Use the regular Struct Visualizer for that. For each variable of the struct, Seer shows these two columns: * Variable name * Value *Variable name* is the name of the variable, at that point in the stuct hiearchy. *Value* is the value of the variable, presented in the best way possible by gdb. This version of the Struct Visualizer expands to all levels when the variable is first entered. After that, levels can be collapsed or expanded again. Also, variables that are pointers are never followed. Use the new implementation for that :^) ### Operation The Struct Visualizer has these main components * Variable entry field * Refresh * Auto mode * Variable Tree ### Variable entry field This entry field allows you to enter the name of a variable. This variable can be for a struct or a class. It could also be a simple datatype like an *int* or a *string* but that would be pointless as simple datatypes have no nesting structure. Enter the variable name and hit return. All levels of the struct will be shown. If it has any subvalues, a '+' icon will appear beside it so that it can later be collapsed. Note, if the variable name is not valid, a message will be printed in the Value field. ### Refresh This will refresh the tree with any variables that have changed values since the last time. ### Auto mode This mode will refresh the tree each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). ### Variable tree As mentioned, the variable tree shows the variable names and values of the struct. A '+' icon is shown beside each level. This will expand or collapse the level. ### Modifying values. This implementation has no feature to modify values. ### Invoking other Visualizers. Using the RMB on a variable will bring up a menu to launch another Visualizer for that variable. seer-2.7/src/resources/help/BreakpointGdbSeerManager.md000066400000000000000000000127201516472651200232330ustar00rootroot00000000000000## Breakpoint/GDB log Manager ### Introduction This part of Seer shows Breakpoints, GDB log, and Seer log information. In detailed, the information is: * Messages * Breakpoints * Watchpoints * Catchpoints * Printpoints * Checkpoints * GDB output * Seer output * Save and load breakpoints * Manual GDB commands. ### Messages Various gdb execution messages are listed in this tab. These occur as you debug the program. The message types are: * Program startup and completion * Breakpoint encouters * Signal encounters * General gdb errors The message tab can be raised in various ways when a message is added to the tab: * Any message * Important messages (program startup, signal encounters) * Never ### Breakpoints Breakpoints sets up a stopping point of the program being debugged when a function and line number is reached. ### Watchpoints Watchpoints catch the access and/or modification of a variable and will stop the program being debugged at that point. ### Catchpoints Catchpoints catch the execution of one of these program actions just before they are called and will stop the program being debugged at that point. * C++ * throw * rethrow * catch * Shared Library * Load * Unload * Ada * assert * exception * handlers There are other types of catchpoints but GDB/mi only supports the above list at the moment. ### Printpoints A printpoint is a type of breakpoint that will print the value of a variable at a certain line of a function. It relies on gdb's ```dprintf``` feature. ### Checkpoints A checkpoint is a simple form of time-travel debugging. You can create a checkpoint at any point where the program you're debugging is stopped. This checkpoint is listed in the Checkpoints tab. You can continue to debug your program. At any time, you can return back to the checkpoint (go back in time) and continue debugging again from that point. You can create as many checkpoints as you want and switch between them. A couple things to note: * This is not supported on all platforms. * Switching to a previous checkpoint does not undo any I/O. You can't unwrite data written to a file or unprint text sent to a printer. ### Modifying existing breakpoints. Once a breakpoint (Breakpoint, Watchpoint, Catchpoint, Printpoint) is created, certain things about the breakpoint can be modified. Not everything, though. For example, you can not change the function or line number for a breakpoint. In that case, you need to delete the breakpoint and recreated it. These things can be modified. * Enable/disable state. * Add or remove a condition. eg: Break if 'i == 10'. * Add or remove an ignore count. eg: Ignore the first 5 occurences of the breakpoint. * Add or remove a series of gdb commands to execute when the breakpoint is reached. Not available for Printpoints. ### GDB output Any output from the GDB program is output to this logger. This is any regualar GDB output, including the result of any GDB command manually entered. ### Seer output Any output from the Seer program is ouput to this logger. Mostly, this is the result of any GDB/mi command, whether the GDB/mi command is manually entered or entered by Seer. Normally this logger is disabled. ### Console output Any output from the program being debugged is output to this logger. Basically, the program's stdout. The stdout can also be echoed to the terminal that started Seer. This logging tab can be started attached along side the other loggers. Or detached as a normal window. Or detached as a minimized window. See Seer's config dialog or View->Console menu option. Be sure to save the config changes. If the program being debugged is asking for stdin input, it can be entered in the "stding input text" field. ### Save and load breakpoints There are two buttons to save or load the various types of breakpoints to/from a file. The breakpoint file can be specified in the Debug dialog or on the command line: ``` --bl, --break-load ``` ### Manual gdb commands This input field allows GDB and GDB/mi commands to be manually entered. The results of the GDB commands will be logged to the GDB output. GDB/mi will be logged to the Seer output. Seer maintains a history of N commands, as set in the Seer Config dialogs. This history is remembered for the next time Seer is used. ### Macro gdb commands There are 10 macros you can create for custom commands. They are labelled "M1" through "M0". Think of your keyboard with numeric keys 1 through 0. They have hotkeys mapped from Ctrl+Shift+1 through Ctrl+Shift+0. Clicking the button or using the hotkey will execute the commands in the macro. Holding down the button will bring up an editor to edit the contents of the macro. Typically the macro contains gdb commands. Output will go to the GDB output tab. The macro is executed using gdb's "source" command, which can handle a lot off unique cases. ### References Consult these gdb references 1. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Set-Breaks.html#Set-Breaks) Using Breakpoints. 2. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Set-Watchpoints.html#Set-Watchpoints) Using Watchpoints. 3. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Set-Catchpoints.html#Set-Catchpoints) Using Catchpoints. 4. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Dynamic-Printf.html#Dynamic-Printf) Using DPrintf for Printpoints. 5. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Checkpoint_002fRestart.html#Checkpoint_002fRestart) Using Checkpoints. seer-2.7/src/resources/help/CodeManager.md000066400000000000000000000046241516472651200205570ustar00rootroot00000000000000## Code Manager ### Introduction This is the main part of Seer that shows source files as they are opened. Opening a source file can happen in three ways: * The program reaching a stopping point (via a 'step', 'next', or breakpoint). * Clicking on a frame in the Stack Info browser. * Clicking on a filename in the Source browser (Source/Symbol/Library browser). As well as the source files, Seer can show the code's assembly as a tab. See: ``` View->Assembly ``` Or ``` Config->Assembly ``` When in a source file, using the RMB will bring up a menu to do any of these: * Create a breakpoint * Create a printpoint * Enable/disable a breakpoint or printpoint * Execute the program to a certain line in the source file. Selecting a variable (highlighting) will allow that variable to be added to one of these via the RMB: * Variable Logger * Variable Tracked * Memory Visualizer * Array Visualizer * Struct Visualizer ### Keys The easiest method for logging a variable to the Variable Logger is to double-click the variable text in the source. When doing this, a key modifier (shift and/or ctrl) can be used to prepend a '*' and/or '&' to the variable. This will better handle pointers and references. ``` Double-Click Modifier Description Example ------------ ------------------------------------ ----------------------- None No modifier is prepended to variable 'argc' Shift Key Prepend '&' to variable '&argc' Ctrl Key Prepend '*' to variable '*argc' Ctrl+Shift Prepend '*&' to variable '*&argc' ``` Other key sequences. ``` Keys Description ------------ ------------------------------------ Ctrl+LMB Goto function defintion identified by text under cursor. ^F Bring up a text search bar in the source window. ^L Bring up a line number search bar in the source window. ^O Bring up a file bar to help locate the file for the source (in case it isn't in the directory that GDB thinks it is). ``` ### Buttons There are these buttons: * File open. Open a file. Can be any file, as long as it is plain text. * Close files. Bring up a dialog to easily select source files to close. * Search. Open the search bar. seer-2.7/src/resources/help/ConnectDebugMode.md000066400000000000000000000025111516472651200215500ustar00rootroot00000000000000## Connect debug mode ### Introduction This mode allows Seer to debug a local or remote process that was started with gdbserver (or other gdb servers). Typically, the gdbserver starts the process and interrupts it before anything happens. It then waits for something to connect to it. When Seer connects with it, the process is ready to continue executing. ### Requirements In this mode, Seer needs: * Optional executable file if the remote gdbserver/gdbstub hasn't loaded one * Optional symbol file if the executable doesn't have debug information * How to look for the gdbserver (machine and port) * Remote target type when connecting to the gdbserver. * 'extended-remote' (default) * 'remote' (sometimes required if gdbserver doesn't support all commands) * Optional enabling of gdb and gdbserver debug communication (set debug remote 1). See the gdb tab for output. * Optional gdb commands to execute before and after Seer connects to the gdbserver ### What can you do? In this mode, Seer will connect to the process via the gdbserver. Typically you set breakpoints first then tell the process to continue. From this point, you can debug the process as normal (stepping and setting breakpoints, etc...) ### References Check references for gdbserver and other gdb servers. * gdbserver * valgrind vgdb * servers for embedded development seer-2.7/src/resources/help/CorefileDebugMode.md000066400000000000000000000020101516472651200217010ustar00rootroot00000000000000## Corefile debug mode ### Introduction This mode allows Seer to debug corefiles. Corefiles are files that are the state of a process that exits unexepectedly via a signal (SIGTERM, SIGSEGV, etc...) ### Requirements In this mode, Seer needs: * The executable * Optional symbol file if the executable doesn't have debug information * The corefile. ### What can you do? In this mode, Seer will load the executable and the corefile. It will try to show the reason for the corefile (which signal). Look for this in the "GDB output" tab. Seer will also show the source and line number where the program crashed. You won't be able to do any stepping. You can move through the stack and show values of variables and memory, though. ### References Check your system's configuration to see how to enable corefile generation. Some distros have it disabled by default. Also, corefiles may not be located in the directory where the program ran. They may be located in some system directory (eg: /var/local/dumps). Check your distro. seer-2.7/src/resources/help/DebugModes.md000066400000000000000000000020201516472651200204140ustar00rootroot00000000000000## Seer debug modes ### Introduction Seer supports most debugging modes that gdb provides. These are: * Starting and running a program * Attaching to a local process on the system * Connecting to a gdbserver * Loading a previously created RR trace session * Loading a corefile leftover from a program that crashed ### What can you do? Select the mode and enter the appropriate arguments and settings. For all modes, you can specify 'pre' and 'post' native gdb commands. * 'pre' - gdb commands to execute before the executable is loaded (or attach, or connect, or loading of corefile). * 'post' - gdb commands to execute afterwards Click OK and Seer will start the debugging session. ### Projects A project file can be created. The project file will save: * Name of executable * Name of symbol file * Working directory * All arguments and settings for the selected mode * All 'pre' and 'post' commands The project file can then be loaded the next time Seer is used. The project file has a simple Json layout and can be hand edited. seer-2.7/src/resources/help/ImageVisualizer.md000066400000000000000000000035441516472651200215120ustar00rootroot00000000000000## Image Visualizer ### Introduction The Image Visualizer shows the contents of a region of memory as an image. ### Operation There are various things to control how the image is display. * Starting address entry field * Image format * Image width * Image height * Refresh * Auto Refresh A check is done to ensure the amount of memory given to the Memory Visualizer will cover the image size. If there is a problem, it's likely the wrong format is selected. ### Starting address entry field The 'Starting Address' input field takes the name of a variable that is in the current Stack Frame (selected by the Stack Frame browser). This variable should result in an address. For example, take this code: ``` int var = 10; ``` To visualize the memory for 'var', the variable should be '&var', not 'var'. As 'var' doesn't resolve to an address. Note, the variable name can be an address. Enter the address like: ``` 0xdeadbeaf ``` It can be the result of a function in your program. ``` myimage.pointer() ``` It can also be one of gdb' special variables. Like the program counter. Enter it like: ``` $pc ``` ### Image format. Two supported formats are available. Others can be added easily. * RGBA8888 * RGB888 ### Image dimensions. The image width and height, in pixels. These fields can take a gdb expression that result with an integer. ``` An integer value A function that returns an integer value A gdb special variable. ``` Examples are: ``` 256 myimage.width() $r9 ``` ### Refresh This will refresh the image since the last time. ### Auto mode This mode will refresh the image each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). ### Image interaction Available Quick keys while in the Image Visualizer: ``` '+' zoom in '-' zoom out ESC reset to default zoom level. ``` seer-2.7/src/resources/help/MainWindow.md000066400000000000000000000024401516472651200204600ustar00rootroot00000000000000## Seer Main Window ### Main Tool Bar The main tool bar has buttons for Seers's common functions. Most of these buttons also have hotkeys assigned to them. These can be configured with "Settings->Configure->Keys". The buttons are arranged in groups. * Restarting the debug session. * Run - Restart the program. Only stop at any previously set breakpoints. * Start - Restart the program. Stop in main(). * Stepping. * Continue - Continue the program until it encounters the next breakpoint or it ends. * Next - Execute the next line. Step over if it's a function. * Step - Exectue the next line. Step into it it's a function. * Finish - Finish the current function. Honor any breakpoints. * Instruction recording. Use gdb's instruction and playback feature. * Record - Start the record mode. * Direction - Set playback mode. Forward or reverse. The direction affects the Stepping functions. * Program interruption. Interrupt the running program or send it a specific signal. * Visualizers * Memory - Visualize a region of memory in a 'hex viewer'. * Array - Visualize a region of memory as arrays. A table and 2D plot. * Struct - Visualize a region of memory as a nested C/C++ structure. * Image - Visualize a region of memory as a RGB or RGBA image. seer-2.7/src/resources/help/MatrixVisualizer.md000066400000000000000000000025751516472651200217370ustar00rootroot00000000000000## Matrix Visualizer ### Introduction The Matrix Visualizer shows the contents of an array as a matrix, a number of rows and an number of columns. The Matrix Visualizer is made up of 3 main parts: * Input parameters * Values table * Statistic information ### Input parameters This part of the Visualizer specifies the array to view. Here are the details for an array. * Variable name of the array. The name name should resolve to an address. * Number of rows and columns. The total length of the array is determined from this. * Array offset. How many elements to initially skip. Default 0 (start at the begining of the array). * Array stride. How the elements are accessed in the array. Default 1 (use every element). 2 would access every second element. * Array data type. * Refresh. By having array offset and array stride, it's possible to handle oddly constructed arrays. ### Values table This part of the Visualizer shows the array's values as a matrix. The number of rows and number of columns reflect the values entered in the input parameters. Note, the array offset and array stride is taken into account. ### Statistic information These statistical values are calculated from the array values. * Count of values * Count of number of rows * Count of number of columns * Minimum value of values * Maximum value of values * Sum of values * Average value * Median value * RMS value seer-2.7/src/resources/help/MemoryVisualizer.md000066400000000000000000000052371516472651200217410ustar00rootroot00000000000000## Memory Visualizer ### Introduction The Memory Visualizer shows the contents of a region of memory in different formats, including strings and assembly. * Hex * Octal * Binary * Decimal * Ascii * UTF-8, UTF-16, UTF-32 * Ebcdic * Assembly The memory displayed in 3 views. * A memory dump in the chosen Display format. Included in this view is the memory displayed in the Character format. A byte can be selected in this view to highlight it. * A table showing the highlighted byte in different numeric formats (int, float, double, etc...). * A separate tab showing the memory as disassembly. A CRC16 checksum of the memory region is also displayed. Useful for quickly determining if different memory regions have the same contents. ### Operation There are various things to control how the memory is display. * Starting address entry field * Number of bytes entry field * Display format * Character format * Column width * Refresh * Auto Refresh ### Starting address entry field The 'Starting Address' input field takes the name of a variable that is in the current Stack Frame (selected by the Stack Frame browser). This variable should result in an address. For example, take this code: ``` int var = 10; ``` To visualize the memory for 'var', the variable should be '&var', not 'var'. As 'var' doesn't resolve to an address. Note, the variable name can be an address. Enter the address like: ``` 0xdeadbeaf ``` It can also be one of gdb' special variables. Like the program counter. Enter it like: ``` $pc ``` ### Number of bytes entry field The default number of bytes to display is 256. Fewer or more than this number can be entered. This can take a gdb expression. * A value. '100' * An expression. '100+50' * The result of a function in the program. 'myarraysize()' ### Display format. The memory dump can be displayed in these formats: * Hex * Octal * Binary * Decimal ### Character format The memory dump can be displayed in these character formats: * Ascii * UTF-8, UTF-16, UTF-32 * Ebcdic Note, when displaying UTF, some features in the visualizer are restricted. For example, when clicking on a byte in the memory dump, the corresponding character in the text view is not highlighted. This is because UTF can be a variable length of bytes per character - due to UTF encoding. A possible delay may happen to load the extra fonts needs for the extra characters that UTF provides. ### Column width This specifies the column width of the memory dump. ### Refresh This will refresh the memory dump since the last time. ### Auto mode This mode will refresh the memory dump each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). seer-2.7/src/resources/help/Printpoints.md000066400000000000000000000102451516472651200207370ustar00rootroot00000000000000## Printpoints ### Introduction Printpoints are a type of gdb breakpoint that simply prints a custom message when the breakpoint is reached. After the message is printed, the program is continued automatically. So, basically, a way to add print statements without adding them to your code. ### Printpoint types There are 3 types of printpoints. ### 'gdb' printpoints The ```gdb``` printpoint is the most common. When used, it uses gdb's ```printf``` command, which provides C style formatting. Consider this example of code: ``` 12 13 std::cout << " C++ loop" << std::endl; 14 for (n=1; n<=count; n++) { 15 nfact = nfact * n; 16 std::cout << std::setw(12) << n << std::setw(14) << nfact << std::endl; 17 } 18 ``` A printpoint can be added to line 15 to print the value of ```n``` and ```count```. Create a printpoint by RMB clicking on line 15 of source, or click 'Add a new printpoint' in the Printpoints tab. Fill in the name of the source file and the line number. Now fill in the printpoint details: ``` Format : "N=%d COUNT=%d\n" Arguments : n count Type : gdb Function : Channel : ``` When you run your program, the print statements will appear in Seer's Gdb tab. ### 'call' printpoints The ```call``` printpoint type allows you to use an alternate ```print``` function instead of gdb's ```printf``` command. There are a couple restrictions for this ```print``` function. - Must have a signature that takes VA_ARGS. - Needs to be part of your program. ie: linked in or part of some .so, like glibc. There are 2 ```call``` methods. One without a "channel" and one with a "channel". What is a "channel"? It's like the first argument to ```fprintf()```, or ```dprintf()``` *** Here is an example of ```call``` without a "channel". It will use ```printf()``` from glibc. We'll use the same code example and will add the printpoint on the same line number. ``` Format : "N=%d COUNT=%d\n" Arguments : n count Type : call Function : printf Channel : ``` When you run your program, the print statements will appear in Seer's Console tab. *** Here is an example of ```call``` ***with*** a "channel". It will use ```dprintf()``` from glibc, which takes a file descriptor as its first argument. We'll be using FD of 1, which is stdout. We'll use the same code example and will add the printpoint on the same line number. ``` Format : "N=%d COUNT=%d\n" Arguments : n count Type : call Function : dprintf Channel : 1 ``` When you run your program, the print statements will appear in Seer's Console tab. ### 'agent' printpoints If your program is started with ```gdbserver```, a printpoint type of ```agent``` will tell the gdbserver to print the message. First, start the program using ```gdbserver```. ``` $ gdbserver :1234 hellodprintf ``` Then start Seer and connect to the ```gdbserver```. We'll use the same code example and will add the printpoint on the same line number. ``` Format : "N=%d COUNT=%d\n" Arguments : n count Type : agent Function : Channel : ``` The print statements will appear from the ```gdbserver``` process. ### Warnings Printpoints, actually ```dprintf```, are not very error friendly. Errors in your parameters are not checked until the breakpoint is reached. This can cause gdb to behave poorly or can, most likely, confuse Seer. You'll end up restarting your debugging session. The ```call``` method seems to work only with C/C++ code. It doesn't work with Fortran. Not sure about any other language. The error message is very vague and appears in the Gdb tab as "parsing error". Seer ends up in a confused state. ### References Printpoints use gdb's ```dprintf``` command. Not to be confused with the C language's ```dprintf()``` function. https://sourceware.org/gdb/current/onlinedocs/gdb.html/Output.html https://sourceware.org/gdb/current/onlinedocs/gdb.html/Dynamic-Printf.html Here's a good article from Andreas Heck where he creates a custom ```print``` function that writes to a file, instead of stdout. This works with a ```call``` printpoint without a channel. https://abstractexpr.com/2024/03/03/dynamic-printf-debugging-with-gdb/ seer-2.7/src/resources/help/RRDebugMode.md000066400000000000000000000042411516472651200205040ustar00rootroot00000000000000## RR debug mode ### Introduction This mode allows Seer to debug a RR replay session. RR allows time-travel debugging. In that, you can step forward or backwards in the execution of program being debugged. gdb has its own notion of time-travel debugging. However, it differs from RR's method. With gdb, the record of instructions is recorded as you are debugging the program. With RR, the record of instructions are made once when you run the program with 'rr record'. Seer can then load the recording (aka: trace-directory) by running the 'rr replay -s' command. Further information on RR is listed below in the references. ### Requirements In this mode, Seer needs: * Optional symbol file if the recording doesn't have debug information * A path to the directory containing the RR recording (aka: trace-directory) * Optional gdb commands to execute before and after Seer connects to the RR replay session See the RR config settings set the path to the RR program. ``` Settings -> Configure -> RR ``` ### What can you do? In this mode, Seer will load the RR replay session by running 'rr replay'. The program will be stopped befor 'main'. At this point you can set breakpoints and tell Seer to 'continue' or any typical debugging command. Seer will show a 'Direction' arrow on the toolbar. This will set the debugging direction to forward or reverse. And affects all commands like: 'step', 'next', 'finish', etc. A typical debugging sequence would look like: ``` # Use RR to record all instructions for a program. # The recording will be saved to 'hellosegv.rr' $ rr record -n --output-trace-dir=hellosegv.rr hellosegv one two three # Use Seer to debug this recording. Can be done as many times as you # want without creating a new recording. $ seergdb --rr hellosegv.rr ``` Now use Seer as you normally would. Use the Direction arrow in the main toolbar to change debugging directions. ### References Check references for RR and gdb. * [RR website](https://rr-project.org) * [RR github](https://github.com/rr-debugger/rr/wiki/Usage) * [gdb's record mode](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Process-Record-and-Replay.html#index-record-mode) seer-2.7/src/resources/help/RunDebugMode.md000066400000000000000000000026151516472651200207300ustar00rootroot00000000000000## Run debug mode ### Introduction This mode allows Seer to debug a program by starting the program itself. This is the most typical way of using Seer. ### Requirements In this mode, Seer needs: * The executable * Optional symbol file if the executable doesn't have debug information * Optional working directory to run the program from * Arguments to run the program with * Various Seer/gdb options to start the program by ### What can you do? There are a couple gdb settings that you can choose from when running the executable. The main one, though, is the initial breakpoint, which there are four ways: * Break in 'main'. The program is started and breaks in the program's main function. The definition of 'main' is language dependant. Seer/gdb will stop in the initial function for that language. * Break in 'function'. The program is started and breaks in a named function or at an address. * Break at 'source'. The program is started and breaks at a line number of a source file. eg: myprog.cpp:36 * No initial breakpoint. The program is started and executes without any breakpoints unless they are specified in the optional breakpoint file. The program will run til the end or when it encounters a signal or breakpoint. No source files will be loaded until a signal or breakpoint is encountered. From this point, you can debug the process as normal (stepping and setting breakpoints, etc...) seer-2.7/src/resources/help/Skips.md000066400000000000000000000046551516472651200175070ustar00rootroot00000000000000## Skips ### Introduction Skips are gdb's way of ignoring non-important arguments that are functions when stepping into a function to debug. For example, consider this code: ``` 101 int func() 102 { 103 foo(boring()); 104 bar(boring()); 105 } ``` ` ` Suppose you wish to step into the functions ```foo``` and ```bar```, but you are not interested in stepping through ```boring```. If you run ```step``` at line 103, you’ll enter ```boring()```, but if you run ```next```, you’ll step over both ```foo``` and ```boring```! One solution is to ```step``` into ```boring``` and use the ```finish``` command to immediately exit it. But this can become tedious if ```boring``` is called from many places. A more flexible solution is to tell gdb to execute ```boring``` with out stepping into it. The ```skip``` command does this. ### Skip types There are 4 types of skips. #### 'file' skips This skip takes a single source file. All functions descriped in the file will be skipped when stepping. #### 'file glob-pattern' skips Functions in files matching file-glob-pattern will be skipped over when stepping. #### 'function' skips This skip takes a single function specification (see the Location-Specifications link below). This function will be skipped when stepping. #### 'function regex' skips Functions whose name matches regexp will be skipped over when stepping. This form is useful for complex function names. For example, there is generally no need to step into C++ std::string constructors or destructors. Plus with C++ templates it can be hard to write out the full name of the function, and often it doesn’t matter what the template arguments are. Specifying the function to be skipped as a regular expression makes this easier. ``` ^std::(allocator|basic_string)<.*>::~?\1 *\( ``` ` ` If you want to skip every templated C++ constructor and destructor in the std namespace you can do: ``` ^std::([a-zA-z0-9_]+)<.*>::~?\1 *\( ``` ` ` ### References Here is gdb's reference for the ```skip``` command. https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html https://sourceware.org/gdb/current/onlinedocs/gdb.html/Location-Specifications.html#Location-Specifications Here's a good article from "MaskRay" where he describes skips in an easy to understand way. https://maskray.me/blog/2024-12-30-skipping-boring-functions-in-debuggers ` ` seer-2.7/src/resources/help/SourceSymbolLibraryInfoBrowser.md000066400000000000000000000125111516472651200245370ustar00rootroot00000000000000## Source/Symbol/Library Info Browser ### Introduction This browser allows the program's symbol table to be seached and browsed. Seer presents this information in three tabs: * Source * Functions * Types * Statics * Libraries * Ada exceptions * Skips ### Source This browser lists the source files used by the program being debugged. They are categorized into three folders bases on setting in ```Config->Source```. ``` Folder Description ---------- --------------------------------------- Source files Source files your program has. Header files Header files your program has. Misc files System related header and source files. ``` Double-clicking on a filename will load the source file in the Code Manager. Source files can be searched for using an Unix style wildcard. This will limit the number of source files listed to those that match. ### Functions This browser lists all the functions that match a Regex wildcard the program being debugged uses. This information is shown for each Function: ``` Column Description ---------- ----------------------------------------------------------------------- Function The function name. File The short name of the source file where Function is declared. Line The line number in the source file where the Function is declared on. Fullname The fullname of the source file. Type The function prototype. Description ``` Double-clicking on an entry will load the source file in the Code Manager. Using RMB on a selected etry will allow that function to be added to the breakpoint list or added to the skip list. ### Types This browser lists all the class/struct types that match a Regex wildcard the program being debugged uses. This information is shown for each Type: ``` Column Description ---------- ----------------------------------------------------------------------- Type The class/struct name. File The short name of the source file where Type is declared. Line The line number in the source file where the Type is declared on. Fullname The fullname of the source file. ``` Double-clicking on an entry will load the source file in the Code Manager. ### Statics This browser lists all the static variables that match a Regex wildcard the program being debugged uses. This information is shown for each Static: ``` Column Description ---------- -------------------------------------------------------------------- Variable The static name. File The short name of the source file where Static is declared. Line The line number in the source file where the Static is declared on. Fullname The fullname of the source file. Type The static prototype. Description ``` Double-clicking on an entry will load the source file in the Code Manager. ### Libraries This browser lists all the shared libraries that match a Regex wildcard the program being debugged uses. This information is shown for each Library: ``` Column Description ---------- ------------------------------------------------- Id Library name. Target-Name Library name. Host-Name Symbols Loaded Are symbols loaded for this library? 1 == yes. Thread Group Which thread group is this entry for. Ranges Memory range where the shared library is loaded. ``` ### Ada exceptions This browser lists all the Ada exceptions that match a Regex wildcard the program being debugged uses. The program must be an Ada program. This information is shown for each exception: ``` Column Description ---------- ------------------------------------------------- Name The name of the exception. Address The address of the exception. ``` There is a button to quickly create a catchpoint for a selected exception. Once created, Seer will stop the program when the exception is raised. ### Skip commands This browser manages the gdb skip commands you might have set up. A skip will bypass entering a function when the 'step' command is used. Skips can be described in various ways - filename, function name, and with glob wildcarding or regex. See the 'gdb skip' reference below. This information is shown for each exception: ``` Column Description ---------- ------------------------------------------------- Number The skip's interal number. Enable Is the skip enabled? Glob Is the skip a file glob wildcard? File The name of the file. Can be if the skip is a function. RE Is the skip a function regex? Function The name of the function. Can be if the skip is a file. ``` Skips can be: added, deleted, enabled, or disabled. As well, they can be saved to Seer's settings or loaded. ### References Consult these references 1. [Link](https://en.wikipedia.org/wiki/Regular_expression) Regular expressions. 2. [Link](https://en.wikipedia.org/wiki/Glob_(programming)) Unix wildcards. 3. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html) GDB Skip command. seer-2.7/src/resources/help/StackInfoBrowser.md000066400000000000000000000063261516472651200216400ustar00rootroot00000000000000## Stack Info Browser ### Introduction The Stack Info browser presents the program's stack information for the current thread/process. The current thread/process is set by the Thread/Process Info browser. Seer presents this information in three tabs: * Frames * Arguments * Locals ### Frames Frames is the most useful. It presents a stack frame (a traceback) for the selected thread. This information is shown for each Frame: ``` Column Description ---------- ----------------------------------------------------------------------- Level The frame level. 0 is the lowest level frame (ie: the executing frame). 1 is the caller of frame 0. 2 is the caller of 1. etc... Function The function name for the level. File The short name of the source file where Function is in. Line The line number in the source file that is being executed. Fullname The fullname of the source file. Address The frame's address in memory. ``` Clicking on a Frame Level will cause Seer to make that frame the active frame. This will in turn cause the Editor Manager to bring up the source file for the frame (if possible). Because the frame is set as the active frame, other Seer and gdb actions will default to that frame. For instance, entering a variable name in a Visualizer will use the variable in the active frame. ### Arguments This tab shows the function argument names and their value for each level. For example, if level 0 is for main(), the arguments for level 0 will be the values for argc and argv. ``` Column Description ---------- --------------------------------------------------------------------------- Level The frame level. 0 is the executing frame. 1 is the caller of frame 0. etc. Name List of variables names at the frame level. Value Value of the variables at the frame level. ``` Using the RMB will bring up a choice of Seer Visualizers and Loggers to further view the values. Note, you may need to set the level as active first in the Frames tab. ### Locals This tab shows the local values in the selected frame. Local values means the variables of the execution line in that frame, plus any established variables before the current line. Selecting a diffent frame in the Frames tab will show the locals for that frame. ``` Column Description ---------- ----------------------------------------------------------------------- Name The variable name. Arg The function argument number, if any. May appear in the Arguements tab. Value Value of the variable. ``` ### Stack This tab shows a window of bytes around the current stack pointer (SP). The window has a start address and an end address, incrementing by 2 bytes. The address of the SP is somewhere between them, depending on your settings. The bytes are shown as 2, 4, and 8 byte groupings. Each grouping can be represented as: hex, octal, int, uint, and float. The line that contains the SP is highlighted. Any line can be double-clicked to bring up a separate Memory Visualizer for the address for that line. ### Refresh The refresh button refreshes the currently exposed tab. seer-2.7/src/resources/help/StructVisualizer.md000066400000000000000000000073521516472651200217550ustar00rootroot00000000000000## Struct Visualizer ### Introduction The Struct Visualizer shows the contents of C/C++ structs and classes in a tree view. For each variable of the struct, Seer shows these three columns: * Variable name * Value * Datatype *Variable name* is the name of the variable, at that point in the stuct hiearchy. *Value* is the value of the variable, presented in the best way possible by gdb. *Datatype* is the variables datatype (basic type, class, or struct). If the variable is a pointer, a '*' is shown at the end of the datatype. A variable of the struct that has a value of '{...}' means it has subvalues (ie: is nested) and can be expanded. There will be a visual icon (like a '+') to show the tree can be expanded at that level. gdb has the notion of virtual levels for structs and classes. * public * protected * private These indicate where the variables reside in scope withing the struct or class. All struct variables will have a scope of 'public'. Classes will have the appropriate scope as they are defined in the class header file. These virtual levels are easy to see in the tree as they have no value or type. ### Operation The Struct Visualizer has these main components * Variable entry field * Expand tree * Collapse tree * Recursive mode * Refresh * Auto mode * Variable Tree ### Variable entry field This entry field allows you to enter the name of a variable. This variable can be for a struct or a class. It could also be a simple datatype like an *int* or a *string* but that would be pointless as simple datatypes have no nesting structure. Enter the variable name and hit return. The first level of the struct will be shown. If it has any subvalues, a '+' icon will appear and you can expand it to look at the subvalues. Note, if the variable name is not valid, an error box is display. ### Expand tree The big '+' icon that appears in the top bar will expand the currently selected level in the tree. If no level is selected, it will expand the top level of the tree. ### Collapse tree The big '-' icon that appears in the top bar will collapse the currently selected level in the tree. If no level is selected, it will collapse the top level of the tree. ### Recursive mode When expanding, the recursive mode determins how many levels to expand. For example, a struct with multiple levels, if the recursive mode is 'off', it will only expand one level each time. If the recursive mode is 'on', it will expand the sublevels indefinetly. **NOTE** The recursive mode can be fooled by some structs and cause an infinite loop. To this end, the recursive mode will always stop if the variable is a pointer ('*'). Also, while the expanding is happening, turning off the recursive mode will stop the recursion imediately. ### Refresh This will refresh the tree with any variables that have changed values since the last time. ### Auto mode This mode will refresh the tree each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). ### Variable tree As mentioned, the variable tree shows the variable names, values, and types of the struct. A '+' icon is shown beside each level. This will expand or collapse the level in the same way as the big '+' or '-' in the top bar. When expanding, it follows the same recursive mode. ### Modifying values. The Struct Visualizer allows variables in the tree to have their value changed. This is for simple datatypes only (int, floats, etc.). For a variable in the tree, double click the 'Value' column for the variable. It will then allow you to enter a new value (after you change it and hit return). An error box is shown if the variable can't be changed. ### Invoking other Visualizers. Using the RMB on a variable will bring up a menu to launch another Visualizer for that variable. seer-2.7/src/resources/help/ThreadProcessInfoBrowser.md000066400000000000000000000113401516472651200233310ustar00rootroot00000000000000## Thread/Process Info Browser ### Introduction The Thread/Process Info browser presents the program's thread and process information. In gdb speak, these are threads and inferiors. Seer presents this information in three tabs: * Frames * Ids * Groups ### Frames Frames is the most useful. It presents a list of Thread Ids the program is currently using. A Thread Id can be: * A system thread (aka, posix thread) * A system process (aka, another inferior because of a fork or exec) This information is shown for each Thread Id: ``` Column Description ---------- --------------------------------------------------- Thread Id An id given to the thread/process by gdb State The running state of the id. 'running' or 'stopped' Target Id Details of the id. Thread or process info Function The function name the thread id is in File The filename the thread id is in Line The line number in the filename Arguments The arguments passed to the function Core Which cpu core the thread id is running on ``` Clicking on a Thread Id will cause Seer to make that Thread Id the active thread. This will in turn cause the Stack Info Browser to refer to that Thread Id. ### Ids Ids is a simplified list of Thread Ids, with no other information. Clicking on a Thread Id will cause Seer to make that Thread Id the active thread. This will in turn cause the Stack Info Browser to refer to that Thread Id. ### Groups Groups is a list of Thread Groups. Basically, inferior processes. Most programs are just one inferior, even if they use threads. Program's that use fork and exec will have multiple inferiors. This information is shown for each Thread Id: ``` Column Description --------------- ---------------------------------------------- Thread Group Id An id given to the thread/process group by gdb Type The Thread Group type. Usually 'process' type Pid The process id Executable The name and path of the process executable Cores List of cpu cores used by the process ``` ### AdaTasks When debugging an Ada program, this view will show the state of all Ada tasks. Clicking on a Task Id will cause that Task Id to be the active task. This will in turn cause the Stack Info Browser to refer to the thread for that Task Id. This information is shown for each Task Id: ``` Column Description --------------- ---------------------------------------------- Active The current task that is active Id The identifier that GDB uses to refer to the Ada task Task Id The identifier that the target uses to refer to the Ada task Thread Id The global thread identifier of the thread corresponding to the Ada task Parent Id This field exists only when the task was created by another task. In this case, it provides the ID of the parent task Priority The base priority of the task State The current state of the task Name The name of the task ``` ### Scheduler Locking mode * Record. Behaves like 'off' in 'record' mode and like 'on' in 'replay' mode. This is the default. * Off. There is no locking and any thread may run at any time. * On. Only the current thread may run when the inferior is resumed. * Step. Optimizes for single-stepping; it prevents other threads from preempting the current thread while you are stepping, so that the focus of debugging does not change unexpectedly. ### Schedule Multiple mode This affects how gdb handles multiple inferiors when a 'continue' is executed. Choices are: * On. All threads of all processes are allowed to run. * Off. Only the threads of the current process are resumed. The default is off. ### Fork Follows mode This affects how gdb handles the program when a fork/vfork is encountered. Possible choices are: * Follow the parent process (the default). The child executes unabated. * Follow the child process. The parent executes unabated. * Follow both processes. A new process (an inferior) appears and either process can be selected. ### References Consult these gdb references 1. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Threads.html#thread-ID-lists) Listing thread information. 2. [Link](https://sourceware.org/gdb/onlinedocs/gdb/All_002dStop-Mode.html#All_002dStop-Mode) GDB all-stop mode. 3. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Forks.html) GDB follow-fork mode. 4. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Process-Record-and-Replay.html) GDB Record or Replay mode. 5. [Link](https://sourceware.org/gdb/download/onlinedocs/gdb/Ada-Tasks.html) Ada tasks. seer-2.7/src/resources/help/VariableRegisterSignalInfoBrowser.md000066400000000000000000000113371516472651200251610ustar00rootroot00000000000000## Variable/Register/Signal Info Browser ### Introduction The Variable/Register/Signal Info browser is a simple, but quick, method of viewing the values of the program's variables. Seer presents this information in four tabs: * Logger * Tracker * Registers * Signals ### Logger The logger is a simple method for printing the value of a variable. There is an entry field to manually enter the name of the variable. The variable must be part of the active stack frame, as selected by the Stack Info browser. This information is shown for each variable. ``` Column Description --------------- ---------------------------------------------- Timestamp When the variable was logged. Name The name of the variable. Value The value of the variable. ``` The easiest method for logging a variable is to double-click the variable text in the code editor. When doing this, a key modifier (shift and/or ctrl) can be used to prepend a '*' and/or '&' to the variable. This will better handle pointers and references. ``` Double-Click Modifier Description Example ------------ ------------------------------------ ----------------------- None No modifier is prepended to variable 'argc' Shift Key Prepend '&' to variable '&argc' Ctrl Key Prepend '*' to variable '*argc' Ctrl+Shift Prepend '*&' to variable '*&argc' ``` There are buttons to clear some or all entries in the logger. ### Tracker The tracker is a method to watch several variables at a time. Manually enter a list of variable names. Their values will be updated in the Logger display at each stopping point (after a 'step' or 'next' or a breakpoint) is reached. The variable must be part of the active stack frame, as selected by the Stack Info browser. There are buttons to clear some or all variables in the tracker. ### Registers Registers is a view of the program's register values. The register values are updated at each stopping point (after a 'step' or 'next' or a breakpoint) is reached. This information is shown for each register. ``` Column Description --------------- ---------------------------------------------- Name The name of the register. Value The value of the register. ``` The register value can be printed in multiple formats. ``` Format Description --------------- ------------------------------------------------------------ Natural Print using a format that's best for the register's purpose. Hex Print in hex. Octal Print in octal. Binary Print in binary. Decimal Print in decimal. Raw Print in the raw form. ``` Register values can be modified. Double-click on a Value column for a register will allow the value to be edited and changed. Using a RMB on a register will bring up a menu to change the register value as well. This second method can better handle resisters that have 'union' like properties (eg: xmm0 with xmm0.v8_bfloat16, xmm0.v4_float, etc...) where the register name needs to be modified slightly to include the 'union' field name. Register profiles can be created. A profile selects which registers to actually show. Multiple profiles are allowed. You can create new ones and modify existing ones. There is one profile that is special. It's called 'allregisters'. It means show all registers. It can't be modified or deleted. Switching between register profiles is easily done using the "Profile" list selector. ### Signals Signals is a view of the program's signal settings and how gdb handles them. The handling can be modified here. This information is shown for each signal. ``` Column Description --------------- ---------------------------------------------- Name The name of the signal. Stop GDB should stop your program when this signal happens. This implies the print keyword as well. Print GDB should print a message when this signal happens. Pass GDB should allow your program to see this signal; your program can handle the signal, or else it may terminate if the signal is fatal and not handled. pass and noignore are synonyms. Description The description of the signal. ``` ### References Consult these gdb references 1. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Registers.html) Viewing/setting register values. 2. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Signals.html) Viewing/setting signal values. seer-2.7/src/resources/help/seergdb.hlp000066400000000000000000000124371516472651200202110ustar00rootroot00000000000000 Usage: seergdb [LAUNCHOPTIONS] [MISCOPTIONS] executable [arguments ...] Seer - A gui frontend for gdb. -h, --help Displays help on commandline options. -v, --version Displays version information. Launch Options (pick one): -r, --run [--sym ] Load the executable and run it without breaking in "main". 'sym' is optional if the debugging info is in a separate file. 'executable' is the name of the executable file. -s, --start [--sym ] Load the executable, break in "main", and run it. 'sym' is optional if the debugging info is in a separate file. 'executable' is the name of the executable file. --attach [--sym ] [] Attach to a locally running process. 'pid' is the id of the running process. 'sym' is optional if the debugging info is in a separate file. 'executable' is the name of the executable file. If 'executable' is not given, use the executable stated by /proc//exe. --connect [--sym ] [] Connect to an already running gdbserver (local or remote). Possible connection mediums are: host:port /dev/ 'sym' is optional if the debugging info is in a separate file. 'executable' is sometimes needed for embedded debugging (qemu). --rr Load a previously created RR trace session from 'trace-directory'. --core [--sym ] Load a corefile. 'corefile' is the corefile to analyze. 'sym' is optional if the debugging info is in a separate file. 'executable' is the name of the executable file. --project Launch using a Seer project. Arguments: executable The executable to debug. Needed for 'run', 'start', 'attach', and 'core' run modes. Optionally for 'connect'. arguments Arguments for the executable. Needed for 'run' and 'start'. Misc Options: --cwd, --working-dir Set gdb's working directory path. --sym, --symbol-file Load symbols from a separate file than the executable. --bl, --break-load Load a previously saved breakpoints file. For 'run', 'start', 'attach', 'connect', or 'rr'. --bf, --break-function Set a breakpoint in a function/address. For 'run' or 'start'. --bs, --break-source Set breakpoints at a list of source files and line numbers. For 'run', 'start', 'attach', 'connect', or 'rr'. eg: --bs myprog.cpp:30,myprog.cpp:210 --sat, --show-assembly-tab Show the Assembly Tab on Seer startup. For 'run' or 'start'. --sar, --start-address-randomize Randomize the program's starting address. For 'run' or 'start'. --nsm, --non-stop-mode Continue to run other threads at breakpoints. For 'run' or 'start'. --gdb-program Use a different gdb than what's set in Seer's configuration. --gdb-arguments Use different gdb arguments than what's set in Seer's configuration. --config Launch with Seer's config dialog. Save settings with: 'Settings->Save Configuration' --xxx-debug Turn on internal Seer debugging messages. --xxx-resources Print the contents of Seer's Qt resources. --xxx-styles Print the names of Qt's available styles. seer-2.7/src/resources/icons-icons/000077500000000000000000000000001516472651200173565ustar00rootroot00000000000000seer-2.7/src/resources/icons-icons/arguments.png000066400000000000000000000021071516472651200220710ustar00rootroot00000000000000PNG  IHDR sgAMA a cHRMz&u0`:pQ<bKGD̿ pHYsvvxtIME :*IDATHǽKTaxDZL] 4QX&]+AB@JMMYU$!1-Wfmѳ:zs8<(RZ T;G5O _]KvI7㕥ѠE1cKFeĝf9S$4̈́U(gj6naݼ+2ƿ z-H9躬p#UDް2%ԶWN֒x,ik>=v[A19 (z:NySp&Yy)C%e6w񊄊r:}6%/J^ ӊqGxm#i}zoA`Р>i„F)䜬W?r .8"cʹ;Ք1U뺨^ńpYFR*kDT߅ 0&w2H(;%!ԕ5{[,Z`BSa۱%tEXtdate:create2020-09-08T07:58:22+00:00k%tEXtdate:modify2020-09-08T07:58:22+00:00 f tEXtsoftwarehttps://imagemagick.orgtEXtThumb::Document::Pages1/tEXtThumb::Image::Height512StEXtThumb::Image::Width512|tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime1599551902p>[tEXtThumb::Size11671BB`UtEXtThumb::URIfile://./uploads/56/VObWL55/2543/setting_balance_equalizer_icon_152217.pngM<IENDB`seer-2.7/src/resources/icons-icons/attach.png000066400000000000000000000026511516472651200213340ustar00rootroot00000000000000PNG  IHDR DgAMA asRGB cHRMz&u0`:pQ<PPLTE      8     %                                                                                           a>pntRNS"ABC!?ђ@=ܦ;D>:./1 % [_s#p$^-o bkubKGDoUa pHYs88q+82IDAT8V`ޥ ``PTET7]pVطjm`Ɓùr]E!r0HD1@@K+VC NM)ޡǁ8~%뀒N%:;IEҙ@>*L ju? K7Ƶџ@(>+Eܔ1qKt==cj =U*!s`V[ڭfL\-`:D罎9fu-fm{J<%tEXtdate:create2019-01-02T15:49:06+01:00F%tEXtdate:modify2019-01-02T15:49:06+01:00XFtEXtsoftwareImageMagick 6.7.8-9 2016-06-16 Q16 http://www.imagemagick.org4tEXtThumb::Document::Pages1/tEXtThumb::Image::height512PQtEXtThumb::Image::Width512|tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime15464405469>jtEXtThumb::Size13.5KBB#'H%ktEXtThumb::URIfile://./uploads/56/WW2WPJb/1744/3643780-attache-attached-attachement-clip-complement_113448.png_IENDB`seer-2.7/src/resources/icons-icons/console.png000066400000000000000000000006051516472651200215270ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs+'IDATX׽JAgcD7X (ւU x ހXX)6BV bvޝsJV!bB]"G8Hh6" J ?HgY >"ԲAv)m %>_@zAui =*Oy7BCi`Y:E fpp[a 猽.ۿ73)I5;@v x]'ﯘl-Q4S$߾M[AIENDB`seer-2.7/src/resources/icons-icons/debug.png000066400000000000000000000023221516472651200211510ustar00rootroot00000000000000PNG  IHDR sgAMA a cHRMz&u0`:pQ<bKGD̿ pHYs88q+8tIMEIzIDATHkG/7&1LF5OUk jAJ[PB]t"e";̃F iD>(7nE~Jt׳33|hr+P\^4 HKT)i4 T|D&5z}X„ />]KI-:uC݋op[[k^on;6K^[mHJɶʇRePsh5$c/ʭsP尝50x?jFyrHyy zj,DI7]rܳ(hv{Ux(+BP OYa9]u?B>)ߚHgu{+Ob@RCl1XK-﷈TrTZcv|J]ӈ[^GYXNcɬ`ƈgwm5gL#4hfsO56r2P^4{S0iRϻT d< _!ﴗ9Zs0[AO/vR[Ab J[Î;bX0fzJ[K`Ӳ/]5#Of2r:k}KQuٗ'`AEv:MEk_l_h%tEXtdate:create2022-02-21T15:29:04+00:00:L%tEXtdate:modify2022-02-21T15:29:04+00:00g tEXtsoftwarehttps://imagemagick.orgtEXtThumb::Document::Pages1/tEXtThumb::Image::Height512StEXtThumb::Image::Width512|tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime1645457344{tEXtThumb::Size11358BB(lAtEXtThumb::URIfile://./uploads/56/7u5SC6c/3404/debug_icon_215819.pngk`IENDB`seer-2.7/src/resources/icons-icons/editor.png000066400000000000000000000126311516472651200213550ustar00rootroot00000000000000PNG  IHDR``w8gAMA a cHRMz&u0`:pQ<bKGD pHYsUU+tIME. jIDATxyugz,`#d "{pf3 FpqlE>q'1v t"Ħ몞h449z5߽{޷~,I%_ f]ofihO'^}f˝ 7 0Ф* AwFwJӄx~S:ң<8z 5ڧ sAIXèd`nfF;[ˁ]'_|#ױſ;iH ,Dy jyH0 '% !O26b-RX8[?h*ww(hV~_rmG)@Bw>}OBIUە+~,h =pF`mtk.~$v * 30'XzBy /C=S'Э@~#;M~t˓Ahg|2jWXMr_}X9CLCGO . =T |˨sHxWM`8BJ W)BO\r(PWU8?i-6fSk/}[hbwVyg;=I ? pюÒU  L7B)L^ jn3F{7mho*L@ao`Q<{#1xl27$۰iӧ"`Y704DTIīHjA8(v*FhgE4t=?}#[@fNnu5Է䰤bv9ؒ '3͖EF #wp=B񽳁U<# z`Bl=Qт~ 3'QO<`$ˊ:v K:tFHx`/S>WElzwj H(X:bdg]dJ> ?wfC~BL~pm:Z\ ȷ=u>̙eg9-Ĺc u~s#;J'0_ L2[-9*5pQ+?ޔ ^Lu.8ٯ2b1]I-ZMP<֭]xCNzbFn |;f-o3>>dʔ'`I#%\AV$Ew;I">ECI-n+oXjf0&F~/p%"w #AzK1eʌBv-?4NX`16"?kdʴ[fM2@.Z O^Dx.+]O+Y񦚵˜K xTO0/jz 8Wai ;e k=d 'SʎM$~ e&m>oKrۂE,ZJr؞?'!;[ҥ~*4k 8xg d{eZw0Taґ /X.+a{@ Z ~03Ѵؾ%k%J=,4pdǑߋHǑ$1= " \.? ܭʙý8.}HC#XU/=JkH󣝡 i:XxV"DG|a_J{)R MNvEBEq f$baDc -s'\"pKED;Jqp "&w &Ccg9?:$ z#ESJi"chlNJ 4:l3Hv,yz~3Nz6C-ؘ!> EgwwiW19)n< S r=Mvm5kx"K,&O`+O(yzOrCe ?cb|"::twg|DX,8Xv=&W;x$+O&@^A|NYHs=`onL;; 7pMA%G8{HT3%>`s@/6/p=r35?E򠈎 <#l*j&3^?V\{&^)AbOwy&$$̍zKIbxK?5}obp`%H/ ɿAbjD(cIȓ#|eBhgnԴin1T7kC'v5 _i av¤dgj8IbRFj;h(;:d9AJ$;cw^ЮQA)@_g[AYو4XVnG<Vl{Bm؊CI'dm$dYطMbX\.g)5, %tEXtdate:create2022-04-21T06:46:11+00:00t%tEXtdate:modify2022-04-21T06:46:11+00:00RH tEXtsoftwarehttps://imagemagick.orgtEXtThumb::Document::Pages1/tEXtThumb::Image::Height512StEXtThumb::Image::Width512|tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime1650523571LxtEXtThumb::Size17893BBG"AatEXtThumb::URIfile://./uploads/56/K0HqM4W/3497/web_design_writing_coding_development_icon_220538.pngrIENDB`seer-2.7/src/resources/icons-icons/exit.png000066400000000000000000000020631516472651200210360ustar00rootroot00000000000000PNG  IHDR sgAMA a cHRMz&u0`:pQ<bKGD̿ pHYs$tIME  SqIDATHǥKTazNaH٢@'$h(kժj"mQV:uCYrJEԡFhf1sݝ}{mPZ9n^jA kwy%A|3P=* XY1c6ܴ,X26y8**vtе~e{z0QEy74oIKʟm/tgpEӊDR r&$eb'%ǫⲒwzSb\,e:e9WD.YrjWPhRFQ+(p'wJbluQ:.M|AS7ԑ˨q?8,4*?"+&Q']3ݩi]p$O4P2e☃VRKWZm&ycӄӌE3Q~k6YRk7=O#%O+^kfn縌v{V'%tEXtdate:create2020-12-17T10:11:06+00:00%tEXtdate:modify2020-12-17T10:11:06+00:00ް} tEXtsoftwarehttps://imagemagick.orgtEXtThumb::Document::Pages1/tEXtThumb::Image::Height512StEXtThumb::Image::Width512|tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime1608199866;QtEXtThumb::Size10897BB].v%GtEXtThumb::URIfile://./uploads/56/hiqBEvd/2751/logout_exit_icon_176185.png^.IENDB`seer-2.7/src/resources/icons-icons/font.png000066400000000000000000000012141516472651200210300ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs+.IDATXKOa\dr)6Lac!咍e6vB)v,g1;Y lX!4eu˱xiN{_z:s9vo< #~s~72ᕴV` [p@|̵x^ܝk]%Nºh<~şm8U3ge[B M9X'\<ɟK^Glj%2k&@L:Jj||Ioܿ@o3tf܉Ɇ٣PI f+Mx+vTapWVmB¼M{{6(ȓ ËR l*Ux~`+b(Uyu{;_w8{d.pO.|Iܯ$W?0Ö\PMqX+ EW$xê ;qNXm5.х؎دx 73WKmwB]'>>u.a*vXH`$Bб؍·b7ĜUK/WVgIENDB`seer-2.7/src/resources/icons-icons/gdb.png000066400000000000000000000106641516472651200206270ustar00rootroot00000000000000PNG  IHDR``w8gAMA asRGB cHRMz&u0`:pQ<bKGD pHYs+:IDATxytUy"AiPPDʠLEs*Pl8PPjZ֡`EĠh eP >^^n !ֺ rs÷>A"D!B"D!B"D!B I .kT! 9eHz?S,iT!  hd7ީ|C@F|,Fm >cUDE8*z nP xxؑA6tw"iv%89Ճ!b`p!R}G`Cb}o5I:*Ɋ x lȈ}qZx5l p)B(],0 &NGTt!ʈhGL!a*RH2[PR$` ϦHa|,0#{ާv7TM LG.h |3ScZjր, = ޫϑ1mB5SU~ DiLsVW@̪w]*pZ`:mmQAg;wW 8ec8[" Zq?7rf@gĚ~&*,b|7Ƕl-۶D )ՂjCnqFRu9N}>2D#H f2%^ bۣ` DE=&(4A7#mȟ*Ӹ6,nc Dnvcg\SM_jB0sPh iƋm[sW8 YV'5kYyA5KV[ʳ6Ѭ{veEH×M[߾gH i>rOR&B!0'TYύh"BړlT_^m:^1/`j}]u' L~o&1eh `^J3RxxBD,7vAf l$ ";Ž5SLx+J&$8^׈!0Yg)ӑwOԥ@P4l Ϡ ~~ HgDD9܍([ގ=PuU+ݡ}ȷCR y9J*M@NYxL.M+@|F|9(,FV.F&ܣ'52PV&eee!"(hJPmT _>i֨ާv3Ps'V!B"D!B"D!B"D!Bz}]%tEXtdate:create2020-02-07T17:31:13+00:00hd%tEXtdate:modify2020-02-07T17:31:13+00:00FtEXtsoftwareImageMagick 6.7.8-9 2019-02-01 Q16 http://www.imagemagick.orgA{tEXtThumb::Document::Pages1/tEXtThumb::Image::height512PQtEXtThumb::Image::Width512|tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime1581096673tEXtThumb::Size24.9KBBEݸ?tEXtThumb::URIfile://./uploads/56/sZzt1Ks/2148/gdb_icon_132365.pngkXIENDB`seer-2.7/src/resources/icons-icons/hide.png000066400000000000000000000015151516472651200207770ustar00rootroot00000000000000PNG  IHDR sgAMA a cHRMz&u0`:pQ<bKGD̿ pHYsvvxtIME (%jIDATH= @H.`)D[ ?{"֞Ô&X&e$deJ1 V,Mg5T+ yYR h<#%T3,t̩{&hTvLYَ~Uh&K9"u]!C@ `3FwڗYov@AHƬ D>ҋ3HisT_1}ǞؕtĜ4`K%tEXtdate:create2020-12-12T14:40:37+00:00tj%tEXtdate:modify2020-12-12T14:40:37+00:00S tEXtsoftwarehttps://imagemagick.orgtEXtThumb::Document::Pages1/tEXtThumb::Image::Height512StEXtThumb::Image::Width512|tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime1607784037ktEXtThumb::Size4431BBg;ItEXtThumb::URIfile://./uploads/56/MuYGGYA/2737/delete_remove_icon_175783.png3kɏIENDB`seer-2.7/src/resources/icons-icons/maximize.png000066400000000000000000000016021516472651200217060ustar00rootroot00000000000000PNG  IHDR sgAMA a cHRMz&u0`:pQ<bKGD̿ pHYsvvxtIME (dW!IDATH?k@tMP([KRWg)L?FoB7ıC+KB ݂.B9x$ UJ޽{_P y!}rK.$4+qŌq ^q36B8s9\"ޙ&2޲ JV<" ~`F?ۧl'E:?y-X8ة6P! Pq ğ1^.P.60nc=<>u0U$ty ej9j$qc$+A׵%tEXtdate:create2020-12-12T14:40:26+00:00@%tEXtdate:modify2020-12-12T14:40:26+00:00 tEXtsoftwarehttps://imagemagick.orgtEXtThumb::Document::Pages1/tEXtThumb::Image::Height512StEXtThumb::Image::Width512|tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime1607784026jttEXtThumb::Size3899BBKWKtEXtThumb::URIfile://./uploads/56/MuYGGYA/2737/resize_maximize_icon_175765.png=deIENDB`seer-2.7/src/resources/icons-icons/minimize.png000066400000000000000000000016641516472651200217140ustar00rootroot00000000000000PNG  IHDR sgAMA a cHRMz&u0`:pQ<bKGD̿ pHYsvvxtIME (~bSIDATH푻JA٬`"1K i| E+< 1paαf,A}X~E)ll죬sgc~b j}R'E]<)6y_$-yD|K`GzUI6H$bw@d\P4ORc"J+V2Qax'FĴB.1pŵd*`W`!Y EHxtg_Rq߁%tEXtdate:create2020-12-12T14:40:28+00:00%tEXtdate:modify2020-12-12T14:40:28+00:00𱼡 tEXtsoftwarehttps://imagemagick.orgtEXtThumb::Document::Pages1/tEXtThumb::Image::Height512StEXtThumb::Image::Width512|tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime1607784028YRGstEXtThumb::Size6354BBXKtEXtThumb::URIfile://./uploads/56/MuYGGYA/2737/minimize_window_icon_175768.pngKVIENDB`seer-2.7/src/resources/icons-icons/style.png000066400000000000000000000027671516472651200212400ustar00rootroot00000000000000PNG  IHDR DgAMA asRGB cHRMz&u0`:pQ<zPLTE"}tRNS?$58}mnfl ~@)1zgwruo _s&NeDYAQUEt`'艤d !C׹+I9:RpS[2*qc;0(À"›bKGD} pHYsKJKJtۃ\IDAT8c`$rXy`|B">+&.! KIb3]N^PTn*fV6u0*K&BZh. :r # # SPDX-License-Identifier: MIT # # Python MI command to manage gdb's "catchpoint" command.. # # Gdb has most catchpoint MI commands, but are missing these: # # -catch-signal # -catch-fork # -catch-vfork # -catch-syscall # -catch-exec # class MICatchpoint(gdb.MICommand): """ Run the 'catchpoint' command. -catch-signal [signal... | ‘all’] The delivery of a signal. -catch-fork A call to fork. -catch-vfork A call to vfork. -catch-syscall [name | number | group:groupname | g:groupname] ... A call to or return from a system call, a.k.a. syscall. -catch-exec A call to exec. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Set-Catchpoints.html#Set-Catchpoints """ def __init__(self, name, mode): self._mode = mode super(MICatchpoint, self).__init__(name) def invoke(self, argv): if self._mode == "signal": gdb.execute ("catch signal " + " ".join(argv), to_string=True) return None elif self._mode == "fork": gdb.execute ("catch fork " + " ".join(argv), to_string=True) return None elif self._mode == "vfork": gdb.execute ("catch vfork " + " ".join(argv), to_string=True) return None elif self._mode == "syscall": gdb.execute ("catch syscall " + " ".join(argv), to_string=True) return None elif self._mode == "exec": gdb.execute ("catch exec " + " ".join(argv), to_string=True) return None else: raise gdb.GdbError("catchpoint: Invalid parameter: %s" % self._mode) MICatchpoint("-catch-signal", "signal") MICatchpoint("-catch-fork", "fork") MICatchpoint("-catch-vfork", "vfork") MICatchpoint("-catch-syscall", "syscall") MICatchpoint("-catch-exec", "exec") seer-2.7/src/resources/mi-python/MICheckpoint.py000066400000000000000000000061121516472651200217450ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to manage gdb's "checkpoint" command.. # # https://sourceware.org/gdb/current/onlinedocs/gdb.html/Checkpoint_002fRestart.html#Checkpoint_002fRestart # class MICheckpoint(gdb.MICommand): """ Run the 'checkpoint' command. -checkpoint-list List all checkpoints, including the id for each checkpoint. -checkpoint-create Create a checkpoint at the current debugging position. -checkpoint-select Select a checkpoint to make active as described by ID. -checkpoint-delete Delete a checkpoint described by ID. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Checkpoint_002fRestart.html#Checkpoint_002fRestart """ def __init__(self, name, mode): self._mode = mode super(MICheckpoint, self).__init__(name) def invoke(self, argv): if self._mode == "list": checkpointentries = [] result = gdb.execute ("info checkpoints " + " ".join(argv), to_string=True) lines = result.split("\n") for line in lines: if (line == ""): continue columns = re.search(r"^([ *])\ (\d+)\ (.*?)\,\ (.*?)\,\ (.*?)$", line) if columns: checkpointmeta = {} checkpointmeta["id"] = columns.group(2) checkpointmeta["state"] = columns.group(1) checkpointmeta["process"] = columns.group(3) checkpointmeta["file"] = re.sub("^file ", "", columns.group(4)) checkpointmeta["line"] = re.sub("^line ", "", columns.group(5)) checkpointentries.append(checkpointmeta) else: columns = re.search(r"^([ *])\ (\d+)\ (.*)$", line) if columns: checkpointmeta = {} checkpointmeta["id"] = columns.group(2) checkpointmeta["state"] = columns.group(1) checkpointmeta["process"] = columns.group(3) checkpointmeta["file"] = "" checkpointmeta["line"] = "" checkpointentries.append(checkpointmeta) return { "checkpoints": checkpointentries} elif self._mode == "create": gdb.execute ("checkpoint " + " ".join(argv), to_string=True) return None elif self._mode == "select": gdb.execute ("restart " + " ".join(argv), to_string=True) return None elif self._mode == "delete": gdb.execute ("delete checkpoint " + " ".join(argv), to_string=True) return None else: raise gdb.GdbError("checkpoints: Invalid parameter: %s" % self._mode) MICheckpoint("-checkpoint-list", "list") MICheckpoint("-checkpoint-create", "create") MICheckpoint("-checkpoint-select", "select") MICheckpoint("-checkpoint-delete", "delete") seer-2.7/src/resources/mi-python/MIEcho.py000066400000000000000000000015571516472651200205440ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT # # Gdb's own custon Python MI command. # # https://sourceware.org/gdb/current/onlinedocs/gdb.html/GDB_002fMI-Commands-In-Python.html#GDB_002fMI-Commands-In-Python # https://sourceware.org/gdb/current/onlinedocs/gdb.html/Basic-Python.html#Basic-Python # class MIEcho(gdb.MICommand): """Echo arguments passed to the command.""" def __init__(self, name, mode): self._mode = mode super(MIEcho, self).__init__(name) def invoke(self, argv): if self._mode == 'dict': return { 'dict': { 'argv' : argv } } elif self._mode == 'list': return { 'list': argv } else: return { 'string': ", ".join(argv) } MIEcho("-echo-dict", "dict") MIEcho("-echo-list", "list") MIEcho("-echo-string", "string") seer-2.7/src/resources/mi-python/MIKill.py000066400000000000000000000025671516472651200205630ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to support gdb's "kill" commands. # # https://sourceware.org/bugzilla/show_bug.cgi?id=31090 # https://stackoverflow.com/questions/9669025/gdb-exit-program-without-exiting-gdb class MIKill(gdb.MICommand): """ Run the 'kill' command. -exec-kill Kill the child process in which your program is running under GDB. -exec-kill-inferiors Kill the inferior or inferiors identified by GDB inferior number(s) infno. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Kill-Process.html https://sourceware.org/gdb/current/onlinedocs/gdb.html/Inferiors-Connections-and-Programs.html#Inferiors-Connections-and-Programs """ def __init__(self, name, mode): self._mode = mode super(MIKill, self).__init__(name) def invoke(self, argv): if self._mode == "kill": gdb.execute ("kill" + " ".join(argv), to_string=True) return None elif self._mode == "killinferiors": gdb.execute ("kill inferiors" + " ".join(argv), to_string=True) return None else: raise gdb.GdbError("kill: Invalid parameter: %s" % self._mode) MIKill("-exec-kill", "kill") MIKill("-exec-kill-inferiors", "killinferiors") seer-2.7/src/resources/mi-python/MIObjectiveC.py000066400000000000000000000020401516472651200216670ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to manage gdb's Objective-C commands. # # https://sourceware.org/gdb/current/onlinedocs/gdb.html/Objective_002dC.html#Objective_002dC # class MIObjectiveC(gdb.MICommand): """ Run the ObjectiveC command. -objc-evaluate-expression Evaluate an Objective-C object via 'print-object' and '_NSPrintForDebugger'. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Objective_002dC.html#Objective_002dC """ def __init__(self, name, mode): self._mode = mode super(MIObjectiveC, self).__init__(name) def invoke(self, argv): if self._mode == "evaluate-expression": result = gdb.execute ("print-object " + " ".join(argv), to_string=True) return { "value": result.rstrip('\n')} else: raise gdb.GdbError("objectivec: Invalid parameter: %s" % self._mode) MIObjectiveC("-objc-evaluate-expression", "evaluate-expression") seer-2.7/src/resources/mi-python/MISignals.py000066400000000000000000000112111516472651200212520ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to manage gdb's "signal" command. # # https://www.sourceware.org/gdb/current/onlinedocs/gdb.html/Signals.html # class MISignal(gdb.MICommand): """ Run the 'signal' command. -signal-list-values List all signals, including the attributes for each signal (name, stop, print, pass, description). (gdb) info signals Signal Stop Print Pass to program Description SIGHUP Yes Yes Yes Hangup SIGINT Yes Yes No Interrupt SIGQUIT Yes Yes Yes Quit ... EXC_BREAKPOINT Yes Yes Yes Breakpoint SIGLIBRT No No Yes librt internal signal Use the "handle" command to change these tables. """ def __init__(self, name, mode): self._mode = mode super(MISignal, self).__init__(name) def invoke(self, argv): if self._mode == "list-names": signalnames = [] result = gdb.execute ("info signals", to_string=True) lines = result.split("\n") for line in lines: if (line == ""): continue columns = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$", line) if columns: if (columns.group(1) == "Signal"): continue if (columns.group(1) == "Use"): continue signalnames.append(columns.group(1)) return { "signal-names": signalnames} elif self._mode == "list-values": command = "" result = "" signalentries = [] if (len(argv) == 0): command = "info signals" else: command = "handle " + " ".join(argv) result = gdb.execute (command, from_tty=True, to_string=True) lines = result.split("\n") for line in lines: if (line == ""): continue columns = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$", line) if columns: if (columns.group(1) == "Signal"): continue if (columns.group(1) == "Use"): continue signalmeta = {} signalmeta["name"] = columns.group(1) signalmeta["stop"] = columns.group(2) signalmeta["print"] = columns.group(3) signalmeta["pass"] = columns.group(4) signalmeta["description"] = columns.group(5) signalentries.append(signalmeta) return { "signal-values": signalentries} elif self._mode == "stop": # handle signal [ signal … ] stop gdb.execute ("handle " + " ".join(argv) + " stop", from_tty=True, to_string=True) return None elif self._mode == "nostop": # handle signal [ signal … ] nostop gdb.execute ("handle " + " ".join(argv) + " nostop", from_tty=True, to_string=True) return None elif self._mode == "print": gdb.execute ("handle " + " ".join(argv) + " print", from_tty=True, to_string=True) return None elif self._mode == "noprint": gdb.execute ("handle " + " ".join(argv) + " noprint", from_tty=True, to_string=True) return None elif self._mode == "pass": gdb.execute ("handle " + " ".join(argv) + " pass", from_tty=True, to_string=True) return None elif self._mode == "nopass": gdb.execute ("handle " + " ".join(argv) + " nopass", from_tty=True, to_string=True) return None elif self._mode == "set-value": # handle signal [ signal … ] [keywords…] gdb.execute ("handle " + " ".join(argv), from_tty=True, to_string=True) return None else: raise gdb.GdbError("signal: Invalid parameter: %s" % self._mode) MISignal("-signal-list-names", "list-names") MISignal("-signal-list-values", "list-values") MISignal("-signal-stop", "stop") MISignal("-signal-nostop", "nostop") MISignal("-signal-print", "print") MISignal("-signal-noprint", "noprint") MISignal("-signal-pass", "pass") MISignal("-signal-nopass", "nopass") MISignal("-signal-set-value", "set-value") seer-2.7/src/resources/mi-python/MISkip.py000066400000000000000000000077701516472651200205770ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to manage gdb's "skip" command.. # # https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html # class MISkip(gdb.MICommand): """ Run the 'skip' command. -skip-list List all skips, including the id for each skip. -skip-delete Delete a list of skip id's. -skip-enable Enable a list of skip id's. -skip-disable Disable a list of skip id's. -skip-create Functions described in manual syntax will be skipped over when stepping. -skip-create-file Functions in file will be skipped over when stepping. -skip-create-gfile Functions in files matching file-glob-pattern will be skipped over when stepping. -skip-create-function Functions named by linespec or the function containing the line named by linespec will be skipped over when stepping. -skip-create-rfunction Functions whose name matches regexp will be skipped over when stepping. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html """ def __init__(self, name, mode): self._mode = mode super(MISkip, self).__init__(name) def invoke(self, argv): if self._mode == "list": skipentries = [] result = gdb.execute ("info skip " + " ".join(argv), to_string=True) lines = result.split("\n") for line in lines: if (line == ""): continue columns = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$", line) if columns: if (columns.group(1) == "Num"): continue if (columns.group(1) == "Not"): continue skipmeta = {} skipmeta["number"] = columns.group(1) skipmeta["enable"] = columns.group(2) skipmeta["glob"] = columns.group(3) skipmeta["file"] = columns.group(4) skipmeta["re"] = columns.group(5) skipmeta["function"] = columns.group(6) skipentries.append(skipmeta) return { "skips": skipentries} elif self._mode == "delete": gdb.execute ("skip delete " + " ".join(argv), to_string=True) return None elif self._mode == "enable": gdb.execute ("skip enable " + " ".join(argv), to_string=True) return None elif self._mode == "disable": gdb.execute ("skip disable " + " ".join(argv), to_string=True) return None elif self._mode == "create": gdb.execute ("skip \"" + " ".join(argv) + "\"", to_string=True) return None elif self._mode == "createfile": gdb.execute ("skip -file \"" + " ".join(argv) + "\"", to_string=True) return None elif self._mode == "creategfile": gdb.execute ("skip -gfile \"" + " ".join(argv) + "\"", to_string=True) return None elif self._mode == "createfunction": gdb.execute ("skip -function \"" + " ".join(argv) + "\"", to_string=True) return None elif self._mode == "createrfunction": gdb.execute ("skip -rfunction \"" + " ".join(argv) + "\"", to_string=True) return None else: raise gdb.GdbError("skips: Invalid parameter: %s" % self._mode) MISkip("-skip-list", "list") MISkip("-skip-delete", "delete") MISkip("-skip-enable", "enable") MISkip("-skip-disable", "disable") MISkip("-skip-create", "create") MISkip("-skip-create-file", "createfile") MISkip("-skip-create-gfile", "creategfile") MISkip("-skip-create-function", "createfunction") MISkip("-skip-create-rfunction", "createrfunction") seer-2.7/src/resources/qdarkstyle/000077500000000000000000000000001516472651200173155ustar00rootroot00000000000000seer-2.7/src/resources/qdarkstyle/ABOUT.md000066400000000000000000000015121516472651200205100ustar00rootroot00000000000000 Seer uses the QDarkStyle style sheets to provide a "dark" theme. Inversely, Seer uses the "light" theme as well. The QDarkStyle project is here: https://github.com/ColinDuquesnoy/QDarkStyleSheet And its license is here: QDarkStyleSheet is released under the MIT license and its icons are released under the CC4.0 license. https://github.com/ColinDuquesnoy/QDarkStyleSheet/blob/master/LICENSE.rst Copyright (c) 2013-2019 Colin Duquesnoy QComboBox menus, with this style, look weird. There's a large "space" to the left of the menu text. It isn't resolved in the official QDarkStyleSheet project. This link shows a fix for the QComboBox entry in the "dark" and "light" css files. So I've applied it to my copy of the stylesheet. https://github.com/ColinDuquesnoy/QDarkStyleSheet/issues/308#issuecomment-1661775924 seer-2.7/src/resources/qdarkstyle/dark/000077500000000000000000000000001516472651200202365ustar00rootroot00000000000000seer-2.7/src/resources/qdarkstyle/dark/darkstyle.qrc000066400000000000000000000233541516472651200227560ustar00rootroot00000000000000 rc/arrow_down.png rc/arrow_down@2x.png rc/arrow_down_disabled.png rc/arrow_down_disabled@2x.png rc/arrow_down_focus.png rc/arrow_down_focus@2x.png rc/arrow_down_pressed.png rc/arrow_down_pressed@2x.png rc/arrow_left.png rc/arrow_left@2x.png rc/arrow_left_disabled.png rc/arrow_left_disabled@2x.png rc/arrow_left_focus.png rc/arrow_left_focus@2x.png rc/arrow_left_pressed.png rc/arrow_left_pressed@2x.png rc/arrow_right.png rc/arrow_right@2x.png rc/arrow_right_disabled.png rc/arrow_right_disabled@2x.png rc/arrow_right_focus.png rc/arrow_right_focus@2x.png rc/arrow_right_pressed.png rc/arrow_right_pressed@2x.png rc/arrow_up.png rc/arrow_up@2x.png rc/arrow_up_disabled.png rc/arrow_up_disabled@2x.png rc/arrow_up_focus.png rc/arrow_up_focus@2x.png rc/arrow_up_pressed.png rc/arrow_up_pressed@2x.png rc/base_icon.png rc/base_icon@2x.png rc/base_icon_disabled.png rc/base_icon_disabled@2x.png rc/base_icon_focus.png rc/base_icon_focus@2x.png rc/base_icon_pressed.png rc/base_icon_pressed@2x.png rc/branch_closed.png rc/branch_closed@2x.png rc/branch_closed_disabled.png rc/branch_closed_disabled@2x.png rc/branch_closed_focus.png rc/branch_closed_focus@2x.png rc/branch_closed_pressed.png rc/branch_closed_pressed@2x.png rc/branch_end.png rc/branch_end@2x.png rc/branch_end_disabled.png rc/branch_end_disabled@2x.png rc/branch_end_focus.png rc/branch_end_focus@2x.png rc/branch_end_pressed.png rc/branch_end_pressed@2x.png rc/branch_line.png rc/branch_line@2x.png rc/branch_line_disabled.png rc/branch_line_disabled@2x.png rc/branch_line_focus.png rc/branch_line_focus@2x.png rc/branch_line_pressed.png rc/branch_line_pressed@2x.png rc/branch_more.png rc/branch_more@2x.png rc/branch_more_disabled.png rc/branch_more_disabled@2x.png rc/branch_more_focus.png rc/branch_more_focus@2x.png rc/branch_more_pressed.png rc/branch_more_pressed@2x.png rc/branch_open.png rc/branch_open@2x.png rc/branch_open_disabled.png rc/branch_open_disabled@2x.png rc/branch_open_focus.png rc/branch_open_focus@2x.png rc/branch_open_pressed.png rc/branch_open_pressed@2x.png rc/checkbox_checked.png rc/checkbox_checked@2x.png rc/checkbox_checked_disabled.png rc/checkbox_checked_disabled@2x.png rc/checkbox_checked_focus.png rc/checkbox_checked_focus@2x.png rc/checkbox_checked_pressed.png rc/checkbox_checked_pressed@2x.png rc/checkbox_indeterminate.png rc/checkbox_indeterminate@2x.png rc/checkbox_indeterminate_disabled.png rc/checkbox_indeterminate_disabled@2x.png rc/checkbox_indeterminate_focus.png rc/checkbox_indeterminate_focus@2x.png rc/checkbox_indeterminate_pressed.png rc/checkbox_indeterminate_pressed@2x.png rc/checkbox_unchecked.png rc/checkbox_unchecked@2x.png rc/checkbox_unchecked_disabled.png rc/checkbox_unchecked_disabled@2x.png rc/checkbox_unchecked_focus.png rc/checkbox_unchecked_focus@2x.png rc/checkbox_unchecked_pressed.png rc/checkbox_unchecked_pressed@2x.png rc/line_horizontal.png rc/line_horizontal@2x.png rc/line_horizontal_disabled.png rc/line_horizontal_disabled@2x.png rc/line_horizontal_focus.png rc/line_horizontal_focus@2x.png rc/line_horizontal_pressed.png rc/line_horizontal_pressed@2x.png rc/line_vertical.png rc/line_vertical@2x.png rc/line_vertical_disabled.png rc/line_vertical_disabled@2x.png rc/line_vertical_focus.png rc/line_vertical_focus@2x.png rc/line_vertical_pressed.png rc/line_vertical_pressed@2x.png rc/radio_checked.png rc/radio_checked@2x.png rc/radio_checked_disabled.png rc/radio_checked_disabled@2x.png rc/radio_checked_focus.png rc/radio_checked_focus@2x.png rc/radio_checked_pressed.png rc/radio_checked_pressed@2x.png rc/radio_unchecked.png rc/radio_unchecked@2x.png rc/radio_unchecked_disabled.png rc/radio_unchecked_disabled@2x.png rc/radio_unchecked_focus.png rc/radio_unchecked_focus@2x.png rc/radio_unchecked_pressed.png rc/radio_unchecked_pressed@2x.png rc/toolbar_move_horizontal.png rc/toolbar_move_horizontal@2x.png rc/toolbar_move_horizontal_disabled.png rc/toolbar_move_horizontal_disabled@2x.png rc/toolbar_move_horizontal_focus.png rc/toolbar_move_horizontal_focus@2x.png rc/toolbar_move_horizontal_pressed.png rc/toolbar_move_horizontal_pressed@2x.png rc/toolbar_move_vertical.png rc/toolbar_move_vertical@2x.png rc/toolbar_move_vertical_disabled.png rc/toolbar_move_vertical_disabled@2x.png rc/toolbar_move_vertical_focus.png rc/toolbar_move_vertical_focus@2x.png rc/toolbar_move_vertical_pressed.png rc/toolbar_move_vertical_pressed@2x.png rc/toolbar_separator_horizontal.png rc/toolbar_separator_horizontal@2x.png rc/toolbar_separator_horizontal_disabled.png rc/toolbar_separator_horizontal_disabled@2x.png rc/toolbar_separator_horizontal_focus.png rc/toolbar_separator_horizontal_focus@2x.png rc/toolbar_separator_horizontal_pressed.png rc/toolbar_separator_horizontal_pressed@2x.png rc/toolbar_separator_vertical.png rc/toolbar_separator_vertical@2x.png rc/toolbar_separator_vertical_disabled.png rc/toolbar_separator_vertical_disabled@2x.png rc/toolbar_separator_vertical_focus.png rc/toolbar_separator_vertical_focus@2x.png rc/toolbar_separator_vertical_pressed.png rc/toolbar_separator_vertical_pressed@2x.png rc/transparent.png rc/transparent@2x.png rc/transparent_disabled.png rc/transparent_disabled@2x.png rc/transparent_focus.png rc/transparent_focus@2x.png rc/transparent_pressed.png rc/transparent_pressed@2x.png rc/window_close.png rc/window_close@2x.png rc/window_close_disabled.png rc/window_close_disabled@2x.png rc/window_close_focus.png rc/window_close_focus@2x.png rc/window_close_pressed.png rc/window_close_pressed@2x.png rc/window_grip.png rc/window_grip@2x.png rc/window_grip_disabled.png rc/window_grip_disabled@2x.png rc/window_grip_focus.png rc/window_grip_focus@2x.png rc/window_grip_pressed.png rc/window_grip_pressed@2x.png rc/window_minimize.png rc/window_minimize@2x.png rc/window_minimize_disabled.png rc/window_minimize_disabled@2x.png rc/window_minimize_focus.png rc/window_minimize_focus@2x.png rc/window_minimize_pressed.png rc/window_minimize_pressed@2x.png rc/window_undock.png rc/window_undock@2x.png rc/window_undock_disabled.png rc/window_undock_disabled@2x.png rc/window_undock_focus.png rc/window_undock_focus@2x.png rc/window_undock_pressed.png rc/window_undock_pressed@2x.png darkstyle.qss seer-2.7/src/resources/qdarkstyle/dark/darkstyle.qss000066400000000000000000001512611516472651200227760ustar00rootroot00000000000000/* --------------------------------------------------------------------------- WARNING! File created programmatically. All changes made in this file will be lost! Created by the qtsass compiler v0.4.0 The definitions are in the "qdarkstyle.qss._styles.scss" module --------------------------------------------------------------------------- */ /* Light Style - QDarkStyleSheet ------------------------------------------ */ /* See Qt documentation: - https://doc.qt.io/qt-5/stylesheet.html - https://doc.qt.io/qt-5/stylesheet-reference.html - https://doc.qt.io/qt-5/stylesheet-examples.html --------------------------------------------------------------------------- */ /* Reset elements ------------------------------------------------------------ Resetting everything helps to unify styles across different operating systems --------------------------------------------------------------------------- */ * { padding: 0px; margin: 0px; border: 0px; border-style: none; border-image: none; outline: 0; } /* specific reset for elements inside QToolBar */ QToolBar * { margin: 0px; padding: 0px; } /* QWidget ---------------------------------------------------------------- --------------------------------------------------------------------------- */ QWidget { background-color: #19232D; border: 0px solid #455364; padding: 0px; color: #DFE1E2; selection-background-color: #346792; selection-color: #DFE1E2; } QWidget:disabled { background-color: #19232D; color: #788D9C; selection-background-color: #26486B; selection-color: #788D9C; } QWidget::item:selected { background-color: #346792; } QWidget::item:hover:!selected { background-color: #1A72BB; } /* QMainWindow ------------------------------------------------------------ This adjusts the splitter in the dock widget, not qsplitter https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow --------------------------------------------------------------------------- */ QMainWindow::separator { background-color: #455364; border: 0px solid #19232D; spacing: 0px; padding: 2px; } QMainWindow::separator:hover { background-color: #60798B; border: 0px solid #1A72BB; } QMainWindow::separator:horizontal { width: 5px; margin-top: 2px; margin-bottom: 2px; image: url(":/qss_icons/dark/rc/toolbar_separator_vertical.png"); } QMainWindow::separator:vertical { height: 5px; margin-left: 2px; margin-right: 2px; image: url(":/qss_icons/dark/rc/toolbar_separator_horizontal.png"); } /* QToolTip --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip --------------------------------------------------------------------------- */ QToolTip { background-color: #346792; color: #DFE1E2; /* If you remove the border property, background stops working on Windows */ border: none; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Remove opacity, fix #174 - may need to use RGBA */ } /* QStatusBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar --------------------------------------------------------------------------- */ QStatusBar { border: 1px solid #455364; /* Fixes Spyder #9120, #9121 */ background: #455364; /* Fixes #205, white vertical borders separating items */ } QStatusBar::item { border: none; } QStatusBar QToolTip { background-color: #1A72BB; border: 1px solid #19232D; color: #19232D; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Reducing transparency to read better */ opacity: 230; } QStatusBar QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; } /* QCheckBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox --------------------------------------------------------------------------- */ QCheckBox { background-color: #19232D; color: #DFE1E2; spacing: 4px; outline: none; padding-top: 4px; padding-bottom: 4px; } QCheckBox:focus { border: none; } QCheckBox QWidget:disabled { background-color: #19232D; color: #788D9C; } QCheckBox::indicator { margin-left: 2px; height: 14px; width: 14px; } QCheckBox::indicator:unchecked { image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QCheckBox::indicator:unchecked:disabled { image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); } QCheckBox::indicator:checked { image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QCheckBox::indicator:checked:disabled { image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); } QCheckBox::indicator:indeterminate { image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); } QCheckBox::indicator:indeterminate:disabled { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_disabled.png"); } QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); } /* QGroupBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { font-weight: bold; border: 1px solid #455364; border-radius: 4px; padding: 2px; margin-top: 6px; margin-bottom: 4px; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left: 4px; padding-left: 2px; padding-right: 4px; padding-top: -4px; } QGroupBox::indicator { margin-left: 2px; margin-top: 2px; padding: 0; height: 14px; width: 14px; } QGroupBox::indicator:unchecked { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QGroupBox::indicator:unchecked:disabled { image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); } QGroupBox::indicator:checked { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QGroupBox::indicator:checked:disabled { image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); } /* QRadioButton ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton --------------------------------------------------------------------------- */ QRadioButton { background-color: #19232D; color: #DFE1E2; spacing: 4px; padding-top: 4px; padding-bottom: 4px; border: none; outline: none; } QRadioButton:focus { border: none; } QRadioButton:disabled { background-color: #19232D; color: #788D9C; border: none; outline: none; } QRadioButton QWidget { background-color: #19232D; color: #DFE1E2; spacing: 0px; padding: 0px; outline: none; border: none; } QRadioButton::indicator { border: none; outline: none; margin-left: 2px; height: 14px; width: 14px; } QRadioButton::indicator:unchecked { image: url(":/qss_icons/dark/rc/radio_unchecked.png"); } QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_unchecked_focus.png"); } QRadioButton::indicator:unchecked:disabled { image: url(":/qss_icons/dark/rc/radio_unchecked_disabled.png"); } QRadioButton::indicator:checked { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked.png"); } QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked_focus.png"); } QRadioButton::indicator:checked:disabled { outline: none; image: url(":/qss_icons/dark/rc/radio_checked_disabled.png"); } /* QMenuBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar --------------------------------------------------------------------------- */ QMenuBar { background-color: #455364; padding: 2px; border: 1px solid #19232D; color: #DFE1E2; selection-background-color: #1A72BB; } QMenuBar:focus { border: 1px solid #346792; } QMenuBar::item { background: transparent; padding: 4px; } QMenuBar::item:selected { padding: 4px; background: transparent; border: 0px solid #455364; background-color: #1A72BB; } QMenuBar::item:pressed { padding: 4px; border: 0px solid #455364; background-color: #1A72BB; color: #DFE1E2; margin-bottom: 0px; padding-bottom: 0px; } /* QMenu ------------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu --------------------------------------------------------------------------- */ QMenu { border: 0px solid #455364; color: #DFE1E2; margin: 0px; background-color: #37414F; selection-background-color: #1A72BB; } QMenu::separator { height: 1px; background-color: #60798B; color: #DFE1E2; } QMenu::item { background-color: #37414F; padding: 4px 24px 4px 28px; /* Reserve space for selection border */ border: 1px transparent #455364; } QMenu::item:selected { color: #DFE1E2; background-color: #1A72BB; } QMenu::item:pressed { background-color: #1A72BB; } QMenu::icon { padding-left: 10px; width: 14px; height: 14px; } QMenu::indicator { padding-left: 8px; width: 12px; height: 12px; /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ } QMenu::indicator:non-exclusive:unchecked { image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QMenu::indicator:non-exclusive:unchecked:hover, QMenu::indicator:non-exclusive:unchecked:focus, QMenu::indicator:non-exclusive:unchecked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QMenu::indicator:non-exclusive:unchecked:disabled { image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); } QMenu::indicator:non-exclusive:checked { image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QMenu::indicator:non-exclusive:checked:hover, QMenu::indicator:non-exclusive:checked:focus, QMenu::indicator:non-exclusive:checked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QMenu::indicator:non-exclusive:checked:disabled { image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate { image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); } QMenu::indicator:non-exclusive:indeterminate:disabled { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate:focus, QMenu::indicator:non-exclusive:indeterminate:hover, QMenu::indicator:non-exclusive:indeterminate:pressed { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); } QMenu::indicator:exclusive:unchecked { image: url(":/qss_icons/dark/rc/radio_unchecked.png"); } QMenu::indicator:exclusive:unchecked:hover, QMenu::indicator:exclusive:unchecked:focus, QMenu::indicator:exclusive:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_unchecked_focus.png"); } QMenu::indicator:exclusive:unchecked:disabled { image: url(":/qss_icons/dark/rc/radio_unchecked_disabled.png"); } QMenu::indicator:exclusive:checked { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked.png"); } QMenu::indicator:exclusive:checked:hover, QMenu::indicator:exclusive:checked:focus, QMenu::indicator:exclusive:checked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked_focus.png"); } QMenu::indicator:exclusive:checked:disabled { outline: none; image: url(":/qss_icons/dark/rc/radio_checked_disabled.png"); } QMenu::right-arrow { margin: 5px; padding-left: 12px; image: url(":/qss_icons/dark/rc/arrow_right.png"); height: 12px; width: 12px; } /* QAbstractItemView ------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QAbstractItemView { alternate-background-color: #19232D; color: #DFE1E2; border: 1px solid #455364; border-radius: 4px; } QAbstractItemView QLineEdit { padding: 2px; } /* QAbstractScrollArea ---------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QAbstractScrollArea { background-color: #19232D; border: 1px solid #455364; border-radius: 4px; /* fix #159 */ padding: 2px; /* remove min-height to fix #244 */ color: #DFE1E2; } QAbstractScrollArea:disabled { color: #788D9C; } /* QScrollArea ------------------------------------------------------------ --------------------------------------------------------------------------- */ QScrollArea QWidget QWidget:disabled { background-color: #19232D; } /* QScrollBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar --------------------------------------------------------------------------- */ QScrollBar:horizontal { height: 16px; margin: 2px 16px 2px 16px; border: 1px solid #455364; border-radius: 4px; background-color: #19232D; } QScrollBar:vertical { background-color: #19232D; width: 16px; margin: 16px 2px 16px 2px; border: 1px solid #455364; border-radius: 4px; } QScrollBar::handle:horizontal { background-color: #60798B; border: 1px solid #455364; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:hover { background-color: #346792; border: #346792; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:focus { border: 1px solid #1A72BB; } QScrollBar::handle:vertical { background-color: #60798B; border: 1px solid #455364; min-height: 8px; border-radius: 4px; } QScrollBar::handle:vertical:hover { background-color: #346792; border: #346792; border-radius: 4px; min-height: 8px; } QScrollBar::handle:vertical:focus { border: 1px solid #1A72BB; } QScrollBar::add-line:horizontal { margin: 0px 0px 0px 0px; border-image: url(":/qss_icons/dark/rc/arrow_right_disabled.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { border-image: url(":/qss_icons/dark/rc/arrow_right.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { border-image: url(":/qss_icons/dark/rc/arrow_down.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { margin: 0px 3px 0px 3px; border-image: url(":/qss_icons/dark/rc/arrow_left_disabled.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { border-image: url(":/qss_icons/dark/rc/arrow_left.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/dark/rc/arrow_up_disabled.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { border-image: url(":/qss_icons/dark/rc/arrow_up.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { background: none; } QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { background: none; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } /* QTextEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets --------------------------------------------------------------------------- */ QTextEdit { background-color: #19232D; color: #DFE1E2; border-radius: 4px; border: 1px solid #455364; } QTextEdit:focus { border: 1px solid #1A72BB; } QTextEdit:selected { background: #346792; color: #455364; } /* QPlainTextEdit --------------------------------------------------------- --------------------------------------------------------------------------- */ QPlainTextEdit { background-color: #19232D; color: #DFE1E2; border-radius: 4px; border: 1px solid #455364; } QPlainTextEdit:focus { border: 1px solid #1A72BB; } QPlainTextEdit:selected { background: #346792; color: #455364; } /* QSizeGrip -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip --------------------------------------------------------------------------- */ QSizeGrip { background: transparent; width: 12px; height: 12px; image: url(":/qss_icons/dark/rc/window_grip.png"); } /* QStackedWidget --------------------------------------------------------- --------------------------------------------------------------------------- */ QStackedWidget { padding: 2px; border: 1px solid #455364; border: 1px solid #19232D; } /* QToolBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar --------------------------------------------------------------------------- */ QToolBar { background-color: #455364; border-bottom: 1px solid #19232D; padding: 1px; font-weight: bold; spacing: 2px; } QToolBar:disabled { /* Fixes #272 */ background-color: #455364; } QToolBar::handle:horizontal { width: 16px; image: url(":/qss_icons/dark/rc/toolbar_move_horizontal.png"); } QToolBar::handle:vertical { height: 16px; image: url(":/qss_icons/dark/rc/toolbar_move_vertical.png"); } QToolBar::separator:horizontal { width: 16px; image: url(":/qss_icons/dark/rc/toolbar_separator_horizontal.png"); } QToolBar::separator:vertical { height: 16px; image: url(":/qss_icons/dark/rc/toolbar_separator_vertical.png"); } QToolButton#qt_toolbar_ext_button { background: #455364; border: 0px; color: #DFE1E2; image: url(":/qss_icons/dark/rc/arrow_right.png"); } /* QAbstractSpinBox ------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractSpinBox { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; border-radius: 4px; /* min-width: 5px; removed to fix 109 */ } QAbstractSpinBox:up-button { background-color: transparent #19232D; subcontrol-origin: border; subcontrol-position: top right; border-left: 1px solid #455364; border-bottom: 1px solid #455364; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-bottom: -1px; } QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { image: url(":/qss_icons/dark/rc/arrow_up_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::up-arrow:hover { image: url(":/qss_icons/dark/rc/arrow_up.png"); } QAbstractSpinBox:down-button { background-color: transparent #19232D; subcontrol-origin: border; subcontrol-position: bottom right; border-left: 1px solid #455364; border-top: 1px solid #455364; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-top: -1px; } QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::down-arrow:hover { image: url(":/qss_icons/dark/rc/arrow_down.png"); } QAbstractSpinBox:hover { border: 1px solid #346792; color: #DFE1E2; } QAbstractSpinBox:focus { border: 1px solid #1A72BB; } QAbstractSpinBox:selected { background: #346792; color: #455364; } /* ------------------------------------------------------------------------ */ /* DISPLAYS --------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QLabel ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe --------------------------------------------------------------------------- */ QLabel { background-color: #19232D; border: 0px solid #455364; padding: 2px; margin: 0px; color: #DFE1E2; } QLabel:disabled { background-color: #19232D; border: 0px solid #455364; color: #788D9C; } /* QTextBrowser ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QTextBrowser { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; } QTextBrowser:disabled { background-color: #19232D; border: 1px solid #455364; color: #788D9C; border-radius: 4px; } QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { border: 1px solid #455364; } /* QGraphicsView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QGraphicsView { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; } QGraphicsView:disabled { background-color: #19232D; border: 1px solid #455364; color: #788D9C; border-radius: 4px; } QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { border: 1px solid #455364; } /* QCalendarWidget -------------------------------------------------------- --------------------------------------------------------------------------- */ QCalendarWidget { border: 1px solid #455364; border-radius: 4px; } QCalendarWidget:disabled { background-color: #19232D; color: #788D9C; } /* QLCDNumber ------------------------------------------------------------- --------------------------------------------------------------------------- */ QLCDNumber { background-color: #19232D; color: #DFE1E2; } QLCDNumber:disabled { background-color: #19232D; color: #788D9C; } /* QProgressBar ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar --------------------------------------------------------------------------- */ QProgressBar { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; text-align: center; } QProgressBar:disabled { background-color: #19232D; border: 1px solid #455364; color: #788D9C; border-radius: 4px; text-align: center; } QProgressBar::chunk { background-color: #346792; color: #19232D; border-radius: 4px; } QProgressBar::chunk:disabled { background-color: #26486B; color: #788D9C; border-radius: 4px; } /* ------------------------------------------------------------------------ */ /* BUTTONS ---------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QPushButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton --------------------------------------------------------------------------- */ QPushButton { background-color: #455364; color: #DFE1E2; border-radius: 4px; padding: 2px; outline: none; border: none; } QPushButton:disabled { background-color: #455364; color: #788D9C; border-radius: 4px; padding: 2px; } QPushButton:checked { background-color: #60798B; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:disabled { background-color: #60798B; color: #788D9C; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:selected { background: #60798B; } QPushButton:hover { background-color: #54687A; color: #DFE1E2; } QPushButton:pressed { background-color: #60798B; } QPushButton:selected { background: #60798B; color: #DFE1E2; } QPushButton::menu-indicator { subcontrol-origin: padding; subcontrol-position: bottom right; bottom: 4px; } QDialogButtonBox QPushButton { /* Issue #194 #248 - Special case of QPushButton inside dialogs, for better UI */ min-width: 80px; } /* QToolButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton --------------------------------------------------------------------------- */ QToolButton { background-color: #455364; color: #DFE1E2; border-radius: 4px; padding: 2px; outline: none; border: none; /* The subcontrols below are used only in the DelayedPopup mode */ /* The subcontrols below are used only in the MenuButtonPopup mode */ /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ } QToolButton:disabled { background-color: #455364; color: #788D9C; border-radius: 4px; padding: 2px; } QToolButton:checked { background-color: #60798B; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:disabled { background-color: #60798B; color: #788D9C; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:hover { background-color: #54687A; color: #DFE1E2; } QToolButton:checked:pressed { background-color: #60798B; } QToolButton:checked:selected { background: #60798B; color: #DFE1E2; } QToolButton:hover { background-color: #54687A; color: #DFE1E2; } QToolButton:pressed { background-color: #60798B; } QToolButton:selected { background: #60798B; color: #DFE1E2; } QToolButton[popupMode="0"] { /* Only for DelayedPopup */ padding-right: 2px; } QToolButton[popupMode="1"] { /* Only for MenuButtonPopup */ padding-right: 20px; } QToolButton[popupMode="1"]::menu-button { border: none; } QToolButton[popupMode="1"]::menu-button:hover { border: none; border-left: 1px solid #455364; border-radius: 0; } QToolButton[popupMode="2"] { /* Only for InstantPopup */ padding-right: 2px; } QToolButton::menu-button { padding: 2px; border-radius: 4px; width: 12px; border: none; outline: none; } QToolButton::menu-button:hover { border: 1px solid #346792; } QToolButton::menu-button:checked:hover { border: 1px solid #346792; } QToolButton::menu-indicator { image: url(":/qss_icons/dark/rc/arrow_down.png"); height: 8px; width: 8px; top: 0; /* Exclude a shift for better image */ left: -2px; /* Shift it a bit */ } QToolButton::menu-arrow { image: url(":/qss_icons/dark/rc/arrow_down.png"); height: 8px; width: 8px; } QToolButton::menu-arrow:hover { image: url(":/qss_icons/dark/rc/arrow_down_focus.png"); } /* QCommandLinkButton ----------------------------------------------------- --------------------------------------------------------------------------- */ QCommandLinkButton { background-color: transparent; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; padding: 0px; margin: 0px; } QCommandLinkButton:disabled { background-color: transparent; color: #788D9C; } /* ------------------------------------------------------------------------ */ /* INPUTS - NO FIELDS ----------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QComboBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QComboBox { border: 1px solid #455364; border-radius: 4px; selection-background-color: #346792; padding-left: 4px; padding-right: 4px; /* padding-right = 36; 4 + 16*2 See scrollbar size */ /* changed to 4px to fix #239 */ /* Fixes #103, #111 */ min-height: 1.5em; /* padding-top: 2px; removed to fix #132 */ /* padding-bottom: 2px; removed to fix #132 */ /* min-width: 75px; removed to fix #109 */ /* Needed to remove indicator - fix #132 */ } QComboBox QAbstractItemView { border: 1px solid #455364; border-radius: 0; background-color: #19232D; selection-background-color: #346792; } QComboBox QAbstractItemView:hover { background-color: #19232D; color: #DFE1E2; } QComboBox QAbstractItemView:selected { background: #346792; color: #455364; } QComboBox QAbstractItemView:alternate { background: #19232D; } QComboBox:disabled { background-color: #19232D; color: #788D9C; } QComboBox:hover { border: 1px solid #346792; } QComboBox:focus { border: 1px solid #1A72BB; } QComboBox:on { selection-background-color: #346792; } QComboBox::item { /* Remove to fix #282, #285 and MR #288*/ /*&:checked { font-weight: bold; } &:selected { border: 0px solid transparent; } */ } QComboBox::item:alternate { background: #19232D; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #455364; } QComboBox::down-arrow { image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { image: url(":/qss_icons/dark/rc/arrow_down.png"); } /* QSlider ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider --------------------------------------------------------------------------- */ QSlider:disabled { background: #19232D; } QSlider:focus { border: none; } QSlider::groove:horizontal { background: #455364; border: 1px solid #455364; height: 4px; margin: 0px; border-radius: 4px; } QSlider::groove:vertical { background: #455364; border: 1px solid #455364; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical { background: #346792; border: 1px solid #455364; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical :disabled { background: #26486B; } QSlider::sub-page:horizontal { background: #346792; border: 1px solid #455364; height: 4px; margin: 0px; border-radius: 4px; } QSlider::sub-page:horizontal:disabled { background: #26486B; } QSlider::handle:horizontal { background: #9DA9B5; border: 1px solid #455364; width: 8px; height: 8px; margin: -8px 0px; border-radius: 4px; } QSlider::handle:horizontal:hover { background: #346792; border: 1px solid #346792; } QSlider::handle:horizontal:focus { border: 1px solid #1A72BB; } QSlider::handle:vertical { background: #9DA9B5; border: 1px solid #455364; width: 8px; height: 8px; margin: 0 -8px; border-radius: 4px; } QSlider::handle:vertical:hover { background: #346792; border: 1px solid #346792; } QSlider::handle:vertical:focus { border: 1px solid #1A72BB; } /* QLineEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit --------------------------------------------------------------------------- */ QLineEdit { background-color: #19232D; padding-top: 2px; /* This QLineEdit fix 103, 111 */ padding-bottom: 2px; /* This QLineEdit fix 103, 111 */ padding-left: 4px; padding-right: 4px; border-style: solid; border: 1px solid #455364; border-radius: 4px; color: #DFE1E2; } QLineEdit:disabled { background-color: #19232D; color: #788D9C; } QLineEdit:hover { border: 1px solid #346792; color: #DFE1E2; } QLineEdit:focus { border: 1px solid #1A72BB; } QLineEdit:selected { background-color: #346792; color: #455364; } /* QTabWiget -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabWidget { padding: 2px; selection-background-color: #455364; } QTabWidget QWidget { /* Fixes #189 */ border-radius: 4px; } QTabWidget::pane { border: 1px solid #455364; border-radius: 4px; margin: 0px; /* Fixes double border inside pane with pyqt5 */ padding: 0px; } QTabWidget::pane:selected { background-color: #455364; border: 1px solid #346792; } /* QTabBar ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabBar, QDockWidget QTabBar { qproperty-drawBase: 0; border-radius: 4px; margin: 0px; padding: 2px; border: 0; /* left: 5px; move to the right by 5px - removed for fix */ } QTabBar::close-button, QDockWidget QTabBar::close-button { border: 0; margin: 0; padding: 4px; image: url(":/qss_icons/dark/rc/window_close.png"); } QTabBar::close-button:hover, QDockWidget QTabBar::close-button:hover { image: url(":/qss_icons/dark/rc/window_close_focus.png"); } QTabBar::close-button:pressed, QDockWidget QTabBar::close-button:pressed { image: url(":/qss_icons/dark/rc/window_close_pressed.png"); } QTabBar::tab, QDockWidget QTabBar::tab { /* !selected and disabled ----------------------------------------- */ /* selected ------------------------------------------------------- */ } QTabBar::tab:top:selected:disabled, QDockWidget QTabBar::tab:top:selected:disabled { border-bottom: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:bottom:selected:disabled, QDockWidget QTabBar::tab:bottom:selected:disabled { border-top: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:left:selected:disabled, QDockWidget QTabBar::tab:left:selected:disabled { border-right: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:disabled { border-left: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled { border-bottom: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled { border-top: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled { border-right: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled { border-left: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected { border-bottom: 2px solid #19232D; margin-top: 2px; } QTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected { border-top: 2px solid #19232D; margin-bottom: 2px; } QTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected { border-left: 2px solid #19232D; margin-right: 2px; } QTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected { border-right: 2px solid #19232D; margin-left: 2px; } QTabBar::tab:top, QDockWidget QTabBar::tab:top { background-color: #455364; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; min-width: 5px; border-bottom: 3px solid #455364; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:selected, QDockWidget QTabBar::tab:top:selected { background-color: #54687A; border-bottom: 3px solid #259AE9; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:!selected:hover, QDockWidget QTabBar::tab:top:!selected:hover { border: 1px solid #1A72BB; border-bottom: 3px solid #1A72BB; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom { border-top: 3px solid #455364; background-color: #455364; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; min-width: 5px; } QTabBar::tab:bottom:selected, QDockWidget QTabBar::tab:bottom:selected { background-color: #54687A; border-top: 3px solid #259AE9; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } QTabBar::tab:bottom:!selected:hover, QDockWidget QTabBar::tab:bottom:!selected:hover { border: 1px solid #1A72BB; border-top: 3px solid #1A72BB; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:left, QDockWidget QTabBar::tab:left { background-color: #455364; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-left-radius: 4px; border-bottom-left-radius: 4px; min-height: 5px; } QTabBar::tab:left:selected, QDockWidget QTabBar::tab:left:selected { background-color: #54687A; border-right: 3px solid #259AE9; } QTabBar::tab:left:!selected:hover, QDockWidget QTabBar::tab:left:!selected:hover { border: 1px solid #1A72BB; border-right: 3px solid #1A72BB; /* Fixes different behavior #271 */ margin-right: 0px; padding-right: -1px; } QTabBar::tab:right, QDockWidget QTabBar::tab:right { background-color: #455364; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; min-height: 5px; } QTabBar::tab:right:selected, QDockWidget QTabBar::tab:right:selected { background-color: #54687A; border-left: 3px solid #259AE9; } QTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hover { border: 1px solid #1A72BB; border-left: 3px solid #1A72BB; /* Fixes different behavior #271 */ margin-left: 0px; padding-left: 0px; } QTabBar QToolButton, QDockWidget QTabBar QToolButton { /* Fixes #136 */ background-color: #455364; height: 12px; width: 12px; } QTabBar QToolButton:pressed, QDockWidget QTabBar QToolButton:pressed { background-color: #455364; } QTabBar QToolButton:pressed:hover, QDockWidget QTabBar QToolButton:pressed:hover { border: 1px solid #346792; } QTabBar QToolButton::left-arrow:enabled, QDockWidget QTabBar QToolButton::left-arrow:enabled { image: url(":/qss_icons/dark/rc/arrow_left.png"); } QTabBar QToolButton::left-arrow:disabled, QDockWidget QTabBar QToolButton::left-arrow:disabled { image: url(":/qss_icons/dark/rc/arrow_left_disabled.png"); } QTabBar QToolButton::right-arrow:enabled, QDockWidget QTabBar QToolButton::right-arrow:enabled { image: url(":/qss_icons/dark/rc/arrow_right.png"); } QTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::right-arrow:disabled { image: url(":/qss_icons/dark/rc/arrow_right_disabled.png"); } /* QDockWiget ------------------------------------------------------------- --------------------------------------------------------------------------- */ QDockWidget { outline: 1px solid #455364; background-color: #19232D; border: 1px solid #455364; border-radius: 4px; titlebar-close-icon: url(":/qss_icons/dark/rc/transparent.png"); titlebar-normal-icon: url(":/qss_icons/dark/rc/transparent.png"); } QDockWidget::title { /* Better size for title bar */ padding: 3px; spacing: 4px; border: none; background-color: #455364; } QDockWidget::close-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/dark/rc/window_close.png"); } QDockWidget::close-button:hover { image: url(":/qss_icons/dark/rc/window_close_focus.png"); } QDockWidget::close-button:pressed { image: url(":/qss_icons/dark/rc/window_close_pressed.png"); } QDockWidget::float-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/dark/rc/window_undock.png"); } QDockWidget::float-button:hover { image: url(":/qss_icons/dark/rc/window_undock_focus.png"); } QDockWidget::float-button:pressed { image: url(":/qss_icons/dark/rc/window_undock_pressed.png"); } /* QTreeView QListView QTableView ----------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview --------------------------------------------------------------------------- */ QTreeView:branch:selected, QTreeView:branch:hover { background: url(":/qss_icons/dark/rc/transparent.png"); } QTreeView:branch:has-siblings:!adjoins-item { border-image: url(":/qss_icons/dark/rc/branch_line.png") 0; } QTreeView:branch:has-siblings:adjoins-item { border-image: url(":/qss_icons/dark/rc/branch_more.png") 0; } QTreeView:branch:!has-children:!has-siblings:adjoins-item { border-image: url(":/qss_icons/dark/rc/branch_end.png") 0; } QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { border-image: none; image: url(":/qss_icons/dark/rc/branch_closed.png"); } QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { border-image: none; image: url(":/qss_icons/dark/rc/branch_open.png"); } QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { image: url(":/qss_icons/dark/rc/branch_closed_focus.png"); } QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { image: url(":/qss_icons/dark/rc/branch_open_focus.png"); } QTreeView::indicator:checked, QListView::indicator:checked, QTableView::indicator:checked, QColumnView::indicator:checked { image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, QListView::indicator:checked:hover, QListView::indicator:checked:focus, QListView::indicator:checked:pressed, QTableView::indicator:checked:hover, QTableView::indicator:checked:focus, QTableView::indicator:checked:pressed, QColumnView::indicator:checked:hover, QColumnView::indicator:checked:focus, QColumnView::indicator:checked:pressed { image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QTreeView::indicator:unchecked, QListView::indicator:unchecked, QTableView::indicator:unchecked, QColumnView::indicator:unchecked { image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, QListView::indicator:unchecked:hover, QListView::indicator:unchecked:focus, QListView::indicator:unchecked:pressed, QTableView::indicator:unchecked:hover, QTableView::indicator:unchecked:focus, QTableView::indicator:unchecked:pressed, QColumnView::indicator:unchecked:hover, QColumnView::indicator:unchecked:focus, QColumnView::indicator:unchecked:pressed { image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QTreeView::indicator:indeterminate, QListView::indicator:indeterminate, QTableView::indicator:indeterminate, QColumnView::indicator:indeterminate { image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); } QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, QListView::indicator:indeterminate:hover, QListView::indicator:indeterminate:focus, QListView::indicator:indeterminate:pressed, QTableView::indicator:indeterminate:hover, QTableView::indicator:indeterminate:focus, QTableView::indicator:indeterminate:pressed, QColumnView::indicator:indeterminate:hover, QColumnView::indicator:indeterminate:focus, QColumnView::indicator:indeterminate:pressed { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); } QTreeView, QListView, QTableView, QColumnView { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; gridline-color: #455364; border-radius: 4px; } QTreeView:disabled, QListView:disabled, QTableView:disabled, QColumnView:disabled { background-color: #19232D; color: #788D9C; } QTreeView:selected, QListView:selected, QTableView:selected, QColumnView:selected { background-color: #346792; color: #455364; } QTreeView:focus, QListView:focus, QTableView:focus, QColumnView:focus { border: 1px solid #1A72BB; } QTreeView::item:pressed, QListView::item:pressed, QTableView::item:pressed, QColumnView::item:pressed { background-color: #346792; } QTreeView::item:selected:active, QListView::item:selected:active, QTableView::item:selected:active, QColumnView::item:selected:active { background-color: #346792; } QTreeView::item:selected:!active, QListView::item:selected:!active, QTableView::item:selected:!active, QColumnView::item:selected:!active { color: #DFE1E2; background-color: #37414F; } QTreeView::item:!selected:hover, QListView::item:!selected:hover, QTableView::item:!selected:hover, QColumnView::item:!selected:hover { outline: 0; color: #DFE1E2; background-color: #37414F; } QTableCornerButton::section { background-color: #19232D; border: 1px transparent #455364; border-radius: 0px; } /* QHeaderView ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview --------------------------------------------------------------------------- */ QHeaderView { background-color: #455364; border: 0px transparent #455364; padding: 0; margin: 0; border-radius: 0; } QHeaderView:disabled { background-color: #455364; border: 1px transparent #455364; } QHeaderView::section { background-color: #455364; color: #DFE1E2; border-radius: 0; text-align: left; font-size: 13px; } QHeaderView::section::horizontal { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-left: 1px solid #19232D; } QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { border-left: 1px solid #455364; } QHeaderView::section::horizontal:disabled { color: #788D9C; } QHeaderView::section::vertical { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-top: 1px solid #19232D; } QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { border-top: 1px solid #455364; } QHeaderView::section::vertical:disabled { color: #788D9C; } QHeaderView::down-arrow { /* Those settings (border/width/height/background-color) solve bug */ /* transparent arrow background and size */ background-color: #455364; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/dark/rc/arrow_down.png"); } QHeaderView::up-arrow { background-color: #455364; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/dark/rc/arrow_up.png"); } /* QToolBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox --------------------------------------------------------------------------- */ QToolBox { padding: 0px; border: 0px; border: 1px solid #455364; } QToolBox:selected { padding: 0px; border: 2px solid #346792; } QToolBox::tab { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-top-left-radius: 4px; border-top-right-radius: 4px; } QToolBox::tab:disabled { color: #788D9C; } QToolBox::tab:selected { background-color: #60798B; border-bottom: 2px solid #346792; } QToolBox::tab:selected:disabled { background-color: #455364; border-bottom: 2px solid #26486B; } QToolBox::tab:!selected { background-color: #455364; border-bottom: 2px solid #455364; } QToolBox::tab:!selected:disabled { background-color: #19232D; } QToolBox::tab:hover { border-color: #1A72BB; border-bottom: 2px solid #1A72BB; } QToolBox QScrollArea { padding: 0px; border: 0px; background-color: #19232D; } /* QFrame ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe https://doc.qt.io/qt-5/qframe.html#-prop https://doc.qt.io/qt-5/qframe.html#details https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color --------------------------------------------------------------------------- */ /* (dot) .QFrame fix #141, #126, #123 */ .QFrame { border-radius: 4px; border: 1px solid #455364; /* No frame */ /* HLine */ /* HLine */ } .QFrame[frameShape="0"] { border-radius: 4px; border: 1px transparent #455364; } .QFrame[frameShape="4"] { max-height: 2px; border: none; background-color: #455364; } .QFrame[frameShape="5"] { max-width: 2px; border: none; background-color: #455364; } /* QSplitter -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter --------------------------------------------------------------------------- */ QSplitter { background-color: #455364; spacing: 0px; padding: 0px; margin: 0px; } QSplitter::handle { background-color: #455364; border: 0px solid #19232D; spacing: 0px; padding: 1px; margin: 0px; } QSplitter::handle:hover { background-color: #9DA9B5; } QSplitter::handle:horizontal { width: 5px; image: url(":/qss_icons/dark/rc/line_vertical.png"); } QSplitter::handle:vertical { height: 5px; image: url(":/qss_icons/dark/rc/line_horizontal.png"); } /* QDateEdit, QDateTimeEdit ----------------------------------------------- --------------------------------------------------------------------------- */ QDateEdit, QDateTimeEdit { selection-background-color: #346792; border-style: solid; border: 1px solid #455364; border-radius: 4px; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; min-width: 10px; } QDateEdit:on, QDateTimeEdit:on { selection-background-color: #346792; } QDateEdit::drop-down, QDateTimeEdit::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #455364; } QDateEdit::down-arrow, QDateTimeEdit::down-arrow { image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus { image: url(":/qss_icons/dark/rc/arrow_down.png"); } QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { background-color: #19232D; border-radius: 4px; border: 1px solid #455364; selection-background-color: #346792; } /* QAbstractView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractView:hover { border: 1px solid #346792; color: #DFE1E2; } QAbstractView:selected { background: #346792; color: #455364; } /* PlotWidget ------------------------------------------------------------- --------------------------------------------------------------------------- */ PlotWidget { /* Fix cut labels in plots #134 */ padding: 0px; } seer-2.7/src/resources/qdarkstyle/dark/rc/000077500000000000000000000000001516472651200206425ustar00rootroot00000000000000seer-2.7/src/resources/qdarkstyle/dark/rc/.keep000066400000000000000000000000021516472651200215570ustar00rootroot00000000000000 seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_down.png000066400000000000000000000010061516472651200235260ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX=QAAL DE-[@PJ BKdg+%"F7<0̝3gpν5555;E7 SNSAY.\v=qӕv}`ϧ/_'0a|]g(t pgEV74=8<=m^&`#.F2 ̍VҼ$)9ORJ%H*tB_k͚K *4F;Iͫt.4='th朵6AB@nt4o^/t=*hrL |pK>sd\.`/8IVFx}ygI>L}}٭gݖ9 / IЫӞ鸵LcN.<(ڴ}5)-`0 `0 {0ӷIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_down_disabled.png000066400000000000000000000010421516472651200253550ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX픱kQ? qIJ%:yHP mfA VuzCu-. .d~3mc~2dȐအd]Fجp(r)@iuxƫןÝ+@HvsxXOsiխrJ0ٓk\L3r/iZrcK[ vh$̆uOAfmHcە0 ݄$ B)4 ^_̜$wYKQ23W!Jϧ7%Ujχ&ff/Q33)}sl*XVs* D' L4wuŮVfD!T>;jozVZZ2dpDQ^IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_down_disabled@2x.png000066400000000000000000000020541516472651200257330ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxk\U?44`q.А"BYĦi Z51 "M@P .4i3t23)#61]m+ @fIcߛ7df4Yys{bX,bX,`!=1Q!~:~j^c]۲<š8"8OeR0@u96/5POG^LB`,ׅ͋A‘t,8]}{4y/q7_m@ yqNE.U'I;NUlP<\su~lAkN@׋GwjͳErdbz$7>:Acjli_/x(̜oȺ!\("N@O6d)YҮO}dM+TED|3^wܹ/iC˹]pi\h R6r׶#wc7)'ɷ)e߹TsK""rȅ+VLdpDiTTfjnmyT- e0~^g_AQRK*E*ԁN#zxkQjKXt<^u]xcP`&()wU9<?y2Rj@R@Tv7ԥ+=UIGf>SC CH oֵ+Ly ) T?Zb/ܲuM'!Nٲucbl$!'FGoeu#ݽWAd5+Y/nor#1qqiY,U2gO,&]Lf(owS"~ocP.|eWA0Шn26k̘2csk+(o$s_9sW/5idx[xbX,bX,dv7oaIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_down_focus.png000066400000000000000000000010131516472651200247230ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX=kQsB 6AZlE;Y຋Q_ @lRX(A CJ$k)RY(X%ݽbfe#<029w`Q#԰٬gMWh$&xl{˩W?EQ0U*e'HH!`#CH$[[~]֧3 mϦ x;X *?wn'™a$tsZ w~;+{~7(7wR" [h D~3 Z^ڙ{;9)A:;FךuȢk&>a0%Z_4ռWY5sOļ{80ݖ75ͣ7?S%DC(rUj9?tuUF*(((W~xǸIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_down_focus@2x.png000066400000000000000000000017401516472651200253040ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMh\UPEڝV\d"hTJBI JkAD`ЭWɢJ5LtӟeDҸ:s_2&ܙDz9}s9@ @ P`pJ {0 D@Nj9I@i6qFm"k.J~![g{"lL8ҌGR!IIDךjY sP0T C㵲l#s~ oO{_6e iD`VÙOm=cJ}2lt^Hmjq¹Fٰl@P?8Dht.w#7!XuVaG'G 7iGlGnˑ?D ɀyߜQtclo^י~Wߡ<\|U3\ډ>lT3{&zGCqbhy޸[oj5}lvNO烅j%$$$*8QIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_down_pressed@2x.png000066400000000000000000000020561516472651200256330ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMh\U2Rč֍`2(4~RJQW͢i&' V]|Db]iLM nEi5 H!Sh潗NfIJoyϻϹ{`0 `0 ýx]PVpt=XIoP:錌 `% T+rWA(֮Sm"rh|n$ <"ތtj\RbPaC&AL#}>& E`9 d9xsmwF]g>-.;=]7H/bkw]\SRvFھj~Oa`.}lg~ Pȁ}!\ZT} g}/H]4ynxTZ}UTe&:g„VRiyU VN X zI'ߥ?'Roz"f^gd^Z$8?nkSD^4]CX\@<ڏY 1- 5T^ώ%;IzoVҖ]e$YXߥ|zFIxbhwCaD?'Bl-:KF Q#>!M}c`9kڧ9"O~ǽ:3`!2`3 '1U _[ @p>C/H30 A0|X 1|df{]O2j{"ˣ;W$CTBϟT>dĄڃG&~7 <833UЪ aK& Sbḧ́Fb~a nNNz`ĢMhe&=nԨ -Eq zʋf_[](:`ƓES/#Q,i5oh3S/> V%u`s4+E~ts0OD|TVdvxge[KKK?MFw!j? X\\^x'p4`aa! Nِ(T`_f6`4GP7/~)(Md"t;3v1b'\L#-`o,1.V4M8 M'yg߹-8`\vX'1*Z!\]\qcT(e}?^6@-!=(zHz)CaVZ 03o]|oXߛ[%1Q뿳Jk{q ^C `ϵπS@LTN,"DDA*(AI|/̚C'/3 u:](=s4-kKXC<P6nyj(x 0DU^1x͈yt4 yUw{˿08ggi}hG IIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_left_disabled@2x.png000066400000000000000000000021651516472651200257210ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+'IDATxOh\UʹZ0+QԍP"Hl'A vѕPEЊ"IE& ;Id (Ņ Am Eyf߽b[~sw:`3CN`dG"2QCs^c Al?;B4  ^kt\Bonx!Xnp^w@_n4X"+dc(qҀ Sn;]3Onw+z`bk(1G8ĸE޾zeojuGhEz- |!a2Bm3 +=DN*@"2o`x䵃s#ֈdPi,ׄy}pޝ50RHF<8ꀾoL K@w$7`2Ԭ} r[d1 =I-o#f@OO1ݥ>HW+`s F$o*߀ 䋳oO6ڨ|˾ ɍ(Ai0b57W/pUg+ElfGö#~$[F ܁ 038/N\xUT\1l -NZlf[boѥAގzl$~V0)X`%Rd8" ud]uYCfED=:5~f|ė=zkAA¼ "HI3S?ЋdMpֆ(ü*'D"p+'gM<\lV4 |#Z9"Y&&$/N '%p1&vU&?D&R7F$z/(ExUqL2tbuEj#9-qޏN>@T2_G]oVsjV?r&"Y5SS. *| ^8=}!0{3r/u>X^\'ȱ- o Xy ψ92pzQywl̄27 #Ex-:蠃5-mIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_left_focus.png000066400000000000000000000010471516472651200247150ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX1kTA3YE *ZXXXMؤL@ ;!?@,BzK!|,YH AMcgdQeJ߼7(;{K ' V8ϭ{4 8& -|p+xJ\GKd3؈a#(@s%.IMx6ik4;|A֨k?4CT u|0b쪕ԁUpl|3^Z KL>E $©+'crg-a_HcjkI3FV>F+z)`GFY L6[ziPdYTP T뷮Ru@.T>Q-^PECԝ wl? Q$[ȏ6#.?nu/S"ۋo6 ֔za_wlwʭIsBIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_left_focus@2x.png000066400000000000000000000021371516472651200252700ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMhUgQWiGEIEU {D*v!*( bqaѐ/ZJ+H]7zzvET߸#y)08y?p^7y,uc<< \Ϋ 0k5VV~sU5^wRӘI9N0tŵܔ 㢗Ul5d\\!S{S0*00'@'=;{ʪ2Sn2 61.lP%}3lT#L*,O$}8-JU*i_?* _AYt:%6L4( *|%}T C3`pkg0ץaR6:fnL.a`B0 > FdF~YIGSf{ 3I?h#J;ܬVl~%;iT3 B+Un<讷a2]BLG̢S`AIȑKiW wǢGLFYSNŭD(,sZii*h!rdX'g""xIJB2|Y,e>ۦ໤/U i-t+վ*P}y]_ 5:XuTDv*Y[*P٣hmHZ>AJ͆z#py7#: 2uT*coة>`&~x pp #Xg0nעz5 M*pk (kmm PCiS6,-26c~KʱQS֖$5Ual5uUWgQVIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_left_pressed.png000066400000000000000000000010761516472651200252450ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX1hSQ?}RA1...Р]+TSM&&M+؇`'p):HAA`EN\"=s/Ђ[Q;0[i}](z 'kN. N({CLg10,*@4wTdu `l*I kciT7@4;~3~^IE3@1#l;u"$<^N`)9d`y``?2V`ˢ-3=`4u5 >a]`^_aC/]0B≷SZ N"ɽ"Y @Y絃$_BvnJo.O,Uu̳$dq%q]Jɵ&u@vh@x@I3YG_WO]sM7?^+QqX} O2 ok IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_left_pressed@2x.png000066400000000000000000000022031516472651200256100ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+5IDATxKUSݓ1$A+Q\Cd1]N0v@|66{ u4:H@tq!Ш( ff~mz\L@s:}=UW_}Ͳ*6kfzJ`H[;g⸮EVa0j<鸮<եf&Aj-oFWh< p@a4 8.F1\XU 뷯-=4s C37t/P rp}͑,E/*GȎ9mo"Ƀ#vAO@NP(5!cז -ꦕCf)eq ҞEˍx}> T\Wj\,|S mzl X2< CC}ggox7Xmk:>pEW! ~fsP( K|&J pͿ1wubZ͛i.uA[sO)⑕Kz07yH`,O {+Pjm 3K9SXjl333N* @z {ǩJn563;H/sB@gà @ʹ&>Lv P`SI:}Df4xM$Thpx71Ē94Q> sB(X8ٽSy8"g~'_\vHzՐR 3nڭB)cʷx %z QNwp"y"/D͟fA0OTB&+V <<|fl+iWMxit/ڈ'C\Z9d~LTCz1dNSc!78e}1- z}a܊1DBt#Xͱl`-u9ƟyoI]Ecqp=Z`6Nkl~0Ώ)ym#.=uN}Cv>bIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_right.png000066400000000000000000000010241516472651200236740ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX=kQF F;uf5_@E,[Ď(X,s煛BOu9͙[܁lFY"g8?w p3>wTpx<;χၽH+K!fV<4`& kndEq',,^FY 3mdЀ 0} 1=Þmj FT5E,X ؍8yxh48@3fd pOg$0 ĭ,zƖitGxt$on]x®JAMN$UZ40bo.q|Mx}UcO/W߾^s#jW5π"@[ȭzo6=vIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_right@2x.png000066400000000000000000000021531516472651200242520ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMEfx1xv̮k\!D! !DЀ"x0`(xCrJBHI gA Wv9L_0a„ Rٓ,KRgzNmm!Lub Y)壦1HZ60b;xؔ K6R- :F1iJL-0lt56. Գµkp\ۧvݢ4@TXxTe)ca`Eő1qf6v?X_L Imdd@IL7 z+M]P3xSv"(IyWqqf0, O$6wH`虰VNw17`H I$I6 *A 0Kn7rD Whl"1ttBxA,Pm v~P##ejMl[gS^7YmJkV(@GMixm-{9Yh$1SS^Z1j# >4% ahl@T21AMmZ (y#~ń/ ,Pxi@~_\|^n `} <377dK lT+ljW=:*˞lZ֯:h4Ul"*3O q* (P(2~ quA9wvxV]]˜,J!Í ޲NKjgfV\za3g(Ϗ]jG=^K \GhX7ZZ%BdR&ϸҧ#*MK 񬀂sw̬pf(5}q'׼?+P58q~@B X~ `Zс@J*:|N3dl5:sz;8 3^? R>0Z5c$ Hzjθ' Ch;{cS`#_qK~]ow$!w_+H H;gs?\dނη:/DVf_7eZ @IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_right_focus@2x.png000066400000000000000000000021301516472651200254440ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATxK\Eϩ4A! |{ڸ0& $L@\(Bх(@&2AdzA\A % [EϨ*5TU.U#0@5O,,7x81 fD(@QEpRƏ 6Z PĴ? `K6@tn`ƱBoP: ja˜6&ㅎ> .h$B3<tŽ]sK@pc{ھ)RHQ j>@?ISrI Tu ji BS#|EzR=Y%icAcݕ2?S w.5s۴*In@\ajK7 e8`yby&\#K # ¶6`}T>-^_@&uel ZynQWsѺʙ⵻'^?-0Sz* Naѫ!D8190kґK+Z,6|8?5J_Zpl:o/LܘF8A/q8̓> o~Pyw]m/VZII:3]i,V 0p {z`}&|T1afk5pn_TF8D`ӛ[i/?cIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_right_pressed@2x.png000066400000000000000000000022121516472651200257730ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+a YGZaS @t&͕~}aѰ_bIʗl 3 ^1>OVЀED$ʢ`{X*&u52E +t5$eMS^LucћY,-=k4(ljjoIm<7[ԉS.c 5@ d}e2 Gc1h81Y;ns# @vZ'm\nvdAߕ7xb$x-nCg %;mi _˲uG#8;k\i@kLa"qUHvoMXdDu-_Ұ !ma_cv!@/[G=,'C^IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_up.png000066400000000000000000000010051516472651200232020ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX픱jQsGBhd̊kIg# >` liffS6Ĉ1;.{9sf?cuZ[D'1Ziթ~T!\<<߽b+ ʋ$eiM k&6E@Rj}v!M;*_X2Yō d>qk` 7EnD @~ !! E,1ؓ8QJIC$M \º{0`aGus,>ø5U'pOv eȁn.InZoxEJ9kD5-vT'rLKAXW K o!tSjhhh8I~Dfh?IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_up@2x.png000066400000000000000000000017471516472651200235710ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxoEƿ7Z. X-gʽ"z"9UPqBBPHUrC詵CP8 !NZ~&߼y3IbX,bX,˫U` Dpy7BǑ`; x ڳrm^]+[:+uocD_ )A$xAyEe*mҭm>AV? +XZ}&*#Dpq|hSBπ7t X @ę~'V"5O<ݑ$s]n>SB [h4!s()]܈]+(o@kDXLE"BEHFCKY9)Tja*߉[xV ExS2u)hkߟQf\ u@81l'+?˕ 6̂8tR+aeS;nP:j܂G|!{Rec0<- )cKD0d xVa0Z?tq6h~t7@|i9yߤ pʓVJq#SD- xϊ$,bX,bX,6S^ihAIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_up_disabled.png000066400000000000000000000010451516472651200250350ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX=hQw(-:t)P$N &.ݜ{ šJD"Q'?&I8{\lBMw{ރ$Mul4KhG_?5I$)WZpl/oay c (2fUw*PpX|@(Ik_p"w+Emk @*@Tk*cĪ<˻v ȗ@ 0}|T@rCQ|k> /jjF&Vq\fN}+jtmD l*p=wZgO͝wZ[bޑ`0z 2F,/QUl/ǭkߺn,ubۜ퀈|0Q| @-/69~ pIS)%%%X7 IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_up_disabled@2x.png000066400000000000000000000020621516472651200254070ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxo[Uƿ9KB$lAjv㴬KEZ?,UTBBB$,0 ha(T*F XTUըϰH;~k1?ɛ oڞ*00A)A)`jbWCDKCtWJ#5P_M60L#d3hH 4Z'Fb?k4}[V:k(xnEq!}z5΁6G ۏ>81}tY( 'i2?} nk}W^@p!"CV>C.%3pnG~v,qƀL`; :]i}H6ֻ$1J~ӃAoÖW'URRRG~Qr/rIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_up_focus@2x.png000066400000000000000000000017361516472651200247660ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxoTUϹ1J݉.uۙ1d.TbB6!P`EL`&2$Ȉ5$U{\̀wo;ޛx?~w@ @ U|EeR_0.4rGc$cty,Ds$?=5 0yU/FVHdF5<|wSXx!H ,:$#߽͟S9`iA+]ߚIR"5zP7k,W 8&Q=뵾&Hŀby#}\^X4 lgZq3N`}\r㌑Z*zgdfΛB`],p$cH"yi>l>г9'\!!҆yY~z2tYk Df+$񨏟,6Vr]Oolj j]jR|[No'&cCWL~hS5[!Z.UH wF&t i;d##?//頱Zn.xFSuv@~IS4pwo4ʼ[BE34#Qvsмj';aRXUɷBEatpqǍ~bl7C`μ<''_m@mOyv2@ @ q^&pP/0{.ޖ@jZs_j)o|.BȻ`'h꘠^nCIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/arrow_up_pressed@2x.png000066400000000000000000000020351516472651200253050ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOlTUyOD%}o t V̈±1!! H5ʪ%PiGĕ\0y:o[o眹PEQEQEQEQ_S Fx EGtB݉Eӹ~`.mvvkl0B=顅əvicB'}U>|i+`-r m#5 |#{el%+gvk1A;]{|DqL˾¦x|AN+ص  J\p`s'x %c)9Oqf$B8d;(R˵\Hh9"mĻJcsA0Dz#VCu ӵ#ul!50SI /Im]tHIο X-<6x!hJXx%AIg?7_as)< ,IB ȼ Rb\ Hs= f=1ChLc @P ޹2 56{ʍ|`{3^$?aRI=ǽ{c0KNY Ul0!M=5LxF[RJx5=sO>kϖQW mg0}2'}OFnߘU)-u yb۾;D ߭;9`pS4XKoj6BJI!; 2v;C$43#!a8v%,:yK8Iu5 Q/?s~@~S*7l_ c->g"6LW61'!nIw<{tAP!{ƻw,mjn@x|$o6`- <6wg|l$sE1 A-te}r1m +3o2y0qzu0n}Ԏjg 5ip} l5;&Tk|;2OIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/base_icon@2x.png000066400000000000000000000063261516472651200236530ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[o[%E(dNA&EѠH }{}*PA6NR iƖl7]HI.a3$wmx@xMBW<n%`2/m fbȘsgwܩ*ϣ5d =^9.Y> 4?4T%pP9mS mh}){q1oR- @V1k Fȼ=r̀#,1@6GU )_ȟ\6Hh?'[sr<%yFuK-2O ?ڼ00kLN`YN{Iϥq'lPcmc*}M|^y^dV7dkg#&ɂq&> 'ʣ!py *_d xZЗ< O*h(])704PZl/T,J4xF % 2]~|̠"ٌ $76]?Q5]|r ΏB}oGE`5{҆ ԟX~π瀷<{U[&[Y)^|)FL.rF?7Yx=kU~ x+Q@ɘ ] aSS7檛uO}ցs"Gp1z[1Y!W< Rq7n==z)NX-%8W/FL)0w}қW M%V;.Hxf:VGc/gcXy .*PF) Kt桞?>NyR9d]<$+z r-fn%b]`&t p CmM@%NCGٿRՓN}k6 ckB[: M,۾UU2o3ն20+c:d"+ |ພH1CX+ tf-*TW%yLZEK'%C4s2yTg~8FWcw2h_.z;gCdlO)ᱩJo -l7 GihnOĩ/ gR'_r'HeH .( GF{e%򐜳:Qxa? 7N|j|XߺV$4 1.{i C`GZ(;06<<ׅ|5r U0AqTw^ndb! Q\=pei?ȴP{f! $ 2b}4s֎zOuG&Gpy#7ճmFXB(@۳.Q@Qa([9Hr9my"')Ibt|2z <gCYsOp`<8ٍ\`-a< š8 2WVoe_n0+$˄:>8m ]_mg0ۿ BhF$VN-h,%F?mnd_82%^(Ιew1,S|Yp*rA8OW8sc*N-t.SNxEfm8Omfa.N&SOpA4ptɺ+rJKU\8/Ώ]I#<(v4_T}DV 6'h92Z']EǗ N=/a!5VM%{SLk'f;gB ¶7oVCܨF0}~REh ȻNJ>dC #Nफ)%̠)yŸ n"@LI LzЪθV] eݪc{2_*n(X@ ܞnyy(F $?w |HUѧ0'Q9hv@f%i.u6TTf"NT죵? hF%&]&eTyv%e،3w WZÿFfBx'P=R" [_h$I !{f3e/Ko#|< Ɨ{Ft=!тE+e߾ bgSŭ}L9q̏B;'S._Zf}DI2P.Z\̲^/L{aBC:f{̉CψCW+DONF^J^땙䝟@1=+DqL˾¦x|AN+ص  J\p`s'x %c)9Oqf$B8d;(R˵\Hh9"mĻJcsA0Dz#VCu ӵ#ul!50SI /Im]tHIο X-<6x!hJXx%AIg?7_as)< ,IB ȼ Rb\ Hs= f=1ChLc @P ޹2 56{ʍ|`{3^$?aRI=ǽ{c0KNY Ul0!M=5LxF[RJx5=sO>kϖQW mg0}2'}OFnߘU)-u yb۾;D ߭;9`pS4XKoj6BJI!; 2v;C$43#!a8v%,:yK8Iu5 Q/?s~@~S*7l_ c->g"6LW61'!nIw<{tAP!{ƻw,mjn@x|$o6`- <6wg|l$sE1 A-te}r1m +3o2y0qzu0n}Ԏjg 5ip} l5;&Tk|;2OIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/base_icon_disabled@2x.png000066400000000000000000000063261516472651200255020ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[o[%E(dNA&EѠH }{}*PA6NR iƖl7]HI.a3$wmx@xMBW<n%`2/m fbȘsgwܩ*ϣ5d =^9.Y> 4?4T%pP9mS mh}){q1oR- @V1k Fȼ=r̀#,1@6GU )_ȟ\6Hh?'[sr<%yFuK-2O ?ڼ00kLN`YN{Iϥq'lPcmc*}M|^y^dV7dkg#&ɂq&> 'ʣ!py *_d xZЗ< O*h(])704PZl/T,J4xF % 2]~|̠"ٌ $76]?Q5]|r ΏB}oGE`5{҆ ԟX~π瀷<{U[&[Y)^|)FL.rF?7Yx=kU~ x+Q@ɘ ] aSS7檛uO}ցs"Gp1z[1Y!W< Rq7n==z)NX-%8W/FL)0w}қW M%V;.Hxf:VGc/gcXy .*PF) Kt桞?>NyR9d]<$+z r-fn%b]`&t p CmM@%NCGٿRՓN}k6 ckB[: M,۾UU2o3ն20+c:d"+ |ພH1CX+ tf-*TW%yLZEK'%C4s2yTg~8FWcw2h_.z;gCdlO)ᱩJo -l7 GihnOĩ/ gR'_r'HeH .( GF{e%򐜳:Qxa? 7N|j|XߺV$4 1.{i C`GZ(;06<<ׅ|5r U0AqTw^ndb! Q\=pei?ȴP{f! $ 2b}4s֎zOuG&Gpy#7ճmFXB(@۳.Q@Qa([9Hr9my"')Ibt|2z <gCYsOp`<8ٍ\`-a< š8 2WVoe_n0+$˄:>8m ]_mg0ۿ BhF$VN-h,%F?mnd_82%^(Ιew1,S|Yp*rA8OW8sc*N-t.SNxEfm8Omfa.N&SOpA4ptɺ+rJKU\8/Ώ]I#<(v4_T}DV 6'h92Z']EǗ N=/a!5VM%{SLk'f;gB ¶7oVCܨF0}~REh ȻNJ>dC #Nफ)%̠)yŸ n"@LI LzЪθV] eݪc{2_*n(X@ ܞnyy(F $?w |HUѧ0'Q9hv@f%i.u6TTf"NT죵? hF%&]&eTyv%e،3w WZÿFfBx'P=R" [_h$I !{f3e/Ko#|< Ɨ{Ft=!тE+e߾ bgSŭ}L9q̏B;'S._Zf}DI2P.Z\̲^/L{aBC:f{̉CψCW+DONF^J^땙䝟@1=+DqL˾¦x|AN+ص  J\p`s'x %c)9Oqf$B8d;(R˵\Hh9"mĻJcsA0Dz#VCu ӵ#ul!50SI /Im]tHIο X-<6x!hJXx%AIg?7_as)< ,IB ȼ Rb\ Hs= f=1ChLc @P ޹2 56{ʍ|`{3^$?aRI=ǽ{c0KNY Ul0!M=5LxF[RJx5=sO>kϖQW mg0}2'}OFnߘU)-u yb۾;D ߭;9`pS4XKoj6BJI!; 2v;C$43#!a8v%,:yK8Iu5 Q/?s~@~S*7l_ c->g"6LW61'!nIw<{tAP!{ƻw,mjn@x|$o6`- <6wg|l$sE1 A-te}r1m +3o2y0qzu0n}Ԏjg 5ip} l5;&Tk|;2OIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/base_icon_focus@2x.png000066400000000000000000000063261516472651200250520ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[o[%E(dNA&EѠH }{}*PA6NR iƖl7]HI.a3$wmx@xMBW<n%`2/m fbȘsgwܩ*ϣ5d =^9.Y> 4?4T%pP9mS mh}){q1oR- @V1k Fȼ=r̀#,1@6GU )_ȟ\6Hh?'[sr<%yFuK-2O ?ڼ00kLN`YN{Iϥq'lPcmc*}M|^y^dV7dkg#&ɂq&> 'ʣ!py *_d xZЗ< O*h(])704PZl/T,J4xF % 2]~|̠"ٌ $76]?Q5]|r ΏB}oGE`5{҆ ԟX~π瀷<{U[&[Y)^|)FL.rF?7Yx=kU~ x+Q@ɘ ] aSS7檛uO}ցs"Gp1z[1Y!W< Rq7n==z)NX-%8W/FL)0w}қW M%V;.Hxf:VGc/gcXy .*PF) Kt桞?>NyR9d]<$+z r-fn%b]`&t p CmM@%NCGٿRՓN}k6 ckB[: M,۾UU2o3ն20+c:d"+ |ພH1CX+ tf-*TW%yLZEK'%C4s2yTg~8FWcw2h_.z;gCdlO)ᱩJo -l7 GihnOĩ/ gR'_r'HeH .( GF{e%򐜳:Qxa? 7N|j|XߺV$4 1.{i C`GZ(;06<<ׅ|5r U0AqTw^ndb! Q\=pei?ȴP{f! $ 2b}4s֎zOuG&Gpy#7ճmFXB(@۳.Q@Qa([9Hr9my"')Ibt|2z <gCYsOp`<8ٍ\`-a< š8 2WVoe_n0+$˄:>8m ]_mg0ۿ BhF$VN-h,%F?mnd_82%^(Ιew1,S|Yp*rA8OW8sc*N-t.SNxEfm8Omfa.N&SOpA4ptɺ+rJKU\8/Ώ]I#<(v4_T}DV 6'h92Z']EǗ N=/a!5VM%{SLk'f;gB ¶7oVCܨF0}~REh ȻNJ>dC #Nफ)%̠)yŸ n"@LI LzЪθV] eݪc{2_*n(X@ ܞnyy(F $?w |HUѧ0'Q9hv@f%i.u6TTf"NT죵? hF%&]&eTyv%e،3w WZÿFfBx'P=R" [_h$I !{f3e/Ko#|< Ɨ{Ft=!тE+e߾ bgSŭ}L9q̏B;'S._Zf}DI2P.Z\̲^/L{aBC:f{̉CψCW+DONF^J^땙䝟@1=+DqL˾¦x|AN+ص  J\p`s'x %c)9Oqf$B8d;(R˵\Hh9"mĻJcsA0Dz#VCu ӵ#ul!50SI /Im]tHIο X-<6x!hJXx%AIg?7_as)< ,IB ȼ Rb\ Hs= f=1ChLc @P ޹2 56{ʍ|`{3^$?aRI=ǽ{c0KNY Ul0!M=5LxF[RJx5=sO>kϖQW mg0}2'}OFnߘU)-u yb۾;D ߭;9`pS4XKoj6BJI!; 2v;C$43#!a8v%,:yK8Iu5 Q/?s~@~S*7l_ c->g"6LW61'!nIw<{tAP!{ƻw,mjn@x|$o6`- <6wg|l$sE1 A-te}r1m +3o2y0qzu0n}Ԏjg 5ip} l5;&Tk|;2OIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/base_icon_pressed@2x.png000066400000000000000000000063261516472651200254000ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[o[%E(dNA&EѠH }{}*PA6NR iƖl7]HI.a3$wmx@xMBW<n%`2/m fbȘsgwܩ*ϣ5d =^9.Y> 4?4T%pP9mS mh}){q1oR- @V1k Fȼ=r̀#,1@6GU )_ȟ\6Hh?'[sr<%yFuK-2O ?ڼ00kLN`YN{Iϥq'lPcmc*}M|^y^dV7dkg#&ɂq&> 'ʣ!py *_d xZЗ< O*h(])704PZl/T,J4xF % 2]~|̠"ٌ $76]?Q5]|r ΏB}oGE`5{҆ ԟX~π瀷<{U[&[Y)^|)FL.rF?7Yx=kU~ x+Q@ɘ ] aSS7檛uO}ցs"Gp1z[1Y!W< Rq7n==z)NX-%8W/FL)0w}қW M%V;.Hxf:VGc/gcXy .*PF) Kt桞?>NyR9d]<$+z r-fn%b]`&t p CmM@%NCGٿRՓN}k6 ckB[: M,۾UU2o3ն20+c:d"+ |ພH1CX+ tf-*TW%yLZEK'%C4s2yTg~8FWcw2h_.z;gCdlO)ᱩJo -l7 GihnOĩ/ gR'_r'HeH .( GF{e%򐜳:Qxa? 7N|j|XߺV$4 1.{i C`GZ(;06<<ׅ|5r U0AqTw^ndb! Q\=pei?ȴP{f! $ 2b}4s֎zOuG&Gpy#7ճmFXB(@۳.Q@Qa([9Hr9my"')Ibt|2z <gCYsOp`<8ٍ\`-a< š8 2WVoe_n0+$˄:>8m ]_mg0ۿ BhF$VN-h,%F?mnd_82%^(Ιew1,S|Yp*rA8OW8sc*N-t.SNxEfm8Omfa.N&SOpA4ptɺ+rJKU\8/Ώ]I#<(v4_T}DV 6'h92Z']EǗ N=/a!5VM%{SLk'f;gB ¶7oVCܨF0}~REh ȻNJ>dC #Nफ)%̠)yŸ n"@LI LzЪθV] eݪc{2_*n(X@ ܞnyy(F $?w |HUѧ0'Q9hv@f%i.u6TTf"NT죵? hF%&]&eTyv%e،3w WZÿFfBx'P=R" [_h$I !{f3e/Ko#|< Ɨ{Ft=!тE+e߾ bgSŭ}L9q̏B;'S._Zf}DI2P.Z\̲^/L{aBC:f{̉CψCW+DONF^J^땙䝟@1=+"YU ־# BfMٙ8=3+8Tvtl̨m ͅ1O7 ) TrFjb^NJEcF7h̜8=:XB\W!o6M"m($V6?'r$rr8?l'`:e^!DEeؾ?'dWT^`Wwdzj4Fh4FѴoz5IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_closed_disabled.png000066400000000000000000000006521516472651200257700ustar00rootroot00000000000000PNG  IHDR szz pHYs+\IDATX?KBQWM!Z lrtp mhAߠI'Tp 2ZѐSC=MZ\K^8>wUMV dqXOC\.詀RFۑzJx\g£>u;X<Jbܙd9H[= 4N3oK j,Oy*I)j6jcB쎆G@xɨZk(+LwC߻' 5Ѿ-eGF 6':;~*3%WG?dنT"IV >#+]O3f}ZZl`)H90 ft̫ed$w30dJoHv9AQ'1ˢ[ka}=2f#`T,T!~m:@'_'୩x( #LK8O0=$-5\pfs2Y0Tt sԾ'zmLfTksV@B/eotsȻx3A\C ?? d0"őc X8"#B/ W:* oω/_O9uH]kq̸2J7Ŏ{W<B 7@6_5? 0wٮa%uxHOBP( BP(BSIIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_closed_focus.png000066400000000000000000000006131516472651200253350ustar00rootroot00000000000000PNG  IHDR szz pHYs+=IDATX?/Cas[Јo]bb4H+lf $:X|v1K,,¢3PMl]g;{~y!##c^KVjMTT zg(<*.5KWfN|̫Щک.EDn )羯@#C)r&zbGq360ݵJaS P37޷o2]>{dF\(9Y1Ur䶑o_-C _0i1-tv㵁9Cuaý3MRțשځ`3p|'nQ3T ### FpbSjIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_closed_focus@2x.png000066400000000000000000000014521516472651200257110ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOHTQy IAPE0!"%g,#ZTAivEHXb"mrQ!D% )Z1 [~9>;bX,bX, 6raS@D=WHrAJC~GuG맯[1{ ۵4uWC 5`*2n_ w2D QGB069 Ҽ3a%-Boy8Bjr S91>+^N,0M^ϔ+d8i2K,STT V>#8 \֚Xkʕ1pb-`KMQ7(Md$6u3!+Bj{c/^d`{ <(X|0-{(%_>3ޱwX0m%dӬ?NK @S"vDX છ3mt.<$5Dn_ )ɐ2P *t, H 'JFx?W$L Wd,D^X`4*G|l*G9Fvּ*W,DY1a%-R*]?\_xqe"6&uhK,YW汣4{ZW׏PG$/h.`K0#iX,bX,R_D̾IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_closed_pressed.png000066400000000000000000000006371516472651200256710ustar00rootroot00000000000000PNG  IHDR szz pHYs+QIDATX-HCQ6gf,UMjqOM^ªYϿdSǴv|{KWq]}peoɞ{&HD+FU:];Z༚;BeujnCa/Wn5ՠ=NCsw E*iog*R|ߴN8g <)ۖP O3C]J@@8:s Lf"Rgrb'iSӊY;^WH}^ɕm[4A9f8X\} yV &&&5a7 meIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_closed_pressed@2x.png000066400000000000000000000015431516472651200262400ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx_HSaƟ+RڙV&D7aUFQk$"humszI&EefA4DK4vc1cCž{λwgD"H$D"H$ [@ӽc81w\ \Sם6NPeJPx}^c=њJy2bϻ ESk<nHBAQO![?B+{.[z}&rhAҡ*Rl"4yz@MjG",j! ZSM}(cHXY Q>L X~Gkajc}ȖcT-XrqL cDMF=MM,87 F Z[ oyAQk" R]TԷof3 /xkӞPJRѥ][jk戴Ez 5w{Dx05OWH++iᒴژ :u_ Sk͍D>)2%뇒!7^hh`LRO*#gމcZS[)HyZr8p ?< KpɶB$- ,`Ǣ|#d\^[<pya9OǣDM@t]䮟8&7^) &*dIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_end_focus.png000066400000000000000000000002251516472651200246310ustar00rootroot00000000000000PNG  IHDR szz pHYs+GIDATXα A*Bi/FJF>گIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_line.png000066400000000000000000000002041516472651200236100ustar00rootroot00000000000000PNG  IHDR szz pHYs+6IDATX 01eO?Mғm|_iXIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_line@2x.png000066400000000000000000000003561516472651200241720ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxA 1ec@kat:@hZt:@u:@hZt:@u:@hZt:@u:@hZt:@{׀|OIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_line_disabled.png000066400000000000000000000002071516472651200254420ustar00rootroot00000000000000PNG  IHDR szz pHYs+9IDATX10A&P ="g#edl>f|e#;X{ IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_line_disabled@2x.png000066400000000000000000000003601516472651200260140ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxA 0o(-h 1]\0:@hZt:@u:@hZt:@u:@hZt:@u:@hZt:@=u +IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_line_focus.png000066400000000000000000000002061516472651200250110ustar00rootroot00000000000000PNG  IHDR szz pHYs+8IDATXA @Ar!$xLĢی/yV1IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_line_focus@2x.png000066400000000000000000000003561516472651200253710ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxA 0SF" #<m hs>W6L9Zt:@u:@hZt:@u:@hZt:@u:@hZt:@u:@hCYIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_line_pressed.png000066400000000000000000000002071516472651200253400ustar00rootroot00000000000000PNG  IHDR szz pHYs+9IDATX10A& ,8"g#eMgMo>f|9?9;&IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_line_pressed@2x.png000066400000000000000000000003571516472651200257200ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxA 0MxAFx4}lrZt:@u:@hZt:@u:@hZt:@u:@hZt:@us(gIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_more.png000066400000000000000000000002421516472651200236250ustar00rootroot00000000000000PNG  IHDR szz pHYs+TIDATX CQ7q&It#ȥ) YMQ*_{(/r5/ IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_more@2x.png000066400000000000000000000004041516472651200241770ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx P u" "tbY/3oZ@S-)@ h 4hMZ@S-)@ h 4|qi33cK\~hMZ@S-)@ h 4hMZ@S-),ą ”WIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_more_disabled.png000066400000000000000000000002471516472651200254610ustar00rootroot00000000000000PNG  IHDR szz pHYs+YIDATXc`44Pb%F0Q:`pPjJ v@Q:`u ?mĽIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_more_disabled@2x.png000066400000000000000000000004071516472651200260310ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxQ Pѥ Zā 88G:|Z@S-)@ h 4hMZ@S-)@ h 4l~ϴٵ%.hMZ@S-)@ h 4hMZ@S-)@ h.VvbIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_more_focus.png000066400000000000000000000002441516472651200250260ustar00rootroot00000000000000PNG  IHDR szz pHYs+VIDATXc`X`o%f0Q`uF0w FwJ!xD0s<F0Q:`p0 (GGIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_more_focus@2x.png000066400000000000000000000004041516472651200253760ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxA @iNQRx&0o3^z!hMZ@S-)@ h 4hMZ@S-)l#L S <߃-q@ h 4hMZ@S-)@ h 4hMZ@}g DLIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_more_pressed.png000066400000000000000000000002411516472651200253510ustar00rootroot00000000000000PNG  IHDR szz pHYs+SIDATXc`dLl0ɘ@LhuF0Q:`B3(E83#\uF0Q G-IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_more_pressed@2x.png000066400000000000000000000004061516472651200257260ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx P $zF1)=2^o75JM 4hMZ@S-)@ h 4hMZ@S-Y>Gׯ0>[ (@ h 4hMZ@S-)@ h 4hMf?j,IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_open.png000066400000000000000000000006271516472651200236330ustar00rootroot00000000000000PNG  IHDR szz pHYs+IIDATXѿJA6I!M@UP VUll,| ),AlEH#z^pXBrT+a N'BrOc"J_apTV,W{kZQ9ׂ< \Qp@U@PUΨvr ` ~FmQ׷Ep *S?gߣ 5Y֎kq>7X Uʸ8O<Ǎ3q[\G gjfxWn^E^2Œ"[MvM51E%RlI)s Oo>NxEIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_open@2x.png000066400000000000000000000014431516472651200242020ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxAHaf.A;;lCE&]ìCD:Du :FET#*$lإӞ2w5Sa1Lu_QÜ5{;ðB!B!B! u} D^Š%"#jΞan +mxpOCzc:wa>hRLU>1Ѿ*h0`ڷ { sD{^oL/_#PF*XAǷ[ }9&Z WF\lm1WJS |ʲԆmNDfCn&5nמֳRXyLPMai`Ta~8O}&Z-R`ė U02!Yi/{͕7n+ADŵϸn;]_mmht&̼`Iu/+=Cq|"-]Ub5"Z;gZg[9uRՆ:& NW|5aY=Xz?z W1-|~ˆT1pW%m3__*@z0Eu2 9Zx_I&^?Ġw>RPT$tGkyi~TtԹ< itM]z7{qmv!B!B!b%'3FIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_open_disabled.png000066400000000000000000000006461516472651200254630ustar00rootroot00000000000000PNG  IHDR szz pHYs+XIDATX1/CQ9BEiDf4bhDBH7E'DZ8.7?y&,˲N +_RoJ#3+^/4 eye8挛35%`Ӕ7Hh'wى)9GٻEzi@䦒|S\(Yv藹7S|}YܥA궲Rkd4^py]Ũ U`p\ȧ3< _}tT\PkW]IO|AޮF(8²,>wk0ԠgIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_open_disabled@2x.png000066400000000000000000000015501516472651200260300ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOle3ۭD4JQ d%nbFL<oFpiB$MT8(&Fʭ!FR}pE3|`1c1c1ƘDž ؘ{+.i*{}4L^ He#/jkyoTSǨ.9vB]]s BR dh߮[-5H$:R|g`񀄾7@]3oc 'r?_t0^`4%}H/:Q?D撻)Ӿ([*o ιt-psN܉dfnʶtNͲ dMEp~/oKF"}y]_~y 3'S6{/D; 8wb oTDay]m###|M&;OOLŶ9{=Α&ɷݛ|hzw80ʶ~i#Q,6Fex_\{z?HK<p{_:uWXdITv t_7 k_&V>c=,~W[ l=tM%V~=㴓ձ7=+ի"@3MU:MnȂ?{oVLžΏ}~)ˀCuUKw}ٹ;GN"Qhi{c1c1c1vC=PpIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_open_focus.png000066400000000000000000000006141516472651200250260ustar00rootroot00000000000000PNG  IHDR szz pHYs+>IDATXҿ+QbR$?X)$,R/)%"eMg<===s  o-uEA7)o:) FYeFM@g>fs}P9+9 *kēe-`KnczN5^r?=_xZ.^/w5Ǭ?Q. xmWK=帣 4 =4 !W4Lj"(҂Vz@nEZޏHi@v|  t]kWl}A +rIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_open_focus@2x.png000066400000000000000000000014271516472651200254030ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMHTQ^K VAAT8E&)&"EE`n(j3WM80 5m#\+̹3A}||fc1c1c1/k@EV! ^L7"Lo| =.P} dO-"[BNgS_#lKN\! @.SO~(Jvc1c1c;_znМIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_open_pressed.png000066400000000000000000000006451516472651200253600ustar00rootroot00000000000000PNG  IHDR szz pHYs+WIDATX+DQ﹓()e 0;e5V;ˆݬdw3#yYXX)%E"ml;0 Ը3c%<===s@4MTP3+`b\URڗHwʃzrSà\l@uԝpӗ 45bhZ3V.kƝ!V`#?ݾW~TPK@c;)/gnB)0H>r>>Ir>˚H}~[RYn:tNT`+83 ࣰlrڮ%Ȏ@KY^]5 w;!n 撗vQ4MsW+iEtLIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/branch_open_pressed@2x.png000066400000000000000000000015341516472651200257300ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxKlTuSځИPMJdcR6LGϤ$,pAK3bL3Q; )1`ݘXRY IqQk%{g|so~ 1c1c1qPM~~[H4ѹ)I%y^@$}w_o=J8P{OXlCŽU5߯o=1]{5/@tmˁCk;|VYkx˻>l ;t!3-Uy-pV$pM hwrx1| @ff^)\7aϡu"K'<ÃO 9zpnPNF! {6kc":anD.Nsپk %WDvp@d((bHDh~2)CC7w @[rG[ٗ߀Db1Dp-YԊw`)"Q0V~+$/@\|X1ȁb}ZRϪjf>Qw@A Qm;'73H$嘴O A] Vd>y#bj3@(0XbdcZe<PJMP-ȼ6W\'QTU-IsDȺ {5dPfS\jʂ"VaI>LuF3t{Mzr:l41teIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_checked@2x.png000066400000000000000000000023261516472651200251610ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOoDƟ6ESTuΚ́R[OKK/ PH$! |Vj(*kzA\6/׮OI{`ʔ)Ҩì%&^/4615Rl]- AI)IL}Y&}]NF |-,F ~k!@HypMĄ@x f/-׽%[_=mb8Wg5G;;z~E@ DUi}AnB1uXuϓ0ZqDK@SOhTP8xYh*%W-_B]/26x|W6P HkHIlJ@SdK4ʱ@c0c*$RRȞ j}S\ N UX_PB%.=ЗTBX$>a|* n7=OQhs )̊se5)*\%qY-)ľm'mۺ̠$&AMAI@H#yLb7rLnY֌ DzLĢk4+TtRQ$X,Ὅ0ryЪf˓zqn8˯Ɔ a܈I Y] 릩K x2m:̶sx꺎Lmnʔ)Ǜ2ӎ@ IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_checked_disabled.png000066400000000000000000000013331516472651200264330ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXOHTQ獸u5Mm2(od\--,'(ƸI(NB)hF{Z?o|o޹{߹w/nD]@S@<\6y_"v|X@;9NvDnuq(8 ^c?QB̿Z,~Ed8%׉cFAu(LA鈝Q9-`yA{}y7Q{,X{yo`V?\h,V{eu~ϲ4JLaU]f5PhVՙh,.;.nc$L&#+5[_1 ]+۷-ֻ؂IE1 U}xܟU HRƲ4Im}f6EdԸȂO} pQq+k޷zƨ eڵZxq.WL^vTb4:;` ջ?-PM#҇xN=g#QB< (obĎJ*E0(}7pfJ[EDw;ޡe3/ pIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_checked_disabled@2x.png000066400000000000000000000024661516472651200270150ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOLUǿYLz!URizq!Hol\C+F4ٍzY 1%f[0b6-z].aléYؙ,gfo{3y4h$Cv".KifʄLf`u=nvʒ-ΦE=3g@wmR)݃0>&7!;k+mXrG%4cw3N{dbWiǬDJ<?ZKm{Dr ux|80JƋ\JД\j[kg+LTwx88^$%sm%njy0@.6]e1&׵t9/09c%+`{LR5MxqI?Ն{7.h=x)pMGx-@$TΚ>*}ⴏ@ jO]& :#;@ $& dvW ~=MRo;+pص>1-N 5Xu3Pصn烧wM/̤t@87EF&t_;ׇZr7Z_xXGLZaM7.X]_˨pk׬/p,[ZPD]VO \^Q+pŭ+ǨoAzĸgMK!8@[,JJ!8`9=a*NBP/pe i c&[iWd |֥:-b|Y`qv;`_: ,jf}P fj} xQse̼ė?ΤG_LŪ'4&1f]4w3)?1N1LU}CyU}Q>% 61MD-ѾD+KbgL(XqAl.1NⳕPvyPRy>UJ#oo~@#38m%ޙQԻ<YU)~_AԅceILꛪQvnm6GkmA' ߒIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_checked_focus.png000066400000000000000000000012171516472651200260040ustar00rootroot00000000000000PNG  IHDR szz pHYs+AIDATX1kQ3Yb vb]B$j$eV0`PAA- vA:A"Nvѯzwgs̼:fe<1US@'ir"Zj)o??j=7R<$:pQD!$^BcVy$YZoc LD,QNYD)‚43 B#~`9g* b rk&3H~JnJxIZ+۞H>`Կ HyV"췪Sؘ :eoN a} k(Fu׬@~`lot1b}[ع+5 `U ɰ -WfF3 h|]H8b ՊHH;̿}&&H!6yݼb՗):@<{4B݂U׋U u"yIg@JK;Ts;&p4Kcv4/N뭹mIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_checked_focus@2x.png000066400000000000000000000023651516472651200263630ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxoUǿg!XX6M0/Mmb[( 4m񑲩&m <-u -й_}Sft1w~ԾOsy{ܹ3hРNF8uϰim'Y `w'<"8gRY^hJ| 7^iza_~l!sK782L@$DY2y'|웙= ĭCkXXZək4 ,r@!oCMgشᔽr+K#ORP< GcM 5lR>.J,sV\$@Au^Sdn?dʒP62=P͘r[uOMw^ZÂ'^Wxy5x!Ch:(t٦ԆwOq; (xn|E*-:3liާ,I>r˸9Iv8t?T@ L;[ x=n_L@OiW,}J/W *}tDbQM #N˟ͅqXTC azA?^%to[]eY@.^S+K<$;DҗM(Vg,o|DkCq_|ԜŬ%I)NkZ6][g)A6`_x } <):VK!/ҷ2}Wqeߛr }- u raHO*ҷv?"B)IFm0b)m&R#Uh_p),}DVuBҷI$uB&ҷIY r)d$}DBK!C$Y7LyOv CJ6?TrT)VQ_%I*o+d;iU/x+%~8\^8zIa -|b_(s.czJ-%$qy-hV%MV ] 16lZ /ű프ձkPU3]xŶtNpq`D+'_S:~\`rQ Ю5thcs-xl"kР?7]VIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_checked_pressed.png000066400000000000000000000013001516472651200263230ustar00rootroot00000000000000PNG  IHDR szz pHYs+rIDATXNak"1QЊL\ q&@I²iXD#-BİM(@}X)1qvԱ?Szޙso2w-TgP}R9BF$|W@$>HKJ)}cnDRaw?To>R P$:3 ɽԺYgx TP\S 47\j8b? ;):\~{{X6jXb>'^5@4 [jmFטFEOHx@+ 9Ufh,Vt*/_?1e%]6;ՑînN;o-6\ة'z^_+kRoـ*",}_:FD#rs",)X) N[,I.ѷnYd^=ؽ-O(lguFv BGi7z?ǻS@icpdGPY y- )6lB2`*R|t#ɠ:J?4g;/ <`!ʺ ~nJԏI]\|왿A$V\N~)r/NIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_checked_pressed@2x.png000066400000000000000000000024471516472651200267120ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOhWǿB"vݐCE$[em.mjKU<6҂fbk/`ĵZ4",x؃!֬E0HzH^;;;f?yy7fxhРVUUY^ uQEn˹ @MədP렚D9םl̯*hH?Oo9+rP?_[-sn׬1xЧK0 ƞ4sAg5n]` Y!cVeUUypם"~ X_ԝ'5iE#KJoePGI?^Ŷ7@f//c6-/:JcЁE Od Vme֞p>=o5iʸM@{ic[[{N+Lr4lP4 ݾLr/Vm B[hT@xo:3e܁w@,+iMxqwzF[?UUј~lYҴ/h= }*txn z*A qUUU# }R Uݾ'Ux0/PX>lS7N(Zt餕VX3w7a}##ab`YWۗN߳rv@[h+n81V'4f,[x/-TPa~jEi}{fD_N?/p&Ƞv/pB5owR+* X_`[L7FV(X_= `~`qGI& $jAǞgR GKY_KO/p| RWF(ϭ/pE:K \{Z ~Y_ːRWI& "lż.e}÷/'k8H)<'OfnXw^UOX1ntv^86Rc"=0nߑhVbBiL u;gh~ĸ($ WCٹLk8LXٵD$44i|3diÌqrMغ3X5i*5Y?ol =?Y06}پO߽[Rl`gY@ײΙjyDD7b),*R3W70!` uO G꺮â΀>݂ ,c|} 2m; 6L\qԙ"6\ R)JkZlΎFӻ@|x1j+?uVD''-IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate@2x.png000066400000000000000000000016271516472651200264260ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IIDATx?OA%V(vC#@ciP@h-$; $' 5P&6v7Q`!⎸'w;73۝ `0zjsޖY&~`ku#Ĵ*}\)-[)Hv?vFVJ_$6`@۞n<<\dƋlܺ ,ӖW*vPBDTMSfi"^{a_ TV9B>m\Y5Jز<3ף2xpV8 T6)ƫoiidd{81uѱDAu3eFjM!T7q »l}'ĸ7^[znݘt [@7&1Ѝ @nit$6נDOB!wˎQ<)牱vsJ_?Lm!V⮴\IuxqPxժAMU-{:48껮/㱹2N uG3\oXIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate_disabled.png000066400000000000000000000010411516472651200276710ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX헱kSQ_^"JG],(.y T^" T38dE  uMmQR=R^}iEM{8sy {gXǬn6^''VHFDfLϞxµrJΣIK]"R 8ٹx'$-¬n6V0-dBxKZzr=wwMP( %)HBgUeSP0˄K_lvxiN> B(G_L$eyU ְs]=s/%5 4qm-(S> V^LU񃉯j=ittuF=E$k tPc@ н; ` xQ^t:z Fb/1p|%Jo{Y'FYUzC?YBy`Xت1ԭt'2!M%1ί$ham-CSsޚ~~sÇ'u vZs mپl^ h+F [lF [lF [lt'.[kWϬ o@yCpa<h1!}C; ]Q녡 !d{m"5[t1 m? {i5@ 2PlQ elQ elQ eMdnDF746K; F}Nj%V|0kntXW0tf5&<6Z0t^#Ncֱ6,}/m&>1Nتh<(y>._S^q7&s<3a1v{\OnKhfy^l{C#Sɇ R|mʩ wm iڜBhoAXIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate_focus.png000066400000000000000000000007221516472651200272460ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXJ#AӺՅ2& /a>`Vb& # "/0 }$k® Il1vt>֥W?gF3e ab#7u,@x|0 $eXiScqu=л2\R6G ,'1lK6uZqPZb p D zWzq ƒ+'jKwpe TT0RB|+`H:)J*<ܫS, wsN *H7u X{J7u]ߢ * ] X@ʬx9ތ`Y6i ?u!wkpoRE&5&f6oLBk+S&ԚU䄆 WIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate_focus@2x.png000066400000000000000000000016421516472651200276220ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+TIDATx훽OSQX$:ˠ$6n( & qS$'?1D4%psҞ{{@γ=_iñTՖr3*t)ؕzP!Y,O_? OIлX6Eł[T'{3l:@gS:j]Ӏ$#"z=mMDF k=t3pIE2KzB  X用^5 Ֆ% HPOVbWimPN‹r$<1V r3״<@OVHP;TP2/؛|_fdETpna ]@籫kV#r4\2Kq ku"z@pfzkڽ`[m`[m`[mZh$?= P="ݲn{@nRQ}!I6mȀ)'}S")g҆81iÐ񓠑ex |IK#|44 6LPBa< 2H/%*i6޹6>[dIж8l 38l 38l 3 P/Lhyr%=D/p ~i!BrND@`Sj5N#Nu _kim[\䧵MEc~Bd<>BY*`;t[ˋXg[|jޛo:_\-ͨG5sn"2 #ųܪUaJKM]ڜw}+^Asmpl~C?IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate_pressed.png000066400000000000000000000010061516472651200275700ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXJQ3IV%B+k4hJ_jF)%%آEp.i4(,cr\d ƎLbi[{7\{\.͡DDi!md()vO騒5? =܊< 0EzـEUy6*E@-e U%cLr& w×h|klmFN4C^@2q[?Ğ l 6`I6nt)H`6tQUF@r&uDff˙[[`/<)Bsv19f!)?!kl\^,f8-YdIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_unchecked@2x.png000066400000000000000000000015171516472651200255250ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOOQϭXCXba#SpuR`$wMD t&RI$.YQXiJYJz\Pio+w9,,uFI*]ry8DFH hq#@n@d38EkIi@^2aݡEYIgv;LC5{/FGGG-Fn_~= o)\@Db HK3݉|"w\nZ ЁPf]wp \not~ (]_羽y~dr¯ uB1T.O|Q^[L&w@yeKD0/dq*㺃K \w L-@ai>V[̟i$6 @Fkf !7V f Qo#pͰh -@kmh -@kmh -@kmh -@kmh &$|7ȬpPm` zTFɺf Z"He3(b\=ߟlfC" ArNRm4fȍuP}Ҏ ud<ϟj@R<ϟ Q#4LTw[TDb${g>X^Hy^_,͞52sT6,7hKMT&cZrl T6!/36gX7pvIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_disabled.png000066400000000000000000000006071516472651200270010ustar00rootroot00000000000000PNG  IHDR szz pHYs+9IDATX׿NP!0Z|@_L&#YdDWFe4"O;PG8*]l77}һ=}_^ ܀zQO *tϏoU#* P>2(t_wzf YaI*zY |Ej0cL( 04Q@"o'7)1>,,,,`|#L$j]Ϋ;@ 0AyEEzbrzz@q&" .&iLo}zU)BHo{5%f/+=IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_disabled@2x.png000066400000000000000000000015441516472651200273540ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx훿OSQǿN#.XWMLus#IѤDD8hMlP) D}MsjiOg={b\dxEX,tPp *wl qWBj/ #Zf! @-jd;/sLE^TtmK{kI#%M ?){J&`i2ѝV,6X, :~;rjϝ{ wD/ȱbt݃Ւ(R6UP PwqQLkKU0Ya{ Bɭ{<\έ_jHi͂>ho/|A'>IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_focus@2x.png000066400000000000000000000015221516472651200267200ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx훽OQϙlzYb!55FhZ_5Hg, $4,T,ܥ`c; "w7_;y'lq/p8n3JQ׺My")@"]I,1C 11Boݔq pjA꼢s םDʟ8^}B#ob{'qc,1"JFz?H7-I~+ҕ )^ƝY_'pq $fV e?#};*wgQADW%JK$_^^=O*k"2! 1 Jhț<*CSC MN_{h*H׺ .w#ThU[T[]`"J D_AC'|sⷧoSF%|-҈D:"rߞF@SskHE.B!pR;o"(I v5ۨC-{RVeoTp=Zl,g61`Db UQpb 9\L>afJ\L>|n2۽dEIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_pressed@2x.png000066400000000000000000000015361516472651200272530ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMOQS!tnݴč HRܘV0_ M[#NI4 +It 2 }]afJ+2=mj:N'n eFM,I0 /h! K/Z}B%N+#c[/aAMĒ;A*x(VTL+7Y|@U( UzI`]FAo%x*; OR2g-K0 ຣhM, XpGRqv'Ker1Zp&^4^F5P;k˾7|| \=c>0zR`uSsֽ4n;΃kcO@#@;6Fvm1hch@#@;6Fvm1hchCGpSP9~CA$@l>dRC-V?#d0'$"\qQk6PmmwÀd/gPM=p/T%sS(dnգ ׂy&ē>"ek!n" *8TU.23~tBZh%!"fUeKE?w˦x*4ET ?wӔhb!l R&@o]w_ -{J;msr&aEIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_horizontal.png000066400000000000000000000001701516472651200245460ustar00rootroot00000000000000PNG  IHDR szz pHYs+*IDATXA bdn{Md7'IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_horizontal@2x.png000066400000000000000000000002111516472651200251140ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+;IDATx E)@f,[#f: ̀t@ !IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_horizontal_disabled.png000066400000000000000000000001711516472651200263760ustar00rootroot00000000000000PNG  IHDR szz pHYs++IDATXA İ o([#1VaJ/<k%IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_horizontal_disabled@2x.png000066400000000000000000000002131516472651200267450ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+=IDATx n&+)@f,[#f: ̀t׺aYoIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_horizontal_focus.png000066400000000000000000000001671516472651200257530ustar00rootroot00000000000000PNG  IHDR szz pHYs+)IDATXA İ SD@H U@X979q ӲjFIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_horizontal_focus@2x.png000066400000000000000000000002111516472651200263130ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+;IDATx R6~ 9V鈤H3 5jC3bIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_horizontal_pressed.png000066400000000000000000000001701516472651200262730ustar00rootroot00000000000000PNG  IHDR szz pHYs+*IDATXA İ Mx hsnr`%0[IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_horizontal_pressed@2x.png000066400000000000000000000002121516472651200266420ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_vertical@2x.png000066400000000000000000000003661516472651200245470ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxб 0@ A?EBGaw_!Y}s]hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4/p12UIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_vertical_disabled.png000066400000000000000000000002071516472651200260160ustar00rootroot00000000000000PNG  IHDR szz pHYs+9IDATX10A&P[ "g#edl>f|5.IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_vertical_disabled@2x.png000066400000000000000000000003711516472651200263720ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx10P*ĕ!n 1s}s_CxO@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-yU;IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_vertical_focus.png000066400000000000000000000002051516472651200253640ustar00rootroot00000000000000PNG  IHDR szz pHYs+7IDATXα01.K5#BRۧEY=Y=_i|IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_vertical_focus@2x.png000066400000000000000000000003661516472651200257460ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx10PZSP|` 3$Mq }s)NDZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4 dA䒭IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_vertical_pressed.png000066400000000000000000000002061516472651200257130ustar00rootroot00000000000000PNG  IHDR szz pHYs+8IDATX10A& Pzz6o3b_;kIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/line_vertical_pressed@2x.png000066400000000000000000000003701516472651200262670ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx10PzbC TV|d26<}᱋?Q-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMX\CIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_checked.png000066400000000000000000000023541516472651200241200ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX]e}+(Y,wfޝudjDABS.,- knKBE7LJ\a evwfޙuJuw13;;]w<<8 E|jR ”\$W2 n3{A{bطI|ǭ=dtJf P(,5&P讓*_f-?]:< ۗ|,?hIN:}w6-f, ą,Gy#LBln]V@2WSW=mŷِ!Ҿ e }j5Z ND?4q톭Cp$L`fԝ{Tj3ӄ+0 ڮf} I&}~&I$uM/lENǜp+k rFi?{H:::FMṶؘt:} ෛ\$5 {A3δ6b-=`Rf3DGGhٞd⠽fy8] `_^jg\FcABMZ)RA~Xd/ilQ5 0P|$b~>/^T>NUT%LL;(+0Tl.0 2spur.tJ:!YEŋ9ɍn3l1K-uT2)RL׬Dobg[~U:ܞ*h*S^ufm RG[478iwi伲ֵ`b;y./Du홴 f2G {8E#OWcp`u@TMTp㋮T,g/c"US Z"Ak,k$ [\uG[}V

99lg/EqIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_checked@2x.png000066400000000000000000000052361516472651200244740ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ PIDATx[kUNd7d^I2==P$JPjP @G ( U@DPRTa2) BGBA LL؝?v=33)Ks{g{i`?c?!bmۦW(j st8Tt$FnHӹ6a= !8jnr$ c"P8J]V Cwohm ln'0U> pi:z3bf3w 7ԱEjJG(HNt8_s.1MWyQ|aխ ȓByMN&4uNNhX\{ ApJ~,qs(\`R(n 4ߏL&2ew(vXqf}7wopmI ?M& m75s*B`JP`rysgӌϦ@Rw gRӻ fBSU/J4]ҚqݥU7/xQ﫛dkGpMmOt!7(2˲J;_ oLh([@'J?og"8?.ݦ`\ Cʞ'Y>KPޗm>v:$(@PMz=Iw%KBu\:76|~%|T*qL&q@W@ F w cxԖXxy2PRw([g3J;޲/6"*ϟ&f7¯_tz]#l6;S22ͻ ):W~k7g= |=s$cXo%Y<^NB,q"93q!7:XRB{IСRg ߚ;$q+I,uZ[3Gl]ww[Qs $N!7lq71C#HpA-n8%X,N} ,uWt j\OU+l]Dc."ɗg\ptWc$>՞Y0VR[ jEAUP@'`Cmhy[\7 d@@;2̩+ ̨QB0"E>EMxЪ~ h'`9f@WJHO(LPڻ„`yzIBD NL&T@;vMxTZ >^U _JUMgG!N$Dfm۞$@T;wnϩ2$QU:A6;̩W!=%|TwSoDAQ *rl%^H;7W@谑 ? iLk iD1`Bl /P,kc"/*%?EׇyU=[{okSjQG&;%.s0{4(a^|%]5XaM"2cJraEqjOJ @5)j; ۶EX(N+ V*&CR#%I5JX3Mj.X(Rf(HU48q gasfrm-nXMffe' RJ崸L&w;T*1L޶4NiY(u,uM0yʴK;QNJzBiׅ;Ff2g-; X6s=xXV29NT,RǴ7Hoe+Ks')qޏA$eq' V,,*@GlpF>JoEޏ؏]kulIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_checked_disabled.png000066400000000000000000000024701516472651200257460ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX[lTUg: $"F*Ѐ)L%֊@)9R"!&`' Em(ҾkCBb,K10ˇ)gzotk}A7Jp$fQIFB 2XU@ lM,ۂe%'Krgs`]զPm#agmjH䞨*cҝJ0+B,ЍI Bԅ5cc-`YVNsav#nouw?.9^^8QAgY4gv(n* h1j(jsx;joV$כU*"505+?!-^36i0g?՘Ecs~ߜ>򮊼cW[^q-;L\0TegwSMe_^\ Pa{tX1eq[ݨ.[S?ٜv[nJ07}M=(veD1d0uU8i"U1kz ڣnw l6=(v|t7/ `r dBc+p>\s0=Ba&QKwO.~),/PGLbNСQu+oUv'D$:7BTU(vW(*ZC@$„q7lxP3H"*Nfm\mr?_v v@FvvbPTya ?GeXu.8awDnÕ˸2|Yf ,PHz5q|m^E6w>,/{\'կM7!M`Gf̚w;ѕ\$~IӮ2T"WڊK3_`EN"P zD0>oE邮HmP8c]h)L<Јحځkbi!#E5I#m-Zx*kˋ. ڰBIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_checked_disabled@2x.png000066400000000000000000000054671516472651200263310ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[}pTM"C?0@CG`6Vh ZNeڱ#h@Dm1_vS"5DVIB@ v!۷o]?޹{yw߽<t.J.k V tB~ Aqoq ̻*25P*~j1sCԴ֯ c#Ь$ģc{bꮪ*9VJcَ305V:] zd1p,B$@4 D 2ZXvHQfKe7+ mpcD[Z7m8\iY@L "=NX\~}X7 QH q9_^[;\jHdS<Rm;ONxRVwp\bIclwV-N9a.T1h_$,z^8ΨrׂnnA\~?}E9O؄ w5~,Di 5|ɷ! Zc\'dLsGG/Z#~YNKW+x߹}SO(G3N!9ŌS@A⩀ I%~}:ψR-c-"Yg}9TT;'̸&03ɂaaJ,r ;FtU=Snj޲یg/0L\0ӡD'p됌vzp|bZ J޼>%m`FSvڋ3thhX=p)_r)AF{}:_0c GD `c;*֞+[S3@IuE vFǹ!a*B'Ʊ sȰ['pW(0>O/-M`U|ǧ愮Oj^FFEdO"Xzi1-'4VBgNM^vrm5KK[W_pz8X&A3p@ `620MQCNDu#|X_ۈ }!Ym;I0  S c B R.K0hNBplmZ'" $Fw>A=;Ѥ e~hj#5}́;"Idc_e̼2P4o~8h2YOD~}? ݈ <.R"%fWI@'k62,}viG|[w藬4 -m^iT!Я4:~e˺>fV;;ڻ2 ;EF림v`7F}ڔΎwOH@`zvUl?hٸ]3$IrVٴ{zƈv(鰽xɥl2xD̆fS秒l f $ȓF}][$8XBHe; $["AZ:1\iYrqM `_ 3?TﮎtTl!*.H}8ڧC0+ψi{k:ޓs1Ra]{wB$[Ƥ[_Q>T`Tt[ ܖ |/UdGk$// LӴO6"BII,J b25Xn⿣kҲ؏r =-6e.;eLXOq"m0$I\-eb,53ۇÈ]V*L@L-JcV'aTq@8AL pH`iǽk$[ .rB7OS{8C>T] 1XL=ď)tX!-4B45oѕJee"H `hkߏZ8ꀲIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_checked_focus.png000066400000000000000000000023201516472651200253100ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX]e+4$\%X*uV>4Qtwkۈ"A.JKڢ2 Њ vV ]6HV %l=]8ή;֝f?=_ԡj&A zv)G:ӬW3NE{-0k]9iUWOndz>S#'AsA d{fnM1mm@Pȱ|sN!5GeJ֢·=dӶ6['3urP@G?׃`NA3 ԁe3XxYZ}4%o]POowMq)|D bvd2{m*ZIy$W\OSp\VDeC~ YyƜž&)' JԂL:ޅJ `O|rXX6^7#c'wEg^+zm黢9/孟j!hE};O4~Hd`! Zt/>mk 3:_k->K 863}y)O"U!]d?ee4TSKj?X<'*8wb ؅OrcGu}1Tw/ AeG_h8tå'N}J Wn,;Hs+N8D=bj٘ ;s j_30,vSweuj-\s7h@TH3M_]RǝjidF :FA ʼYw'{Lu Y5*Zí|QЪ!@-Iq`k[_q|DCŸaTV}:n-vf4{P>{[Ԑ< [R<+Mh2酭.by)*mTVwϊ" wAˀuog7`}Kfm-KaPShv)j󰾭>h)zloY.d0sp}qmy˘6Ɛ*|3 %bLPnUf}#s4 z@BfX 淚Sx6IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_checked_focus@2x.png000066400000000000000000000051401516472651200256650ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[k=̮,HJ(1Lp]+T,#*&$&ZFU"d`w-Qĵ]^j2QB4*Cy==33;3pGM88gp4rJR֎pA"' (N;VK雎AN0_Nw`Z,w$6p0 *pVC< V74c;5r{[yjUN`f; 086$k*΢);. ݭ\T54Ng.K\V4qs!ja+_H x4-hSH3T;8ym|]W/0Nܭ ⸞Vv"jlJSiuc Keu$ }6t|ug_Hӻ~N׼ᾢld2 oۣ],YUa#gq\8hÆ "vd1Yg}t]][fH|0pK]do%tiY{Ss-*./6F"ԍx(bg?U)A-ow mD1͂ʵ=3/aoevJR+@5g*re@zi\ԜX2PZq]wpf\vW?{~|q#4V͆qiEew8wΣxމrښ)_6Agz prPREmg w Rpj4U 4_`\٬)@?%N*1jҀD`n{)o!hH*D3B+^5m,jQTٔ.eͿ1݊Y$,asڂf"YGguQRt] `hO=36A2,MrM"g2Cu4X%,!-QH8fjl&U"g4sM)D}JgJ@o9_sQOfeƎBPWVgŷbn AGSu u1vޏ맛=ieY ^a/-pZL4'<% BV}6zҬ|O*". ZymIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_checked_pressed.png000066400000000000000000000024101516472651200256360ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX[lEg*x!-rm@Qt7$\4VC4btKa ĵ@]ZvmbHx T@I4𤥻6<`L `iK&aE}g973 8*̴QY0aAHiGmSKdooyxqY[EugkdI@qY~z`m Y?kdc5NJc Kղav_N*aەq XXq`Iڣ> t/OUU%GR0ho-.Xu&RyvbsZi'[j+xByS{CX\Gx6vmT ~(R&y*;PC; tJw9CRE("O,EUA?hkD}嵅l0]C@kV?͏GfA@uU>Gn`1㎶C}K99jPhvrU \ (.?%fOOĝ] ]P@}p 4KO  koJdM v<)-C?}jK.z2H"/~44vYLqlt1ߥs`&#rʊ !3ydFn P8q+9L2 r#3gMe8S8a%׽xҺ\pg;8hXs+U БS"ԂIJC? ? ʑfU]Q\He;73 nUY`lipSʦA~4 mMmn (~ib[7í BpQ t_oQGaܞkU46]gv[ oGbk,P)H_F:`5[V[N"# H? }1ϵ5$_9^oyx;trt=lVgR k$C4{w~AX`#p ϟbmJK6Q@CciJ}W_*{fu??)DX'%Q}Mpo~-/ۜ@ EWdyO/6 =7jr+0:L_Po\O̓eZ:.\] j)! >Bk5Ƽah{tN.''uW7"Eoo_soQ;1LpACa|[RDhQ$ u˟tN`Pt\qB7|e"5İNzp:GVv:\]q`ډqf@-GSf<"rN 5ad(-U۴˴@(V5"^N~*0ϩ^&I̙Wezlyqʝr(9z))3guc؇@O|rڰن+ļax Uݯ`}U4@`v0þ4¿V7Lhם7V#^kJ@LkPSYazز\@0n|}i¬ UM}C[%  -Dɮ% p[<ϛ vȗJ UFC]NrNl :=Ч}hǒ^]`Ť} ߯䋥ۑ@/.<YIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_unchecked@2x.png000066400000000000000000000041671516472651200250410ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+)IDATxeǿ]ۻbEٝZbb9ZP$Q0)R5F `UR~P i0AJ.]wgvڣ"my.Ww}}aNdy]rER./N89@id2m% (f*S %<5<&" U$BNI @V[4[:rrq + j3b:Ix"r2:n EJFiʉJO-Htr9sO$dn @HD^bo5;:s%E[`u9p a<5@ >JܓH$ޞj|7t::gN: d&3[DTNIN_{(+4FF{6o'0+ ;9K?L̦@Rv>k:DM֤W7UF XpOҩ o4̉|~c p.br۽-`Wg;IX l.A9y8aBR\s-l&h$FC 8 k>=:Ʉa؎fm#xS*xb … Z7. myԲ4e6X2kޭaR..s=[7m{.Oq`hhH|G]\KLI!?pn-jmTM65111V Le#TZGc$HdQ>Mm olt*T*fjIQ 0^p@DO{ 7&*o@&4uBtj|*oP pۜd,*-.U%X,~@XMwDDQDuʪ(`/|yAHv0%#m4laBHv^ :_ LO#laįzGojm:L&*.S4NG>U a;Jc]as`YVҒ%KJn9J򂶨w<%v)U3EScVOu7u}$z:Ps0e~ͻ>^2B!BR#dǨ=~[{m(7|J.x@Q[GЫ5B L@Dv.j8 qBUFHj\ e[o` 8b).\p4Mv\ք?_d2p$t:^4: 0 %0*zdcʬ9sk{!MF۶զ o_$rۄERwo4{ 3! _wdkƁR; 3oK` dͻIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_unchecked_disabled.png000066400000000000000000000020251516472651200263050ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXQH]e]m!J&+Z V+ 3B6mD/A Ez*bN-"WKk{u\_BF+F] Zpv9/^{9MxՉ%R:g̩@|0nMO'C]#pZ/$f :G&&><8vZ`W242{UN^ke؟~Gp[l-iuͥSe/ڣ[xsHs]8Z~}K`MߊtV06_5胠?Pmmm6xj}_}s D:fRL| 4Վ Xc?%m+N*kz scnp;k]GBKVPs*\Xݑ--E&iE;ۗsM?Q-+k@0Wpq= #}TA뺹xMe6@30P{j JHe}󛈾0M6zEK/w}Qm q-< &اBoVk̀%Wf {D01a~;L /69&lwjΠYIM3n$ yf4'`z/Lh |",~%L27b1 ?S@0RD:1s @` 8j?\l"2@)t$}.o6O\eCʸp` A,q=X\}uX w=HD5"Dt?mn~5Eq OG_O̧d6cgF]T5{/ƛ7Kjq_R1`H8ִ^Oθ x<].A\|Wvnf!%tK,ybz\7G$}u޵`v/ sj Z1TqgL U`<<{[cWrPigd&Ѕ,nXk)Sq0]yy{ T. :XbescMWb-ASӋ2709_D.DouzDZFg lQsxҵf͸ԀeJB-PQAa :-E(-[a_M`/Z3aLSp74 O)*2Obdz_C#3b pHǃNlm~fFK`9?d;+55%n@$`Dpǜ$kʳٓNn" kpv^ǍvTUUI04?dN Vptu#k3fc LuQJ0"N v4^-!G?(>Uc4 i=U295ф~!TEY$ 1*Bĸ `h6w JJ|>߀:&rp}vȰFuue}L'"{;Ir81tdY#b9}Lld`>N`j'vq [.l@+x~!mnWs!%]9(S ԝ>p=,2U^3VAj*wBx<ALtXCkWQIAioZ?۵e> ^*?~t릩8j3j@TI 6fsdZV gowJmg&-Ek]JyĺhA zRC2~X1{-mgERjEq:^BuS?Woa Uia,q?~=?xWKC9bRLGd:;N_̚9ߺ0g7N򷷷Vmȵ l :~g1xY9wޭ9}2y׾5gN]GyPř9s6A/e?$3CjdP&\?vE|rv<{zitUgFV#3@ $[ ;>7o,U6?eF&-_ēs؝]^Ƅ+Dx֖tmk<!/cwLXPWޚ!O|zql! =pȖr8 r+MÃXVG?`0ZQ: 8„26%w;%_), tfQiQr$~T"M]* ]*4t&a f `k05TmEfr++f1P"ӇO%urOo 1zVNb 0M wncVc78^bIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_unchecked_focus.png000066400000000000000000000017231516472651200256610ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXMhUf)6I𧥴Tip').(pEDMh3i,Bi CAFj?w_3IN&dgs?w>~\M ~ -ZTc 0WB&ۦ Дq:]9&JC͂}k*=]ta;#JY":R%A@beۼ\7+?k:u<% Fh:`ATg5ackVlǀq9ڇ'Xhә4 x%}=^5O^:ry+}UcCBGW֦A-tKɟaOAoc=IgA .Ë9`K!v O‚ŋ6ܮB5y&ymJ;Z.023_# e$~㣅&|UvE,m)@Յ ̺i X$[[9>K^`Ҽpi"=fpHMa 8n_,ՎT0zW]h@TȔ|۬1`M^`R-d.Eicm.9Y'[t᳖uZ!ɢ+g?T#ITdR%qyBUC](71Cu&9]L=nKnQ켮fopy+PMrxHȜhӹ佹?Gc&IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_unchecked_focus@2x.png000066400000000000000000000041171516472651200262330ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx[}pT=&a ~N [ lBiqLJuֱ֙tpFj+H[?**ә:S |lBQc0Z {GP{fƤ͙?{0 IeIk/ 8H 7|Jf.I[|DxF[5Ow4`Ho$qgj \'뼍IpLa ~́w.o? oJۇ~TgR8l-' *ˀQ2'`<:%vkc(FQ5J8͔drGJpi"oian (J+/_#DuTA,t/V܋.܀f${e+)ʬH4`y72iq'*ZCi.lkBrf@Lr.CFvE^P~"E0{;\sx,\.)q@5 .tFھ¥F0K$tDE=>kUՀpf*Fo)eO1Gp{or /=^^ޢW^a`]6L^=TUWDu*Kf !Z65;%O*ɠ.Z^Lp=Nk11GbPU;c"Wg^ /a8 ]ekrs "y'vS8y)\J%|gc6;6PϺR~>ֳ#\϶i!( w;AbmwZ ŤND?'EAW6~@R`[:y(WR:[]ċs87cϋvU`Ju\`zί O8^o~l.@-&rg?,4o>*⇄xK*:x*׭(BfU!{ì v"Qޯjl,]tkbic 2KQUH2vzنIK#|?״X= Z6Yn_%M+84H4ƁO:W瓚\;D.IDY~ߞq]# $llO߁L̴I725*tOGd# h]tcL>Vfmkx?ִD#1JHEgs#>;XcS/IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/radio_unchecked_pressed.png000066400000000000000000000020031516472651200261770ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX]hUySlزYbA5¯96DNȜ t txC 4&Wt:P+X 6m6{/~fZz>=<nvj뚻+/***P "Is_ m P:V8k\TţG_@mc鏀sH*gqG_*`XیaZqC'.`{sw>DR"o2@(Y`x'_9Zn`h+ [4lrJxye:.4M!2c>n!@xc&͏5~LA(dWc>':]wK^O0Djƣ"*8.(zE8j遵A\lFvzg;g5|*x+1fj;By:5-@/08oɦw8r5_1mK)XU9.p/T5k?]/}ٶW:7HC. ֌t+))avbs0Yq񞖉KI "qqSmp WZTU t<k-!^S Ņi Tc +k^ay1b}uP8tG lh(;yji9"4#˿w}T؅މ4m2.\4̠AM;J% `eI* K@x@? ]nɋVybVn3;ڲ*oyWMo D0cN]qV3.*E$MSUGI-y~7vӁOB%*𥆞Y_0 zn3h] J-G'kt㆓937SO]q cчY$nCV۝ uuLjPq@Ov+F?pqƼUIm)t#vskԙv}2ChZQQ^.}q}8c>;150ͺkȏ+N٤1DAG0p: diIPۅ!n,<^$-'o \~ե[6IBwt!^tVLJ93h:֕wj5I鱗~|8;@5IyRcQ&$ȇ|f_} ΄F9$t̺M+ wS @{>i൶K7TUpb2Sh*tQkDQ'F]-1ֿE,[yf`g}yy$7.5387xU LKxS `m &#߯=`&K BexpM`Co8p_Yݐ+K0Šry#hdǰ(#˩ݍ$r(K߯~7m/( ɰ.y'sj{2䍰w!brk AeEfv(m%+Z5^ CY0 0M9֓t>Y^'y<@@0 ]ϸAgq&a)qAPSv`3AavIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal.png000066400000000000000000000002321516472651200263060ustar00rootroot00000000000000PNG  IHDR szz pHYs+LIDATX S,K҈O|>Df+byg5[խ= ϨH)r,IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal@2x.png000066400000000000000000000004631516472651200266660ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxб @. 55Y& L`Atg"_7V[4OK=IRp}aO1uH~XVX}6h @@3=fz4h @@3=fz4h @@3=fz4h{x|ud99:/(8I:IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal_disabled.png000066400000000000000000000002331516472651200301360ustar00rootroot00000000000000PNG  IHDR szz pHYs+MIDATXױ Q4f&" kduQ`Z ҟQٙ !{IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal_disabled@2x.png000066400000000000000000000004651516472651200305170ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx훱0Ş"10 #pL4)]:ۈ;}ND)?$=[ٍxLIa=[ c^M|#OcZh4h @ 1-@cZh4h @ 1-@cZh4h @ 1-@cZfdٚ{2<@MNI$:wi,'"0BIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal_focus.png000066400000000000000000000002321516472651200275050ustar00rootroot00000000000000PNG  IHDR szz pHYs+LIDATX FavMAt|]dtQ`Z Q) y9IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal_focus@2x.png000066400000000000000000000004611516472651200300630ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxб@[X-Y]PuYFwθ_t D?pqz~VXSN{~IDATXӡ BR0tMB)$(,sNKol!I#]k  IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical@2x.png000066400000000000000000000003241516472651200263020ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxױ @ P;C  T(0O$!rBʽW~vu,{mKBZcopN|Dĵ ez;@a(eS S']>/_N|(IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_disabled.png000066400000000000000000000002141516472651200275550ustar00rootroot00000000000000PNG  IHDR szz pHYs+>IDATXӱ2 ,-hњH*$>AY8#(:Go J7@6) {iIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_disabled@2x.png000066400000000000000000000003261516472651200301330ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxױ @}@D qENh Y4/B=.ػ,~)5cc>)\|C3哤&$2o7jɐݡ˪J2'z__';SIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_focus.png000066400000000000000000000002131516472651200271240ustar00rootroot00000000000000PNG  IHDR szz pHYs+=IDATX!R.fd2*R6}$}Hm ?YcO҅/$ X 2eIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_focus@2x.png000066400000000000000000000003231516472651200275000ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxױ @}Q u : rEĢxR&3ꂽ.`;Jn\S$}4]Kvj'ɱ؆l%eHeiS}w ک.~ ]$lAIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_pressed.png000066400000000000000000000002171516472651200274560ustar00rootroot00000000000000PNG  IHDR szz pHYs+AIDATXӡ х(ZpJ1"f:@,Qژ@T?JP:$[  IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_pressed@2x.png000066400000000000000000000003211516472651200300240ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxױ @}@4B#@ E#TB,xRd}j3ꂽ.eoK& iNuz_1䔔qЕd}sRK/_/@'>:WIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal.png000066400000000000000000000002271516472651200273440ustar00rootroot00000000000000PNG  IHDR szz pHYs+IIDATXױ A%!LHT.{'#^RO -^AT(|IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal@2x.png000066400000000000000000000004441516472651200277170ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxб PD;ph5Y& L`AAN"Z}<Ϗگ[UU8bI|ZUCU /?$%%%%%%%%%%%%%%%%%%%%%%%%]T]Ku-vDımT IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled.png000066400000000000000000000002271516472651200311730ustar00rootroot00000000000000PNG  IHDR szz pHYs+IIDATXױ A&dtDFՑ2 ۼtt^AIvIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled@2x.png000066400000000000000000000004431516472651200315450ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx1@ " A &.BARga_u ?a0vKǏ ayySfP{[l ``+=V{[l ``+=V{[l ``+=V{4ִ3 sl PyIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus.png000066400000000000000000000002251516472651200305410ustar00rootroot00000000000000PNG  IHDR szz pHYs+GIDATXױ A)-gl1c]""ey G|c~IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus@2x.png000066400000000000000000000004401516472651200311120ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxбPD]"+ "4Ӕ9̍~g_UDY6n}{=iUOoC!------------------------MxxX{ꮥZ{b;"^hN;FIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_pressed.png000066400000000000000000000002271516472651200310710ustar00rootroot00000000000000PNG  IHDR szz pHYs+IIDATXA  pS?CRk8~{o%2v6i潦;ng4t9>aIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_pressed@2x.png000066400000000000000000000004461516472651200314460ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxұMPF&,R DaTla ,h}"s>_y&3{Qf洽~|?/bǫtsZguf[ݱۇߝ&P=@+@ hZzV=@+@ hZzV=@+@ hZzV=@~9 X3s{֣ۑnJ" IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical.png000066400000000000000000000002111516472651200267550ustar00rootroot00000000000000PNG  IHDR szz pHYs+;IDATX͡ уAQ0lMQE@"1Hw7a/MgeCI %!U"IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical@2x.png000066400000000000000000000003051516472651200273330ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+wIDATxб P P;C  T(0O$!bZS/ʓEgm,{6GGY;ګ?}>"ZCmlvd SD{9ؚ[NK%~S IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled.png000066400000000000000000000002101516472651200306030ustar00rootroot00000000000000PNG  IHDR szz pHYs+:IDATXͱ0V0,YMUjtI~NRM-CI ~cIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled@2x.png000066400000000000000000000003101516472651200311560ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+zIDATxбm`g2bx"6 Y,ᴑ]%8z}w0rKc>3j^??l_uox7TwPjڻ|  [IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_focus.png000066400000000000000000000002071516472651200301610ustar00rootroot00000000000000PNG  IHDR szz pHYs+9IDATX͡c)U1EM=Rځ$I 'R[ȏ}Xⓡ$Ie9IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_focus@2x.png000066400000000000000000000003051516472651200305320ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+wIDATxб @=Q u : rEĢxR%<.؂ӭ[ژB%Myqw$9־}8`kfTjH\Ҧa}N*?IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_pressed.png000066400000000000000000000002121516472651200305030ustar00rootroot00000000000000PNG  IHDR szz pHYs+$ 5KٽGpIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/transparent.png000066400000000000000000000001501516472651200237050ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX nH@ GIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/transparent@2x.png000066400000000000000000000001651516472651200242650ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+'IDATx  Om7w@@QIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/transparent_disabled.png000066400000000000000000000001501516472651200255340ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX nH@ GIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/transparent_disabled@2x.png000066400000000000000000000001651516472651200261140ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+'IDATx  Om7w@@QIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/transparent_focus.png000066400000000000000000000001501516472651200251040ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX nH@ GIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/transparent_focus@2x.png000066400000000000000000000001651516472651200254640ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+'IDATx  Om7w@@QIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/transparent_pressed.png000066400000000000000000000001501516472651200254320ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX nH@ GIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/transparent_pressed@2x.png000066400000000000000000000001651516472651200260120ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+'IDATx  Om7w@@QIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_close.png000066400000000000000000000013351516472651200240460ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXInA@d]m \@B3I8X@y@H3=Ip`AihVWϿmCXqy^F-[Ƙ/\? zp!,6m (ǀȷi<`;5ʉ1h- S "Uݚp5R4鶌hiLUot[qkmʫ4{??!v$E=LH(2" .I,s/UD rZ^(P bx%A$EmsXT@sb9*!6̋i),fW+ X/ESUy\$zϪ,}Cl T$\icAb;^ZGpDZwHLZ@hx\Be;f] QvIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_close@2x.png000066400000000000000000000031241516472651200244160ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxsEYX @EI! C6NpwP@+{X*bkFC Cq2lX3({^ni$ Xc3nܹs7={@Έ^ -0 *}/fAN^޸[\"য়߲~.]`>Ϫ4V1_oھ}aӼ W^l`V+q'ՎSdu^jn`cKܣW%,:zyET?ɬVww'# ~%[kpޫ.!Ix`f̫̓-ʞ9U9 = = mQ:;- _8vME[dܹZ/a]]T4C[*qøK8P.tYە0 R1h`tt+!9-EkŰ(n#yxr  v@Je1Lm? I >Mr }$X#K aR1cd>^4%$ /._[;Ҕ!bA^r(l0 jP|knJ0 Gi R~cǀ-s/[twp$j@B ʌe!Q=)ǝe RZ:T%dRxX ?Z* aً HʛnسϯvkFoeC'fIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_close_disabled.png000066400000000000000000000014641516472651200257000ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXn@@ ,Hi $;i6HKB-[H|KvH$@&v6)ڼb^i.) jlsJ>*ި *W-C/Tm2Um'(:7-xje2 !QUu-XD@\zӔֹx!mw&_|,nRnw' "pXj6D%^Hd&؇ ߇|l჈D$oDٴXx@_*NB%Q65 (KJ]`1|vFq |9 >R%f tpIGƼi]V =D/Q1pՕVܩ$zRas/gE>D!\Kp.U( fz4D()蓄u`fNm;S(W-C)p8گDc|isn`g" !AML{l {IY|X\ dpJU󆽄hʕV}u;IF6_rFI$ ߹?#L$+P1ki~xn{'Qb9Q@Ŭ-*PnA\iDDH\@6b{ '@lN [xP"/|H򅝮y>5 :܏f㮠>qX[UPkٸ{P@F*Q]<(,#|>Jo ߐIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_close_disabled@2x.png000066400000000000000000000032651516472651200262530ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+gIDATxMp[W*ФM?g 4I6h/ڊvmgb֬Ll2S[vWF4 M?壄-0tJQ ij;’1Oz6{;>=}?K }};(#AC`KԗyǁuU.ߊ}G~Isl ;n3?N7M]L[}3CQ|b+F yOK/n5 i5pDQ/y,~CUgPm6@\BUoJayKmBHgsg$Jf&2_ѻ֔df Z.z}*~<{h g+ۡne t$=j)vUIŹ8TvT;{*\GIU_&0C m23)B(/-U鉙-pWXjl/,\vBTfTlԃ)y#2jS_Epd+!yI{s R#0A m;aBHdrEŏ< |\YBP/5NwN WȰu;F9=1pD";-Wc jBX .LMU Vi0SXn1Õ/xS ؘ2!DWQqty@r"uDM7pny1m)*CwN*Pc-?F Q}2* h(X{8Wy}59CY{]ºXMGm"ۥ֮"r1="L4Pu޾.9U?>]gJQ&y3?0/f_ gNŧG' fE 9aT:Dvlż†Cڣ֘HVB֬0lTSwG!qYq5o>\\XHfW9\!)@  A7[ԼX{|d\f! tsՈf]p<3S'nl{fmzf1ΜpC>L?h̯#z8Q%@P0n0Ukbs!P7_sV̀DWk~gA[8WqM!5Bx2U`TxKًnjh^,ao+嫈 HB-Џy/;\Whg}$Vm+ xh,gǢ6P^=;߫Fڮ-E6;Z^\bCSЕ`Ksjh0[o)w%{1xtQ|=4 7$~A|5l34( 껾u@+l<u?k$$p:MHK :%&sHO <"2$Np}EpаyBUxꗃ<~H6`U\z@˅o Ep JĒ\zʅKg\ 73 RPD3sBU$_yh R7Kb;OK IH@b*+ J=H\ {UR%$كDGհJ@-H̘GJf-pA k; #~R+%a@rK ]:jha74 ܚWb@ӗGʆ @h͑(z|o]ۖbDKhR,2|W`%n6}=!u]|:'8Ё,Zy7[FMԋ=2x@LEUzmB! C܂e"lmVBr*7gϙlF@C֣BH<ʴ&`8*g˙Iq;PZY"X@?~;!ib}ZsFl~猽01F]բ*wl9;oχϗ^>@ /il@2MkveʖvơB~;ZAiNXsMm:?yHZ/ l۳l8Id_VqC l;~@<&6d@e !9{d hצ^"ڔ HB!oԸB<Lj`?T_Jv\ozR B LOzo;X0Vqot@xە3Ȯ ̭?⚗T-j%;6Z: `1WfZD2e6 wB$ASՂbckl^vfoƣ `̷Ԅ6t٩;^gJ3Z%`3*VVJv|nf![3ZMRq;gν.7x_̷+Ysh}Zk_~[1_Y-2<-ҹ^dו4RVSAЙΕ^Rfu#ȴոFCPoo!4=L[t]!Ε.f_֛ J2,hqGƇ]\P+ʁxә^f-Ug<w#dxh[^']߁trI0.:IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_close_pressed.png000066400000000000000000000013501516472651200255700ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX喻r@#%TR !dr#Dj,7(e5' !03PY~ PJd]lqp*iVم$0^: ]^}4AY]R5oD+( G9aiBz>;1EӐ(Z*Qp/! "@oR=U9H^"q:a%Eq [Z|,Eb&DxsA~]R"*Cᖳ*M`fPZ)&ϡ4,g5Ex%/@XU}J#&UgbwWD,/|,t7I ɨ$ydPllx.Dcȸ\74@c|'//*~)+yr -wsIo;/էy2s,0ig"E[FX3W`;"0Er"`9YNR|Hb,T.pv;J=l* Qm~ߩU"$fGIdmOD5.Z^"f.98%@to8َ2L%-@#hbnB0p7a[aC|㶯f FtfeÄz}GKROl!5t2]A#98с2;ltE}0;ZpmxXY]|f⡁L[<8;,bp4 W#Eܮ$'"v8~`W×:P)`LJ4v(h~Z2 98([S鑥# hb&4=+;_.=9]ҹ:3G~Tz`7۝p~.%s&pғ5f/*jGE,vB RɃCxK=tO *Koq6+⃹Nd၉G,\Q ,s:l%A{q<A*T[e4%>?<4ccέ:a8<0:8ϼ*}Q(䳋n4 VYmקnxj*rzu&3A;Ak/82oi[xȡmLOkLXʋU׌-Cg3 Xzq?מ{HvӸ OيG.-Ʉm5l}n'(Uc D8_13u/ \!ISXma‡*sƿ/pW^CyP(Nq&_i⯫xY<@DE_7~xe]v^^&IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_grip.png000066400000000000000000000006341516472651200237030ustar00rootroot00000000000000PNG  IHDR szz pHYs+NIDATXֽN@ ށ&YBVV֋`WjlLLXBg5-̙BJ8y4%VU  Ԥx \ǩ>?Iqk_/kWi~L`ƒl {{ ˲ ;9!.Bvnm[čkԫ1\ 0^f q=7}42,ƹksþqR̊Ʉ33Q?>|sf6?!΍cs6̬ٸ| Vd}ˤTIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_grip@2x.png000066400000000000000000000013101516472651200242450ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+zIDATx횿nPKT6;6</B ++o+J !UbAH0 !ic{}htO6du}(A#ߎW:!0eW̨yFun*<N@#<:MKu~P/e&Ou F@x0]!p]!`&!P!@&!0! 6!!6sc.SCᏋ➨QD`>[73l7 *:ZcC>ƒ#$I~.||BKB BBBCBW$:Z(vEX O遠 ߐV|?99ݯ7 ^ETC ]y)CKpUKSw5}+}j <8.]A0~I_9Ymwv\/]n tT~ + ۥKR鰦" MӟO_?򟜚iÚkl6βl׾<ϯd5[taIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_grip_disabled.png000066400000000000000000000006621516472651200255330ustar00rootroot00000000000000PNG  IHDR szz pHYs+dIDATX1N0sr:pX\5*,B{&Ҙ!vl)߇ԉEAKe<zq `vZpsD$."! hpl۟=-jV:ϥ^*WjwG_\TZ_=@ /=Q.+sPO1^ ) (꽅 $di} wZ)4PiCCLCLCLC`LC@lC lClƒlÃ\\L×;zqyw&B%` %o؀7R^p?c7wR'?M%a79 r<8<8#<8=/>Le]`Y`Q@`I@(`A@H`X@h`P@`H@`!WfjORUsL%|ݝTTH37L`L%wr(`"V32 >Lw۵{JwzޤW (*<\ژliÄ'%a8 _#Lyb^#2"ٹ!}B)7SǃcCS'䥆7IpdNХL˴XyrH؊Np=ԃK^b>YXn4}ͻ}dެfu}YIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_grip_focus.png000066400000000000000000000006301516472651200250760ustar00rootroot00000000000000PNG  IHDR szz pHYs+JIDATX?J@K[x*` @z"!n'^B+Y(ęS d68ޝYw?9][WZֲ N-Hh-6y}P}#e㱞'{Zlu_k-ZƽvCQi2eCC\C\C\Cb\CB|C"|C|C|CBCBC\wzhײQM\w:504D#|A޹B@ |oBv˶ cGE& xI@,P!!!PL0i3;uL鼔% ;myUaNxx@@Mzϛ5*(B/GSJ2ye?=l;>\~J^ixy'~66TXJA^ͺ΃OaOd*gryf_e͏Zh5ּ/te޲AL+lIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_grip_pressed.png000066400000000000000000000007071516472651200254310ustar00rootroot00000000000000PNG  IHDR szz pHYs+yIDATX1N0r:pԹHpT T :Q('`!5CicNh?ɶ }HXo$Z߁y zgR\L d/UibMϒt+OK `/% =+5@[[znk4uC'tćPO P?^k` sB\đ>:;;(>V18X  P70%hgN$|f G̯gCs_grf_!'fo^EҘ;B-÷ߧ=SCA ""`"` "`"`"" " `ܑ>(Aن$M)ysOSA /23s]wӞM@𐓀P!!gG!ƒ'Ud>Z%˹XX!_d>^5j<{>῎:÷rdO0 xK<|O'̳'7|=]}c-t^H@Qk7x}dxvOV  _i0ϊ3 x孱lI _Mz5H[som߁ݙ'ex=\t,%%/`m!ˇTy ?z39f6 vºPn=xqfަ6u/W>4aIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_minimize.png000066400000000000000000000003131516472651200245550ustar00rootroot00000000000000PNG  IHDR szz pHYs+}IDATX!@;4@&QÑ*=7A HCwMH&kfĂHe{D v68 \3@lxȏ؅P|dl EDDW(1IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_minimize@2x.png000066400000000000000000000005151516472651200251330ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx!NPJ'A6I% ` M$`CXZp$Ǵ0 ᷣ):uıԇIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_minimize_disabled@2x.png000066400000000000000000000005201516472651200267560ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx-NQs)K |<#1,tMI% v"!ufʻX5#3#`݋bҤ!BYg{0rөQkMc2`%;P.Eu0| >?|yIڷu0]<}3q%M2Q$wY2@g}(SFy-|8LN_Cu%-KfU&V@GhOB헆IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_minimize_focus.png000066400000000000000000000003161516472651200257570ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX!@;p䞁 0 "8 I@& [3{o7"""6d +$8vaPuL[۷ߧ\@x7<2.68ˆ}^ 7IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_minimize_focus@2x.png000066400000000000000000000005151516472651200263320ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx֡JQ̌}AP\l9,>K-Š)iAlA1X^Ypx΄~ΕA?vܪҋUo 8Q撝J-]NEV(Ʒ݈tQ\zS{>/LdҎy>/ p; I&糲) 0[C.geՅǀ<.<,'C/%W'Fm@! '; |PIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_minimize_pressed.png000066400000000000000000000003221516472651200263020ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXұ P܁=M,lAkgwvгR!$vu%w334*cYxk'fʺ.6瀀W}E:rw߀x. GylOhff7y g/IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_minimize_pressed@2x.png000066400000000000000000000005211516472651200266550ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx!NPs  < !LHXP@HpQH8L^,yp}VJ gySOR~8ņY5t,in,~VzGR/&mein{vs=.ڥlB1df)&Y:?G.=Y2@4q5KL8`v5e'Vgn=[-m'HC<56PiIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_undock.png000066400000000000000000000010111516472651200242130ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX햿JPϗD @ ^pA|A\|]K .'\tZkCMT&=ӽw%Dt]7xk!0!YҏL|nlނȥ3@iZח}-gޟ>Ȇ?6˂|.kEeo{w4rRmi,Yu'"I>HM۶oC uTI sXh$  R RKq{Vq7b ]+9 y' ҜzaBDE<DJP1#Yq[UG=l"Nmcgq;a @#L`4-C_$XЗ!زm4/X=\IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_undock@2x.png000066400000000000000000000015601516472651200245760ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+"IDATx횽kAƟw/;"6bxw{{ !`k.t6!DvB !n F,KEB۽ǛeWν33h44Cqnnh44FtaU/mr#[*2Z2@ đOM}:F൚3Iw'@@+LT61VcѠڀ1D[9!?8hL%# ڀ' !Nu2qw+T P-@5Tznj%#fnU =ZnT* =UǹK祅`3YVsu vm]ߘ%i<X0O"0l۽.gm%0^J%@jmmDp0f$9} gH$ 2|S^b]DU$dax;'pDh Nol # kT P6@hT P6@hT P6@Dy+N|nkAze2Ke1w;o-OM<n&4A_.>=VخisCCC۝*XkfᤃgI~HD >H$ $s2r|QN03@71rXg^Ԗ@Qt`#fMX,Nvw345o]ȇ$Eh =RlZc1 rsҊplJVЧ nE](W=k >uWQ?uĊyȟyIU U2ō%$m3v/O.OSs( Hd_@=@gۀrZIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_undock_disabled@2x.png000066400000000000000000000016341516472651200264270ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+NIDATxkAƟwӨR""`m<ѓފ6TQi"ԃ1UZM*"=X̥If<M1>d23 !m7 :XF Gb: r $E hXUe_'̉nU4е/>}o-{#G F#B nkGUTFrpN(t )Œ#gN Y1]7^-0T F ۀlT Ȧ(f` $`.|Gf8vmyofrrժF1 =ˈؑ7X@[6]tNE_3_߼Y0_ rDC" oGc 8uo/'/\Dx(B\@֕p!lМK_! " م e4*"dhN1^,otzesj~+m@6*dm@6*dm@6*dc|8RFX/lPT[h5!TܣU3$G Ṹp-d›=1<9{\#fuXk@R"8k |sp`YQ" نY]c7dDw º/F-{Y/bb*FNxkM(X. 'cD~34??/S_WW:Q`V8r2%H7aiCi&Ouϟ\z )lIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_undock_focus.png000066400000000000000000000007671516472651200254330ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX햱JPd_@7`A|) *]|]ND8YI:A RP;(ԩǡ&6MLkns{uѨ*'QdPjDMGS  rr5kjB(DG`kjW)w٧"X[s;/[V4e^Tl{, 3n $B= i S<ChK#-O# *6@媅5;J7ݠt@t~ st=[B޺; 6h:R1~uKXӁmMП 0'btP[d{zڡYj 0| P62{2bkIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_undock_focus@2x.png000066400000000000000000000015421516472651200257750ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx;hQϙ]0b1X aw0 1` ) ZXZ$ $ ـE$łX(>ܝcDwfw33{&|坛9ǿw.gUoZi K`[+E3L=oG [ @tE1HH)&8aEz{h![p NBZ@Li+!p}kZb}Wx?(@׺i?~Ci?~AEKy'rolUc~޷SI & $6`д:R޴^c 4)oš eR?pFsu.F<^, p1ȟ5oZ`5nH/v4N<yoC  IENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_undock_pressed.png000066400000000000000000000010331516472651200257440ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX햱J#QdTp-0#,+,"6V)#+V*yA T,TB APNL3$9so=sgM6 ~#jd>6M6}il D+2~>!NpQ=w鯶y^ʀ= 9y6wdK>Fu5=&_7&IED^o;Cwe3B_)NeiEAt{p.=} i(,#Wׂ@f5.8zk|jiT~ jE> TܱJe@,$gX*e0-֍rdk!c'.z:cu 4WLt,jKsT7bmz H(4 Wr7rX.T3__=DGro~r='ywYIENDB`seer-2.7/src/resources/qdarkstyle/dark/rc/window_undock_pressed@2x.png000066400000000000000000000016111516472651200263200ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+;IDATx횽kAƟ ؈c CbBrє' x`6S *Kr)6BH.)$)3}-"{{ssW s "ʰG38O2Bh W ,g>%W: f)AtRx>{U_؀ع6u5s!hFfuplqCugSA&l^/0T F ۀlT &T<u4-A`Ah?f|! ȾK~֪b%X4E4}>Cv$Dg¼8We@0asÇIfmY1n#}U3hgU@AM*]-sq[[pbhE"(!րBC"|re;qXADž 4EH @٨d @٨d @٨dh ҦH@ ӥmQ ƨ-to8 pv}zPe17׋[sl{^+l#lQ=",BᵈBAa7"tmhC"eY"҆ UE',v<<TDA0F Qo?kY۵T~bYaO6Ea!0aH3)lm= E:1K4jIENDB`seer-2.7/src/resources/qdarkstyle/light/000077500000000000000000000000001516472651200204245ustar00rootroot00000000000000seer-2.7/src/resources/qdarkstyle/light/lightstyle.qrc000066400000000000000000000233571516472651200233350ustar00rootroot00000000000000 rc/arrow_down.png rc/arrow_down@2x.png rc/arrow_down_disabled.png rc/arrow_down_disabled@2x.png rc/arrow_down_focus.png rc/arrow_down_focus@2x.png rc/arrow_down_pressed.png rc/arrow_down_pressed@2x.png rc/arrow_left.png rc/arrow_left@2x.png rc/arrow_left_disabled.png rc/arrow_left_disabled@2x.png rc/arrow_left_focus.png rc/arrow_left_focus@2x.png rc/arrow_left_pressed.png rc/arrow_left_pressed@2x.png rc/arrow_right.png rc/arrow_right@2x.png rc/arrow_right_disabled.png rc/arrow_right_disabled@2x.png rc/arrow_right_focus.png rc/arrow_right_focus@2x.png rc/arrow_right_pressed.png rc/arrow_right_pressed@2x.png rc/arrow_up.png rc/arrow_up@2x.png rc/arrow_up_disabled.png rc/arrow_up_disabled@2x.png rc/arrow_up_focus.png rc/arrow_up_focus@2x.png rc/arrow_up_pressed.png rc/arrow_up_pressed@2x.png rc/base_icon.png rc/base_icon@2x.png rc/base_icon_disabled.png rc/base_icon_disabled@2x.png rc/base_icon_focus.png rc/base_icon_focus@2x.png rc/base_icon_pressed.png rc/base_icon_pressed@2x.png rc/branch_closed.png rc/branch_closed@2x.png rc/branch_closed_disabled.png rc/branch_closed_disabled@2x.png rc/branch_closed_focus.png rc/branch_closed_focus@2x.png rc/branch_closed_pressed.png rc/branch_closed_pressed@2x.png rc/branch_end.png rc/branch_end@2x.png rc/branch_end_disabled.png rc/branch_end_disabled@2x.png rc/branch_end_focus.png rc/branch_end_focus@2x.png rc/branch_end_pressed.png rc/branch_end_pressed@2x.png rc/branch_line.png rc/branch_line@2x.png rc/branch_line_disabled.png rc/branch_line_disabled@2x.png rc/branch_line_focus.png rc/branch_line_focus@2x.png rc/branch_line_pressed.png rc/branch_line_pressed@2x.png rc/branch_more.png rc/branch_more@2x.png rc/branch_more_disabled.png rc/branch_more_disabled@2x.png rc/branch_more_focus.png rc/branch_more_focus@2x.png rc/branch_more_pressed.png rc/branch_more_pressed@2x.png rc/branch_open.png rc/branch_open@2x.png rc/branch_open_disabled.png rc/branch_open_disabled@2x.png rc/branch_open_focus.png rc/branch_open_focus@2x.png rc/branch_open_pressed.png rc/branch_open_pressed@2x.png rc/checkbox_checked.png rc/checkbox_checked@2x.png rc/checkbox_checked_disabled.png rc/checkbox_checked_disabled@2x.png rc/checkbox_checked_focus.png rc/checkbox_checked_focus@2x.png rc/checkbox_checked_pressed.png rc/checkbox_checked_pressed@2x.png rc/checkbox_indeterminate.png rc/checkbox_indeterminate@2x.png rc/checkbox_indeterminate_disabled.png rc/checkbox_indeterminate_disabled@2x.png rc/checkbox_indeterminate_focus.png rc/checkbox_indeterminate_focus@2x.png rc/checkbox_indeterminate_pressed.png rc/checkbox_indeterminate_pressed@2x.png rc/checkbox_unchecked.png rc/checkbox_unchecked@2x.png rc/checkbox_unchecked_disabled.png rc/checkbox_unchecked_disabled@2x.png rc/checkbox_unchecked_focus.png rc/checkbox_unchecked_focus@2x.png rc/checkbox_unchecked_pressed.png rc/checkbox_unchecked_pressed@2x.png rc/line_horizontal.png rc/line_horizontal@2x.png rc/line_horizontal_disabled.png rc/line_horizontal_disabled@2x.png rc/line_horizontal_focus.png rc/line_horizontal_focus@2x.png rc/line_horizontal_pressed.png rc/line_horizontal_pressed@2x.png rc/line_vertical.png rc/line_vertical@2x.png rc/line_vertical_disabled.png rc/line_vertical_disabled@2x.png rc/line_vertical_focus.png rc/line_vertical_focus@2x.png rc/line_vertical_pressed.png rc/line_vertical_pressed@2x.png rc/radio_checked.png rc/radio_checked@2x.png rc/radio_checked_disabled.png rc/radio_checked_disabled@2x.png rc/radio_checked_focus.png rc/radio_checked_focus@2x.png rc/radio_checked_pressed.png rc/radio_checked_pressed@2x.png rc/radio_unchecked.png rc/radio_unchecked@2x.png rc/radio_unchecked_disabled.png rc/radio_unchecked_disabled@2x.png rc/radio_unchecked_focus.png rc/radio_unchecked_focus@2x.png rc/radio_unchecked_pressed.png rc/radio_unchecked_pressed@2x.png rc/toolbar_move_horizontal.png rc/toolbar_move_horizontal@2x.png rc/toolbar_move_horizontal_disabled.png rc/toolbar_move_horizontal_disabled@2x.png rc/toolbar_move_horizontal_focus.png rc/toolbar_move_horizontal_focus@2x.png rc/toolbar_move_horizontal_pressed.png rc/toolbar_move_horizontal_pressed@2x.png rc/toolbar_move_vertical.png rc/toolbar_move_vertical@2x.png rc/toolbar_move_vertical_disabled.png rc/toolbar_move_vertical_disabled@2x.png rc/toolbar_move_vertical_focus.png rc/toolbar_move_vertical_focus@2x.png rc/toolbar_move_vertical_pressed.png rc/toolbar_move_vertical_pressed@2x.png rc/toolbar_separator_horizontal.png rc/toolbar_separator_horizontal@2x.png rc/toolbar_separator_horizontal_disabled.png rc/toolbar_separator_horizontal_disabled@2x.png rc/toolbar_separator_horizontal_focus.png rc/toolbar_separator_horizontal_focus@2x.png rc/toolbar_separator_horizontal_pressed.png rc/toolbar_separator_horizontal_pressed@2x.png rc/toolbar_separator_vertical.png rc/toolbar_separator_vertical@2x.png rc/toolbar_separator_vertical_disabled.png rc/toolbar_separator_vertical_disabled@2x.png rc/toolbar_separator_vertical_focus.png rc/toolbar_separator_vertical_focus@2x.png rc/toolbar_separator_vertical_pressed.png rc/toolbar_separator_vertical_pressed@2x.png rc/transparent.png rc/transparent@2x.png rc/transparent_disabled.png rc/transparent_disabled@2x.png rc/transparent_focus.png rc/transparent_focus@2x.png rc/transparent_pressed.png rc/transparent_pressed@2x.png rc/window_close.png rc/window_close@2x.png rc/window_close_disabled.png rc/window_close_disabled@2x.png rc/window_close_focus.png rc/window_close_focus@2x.png rc/window_close_pressed.png rc/window_close_pressed@2x.png rc/window_grip.png rc/window_grip@2x.png rc/window_grip_disabled.png rc/window_grip_disabled@2x.png rc/window_grip_focus.png rc/window_grip_focus@2x.png rc/window_grip_pressed.png rc/window_grip_pressed@2x.png rc/window_minimize.png rc/window_minimize@2x.png rc/window_minimize_disabled.png rc/window_minimize_disabled@2x.png rc/window_minimize_focus.png rc/window_minimize_focus@2x.png rc/window_minimize_pressed.png rc/window_minimize_pressed@2x.png rc/window_undock.png rc/window_undock@2x.png rc/window_undock_disabled.png rc/window_undock_disabled@2x.png rc/window_undock_focus.png rc/window_undock_focus@2x.png rc/window_undock_pressed.png rc/window_undock_pressed@2x.png lightstyle.qss seer-2.7/src/resources/qdarkstyle/light/lightstyle.qss000066400000000000000000001514211516472651200233500ustar00rootroot00000000000000/* --------------------------------------------------------------------------- WARNING! File created programmatically. All changes made in this file will be lost! Created by the qtsass compiler v0.4.0 The definitions are in the "qdarkstyle.qss._styles.scss" module --------------------------------------------------------------------------- */ /* Dark Style - QDarkStyleSheet ------------------------------------------ */ /* See Qt documentation: - https://doc.qt.io/qt-5/stylesheet.html - https://doc.qt.io/qt-5/stylesheet-reference.html - https://doc.qt.io/qt-5/stylesheet-examples.html --------------------------------------------------------------------------- */ /* Reset elements ------------------------------------------------------------ Resetting everything helps to unify styles across different operating systems --------------------------------------------------------------------------- */ * { padding: 0px; margin: 0px; border: 0px; border-style: none; border-image: none; outline: 0; } /* specific reset for elements inside QToolBar */ QToolBar * { margin: 0px; padding: 0px; } /* QWidget ---------------------------------------------------------------- --------------------------------------------------------------------------- */ QWidget { background-color: #FAFAFA; border: 0px solid #C0C4C8; padding: 0px; color: #19232D; selection-background-color: #9FCBFF; selection-color: #19232D; } QWidget:disabled { background-color: #FAFAFA; color: #9DA9B5; selection-background-color: #DAEDFF; selection-color: #9DA9B5; } QWidget::item:selected { background-color: #9FCBFF; } QWidget::item:hover:!selected { background-color: #73C7FF; } /* QMainWindow ------------------------------------------------------------ This adjusts the splitter in the dock widget, not qsplitter https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow --------------------------------------------------------------------------- */ QMainWindow::separator { background-color: #C0C4C8; border: 0px solid #FAFAFA; spacing: 0px; padding: 2px; } QMainWindow::separator:hover { background-color: #ACB1B6; border: 0px solid #73C7FF; } QMainWindow::separator:horizontal { width: 5px; margin-top: 2px; margin-bottom: 2px; image: url(":/qss_icons/light/rc/toolbar_separator_vertical.png"); } QMainWindow::separator:vertical { height: 5px; margin-left: 2px; margin-right: 2px; image: url(":/qss_icons/light/rc/toolbar_separator_horizontal.png"); } /* QToolTip --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip --------------------------------------------------------------------------- */ QToolTip { background-color: #9FCBFF; color: #19232D; /* If you remove the border property, background stops working on Windows */ border: none; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Remove opacity, fix #174 - may need to use RGBA */ } /* QStatusBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar --------------------------------------------------------------------------- */ QStatusBar { border: 1px solid #C0C4C8; /* Fixes Spyder #9120, #9121 */ background: #C0C4C8; /* Fixes #205, white vertical borders separating items */ } QStatusBar::item { border: none; } QStatusBar QToolTip { background-color: #73C7FF; border: 1px solid #FAFAFA; color: #FAFAFA; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Reducing transparency to read better */ opacity: 230; } QStatusBar QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; } /* QCheckBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox --------------------------------------------------------------------------- */ QCheckBox { background-color: #FAFAFA; color: #19232D; spacing: 4px; outline: none; padding-top: 4px; padding-bottom: 4px; } QCheckBox:focus { border: none; } QCheckBox QWidget:disabled { background-color: #FAFAFA; color: #9DA9B5; } QCheckBox::indicator { margin-left: 2px; height: 14px; width: 14px; } QCheckBox::indicator:unchecked { image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QCheckBox::indicator:unchecked:disabled { image: url(":/qss_icons/light/rc/checkbox_unchecked_disabled.png"); } QCheckBox::indicator:checked { image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QCheckBox::indicator:checked:disabled { image: url(":/qss_icons/light/rc/checkbox_checked_disabled.png"); } QCheckBox::indicator:indeterminate { image: url(":/qss_icons/light/rc/checkbox_indeterminate.png"); } QCheckBox::indicator:indeterminate:disabled { image: url(":/qss_icons/light/rc/checkbox_indeterminate_disabled.png"); } QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { image: url(":/qss_icons/light/rc/checkbox_indeterminate_focus.png"); } /* QGroupBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { font-weight: bold; border: 1px solid #C0C4C8; border-radius: 4px; padding: 2px; margin-top: 6px; margin-bottom: 4px; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left: 4px; padding-left: 2px; padding-right: 4px; padding-top: -4px; } QGroupBox::indicator { margin-left: 2px; margin-top: 2px; padding: 0; height: 14px; width: 14px; } QGroupBox::indicator:unchecked { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QGroupBox::indicator:unchecked:disabled { image: url(":/qss_icons/light/rc/checkbox_unchecked_disabled.png"); } QGroupBox::indicator:checked { border: none; image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QGroupBox::indicator:checked:disabled { image: url(":/qss_icons/light/rc/checkbox_checked_disabled.png"); } /* QRadioButton ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton --------------------------------------------------------------------------- */ QRadioButton { background-color: #FAFAFA; color: #19232D; spacing: 4px; padding-top: 4px; padding-bottom: 4px; border: none; outline: none; } QRadioButton:focus { border: none; } QRadioButton:disabled { background-color: #FAFAFA; color: #9DA9B5; border: none; outline: none; } QRadioButton QWidget { background-color: #FAFAFA; color: #19232D; spacing: 0px; padding: 0px; outline: none; border: none; } QRadioButton::indicator { border: none; outline: none; margin-left: 2px; height: 14px; width: 14px; } QRadioButton::indicator:unchecked { image: url(":/qss_icons/light/rc/radio_unchecked.png"); } QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_unchecked_focus.png"); } QRadioButton::indicator:unchecked:disabled { image: url(":/qss_icons/light/rc/radio_unchecked_disabled.png"); } QRadioButton::indicator:checked { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked.png"); } QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked_focus.png"); } QRadioButton::indicator:checked:disabled { outline: none; image: url(":/qss_icons/light/rc/radio_checked_disabled.png"); } /* QMenuBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar --------------------------------------------------------------------------- */ QMenuBar { background-color: #C0C4C8; padding: 2px; border: 1px solid #FAFAFA; color: #19232D; selection-background-color: #73C7FF; } QMenuBar:focus { border: 1px solid #9FCBFF; } QMenuBar::item { background: transparent; padding: 4px; } QMenuBar::item:selected { padding: 4px; background: transparent; border: 0px solid #C0C4C8; background-color: #73C7FF; } QMenuBar::item:pressed { padding: 4px; border: 0px solid #C0C4C8; background-color: #73C7FF; color: #19232D; margin-bottom: 0px; padding-bottom: 0px; } /* QMenu ------------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu --------------------------------------------------------------------------- */ QMenu { border: 0px solid #C0C4C8; color: #19232D; margin: 0px; background-color: #D2D5D8; selection-background-color: #73C7FF; } QMenu::separator { height: 1px; background-color: #ACB1B6; color: #19232D; } QMenu::item { background-color: #D2D5D8; padding: 4px 24px 4px 28px; /* Reserve space for selection border */ border: 1px transparent #C0C4C8; } QMenu::item:selected { color: #19232D; background-color: #73C7FF; } QMenu::item:pressed { background-color: #73C7FF; } QMenu::icon { padding-left: 10px; width: 14px; height: 14px; } QMenu::indicator { padding-left: 8px; width: 12px; height: 12px; /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ } QMenu::indicator:non-exclusive:unchecked { image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QMenu::indicator:non-exclusive:unchecked:hover, QMenu::indicator:non-exclusive:unchecked:focus, QMenu::indicator:non-exclusive:unchecked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QMenu::indicator:non-exclusive:unchecked:disabled { image: url(":/qss_icons/light/rc/checkbox_unchecked_disabled.png"); } QMenu::indicator:non-exclusive:checked { image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QMenu::indicator:non-exclusive:checked:hover, QMenu::indicator:non-exclusive:checked:focus, QMenu::indicator:non-exclusive:checked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QMenu::indicator:non-exclusive:checked:disabled { image: url(":/qss_icons/light/rc/checkbox_checked_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate { image: url(":/qss_icons/light/rc/checkbox_indeterminate.png"); } QMenu::indicator:non-exclusive:indeterminate:disabled { image: url(":/qss_icons/light/rc/checkbox_indeterminate_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate:focus, QMenu::indicator:non-exclusive:indeterminate:hover, QMenu::indicator:non-exclusive:indeterminate:pressed { image: url(":/qss_icons/light/rc/checkbox_indeterminate_focus.png"); } QMenu::indicator:exclusive:unchecked { image: url(":/qss_icons/light/rc/radio_unchecked.png"); } QMenu::indicator:exclusive:unchecked:hover, QMenu::indicator:exclusive:unchecked:focus, QMenu::indicator:exclusive:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_unchecked_focus.png"); } QMenu::indicator:exclusive:unchecked:disabled { image: url(":/qss_icons/light/rc/radio_unchecked_disabled.png"); } QMenu::indicator:exclusive:checked { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked.png"); } QMenu::indicator:exclusive:checked:hover, QMenu::indicator:exclusive:checked:focus, QMenu::indicator:exclusive:checked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked_focus.png"); } QMenu::indicator:exclusive:checked:disabled { outline: none; image: url(":/qss_icons/light/rc/radio_checked_disabled.png"); } QMenu::right-arrow { margin: 5px; padding-left: 12px; image: url(":/qss_icons/light/rc/arrow_right.png"); height: 12px; width: 12px; } /* QAbstractItemView ------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QAbstractItemView { alternate-background-color: #FAFAFA; color: #19232D; border: 1px solid #C0C4C8; border-radius: 4px; } QAbstractItemView QLineEdit { padding: 2px; } /* QAbstractScrollArea ---------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QAbstractScrollArea { background-color: #FAFAFA; border: 1px solid #C0C4C8; border-radius: 4px; /* fix #159 */ padding: 2px; /* remove min-height to fix #244 */ color: #19232D; } QAbstractScrollArea:disabled { color: #9DA9B5; } /* QScrollArea ------------------------------------------------------------ --------------------------------------------------------------------------- */ QScrollArea QWidget QWidget:disabled { background-color: #FAFAFA; } /* QScrollBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar --------------------------------------------------------------------------- */ QScrollBar:horizontal { height: 16px; margin: 2px 16px 2px 16px; border: 1px solid #C0C4C8; border-radius: 4px; background-color: #FAFAFA; } QScrollBar:vertical { background-color: #FAFAFA; width: 16px; margin: 16px 2px 16px 2px; border: 1px solid #C0C4C8; border-radius: 4px; } QScrollBar::handle:horizontal { background-color: #ACB1B6; border: 1px solid #C0C4C8; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:hover { background-color: #9FCBFF; border: #9FCBFF; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:focus { border: 1px solid #73C7FF; } QScrollBar::handle:vertical { background-color: #ACB1B6; border: 1px solid #C0C4C8; min-height: 8px; border-radius: 4px; } QScrollBar::handle:vertical:hover { background-color: #9FCBFF; border: #9FCBFF; border-radius: 4px; min-height: 8px; } QScrollBar::handle:vertical:focus { border: 1px solid #73C7FF; } QScrollBar::add-line:horizontal { margin: 0px 0px 0px 0px; border-image: url(":/qss_icons/light/rc/arrow_right_disabled.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { border-image: url(":/qss_icons/light/rc/arrow_right.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { border-image: url(":/qss_icons/light/rc/arrow_down.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { margin: 0px 3px 0px 3px; border-image: url(":/qss_icons/light/rc/arrow_left_disabled.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { border-image: url(":/qss_icons/light/rc/arrow_left.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/light/rc/arrow_up_disabled.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { border-image: url(":/qss_icons/light/rc/arrow_up.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { background: none; } QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { background: none; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } /* QTextEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets --------------------------------------------------------------------------- */ QTextEdit { background-color: #FAFAFA; color: #19232D; border-radius: 4px; border: 1px solid #C0C4C8; } QTextEdit:focus { border: 1px solid #73C7FF; } QTextEdit:selected { background: #9FCBFF; color: #C0C4C8; } /* QPlainTextEdit --------------------------------------------------------- --------------------------------------------------------------------------- */ QPlainTextEdit { background-color: #FAFAFA; color: #19232D; border-radius: 4px; border: 1px solid #C0C4C8; } QPlainTextEdit:focus { border: 1px solid #73C7FF; } QPlainTextEdit:selected { background: #9FCBFF; color: #C0C4C8; } /* QSizeGrip -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip --------------------------------------------------------------------------- */ QSizeGrip { background: transparent; width: 12px; height: 12px; image: url(":/qss_icons/light/rc/window_grip.png"); } /* QStackedWidget --------------------------------------------------------- --------------------------------------------------------------------------- */ QStackedWidget { padding: 2px; border: 1px solid #C0C4C8; border: 1px solid #FAFAFA; } /* QToolBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar --------------------------------------------------------------------------- */ QToolBar { background-color: #C0C4C8; border-bottom: 1px solid #FAFAFA; padding: 1px; font-weight: bold; spacing: 2px; } QToolBar:disabled { /* Fixes #272 */ background-color: #C0C4C8; } QToolBar::handle:horizontal { width: 16px; image: url(":/qss_icons/light/rc/toolbar_move_horizontal.png"); } QToolBar::handle:vertical { height: 16px; image: url(":/qss_icons/light/rc/toolbar_move_vertical.png"); } QToolBar::separator:horizontal { width: 16px; image: url(":/qss_icons/light/rc/toolbar_separator_horizontal.png"); } QToolBar::separator:vertical { height: 16px; image: url(":/qss_icons/light/rc/toolbar_separator_vertical.png"); } QToolButton#qt_toolbar_ext_button { background: #C0C4C8; border: 0px; color: #19232D; image: url(":/qss_icons/light/rc/arrow_right.png"); } /* QAbstractSpinBox ------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractSpinBox { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; border-radius: 4px; /* min-width: 5px; removed to fix 109 */ } QAbstractSpinBox:up-button { background-color: transparent #FAFAFA; subcontrol-origin: border; subcontrol-position: top right; border-left: 1px solid #C0C4C8; border-bottom: 1px solid #C0C4C8; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-bottom: -1px; } QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { image: url(":/qss_icons/light/rc/arrow_up_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::up-arrow:hover { image: url(":/qss_icons/light/rc/arrow_up.png"); } QAbstractSpinBox:down-button { background-color: transparent #FAFAFA; subcontrol-origin: border; subcontrol-position: bottom right; border-left: 1px solid #C0C4C8; border-top: 1px solid #C0C4C8; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-top: -1px; } QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::down-arrow:hover { image: url(":/qss_icons/light/rc/arrow_down.png"); } QAbstractSpinBox:hover { border: 1px solid #9FCBFF; color: #19232D; } QAbstractSpinBox:focus { border: 1px solid #73C7FF; } QAbstractSpinBox:selected { background: #9FCBFF; color: #C0C4C8; } /* ------------------------------------------------------------------------ */ /* DISPLAYS --------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QLabel ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe --------------------------------------------------------------------------- */ QLabel { background-color: #FAFAFA; border: 0px solid #C0C4C8; padding: 2px; margin: 0px; color: #19232D; } QLabel:disabled { background-color: #FAFAFA; border: 0px solid #C0C4C8; color: #9DA9B5; } /* QTextBrowser ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QTextBrowser { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; } QTextBrowser:disabled { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #9DA9B5; border-radius: 4px; } QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { border: 1px solid #C0C4C8; } /* QGraphicsView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QGraphicsView { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; } QGraphicsView:disabled { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #9DA9B5; border-radius: 4px; } QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { border: 1px solid #C0C4C8; } /* QCalendarWidget -------------------------------------------------------- --------------------------------------------------------------------------- */ QCalendarWidget { border: 1px solid #C0C4C8; border-radius: 4px; } QCalendarWidget:disabled { background-color: #FAFAFA; color: #9DA9B5; } /* QLCDNumber ------------------------------------------------------------- --------------------------------------------------------------------------- */ QLCDNumber { background-color: #FAFAFA; color: #19232D; } QLCDNumber:disabled { background-color: #FAFAFA; color: #9DA9B5; } /* QProgressBar ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar --------------------------------------------------------------------------- */ QProgressBar { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; text-align: center; } QProgressBar:disabled { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #9DA9B5; border-radius: 4px; text-align: center; } QProgressBar::chunk { background-color: #9FCBFF; color: #FAFAFA; border-radius: 4px; } QProgressBar::chunk:disabled { background-color: #DAEDFF; color: #9DA9B5; border-radius: 4px; } /* ------------------------------------------------------------------------ */ /* BUTTONS ---------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QPushButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton --------------------------------------------------------------------------- */ QPushButton { background-color: #C0C4C8; color: #19232D; border-radius: 4px; padding: 2px; outline: none; border: none; } QPushButton:disabled { background-color: #C0C4C8; color: #9DA9B5; border-radius: 4px; padding: 2px; } QPushButton:checked { background-color: #ACB1B6; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:disabled { background-color: #ACB1B6; color: #9DA9B5; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:selected { background: #ACB1B6; } QPushButton:hover { background-color: #B4B8BC; color: #19232D; } QPushButton:pressed { background-color: #ACB1B6; } QPushButton:selected { background: #ACB1B6; color: #19232D; } QPushButton::menu-indicator { subcontrol-origin: padding; subcontrol-position: bottom right; bottom: 4px; } QDialogButtonBox QPushButton { /* Issue #194 #248 - Special case of QPushButton inside dialogs, for better UI */ min-width: 80px; } /* QToolButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton --------------------------------------------------------------------------- */ QToolButton { background-color: #C0C4C8; color: #19232D; border-radius: 4px; padding: 2px; outline: none; border: none; /* The subcontrols below are used only in the DelayedPopup mode */ /* The subcontrols below are used only in the MenuButtonPopup mode */ /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ } QToolButton:disabled { background-color: #C0C4C8; color: #9DA9B5; border-radius: 4px; padding: 2px; } QToolButton:checked { background-color: #ACB1B6; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:disabled { background-color: #ACB1B6; color: #9DA9B5; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:hover { background-color: #B4B8BC; color: #19232D; } QToolButton:checked:pressed { background-color: #ACB1B6; } QToolButton:checked:selected { background: #ACB1B6; color: #19232D; } QToolButton:hover { background-color: #B4B8BC; color: #19232D; } QToolButton:pressed { background-color: #ACB1B6; } QToolButton:selected { background: #ACB1B6; color: #19232D; } QToolButton[popupMode="0"] { /* Only for DelayedPopup */ padding-right: 2px; } QToolButton[popupMode="1"] { /* Only for MenuButtonPopup */ padding-right: 20px; } QToolButton[popupMode="1"]::menu-button { border: none; } QToolButton[popupMode="1"]::menu-button:hover { border: none; border-left: 1px solid #C0C4C8; border-radius: 0; } QToolButton[popupMode="2"] { /* Only for InstantPopup */ padding-right: 2px; } QToolButton::menu-button { padding: 2px; border-radius: 4px; width: 12px; border: none; outline: none; } QToolButton::menu-button:hover { border: 1px solid #9FCBFF; } QToolButton::menu-button:checked:hover { border: 1px solid #9FCBFF; } QToolButton::menu-indicator { image: url(":/qss_icons/light/rc/arrow_down.png"); height: 8px; width: 8px; top: 0; /* Exclude a shift for better image */ left: -2px; /* Shift it a bit */ } QToolButton::menu-arrow { image: url(":/qss_icons/light/rc/arrow_down.png"); height: 8px; width: 8px; } QToolButton::menu-arrow:hover { image: url(":/qss_icons/light/rc/arrow_down_focus.png"); } /* QCommandLinkButton ----------------------------------------------------- --------------------------------------------------------------------------- */ QCommandLinkButton { background-color: transparent; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; padding: 0px; margin: 0px; } QCommandLinkButton:disabled { background-color: transparent; color: #9DA9B5; } /* ------------------------------------------------------------------------ */ /* INPUTS - NO FIELDS ----------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QComboBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QComboBox { border: 1px solid #C0C4C8; border-radius: 4px; selection-background-color: #9FCBFF; padding-left: 4px; padding-right: 4px; /* padding-right = 36; 4 + 16*2 See scrollbar size */ /* changed to 4px to fix #239 */ /* Fixes #103, #111 */ min-height: 1.5em; /* padding-top: 2px; removed to fix #132 */ /* padding-bottom: 2px; removed to fix #132 */ /* min-width: 75px; removed to fix #109 */ /* Needed to remove indicator - fix #132 */ } QComboBox QAbstractItemView { border: 1px solid #C0C4C8; border-radius: 0; background-color: #FAFAFA; selection-background-color: #9FCBFF; } QComboBox QAbstractItemView:hover { background-color: #FAFAFA; color: #19232D; } QComboBox QAbstractItemView:selected { background: #9FCBFF; color: #C0C4C8; } QComboBox QAbstractItemView:alternate { background: #FAFAFA; } QComboBox:disabled { background-color: #FAFAFA; color: #9DA9B5; } QComboBox:hover { border: 1px solid #9FCBFF; } QComboBox:focus { border: 1px solid #73C7FF; } QComboBox:on { selection-background-color: #9FCBFF; } QComboBox::item { /* Remove to fix #282, #285 and MR #288*/ /*&:checked { font-weight: bold; } &:selected { border: 0px solid transparent; } */ } QComboBox::item:alternate { background: #FAFAFA; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #C0C4C8; } QComboBox::down-arrow { image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { image: url(":/qss_icons/light/rc/arrow_down.png"); } /* QSlider ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider --------------------------------------------------------------------------- */ QSlider:disabled { background: #FAFAFA; } QSlider:focus { border: none; } QSlider::groove:horizontal { background: #C0C4C8; border: 1px solid #C0C4C8; height: 4px; margin: 0px; border-radius: 4px; } QSlider::groove:vertical { background: #C0C4C8; border: 1px solid #C0C4C8; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical { background: #9FCBFF; border: 1px solid #C0C4C8; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical :disabled { background: #DAEDFF; } QSlider::sub-page:horizontal { background: #9FCBFF; border: 1px solid #C0C4C8; height: 4px; margin: 0px; border-radius: 4px; } QSlider::sub-page:horizontal:disabled { background: #DAEDFF; } QSlider::handle:horizontal { background: #788D9C; border: 1px solid #C0C4C8; width: 8px; height: 8px; margin: -8px 0px; border-radius: 4px; } QSlider::handle:horizontal:hover { background: #9FCBFF; border: 1px solid #9FCBFF; } QSlider::handle:horizontal:focus { border: 1px solid #73C7FF; } QSlider::handle:vertical { background: #788D9C; border: 1px solid #C0C4C8; width: 8px; height: 8px; margin: 0 -8px; border-radius: 4px; } QSlider::handle:vertical:hover { background: #9FCBFF; border: 1px solid #9FCBFF; } QSlider::handle:vertical:focus { border: 1px solid #73C7FF; } /* QLineEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit --------------------------------------------------------------------------- */ QLineEdit { background-color: #FAFAFA; padding-top: 2px; /* This QLineEdit fix 103, 111 */ padding-bottom: 2px; /* This QLineEdit fix 103, 111 */ padding-left: 4px; padding-right: 4px; border-style: solid; border: 1px solid #C0C4C8; border-radius: 4px; color: #19232D; } QLineEdit:disabled { background-color: #FAFAFA; color: #9DA9B5; } QLineEdit:hover { border: 1px solid #9FCBFF; color: #19232D; } QLineEdit:focus { border: 1px solid #73C7FF; } QLineEdit:selected { background-color: #9FCBFF; color: #C0C4C8; } /* QTabWiget -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabWidget { padding: 2px; selection-background-color: #C0C4C8; } QTabWidget QWidget { /* Fixes #189 */ border-radius: 4px; } QTabWidget::pane { border: 1px solid #C0C4C8; border-radius: 4px; margin: 0px; /* Fixes double border inside pane with pyqt5 */ padding: 0px; } QTabWidget::pane:selected { background-color: #C0C4C8; border: 1px solid #9FCBFF; } /* QTabBar ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabBar, QDockWidget QTabBar { qproperty-drawBase: 0; border-radius: 4px; margin: 0px; padding: 2px; border: 0; /* left: 5px; move to the right by 5px - removed for fix */ } QTabBar::close-button, QDockWidget QTabBar::close-button { border: 0; margin: 0; padding: 4px; image: url(":/qss_icons/light/rc/window_close.png"); } QTabBar::close-button:hover, QDockWidget QTabBar::close-button:hover { image: url(":/qss_icons/light/rc/window_close_focus.png"); } QTabBar::close-button:pressed, QDockWidget QTabBar::close-button:pressed { image: url(":/qss_icons/light/rc/window_close_pressed.png"); } QTabBar::tab, QDockWidget QTabBar::tab { /* !selected and disabled ----------------------------------------- */ /* selected ------------------------------------------------------- */ } QTabBar::tab:top:selected:disabled, QDockWidget QTabBar::tab:top:selected:disabled { border-bottom: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:bottom:selected:disabled, QDockWidget QTabBar::tab:bottom:selected:disabled { border-top: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:left:selected:disabled, QDockWidget QTabBar::tab:left:selected:disabled { border-right: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:disabled { border-left: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled { border-bottom: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled { border-top: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled { border-right: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled { border-left: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected { border-bottom: 2px solid #FAFAFA; margin-top: 2px; } QTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected { border-top: 2px solid #FAFAFA; margin-bottom: 2px; } QTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected { border-left: 2px solid #FAFAFA; margin-right: 2px; } QTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected { border-right: 2px solid #FAFAFA; margin-left: 2px; } QTabBar::tab:top, QDockWidget QTabBar::tab:top { background-color: #C0C4C8; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; min-width: 5px; border-bottom: 3px solid #C0C4C8; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:selected, QDockWidget QTabBar::tab:top:selected { background-color: #B4B8BC; border-bottom: 3px solid #37AEFE; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:!selected:hover, QDockWidget QTabBar::tab:top:!selected:hover { border: 1px solid #73C7FF; border-bottom: 3px solid #73C7FF; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom { border-top: 3px solid #C0C4C8; background-color: #C0C4C8; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; min-width: 5px; } QTabBar::tab:bottom:selected, QDockWidget QTabBar::tab:bottom:selected { background-color: #B4B8BC; border-top: 3px solid #37AEFE; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } QTabBar::tab:bottom:!selected:hover, QDockWidget QTabBar::tab:bottom:!selected:hover { border: 1px solid #73C7FF; border-top: 3px solid #73C7FF; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:left, QDockWidget QTabBar::tab:left { background-color: #C0C4C8; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-left-radius: 4px; border-bottom-left-radius: 4px; min-height: 5px; } QTabBar::tab:left:selected, QDockWidget QTabBar::tab:left:selected { background-color: #B4B8BC; border-right: 3px solid #37AEFE; } QTabBar::tab:left:!selected:hover, QDockWidget QTabBar::tab:left:!selected:hover { border: 1px solid #73C7FF; border-right: 3px solid #73C7FF; /* Fixes different behavior #271 */ margin-right: 0px; padding-right: -1px; } QTabBar::tab:right, QDockWidget QTabBar::tab:right { background-color: #C0C4C8; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; min-height: 5px; } QTabBar::tab:right:selected, QDockWidget QTabBar::tab:right:selected { background-color: #B4B8BC; border-left: 3px solid #37AEFE; } QTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hover { border: 1px solid #73C7FF; border-left: 3px solid #73C7FF; /* Fixes different behavior #271 */ margin-left: 0px; padding-left: 0px; } QTabBar QToolButton, QDockWidget QTabBar QToolButton { /* Fixes #136 */ background-color: #C0C4C8; height: 12px; width: 12px; } QTabBar QToolButton:pressed, QDockWidget QTabBar QToolButton:pressed { background-color: #C0C4C8; } QTabBar QToolButton:pressed:hover, QDockWidget QTabBar QToolButton:pressed:hover { border: 1px solid #9FCBFF; } QTabBar QToolButton::left-arrow:enabled, QDockWidget QTabBar QToolButton::left-arrow:enabled { image: url(":/qss_icons/light/rc/arrow_left.png"); } QTabBar QToolButton::left-arrow:disabled, QDockWidget QTabBar QToolButton::left-arrow:disabled { image: url(":/qss_icons/light/rc/arrow_left_disabled.png"); } QTabBar QToolButton::right-arrow:enabled, QDockWidget QTabBar QToolButton::right-arrow:enabled { image: url(":/qss_icons/light/rc/arrow_right.png"); } QTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::right-arrow:disabled { image: url(":/qss_icons/light/rc/arrow_right_disabled.png"); } /* QDockWiget ------------------------------------------------------------- --------------------------------------------------------------------------- */ QDockWidget { outline: 1px solid #C0C4C8; background-color: #FAFAFA; border: 1px solid #C0C4C8; border-radius: 4px; titlebar-close-icon: url(":/qss_icons/light/rc/transparent.png"); titlebar-normal-icon: url(":/qss_icons/light/rc/transparent.png"); } QDockWidget::title { /* Better size for title bar */ padding: 3px; spacing: 4px; border: none; background-color: #C0C4C8; } QDockWidget::close-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/light/rc/window_close.png"); } QDockWidget::close-button:hover { image: url(":/qss_icons/light/rc/window_close_focus.png"); } QDockWidget::close-button:pressed { image: url(":/qss_icons/light/rc/window_close_pressed.png"); } QDockWidget::float-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/light/rc/window_undock.png"); } QDockWidget::float-button:hover { image: url(":/qss_icons/light/rc/window_undock_focus.png"); } QDockWidget::float-button:pressed { image: url(":/qss_icons/light/rc/window_undock_pressed.png"); } /* QTreeView QListView QTableView ----------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview --------------------------------------------------------------------------- */ QTreeView:branch:selected, QTreeView:branch:hover { background: url(":/qss_icons/light/rc/transparent.png"); } QTreeView:branch:has-siblings:!adjoins-item { border-image: url(":/qss_icons/light/rc/branch_line.png") 0; } QTreeView:branch:has-siblings:adjoins-item { border-image: url(":/qss_icons/light/rc/branch_more.png") 0; } QTreeView:branch:!has-children:!has-siblings:adjoins-item { border-image: url(":/qss_icons/light/rc/branch_end.png") 0; } QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { border-image: none; image: url(":/qss_icons/light/rc/branch_closed.png"); } QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { border-image: none; image: url(":/qss_icons/light/rc/branch_open.png"); } QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { image: url(":/qss_icons/light/rc/branch_closed_focus.png"); } QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { image: url(":/qss_icons/light/rc/branch_open_focus.png"); } QTreeView::indicator:checked, QListView::indicator:checked, QTableView::indicator:checked, QColumnView::indicator:checked { image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, QListView::indicator:checked:hover, QListView::indicator:checked:focus, QListView::indicator:checked:pressed, QTableView::indicator:checked:hover, QTableView::indicator:checked:focus, QTableView::indicator:checked:pressed, QColumnView::indicator:checked:hover, QColumnView::indicator:checked:focus, QColumnView::indicator:checked:pressed { image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QTreeView::indicator:unchecked, QListView::indicator:unchecked, QTableView::indicator:unchecked, QColumnView::indicator:unchecked { image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, QListView::indicator:unchecked:hover, QListView::indicator:unchecked:focus, QListView::indicator:unchecked:pressed, QTableView::indicator:unchecked:hover, QTableView::indicator:unchecked:focus, QTableView::indicator:unchecked:pressed, QColumnView::indicator:unchecked:hover, QColumnView::indicator:unchecked:focus, QColumnView::indicator:unchecked:pressed { image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QTreeView::indicator:indeterminate, QListView::indicator:indeterminate, QTableView::indicator:indeterminate, QColumnView::indicator:indeterminate { image: url(":/qss_icons/light/rc/checkbox_indeterminate.png"); } QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, QListView::indicator:indeterminate:hover, QListView::indicator:indeterminate:focus, QListView::indicator:indeterminate:pressed, QTableView::indicator:indeterminate:hover, QTableView::indicator:indeterminate:focus, QTableView::indicator:indeterminate:pressed, QColumnView::indicator:indeterminate:hover, QColumnView::indicator:indeterminate:focus, QColumnView::indicator:indeterminate:pressed { image: url(":/qss_icons/light/rc/checkbox_indeterminate_focus.png"); } QTreeView, QListView, QTableView, QColumnView { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; gridline-color: #C0C4C8; border-radius: 4px; } QTreeView:disabled, QListView:disabled, QTableView:disabled, QColumnView:disabled { background-color: #FAFAFA; color: #9DA9B5; } QTreeView:selected, QListView:selected, QTableView:selected, QColumnView:selected { background-color: #9FCBFF; color: #C0C4C8; } QTreeView:focus, QListView:focus, QTableView:focus, QColumnView:focus { border: 1px solid #73C7FF; } QTreeView::item:pressed, QListView::item:pressed, QTableView::item:pressed, QColumnView::item:pressed { background-color: #9FCBFF; } QTreeView::item:selected:active, QListView::item:selected:active, QTableView::item:selected:active, QColumnView::item:selected:active { background-color: #9FCBFF; } QTreeView::item:selected:!active, QListView::item:selected:!active, QTableView::item:selected:!active, QColumnView::item:selected:!active { color: #19232D; background-color: #D2D5D8; } QTreeView::item:!selected:hover, QListView::item:!selected:hover, QTableView::item:!selected:hover, QColumnView::item:!selected:hover { outline: 0; color: #19232D; background-color: #D2D5D8; } QTableCornerButton::section { background-color: #FAFAFA; border: 1px transparent #C0C4C8; border-radius: 0px; } /* QHeaderView ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview --------------------------------------------------------------------------- */ QHeaderView { background-color: #C0C4C8; border: 0px transparent #C0C4C8; padding: 0; margin: 0; border-radius: 0; } QHeaderView:disabled { background-color: #C0C4C8; border: 1px transparent #C0C4C8; } QHeaderView::section { background-color: #C0C4C8; color: #19232D; border-radius: 0; text-align: left; font-size: 13px; } QHeaderView::section::horizontal { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-left: 1px solid #FAFAFA; } QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { border-left: 1px solid #C0C4C8; } QHeaderView::section::horizontal:disabled { color: #9DA9B5; } QHeaderView::section::vertical { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-top: 1px solid #FAFAFA; } QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { border-top: 1px solid #C0C4C8; } QHeaderView::section::vertical:disabled { color: #9DA9B5; } QHeaderView::down-arrow { /* Those settings (border/width/height/background-color) solve bug */ /* transparent arrow background and size */ background-color: #C0C4C8; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/light/rc/arrow_down.png"); } QHeaderView::up-arrow { background-color: #C0C4C8; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/light/rc/arrow_up.png"); } /* QToolBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox --------------------------------------------------------------------------- */ QToolBox { padding: 0px; border: 0px; border: 1px solid #C0C4C8; } QToolBox:selected { padding: 0px; border: 2px solid #9FCBFF; } QToolBox::tab { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-top-left-radius: 4px; border-top-right-radius: 4px; } QToolBox::tab:disabled { color: #9DA9B5; } QToolBox::tab:selected { background-color: #ACB1B6; border-bottom: 2px solid #9FCBFF; } QToolBox::tab:selected:disabled { background-color: #C0C4C8; border-bottom: 2px solid #DAEDFF; } QToolBox::tab:!selected { background-color: #C0C4C8; border-bottom: 2px solid #C0C4C8; } QToolBox::tab:!selected:disabled { background-color: #FAFAFA; } QToolBox::tab:hover { border-color: #73C7FF; border-bottom: 2px solid #73C7FF; } QToolBox QScrollArea { padding: 0px; border: 0px; background-color: #FAFAFA; } /* QFrame ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe https://doc.qt.io/qt-5/qframe.html#-prop https://doc.qt.io/qt-5/qframe.html#details https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color --------------------------------------------------------------------------- */ /* (dot) .QFrame fix #141, #126, #123 */ .QFrame { border-radius: 4px; border: 1px solid #C0C4C8; /* No frame */ /* HLine */ /* HLine */ } .QFrame[frameShape="0"] { border-radius: 4px; border: 1px transparent #C0C4C8; } .QFrame[frameShape="4"] { max-height: 2px; border: none; background-color: #C0C4C8; } .QFrame[frameShape="5"] { max-width: 2px; border: none; background-color: #C0C4C8; } /* QSplitter -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter --------------------------------------------------------------------------- */ QSplitter { background-color: #C0C4C8; spacing: 0px; padding: 0px; margin: 0px; } QSplitter::handle { background-color: #C0C4C8; border: 0px solid #FAFAFA; spacing: 0px; padding: 1px; margin: 0px; } QSplitter::handle:hover { background-color: #788D9C; } QSplitter::handle:horizontal { width: 5px; image: url(":/qss_icons/light/rc/line_vertical.png"); } QSplitter::handle:vertical { height: 5px; image: url(":/qss_icons/light/rc/line_horizontal.png"); } /* QDateEdit, QDateTimeEdit ----------------------------------------------- --------------------------------------------------------------------------- */ QDateEdit, QDateTimeEdit { selection-background-color: #9FCBFF; border-style: solid; border: 1px solid #C0C4C8; border-radius: 4px; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; min-width: 10px; } QDateEdit:on, QDateTimeEdit:on { selection-background-color: #9FCBFF; } QDateEdit::drop-down, QDateTimeEdit::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #C0C4C8; } QDateEdit::down-arrow, QDateTimeEdit::down-arrow { image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus { image: url(":/qss_icons/light/rc/arrow_down.png"); } QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { background-color: #FAFAFA; border-radius: 4px; border: 1px solid #C0C4C8; selection-background-color: #9FCBFF; } /* QAbstractView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractView:hover { border: 1px solid #9FCBFF; color: #19232D; } QAbstractView:selected { background: #9FCBFF; color: #C0C4C8; } /* PlotWidget ------------------------------------------------------------- --------------------------------------------------------------------------- */ PlotWidget { /* Fix cut labels in plots #134 */ padding: 0px; } seer-2.7/src/resources/qdarkstyle/light/rc/000077500000000000000000000000001516472651200210305ustar00rootroot00000000000000seer-2.7/src/resources/qdarkstyle/light/rc/.keep000066400000000000000000000000021516472651200217450ustar00rootroot00000000000000 seer-2.7/src/resources/qdarkstyle/light/rc/arrow_down.png000066400000000000000000000010501516472651200237130ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX=kQsg!BXq &0 -lcc H?_`P,,1XX:,b& NNvleMv`yιιw I'f͵+&]R߰tzev8%.½yWzxSGrfG+ Kys=|ުDK8R=K'WѲZ*\:YٮdC$?F T-,Pr : ^_}%L\m,@lhiAvy:h"mn*~b VG'~oO@u)ˡtFYkI֪.hyᚠj:TNhu"K0K8l*qZ\VCg^0ȥz`@ +ߞ.7?ydw%k/0[AN33 )Z;˻NJ¤jj*_JFS5heH+|Ko߆?b%G h sSW0Kw$z x}^Fe}'J|Ld_2 @[ 068+t{I "EG[ ܈5:q?HL#?Z>Kv=6:BY&i+E0ܙfs$/vl`Q"߯ceg^WU*V8gG{YqT8yh!&,#כo}Gd2Aɥ'68){5R>sƩZ\;DWo~[ͱv~XGwTV-WZŅ;{zw<U\*vbX,bX,byh(׮IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_down_disabled.png000066400000000000000000000010351516472651200255450ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX?kSQϵ M,t ĥ 4$I'RZĂ-yr].ys{0 fvώDN]]^pl'] q2zMfHw>z2:Rgh6G=JC9 ىyyrؽL&֝3mV$5歼=rxڍNB=>kmϝ+I'}uv#jʓܥmW3]3d.vYD/zi}JcB+(¸sHV~trm^Ǒ,;XMJOw6w^) oVta9p&Y(ӠZCtj:#_# j(ī-@DXIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_down_disabled@2x.png000066400000000000000000000020251516472651200261170ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOh\UsgAt;Z]'3_^*MAJ+Ѫ("b7)Zn\I]XΘڝШI3s1{Lyoy=wx<x<YXBm~=I93%ff4nl&FnhK.mK2D)n*&9w*BugD7@ yJz*03[vtk!u#O*-=hu1 ŷHx/T{RpH;NM80''5DOy: 55u!\r䵤FSGhd%q`&EeJI4GJ?V*@j}-[7au0ױ V5w(ZWctG4̲/¦HhߗOLNNؕ!jSɔc2 K?yt2}/40mfoGO>8asd&vb^ T~mGyq'un7H ҙn1..RJӚej$ì?<\͑/:yȠ_frԚb%Y㲋7Jed9X37vNR!hnӭ}`U'bzV1fr(:03,NIkGL2.lkDž>'%z೸lEY7 N?{F( 'l(e~08,_{ǶàS[|I%!^?v,gP]y)㕨\bx<x<Iz[Gy.fIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_down_focus.png000066400000000000000000000010131516472651200251110ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXKTQϙ>t:B\JZ. hB.ҦEK]$-[ز\9);` 0m3cwf\8<9=2222N%BP)< S_E]q ^UcƱ|FkXX/oM`eba+:n!xF׋[M5#Ю:3P6?o,0ǕعyA2=&LB81C`f=Ej6x`s,uwLGlZT AK Lăjiev c@!!`r~ݮ:ܟGp\@hIc%C]?1?oah@*eS7z=k aEEN_^[2뗣Fr~q!ʋk*IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_down_focus@2x.png000066400000000000000000000017551516472651200255000ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOhTWƿsߤ"ҙJ aUME\KA R FkgtUv!vmu:ZMt2&ikмusߍ̼7m9μ{/((((<_ݐO  `|ʼn4F̗%?}W+Vxm^xO)'H(_Qf;#F9[ dƆA4%J^b, N4 /xْl"3ꧯIO_3yے ;ę-㙡CSs" [fZ K UGF:>h0'K%Lz$/Wz#qm^o XHh qR#a-K/t<[ @$5!\:LsRr/J~X3f}NPM@-K.rc |T3uʋ((((<#,;lgIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_down_pressed.png000066400000000000000000000007741516472651200254540ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX1kQ XX (٘NIl/@lҨ(VZ()Sv$2T4 3'llf5|0x9}%%%%njEwQ3af8_:E @HRM 3V\xaҎ#i>n_^ostB$U$Fcڮ3&3ӮQg\nT׹ylk4aZ_"3,k } s_h˱yGkͬV֍6'57&#bIyu/?3S*p*v9\m%=XazB YV-=/Ce%7^Z 7 eqjmw0uacgi]"9ߙ2/`uDo{hegB80'$*A8oto.QҴw"G ̦&olVzu:愬+d%E/s SIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_left@2x.png000066400000000000000000000020711516472651200242540ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMh\Ug2-E[u^l5DHn$VX( AXAp!7.,*1QfmDi?53 ]u{ݏw޼ꫯ*jT [Tt5B7cm RQdbirhr Q,JlvD @t ;Ems`F|Alv-o*S+\k8KT(͉C:<`T~V8<.VSx|1TW`㫆̎@T_S&=ܝ_]z@aW* P(g+&o^LVfO/Uσ=JpGWlʡ\vTx֭W1GLL~~᾿?r'^`V~M.vDsF<_uQ8=&D}O _nNWF+y ̛@wyzlX5c '[7Uxe#+Y]V*{XBE[  /eC.VkF\GrUPoK-#.6ېbWuevЏ҆i!q<a&H0yg?۝%U9z#!xۆ_.*r}sܘ 7+i';/HnjB&7q\yt_BQԘ{#d,C< x|yʼϠ44Nɯ{O ٣1('d7|Xn~Kw+H_tv!vh絓ۍa?e8-}o B}Qk IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_left_disabled.png000066400000000000000000000011001516472651200255210ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX嗿kSQ?J_Щi*BJ8)AE;tHEڴ;dDAR W\ z \4=ܷ{V?7zhwo ˙zC7(Vۏon0Wv`)}u pi3nO<`q{Up@ș̓_N!Hr/YYGj%̊{,1s2&>鞒6ErizπsA}(I{."oǍ\]>$1\0 PW4wzΔ4u0 «R2 3%̚(tYfQʌi2AyXUKN#xƫ1=pοlǛO$Af98rp5`W'F+_{/ݿhJ%cw7ť!IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_left_disabled@2x.png000066400000000000000000000022231516472651200261020ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+EIDATxOEg6 Eԓ(f'5ГQAT"‚F7J8;yt0l4^}ޫna.dXl }HϧE >D{9683;gώ|<$O$0w$u|+ɫ,K6I'HZe}[W5ovmE *$_z"$a`Hm"$mrN73!=`2˙!)C t >7JDgaf/*|772X{ڻ(EdqHvc.@۝0#&7gQZZӔV7CtN43FTZ ("8Ns*0|0)>[3u};h6$_[FEE.n{uvgo0b>e^[ȷq43Ljg` t{:b}b pi[}@Zh@sE=!E7ϩqQٓMwX[j1mzI@UEN'.(C$ @p)s]'Xc(6ť2]HP*Vu `C(̀Bi&ؚ*$yJt^rhOXv FgQkN%,K9vJ1f14@s9cc3ae2W+xBcC G~EO[ZLmڄzںek;('hn0ca 8S6"TsExn#PJ1'J7Bi~8UA$Xs^yh+ʑ_%xjz Hާ*|1 @e v(L]Z8$Pu6_f}ۿhef&:> u:b˺jj3IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_left_pressed.png000066400000000000000000000010211516472651200254210ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX喿kTA5h*.2&ŦJlBҋ -laIBy{,6[͠|sR|M]s)w=Q\էJ򄷈$wց `[)? l:D=X<@ (P<pE׳@+^ Uw # Pt}b8ϰA'> u=pIJ#^`mN#Gc'Ȫ`/h0@'JUX/2jr|Z]F2$oiGfa7 AK1mںZ;[rLeMƬff&jLf@}hz9%n+ a2}C$vxh= C?ڴoH_JWio_R): a.T/p_kr!OJO5xvz;:$[J` x/Baj܂_p, Bj q"BImo$| U72 cCpc&`jUC(mnߤ]k&+P{kN<* /D#k *z*Y[7C:TѴ'&JVSs!`Wʋ/ ^͘* 'oQ*3sG}{OfYwPp xde+iZP IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_right@2x.png000066400000000000000000000021131516472651200244340ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx_hWƿ3M[IA Jh; +hkEEVBA-|j)}PAK--AZJQ>(HKM6 :YD`ULTԹ7{\ao;}s;Zhby_NAu2_,L!SJ {xyLo 2S񱈘Rs`HR;>^05:R˜YLVtt1QpiVH0^G&@zIݢf A*~Ʋe,6%/ ς@ @9_췯tdG v!i >+-$J%0w~'kB@KXy[Cqq=ߔvA? 0䨿HHVyH߳5)Y0ެWKW$ d4a>67^@v,itww`SّhOޚh8hR&,yu-@_ bsX8A9<Twr5B`*q9@W 7)2xﱱsꑉ~453og-}EצV'49yS>} 5zrGPw&\=n=֘qXIob:&m:fInSwm*'@?nϸ0=0pqۊkjc2 8[5*"3$D찤 P˞Ix7v#e (z:QX;$(^ЃPf|eo2?5CYlzkp`%y6HO{ M#VfS 8^1V?wM@iLbD:<^٨lN,&+ mdUtqA cZՇϘ&>f̈nѢE +lIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_right_disabled.png000066400000000000000000000010661516472651200257170ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX=kQsnMA r!vcfG+m*)B~DZBVqXYVB~c1Y˙Z3g.z1ɢVQ5OIHyH7ؙ_{@DuZm9)/MN=  H4Zku6jom@HHGgvw)(#^7b c'qo\Aiͻ0 8Dn7Nq) k&+h]K VV|S<0ȥ[9sdTx &A. 8yWvQ+\ڼ9(n-]jO<H(r75$3j~#-Y5Ap`VW2KnkTw. Fv<Y2$}٨}5m4 2ٙ-1x0 3tė?qz r'[nQyEs3.3hn|yx"$ WZ (!=?wK唵L2S"sIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_right_focus.png000066400000000000000000000010361516472651200252640ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX햿kQ;ki2% )%MDmDwQHM )$bbiaHl-İw,fl93;< =wރ]eSo&lpx>L &CS}Um\08k^_T[p5UÐ.E1R*.A܎~v @܍E̥DkK}$&Eނ_DJWѥx7$)Ԋi{A,5 D23cO @rKvz?_Jp0Kɮ.߲eov̷\V!o8tm.Ỽ IH ZUIՂ} hxй>*j@ Iw0_Do&ݸS~ί_<1('Зj0XxegY+0SIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_right_focus@2x.png000066400000000000000000000021611516472651200256360ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+#IDATx_hUƿ3cڢݸ-W_b+CAm )(b >Dn6QDѧZJE;5EݥRm5;aSmfF{vXwη93@>}ψJ֋@#`hB&f@a ~$E 9]/Kމj6]B؅Aљ֨> h4LUS#o-nӨ#kVZd3A;zǤkPn"u0YhPkL 1q{w5u`Ɩ7AjA{E!>Y6_6,lx!S%^)UZ!MR%TƘ8.î"\@_Zj,F@0'lxi;lcGc܄Hbuƀə@lSۧnD/ ?;rl9c#\Zr0yni!Q-U6M&]1 1΁k?0Km:BP|]CB۱x )1rFܝM H?Sa9.wg@J ^Ym%N˙#C!OC•A =ĽD-c%/uŀ俎8pxIa $U ۂ{dZכİGj|m$GBY[Aj (a0@&Bb, r_ t 5{ y4ܗKtvanas y,Ɛr_jP_$Ӫw [R Q~1<`րn_Aݮ0i@|ŋg~ѠfX9 qϙ[~ 63rM Z]s$\ 5hE H<>/T{ i_fk/o}:J gӧOC8oVIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_right_pressed.png000066400000000000000000000010211516472651200256040ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXֽkA3+bRP #;{lxb?X0 8Kp JuGGCd1X^^g1)@`y!)c4DDjxG3;O T85@،ǒ$ŧ8wFSoè{'.5Qz 6B8ij[e`.0jy*}~V / 0ȿ{V{ / Ňm6#o An.Jq~._=uÈbKFqMm~QQ=fIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_right_pressed@2x.png000066400000000000000000000021121516472651200261600ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOh\E?߷mXH1,ڋJ)B| )(b *fKiS-b%EZCn = ;yHKͼHҙyoB>}WCSm{E ͺ&|oZm 9ӾE!-3>ku_›Dy2HO&v`Xk8ٚur>tYHY0K93NX1>ˎtB:/_JxpF2|BFnra:\BX˖w%6Hn_[{t!V0ti]_Ĭ EM:s,y1k&f-W8@"TOSiCĪ%5Dӌ҆ލUCQH9o4Gʿ&|T1y.f~w|xvVd~}ȣ L sglۤeX jl۠#-[7Y+ף9I:^wr< \6^ח2+pN͆ 2 6' "v~QIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_up.png000066400000000000000000000010211516472651200233660ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXkA7D(ҤmY ^= ?woz@z'xDVkag߼abbbb:qf%yH$r_>%TatݽŠ_rK]B /W.UϯU@(U+")6QvH }6Nbewg GRfm꤈<1?i>,],=y ^ePp/=5stn* bEwb%V/* O]gX\L[;r9 Hx[C7ݜH=^Uo15V0d8Mo6g˓$onh#!{״l4>~HC:IЬH`k=&(bK# \1vR~*[6IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_up@2x.png000066400000000000000000000017461516472651200237560ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxKhQG0L3Ѷ: R4*P[pƅJq%+7*SW-ZP(>E⫴s]$d֤ ɹ{\0 0 0 0 04SK8?2LĤ8%~!]'t"Núvo|.L=4"Z C`B>wYc@*S|mݘCbrE?YmihtoUQa%x$]NfnsՀ`<hnb$d~rNo\1@Xe Gk ~)9LyӰp}֨WEIp6d2?nڻZ[n (֖e&oC]Wcblomޖ#\Ӏw 0 Evx!.mSFҹ"Y4Ir1} B-J$+A}d:XP@4%Ho`P)YhUҞP2m6d@QBՒ〘 ܇&FUYQY bN`vsaaaa6q(IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_up_disabled.png000066400000000000000000000010221516472651200252160ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX픿jQgv,6ZI*L!f#Sڈ +#|ABAffr{,ٽ&:lb3\8p|{\TR,+Y9-.Zexeޅ 0ON釋+ Ê9/َDIfrmଁFA9$[;06@[)0n3p`Xmmiﶙ^ @ |aÓ^Dig@0pujžGi^iI%G;|Zmq>5!ɋln^dNHjg63I^ޯ'WW/?;`0Կ|yIoL*^x `w&@?c&P|CF ̈LWE݅K_qш1-u7=M~N ӭRJ/{%UIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_up_disabled@2x.png000066400000000000000000000020151516472651200255730ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx혿oEƟDTX6JIې$oQ鐡T@PEnjT 1"7  HZĉ>}||gx<x<ÚT/!qsaem.Vt-J  ,mIج'.Cߟ;{ I B@ 昛}_A賴`'G:LRЃAS__ j4p @&nrFRR8ƾ3cEvjgSH~FRmw0;;K?tŀJe&kFAr{i uaӼ87wnZ37\>@<]|FIʸ`f,fj@is&]W> a¯3ۇS/]7^:ų@H f}g121V/p,C pLRT/CP~ `{юu\@}V^>Dz4_CI*+I)&ڰj'=XkL<^:!#[JbD;?s^6Zu""f򩐔d¹O߿

1TȴjNd? ۴^\NvIJJJq&ї4 IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_up_focus@2x.png000066400000000000000000000017541516472651200251540ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx?lSWƿs"JCml{"aFN2UB-lHB S#E*mTT&vLVJw6`?خFw=X,bX,b^vmJW/컴:ŀW!$@=Bάdߚ[jHx)ҧq뉯Hq>n^w"CV,2QxA|g)xY*Uo>LlZ3MARWU9_ϿO?Հ?Pm'#D :"ſPe0Ih*_}ZWs er= #2ҹb("ЦhHbH+'&\tJ'g͝єWz:z6 A|`WcD4z)uv6mLxO~eMz֣u3+}jsضQtDIL<)N7ipEQdn0dYc|88 8tL'?ϭ}>t ( }[#cm,Kd H Z9 BiBXl' !W#Oڥ5`l0*" GB0ΐ(S[?9BT!2 6DB M9jby:U`&W>N 6/;xz0@tc4laX~Vz aV|dXQ/qSJ+˗ )CPͮfh`^ 0b5  W>rkY,bX,bX^k0+>%IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/arrow_up_pressed.png000066400000000000000000000007731516472651200251300ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX픿kAw/h4ʁbJ "O0r{!J@,P$F+""Z޹z zٙg]((((8bw{2o0c%}S'ʳ)Pf ?k|Z=w c[LL_F/z@8b 1,0g"Pmx*pJ†CVkUZ-Ao-Z ,Z @) E[d]ಙib@Gt9.] cN;h5Ķm3o25'zs#=FCD.@T,`0=#Hl}i =gCW|[kbY^l&%&FϢaTёRUcf<P30#shpfNa]ټԌEZexq{ӸULDqL˾¦x|AN+ص  J\p`s'x %c)9Oqf$B8d;(R˵\Hh9"mĻJcsA0Dz#VCu ӵ#ul!50SI /Im]tHIο X-<6x!hJXx%AIg?7_as)< ,IB ȼ Rb\ Hs= f=1ChLc @P ޹2 56{ʍ|`{3^$?aRI=ǽ{c0KNY Ul0!M=5LxF[RJx5=sO>kϖQW mg0}2'}OFnߘU)-u yb۾;D ߭;9`pS4XKoj6BJI!; 2v;C$43#!a8v%,:yK8Iu5 Q/?s~@~S*7l_ c->g"6LW61'!nIw<{tAP!{ƻw,mjn@x|$o6`- <6wg|l$sE1 A-te}r1m +3o2y0qzu0n}Ԏjg 5ip} l5;&Tk|;2OIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/base_icon@2x.png000066400000000000000000000063261516472651200240410ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[o[%E(dNA&EѠH }{}*PA6NR iƖl7]HI.a3$wmx@xMBW<n%`2/m fbȘsgwܩ*ϣ5d =^9.Y> 4?4T%pP9mS mh}){q1oR- @V1k Fȼ=r̀#,1@6GU )_ȟ\6Hh?'[sr<%yFuK-2O ?ڼ00kLN`YN{Iϥq'lPcmc*}M|^y^dV7dkg#&ɂq&> 'ʣ!py *_d xZЗ< O*h(])704PZl/T,J4xF % 2]~|̠"ٌ $76]?Q5]|r ΏB}oGE`5{҆ ԟX~π瀷<{U[&[Y)^|)FL.rF?7Yx=kU~ x+Q@ɘ ] aSS7檛uO}ցs"Gp1z[1Y!W< Rq7n==z)NX-%8W/FL)0w}қW M%V;.Hxf:VGc/gcXy .*PF) Kt桞?>NyR9d]<$+z r-fn%b]`&t p CmM@%NCGٿRՓN}k6 ckB[: M,۾UU2o3ն20+c:d"+ |ພH1CX+ tf-*TW%yLZEK'%C4s2yTg~8FWcw2h_.z;gCdlO)ᱩJo -l7 GihnOĩ/ gR'_r'HeH .( GF{e%򐜳:Qxa? 7N|j|XߺV$4 1.{i C`GZ(;06<<ׅ|5r U0AqTw^ndb! Q\=pei?ȴP{f! $ 2b}4s֎zOuG&Gpy#7ճmFXB(@۳.Q@Qa([9Hr9my"')Ibt|2z <gCYsOp`<8ٍ\`-a< š8 2WVoe_n0+$˄:>8m ]_mg0ۿ BhF$VN-h,%F?mnd_82%^(Ιew1,S|Yp*rA8OW8sc*N-t.SNxEfm8Omfa.N&SOpA4ptɺ+rJKU\8/Ώ]I#<(v4_T}DV 6'h92Z']EǗ N=/a!5VM%{SLk'f;gB ¶7oVCܨF0}~REh ȻNJ>dC #Nफ)%̠)yŸ n"@LI LzЪθV] eݪc{2_*n(X@ ܞnyy(F $?w |HUѧ0'Q9hv@f%i.u6TTf"NT죵? hF%&]&eTyv%e،3w WZÿFfBx'P=R" [_h$I !{f3e/Ko#|< Ɨ{Ft=!тE+e߾ bgSŭ}L9q̏B;'S._Zf}DI2P.Z\̲^/L{aBC:f{̉CψCW+DONF^J^땙䝟@1=+DqL˾¦x|AN+ص  J\p`s'x %c)9Oqf$B8d;(R˵\Hh9"mĻJcsA0Dz#VCu ӵ#ul!50SI /Im]tHIο X-<6x!hJXx%AIg?7_as)< ,IB ȼ Rb\ Hs= f=1ChLc @P ޹2 56{ʍ|`{3^$?aRI=ǽ{c0KNY Ul0!M=5LxF[RJx5=sO>kϖQW mg0}2'}OFnߘU)-u yb۾;D ߭;9`pS4XKoj6BJI!; 2v;C$43#!a8v%,:yK8Iu5 Q/?s~@~S*7l_ c->g"6LW61'!nIw<{tAP!{ƻw,mjn@x|$o6`- <6wg|l$sE1 A-te}r1m +3o2y0qzu0n}Ԏjg 5ip} l5;&Tk|;2OIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/base_icon_disabled@2x.png000066400000000000000000000063261516472651200256700ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[o[%E(dNA&EѠH }{}*PA6NR iƖl7]HI.a3$wmx@xMBW<n%`2/m fbȘsgwܩ*ϣ5d =^9.Y> 4?4T%pP9mS mh}){q1oR- @V1k Fȼ=r̀#,1@6GU )_ȟ\6Hh?'[sr<%yFuK-2O ?ڼ00kLN`YN{Iϥq'lPcmc*}M|^y^dV7dkg#&ɂq&> 'ʣ!py *_d xZЗ< O*h(])704PZl/T,J4xF % 2]~|̠"ٌ $76]?Q5]|r ΏB}oGE`5{҆ ԟX~π瀷<{U[&[Y)^|)FL.rF?7Yx=kU~ x+Q@ɘ ] aSS7檛uO}ցs"Gp1z[1Y!W< Rq7n==z)NX-%8W/FL)0w}қW M%V;.Hxf:VGc/gcXy .*PF) Kt桞?>NyR9d]<$+z r-fn%b]`&t p CmM@%NCGٿRՓN}k6 ckB[: M,۾UU2o3ն20+c:d"+ |ພH1CX+ tf-*TW%yLZEK'%C4s2yTg~8FWcw2h_.z;gCdlO)ᱩJo -l7 GihnOĩ/ gR'_r'HeH .( GF{e%򐜳:Qxa? 7N|j|XߺV$4 1.{i C`GZ(;06<<ׅ|5r U0AqTw^ndb! Q\=pei?ȴP{f! $ 2b}4s֎zOuG&Gpy#7ճmFXB(@۳.Q@Qa([9Hr9my"')Ibt|2z <gCYsOp`<8ٍ\`-a< š8 2WVoe_n0+$˄:>8m ]_mg0ۿ BhF$VN-h,%F?mnd_82%^(Ιew1,S|Yp*rA8OW8sc*N-t.SNxEfm8Omfa.N&SOpA4ptɺ+rJKU\8/Ώ]I#<(v4_T}DV 6'h92Z']EǗ N=/a!5VM%{SLk'f;gB ¶7oVCܨF0}~REh ȻNJ>dC #Nफ)%̠)yŸ n"@LI LzЪθV] eݪc{2_*n(X@ ܞnyy(F $?w |HUѧ0'Q9hv@f%i.u6TTf"NT죵? hF%&]&eTyv%e،3w WZÿFfBx'P=R" [_h$I !{f3e/Ko#|< Ɨ{Ft=!тE+e߾ bgSŭ}L9q̏B;'S._Zf}DI2P.Z\̲^/L{aBC:f{̉CψCW+DONF^J^땙䝟@1=+DqL˾¦x|AN+ص  J\p`s'x %c)9Oqf$B8d;(R˵\Hh9"mĻJcsA0Dz#VCu ӵ#ul!50SI /Im]tHIο X-<6x!hJXx%AIg?7_as)< ,IB ȼ Rb\ Hs= f=1ChLc @P ޹2 56{ʍ|`{3^$?aRI=ǽ{c0KNY Ul0!M=5LxF[RJx5=sO>kϖQW mg0}2'}OFnߘU)-u yb۾;D ߭;9`pS4XKoj6BJI!; 2v;C$43#!a8v%,:yK8Iu5 Q/?s~@~S*7l_ c->g"6LW61'!nIw<{tAP!{ƻw,mjn@x|$o6`- <6wg|l$sE1 A-te}r1m +3o2y0qzu0n}Ԏjg 5ip} l5;&Tk|;2OIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/base_icon_focus@2x.png000066400000000000000000000063261516472651200252400ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[o[%E(dNA&EѠH }{}*PA6NR iƖl7]HI.a3$wmx@xMBW<n%`2/m fbȘsgwܩ*ϣ5d =^9.Y> 4?4T%pP9mS mh}){q1oR- @V1k Fȼ=r̀#,1@6GU )_ȟ\6Hh?'[sr<%yFuK-2O ?ڼ00kLN`YN{Iϥq'lPcmc*}M|^y^dV7dkg#&ɂq&> 'ʣ!py *_d xZЗ< O*h(])704PZl/T,J4xF % 2]~|̠"ٌ $76]?Q5]|r ΏB}oGE`5{҆ ԟX~π瀷<{U[&[Y)^|)FL.rF?7Yx=kU~ x+Q@ɘ ] aSS7檛uO}ցs"Gp1z[1Y!W< Rq7n==z)NX-%8W/FL)0w}қW M%V;.Hxf:VGc/gcXy .*PF) Kt桞?>NyR9d]<$+z r-fn%b]`&t p CmM@%NCGٿRՓN}k6 ckB[: M,۾UU2o3ն20+c:d"+ |ພH1CX+ tf-*TW%yLZEK'%C4s2yTg~8FWcw2h_.z;gCdlO)ᱩJo -l7 GihnOĩ/ gR'_r'HeH .( GF{e%򐜳:Qxa? 7N|j|XߺV$4 1.{i C`GZ(;06<<ׅ|5r U0AqTw^ndb! Q\=pei?ȴP{f! $ 2b}4s֎zOuG&Gpy#7ճmFXB(@۳.Q@Qa([9Hr9my"')Ibt|2z <gCYsOp`<8ٍ\`-a< š8 2WVoe_n0+$˄:>8m ]_mg0ۿ BhF$VN-h,%F?mnd_82%^(Ιew1,S|Yp*rA8OW8sc*N-t.SNxEfm8Omfa.N&SOpA4ptɺ+rJKU\8/Ώ]I#<(v4_T}DV 6'h92Z']EǗ N=/a!5VM%{SLk'f;gB ¶7oVCܨF0}~REh ȻNJ>dC #Nफ)%̠)yŸ n"@LI LzЪθV] eݪc{2_*n(X@ ܞnyy(F $?w |HUѧ0'Q9hv@f%i.u6TTf"NT죵? hF%&]&eTyv%e،3w WZÿFfBx'P=R" [_h$I !{f3e/Ko#|< Ɨ{Ft=!тE+e߾ bgSŭ}L9q̏B;'S._Zf}DI2P.Z\̲^/L{aBC:f{̉CψCW+DONF^J^땙䝟@1=+DqL˾¦x|AN+ص  J\p`s'x %c)9Oqf$B8d;(R˵\Hh9"mĻJcsA0Dz#VCu ӵ#ul!50SI /Im]tHIο X-<6x!hJXx%AIg?7_as)< ,IB ȼ Rb\ Hs= f=1ChLc @P ޹2 56{ʍ|`{3^$?aRI=ǽ{c0KNY Ul0!M=5LxF[RJx5=sO>kϖQW mg0}2'}OFnߘU)-u yb۾;D ߭;9`pS4XKoj6BJI!; 2v;C$43#!a8v%,:yK8Iu5 Q/?s~@~S*7l_ c->g"6LW61'!nIw<{tAP!{ƻw,mjn@x|$o6`- <6wg|l$sE1 A-te}r1m +3o2y0qzu0n}Ԏjg 5ip} l5;&Tk|;2OIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/base_icon_pressed@2x.png000066400000000000000000000063261516472651200255660ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[o[%E(dNA&EѠH }{}*PA6NR iƖl7]HI.a3$wmx@xMBW<n%`2/m fbȘsgwܩ*ϣ5d =^9.Y> 4?4T%pP9mS mh}){q1oR- @V1k Fȼ=r̀#,1@6GU )_ȟ\6Hh?'[sr<%yFuK-2O ?ڼ00kLN`YN{Iϥq'lPcmc*}M|^y^dV7dkg#&ɂq&> 'ʣ!py *_d xZЗ< O*h(])704PZl/T,J4xF % 2]~|̠"ٌ $76]?Q5]|r ΏB}oGE`5{҆ ԟX~π瀷<{U[&[Y)^|)FL.rF?7Yx=kU~ x+Q@ɘ ] aSS7檛uO}ցs"Gp1z[1Y!W< Rq7n==z)NX-%8W/FL)0w}қW M%V;.Hxf:VGc/gcXy .*PF) Kt桞?>NyR9d]<$+z r-fn%b]`&t p CmM@%NCGٿRՓN}k6 ckB[: M,۾UU2o3ն20+c:d"+ |ພH1CX+ tf-*TW%yLZEK'%C4s2yTg~8FWcw2h_.z;gCdlO)ᱩJo -l7 GihnOĩ/ gR'_r'HeH .( GF{e%򐜳:Qxa? 7N|j|XߺV$4 1.{i C`GZ(;06<<ׅ|5r U0AqTw^ndb! Q\=pei?ȴP{f! $ 2b}4s֎zOuG&Gpy#7ճmFXB(@۳.Q@Qa([9Hr9my"')Ibt|2z <gCYsOp`<8ٍ\`-a< š8 2WVoe_n0+$˄:>8m ]_mg0ۿ BhF$VN-h,%F?mnd_82%^(Ιew1,S|Yp*rA8OW8sc*N-t.SNxEfm8Omfa.N&SOpA4ptɺ+rJKU\8/Ώ]I#<(v4_T}DV 6'h92Z']EǗ N=/a!5VM%{SLk'f;gB ¶7oVCܨF0}~REh ȻNJ>dC #Nफ)%̠)yŸ n"@LI LzЪθV] eݪc{2_*n(X@ ܞnyy(F $?w |HUѧ0'Q9hv@f%i.u6TTf"NT죵? hF%&]&eTyv%e،3w WZÿFfBx'P=R" [_h$I !{f3e/Ko#|< Ɨ{Ft=!тE+e߾ bgSŭ}L9q̏B;'S._Zf}DI2P.Z\̲^/L{aBC:f{̉CψCW+DONF^J^땙䝟@1=+0V)zӺ21BcU!MDL 8E( ֱpDS:뵃}‚Rrh[`Ƶ|IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_closed@2x.png000066400000000000000000000015061516472651200247000ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxKaǿnѮSR #RdDDK@PE=(!AQ A ݲtsT,-]:쎣9~}}w    6 s+/s;Hm@kkk*/kΙLp8wф.w; /XkddWC:a@zpQ5x^ZeWE7̒|Q~eWM7Td e[0o}jX]}U9pfK O=ҩXvya.2B7~WݺpΙgY|ii0CS/Ӫr` ^s z(z8"En *">Q4g}oZie޻ ֑󢢚h[G }~<9^Uk[.>7GxmpVꎊ6@78؇9$4ɛ`a0Rk*t.<Y7 HvjPW&/qGң( &vQu戋~,P؀cM ٟ 7KUÍP)_8*ݛH?Va3TLڊ{BxjOn+;0oeߣCYROx<ZuԖc5EtMN!ud#@L%޳[~-nN}c4ҴR=.Փ     'wIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_closed_disabled.png000066400000000000000000000006341516472651200261560ustar00rootroot00000000000000PNG  IHDR szz pHYs+NIDATX풽JQFϬE,,^lL XZىv> X5bgbb V"*?F#]=7{rrr;YEgm0~L+$ C^Tztl3SJHퟺ.3+M]NE@#K3nWJi?SIAt,V3I2w9} (iF*B}S H0u;@3nm!'囤GIV'>9^/8[]%Ј/&s@?N8[]X@:ư:[H?I jf.@NNNjqIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_closed_disabled@2x.png000066400000000000000000000015031516472651200265240ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMhQϝ BuQ,+wc3LҤ Ją w.t'{A"A\ $dLK7 ZlK3B*tb,)幐srLBP( BP($ڠ8千qB>=4&s;m@P=!y$gAz6Y. go(]ehV^X C_bf5?j9۔RiKj%sedh%A KwGV0RHvuYY6e΅uM RY˚%zltm lFhӂeY R{;(}=VYÉaԸFJ7byc)qxK]pǢcoGaӢwE(wW4@s*colRҭ\&k&&&?q Mbm@o 6D9$4Mw Bk~F曢XP,OD`/2Hod҈ :e-͚odI4+g@4 Ng̪,H;+J ?1.la"4㴯Su"224C `f-@&TzR7DB (MM_~7XGqeEYwz 8Ӟx@-do-I  0 F1iCCEz* BP( BPqr;IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_closed_focus.png000066400000000000000000000006261516472651200255270ustar00rootroot00000000000000PNG  IHDR szz pHYs+HIDATX퓡NPS!&' A"p8$l< L`x2e&%0IJ[l46;ɽrߑDUŹ"YX&iDclA_hK*ҙaK˾CW3p\T q}5n ,v*]lf*@[LV4}VLtN=]K T"ߎ*I3A xI;-c`kh]KY6Pr 4d *aaeڊ|IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_closed_focus@2x.png000066400000000000000000000015111516472651200260730ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxQHSQƿݚsՔj˂݂ ̗^*"zp*ނ|·m>DDQ=>Ams;DCm]\þ~ܝ;aaaa m'a؝td{]W-k0dcQ+A*C^V+A# tͥS9 Z`Y OwHoΗ@yHE+CFdVv=aTÊg0}9 `3IUfYB.`4 p*f7*8Rq# By@siͩ7U9+Xoj>A^3!G QD1`7ӓ*28~KǚMM5D/ѦQN$N^fS:aj%iF:e{;^@8>s <R1 \Owe;[Ha{e$3`LrOM{Ad{HZm; 'rmj.C"G ؙ0 J}-*(/@@4 LS]w(r zʋ/p܉M(2]grXQR@?SW0=@U9*2,F^ reפ@zUop zi.FUB.ԑ?[faiۨ~- P&]rbT,i:'Y'0 0 0 0L-~dbIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_closed_pressed.png000066400000000000000000000006051516472651200260520ustar00rootroot00000000000000PNG  IHDR szz pHYs+7IDATX퓽JQFl !O nkZMTbM"HƄ`wapg.xX~οফ} *`f.}B-DSơppXA֒{A(8Fv:<$S@ nGy ī 4Ҽ|`R?IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_closed_pressed@2x.png000066400000000000000000000014441516472651200264260ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMHTQ3H6&DZ&ME`8(Aiv0 BB@([̴(\T2E-Ǚ63^ιBY;p8p8! IQ8 6Iܴf0Z@l\+R G"2nw3x&?|B-<JhI`%U/{e޴1OWb_ո1LYY]ibXZd.oK 6mSzVB>MTBʥxBlfY.G,qHAs$, Y) ԏ@==䫭Tvʒ_>, e,h}^jfmd$(383%i ;>3D"L% |Q|F/VJ+KKx(Wai3hZRMya;L P Dxz"{HwNEy&o)+=/YҴDZ, Ni(yh4[y~ %^G\ p:ܞ]0ghXQ4TR`.ʵhXmdzճ:ru0WLxu^7S1,P)h:(V~  囬p|\<.Q(3$p,zXMz:p8p7/l1`IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_end.png000066400000000000000000000002241516472651200236170ustar00rootroot00000000000000PNG  IHDR szz pHYs+FIDATXα A"u3`Hiz[?#Gc*  =`U=-x=qqO4IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_end@2x.png000066400000000000000000000003161516472651200241730ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx A Μ2ęˆc־)7\/PPPPPPPPPPPPPP}YǨ_2 ^ݿ x߶r 2 UIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_end_disabled@2x.png000066400000000000000000000003151516472651200260210ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxٱ 0r@hʔH43τuuݻpǿ@z@Mz@Mz@Mz@Mz@Mz@Mz@Mz@Mz@Mz@Mz@Mz@Mz@Mz@x5>S=Oz )%uIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_end_focus.png000066400000000000000000000002301516472651200250130ustar00rootroot00000000000000PNG  IHDR szz pHYs+JIDATXA ! DҠ6D&w7D֊|2@L"'oG$ Mo;IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_end_focus@2x.png000066400000000000000000000003141516472651200253700ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+~IDATxA AZ/FRTM1_6#4׻zw.x5>F>.OhIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_end_pressed.png000066400000000000000000000002231516472651200253430ustar00rootroot00000000000000PNG  IHDR szz pHYs+EIDATXA Qp-M` BaaF|V##1*  ylX& U8A uwIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_end_pressed@2x.png000066400000000000000000000003121516472651200257140ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+|IDATxQ 0DK_gB{{P P P P P P P P P P P P P P*_3 xpw BdsIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_line.png000066400000000000000000000002061516472651200240000ustar00rootroot00000000000000PNG  IHDR szz pHYs+8IDATXα01.cPS3#g(}XՓճxEH+/IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_line@2x.png000066400000000000000000000003601516472651200243530ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx1 @ ff3͏}ʆ):@u:@hZt:@u:@hZt:@u:@hZt:@u:@hZcIO7}LIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_line_disabled.png000066400000000000000000000002061516472651200256270ustar00rootroot00000000000000PNG  IHDR szz pHYs+8IDATXα01.ke(}XT=Y=xEtGTIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_line_disabled@2x.png000066400000000000000000000003601516472651200262020ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx1 @Q 3͏}ʆ):@u:@hZt:@u:@hZt:@u:@hZt:@u:@hZHOIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_line_focus.png000066400000000000000000000002071516472651200252000ustar00rootroot00000000000000PNG  IHDR szz pHYs+9IDATX10A&bЉ $""g#eOeOm>f|z?IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_line_focus@2x.png000066400000000000000000000003571516472651200255600ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxA 0/!*@Fx4}lrZt:@u:@hZt:@u:@hZt:@u:@hZt:@uKͼ IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_line_pressed.png000066400000000000000000000002061516472651200255250ustar00rootroot00000000000000PNG  IHDR szz pHYs+8IDATX10A&q DP''7o3lI#IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_line_pressed@2x.png000066400000000000000000000003571516472651200261060ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxA @B!cxt lkAΜ;#At:@u:@hZt:@u:@hZt:@u:@hZt:@u:@hqOz2TIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_more.png000066400000000000000000000002471516472651200240200ustar00rootroot00000000000000PNG  IHDR szz pHYs+YIDATXc`H5H5Pb%F0Q:`pPjTC??P-)@ h 4hMZ@S-)@ h 4h6y\gZZ`f}_@Z@S-)@ h 4hMZ@S-)@ h 4xP+ igIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_more_disabled.png000066400000000000000000000002401516472651200256400ustar00rootroot00000000000000PNG  IHDR szz pHYs+RIDATXձ DQtl"k _qMJqdVύ)GHX嵜 9IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_more_disabled@2x.png000066400000000000000000000004051516472651200262150ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxٱ ` P)(o/pHMhMZ@S-)@ h 4hMZ@S-),#L 9[ (@ h 4hMZ@S-)@ h 4hMf= PIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_more_focus.png000066400000000000000000000002501516472651200252110ustar00rootroot00000000000000PNG  IHDR szz pHYs+ZIDATXc`|٠6e%f0Q`uF0w g@I~ϴٵ}~_@Z@S-)@ h 4hMZ@S-)@ h 4: uIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_more_pressed.png000066400000000000000000000002421516472651200255400ustar00rootroot00000000000000PNG  IHDR szz pHYs+TIDATXc`?a DfjQ:`u,T0Á*yXDSr5x:`uF0+l IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_more_pressed@2x.png000066400000000000000000000004031516472651200261110ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxA @IJTd60^ e@y(@ h 4hMZ@S-)@ h 4hM<_3-`n-03^l/Z@S-)@ h 4hMZ@S-)@ h 4^ P\IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_open.png000066400000000000000000000006701516472651200240170ustar00rootroot00000000000000PNG  IHDR szz pHYs+jIDATX1K[Q{/ޛbn.M\2A(N~ !_B2thGEAH)tդ&h &Cr B<.Bo<<<s8he1Ks6ָ1*$n'79T_Z#Qy)*?'+y|;cE/~VP.DwExa$"mr0}>Nj䰍Mp;zxRC]L2?}4heoO,>ӋkL-_{Bnhe؟cbag/] ntq~_țx:tCc3s.z76)ߥwR]he/ 1@]anxb8?;mK?u(W^|l=َ6-^uo;ζW+T*kzLp^:8vvjU;}dppZO&I&J)RJ)RJ)wmIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_open_disabled.png000066400000000000000000000006311516472651200256430ustar00rootroot00000000000000PNG  IHDR szz pHYs+KIDATX푡Ka2dhվ 1KYg1L 6 `le`v; fk`]~?>0 Gnq.(-; HFcjKE-dED{e(9va!*7miKSG0luJ(z~ \0 C_V-Ov9)wᶠgQTr+NG*7wT8,PٶvXTD8ZZG-U7\cUSr>7p zLuO-6NnPWjB_׎J~yoB!B!BUـp8_Wn4{o[ۚ1s-McfL `WB^}GE~Óպ-ҬVX2b;ueAwx=7ykdG1ۘ}>;S x<م@xl(U)σDFBZUa]3n/7XLk17\Yu_&"wχ"n&~aHvV8\.ׂZ>UH,l%pz',_ef ik00abggg>6F'z ʰvPGdYjn.S&ƅf_@z, `]PmXy*l^^r,f]Ӊ{}Ld)3 v8hj/_|tK0ŊX+d2Y63zּ)[G Jȝh *G))VLtSu%UUV>B!B!B-'SF IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_open_focus.png000066400000000000000000000006521516472651200252160ustar00rootroot00000000000000PNG  IHDR szz pHYs+\IDATX=(Q ""Ũl&yٔRlI&),ŠL%,t-/o1xܻ_~s,/Idm7֟u% sﲎ_@c0ꥻ-^5 t}MʨDwRQ=Wtt_ l,$oPZ(F8bJQ˪ݗ#5~ࣈPyAu 7v|k!3 2^9yIB~1TyEXj3g~gIc1c1c1 ybK^DZRÈhޤ'!AO'.xnwU OG斂*I[oVMDJ וf|%C0^ &"Ol~t N0WScނxм Ȩld?jʡܽn~*@WD+뇺[7iwӨ"7Գ;۞lP[/p 1X'/YtV)0z]/Z*qc^06Z(\h2u<`SeG~D3꙯r_Eli\\РʎL8(qisd_@#r3.?}R\pm!ZYԨÏݳTQ!㫜}RpwFi$݂+y.7ؼ|d4: wc1c1c1#nIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/branch_open_pressed.png000066400000000000000000000006171516472651200255450ustar00rootroot00000000000000PNG  IHDR szz pHYs+AIDATX1/CQ{ՠD$t҆IL&3t0$Hv$fAb@R8seY߉i tH6!vB+M <\fED[:m ]pYiدk$0h7}#+pKȉbk:!1ҿr ЭW߾ϫ*G@\C:?&O|| 8ޫPxLLl"hzy^U3@L +))uq݊p0ya.iY Wtp6zFTJA{{C9Y~4G%7վN`s}V=.٭n6>!5Z \ԥA_|pW7Ӈ&٧Ur_ Gep*}ftQ^Fv6TKTz~c#<ʼχvԄqxiMqPkRD=t =_Og>'Tu8ʉ g_E9"RnZ3*|3oڀuZa]URiN2A0GvΒ ֭ED|ȮDLt=YƸۧ(GIk2t.]`C[lfߥcN=,e %EO ÎƵ[h L&Ya𷛅CM9e@sTG %5ɶ'Y7UOKU͐ 7娯˗r)ƹzYFUjNN࿔֊nsc1c1c17YyIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_checked.png000066400000000000000000000013171516472651200247740ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXkAƟw6B$)1|@QA5QAZ'OZZ`тAJ)WH-!&9 3ϏgvE9tSbA<%%&\30$oo+7>/2nh7iQBSPżEvam XuM2 7H\mG=cW:0@-6fZ kS`1N!tDo֠-0c'@ވC 8}]O2=4C+|Q j7!@Do4J\]#yb~Xi-H-; dM%H>?2EwB*8M 6zC?ǹticNTvm^htHy"~XΨ)|:@܀w0ht9BvdcT.u=/!A󪍊JOklo^]JPUIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_checked@2x.png000066400000000000000000000024611516472651200253470ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxMoU33RB$6UDHT`STl`4DBe/T5lt,6@1 *86h*gx3|{==úСAlYRl} e#ZRMt0 b[Ac$+4v82kuE:\eJ_Ņ1@ݢr"VYeW~d&FS⠥,  R!Wq& TUn>ѧTU\Jܶ0;$0 }wL.*8n5_,P.dm>I_if*7髸 *}BO >K_œSWf)^*"}S! x I_`&S!źvXD1D(r>`#RmK8l7>N:Or o-}钟}'1bO?5-]aJ6d ESQ}`*h\4w#@)z0pw(=@4)>>yt8ȱ;aBK/??ED ^֒aR>YU)nZ^lt;<.㷪/ 7#'Kkٯ[}mxu\С?0 r.ʙIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_checked_disabled.png000066400000000000000000000012321516472651200266170ustar00rootroot00000000000000PNG  IHDR szz pHYs+LIDATX헱nPY*1PTzQqW]p5cúސw*,XVYkay'cW (Sb;`X-  +=8TRι@i8B Buͤ}N֟:sF_I_j}\RF (עBacCo!)j/N@LL~"L|m}d/H^pbNnj ~N$2:s+0d,;9`}Ab_xQ E 84B=8Q |vÐ=3(R0MELRxɐL/v0WX adb}`R؊̬/*@R#S OB2F)dn}A*,\/HY F)b}ACJ!7 R4)λ,UR aspi9h4fD}e&0u} YBERGJE*tym"'rieOk?,f!98͍Yt5ZI"KW8͍Yol`4Z\˓\緷\^-0~'g7R6}m{pv6MmcN8\msX0ζ=zn4ZIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_checked_focus.png000066400000000000000000000012701516472651200261710ustar00rootroot00000000000000PNG  IHDR szz pHYs+jIDATXJQsոm5RZ.ҕoFUեXBA_4mB$pa{L:jM2f=wo~gub gdѻ@O@uP1mL~*`0<$, (s_z_\0V 3!SL+wֿ_/PL`f \'$9@f ds(U3rsBsr.)<=W秷~NnJn &s IJ_}j* ED$ ךcj bAUxc4Se޼@rq>`e׮^@eE8bMۂzoug3r@ 琭h*qGZKإjްm6e}TYa|>/L!-XR ޘ|Z߰ŊqFod&J늨2g/[[[@V4m8Vƀ}`Zkz?o@nbx8g/2r]:-\PU R]7Vniӄ ,bNNӞ5\K tΎ*/k4Uژ$rtlE Vښt8IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_checked_focus@2x.png000066400000000000000000000023761516472651200265530ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOlEƿ76EꥪPumUJ"T$r hRn\H$$n[R.Uz ^5؊Q֑ZR%8Syeݿ!I9[ϛ/۝gfKPvs09/[l&E&kenݙM\ꯃ_&Ȩ?e킄c 3k`,( :`vG; PY8E?/V?qjUk{,XLVm/npc0Kq$gNxî,*n0M岦y Uu-͘Zz9n1ZJ6 w`雄~sz;6#*vB3T˚s60Ә"!o^4 zc;yƃ}JEMysc8Kݾ[f]B:PuSx  l#:#B] `/pP D Pp:%6Y>-j^ GX c4v?Tᴐ ~W"pS귯 n\(Z|D|^H}YbMqX_Ȼz)51!-ALy28Z+|;P t9!k㱾·)SpTaGi}o+4[ة=o .֎m}EB)ds)$ 4.eD<J!)Wr8Ү|%l4X_wfhS \K)xqH)?Rp#*+} z,G"P(;""BW2ⰾ",X]k)e}E/Cn -.E+L⽸u9i0O43Ox,L"Y(f}K";6 G78M*!`}b=6MmFI6|ms y(IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_checked_pressed.png000066400000000000000000000012151516472651200265160ustar00rootroot00000000000000PNG  IHDR szz pHYs+?IDATXMOQ3 &ZKMAXFX). aUHHӖ ?&HH0h[v>:unΜǹ#큲^HJuN}l^ (}ӗ"$,%K%zQvbڳ#+Wրk(KŹlQVSQ-pysji"_[)XPH@@xRM%ܰL섔uR Ӝ|نaudUCJj< E@,Eq9α1p]?WDLaS=汀\LA@~Q`T UW\?[⾆C6U4[Y cGy!zKh sl(c#xL# X1^IH!g?EYbh70C J{%o TIM*6H!U`[~G*T#.; LO┾C!܈UBMI%Xk*$!}HPc*$"}BRweZ*$)}H0+y=pd7x?);D:<)ED[,Jb,>#[;qU+*$n-nΪ/n[7r:LrʍJq;op1db2TV\+7J+i+K{2-إXKwS8`2sl.1.0Wn[vy |[&?vyiC`@ۘg0UFs+aF7y:4e 硩]i<6j-ԩsWPIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_indeterminate.png000066400000000000000000000010141516472651200262300ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX헿KqƟ"̖Ƃչ p jO!V5,,qAQxoC'D^iQ>{/}Ot#:" Sdx2}!$+Z5I:Z?88 w܁xN|ɍ}RS a*vIr/r`⣞0*`]c7E*um^3QMH3ļ 5&ZʟmZYNۣy sh'昷GU PYdfhU֘hN$ VEހC=~G{ @d f>R@%bxsb9ptƇAWiDCM-|qD:`Pm4|n³+ht7;5*U~#5n,Q%{=nz{7P?,Zio2 ʠS25d`ЩtzL G(i[ K0;5*[̗{=^U'AT P-@5T P-@5T P-@5X_i?2ǥ fxwM) x+7Jϝmc/1 1!Bqod+i͎Xgmu숅txi4#͕dcsx[ .Ck 9D'7?יm|H6_`t}un%|6#^UWs`pf&qѫ7N4OYa03K*Ds|sCIx0JܨT9=ewl^_TslNѬnhwzFIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_indeterminate_disabled.png000066400000000000000000000007351516472651200300700ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX.Q3ҫFxbAVYzS륑~B%rTJJ}yq)HI5]w_v#)O `-n#2G6WmW34Bot{<2[`Rcrw$hfs^c Ff^fMz{3IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_indeterminate_disabled@2x.png000066400000000000000000000016651516472651200304450ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+gIDATx?O@Ɵs5Z2"PqH!RH" P"T D Sh;C:Ҡ$~;$H$Hs^<ؾ;%a$麮*4Ay0t]t =s6hO]Lc |}wz!ga󿒔Z%әE;m8xL DTF4 u--oR.::Lcvl3{TK<} ۖ2:T?l}b6iYua,COULϊOeӴlA,3K_U:k-B_l-1M˂ђ5f8 pEB[n VP6m!{잵CsMZ{>S ih ih ihQ$kw<[6 Jg戰 `<۩tf3.t@xE4 >AO\01;<}pri:~2/.\ e Me@4:xyG<}p*c %\-*og1,9  ih ih ihTإ}^qjcIZ[`_A= سL&]U!Sо=sM $ #b1|nPZZ;`9,m=1~hs܆˃+(7`AE|/ґ]Xr2b̄đM&*8SS]f.yc cp>LN ×&A %(@eVT9tRfVdLyX{4cmOt}M$o~)ab߮lyvMarۍJ;0(1k(jѳ @k EF%Fֱ$ kBͰ]&+ߗNXGdRZtlيz4s3rlΤLma8y tatL->;-RT7nfa1wYr L͖I9㽼9fMGcVsb⹲2ᢽ ZOx'k_ NkA [lF [lF [l&"WFV"p_ +3ӓGFa@O߸AHGt1!F7Ra7u"kpnw "kr1dGPȀ?l{sJFȀ&1!1/7E~R}1f7`[/4&'~,'@}e 2@(d 2@(d 2@(\v,I(pj߱8 ` [FʇU{Px.ͦa֑&=Y(I4a s>a螫>Gnp1 $P0?M&K*Y)\52OrZ,\Hb-?\RBnc0b* Lyi 4z*uiksْks*狹6P(6~(MS%IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_indeterminate_pressed.png000066400000000000000000000007141516472651200277630ustar00rootroot00000000000000PNG  IHDR szz pHYs+~IDATXJQ3"R B r#d"6 @PӋKqN gl(Ig4hp7\s#-Q8@ԣ:].PHyCSOE'\]Cy>ܠOh[޽z+"&gD2%ĥEaC喊BjK Լ,DL+ϜQ/&mh8KM xl1eyfKn݂\oT R]c3 ,WlR('@o=\6)moko -ЅWJC#(qukz5B> @RhJC#jRLbR1y1fJ9΅Ah[>Dr PIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_indeterminate_pressed@2x.png000066400000000000000000000016571516472651200303440ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+aIDATx=LSQ~$щ:jp4$8hHX`bI($.2@G1 FhH$ Kmnޏf/4\Gz\%4{╶eV*d%Ӆe&F/mh@fN DfQntg =PUi?0SsP3#OU~e ܉C[5nf[euf )Tp;gj";;%T35U " [%_hi?{s\mGJDz0Xn.z[ew+(;utcK PKEmH_m/(VY# B ($LE/:$rLۢ Ƅ E>Fjh? 3膷vZSp`gmq`gmq`gmIF1hV+G9&k0@w"J̆` 5UQZ>*#Yf:7zPǦ"*EG7zd #UM0@ACMȀ|T12|W&p|7x dL [QqDГ1"c3n-6l -6l -6l [75Q%-}%fgWQ&!?cJ%q1b]U#Vu04Q2Ӣ28<ˋY'π/871`a ЮOjɄd颌qa~a`H'rLnt\v T.FZ &T9-CaR }ݧW.`SES 58&*);߬X6I[)s8;?W TIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_unchecked.png000066400000000000000000000006011516472651200253320ustar00rootroot00000000000000PNG  IHDR szz pHYs+3IDATXױNP$0R6,Ml}xgug0&>A7qbg 8Bb 8x,9#AeԳB1f4{}> hCX QJJhYPdHNk pKRry:]dHؠ"T*ʏ HTS?- ' 8PiV(8PbDݪ=?tQи0f4 :^^yy0y B[ Ϗl_NS7nv8^4Fjiff1IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_unchecked@2x.png000066400000000000000000000015271516472651200257140ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx훱NPcK"R ھE*RVJЎ J+ b@b &R*e K9RM\[sorP(n3ɢmgfsL]UclKSmR;(_g5G#}g _F` zW/;4Ӥ`mLFȼ _ܠc"4nT 4΃)+3*5x[$/سC3#)1% &x[vF3]>(F"gQQt[P>!`RbW]o;pp1 =毂|h< 3xhJ]Cs{xWcڮ!v'pPH F -@eiQH F -@eiQH F -@eiQH F -@eiQH &ɀzErGI /놨^Ҝqv&z{ R 9ntAblY`U3]3l f݇}wF<3x9 (9NZ K5Ǭq s̚uhhz)UBd/wļVE M3o5Giw!U{١yRMJ6 8U/;Eߝ4Mi"@Ko Uyޞ lp6:iS(C8eIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_unchecked_disabled.png000066400000000000000000000006161516472651200271670ustar00rootroot00000000000000PNG  IHDR szz pHYs+@IDATX?NQy<^ka ܁S`)81!%^`@@v]Xr}G i@59&Fzg'^ 4~xWKBuM W]q<%F"QXV0jNT? B P[0'r5\ Nw5VUwk( 8U8X `3Z5k8X `3Z5k8X `3Z5k8X `3Z5k8Xf@nw@ !+=(Dk+[(tJDG/)5wOE |NW @6X ECPv{hzz:(>݋BMc;p$ql2}n⳰Iשna1L@X*R1ȣۿk/yQXshIe2@t@OJuLAEG7MM4MS~Rx]zN} U6En6mpn4IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_unchecked_focus.png000066400000000000000000000006001516472651200265300ustar00rootroot00000000000000PNG  IHDR szz pHYs+2IDATX헱NPsI`.ՠC_O`" # ;yc:(;B!@k*8x|_]=p>npJ$@0|q_ \LBЏrrx@av>1 n7ڝZq9tx45 %Lv*^+n _%PPH)& IV X+`IVq] /Uٞ"h̪8FnFb2Q5b]1-&Yjo£KE~5e9xIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/checkbox_unchecked_focus@2x.png000066400000000000000000000015511516472651200271100ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxOOAw"^&U`$/B>A#/b-bHWJ[BbH-v#ay0ivf6͓ٝ˼p82rI]ozx7{@tm?tUnk,6DX{7Xrں%i K#ש߳7j0zl-0v"|S$YϏ"ݪ eϢvB̕GT_ c/'m@UҳGx2r-“|xzR8׿ڈ/s'ycOeAW1Ѯ ᩾lf6^zw:GAԗx"ga|upQjHoxJz 1E4kPP;;5QNuk8qXX ``':5Nuk8qXX ``':5NukU4Q ,SqLkX+Ֆ!Qjz-֚ЗP-`ds$@nLߞ+7ݧp][@W1.`y%ΕsPt4ڪ@W[ɨJzPBރ%ʍvTσ hyԽ-@@@BTT3?ES*UyCMEl~奼IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/line_horizontal_pressed@2x.png000066400000000000000000000002121516472651200270300ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/line_vertical_disabled@2x.png000066400000000000000000000003671516472651200265650ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxС0PTFG تX6ĝ qCxO@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-yj1^IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/line_vertical_focus.png000066400000000000000000000002061516472651200255530ustar00rootroot00000000000000PNG  IHDR szz pHYs+8IDATX10A&^0CTPzz6o39IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/line_vertical_focus@2x.png000066400000000000000000000003711516472651200261300ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx10P*T!n q\CxO@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-y`fA$IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/line_vertical_pressed.png000066400000000000000000000002051516472651200261000ustar00rootroot00000000000000PNG  IHDR szz pHYs+7IDATXA@1{@z"E=IOxE+uqIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/line_vertical_pressed@2x.png000066400000000000000000000003661516472651200264620ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx1@POBuS$T9ϻw׌8(@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@S-)@ h 4hMZ@lk:IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_checked.png000066400000000000000000000024151516472651200243040ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXMlTU)Qe:0N+JE%E>4ACb$AH &(uc"~]AB# HJ F)m_FS3 3ꎳ{νsn)$:Z6R NXj7v%~>P,m}j,-݉?'id `*4Gl]MJ1*Y`h'q8etՂʫ#A`gݭ 1Bu@lܙq̮ FO~]ook L#zbY{ϴ PO-?]nGmb/ G7N&qwן>X QզDyYu <<Q.P2{hdCqwJC9@MVi8.*֫z:bM"H>2O彉T#ѭi 2* \^lC^B( սqF@휹9Ίtr(Ϯ Y6B?x2*Զ_QmMB=)=hXtf GIy)H%m1DJý΀P+wNV8r4C;k1A_4a#7RE#=x? b؆YpjYvjX@f]-!X{98NG̱m>-]Uw^m;?Q2 j#pdVx_̝xBBߛV\xn5ӄ$yq;=twގ$N71o?/T5gDkTYd羙"e] _;:$xRa* khqgjs9hOd 27ѺixO"RV]Ic"yJ[K}@8/$oD"@n"yyr]vX6ЗA|Y8:Kܠ G_by,gc4تkFm#I8] ARAc!(ǒ&bw4qu9EЀxD7cc%tV-ˬѥ*D(G..$ѽzݻ;_eCcIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_checked@2x.png000066400000000000000000000053501516472651200246570ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx[kpΕ,ůν `3"NG#.9I&H x.@4!&>>0;z[[ؘ0`VN ?#[=K9J/`x,. gD>ڌi`Af& Iu$EٝIIR;9,-aB#PhsX x:W_B€[xAokH{gn,L8/"+XQb3` \τg8xdžCZs~H,Heoz:ZDO@^] #PW~MQq晥xD3%WGb4o!uJ#ݐd/+,%HpwщU_"ݞz~"Xv^C]&hΙ-jU_Uwz\c~Ι^ixЪ\ah+{yvY1՛?/ѫ짌z:[ &2ԞS [:9p~I`lwY}1`a}}pL.D"u? ,fFj'@3bx)=q6ND.Êf'r}(|Q: z+ufhG֤ ^y 8OaSS547pם$w(L, ޷" \Zᧀi$# }A& PIh},]1Johє lvhT44T? ("^_\4E`yr<㽽ӠhhŔē6<`yѢiT BQy1FKiPE" ~aH$2@t|>R?P ʕ"Ӆ:HY N606\!ŋ;bmmmJNJʨJ&"9Ӱ7~"lv4}Gb^2*'aIh'k9F^(H m g<>v2ejoM @PG2}`f2\Sd˕)95mk1=UE)/bܐ[?bDp-mМ(V}L]V5 >0uuwBB(۶@}|{/ZS(oqrz'ܪ=BڤIsDLzlS$p5Τ:Me w&nIz]&]TMk?jZ/5L \ᣄ̎&Vx$P mgC z3}Z:I۹`F<0o&, n)qt| >w{{p`',*61~u10v^o6{ICTy`j0=u{Qa:ʯAr=n`z3A4*:wZ^}>c`̶ 'm sˌ\ ! Epx̊8`2u^8v)]FSGAf`[˜iwm=Mvy0G0bP7x`nF[b g:*3 \FkíOյ|IS;2r`#PgG{-wYq`P/TRVYD shR4ίy=Yψe9sKOpT?$SSq3"Kw3&op "z;[Z2&%$>v&m+"=/mYh/wFE\AX[R(.u|xf~h~]"@gjeeу3ڔeU6qjb2FDbdc& r 3$ccOg=V)13Mx @N11-`|>ਭp%)p ^geOi_kQcHw@oH ~{b1ljd(.MHQK@K6hCz:ZvNG?|ʧ&d'3_ нw'6J ?M#)쥂y WX( s=Z,0il㯑@=M܎|AΌv;p>K`38pkIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_checked_disabled.png000066400000000000000000000024131516472651200261310ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX]lemǦ(3 T&"^t]DC@$^xa1A !1$\a- D 9^mnFq- Eĸ)孷7HV(pE]&}P)Ҟhyك~ZOb3ltA:0PeeGF2Tޜ[ƬY˘~Դ1u% |w4 v_Jrpl5o쯳؟IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_checked_disabled@2x.png000066400000000000000000000052741516472651200265130ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ nIDATx[{l[{m'a QZXن@hq`ρ::`166@:[VHZ S'Cf<Ҵipo$^ډ]M[}\00!HWWױ9Y9U!r#>[?kooy־,z/"q3Ʃ=^'[g"*Dh0`"&ynnnVKk hx_ KBmsVWGL8R<,4  "-yJ>SJH}sd"3-DP9Ji/8H b֫#4 ~3o}?nSsJuWZ4s;lE {zA<őV0R(x# WΊ@R{@phC/©T< \y߿\]Z%%EҔP5 OS!BXKxpk:;;ru$71\jD\ s[;sY4 Po?ru-Vg"OTfPivWzzd:e+}Ә.&x4hvl*hg7G4ŹNu]IV$Anv QscSb npj9uypS .̗ScڵuG4փj#0r%-9) RL"h5T9Nz.Z9"xMD~ֲ+4OiS ohH:%g"ki|__7H=* !^BuƚB~r׺uTJñIթD,;z(} Mnr!"D=;•&ɔIdtM`pλN//(-WGKԜ"th8ڭ'1LEQn-6(,=&Q6 C9\0*$qn{ wL44hėGU~'NF#ɞ+^\pw8]1pv*%Ѷ'/'D9 2? sN嵄Nh[,) o; ^ۘ*ak0Չ@; {kaf'NJN7a ՆŎNj&5Mf`Xy]Y_2"BwWohO`6!" 큖+=xY&o@Iʹ] *h[΃ H$SʳkG+G=Knn.kzMӾ]{֓l7ߘTiv+t @"i烻-X`9GCs \,N17gոksC4޽M[J )@"0-O$A"L6 JY X&5r}{e[ݲSd"UX3.Me$,:!{_$%(vIYG[o/7Ȍ %KG!Sx7)xAJN}C9 [get:ڗ„ ueD +P/]g)isЈS5sYZ%7)yA?&?6(@Pp@d?QOfhB ]!\fU5Sskx:"~p8| Zduv|<|6NFPCT3 ȑb/@l-Z^`[ ȇqK;IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_checked_focus.png000066400000000000000000000024141516472651200255020ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX[len. vQIF1D# ln 8 ƄI;!j&.0%TBlwhk뺯tnxsӾ{~~ xHI]RP`P"aTX*j^='{2PtuT?JI1Z{Dz"Q\TTV+qz"!ru k1@u"NĸCS,|[v!WfUwmᅬ  aY@͏=]h= yV#TOh p-_? {B{{2PVEwaE}L^bB%*Ly#].*EUr܋iMn@kLTbAu ": {69 fiNf:5űc̷Q0KHe ""5`wo؟%}=ʱ!'݇jjpk!Z2)6x 3=f GJQlN/o>a a\ph8<0P&)?59y%*/n] g2ɘfv;aDsXiJr9m+ }9+ɿ%(=rTl2No soD b# WR rփӆ/At~y,CO0PJ-g8sO',K#u?0`cVwcd)t8xISǮvf'* I;YhDrX=@F_: nr{Ylo"'ZWoj_6H{+uk_j$k@0r$Tewhz:+Zv1W1_C`MqBVluHcF_Wd[@ Po:p' /z"-c$mb]U-}csCF]TԳ ss֨"cDeܡcj}?ߍsWU4-!"*ZW.*$]ʋf42/9G|bW5-+;fyb1 ፑPǑ>4ǮH+ Ik&ss㍯ܶvwj"yoAH>5 @? -*EZhhFwqsUu0YFEwRqw>1J׷ U^Q:z;xㄿ* BƄKCs5Oǁ Iezxft%ؤk|[&7\c<-M]KsST'`H׹IWuc3uK:υZk vC/>~ޓe aTHCA7nQ]>@8"K4R93Znj+@ ȍSPNܶvw272'CdM4t..5 ĩ[1oxuY lN,p65 ϊ*%`sR υo/;B[r!^9f-@ ӚؔßLW0_K T 4;TAQxcdB 4$lKOOTَ+(h3Ɏr\`4sxX HߩKlV|n[{Ћ ~`8pdqn (˳ L^)y2=RFkA,˃({ј|͸]V-CqN .BA@8f0cRҤ<5 pTB.6tf5LbeRE!v]jB3 FgLjߥPUgűRI!<@|'[fe0|gpkL1F %]tPl_)@t_:2P)6#G @<ɔ;a]"`I"t+F '(Lre{ .jO u“Ip/RW-foZtR@ #8~|ߊRW9b2pț=1GגaOfZ. [pΦ[ vRy:8y?C.{`(ڊN~2X]񮑗Eqx:+7`]1*"=ˏ?hɁCMPeF/5vy};>_qYq.n$5PT&M̨tzzEYcq[WJ*r_29[Xo}0"l;Mn^ML&A)vqsVbuӡtWl1LnXa9Dj+w%3*>>ȳCɅvYH}]}8l#@zz}MK O X y 3{6!d] 7n@M)rz.4żSVa )W?v>v5;^5M1Th=p(dyI̓Bʱ.<,Onܵ!7IcJ.j;C([Hbi!$Mti_8~k6 FC|s^߸ ®}m }Ax\B^ ːU(涵S'^x/E~ 6:\fhrvW;xyGI{Aגv1ci#؟xq%!lRSxe怪ƽeeSܷ y7!ӵm^Q:׷J2 xL=l¢ibI@c{W(hXX1#30T!/A%tlW\,K-Ó.eφ75=+IԂFJݩ/wi)$8tPgr>FR-wTe<Ѫp*3 zA]?!oDq6 T% &v"#ί6jn4w@YL`AP"<l(v@3ԴH;%q29߸ B77E>8]0kIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_checked_pressed.png000066400000000000000000000022721516472651200260320ustar00rootroot00000000000000PNG  IHDR szz pHYs+lIDATXKlU` TJi^HuR^@ T5D7D&((֍ H2@(V!A!՘\K/39wl<*$RrUF% ^]f?fL뢢As{TFOkGs91IRc H#6IL@KG}ȘotW=3>1A3ޯZI/*o.jJ+}DiJM^"`F8% _R|r%6 :lL |C?Ҕ(zDr(ۉR:K{x*@رȖ,G2vٝ-p|h&4G%M 71{a6%I<@,M'^IUHC\*fPT(Z,œ%;G27gc?+D/+67^dẙv9 p=qphl?v%9Rt1y$v*W$:)dzќ(p8NG'D)oW[n?{c,@Æ$kёFn#NfƤ]D^?EMRw `팦DŽ6JZʪ7QVv,_TCln;su-j7fY8s.ar(ic u 3ӀB9RLa/W]Qᯆdg,I= gNǢ$EDUp@}1} #.#<)OW Kj,Fwtq\A3Ql`e0ا!2:BUHl*LWa30bO1kY16mj+^) _ wkj59yMW^F”6nEde:y0ڭ0B^|?!Z(7#d>4L[p m /3Jaec_:W'u/3ow<*Lɤ1=oDV/)x~6_Z +ͪSwS|FuGn2pŔNgS P' 'q|u<)ʿmKp /D[]_$f4q݂ZW'u<)& arWŮY:9ܮϥjp,JļjH^;y'/'~jZcDu 2Qn\d(U>:e~8Sr9P8aX1P׀c8%Œ.=ՋЮs8v\S^:Ynڵ w-4G%ϹRg= ?m+whWvrz@YħC9٠ UN4h#eLؚU ux v;pO|nıA ȟ؂PA|>rl>FnslbIxf۷PΔa+'(p -;#Lv99aܑӁ>A} ';*;9ncJ */)|Vá`6ElIFRl%Į^"hJ^ҼhfSjiWJY@f8y9=[{j 0˸[oQĴi jQ%m(U.jlwƨP2Ux-= 5 <k3A'U &M7kF=6YLF&8܆e2B9oy7U'!)D+{Dp9\B 18.ާa~hӡhYadE3BԂ{LjMHS痘H qmG8fT=?ŷ~3(>DX0oX)#|X4Gjr8 X ktnש~d)ʪaoH5ާ!6[̯ {ܮS3üg1owv"\d)_-a(OVVs懶nD[bXsA"M+?@֛EůnKRm n\(<>[ UnUQي0ٜUxja`M:%_R!ާ$kT5POvPP:kNVi0$ڒ:_Av:8"Gs׍' (k`5+8XZU _pPަ|.e µAgU.RX#1)Rx N2ܖi%AF|un=Qw8ɘTe &!Me(!\3!Kb53`"2d *%(;i'O;QOfU4 7rMRM/n=h6iݼOQ^~84u뉆PoiݮN*{Se;ŦYp00_t9=IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_unchecked.png000066400000000000000000000017601516472651200246510ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXOheof5"A7Ɇ$1 BXEMTDj*z=(EѫF,IJغSTT#]vyIH ɚ]/}a7{nJ[ۀ-$KaR 'pR{(bUoKA^gݳʑ6$%{m2>l( 'l٢] cqL!b= G%c"{. [#Ѡ)єՒyFEo1&'έ[{SI&xZ&%nlD9r],kT) ;+~=ʛ@nX篿OchI~$S5D9`@ [b0¸®x2ت U}`EoaA}k3µ1AdC@2: *_?[m@U9D ^2@Lv mb1Q+ ldXA@aQ̔j Db 6e`z?$4? iX4$@^umf`Qm}cZh::{c%ɘd^Ikg[,cTݮI8DFkl`08@nx<6O@oG& ``D] fP]]]*0'>X*G^biDhVǭOqL@ R5ݡiJ/Wb0CgnkĻ9 KmT8W9)6tyI @ۣI[HPtWTRT ch/_jhجv3 <MO俇V} `Zg3;,NW>tAhtf/;*\ o,T,^M\_/뷃IUTST([\RKKMM -/5vkLbfT6f@W%0')ijV̻:4cO(/(MP=&q`2M Yh+6L xWO,o!X˻!x{8B`%1FmEb=.cŐ&n$ť+z,&as @Y1@? u1.쉌pt?O {G5bfry'2L 7t_1#SJwZuteWq+8vfCďS?gy&4mikIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_unchecked_disabled.png000066400000000000000000000017771516472651200265100ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX_hU?]:F-e*SmKZ7Dn Ň B}ph'e( ZlӉI4ɂEP*h*R?~ImKI˾O;߹pKv&^f W,"Qqt(XUXWE|UA_Pep*b黁G?|ZE;C C%V |V "0`O`/maWR@v ;[J j}ZM--,kSK΁QB^w[__=W;H}JliixfX KI,Qy ƹ{D.J$%ND``"k'Ty^K5ф ` :rYT#dv$iyBo?CoC Ua dD'j#] -5e@09;5/ɀx^kgs4ت-)z}ACbr\,<`oG(H6/ŧ  'Gߊd2;~2 0N@#"]$U$(& ȋGNy A4$0(syE@RE!ԫ|E(*ilBք+.4*XO(T)LF{ 2v\Hv8pR9Ph7AR"A>k_5y?($GAuvЯ45Qb&':+';[ /K k@kSS ~m(|kHh'5PII \~wb9(q ӆ< <;D]zK\,\p0M}DsW}p5gz'JRZF,Xm#)o׀PgW3JT?,YeA 3jC2eiO|9 z.'U JyQdGseްPWLz\9 _6 -U mݕY>e@)\/b&GU s]Y1ϟXnnZAS^2[3P ::DD8f$k2ClGNU ʦJfe8_p\0Pv:(m 5Azڧ;c dSʪ$:OtF=HTQklc ʗL&|E9&˅#@[i爸X͞=5&!+,*LMMsdO B'#W91B~]Yhش} {g̅vd=R]>~N %Sˠ Xd#ag\߭uȴ,rƍuD⻯i8,)J%nڡY^7M3i*jp Hlܐ+6CݒJ+uEG,q+=ߞ+6練 ;#]r"LYk`}24V!8z`=aj}I>ՙZW+La+'O@-ݠeklڑH\VVבL&}ʗ5Dpv؋<)yu֭OO=EBF*р#GSydEjGB3q/!X9,/l;C`jrؕPL>Pr2x%~!9:ή!–@$7fݱ|dwT3ۦئ9QTؑw=p#"H<~u1JA,rԙثUy`ƔM9 !ޫ2s.>h~-UںYJ:ΐ|+k)XPoR^iG=-SlfHԯ$GI[(Rc`{f$Iѓ}Y r݆%(p\>FC? aR"/C xY'zӪ6mtE<@0)J֔?&q= LJ{TdCw__c3SP,  .":gs6H?H%\jؗ~vQkSL,[fy v~ y=u3TOkϾ{R8W{̔[<_ SM9mP ȕG'B9봜dnƮ}o3W@!zƞ1yA¦N-}JF?rvhM꽒$T7&&O^={X$A=E<[ŰN_ h5O^n 8?oѢtSoU;Hhg$x9Ei&G jcJ_,;@^]qA=ՉqӾ{mpƭ7Sl5 p6W]]Ic \T.٦:/{DRmqAΡ4V9R̸wvwc?z,3IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_unchecked_focus@2x.png000066400000000000000000000042471516472651200264250ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+YIDATx[opT=f!(f!aJfŠi: mPZV;*Pu@+i$eډ2:vIvBlBd_?t{6;Iwyw޻$&1gp,n2-:'q \ A/^9F(!GC֖55]%$Lsz%8( Yln4Bcʇ91Jj:QV 93 Z)Բֻ׉u]n7L q]sJG;W))R,ARnu<"P?DFwu|Yl>`쭦>N'wQiSo +ܣ!G!@tQO~~(kh/B"$_B%}͝U "R\#miMWӕz|X&~Ow]ﻘN { ߵSSZ^ZF@E@W7p/<27\Z:7.-ninU [`" Tsuo,ܗl?Z 5r%fCcMJG l *O93O l =ѯɑ{d9Yj"|H.W{ԍ eM Sn2rJpX_n/x{;o% _1P?QQx7)JXL0@4\ka8m 0i !6cc&tI\c癮۟ z̬`5&yq^O6e1@Hkm jOe:2[ Pw8j{Bm h.8hhqͺ>n( pksڼb w1YBYCO(l0Tm =n!~޷qvNsk;'ԏ,=%u j3򄑣ބ)e 7 >Dec׋ 28=Boa>C<Woa]qu#x-=l="}W5PGr;˜7qj #!P۵FN(Iڮ O\jsft?l=faimàla W~J`im36XTwT%54z=Rn)cd=+ *퉾 `%ϴ%;:}y>x7#q{?bPql9^鏦7U~X6sjIAEMW_鴿^h/iyDOM`֤Wq+~3Wx$HA31HF;dboa!`q3S_C&MǨ}In]x1D}={yvQ\+*vK! >gi\k3b:lT  x9GEamWܯxt,WJRL^h*PPɒU /Ē}EҸRWS<ȱnjm&5ʭ+[qgUSmqIvs cz={Z9.v_!vם㩁_hRcxcD5IJxA$odZ>2IƋs1!8n0ɐpdi9 e'=}au1]L&\`3{CvVe]FΨUՌ'73 i r?!JԃIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/radio_unchecked_pressed@2x.png000066400000000000000000000040371516472651200267500ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxlU? ,nQ"H\@h fۢ8cR:8L1V,!cda-l.u SRo;=+>sss=p\4eNE뀙S =@ฉfqٿtu[[ܡkpaa0^ĥ3S!Hx̠2Xwx~EC-X'( +fJnR#F6] n.>f"$4HqĘfIdY(mD`e<{s4G湰 dSoL6R|W.[/ʭwӜ`ٲryq:t(L!jSa!?{v*Oēk379'^rJĪ@k15n6l}UN!<*(WĒXo.1sJ@`pOwU[{.FJCP+C4-_lc9xF/"FX5XE;vO:hmUAN@c(Z8M2Gq¢jה;ǡ{Kx:8Y[_WS2,Wb&k3)mKvi<Ю^Cjh ;4w&uXc:pWmּ`fJ5PWLu3&`k<&so\k 6<3KIV -Qju`(&6M1 zL7upOun2GU%T0 WH;d~͂/ pv\sru ̱RbN/4藔w 1̎;g|εyʤLÕ6vO`|*p|4Bk7m#UČ@qOGP$蓪a 3N'i/z .9ͱ'jna`cv;''$?_$?#7\(4Pj}I?jL͏3XĔT'=8=v*]1CN@ÑOo7)rAdA]ЦB֖w%qh %%k^[$t0#F):~|_QC6&~2^ZSiA p _j6. ]e_LM{n)q/CNw=I?+,~=v܋\"< 7IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal.png000066400000000000000000000002311516472651200264730ustar00rootroot00000000000000PNG  IHDR szz pHYs+KIDATXױ 0Q Y2xղ V*ߚ *is3|FSsoIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal@2x.png000066400000000000000000000004621516472651200270530ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxб 0oDK4@Dl4i` SQAe;Ľʅ|_"韕?rNz߮[mF~1ν7Y#O3=fz4h @@3=fz4h @@3=fz4h @@3=FǗsM5$sy9w/I-Ο"0IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_disabled.png000066400000000000000000000002301516472651200303210ustar00rootroot00000000000000PNG  IHDR szz pHYs+JIDATXױ 0Q ,pl`+?Ufð{ :.v_~/IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_disabled@2x.png000066400000000000000000000004641516472651200307040ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx퐱 1^vABbVb"`$$-BqA䌄]+w""Lv?ԔY=wKV6#O1S}XVŗ~ki @ 1-@cZh4h @ 1-@cZh4h @ 1-@cZh4h @ Ьe%9&uN}EDZxL"0W)IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_focus.png000066400000000000000000000002331516472651200276740ustar00rootroot00000000000000PNG  IHDR szz pHYs+MIDATX FaVqt}\6"L͗Vqr3(|F2;J LZIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_focus@2x.png000066400000000000000000000004631516472651200302530ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx풱 0"LBQ0;UDTCN+r""L}IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_pressed.png000066400000000000000000000002321516472651200302210ustar00rootroot00000000000000PNG  IHDR szz pHYs+LIDATX FakS lL*B|~ݣF0^9?&2;E5IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_pressed@2x.png000066400000000000000000000004611516472651200305770ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx @ѿR,$'+,2E{o @@3=fz4h @@3=fz4h @@3=fz4h @m&[58/I_{8IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_vertical.png000066400000000000000000000002161516472651200261160ustar00rootroot00000000000000PNG  IHDR szz pHYs+@IDATXӡ х.kfRD4:mX٧έ:$K{@:@|$Ip IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_vertical@2x.png000066400000000000000000000003211516472651200264650ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxױ @}@S -"wB#/7Ojpuee/[JW賤Z||nl'ɩ?hmH2jk.@7w~v ) fIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_disabled.png000066400000000000000000000002111516472651200277400ustar00rootroot00000000000000PNG  IHDR szz pHYs+;IDATX!TcIJMZ$}su<궒Sҕ/$ ? !IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_disabled@2x.png000066400000000000000000000003231516472651200303160ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxױ @}@BD@ 9[hIћzdτ .(m|M2&9v賦$FOSMpqYIm.)C S]> `'>^8IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_focus.png000066400000000000000000000002201516472651200273100ustar00rootroot00000000000000PNG  IHDR szz pHYs+BIDATXc``Q0Pj?:ٻv+,'`Q0 F IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_focus@2x.png000066400000000000000000000003251516472651200276700ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxױ P 3CD,B(2Q `&,iQ"W\9`?jnsZ$ }S1?lr'Ik9ֆi>?P铼~_eYU_? . o"-IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_pressed.png000066400000000000000000000002131516472651200276400ustar00rootroot00000000000000PNG  IHDR szz pHYs+=IDATXӡENbY90I)^ I,@~5__ Iw0 FƪIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_pressed@2x.png000066400000000000000000000003161516472651200302160ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxױ P  XEQelLeТm<8s@?:x[1-liJ_;<G\>I.IuX+,d{Sa G\> t#6+IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal.png000066400000000000000000000002241516472651200275270ustar00rootroot00000000000000PNG  IHDR szz pHYs+FIDATXױ Qb\܄y-ZlLh> @ @]̜IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal@2x.png000066400000000000000000000004401516472651200301010ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxСPD EdZ@Q]P ]A6T?a8'It]/bF<$$;>^ @@@@@@@@@@@@@@@@@@@@@@@@@dǗ{U,wۋر&cB`|ӽ*'4555555555555555555555555/X!9&rWU ˏPIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_focus.png000066400000000000000000000002271516472651200307310ustar00rootroot00000000000000PNG  IHDR szz pHYs+IIDATXA  J}ZH&@c|+QdWd1=Y޽4p3?#'EcIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_focus@2x.png000066400000000000000000000004421516472651200313020ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxұ 0D3C, (؁` (QCɝ_I u:˼|?nbF\$I 0=~*'4555555555555555555555555ct^1cTIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_pressed.png000066400000000000000000000002261516472651200312560ustar00rootroot00000000000000PNG  IHDR szz pHYs+HIDATXױ AMRPaǺ6EuFu:4l^73y DIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_pressed@2x.png000066400000000000000000000004421516472651200316300ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxұmPF ( +&1؂D=}Lw?o\c;u92y؝ ;P=@+@ hZzV=@+@ hZzV=@+@ hZzV=@w%3sߞHƾ T {IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical.png000066400000000000000000000002111516472651200271430ustar00rootroot00000000000000PNG  IHDR szz pHYs+;IDATX!zsYv ITӴI^v\P/}9/ %IIv IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical@2x.png000066400000000000000000000003021516472651200275160ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+tIDATxб @}@S -"wB#Ė8RmKx&\] pm\oGZw賦*~?OKka?T Inʰw `{_bIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_disabled.png000066400000000000000000000002051516472651200307750ustar00rootroot00000000000000PNG  IHDR szz pHYs+7IDATX!q*AP{$QU짵$I '\(T⣡$I!IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_disabled@2x.png000066400000000000000000000003051516472651200313500ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+wIDATx PYK ؃-xJEĻ `߫cw0; tk1q>k+_/wx$9bJ7貶R%( |lMIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_focus.png000066400000000000000000000002151516472651200303460ustar00rootroot00000000000000PNG  IHDR szz pHYs+?IDATXc``Q0 F:`1Tg߁N&D' G(`Q0 pOsIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_focus@2x.png000066400000000000000000000003071516472651200307220ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+yIDATxб @=hh"A1T`hI?-pu&2<״LI*sR}xOrnM˼`*cUUƽ{-f5IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_pressed.png000066400000000000000000000002071516472651200306750ustar00rootroot00000000000000PNG  IHDR szz pHYs+9IDATX͡c'],=ځ$I '\ȏP⋡$I\QIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_pressed@2x.png000066400000000000000000000003001516472651200312410ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+rIDATxб @}Ё刊" HL`o 1K2uC3-ILIN2RϚMη$.\o D-QIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/transparent.png000066400000000000000000000001501516472651200240730ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX nH@ GIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/transparent@2x.png000066400000000000000000000001651516472651200244530ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+'IDATx  Om7w@@QIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/transparent_disabled.png000066400000000000000000000001501516472651200257220ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX nH@ GIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/transparent_disabled@2x.png000066400000000000000000000001651516472651200263020ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+'IDATx  Om7w@@QIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/transparent_focus.png000066400000000000000000000001501516472651200252720ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX nH@ GIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/transparent_focus@2x.png000066400000000000000000000001651516472651200256520ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+'IDATx  Om7w@@QIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/transparent_pressed.png000066400000000000000000000001501516472651200256200ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX nH@ GIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/transparent_pressed@2x.png000066400000000000000000000001651516472651200262000ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+'IDATx  Om7w@@QIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_close.png000066400000000000000000000014561516472651200242400ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXOovUI$ G)LZ&T%){vm[2Y&$i@M bm`c˴~g0}(O }c̾j6jϦ*U-z_׏dLXTew}Zbyyi_P\S[Q=C(7 {8Һ=7MD쮇3q1oxB gCWqƑm]՞V-Ix82VSFF?B-^zxSq_x$hE!VN]6.>#:fSY%x,EON*N8IcG'c[ͳڏNA%Ä[^}8kFHO #AE(q3e#3tVPZ"{zչEN(US`6_W|9$&BqCw m 3ȞJ$sO\B]A9*~Q?sם7;l%bQq>;bY$10!}DmZD$P^ OB#r^B8/ b!0B(XY?o}?))0"R\vZwG|H0t5,}Cq@CD5xl㵡i$N~5IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_close@2x.png000066400000000000000000000032771516472651200246150ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+qIDATx]s[WДN?JÅeeiCKI ?GpU.Eo7h:e()P 0l7'Ņ>9gj-{ӞɒFD<_Lkv|Li{LcAD7{|SD͡{|"phavW6/zxCdh-? SM3<:@.أg*bR϶٫X &\e@OP.g{`B_4~)΀sH&x_ Mb7՚#߾׵bEnhxL)Ʀ wsuZ}C#oS |F?ᡍLlRi/Y`],pHĤKp7X;xp耪Go8vg/\R,N/:7B>{%X{F*hWxAϕ ?d<5ax!?۩ ::0:0,vC@&ǒ'Tm*LF;Lm\Z;4m Ϲxk;|p5}cuyԜ|耪W*CEL9;Y Q^j{̹,'vg +X?4\KyRۤ@ M| 4S0juF8KyHv@U}^A8*|ln`'U>rߐ>XlVH++Vk<6T\t 82OTL QzGdmTၗ;J 5R90㺿}:`4(/Y UUt@8:2bDAz}I(5;P%ߖ>mC;~xWU8#_>u@x(7gx{KHlǢ||;!7KLWojLz[d`)TEq*F  QWûϼEƗ fK9@[:6kx;VUm2a}ZȈC 3trR$3?2* LwDڿm2\fO>%h'6ুW»W0 k~Lt T8 ;J];u@$vhhbvʵ;mxzoxBfڨL : _K9vhl[m M;`y4mPa ;~kFpjvBo͘x{k1XQJxf5'@rL`iͪ(\FR*ܻ>cY%7Q(߄{>5ڏ#CRa ' \V".D/[%;^0Ro? h> {=L'LS &6IZJ Q,0@RX,5<@HbkL= B2ٜ[meK$a7LY2MoM;bOhȘ(G.p09Nڂyޒ1G4C'pRoǴrgF$/$N .BrI$ O n))BDb|D-8ܾg/s&[d6THc<:[4]G ߧ{{F 9i͑a7~ݟ.rC[˯|?$ݟ#6,D5կ F}}-.VnOXp3PS1Q+W:uO+~[q;uJHP)>h#gK\Z?NY!#K^pg}?ϣAc/욪.g4, dǚQ9\MB?067>|%Yvip98Ha+`_UvT:I ުW%A?4 G*??sENJ2BFwXd>ׯSoOOks'?ﭨ, LT;iNs?c//IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_close_focus.png000066400000000000000000000013141516472651200254300ustar00rootroot00000000000000PNG  IHDR szz pHYs+~IDATXIr@ggY+W` $x ,R2&UC` ‘ ɒ [IV{ItpS7MTvyW( E^| Q)p0QږUlo P7r{%Tp-(r0ĺ#NSr(PUF: I$,ǫ\R{DS=(數޹Pu~_!-)"{CFbD ԰R_/洲Dfr.IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_close_focus@2x.png000066400000000000000000000032551516472651200260100ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+_IDATxs[EP<&%͔+A  !N N7"UP,XTlX`YJlKod,,[bl YHW[=:ݿð?#w+wQ#%%Pe3zkT lVhl0ϡD6-(<85':>t_h"˜"t(/Y@4[Tγpt/kO7 #M?klV,x MS<ͱ I^cm**x]?9lԎu%w4*ogw@1LJL3a7o+Ҳ{ A?Xm;|<:@ -4bL-Q9T}Xy((ѝOE7x|e<ĺJ.%#XJO!#P\8}2 %gv[HmvT)X=gk-y ׅ%gv[%Bx-=-@HvY%l5ເܮHu[@v x-{/(8G"jq.6 -;)hԕ'h&ѹ: ĺYOިOWb \ER8sHt.qR^)P&l$F0W$1F@oAUI^K !_22Uv(icPnՁpC#Q;_ݡ̚C8pEi nj4 f4 HtVJ޹(kYg hZoEд^3,T2Z7;>hZ$%⹥ӎ&Ss#ya2oբF7Wip*8ZWbL%8ߤT*wEN<+wڥٽ}E'*`܂g%V|>Ad{5y~B`4&FTvZQ$app`|g|^_G;ieIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_close_pressed@2x.png000066400000000000000000000031541516472651200263340ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxsSu?G@ :-T^ytw $u.tpRWG>yI눏0+EPʫ;.tJnro~{9n&%-,x憮?CcJ K*ןN &VM4 @]#+$=ZQ @ԓB? xflJ``(}c5yeSGeX5_ K((J_&qmQzXYV UBרFaR[s P{!1LhOKWp(ۡ`s Вj_K/T|iB?PT\r5w\#j9p(J !H BPdU8LxkF5KcShXZ̃j !J`-:2ߣN ~XZ:r%('Uiu5>&qmqZV; ~ ~̫0L9]oL8(Ǣrx! 8&?p4ɸ\V> duk(3tN`؏ ^;"^pquDǪ'y5HpI &&sڴ WC[:"Csbr־EE9ˠKuRa_**?pfu ø|Q 70_TfLZ,!Bufu}M:2lcX if '=?:26!4NGt_qpmK  bv5bRܯz_op8y~L~/h^do 0',^q(4)dTbk_MJ+i~J2_TPdkv9c|Q]Y=`oʟ t\~\yθ _Lz |R\1ǡm {KyO,MȽy۔O,p%Z^oZ#Jvm/lhl(\\|`ll*#,rЈ9p Q< `YY>\e;*@(+#΁ sиS8X[<M2,vO]BfpN otA:acqVlX+^LƿvJЛM~$S C\\\y(Qx%x؄e\|C||||M| K]e+=QryMu%gX%oØkIy85A/w<-k>ç"/::|eq~:o+BJ0#GGWR+-ZMWMyZ5pn2IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_grip_disabled.png000066400000000000000000000006551516472651200257230ustar00rootroot00000000000000PNG  IHDR szz pHYs+_IDATXֱN0Ny:Hv$xRĂDN0Ğ@4%vÀG't2%mb49w ar …IJG裼d,MpM _ŲWN0 n9 ؝{M70ŎxXʆiL)n@U#X\r!;.P5?,Uu6UTv0 oԊcW5IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_grip_disabled@2x.png000066400000000000000000000013331516472651200262670ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx횽nP/* lQ ++wT0 ni&7 ) "*`9>;ڟ_XGuYg#E/v;RqsgkE-E#@QtR}gg*,~.เLΕR@* ;nn!Nx#|JB#0}-\;x}ܽ19_C1A5   < 'xp,7xp(Gxp$,e]`Y`Q@`I@(`A@H`X@h`P@`H@`39W7޲}ǧg KVh0WgeO0xQް1OR d= ?dߢ+ (+<\A+xeeKt2">ٷ(UCwga~N_>/qo<1s83 &8̡\Z>Hh>~c:yI ͳX}s78/&YgUI{IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_grip_focus.png000066400000000000000000000006531516472651200252710ustar00rootroot00000000000000PNG  IHDR szz pHYs+]IDATXOJ@MCA#*UW TxGO)^DNxGf 4-Vq=5OoWkͣ_{p<%* 4 Xx #n ?%pI1+ /ZcnB6,OhU$^kWEnK [5kl0iͤ :DIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_grip_focus@2x.png000066400000000000000000000013501516472651200256360ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx횽nAFu.K_ %/ACdD@ NqAxG"m)!KfYcڷihaYZ"=ՌFwUx.[5~JYsQްj {jA]K*7}՚>KVNTx^KR7KΩ$^F`%9荷 O n? ؊tπSrÛ΃S *[JJ^ɚ΃G~RVr&vɚΛZHW}ͻ5yZ?<$ㅅIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_grip_pressed.png000066400000000000000000000006701516472651200256160ustar00rootroot00000000000000PNG  IHDR szz pHYs+jIDATX1N0C8Aa@ -@ $Qэ $v  01V4vjl)߇4 J 7yGN&qcv16  W`H*>봍 N7IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_grip_pressed@2x.png000066400000000000000000000013071516472651200261660ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+yIDATx횽n@F]HB]ā74P$O ﺣ $R@a&v6g3^Ҿ4H C 5:tוzxQKe #WbϨuylc(W̾^ (~/ۻW agWYi"˞鍀&MCClClClCdlCD\C$\C\C\C|C|ClgBy 0Z5TD:ߙ1 l/GL͞`8?w ~)cs=*N7AGet& xH@(Ё_wDr. dxp, txp( xp$ xp &x, 6x( Fx$ Vx/xDfuz[`&~>\Tb&YH@s-3^7f`fgAyktK@_r`7ݑy-aB?XDW5*.P"y%UyM7LsT W5Ip VRRJZ-vS'/Da3OIΫtkFyd3oָ0wVjIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_minimize.png000066400000000000000000000003101516472651200247400ustar00rootroot00000000000000PNG  IHDR szz pHYs+zIDATX!1u@C& =ݤw ՚&f>7Kfɬ1.] x3`l1=]@rr:w43cV' 7^IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_minimize@2x.png000066400000000000000000000005161516472651200253220ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx1JQE2B,,D ;`'tad)l hBdlbpW;I$I$I$Ÿ~dQF90{T#`eQ2EYﮟcm^o7VvMyy}ҧ:t/Qad 40WKG2j8rlRU$ ko>s=KŚ, I$I$I$IM6̮aIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_minimize_disabled.png000066400000000000000000000003161516472651200265750ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX1 @6w lNba,= )r!w0*A <)5*t[ߒgs;r0ȨxxutPm e 뀈 Ӝt^B'433k!'IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_minimize_disabled@2x.png000066400000000000000000000005151516472651200271500ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx!NPsi'$x6@@߀Ǵ>͝=%{zsI1C9@#e[=;B') GQ UD|IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_minimize_focus@2x.png000066400000000000000000000005151516472651200265200ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATxֱ.QlB6Z$ hlVyDBC"BcV~Oq43 I$I$I$uBc>ԥWP3 oX?yXCo`Xh\&S(~1=6X?/XP.Iظ;XySas{y~/2Jvԙn5#rF[y٤ acKxR]S( I$I$I$I]|4C꿤IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_minimize_pressed.png000066400000000000000000000003121516472651200264670ustar00rootroot00000000000000PNG  IHDR szz pHYs+|IDATXұ 0);kobB1Re3H@;K%)j=+fffE$zpjYN#B_& - 20_xּ 8JLn"+uT IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_minimize_pressed@2x.png000066400000000000000000000005071516472651200270470ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx!N@o]@$ VHb8XEC"0EB!&vdpM_L $I$I$I 1pHUL/!t9n#GZoXw]nxK7Oq}YBdDM$GSˊ?|yͺfYae M6@U)"pF E 5o0x>F-{"n I$I$I$IC̓7 YQIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_undock.png000066400000000000000000000010121516472651200244020ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX1K@/)TPhbRpA REqAt)~'~A .E#BE-hiMlڄ3.{w0a1E ΁( G+ "Y]k)JThr7c+Jx]Ha# $JnϽa4Q=z%QyPn'MԀHCqI޵K% )-pq`*Yiq@Gުku\mAkZ7tŐZ9q9wD_:IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_undock@2x.png000066400000000000000000000016131516472651200247630ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+=IDATxOAƿ[h)"J"@-ģg=x3bbBb聣1zzӄZV6@Kj-Xw{|} ϐdeKc%)eb@36}juadٕVh@8ɓK:N#RNc4F"/V̀: Y+yC'[̈́ N&ám#HkV}rMlR|]Q}Sb;@,LC~si׵b!yl,0d M`l -@67f!t`%4Q*≡S1|~wkVmqm"3O-cPhg5*ASZц&d  @4ĸ-2QA4ՆOJ`2DJU1!Mn2T}d!7Dz.H ee?͂tս!B?&Bl8Vm@>б71/d M`l -@6&0@ '@֎خl T6bTɀ|Ml:Ͽm@x`IENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_undock_disabled.png000066400000000000000000000010031516472651200262310ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXVNP=(89HLChat11ƅB'I@JR B{@+-mv3w;{ME-jJWN@6X(bo!y ؎Vb5g7;9$zɜ8 I߀F],5ϥ%ŴjͅqH^BG i. A<..e'ƕ,:rCK@O^ʄn}]p|x0pIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_undock_disabled@2x.png000066400000000000000000000015611516472651200266140ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+#IDATxkQƿ3X u!;m6UtN ZܔKEtѥ|LN p" ".)&s\RLLNoӹ92p&Peq&P!,<1ϻl:QsvT۹Q(0JϫM1.;cԶYqFO AvŹČED0p)$66w-Pc0 \}L q4о?q7'~Caj5x'?Jk(dl,T P-@5T{BKKF6΃pQgw0(Кi~k{Ԭڲv*K+AoZu X+)=@eoI&5 kFyB26i!e;TV.wAG1\ ,ݔ.H${oyEta=%!et'EK`}} X+6/FZjFZjFZjBOֻW ʑX@c1QpKPa̯oДAkx`O._upfxgٕkdOgIDX7CB"Qd_J4 D|5} h7l<:8xDhBh=0K$ SާR} "w(3oJiq}6 HQX`{{?h4/b#ԽGIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_undock_focus.png000066400000000000000000000010231516472651200256030ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX햱KQ?@6!P@'J`qqp0.".N.tK'.B tl&i!K;6~zx׋ɐ|~`%fD!xDҥkgՃb-!e Ÿ*Ny1 kݛӏ`xc/S]!G;v}x?}uDĈx䓯=n%׿XorcgAT>v2Wv5-/AwTD7@ڛ_@9,@K9ʥ|]",yJk`0p(]W*enrJ\wfHLah19Hl pr}.B$4BXKn+<Km|wuԂԹIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_undock_focus@2x.png000066400000000000000000000015541516472651200261660ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+IDATx=LAo !B.BbkG!0p|†PZ g(m1&`v;)G(4x~ ñ+޽̾ P( MП-$0Io4d° C[z]/@ Y7`ѝ<tlC=ua!SۓۀlU"vx|; L&]{÷vM{5LQS{k,h*toôcfŅ -@6d -@67a#7ٹĸ@QaZz"O|ngצDFh!.|aۅL/5j%`4y&wi,j@o4Д+]Uad*bz?:+"ÀMR,tzwLDb Q(4LBtG} bkd]BZ|> ԥiEd&2@(d 2@(d 2@(d Mit{kbJH `hcq2xl`\ 0vo6TAg{'O˟9e~8j]+hJ:&u( ̀7" oEu@6(V͉H0`m<݀}xXdžܮP{" g #闢wK2=[?4IO,'E0 b(bV':B=Bc hIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_undock_pressed.png000066400000000000000000000007631516472651200261430ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATX햿JP yA" 8(.SѥO" y)\\t5!ѤIM{r ]A"0ѫ\ZzB:-%L=~qE6vse_ɺS_ﴷJ / nI F*훁v N:b+yC7xnqQ>* |WPm.$),@u .p'#XLB{#4mxg*lxzq9awN PhI-: lT$1t:| @`v@2pZ@9=w 󭂡/PLf餜 UUWTx`7rdLJʶ2Smxr/!`tvzIENDB`seer-2.7/src/resources/qdarkstyle/light/rc/window_undock_pressed@2x.png000066400000000000000000000015271516472651200265140ustar00rootroot00000000000000PNG  IHDR@@iq pHYs+ IDATx=hAo/FDD )a-B@Tب ) ؈j'sI!Pp " HTݻdrٹ󿙝aAJJJFtGx"be9h_:G2 YQBvɋr}Z<ߪX6V\f،Ten2ETLm/i@aa;K %m(m?=zcQd X 5ϻ]l\^czy#5ۤ`lxUkǀ=V1P&=#?k"gyzF! 2-$yκ2GUNj%a<@ s3zd@ڇ0h2ɠfT7z@{@Ǐt>!Hdb"NHFtgCB_)Ҋ0Y'\ꐚ:?d<+pjmI -6&5ۤ`lSK}-V˥ ɚ\iS p7%bI1T7\.W/\O@hKw/ [.42r]*u]5ǰך%q z|;IL|5gK"2g@b"Y781g#NPDsNn <104ʰ-L47Iu-2d2I/j{aP8ۤuA&dQd:_JJJ NlaXIENDB`seer-2.7/src/resources/seergdb.desktop000066400000000000000000000002411516472651200201350ustar00rootroot00000000000000[Desktop Entry] Name=SeerGdb GenericName=Debugger Comment=GUI frontend to gdb. Exec=seergdb Icon=seergdb Terminal=false Type=Application Categories=Development; seer-2.7/src/resources/seergdb.metainfo.xml000066400000000000000000000020131516472651200210640ustar00rootroot00000000000000 seergdb.desktop SeerGdb

A modern GDB front-end CC0-1.0 GPL-3.0-or-later AND LGPL-3.0-or-later AND BSD-2-Clause AND MIT AND CC-BY-3.0 AND CC-BY-4.0 https://github.com/epasveer/seer

Seer is a graphical user interface to the GNU Debugger (gdb) for Linux.

It provides a simple yet visually pleasing interface to gdb, making it easier to debug applications without using the command line directly.

seergdb.desktop https://github.com/epasveer/seer https://github.com/epasveer/seer/issues seer-2.7/src/resources/thenounproject/000077500000000000000000000000001516472651200202015ustar00rootroot00000000000000seer-2.7/src/resources/thenounproject/assembly.svg000066400000000000000000000124131516472651200225420ustar00rootroot00000000000000 image/svg+xml seer-2.7/src/resources/thenounproject/configure.svg000066400000000000000000000637061516472651200227170ustar00rootroot00000000000000 image/svg+xml seer-2.7/src/resources/thenounproject/fortune-teller.readme000066400000000000000000000013261516472651200243310ustar00rootroot00000000000000 The Seer icon is from: https://thenounproject.com/icon/fortune-teller-3505303/ noun-fortune-teller-3505303.svg https://creativecommons.org/licenses/by/3.0/ Convert to png and resize. mv noun-fortune-teller-3505303.svg fortune-teller.svg convert -background transparent -resize 32x32 fortune-teller.svg ../seergdb_32x32.png convert -background transparent -resize 64x64 fortune-teller.svg ../seergdb_64x64.png convert -background transparent -resize 128x128 fortune-teller.svg ../seergdb_128x128.png convert -background transparent -resize 256x256 fortune-teller.svg ../seergdb_256x256.png convert -background transparent -resize 515x512 fortune-teller.svg ../seergdb_512x512.png seer-2.7/src/resources/thenounproject/fortune-teller.svg000066400000000000000000000322301516472651200236710ustar00rootroot00000000000000 seer-2.7/src/resources/thenounproject/keyboard.svg000066400000000000000000000407241516472651200225310ustar00rootroot00000000000000 seer-2.7/src/resources/thenounproject/memory.svg000066400000000000000000000431711516472651200222400ustar00rootroot00000000000000 image/svg+xml seer-2.7/src/resources/thenounproject/preferences.svg000066400000000000000000000016341516472651200232270ustar00rootroot00000000000000Created by Blair Adamsfrom the Noun Project seer-2.7/src/resources/thenounproject/source.svg000066400000000000000000000561541516472651200222350ustar00rootroot00000000000000 image/svg+xml seer-2.7/src/resources/thenounproject/stop.svg000066400000000000000000000542461516472651200217220ustar00rootroot00000000000000 image/svg+xml seer-2.7/src/seergdb.cpp000066400000000000000000000317651516472651200152530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMainWindow.h" #include "SeerUtl.h" #include "QProcessInfo.h" #include #include #include #include #include #include #include #include #include #include #include #include static void seerhelp() { QString text; QString fileName(":/seer/resources/help/seergdb.hlp"); QFile file(fileName); if (file.open(QIODevice::ReadOnly) == false) { text = "seer: no help available.\n"; }else{ text = file.readAll(); } file.close(); QTextStream(stdout) << text; exit(0); } int main (int argc, char* argv[]) { // // Set up logging and message formats. // QLoggingCategory::setFilterRules("*.debug=false\n" "*.info=false\n" "*.warning=false\n" "*.critical=true"); qSetMessagePattern("[%{time hh:mm:ss}][%{function}:%{line}][%{category}] %{message}"); // // Create the app. // QApplication app(argc, argv); QCoreApplication::setApplicationName("seergdb"); QCoreApplication::setOrganizationName("seergdb"); QCoreApplication::setApplicationVersion(Seer::version() + " - Ernie Pasveer (c)2021 - 2025"); // // Parse arguments. // QCommandLineParser parser; parser.setApplicationDescription("\nSeer - A gui frontend for gdb."); parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments); // Treat all arguments after the executable name as positional arguments too. parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); // Treat all arguments long options. parser.addVersionOption(); // Run or start options. QCommandLineOption runOption(QStringList() << "r" << "run"); parser.addOption(runOption); QCommandLineOption startOption(QStringList() << "s" << "start"); parser.addOption(startOption); QCommandLineOption attachOption(QStringList() << "attach", "", "pid"); parser.addOption(attachOption); QCommandLineOption connectOption(QStringList() << "connect", "", "medium"); parser.addOption(connectOption); QCommandLineOption rrOption(QStringList() << "rr", "", "hostport"); parser.addOption(rrOption); QCommandLineOption corefileOption(QStringList() << "core", "", "corefile"); parser.addOption(corefileOption); QCommandLineOption projectOption(QStringList() << "project", "", "project"); parser.addOption(projectOption); QCommandLineOption configOption(QStringList() << "config"); parser.addOption(configOption); QCommandLineOption workingdirOption(QStringList() << "cwd" << "working-dir", "", "workingdirectory"); parser.addOption(workingdirOption); QCommandLineOption symbolfileOption(QStringList() << "sym" << "symbol-file", "", "symbolfile"); parser.addOption(symbolfileOption); QCommandLineOption breakfileOption(QStringList() << "bl" << "break-load", "", "breakpointfile"); parser.addOption(breakfileOption); QCommandLineOption breakfunctionOption(QStringList() << "bf" << "break-function", "", "breakpointfunction"); parser.addOption(breakfunctionOption); QCommandLineOption breaksourceOption(QStringList() << "bs" << "break-source", "", "breakpointsource"); parser.addOption(breaksourceOption); QCommandLineOption showAssemblyTabOption(QStringList() << "sat" << "show-assembly-tab", "", "showassemblytab"); parser.addOption(showAssemblyTabOption); QCommandLineOption startAddressRandomizeOption(QStringList() << "sar" << "start-address-randomize", "", "startaddressrandomize"); parser.addOption(startAddressRandomizeOption); QCommandLineOption nonStopModeOption(QStringList() << "nsm" << "non-stop-mode", "", "nonstopmode"); parser.addOption(nonStopModeOption); QCommandLineOption gdbProgramOption(QStringList() << "gdb-program", "", "gdbprogram"); parser.addOption(gdbProgramOption); QCommandLineOption gdbArgumentsOption(QStringList() << "gdb-arguments", "", "gdbarguments"); parser.addOption(gdbArgumentsOption); QCommandLineOption xxxdebugOption(QStringList() << "xxx-debug"); parser.addOption(xxxdebugOption); QCommandLineOption xxxresourcesOption(QStringList() << "xxx-resources"); parser.addOption(xxxresourcesOption); QCommandLineOption xxxstylesOption(QStringList() << "xxx-styles"); parser.addOption(xxxstylesOption); QCommandLineOption helpOption(QStringList() << "h" << "help"); parser.addOption(helpOption); // A positional argument for executable name. // All other arguments after that are treated as positional arguments for the executable. parser.addPositionalArgument("executableandarguments", ""); // Process the arguments. parser.process(app); if (parser.isSet(helpOption)) { seerhelp(); } if (parser.isSet(xxxdebugOption)) { QLoggingCategory::setFilterRules("*.debug=false\n" "*.info=false\n" "*.warning=false\n" "*.critical=true\n" "default.debug=true"); QSettings settings; qDebug() << "SETTINGS" << settings.fileName(); } if (parser.isSet(xxxresourcesOption)) { QTextStream(stdout) << "RESOURCES" << "\n"; QDirIterator it(":", QDirIterator::Subdirectories); while (it.hasNext()) { QTextStream(stdout) << " " << it.next() << "\n"; } QTextStream(stdout) << "ENDRESOURCES" << "\n"; return 0; } if (parser.isSet(xxxstylesOption)) { QTextStream(stdout) << "STYLES" << "\n"; QStringList styles = QStyleFactory::keys(); for (auto style : styles) { QTextStream(stdout) << " " << style << "\n"; } QTextStream(stdout) << "ENDSTYLES" << "\n"; return 0; } // Get the positional arguments. (The ones at the end of the line - executable name and its arguments. QStringList positionalArguments = parser.positionalArguments(); // Get the executable name from the arguments; QString executableName; if (positionalArguments.size() > 0) { executableName = positionalArguments.takeFirst(); } // Get launch mode. QString launchMode = "none"; QString breakMode = "none"; int executablePid = -1; QString executableConnectHostPort; QString executableRRTraceDirectory; QString executableWorkingDirectory; QString executableSymbolFilename; QString executableBreakpointsFilename; QString executableBreakpointFunctionName; QString executableBreakpointSourceFilenameAndLineno; QString executableShowAssemblyTab; QString executableStartAddressRandomize; QString executableNonStopMode; QString executableCoreFilename; QString projectFilename; QString gdbProgram; QString gdbArguments; if (parser.isSet(runOption)) { launchMode = "run"; breakMode = "none"; } if (parser.isSet(startOption)) { launchMode = "run"; breakMode = "inmain"; } if (parser.isSet(workingdirOption)) { executableWorkingDirectory = parser.value(workingdirOption); } if (parser.isSet(symbolfileOption)) { executableSymbolFilename = parser.value(symbolfileOption); } if (parser.isSet(breakfileOption)) { executableBreakpointsFilename = parser.value(breakfileOption); } if (parser.isSet(breakfunctionOption)) { executableBreakpointFunctionName = parser.value(breakfunctionOption); breakMode = "infunction"; } if (parser.isSet(breaksourceOption)) { executableBreakpointSourceFilenameAndLineno = parser.value(breaksourceOption); breakMode = "insource"; } if (parser.isSet(showAssemblyTabOption)) { executableShowAssemblyTab = parser.value(showAssemblyTabOption); } if (parser.isSet(startAddressRandomizeOption)) { executableStartAddressRandomize = parser.value(startAddressRandomizeOption); } if (parser.isSet(nonStopModeOption)) { executableNonStopMode = parser.value(nonStopModeOption); } if (parser.isSet(attachOption)) { launchMode = "attach"; QString pid = parser.value(attachOption); executablePid = pid.toInt(); if (executableName == "") { QProcessInfo info = QProcessInfo::populate(executablePid); executableName = info.path() + "/" + info.name(); } } if (parser.isSet(connectOption)) { launchMode = "connect"; executableConnectHostPort = parser.value(connectOption); } if (parser.isSet(rrOption)) { launchMode = "rr"; executableRRTraceDirectory = parser.value(rrOption); } if (parser.isSet(corefileOption)) { launchMode = "corefile"; executableCoreFilename = parser.value(corefileOption); } if (parser.isSet(projectOption)) { launchMode = "project"; projectFilename = parser.value(projectOption); } if (parser.isSet(configOption)) { launchMode = "configdialog"; } if (parser.isSet(gdbProgramOption)) { gdbProgram = parser.value(gdbProgramOption); } if (parser.isSet(gdbArgumentsOption)) { gdbArguments = parser.value(gdbArgumentsOption); } // // Start Seer // SeerMainWindow seer; seer.setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); seer.setExecutableName(executableName); seer.setExecutableWorkingDirectory(executableWorkingDirectory); seer.setExecutableSymbolName(executableSymbolFilename); seer.setExecutableArguments(positionalArguments); if (executableBreakpointsFilename != "") { seer.setExecutableBreakpointsFilename(executableBreakpointsFilename); } if (executableBreakpointFunctionName != "") { seer.setExecutableBreakpointFunctionName(executableBreakpointFunctionName); } if (executableBreakpointSourceFilenameAndLineno != "") { seer.setExecutableBreakpointSourceName(executableBreakpointSourceFilenameAndLineno); } if (executableShowAssemblyTab != "") { if (executableShowAssemblyTab == "yes") { seer.setExecutableShowAssemblyTabMode("always"); }else if (executableShowAssemblyTab == "no") { seer.setExecutableShowAssemblyTabMode("never"); }else if (executableShowAssemblyTab == "auto") { seer.setExecutableShowAssemblyTabMode("auto"); }else{ printf("%s: Unknown --show-assembly-tab option '%s'\n", qPrintable(QCoreApplication::applicationName()), qPrintable(executableShowAssemblyTab)); return 1; } } if (executableStartAddressRandomize != "") { if (executableStartAddressRandomize == "yes") { seer.setExecutableRandomizeStartAddress(true); }else if (executableStartAddressRandomize == "no") { seer.setExecutableRandomizeStartAddress(false); }else{ printf("%s: Unknown --start-address-randomize option '%s'\n", qPrintable(QCoreApplication::applicationName()), qPrintable(executableStartAddressRandomize)); return 1; } } if (executableNonStopMode != "") { if (executableNonStopMode == "yes") { seer.setExecutableNonStopMode(true); }else if (executableNonStopMode == "no") { seer.setExecutableNonStopMode(false); }else{ printf("%s: Unknown --non-stop-mode option '%s'\n", qPrintable(QCoreApplication::applicationName()), qPrintable(executableNonStopMode)); return 1; } } if (gdbProgram != "") { seer.setGdbProgramOverride(gdbProgram); } if (gdbArguments != "") { seer.setGdbArgumentsOverride(gdbArguments); } qDebug() << "EXECUTABLENAME" << executableName; qDebug() << "WORKINGDIRECTORY" << executableWorkingDirectory; qDebug() << "SYMBOLNAME" << executableSymbolFilename; qDebug() << "PID" << executablePid; qDebug() << "CONNECTHOST" << executableConnectHostPort; qDebug() << "RRTRACEDIRECTORY" << executableRRTraceDirectory; qDebug() << "COREFILENAME" << executableCoreFilename; qDebug() << "PROJECTFILE" << projectFilename; qDebug() << "ARGUMENTS" << positionalArguments; seer.setExecutablePid(executablePid); seer.setExecutableConnectHostPort(executableConnectHostPort); seer.setExecutableRRTraceDirectory(executableRRTraceDirectory); seer.setExecutableCoreFilename(executableCoreFilename); seer.setProjectFilename(projectFilename); seer.launchExecutable(launchMode, breakMode); seer.show(); seer.activateWindow(); return app.exec(); } seer-2.7/src/seerutl_test.cpp000066400000000000000000000004611516472651200163470ustar00rootroot00000000000000#include "SeerUtl.h" #include int main (int argc, char* argv[]) { Q_UNUSED(argc); Q_UNUSED(argv); QString text("Function\\n1"); QString result; result = Seer::filterEscapes(text); qDebug().noquote() << text; qDebug().noquote() << result; return 1; }