Compare commits

..

37 Commits

Author SHA1 Message Date
Le Tan
856d2597df release v3.19.2 2025-05-15 20:23:24 +08:00
Le Tan
44a0d75996 theme: fix toolbar expansion button style 2025-05-14 15:16:55 +08:00
Le Tan
62f6b7f3c5 theme: support hot-reload via --watch-themes cmd option 2025-05-13 22:10:00 +08:00
Le Tan
6150d327da fix macos build 2025-05-13 19:07:52 +08:00
Le Tan
522ccfecc4
fix macos deployment (#2610) 2025-05-11 19:56:24 +08:00
Le
4788ae4ccf add icons for macOS store 2025-04-24 23:17:19 +08:00
Le Tan
c3191e8f88 add privacy policy 2025-04-23 20:21:16 +08:00
Le Tan
4952c88b2e fix readme 2025-04-23 19:35:35 +08:00
Le Tan
ebd4489adf update welcome doc 2025-04-23 19:14:01 +08:00
Le Tan
d9aee037ad
code sign and notarization on macOS(#2605) 2025-04-23 15:27:13 +08:00
Le Tan
87e87619fb release v3.19.1 2025-04-17 09:48:02 +08:00
Le Tan
8494a714cd
fix button popup (#2603) 2025-04-16 22:29:56 +08:00
goodl3000
3ec78f4c36 !1 fix popup windows
* fix popup windows
2025-04-16 13:33:06 +00:00
Le Tan
a27485c021 add gitee project 2025-04-15 21:04:08 +08:00
Le Tan
713b98f29e release v3.19.0 2025-04-10 20:46:58 +08:00
Le Tan
82b0ec751d update vtextedit for VSCode-style shortcuts 2025-04-10 10:25:55 +08:00
Le Tan
a7348c0aa0 update vtextedit 2025-04-08 22:23:49 +08:00
Le Tan
85d2ee950d export: allow local file remote access 2025-04-07 23:23:29 +08:00
Le Tan
b0b51570b0 init stylesheet before mainwindow is shown 2025-04-02 22:00:29 +08:00
Le Tan
a5a9b32ea3
upgrade to Qt 6.8.3 (#2598)
* upgrade to Qt 6.8.3

* fix cache action

* use 2022 for 6.8

* fix vs

* fix linjux

* fix
2025-04-02 13:27:30 +08:00
Le Tan
ac20b7f80c fix mainwindow flashing issue 2025-04-01 21:54:23 +08:00
Le Tan
b462337824 fix build error on Linux 2025-02-11 16:04:48 +08:00
faveoled
bbb88ded57
Metainfo update (#2584) 2025-02-10 08:06:22 +08:00
Integral
0f0995d4fe
ci: update actions/upload-artifact to v4 (#2568) 2024-12-03 10:34:05 +08:00
Integral
0881dd581a
refactor: replace non-empty QString constructors with QStringLiteral() (#2563) 2024-12-02 21:09:57 +08:00
Le Tan
c4512bb69a change minimum macOS supported version 2024-08-13 14:44:17 +08:00
Le Tan
5e4a6fa72a release v3.18.2 2024-08-06 21:56:46 +08:00
Le Tan
5da9268aa7 fix open alert 2024-08-06 21:23:48 +08:00
Le Tan
f1af78573a
fix xss (#2531) 2024-07-22 22:36:38 +08:00
Le Tan
a7600fa7f7
codesign --remove-signature will cause broken binary (#2530)
* codesign --remove-signature will cause broken binary

* fix
2024-07-19 19:44:24 +08:00
Le Tan
78de724757 update xss whitelist 2024-07-18 23:20:32 +08:00
Le Tan
05078a7857 update xss whitelist 2024-07-18 22:58:29 +08:00
Le Tan
84d396f6c4 release v3.18.1 2024-07-10 22:23:14 +08:00
Le Tan
b2fb5b1664 add mark for exemption 2024-07-08 21:52:02 +08:00
Le Tan
3477469b66 check link before open 2024-07-07 22:51:07 +08:00
Le Tan
bed95b1757 update vtextedit 2024-07-07 22:07:46 +08:00
Le Tan
f83761d95f fix artifact suffix 2024-07-03 14:46:45 +08:00
118 changed files with 950 additions and 573 deletions

View File

@ -16,7 +16,7 @@ on:
default: false default: false
env: env:
VNOTE_VER: 3.18.0 VNOTE_VER: 3.19.2
CMAKE_VER: 3.24.3 CMAKE_VER: 3.24.3
jobs: jobs:
@ -62,15 +62,15 @@ jobs:
- name: Cache Qt - name: Cache Qt
id: cache-qt id: cache-qt
uses: actions/cache@v1 # not v2! uses: actions/cache@v4
with: with:
path: ../Qt path: ${{runner.workspace}}/Qt
key: ${{ runner.os }}-QtCache-6.5 key: ${{ runner.os }}-QtCache-6.8
- name: Install Qt - name: Install Qt
uses: jurplel/install-qt-action@v3 uses: jurplel/install-qt-action@v3
with: with:
version: 6.5.3 version: 6.8.3
target: desktop target: desktop
modules: 'qtwebengine qtwebchannel qtpositioning qtpdf qtimageformats qt5compat qtserialport' modules: 'qtwebengine qtwebchannel qtpositioning qtpdf qtimageformats qt5compat qtserialport'
tools: 'tools_opensslv3_src' tools: 'tools_opensslv3_src'
@ -114,6 +114,8 @@ jobs:
- name: Build Project - name: Build Project
run: | run: |
# Remove the libqsqlmimer.so as libmimerapi.so is not deployed with Qt6
rm ${{runner.workspace}}/Qt/6.*/gcc_64/plugins/sqldrivers/libqsqlmimer.so
cmake --build . --target pack cmake --build . --target pack
working-directory: ${{runner.workspace}}/build working-directory: ${{runner.workspace}}/build
@ -135,7 +137,7 @@ jobs:
working-directory: ${{runner.workspace}}/build working-directory: ${{runner.workspace}}/build
- name: Archive Artifacts - name: Archive Artifacts
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: VNote-${{env.VNOTE_VER}}-linux-x64.AppImage name: VNote-${{env.VNOTE_VER}}-linux-x64.AppImage
path: ${{runner.workspace}}/build/VNote-${{env.VNOTE_VER}}-linux-x64.AppImage path: ${{runner.workspace}}/build/VNote-${{env.VNOTE_VER}}-linux-x64.AppImage

View File

@ -16,11 +16,12 @@ on:
default: false default: false
env: env:
VNOTE_VER: 3.18.0 VNOTE_VER: 3.19.2
CMAKE_VER: 3.24.3 CMAKE_VER: 3.24.3
jobs: jobs:
build: build:
environment: Mac-code-sign
name: Build On MacOS name: Build On MacOS
timeout-minutes: 120 timeout-minutes: 120
@ -31,7 +32,7 @@ jobs:
- name: "Build on Arm64" - name: "Build on Arm64"
os: macos-latest os: macos-latest
arch: universal arch: universal
qt: 6.5.3 qt: 6.8.3
runs-on: ${{matrix.config.os}} runs-on: ${{matrix.config.os}}
@ -72,12 +73,19 @@ jobs:
git clone https://github.com/tamlok/macdeployqtfix.git macdeployqtfix --depth=1 git clone https://github.com/tamlok/macdeployqtfix.git macdeployqtfix --depth=1
working-directory: ${{runner.workspace}} working-directory: ${{runner.workspace}}
- name: Install optool
run: |
wget --no-verbose https://github.com/alexzielenski/optool/releases/download/0.1/optool.zip
unzip ./optool.zip
sudo ln -s ./optool /usr/local/bin/optool
working-directory: ${{runner.workspace}}
- name: Cache Qt - name: Cache Qt
id: cache-qt id: cache-qt
uses: actions/cache@v1 # not v2! uses: actions/cache@v4
with: with:
path: ../Qt path: ${{runner.workspace}}/Qt
key: ${{ runner.os }}-QtCache-6.5 key: ${{ runner.os }}-QtCache-6.8
- name: Install Qt - name: Install Qt
uses: jurplel/install-qt-action@v3 uses: jurplel/install-qt-action@v3
@ -100,19 +108,102 @@ jobs:
- name: Build Project - name: Build Project
run: | run: |
# Keep only required SQL drivers
rm ${{env.Qt6_DIR}}/plugins/sqldrivers/libqsqlmimer.dylib
rm ${{env.Qt6_DIR}}/plugins/sqldrivers/libqsqlodbc.dylib
rm ${{env.Qt6_DIR}}/plugins/sqldrivers/libqsqlpsql.dylib
# Build the project
cmake --build . --target pack cmake --build . --target pack
ls -ls .
ls -ls src # Fix Qt frameworks
mv src/VNote.dmg VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}}.dmg python3 ${{runner.workspace}}/macdeployqtfix/macdeployqtfix.py ./src/VNote.app/Contents/MacOS/VNote ${{env.Qt6_DIR}}/../..
# Only delete rpaths that exist to avoid errors
for rpath in $(otool -l ./src/VNote.app/Contents/MacOS/VNote | awk '/LC_RPATH/ {getline; getline; print $2}' | grep 'vnote'); do
echo "Checking rpath: $rpath"
if otool -l ./src/VNote.app/Contents/MacOS/VNote | grep -q "$rpath"; then
echo "Deleting rpath: $rpath"
install_name_tool -delete_rpath "$rpath" ./src/VNote.app/Contents/MacOS/VNote
else
echo "Rpath not found: $rpath"
fi
done
for rpath in $(otool -l ./src/VNote.app/Contents/Frameworks/libVTextEdit.dylib | awk '/LC_RPATH/ {getline; getline; print $2}' | grep 'vnote'); do
echo "Checking rpath: $rpath"
if otool -l ./src/VNote.app/Contents/Frameworks/libVTextEdit.dylib | grep -q "$rpath"; then
echo "Deleting rpath: $rpath"
install_name_tool -delete_rpath "$rpath" ./src/VNote.app/Contents/Frameworks/libVTextEdit.dylib
else
echo "Rpath not found: $rpath"
fi
done
# Run macdeployqtfix again to ensure all dependencies are properly fixed
python3 ${{runner.workspace}}/macdeployqtfix/macdeployqtfix.py ./src/VNote.app/Contents/MacOS/VNote ${{env.Qt6_DIR}}/../..
working-directory: ${{runner.workspace}}/build working-directory: ${{runner.workspace}}/build
- name: Codesign Bundle
# Extract the secrets we defined earlier as environment variables
env:
MACOS_CERTIFICATE: ${{ secrets.CLI_MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.CLI_MACOS_CERTIFICATE_PWD }}
MACOS_CERTIFICATE_NAME: ${{ secrets.CLI_MACOS_CERTIFICATE_NAME }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.CLI_MACOS_CERTIFICATE }}
run: |
# Turn our base64-encoded certificate back to a regular .p12 file
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
# We need to create a new keychain, otherwise using the certificate will prompt
# with a UI dialog asking for the certificate password, which we can't
# use in a headless CI environment
security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
echo "Codesigning main app bundle"
codesign --force --deep -s "$MACOS_CERTIFICATE_NAME" --entitlements ${{github.workspace}}/package/entitlements.xml --options runtime ./src/VNote.app
codesign -v -vvv ./src/VNote.app
hdiutil create -volname "VNote" -srcfolder ./src/VNote.app -ov -format UDZO VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}}.dmg
codesign --force --deep -s "$MACOS_CERTIFICATE_NAME" --entitlements ${{github.workspace}}/package/entitlements.xml --options runtime ./VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}}.dmg
codesign -v -vvv ./VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}}.dmg
working-directory: ${{runner.workspace}}/build
- name: "Notarize Bundle"
# Extract the secrets we defined earlier as environment variables
env:
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.CLI_MACOS_NOTARY_USER }}
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.CLI_MACOS_TEAM_ID }}
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.CLI_MACOS_NOTARY_PWD }}
run: |
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if
# you're curious
echo "Notarize app"
xcrun notarytool submit "${{runner.workspace}}/build/VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}}.dmg" --keychain-profile "notarytool-profile" --wait
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
# validated by macOS even when an internet connection is not available.
echo "Attach staple"
xcrun stapler staple "${{runner.workspace}}/build/VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}}.dmg"
# Enable tmate debugging of manually-triggered workflows if the input option was provided # Enable tmate debugging of manually-triggered workflows if the input option was provided
- name: Setup tmate session - name: Setup tmate session
uses: mxschmitt/action-tmate@v3 uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
- name: Archive Artifacts - name: Archive DMG
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}} name: VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}}
path: ${{runner.workspace}}/build/VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}}.dmg path: ${{runner.workspace}}/build/VNote-${{env.VNOTE_VER}}-mac-${{matrix.config.arch}}.dmg

View File

@ -16,12 +16,12 @@ on:
default: false default: false
env: env:
VNOTE_VER: 3.18.0 VNOTE_VER: 3.19.2
jobs: jobs:
build: build:
name: ${{ matrix.config.name }} name: ${{ matrix.config.name }}
runs-on: windows-2019 runs-on: windows-${{ matrix.config.vs_version }}
timeout-minutes: 120 timeout-minutes: 120
strategy: strategy:
@ -30,14 +30,18 @@ jobs:
config: config:
- name: "Build on Win64 Qt 5.15" - name: "Build on Win64 Qt 5.15"
arch: win64_msvc2019_64 arch: win64_msvc2019_64
vs_version: 2019
vs_cmd: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Auxiliary\\Build\\vcvars64.bat"
qt: 5.15.2 qt: 5.15.2
qt_modules: qtwebengine qt_modules: qtwebengine
qt_tools: tools_opensslv3_x64 qt_tools: tools_opensslv3_x64
qt_major: 5 qt_major: 5
suffix: "-windows7" suffix: "-windows7"
- name: "Build on Win64 Qt 6.5" - name: "Build on Win64 Qt 6"
arch: win64_msvc2019_64 arch: win64_msvc2022_64
qt: 6.5.3 vs_version: 2022
vs_cmd: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvars64.bat"
qt: 6.8.3
qt_modules: "qtwebengine qtwebchannel qtpositioning qtpdf qtimageformats qt5compat" qt_modules: "qtwebengine qtwebchannel qtpositioning qtpdf qtimageformats qt5compat"
qt_tools: tools_opensslv3_x64 qt_tools: tools_opensslv3_x64
qt_major: 6 qt_major: 6
@ -58,9 +62,9 @@ jobs:
- name: Cache Qt - name: Cache Qt
id: cache-qt id: cache-qt
uses: actions/cache@v1 # not v2! uses: actions/cache@v4
with: with:
path: ../Qt path: ${{runner.workspace}}/Qt
key: ${{runner.os}}-${{matrix.config.arch}}-QtCache-${{matrix.config.qt}} key: ${{runner.os}}-${{matrix.config.arch}}-QtCache-${{matrix.config.qt}}
- name: Install Qt Official Build - name: Install Qt Official Build
@ -94,7 +98,7 @@ jobs:
shell: cmd shell: cmd
run: | run: |
cmake --version cmake --version
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 call "${{matrix.config.vs_cmd}}"
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DQT_DEFAULT_MAJOR_VERSION=${{matrix.config.qt_major}} -DOPENSSL_EXTRA_LIB_DIR=${{runner.workspace}}\build\openssl-utils.git\1.1.1j\Win_x64 %GITHUB_WORKSPACE% cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DQT_DEFAULT_MAJOR_VERSION=${{matrix.config.qt_major}} -DOPENSSL_EXTRA_LIB_DIR=${{runner.workspace}}\build\openssl-utils.git\1.1.1j\Win_x64 %GITHUB_WORKSPACE%
cmake --build . cmake --build .
cmake --build . --target=pack cmake --build . --target=pack
@ -111,14 +115,14 @@ jobs:
working-directory: ${{runner.workspace}}/build working-directory: ${{runner.workspace}}/build
- name: Archive Artifacts - name: Archive Artifacts
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: VNote-${{env.VNOTE_VER}}-win64${{matrix.config.suffix}}.zip name: VNote-${{env.VNOTE_VER}}-win64${{matrix.config.suffix}}
path: ${{runner.workspace}}/build/VNote-${{env.VNOTE_VER}}-win64${{matrix.config.suffix}} path: ${{runner.workspace}}/build/VNote-${{env.VNOTE_VER}}-win64${{matrix.config.suffix}}
- name: Archive Installer - name: Archive Installer
if: ${{!startsWith(matrix.config.qt, '5.15')}} if: ${{!startsWith(matrix.config.qt, '5.15')}}
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: VNote-${{env.VNOTE_VER}}-win64${{matrix.config.suffix}}.msi name: VNote-${{env.VNOTE_VER}}-win64${{matrix.config.suffix}}.msi
path: ${{runner.workspace}}/build/VNote*.msi path: ${{runner.workspace}}/build/VNote*.msi

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
*.pro.user.* *.pro.user.*
.ccls .ccls
compile_commands.json compile_commands.json
compile_commands.json.*
compile_flags.txt compile_flags.txt
.cache .cache
.tasks .tasks

View File

@ -3,7 +3,7 @@ cmake_minimum_required (VERSION 3.20)
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.1" CACHE STRING "Minimum OS X deployment version") set(CMAKE_OSX_DEPLOYMENT_TARGET "12.1" CACHE STRING "Minimum OS X deployment version")
project(VNote project(VNote
VERSION 3.18.0 VERSION 3.19.2
DESCRIPTION "A pleasant note-taking platform" DESCRIPTION "A pleasant note-taking platform"
HOMEPAGE_URL "https://app.vnote.fun" HOMEPAGE_URL "https://app.vnote.fun"
LANGUAGES C CXX) LANGUAGES C CXX)

View File

@ -3,9 +3,11 @@
[简体中文](README_zh_CN.md) [简体中文](README_zh_CN.md)
[Project on Gitee](https://gitee.com/vnotex/vnote)
A pleasant note-taking platform. A pleasant note-taking platform.
For more information, please visit [**VNote's Home Page**](https://vnotex.github.io/vnote) or [Home Page on Gitee](https://tamlok.gitee.io/vnote). For more information, please visit [**VNote's Home Page**](https://vnotex.github.io/vnote).
![VNote](pics/vnote.png) ![VNote](pics/vnote.png)
@ -26,7 +28,7 @@ Continuous builds on `master` branch could be found at the [Continuous Build](ht
Latest stable builds could be found at the [latest release](https://github.com/vnotex/vnote/releases/latest). Alternative download services are available: Latest stable builds could be found at the [latest release](https://github.com/vnotex/vnote/releases/latest). Alternative download services are available:
* [Tianyi Netdisk](https://cloud.189.cn/t/Av67NvmEJVBv) * [Tianyi Netdisk](https://cloud.189.cn/t/Av67NvmEJVBv)
* [Baidu Netdisk](https://pan.baidu.com/s/1Fou1flmBsQUQ8Qs9V_M6Aw) with the code `note` * [Baidu Netdisk](https://pan.baidu.com/s/1lX69oMBw8XuJshQDN3HiHw?pwd=f8fk)
## Supports ## Supports
* [GitHub Issues](https://github.com/vnotex/vnote/issues); * [GitHub Issues](https://github.com/vnotex/vnote/issues);

View File

@ -3,9 +3,11 @@
[English](README.md) [English](README.md)
[Gitee托管项目](https://gitee.com/vnotex/vnote)
一个舒适的笔记平台! 一个舒适的笔记平台!
更多信息,请访问[VNote主页](https://vnotex.github.io/vnote)或者[由Gitee托管的主页](https://tamlok.gitee.io/vnote) 更多信息,请访问[VNote主页](https://vnotex.github.io/vnote)。
![VNote](pics/vnote.png) ![VNote](pics/vnote.png)
@ -26,7 +28,7 @@ VNote不是一个简单的Markdown编辑器。通过提供强大的笔记管理
最新的[稳定版本发布](https://github.com/vnotex/vnote/releases/latest)。其他下载选项: 最新的[稳定版本发布](https://github.com/vnotex/vnote/releases/latest)。其他下载选项:
* [天翼云盘](https://cloud.189.cn/t/Av67NvmEJVBv) * [天翼云盘](https://cloud.189.cn/t/Av67NvmEJVBv)
* [百度云盘](https://pan.baidu.com/s/1Fou1flmBsQUQ8Qs9V_M6Aw) 提取码`note` * [百度云盘](https://pan.baidu.com/s/1lX69oMBw8XuJshQDN3HiHw?pwd=f8fk)
## 支持 ## 支持
* [GitHub Issues](https://github.com/vnotex/vnote/issues) * [GitHub Issues](https://github.com/vnotex/vnote/issues)

View File

@ -1,4 +1,20 @@
# Changes # Changes
## v3.19.2
* Codesign MacOS Bundle
* Fix toolbar expansion button style
* Support hot-reloading of theme via --watch-themes option
## v3.19.1
* Fix toolbar button in Qt 6.8
## v3.19.0
* Add VSCode-sytle editor shortcuts
## v3.18.1
* Fix crash caused by Qt6 change
* Fix XSS protection exemption
* Check link before open
## v3.18.0 ## v3.18.0
* Upgrade to Qt6 * Upgrade to Qt6
* Support MacOS universal build * Support MacOS universal build

@ -1 +1 @@
Subproject commit f2d0cdcf3ca212164ce8b8d6d9fc6a9042dd0a1b Subproject commit 50b1421793af3882ddc62ad4e6cf5537e1d7906f

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.get-task-allow</key>
<true/>
<key>com.apple.security.cs.debugger</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>

24
package/entitlements.xml Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.get-task-allow</key>
<true/>
<key>com.apple.security.cs.debugger</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>

26
privacy_policy.md Normal file
View File

@ -0,0 +1,26 @@
# Privacy Policy
## Introduction
Welcome to VNote! We value your privacy and are committed to protecting your personal information. This Privacy Policy explains how we handle your information when you use our application.
## Information We Collect
VNote does not collect any personal or usage data from its users. Your interactions with the app remain private and are not stored or shared.
## How We Use Your Information
Since VNote does not collect any user data, we do not use, store, or process any personal information.
## Sharing Your Information
As VNote does not collect any user data, we do not share any personal information with third parties.
## Security
While VNote does not collect any user data, we still implement security measures to ensure the integrity and safety of the application itself.
## Your Choices
Since no data is collected, there are no choices or actions required from users regarding their personal information.
## Children's Privacy
Our services are not intended for children under the age of 13. We do not knowingly collect personal information from children under 13.
## Changes to This Privacy Policy
We may update this Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on our app. You are advised to review this Privacy Policy periodically for any changes.

View File

@ -7,6 +7,7 @@ if len(sys.argv) < 2:
exit exit
newVersion = sys.argv[1] newVersion = sys.argv[1]
shortVersion = re.match('^(\\d+\\.\\d+).', newVersion).group(1)
print("New version: {0}".format(newVersion)) print("New version: {0}".format(newVersion))
# CMakeList # CMakeList
@ -25,6 +26,10 @@ for line in fileinput.input(['.github/workflows/ci-win.yml', '.github/workflows/
print(regExp.sub('\\1VNOTE_VER: ' + newVersion, line), end='') print(regExp.sub('\\1VNOTE_VER: ' + newVersion, line), end='')
# Info.plist # Info.plist
regExp = re.compile('(\\s+)<string>(?!10\\.15)\\d+\\.\\d+</string>')
for line in fileinput.input(['src/data/core/Info.plist'], inplace = True):
print(regExp.sub('\\1<string>' + shortVersion + '</string>', line), end='')
regExp = re.compile('(\\s+)<string>\\d+\\.\\d+\\.\\d+</string>') regExp = re.compile('(\\s+)<string>\\d+\\.\\d+\\.\\d+</string>')
for line in fileinput.input(['src/data/core/Info.plist'], inplace = True): for line in fileinput.input(['src/data/core/Info.plist'], inplace = True):
print(regExp.sub('\\1<string>' + newVersion + '</string>', line), end='') print(regExp.sub('\\1<string>' + newVersion + '</string>', line), end='')

View File

@ -139,7 +139,7 @@ elseif(APPLE)
OUTPUT_NAME "${PROJECT_NAME}" OUTPUT_NAME "${PROJECT_NAME}"
MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}" MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}"
MACOSX_BUNDLE_INFO_STRING "${PROJECT_DESCRIPTION}" MACOSX_BUNDLE_INFO_STRING "${PROJECT_DESCRIPTION}"
MACOSX_BUNDLE_GUI_IDENTIFIER "fun.vnote.app" MACOSX_BUNDLE_GUI_IDENTIFIER "fun.vnote.vnote"
MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}" MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}" MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}"

View File

@ -1,7 +1,6 @@
execute_process(COMMAND "codesign" --remove-signature ${CMAKE_CURRENT_BINARY_DIR}/VNote.app execute_process(COMMAND "optool" strip -t ${CMAKE_CURRENT_BINARY_DIR}/VNote.app
WORKING_DIRECTORY ${CPACK_PACKAGE_DIRECTORY} WORKING_DIRECTORY ${CPACK_PACKAGE_DIRECTORY}
) )
execute_process(COMMAND "${MACDEPLOYQT_EXECUTABLE}" ${CMAKE_CURRENT_BINARY_DIR}/VNote.app -dmg execute_process(COMMAND "${MACDEPLOYQT_EXECUTABLE}" ${CMAKE_CURRENT_BINARY_DIR}/VNote.app -always-overwrite -verbose=1
-always-overwrite -verbose=1
WORKING_DIRECTORY ${CPACK_PACKAGE_DIRECTORY} WORKING_DIRECTORY ${CPACK_PACKAGE_DIRECTORY}
) )

View File

@ -2,6 +2,11 @@
#include <QFileOpenEvent> #include <QFileOpenEvent>
#include <QDebug> #include <QDebug>
#include <QDir>
#include <QStyle>
#include <QFileSystemWatcher>
#include <QTimer>
#include <core/vnotex.h>
using namespace vnotex; using namespace vnotex;
@ -10,6 +15,53 @@ Application::Application(int &p_argc, char **p_argv)
{ {
} }
void Application::watchThemeFolder(const QString &p_themeFolderPath)
{
if (p_themeFolderPath.isEmpty()) {
return;
}
// Initialize watchers only when needed
if (!m_styleWatcher) {
m_styleWatcher = new QFileSystemWatcher(this);
}
if (!m_reloadTimer) {
m_reloadTimer = new QTimer(this);
m_reloadTimer->setSingleShot(true);
m_reloadTimer->setInterval(500); // 500ms debounce delay
connect(m_reloadTimer, &QTimer::timeout,
this, &Application::reloadThemeResources);
// Connect file watcher to timer
connect(m_styleWatcher, &QFileSystemWatcher::directoryChanged,
m_reloadTimer, qOverload<>(&QTimer::start));
connect(m_styleWatcher, &QFileSystemWatcher::fileChanged,
m_reloadTimer, qOverload<>(&QTimer::start));
}
// Watch the theme folder and its files
m_styleWatcher->addPath(p_themeFolderPath);
// Also watch individual files in the theme folder
QDir themeDir(p_themeFolderPath);
QStringList files = themeDir.entryList(QDir::Files);
for (const QString &file : files) {
m_styleWatcher->addPath(themeDir.filePath(file));
}
}
void Application::reloadThemeResources()
{
VNoteX::getInst().getThemeMgr().refreshCurrentTheme();
auto stylesheet = VNoteX::getInst().getThemeMgr().fetchQtStyleSheet();
if (!stylesheet.isEmpty()) {
setStyleSheet(stylesheet);
style()->unpolish(this);
style()->polish(this);
}
}
bool Application::event(QEvent *p_event) bool Application::event(QEvent *p_event)
{ {
// On macOS, we need this to open file from Finder. // On macOS, we need this to open file from Finder.

View File

@ -1,8 +1,10 @@
#ifndef APPLICATION_H #ifndef APPLICATION_H
#define APPLICATION_H #define APPLICATION_H
#include <QApplication> #include <QApplication>
class QFileSystemWatcher;
class QTimer;
namespace vnotex namespace vnotex
{ {
class Application : public QApplication class Application : public QApplication
@ -11,11 +13,21 @@ namespace vnotex
public: public:
Application(int &p_argc, char **p_argv); Application(int &p_argc, char **p_argv);
// Set up theme folder watcher for hot-reload
void watchThemeFolder(const QString &p_themeFolderPath);
// Reload the theme resources (stylesheet, icons, etc)
void reloadThemeResources();
signals: signals:
void openFileRequested(const QString &p_filePath); void openFileRequested(const QString &p_filePath);
protected: protected:
bool event(QEvent *p_event) Q_DECL_OVERRIDE; bool event(QEvent *p_event) Q_DECL_OVERRIDE;
private:
QFileSystemWatcher *m_styleWatcher = nullptr;
QTimer *m_reloadTimer = nullptr;
}; };
} }

View File

@ -25,6 +25,9 @@ CommandLineOptions::ParseResult CommandLineOptions::parse(const QStringList &p_a
const QCommandLineOption logStderrOpt("log-stderr", MainWindow::tr("Log to stderr.")); const QCommandLineOption logStderrOpt("log-stderr", MainWindow::tr("Log to stderr."));
parser.addOption(logStderrOpt); parser.addOption(logStderrOpt);
const QCommandLineOption watchThemesOpt("watch-themes", MainWindow::tr("Watch theme folder for changes."));
parser.addOption(watchThemesOpt);
// WebEngine options. // WebEngine options.
// No need to handle them. Just add them to the parser to avoid parse error. // No need to handle them. Just add them to the parser to avoid parse error.
{ {
@ -70,5 +73,9 @@ CommandLineOptions::ParseResult CommandLineOptions::parse(const QStringList &p_a
m_logToStderr = true; m_logToStderr = true;
} }
if (parser.isSet(watchThemesOpt)) {
m_watchThemes = true;
}
return ParseResult::Ok; return ParseResult::Ok;
} }

View File

@ -27,6 +27,9 @@ public:
bool m_verbose = false; bool m_verbose = false;
bool m_logToStderr = false; bool m_logToStderr = false;
// Whether to watch theme folder for changes
bool m_watchThemes = false;
}; };
#endif // COMMANDLINEOPTIONS_H #endif // COMMANDLINEOPTIONS_H

View File

@ -358,7 +358,7 @@ void Buffer::writeBackupFile()
QString Buffer::generateBackupFileHead() const QString Buffer::generateBackupFileHead() const
{ {
return QString("vnotex_backup_file %1|").arg(getContentPath()); return QStringLiteral("vnotex_backup_file %1|").arg(getContentPath());
} }
void Buffer::checkBackupFileOfPreviousSession() void Buffer::checkBackupFileOfPreviousSession()
@ -373,7 +373,7 @@ void Buffer::checkBackupFileOfPreviousSession()
QDir backupDir(backupDirPath); QDir backupDir(backupDirPath);
QStringList backupFiles; QStringList backupFiles;
{ {
const QString nameFilter = QString("%1*%2").arg(getName(), config.getBackupFileExtension()); const QString nameFilter = QStringLiteral("%1*%2").arg(getName(), config.getBackupFileExtension());
backupFiles = backupDir.entryList(QStringList(nameFilter), backupFiles = backupDir.entryList(QStringList(nameFilter),
QDir::Files | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot); QDir::Files | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot);
} }

View File

@ -75,7 +75,7 @@ void BufferMgr::open(Node *p_node, const QSharedPointer<FileOpenParameters> &p_p
} }
if (!p_node->checkExists()) { if (!p_node->checkExists()) {
auto msg = QString("Failed to open node that does not exist (%1)").arg(p_node->fetchAbsolutePath()); auto msg = QStringLiteral("Failed to open node that does not exist (%1)").arg(p_node->fetchAbsolutePath());
qWarning() << msg; qWarning() << msg;
VNoteX::getInst().showStatusMessageShort(msg); VNoteX::getInst().showStatusMessageShort(msg);
return; return;
@ -133,7 +133,7 @@ void BufferMgr::open(const QString &p_filePath, const QSharedPointer<FileOpenPar
QFileInfo finfo(p_filePath); QFileInfo finfo(p_filePath);
if (!finfo.exists()) { if (!finfo.exists()) {
auto msg = QString("Failed to open file that does not exist (%1)").arg(p_filePath); auto msg = QStringLiteral("Failed to open file that does not exist (%1)").arg(p_filePath);
qWarning() << msg; qWarning() << msg;
VNoteX::getInst().showStatusMessageShort(msg); VNoteX::getInst().showStatusMessageShort(msg);
WidgetUtils::openUrlByDesktop(QUrl::fromUserInput(p_filePath)); WidgetUtils::openUrlByDesktop(QUrl::fromUserInput(p_filePath));

View File

@ -63,14 +63,14 @@ void ClipboardData::fromJson(const QJsonObject &p_jobj)
|| !p_jobj.contains(c_action) || !p_jobj.contains(c_action)
|| !p_jobj.contains(c_data)) { || !p_jobj.contains(c_data)) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("fail to parse ClipboardData from json (%1)").arg(p_jobj.keys().join(','))); QStringLiteral("fail to parse ClipboardData from json (%1)").arg(p_jobj.keys().join(',')));
return; return;
} }
auto idRet = stringToID(p_jobj[c_instanceId].toString()); auto idRet = stringToID(p_jobj[c_instanceId].toString());
if (!idRet.first) { if (!idRet.first) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("fail to parse ClipboardData from json (%1)").arg(p_jobj.keys().join(','))); QStringLiteral("fail to parse ClipboardData from json (%1)").arg(p_jobj.keys().join(',')));
return; return;
} }
m_instanceId = idRet.second; m_instanceId = idRet.second;
@ -79,7 +79,7 @@ void ClipboardData::fromJson(const QJsonObject &p_jobj)
m_action = intToAction(act); m_action = intToAction(act);
if (m_action == Action::Invalid) { if (m_action == Action::Invalid) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("fail to parse ClipboardData from json (%1)").arg(p_jobj.keys().join(','))); QStringLiteral("fail to parse ClipboardData from json (%1)").arg(p_jobj.keys().join(',')));
return; return;
} }

View File

@ -195,7 +195,7 @@ bool ConfigMgr::checkAppConfig()
bool ret = QResource::registerResource(extraRcc); bool ret = QResource::registerResource(extraRcc);
if (!ret) { if (!ret) {
Exception::throwOne(Exception::Type::FailToReadFile, Exception::throwOne(Exception::Type::FailToReadFile,
QString("failed to register resource file %1").arg(extraRcc)); QStringLiteral("failed to register resource file %1").arg(extraRcc));
} }
auto cleanup = qScopeGuard([extraRcc]() { auto cleanup = qScopeGuard([extraRcc]() {
QResource::unregisterResource(extraRcc); QResource::unregisterResource(extraRcc);

View File

@ -47,46 +47,46 @@ namespace vnotex
{ {
switch (p_type) { switch (p_type) {
case Type::InvalidPath: case Type::InvalidPath:
return QString("InvalidPath"); return QStringLiteral("InvalidPath");
case Type::FailToCreateDir: case Type::FailToCreateDir:
return QString("FailToCreateDir"); return QStringLiteral("FailToCreateDir");
case Type::FailToWriteFile: case Type::FailToWriteFile:
return QString("FailToWriteFile"); return QStringLiteral("FailToWriteFile");
case Type::FailToReadFile: case Type::FailToReadFile:
return QString("FailToReadFile"); return QStringLiteral("FailToReadFile");
case Type::FailToRenameFile: case Type::FailToRenameFile:
return QString("FailToRenameFile"); return QStringLiteral("FailToRenameFile");
case Type::FailToCopyFile: case Type::FailToCopyFile:
return QString("FailToCopyFile"); return QStringLiteral("FailToCopyFile");
case Type::FailToCopyDir: case Type::FailToCopyDir:
return QString("FailToCopyDir"); return QStringLiteral("FailToCopyDir");
case Type::FailToRemoveFile: case Type::FailToRemoveFile:
return QString("FailToRemoveFile"); return QStringLiteral("FailToRemoveFile");
case Type::FailToRemoveDir: case Type::FailToRemoveDir:
return QString("FailToRemoveDir"); return QStringLiteral("FailToRemoveDir");
case Type::FileMissingOnDisk: case Type::FileMissingOnDisk:
return QString("FileMissingOnDisk"); return QStringLiteral("FileMissingOnDisk");
case Type::EssentialFileMissing: case Type::EssentialFileMissing:
return QString("EssentialFileMissing"); return QStringLiteral("EssentialFileMissing");
case Type::FileExistsOnCreate: case Type::FileExistsOnCreate:
return QString("FileExistsOnCreate"); return QStringLiteral("FileExistsOnCreate");
case Type::DirExistsOnCreate: case Type::DirExistsOnCreate:
return QString("DirExistsOnCreate"); return QStringLiteral("DirExistsOnCreate");
case Type::InvalidArgument: case Type::InvalidArgument:
return QString("InvalidArgument"); return QStringLiteral("InvalidArgument");
} }
return QString::number(static_cast<int>(p_type)); return QString::number(static_cast<int>(p_type));

View File

@ -25,27 +25,27 @@ HtmlTemplateHelper::Template HtmlTemplateHelper::s_mindMapEditorTemplate;
QString MarkdownWebGlobalOptions::toJavascriptObject() const QString MarkdownWebGlobalOptions::toJavascriptObject() const
{ {
return QStringLiteral("window.vxOptions = {\n") return QStringLiteral("window.vxOptions = {\n")
+ QString("webPlantUml: %1,\n").arg(Utils::boolToString(m_webPlantUml)) + QStringLiteral("webPlantUml: %1,\n").arg(Utils::boolToString(m_webPlantUml))
+ QString("plantUmlWebService: '%1',\n").arg(m_plantUmlWebService) + QStringLiteral("plantUmlWebService: '%1',\n").arg(m_plantUmlWebService)
+ QString("webGraphviz: %1,\n").arg(Utils::boolToString(m_webGraphviz)) + QStringLiteral("webGraphviz: %1,\n").arg(Utils::boolToString(m_webGraphviz))
+ QString("mathJaxScript: '%1',\n").arg(m_mathJaxScript) + QStringLiteral("mathJaxScript: '%1',\n").arg(m_mathJaxScript)
+ QString("constrainImageWidthEnabled: %1,\n").arg(Utils::boolToString(m_constrainImageWidthEnabled)) + QStringLiteral("constrainImageWidthEnabled: %1,\n").arg(Utils::boolToString(m_constrainImageWidthEnabled))
+ QString("imageAlignCenterEnabled: %1,\n").arg(Utils::boolToString(m_imageAlignCenterEnabled)) + QStringLiteral("imageAlignCenterEnabled: %1,\n").arg(Utils::boolToString(m_imageAlignCenterEnabled))
+ QString("protectFromXss: %1,\n").arg(Utils::boolToString(m_protectFromXss)) + QStringLiteral("protectFromXss: %1,\n").arg(Utils::boolToString(m_protectFromXss))
+ QString("htmlTagEnabled: %1,\n").arg(Utils::boolToString(m_htmlTagEnabled)) + QStringLiteral("htmlTagEnabled: %1,\n").arg(Utils::boolToString(m_htmlTagEnabled))
+ QString("autoBreakEnabled: %1,\n").arg(Utils::boolToString(m_autoBreakEnabled)) + QStringLiteral("autoBreakEnabled: %1,\n").arg(Utils::boolToString(m_autoBreakEnabled))
+ QString("linkifyEnabled: %1,\n").arg(Utils::boolToString(m_linkifyEnabled)) + QStringLiteral("linkifyEnabled: %1,\n").arg(Utils::boolToString(m_linkifyEnabled))
+ QString("indentFirstLineEnabled: %1,\n").arg(Utils::boolToString(m_indentFirstLineEnabled)) + QStringLiteral("indentFirstLineEnabled: %1,\n").arg(Utils::boolToString(m_indentFirstLineEnabled))
+ QString("codeBlockLineNumberEnabled: %1,\n").arg(Utils::boolToString(m_codeBlockLineNumberEnabled)) + QStringLiteral("codeBlockLineNumberEnabled: %1,\n").arg(Utils::boolToString(m_codeBlockLineNumberEnabled))
+ QString("sectionNumberEnabled: %1,\n").arg(Utils::boolToString(m_sectionNumberEnabled)) + QStringLiteral("sectionNumberEnabled: %1,\n").arg(Utils::boolToString(m_sectionNumberEnabled))
+ QString("transparentBackgroundEnabled: %1,\n").arg(Utils::boolToString(m_transparentBackgroundEnabled)) + QStringLiteral("transparentBackgroundEnabled: %1,\n").arg(Utils::boolToString(m_transparentBackgroundEnabled))
+ QString("scrollable: %1,\n").arg(Utils::boolToString(m_scrollable)) + QStringLiteral("scrollable: %1,\n").arg(Utils::boolToString(m_scrollable))
+ QString("bodyWidth: %1,\n").arg(m_bodyWidth) + QStringLiteral("bodyWidth: %1,\n").arg(m_bodyWidth)
+ QString("bodyHeight: %1,\n").arg(m_bodyHeight) + QStringLiteral("bodyHeight: %1,\n").arg(m_bodyHeight)
+ QString("transformSvgToPngEnabled: %1,\n").arg(Utils::boolToString(m_transformSvgToPngEnabled)) + QStringLiteral("transformSvgToPngEnabled: %1,\n").arg(Utils::boolToString(m_transformSvgToPngEnabled))
+ QString("mathJaxScale: %1,\n").arg(m_mathJaxScale) + QStringLiteral("mathJaxScale: %1,\n").arg(m_mathJaxScale)
+ QString("removeCodeToolBarEnabled: %1,\n").arg(Utils::boolToString(m_removeCodeToolBarEnabled)) + QStringLiteral("removeCodeToolBarEnabled: %1,\n").arg(Utils::boolToString(m_removeCodeToolBarEnabled))
+ QString("sectionNumberBaseLevel: %1\n").arg(m_sectionNumberBaseLevel) + QStringLiteral("sectionNumberBaseLevel: %1\n").arg(m_sectionNumberBaseLevel)
+ QStringLiteral("}"); + QStringLiteral("}");
} }
@ -83,7 +83,7 @@ static QString fillStyleTag(const QString &p_styleFile)
return ""; return "";
} }
auto url = PathUtils::pathToUrl(p_styleFile); auto url = PathUtils::pathToUrl(p_styleFile);
return QString("<link rel=\"stylesheet\" type=\"text/css\" href=\"%1\">\n").arg(url.toString()); return QStringLiteral("<link rel=\"stylesheet\" type=\"text/css\" href=\"%1\">\n").arg(url.toString());
} }
static QString fillScriptTag(const QString &p_scriptFile) static QString fillScriptTag(const QString &p_scriptFile)
@ -92,7 +92,7 @@ static QString fillScriptTag(const QString &p_scriptFile)
return ""; return "";
} }
auto url = PathUtils::pathToUrl(p_scriptFile); auto url = PathUtils::pathToUrl(p_scriptFile);
return QString("<script type=\"text/javascript\" src=\"%1\"></script>\n").arg(url.toString()); return QStringLiteral("<script type=\"text/javascript\" src=\"%1\"></script>\n").arg(url.toString());
} }
static void fillThemeStyles(QString &p_template, const QString &p_webStyleSheetFile, const QString &p_highlightStyleSheetFile) static void fillThemeStyles(QString &p_template, const QString &p_webStyleSheetFile, const QString &p_highlightStyleSheetFile)
@ -300,7 +300,7 @@ void HtmlTemplateHelper::fillTitle(QString &p_template, const QString &p_title)
{ {
if (!p_title.isEmpty()) { if (!p_title.isEmpty()) {
p_template.replace("<!-- VX_TITLE_PLACEHOLDER -->", p_template.replace("<!-- VX_TITLE_PLACEHOLDER -->",
QString("<title>%1</title>").arg(HtmlUtils::escapeHtml(p_title))); QStringLiteral("<title>%1</title>").arg(HtmlUtils::escapeHtml(p_title)));
} }
} }

View File

@ -86,7 +86,7 @@ void Logger::log(QtMsgType p_type, const QMessageLogContext &p_context, const QS
if (!s_logToStderr) { if (!s_logToStderr) {
QTextStream stream(&s_file); QTextStream stream(&s_file);
stream << header << (QString("(%1:%2) ").arg(fileName).arg(p_context.line)) stream << header << (QStringLiteral("(%1:%2) ").arg(fileName).arg(p_context.line))
<< localMsg << "\n"; << localMsg << "\n";
if (p_type == QtFatalMsg) { if (p_type == QtFatalMsg) {

View File

@ -119,5 +119,4 @@ QString MainConfig::getVersion(const QJsonObject &p_jobj)
void MainConfig::doVersionSpecificOverride() void MainConfig::doVersionSpecificOverride()
{ {
// In a new version, we may want to change one value by force. // In a new version, we may want to change one value by force.
m_editorConfig->getMarkdownEditorConfig().m_protectFromXss = true;
} }

View File

@ -93,7 +93,7 @@ void BundleNotebook::remove()
// Remove notebook root folder if it is empty. // Remove notebook root folder if it is empty.
if (!FileUtils::removeDirIfEmpty(getRootFolderAbsolutePath())) { if (!FileUtils::removeDirIfEmpty(getRootFolderAbsolutePath())) {
qInfo() << QString("root folder of notebook (%1) is not empty and needs manual clean up") qInfo() << QStringLiteral("root folder of notebook (%1) is not empty and needs manual clean up")
.arg(getRootFolderAbsolutePath()); .arg(getRootFolderAbsolutePath());
} }
} }

View File

@ -40,7 +40,7 @@ static void checkRootFolderForNewNotebook(const NotebookParameters &p_paras)
qCritical() << msg; qCritical() << msg;
throw Exception(Exception::Type::InvalidPath, msg); throw Exception(Exception::Type::InvalidPath, msg);
} else if (p_paras.m_ensureEmptyRootFolder && !PathUtils::isEmptyDir(p_paras.m_rootFolderPath)) { } else if (p_paras.m_ensureEmptyRootFolder && !PathUtils::isEmptyDir(p_paras.m_rootFolderPath)) {
QString msg = QString("local root folder must be empty: %1 (%2)") QString msg = QStringLiteral("local root folder must be empty: %1 (%2)")
.arg(p_paras.m_rootFolderPath, PathUtils::absolutePath(p_paras.m_rootFolderPath)); .arg(p_paras.m_rootFolderPath, PathUtils::absolutePath(p_paras.m_rootFolderPath));
qCritical() << msg; qCritical() << msg;
throw Exception(Exception::Type::InvalidPath, msg); throw Exception(Exception::Type::InvalidPath, msg);
@ -88,7 +88,7 @@ void BundleNotebookFactory::checkParameters(const NotebookParameters &p_paras) c
auto configMgr = dynamic_cast<BundleNotebookConfigMgr *>(p_paras.m_notebookConfigMgr.data()); auto configMgr = dynamic_cast<BundleNotebookConfigMgr *>(p_paras.m_notebookConfigMgr.data());
if (!configMgr) { if (!configMgr) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("Invalid notebook configuration manager")); QStringLiteral("Invalid notebook configuration manager"));
} }
} }

View File

@ -254,7 +254,7 @@ QSharedPointer<Node> Notebook::copyNodeAsChildOf(const QSharedPointer<Node> &p_s
if (Node::isAncestor(p_src.data(), p_dest)) { if (Node::isAncestor(p_src.data(), p_dest)) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("source (%1) is the ancestor of destination (%2)") QStringLiteral("source (%1) is the ancestor of destination (%2)")
.arg(p_src->fetchPath(), p_dest->fetchPath())); .arg(p_src->fetchPath(), p_dest->fetchPath()));
return nullptr; return nullptr;
} }

View File

@ -30,7 +30,7 @@ bool NotebookDatabaseAccess::open()
auto db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), m_connectionName); auto db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), m_connectionName);
db.setDatabaseName(m_databaseFile); db.setDatabaseName(m_databaseFile);
if (!db.open()) { if (!db.open()) {
qWarning() << QString("failed to open notebook database (%1) (%2)").arg(m_databaseFile, db.lastError().text()); qWarning() << QStringLiteral("failed to open notebook database (%1) (%2)").arg(m_databaseFile, db.lastError().text());
return false; return false;
} }
@ -71,35 +71,35 @@ void NotebookDatabaseAccess::setupTables(QSqlDatabase &p_db, int p_configVersion
if (m_fresh) { if (m_fresh) {
// Node. // Node.
bool ret = query.exec(QString("CREATE TABLE %1 (\n" bool ret = query.exec(QStringLiteral("CREATE TABLE %1 (\n"
" id INTEGER PRIMARY KEY,\n" " id INTEGER PRIMARY KEY,\n"
" name TEXT NOT NULL,\n" " name TEXT NOT NULL,\n"
" signature INTEGER NOT NULL,\n" " signature INTEGER NOT NULL,\n"
" parent_id INTEGER NULL REFERENCES %1(id) ON DELETE CASCADE ON UPDATE CASCADE)\n").arg(c_nodeTableName)); " parent_id INTEGER NULL REFERENCES %1(id) ON DELETE CASCADE ON UPDATE CASCADE)\n").arg(c_nodeTableName));
if (!ret) { if (!ret) {
qWarning() << QString("failed to create database table (%1) (%2)").arg(c_nodeTableName, query.lastError().text()); qWarning() << QStringLiteral("failed to create database table (%1) (%2)").arg(c_nodeTableName, query.lastError().text());
m_valid = false; m_valid = false;
return; return;
} }
// Tag. // Tag.
ret = query.exec(QString("CREATE TABLE %1 (\n" ret = query.exec(QStringLiteral("CREATE TABLE %1 (\n"
" name TEXT PRIMARY KEY,\n" " name TEXT PRIMARY KEY,\n"
" parent_name TEXT NULL REFERENCES %1(name) ON DELETE CASCADE ON UPDATE CASCADE) WITHOUT ROWID\n").arg(c_tagTableName)); " parent_name TEXT NULL REFERENCES %1(name) ON DELETE CASCADE ON UPDATE CASCADE) WITHOUT ROWID\n").arg(c_tagTableName));
if (!ret) { if (!ret) {
qWarning() << QString("failed to create database table (%1) (%2)").arg(c_tagTableName, query.lastError().text()); qWarning() << QStringLiteral("failed to create database table (%1) (%2)").arg(c_tagTableName, query.lastError().text());
m_valid = false; m_valid = false;
return; return;
} }
// Node_Tag. // Node_Tag.
ret = query.exec(QString("CREATE TABLE %1 (\n" ret = query.exec(QStringLiteral("CREATE TABLE %1 (\n"
" node_id INTEGER REFERENCES %2(id) ON DELETE CASCADE ON UPDATE CASCADE,\n" " node_id INTEGER REFERENCES %2(id) ON DELETE CASCADE ON UPDATE CASCADE,\n"
" tag_name TEXT REFERENCES %3(name) ON DELETE CASCADE ON UPDATE CASCADE)\n").arg(c_nodeTagTableName, " tag_name TEXT REFERENCES %3(name) ON DELETE CASCADE ON UPDATE CASCADE)\n").arg(c_nodeTagTableName,
c_nodeTableName, c_nodeTableName,
c_tagTableName)); c_tagTableName));
if (!ret) { if (!ret) {
qWarning() << QString("failed to create database table (%1) (%2)").arg(c_nodeTagTableName, query.lastError().text()); qWarning() << QStringLiteral("failed to create database table (%1) (%2)").arg(c_nodeTagTableName, query.lastError().text());
m_valid = false; m_valid = false;
return; return;
} }
@ -130,7 +130,7 @@ bool NotebookDatabaseAccess::addNode(Node *p_node, bool p_ignoreId)
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
if (p_ignoreId) { if (p_ignoreId) {
query.prepare(QString("INSERT INTO %1 (name, signature, parent_id)\n" query.prepare(QStringLiteral("INSERT INTO %1 (name, signature, parent_id)\n"
" VALUES (:name, :signature, :parent_id)").arg(c_nodeTableName)); " VALUES (:name, :signature, :parent_id)").arg(c_nodeTableName));
query.bindValue(":name", p_node->getName()); query.bindValue(":name", p_node->getName());
query.bindValue(":signature", p_node->getSignature()); query.bindValue(":signature", p_node->getSignature());
@ -170,10 +170,10 @@ bool NotebookDatabaseAccess::addNode(Node *p_node, bool p_ignoreId)
} }
if (useNewId) { if (useNewId) {
query.prepare(QString("INSERT INTO %1 (name, signature, parent_id)\n" query.prepare(QStringLiteral("INSERT INTO %1 (name, signature, parent_id)\n"
" VALUES (:name, :signature, :parent_id)").arg(c_nodeTableName)); " VALUES (:name, :signature, :parent_id)").arg(c_nodeTableName));
} else { } else {
query.prepare(QString("INSERT INTO %1 (id, name, signature, parent_id)\n" query.prepare(QStringLiteral("INSERT INTO %1 (id, name, signature, parent_id)\n"
" VALUES (:id, :name, :signature, :parent_id)").arg(c_nodeTableName)); " VALUES (:id, :name, :signature, :parent_id)").arg(c_nodeTableName));
query.bindValue(":id", p_node->getId()); query.bindValue(":id", p_node->getId());
} }
@ -212,7 +212,7 @@ QSharedPointer<NotebookDatabaseAccess::NodeRecord> NotebookDatabaseAccess::query
{ {
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("SELECT id, name, signature, parent_id FROM %1 WHERE id = :id").arg(c_nodeTableName)); query.prepare(QStringLiteral("SELECT id, name, signature, parent_id FROM %1 WHERE id = :id").arg(c_nodeTableName));
query.bindValue(":id", p_id); query.bindValue(":id", p_id);
if (!query.exec()) { if (!query.exec()) {
qWarning() << "failed to query node" << query.executedQuery() << query.lastError().text(); qWarning() << "failed to query node" << query.executedQuery() << query.lastError().text();
@ -264,7 +264,7 @@ QStringList NotebookDatabaseAccess::queryNodeParentPath(ID p_id)
{ {
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("WITH RECURSIVE cte_parents(id, name, parent_id) AS (\n" query.prepare(QStringLiteral("WITH RECURSIVE cte_parents(id, name, parent_id) AS (\n"
" SELECT node.id, node.name, node.parent_id\n" " SELECT node.id, node.name, node.parent_id\n"
" FROM %1 node\n" " FROM %1 node\n"
" WHERE node.id = :id\n" " WHERE node.id = :id\n"
@ -315,7 +315,7 @@ bool NotebookDatabaseAccess::updateNode(const Node *p_node)
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("UPDATE %1\n" query.prepare(QStringLiteral("UPDATE %1\n"
"SET name = :name,\n" "SET name = :name,\n"
" signature = :signature,\n" " signature = :signature,\n"
" parent_id = :parent_id\n" " parent_id = :parent_id\n"
@ -367,7 +367,7 @@ bool NotebookDatabaseAccess::removeNode(ID p_id)
{ {
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("DELETE FROM %1\n" query.prepare(QStringLiteral("DELETE FROM %1\n"
"WHERE id = :id").arg(c_nodeTableName)); "WHERE id = :id").arg(c_nodeTableName));
query.bindValue(":id", p_id); query.bindValue(":id", p_id);
if (!query.exec()) { if (!query.exec()) {
@ -455,7 +455,7 @@ bool NotebookDatabaseAccess::addTag(const QString &p_name, const QString &p_pare
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("INSERT INTO %1 (name, parent_name)\n" query.prepare(QStringLiteral("INSERT INTO %1 (name, parent_name)\n"
" VALUES (:name, :parent_name)").arg(c_tagTableName)); " VALUES (:name, :parent_name)").arg(c_tagTableName));
query.bindValue(":name", p_name); query.bindValue(":name", p_name);
query.bindValue(":parent_name", p_parentName.isEmpty() ? QVariant() : p_parentName); query.bindValue(":parent_name", p_parentName.isEmpty() ? QVariant() : p_parentName);
@ -473,7 +473,7 @@ QSharedPointer<NotebookDatabaseAccess::TagRecord> NotebookDatabaseAccess::queryT
{ {
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("SELECT name, parent_name FROM %1 WHERE name = :name").arg(c_tagTableName)); query.prepare(QStringLiteral("SELECT name, parent_name FROM %1 WHERE name = :name").arg(c_tagTableName));
query.bindValue(":name", p_name); query.bindValue(":name", p_name);
if (!query.exec()) { if (!query.exec()) {
qWarning() << "failed to query tag" << query.executedQuery() << query.lastError().text(); qWarning() << "failed to query tag" << query.executedQuery() << query.lastError().text();
@ -494,7 +494,7 @@ bool NotebookDatabaseAccess::updateTagParent(const QString &p_name, const QStrin
{ {
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("UPDATE %1\n" query.prepare(QStringLiteral("UPDATE %1\n"
"SET parent_name = :parent_name\n" "SET parent_name = :parent_name\n"
"WHERE name = :name").arg(c_tagTableName)); "WHERE name = :name").arg(c_tagTableName));
query.bindValue(":name", p_name); query.bindValue(":name", p_name);
@ -518,7 +518,7 @@ bool NotebookDatabaseAccess::renameTag(const QString &p_name, const QString &p_n
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("UPDATE %1\n" query.prepare(QStringLiteral("UPDATE %1\n"
"SET name = :new_name\n" "SET name = :new_name\n"
"WHERE name = :name").arg(c_tagTableName)); "WHERE name = :name").arg(c_tagTableName));
query.bindValue(":name", p_name); query.bindValue(":name", p_name);
@ -537,7 +537,7 @@ bool NotebookDatabaseAccess::removeTag(const QString &p_name)
{ {
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("DELETE FROM %1\n" query.prepare(QStringLiteral("DELETE FROM %1\n"
"WHERE name = :name").arg(c_tagTableName)); "WHERE name = :name").arg(c_tagTableName));
query.bindValue(":name", p_name); query.bindValue(":name", p_name);
if (!query.exec()) { if (!query.exec()) {
@ -603,7 +603,7 @@ QStringList NotebookDatabaseAccess::queryNodeTags(ID p_id)
{ {
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("SELECT tag_name FROM %1 WHERE node_id = :node_id").arg(c_nodeTagTableName)); query.prepare(QStringLiteral("SELECT tag_name FROM %1 WHERE node_id = :node_id").arg(c_nodeTagTableName));
query.bindValue(":node_id", p_id); query.bindValue(":node_id", p_id);
if (!query.exec()) { if (!query.exec()) {
qWarning() << "failed to query node's tags" << query.executedQuery() << query.lastError().text(); qWarning() << "failed to query node's tags" << query.executedQuery() << query.lastError().text();
@ -621,7 +621,7 @@ bool NotebookDatabaseAccess::removeNodeTags(ID p_id)
{ {
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("DELETE FROM %1\n" query.prepare(QStringLiteral("DELETE FROM %1\n"
"WHERE node_id = :node_id").arg(c_nodeTagTableName)); "WHERE node_id = :node_id").arg(c_nodeTagTableName));
query.bindValue(":node_id", p_id); query.bindValue(":node_id", p_id);
if (!query.exec()) { if (!query.exec()) {
@ -641,7 +641,7 @@ bool NotebookDatabaseAccess::addNodeTags(ID p_id, const QStringList &p_tags)
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("INSERT INTO %1 (node_id, tag_name)\n" query.prepare(QStringLiteral("INSERT INTO %1 (node_id, tag_name)\n"
" VALUES (?, ?)").arg(c_nodeTagTableName)); " VALUES (?, ?)").arg(c_nodeTagTableName));
QVariantList ids; QVariantList ids;
@ -668,7 +668,7 @@ QList<ID> NotebookDatabaseAccess::queryTagNodes(const QString &p_tag)
QList<ID> nodes; QList<ID> nodes;
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("SELECT node_id FROM %1 WHERE tag_name = :tag_name").arg(c_nodeTagTableName)); query.prepare(QStringLiteral("SELECT node_id FROM %1 WHERE tag_name = :tag_name").arg(c_nodeTagTableName));
query.bindValue(":tag_name", p_tag); query.bindValue(":tag_name", p_tag);
if (!query.exec()) { if (!query.exec()) {
qWarning() << "failed to query nodes of tag" << query.executedQuery() << query.lastError().text(); qWarning() << "failed to query nodes of tag" << query.executedQuery() << query.lastError().text();
@ -703,7 +703,7 @@ QStringList NotebookDatabaseAccess::queryTagAndChildren(const QString &p_tag)
{ {
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("WITH RECURSIVE cte_children(name, parent_name) AS (\n" query.prepare(QStringLiteral("WITH RECURSIVE cte_children(name, parent_name) AS (\n"
" SELECT tag.name, tag.parent_name\n" " SELECT tag.name, tag.parent_name\n"
" FROM %1 tag\n" " FROM %1 tag\n"
" WHERE tag.name = :name\n" " WHERE tag.name = :name\n"
@ -768,7 +768,7 @@ QList<NotebookDatabaseAccess::TagRecord> NotebookDatabaseAccess::getAllTags()
auto db = getDatabase(); auto db = getDatabase();
QSqlQuery query(db); QSqlQuery query(db);
query.prepare(QString("SELECT name, parent_name FROM %1 ORDER BY parent_name, name").arg(c_tagTableName)); query.prepare(QStringLiteral("SELECT name, parent_name FROM %1 ORDER BY parent_name, name").arg(c_tagTableName));
if (!query.exec()) { if (!query.exec()) {
qWarning() << "failed to query tags" << query.executedQuery() << query.lastError().text(); qWarning() << "failed to query tags" << query.executedQuery() << query.lastError().text();
return ret; return ret;

View File

@ -11,7 +11,7 @@ void INotebookBackend::constrainPath(const QString &p_path) const
{ {
if (!PathUtils::pathContains(m_rootPath, p_path)) { if (!PathUtils::pathContains(m_rootPath, p_path)) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("path (%1) does not locate in root folder (%2)") QStringLiteral("path (%1) does not locate in root folder (%2)")
.arg(p_path, m_rootPath)); .arg(p_path, m_rootPath));
} }
} }

View File

@ -52,7 +52,7 @@ void LocalNotebookBackend::makePath(const QString &p_dirPath)
QDir dir(getRootPath()); QDir dir(getRootPath());
if (!dir.mkpath(p_dirPath)) { if (!dir.mkpath(p_dirPath)) {
Exception::throwOne(Exception::Type::FailToCreateDir, Exception::throwOne(Exception::Type::FailToCreateDir,
QString("fail to create directory: %1").arg(p_dirPath)); QStringLiteral("fail to create directory: %1").arg(p_dirPath));
} }
} }

View File

@ -56,7 +56,7 @@ void NotebookConfig::fromJson(const QJsonObject &p_jobj)
|| !p_jobj.contains(QStringLiteral("version_controller")) || !p_jobj.contains(QStringLiteral("version_controller"))
|| !p_jobj.contains(QStringLiteral("config_mgr"))) { || !p_jobj.contains(QStringLiteral("config_mgr"))) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("failed to read notebook configuration from JSON (%1)").arg(QJsonObjectToString(p_jobj))); QStringLiteral("failed to read notebook configuration from JSON (%1)").arg(QJsonObjectToString(p_jobj)));
return; return;
} }

View File

@ -126,12 +126,12 @@ QSharedPointer<NodeConfig> VXNotebookConfigMgr::readNodeConfig(const QString &p_
auto backend = getBackend(); auto backend = getBackend();
if (!backend->exists(p_path)) { if (!backend->exists(p_path)) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("node path (%1) does not exist").arg(p_path)); QStringLiteral("node path (%1) does not exist").arg(p_path));
} }
if (backend->isFile(p_path)) { if (backend->isFile(p_path)) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("node (%1) is a file node without config").arg(p_path)); QStringLiteral("node (%1) is a file node without config").arg(p_path));
} else { } else {
auto configPath = PathUtils::concatenateFilePath(p_path, c_nodeConfigName); auto configPath = PathUtils::concatenateFilePath(p_path, c_nodeConfigName);
auto data = backend->readFile(configPath); auto data = backend->readFile(configPath);
@ -309,7 +309,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::newFileNode(Node *p_parent,
if (getBackend()->childExistsCaseInsensitive(p_parent->fetchPath(), p_name)) { if (getBackend()->childExistsCaseInsensitive(p_parent->fetchPath(), p_name)) {
// File already exists. Exception. // File already exists. Exception.
Exception::throwOne(Exception::Type::FileExistsOnCreate, Exception::throwOne(Exception::Type::FileExistsOnCreate,
QString("file (%1) already exists when creating new node").arg(node->fetchPath())); QStringLiteral("file (%1) already exists when creating new node").arg(node->fetchPath()));
return nullptr; return nullptr;
} }
@ -345,7 +345,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::newFolderNode(Node *p_parent,
if (getBackend()->childExistsCaseInsensitive(p_parent->fetchPath(), p_name)) { if (getBackend()->childExistsCaseInsensitive(p_parent->fetchPath(), p_name)) {
// Dir already exists. Exception. // Dir already exists. Exception.
Exception::throwOne(Exception::Type::DirExistsOnCreate, Exception::throwOne(Exception::Type::DirExistsOnCreate,
QString("dir (%1) already exists when creating new node").arg(node->fetchPath())); QStringLiteral("dir (%1) already exists when creating new node").arg(node->fetchPath()));
return nullptr; return nullptr;
} }

View File

@ -108,7 +108,7 @@ QSharedPointer<INotebookBackend> NotebookMgr::createNotebookBackend(const QStrin
return factory->createNotebookBackend(p_rootFolderPath); return factory->createNotebookBackend(p_rootFolderPath);
} else { } else {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("failed to find notebook backend factory %1").arg(p_backendName)); QStringLiteral("failed to find notebook backend factory %1").arg(p_backendName));
} }
return nullptr; return nullptr;
@ -121,7 +121,7 @@ QSharedPointer<IVersionController> NotebookMgr::createVersionController(const QS
return factory->createVersionController(); return factory->createVersionController();
} else { } else {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("failed to find version controller factory %1").arg(p_controllerName)); QStringLiteral("failed to find version controller factory %1").arg(p_controllerName));
} }
return nullptr; return nullptr;
@ -135,7 +135,7 @@ QSharedPointer<INotebookConfigMgr> NotebookMgr::createNotebookConfigMgr(const QS
return factory->createNotebookConfigMgr(p_backend); return factory->createNotebookConfigMgr(p_backend);
} else { } else {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("failed to find notebook config manager factory %1").arg(p_mgrName)); QStringLiteral("failed to find notebook config manager factory %1").arg(p_mgrName));
} }
return nullptr; return nullptr;
@ -171,7 +171,7 @@ QSharedPointer<Notebook> NotebookMgr::newNotebook(const QSharedPointer<NotebookP
auto factory = m_notebookServer->getItem(p_parameters->m_type); auto factory = m_notebookServer->getItem(p_parameters->m_type);
if (!factory) { if (!factory) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("failed to find notebook factory %1").arg(p_parameters->m_type)); QStringLiteral("failed to find notebook factory %1").arg(p_parameters->m_type));
} }
auto notebook = factory->newNotebook(*p_parameters); auto notebook = factory->newNotebook(*p_parameters);
@ -246,7 +246,7 @@ QSharedPointer<Notebook> NotebookMgr::readNotebookFromConfig(const SessionConfig
auto factory = m_notebookServer->getItem(p_item.m_type); auto factory = m_notebookServer->getItem(p_item.m_type);
if (!factory) { if (!factory) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("failed to find notebook factory %1").arg(p_item.m_type)); QStringLiteral("failed to find notebook factory %1").arg(p_item.m_type));
} }
auto backend = createNotebookBackend(p_item.m_backend, p_item.m_rootFolderPath); auto backend = createNotebookBackend(p_item.m_backend, p_item.m_rootFolderPath);
@ -330,7 +330,7 @@ void NotebookMgr::closeNotebook(ID p_id)
emit notebooksUpdated(); emit notebooksUpdated();
setCurrentNotebookAfterUpdate(); setCurrentNotebookAfterUpdate();
qInfo() << QString("notebook %1 (%2) is closed").arg(notebookToClose->getName(), qInfo() << QStringLiteral("notebook %1 (%2) is closed").arg(notebookToClose->getName(),
notebookToClose->getRootFolderPath()); notebookToClose->getRootFolderPath());
} }
@ -359,13 +359,13 @@ void NotebookMgr::removeNotebook(ID p_id)
try { try {
nbToRemove->remove(); nbToRemove->remove();
} catch (Exception &p_e) { } catch (Exception &p_e) {
qWarning() << QString("failed to remove notebook %1 (%2) (%3)").arg(nbToRemove->getName(), qWarning() << QStringLiteral("failed to remove notebook %1 (%2) (%3)").arg(nbToRemove->getName(),
nbToRemove->getRootFolderPath(), nbToRemove->getRootFolderPath(),
p_e.what()); p_e.what());
throw; throw;
} }
qInfo() << QString("notebook %1 (%2) is removed").arg(nbToRemove->getName(), qInfo() << QStringLiteral("notebook %1 (%2) is removed").arg(nbToRemove->getName(),
nbToRemove->getRootFolderPath()); nbToRemove->getRootFolderPath());
} }

View File

@ -87,7 +87,7 @@ QJsonObject SessionConfig::ExternalProgram::toJson() const
QString SessionConfig::ExternalProgram::fetchCommand(const QString &p_file) const QString SessionConfig::ExternalProgram::fetchCommand(const QString &p_file) const
{ {
auto command(m_command); auto command(m_command);
command.replace(QStringLiteral("%1"), QString("\"%1\"").arg(p_file)); command.replace(QStringLiteral("%1"), QStringLiteral("\"%1\"").arg(p_file));
return command; return command;
} }

View File

@ -24,6 +24,11 @@ Theme::Theme(const QString &p_themeFolderPath,
{ {
} }
QString vnotex::Theme::getThemeFolder() const
{
return m_themeFolderPath;
}
bool Theme::isValidThemeFolder(const QString &p_folder) bool Theme::isValidThemeFolder(const QString &p_folder)
{ {
QDir dir(p_folder); QDir dir(p_folder);
@ -50,12 +55,12 @@ QString Theme::getDisplayName(const QString &p_folder, const QString &p_locale)
if (!p_locale.isEmpty()) { if (!p_locale.isEmpty()) {
// Check full locale. // Check full locale.
auto fullLocale = QString("%1_%2").arg(prefix, p_locale); auto fullLocale = QStringLiteral("%1_%2").arg(prefix, p_locale);
if (metaObj.contains(fullLocale)) { if (metaObj.contains(fullLocale)) {
return metaObj.value(fullLocale).toString(); return metaObj.value(fullLocale).toString();
} }
auto shortLocale = QString("%1_%2").arg(prefix, p_locale.split('_')[0]); auto shortLocale = QStringLiteral("%1_%2").arg(prefix, p_locale.split('_')[0]);
if (metaObj.contains(shortLocale)) { if (metaObj.contains(shortLocale)) {
return metaObj.value(shortLocale).toString(); return metaObj.value(shortLocale).toString();
} }
@ -258,7 +263,6 @@ QString Theme::fetchQtStyleSheet() const
translateStyleByPalette(m_palette, style); translateStyleByPalette(m_palette, style);
translateUrlToAbsolute(m_themeFolderPath, style); translateUrlToAbsolute(m_themeFolderPath, style);
translateFontFamilyList(style); translateFontFamilyList(style);
translateScaledSize(WidgetUtils::calculateScaleFactor(), style);
return style; return style;
} }
@ -297,7 +301,7 @@ void Theme::translateUrlToAbsolute(const QString &p_basePath, QString &p_style)
const int urlCapturedIdx = 2; const int urlCapturedIdx = 2;
QDir dir(p_basePath); QDir dir(p_basePath);
const int literalSize = QString("url(").size(); const int literalSize = QStringLiteral("url(").size();
int pos = 0; int pos = 0;
QRegularExpressionMatch match; QRegularExpressionMatch match;
while (pos < p_style.size()) { while (pos < p_style.size()) {
@ -346,7 +350,7 @@ void Theme::translateFontFamilyList(QString &p_style)
family = "\"" + family + "\""; family = "\"" + family + "\"";
} }
auto newStr = QString("%1font-family: %2;").arg(match.captured(prefixCapturedIdx), family); auto newStr = QStringLiteral("%1font-family: %2;").arg(match.captured(prefixCapturedIdx), family);
p_style.replace(idx, match.capturedLength(), newStr); p_style.replace(idx, match.capturedLength(), newStr);
pos = idx + newStr.size(); pos = idx + newStr.size();
} else { } else {
@ -355,40 +359,6 @@ void Theme::translateFontFamilyList(QString &p_style)
} }
} }
void Theme::translateScaledSize(qreal p_factor, QString &p_style)
{
QRegularExpression scaleRe("(\\s|:)\\$([+-]?)(\\d+)(?=\\D)");
const int prefixCapturedIdx = 1;
const int signCapturedIdx = 2;
const int numCapturedIdx = 3;
qDebug() << "translateScaledSize of Qt style sheet" << p_factor;
int pos = 0;
QRegularExpressionMatch match;
while (pos < p_style.size()) {
int idx = p_style.indexOf(scaleRe, pos, &match);
if (idx == -1) {
break;
}
auto numStr = match.captured(numCapturedIdx);
bool ok = false;
int val = numStr.toInt(&ok);
if (!ok) {
pos = idx + match.capturedLength();
continue;
}
val = val * p_factor + 0.5;
auto newStr = QString("%1%2%3").arg(match.captured(prefixCapturedIdx),
match.captured(signCapturedIdx),
QString::number(val));
p_style.replace(idx, match.capturedLength(), newStr);
pos = idx + newStr.size();
}
}
QString Theme::paletteColor(const QString &p_name) const QString Theme::paletteColor(const QString &p_name) const
{ {
auto val = findValueByKeyPath(m_palette, p_name).toString(); auto val = findValueByKeyPath(m_palette, p_name).toString();

View File

@ -47,6 +47,8 @@ namespace vnotex
QString name() const; QString name() const;
QString getThemeFolder() const;
static bool isValidThemeFolder(const QString &p_folder); static bool isValidThemeFolder(const QString &p_folder);
static Theme *fromFolder(const QString &p_folder); static Theme *fromFolder(const QString &p_folder);
@ -113,8 +115,6 @@ namespace vnotex
// Thus we need to choose one available font from the list. // Thus we need to choose one available font from the list.
static void translateFontFamilyList(QString &p_style); static void translateFontFamilyList(QString &p_style);
static void translateScaledSize(qreal p_factor, QString &p_style);
static QJsonObject readJsonFile(const QString &p_filePath); static QJsonObject readJsonFile(const QString &p_filePath);
static QJsonObject readPaletteFile(const QString &p_folder); static QJsonObject readPaletteFile(const QString &p_folder);

View File

@ -24,8 +24,6 @@ ThemeMgr::ThemeMgr(const QString &p_currentThemeName, QObject *p_parent)
loadAvailableThemes(); loadAvailableThemes();
loadCurrentTheme(p_currentThemeName); loadCurrentTheme(p_currentThemeName);
IconUtils::setDefaultIconForeground(paletteColor("base#icon#fg"), paletteColor("base#icon#disabled#fg"));
} }
QString ThemeMgr::getIconFile(const QString &p_icon) const QString ThemeMgr::getIconFile(const QString &p_icon) const
@ -56,7 +54,7 @@ void ThemeMgr::loadAvailableThemes()
if (m_themes.isEmpty()) { if (m_themes.isEmpty()) {
Exception::throwOne(Exception::Type::EssentialFileMissing, Exception::throwOne(Exception::Type::EssentialFileMissing,
QString("no available themes found in paths: %1").arg(s_searchPaths.join(QLatin1Char(';')))); QStringLiteral("no available themes found in paths: %1").arg(s_searchPaths.join(QLatin1Char(';'))));
} }
} }
@ -91,6 +89,7 @@ const Theme &ThemeMgr::getCurrentTheme() const
void ThemeMgr::loadCurrentTheme(const QString &p_themeName) void ThemeMgr::loadCurrentTheme(const QString &p_themeName)
{ {
m_currentTheme.reset();
auto themeFolder = findThemeFolder(p_themeName); auto themeFolder = findThemeFolder(p_themeName);
if (themeFolder.isNull()) { if (themeFolder.isNull()) {
qWarning() << "failed to locate theme" << p_themeName; qWarning() << "failed to locate theme" << p_themeName;
@ -104,6 +103,8 @@ void ThemeMgr::loadCurrentTheme(const QString &p_themeName)
qWarning() << "fall back to default theme" << defaultTheme; qWarning() << "fall back to default theme" << defaultTheme;
m_currentTheme.reset(loadTheme(findThemeFolder(defaultTheme))); m_currentTheme.reset(loadTheme(findThemeFolder(defaultTheme)));
} }
IconUtils::setDefaultIconForeground(paletteColor("base#icon#fg"), paletteColor("base#icon#disabled#fg"));
} }
Theme *ThemeMgr::loadTheme(const QString &p_themeFolder) Theme *ThemeMgr::loadTheme(const QString &p_themeFolder)
@ -211,6 +212,14 @@ QPixmap ThemeMgr::getThemePreview(const QString &p_name) const
void ThemeMgr::refresh() void ThemeMgr::refresh()
{ {
loadAvailableThemes(); loadAvailableThemes();
refreshCurrentTheme();
}
void vnotex::ThemeMgr::refreshCurrentTheme()
{
if (m_currentTheme) {
loadCurrentTheme(m_currentTheme->name());
}
} }
void ThemeMgr::addWebStylesSearchPath(const QString &p_path) void ThemeMgr::addWebStylesSearchPath(const QString &p_path)

View File

@ -60,10 +60,11 @@ namespace vnotex
const ThemeInfo *findTheme(const QString &p_name) const; const ThemeInfo *findTheme(const QString &p_name) const;
// Refresh the themes list. // Refresh the themes list and reload current theme.
// Won't affect current theme since we do not support changing theme real time for now.
void refresh(); void refresh();
void refreshCurrentTheme();
// Return all web stylesheets available, including those from themes and web styles search paths. // Return all web stylesheets available, including those from themes and web styles search paths.
// <DisplayName, FilePath>. // <DisplayName, FilePath>.
QVector<QPair<QString, QString>> getWebStyles() const; QVector<QPair<QString, QString>> getWebStyles() const;

View File

@ -16,28 +16,30 @@
<string>public.plain-text</string> <string>public.plain-text</string>
<string>net.daringfireball.markdown</string> <string>net.daringfireball.markdown</string>
</array> </array>
<key>LSHandlerRank</key>
<string>Owner</string>
</dict> </dict>
</array> </array>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>VNote</string> <string>VNote</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>vnote</string> <string>VNote</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>3.17</string> <string>3.19</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>3.18.0</string> <string>3.19.2</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Distributed under LGPL-3.0 license. Copyright (c) 2024 app.vnote.fun</string> <string>Distributed under LGPL-3.0 license. Copyright (c) 2025 app.vnote.fun</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>vnote.icns</string> <string>vnote.icns</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>fun.vnote.app</string> <string>fun.vnote.vnote</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.productivity</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>12.1</string> <string>10.15</string>
<key>NOTE</key> <key>NOTE</key>
<string>A pleasant note-taking platform</string> <string>A pleasant note-taking platform</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>

View File

@ -49,6 +49,11 @@
</ul> </ul>
</description> </description>
<launchable type="desktop-id">fun.vnote.app.VNote.desktop</launchable> <launchable type="desktop-id">fun.vnote.app.VNote.desktop</launchable>
<url type="donation">https://github.com/vnotex/vnote#donate</url>
<url type="faq">https://app.vnote.fun/en_us/#!docs/Users/Frequently%20Asked%20Questions.md</url>
<url type="help">https://join.slack.com/t/vnote/shared_invite/enQtNDg2MzY0NDg3NzI4LTQ1Yzk1YjA5MjAyYTU0MjJkMTUxNmRiYWQ2YjlkOWU0ZGZlMTFlZTAxNzg0ZGUyNzI0ZGY2NDg4MmU1M2FkMDg</url>
<url type="homepage">https://app.vnote.fun/</url>
<url type="vcs-browser">https://github.com/vnotex/vnote</url>
<screenshots> <screenshots>
<screenshot type="default"> <screenshot type="default">
<image>https://app.vnote.fun/en_us/vx_images/90420129296.png</image> <image>https://app.vnote.fun/en_us/vx_images/90420129296.png</image>
@ -59,6 +64,9 @@
</screenshots> </screenshots>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1" />
<releases> <releases>
<release version="3.18.2" date="2024-08-06" />
<release version="3.18.1" date="2024-07-10" />
<release version="3.18.0" date="2024-07-01" />
<release version="3.17.0" date="2023-09-27" /> <release version="3.17.0" date="2023-09-27" />
</releases> </releases>
</component> </component>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -70,17 +70,17 @@
<context> <context>
<name>QWebEnginePage</name> <name>QWebEnginePage</name>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="303"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="313"/>
<source>&amp;Back</source> <source>&amp;Back</source>
<translation>(&amp;B)</translation> <translation>(&amp;B)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="304"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="314"/>
<source>&amp;Forward</source> <source>&amp;Forward</source>
<translation>(&amp;F)</translation> <translation>(&amp;F)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="305"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="315"/>
<source>&amp;Reload</source> <source>&amp;Reload</source>
<translation>(&amp;R)</translation> <translation>(&amp;R)</translation>
</message> </message>
@ -1101,12 +1101,12 @@
<context> <context>
<name>vnotex::FullScreenToggleAction</name> <name>vnotex::FullScreenToggleAction</name>
<message> <message>
<location filename="../../../widgets/fullscreentoggleaction.cpp" line="11"/> <location filename="../../../widgets/fullscreentoggleaction.cpp" line="12"/>
<source>F&amp;ull Screen</source> <source>F&amp;ull Screen</source>
<translation>(&amp;F)</translation> <translation>(&amp;F)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/fullscreentoggleaction.cpp" line="13"/> <location filename="../../../widgets/fullscreentoggleaction.cpp" line="14"/>
<source>Exit F&amp;ull Screen</source> <source>Exit F&amp;ull Screen</source>
<translation>(&amp;A)</translation> <translation>(&amp;A)</translation>
</message> </message>
@ -1802,85 +1802,90 @@
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../commandlineoptions.cpp" line="29"/> <location filename="../../../commandlineoptions.cpp" line="25"/>
<source>Log to stderr.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../commandlineoptions.cpp" line="32"/>
<source>WebEngine remote debugging port.</source> <source>WebEngine remote debugging port.</source>
<translation>WebEngineリモートデバッグポート</translation> <translation>WebEngineリモートデバッグポート</translation>
</message> </message>
<message> <message>
<location filename="../../../commandlineoptions.cpp" line="30"/> <location filename="../../../commandlineoptions.cpp" line="33"/>
<source>port_number</source> <source>port_number</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../commandlineoptions.cpp" line="34"/> <location filename="../../../commandlineoptions.cpp" line="37"/>
<source>WebEngine without sandbox.</source> <source>WebEngine without sandbox.</source>
<translation>WebEngine</translation> <translation>WebEngine</translation>
</message> </message>
<message> <message>
<location filename="../../../commandlineoptions.cpp" line="38"/> <location filename="../../../commandlineoptions.cpp" line="41"/>
<source>WebEngine with GPU disabled.</source> <source>WebEngine with GPU disabled.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../main.cpp" line="134"/> <location filename="../../../main.cpp" line="135"/>
<source>%1 failed to start.</source> <source>%1 failed to start.</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../../../main.cpp" line="135"/> <location filename="../../../main.cpp" line="136"/>
<source>Failed to initialize configuration manager. Please check if all the files are intact or reinstall the application.</source> <source>Failed to initialize configuration manager. Please check if all the files are intact or reinstall the application.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="813"/> <location filename="../../../widgets/mainwindow.cpp" line="819"/>
<source>Failed to check for updates (%1)</source> <source>Failed to check for updates (%1)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="815"/> <location filename="../../../widgets/mainwindow.cpp" line="821"/>
<source>Updates available: %1</source> <source>Updates available: %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="104"/> <location filename="../../../widgets/mainwindow.cpp" line="107"/>
<source>Initializing core components...</source> <source>Initializing core components...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="377"/> <location filename="../../../widgets/mainwindow.cpp" line="385"/>
<source>Do you want to minimize %1 to system tray instead of quitting when closed?</source> <source>Do you want to minimize %1 to system tray instead of quitting when closed?</source>
<translation>%1?</translation> <translation>%1?</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="379"/> <location filename="../../../widgets/mainwindow.cpp" line="387"/>
<source>You could change the option in Settings later.</source> <source>You could change the option in Settings later.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="432"/> <location filename="../../../widgets/mainwindow.cpp" line="440"/>
<source>%1 is still running here.</source> <source>%1 is still running here.</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="593"/> <location filename="../../../widgets/mainwindow.cpp" line="599"/>
<location filename="../../../widgets/mainwindow.cpp" line="604"/> <location filename="../../../widgets/mainwindow.cpp" line="610"/>
<source>Global</source> <source>Global</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="708"/> <location filename="../../../widgets/mainwindow.cpp" line="714"/>
<source>There is one export dialog running. Please close it first.</source> <source>There is one export dialog running. Please close it first.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../../../widgets/mainwindow.cpp" line="829"/> <location filename="../../../widgets/mainwindow.cpp" line="835"/>
<source>Failed to load %n notebook(s).</source> <source>Failed to load %n notebook(s).</source>
<translation type="unfinished"> <translation type="unfinished">
<numerusform></numerusform> <numerusform></numerusform>
</translation> </translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="830"/> <location filename="../../../widgets/mainwindow.cpp" line="836"/>
<source>These notebooks may be moved or deleted. It is recommended to remove them from configuration and open them with the correct root folder path later. <source>These notebooks may be moved or deleted. It is recommended to remove them from configuration and open them with the correct root folder path later.
Remove them from the configuration?</source> Remove them from the configuration?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -2168,6 +2173,16 @@ Remove them from the configuration?</source>
<source>About Qt</source> <source>About Qt</source>
<translation>Qtについて</translation> <translation>Qtについて</translation>
</message> </message>
<message>
<location filename="../../../utils/widgetutils.cpp" line="84"/>
<source>Are you sure to open link (%1)?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../utils/widgetutils.cpp" line="85"/>
<source>Malicious link might do harm to your device.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>vnotex::ManageNotebooksDialog</name> <name>vnotex::ManageNotebooksDialog</name>
@ -2232,7 +2247,7 @@ Remove them from the configuration?</source>
<name>vnotex::MarkdownEditor</name> <name>vnotex::MarkdownEditor</name>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="250"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="250"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="747"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="748"/>
<source>Insert Link</source> <source>Insert Link</source>
<translation></translation> <translation></translation>
</message> </message>
@ -2248,7 +2263,7 @@ Remove them from the configuration?</source>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="377"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="377"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1554"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1557"/>
<source>Failed to read local image file (%1) (%2).</source> <source>Failed to read local image file (%1) (%2).</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -2268,185 +2283,185 @@ Remove them from the configuration?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="552"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="553"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="589"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="590"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="659"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="660"/>
<source>Insert From Clipboard</source> <source>Insert From Clipboard</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="553"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="554"/>
<source>Insert From URL</source> <source>Insert From URL</source>
<translation>URLから挿入</translation> <translation>URLから挿入</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="554"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="555"/>
<source>Insert From Image Data</source> <source>Insert From Image Data</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="555"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="556"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="592"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="593"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="662"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="663"/>
<source>Insert As Image Link</source> <source>Insert As Image Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="590"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="591"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="661"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="662"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="811"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="812"/>
<source>Insert As Image</source> <source>Insert As Image</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="591"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="592"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="677"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="678"/>
<source>Insert As Text</source> <source>Insert As Text</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="664"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="665"/>
<source>Insert As Relative Image Link</source> <source>Insert As Relative Image Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="668"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="669"/>
<source>Insert As Link</source> <source>Insert As Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="670"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="671"/>
<source>Insert As Relative Link</source> <source>Insert As Relative Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="673"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="674"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="814"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="815"/>
<source>Attach And Insert Link</source> <source>Attach And Insert Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="679"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="680"/>
<source>Insert File Content</source> <source>Insert File Content</source>
<translation></translation> <translation></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../../../widgets/editors/markdowneditor.cpp" line="809"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="810"/>
<source>Insert From Clipboard (%n items)</source> <source>Insert From Clipboard (%n items)</source>
<translation type="unfinished"> <translation type="unfinished">
<numerusform></numerusform> <numerusform></numerusform>
</translation> </translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="862"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="863"/>
<source>Insert Image From Clipboard</source> <source>Insert Image From Clipboard</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="878"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="879"/>
<source>Insert Image From URL</source> <source>Insert Image From URL</source>
<translation>URLからイメージを挿入</translation> <translation>URLからイメージを挿入</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1071"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1072"/>
<source>&amp;Read</source> <source>&amp;Read</source>
<translation>(&amp;R)</translation> <translation>(&amp;R)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1089"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1090"/>
<source>Rich Paste</source> <source>Rich Paste</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1089"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1090"/>
<source>Paste as Plain Text</source> <source>Paste as Plain Text</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1098"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1099"/>
<source>Parse to Markdown and Paste</source> <source>Parse to Markdown and Paste</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1110"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1111"/>
<source>Insert Snippet</source> <source>Insert Snippet</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1473"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1476"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1572"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1575"/>
<source>Failed to upload image to image host (%1) as (%2).</source> <source>Failed to upload image to image host (%1) as (%2).</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1652"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1655"/>
<source>View Image</source> <source>View Image</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1661"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1664"/>
<source>Copy Image URL</source> <source>Copy Image URL</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1671"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1674"/>
<source>Copy Image</source> <source>Copy Image</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1728"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1731"/>
<source>Copy In-Place Preview</source> <source>Copy In-Place Preview</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1773"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1776"/>
<source>Open Link</source> <source>Open Link</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1782"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1785"/>
<source>Copy Link</source> <source>Copy Link</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1214"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1215"/>
<source>Fetching images to local...</source> <source>Fetching images to local...</source>
<translation>...</translation> <translation>...</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1215"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1216"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1518"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1521"/>
<source>Abort</source> <source>Abort</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1220"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1221"/>
<source>Fetch Images To Local</source> <source>Fetch Images To Local</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1247"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1249"/>
<source>Fetching image (%1)</source> <source>Fetching image (%1)</source>
<translation> (%1) </translation> <translation> (%1) </translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1485"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1488"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1523"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1526"/>
<source>Upload Images To Image Host</source> <source>Upload Images To Image Host</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1489"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1492"/>
<source>None</source> <source>None</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1517"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1520"/>
<source>Uploading local images...</source> <source>Uploading local images...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1545"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1548"/>
<source>Upload image (%1)</source> <source>Upload image (%1)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -2816,66 +2831,76 @@ Remove them from the configuration?</source>
<context> <context>
<name>vnotex::MarkdownViewWindow</name> <name>vnotex::MarkdownViewWindow</name>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="453"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="459"/>
<source>Markdown Viewer</source> <source>Markdown Viewer</source>
<translation>Markdownビューア</translation> <translation>Markdownビューア</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="800"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="808"/>
<location filename="../../../widgets/markdownviewwindow.cpp" line="832"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="840"/>
<source>Clear Obsolete Images</source> <source>Clear Obsolete Images</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="801"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="809"/>
<source>These images seems to be not in use anymore. Please confirm the deletion of them.</source> <source>These images seems to be not in use anymore. Please confirm the deletion of them.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="802"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="810"/>
<source>Deleted local images could be found in the recycle bin of notebook if it is from a bundle notebook.</source> <source>Deleted local images could be found in the recycle bin of notebook if it is from a bundle notebook.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="826"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="834"/>
<source>Clearing obsolete images...</source> <source>Clearing obsolete images...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="827"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="835"/>
<source>Abort</source> <source>Abort</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="841"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="849"/>
<source>Clear image (%1)</source> <source>Clear image (%1)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../../../widgets/markdownviewwindow.cpp" line="853"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="861"/>
<source>Cleared %n obsolete images</source> <source>Cleared %n obsolete images</source>
<translation type="unfinished"> <translation type="unfinished">
<numerusform></numerusform> <numerusform></numerusform>
</translation> </translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1278"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="1286"/>
<source>View Mode Not Supported In Read Mode</source> <source>View Mode Not Supported In Read Mode</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1296"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="1304"/>
<source>Edit Only</source> <source>Edit Only</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1307"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="1315"/>
<source>Edit with Preview</source> <source>Edit with Preview</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1011"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="1424"/>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1020"/> <source>Printed to PDF</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1424"/>
<source>Failed to print to PDF</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1019"/>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1028"/>
<source>Replace is not supported in read mode</source> <source>Replace is not supported in read mode</source>
<translation></translation> <translation></translation>
</message> </message>
@ -2883,12 +2908,12 @@ Remove them from the configuration?</source>
<context> <context>
<name>vnotex::MarkdownViewer</name> <name>vnotex::MarkdownViewer</name>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="131"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="136"/>
<source>&amp;Edit</source> <source>&amp;Edit</source>
<translation>(&amp;E)</translation> <translation>(&amp;E)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="411"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="421"/>
<source>Cross Copy</source> <source>Cross Copy</source>
<translation></translation> <translation></translation>
</message> </message>
@ -3996,7 +4021,7 @@ Description: %3</source>
<context> <context>
<name>vnotex::OutlineProvider</name> <name>vnotex::OutlineProvider</name>
<message> <message>
<location filename="../../../widgets/outlineprovider.h" line="103"/> <location filename="../../../widgets/outlineprovider.h" line="105"/>
<source>[EMPTY]</source> <source>[EMPTY]</source>
<translation>[]</translation> <translation>[]</translation>
</message> </message>
@ -5912,12 +5937,12 @@ Backup file last modified time: %2</source>
<context> <context>
<name>vnotex::WebViewExporter</name> <name>vnotex::WebViewExporter</name>
<message> <message>
<location filename="../../../export/webviewexporter.cpp" line="354"/> <location filename="../../../export/webviewexporter.cpp" line="355"/>
<source>Table of Contents</source> <source>Table of Contents</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../export/webviewexporter.cpp" line="586"/> <location filename="../../../export/webviewexporter.cpp" line="590"/>
<source>Copy output file (%1) to (%2).</source> <source>Copy output file (%1) to (%2).</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View File

@ -70,17 +70,17 @@
<context> <context>
<name>QWebEnginePage</name> <name>QWebEnginePage</name>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="303"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="313"/>
<source>&amp;Back</source> <source>&amp;Back</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="304"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="314"/>
<source>&amp;Forward</source> <source>&amp;Forward</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="305"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="315"/>
<source>&amp;Reload</source> <source>&amp;Reload</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -1110,12 +1110,12 @@
<context> <context>
<name>vnotex::FullScreenToggleAction</name> <name>vnotex::FullScreenToggleAction</name>
<message> <message>
<location filename="../../../widgets/fullscreentoggleaction.cpp" line="11"/> <location filename="../../../widgets/fullscreentoggleaction.cpp" line="12"/>
<source>F&amp;ull Screen</source> <source>F&amp;ull Screen</source>
<translation>(&amp;U)</translation> <translation>(&amp;U)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/fullscreentoggleaction.cpp" line="13"/> <location filename="../../../widgets/fullscreentoggleaction.cpp" line="14"/>
<source>Exit F&amp;ull Screen</source> <source>Exit F&amp;ull Screen</source>
<translation>退(&amp;U)</translation> <translation>退(&amp;U)</translation>
</message> </message>
@ -1802,55 +1802,55 @@
<context> <context>
<name>vnotex::MainWindow</name> <name>vnotex::MainWindow</name>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="813"/> <location filename="../../../widgets/mainwindow.cpp" line="819"/>
<source>Failed to check for updates (%1)</source> <source>Failed to check for updates (%1)</source>
<translation>(%1)</translation> <translation>(%1)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="815"/> <location filename="../../../widgets/mainwindow.cpp" line="821"/>
<source>Updates available: %1</source> <source>Updates available: %1</source>
<translation>: %1</translation> <translation>: %1</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="104"/> <location filename="../../../widgets/mainwindow.cpp" line="107"/>
<source>Initializing core components...</source> <source>Initializing core components...</source>
<translation>...</translation> <translation>...</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="377"/> <location filename="../../../widgets/mainwindow.cpp" line="385"/>
<source>Do you want to minimize %1 to system tray instead of quitting when closed?</source> <source>Do you want to minimize %1 to system tray instead of quitting when closed?</source>
<translation>%1退</translation> <translation>%1退</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="379"/> <location filename="../../../widgets/mainwindow.cpp" line="387"/>
<source>You could change the option in Settings later.</source> <source>You could change the option in Settings later.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="432"/> <location filename="../../../widgets/mainwindow.cpp" line="440"/>
<source>%1 is still running here.</source> <source>%1 is still running here.</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="593"/> <location filename="../../../widgets/mainwindow.cpp" line="599"/>
<location filename="../../../widgets/mainwindow.cpp" line="604"/> <location filename="../../../widgets/mainwindow.cpp" line="610"/>
<source>Global</source> <source>Global</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="708"/> <location filename="../../../widgets/mainwindow.cpp" line="714"/>
<source>There is one export dialog running. Please close it first.</source> <source>There is one export dialog running. Please close it first.</source>
<translation></translation> <translation></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../../../widgets/mainwindow.cpp" line="829"/> <location filename="../../../widgets/mainwindow.cpp" line="835"/>
<source>Failed to load %n notebook(s).</source> <source>Failed to load %n notebook(s).</source>
<translation> <translation>
<numerusform> %n </numerusform> <numerusform> %n </numerusform>
</translation> </translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/mainwindow.cpp" line="830"/> <location filename="../../../widgets/mainwindow.cpp" line="836"/>
<source>These notebooks may be moved or deleted. It is recommended to remove them from configuration and open them with the correct root folder path later. <source>These notebooks may be moved or deleted. It is recommended to remove them from configuration and open them with the correct root folder path later.
Remove them from the configuration?</source> Remove them from the configuration?</source>
<translation>使 <translation>使
@ -2144,12 +2144,12 @@ Remove them from the configuration?</source>
<translation>Qt</translation> <translation>Qt</translation>
</message> </message>
<message> <message>
<location filename="../../../main.cpp" line="134"/> <location filename="../../../main.cpp" line="135"/>
<source>%1 failed to start.</source> <source>%1 failed to start.</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../../../main.cpp" line="135"/> <location filename="../../../main.cpp" line="136"/>
<source>Failed to initialize configuration manager. Please check if all the files are intact or reinstall the application.</source> <source>Failed to initialize configuration manager. Please check if all the files are intact or reinstall the application.</source>
<translation></translation> <translation></translation>
</message> </message>
@ -2169,25 +2169,40 @@ Remove them from the configuration?</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../commandlineoptions.cpp" line="29"/> <location filename="../../../commandlineoptions.cpp" line="25"/>
<source>Log to stderr.</source>
<translation></translation>
</message>
<message>
<location filename="../../../commandlineoptions.cpp" line="32"/>
<source>WebEngine remote debugging port.</source> <source>WebEngine remote debugging port.</source>
<translation>WebEngine远程调试端口</translation> <translation>WebEngine远程调试端口</translation>
</message> </message>
<message> <message>
<location filename="../../../commandlineoptions.cpp" line="30"/> <location filename="../../../commandlineoptions.cpp" line="33"/>
<source>port_number</source> <source>port_number</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../commandlineoptions.cpp" line="34"/> <location filename="../../../commandlineoptions.cpp" line="37"/>
<source>WebEngine without sandbox.</source> <source>WebEngine without sandbox.</source>
<translation>WebEngine</translation> <translation>WebEngine</translation>
</message> </message>
<message> <message>
<location filename="../../../commandlineoptions.cpp" line="38"/> <location filename="../../../commandlineoptions.cpp" line="41"/>
<source>WebEngine with GPU disabled.</source> <source>WebEngine with GPU disabled.</source>
<translation>WebEngine中禁用GPU</translation> <translation>WebEngine中禁用GPU</translation>
</message> </message>
<message>
<location filename="../../../utils/widgetutils.cpp" line="84"/>
<source>Are you sure to open link (%1)?</source>
<translation> (%1)</translation>
</message>
<message>
<location filename="../../../utils/widgetutils.cpp" line="85"/>
<source>Malicious link might do harm to your device.</source>
<translation></translation>
</message>
</context> </context>
<context> <context>
<name>vnotex::ManageNotebooksDialog</name> <name>vnotex::ManageNotebooksDialog</name>
@ -2256,7 +2271,7 @@ Remove them from the configuration?</source>
<name>vnotex::MarkdownEditor</name> <name>vnotex::MarkdownEditor</name>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="250"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="250"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="747"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="748"/>
<source>Insert Link</source> <source>Insert Link</source>
<translation></translation> <translation></translation>
</message> </message>
@ -2272,7 +2287,7 @@ Remove them from the configuration?</source>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="377"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="377"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1554"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1557"/>
<source>Failed to read local image file (%1) (%2).</source> <source>Failed to read local image file (%1) (%2).</source>
<translation>(%1)(%2)</translation> <translation>(%1)(%2)</translation>
</message> </message>
@ -2292,185 +2307,185 @@ Remove them from the configuration?</source>
<translation>Markdown并粘贴</translation> <translation>Markdown并粘贴</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="552"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="553"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="589"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="590"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="659"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="660"/>
<source>Insert From Clipboard</source> <source>Insert From Clipboard</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="553"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="554"/>
<source>Insert From URL</source> <source>Insert From URL</source>
<translation>URL插入</translation> <translation>URL插入</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="554"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="555"/>
<source>Insert From Image Data</source> <source>Insert From Image Data</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="555"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="556"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="592"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="593"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="662"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="663"/>
<source>Insert As Image Link</source> <source>Insert As Image Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="590"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="591"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="661"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="662"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="811"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="812"/>
<source>Insert As Image</source> <source>Insert As Image</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="591"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="592"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="677"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="678"/>
<source>Insert As Text</source> <source>Insert As Text</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="664"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="665"/>
<source>Insert As Relative Image Link</source> <source>Insert As Relative Image Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="668"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="669"/>
<source>Insert As Link</source> <source>Insert As Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="670"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="671"/>
<source>Insert As Relative Link</source> <source>Insert As Relative Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="673"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="674"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="814"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="815"/>
<source>Attach And Insert Link</source> <source>Attach And Insert Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="679"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="680"/>
<source>Insert File Content</source> <source>Insert File Content</source>
<translation></translation> <translation></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../../../widgets/editors/markdowneditor.cpp" line="809"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="810"/>
<source>Insert From Clipboard (%n items)</source> <source>Insert From Clipboard (%n items)</source>
<translation> <translation>
<numerusform>(%n项)</numerusform> <numerusform>(%n项)</numerusform>
</translation> </translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="862"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="863"/>
<source>Insert Image From Clipboard</source> <source>Insert Image From Clipboard</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="878"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="879"/>
<source>Insert Image From URL</source> <source>Insert Image From URL</source>
<translation>URL插入图片</translation> <translation>URL插入图片</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1071"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1072"/>
<source>&amp;Read</source> <source>&amp;Read</source>
<translation>(&amp;R)</translation> <translation>(&amp;R)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1089"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1090"/>
<source>Rich Paste</source> <source>Rich Paste</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1089"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1090"/>
<source>Paste as Plain Text</source> <source>Paste as Plain Text</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1098"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1099"/>
<source>Parse to Markdown and Paste</source> <source>Parse to Markdown and Paste</source>
<translation>Markodwn并粘贴</translation> <translation>Markodwn并粘贴</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1110"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1111"/>
<source>Insert Snippet</source> <source>Insert Snippet</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1473"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1476"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1572"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1575"/>
<source>Failed to upload image to image host (%1) as (%2).</source> <source>Failed to upload image to image host (%1) as (%2).</source>
<translation>(%2)(%1</translation> <translation>(%2)(%1</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1652"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1655"/>
<source>View Image</source> <source>View Image</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1661"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1664"/>
<source>Copy Image URL</source> <source>Copy Image URL</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1671"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1674"/>
<source>Copy Image</source> <source>Copy Image</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1728"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1731"/>
<source>Copy In-Place Preview</source> <source>Copy In-Place Preview</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1773"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1776"/>
<source>Open Link</source> <source>Open Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1782"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1785"/>
<source>Copy Link</source> <source>Copy Link</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1214"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1215"/>
<source>Fetching images to local...</source> <source>Fetching images to local...</source>
<translation>...</translation> <translation>...</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1215"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1216"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1518"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1521"/>
<source>Abort</source> <source>Abort</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1220"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1221"/>
<source>Fetch Images To Local</source> <source>Fetch Images To Local</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1247"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1249"/>
<source>Fetching image (%1)</source> <source>Fetching image (%1)</source>
<translation>(%1)</translation> <translation>(%1)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1485"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1488"/>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1523"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1526"/>
<source>Upload Images To Image Host</source> <source>Upload Images To Image Host</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1489"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1492"/>
<source>None</source> <source>None</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1517"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1520"/>
<source>Uploading local images...</source> <source>Uploading local images...</source>
<translation>...</translation> <translation>...</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdowneditor.cpp" line="1545"/> <location filename="../../../widgets/editors/markdowneditor.cpp" line="1548"/>
<source>Upload image (%1)</source> <source>Upload image (%1)</source>
<translation>(%1)</translation> <translation>(%1)</translation>
</message> </message>
@ -2860,66 +2875,76 @@ Remove them from the configuration?</source>
<context> <context>
<name>vnotex::MarkdownViewWindow</name> <name>vnotex::MarkdownViewWindow</name>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="453"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="459"/>
<source>Markdown Viewer</source> <source>Markdown Viewer</source>
<translation>Markdown查看器</translation> <translation>Markdown查看器</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="800"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="808"/>
<location filename="../../../widgets/markdownviewwindow.cpp" line="832"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="840"/>
<source>Clear Obsolete Images</source> <source>Clear Obsolete Images</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="801"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="809"/>
<source>These images seems to be not in use anymore. Please confirm the deletion of them.</source> <source>These images seems to be not in use anymore. Please confirm the deletion of them.</source>
<translation>使</translation> <translation>使</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="802"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="810"/>
<source>Deleted local images could be found in the recycle bin of notebook if it is from a bundle notebook.</source> <source>Deleted local images could be found in the recycle bin of notebook if it is from a bundle notebook.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="826"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="834"/>
<source>Clearing obsolete images...</source> <source>Clearing obsolete images...</source>
<translation>...</translation> <translation>...</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="827"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="835"/>
<source>Abort</source> <source>Abort</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="841"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="849"/>
<source>Clear image (%1)</source> <source>Clear image (%1)</source>
<translation>(%1)</translation> <translation>(%1)</translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../../../widgets/markdownviewwindow.cpp" line="853"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="861"/>
<source>Cleared %n obsolete images</source> <source>Cleared %n obsolete images</source>
<translation> <translation>
<numerusform> %n </numerusform> <numerusform> %n </numerusform>
</translation> </translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1278"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="1286"/>
<source>View Mode Not Supported In Read Mode</source> <source>View Mode Not Supported In Read Mode</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1296"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="1304"/>
<source>Edit Only</source> <source>Edit Only</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1307"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="1315"/>
<source>Edit with Preview</source> <source>Edit with Preview</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1011"/> <location filename="../../../widgets/markdownviewwindow.cpp" line="1424"/>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1020"/> <source>Printed to PDF</source>
<translation>PDF</translation>
</message>
<message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1424"/>
<source>Failed to print to PDF</source>
<translation>PDF</translation>
</message>
<message>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1019"/>
<location filename="../../../widgets/markdownviewwindow.cpp" line="1028"/>
<source>Replace is not supported in read mode</source> <source>Replace is not supported in read mode</source>
<translation></translation> <translation></translation>
</message> </message>
@ -2927,12 +2952,12 @@ Remove them from the configuration?</source>
<context> <context>
<name>vnotex::MarkdownViewer</name> <name>vnotex::MarkdownViewer</name>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="131"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="136"/>
<source>&amp;Edit</source> <source>&amp;Edit</source>
<translation>(&amp;E)</translation> <translation>(&amp;E)</translation>
</message> </message>
<message> <message>
<location filename="../../../widgets/editors/markdownviewer.cpp" line="411"/> <location filename="../../../widgets/editors/markdownviewer.cpp" line="421"/>
<source>Cross Copy</source> <source>Cross Copy</source>
<translation></translation> <translation></translation>
</message> </message>
@ -4068,7 +4093,7 @@ Description: %3</source>
<context> <context>
<name>vnotex::OutlineProvider</name> <name>vnotex::OutlineProvider</name>
<message> <message>
<location filename="../../../widgets/outlineprovider.h" line="103"/> <location filename="../../../widgets/outlineprovider.h" line="105"/>
<source>[EMPTY]</source> <source>[EMPTY]</source>
<translation>[]</translation> <translation>[]</translation>
</message> </message>
@ -6012,12 +6037,12 @@ Backup file last modified time: %2</source>
<context> <context>
<name>vnotex::WebViewExporter</name> <name>vnotex::WebViewExporter</name>
<message> <message>
<location filename="../../../export/webviewexporter.cpp" line="354"/> <location filename="../../../export/webviewexporter.cpp" line="355"/>
<source>Table of Contents</source> <source>Table of Contents</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../export/webviewexporter.cpp" line="586"/> <location filename="../../../export/webviewexporter.cpp" line="590"/>
<source>Copy output file (%1) to (%2).</source> <source>Copy output file (%1) to (%2).</source>
<translation>(%1)(%2)</translation> <translation>(%1)(%2)</translation>
</message> </message>

View File

@ -3,7 +3,7 @@
"metadata" : { "metadata" : {
"//comment": "When releasing new version, please go through the following configs to check if override is needed.", "//comment": "When releasing new version, please go through the following configs to check if override is needed.",
"//Comment": "markdown_editor#override_viewer_resource", "//Comment": "markdown_editor#override_viewer_resource",
"version" : "3.18.0" "version" : "3.19.2"
}, },
"core" : { "core" : {
"theme" : "pure", "theme" : "pure",

View File

@ -59,6 +59,18 @@ Expand the selection to the beginning or end of current paragraph.
Expand the selection to the beginning or end of current line. Expand the selection to the beginning or end of current line.
- `Ctrl+Shift+Home`, `Ctrl+Shift+End` - `Ctrl+Shift+Home`, `Ctrl+Shift+End`
Expand the selection to the beginning or end of current note. Expand the selection to the beginning or end of current note.
- `Ctrl+Shift+G`
Go to line.
- `Ctrl+C/X`
Copy/Cut line if there is no selection.
- `Ctrl+L`
Select line.
- `Alt+Up/Down`
Move line up/down.
- `Shift+Alt+Up/Down`
Copy line up/down.
- `Ctrl+Shift+K`
Delete line.
## Markdown Editor ## Markdown Editor
### Read Mode ### Read Mode

View File

@ -1,7 +1,7 @@
# Welcome to VNote # Welcome to VNote
A pleasant note-taking platform. A pleasant note-taking platform.
For more information, please visit [**VNote's Home Page**](https://vnotex.github.io/vnote) or [Home Page on Gitee](https://tamlok.gitee.io/vnote). For more information, please visit [**VNote's Home Page**](https://vnotex.github.io/vnote).
## FAQs ## FAQs
* Hover the mouse over buttons to get detailed information. * Hover the mouse over buttons to get detailed information.

View File

@ -59,6 +59,18 @@ VNote的很多部件均支持`Ctrl+J`和`Ctrl+K`导航。
扩展选定到行首和行尾。 扩展选定到行首和行尾。
- `Ctrl+Shift+Home`, `Ctrl+Shift+End` - `Ctrl+Shift+Home`, `Ctrl+Shift+End`
扩展选定到笔记开始或结尾处。 扩展选定到笔记开始或结尾处。
- `Ctrl+Shift+G`
跳转到指定行。
- `Ctrl+C/X`
在没有选中文本时复制/剪切整行。
- `Ctrl+L`
选择当前行。
- `Alt+Up/Down`
向上/向下移动行。
- `Shift+Alt+Up/Down`
向上/向下复制行。
- `Ctrl+Shift+K`
删除行。
## Markdown 编辑器 ## Markdown 编辑器
### 阅读模式 ### 阅读模式

View File

@ -1,7 +1,7 @@
# 欢迎使用 VNote # 欢迎使用 VNote
一个舒适的笔记平台。 一个舒适的笔记平台。
更多信息,请访问[VNote主页](https://vnotex.github.io/vnote)或者[由Gitee托管的主页](https://tamlok.gitee.io/vnote) 更多信息,请访问[VNote主页](https://vnotex.github.io/vnote)。
## 常见问题 ## 常见问题
* 将鼠标悬停在按钮上可以获取详细信息。 * 将鼠标悬停在按钮上可以获取详细信息。

View File

@ -349,6 +349,7 @@
<file>themes/moonlight/checkbox_unchecked.svg</file> <file>themes/moonlight/checkbox_unchecked.svg</file>
<file>themes/moonlight/checkbox_unchecked_disabled.svg</file> <file>themes/moonlight/checkbox_unchecked_disabled.svg</file>
<file>themes/moonlight/close.svg</file> <file>themes/moonlight/close.svg</file>
<file>themes/moonlight/expand_toolbar.svg</file>
<file>themes/moonlight/close_grey.svg</file> <file>themes/moonlight/close_grey.svg</file>
<file>themes/moonlight/cover.png</file> <file>themes/moonlight/cover.png</file>
<file>themes/moonlight/down.svg</file> <file>themes/moonlight/down.svg</file>
@ -381,6 +382,7 @@
<file>themes/pure/checkbox_unchecked.svg</file> <file>themes/pure/checkbox_unchecked.svg</file>
<file>themes/pure/checkbox_unchecked_disabled.svg</file> <file>themes/pure/checkbox_unchecked_disabled.svg</file>
<file>themes/pure/close.svg</file> <file>themes/pure/close.svg</file>
<file>themes/pure/expand_toolbar.svg</file>
<file>themes/pure/close_grey.svg</file> <file>themes/pure/close_grey.svg</file>
<file>themes/pure/cover.png</file> <file>themes/pure/cover.png</file>
<file>themes/pure/down.svg</file> <file>themes/pure/down.svg</file>
@ -413,6 +415,7 @@
<file>themes/solarized-dark/checkbox_unchecked.svg</file> <file>themes/solarized-dark/checkbox_unchecked.svg</file>
<file>themes/solarized-dark/checkbox_unchecked_disabled.svg</file> <file>themes/solarized-dark/checkbox_unchecked_disabled.svg</file>
<file>themes/solarized-dark/close.svg</file> <file>themes/solarized-dark/close.svg</file>
<file>themes/solarized-dark/expand_toolbar.svg</file>
<file>themes/solarized-dark/close_grey.svg</file> <file>themes/solarized-dark/close_grey.svg</file>
<file>themes/solarized-dark/cover.png</file> <file>themes/solarized-dark/cover.png</file>
<file>themes/solarized-dark/down.svg</file> <file>themes/solarized-dark/down.svg</file>
@ -445,6 +448,7 @@
<file>themes/solarized-light/checkbox_unchecked.svg</file> <file>themes/solarized-light/checkbox_unchecked.svg</file>
<file>themes/solarized-light/checkbox_unchecked_disabled.svg</file> <file>themes/solarized-light/checkbox_unchecked_disabled.svg</file>
<file>themes/solarized-light/close.svg</file> <file>themes/solarized-light/close.svg</file>
<file>themes/solarized-light/expand_toolbar.svg</file>
<file>themes/solarized-light/close_grey.svg</file> <file>themes/solarized-light/close_grey.svg</file>
<file>themes/solarized-light/cover.png</file> <file>themes/solarized-light/cover.png</file>
<file>themes/solarized-light/down.svg</file> <file>themes/solarized-light/down.svg</file>
@ -804,6 +808,7 @@
<file>themes/vscode-dark/checkbox_unchecked.svg</file> <file>themes/vscode-dark/checkbox_unchecked.svg</file>
<file>themes/vscode-dark/checkbox_unchecked_disabled.svg</file> <file>themes/vscode-dark/checkbox_unchecked_disabled.svg</file>
<file>themes/vscode-dark/close.svg</file> <file>themes/vscode-dark/close.svg</file>
<file>themes/vscode-dark/expand_toolbar.svg</file>
<file>themes/vscode-dark/close_grey.svg</file> <file>themes/vscode-dark/close_grey.svg</file>
<file>themes/vscode-dark/cover.png</file> <file>themes/vscode-dark/cover.png</file>
<file>themes/vscode-dark/down.svg</file> <file>themes/vscode-dark/down.svg</file>
@ -837,6 +842,7 @@
<file>themes/vue-light/checkbox_unchecked.svg</file> <file>themes/vue-light/checkbox_unchecked.svg</file>
<file>themes/vue-light/checkbox_unchecked_disabled.svg</file> <file>themes/vue-light/checkbox_unchecked_disabled.svg</file>
<file>themes/vue-light/close.svg</file> <file>themes/vue-light/close.svg</file>
<file>themes/vue-light/expand_toolbar.svg</file>
<file>themes/vue-light/close_grey.svg</file> <file>themes/vue-light/close_grey.svg</file>
<file>themes/vue-light/cover.png</file> <file>themes/vue-light/cover.png</file>
<file>themes/vue-light/down.svg</file> <file>themes/vue-light/down.svg</file>
@ -869,6 +875,7 @@
<file>themes/vue-dark/checkbox_unchecked.svg</file> <file>themes/vue-dark/checkbox_unchecked.svg</file>
<file>themes/vue-dark/checkbox_unchecked_disabled.svg</file> <file>themes/vue-dark/checkbox_unchecked_disabled.svg</file>
<file>themes/vue-dark/close.svg</file> <file>themes/vue-dark/close.svg</file>
<file>themes/vue-dark/expand_toolbar.svg</file>
<file>themes/vue-dark/close_grey.svg</file> <file>themes/vue-dark/close_grey.svg</file>
<file>themes/vue-dark/cover.png</file> <file>themes/vue-dark/cover.png</file>
<file>themes/vue-dark/down.svg</file> <file>themes/vue-dark/down.svg</file>
@ -905,6 +912,7 @@
<file>themes/vx-idea/checkbox_unchecked.svg</file> <file>themes/vx-idea/checkbox_unchecked.svg</file>
<file>themes/vx-idea/checkbox_unchecked_disabled.svg</file> <file>themes/vx-idea/checkbox_unchecked_disabled.svg</file>
<file>themes/vx-idea/close.svg</file> <file>themes/vx-idea/close.svg</file>
<file>themes/vx-idea/expand_toolbar.svg</file>
<file>themes/vx-idea/close_grey.svg</file> <file>themes/vx-idea/close_grey.svg</file>
<file>themes/vx-idea/cover.png</file> <file>themes/vx-idea/cover.png</file>
<file>themes/vx-idea/down.svg</file> <file>themes/vx-idea/down.svg</file>

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747190112225" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2510" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M798.165333 524.501333a42.666667 42.666667 0 0 0-60.330666 0L512 750.336l-225.834667-225.834667a42.666667 42.666667 0 0 0-60.330666 60.330667l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330667z" p-id="2511" fill="#9EA5B4"></path><path d="M798.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 0L512 451.669333 286.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 60.330666l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330666z" p-id="2512" fill="#9EA5B4"></path></svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -5,7 +5,6 @@
* same specificity and the rule that appears last takes precedence. * same specificity and the rule that appears last takes precedence.
* VNote specific syntax: * VNote specific syntax:
* - @widgets#toolbox#title#border: reference to a color defined in palette.ini; * - @widgets#toolbox#title#border: reference to a color defined in palette.ini;
* - $2px: 2 will be scaled by multiplying current display scaled factor.
*/ */
QWidget { QWidget {
@ -148,13 +147,16 @@ QToolBar::separator {
} }
QToolBarExtension#qt_toolbar_ext_button { QToolBarExtension#qt_toolbar_ext_button {
background-color: @widgets#qtoolbar#extension#bg; qproperty-icon: url(expand_toolbar.svg);
margin: 30px; background-color: @widgets#qtoolbutton#bg;
} }
QToolBarExtension#qt_toolbar_ext_button:hover { QToolBarExtension#qt_toolbar_ext_button:hover {
background-color: @widgets#qtoolbar#extension#hover#bg; background-color: @widgets#qtoolbutton#hover#bg;
margin: 30px; }
QToolBarExtension#qt_toolbar_ext_button:pressed {
background-color: @widgets#qtoolbutton#pressed#bg;
} }
/* QToolButton */ /* QToolButton */
@ -586,7 +588,7 @@ QTabBar::close-button:hover {
} }
QTabBar::scroller { QTabBar::scroller {
width: $20px; width: 20px;
} }
QTabBar QToolButton { QTabBar QToolButton {

View File

@ -5,7 +5,6 @@
* same specificity and the rule that appears last takes precedence. * same specificity and the rule that appears last takes precedence.
* VNote specific syntax: * VNote specific syntax:
* - @widgets#toolbox#title#border: reference to a color defined in palette.ini; * - @widgets#toolbox#title#border: reference to a color defined in palette.ini;
* - $2px: 2 will be scaled by multiplying current display scaled factor.
*/ */
QWidget[HitSettingWidget="true"] { QWidget[HitSettingWidget="true"] {

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747190112225" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2510" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M798.165333 524.501333a42.666667 42.666667 0 0 0-60.330666 0L512 750.336l-225.834667-225.834667a42.666667 42.666667 0 0 0-60.330666 60.330667l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330667z" p-id="2511" fill="#222222"></path><path d="M798.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 0L512 451.669333 286.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 60.330666l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330666z" p-id="2512" fill="#222222"></path></svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -5,7 +5,6 @@
* same specificity and the rule that appears last takes precedence. * same specificity and the rule that appears last takes precedence.
* VNote specific syntax: * VNote specific syntax:
* - @widgets#toolbox#title#border: reference to a color defined in palette.ini; * - @widgets#toolbox#title#border: reference to a color defined in palette.ini;
* - $2px: 2 will be scaled by multiplying current display scaled factor.
*/ */
QWidget { QWidget {
@ -167,13 +166,16 @@ QToolBar::separator {
} }
QToolBarExtension#qt_toolbar_ext_button { QToolBarExtension#qt_toolbar_ext_button {
background-color: @widgets#qtoolbar#extension#bg; qproperty-icon: url(expand_toolbar.svg);
margin: 30px; background-color: @widgets#qtoolbutton#bg;
} }
QToolBarExtension#qt_toolbar_ext_button:hover { QToolBarExtension#qt_toolbar_ext_button:hover {
background-color: @widgets#qtoolbar#extension#hover#bg; background-color: @widgets#qtoolbutton#hover#bg;
margin: 30px; }
QToolBarExtension#qt_toolbar_ext_button:pressed {
background-color: @widgets#qtoolbutton#pressed#bg;
} }
/* QToolButton */ /* QToolButton */
@ -624,7 +626,7 @@ QTabBar::close-button:hover {
} }
QTabBar::scroller { QTabBar::scroller {
width: $20px; width: 20px;
} }
QTabBar QToolButton { QTabBar QToolButton {

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747190112225" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2510" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M798.165333 524.501333a42.666667 42.666667 0 0 0-60.330666 0L512 750.336l-225.834667-225.834667a42.666667 42.666667 0 0 0-60.330666 60.330667l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330667z" p-id="2511" fill="#9EA5B4"></path><path d="M798.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 0L512 451.669333 286.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 60.330666l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330666z" p-id="2512" fill="#9EA5B4"></path></svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -5,7 +5,6 @@
* same specificity and the rule that appears last takes precedence. * same specificity and the rule that appears last takes precedence.
* VNote specific syntax: * VNote specific syntax:
* - @widgets#toolbox#title#border: reference to a color defined in palette.ini; * - @widgets#toolbox#title#border: reference to a color defined in palette.ini;
* - $2px: 2 will be scaled by multiplying current display scaled factor.
*/ */
QWidget { QWidget {
@ -144,13 +143,16 @@ QToolBar::separator {
} }
QToolBarExtension#qt_toolbar_ext_button { QToolBarExtension#qt_toolbar_ext_button {
background-color: @widgets#qtoolbar#extension#bg; qproperty-icon: url(expand_toolbar.svg);
margin: 30px; background-color: @widgets#qtoolbutton#bg;
} }
QToolBarExtension#qt_toolbar_ext_button:hover { QToolBarExtension#qt_toolbar_ext_button:hover {
background-color: @widgets#qtoolbar#extension#hover#bg; background-color: @widgets#qtoolbutton#hover#bg;
margin: 30px; }
QToolBarExtension#qt_toolbar_ext_button:pressed {
background-color: @widgets#qtoolbutton#pressed#bg;
} }
/* QToolButton */ /* QToolButton */
@ -582,7 +584,7 @@ QTabBar::close-button:hover {
} }
QTabBar::scroller { QTabBar::scroller {
width: $20px; width: 20px;
} }
QTabBar QToolButton { QTabBar QToolButton {

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747190112225" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2510" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M798.165333 524.501333a42.666667 42.666667 0 0 0-60.330666 0L512 750.336l-225.834667-225.834667a42.666667 42.666667 0 0 0-60.330666 60.330667l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330667z" p-id="2511" fill="#9EA5B4"></path><path d="M798.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 0L512 451.669333 286.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 60.330666l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330666z" p-id="2512" fill="#9EA5B4"></path></svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -5,7 +5,6 @@
* same specificity and the rule that appears last takes precedence. * same specificity and the rule that appears last takes precedence.
* VNote specific syntax: * VNote specific syntax:
* - @widgets#toolbox#title#border: reference to a color defined in palette.ini; * - @widgets#toolbox#title#border: reference to a color defined in palette.ini;
* - $2px: 2 will be scaled by multiplying current display scaled factor.
*/ */
QWidget { QWidget {
@ -144,13 +143,16 @@ QToolBar::separator {
} }
QToolBarExtension#qt_toolbar_ext_button { QToolBarExtension#qt_toolbar_ext_button {
background-color: @widgets#qtoolbar#extension#bg; qproperty-icon: url(expand_toolbar.svg);
margin: 30px; background-color: @widgets#qtoolbutton#bg;
} }
QToolBarExtension#qt_toolbar_ext_button:hover { QToolBarExtension#qt_toolbar_ext_button:hover {
background-color: @widgets#qtoolbar#extension#hover#bg; background-color: @widgets#qtoolbutton#hover#bg;
margin: 30px; }
QToolBarExtension#qt_toolbar_ext_button:pressed {
background-color: @widgets#qtoolbutton#pressed#bg;
} }
/* QToolButton */ /* QToolButton */
@ -582,7 +584,7 @@ QTabBar::close-button:hover {
} }
QTabBar::scroller { QTabBar::scroller {
width: $20px; width: 20px;
} }
QTabBar QToolButton { QTabBar QToolButton {

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747190112225" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2510" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M798.165333 524.501333a42.666667 42.666667 0 0 0-60.330666 0L512 750.336l-225.834667-225.834667a42.666667 42.666667 0 0 0-60.330666 60.330667l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330667z" p-id="2511" fill="#9EA5B4"></path><path d="M798.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 0L512 451.669333 286.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 60.330666l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330666z" p-id="2512" fill="#9EA5B4"></path></svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -5,7 +5,6 @@
* same specificity and the rule that appears last takes precedence. * same specificity and the rule that appears last takes precedence.
* VNote specific syntax: * VNote specific syntax:
* - @widgets#toolbox#title#border: reference to a color defined in palette.ini; * - @widgets#toolbox#title#border: reference to a color defined in palette.ini;
* - $2px: 2 will be scaled by multiplying current display scaled factor.
*/ */
QWidget { QWidget {
@ -144,13 +143,16 @@ QToolBar::separator {
} }
QToolBarExtension#qt_toolbar_ext_button { QToolBarExtension#qt_toolbar_ext_button {
background-color: @widgets#qtoolbar#extension#bg; qproperty-icon: url(expand_toolbar.svg);
margin: 30px; background-color: @widgets#qtoolbutton#bg;
} }
QToolBarExtension#qt_toolbar_ext_button:hover { QToolBarExtension#qt_toolbar_ext_button:hover {
background-color: @widgets#qtoolbar#extension#hover#bg; background-color: @widgets#qtoolbutton#hover#bg;
margin: 30px; }
QToolBarExtension#qt_toolbar_ext_button:pressed {
background-color: @widgets#qtoolbutton#pressed#bg;
} }
/* QToolButton */ /* QToolButton */
@ -582,7 +584,7 @@ QTabBar::close-button:hover {
} }
QTabBar::scroller { QTabBar::scroller {
width: $20px; width: 20px;
} }
QTabBar QToolButton { QTabBar QToolButton {

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747190112225" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2510" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M798.165333 524.501333a42.666667 42.666667 0 0 0-60.330666 0L512 750.336l-225.834667-225.834667a42.666667 42.666667 0 0 0-60.330666 60.330667l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330667z" p-id="2511" fill="#4d5765"></path><path d="M798.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 0L512 451.669333 286.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 60.330666l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330666z" p-id="2512" fill="#4d5765"></path></svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -5,7 +5,6 @@
* same specificity and the rule that appears last takes precedence. * same specificity and the rule that appears last takes precedence.
* VNote specific syntax: * VNote specific syntax:
* - @widgets#toolbox#title#border: reference to a color defined in palette.ini; * - @widgets#toolbox#title#border: reference to a color defined in palette.ini;
* - $2px: 2 will be scaled by multiplying current display scaled factor.
*/ */
QWidget { QWidget {
@ -149,13 +148,16 @@ QToolBar::separator {
} }
QToolBarExtension#qt_toolbar_ext_button { QToolBarExtension#qt_toolbar_ext_button {
background-color: @widgets#qtoolbar#extension#bg; qproperty-icon: url(expand_toolbar.svg);
margin: 30px; background-color: @widgets#qtoolbutton#bg;
} }
QToolBarExtension#qt_toolbar_ext_button:hover { QToolBarExtension#qt_toolbar_ext_button:hover {
background-color: @widgets#qtoolbar#extension#hover#bg; background-color: @widgets#qtoolbutton#hover#bg;
margin: 30px; }
QToolBarExtension#qt_toolbar_ext_button:pressed {
background-color: @widgets#qtoolbutton#pressed#bg;
} }
/* QToolButton */ /* QToolButton */
@ -587,7 +589,7 @@ QTabBar::close-button:hover {
} }
QTabBar::scroller { QTabBar::scroller {
width: $20px; width: 20px;
} }
QTabBar QToolButton { QTabBar QToolButton {

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747190112225" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2510" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M798.165333 524.501333a42.666667 42.666667 0 0 0-60.330666 0L512 750.336l-225.834667-225.834667a42.666667 42.666667 0 0 0-60.330666 60.330667l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330667z" p-id="2511" fill="#222222"></path><path d="M798.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 0L512 451.669333 286.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 60.330666l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330666z" p-id="2512" fill="#222222"></path></svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -5,7 +5,6 @@
* same specificity and the rule that appears last takes precedence. * same specificity and the rule that appears last takes precedence.
* VNote specific syntax: * VNote specific syntax:
* - @widgets#toolbox#title#border: reference to a color defined in palette.ini; * - @widgets#toolbox#title#border: reference to a color defined in palette.ini;
* - $2px: 2 will be scaled by multiplying current display scaled factor.
*/ */
QWidget { QWidget {
@ -167,13 +166,16 @@ QToolBar::separator {
} }
QToolBarExtension#qt_toolbar_ext_button { QToolBarExtension#qt_toolbar_ext_button {
background-color: @widgets#qtoolbar#extension#bg; qproperty-icon: url(expand_toolbar.svg);
margin: 30px; background-color: @widgets#qtoolbutton#bg;
} }
QToolBarExtension#qt_toolbar_ext_button:hover { QToolBarExtension#qt_toolbar_ext_button:hover {
background-color: @widgets#qtoolbar#extension#hover#bg; background-color: @widgets#qtoolbutton#hover#bg;
margin: 30px; }
QToolBarExtension#qt_toolbar_ext_button:pressed {
background-color: @widgets#qtoolbutton#pressed#bg;
} }
/* QToolButton */ /* QToolButton */
@ -624,7 +626,7 @@ QTabBar::close-button:hover {
} }
QTabBar::scroller { QTabBar::scroller {
width: $20px; width: 20px;
} }
QTabBar QToolButton { QTabBar QToolButton {

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747190112225" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2510" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M798.165333 524.501333a42.666667 42.666667 0 0 0-60.330666 0L512 750.336l-225.834667-225.834667a42.666667 42.666667 0 0 0-60.330666 60.330667l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330667z" p-id="2511" fill="#222222"></path><path d="M798.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 0L512 451.669333 286.165333 225.834667a42.666667 42.666667 0 0 0-60.330666 60.330666l256 256a42.666667 42.666667 0 0 0 60.330666 0l256-256a42.666667 42.666667 0 0 0 0-60.330666z" p-id="2512" fill="#222222"></path></svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -5,7 +5,6 @@
* same specificity and the rule that appears last takes precedence. * same specificity and the rule that appears last takes precedence.
* VNote specific syntax: * VNote specific syntax:
* - @widgets#toolbox#title#border: reference to a color defined in palette.ini; * - @widgets#toolbox#title#border: reference to a color defined in palette.ini;
* - $2px: 2 will be scaled by multiplying current display scaled factor.
*/ */
QWidget { QWidget {
@ -168,13 +167,16 @@ QToolBar::separator {
} }
QToolBarExtension#qt_toolbar_ext_button { QToolBarExtension#qt_toolbar_ext_button {
background-color: @widgets#qtoolbar#extension#bg; qproperty-icon: url(expand_toolbar.svg);
margin: 30px; background-color: @widgets#qtoolbutton#bg;
} }
QToolBarExtension#qt_toolbar_ext_button:hover { QToolBarExtension#qt_toolbar_ext_button:hover {
background-color: @widgets#qtoolbar#extension#hover#bg; background-color: @widgets#qtoolbutton#hover#bg;
margin: 30px; }
QToolBarExtension#qt_toolbar_ext_button:pressed {
background-color: @widgets#qtoolbutton#pressed#bg;
} }
/* QToolButton */ /* QToolButton */
@ -643,7 +645,7 @@ QTabBar::close-button:hover {
} }
QTabBar::scroller { QTabBar::scroller {
width: $20px; width: 20px;
} }
QTabBar QToolButton { QTabBar QToolButton {

View File

@ -4,17 +4,24 @@
module.exports = function protect_xss(md, opts = {}) { module.exports = function protect_xss(md, opts = {}) {
const proxy = (tokens, idx, options, env, self) => self.renderToken(tokens, idx, options); const proxy = (tokens, idx, options, env, self) => self.renderToken(tokens, idx, options);
const defaultHtmlInlineRenderer = md.renderer.rules.html_inline || proxy; const defaultHtmlInlineRenderer = md.renderer.rules.html_inline || proxy;
const defaultHtmlBlockRenderer = md.renderer.rules.html_block || proxy;
opts.whiteList = {...window.filterXSS.getDefaultWhiteList(), ...opts.whiteList};
// Do not escape value when it is a tag and attr in the whitelist.
opts.safeAttrValue = (tag, name, value, cssFilter) => { return value; }
function protectFromXSS(html) { function protectFromXSS(html) {
return filterXSS(html, opts); return filterXSS(html, opts);
} }
function filterContent(tokens, idx, options, env, slf) { function filterContent(tokens, idx, options, env, slf, fallback) {
tokens[idx].content = protectFromXSS(tokens[idx].content); tokens[idx].content = protectFromXSS(tokens[idx].content);
return defaultHtmlInlineRenderer(tokens, idx, options, env, slf); return fallback(tokens, idx, options, env, slf);
} }
md.renderer.rules.html_inline = filterContent; md.renderer.rules.html_inline = (tokens, idx, options, env, slf) =>
filterContent(tokens, idx, options, env, slf, defaultHtmlInlineRenderer);
md.renderer.rules.html_block = (tokens, idx, options, env, slf) =>
filterContent(tokens, idx, options, env, slf, defaultHtmlBlockRenderer);
}; };
},{}]},{},[1])(1) },{}]},{},[1])(1)

View File

@ -213,7 +213,8 @@ class MarkdownIt extends VxWorker {
() => { () => {
this.mdit.use(window.markdownItXSS, { this.mdit.use(window.markdownItXSS, {
whiteList: { whiteList: {
input: ["class", "disabled", "type", "checked"], input: ["style", "class", "disabled", "type", "checked"],
span: ["style", "class"],
} }
}); });
}); });

View File

@ -677,7 +677,7 @@ QString Exporter::evaluateCommand(const ExportOption &p_option,
QString Exporter::getQuotedPath(const QString &p_path) QString Exporter::getQuotedPath(const QString &p_path)
{ {
return QString("\"%1\"").arg(QDir::toNativeSeparators(p_path)); return QStringLiteral("\"%1\"").arg(QDir::toNativeSeparators(p_path));
} }
void Exporter::collectFiles(const QList<QSharedPointer<File>> &p_files, QStringList &p_inputFiles, QStringList &p_resourcePaths) void Exporter::collectFiles(const QList<QSharedPointer<File>> &p_files, QStringList &p_inputFiles, QStringList &p_resourcePaths)

View File

@ -201,7 +201,7 @@ bool WebViewExporter::writeHtmlFile(const QString &p_file,
auto htmlContent = m_exportHtmlTemplate; auto htmlContent = m_exportHtmlTemplate;
const auto title = QString("%1").arg(baseName); const auto title = QStringLiteral("%1").arg(baseName);
HtmlTemplateHelper::fillTitle(htmlContent, title); HtmlTemplateHelper::fillTitle(htmlContent, title);
if (!p_styleContent.isEmpty() && p_embedStyles) { if (!p_styleContent.isEmpty() && p_embedStyles) {
@ -311,7 +311,7 @@ void WebViewExporter::prepare(const ExportOption &p_option)
static QString marginToStrMM(qreal p_margin) static QString marginToStrMM(qreal p_margin)
{ {
return QString("%1mm").arg(p_margin); return QStringLiteral("%1mm").arg(p_margin);
} }
void WebViewExporter::prepareWkhtmltopdfArguments(const ExportPdfOption &p_pdfOption) void WebViewExporter::prepareWkhtmltopdfArguments(const ExportPdfOption &p_pdfOption)
@ -374,7 +374,7 @@ bool WebViewExporter::embedStyleResources(QString &p_html) const
pos = idx + match.capturedLength(); pos = idx + match.capturedLength();
} else { } else {
// Replace the url string in html. // Replace the url string in html.
QString newUrl = QString("url('%1');").arg(dataURI); QString newUrl = QStringLiteral("url('%1');").arg(dataURI);
p_html.replace(idx, match.capturedLength(), newUrl); p_html.replace(idx, match.capturedLength(), newUrl);
pos = idx + newUrl.size(); pos = idx + newUrl.size();
altered = true; altered = true;
@ -412,7 +412,7 @@ bool WebViewExporter::embedBodyResources(const QUrl &p_baseUrl, QString &p_html)
pos = idx + match.capturedLength(); pos = idx + match.capturedLength();
} else { } else {
// Replace the url string in html. // Replace the url string in html.
QString newUrl = QString("<img %1src='%2'%3>").arg(match.captured(1), dataURI, match.captured(3)); QString newUrl = QStringLiteral("<img %1src='%2'%3>").arg(match.captured(1), dataURI, match.captured(3));
p_html.replace(idx, match.capturedLength(), newUrl); p_html.replace(idx, match.capturedLength(), newUrl);
pos = idx + newUrl.size(); pos = idx + newUrl.size();
altered = true; altered = true;
@ -460,7 +460,7 @@ bool WebViewExporter::fixBodyResources(const QUrl &p_baseUrl,
pos = idx + match.capturedLength(); pos = idx + match.capturedLength();
} else { } else {
// Replace the url string in html. // Replace the url string in html.
QString newUrl = QString("<img %1src=\"%2\"%3>").arg(match.captured(1), getResourceRelativePath(targetFile), match.captured(3)); QString newUrl = QStringLiteral("<img %1src=\"%2\"%3>").arg(match.captured(1), getResourceRelativePath(targetFile), match.captured(3));
p_html.replace(idx, match.capturedLength(), newUrl); p_html.replace(idx, match.capturedLength(), newUrl);
pos = idx + newUrl.size(); pos = idx + newUrl.size();
altered = true; altered = true;

View File

@ -40,7 +40,7 @@ void GiteeImageHost::setConfig(const QJsonObject &p_jobj)
parseConfig(p_jobj, m_personalAccessToken, m_userName, m_repoName); parseConfig(p_jobj, m_personalAccessToken, m_userName, m_repoName);
// Do not assume the default branch. // Do not assume the default branch.
m_imageUrlPrefix = QString("https://gitee.com/%1/%2/raw/").arg(m_userName, m_repoName); m_imageUrlPrefix = QStringLiteral("https://gitee.com/%1/%2/raw/").arg(m_userName, m_repoName);
} }
vte::NetworkAccess::RawHeaderPairs GiteeImageHost::prepareCommonHeaders() vte::NetworkAccess::RawHeaderPairs GiteeImageHost::prepareCommonHeaders()
@ -53,9 +53,9 @@ vte::NetworkAccess::RawHeaderPairs GiteeImageHost::prepareCommonHeaders()
QString GiteeImageHost::addAccessToken(const QString &p_token, QString p_url) QString GiteeImageHost::addAccessToken(const QString &p_token, QString p_url)
{ {
if (p_url.contains(QLatin1Char('?'))) { if (p_url.contains(QLatin1Char('?'))) {
p_url += QString("&access_token=%1").arg(p_token); p_url += QStringLiteral("&access_token=%1").arg(p_token);
} else { } else {
p_url += QString("?access_token=%1").arg(p_token); p_url += QStringLiteral("?access_token=%1").arg(p_token);
} }
return p_url; return p_url;
} }
@ -63,7 +63,7 @@ QString GiteeImageHost::addAccessToken(const QString &p_token, QString p_url)
vte::NetworkReply GiteeImageHost::getRepoInfo(const QString &p_token, const QString &p_userName, const QString &p_repoName) const vte::NetworkReply GiteeImageHost::getRepoInfo(const QString &p_token, const QString &p_userName, const QString &p_repoName) const
{ {
auto rawHeader = prepareCommonHeaders(); auto rawHeader = prepareCommonHeaders();
auto urlStr = QString("%1/repos/%2/%3").arg(c_apiUrl, p_userName, p_repoName); auto urlStr = QStringLiteral("%1/repos/%2/%3").arg(c_apiUrl, p_userName, p_repoName);
auto reply = vte::NetworkAccess::request(QUrl(addAccessToken(p_token, urlStr)), rawHeader); auto reply = vte::NetworkAccess::request(QUrl(addAccessToken(p_token, urlStr)), rawHeader);
return reply; return reply;
} }
@ -88,7 +88,7 @@ QString GiteeImageHost::create(const QByteArray &p_data, const QString &p_path,
} }
auto rawHeader = prepareCommonHeaders(); auto rawHeader = prepareCommonHeaders();
const auto urlStr = QString("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, p_path); const auto urlStr = QStringLiteral("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, p_path);
// Check if @p_path already exists. // Check if @p_path already exists.
auto reply = vte::NetworkAccess::request(QUrl(addAccessToken(m_personalAccessToken, urlStr)), rawHeader); auto reply = vte::NetworkAccess::request(QUrl(addAccessToken(m_personalAccessToken, urlStr)), rawHeader);
@ -105,7 +105,7 @@ QString GiteeImageHost::create(const QByteArray &p_data, const QString &p_path,
// Create the content. // Create the content.
QJsonObject requestDataObj; QJsonObject requestDataObj;
requestDataObj[QStringLiteral("access_token")] = m_personalAccessToken; requestDataObj[QStringLiteral("access_token")] = m_personalAccessToken;
requestDataObj[QStringLiteral("message")] = QString("VX_ADD: %1").arg(p_path); requestDataObj[QStringLiteral("message")] = QStringLiteral("VX_ADD: %1").arg(p_path);
requestDataObj[QStringLiteral("content")] = QString::fromUtf8(p_data.toBase64()); requestDataObj[QStringLiteral("content")] = QString::fromUtf8(p_data.toBase64());
auto requestData = Utils::toJsonString(requestDataObj); auto requestData = Utils::toJsonString(requestDataObj);
reply = vte::NetworkAccess::post(QUrl(urlStr), rawHeader, requestData); reply = vte::NetworkAccess::post(QUrl(urlStr), rawHeader, requestData);
@ -143,7 +143,7 @@ bool GiteeImageHost::remove(const QString &p_url, QString &p_msg)
const auto resourcePath = fetchResourcePath(m_imageUrlPrefix, p_url); const auto resourcePath = fetchResourcePath(m_imageUrlPrefix, p_url);
auto rawHeader = prepareCommonHeaders(); auto rawHeader = prepareCommonHeaders();
const auto urlStr = QString("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, resourcePath); const auto urlStr = QStringLiteral("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, resourcePath);
// Get the SHA of the resource. // Get the SHA of the resource.
auto reply = vte::NetworkAccess::request(QUrl(addAccessToken(m_personalAccessToken, urlStr)), rawHeader); auto reply = vte::NetworkAccess::request(QUrl(addAccessToken(m_personalAccessToken, urlStr)), rawHeader);
@ -163,7 +163,7 @@ bool GiteeImageHost::remove(const QString &p_url, QString &p_msg)
// Delete. // Delete.
QJsonObject requestDataObj; QJsonObject requestDataObj;
requestDataObj[QStringLiteral("access_token")] = m_personalAccessToken; requestDataObj[QStringLiteral("access_token")] = m_personalAccessToken;
requestDataObj[QStringLiteral("message")] = QString("VX_DEL: %1").arg(resourcePath); requestDataObj[QStringLiteral("message")] = QStringLiteral("VX_DEL: %1").arg(resourcePath);
requestDataObj[QStringLiteral("sha")] = sha; requestDataObj[QStringLiteral("sha")] = sha;
auto requestData = Utils::toJsonString(requestDataObj); auto requestData = Utils::toJsonString(requestDataObj);
reply = vte::NetworkAccess::deleteResource(QUrl(urlStr), rawHeader, requestData); reply = vte::NetworkAccess::deleteResource(QUrl(urlStr), rawHeader, requestData);

View File

@ -41,7 +41,7 @@ void GitHubImageHost::setConfig(const QJsonObject &p_jobj)
parseConfig(p_jobj, m_personalAccessToken, m_userName, m_repoName); parseConfig(p_jobj, m_personalAccessToken, m_userName, m_repoName);
// Do not assume the default branch. // Do not assume the default branch.
m_imageUrlPrefix = QString("https://raw.githubusercontent.com/%1/%2/").arg(m_userName, m_repoName); m_imageUrlPrefix = QStringLiteral("https://raw.githubusercontent.com/%1/%2/").arg(m_userName, m_repoName);
} }
QPair<QByteArray, QByteArray> GitHubImageHost::authorizationHeader(const QString &p_token) QPair<QByteArray, QByteArray> GitHubImageHost::authorizationHeader(const QString &p_token)
@ -66,7 +66,7 @@ vte::NetworkAccess::RawHeaderPairs GitHubImageHost::prepareCommonHeaders(const Q
vte::NetworkReply GitHubImageHost::getRepoInfo(const QString &p_token, const QString &p_userName, const QString &p_repoName) const vte::NetworkReply GitHubImageHost::getRepoInfo(const QString &p_token, const QString &p_userName, const QString &p_repoName) const
{ {
auto rawHeader = prepareCommonHeaders(p_token); auto rawHeader = prepareCommonHeaders(p_token);
const auto urlStr = QString("%1/repos/%2/%3").arg(c_apiUrl, p_userName, p_repoName); const auto urlStr = QStringLiteral("%1/repos/%2/%3").arg(c_apiUrl, p_userName, p_repoName);
auto reply = vte::NetworkAccess::request(QUrl(urlStr), rawHeader); auto reply = vte::NetworkAccess::request(QUrl(urlStr), rawHeader);
return reply; return reply;
} }
@ -86,7 +86,7 @@ QString GitHubImageHost::create(const QByteArray &p_data, const QString &p_path,
} }
auto rawHeader = prepareCommonHeaders(m_personalAccessToken); auto rawHeader = prepareCommonHeaders(m_personalAccessToken);
const auto urlStr = QString("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, p_path); const auto urlStr = QStringLiteral("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, p_path);
// Check if @p_path already exists. // Check if @p_path already exists.
auto reply = vte::NetworkAccess::request(QUrl(urlStr), rawHeader); auto reply = vte::NetworkAccess::request(QUrl(urlStr), rawHeader);
@ -100,7 +100,7 @@ QString GitHubImageHost::create(const QByteArray &p_data, const QString &p_path,
// Create the content. // Create the content.
QJsonObject requestDataObj; QJsonObject requestDataObj;
requestDataObj[QStringLiteral("message")] = QString("VX_ADD: %1").arg(p_path); requestDataObj[QStringLiteral("message")] = QStringLiteral("VX_ADD: %1").arg(p_path);
requestDataObj[QStringLiteral("content")] = QString::fromUtf8(p_data.toBase64()); requestDataObj[QStringLiteral("content")] = QString::fromUtf8(p_data.toBase64());
auto requestData = Utils::toJsonString(requestDataObj); auto requestData = Utils::toJsonString(requestDataObj);
reply = vte::NetworkAccess::put(QUrl(urlStr), rawHeader, requestData); reply = vte::NetworkAccess::put(QUrl(urlStr), rawHeader, requestData);
@ -137,7 +137,7 @@ bool GitHubImageHost::remove(const QString &p_url, QString &p_msg)
const auto resourcePath = fetchResourcePath(m_imageUrlPrefix, p_url); const auto resourcePath = fetchResourcePath(m_imageUrlPrefix, p_url);
auto rawHeader = prepareCommonHeaders(m_personalAccessToken); auto rawHeader = prepareCommonHeaders(m_personalAccessToken);
const auto urlStr = QString("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, resourcePath); const auto urlStr = QStringLiteral("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, resourcePath);
// Get the SHA of the resource. // Get the SHA of the resource.
QString sha = ""; QString sha = "";
@ -177,7 +177,7 @@ bool GitHubImageHost::remove(const QString &p_url, QString &p_msg)
// Delete. // Delete.
QJsonObject requestDataObj; QJsonObject requestDataObj;
requestDataObj[QStringLiteral("message")] = QString("VX_DEL: %1").arg(resourcePath); requestDataObj[QStringLiteral("message")] = QStringLiteral("VX_DEL: %1").arg(resourcePath);
requestDataObj[QStringLiteral("sha")] = sha; requestDataObj[QStringLiteral("sha")] = sha;
auto requestData = Utils::toJsonString(requestDataObj); auto requestData = Utils::toJsonString(requestDataObj);
reply = vte::NetworkAccess::deleteResource(QUrl(urlStr), rawHeader, requestData); reply = vte::NetworkAccess::deleteResource(QUrl(urlStr), rawHeader, requestData);

View File

@ -28,6 +28,6 @@ QString ImageHost::typeString(ImageHost::Type p_type)
default: default:
Q_ASSERT(false); Q_ASSERT(false);
return QString("Unknown"); return QStringLiteral("Unknown");
} }
} }

View File

@ -107,7 +107,7 @@ int main(int argc, char *argv[])
case CommandLineOptions::VersionRequested: case CommandLineOptions::VersionRequested:
{ {
auto versionStr = QString("%1 %2").arg(app.applicationName()).arg(app.applicationVersion()); auto versionStr = QStringLiteral("%1 %2").arg(app.applicationName()).arg(app.applicationVersion());
showMessageOnCommandLineIfAvailable(versionStr); showMessageOnCommandLineIfAvailable(versionStr);
return 0; return 0;
} }
@ -142,7 +142,7 @@ int main(int argc, char *argv[])
// Init logger after app info is set. // Init logger after app info is set.
Logger::init(cmdOptions.m_verbose, cmdOptions.m_logToStderr); Logger::init(cmdOptions.m_verbose, cmdOptions.m_logToStderr);
qInfo() << QString("%1 (v%2) started at %3 (%4)").arg(ConfigMgr::c_appName, qInfo() << QStringLiteral("%1 (v%2) started at %3 (%4)").arg(ConfigMgr::c_appName,
app.applicationVersion(), app.applicationVersion(),
QDateTime::currentDateTime().toString(), QDateTime::currentDateTime().toString(),
QSysInfo::productType()); QSysInfo::productType());
@ -157,6 +157,18 @@ int main(int argc, char *argv[])
// Should set the correct locale before VNoteX::getInst(). // Should set the correct locale before VNoteX::getInst().
loadTranslators(app); loadTranslators(app);
if (app.styleSheet().isEmpty()) {
auto style = VNoteX::getInst().getThemeMgr().fetchQtStyleSheet();
if (!style.isEmpty()) {
app.setStyleSheet(style);
// Set up hot-reload for the theme folder if enabled via command line
if (cmdOptions.m_watchThemes) {
const auto themeFolderPath = VNoteX::getInst().getThemeMgr().getCurrentTheme().getThemeFolder();
app.watchThemeFolder(themeFolderPath);
}
}
}
MainWindow window; MainWindow window;
window.show(); window.show();
@ -173,14 +185,6 @@ int main(int argc, char *argv[])
// Let MainWindow show first to decide the screen on which app is running. // Let MainWindow show first to decide the screen on which app is running.
WidgetUtils::calculateScaleFactor(window.windowHandle()->screen()); WidgetUtils::calculateScaleFactor(window.windowHandle()->screen());
if (app.styleSheet().isEmpty()) {
auto style = VNoteX::getInst().getThemeMgr().fetchQtStyleSheet();
if (!style.isEmpty()) {
app.setStyleSheet(style);
WidgetUtils::updateStyle(&window);
}
}
VNoteX::getInst().getThemeMgr().setBaseBackground(window.palette().color(QPalette::Base)); VNoteX::getInst().getThemeMgr().setBaseBackground(window.palette().color(QPalette::Base));
window.kickOffOnStart(cmdOptions.m_pathsToOpen); window.kickOffOnStart(cmdOptions.m_pathsToOpen);
@ -258,7 +262,7 @@ void showMessageOnCommandLineIfAvailable(const QString &p_msg)
{ {
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
MessageBoxHelper::notify(MessageBoxHelper::Information, MessageBoxHelper::notify(MessageBoxHelper::Information,
QString("<pre>%1</pre>").arg(p_msg)); QStringLiteral("<pre>%1</pre>").arg(p_msg));
#else #else
fprintf(stderr, "%s\n", qPrintable(p_msg)); fprintf(stderr, "%s\n", qPrintable(p_msg));
#endif #endif

View File

@ -3,7 +3,6 @@
#include <QFile> #include <QFile>
#include <QDebug> #include <QDebug>
#include "searchresultitem.h"
#include <utils/fileutils.h> #include <utils/fileutils.h>
using namespace vnotex; using namespace vnotex;

View File

@ -12,11 +12,10 @@
#include "searchtoken.h" #include "searchtoken.h"
#include "searchdata.h" #include "searchdata.h"
#include "searchresultitem.h"
namespace vnotex namespace vnotex
{ {
struct SearchResultItem;
class FileSearchEngineWorker : public AsyncWorker class FileSearchEngineWorker : public AsyncWorker
{ {
Q_OBJECT Q_OBJECT

View File

@ -22,7 +22,7 @@ using namespace vnotex;
const QChar SnippetMgr::c_snippetSymbolGuard = QLatin1Char('%'); const QChar SnippetMgr::c_snippetSymbolGuard = QLatin1Char('%');
const QString SnippetMgr::c_snippetSymbolRegExp = QString("%1([^%]+)%1").arg(c_snippetSymbolGuard); const QString SnippetMgr::c_snippetSymbolRegExp = QStringLiteral("%1([^%]+)%1").arg(c_snippetSymbolGuard);
SnippetMgr::SnippetMgr() SnippetMgr::SnippetMgr()
{ {

View File

@ -279,13 +279,13 @@ void TaskVariableMgr::initInputVariables()
addVariable("input", [this](Task *task, const QString &val) { addVariable("input", [this](Task *task, const QString &val) {
if (val.isEmpty()) { if (val.isEmpty()) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("task (%1) with empty input id").arg(task->getLabel())); QStringLiteral("task (%1) with empty input id").arg(task->getLabel()));
} }
auto input = task->findInput(val); auto input = task->findInput(val);
if (!input) { if (!input) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("task (%1) with invalid input id (%2)").arg(task->getLabel(), val)); QStringLiteral("task (%1) with invalid input id (%2)").arg(task->getLabel(), val));
} }
if (input->type == "promptString") { if (input->type == "promptString") {
@ -319,7 +319,7 @@ void TaskVariableMgr::initInputVariables()
} }
} else { } else {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("task (%1) with invalid input type (%2)(%3)").arg(task->getLabel(), input->id, input->type)); QStringLiteral("task (%1) with invalid input type (%2)(%3)").arg(task->getLabel(), input->id, input->type));
} }
return QString(); return QString();
@ -337,7 +337,7 @@ void TaskVariableMgr::initShellVariables()
const int timeout = 1000; const int timeout = 1000;
if (!process.waitForStarted(timeout) || !process.waitForFinished(timeout)) { if (!process.waitForStarted(timeout) || !process.waitForFinished(timeout)) {
Exception::throwOne(Exception::Type::InvalidArgument, Exception::throwOne(Exception::Type::InvalidArgument,
QString("task (%1) failed to fetch shell variable (%2)").arg(task->getLabel(), val)); QStringLiteral("task (%1) failed to fetch shell variable (%2)").arg(task->getLabel(), val));
} }
return Task::decodeText(process.readAllStandardOutput()); return Task::decodeText(process.readAllStandardOutput());
}); });

View File

@ -107,7 +107,7 @@ void ContentMediaUtils::copyMarkdownMediaFiles(const QString &p_content,
// Rename happens. // Rename happens.
const auto oldFileName = PathUtils::fileName(oldDestFilePath); const auto oldFileName = PathUtils::fileName(oldDestFilePath);
const auto newFileName = PathUtils::fileName(destFilePath); const auto newFileName = PathUtils::fileName(destFilePath);
qWarning() << QString("image name conflicts when copy, renamed from (%1) to (%2)").arg(oldFileName, newFileName); qWarning() << QStringLiteral("image name conflicts when copy, renamed from (%1) to (%2)").arg(oldFileName, newFileName);
// Update the text content. // Update the text content.
const auto encodedOldFileName = PathUtils::fileName(link.m_urlInLink); const auto encodedOldFileName = PathUtils::fileName(link.m_urlInLink);

View File

@ -29,9 +29,9 @@ QString DocsUtils::getDocFile(const QString &p_baseName)
{ {
const auto shortLocale = s_locale.split('_')[0]; const auto shortLocale = s_locale.split('_')[0];
const auto fullLocaleName = QString("%1/%2").arg(s_locale, p_baseName); const auto fullLocaleName = QStringLiteral("%1/%2").arg(s_locale, p_baseName);
const auto shortLocaleName = QString("%1/%2").arg(shortLocale, p_baseName); const auto shortLocaleName = QStringLiteral("%1/%2").arg(shortLocale, p_baseName);
const auto defaultLocaleName = QString("%1/%2").arg(QStringLiteral("en"), p_baseName); const auto defaultLocaleName = QStringLiteral("%1/%2").arg(QStringLiteral("en"), p_baseName);
for (const auto &pa : s_searchPaths) { for (const auto &pa : s_searchPaths) {
QDir dir(pa); QDir dir(pa);

View File

@ -19,7 +19,7 @@ QByteArray FileUtils::readFile(const QString &p_filePath)
QFile file(p_filePath); QFile file(p_filePath);
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
Exception::throwOne(Exception::Type::FailToReadFile, Exception::throwOne(Exception::Type::FailToReadFile,
QString("failed to read file: %1").arg(p_filePath)); QStringLiteral("failed to read file: %1").arg(p_filePath));
} }
return file.readAll(); return file.readAll();
@ -30,7 +30,7 @@ QString FileUtils::readTextFile(const QString &p_filePath)
QFile file(p_filePath); QFile file(p_filePath);
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
Exception::throwOne(Exception::Type::FailToReadFile, Exception::throwOne(Exception::Type::FailToReadFile,
QString("failed to read file: %1").arg(p_filePath)); QStringLiteral("failed to read file: %1").arg(p_filePath));
} }
// TODO: determine the encoding of the text. // TODO: determine the encoding of the text.
@ -49,7 +49,7 @@ void FileUtils::writeFile(const QString &p_filePath, const QByteArray &p_data)
QFile file(p_filePath); QFile file(p_filePath);
if (!file.open(QIODevice::WriteOnly)) { if (!file.open(QIODevice::WriteOnly)) {
Exception::throwOne(Exception::Type::FailToWriteFile, Exception::throwOne(Exception::Type::FailToWriteFile,
QString("failed to write to file: %1").arg(p_filePath)); QStringLiteral("failed to write to file: %1").arg(p_filePath));
} }
file.write(p_data); file.write(p_data);
@ -61,7 +61,7 @@ void FileUtils::writeFile(const QString &p_filePath, const QString &p_text)
QFile file(p_filePath); QFile file(p_filePath);
if (!file.open(QIODevice::WriteOnly)) { if (!file.open(QIODevice::WriteOnly)) {
Exception::throwOne(Exception::Type::FailToWriteFile, Exception::throwOne(Exception::Type::FailToWriteFile,
QString("failed to write to file: %1").arg(p_filePath)); QStringLiteral("failed to write to file: %1").arg(p_filePath));
} }
QTextStream stream(&file); QTextStream stream(&file);
@ -81,7 +81,7 @@ void FileUtils::renameFile(const QString &p_path, const QString &p_name)
QFile file(p_path); QFile file(p_path);
if (!file.exists() || !file.rename(newFilePath)) { if (!file.exists() || !file.rename(newFilePath)) {
Exception::throwOne(Exception::Type::FailToRenameFile, Exception::throwOne(Exception::Type::FailToRenameFile,
QString("failed to rename file: %1").arg(p_path)); QStringLiteral("failed to rename file: %1").arg(p_path));
} }
} }
@ -119,7 +119,7 @@ void FileUtils::copyFile(const QString &p_filePath,
QDir dir; QDir dir;
if (!dir.mkpath(PathUtils::parentDirPath(p_destPath))) { if (!dir.mkpath(PathUtils::parentDirPath(p_destPath))) {
Exception::throwOne(Exception::Type::FailToCreateDir, Exception::throwOne(Exception::Type::FailToCreateDir,
QString("failed to create directory: %1").arg(PathUtils::parentDirPath(p_destPath))); QStringLiteral("failed to create directory: %1").arg(PathUtils::parentDirPath(p_destPath)));
} }
bool failed = false; bool failed = false;
@ -136,7 +136,7 @@ void FileUtils::copyFile(const QString &p_filePath,
if (failed) { if (failed) {
Exception::throwOne(Exception::Type::FailToCopyFile, Exception::throwOne(Exception::Type::FailToCopyFile,
QString("failed to copy file: %1 %2").arg(p_filePath, p_destPath)); QStringLiteral("failed to copy file: %1 %2").arg(p_filePath, p_destPath));
} }
} }
@ -150,7 +150,7 @@ void FileUtils::copyDir(const QString &p_dirPath,
if (QFileInfo::exists(p_destPath)) { if (QFileInfo::exists(p_destPath)) {
Exception::throwOne(Exception::Type::FailToCopyDir, Exception::throwOne(Exception::Type::FailToCopyDir,
QString("target directory %1 already exists").arg(p_destPath)); QStringLiteral("target directory %1 already exists").arg(p_destPath));
} }
// QDir.rename() could not move directory across dirves. // QDir.rename() could not move directory across dirves.
@ -159,7 +159,7 @@ void FileUtils::copyDir(const QString &p_dirPath,
QDir destDir(p_destPath); QDir destDir(p_destPath);
if (!destDir.mkpath(p_destPath)) { if (!destDir.mkpath(p_destPath)) {
Exception::throwOne(Exception::Type::FailToCreateDir, Exception::throwOne(Exception::Type::FailToCreateDir,
QString("failed to create directory: %1").arg(p_destPath)); QStringLiteral("failed to create directory: %1").arg(p_destPath));
} }
// Copy directory contents recursively. // Copy directory contents recursively.
@ -182,7 +182,7 @@ void FileUtils::copyDir(const QString &p_dirPath,
if (p_move) { if (p_move) {
if (!destDir.rmdir(p_dirPath)) { if (!destDir.rmdir(p_dirPath)) {
Exception::throwOne(Exception::Type::FailToRemoveDir, Exception::throwOne(Exception::Type::FailToRemoveDir,
QString("failed to remove source directory after move: %1").arg(p_dirPath)); QStringLiteral("failed to remove source directory after move: %1").arg(p_dirPath));
} }
} }
} }
@ -196,7 +196,7 @@ QString FileUtils::renameIfExistsCaseInsensitive(const QString &p_path)
auto name = fi.fileName(); auto name = fi.fileName();
int idx = 1; int idx = 1;
while (childExistsCaseInsensitive(dirPath, name)) { while (childExistsCaseInsensitive(dirPath, name)) {
name = QString("%1_%2").arg(baseName, QString::number(idx)); name = QStringLiteral("%1_%2").arg(baseName, QString::number(idx));
if (!suffix.isEmpty()) { if (!suffix.isEmpty()) {
name += QStringLiteral(".") + suffix; name += QStringLiteral(".") + suffix;
} }
@ -213,7 +213,7 @@ void FileUtils::removeFile(const QString &p_filePath)
QFile file(p_filePath); QFile file(p_filePath);
if (!file.remove()) { if (!file.remove()) {
Exception::throwOne(Exception::Type::FailToRemoveFile, Exception::throwOne(Exception::Type::FailToRemoveFile,
QString("failed to remove file: %1").arg(p_filePath)); QStringLiteral("failed to remove file: %1").arg(p_filePath));
} }
} }
@ -226,7 +226,7 @@ bool FileUtils::removeDirIfEmpty(const QString &p_dirPath)
if (!dir.rmdir(p_dirPath)) { if (!dir.rmdir(p_dirPath)) {
Exception::throwOne(Exception::Type::FailToRemoveFile, Exception::throwOne(Exception::Type::FailToRemoveFile,
QString("failed to remove directory: %1").arg(p_dirPath)); QStringLiteral("failed to remove directory: %1").arg(p_dirPath));
return false; return false;
} }
@ -238,7 +238,7 @@ void FileUtils::removeDir(const QString &p_dirPath)
QDir dir(p_dirPath); QDir dir(p_dirPath);
if (!dir.removeRecursively()) { if (!dir.removeRecursively()) {
Exception::throwOne(Exception::Type::FailToRemoveFile, Exception::throwOne(Exception::Type::FailToRemoveFile,
QString("failed to remove directory recursively: %1").arg(p_dirPath)); QStringLiteral("failed to remove directory recursively: %1").arg(p_dirPath));
} }
} }
@ -302,7 +302,7 @@ QString FileUtils::generateUniqueFileName(const QString &p_folderPath,
auto suffix = suffixIdx == -1 ? QStringLiteral("") : fileName.mid(suffixIdx); auto suffix = suffixIdx == -1 ? QStringLiteral("") : fileName.mid(suffixIdx);
int index = 1; int index = 1;
while (childExistsCaseInsensitive(p_folderPath, fileName)) { while (childExistsCaseInsensitive(p_folderPath, fileName)) {
fileName = QString("%1_%2%3").arg(baseName, QString::number(index++), suffix); fileName = QStringLiteral("%1_%2%3").arg(baseName, QString::number(index++), suffix);
} }
return fileName; return fileName;
@ -338,7 +338,7 @@ QString FileUtils::generateFileNameWithSequence(const QString &p_folderPath,
auto suffix = p_suffix.isEmpty() ? QString() : QStringLiteral(".") + p_suffix; auto suffix = p_suffix.isEmpty() ? QString() : QStringLiteral(".") + p_suffix;
int index = 1; int index = 1;
while (childExistsCaseInsensitive(p_folderPath, fileName)) { while (childExistsCaseInsensitive(p_folderPath, fileName)) {
fileName = QString("%1_%2%3").arg(p_baseName, QString::number(index++), suffix); fileName = QStringLiteral("%1_%2%3").arg(p_baseName, QString::number(index++), suffix);
} }
return fileName; return fileName;

View File

@ -22,7 +22,7 @@ QString HtmlUtils::unicodeEncode(const QString &p_text)
QString encodedStr; QString encodedStr;
for (const auto ch : p_text) { for (const auto ch : p_text) {
if (ch.unicode() > 255) { if (ch.unicode() > 255) {
encodedStr += QString("&#%1;").arg(static_cast<int>(ch.unicode())); encodedStr += QStringLiteral("&#%1;").arg(static_cast<int>(ch.unicode()));
} else { } else {
encodedStr += ch; encodedStr += ch;
} }

View File

@ -70,7 +70,7 @@ QString IconUtils::replaceForegroundOfIcon(const QString &p_iconContent, const Q
QRegularExpression styleRe(R"((\s|"|;)(fill|stroke)(:|(="))(?!none)[^;"]*)"); QRegularExpression styleRe(R"((\s|"|;)(fill|stroke)(:|(="))(?!none)[^;"]*)");
if (p_iconContent.indexOf(styleRe) > -1) { if (p_iconContent.indexOf(styleRe) > -1) {
auto newContent(p_iconContent); auto newContent(p_iconContent);
newContent.replace(styleRe, QString("\\1\\2\\3%1").arg(p_foreground)); newContent.replace(styleRe, QStringLiteral("\\1\\2\\3%1").arg(p_foreground));
return newContent; return newContent;
} }

View File

@ -7,7 +7,7 @@
using namespace vnotex; using namespace vnotex;
const QString PathUtils::c_fileNameRegularExpression = QString("\\A(?:[^\\\\/:\\*\\?\"<>\\|\\s]| )+\\z"); const QString PathUtils::c_fileNameRegularExpression = QStringLiteral("\\A(?:[^\\\\/:\\*\\?\"<>\\|\\s]| )+\\z");
QString PathUtils::parentDirPath(const QString &p_path) QString PathUtils::parentDirPath(const QString &p_path)
{ {

View File

@ -46,7 +46,7 @@ QString WebUtils::toDataUri(const QUrl &p_url, bool p_keepTitle)
} }
if (suffix == "svg") { if (suffix == "svg") {
uri = QString("data:image/svg+xml;utf8,%1").arg(QString::fromUtf8(data)); uri = QStringLiteral("data:image/svg+xml;utf8,%1").arg(QString::fromUtf8(data));
uri.replace('\r', "").replace('\n', ""); uri.replace('\r', "").replace('\n', "");
// Using unescaped '#' characters in a data URI body is deprecated and // Using unescaped '#' characters in a data URI body is deprecated and
@ -63,7 +63,7 @@ QString WebUtils::toDataUri(const QUrl &p_url, bool p_keepTitle)
uri.remove(reg); uri.remove(reg);
} }
} else { } else {
uri = QString("data:image/%1;base64,%2").arg(suffix, QString::fromUtf8(data.toBase64())); uri = QStringLiteral("data:image/%1;base64,%2").arg(suffix, QString::fromUtf8(data.toBase64()));
} }
return uri; return uri;

View File

@ -25,8 +25,11 @@
#include <QPushButton> #include <QPushButton>
#include <QSplitter> #include <QSplitter>
#include <QFormLayout> #include <QFormLayout>
#include <QFileInfo>
#include <core/global.h> #include <core/global.h>
#include <widgets/messageboxhelper.h>
#include <widgets/mainwindow.h>
using namespace vnotex; using namespace vnotex;
@ -75,6 +78,20 @@ QSize WidgetUtils::availableScreenSize(QWidget *p_widget)
void WidgetUtils::openUrlByDesktop(const QUrl &p_url) void WidgetUtils::openUrlByDesktop(const QUrl &p_url)
{ {
const auto scheme = p_url.scheme();
if (scheme != "http" && scheme != "https" &&
!(p_url.isLocalFile() && QFileInfo(p_url.toLocalFile()).isDir())) {
// Prompt for user.
int ret = MessageBoxHelper::questionYesNo(MessageBoxHelper::Warning,
MainWindow::tr("Are you sure to open link (%1)?").arg(p_url.toString()),
MainWindow::tr("Malicious link might do harm to your device."),
QString(),
nullptr);
if (ret == QMessageBox::No) {
return;
}
}
QDesktopServices::openUrl(p_url); QDesktopServices::openUrl(p_url);
} }
@ -198,7 +215,7 @@ void WidgetUtils::addActionShortcut(QAction *p_action,
p_action->setShortcut(kseq); p_action->setShortcut(kseq);
p_action->setShortcutContext(p_context); p_action->setShortcutContext(p_context);
p_action->setText(QString("%1\t%2").arg(p_action->text(), kseq.toString(QKeySequence::NativeText))); p_action->setText(QStringLiteral("%1\t%2").arg(p_action->text(), kseq.toString(QKeySequence::NativeText)));
} }
void WidgetUtils::addActionShortcutText(QAction *p_action, const QString &p_shortcut) void WidgetUtils::addActionShortcutText(QAction *p_action, const QString &p_shortcut)
@ -212,7 +229,7 @@ void WidgetUtils::addActionShortcutText(QAction *p_action, const QString &p_shor
return; return;
} }
p_action->setText(QString("%1\t%2").arg(p_action->text(), kseq.toString(QKeySequence::NativeText))); p_action->setText(QStringLiteral("%1\t%2").arg(p_action->text(), kseq.toString(QKeySequence::NativeText)));
} }
void WidgetUtils::addButtonShortcutText(QPushButton *p_button, const QString &p_shortcut) void WidgetUtils::addButtonShortcutText(QPushButton *p_button, const QString &p_shortcut)
@ -226,7 +243,7 @@ void WidgetUtils::addButtonShortcutText(QPushButton *p_button, const QString &p_
return; return;
} }
p_button->setText(QString("%1 (%2)").arg(p_button->text(), kseq.toString(QKeySequence::NativeText))); p_button->setText(QStringLiteral("%1 (%2)").arg(p_button->text(), kseq.toString(QKeySequence::NativeText)));
} }
void WidgetUtils::updateSize(QWidget *p_widget) void WidgetUtils::updateSize(QWidget *p_widget)

View File

@ -8,6 +8,7 @@
#include <QFileDialog> #include <QFileDialog>
#include <QInputDialog> #include <QInputDialog>
#include <QTimer> #include <QTimer>
#include <QWidgetAction>
#include "propertydefs.h" #include "propertydefs.h"
@ -28,8 +29,7 @@
using namespace vnotex; using namespace vnotex;
AttachmentPopup::AttachmentPopup(QToolButton *p_btn, QWidget *p_parent) AttachmentPopup::AttachmentPopup(QToolButton *p_btn, QWidget *p_parent)
: QMenu(p_parent), : ButtonPopup(p_btn, p_parent)
m_button(p_btn)
{ {
setupUI(); setupUI();
@ -46,7 +46,8 @@ AttachmentPopup::AttachmentPopup(QToolButton *p_btn, QWidget *p_parent)
void AttachmentPopup::setupUI() void AttachmentPopup::setupUI()
{ {
auto mainLayout = new QVBoxLayout(this); QWidget *widget = new QWidget{};
auto mainLayout = new QVBoxLayout(widget);
const auto &themeMgr = VNoteX::getInst().getThemeMgr(); const auto &themeMgr = VNoteX::getInst().getThemeMgr();
@ -66,7 +67,7 @@ void AttachmentPopup::setupUI()
const auto destFolderPath = getDestFolderPath(); const auto destFolderPath = getDestFolderPath();
auto &sessionConfig = ConfigMgr::getInst().getSessionConfig(); auto &sessionConfig = ConfigMgr::getInst().getSessionConfig();
auto files = QFileDialog::getOpenFileNames(this, auto files = QFileDialog::getOpenFileNames(nullptr,
tr("Select Files As Attachments"), tr("Select Files As Attachments"),
sessionConfig.getExternalMediaDefaultPath()); sessionConfig.getExternalMediaDefaultPath());
if (files.isEmpty()) { if (files.isEmpty()) {
@ -202,7 +203,9 @@ void AttachmentPopup::setupUI()
}); });
mainLayout->addWidget(m_viewer); mainLayout->addWidget(m_viewer);
setMinimumSize(320, 384); widget->setMinimumSize(320, 384);
addWidget(widget);
} }
QToolButton *AttachmentPopup::createButton() QToolButton *AttachmentPopup::createButton()

View File

@ -1,16 +1,14 @@
#ifndef ATTACHMENTPOPUP_H #ifndef ATTACHMENTPOPUP_H
#define ATTACHMENTPOPUP_H #define ATTACHMENTPOPUP_H
#include <QMenu> #include "buttonpopup.h"
class QToolButton;
namespace vnotex namespace vnotex
{ {
class FileSystemViewer; class FileSystemViewer;
class Buffer; class Buffer;
class AttachmentPopup : public QMenu class AttachmentPopup : public ButtonPopup
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -43,9 +41,6 @@ namespace vnotex
FileSystemViewer *m_viewer = nullptr; FileSystemViewer *m_viewer = nullptr;
bool m_needUpdateAttachmentFolder = true; bool m_needUpdateAttachmentFolder = true;
// Button for this menu.
QToolButton *m_button = nullptr;
}; };
} }

View File

@ -1,6 +1,6 @@
#include "buttonpopup.h" #include "buttonpopup.h"
#include <QVBoxLayout> #include <QWidgetAction>
#include <utils/widgetutils.h> #include <utils/widgetutils.h>
@ -10,8 +10,6 @@ ButtonPopup::ButtonPopup(QToolButton *p_btn, QWidget *p_parent)
: QMenu(p_parent), : QMenu(p_parent),
m_button(p_btn) m_button(p_btn)
{ {
setupUI();
#if defined(Q_OS_MACOS) || defined(Q_OS_MAC) #if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
// Qt::Popup on macOS does not work well with input method. // Qt::Popup on macOS does not work well with input method.
setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint); setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint);
@ -19,16 +17,10 @@ ButtonPopup::ButtonPopup(QToolButton *p_btn, QWidget *p_parent)
#endif #endif
} }
void ButtonPopup::setupUI() void ButtonPopup::addWidget(QWidget *p_widget)
{ {
auto mainLayout = new QVBoxLayout(this); auto act = new QWidgetAction(this);
WidgetUtils::setContentsMargins(mainLayout); // @act will own @p_widget.
} act->setDefaultWidget(p_widget);
addAction(act);
void ButtonPopup::setCentralWidget(QWidget *p_widget)
{
Q_ASSERT(p_widget);
auto mainLayout = layout();
Q_ASSERT(mainLayout->count() == 0);
mainLayout->addWidget(p_widget);
} }

View File

@ -15,10 +15,7 @@ namespace vnotex
ButtonPopup(QToolButton *p_btn, QWidget *p_parent = nullptr); ButtonPopup(QToolButton *p_btn, QWidget *p_parent = nullptr);
protected: protected:
void setCentralWidget(QWidget *p_widget); void addWidget(QWidget *p_widget);
private:
void setupUI();
// Button for this menu. // Button for this menu.
QToolButton *m_button = nullptr; QToolButton *m_button = nullptr;

View File

@ -879,7 +879,7 @@ void ExportDialog::updatePageLayoutButtonLabel()
{ {
Q_ASSERT(m_pageLayout); Q_ASSERT(m_pageLayout);
m_pageLayoutBtn->setText( m_pageLayoutBtn->setText(
QString("%1, %2").arg(m_pageLayout->pageSize().name(), QStringLiteral("%1, %2").arg(m_pageLayout->pageSize().name(),
m_pageLayout->orientation() == QPageLayout::Portrait ? tr("Portrait") : tr("Landscape"))); m_pageLayout->orientation() == QPageLayout::Portrait ? tr("Portrait") : tr("Landscape")));
} }

View File

@ -29,7 +29,7 @@ void GeneralPage::setupUI()
m_localeComboBox->addItem(tr("Default"), QString()); m_localeComboBox->addItem(tr("Default"), QString());
for (const auto &loc : ConfigMgr::getInst().getCoreConfig().getAvailableLocales()) { for (const auto &loc : ConfigMgr::getInst().getCoreConfig().getAvailableLocales()) {
QLocale locale(loc); QLocale locale(loc);
m_localeComboBox->addItem(QString("%1 (%2)").arg(locale.nativeLanguageName(), locale.nativeCountryName()), m_localeComboBox->addItem(QStringLiteral("%1 (%2)").arg(locale.nativeLanguageName(), locale.nativeCountryName()),
loc); loc);
} }

View File

@ -330,7 +330,7 @@ void DockWidgetHelper::setupDockActivateShortcut(QDockWidget *p_dock, const QStr
{ {
auto shortcut = WidgetUtils::createShortcut(p_keys, m_mainWindow); auto shortcut = WidgetUtils::createShortcut(p_keys, m_mainWindow);
if (shortcut) { if (shortcut) {
p_dock->setToolTip(QString("%1\t%2").arg(p_dock->windowTitle(), p_dock->setToolTip(QStringLiteral("%1\t%2").arg(p_dock->windowTitle(),
QKeySequence(p_keys).toString(QKeySequence::NativeText))); QKeySequence(p_keys).toString(QKeySequence::NativeText)));
connect(shortcut, &QShortcut::activated, connect(shortcut, &QShortcut::activated,
this, [this, p_dock]() { this, [this, p_dock]() {

View File

@ -64,7 +64,7 @@ QPair<bool, QString> GraphvizHelper::testGraphviz(const QString &p_graphvizFile)
errData); errData);
ret.first = (state == ProcessUtils::Succeeded) && (exitCode == 0); ret.first = (state == ProcessUtils::Succeeded) && (exitCode == 0);
ret.second = QString("%1 %2\n\nExitcode: %3\n\nOutput: %4\n\nError: %5") ret.second = QStringLiteral("%1 %2\n\nExitcode: %3\n\nOutput: %4\n\nError: %5")
.arg(program, args.join(' '), QString::number(exitCode), QString::fromLocal8Bit(outData), QString::fromLocal8Bit(errData)); .arg(program, args.join(' '), QString::number(exitCode), QString::fromLocal8Bit(outData), QString::fromLocal8Bit(errData));
return ret; return ret;

View File

@ -1323,7 +1323,7 @@ void MarkdownEditor::fetchImagesToLocalAndReplace(QString &p_text)
} }
// Replace URL in link. // Replace URL in link.
QString newLink = QString("![%1](%2%3%4)") QString newLink = QStringLiteral("![%1](%2%3%4)")
.arg(imageTitle, urlInLink, match.captured(3), match.captured(6)); .arg(imageTitle, urlInLink, match.captured(3), match.captured(6));
p_text.replace(reg.m_startPos, p_text.replace(reg.m_startPos,
reg.m_endPos - reg.m_startPos, reg.m_endPos - reg.m_startPos,

Some files were not shown because too many files have changed in this diff Show More