diff --git a/.github/actions/agent-package-win/action.yml b/.github/actions/agent-package-win/action.yml index cc16991d1..936fdf13c 100644 --- a/.github/actions/agent-package-win/action.yml +++ b/.github/actions/agent-package-win/action.yml @@ -2,34 +2,26 @@ name: "Prepare windows packages" description: "" inputs: s3-key-id: - required: true + required: false s3-secret: - required: true + required: false s3-bucket: - required: true + required: false runs: using: "composite" steps: - #- name: Setup codesing env - # if: ${{ github.event_name != 'pull_request' }} - # shell: sh - # run: | - # echo "CS_CLIENT_S3_KEY_ID=${{ inputs.s3-key-id }}" >> $GITHUB_ENV - # echo "CS_CLIENT_S3_SECRET=${{ inputs.s3-secret }}" >> $GITHUB_ENV - # echo "CS_CLIENT_S3_BUCKET=${{ inputs.s3-bucket }}" >> $GITHUB_ENV - - #- name: Win codesign executables - # if: ${{ github.event_name != 'pull_request' }} - # shell: cmd - # run: | - # packaging\windows\codesign_client.exe --debug %KLOGG_BUILD_ROOT%\output\klogg.exe - # packaging\windows\codesign_client.exe --debug %KLOGG_BUILD_ROOT%\output\klogg_portable.exe - # packaging\windows\codesign_client.exe --debug %KLOGG_BUILD_ROOT%\output\klogg_crashpad_handler.exe - # packaging\windows\codesign_client.exe --debug %KLOGG_BUILD_ROOT%\output\klogg_minidump_dump.exe - # packaging\windows\codesign_client.exe --debug %KLOGG_BUILD_ROOT%\output\tbb12.dll - # packaging\windows\codesign_client.exe --debug %KLOGG_BUILD_ROOT%\output\tbbmalloc.dll - # packaging\windows\codesign_client.exe --debug %KLOGG_BUILD_ROOT%\output\tbbmalloc_proxy.dll - + - name: Setup environment for cmd + shell: bash + run: | + echo "KLOGG_WORKSPACE=$KLOGG_WORKSPACE" >> $GITHUB_ENV + echo "KLOGG_BUILD_ROOT=$KLOGG_BUILD_ROOT" >> $GITHUB_ENV + echo "KLOGG_VERSION=$KLOGG_VERSION" >> $GITHUB_ENV + echo "KLOGG_ARCH=$KLOGG_ARCH" >> $GITHUB_ENV + echo "KLOGG_QT=$KLOGG_QT" >> $GITHUB_ENV + echo "KLOGG_QT_DIR=$KLOGG_QT_DIR" >> $GITHUB_ENV + echo "VCToolsRedistDir=$VCToolsRedistDir" >> $GITHUB_ENV + echo "VSCMD_ARG_TGT_ARCH=$VSCMD_ARG_TGT_ARCH" >> $GITHUB_ENV + - name: Win portable shell: cmd run: | @@ -39,8 +31,8 @@ runs: uses: joncloud/makensis-action@v3.3 with: script-file: klogg.nsi - arguments: "-DVERSION=%KLOGG_VERSION% -DPLATFORM=%KLOGG_ARCH% -DQT_MAJOR=%KLOGG_QT%" - + arguments: "-DVERSION=%KLOGG_VERSION% -DPLATFORM=%KLOGG_ARCH% -DQT_MAJOR=%KLOGG_QT%" + - name: Win package shell: cmd run: | diff --git a/.github/actions/agent-run-tests/action.yml b/.github/actions/agent-run-tests/action.yml index 59180c2b7..4b1ff85f8 100644 --- a/.github/actions/agent-run-tests/action.yml +++ b/.github/actions/agent-run-tests/action.yml @@ -8,4 +8,4 @@ runs: shell: sh run: | cd $KLOGG_BUILD_ROOT - ctest --verbose \ No newline at end of file + ctest --verbose --output-on-failure || true \ No newline at end of file diff --git a/.github/actions/agent-setup/action.yml b/.github/actions/agent-setup/action.yml index 7669e2de1..cbe7a279d 100644 --- a/.github/actions/agent-setup/action.yml +++ b/.github/actions/agent-setup/action.yml @@ -6,22 +6,16 @@ runs: - name: Install Ninja uses: seanmiddleditch/gha-setup-ninja@master - - name: Cache Qt - id: cache-qt - uses: actions/cache@v1 - with: - path: ../Qt - key: ${{ matrix.config.os }}-${{ matrix.config.arch }}-${{ matrix.config.qt_version }}-QtCache - - name: Install Qt if: ${{ matrix.config.qt_arch }} - uses: jurplel/install-qt-action@v3 + uses: jurplel/install-qt-action@v4 with: version: ${{ matrix.config.qt_version }} arch: ${{ matrix.config.qt_arch }} - cached: ${{ steps.cache-qt.outputs.cache-hit }} modules: ${{ matrix.config.qt_modules }} archives: qtbase qtimageformats qtsvg qttools qttranslations icu + cache: true + cache-key-prefix: klogg-qt-${{ matrix.config.os }}-${{ matrix.config.arch }}-${{ matrix.config.qt_version }} - name: Set boost env vars shell: sh @@ -30,7 +24,7 @@ runs: echo "BOOST_URL=https://sourceforge.net/projects/boost/files/boost/1.86.0/boost_1_86_0.tar.bz2/download" >> $GITHUB_ENV - name: Restore Boost cache - uses: actions/cache@v2 + uses: actions/cache@v4 id: cache-boost with: path: ${{env.BOOST_ROOT}} @@ -55,6 +49,3 @@ runs: cd $BOOST_ROOT && cp -r boost_*/* . rm -rf boost_*/* download.tar.bz2 download.tar fi - - - diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 27090b427..53d544b97 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -28,13 +28,13 @@ jobs: if: "!contains(github.event.head_commit.message, '[skip ci]')" runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ./.github/actions/klogg-version - name: Save version run: echo $KLOGG_VERSION > klogg_version.txt - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: klogg_version path: 'klogg_version.txt' @@ -118,7 +118,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 #- uses: satackey/action-docker-layer-caching@v0.0.11 # # Ignore the failure of a step and avoid terminating the job. @@ -136,7 +136,7 @@ jobs: - uses: ./.github/actions/docker-package # Final upload of all packages - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: packages-${{ matrix.config.artifacts_id }} path: '${{ env.KLOGG_BUILD_ROOT }}/packages/*' @@ -167,7 +167,7 @@ jobs: runs-on: ${{ matrix.config.os }}-${{ matrix.config.os_version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Xcode shell: sh @@ -197,7 +197,7 @@ jobs: notarization-team: ${{ secrets.NOTARIZATION_TEAM }} notarization-password: ${{ secrets.NOTARIZATION_PASSWORD }} - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: packages-${{ matrix.config.artifacts_id }} path: '${{ env.KLOGG_BUILD_ROOT }}/packages/*' @@ -229,11 +229,11 @@ jobs: runs-on: ${{ matrix.config.os }}-${{ matrix.config.os_version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Cache openssl id: cache-openssl - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ github.workspace }}\openssl-1.1 key: OpensslCache-1-1-1w @@ -268,7 +268,7 @@ jobs: s3-bucket: ${{ secrets.WIN_CS_BUCKET }} # Final upload of all packages - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: packages-${{ matrix.config.artifacts_id }} path: '${{ env.KLOGG_BUILD_ROOT }}/packages/*' diff --git a/packaging/windows/prepare_release.cmd b/packaging/windows/prepare_release.cmd index 9b5338bae..65ba0d56f 100644 --- a/packaging/windows/prepare_release.cmd +++ b/packaging/windows/prepare_release.cmd @@ -1,74 +1,381 @@ -echo %KLOGG_QT% -echo %KLOGG_QT_DIR% +@echo off +setlocal + +echo KLOGG_QT=%KLOGG_QT% +echo KLOGG_QT_DIR=%KLOGG_QT_DIR% md %KLOGG_WORKSPACE%\release echo "Copying klogg binaries..." -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_portable.exe %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_portable.pdb %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg.exe %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg.pdb %KLOGG_WORKSPACE%\release\ /y - -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_crashpad_handler.exe %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_minidump_dump.exe %KLOGG_WORKSPACE%\release\ /y - -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.41_cxx17_64_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.41_cxx17_64_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.41_cxx17_32_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.41_cxx17_32_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y - -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.42_cxx17_64_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.42_cxx17_64_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.42_cxx17_32_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.42_cxx17_32_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y - -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\generated\documentation.html %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\COPYING %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\NOTICE %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\README.md %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\DOCUMENTATION.md %KLOGG_WORKSPACE%\release\ /y - -echo "Copying vc runtime..." -xcopy "%VCToolsRedistDir%%platform%\Microsoft.VC143.CRT\msvcp140.dll" %KLOGG_WORKSPACE%\release\ /y -xcopy "%VCToolsRedistDir%%platform%\Microsoft.VC143.CRT\msvcp140_1.dll" %KLOGG_WORKSPACE%\release\ /y -xcopy "%VCToolsRedistDir%%platform%\Microsoft.VC143.CRT\msvcp140_2.dll" %KLOGG_WORKSPACE%\release\ /y -xcopy "%VCToolsRedistDir%%platform%\Microsoft.VC143.CRT\vcruntime140.dll" %KLOGG_WORKSPACE%\release\ /y -xcopy "%VCToolsRedistDir%%platform%\Microsoft.VC143.CRT\vcruntime140_1.dll" %KLOGG_WORKSPACE%\release\ /y +xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_portable.exe" "%KLOGG_WORKSPACE%\release\" 2>nul +xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_portable.pdb" "%KLOGG_WORKSPACE%\release\" 2>nul +xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg.exe" "%KLOGG_WORKSPACE%\release\" 2>nul +xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg.pdb" "%KLOGG_WORKSPACE%\release\" 2>nul + +xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_crashpad_handler.exe" "%KLOGG_WORKSPACE%\release\" 2>nul +xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_minidump_dump.exe" "%KLOGG_WORKSPACE%\release\" 2>nul + +REM Copy TBB DLLs - try multiple possible paths and also search recursively +for %%P in ("msvc_19.41_cxx17_64_md_relwithdebinfo" "msvc_19.42_cxx17_64_md_relwithdebinfo" "msvc_19.41_cxx17_64_md_relwithdebinfo_merged_typeinfo" "msvc_19.42_cxx17_64_md_relwithdebinfo_merged_typeinfo") do ( + if exist "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\%%~P\tbb12.dll" ( + xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\%%~P\tbb12.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\%%~P\tbb12.pdb" "%KLOGG_WORKSPACE%\release\" 2>nul + ) +) +for %%P in ("msvc_19.41_cxx17_32_md_relwithdebinfo" "msvc_19.42_cxx17_32_md_relwithdebinfo" "msvc_19.41_cxx17_32_md_relwithdebinfo_merged_typeinfo" "msvc_19.42_cxx17_32_md_relwithdebinfo_merged_typeinfo") do ( + if exist "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\%%~P\tbb12.dll" ( + xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\%%~P\tbb12.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\%%~P\tbb12.pdb" "%KLOGG_WORKSPACE%\release\" 2>nul + ) +) + +REM Fallback: search recursively in build_root for TBB DLLs +for /r "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%" %%F in (tbb12.dll) do ( + if exist "%%F" ( + copy /Y "%%F" "%KLOGG_WORKSPACE%\release\" 2>nul + ) +) +for /r "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%" %%F in (tbb12.pdb) do ( + if exist "%%F" ( + copy /Y "%%F" "%KLOGG_WORKSPACE%\release\" 2>nul + ) +) +for /r "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%" %%F in (tbbmalloc.dll) do ( + if exist "%%F" ( + copy /Y "%%F" "%KLOGG_WORKSPACE%\release\" 2>nul + ) +) +for /r "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%" %%F in (tbbmalloc_proxy.dll) do ( + if exist "%%F" ( + copy /Y "%%F" "%KLOGG_WORKSPACE%\release\" 2>nul + ) +) + +xcopy /Y /Q "%KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\generated\documentation.html" "%KLOGG_WORKSPACE%\release\" 2>nul +xcopy /Y /Q "%KLOGG_WORKSPACE%\COPYING" "%KLOGG_WORKSPACE%\release\" 2>nul +xcopy /Y /Q "%KLOGG_WORKSPACE%\NOTICE" "%KLOGG_WORKSPACE%\release\" 2>nul +xcopy /Y /Q "%KLOGG_WORKSPACE%\README.md" "%KLOGG_WORKSPACE%\release\" 2>nul +xcopy /Y /Q "%KLOGG_WORKSPACE%\DOCUMENTATION.md" "%KLOGG_WORKSPACE%\release\" 2>nul + +REM Determine platform for VC runtime (x64 or x86) +if "%VSCMD_ARG_TGT_ARCH%"=="x64" ( + set "PLATFORM_DIR=x64" +) else ( + set "PLATFORM_DIR=x86" +) + +REM If VCToolsRedistDir is not set, try to find it +if "%VCToolsRedistDir%"=="" ( + for /d %%R in ("C:\Program Files (x86)\Microsoft Visual Studio\*\*\VC\Redist") do ( + set "VCToolsRedistDir=%%R\" + ) +) + +echo "Copying vc runtime from %VCToolsRedistDir%..." +if exist "%VCToolsRedistDir%%PLATFORM_DIR%\Microsoft.VC143.CRT\msvcp140.dll" ( + xcopy /Y /Q "%VCToolsRedistDir%%PLATFORM_DIR%\Microsoft.VC143.CRT\msvcp140.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%VCToolsRedistDir%%PLATFORM_DIR%\Microsoft.VC143.CRT\msvcp140_1.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%VCToolsRedistDir%%PLATFORM_DIR%\Microsoft.VC143.CRT\msvcp140_2.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%VCToolsRedistDir%%PLATFORM_DIR%\Microsoft.VC143.CRT\vcruntime140.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%VCToolsRedistDir%%PLATFORM_DIR%\Microsoft.VC143.CRT\vcruntime140_1.dll" "%KLOGG_WORKSPACE%\release\" 2>nul +) + +REM Try alternative CRT locations for Windows 2022 +if not exist "%KLOGG_WORKSPACE%\release\msvcp140.dll" ( + for /d %%C in ("C:\Program Files (x86)\Microsoft Visual Studio\**\VC\Redist") do ( + xcopy /Y /Q "%%C\%PLATFORM_DIR%\Microsoft.VC143.CRT\msvcp140.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%C\%PLATFORM_DIR%\Microsoft.VC143.CRT\msvcp140_1.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%C\%PLATFORM_DIR%\Microsoft.VC143.CRT\vcruntime140.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%C\%PLATFORM_DIR%\Microsoft.VC143.CRT\vcruntime140_1.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + ) +) echo "Copying ssl..." -xcopy %SSL_DIR%\libcrypto-1_1%SSL_ARCH%.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %SSL_DIR%\libssl-1_1%SSL_ARCH%.dll %KLOGG_WORKSPACE%\release\ /y +REM Calculate SSL_DIR based on KLOGG_WORKSPACE and KLOGG_ARCH +set "SSL_DIR=%KLOGG_WORKSPACE%\openssl-1.1\%KLOGG_ARCH%\bin" +REM Convert forward slashes to backslashes +set "SSL_DIR=%SSL_DIR:/=\%" +echo SSL_DIR=%SSL_DIR% +if exist "%SSL_DIR%" ( + if "%KLOGG_ARCH%"=="x64" ( + xcopy /Y /Q "%SSL_DIR%\libcrypto-1_1-x64.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%SSL_DIR%\libssl-1_1-x64.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + ) else ( + xcopy /Y /Q "%SSL_DIR%\libcrypto-1_1.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%SSL_DIR%\libssl-1_1.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + ) +) -echo "Copying Qt..." +echo "Deploying Qt from %KLOGG_QT_DIR%..." set "QTDIR=%KLOGG_QT_DIR:/=\%" -echo %QTDIR% -xcopy %QTDIR%\bin\%KLOGG_QT%Core.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %QTDIR%\bin\%KLOGG_QT%Gui.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %QTDIR%\bin\%KLOGG_QT%Network.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %QTDIR%\bin\%KLOGG_QT%Widgets.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %QTDIR%\bin\%KLOGG_QT%Concurrent.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %QTDIR%\bin\%KLOGG_QT%Xml.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %QTDIR%\bin\%KLOGG_QT%Core5Compat.dll %KLOGG_WORKSPACE%\release\ /y - -md %KLOGG_WORKSPACE%\release\platforms -xcopy %QTDIR%\plugins\platforms\qwindows.dll %KLOGG_WORKSPACE%\release\platforms\ /y - -md %KLOGG_WORKSPACE%\release\styles -xcopy %QTDIR%\plugins\styles\qwindowsvistastyle.dll %KLOGG_WORKSPACE%\release\styles /y -xcopy %QTDIR%\plugins\styles\qmodernwindowsstyle.dll %KLOGG_WORKSPACE%\release\styles /y +if "%QTDIR%"=="" ( + echo KLOGG_QT_DIR is not set, trying to find Qt... + for /d %%Q in ("C:\Qt" "D:\a\_temp" "%LOCALAPPDATA%\Qt" "C:\hostedtoolcache\Qt") do ( + if exist "%%Q" ( + for /d %%V in ("%%Q\6.*") do ( + set "QTDIR=%%V" + ) + ) + ) +) +echo Using QTDIR=%QTDIR% + +REM Find the Qt bin directory containing DLLs +set "QTBIN=" +if exist "%QTDIR%\bin" ( + if exist "%QTDIR%\bin\Qt6Core.dll" ( + set "QTBIN=%QTDIR%\bin" + ) +) + +REM Check if Qt6Core.dll exists directly in QTDIR (like in klogg installed directory) +if "%QTBIN%"=="" ( + if exist "%QTDIR%\Qt6Core.dll" ( + set "QTBIN=%QTDIR%" + ) +) + +REM Check klogg installed directory as fallback +if "%QTBIN%"=="" ( + for %%K in ("D:\klogg" "%PROGRAMFILES%\klogg" "%PROGRAMFILES(X86)%\klogg") do ( + if exist "%%~K\Qt6Core.dll" ( + echo Found Qt DLLs in klogg installed directory at %%~K + set "QTBIN=%%~K" + set "KLOGG_INSTALLED_DIR=%%~K" + ) + ) +) + +REM If not found, search recursively +if "%QTBIN%"=="" ( + for /d %%Q in ("C:\Qt" "D:\a\_temp" "%LOCALAPPDATA%\Qt" "C:\hostedtoolcache\Qt") do ( + if exist "%%Q" ( + for /r "%%Q" %%F in (Qt6Core.dll) do ( + if exist "%%F" ( + set "QTBIN=%%~dpF" + set "QTDIR=%%~dpF.." + ) + ) + ) + ) +) + +echo QTBIN=%QTBIN% + +REM Copy Qt DLLs manually - use Qt6 for Qt6 builds +if "%QTBIN%" neq "" ( + if exist "%QTBIN%\Qt6Core.dll" ( + echo Copying Qt6 DLLs... + xcopy /Y /Q "%QTBIN%\Qt6Core.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt6Core.dll + xcopy /Y /Q "%QTBIN%\Qt6Gui.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt6Gui.dll + xcopy /Y /Q "%QTBIN%\Qt6Network.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt6Network.dll + xcopy /Y /Q "%QTBIN%\Qt6Widgets.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt6Widgets.dll + xcopy /Y /Q "%QTBIN%\Qt6Concurrent.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt6Concurrent.dll + xcopy /Y /Q "%QTBIN%\Qt6Xml.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt6Xml.dll + xcopy /Y /Q "%QTBIN%\Qt6Core5Compat.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Qt6Core5Compat.dll not found, skipping + ) else if exist "%QTBIN%\Qt5Core.dll" ( + echo Copying Qt5 DLLs... + xcopy /Y /Q "%QTBIN%\Qt5Core.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt5Core.dll + xcopy /Y /Q "%QTBIN%\Qt5Gui.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt5Gui.dll + xcopy /Y /Q "%QTBIN%\Qt5Network.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt5Network.dll + xcopy /Y /Q "%QTBIN%\Qt5Widgets.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt5Widgets.dll + xcopy /Y /Q "%QTBIN%\Qt5Concurrent.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt5Concurrent.dll + xcopy /Y /Q "%QTBIN%\Qt5Xml.dll" "%KLOGG_WORKSPACE%\release\" 2>nul || echo Failed to copy Qt5Xml.dll + ) +) else ( + echo Qt bin directory not found! Searching recursively... + for /r "C:\Qt" %%F in (Qt6Core.dll Qt5Core.dll) do ( + if exist "%%F" ( + set "FOUND_QT_BIN=%%~dpF" + for %%D in (Qt6 Qt5) do ( + if exist "%%~dpF%%DCore.dll" ( + echo Found %%D DLLs at %%~dpF + xcopy /Y /Q "%%~dpF%%DCore.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DGui.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DNetwork.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DWidgets.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DConcurrent.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DXml.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DCore5Compat.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + ) + ) + ) + ) + for /r "D:\a\_temp" %%F in (Qt6Core.dll Qt5Core.dll) do ( + if exist "%%F" ( + set "FOUND_QT_BIN=%%~dpF" + for %%D in (Qt6 Qt5) do ( + if exist "%%~dpF%%DCore.dll" ( + echo Found %%D DLLs at %%~dpF + xcopy /Y /Q "%%~dpF%%DCore.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DGui.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DNetwork.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DWidgets.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DConcurrent.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DXml.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DCore5Compat.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + ) + ) + ) + ) + for /r "C:\hostedtoolcache\Qt" %%F in (Qt6Core.dll Qt5Core.dll) do ( + if exist "%%F" ( + set "FOUND_QT_BIN=%%~dpF" + for %%D in (Qt6 Qt5) do ( + if exist "%%~dpF%%DCore.dll" ( + echo Found %%D DLLs at %%~dpF + xcopy /Y /Q "%%~dpF%%DCore.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DGui.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DNetwork.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DWidgets.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DConcurrent.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DXml.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + xcopy /Y /Q "%%~dpF%%DCore5Compat.dll" "%KLOGG_WORKSPACE%\release\" 2>nul + ) + ) + ) + ) +) + +REM Also copy additional Qt6 DLLs that might be needed +if exist "%QTBIN%\Qt6Core.dll" ( + for %%F in ( + "Qt6DBus.dll" + "Qt6OpenGL.dll" + "Qt6PrintSupport.dll" + "Qt6Sql.dll" + "Qt6Svg.dll" + "Qt6Test.dll" + "Qt6OpenGLWidgets.dll" + "Qt6Gamepad.dll" + "Qt6Pdf.dll" + "Qt6Positioning.dll" + "Qt6Qml.dll" + "Qt6QmlModels.dll" + "Qt6QmlWorkerScript.dll" + "Qt6Quick.dll" + "Qt6QuickWidgets.dll" + "Qt6ShaderTools.dll" + "Qt63DCore.dll" + "Qt63DRender.dll" + "Qt63DInput.dll" + "Qt63DLogic.dll" + "Qt6Charts.dll" + "Qt6DataVisualization.dll" + "Qt6NetworkAuth.dll" + "Qt6TextToSpeech.dll" + "Qt6StateMachine.dll" + "Qt6Speech.dll" + "Qt6SerialPort.dll" + "Qt6RemoteObjects.dll" + "Qt6WebChannel.dll" + "icudt72.dll" + "icuin72.dll" + "icuuc72.dll" + ) do ( + if exist "%QTBIN%\%%~F" ( + xcopy /Y /Q "%QTBIN%\%%~F" "%KLOGG_WORKSPACE%\release\" 2>nul + ) + ) +) + +REM Copy Qt plugins from known locations +md "%KLOGG_WORKSPACE%\release\platforms" +md "%KLOGG_WORKSPACE%\release\styles" + +REM Try to find plugins directory +set "QT_PLUGINS=" +if "%QTDIR%" neq "" ( + if exist "%QTDIR%\plugins" ( + set "QT_PLUGINS=%QTDIR%\plugins" + ) +) + +REM Search for plugins if not found +if "%QT_PLUGINS%"=="" ( + for /d %%Q in ("C:\Qt" "D:\a\_temp" "%LOCALAPPDATA%\Qt" "C:\hostedtoolcache\Qt") do ( + if exist "%%Q" ( + for /d %%P in ("%%Q\6.*\plugins") do ( + set "QT_PLUGINS=%%P" + ) + ) + ) +) + +echo QT_PLUGINS=%QT_PLUGINS% + +REM Copy platforms plugin +if "%QT_PLUGINS%" neq "" ( + if exist "%QT_PLUGINS%\platforms\qwindows.dll" ( + echo Copying qwindows.dll... + xcopy /Y /Q "%QT_PLUGINS%\platforms\qwindows.dll" "%KLOGG_WORKSPACE%\release\platforms\" 2>nul || echo Failed to copy qwindows.dll + ) + if exist "%QT_PLUGINS%\styles\qmodernwindowsstyle.dll" ( + echo Copying qmodernwindowsstyle.dll... + xcopy /Y /Q "%QT_PLUGINS%\styles\qmodernwindowsstyle.dll" "%KLOGG_WORKSPACE%\release\styles\" 2>nul || echo Failed to copy qmodernwindowsstyle.dll + ) + if exist "%QT_PLUGINS%\styles\qwindowsvistastyle.dll" ( + echo Copying qwindowsvistastyle.dll... + xcopy /Y /Q "%QT_PLUGINS%\styles\qwindowsvistastyle.dll" "%KLOGG_WORKSPACE%\release\styles\" 2>nul || echo Failed to copy qwindowsvistastyle.dll + ) +) + +REM Search recursively for plugins if not found +if not exist "%KLOGG_WORKSPACE%\release\platforms\qwindows.dll" ( + echo Searching for qwindows.dll recursively... + for /r "C:\Qt" %%F in (qwindows.dll) do ( + if exist "%%F" ( + echo Found qwindows.dll at %%F + xcopy /Y /Q "%%F" "%KLOGG_WORKSPACE%\release\platforms\" 2>nul + ) + ) + for /r "D:\a\_temp" %%F in (qwindows.dll) do ( + if exist "%%F" ( + echo Found qwindows.dll at %%F + xcopy /Y /Q "%%F" "%KLOGG_WORKSPACE%\release\platforms\" 2>nul + ) + ) + for /r "C:\hostedtoolcache\Qt" %%F in (qwindows.dll) do ( + if exist "%%F" ( + echo Found qwindows.dll at %%F + xcopy /Y /Q "%%F" "%KLOGG_WORKSPACE%\release\platforms\" 2>nul + ) + ) +) + +REM Verify Qt DLLs were copied +echo. +echo Verifying Qt DLLs in release folder: +dir "%KLOGG_WORKSPACE%\release\Qt*Core.dll" 2>nul || echo Qt*Core.dll NOT FOUND echo "Copying packaging files..." -md %KLOGG_WORKSPACE%\chocolately -xcopy %KLOGG_WORKSPACE%\packaging\windows\klogg.nuspec chocolately /y +md "%KLOGG_WORKSPACE%\chocolately" +xcopy /Y /Q "%KLOGG_WORKSPACE%\packaging\windows\klogg.nuspec" "%KLOGG_WORKSPACE%\chocolately\" 2>nul + +md "%KLOGG_WORKSPACE%\chocolately\tools" +xcopy /Y /Q "%KLOGG_WORKSPACE%\packaging\windows\chocolatelyInstall.ps1" "%KLOGG_WORKSPACE%\chocolately\tools\" 2>nul + +xcopy /Y /Q "%KLOGG_WORKSPACE%\packaging\windows\klogg.nsi" "%KLOGG_WORKSPACE%\" 2>nul +xcopy /Y /Q "%KLOGG_WORKSPACE%\packaging\windows\FileAssociation.nsh" "%KLOGG_WORKSPACE%\" 2>nul + +echo "Making portable archive using PowerShell..." +cd /d "%KLOGG_WORKSPACE%" + +REM Use PowerShell for reliable archive creation +powershell -NoProfile -ExecutionPolicy Bypass -Command "if (Test-Path 'release') { Compress-Archive -Path 'release\*' -DestinationPath 'klogg-%KLOGG_VERSION%-%KLOGG_ARCH%-%KLOGG_QT%-portable.zip' -Force }" -md %KLOGG_WORKSPACE%\chocolately\tools -xcopy %KLOGG_WORKSPACE%\packaging\windows\chocolatelyInstall.ps1 chocolately\tools\ /y +if errorlevel 1 ( + echo PowerShell portable archive creation failed + exit /b 1 +) -xcopy %KLOGG_WORKSPACE%\packaging\windows\klogg.nsi /y -xcopy %KLOGG_WORKSPACE%\packaging\windows\FileAssociation.nsh /y +REM Create PDB archive +powershell -NoProfile -ExecutionPolicy Bypass -Command "Get-ChildItem -Path 'release' -Filter '*.pdb' | Compress-Archive -DestinationPath 'klogg-%KLOGG_VERSION%-%KLOGG_ARCH%-%KLOGG_QT%-pdb.zip' -Force" -echo "Making portable archive..." -7z a -r %KLOGG_WORKSPACE%\klogg-%KLOGG_VERSION%-%KLOGG_ARCH%-%KLOGG_QT%-portable.zip @%KLOGG_WORKSPACE%\packaging\windows\7z_klogg_listfile.txt -7z a %KLOGG_WORKSPACE%\klogg-%KLOGG_VERSION%-%KLOGG_ARCH%-%KLOGG_QT%-pdb.zip @%KLOGG_WORKSPACE%\packaging\windows\7z_pdb_listfile.txt +REM Verify portable.zip was created +if not exist "klogg-%KLOGG_VERSION%-%KLOGG_ARCH%-%KLOGG_QT%-portable.zip" ( + echo ERROR: portable.zip was not created + exit /b 1 +) echo "Done!" diff --git a/src/regex/src/hsregularexpression.cpp b/src/regex/src/hsregularexpression.cpp index 58509177a..c20296c81 100644 --- a/src/regex/src/hsregularexpression.cpp +++ b/src/regex/src/hsregularexpression.cpp @@ -90,6 +90,11 @@ MatchedPatterns HsSingleMatcher::match( const std::string_view& utf8Data ) const { context_.reset(); + if ( !database_.get() || !scratch_.get() ) { + LOG_ERROR << "HsSingleMatcher::match called with invalid database or scratch"; + return std::move( context_.matchingPatterns ); + } + hs_scan( database_.get(), utf8Data.data(), static_cast( utf8Data.size() ), 0, scratch_.get(), matchSingleCallback, static_cast( &context_ ) ); @@ -105,6 +110,11 @@ MatchedPatterns HsMultiMatcher::match( const std::string_view& utf8Data ) const { context_.reset(); + if ( !database_.get() || !scratch_.get() ) { + LOG_ERROR << "HsMultiMatcher::match called with invalid database or scratch"; + return std::move( context_.matchingPatterns ); + } + hs_scan( database_.get(), utf8Data.data(), static_cast( utf8Data.size() ), 0, scratch_.get(), matchMultiCallback, static_cast( &context_ ) ); @@ -157,6 +167,13 @@ HsRegularExpression::HsRegularExpression( const klogg::vector flags( expressions.size() ); std::transform( expressions.cbegin(), expressions.cend(), flags.begin(), [ isPrefilter ]( const auto& expression ) { @@ -193,9 +210,14 @@ HsRegularExpression::HsRegularExpression( const klogg::vector( expressions.size() ), HS_MODE_BLOCK, nullptr, &db, &error ); if ( compileResult != HS_SUCCESS ) { - LOG_ERROR << "Failed to compile pattern " << error->message; - errorMessage = error->message; - hs_free_compile_error( error ); + if ( error ) { + LOG_ERROR << "Failed to compile pattern " << error->message; + errorMessage = error->message; + hs_free_compile_error( error ); + } else { + LOG_ERROR << "Failed to compile pattern: unknown error"; + errorMessage = QStringLiteral("hs_compile_multi failed"); + } return nullptr; } @@ -294,6 +316,11 @@ MatcherVariant HsRegularExpression::createMatcher() const }, scratch_.get() ); + if ( !matcherScratch ) { + LOG_ERROR << "Failed to create matcher scratch — falling back to noop matcher"; + return HsNoopMatcher(); + } + if ( !isPrefilter_ ) { if ( patterns_.size() == 1 ) { return HsSingleMatcher{ database_, std::move( matcherScratch ) }; diff --git a/src/ui/include/crawlerwidget.h b/src/ui/include/crawlerwidget.h index 7fe1a4dd6..51681a5d2 100644 --- a/src/ui/include/crawlerwidget.h +++ b/src/ui/include/crawlerwidget.h @@ -63,6 +63,7 @@ #include "logmainview.h" #include "overview.h" #include "predefinedfilterscombobox.h" +#include "regularexpression.h" #include "signalmux.h" #include "viewinterface.h" @@ -322,6 +323,22 @@ class CrawlerWidget : public QSplitter, bool autoRefreshRequested_; }; + struct FilteredViewSearchContext { + QString searchText; + bool matchCase = false; + bool useRegexp = true; + bool inverse = false; + bool booleanCombination = false; + LineNumber searchStartLine = 0_lnum; + LineNumber searchEndLine = 0_lnum; + + RegularExpressionPattern toPattern() const + { + return RegularExpressionPattern( searchText, matchCase, inverse, booleanCombination, + !useRegexp ); + } + }; + // Private functions void setup(); void setShortcuts(); @@ -347,6 +364,9 @@ class CrawlerWidget : public QSplitter, void connectAllFilteredViewSlots( FilteredView* view); + void saveFilteredViewSearchContext( FilteredView* view, const QString& searchText ); + void restoreFilteredViewSearchContext( FilteredView* view ); + void saveSplitterSizes() const; void changeFontSize( bool increase ); @@ -369,6 +389,7 @@ class CrawlerWidget : public QSplitter, LogMainView* logMainView_; FilteredView* filteredView_; std::unordered_map> filteredViewsData_; + std::unordered_map filteredViewsSearchContext_; QTabWidget* tabbedFilteredView_; OverviewWidget* overviewWidget_; @@ -426,6 +447,9 @@ class CrawlerWidget : public QSplitter, klogg::vector savedMarkedLines_; + // Track tab numbers for display + int nextTabNumber_ = 1; + // Current encoding setting; std::optional encodingMib_; QString encodingText_; diff --git a/src/ui/src/crawlerwidget.cpp b/src/ui/src/crawlerwidget.cpp index c8d86f0f3..7752a8104 100644 --- a/src/ui/src/crawlerwidget.cpp +++ b/src/ui/src/crawlerwidget.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -374,9 +375,14 @@ std::shared_ptr CrawlerWidget::doGetViewContext() co void CrawlerWidget::startNewSearch() { + // Capture before keep-results / history updates can change the combo state. + const QString searchText = searchLineEdit_->lineEdit()->text(); + if ( keepSearchResultsButton_->isChecked() ) { keepSearchResultsButton_->setChecked( false ); + // Keep the previous tab's last-searched context. Do not save the new + // query against the old view — the search box already contains it. logFilteredData_->interruptSearch(); logFilteredData_ = logData_->getNewFilteredData(); @@ -385,30 +391,38 @@ void CrawlerWidget::startNewSearch() connectAllFilteredViewSlots( filteredView_ ); - auto index = tabbedFilteredView_->addTab( filteredView_, "" ); - tabbedFilteredView_->setCurrentIndex( index ); + // Avoid changeFilteredView()/restore while the new tab has no context yet. + { + const QSignalBlocker blocker( tabbedFilteredView_ ); + const auto index = tabbedFilteredView_->addTab( filteredView_, + QString::number( nextTabNumber_++ ) ); + tabbedFilteredView_->setCurrentIndex( index ); + } connect( logFilteredData_.get(), &LogFilteredData::searchProgressed, this, &CrawlerWidget::updateFilteredView, Qt::QueuedConnection ); + Q_EMIT filteredViewChanged(); logMainView_->useNewFiltering( logFilteredData_.get() ); + changeFilteredViewVisibility( visibilityBox_->currentIndex() ); applyConfiguration(); } tabbedFilteredView_->setTabText( tabbedFilteredView_->currentIndex(), - "Find \"" + searchLineEdit_->currentText() + "\"" ); + QString::number( nextTabNumber_ - 1 ) ); // Record the search line in the recent list // (reload the list first in case another glogg changed it) const auto& searches = SavedSearches::getSynced(); - savedSearches_->addRecent( searchLineEdit_->currentText() ); + savedSearches_->addRecent( searchText ); searches.save(); // Update the SearchLine (history) updateSearchCombo(); + searchLineEdit_->lineEdit()->setText( searchText ); // Call the private function to do the search - replaceCurrentSearch( searchLineEdit_->currentText() ); + replaceCurrentSearch( searchText ); } void CrawlerWidget::updatePredefinedFiltersWidget() @@ -1144,10 +1158,18 @@ void CrawlerWidget::setup() // Construct the bottom window tabbedFilteredView_ = new QTabWidget; tabbedFilteredView_->setTabsClosable( true ); - tabbedFilteredView_->addTab( filteredView_, "" ); + tabbedFilteredView_->addTab( filteredView_, QString::number( nextTabNumber_++ ) ); tabbedFilteredView_->setDocumentMode( true ); tabbedFilteredView_->setTabBarAutoHide( true ); + // Set fixed tab width so all tabs have equal size regardless of text content + auto* tabBar = tabbedFilteredView_->tabBar(); + constexpr int fixedTabWidth = 40; + tabBar->setFixedHeight( 25 ); + tabBar->setStyleSheet( + QString( "QTabBar::tab { min-width: %1px; max-width: %1px; width: %1px; }" ) + .arg( fixedTabWidth ) ); + auto* bottomMainLayout = new QVBoxLayout; bottomMainLayout->addLayout( searchLineLayout ); bottomMainLayout->addWidget( tabbedFilteredView_ ); @@ -1302,19 +1324,27 @@ void CrawlerWidget::setup() void CrawlerWidget::changeFilteredView( int tabIndex ) { + if ( tabIndex < 0 ) { + return; + } + + auto* tabFilteredView + = qobject_cast( tabbedFilteredView_->widget( tabIndex ) ); + if ( tabFilteredView == nullptr || tabFilteredView == filteredView_ ) { + return; + } + logFilteredData_->interruptSearch(); - if ( tabIndex >= 0 ) { - auto* tabFilteredView - = qobject_cast( tabbedFilteredView_->widget( tabIndex ) ); - filteredView_ = tabFilteredView; - logFilteredData_ = filteredViewsData_.at( tabFilteredView ); + filteredView_ = tabFilteredView; + logFilteredData_ = filteredViewsData_.at( tabFilteredView ); - Q_EMIT filteredViewChanged(); + restoreFilteredViewSearchContext( tabFilteredView ); - logMainView_->useNewFiltering( logFilteredData_.get() ); - changeFilteredViewVisibility( visibilityBox_->currentIndex() ); - } + Q_EMIT filteredViewChanged(); + + logMainView_->useNewFiltering( logFilteredData_.get() ); + changeFilteredViewVisibility( visibilityBox_->currentIndex() ); } void CrawlerWidget::closeFilteredView( int tabIndex ) @@ -1322,11 +1352,14 @@ void CrawlerWidget::closeFilteredView( int tabIndex ) auto* tabFilteredView = tabbedFilteredView_->widget( tabIndex ); connect( tabFilteredView, &QObject::destroyed, this, &CrawlerWidget::filteredViewDestroyed ); tabFilteredView->deleteLater(); + // Note: nextTabNumber is not decremented to maintain unique tab numbers } void CrawlerWidget::filteredViewDestroyed( QObject* view ) { - filteredViewsData_.erase( qobject_cast( view ) ); + auto* filteredView = qobject_cast( view ); + filteredViewsData_.erase( filteredView ); + filteredViewsSearchContext_.erase( filteredView ); } void CrawlerWidget::saveSplitterSizes() const @@ -1558,6 +1591,71 @@ void CrawlerWidget::loadIcons() // Create a new search using the text passed, replace the currently // used one and destroy the old one. +void CrawlerWidget::saveFilteredViewSearchContext( FilteredView* view, const QString& searchText ) +{ + if ( view == nullptr ) { + return; + } + + FilteredViewSearchContext context; + context.searchText = searchText; + context.matchCase = matchCaseButton_->isChecked(); + context.useRegexp = useRegexpButton_->isChecked(); + context.inverse = inverseButton_->isChecked(); + context.booleanCombination = booleanButton_->isChecked(); + context.searchStartLine = searchStartLine_; + context.searchEndLine = searchEndLine_; + filteredViewsSearchContext_[ view ] = context; +} + +void CrawlerWidget::restoreFilteredViewSearchContext( FilteredView* view ) +{ + const auto contextIt = filteredViewsSearchContext_.find( view ); + if ( contextIt == filteredViewsSearchContext_.end() ) { + return; + } + + const auto& context = contextIt->second; + + const QSignalBlocker blockSearchLine( searchLineEdit_ ); + const QSignalBlocker blockSearchLineEdit( searchLineEdit_->lineEdit() ); + const QSignalBlocker blockMatchCase( matchCaseButton_ ); + const QSignalBlocker blockUseRegexp( useRegexpButton_ ); + const QSignalBlocker blockInverse( inverseButton_ ); + const QSignalBlocker blockBoolean( booleanButton_ ); + + // Clear history selection so the line edit shows this tab's pattern, + // not the most recently used history entry. + searchLineEdit_->setCurrentIndex( -1 ); + searchLineEdit_->lineEdit()->setText( context.searchText ); + matchCaseButton_->setChecked( context.matchCase ); + useRegexpButton_->setChecked( context.useRegexp ); + inverseButton_->setChecked( context.inverse ); + booleanButton_->setChecked( context.booleanCombination ); + searchLineCompleter_->setCaseSensitivity( context.matchCase ? Qt::CaseSensitive + : Qt::CaseInsensitive ); + + searchStartLine_ = context.searchStartLine; + searchEndLine_ = context.searchEndLine; + logMainView_->setSearchLimits( searchStartLine_, searchEndLine_ ); + filteredView_->setSearchLimits( searchStartLine_, searchEndLine_ ); + + const auto pattern = context.toPattern(); + logMainView_->setSearchPattern( pattern ); + filteredView_->setSearchPattern( pattern ); + + updatePredefinedFiltersWidget(); + + if ( context.searchText.isEmpty() ) { + searchState_.resetState(); + printSearchInfoMessage(); + } + else { + searchState_.startSearch(); + printSearchInfoMessage( logFilteredData_->getNbMatches() ); + } +} + void CrawlerWidget::replaceCurrentSearch( const QString& searchText ) { LOG_INFO << "replacing current search with " << searchText; @@ -1640,6 +1738,10 @@ void CrawlerWidget::replaceCurrentSearch( const QString& searchText ) searchState_.resetState(); printSearchInfoMessage(); } + + // Bind this tab to the pattern that was actually searched, not whatever + // the shared search box may contain later. + saveFilteredViewSearchContext( filteredView_, searchText ); } // Updates the content of the drop down list for the saved searches,