├── .gitattributes ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE-Qt.md ├── LICENSE.md ├── Makefile ├── README.md ├── WinMake.sh ├── docs └── man │ └── qtext.1 ├── package ├── deb │ ├── DEBIAN │ │ ├── config │ │ ├── control │ │ ├── postinst │ │ ├── postrm │ │ ├── prerm │ │ └── templates │ ├── copyright │ └── usr │ │ └── share │ │ └── applications │ │ └── qtext.desktop └── win │ ├── License.rtf │ └── QText.iss ├── scripts └── autoformat.sh └── src ├── .astylerc ├── QText.pro ├── app.cpp ├── clipboard.cpp ├── clipboard.h ├── deletion.cpp ├── deletion.h ├── find.cpp ├── find.h ├── helpers.cpp ├── helpers.h ├── icons.cpp ├── icons.h ├── icons ├── 128x128 │ ├── app.png │ ├── appBlack.png │ ├── appDebug.png │ ├── appMono.png │ └── appWhite.png ├── 16x16 │ ├── app.png │ ├── appBlack.png │ ├── appDebug.png │ ├── appMono.png │ ├── appWhite.png │ ├── bold.png │ ├── copy.png │ ├── cut.png │ ├── delete.png │ ├── file.png │ ├── find.png │ ├── findNext.png │ ├── folder.png │ ├── goto.png │ ├── italic.png │ ├── new.png │ ├── paste.png │ ├── print.png │ ├── printPdf.png │ ├── printPreview.png │ ├── redo.png │ ├── rename.png │ ├── save.png │ ├── settings.png │ ├── settingsWithUpgrade.png │ ├── strikethrough.png │ ├── underline.png │ ├── undo.png │ └── vscode.png ├── 192x192 │ ├── app.png │ ├── appBlack.png │ ├── appDebug.png │ ├── appMono.png │ └── appWhite.png ├── 24x24 │ ├── app.png │ ├── appBlack.png │ ├── appDebug.png │ ├── appMono.png │ ├── appWhite.png │ ├── bold.png │ ├── copy.png │ ├── cut.png │ ├── delete.png │ ├── file.png │ ├── find.png │ ├── findNext.png │ ├── folder.png │ ├── goto.png │ ├── italic.png │ ├── new.png │ ├── paste.png │ ├── print.png │ ├── printPdf.png │ ├── printPreview.png │ ├── redo.png │ ├── rename.png │ ├── save.png │ ├── settings.png │ ├── settingsWithUpgrade.png │ ├── strikethrough.png │ ├── underline.png │ ├── undo.png │ └── vscode.png ├── 256x256 │ ├── app.png │ ├── appBlack.png │ ├── appDebug.png │ ├── appMono.png │ └── appWhite.png ├── 32x32 │ ├── app.png │ ├── appBlack.png │ ├── appDebug.png │ ├── appMono.png │ ├── appWhite.png │ ├── bold.png │ ├── copy.png │ ├── cut.png │ ├── delete.png │ ├── file.png │ ├── find.png │ ├── findNext.png │ ├── folder.png │ ├── goto.png │ ├── italic.png │ ├── new.png │ ├── paste.png │ ├── print.png │ ├── printPdf.png │ ├── printPreview.png │ ├── redo.png │ ├── rename.png │ ├── save.png │ ├── settings.png │ ├── settingsWithUpgrade.png │ ├── strikethrough.png │ ├── underline.png │ ├── undo.png │ └── vscode.png ├── 48x48 │ ├── app.png │ ├── appBlack.png │ ├── appDebug.png │ ├── appMono.png │ ├── appWhite.png │ ├── bold.png │ ├── copy.png │ ├── cut.png │ ├── delete.png │ ├── file.png │ ├── find.png │ ├── findNext.png │ ├── folder.png │ ├── goto.png │ ├── italic.png │ ├── new.png │ ├── paste.png │ ├── print.png │ ├── printPdf.png │ ├── printPreview.png │ ├── redo.png │ ├── rename.png │ ├── save.png │ ├── settings.png │ ├── settingsWithUpgrade.png │ ├── strikethrough.png │ ├── underline.png │ ├── undo.png │ └── vscode.png ├── 64x64 │ ├── app.png │ ├── appBlack.png │ ├── appDebug.png │ ├── appMono.png │ ├── appWhite.png │ ├── bold.png │ ├── copy.png │ ├── cut.png │ ├── delete.png │ ├── file.png │ ├── find.png │ ├── findNext.png │ ├── folder.png │ ├── goto.png │ ├── italic.png │ ├── new.png │ ├── paste.png │ ├── print.png │ ├── printPdf.png │ ├── printPreview.png │ ├── redo.png │ ├── rename.png │ ├── save.png │ ├── settings.png │ ├── settingsWithUpgrade.png │ ├── strikethrough.png │ ├── underline.png │ ├── undo.png │ └── vscode.png ├── 96x96 │ ├── app.png │ ├── appBlack.png │ ├── appDebug.png │ ├── appMono.png │ └── appWhite.png └── app.ico ├── medo ├── about.cpp ├── about.h ├── appsetupmutex.cpp ├── appsetupmutex.h ├── config.cpp ├── config.h ├── dconfHotkey.cpp ├── dconfHotkey.h ├── feedback.cpp ├── feedback.h ├── hotkey.cpp ├── hotkey.h ├── lifetimewatch.cpp ├── lifetimewatch.h ├── singleinstance.cpp ├── singleinstance.h ├── state.cpp ├── state.h ├── upgrade.cpp ├── upgrade.h ├── winHotkey.cpp ├── winHotkey.h ├── xcbHotkey.cpp └── xcbHotkey.h ├── phoneticalphabet.cpp ├── phoneticalphabet.h ├── qtext.qrc ├── rtfconverter.cpp ├── rtfconverter.h ├── settings.cpp ├── settings.h ├── setup.cpp ├── setup.h ├── storage ├── deletionstyle.h ├── fileitem.cpp ├── fileitem.h ├── filetype.h ├── folderitem.cpp ├── folderitem.h ├── storage.cpp ├── storage.h ├── storagemonitorlocker.cpp ├── storagemonitorlocker.h ├── storagemonitorthread.cpp └── storagemonitorthread.h ├── test.qrc ├── test ├── Config │ ├── CommentsOnly.cfg │ ├── CommentsWithValues.cfg │ ├── Empty.cfg │ ├── EmptyLinesCR.cfg │ ├── EmptyLinesCRLF.cfg │ ├── EmptyLinesLF.cfg │ ├── EmptyLinesMixed.Good.cfg │ ├── EmptyLinesMixed.cfg │ ├── KeyWhitespace.Good.cfg │ ├── KeyWhitespace.cfg │ ├── Remove.Good.cfg │ ├── Remove.cfg │ ├── RemoveMulti.Good.cfg │ ├── RemoveMulti.cfg │ ├── Replace.Good.cfg │ ├── Replace.cfg │ ├── ReplaceOnlyLast.Good.cfg │ ├── ReplaceOnlyLast.cfg │ ├── SpacingCorrections.Good.cfg │ ├── SpacingCorrections.cfg │ ├── SpacingEscape.Good.cfg │ ├── SpacingEscape.cfg │ ├── SpacingPreserved.Good.cfg │ ├── SpacingPreserved.cfg │ ├── SpacingPreservedOnAdd.Good.cfg │ ├── SpacingPreservedOnAdd.cfg │ ├── WriteBasic.Good.cfg │ ├── WriteConvertedCpp.Good.cfg │ ├── WriteMulti.Good.cfg │ ├── WriteMulti.cfg │ ├── WriteNoEmptyLine.Good.cfg │ ├── WriteNoEmptyLine.cfg │ ├── WriteSameSeparatorEquals.Good.cfg │ ├── WriteSameSeparatorEquals.cfg │ ├── WriteSameSeparatorSpace.Good.cfg │ └── WriteSameSeparatorSpace.cfg ├── test_config.cpp ├── test_config.h ├── test_helpers.cpp ├── test_helpers.h └── test_main.cpp └── ui ├── finddialog.cpp ├── finddialog.h ├── finddialog.ui ├── foldersdialog.cpp ├── foldersdialog.h ├── foldersdialog.ui ├── gotodialog.cpp ├── gotodialog.h ├── gotodialog.ui ├── hotkeyedit.cpp ├── hotkeyedit.h ├── inserttimedialog.cpp ├── inserttimedialog.h ├── inserttimedialog.ui ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── newfiledialog.cpp ├── newfiledialog.h ├── newfiledialog.ui ├── phoneticdialog.cpp ├── phoneticdialog.h ├── phoneticdialog.ui ├── qtabbarex.cpp ├── qtabbarex.h ├── qtabwidgetex.cpp ├── qtabwidgetex.h ├── renamefiledialog.cpp ├── renamefiledialog.h ├── renamefiledialog.ui ├── settingsdialog.cpp ├── settingsdialog.h └── settingsdialog.ui /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.cpp text 4 | *.h text 5 | *.md text 6 | *.pro text 7 | *.ui text 8 | Makefile text 9 | src/test/Config/* binary 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | dist/ 3 | build/ 4 | src/build 5 | src/build-* 6 | 7 | **/*.pro.user 8 | **/*.pro.user.* 9 | **/*.rs.bk 10 | 11 | *.rar 12 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "configurations": [ 4 | { 5 | "name": "C++ Launch", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/bin/qtext", 9 | "windows": { 10 | "program": "${workspaceFolder}\\bin\\QText.exe" 11 | }, 12 | "externalConsole": false, 13 | "cwd": "${workspaceFolder}", 14 | "preLaunchTask": "build" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | ".vscode/": true, 4 | "bin/": true, 5 | "build/": true, 6 | "build-*/": true, 7 | "dist/": true, 8 | ".gitignore": true 9 | } 10 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "type": "shell", 7 | "command": "make", 8 | "args": [ "all" ], 9 | "windows": { 10 | "command": "bash -c './WinMake.sh'", 11 | "args": [ ] 12 | }, 13 | "group": { 14 | "kind": "build", 15 | "isDefault": true 16 | }, 17 | "presentation": { 18 | "reveal": "always", 19 | "panel": "dedicated", 20 | "clear": true 21 | }, 22 | "problemMatcher": { 23 | "owner": "cpp", 24 | "fileLocation": ["relative", "${workspaceRoot}"], 25 | "pattern": { 26 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 27 | "file": 1, 28 | "line": 2, 29 | "column": 3, 30 | "severity": 4, 31 | "message": 5 32 | } 33 | } 34 | }, 35 | 36 | { 37 | "label": "test", 38 | "type": "shell", 39 | "command": "make", 40 | "args": [ "test" ], 41 | "windows": { 42 | "command": "bash -c './WinMake.sh test'", 43 | "args": [ ] 44 | }, 45 | "group": { 46 | "kind": "test", 47 | "isDefault": true 48 | }, 49 | "presentation": { 50 | "reveal": "always", 51 | "panel": "dedicated", 52 | "clear": true 53 | } 54 | }, 55 | 56 | { 57 | "label": "launch", 58 | "type": "process", 59 | "command": "bin/qtext", 60 | "windows": { 61 | "command": ".\\bin\\QText.exe" 62 | }, 63 | "presentation": { 64 | "reveal": "never", 65 | "panel": "dedicated", 66 | "clear": true 67 | }, 68 | "dependsOn": "build" 69 | } 70 | ] 71 | } 72 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | Welcome and thank you for your interest in contributing. 4 | 5 | 6 | ### Compiling Code 7 | 8 | Project uses Qt 5.12.8 (Linux) and Qt 5.15.2 (Windows) with Qt Creator being the 9 | preferred development environment. 10 | 11 | All code is situated in `src` directory. 12 | 13 | 14 | #### Linux 15 | 16 | To build project under Linux, the following packages are required (in addition 17 | to Qt Creator): 18 | * build-essentials 19 | * libqt5x11extras5-dev 20 | * qtbase5-dev 21 | * lintian 22 | 23 | To build executables, one can use `make`: 24 | 25 | make clean 26 | make 27 | 28 | To build debian package: 29 | 30 | make clean 31 | make package 32 | 33 | 34 | #### Windows 35 | 36 | To build project under Windows, in adition to Qt Creator with MinGW compiler, 37 | one also needs Git Bash to execute build script: 38 | 39 | ./WinMake.sh 40 | 41 | To make package you need InnoSetup application and executing build script with 42 | `package` argument: 43 | 44 | ./WinMake.sh package 45 | 46 | 47 | ### Running Unit Tests 48 | 49 | To run unit tests, you will need to create a new build configuration. To do so 50 | go to Projects and use Add button to add it. Under qmake build configuration add 51 | `CONFIG+=test` in Additional arguments. If you press Run, it will now execute 52 | all test cases. 53 | 54 | 55 | ### Contributing Fixes 56 | 57 | Fixes can be contributed using pull requests. Do note project is under MIT 58 | license and any contribution will inherit the same. 59 | 60 | LF line ending is strongly preferred. To have Git check it for you, configure 61 | `core.whitespace` setting: 62 | 63 | git config core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol 64 | 65 | All textual files should be encoded as UTF-8 without BOM. 66 | 67 | 68 | ### Coding style 69 | 70 | For non code files (xml, etc), use the best judgment. Albeit, do note that `tab` 71 | character should be avoided and a number of `space` characters should be used 72 | instead (4 being preferred). 73 | 74 | Code uses K&R coding style. Please do make sure any contribution follows the 75 | coding style already in use. 76 | 77 | 78 | # Thank You! 79 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## The MIT License 2 | 3 | Copyright 2004 Josip Medved 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | * The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | 23 | 24 | ## Other Licenses 25 | 26 | This software is compiled using [Qt under GPLv3](LICENSE-Qt.md). 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [QText](https://medo64.com/qtext/) 2 | ================================== 3 | 4 | Simple note taking program. 5 | 6 | 7 | ## Shortcuts 8 | 9 | | Key | Description | 10 | |-------------------|---------------------------------------------------------| 11 | | `F1` | Show application menu | 12 | | `Shift+F1` | Show phonetic spelling dialog | 13 | | `Ctrl+F1` | Show settings | 14 | | `F2` | Rename file | 15 | | `F3` | Find next text match | 16 | | `Shift+F3` | Find previous text match | 17 | | `F4` | Show folder menu | 18 | | `Shift+F4` | Show folder edit dialog | 19 | | `F5` | Insert time and date | 20 | | `Alt+F8` | Show file and/or directory in Visual Studio Code | 21 | | `Ctrl+C` | Copy text | 22 | | `Ctrl+F` | Find text | 23 | | `Ctrl+G` | Find folder or file by name | 24 | | `Ctrl+N` | New file | 25 | | `Ctrl+O` | Show folder menu | 26 | | `Ctrl+Shift+O` | Show folder edit dialog | 27 | | `Ctrl+P` | Print | 28 | | `Ctrl+Shift+P` | Print preview | 29 | | `Ctrl+Alt+R` | Show containing directory | 30 | | `Ctrl+S` | Save file immediatelly | 31 | | `Ctrl+T` | Toggle always on top (might not work on Linux) | 32 | | `Ctrl+V` | Paste text | 33 | | `Ctrl+X` | Cut text | 34 | | `Ctrl+Y` | Redo action | 35 | | `Ctrl+Z` | Undo action | 36 | | `Alt+1` | Select first tab | 37 | | `Alt+2` | Select second tab | 38 | | `Alt+3` | Select third tab | 39 | | `Alt+4` | Select fourth tab | 40 | | `Alt+5` | Select fifth tab | 41 | | `Alt+6` | Select sixth tab | 42 | | `Alt+7` | Select seventh tab | 43 | | `Alt+8` | Select eight tab | 44 | | `Alt+9` | Select ninth tab | 45 | | `Alt+0` | Select tenth tab | 46 | | `Alt+Left` | Select file to the left | 47 | | `Alt+Shift+Left` | Select file to the left | 48 | | `Alt+Right` | Select file to the right | 49 | | `Alt+Shift+Right` | Select file to the right | 50 | | `Alt+Up` | Select previous folder | 51 | | `Alt+Down` | Select next folder | 52 | | `Alt+Home` | Select base folder | 53 | | `Alt+End` | Show folder selection menu | 54 | | `Alt+PageUp` | Select previous folder | 55 | | `Alt+PageDown` | Select next folder | 56 | | `Menu` | Show context menu for text | 57 | | `Shift+Menu` | Show context menu for file | 58 | -------------------------------------------------------------------------------- /package/deb/DEBIAN/config: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | # Show dialog if repository is not there 4 | SOURCE_FILE="/etc/apt/sources.list.d/medo64.list" 5 | if ! [ -f "$SOURCE_FILE" ] && [ "$DEBIAN_FRONTEND" != "noninteractive" ]; then 6 | . /usr/share/debconf/confmodule 7 | 8 | db_input high qtext/add_repository 9 | db_go 10 | db_get qtext/add_repository 11 | case "$RET" in 12 | n*|N*|f*|F*) DO_ADD_REPO=0 ;; 13 | esac 14 | fi 15 | 16 | DO_ADD_REPO=0 17 | SOURCE_FILE="/etc/apt/sources.list.d/medo64.list" 18 | if ! [ -f "$SOURCE_FILE" ] && [ "$DEBIAN_FRONTEND" != "noninteractive" ]; then 19 | . /usr/share/debconf/confmodule 20 | db_get qtext/add_repository 21 | case "$RET" in 22 | y*|Y*|T*|t*) DO_ADD_REPO=1 ;; 23 | esac 24 | fi 25 | 26 | if [ "$DO_ADD_REPO" -ne 0 ]; then 27 | echo "deb http://packages.medo64.com/deb stable main" > "$SOURCE_FILE" 28 | if [ -d "/etc/apt/trusted.gpg.d/" ]; then 29 | echo "-----BEGIN PGP PUBLIC KEY BLOCK----- 30 | Version: GnuPG v1 31 | 32 | mQENBFqxbGoBCACnavHwueNmk947TOkLDsnay/4uQIan79YFyHnv2zTFRuszuwFw 33 | 65sbflaBTjR57CZRzNyXHEcPb/NrxxuhXKHOXzbURy6FBv0CQZVjf9bm0Lroq5Ab 34 | oZ9v0UZukpLoAyHkNca/zyHJoHtAq2Deq5X44dPRsCALn2zWJKya+hyA8ZYnGlcG 35 | hERdnR8mMB+i0xb44rnDNY7GwdRykSialn3WopSFBrHv9pYOd2wtnrb3H9pFjT3H 36 | jNp1+3/4mW6WDdVzC7mkJk9ia8mHqAw0IgtE7fP7HYcJnmdqCqgI3sZBR+D1VpyM 37 | CgNGK6DrGD5IUp1ktZe2wAL8Jig2/Xmk02g7ABEBAAG0L0pvc2lwIE1lZHZlZCAo 38 | UmVwb3NpdG9yeSkgPGptZWR2ZWRAam1lZHZlZC5jb20+iQE4BBMBCAAiBQJasWxq 39 | AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA4LnS5Ecf8hgj0B/0XeXn8 40 | aPkDLwHJzLbily9SUxn3WYcZhXEE1JSXtDHWI1owS/TT7kZxswHRh1DyZDQJSK0B 41 | LCsHx1zoIVIvlkGz8PNfN+G/E+2CAI8/cdDBa5z8DM+w8wpQ02NZjWnS5pmpr3MT 42 | sP7hLlyEeq/ErtKmZMlquDtTR7lUjundgtUIgofiSDiri/1xNynUmPgykkKR/vR2 43 | mrPHCxIqiEEq5RkFvIDpH6zltld97AeNP2vEcmkpyS9npFRkHgPNjxZhvHhhjbHP 44 | pXF542bTCX+bXOfPWbdl/mnIBRKdsNGNu/FbXTQ4gEmXQwmki5YL8kRwbBloxuH2 45 | 5VcfjRkkgrnxUy4S 46 | =gY4j 47 | -----END PGP PUBLIC KEY BLOCK-----" > /etc/apt/trusted.gpg.d/medo64.asc 48 | else # add it using deprecated apt-key 49 | echo "-----BEGIN PGP PUBLIC KEY BLOCK----- 50 | Version: GnuPG v1 51 | 52 | mQENBFqxbGoBCACnavHwueNmk947TOkLDsnay/4uQIan79YFyHnv2zTFRuszuwFw 53 | 65sbflaBTjR57CZRzNyXHEcPb/NrxxuhXKHOXzbURy6FBv0CQZVjf9bm0Lroq5Ab 54 | oZ9v0UZukpLoAyHkNca/zyHJoHtAq2Deq5X44dPRsCALn2zWJKya+hyA8ZYnGlcG 55 | hERdnR8mMB+i0xb44rnDNY7GwdRykSialn3WopSFBrHv9pYOd2wtnrb3H9pFjT3H 56 | jNp1+3/4mW6WDdVzC7mkJk9ia8mHqAw0IgtE7fP7HYcJnmdqCqgI3sZBR+D1VpyM 57 | CgNGK6DrGD5IUp1ktZe2wAL8Jig2/Xmk02g7ABEBAAG0L0pvc2lwIE1lZHZlZCAo 58 | UmVwb3NpdG9yeSkgPGptZWR2ZWRAam1lZHZlZC5jb20+iQE4BBMBCAAiBQJasWxq 59 | AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA4LnS5Ecf8hgj0B/0XeXn8 60 | aPkDLwHJzLbily9SUxn3WYcZhXEE1JSXtDHWI1owS/TT7kZxswHRh1DyZDQJSK0B 61 | LCsHx1zoIVIvlkGz8PNfN+G/E+2CAI8/cdDBa5z8DM+w8wpQ02NZjWnS5pmpr3MT 62 | sP7hLlyEeq/ErtKmZMlquDtTR7lUjundgtUIgofiSDiri/1xNynUmPgykkKR/vR2 63 | mrPHCxIqiEEq5RkFvIDpH6zltld97AeNP2vEcmkpyS9npFRkHgPNjxZhvHhhjbHP 64 | pXF542bTCX+bXOfPWbdl/mnIBRKdsNGNu/FbXTQ4gEmXQwmki5YL8kRwbBloxuH2 65 | 5VcfjRkkgrnxUy4S 66 | =gY4j 67 | -----END PGP PUBLIC KEY BLOCK-----" | apt-key add - 68 | fi 69 | fi 70 | 71 | # Done 72 | exit 0 73 | -------------------------------------------------------------------------------- /package/deb/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Package: qtext 2 | Version: MAJOR.MINOR.PATCH 3 | Architecture: ARCHITECTURE 4 | Maintainer: Josip Medved 5 | Homepage: https://www.medo64.com/qtext/ 6 | Description: Note taking utility 7 | It's similar to notepad which can be brought from tray when needed but has also 8 | auto-save thing going on. 9 | Section: utils 10 | Priority: optional 11 | Depends: debconf, gnupg2, libc6, qtbase5-dev, libqt5x11extras5, openssl, dconf-cli 12 | Build-Depends: qtbase5-dev, libqt5x11extras5-dev 13 | -------------------------------------------------------------------------------- /package/deb/DEBIAN/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Update man pages 5 | mandb -q 6 | 7 | # Just loading to suppress warning 8 | . /usr/share/debconf/confmodule || true 9 | 10 | # Done 11 | exit 0 12 | -------------------------------------------------------------------------------- /package/deb/DEBIAN/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Update man pages 5 | mandb -q 6 | 7 | # Purge debconf 8 | if [ "$1" = "purge" -a -e /usr/share/debconf/confmodule ]; then 9 | . /usr/share/debconf/confmodule 10 | db_purge 11 | fi 12 | 13 | # Done 14 | exit 0 15 | -------------------------------------------------------------------------------- /package/deb/DEBIAN/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Kill application 5 | PID=$(ps aux | grep '[/]opt/qtext/qtext' | awk '{print $2}') 6 | if [[ $PID != "" ]]; then 7 | sudo kill $PID 2>/dev/null || true 8 | fi 9 | 10 | # Done 11 | exit 0 12 | -------------------------------------------------------------------------------- /package/deb/DEBIAN/templates: -------------------------------------------------------------------------------- 1 | Template: qtext/add_repository 2 | Type: boolean 3 | Default: true 4 | Description: Should the repository be added to the system? 5 | If selected, the repository for the package will be added for the purpose 6 | of simplifying the future upgrades. If not added, each update will have to 7 | be manually installed. 8 | -------------------------------------------------------------------------------- /package/deb/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: qtext 3 | Upstream-Contact: Josip Medved 4 | Source: https://www.medo64.com/qtext/ 5 | 6 | Files: * 7 | Copyright: 2019 Josip Medved 8 | License: MIT 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | this software and associated documentation files (the "Software"), to deal in 11 | the Software without restriction, including without limitation the rights to 12 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 13 | of the Software, and to permit persons to whom the Software is furnished to do 14 | so, subject to the following conditions: 15 | . 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | . 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /package/deb/usr/share/applications/qtext.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=QText 3 | GenericName=Notes 4 | Comment=Note taking utility with auto-save 5 | TryExec=/opt/qtext/qtext 6 | Exec=env QT_QPA_PLATFORM=xcb /opt/qtext/qtext %f 7 | Icon=qtext 8 | Type=Application 9 | Categories=GTK;GNOME;Utility; 10 | X-KDE-Shortcuts=Ctrl+Shift+Q 11 | -------------------------------------------------------------------------------- /package/win/License.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033\deflangfe1033{\fonttbl{\f0\fswiss\fprq2\fcharset238 Calibri;}{\f1\fnil\fcharset2 Symbol;}} 2 | {\*\generator Riched20 10.0.17134}{\*\mmathPr\mnaryLim0\mdispDef1\mwrapIndent1440 }\viewkind4\uc1 3 | \pard\nowidctlpar\sa200\sl276\slmult1\b\f0\fs22\lang9 The MIT License\par 4 | \b0 Copyright 2004 Josip Medved \par 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\par 6 | 7 | \pard{\pntext\f1\'B7\tab}{\*\pn\pnlvlblt\pnf1\pnindent0{\pntxtb\'B7}}\nowidctlpar\fi-360\li720\sa200\sl276\slmult1 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\par 8 | {\pntext\f1\'B7\tab}THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\par 9 | } 10 | -------------------------------------------------------------------------------- /package/win/QText.iss: -------------------------------------------------------------------------------- 1 | #define AppName GetStringFileInfo('..\..\bin\QText.exe', 'ProductName') 2 | #define AppVersion GetStringFileInfo('..\..\bin\QText.exe', 'ProductVersion') 3 | #define AppFileVersion GetStringFileInfo('..\..\bin\QText.exe', 'FileVersion') 4 | #define AppCompany GetStringFileInfo('..\..\bin\QText.exe', 'CompanyName') 5 | #define AppCopyright GetStringFileInfo('..\..\bin\QText.exe', 'LegalCopyright') 6 | #define AppBase LowerCase(StringChange(AppName, ' ', '')) 7 | #define AppVersion3 Copy(AppVersion, 1, RPos('.', AppVersion) - 1) 8 | #define AppSetupFile AppBase + '-' + AppVersion3 9 | 10 | 11 | [Setup] 12 | AppName={#AppName} 13 | AppVersion={#AppVersion} 14 | AppVerName={#AppName} {#AppVersion} 15 | AppPublisher={#AppCompany} 16 | AppPublisherURL=https://www.medo64.com/{#AppBase}/ 17 | AppCopyright={#AppCopyright} 18 | VersionInfoProductVersion={#AppVersion} 19 | VersionInfoProductTextVersion={#AppVersion3} 20 | VersionInfoVersion={#AppFileVersion} 21 | DefaultDirName={autopf}\{#AppCompany}\{#AppName} 22 | OutputBaseFilename={#AppSetupFile} 23 | SourceDir=..\..\bin 24 | OutputDir=..\dist 25 | AppId=JosipMedved_QText 26 | CloseApplications="force" 27 | RestartApplications="no" 28 | //AppMutex=JosipMedved_QText 29 | SetupMutex=JosipMedved_QText_Setup 30 | UninstallDisplayIcon={app}\QText.exe 31 | AlwaysShowComponentsList=no 32 | ArchitecturesInstallIn64BitMode=x64 33 | DisableProgramGroupPage=yes 34 | MergeDuplicateFiles=yes 35 | MinVersion=0,6.1sp1 36 | PrivilegesRequired=lowest 37 | PrivilegesRequiredOverridesAllowed=dialog 38 | ShowLanguageDialog=no 39 | SolidCompression=yes 40 | ChangesAssociations=no 41 | DisableWelcomePage=yes 42 | LicenseFile=../package/win/License.rtf 43 | 44 | 45 | [Messages] 46 | SetupAppTitle=Setup {#AppName} {#AppVersion3} 47 | SetupWindowTitle=Setup {#AppName} {#AppVersion3} 48 | BeveledLabel=medo64.com 49 | 50 | [Dirs] 51 | Name: "{userappdata}\Josip Medved\QText"; Flags: uninsalwaysuninstall 52 | 53 | [Files] 54 | Source: "QText.exe"; DestDir: "{app}"; Flags: ignoreversion; 55 | Source: "libgcc_s_seh-1.dll"; DestDir: "{app}"; Flags: ignoreversion; 56 | Source: "libstdc++-6.dll"; DestDir: "{app}"; Flags: ignoreversion; 57 | Source: "libstdc++-6.dll"; DestDir: "{app}"; Flags: ignoreversion; 58 | Source: "libwinpthread-1.dll"; DestDir: "{app}"; Flags: ignoreversion; 59 | Source: "Qt5Core.dll"; DestDir: "{app}"; Flags: ignoreversion; 60 | Source: "Qt5Gui.dll"; DestDir: "{app}"; Flags: ignoreversion; 61 | Source: "Qt5Network.dll"; DestDir: "{app}"; Flags: ignoreversion; 62 | Source: "Qt5PrintSupport.dll"; DestDir: "{app}"; Flags: ignoreversion; 63 | Source: "Qt5Widgets.dll"; DestDir: "{app}"; Flags: ignoreversion; 64 | Source: "libcrypto-1_1-x64.dll"; DestDir: "{app}"; Flags: ignoreversion; 65 | Source: "libssl-1_1-x64.dll"; DestDir: "{app}"; Flags: ignoreversion; 66 | Source: "platforms/qwindows.dll"; DestDir: "{app}/platforms"; Flags: ignoreversion; 67 | Source: "styles/qwindowsvistastyle.dll"; DestDir: "{app}/styles"; Flags: ignoreversion; 68 | Source: "..\README.md"; DestName: "README.txt"; DestDir: "{app}"; Flags: overwritereadonly uninsremovereadonly; Attribs: readonly; 69 | Source: "..\LICENSE.md"; DestName: "LICENSE.txt"; DestDir: "{app}"; Flags: overwritereadonly uninsremovereadonly; Attribs: readonly; 70 | 71 | [Icons] 72 | Name: "{userstartmenu}\QText"; Filename: "{app}\QText.exe" 73 | 74 | [Registry] 75 | Root: HKCU; Subkey: "Software\Josip Medved"; Flags: uninsdeletekeyifempty 76 | Root: HKCU; Subkey: "Software\Josip Medved\QText"; Flags: uninsdeletekey 77 | Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "QText"; ValueData: """{app}\QText.exe"" --hide"; Flags: uninsdeletevalue 78 | 79 | [Run] 80 | Description: "Launch application now"; Filename: "{app}\QText.exe"; Parameters: "/setup"; Flags: postinstall nowait skipifsilent runasoriginaluser shellexec 81 | Description: "View ReadMe.txt"; Filename: "{app}\ReadMe.txt"; Flags: postinstall nowait skipifsilent runasoriginaluser shellexec unchecked 82 | 83 | 84 | [Code] 85 | 86 | procedure InitializeWizard; 87 | begin 88 | WizardForm.LicenseAcceptedRadio.Checked := True; 89 | end; 90 | -------------------------------------------------------------------------------- /scripts/autoformat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIRECTORY=$(dirname $(realpath $0)) 4 | 5 | command -v astyle >/dev/null 6 | if [[ $? -eq 0 ]]; then 7 | EXE="astyle" 8 | elif [[ -f "/c/Qt/AStyle/bin/AStyle.exe" ]]; then 9 | EXE="/c/Qt/AStyle/bin/AStyle.exe" 10 | else 11 | echo "AStyle not found!" >&2 12 | exit 1 13 | fi 14 | 15 | DIRECTORY=$(realpath "$SCRIPT_DIRECTORY/../src") 16 | cd $DIRECTORY 17 | 18 | $EXE --project=.astylerc --suffix=none --recursive --formatted --lineend=linux *.cpp,*.h | tail -n +4 19 | exit $? 20 | -------------------------------------------------------------------------------- /src/.astylerc: -------------------------------------------------------------------------------- 1 | --style=attach 2 | --indent=spaces=4 3 | --indent-preproc-block 4 | --indent-namespaces 5 | --indent-classes 6 | --indent-switches 7 | --indent-cases 8 | --keep-one-line-blocks 9 | --keep-one-line-statements 10 | --add-one-line-braces 11 | --align-pointer=type 12 | --align-reference=type 13 | --pad-oper 14 | --pad-comma 15 | --pad-header 16 | -------------------------------------------------------------------------------- /src/app.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "medo/appsetupmutex.h" 4 | #include "medo/config.h" 5 | #include "medo/singleinstance.h" 6 | #include "medo/state.h" 7 | #include "ui/mainwindow.h" 8 | #include "settings.h" 9 | #include "setup.h" 10 | 11 | static Storage* storage; 12 | 13 | int main(int argc, char* argv[]) { 14 | QCoreApplication::setApplicationName(APP_PRODUCT); 15 | QCoreApplication::setOrganizationName(APP_COMPANY); 16 | QCoreApplication::setApplicationVersion(APP_VERSION); 17 | 18 | QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); 19 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 20 | 21 | AppSetupMutex appMutex("JosipMedved_QText"); 22 | QApplication app(argc, argv); 23 | 24 | QCommandLineParser cli; 25 | cli.setApplicationDescription(APP_DESCRIPTION); 26 | cli.addHelpOption(); 27 | cli.addVersionOption(); 28 | QCommandLineOption hideOption(QStringList() << "s" << "hide", "Application is immediately sent to tray."); 29 | cli.addOption(hideOption); 30 | cli.process(app); 31 | 32 | QApplication::setQuitOnLastWindowClosed(false); 33 | 34 | if (!SingleInstance::attach()) { 35 | return static_cast(0x80004004); //exit immediately if another instance is running 36 | } 37 | 38 | QStringList dataPaths = Settings::dataPaths(); 39 | Config::setStateFilePath(dataPaths[0] + "/.qtext.user"); //store state file in the first directory 40 | QApplication::connect(State::instance(), &State::writeToConfig, [ = ] (QString key, QString value) { Config::stateWrite("State!" + key, value); }); 41 | QApplication::connect(State::instance(), &State::readFromConfig, [ = ] (QString key) { return Config::stateRead("State!" + key, QString()); }); 42 | QApplication::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [ = ] () { Config::quit(); }); 43 | 44 | if (Settings::waitForDirectory()) { 45 | bool anyFailed = false; 46 | do { 47 | anyFailed = false; 48 | for (QString path : dataPaths) { 49 | QDir directory = path; 50 | if (!directory.exists()) { 51 | qDebug().noquote() << "Waiting for directory '" << directory << "'"; 52 | QThread::msleep(100); 53 | anyFailed = true; 54 | } 55 | } 56 | } while (anyFailed); 57 | } 58 | 59 | storage = new Storage(dataPaths); 60 | MainWindow w { storage }; 61 | 62 | #ifndef QT_DEBUG 63 | if (!QSystemTrayIcon::isSystemTrayAvailable() || !cli.isSet(hideOption)) { 64 | w.show(); 65 | } 66 | #else //show immediately when debugging 67 | w.show(); 68 | #endif 69 | 70 | if (!Settings::setupCompleted() && !Config::isPortable()) { 71 | Settings::setSetupCompleted(true); 72 | Setup::setAutostart(true); 73 | } 74 | 75 | return app.exec(); 76 | } 77 | -------------------------------------------------------------------------------- /src/clipboard.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "clipboard.h" 6 | 7 | bool Clipboard::hasPlain() { 8 | auto mimeData = QApplication::clipboard()->mimeData(); 9 | return mimeData->hasText(); 10 | } 11 | 12 | bool Clipboard::hasHtml() { 13 | auto mimeData = QApplication::clipboard()->mimeData(); 14 | return mimeData->hasHtml(); 15 | } 16 | 17 | bool Clipboard::setData(QString plainText, QString htmlText) { 18 | if (plainText.isEmpty()) { return false; } //plain text has to be present 19 | 20 | QClipboard* clipboard = QApplication::clipboard(); 21 | 22 | QMimeData* data = new QMimeData; 23 | data->setText(plainText); 24 | if (!htmlText.isEmpty()) { data->setHtml(htmlText); } 25 | clipboard->setMimeData(data, QClipboard::Clipboard); 26 | 27 | if (clipboard->supportsSelection()) { //to support Linux Terminal app, only plain text 28 | clipboard->setText(plainText, QClipboard::Selection); 29 | } 30 | 31 | #if defined(Q_OS_LINUX) 32 | QThread::msleep(1); //workaround for copied text not being available... 33 | #endif 34 | 35 | return true; 36 | } 37 | 38 | 39 | bool Clipboard::cutPlain(QTextCursor cursor) { 40 | if (copyPlain(cursor)) { 41 | cursor.removeSelectedText(); 42 | return true; 43 | } 44 | return false; 45 | } 46 | 47 | bool Clipboard::copyPlain(QTextCursor cursor) { 48 | if (cursor.hasSelection()) { 49 | return setData(cursor.selection().toPlainText()); 50 | } 51 | return false; 52 | } 53 | 54 | bool Clipboard::pastePlain(QTextCursor cursor) { 55 | auto data = QApplication::clipboard()->mimeData(); 56 | if (data->hasText()) { 57 | if (cursor.hasSelection()) { cursor.removeSelectedText(); } 58 | cursor.insertText(data->text()); 59 | return true; 60 | } 61 | return false; 62 | } 63 | 64 | 65 | bool Clipboard::cutHtml(QTextCursor cursor) { 66 | if (copyHtml(cursor)) { 67 | cursor.removeSelectedText(); 68 | return true; 69 | } 70 | return false; 71 | } 72 | 73 | bool Clipboard::copyHtml(QTextCursor cursor) { 74 | if (cursor.hasSelection()) { 75 | return setData(cursor.selection().toPlainText(), cursor.selection().toHtml()); 76 | } 77 | return false; 78 | } 79 | 80 | bool Clipboard::pasteHtml(QTextCursor cursor) { 81 | auto data = QApplication::clipboard()->mimeData(); 82 | if (data->hasText()) { 83 | if (cursor.hasSelection()) { cursor.removeSelectedText(); } 84 | if (data->hasHtml()) { 85 | cursor.insertHtml(data->html()); 86 | } else { 87 | cursor.insertText(data->text()); 88 | } 89 | return true; 90 | } 91 | return false; 92 | } 93 | -------------------------------------------------------------------------------- /src/clipboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class Clipboard { 8 | 9 | public: 10 | static bool hasPlain(); 11 | static bool hasHtml(); 12 | static bool setData(QString plainText, QString htmlText = ""); 13 | static bool cutPlain(QTextCursor cursor); 14 | static bool copyPlain(QTextCursor cursor); 15 | static bool pastePlain(QTextCursor cursor); 16 | static bool cutHtml(QTextCursor cursor); 17 | static bool copyHtml(QTextCursor cursor); 18 | static bool pasteHtml(QTextCursor cursor); 19 | 20 | }; 21 | -------------------------------------------------------------------------------- /src/deletion.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "deletion.h" 7 | 8 | #if defined(Q_OS_WIN) 9 | #include 10 | #elif defined(Q_OS_LINUX) //no need for imports 11 | #else 12 | #error "Only Linux and Windows are supported!" 13 | #endif 14 | 15 | 16 | bool Deletion::deleteFile(FileItem* file) { 17 | QFile osFile(file->path()); 18 | return osFile.remove(); 19 | } 20 | 21 | bool Deletion::overwriteFile(FileItem* file) { 22 | QFile osFile(file->path()); 23 | int length = osFile.size(); 24 | osFile.open(QIODevice::WriteOnly | QIODevice::Unbuffered); 25 | int size = ((length + 4095) / 4096) * 4096; //round size up to the nearest 4K 26 | char buffer[size]; 27 | QRandomGenerator rnd; 28 | for (auto i = 0; i < static_cast(sizeof(buffer)); i += 4) { 29 | qint32 n = rnd.generate(); 30 | memcpy(&buffer[i], &n, 4); 31 | } 32 | osFile.seek(0); 33 | osFile.write(buffer, length); 34 | osFile.flush(); 35 | return osFile.remove(); 36 | } 37 | 38 | bool Deletion::recycleFile(FileItem* file) { 39 | QString path = file->path(); 40 | QFile osFile(path); 41 | 42 | #if defined(Q_OS_WIN) 43 | 44 | WCHAR fromPathArray[4096]; 45 | memset(&fromPathArray, 0, sizeof(fromPathArray)); 46 | int fromPathLength = path.toWCharArray(fromPathArray); 47 | if (fromPathLength < 4096) { 48 | fromPathArray[fromPathLength] = '\0'; //terminate with null char 49 | SHFILEOPSTRUCTW fileOp; 50 | memset(&fileOp, 0, sizeof(fileOp)); 51 | fileOp.wFunc = FO_DELETE; 52 | fileOp.pFrom = fromPathArray; 53 | fileOp.fFlags = FOF_NO_UI | FOF_ALLOWUNDO; 54 | if (SHFileOperation(&fileOp) == 0) { 55 | return true; 56 | } else { //just delete if recycle fails 57 | qDebug().noquote() << "[Deletion] Recycle failed for '" << osFile.fileName() << "'"; 58 | return osFile.remove(); 59 | } 60 | } else { //don't bother deleting if 4096 characters or longer 61 | return osFile.remove(); 62 | } 63 | 64 | #elif defined(Q_OS_LINUX) //no need for imports 65 | 66 | QString home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); 67 | QDir localTrashDir(QDir::cleanPath(home + "/.local/share/Trash")); 68 | QDir userTrashDir(QDir::cleanPath(home + "/.trash")); 69 | QDir trashDir; 70 | if (localTrashDir.exists()) { 71 | trashDir = localTrashDir; 72 | } else if (userTrashDir.exists()) { 73 | trashDir = userTrashDir; 74 | } else if (userTrashDir.mkdir(".")) { //try creating it if it doesn't exist 75 | trashDir = userTrashDir; 76 | } else { //just delete it if recycle is not feasible 77 | return osFile.remove(); 78 | } 79 | 80 | QFileInfo fileInfo(path); 81 | QFileInfo trashBaseFile(QDir::cleanPath(trashDir.path() + "/" + fileInfo.fileName())); 82 | QString trashPath = trashBaseFile.path(); 83 | for (int i = 2; i < 100; i++) { //check for duplicates up to 100 times, then give up and overwrite 84 | if (!QFile::exists(trashPath)) { break; } 85 | trashPath = QDir::cleanPath(trashDir.path() + "/" 86 | + trashBaseFile.completeBaseName() + "~" + QString::number(i) 87 | + "." + trashBaseFile.suffix()); 88 | } 89 | 90 | if (QFile::rename(path, trashPath)) { 91 | return true; 92 | } else { //give up and delete 93 | qDebug().noquote() << "[Deletion] Recycle failed for '" << osFile.fileName() << "' due to '" << osFile.errorString() << "'"; 94 | return osFile.remove(); 95 | } 96 | 97 | #else //just delete on unknown platform 98 | return osFile.remove(); 99 | #endif 100 | } 101 | 102 | 103 | bool Deletion::deleteFolder(FolderItem* folder) { 104 | if (folder->isRoot()) { return false; } //cannot delete root folders 105 | QDir directory(folder->path()); 106 | return directory.removeRecursively(); 107 | } 108 | 109 | bool Deletion::overwriteFolder(FolderItem* folder) { 110 | for (auto file : *folder) { 111 | overwriteFile(file); 112 | } 113 | return deleteFolder(folder); 114 | } 115 | 116 | bool Deletion::recycleFolder(FolderItem* folder) { 117 | for (auto file : *folder) { 118 | recycleFile(file); 119 | } 120 | return deleteFolder(folder); 121 | } 122 | -------------------------------------------------------------------------------- /src/deletion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "storage/fileitem.h" 5 | 6 | class Deletion { 7 | 8 | public: 9 | static bool deleteFile(FileItem* file); 10 | static bool overwriteFile(FileItem* file); 11 | static bool recycleFile(FileItem* file); 12 | static bool deleteFolder(FolderItem* folder); 13 | static bool overwriteFolder(FolderItem* folder); 14 | static bool recycleFolder(FolderItem* folder); 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /src/find.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "find.h" 5 | 6 | 7 | Storage* Find::_storage = nullptr; 8 | QString Find::_findText; 9 | QFlags Find::_findFlags; 10 | bool Find::_findUseRegEx; 11 | FileItem* Find::_firstMatchFile = nullptr; 12 | QTextCursor Find::_firstMatchCursor; 13 | bool Find::_firstMatchBackward; 14 | Find::SearchScope Find::_findScope = Find::SearchScope::AllFolders; 15 | 16 | 17 | void Find::setup(Storage* storage, QString text, bool matchCase, bool wholeWord, bool useRegEx, Find::SearchScope searchScope) { 18 | _storage = storage; 19 | 20 | _findText = text; 21 | _findFlags = QTextDocument::FindFlag(); 22 | if (matchCase) { _findFlags |= QTextDocument::FindCaseSensitively; } 23 | if (wholeWord) { _findFlags |= QTextDocument::FindWholeWords; } 24 | _findUseRegEx = useRegEx; 25 | 26 | _firstMatchFile = nullptr; 27 | _firstMatchCursor = QTextCursor(); 28 | _firstMatchBackward = false; 29 | 30 | _findScope = searchScope; 31 | } 32 | 33 | FileItem* Find::findNext(FileItem* currentFile, bool backward) { 34 | bool firstFile = true; 35 | for (auto file : fileList(currentFile, backward)) { 36 | auto cursor = file->textCursor(); 37 | if (!firstFile) { cursor.movePosition(backward ? QTextCursor::End : QTextCursor::Start); } 38 | auto flags = backward ? _findFlags | QTextDocument::FindBackward : _findFlags; 39 | 40 | auto document = file->document(); 41 | QTextCursor resultCursor; 42 | if (_findUseRegEx) { 43 | auto regEx = QRegExp(_findText, _findFlags.testFlag(QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive); 44 | resultCursor = document->find(regEx, cursor, flags); 45 | } else { 46 | resultCursor = document->find(_findText, cursor, flags); 47 | } 48 | 49 | if (!resultCursor.isNull()) { 50 | if ((_firstMatchFile == nullptr) || (_firstMatchBackward != backward)) { //save first match 51 | _firstMatchFile = file; 52 | _firstMatchCursor = resultCursor; 53 | _firstMatchBackward = backward; 54 | } else if ((file == _firstMatchFile) && (resultCursor == _firstMatchCursor)) { //check if we wrapped around 55 | QApplication::beep(); 56 | } 57 | file->setTextCursor(resultCursor); 58 | return file; 59 | } 60 | firstFile = false; 61 | } 62 | 63 | //nothing found 64 | QApplication::beep(); 65 | return nullptr; 66 | } 67 | 68 | QList Find::fileList(FileItem* pivotFile, bool backward) { 69 | QList items; 70 | 71 | if (_findScope == Find::SearchScope::CurrentFile) { 72 | items.append(pivotFile); 73 | items.append(pivotFile); 74 | } else { 75 | bool foundPivot = false; 76 | int insertLocation = 0; 77 | for (FolderItem* folder : *_storage) { 78 | if ((_findScope == Find::SearchScope::CurrentFolder) && (folder != pivotFile->folder())) { continue; } 79 | 80 | for (FileItem* file : *folder) { 81 | if (backward) { //if we're ordering them backward 82 | if (foundPivot) { 83 | items.insert(insertLocation, file); 84 | } else { 85 | items.insert(0, file); 86 | insertLocation++; 87 | } 88 | if (file == pivotFile) { foundPivot = true; } 89 | } else { 90 | if (file == pivotFile) { foundPivot = true; } 91 | if (foundPivot) { //insert to the front of the list 92 | items.insert(insertLocation, file); 93 | insertLocation++; 94 | } else { 95 | items.append(file); 96 | } 97 | } 98 | } 99 | } 100 | 101 | if (foundPivot) { //add pivot file again at the end to allow checking before the first cursor 102 | items.append(items[0]); 103 | } 104 | } 105 | 106 | return items; 107 | } 108 | 109 | 110 | bool Find::hasText() { 111 | return _findText.length() > 0; 112 | } 113 | 114 | QString Find::lastText() { 115 | return _findText; 116 | } 117 | 118 | bool Find::lastMatchCase() { 119 | return _findFlags.testFlag(QTextDocument::FindCaseSensitively); 120 | } 121 | 122 | bool Find::lastWholeWord() { 123 | return _findFlags.testFlag(QTextDocument::FindWholeWords); 124 | } 125 | 126 | bool Find::lastUseRegEx() { 127 | return _findUseRegEx; 128 | } 129 | 130 | Find::SearchScope Find::lastSearchScope() { 131 | return _findScope; 132 | } 133 | -------------------------------------------------------------------------------- /src/find.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "storage/storage.h" 6 | 7 | class Find { 8 | 9 | public: 10 | enum class SearchScope { 11 | CurrentFile = 0, 12 | CurrentFolder = 1, 13 | AllFolders = 2, 14 | }; 15 | 16 | public: 17 | static void setup(Storage* storage, QString text, bool matchCase, bool wholeWord, bool useRegEx, Find::SearchScope searchScope); 18 | static FileItem* findNext(FileItem* currentFile, bool backward = false); 19 | static bool hasText(); 20 | static QString lastText(); 21 | static bool lastMatchCase(); 22 | static bool lastWholeWord(); 23 | static bool lastUseRegEx(); 24 | static SearchScope lastSearchScope(); 25 | 26 | private: 27 | static QList fileList(FileItem* pivotFile, bool backward = false); 28 | static Storage* _storage; 29 | static QString _findText; 30 | static QFlags _findFlags; 31 | static bool _findUseRegEx; 32 | static FileItem* _firstMatchFile; 33 | static QTextCursor _firstMatchCursor; 34 | static bool _firstMatchBackward; 35 | static SearchScope _findScope; 36 | 37 | }; 38 | -------------------------------------------------------------------------------- /src/helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "storage/fileitem.h" 6 | #include "storage/folderitem.h" 7 | 8 | class Helpers { 9 | 10 | public: 11 | static QString getFileNameFromTitle(QString fileTitle); 12 | static QString getFileTitleFromName(QString fileName); 13 | static QString getFolderNameFromTitle(QString folderTitle); 14 | static QString getFolderTitleFromName(QString folderName); 15 | static QString getTextWithoutAccents(QString text); 16 | static bool showInFileManager(QString directoryPath, QString filePath); 17 | static bool openWithDefaultApplication(QString filePath); 18 | static bool openFileWithVSCode(FileItem* file); 19 | static bool openFileWithVSCode(QString filePath); 20 | static bool openDirectoryWithVSCode(FileItem* file); 21 | static bool openDirectoryWithVSCode(FolderItem* folder); 22 | static bool openDirectoriesWithVSCode(QStringList directoryPaths); 23 | static bool openWithVSCodeAvailable(); 24 | static void setReadonlyPalette(QWidget* widget); 25 | static void setupResizableDialog(QWidget* dialog); 26 | static void setupFixedSizeDialog(QWidget* dialog); 27 | static void setupTheme(bool darkMode); 28 | static bool isOSInDarkMode(); 29 | static void openUrl(QString url); 30 | static bool isWayland(); 31 | 32 | private: 33 | static bool isValidTitleChar(QChar ch); 34 | static QString getFSNameFromTitle(QString fsTitle, bool isFolder); 35 | static QString getFSTitleFromName(QString fsName); 36 | 37 | }; 38 | -------------------------------------------------------------------------------- /src/icons.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Icons { 7 | 8 | public: 9 | static QIcon app(); 10 | static QIcon appMono(); 11 | static QIcon appBlack(); 12 | static QIcon appWhite(); 13 | 14 | static QIcon newFile(); 15 | static QIcon saveFile(); 16 | static QIcon renameFile(); 17 | static QIcon deleteFile(); 18 | static QIcon printFile(); 19 | static QIcon printPreviewFile(); 20 | static QIcon printToPdfFile(); 21 | 22 | static QIcon cut(); 23 | static QIcon copy(); 24 | static QIcon paste(); 25 | 26 | static QIcon undo(); 27 | static QIcon redo(); 28 | 29 | static QIcon fontBold(); 30 | static QIcon fontItalic(); 31 | static QIcon fontUnderline(); 32 | static QIcon fontStrikethrough(); 33 | 34 | static QIcon find(); 35 | static QIcon findNext(); 36 | 37 | static QIcon gotoIcon(); 38 | 39 | static QIcon settings(); 40 | static QIcon settingsWithUpgrade(); 41 | 42 | static QIcon gotoFile(); 43 | static QIcon gotoFolder(); 44 | 45 | static void setDarkMode(bool darkMode); 46 | 47 | private: 48 | static bool _darkMode; 49 | static QPixmap getPixmap(QString baseName, int size); 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /src/icons/128x128/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/128x128/app.png -------------------------------------------------------------------------------- /src/icons/128x128/appBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/128x128/appBlack.png -------------------------------------------------------------------------------- /src/icons/128x128/appDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/128x128/appDebug.png -------------------------------------------------------------------------------- /src/icons/128x128/appMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/128x128/appMono.png -------------------------------------------------------------------------------- /src/icons/128x128/appWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/128x128/appWhite.png -------------------------------------------------------------------------------- /src/icons/16x16/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/app.png -------------------------------------------------------------------------------- /src/icons/16x16/appBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/appBlack.png -------------------------------------------------------------------------------- /src/icons/16x16/appDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/appDebug.png -------------------------------------------------------------------------------- /src/icons/16x16/appMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/appMono.png -------------------------------------------------------------------------------- /src/icons/16x16/appWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/appWhite.png -------------------------------------------------------------------------------- /src/icons/16x16/bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/bold.png -------------------------------------------------------------------------------- /src/icons/16x16/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/copy.png -------------------------------------------------------------------------------- /src/icons/16x16/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/cut.png -------------------------------------------------------------------------------- /src/icons/16x16/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/delete.png -------------------------------------------------------------------------------- /src/icons/16x16/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/file.png -------------------------------------------------------------------------------- /src/icons/16x16/find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/find.png -------------------------------------------------------------------------------- /src/icons/16x16/findNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/findNext.png -------------------------------------------------------------------------------- /src/icons/16x16/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/folder.png -------------------------------------------------------------------------------- /src/icons/16x16/goto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/goto.png -------------------------------------------------------------------------------- /src/icons/16x16/italic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/italic.png -------------------------------------------------------------------------------- /src/icons/16x16/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/new.png -------------------------------------------------------------------------------- /src/icons/16x16/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/paste.png -------------------------------------------------------------------------------- /src/icons/16x16/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/print.png -------------------------------------------------------------------------------- /src/icons/16x16/printPdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/printPdf.png -------------------------------------------------------------------------------- /src/icons/16x16/printPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/printPreview.png -------------------------------------------------------------------------------- /src/icons/16x16/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/redo.png -------------------------------------------------------------------------------- /src/icons/16x16/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/rename.png -------------------------------------------------------------------------------- /src/icons/16x16/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/save.png -------------------------------------------------------------------------------- /src/icons/16x16/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/settings.png -------------------------------------------------------------------------------- /src/icons/16x16/settingsWithUpgrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/settingsWithUpgrade.png -------------------------------------------------------------------------------- /src/icons/16x16/strikethrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/strikethrough.png -------------------------------------------------------------------------------- /src/icons/16x16/underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/underline.png -------------------------------------------------------------------------------- /src/icons/16x16/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/undo.png -------------------------------------------------------------------------------- /src/icons/16x16/vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/16x16/vscode.png -------------------------------------------------------------------------------- /src/icons/192x192/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/192x192/app.png -------------------------------------------------------------------------------- /src/icons/192x192/appBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/192x192/appBlack.png -------------------------------------------------------------------------------- /src/icons/192x192/appDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/192x192/appDebug.png -------------------------------------------------------------------------------- /src/icons/192x192/appMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/192x192/appMono.png -------------------------------------------------------------------------------- /src/icons/192x192/appWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/192x192/appWhite.png -------------------------------------------------------------------------------- /src/icons/24x24/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/app.png -------------------------------------------------------------------------------- /src/icons/24x24/appBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/appBlack.png -------------------------------------------------------------------------------- /src/icons/24x24/appDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/appDebug.png -------------------------------------------------------------------------------- /src/icons/24x24/appMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/appMono.png -------------------------------------------------------------------------------- /src/icons/24x24/appWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/appWhite.png -------------------------------------------------------------------------------- /src/icons/24x24/bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/bold.png -------------------------------------------------------------------------------- /src/icons/24x24/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/copy.png -------------------------------------------------------------------------------- /src/icons/24x24/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/cut.png -------------------------------------------------------------------------------- /src/icons/24x24/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/delete.png -------------------------------------------------------------------------------- /src/icons/24x24/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/file.png -------------------------------------------------------------------------------- /src/icons/24x24/find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/find.png -------------------------------------------------------------------------------- /src/icons/24x24/findNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/findNext.png -------------------------------------------------------------------------------- /src/icons/24x24/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/folder.png -------------------------------------------------------------------------------- /src/icons/24x24/goto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/goto.png -------------------------------------------------------------------------------- /src/icons/24x24/italic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/italic.png -------------------------------------------------------------------------------- /src/icons/24x24/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/new.png -------------------------------------------------------------------------------- /src/icons/24x24/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/paste.png -------------------------------------------------------------------------------- /src/icons/24x24/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/print.png -------------------------------------------------------------------------------- /src/icons/24x24/printPdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/printPdf.png -------------------------------------------------------------------------------- /src/icons/24x24/printPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/printPreview.png -------------------------------------------------------------------------------- /src/icons/24x24/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/redo.png -------------------------------------------------------------------------------- /src/icons/24x24/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/rename.png -------------------------------------------------------------------------------- /src/icons/24x24/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/save.png -------------------------------------------------------------------------------- /src/icons/24x24/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/settings.png -------------------------------------------------------------------------------- /src/icons/24x24/settingsWithUpgrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/settingsWithUpgrade.png -------------------------------------------------------------------------------- /src/icons/24x24/strikethrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/strikethrough.png -------------------------------------------------------------------------------- /src/icons/24x24/underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/underline.png -------------------------------------------------------------------------------- /src/icons/24x24/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/undo.png -------------------------------------------------------------------------------- /src/icons/24x24/vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/24x24/vscode.png -------------------------------------------------------------------------------- /src/icons/256x256/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/256x256/app.png -------------------------------------------------------------------------------- /src/icons/256x256/appBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/256x256/appBlack.png -------------------------------------------------------------------------------- /src/icons/256x256/appDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/256x256/appDebug.png -------------------------------------------------------------------------------- /src/icons/256x256/appMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/256x256/appMono.png -------------------------------------------------------------------------------- /src/icons/256x256/appWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/256x256/appWhite.png -------------------------------------------------------------------------------- /src/icons/32x32/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/app.png -------------------------------------------------------------------------------- /src/icons/32x32/appBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/appBlack.png -------------------------------------------------------------------------------- /src/icons/32x32/appDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/appDebug.png -------------------------------------------------------------------------------- /src/icons/32x32/appMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/appMono.png -------------------------------------------------------------------------------- /src/icons/32x32/appWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/appWhite.png -------------------------------------------------------------------------------- /src/icons/32x32/bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/bold.png -------------------------------------------------------------------------------- /src/icons/32x32/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/copy.png -------------------------------------------------------------------------------- /src/icons/32x32/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/cut.png -------------------------------------------------------------------------------- /src/icons/32x32/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/delete.png -------------------------------------------------------------------------------- /src/icons/32x32/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/file.png -------------------------------------------------------------------------------- /src/icons/32x32/find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/find.png -------------------------------------------------------------------------------- /src/icons/32x32/findNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/findNext.png -------------------------------------------------------------------------------- /src/icons/32x32/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/folder.png -------------------------------------------------------------------------------- /src/icons/32x32/goto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/goto.png -------------------------------------------------------------------------------- /src/icons/32x32/italic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/italic.png -------------------------------------------------------------------------------- /src/icons/32x32/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/new.png -------------------------------------------------------------------------------- /src/icons/32x32/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/paste.png -------------------------------------------------------------------------------- /src/icons/32x32/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/print.png -------------------------------------------------------------------------------- /src/icons/32x32/printPdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/printPdf.png -------------------------------------------------------------------------------- /src/icons/32x32/printPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/printPreview.png -------------------------------------------------------------------------------- /src/icons/32x32/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/redo.png -------------------------------------------------------------------------------- /src/icons/32x32/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/rename.png -------------------------------------------------------------------------------- /src/icons/32x32/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/save.png -------------------------------------------------------------------------------- /src/icons/32x32/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/settings.png -------------------------------------------------------------------------------- /src/icons/32x32/settingsWithUpgrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/settingsWithUpgrade.png -------------------------------------------------------------------------------- /src/icons/32x32/strikethrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/strikethrough.png -------------------------------------------------------------------------------- /src/icons/32x32/underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/underline.png -------------------------------------------------------------------------------- /src/icons/32x32/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/undo.png -------------------------------------------------------------------------------- /src/icons/32x32/vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/32x32/vscode.png -------------------------------------------------------------------------------- /src/icons/48x48/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/app.png -------------------------------------------------------------------------------- /src/icons/48x48/appBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/appBlack.png -------------------------------------------------------------------------------- /src/icons/48x48/appDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/appDebug.png -------------------------------------------------------------------------------- /src/icons/48x48/appMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/appMono.png -------------------------------------------------------------------------------- /src/icons/48x48/appWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/appWhite.png -------------------------------------------------------------------------------- /src/icons/48x48/bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/bold.png -------------------------------------------------------------------------------- /src/icons/48x48/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/copy.png -------------------------------------------------------------------------------- /src/icons/48x48/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/cut.png -------------------------------------------------------------------------------- /src/icons/48x48/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/delete.png -------------------------------------------------------------------------------- /src/icons/48x48/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/file.png -------------------------------------------------------------------------------- /src/icons/48x48/find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/find.png -------------------------------------------------------------------------------- /src/icons/48x48/findNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/findNext.png -------------------------------------------------------------------------------- /src/icons/48x48/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/folder.png -------------------------------------------------------------------------------- /src/icons/48x48/goto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/goto.png -------------------------------------------------------------------------------- /src/icons/48x48/italic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/italic.png -------------------------------------------------------------------------------- /src/icons/48x48/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/new.png -------------------------------------------------------------------------------- /src/icons/48x48/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/paste.png -------------------------------------------------------------------------------- /src/icons/48x48/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/print.png -------------------------------------------------------------------------------- /src/icons/48x48/printPdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/printPdf.png -------------------------------------------------------------------------------- /src/icons/48x48/printPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/printPreview.png -------------------------------------------------------------------------------- /src/icons/48x48/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/redo.png -------------------------------------------------------------------------------- /src/icons/48x48/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/rename.png -------------------------------------------------------------------------------- /src/icons/48x48/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/save.png -------------------------------------------------------------------------------- /src/icons/48x48/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/settings.png -------------------------------------------------------------------------------- /src/icons/48x48/settingsWithUpgrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/settingsWithUpgrade.png -------------------------------------------------------------------------------- /src/icons/48x48/strikethrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/strikethrough.png -------------------------------------------------------------------------------- /src/icons/48x48/underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/underline.png -------------------------------------------------------------------------------- /src/icons/48x48/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/undo.png -------------------------------------------------------------------------------- /src/icons/48x48/vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/48x48/vscode.png -------------------------------------------------------------------------------- /src/icons/64x64/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/app.png -------------------------------------------------------------------------------- /src/icons/64x64/appBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/appBlack.png -------------------------------------------------------------------------------- /src/icons/64x64/appDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/appDebug.png -------------------------------------------------------------------------------- /src/icons/64x64/appMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/appMono.png -------------------------------------------------------------------------------- /src/icons/64x64/appWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/appWhite.png -------------------------------------------------------------------------------- /src/icons/64x64/bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/bold.png -------------------------------------------------------------------------------- /src/icons/64x64/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/copy.png -------------------------------------------------------------------------------- /src/icons/64x64/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/cut.png -------------------------------------------------------------------------------- /src/icons/64x64/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/delete.png -------------------------------------------------------------------------------- /src/icons/64x64/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/file.png -------------------------------------------------------------------------------- /src/icons/64x64/find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/find.png -------------------------------------------------------------------------------- /src/icons/64x64/findNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/findNext.png -------------------------------------------------------------------------------- /src/icons/64x64/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/folder.png -------------------------------------------------------------------------------- /src/icons/64x64/goto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/goto.png -------------------------------------------------------------------------------- /src/icons/64x64/italic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/italic.png -------------------------------------------------------------------------------- /src/icons/64x64/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/new.png -------------------------------------------------------------------------------- /src/icons/64x64/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/paste.png -------------------------------------------------------------------------------- /src/icons/64x64/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/print.png -------------------------------------------------------------------------------- /src/icons/64x64/printPdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/printPdf.png -------------------------------------------------------------------------------- /src/icons/64x64/printPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/printPreview.png -------------------------------------------------------------------------------- /src/icons/64x64/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/redo.png -------------------------------------------------------------------------------- /src/icons/64x64/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/rename.png -------------------------------------------------------------------------------- /src/icons/64x64/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/save.png -------------------------------------------------------------------------------- /src/icons/64x64/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/settings.png -------------------------------------------------------------------------------- /src/icons/64x64/settingsWithUpgrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/settingsWithUpgrade.png -------------------------------------------------------------------------------- /src/icons/64x64/strikethrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/strikethrough.png -------------------------------------------------------------------------------- /src/icons/64x64/underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/underline.png -------------------------------------------------------------------------------- /src/icons/64x64/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/undo.png -------------------------------------------------------------------------------- /src/icons/64x64/vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/64x64/vscode.png -------------------------------------------------------------------------------- /src/icons/96x96/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/96x96/app.png -------------------------------------------------------------------------------- /src/icons/96x96/appBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/96x96/appBlack.png -------------------------------------------------------------------------------- /src/icons/96x96/appDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/96x96/appDebug.png -------------------------------------------------------------------------------- /src/icons/96x96/appMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/96x96/appMono.png -------------------------------------------------------------------------------- /src/icons/96x96/appWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/96x96/appWhite.png -------------------------------------------------------------------------------- /src/icons/app.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/icons/app.ico -------------------------------------------------------------------------------- /src/medo/about.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "about.h" 4 | 5 | void About::showDialog(QWidget* parent) { 6 | QString description = QCoreApplication::applicationName(); 7 | description.append(" "); 8 | #ifdef APP_VERSION 9 | description.append(APP_VERSION); 10 | #else 11 | description.append(QCoreApplication::applicationVersion()); 12 | #endif 13 | 14 | #ifdef APP_COMMIT 15 | QString commit = APP_COMMIT; 16 | if (commit.length() > 0) { 17 | description.append("+"); 18 | description.append(APP_COMMIT); 19 | } 20 | #endif 21 | 22 | #ifdef QT_DEBUG 23 | description.append("\nDEBUG"); 24 | #endif 25 | 26 | description.append("\n\nQt "); 27 | 28 | QString runtimeVersion = qVersion(); 29 | QString compileVersion = APP_QT_VERSION; 30 | description.append(runtimeVersion); 31 | if (runtimeVersion != compileVersion) { 32 | description.append(" / "); 33 | description.append(compileVersion); 34 | } 35 | description.append("\n" + QSysInfo::prettyProductName()); 36 | description.append("\n" + QSysInfo::kernelType() + " " + QSysInfo::kernelVersion()); 37 | 38 | #ifdef APP_COPYRIGHT 39 | description.append("\n\n"); 40 | description.append(APP_COPYRIGHT); 41 | #endif 42 | 43 | QMessageBox::about(parent, "About", description); 44 | } 45 | -------------------------------------------------------------------------------- /src/medo/about.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | // 2020-01-03: Initial version 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace Medo { class About; } 10 | 11 | class About { 12 | 13 | public: 14 | static void showDialog(QWidget* parent = nullptr); 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /src/medo/appsetupmutex.cpp: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | #include 4 | #include "appsetupmutex.h" 5 | 6 | const int mutexNameLength = 4096; 7 | 8 | AppSetupMutex::AppSetupMutex(const QString& mutexName) { 9 | #if defined(Q_OS_WIN) 10 | wchar_t mutexNameChars[mutexNameLength]; //assume 4K is enough 11 | int len = mutexName.toWCharArray(mutexNameChars); 12 | assert(len + 1 < mutexNameLength); 13 | mutexNameChars[len] = '\0'; 14 | _mutexHandle = CreateMutex(NULL, false, mutexNameChars); 15 | if (_mutexHandle != nullptr) { 16 | qDebug().noquote() << "[AppSetupMutex]" << mutexName << "created as" << _mutexHandle; 17 | } else { 18 | qDebug().noquote() << "[AppSetupMutex]" << mutexName << "could not be created"; 19 | } 20 | #else 21 | Q_UNUSED(mutexName) 22 | #endif 23 | } 24 | 25 | AppSetupMutex::~AppSetupMutex() { 26 | #if defined(Q_OS_WIN) 27 | CloseHandle(_mutexHandle); 28 | qDebug().noquote() << "[AppSetupMutex]" << _mutexHandle << "closed"; 29 | #endif 30 | } 31 | -------------------------------------------------------------------------------- /src/medo/appsetupmutex.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | // 2020-06-09: Initial version 4 | 5 | #pragma once 6 | 7 | #include 8 | #if defined(Q_OS_WIN) 9 | #include "windows.h" 10 | #endif 11 | 12 | namespace Medo { class AppSetupMutex; } 13 | 14 | /* Intended for use with InnoSetup - make sense for Windows only */ 15 | class AppSetupMutex { 16 | 17 | public: 18 | AppSetupMutex(const QString& mutexName); 19 | ~AppSetupMutex(); 20 | 21 | private: 22 | #if defined(Q_OS_WIN) 23 | HANDLE _mutexHandle; 24 | #endif 25 | 26 | }; 27 | -------------------------------------------------------------------------------- /src/medo/dconfHotkey.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | // 2022-03-05: Initial version 3 | 4 | #pragma once 5 | #include 6 | #include 7 | 8 | namespace Medo { class DConfHotkey; } 9 | 10 | class DConfHotkey : public QObject { 11 | Q_OBJECT 12 | 13 | public: 14 | 15 | /*! Creates a new instance */ 16 | explicit DConfHotkey(QString name, QObject* parent = nullptr); 17 | 18 | /*! Registers hotkey. 19 | * \param key Hotkey. Cannot have more than one key combination. */ 20 | bool registerHotkey(QKeySequence key); 21 | 22 | /*! Disables currently registered hotkey. */ 23 | bool unregisterHotkey(); 24 | 25 | /*! Has registered hotkey. */ 26 | bool hasRegisteredHotkey(); 27 | 28 | 29 | private: 30 | QString _name; 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /src/medo/feedback.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | // 2020-06-09: Improving server responses 3 | // 2020-06-07: Handling server errors 4 | // 2020-06-05: Initial version 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | namespace Medo { class Feedback; } 12 | 13 | class Feedback { 14 | 15 | public: 16 | /*! Shows feedback dialog. */ 17 | static bool showDialog(QWidget* parent, QUrl url); 18 | 19 | private: 20 | static bool sendFeedback(QString text, QString senderEmail, QString senderDisplayName, QUrl url); 21 | static QString _errorMessage; 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /src/medo/hotkey.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | // 2020-06-06: Added support for suspend and resume 3 | // 2019-10-04: Reorganizing includes to minimize conflicts 4 | // 2019-09-16: Allowing Meta/Win key as a hotkey modifier 5 | // 2019-07-05: Initial version 6 | 7 | #pragma once 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace Medo { class Hotkey; } 14 | 15 | class Hotkey : public QObject, QAbstractNativeEventFilter { 16 | Q_OBJECT 17 | 18 | public: 19 | 20 | /*! Creates a new instance */ 21 | explicit Hotkey(QObject* parent = nullptr); 22 | 23 | /*! Destroys the instance */ 24 | ~Hotkey() override; 25 | 26 | /*! Registers hotkey. 27 | * \param key Hotkey. Cannot have more than one key combination. */ 28 | bool registerHotkey(QKeySequence key); 29 | 30 | /*! Disables currently registered hotkey. */ 31 | bool unregisterHotkey(); 32 | 33 | /*! Temporarily suspends hotkey capturing. Not thread-safe. */ 34 | void suspend(); 35 | 36 | /*! Resumes previously suspended capturing. Not thread-safe. */ 37 | void resume(); 38 | 39 | 40 | signals: 41 | 42 | /*! Signals hotkey has been activated */ 43 | void activated(); 44 | 45 | 46 | protected: 47 | bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override; 48 | 49 | private: 50 | bool _isRegistered = false; 51 | int suspensionLevel = 0; 52 | QKeySequence _key; 53 | void nativeInit(); 54 | bool nativeRegisterHotkey(Qt::Key key, Qt::KeyboardModifiers modifiers); 55 | bool nativeUnregisterHotkey(); 56 | 57 | #if defined(Q_OS_WIN) 58 | static std::atomic _globalHotkeyCounter; //actually WPARAM; just 64-bit integer here to avoid include of windows.h 59 | uint64_t _hotkeyId = 0; //0x0000 through 0xBFFF 60 | #elif defined(Q_OS_LINUX) 61 | uint16_t _hotkeyMods; 62 | uint8_t _hotkeyKey; //actually xcb_keycode_t; just 64-bit integer here to avoid include of X11 headers 63 | #endif 64 | 65 | }; 66 | -------------------------------------------------------------------------------- /src/medo/lifetimewatch.cpp: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | #include 4 | #include "lifetimewatch.h" 5 | 6 | 7 | LifetimeWatch::LifetimeWatch(const QString& text) 8 | : LifetimeWatch(text, false) { 9 | } 10 | 11 | LifetimeWatch::LifetimeWatch(const QString& text, bool addGuid) { 12 | #ifdef QT_DEBUG 13 | _text = text; 14 | _stopwatch = new QElapsedTimer(); 15 | _stopwatch->start(); 16 | if (addGuid) { _uuid = QUuid::createUuid(); } 17 | qDebug().noquote().nospace() << "[LifeTimeWatch] " << text 18 | << ( _uuid.isNull() ? "" : " " + _uuid.toString() ); 19 | #else 20 | Q_UNUSED(text) 21 | Q_UNUSED(addGuid) 22 | #endif 23 | } 24 | 25 | void LifetimeWatch::elapsed() { 26 | this->elapsed(""); 27 | } 28 | 29 | void LifetimeWatch::elapsed(const QString& extraText) { 30 | #ifdef QT_DEBUG 31 | _mutex.lock(); 32 | if (_stopwatch != nullptr) { 33 | qDebug().noquote().nospace() << "[LifeTimeWatch] " << _text 34 | << " elapsed at " << _stopwatch->elapsed() << "ms" 35 | << ( extraText.length() > 0 ? " (" + extraText + ")" : "" ) 36 | << ( _uuid.isNull() ? "" : " " + _uuid.toString() ); 37 | } 38 | _mutex.unlock(); 39 | #else 40 | Q_UNUSED(extraText) 41 | #endif 42 | } 43 | 44 | void LifetimeWatch::done() { 45 | #ifdef QT_DEBUG 46 | _mutex.lock(); 47 | if (_stopwatch != nullptr) { 48 | qDebug().noquote().nospace() << "[LifeTimeWatch] " << _text 49 | << " done in " << _stopwatch->elapsed() << "ms" 50 | << ( _uuid.isNull() ? "" : " " + _uuid.toString() ); 51 | delete(_stopwatch); 52 | _stopwatch = nullptr; 53 | } 54 | _mutex.unlock(); 55 | #endif 56 | } 57 | 58 | LifetimeWatch::~LifetimeWatch() { 59 | this->done(); 60 | } 61 | -------------------------------------------------------------------------------- /src/medo/lifetimewatch.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | // 2021-12-09: Initial version 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Medo { class LifetimeWatch; } 13 | 14 | class LifetimeWatch { 15 | 16 | public: 17 | LifetimeWatch(const QString& text); 18 | LifetimeWatch(const QString& text, bool addGuid); 19 | ~LifetimeWatch(); 20 | void done(); 21 | void elapsed(); 22 | void elapsed(const QString& extraText); 23 | 24 | private: 25 | QMutex _mutex; 26 | QUuid _uuid; 27 | QElapsedTimer* _stopwatch = nullptr; 28 | QString _text; 29 | 30 | }; 31 | -------------------------------------------------------------------------------- /src/medo/singleinstance.cpp: -------------------------------------------------------------------------------- 1 | #include "singleinstance.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #if defined(Q_OS_WIN) 8 | #include 9 | #endif 10 | 11 | SingleInstance SingleInstance::_instance; 12 | QMutex SingleInstance::_mutex(QMutex::NonRecursive); 13 | QLocalServer* SingleInstance::_server(nullptr); 14 | bool SingleInstance::_isFirstInstance(false); 15 | 16 | 17 | SingleInstance::SingleInstance() 18 | : QObject(nullptr) { 19 | } 20 | 21 | SingleInstance::~SingleInstance() { 22 | QMutexLocker locker(&_mutex); 23 | 24 | if (_server != nullptr) { 25 | _server->close(); 26 | delete _server; 27 | } 28 | } 29 | 30 | SingleInstance* SingleInstance::instance() { 31 | return &_instance; 32 | } 33 | 34 | 35 | bool SingleInstance::attach() { 36 | QMutexLocker locker(&_mutex); 37 | 38 | if (_server != nullptr) { return _isFirstInstance; } 39 | 40 | QString serverNameSource = QCoreApplication::applicationFilePath(); 41 | serverNameSource += QDir::home().dirName(); //instead of user name 42 | serverNameSource += QSysInfo::machineHostName(); 43 | QString serverName = QString(QCryptographicHash::hash(serverNameSource.toUtf8(), QCryptographicHash::Sha256) 44 | .toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)); 45 | qDebug().noquote() << "[SingleInstance]" << "Local server name is" << serverName; 46 | 47 | bool hasAlreadyConnected = false; 48 | _server = new QLocalServer(); 49 | bool serverListening = _server->listen(serverName); 50 | if (!serverListening && (_server->serverError() == QAbstractSocket::AddressInUseError)) { 51 | QLocalSocket* client = new QLocalSocket(); 52 | client->connectToServer(serverName); 53 | if (client->waitForConnected(250)) { 54 | qDebug().noquote() << "[SingleInstance]" << "Another instance is already running"; 55 | hasAlreadyConnected = true; 56 | } else { //no answer - assume cleanup is needed 57 | QLocalServer::removeServer(serverName); 58 | serverListening = _server->listen(serverName); 59 | } 60 | delete client; 61 | } 62 | 63 | bool isFirstInstance = false; 64 | if (serverListening) { //only the first instance can listen (on Linux) 65 | isFirstInstance = true; 66 | connect(_server, &QLocalServer::newConnection, SingleInstance::instance(), &SingleInstance::onNewConnection); 67 | 68 | #if defined(Q_OS_WIN) //check if there is a server running - needed on Windows as two local servers can run there 69 | CreateMutexW(nullptr, true, reinterpret_cast(serverName.utf16())); 70 | if (GetLastError() == ERROR_ALREADY_EXISTS) { //someone has this Mutex 71 | _server->close(); //disable server 72 | isFirstInstance = false; 73 | } 74 | #endif 75 | } 76 | 77 | if (!isFirstInstance && !hasAlreadyConnected) { //contact main instance if we're not the one 78 | qDebug().noquote() << "[SingleInstance]" << "Another instance is already running"; 79 | QLocalSocket* client = new QLocalSocket(); 80 | client->connectToServer(serverName); 81 | delete client; 82 | } 83 | 84 | _isFirstInstance = isFirstInstance; 85 | return _isFirstInstance; 86 | } 87 | 88 | bool SingleInstance::isOtherInstanceRunning() { 89 | QMutexLocker locker(&_mutex); 90 | return !_isFirstInstance; 91 | } 92 | 93 | 94 | void SingleInstance::onNewConnection() { 95 | QLocalSocket* client = _server->nextPendingConnection(); 96 | connect(client, &QLocalSocket::disconnected, client, &QLocalSocket::deleteLater); 97 | delete client; 98 | qDebug().noquote() << "[SingleInstance]" << "New instance detected"; 99 | emit newInstanceDetected(); 100 | } 101 | -------------------------------------------------------------------------------- /src/medo/singleinstance.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | // 2020-05-07: Changed signal/slot call 4 | // 2019-07-06: Initial version 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Medo { class SingleInstance; } 13 | 14 | class SingleInstance : public QObject { 15 | Q_OBJECT 16 | 17 | public: 18 | 19 | /*! Returns singleton instance. */ 20 | static SingleInstance* instance(); 21 | 22 | /*! Returns true if current application is the first instance. */ 23 | static bool attach(); 24 | 25 | /*! Returns true if there is another instance running. */ 26 | static bool isOtherInstanceRunning(); 27 | 28 | signals: 29 | 30 | /*! Signals that a new instance attempted attach operation. */ 31 | void newInstanceDetected(); 32 | 33 | 34 | private: 35 | explicit SingleInstance(); 36 | ~SingleInstance() override; 37 | SingleInstance(const SingleInstance&) = delete; 38 | SingleInstance& operator=(const SingleInstance&) = delete; 39 | static SingleInstance _instance; 40 | static QMutex _mutex; 41 | static QLocalServer* _server; 42 | static bool _isFirstInstance; 43 | 44 | private slots: 45 | void onNewConnection(); 46 | 47 | }; 48 | -------------------------------------------------------------------------------- /src/medo/state.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "state.h" 6 | 7 | State State::_instance; 8 | 9 | State::State() 10 | : QObject(nullptr) { 11 | } 12 | 13 | State::~State() { 14 | } 15 | 16 | State* State::instance() { 17 | return &_instance; 18 | } 19 | 20 | 21 | void State::load(QMainWindow* window) { 22 | load(QString(), window); 23 | } 24 | 25 | void State::load(QString objectName, QMainWindow* window) { 26 | if (window == nullptr) { return; } 27 | if (objectName.isNull()) { objectName = window->objectName(); } 28 | #ifdef QT_DEBUG 29 | qDebug().noquote().nospace() << "[State] load(" << objectName << ", window)"; 30 | #endif 31 | instance()->loadEx(objectName, window); 32 | } 33 | 34 | void State::save(QMainWindow* window) { 35 | save(QString(), window); 36 | } 37 | 38 | void State::save(QString objectName, QMainWindow* window) { 39 | if (window == nullptr) { return; } 40 | if (objectName.isNull()) { objectName = window->objectName(); } 41 | #ifdef QT_DEBUG 42 | qDebug().noquote().nospace() << "[State] save(" << objectName << ", window)"; 43 | #endif 44 | instance()->saveEx(objectName, window); 45 | } 46 | 47 | 48 | void State::loadEx(QString objectName, QMainWindow* window) { 49 | QString value = emit readFromConfig(objectName); 50 | QStringList parts = value.split(' '); 51 | if (parts.length() == 2) { 52 | QByteArray geometry = QByteArray::fromBase64(parts[0].toUtf8()); 53 | QByteArray state = QByteArray::fromBase64(parts[1].toUtf8()); 54 | window->restoreGeometry(geometry); 55 | window->restoreState(state); 56 | } 57 | } 58 | 59 | void State::saveEx(QString objectName, QMainWindow* window) { 60 | QString geometry = window->saveGeometry().toBase64(); 61 | QString state = window->saveState().toBase64(); 62 | emit writeToConfig(objectName, geometry + " " + state); 63 | } 64 | 65 | 66 | void State::load(QWidget* widget) { 67 | load(QString(), widget); 68 | } 69 | 70 | void State::load(QString objectName, QWidget* widget) { 71 | if (widget == nullptr) { return; } 72 | if (objectName.isNull()) { objectName = widget->objectName(); } 73 | #ifdef QT_DEBUG 74 | qDebug().noquote().nospace() << "[State] load(" << objectName << ", widget)"; 75 | #endif 76 | instance()->loadEx(objectName, widget); 77 | 78 | QWidget* parent = widget->parentWidget(); 79 | if (parent != nullptr) { 80 | QScreen* screen = nullptr; 81 | QWindow* widgetHandle = widget->windowHandle(); 82 | if (widgetHandle != nullptr) { screen = widgetHandle->screen(); } 83 | if (screen == nullptr) { 84 | QWindow* parentHandle = parent->windowHandle(); 85 | if (parentHandle != nullptr) { screen = parentHandle->screen(); } 86 | } 87 | if (screen == nullptr) { screen = QGuiApplication::screenAt(widget->pos()); } 88 | if (screen == nullptr) { screen = QGuiApplication::primaryScreen(); } 89 | 90 | int minX = screen->availableGeometry().x(); 91 | int minY = screen->availableGeometry().y(); 92 | int maxW = screen->availableGeometry().width(); 93 | int maxH = screen->availableGeometry().height(); 94 | 95 | int newX = parent->x() + (parent->width() - widget->width()) / 2; 96 | int newY = parent->y() + (parent->height() - widget->height()) / 2 + QApplication::startDragDistance() * 2; //frame geometry doesn't really work on X11 so drag distance is workaround 97 | int newW = widget->width(); 98 | int newH = widget->height(); 99 | if (newX < minX) { newX = minX; } 100 | if (newY < minY) { newY = minY; } 101 | if (newX + newW > maxW) { newW = maxW - newX; } 102 | if (newY + newH > maxH) { newH = maxH - newY; } 103 | 104 | widget->setGeometry(newX, newY, newW, newH); 105 | } 106 | } 107 | 108 | void State::save(QWidget* widget) { 109 | save(QString(), widget); 110 | } 111 | 112 | void State::save(QString objectName, QWidget* widget) { 113 | if (widget == nullptr) { return; } 114 | if (objectName.isNull()) { objectName = widget->objectName(); } 115 | #ifdef QT_DEBUG 116 | qDebug().noquote().nospace() << "[State] save(" << objectName << ", widget)"; 117 | #endif 118 | instance()->saveEx(objectName, widget); 119 | } 120 | 121 | 122 | void State::loadEx(QString objectName, QWidget* widget) { 123 | QString value = emit readFromConfig(objectName); 124 | QByteArray geometry = QByteArray::fromBase64(value.toUtf8()); 125 | widget->restoreGeometry(geometry); 126 | } 127 | 128 | void State::saveEx(QString objectName, QWidget* widget) { 129 | QString geometry = widget->saveGeometry().toBase64(); 130 | emit writeToConfig(objectName, geometry); 131 | } 132 | -------------------------------------------------------------------------------- /src/medo/state.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | // 2019-07-15: Initial version 4 | // 2020-01-01: Added widget methods 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace Medo { class State; } 14 | 15 | class State : public QObject { 16 | Q_OBJECT 17 | 18 | public: 19 | 20 | /*! Returns singleton instance. */ 21 | static State* instance(); 22 | 23 | 24 | /*! Loads window state if one exists. 25 | * \param window Window. */ 26 | static void load(QMainWindow* window); 27 | 28 | /*! Loads window state if one exists. 29 | * \param objectName Object name. 30 | * \param window Window. */ 31 | static void load(QString objectName, QMainWindow* window); 32 | 33 | /*! Saves window state. 34 | * \param window Window. */ 35 | static void save(QMainWindow* window); 36 | 37 | /*! Saves window state. 38 | * \param objectName Object name. 39 | * \param window Window. */ 40 | static void save(QString objectName, QMainWindow* window); 41 | 42 | 43 | /*! Loads widget state if one exists. 44 | * \param widget Widget. */ 45 | static void load(QWidget* widget); 46 | 47 | /*! Loads widget state if one exists. 48 | * \param objectName Object name. 49 | * \param widget Widget. */ 50 | static void load(QString objectName, QWidget* widget); 51 | 52 | /*! Saves widget state. 53 | * \param widget Widget. */ 54 | static void save(QWidget* widget); 55 | 56 | /*! Saves widget state. 57 | * \param objectName Object name. 58 | * \param widget Widget. */ 59 | static void save(QString objectName, QWidget* widget); 60 | 61 | 62 | signals: 63 | 64 | /*! Signals a read from config is needed. If key cannot be found, null QString() should be returned. */ 65 | QString readFromConfig(QString key); 66 | 67 | /*! Signals a write to config */ 68 | void writeToConfig(QString key, QString value); 69 | 70 | 71 | private: 72 | explicit State(); 73 | ~State() override; 74 | State(const State&) = delete; 75 | State& operator=(const State&) = delete; 76 | static State _instance; 77 | 78 | private: 79 | void loadEx(QString objectName, QMainWindow* window); 80 | void saveEx(QString objectName, QMainWindow* window); 81 | void loadEx(QString objectName, QWidget* widget); 82 | void saveEx(QString objectName, QWidget* widget); 83 | 84 | }; 85 | -------------------------------------------------------------------------------- /src/medo/upgrade.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | // 2021-12-13: Updated HTTP status code for upgrade 4 | // 2021-12-12: Fixed TLS 1.3 connection 5 | // 2020-10-23: Initial version 6 | 7 | #pragma once 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace Medo { 16 | class Upgrade; 17 | class UpgradeFile; 18 | } 19 | 20 | class UpgradeFile; 21 | 22 | class Upgrade { 23 | 24 | public: 25 | /*! Shows upgrade dialog. Returns true if upgrade has started. */ 26 | static bool showDialog(QWidget* parent, QUrl serviceUrl); 27 | 28 | /*! Shows upgrade dialog. Returns true if upgrade has started. */ 29 | static bool showDialog(QWidget* parent, QString serviceUrl); 30 | 31 | /*! Returns upgrade file. */ 32 | static UpgradeFile upgradeFile(QUrl serviceUrl); 33 | 34 | /*! Returns upgrade file. */ 35 | static UpgradeFile upgradeFile(QString serviceUrl); 36 | 37 | /*! Returns true if upgrade is available. */ 38 | static bool available(QUrl url); 39 | 40 | /*! Returns true if upgrade is available. */ 41 | static bool available(QString url); 42 | 43 | private: 44 | static UpgradeFile getUpgradeFileFromURL(QElapsedTimer* stopwatch, QUrl url); 45 | static QString processUrl(QUrl url, int* statusCode); 46 | 47 | }; 48 | 49 | class UpgradeFile { 50 | friend class Upgrade; 51 | 52 | public: 53 | /*! Returns true if upgrade is available. */ 54 | bool available(); 55 | 56 | /*! Gets URL for upgrade file. Empty if no upgrade file is found. */ 57 | QUrl fileUrl(); 58 | 59 | /*! Gets upgrade file name. Empty if no upgrade file is found. */ 60 | QString fileName(); 61 | 62 | /*! Returns suggested file name in temporary directory. */ 63 | QString suggestedLocalFileName(); 64 | 65 | /*! Downloads full file and returns true if successful. */ 66 | bool downloadFile(QString fileName, int timeout = 30000, QProgressBar* progressBar = nullptr); 67 | 68 | private: 69 | explicit UpgradeFile(); 70 | explicit UpgradeFile(QUrl fileUrl); 71 | QUrl _downloadUrl; 72 | 73 | }; 74 | -------------------------------------------------------------------------------- /src/medo/winHotkey.cpp: -------------------------------------------------------------------------------- 1 | #include "winHotkey.h" 2 | #include 3 | #include 4 | #include 5 | 6 | WinHotkey::WinHotkey(QObject* parent) 7 | : QObject(parent) { 8 | 9 | nativeInit(); 10 | qApp->installNativeEventFilter(this); 11 | } 12 | 13 | WinHotkey::~WinHotkey() { 14 | if (_isRegistered) { unregisterHotkey(); } 15 | qApp->removeNativeEventFilter(this); 16 | } 17 | 18 | 19 | bool WinHotkey::registerHotkey(QKeySequence key) { 20 | if (_isRegistered) { 21 | qDebug().noquote() << "[WinHotkey]" << "Hotkey already registered!"; 22 | return false; 23 | } 24 | 25 | if (key.count() != 1) { 26 | qDebug().noquote() << "[WinHotkey]" << "Must have only one key combination!"; 27 | return false; 28 | } 29 | 30 | auto keyboardKey = Qt::Key(key[0] & static_cast(~Qt::KeyboardModifierMask)); 31 | auto keyboardModifiers = Qt::KeyboardModifiers(key[0] & static_cast(Qt::KeyboardModifierMask)); 32 | 33 | bool successful = nativeRegisterHotkey(keyboardKey, keyboardModifiers); 34 | if (successful) { 35 | _key = key; 36 | _isRegistered = true; 37 | } else { 38 | qDebug().noquote().nospace() << "[WinHotkey] Failed to register hotkey " << key.toString(QKeySequence::PortableText) << "!"; 39 | } 40 | return successful; 41 | } 42 | 43 | bool WinHotkey::unregisterHotkey() { 44 | if (!_isRegistered) { 45 | qDebug().noquote() << "[WinHotkey]" << "Hotkey not registered!"; 46 | return false; 47 | } 48 | 49 | bool successful = nativeUnregisterHotkey(); 50 | if (successful) { 51 | _isRegistered = false; 52 | } else { 53 | qDebug().noquote() << "[WinHotkey]" << "Failed to deregister hotkey" << _key.toString(QKeySequence::PortableText) << "!"; 54 | } 55 | return successful; 56 | } 57 | 58 | void WinHotkey::suspend() { 59 | ++suspensionLevel; 60 | } 61 | 62 | void WinHotkey::resume() { 63 | --suspensionLevel; 64 | } 65 | 66 | 67 | std::atomic WinHotkey::_globalHotkeyCounter(0); 68 | 69 | void WinHotkey::nativeInit() { 70 | _hotkeyId = reinterpret_cast(_globalHotkeyCounter++); 71 | } 72 | 73 | bool WinHotkey::nativeRegisterHotkey(Qt::Key key, Qt::KeyboardModifiers modifiers) { 74 | if (_hotkeyId > 0xBFFF) { 75 | qDebug().noquote() << "[WinHotkey]" << "No more Hotkey IDs!"; //cannot be bothered to track IDs as this is unlikely 76 | return false; 77 | } 78 | 79 | uint modValue = 0; 80 | if (modifiers & Qt::AltModifier) { modValue += MOD_ALT; } 81 | if (modifiers & Qt::ControlModifier) { modValue += MOD_CONTROL; } 82 | if (modifiers & Qt::ShiftModifier) { modValue += MOD_SHIFT; } 83 | if (modifiers & Qt::MetaModifier) { modValue += MOD_WIN; } 84 | 85 | if (modifiers & ~(Qt::AltModifier | Qt::ControlModifier | Qt::ShiftModifier | Qt::MetaModifier)) { 86 | qDebug().noquote().nospace() << "[Hotkey] " << "Unrecognized modifiers (" << modifiers << ")!"; 87 | return false; 88 | } 89 | 90 | uint keyValue; 91 | if (((key >= Qt::Key_A) && (key <= Qt::Key_Z)) || ((key >= Qt::Key_0) && (key <= Qt::Key_9))) { 92 | keyValue = key; 93 | } else if ((key >= Qt::Key_F1) && (key <= Qt::Key_F24)) { 94 | keyValue = VK_F1 + (key - Qt::Key_F1); 95 | } else { 96 | qDebug().noquote().nospace() << "[WinHotkey] " << "Unrecognized key (" << key << ")!"; 97 | return false; 98 | } 99 | 100 | return RegisterHotKey(nullptr, static_cast(_hotkeyId), modValue, keyValue); 101 | } 102 | 103 | bool WinHotkey::nativeUnregisterHotkey() { 104 | return UnregisterHotKey(nullptr, static_cast(_hotkeyId)); 105 | } 106 | 107 | 108 | bool WinHotkey::nativeEventFilter(const QByteArray&, void* message, long*) { 109 | MSG* msg = static_cast(message); 110 | if (msg->message == WM_HOTKEY) { 111 | if (msg->wParam == static_cast(_hotkeyId)) { 112 | if (suspensionLevel <= 0) { 113 | qDebug().noquote() << "[WinHotkey]" << "Hotkey" << _key.toString(QKeySequence::PortableText) << "detected"; 114 | emit activated(); 115 | return true; 116 | } else { 117 | qDebug().noquote() << "[WinHotkey]" << "Hotkey" << _key.toString(QKeySequence::PortableText) << "ignored"; 118 | return false; 119 | } 120 | } 121 | } 122 | return false; 123 | } 124 | -------------------------------------------------------------------------------- /src/medo/winHotkey.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | // 2023-05-28: Split into separate files for Dconf/XCB/Wind 3 | // 2020-06-06: Added support for suspend and resume 4 | // 2019-10-04: Reorganizing includes to minimize conflicts 5 | // 2019-09-16: Allowing Meta/Win key as a hotkey modifier 6 | // 2019-07-05: Initial version 7 | 8 | #pragma once 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace Medo { class WinHotkey; } 15 | 16 | class WinHotkey : public QObject, QAbstractNativeEventFilter { 17 | Q_OBJECT 18 | 19 | public: 20 | 21 | /*! Creates a new instance */ 22 | explicit WinHotkey(QObject* parent = nullptr); 23 | 24 | /*! Destroys the instance */ 25 | ~WinHotkey(); 26 | 27 | /*! Registers hotkey. 28 | * \param key Hotkey. Cannot have more than one key combination. */ 29 | bool registerHotkey(QKeySequence key); 30 | 31 | /*! Disables currently registered hotkey. */ 32 | bool unregisterHotkey(); 33 | 34 | /*! Temporarily suspends hotkey capturing. Not thread-safe. */ 35 | void suspend(); 36 | 37 | /*! Resumes previously suspended capturing. Not thread-safe. */ 38 | void resume(); 39 | 40 | 41 | signals: 42 | 43 | /*! Signals hotkey has been activated */ 44 | void activated(); 45 | 46 | 47 | protected: 48 | bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override; 49 | 50 | private: 51 | bool _isRegistered = false; 52 | int suspensionLevel = 0; 53 | QKeySequence _key; 54 | void nativeInit(); 55 | bool nativeRegisterHotkey(Qt::Key key, Qt::KeyboardModifiers modifiers); 56 | bool nativeUnregisterHotkey(); 57 | 58 | static std::atomic _globalHotkeyCounter; //actually WPARAM; just 64-bit integer here to avoid include of windows.h 59 | uint64_t _hotkeyId = 0; //0x0000 through 0xBFFF 60 | 61 | }; 62 | -------------------------------------------------------------------------------- /src/medo/xcbHotkey.h: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | // 2023-05-28: Split into separate files for Dconf/XCB/Wind 3 | // 2020-06-06: Added support for suspend and resume 4 | // 2019-10-04: Reorganizing includes to minimize conflicts 5 | // 2019-09-16: Allowing Meta/Win key as a hotkey modifier 6 | // 2019-07-05: Initial version 7 | 8 | #pragma once 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace Medo { class Medo; } 15 | 16 | class XcbHotkey : public QObject, QAbstractNativeEventFilter { 17 | Q_OBJECT 18 | 19 | public: 20 | 21 | /*! Creates a new instance */ 22 | explicit XcbHotkey(QObject* parent = nullptr); 23 | 24 | /*! Destroys the instance */ 25 | ~XcbHotkey(); 26 | 27 | /*! Registers hotkey. 28 | * \param key Hotkey. Cannot have more than one key combination. */ 29 | bool registerHotkey(QKeySequence key); 30 | 31 | /*! Disables currently registered hotkey. */ 32 | bool unregisterHotkey(); 33 | 34 | /*! Temporarily suspends hotkey capturing. Not thread-safe. */ 35 | void suspend(); 36 | 37 | /*! Resumes previously suspended capturing. Not thread-safe. */ 38 | void resume(); 39 | 40 | 41 | signals: 42 | 43 | /*! Signals hotkey has been activated */ 44 | void activated(); 45 | 46 | 47 | protected: 48 | bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override; 49 | 50 | private: 51 | bool _isRegistered = false; 52 | int suspensionLevel = 0; 53 | QKeySequence _key; 54 | void nativeInit(); 55 | bool nativeRegisterHotkey(Qt::Key key, Qt::KeyboardModifiers modifiers); 56 | bool nativeUnregisterHotkey(); 57 | 58 | uint16_t _hotkeyMods; 59 | uint8_t _hotkeyKey; //actually xcb_keycode_t; just 64-bit integer here to avoid include of X11 headers 60 | 61 | }; 62 | -------------------------------------------------------------------------------- /src/phoneticalphabet.cpp: -------------------------------------------------------------------------------- 1 | #include "helpers.h" 2 | #include "phoneticalphabet.h" 3 | 4 | QString PhoneticAlphabet::getNatoText(QString character) { 5 | QString chLatin = Helpers::getTextWithoutAccents(character).toUpper(); 6 | QChar ch = chLatin[0]; 7 | 8 | QString out; 9 | if (ch == 'A') { 10 | out = "Alfa"; 11 | } else if (ch == 'B') { 12 | out = "Bravo"; 13 | } else if (ch == 'C') { 14 | out = "Charlie"; 15 | } else if (ch == 'D') { 16 | out = "Delta"; 17 | } else if (ch == 'E') { 18 | out = "Echo"; 19 | } else if (ch == 'F') { 20 | out = "Foxtrot"; 21 | } else if (ch == 'G') { 22 | out = "Golf"; 23 | } else if (ch == 'H') { 24 | out = "Hotel"; 25 | } else if (ch == 'I') { 26 | out = "India"; 27 | } else if (ch == 'J') { 28 | out = "Juliett"; 29 | } else if (ch == 'K') { 30 | out = "Kilo"; 31 | } else if (ch == 'L') { 32 | out = "Lima"; 33 | } else if (ch == 'M') { 34 | out = "Mike"; 35 | } else if (ch == 'N') { 36 | out = "November"; 37 | } else if (ch == 'O') { 38 | out = "Oscar"; 39 | } else if (ch == 'P') { 40 | out = "Papa"; 41 | } else if (ch == 'Q') { 42 | out = "Quebec"; 43 | } else if (ch == 'R') { 44 | out = "Romeo"; 45 | } else if (ch == 'S') { 46 | out = "Sierra"; 47 | } else if (ch == 'T') { 48 | out = "Tango"; 49 | } else if (ch == 'U') { 50 | out = "Uniform"; 51 | } else if (ch == 'V') { 52 | out = "Victor"; 53 | } else if (ch == 'W') { 54 | out = "Whiskey"; 55 | } else if (ch == 'X') { 56 | out = "X-ray"; 57 | } else if (ch == 'Y') { 58 | out = "Yankee"; 59 | } else if (ch == 'Z') { 60 | out = "Zulu"; 61 | } else if (ch == '0') { 62 | out = "Zero"; 63 | } else if (ch == '1') { 64 | out = "One"; 65 | } else if (ch == '2') { 66 | out = "Two"; 67 | } else if (ch == '3') { 68 | out = "Three"; 69 | } else if (ch == '4') { 70 | out = "Four"; 71 | } else if (ch == '5') { 72 | out = "Five"; 73 | } else if (ch == '6') { 74 | out = "Six"; 75 | } else if (ch == '7') { 76 | out = "Seven"; 77 | } else if (ch == '8') { 78 | out = "Eight"; 79 | } else if (ch == '9') { 80 | out = "Nine"; 81 | } else { 82 | return "[" + getNonAlphanumericCharacterText(ch) + "]"; 83 | } 84 | 85 | if (chLatin.length() > 1) { out += "'"; } //add prime if character had accents 86 | return out; 87 | } 88 | 89 | 90 | QString PhoneticAlphabet::getNonAlphanumericCharacterText(QChar ch) { 91 | if (ch == '!') { 92 | return "Exclamation mark"; 93 | } else if (ch == '"') { 94 | return "Double quotation mark"; 95 | } else if (ch == '#') { 96 | return "Number sign"; 97 | } else if (ch == '$') { 98 | return "Dollar sign"; 99 | } else if (ch == '%') { 100 | return "Percent sign"; 101 | } else if (ch == '&') { 102 | return "Ampersand"; 103 | } else if (ch == '\'') { 104 | return "Apostrophe"; 105 | } else if (ch == '(') { 106 | return "Left parenthesis"; 107 | } else if (ch == ')') { 108 | return "Right parenthesis"; 109 | } else if (ch == '*') { 110 | return "Asterisk"; 111 | } else if (ch == '+') { 112 | return "Plus sign"; 113 | } else if (ch == ',') { 114 | return "Comma"; 115 | } else if (ch == '-') { 116 | return "Minus sign"; 117 | } else if (ch == '.') { 118 | return "Period"; 119 | } else if (ch == '/') { 120 | return "Slash"; 121 | } else if (ch == ':') { 122 | return "Colon"; 123 | } else if (ch == ';') { 124 | return "Semicolon"; 125 | } else if (ch == '<') { 126 | return "Less-than sign"; 127 | } else if (ch == '=') { 128 | return "Equal sign"; 129 | } else if (ch == '>') { 130 | return "Greater-than sign"; 131 | } else if (ch == '?') { 132 | return "Question mark"; 133 | } else if (ch == '@') { 134 | return "At sign"; 135 | } else if (ch == '[') { 136 | return "Left square bracket"; 137 | } else if (ch == '\\') { 138 | return "Backslash"; 139 | } else if (ch == ']') { 140 | return "Right square bracket"; 141 | } else if (ch == '^') { 142 | return "Circumflex accent"; 143 | } else if (ch == '_') { 144 | return "Underscore"; 145 | } else if (ch == '`') { 146 | return "Backtick"; 147 | } else if (ch == '{') { 148 | return "left curly bracket"; 149 | } else if (ch == '|') { 150 | return "Pipe"; 151 | } else if (ch == '}') { 152 | return "Right curly bracket"; 153 | } else if (ch == '~') { 154 | return "Tilde"; 155 | } else { 156 | return ch; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/phoneticalphabet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class PhoneticAlphabet { 6 | 7 | public: 8 | static QString getNatoText(QString character); 9 | 10 | private: 11 | static QString getNonAlphanumericCharacterText(QChar character); 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /src/rtfconverter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class RtfConverter { 7 | 8 | public: 9 | static bool convertFile(QString filePath); 10 | 11 | private: 12 | enum class State { 13 | Text, 14 | Group, 15 | Command, 16 | Escape, 17 | EscapeHex1, 18 | EscapeHex2, 19 | }; 20 | struct Context { 21 | int defaultCodePage = 0; 22 | int codePage = 0; 23 | int fontSize = 0; 24 | bool fontBold = false; 25 | bool fontItalic = false; 26 | bool fontUnderline = false; 27 | bool fontStrike = false; 28 | bool fontSub = false; 29 | bool fontSuper = false; 30 | QString htmlOutput; 31 | }; 32 | 33 | private: 34 | static QChar nextChar(QBuffer& buffer); 35 | static bool processGroup(QBuffer& buffer, Context& context, int level); 36 | static void processCommand(QString& command, Context& context, int& level); 37 | static void processText(QByteArray& bytes, Context& context, int level); 38 | static int codePageFromLocale(int locale, int defaultCodePage); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /src/settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "medo/config.h" 6 | #include "storage/deletionstyle.h" 7 | #include "storage/filetype.h" 8 | 9 | class Settings { 10 | 11 | public: 12 | 13 | static bool alwaysOnTop(); 14 | static void setAlwaysOnTop(bool newAlwaysOnTop); 15 | static bool defaultAlwaysOnTop() { return false; } 16 | 17 | static int clearUndoInterval(); 18 | static void setClearUndoInterval(int newClearUndoInterval); 19 | static int defaultClearUndoInterval() { return 15 * 60; } //15 minutes 20 | 21 | static bool colorTrayIcon(); 22 | static void setColorTrayIcon(bool newColorTrayIcon); 23 | static bool defaultColorTrayIcon() { 24 | return false; // auto detect 25 | } 26 | 27 | static QString dataPath(); 28 | static void setDataPath(QString newPath); 29 | static QString defaultDataPath() { return defaultDataPaths()[0]; } 30 | static QStringList dataPaths(); 31 | static void setDataPaths(QStringList newPaths); 32 | static QStringList defaultDataPaths() { return QStringList(Config::dataDirectory()); } 33 | 34 | static FileType defaultFileType(); 35 | static void setDefaultFileType(FileType newDefaultFileType); 36 | static FileType defaultDefaultFileType() { return FileType::Plain; } 37 | 38 | static DeletionStyle deletionSyle(); 39 | static void setDeletionStyle(DeletionStyle newDeletionStyle); 40 | static DeletionStyle defaultDeletionStyle() { return DeletionStyle::Delete; } 41 | 42 | static bool followUrlWithCtrl(); 43 | static void setFollowUrlWithCtrl(bool newFollowUrlWithCtrl); 44 | static bool defaultFollowUrlWithCtrl() { return true; } 45 | 46 | static bool followUrlWithDoubleClick(); 47 | static void setFollowUrlWithDoubleClick(bool newFollowUrlWithDoubleClick); 48 | static bool defaultFollowUrlWithDoubleClick() { return false; } 49 | 50 | static QFont font(); 51 | static void setFont(QFont newFont); 52 | 53 | static QString fontName(); 54 | static void setFontName(QString newFontName); 55 | static QString defaultFontName() { 56 | #if defined(Q_OS_WIN) 57 | return "Calibri"; 58 | #else 59 | return "DejaVu Sans"; 60 | #endif 61 | } 62 | 63 | static int fontSize(); 64 | static void setFontSize(int newFontSize); 65 | static int defaultFontSize() { return 11; } 66 | 67 | static bool forceDarkMode(); 68 | static void setForceDarkMode(bool newForceDarkMode); 69 | static bool defaultForceDarkMode() { return false; } 70 | 71 | static bool forcePlainCopyPaste(); 72 | static void setForcePlainCopyPaste(bool newForcePlainCopyPaste); 73 | static bool defaultForcePlainCopyPaste() { return false; } 74 | 75 | static QKeySequence hotkey(); 76 | static void setHotkey(QKeySequence newHotkey); 77 | static QKeySequence defaultHotkey() { 78 | QKeySequence defaultHotkey { "Ctrl+Shift+Q" }; 79 | return defaultHotkey; 80 | } 81 | 82 | static bool hotkeyTogglesVisibility(); 83 | static void setHotkeyTogglesVisibility(bool newHotkeyTogglesVisibility); 84 | static bool defaultHotkeyTogglesVisibility() { return false; } 85 | 86 | static bool hotkeyUseDConf(); 87 | static void setHotkeyUseDConf(bool newHotkeyUseDConf); 88 | static bool defaultHotkeyUseDConf(); 89 | 90 | static bool minimizeToTray(); 91 | static void setMinimizeToTray(bool newMinimizeToTray); 92 | static bool defaultMinimizeToTray() { return true; } 93 | 94 | static int quickSaveInterval(); 95 | static void setQuickSaveInterval(int newQuickSaveInterval); 96 | static int defaultQuickSaveInterval() { return 2500; } 97 | 98 | static bool showInTaskbar(); 99 | static void setShowInTaskbar(bool newShowInTaskbar); 100 | static bool defaultShowInTaskbar() { return true; } 101 | 102 | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) 103 | static bool showMarkdown(); 104 | static void setShowMarkdown(bool newShowMarkdown); 105 | static bool defaultShowMarkdown() { return false; } 106 | #endif 107 | 108 | static bool tabTextColorPerType(); 109 | static void setTabTextColorPerType(bool newTabTextColorPerType); 110 | static bool defaultTabTextColorPerType() { return false; } 111 | 112 | static int tabWidth(); 113 | static void setTabWidth(int newTabWidth); 114 | static int defaultTabWidth() { return 4; } 115 | 116 | static QString timeFormat(); 117 | static void setTimeFormat(QString newTimeFormat); 118 | static QString defaultTimeFormat() { return QString(); } 119 | 120 | static bool wordWrap(); 121 | static void setWordWrap(bool newWordWrap); 122 | static bool defaultWordWrap() { return true; } 123 | 124 | static bool waitForDirectory(); 125 | static void setWaitForDirectory(bool newWaitForDirectory); 126 | static bool defaultWaitForDirectory() { return false; } 127 | 128 | 129 | public: 130 | 131 | static QString lastFile(QString folder); 132 | static void setLastFile(QString folder, QString file); 133 | 134 | static QString lastFolder(); 135 | static void setLastFolder(QString folder); 136 | 137 | static bool setupCompleted(); 138 | static void setSetupCompleted(bool newSetupCompleted); 139 | 140 | }; 141 | -------------------------------------------------------------------------------- /src/setup.cpp: -------------------------------------------------------------------------------- 1 | #include "setup.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #if defined(Q_OS_WIN) 8 | #include 9 | #endif 10 | 11 | bool Setup::autostart() { 12 | return nativeAutostartCheck(); 13 | } 14 | 15 | void Setup::setAutostart(bool newAutostart) { 16 | if (newAutostart) { 17 | nativeAutostartAdd(); 18 | } else { 19 | nativeAutostartRemove(); 20 | } 21 | } 22 | 23 | 24 | #if defined(Q_OS_WIN) 25 | 26 | void Setup::nativeAutostartAdd() { 27 | QString valueName = QCoreApplication::applicationName(); 28 | QString value = QString("\"%1\" --hide").arg(QDir::toNativeSeparators(QCoreApplication::applicationFilePath())); 29 | HKEY runKey = nullptr; 30 | if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_WRITE, &runKey) == ERROR_SUCCESS) { 31 | QByteArray buffer = QByteArray(reinterpret_cast(value.utf16()), (value.length() + 1) * 2); 32 | RegSetValueEx(runKey, reinterpret_cast(valueName.utf16()), 0, REG_SZ, 33 | reinterpret_cast(buffer.constData()), static_cast(buffer.size())); 34 | } 35 | RegCloseKey(runKey); 36 | } 37 | 38 | void Setup::nativeAutostartRemove() { 39 | QString valueName = QCoreApplication::applicationName(); 40 | HKEY runKey = nullptr; 41 | if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_WRITE, &runKey) == ERROR_SUCCESS) { 42 | RegDeleteValue(runKey, reinterpret_cast(valueName.utf16())); 43 | } 44 | RegCloseKey(runKey); 45 | } 46 | 47 | bool Setup::nativeAutostartCheck() { 48 | QString valueName = QCoreApplication::applicationName(); 49 | QString expectedValue = QString("\"%1\" --hide").arg(QDir::toNativeSeparators(QCoreApplication::applicationFilePath())); 50 | bool isFound = false; 51 | HKEY runKey = nullptr; 52 | if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_READ, &runKey) == ERROR_SUCCESS) { 53 | ushort valueBuffer[4096]; 54 | DWORD valueBufferSize = sizeof(valueBuffer); 55 | if (RegGetValue(runKey, nullptr, reinterpret_cast(valueName.utf16()), RRF_RT_REG_SZ, nullptr, valueBuffer, &valueBufferSize) == ERROR_SUCCESS) { 56 | auto value = QString::fromUtf16(valueBuffer, static_cast(valueBufferSize) / 2 - 1); 57 | isFound = (expectedValue.compare(value) == 0); 58 | } 59 | } 60 | RegCloseKey(runKey); 61 | return isFound; 62 | } 63 | 64 | #elif defined(Q_OS_LINUX) 65 | 66 | void Setup::nativeAutostartAdd() { 67 | QDir autostartDirectory(QDir::cleanPath(QDir::homePath() + "/.config/autostart")); 68 | if (!autostartDirectory.exists()) { autostartDirectory.mkpath("."); } 69 | QString autostartFile = QDir::cleanPath(autostartDirectory.path() + "/qtext.desktop"); 70 | QString execLine = QCoreApplication::applicationFilePath() + " --hide"; 71 | 72 | QFile file(autostartFile); 73 | if (file.open(QIODevice::WriteOnly)) { 74 | QTextStream stream(&file); 75 | stream << "[Desktop Entry]" << Qt::endl; 76 | stream << "Name=QText" << Qt::endl; 77 | stream << "Exec=" << execLine << Qt::endl; 78 | stream << "Terminal=false" << Qt::endl; 79 | stream << "Type=Application" << Qt::endl; 80 | stream << "StartupNotify=false" << Qt::endl; 81 | stream << "X-GNOME-Autostart-enabled=true" << Qt::endl; 82 | } 83 | } 84 | 85 | void Setup::nativeAutostartRemove() { 86 | QDir autostartDirectory(QDir::cleanPath(QDir::homePath() + "/.config/autostart")); 87 | if (!autostartDirectory.exists()) { autostartDirectory.mkpath("."); } 88 | QString autostartFile = QDir::cleanPath(autostartDirectory.path() + "/qtext.desktop"); 89 | QFile::remove(autostartFile); 90 | } 91 | 92 | bool Setup::nativeAutostartCheck() { 93 | QDir autostartDirectory(QDir::cleanPath(QDir::homePath() + "/.config/autostart")); 94 | if (!autostartDirectory.exists()) { autostartDirectory.mkpath("."); } 95 | QString autostartFile = QDir::cleanPath(autostartDirectory.path() + "/qtext.desktop"); 96 | QString execLine = QCoreApplication::applicationFilePath() + " --hide"; 97 | 98 | QFile file(autostartFile); 99 | if (file.open(QIODevice::ReadOnly)) { 100 | QTextStream stream(&file); 101 | while (!stream.atEnd()) { 102 | QString line = stream.readLine(); 103 | if (line.startsWith("Exec=")) { 104 | QStringList parts = line.split("="); 105 | QString execLineFound = parts[1].trimmed(); 106 | if (execLine.compare(execLineFound, Qt::CaseSensitive) == 0) { return true; } 107 | break; 108 | } 109 | } 110 | } 111 | return false; 112 | } 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /src/setup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Setup { 4 | 5 | public: 6 | static bool autostart(); 7 | static void setAutostart(bool newAutostart); 8 | 9 | private: 10 | static void nativeAutostartAdd(); 11 | static void nativeAutostartRemove(); 12 | static bool nativeAutostartCheck(); 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /src/storage/deletionstyle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class DeletionStyle { 4 | Delete = 0, 5 | Overwrite = 1, 6 | Recycle = 2, 7 | }; 8 | -------------------------------------------------------------------------------- /src/storage/fileitem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "filetype.h" 12 | #include "folderitem.h" 13 | 14 | class FolderItem; 15 | 16 | class FileItem : public QTextEdit { 17 | Q_OBJECT 18 | friend class FolderItem; 19 | friend class Storage; 20 | 21 | public: 22 | FolderItem* folder() const; 23 | QUuid key() const { return _key; } 24 | QString name() const; 25 | QString path() const; 26 | QString title() const; 27 | void setTitle(QString newTitle); 28 | FileType type() const; 29 | bool setType(FileType newType); 30 | QString extension() const; 31 | bool isModified() const; 32 | bool isEmpty() const; 33 | bool load(); 34 | bool save() const; 35 | bool setFolder(FolderItem* newFolder); 36 | 37 | public: 38 | bool isTextUndoAvailable(); 39 | void textUndo(); 40 | bool isTextRedoAvailable(); 41 | void textRedo(); 42 | 43 | bool canTextCut(); 44 | void textCut(bool forcePlain = false); 45 | bool canTextCopy(); 46 | void textCopy(bool forcePlain = false); 47 | bool canTextPaste(); 48 | void textPaste(bool forcePlain = false); 49 | 50 | bool isFontBold(); 51 | void setFontBold(bool bold = true); 52 | bool isFontItalic(); 53 | void setFontItalic(bool italic = true); 54 | bool isFontUnderline(); 55 | void setFontUnderline(bool underline = true); 56 | bool isFontStrikethrough(); 57 | void setFontStrikethrough(bool strikethrough = true); 58 | 59 | public: 60 | FileItem(const FileItem&) = delete; 61 | void operator=(const FileItem&) = delete; 62 | 63 | protected: 64 | virtual bool event(QEvent* event); 65 | virtual bool eventFilter(QObject* obj, QEvent* event); 66 | virtual void focusInEvent(QFocusEvent* e); 67 | virtual void focusOutEvent(QFocusEvent* e); 68 | virtual void wheelEvent(QWheelEvent* e); 69 | 70 | private: 71 | FileItem(FolderItem* folder, QString fileName); 72 | ~FileItem(); 73 | QString findAnchorAt(QPoint pos); 74 | QUuid _key = QUuid::createUuid(); 75 | FolderItem* _folder = nullptr; 76 | QString _fileName; 77 | QTextEdit* _editor = nullptr; 78 | QTextCodec* _utf8Codec = QTextCodec::codecForName("UTF-8"); 79 | QTimer* _timerSavePending = nullptr; 80 | mutable QDateTime _modificationTime; 81 | int zoomAmount = 0; 82 | bool customCursorSet = false; 83 | 84 | signals: 85 | void activated(FileItem* file); 86 | void titleChanged(FileItem* file); 87 | void modificationChanged(FileItem* file, bool isModified); 88 | 89 | public slots: 90 | void printPreview(QPrinter* printer); 91 | 92 | private slots: 93 | void onModificationChanged(bool changed); 94 | void onSavePendingTimeout(); 95 | void onContextMenuRequested(const QPoint&); 96 | void onContextMenuUndo(); 97 | void onContextMenuRedo(); 98 | void onContextMenuCut(); 99 | void onContextMenuCopy(); 100 | void onContextMenuPaste(); 101 | void onContextMenuCutPlain(); 102 | void onContextMenuCopyPlain(); 103 | void onContextMenuPastePlain(); 104 | void onContextMenuDelete(); 105 | void onContextMenuSelectAll(); 106 | void onContextMenuInsertTime(); 107 | void onContextMenuResetFont(); 108 | void onContextCopyUrl(); 109 | void onContextGoToUrl(); 110 | 111 | }; 112 | -------------------------------------------------------------------------------- /src/storage/filetype.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | enum class FileType { 5 | Plain = 0, 6 | Html = 1, 7 | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) 8 | Markdown = 2, 9 | #endif 10 | }; 11 | -------------------------------------------------------------------------------- /src/storage/folderitem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "fileitem.h" 6 | #include "filetype.h" 7 | #include "settings.h" 8 | #include "storagemonitorthread.h" 9 | 10 | class FileItem; 11 | class FolderItem; 12 | class Storage; 13 | 14 | class FolderItemInternal { //just to keep private variables not visible to friends 15 | friend class FolderItem; 16 | 17 | private: 18 | QUuid _key = QUuid::createUuid(); 19 | Storage* _storage; 20 | FolderItem* _rootFolder; 21 | QString _directoryPath; 22 | QString _directoryName; 23 | int _pathIndex; 24 | QVector _files; 25 | 26 | }; 27 | 28 | class FolderItem : public FolderItemInternal { 29 | friend class FileItem; 30 | friend class Storage; 31 | 32 | public: 33 | FolderItem* rootFolder() const; 34 | QUuid key() const { return _key; } 35 | QString name() const; 36 | QString path() const; 37 | int pathIndex() const; 38 | QString title() const; 39 | bool rename(QString newTitle); 40 | bool isRoot() const; 41 | bool isPrimary() const; 42 | int fileCount() const; 43 | FileItem* fileAt(int index) const; 44 | FileItem* newFile(QString title, FileType type, FileItem* afterItem); 45 | bool deleteFile(FileItem* file, DeletionStyle deletionStyle); 46 | bool saveAll() const; 47 | bool fileExists(QString title) const; 48 | bool moveFile(int from, int to); 49 | 50 | public: 51 | inline QVector::const_iterator begin() const { return _files.constBegin(); } 52 | inline QVector::const_iterator end() const { return _files.constEnd(); } 53 | 54 | public: 55 | FolderItem(const FolderItem&) = delete; 56 | void operator=(const FolderItem&) = delete; 57 | 58 | private: 59 | FolderItem(Storage* storage, FolderItem* rootFolder, const int pathIndex, const QString directoryBase, const QString directoryName); 60 | ~FolderItem(); 61 | void addItem(FileItem* item); 62 | void addItemAfter(FileItem* item, FileItem* afterItem); 63 | bool removeItem(FileItem* item); 64 | void removeItemAt(int index); 65 | Storage* storage() const { return _storage; } 66 | 67 | private: 68 | void cleanOrdering(); 69 | void saveOrdering(); 70 | void loadOrdering(); 71 | 72 | }; 73 | -------------------------------------------------------------------------------- /src/storage/storage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "folderitem.h" 5 | #include "storagemonitorthread.h" 6 | 7 | const QString _plainSuffix = "txt"; 8 | const QString _htmlSuffix = "html"; 9 | const QString _markdownSuffix = "md"; 10 | const QStringList _supportedExtensions = QStringList({"." + _plainSuffix, "." + _htmlSuffix, "." + _markdownSuffix}); 11 | const QStringList _supportedExtensionFilters = QStringList({"*." + _plainSuffix, "*." + _htmlSuffix, "*." + _markdownSuffix}); 12 | 13 | class StorageInternal : public QObject { //just to keep private variables not visible to friends 14 | friend class Storage; 15 | 16 | private: 17 | QVector _folders; 18 | StorageMonitorThread* _monitor; 19 | 20 | }; 21 | 22 | class Storage : public StorageInternal { 23 | Q_OBJECT 24 | friend class FileItem; 25 | friend class FolderItem; 26 | friend class StorageMonitorThread; 27 | 28 | public: 29 | Storage(const QStringList paths); 30 | ~Storage(); 31 | int folderCount() const; 32 | FolderItem* folderAt(int index) const; 33 | FolderItem* folderFromKey(QUuid key) const; 34 | FolderItem* baseFolder() const; 35 | FolderItem* newFolder(QString title); 36 | bool deleteFolder(FolderItem* folder, DeletionStyle deletionStyle); 37 | bool saveAll(); 38 | StorageMonitorThread* monitor() const; 39 | 40 | public: 41 | inline QVector::const_iterator begin() const { return _folders.constBegin(); } 42 | inline QVector::const_iterator end() const { return _folders.constEnd(); } 43 | 44 | public: 45 | Storage(const Storage&) = delete; 46 | void operator=(const Storage&) = delete; 47 | 48 | private: 49 | static QString plainSuffix() { return _plainSuffix; }; 50 | static QString htmlSuffix() { return _htmlSuffix; }; 51 | static QString markdownSuffix() { return _markdownSuffix; }; 52 | static QStringList supportedExtensions() { return _supportedExtensions; }; 53 | static QStringList supportedExtensionFilters() { return _supportedExtensionFilters; }; 54 | void addItem(FolderItem* item); 55 | void removeItemAt(int index); 56 | 57 | private: 58 | void sortFolders(); 59 | 60 | private slots: 61 | void onDirectoryAdded(QString folderPath); 62 | void onDirectoryRemoved(QString folderPath); 63 | void onFileAdded(QString folderPath, QString fileName); 64 | void onFileRemoved(QString folderPath, QString fileName); 65 | 66 | signals: 67 | void updatedFolder(FolderItem* folder); 68 | 69 | }; 70 | -------------------------------------------------------------------------------- /src/storage/storagemonitorlocker.cpp: -------------------------------------------------------------------------------- 1 | #include "storagemonitorlocker.h" 2 | #include "storagemonitorthread.h" 3 | 4 | StorageMonitorLocker::StorageMonitorLocker(StorageMonitorThread* monitor) { 5 | _monitor = monitor; 6 | _monitor->stopMonitoring(); 7 | } 8 | 9 | StorageMonitorLocker::~StorageMonitorLocker() { 10 | _monitor->continueMonitoring(); 11 | } 12 | -------------------------------------------------------------------------------- /src/storage/storagemonitorlocker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "storagemonitorthread.h" 4 | 5 | class StorageMonitorLocker { 6 | 7 | public: 8 | StorageMonitorLocker(StorageMonitorThread* monitor); 9 | ~StorageMonitorLocker(); 10 | 11 | private: 12 | StorageMonitorThread* _monitor; 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /src/storage/storagemonitorthread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class StorageMonitorLocker; 9 | class StorageMonitorThread : public QThread { 10 | Q_OBJECT 11 | 12 | friend class StorageMonitorLocker; 13 | private: //used by StorageMonitorLocker 14 | void continueMonitoring(); 15 | void stopMonitoring(); 16 | 17 | 18 | public: 19 | explicit StorageMonitorThread(QStringList paths); 20 | ~StorageMonitorThread(); 21 | 22 | public: 23 | StorageMonitorThread(const StorageMonitorThread&) = delete; 24 | void operator=(const StorageMonitorThread&) = delete; 25 | 26 | private: 27 | QMutex _mutex; 28 | bool _isMonitoring = true; 29 | QStringList _paths; 30 | QStringList _prevPaths; 31 | void run(); 32 | QStringList findPaths(QString rootPath, int depth = 0); 33 | 34 | signals: 35 | void directoryAdded(QString folderPath); 36 | void directoryRemoved(QString folderPath); 37 | void fileAdded(QString folderPath, QString fileName); 38 | void fileRemoved(QString folderPath, QString fileName); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /src/test.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | test/Config/CommentsOnly.cfg 4 | test/Config/CommentsWithValues.cfg 5 | test/Config/Empty.cfg 6 | test/Config/EmptyLinesCR.cfg 7 | test/Config/EmptyLinesCRLF.cfg 8 | test/Config/EmptyLinesLF.cfg 9 | test/Config/EmptyLinesMixed.cfg 10 | test/Config/EmptyLinesMixed.Good.cfg 11 | test/Config/KeyWhitespace.cfg 12 | test/Config/KeyWhitespace.Good.cfg 13 | test/Config/Remove.cfg 14 | test/Config/Remove.Good.cfg 15 | test/Config/RemoveMulti.cfg 16 | test/Config/RemoveMulti.Good.cfg 17 | test/Config/Replace.cfg 18 | test/Config/Replace.Good.cfg 19 | test/Config/ReplaceOnlyLast.cfg 20 | test/Config/ReplaceOnlyLast.Good.cfg 21 | test/Config/SpacingCorrections.cfg 22 | test/Config/SpacingCorrections.Good.cfg 23 | test/Config/SpacingEscape.cfg 24 | test/Config/SpacingEscape.Good.cfg 25 | test/Config/SpacingPreserved.cfg 26 | test/Config/SpacingPreserved.Good.cfg 27 | test/Config/SpacingPreservedOnAdd.cfg 28 | test/Config/SpacingPreservedOnAdd.Good.cfg 29 | test/Config/WriteBasic.Good.cfg 30 | test/Config/WriteMulti.cfg 31 | test/Config/WriteMulti.Good.cfg 32 | test/Config/WriteNoEmptyLine.cfg 33 | test/Config/WriteNoEmptyLine.Good.cfg 34 | test/Config/WriteSameSeparatorEquals.cfg 35 | test/Config/WriteSameSeparatorEquals.Good.cfg 36 | test/Config/WriteSameSeparatorSpace.cfg 37 | test/Config/WriteSameSeparatorSpace.Good.cfg 38 | test/Config/WriteConvertedCpp.Good.cfg 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/test/Config/CommentsOnly.cfg: -------------------------------------------------------------------------------- 1 | # Test 2 | # Test with prefix -------------------------------------------------------------------------------- /src/test/Config/CommentsWithValues.cfg: -------------------------------------------------------------------------------- 1 | Key1 #Test with no value 2 | Key2 = Value2 #Test 3 | Key3 Value3 # Test with whitespace at the end 4 | Key4: Value 4 # Test with whitespace at the end 5 | -------------------------------------------------------------------------------- /src/test/Config/Empty.cfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/QText/841051377eec27b4aeadda674fbce5d1be02524a/src/test/Config/Empty.cfg -------------------------------------------------------------------------------- /src/test/Config/EmptyLinesCR.cfg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/test/Config/EmptyLinesCRLF.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/test/Config/EmptyLinesLF.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/test/Config/EmptyLinesMixed.Good.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/test/Config/EmptyLinesMixed.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/test/Config/KeyWhitespace.Good.cfg: -------------------------------------------------------------------------------- 1 | Key\_1: Value 1 2 | Key\_2: Value 2a 3 | Key\_2: Value 2b 4 | Key\_3: Value 3 5 | Key\_2: Value 2c 6 | -------------------------------------------------------------------------------- /src/test/Config/KeyWhitespace.cfg: -------------------------------------------------------------------------------- 1 | Key\ 1: Value 1 2 | Key\_2: Value 2a 3 | Key\ 2: Value 2b 4 | Key\_3: Value 3 5 | Key\_2: Value 2c 6 | -------------------------------------------------------------------------------- /src/test/Config/Remove.Good.cfg: -------------------------------------------------------------------------------- 1 | Key2: Value 2 2 | -------------------------------------------------------------------------------- /src/test/Config/Remove.cfg: -------------------------------------------------------------------------------- 1 | Key1: Value 1 2 | Key2: Value 2 3 | -------------------------------------------------------------------------------- /src/test/Config/RemoveMulti.Good.cfg: -------------------------------------------------------------------------------- 1 | Key1: Value 1 2 | -------------------------------------------------------------------------------- /src/test/Config/RemoveMulti.cfg: -------------------------------------------------------------------------------- 1 | Key2: Value 2a 2 | Key1: Value 1 3 | Key2: Value 2b 4 | Key2: Value 2c 5 | -------------------------------------------------------------------------------- /src/test/Config/Replace.Good.cfg: -------------------------------------------------------------------------------- 1 | Key1: Value 1a 2 | Key2: Value 2a 3 | -------------------------------------------------------------------------------- /src/test/Config/Replace.cfg: -------------------------------------------------------------------------------- 1 | Key1: Value 1 2 | Key2: Value 2 3 | -------------------------------------------------------------------------------- /src/test/Config/ReplaceOnlyLast.Good.cfg: -------------------------------------------------------------------------------- 1 | Key1: Value 1 #Coment 1 2 | Key2: Value 2 3 | Key1: Value 1a #Coment 2 4 | Key2: Value 2a 5 | Key3: Value 3 6 | -------------------------------------------------------------------------------- /src/test/Config/ReplaceOnlyLast.cfg: -------------------------------------------------------------------------------- 1 | Key1: Value 1 #Coment 1 2 | Key2: Value 2 3 | Key1: Value 1 #Coment 2 4 | Key2: Value 2 5 | Key3: Value 3 6 | -------------------------------------------------------------------------------- /src/test/Config/SpacingCorrections.Good.cfg: -------------------------------------------------------------------------------- 1 | Key1 # Preserve spacing after key 2 | Key2 = Value 2 # Spaces to go around equals (=) separator 3 | Key3 = Value 3 # Spaces to go around equals (=) separator 4 | Key4: Value 4 # Space to go after colon (:) separator 5 | Key5: Value 5 # Space to go after colon (:) separator 6 | Key6 Value 6 # Single space as separator 7 | -------------------------------------------------------------------------------- /src/test/Config/SpacingCorrections.cfg: -------------------------------------------------------------------------------- 1 | Key1 # Preserve spacing after key 2 | Key2=Value 2 # Spaces to go around equals (=) separator 3 | Key3 = Value 3 # Spaces to go around equals (=) separator 4 | Key4:Value 4 # Space to go after colon (:) separator 5 | Key5 : Value 5 # Space to go after colon (:) separator 6 | Key6 Value 6 # Single space as separator 7 | -------------------------------------------------------------------------------- /src/test/Config/SpacingEscape.Good.cfg: -------------------------------------------------------------------------------- 1 | Key1: \_Value 1 # Starting space 2 | Key2: Value 2\_ # Trailing space 3 | Key3: \_Value 3\_ # Trailing space 4 | Key4: \_ Value 4 \_ # Trailing space 5 | Key5: \tValue 5\t # Tab 6 | Key6: \tValue 6 # Tab 7 | Null: \0Null\0 8 | -------------------------------------------------------------------------------- /src/test/Config/SpacingEscape.cfg: -------------------------------------------------------------------------------- 1 | Key1: \ Value 1 # Starting space 2 | Key2: Value 2\ # Trailing space 3 | Key3: \ Value 3\ # Trailing space 4 | Key4: \ Value 4 \ # Trailing space 5 | Key5: \tValue 5\t # Tab 6 | Key6: \u0009Value 6 # Tab 7 | Null: \0 8 | -------------------------------------------------------------------------------- /src/test/Config/SpacingPreserved.Good.cfg: -------------------------------------------------------------------------------- 1 | KeyOne: Value 1a #testing1 2 | KeyTwo : Value 2b #testing2 3 | KeyThree: Value 3c #testing3 4 | -------------------------------------------------------------------------------- /src/test/Config/SpacingPreserved.cfg: -------------------------------------------------------------------------------- 1 | KeyOne: Value 1 #testing1 2 | KeyTwo : Value 2 #testing2 3 | KeyThree: Value 3 #testing3 4 | -------------------------------------------------------------------------------- /src/test/Config/SpacingPreservedOnAdd.Good.cfg: -------------------------------------------------------------------------------- 1 | One: Value 1a 2 | Two: Value 2a 3 | Two: Value 2b 4 | Three: Value 3a 5 | Four: Value 4a 6 | Five: Value 5a 7 | Five: Value 5b 8 | Five: Value 5c 9 | FourtyTwo: 42 10 | -------------------------------------------------------------------------------- /src/test/Config/SpacingPreservedOnAdd.cfg: -------------------------------------------------------------------------------- 1 | One: Value 1 2 | Two: Value 2 3 | Three: Value 3 4 | -------------------------------------------------------------------------------- /src/test/Config/WriteBasic.Good.cfg: -------------------------------------------------------------------------------- 1 | Key1: Value 1 2 | Key2: Value 2 3 | -------------------------------------------------------------------------------- /src/test/Config/WriteConvertedCpp.Good.cfg: -------------------------------------------------------------------------------- 1 | Integer: 42 2 | Integer\_Min: -2147483648 3 | Integer\_Max: 2147483647 4 | Long: 42 5 | Long\_Min: -9223372036854775808 6 | Long\_Max: 9223372036854775807 7 | Boolean: true 8 | Double: 42.42 9 | Double\_Pi: 3.1415926535898 10 | Double\_Third: 0.33333333333333 11 | Double\_Seventh: 0.14285714285714 12 | Double\_Min: -1.7976931348623E+308 13 | Double\_Max: 1.7976931348623E+308 14 | Double\_NaN: NaN 15 | Double\_Infinity+: Infinity 16 | Double\_Infinity-: -Infinity 17 | -------------------------------------------------------------------------------- /src/test/Config/WriteMulti.Good.cfg: -------------------------------------------------------------------------------- 1 | Key1: Value 1 2 | Key2: Value 2a 3 | Key2: Value 2b 4 | Key2: Value 2c 5 | Key3: Value 3 6 | -------------------------------------------------------------------------------- /src/test/Config/WriteMulti.cfg: -------------------------------------------------------------------------------- 1 | Key1: Value 1 2 | Key2: Value 2 3 | Key3: Value 3 4 | -------------------------------------------------------------------------------- /src/test/Config/WriteNoEmptyLine.Good.cfg: -------------------------------------------------------------------------------- 1 | Key0: Value 0 2 | Key1: Value 1 3 | Key2: Value 2 -------------------------------------------------------------------------------- /src/test/Config/WriteNoEmptyLine.cfg: -------------------------------------------------------------------------------- 1 | Key0: Value 0 -------------------------------------------------------------------------------- /src/test/Config/WriteSameSeparatorEquals.Good.cfg: -------------------------------------------------------------------------------- 1 | Key0 = Value 0 2 | Key1 = Value 1 3 | Key2 = Value 2 4 | -------------------------------------------------------------------------------- /src/test/Config/WriteSameSeparatorEquals.cfg: -------------------------------------------------------------------------------- 1 | Key0 = Value 0 2 | -------------------------------------------------------------------------------- /src/test/Config/WriteSameSeparatorSpace.Good.cfg: -------------------------------------------------------------------------------- 1 | Key0 Value 0 2 | Key1 Value 1 3 | Key2 Value 2 4 | -------------------------------------------------------------------------------- /src/test/Config/WriteSameSeparatorSpace.cfg: -------------------------------------------------------------------------------- 1 | Key0 Value 0 2 | -------------------------------------------------------------------------------- /src/test/test_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Test_Config : public QObject { 7 | Q_OBJECT 8 | 9 | private: 10 | void setup(QString applicationName, QString organizationName); 11 | void setup(QString applicationName, QString organizationName, QString testConfigFile); 12 | void cleanup(QString configFile, QString stateFile, QString dataDirectory); 13 | void cleanup(); 14 | void verifyTestFile(QString testFileName, QString actualFileName); 15 | 16 | private slots: 17 | void paths(); 18 | void pathsWithSpaces(); 19 | void reset(); 20 | void nullKey(); 21 | void nullKeyState(); 22 | void emptyKey(); 23 | void emptyKeyState(); 24 | void emptySave(); 25 | void emptyLinesCrLf(); 26 | void emptyLinesLf(); 27 | void emptyLinesCr(); 28 | void emptyLinesMixed(); 29 | void commentsOnly(); 30 | void commentsWithValues(); 31 | void spacingEscape(); 32 | void writeBasic(); 33 | void writeBasicState(); 34 | void writeNoEmptyLine(); 35 | void writeSameSeparatorEquals(); 36 | void writeSameSeparatorSpace(); 37 | void replace(); 38 | void replaceState(); 39 | void spacingPreserved(); 40 | void spacingPreservedOnAdd(); 41 | void writeToEmpty(); 42 | void replaceOnlyLast(); 43 | void removeSingle(); 44 | void removeMulti(); 45 | void readMulti(); 46 | void multiWrite(); 47 | void multiReplace(); 48 | void testConversionWrite(); 49 | void testConversionRead(); 50 | void keyWhitespace(); 51 | void deleteAll(); 52 | void twoReadsWithDifferentDefault(); 53 | void writeOverridesReads(); 54 | void removeCausesDefault(); 55 | void removeAllCausesDefault(); 56 | void writeChangesOnlyLastEntry(); 57 | void caseInsensitiveDefaults(); 58 | void caseInsensitiveWrites(); 59 | 60 | }; 61 | -------------------------------------------------------------------------------- /src/test/test_helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Test_Helpers : public QObject { 7 | Q_OBJECT 8 | 9 | private slots: 10 | void encodeTitle_colon(); 11 | void encodeTitle_allPrintable(); 12 | void decodeTitle_allPrintable(); 13 | void encodeTitle_tab(); 14 | void decodeTitle_tab(); 15 | void encodeTitle_dotInMiddle(); 16 | void decodeTitle_dotInMiddle(); 17 | void encodeTitle_dotAtEnd(); 18 | void decodeTitle_dotAtEnd(); 19 | void decodeTitle_accidentalDotAtEnd(); 20 | void encodeTitle_doubleDotAtEnd(); 21 | void decodeTitle_doubleDotAtEnd(); 22 | void decodeTitle_accidentalDoubleDotAtEnd(); 23 | void encodeTitle_spaceAtStart(); 24 | void decodeTitle_spaceAtStart(); 25 | void decodeTitle_accidentalSpaceAtStart(); 26 | void encodeTitle_doubleSpaceAtStart(); 27 | void decodeTitle_doubleSpaceAtStart(); 28 | void decodeTitle_accidentalDoubleSpaceAtStart(); 29 | void encodeTitle_spaceAtEnd(); 30 | void decodeTitle_spaceAtEnd(); 31 | void decodeTitle_accidentalSpaceAtEnd(); 32 | void encodeTitle_doubleSpaceAtEnd(); 33 | void decodeTitle_doubleSpaceAtEnd(); 34 | void decodeTitle_accidentalDoubleSpaceAtEnd(); 35 | void decodeTitle_accidental1(); 36 | void decodeTitle_accidental2(); 37 | void decodeTitle_accidental3(); 38 | void decodeTitle_accidental4(); 39 | void decodeTitle_accidental5(); 40 | 41 | }; 42 | -------------------------------------------------------------------------------- /src/test/test_main.cpp: -------------------------------------------------------------------------------- 1 | #include "test_config.h" 2 | #include "test_helpers.h" 3 | 4 | int main(int argc, char* argv[]) { 5 | int status = 0; 6 | 7 | QApplication a(argc, argv); 8 | 9 | status |= QTest::qExec(new Test_Config, argc, argv); 10 | status |= QTest::qExec(new Test_Helpers, argc, argv); 11 | 12 | return status; 13 | } 14 | -------------------------------------------------------------------------------- /src/ui/finddialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "find.h" 5 | 6 | namespace Ui { 7 | class FindDialog; 8 | } 9 | 10 | class FindDialog : public QDialog { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit FindDialog(QWidget* parent); 15 | ~FindDialog(); 16 | 17 | public: 18 | QString searchText() const; 19 | bool matchCase() const; 20 | bool wholeWord() const; 21 | bool useRegEx() const; 22 | Find::SearchScope searchScope() const; 23 | 24 | protected: 25 | void accept() override; 26 | 27 | private: 28 | Ui::FindDialog* ui; 29 | 30 | private: 31 | QString composeTerm(QString text, bool matchCase, bool wholeWord, bool useRegEx, Find::SearchScope searchScope); 32 | QString decomposeTerm(QString term, bool* matchCase, bool* wholeWord, bool* useRegEx, Find::SearchScope* searchScope); 33 | QString decomposeTerm(QString term); 34 | 35 | private slots: 36 | void onStateChanged(); 37 | void onHistorySelected(); 38 | 39 | }; 40 | -------------------------------------------------------------------------------- /src/ui/finddialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FindDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 143 11 | 12 | 13 | 14 | Find 15 | 16 | 17 | 18 | :/icons/16x16/appMono.png:/icons/16x16/appMono.png 19 | 20 | 21 | 22 | 23 | 24 | Search text: 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 0 34 | 35 | 36 | 37 | Qt::Horizontal 38 | 39 | 40 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | &Match case 55 | 56 | 57 | 58 | 59 | 60 | 61 | &Whole word 62 | 63 | 64 | 65 | 66 | 67 | 68 | &Regular expression 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Current &file 80 | 81 | 82 | 83 | 84 | 85 | 86 | &Current folder 87 | 88 | 89 | 90 | 91 | 92 | 93 | &All folders 94 | 95 | 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | comboSearch 108 | buttonBox 109 | 110 | 111 | 112 | 113 | 114 | 115 | buttonBox 116 | accepted() 117 | FindDialog 118 | accept() 119 | 120 | 121 | 248 122 | 254 123 | 124 | 125 | 157 126 | 274 127 | 128 | 129 | 130 | 131 | buttonBox 132 | rejected() 133 | FindDialog 134 | reject() 135 | 136 | 137 | 316 138 | 260 139 | 140 | 141 | 286 142 | 274 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /src/ui/foldersdialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "storage/folderitem.h" 8 | #include "storage/storage.h" 9 | 10 | namespace Ui { 11 | class FoldersDialog; 12 | } 13 | 14 | class FoldersDialog : public QDialog { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit FoldersDialog(QWidget* parent, Storage* storage, FolderItem* selectedFolder); 19 | ~FoldersDialog(); 20 | FolderItem* selectedFolder() const { return _selectedFolder; } 21 | 22 | protected: 23 | void keyPressEvent(QKeyEvent* event); 24 | void hideEvent(QHideEvent* event); 25 | 26 | private: 27 | Ui::FoldersDialog* ui; 28 | QPushButton* _newButton; 29 | QPushButton* _renameButton; 30 | QPushButton* _deleteButton; 31 | Storage* _storage = nullptr; 32 | FolderItem* _selectedFolder = nullptr; 33 | void fillList(); 34 | 35 | private slots: 36 | void onNew(); 37 | void onRename(); 38 | void onDelete(); 39 | void onCurrentItemChanged(QListWidgetItem* current); 40 | void onItemChanged(QListWidgetItem* item); 41 | void onItemDoubleClicked(QListWidgetItem* item); 42 | 43 | }; 44 | -------------------------------------------------------------------------------- /src/ui/foldersdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FoldersDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 360 10 | 400 11 | 12 | 13 | 14 | 15 | 320 16 | 400 17 | 18 | 19 | 20 | Folders 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Qt::Vertical 30 | 31 | 32 | QDialogButtonBox::Close 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | buttonBox 42 | accepted() 43 | FoldersDialog 44 | accept() 45 | 46 | 47 | 248 48 | 254 49 | 50 | 51 | 157 52 | 274 53 | 54 | 55 | 56 | 57 | buttonBox 58 | rejected() 59 | FoldersDialog 60 | reject() 61 | 62 | 63 | 316 64 | 260 65 | 66 | 67 | 286 68 | 274 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/ui/gotodialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "storage/storage.h" 7 | 8 | namespace Ui { 9 | class GotoDialog; 10 | } 11 | 12 | class GotoDialog : public QDialog { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit GotoDialog(QWidget* parent = nullptr, Storage* storage = nullptr); 17 | ~GotoDialog(); 18 | QString folderKey() const { return _folderKey; } 19 | QString fileKey() const { return _fileKey; } 20 | 21 | protected: 22 | void accept(); 23 | void hideEvent(QHideEvent* event); 24 | 25 | private: 26 | Ui::GotoDialog* ui; 27 | bool eventFilter(QObject* obj, QEvent* event); 28 | QString _folderKey; 29 | QString _fileKey; 30 | Storage* _storage = nullptr; 31 | 32 | private slots: 33 | void onTextEdited(const QString& text); 34 | void onItemSelectionChanged(); 35 | void onItemActivated(); 36 | 37 | }; 38 | -------------------------------------------------------------------------------- /src/ui/gotodialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | GotoDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 400 11 | 12 | 13 | 14 | Go To 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Search: 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | Qt::Horizontal 38 | 39 | 40 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 41 | 42 | 43 | false 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | buttonBox 53 | accepted() 54 | GotoDialog 55 | accept() 56 | 57 | 58 | 248 59 | 254 60 | 61 | 62 | 157 63 | 274 64 | 65 | 66 | 67 | 68 | buttonBox 69 | rejected() 70 | GotoDialog 71 | reject() 72 | 73 | 74 | 316 75 | 260 76 | 77 | 78 | 286 79 | 274 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/ui/hotkeyedit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "hotkeyedit.h" 5 | 6 | static const char* NoShortcutText = "No shortcut assigned"; 7 | static const char* ChangeShortcutText = "Press hotkey combination"; 8 | 9 | static QString getPlaceholderText(QKeySequence key) { 10 | if (key == 0) { 11 | return QString(NoShortcutText); 12 | } else { 13 | return key.toString(QKeySequence::NativeText); 14 | } 15 | } 16 | 17 | HotkeyEdit::HotkeyEdit(QWidget* parent) 18 | : QLineEdit(parent) { 19 | setReadOnly(true); 20 | } 21 | 22 | 23 | void HotkeyEdit::setHotkey(Hotkey* hotkey, QKeySequence key) { 24 | _hotkey = hotkey; 25 | _oldKey = key; 26 | _newKey = key; 27 | setPlaceholderText(getPlaceholderText(key)); 28 | } 29 | 30 | void HotkeyEdit::setNewKey(QKeySequence key) { 31 | _newKey = key; 32 | if (key == _oldKey) { 33 | setText(QString()); 34 | setPlaceholderText(getPlaceholderText(_oldKey)); 35 | } else { 36 | setPlaceholderText(getPlaceholderText(key)); 37 | } 38 | } 39 | 40 | bool HotkeyEdit::event(QEvent* event) { 41 | if (event->type() == QEvent::KeyPress) { 42 | QKeyEvent* e = static_cast(event); 43 | auto eModifiers = e->modifiers(); 44 | auto eKey = e->key(); 45 | 46 | if (eModifiers & Qt::ShiftModifier) { eKey += Qt::SHIFT; eModifiers ^= Qt::ShiftModifier; } 47 | if (eModifiers & Qt::ControlModifier) { eKey += Qt::CTRL; eModifiers ^= Qt::ControlModifier; } 48 | if (eModifiers & Qt::AltModifier) { eKey += Qt::ALT; eModifiers ^= Qt::AltModifier; } 49 | if (eModifiers & Qt::MetaModifier) { eKey += Qt::META; eModifiers ^= Qt::MetaModifier; } 50 | 51 | if (eModifiers == 0) { //all modifiers have been processed 52 | QKeySequence key = QKeySequence(eKey); 53 | auto keyboardKey = Qt::Key(key[0] & static_cast(~Qt::KeyboardModifierMask)); 54 | auto keyboardModifiers = Qt::KeyboardModifiers(key[0] & static_cast(Qt::KeyboardModifierMask)); 55 | 56 | if ((keyboardModifiers == Qt::NoModifier) && (keyboardKey == Qt::Key_Escape)) { // cancel edit 57 | _newKey = _oldKey; 58 | setText(QString()); 59 | setPlaceholderText(getPlaceholderText(_oldKey)); 60 | return true; 61 | } else if ((keyboardModifiers == Qt::NoModifier) && (keyboardKey == Qt::Key_Backspace)) { 62 | _newKey = 0; 63 | if (_oldKey != _newKey) { setText(QString(NoShortcutText)); } // mark as changed only if different 64 | setPlaceholderText(getPlaceholderText(0)); 65 | return true; 66 | } else if ((keyboardKey > 0) && (keyboardKey < 0xFFFF) && (keyboardModifiers != Qt::NoModifier) && (keyboardModifiers != Qt::ShiftModifier)) { 67 | _newKey = key; 68 | if (_oldKey != _newKey) { setText(QString(NoShortcutText)); } // mark as changed only if different 69 | setText(key.toString(QKeySequence::NativeText)); 70 | setPlaceholderText(getPlaceholderText(_oldKey)); 71 | return true; 72 | } 73 | } 74 | } 75 | return QLineEdit::event(event); 76 | } 77 | 78 | void HotkeyEdit::focusInEvent(QFocusEvent* e) { 79 | if (_hotkey != nullptr) { _hotkey->suspend(); } 80 | QLineEdit::focusInEvent(e); 81 | setPlaceholderText(QString(ChangeShortcutText)); 82 | } 83 | 84 | void HotkeyEdit::focusOutEvent(QFocusEvent* e) { 85 | if (_hotkey != nullptr) { _hotkey->resume(); } 86 | QLineEdit::focusOutEvent(e); 87 | setPlaceholderText(getPlaceholderText(_newKey)); 88 | } 89 | -------------------------------------------------------------------------------- /src/ui/hotkeyedit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "medo/hotkey.h" 4 | 5 | class HotkeyEdit: public QLineEdit { 6 | Q_OBJECT 7 | 8 | public: 9 | HotkeyEdit(QWidget* parent = nullptr); 10 | void setHotkey(Hotkey* hotkey, QKeySequence key); 11 | QKeySequence newKey() const { return _newKey; } 12 | void setNewKey(QKeySequence key); 13 | 14 | protected: 15 | bool event(QEvent* event); 16 | void focusInEvent(QFocusEvent* e); 17 | void focusOutEvent(QFocusEvent* e); 18 | 19 | private : 20 | Hotkey* _hotkey = nullptr; 21 | QKeySequence _oldKey; 22 | QKeySequence _newKey; 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /src/ui/inserttimedialog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "inserttimedialog.h" 4 | #include "ui_inserttimedialog.h" 5 | #include "helpers.h" 6 | #include "settings.h" 7 | 8 | InsertTimeDialog::InsertTimeDialog(QWidget* parent) : QDialog(parent), ui(new Ui::InsertTimeDialog) { 9 | ui->setupUi(this); 10 | Helpers::setupFixedSizeDialog(this); 11 | Helpers::setReadonlyPalette(ui->exampleText); 12 | 13 | ui->formatText->setText(Settings::timeFormat()); 14 | 15 | updateExample = new QTimer(this); 16 | connect(updateExample, &QTimer::timeout, this, &InsertTimeDialog::onUpdateExampleTimeout); 17 | updateExample->start(1000); 18 | 19 | connect(ui->formatText, &QLineEdit::textEdited, this, &InsertTimeDialog::onTextEdited); 20 | onUpdateExampleTimeout(); 21 | } 22 | 23 | InsertTimeDialog::~InsertTimeDialog() { 24 | delete ui; 25 | } 26 | 27 | void InsertTimeDialog::accept() { 28 | Settings::setTimeFormat(ui->formatText->text()); 29 | 30 | _formattedTime = getFormattedText(ui->formatText->text()); 31 | QDialog::accept(); 32 | } 33 | 34 | 35 | void InsertTimeDialog::onTextEdited(const QString& text) { 36 | ui->exampleText->setText(getFormattedText(text)); 37 | } 38 | 39 | void InsertTimeDialog::onUpdateExampleTimeout() { 40 | ui->exampleText->setText(getFormattedText(ui->formatText->text())); 41 | } 42 | 43 | QString InsertTimeDialog::getFormattedText(QString format) { 44 | if (format.trimmed().length() == 0) { 45 | return QDateTime::currentDateTime().toString(Qt::SystemLocaleShortDate); 46 | } else { 47 | return QDateTime::currentDateTime().toString(format); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/ui/inserttimedialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Ui { 6 | class InsertTimeDialog; 7 | } 8 | 9 | class InsertTimeDialog : public QDialog { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit InsertTimeDialog(QWidget* parent = nullptr); 14 | ~InsertTimeDialog(); 15 | QString formattedTime() const { return _formattedTime; } 16 | 17 | protected: 18 | void accept(); 19 | 20 | private: 21 | Ui::InsertTimeDialog* ui; 22 | QString _formattedTime; 23 | QTimer* updateExample = nullptr; 24 | QString getFormattedText(QString format = QString()); 25 | 26 | private slots: 27 | void onTextEdited(const QString& text); 28 | void onUpdateExampleTimeout(); 29 | 30 | }; 31 | -------------------------------------------------------------------------------- /src/ui/mainwindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "medo/dconfHotkey.h" 9 | #include "medo/hotkey.h" 10 | #include "storage/storage.h" 11 | 12 | 13 | namespace Ui { 14 | class MainWindow; 15 | } 16 | 17 | class MainWindow : public QMainWindow { 18 | Q_OBJECT 19 | 20 | public: 21 | explicit MainWindow(Storage* storage); 22 | ~MainWindow(); 23 | 24 | protected: 25 | void closeEvent(QCloseEvent* event) override; 26 | void changeEvent(QEvent* event) override; 27 | void keyPressEvent(QKeyEvent* event) override; 28 | void moveEvent(QMoveEvent* event) override; 29 | void resizeEvent(QResizeEvent* event) override; 30 | 31 | private: 32 | Ui::MainWindow* ui; 33 | Storage* _storage = nullptr; 34 | FolderItem* _folder = nullptr; 35 | QSystemTrayIcon* _tray = nullptr; 36 | QToolButton* _printButton = nullptr; 37 | QToolButton* _folderButton = nullptr; 38 | QToolButton* _appButton = nullptr; 39 | Hotkey* _hotkey = nullptr; 40 | DConfHotkey* _dconfHotkey = nullptr; 41 | QFutureWatcher* _futureWatcher = nullptr; 42 | QTimer* _moveTimer = nullptr; 43 | void applySettings() { applySettings(true, true, true, false, false, false, false, false); } 44 | void applySettings(bool applyShowInTaskbar, bool applyTabTextColorPerType, bool applyAlwaysOnTop, bool applyHotkey, bool applyDConfHotkey, bool applyDataPath, bool applyFont, bool applyForceDarkMode); 45 | void applyToolbarIcons(); 46 | bool selectFolder(QString folderName); 47 | bool selectFolder(FolderItem* folder); 48 | void selectFile(QString fileName); 49 | void selectFile(FileItem* file); 50 | 51 | private slots: 52 | void onFileActivated(FileItem* file); 53 | void onFileTitleChanged(FileItem* file); 54 | void onFileModificationChanged(FileItem* file, bool isModified); 55 | void onFileNew(); 56 | void onFileReopen(); 57 | void onFileSave(); 58 | void onFileRename(); 59 | void onFileDelete(); 60 | void onFilePrint(); 61 | void onFilePrintPreview(); 62 | void onFilePrintToPdf(); 63 | void onTextCut(); 64 | void onTextCopy(); 65 | void onTextPaste(); 66 | void onTextUndo(); 67 | void onTextRedo(); 68 | void onTextFontBold(); 69 | void onTextFontItalic(); 70 | void onTextFontUnderline(); 71 | void onTextFontStrikethrough(); 72 | void onFind(); 73 | void onFindNext(bool backward = false); 74 | void onGoto(); 75 | void onFolderSetup(); 76 | void onFolderMenuShow(); 77 | void onFolderMenuSelect(); 78 | void onFolderMove(); 79 | void onFileConvert(); 80 | void onOpenWithDefaultApplication(); 81 | void onOpenWithVisualStudioCode(); 82 | void onShowContainingDirectory(); 83 | void onShowContainingDirectoryOnly(); 84 | void onCopyContainingPath(); 85 | void onPhoneticSpelling(); 86 | void onTopMost(); 87 | void onAppSettings(); 88 | void onAppFeedback(); 89 | void onAppUpgrade(); 90 | void onAppUpgradeChecked(); 91 | void onAppAbout(); 92 | void onAppQuit(); 93 | void onTabMenuRequested(const QPoint&); 94 | void onTabChanged(); 95 | void onTabMoved(int from, int to); 96 | void onTextStateChanged(); 97 | void onHotkeyPress(); 98 | void onTrayActivate(QSystemTrayIcon::ActivationReason reason); 99 | void onTrayShow(); 100 | void onUpdatedFolder(FolderItem* folder); 101 | 102 | }; 103 | -------------------------------------------------------------------------------- /src/ui/newfiledialog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "helpers.h" 3 | #include "newfiledialog.h" 4 | #include "settings.h" 5 | #include "ui_newfiledialog.h" 6 | 7 | NewFileDialog::NewFileDialog(QWidget* parent, FolderItem* folder) : QDialog(parent), ui(new Ui::NewFileDialog) { 8 | ui->setupUi(this); 9 | Helpers::setupFixedSizeDialog(this); 10 | 11 | _folder = folder; 12 | 13 | QString baseFileTitle = "New file"; 14 | int index = 1; 15 | QString newFileTitle = baseFileTitle; 16 | while (folder->fileExists(newFileTitle)) { 17 | index++; 18 | newFileTitle = QString("%1 (%2)").arg(baseFileTitle, QString::number(index)); 19 | } 20 | ui->textTitle->setText(newFileTitle); 21 | 22 | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) 23 | bool showMarkdown = Settings::showMarkdown() || (Settings::defaultFileType() == FileType::Markdown); 24 | #else 25 | bool showMarkdown = false; 26 | #endif 27 | ui->radioMarkdown->setVisible(showMarkdown); 28 | 29 | switch (Settings::defaultFileType()) { 30 | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) 31 | case FileType::Markdown: ui->radioMarkdown->setChecked(true); break; 32 | #endif 33 | case FileType::Html: ui->radioHtml->setChecked(true); break; 34 | default: ui->radioPlain->setChecked(true); break; 35 | } 36 | 37 | connect(ui->textTitle, &QLineEdit::textChanged, this, &NewFileDialog::onChanged); 38 | connect(ui->radioMarkdown, &QRadioButton::toggled, this, &NewFileDialog::onChanged); 39 | connect(ui->radioPlain, &QRadioButton::toggled, this, &NewFileDialog::onChanged); 40 | connect(ui->radioHtml, &QRadioButton::toggled, this, &NewFileDialog::onChanged); 41 | onChanged(); 42 | 43 | ui->labelError->setStyleSheet("QLabel { background-color : red; color : black; padding-left: 3px; padding-right: 3px; }"); 44 | ui->labelError->setVisible(false); 45 | 46 | ui->textTitle->setFocus(); 47 | } 48 | 49 | NewFileDialog::~NewFileDialog() { 50 | delete ui; 51 | } 52 | 53 | 54 | QString NewFileDialog::title() const { 55 | return ui->textTitle->text(); 56 | } 57 | 58 | FileType NewFileDialog::type() const { 59 | if (ui->radioHtml->isChecked()) { 60 | return FileType::Html; 61 | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) 62 | } else if (ui->radioMarkdown->isChecked()) { 63 | return FileType::Markdown; 64 | #endif 65 | } else { 66 | return FileType::Plain; 67 | } 68 | } 69 | 70 | 71 | void NewFileDialog::onChanged() { 72 | QString text = ui->textTitle->text(); 73 | ui->labelError->setVisible(false); 74 | 75 | if (text.length() == 0) { 76 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 77 | } else { 78 | bool matchesName = false; 79 | for (FileItem* iFile : *_folder) { 80 | if (text.compare(iFile->title(), Qt::CaseInsensitive) == 0) { matchesName = true; break; } 81 | } 82 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!matchesName); 83 | if (matchesName) { 84 | ui->labelError->setText("File already exists"); 85 | ui->labelError->setVisible(true); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/ui/newfiledialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "storage/fileitem.h" 7 | #include "storage/folderitem.h" 8 | 9 | namespace Ui { 10 | class NewFileDialog; 11 | } 12 | 13 | class NewFileDialog : public QDialog { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit NewFileDialog(QWidget* parent, FolderItem* folder); 18 | ~NewFileDialog(); 19 | 20 | public: 21 | QString title() const; 22 | FileType type() const; 23 | 24 | private: 25 | Ui::NewFileDialog* ui; 26 | 27 | private: 28 | FolderItem* _folder = nullptr; //used for new file 29 | 30 | private slots: 31 | void onChanged(); 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /src/ui/newfiledialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | NewFileDialog 4 | 5 | 6 | Qt::WindowModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 320 13 | 112 14 | 15 | 16 | 17 | 18 | 320 19 | 0 20 | 21 | 22 | 23 | File Name 24 | 25 | 26 | 27 | 28 | 29 | 12 30 | 31 | 32 | 0 33 | 34 | 35 | 36 | 37 | Plain 38 | 39 | 40 | true 41 | 42 | 43 | 44 | 45 | 46 | 47 | Html 48 | 49 | 50 | 51 | 52 | 53 | 54 | Markdown 55 | 56 | 57 | 58 | 59 | 60 | 61 | Qt::Horizontal 62 | 63 | 64 | 65 | 40 66 | 20 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | File name: 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | true 93 | 94 | 95 | Error 96 | 97 | 98 | true 99 | 100 | 101 | false 102 | 103 | 104 | 105 | 106 | 107 | 108 | Qt::Horizontal 109 | 110 | 111 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | buttonBox 123 | rejected() 124 | NewFileDialog 125 | reject() 126 | 127 | 128 | 316 129 | 260 130 | 131 | 132 | 286 133 | 274 134 | 135 | 136 | 137 | 138 | buttonBox 139 | accepted() 140 | NewFileDialog 141 | accept() 142 | 143 | 144 | 248 145 | 254 146 | 147 | 148 | 157 149 | 274 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /src/ui/phoneticdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "helpers.h" 2 | #include "phoneticalphabet.h" 3 | #include "phoneticdialog.h" 4 | #include "ui_phoneticdialog.h" 5 | 6 | PhoneticDialog::PhoneticDialog(QWidget* parent, QString text) 7 | : QDialog(parent), ui(new Ui::PhoneticDialog) { 8 | ui->setupUi(this); 9 | Helpers::setupResizableDialog(this); 10 | Helpers::setReadonlyPalette(ui->txtOutput); 11 | 12 | connect(ui->txtInput, &QLineEdit::textChanged, this, &PhoneticDialog::onChanged); 13 | 14 | ui->txtInput->setText(text); 15 | } 16 | 17 | PhoneticDialog::~PhoneticDialog() { 18 | delete ui; 19 | } 20 | 21 | 22 | void PhoneticDialog::onChanged() { 23 | QString text = ui->txtInput->text(); 24 | QString output; 25 | 26 | bool addSpace = false; 27 | foreach (QString ch, text.split("")) { //splits on UTF-8 borders correctly 28 | if (ch.isEmpty()) { continue; } // SkipEmptyParts not supported on 5.12 29 | if (ch == " ") { 30 | output += "\n"; 31 | addSpace = false; 32 | } else { 33 | if (addSpace) { output += " "; } else { addSpace = true; } 34 | output += PhoneticAlphabet::getNatoText(ch); 35 | } 36 | } 37 | 38 | ui->txtOutput->document()->setPlainText(output); 39 | } 40 | -------------------------------------------------------------------------------- /src/ui/phoneticdialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Ui { 6 | class PhoneticDialog; 7 | } 8 | 9 | class PhoneticDialog : public QDialog { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit PhoneticDialog(QWidget* parent, QString text); 14 | ~PhoneticDialog(); 15 | 16 | private: 17 | Ui::PhoneticDialog* ui; 18 | 19 | private slots: 20 | void onChanged(); 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /src/ui/phoneticdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | PhoneticDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | Qt::Horizontal 21 | 22 | 23 | QDialogButtonBox::Close 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | true 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | buttonBox 43 | accepted() 44 | PhoneticDialog 45 | accept() 46 | 47 | 48 | 248 49 | 254 50 | 51 | 52 | 157 53 | 274 54 | 55 | 56 | 57 | 58 | buttonBox 59 | rejected() 60 | PhoneticDialog 61 | reject() 62 | 63 | 64 | 316 65 | 260 66 | 67 | 68 | 286 69 | 274 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/ui/qtabbarex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "qtabbarex.h" 5 | 6 | QTabBarEx::QTabBarEx(QWidget* parent) 7 | : QTabBar(parent) { 8 | 9 | } 10 | 11 | void QTabBarEx::mouseMoveEvent(QMouseEvent* event) { 12 | if ((event->buttons() & Qt::LeftButton) && (_sourceIndex >= 0) && !_moveInProgress) { 13 | auto destinationPoint = event->pos(); 14 | auto distanceSquared = pow(destinationPoint.x() - _sourcePoint.x(), 2) + pow(destinationPoint.y() - _sourcePoint.y(), 2); 15 | if (distanceSquared >= QApplication::startDragDistance()) { 16 | this->setCursor(Qt::SizeHorCursor); 17 | _moveInProgress = true; 18 | } 19 | } 20 | QTabBar::mouseMoveEvent(event); 21 | } 22 | 23 | void QTabBarEx::mousePressEvent(QMouseEvent* event) { 24 | if (event->button() == Qt::LeftButton) { 25 | if (_longClickTimer != nullptr) { delete _longClickTimer; } 26 | if (QElapsedTimer::isMonotonic()) { //don't deal with time if clock is not monotonic 27 | _longClickTimer = new QElapsedTimer(); 28 | _longClickTimer->start(); 29 | } 30 | 31 | _sourceIndex = this->tabAt(event->pos()); 32 | if (_sourceIndex >= 0) { 33 | _sourcePoint = event->pos(); 34 | _moveInProgress = false; 35 | } 36 | } 37 | QTabBar::mousePressEvent(event); 38 | } 39 | 40 | void QTabBarEx::mouseReleaseEvent(QMouseEvent* event) { 41 | if ((event->button() == Qt::LeftButton) && (_sourceIndex >= 0) && _moveInProgress) { 42 | int destinationIndex = this->tabAt(event->pos()); 43 | if (destinationIndex == -1) { 44 | if (event->x() > this->tabRect(this->count() - 1).right()) { 45 | destinationIndex = this->count() - 1; 46 | } else if (event->x() < this->tabRect(0).left()) { 47 | destinationIndex = 0; 48 | } 49 | } 50 | if ((_sourceIndex != destinationIndex) && (destinationIndex >= 0)) { 51 | moveTab(_sourceIndex, destinationIndex); 52 | } 53 | } else if ((event->button() == Qt::LeftButton) && (_longClickTimer != nullptr) && !_moveInProgress) { 54 | bool longPress = _longClickTimer->elapsed() >= (QApplication::startDragTime() * 3); 55 | delete _longClickTimer; 56 | _longClickTimer = nullptr; 57 | if (longPress) { this->customContextMenuRequested(event->pos()); } 58 | } 59 | 60 | _sourceIndex = -1; 61 | _moveInProgress = false; 62 | this->setCursor(Qt::ArrowCursor); 63 | QTabBar::mouseReleaseEvent(event); 64 | } 65 | 66 | void QTabBarEx::moveTab(int from, int to) { 67 | QTabBar::moveTab(from, to); 68 | emit tabMoved(from, to); 69 | } 70 | -------------------------------------------------------------------------------- /src/ui/qtabbarex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class QTabBarEx : public QTabBar { 9 | Q_OBJECT 10 | 11 | public: 12 | QTabBarEx(QWidget* parent = nullptr); 13 | void moveTab(int from, int to); 14 | 15 | protected: 16 | void mouseMoveEvent(QMouseEvent* event); 17 | void mousePressEvent(QMouseEvent* event); 18 | void mouseReleaseEvent(QMouseEvent* event); 19 | 20 | private: 21 | int _sourceIndex; 22 | QPoint _sourcePoint; 23 | bool _moveInProgress; 24 | QElapsedTimer* _longClickTimer = nullptr; 25 | 26 | signals: 27 | void tabMoved(int from, int to); 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /src/ui/qtabwidgetex.cpp: -------------------------------------------------------------------------------- 1 | #include "storage/fileitem.h" 2 | #include "qtabwidgetex.h" 3 | #include "qtabbarex.h" 4 | 5 | QTabWidgetEx::QTabWidgetEx(QWidget* parent) 6 | : QTabWidget(parent) { 7 | QTabBarEx* bar = new QTabBarEx(); 8 | this->setTabBar(bar); 9 | 10 | connect(bar, &QTabBarEx::tabMoved, this, &QTabWidgetEx::onTabMoved); 11 | } 12 | 13 | 14 | int QTabWidgetEx::addTab(QWidget* widget, const QString& text) { 15 | FileItem* item = dynamic_cast(widget); 16 | 17 | QTabBar* tabBar = this->tabBar(); 18 | int index = QTabWidget::addTab(widget, text); 19 | 20 | if (Settings::tabTextColorPerType()) { //playing with color 21 | QColor color = tabBar->tabTextColor(index); 22 | bool isDark = ((color.red() + color.green() + color.blue()) / 3) < 64; 23 | QColor newColor; 24 | switch (item->type()) { 25 | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) 26 | case FileType::Markdown: //green 27 | newColor = isDark ? QColor(color.red(), 96, color.blue()) 28 | : QColor(color.red() * 0.75, color.green(), color.blue() * 0.75); 29 | break; 30 | #endif 31 | case FileType::Html: //blue 32 | newColor = isDark ? QColor(color.red(), color.green(), 128) 33 | : QColor(color.red() * 0.75, color.green() * 0.75, color.blue()); 34 | break; 35 | default: 36 | newColor = color; 37 | break; 38 | } 39 | this->tabBar()->setTabTextColor(index, newColor); 40 | } 41 | 42 | return index; 43 | } 44 | 45 | 46 | void QTabWidgetEx::onTabMoved(int from, int to) { 47 | auto fileFrom = dynamic_cast(this->widget(from)); 48 | this->setTabText(from, fileFrom->title()); 49 | auto fileTo = dynamic_cast(this->widget(to)); 50 | this->setTabText(to, fileTo->title()); 51 | emit tabMoved(from, to); 52 | } 53 | -------------------------------------------------------------------------------- /src/ui/qtabwidgetex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class QTabWidgetEx : public QTabWidget { 7 | Q_OBJECT 8 | 9 | public: 10 | QTabWidgetEx(QWidget* parent = nullptr); 11 | int addTab(QWidget* widget, const QString& text); 12 | 13 | private slots: 14 | void onTabMoved(int from, int to); 15 | 16 | signals: 17 | void tabMoved(int from, int to); 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /src/ui/renamefiledialog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "renamefiledialog.h" 3 | #include "ui_renamefiledialog.h" 4 | #include "helpers.h" 5 | 6 | RenameFileDialog::RenameFileDialog(QWidget* parent, FileItem* file) : QDialog(parent), ui(new Ui::RenameFileDialog) { 7 | ui->setupUi(this); 8 | Helpers::setupFixedSizeDialog(this); 9 | 10 | _file = file; 11 | 12 | ui->textTitle->setText(file->title()); 13 | 14 | connect(ui->textTitle, &QLineEdit::textChanged, this, &RenameFileDialog::onChanged); 15 | onChanged(); 16 | 17 | ui->textTitle->setFocus(); 18 | } 19 | 20 | RenameFileDialog::~RenameFileDialog() { 21 | delete ui; 22 | } 23 | 24 | 25 | QString RenameFileDialog::title() const { 26 | return ui->textTitle->text(); 27 | } 28 | 29 | 30 | void RenameFileDialog::onChanged() { 31 | QString text = ui->textTitle->text(); 32 | 33 | if (text.length() == 0) { 34 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 35 | } else { 36 | bool foundMatch = false; 37 | for (FileItem* iFile : *_file->folder()) { 38 | if (_file == iFile) { 39 | if (text.compare(iFile->title(), Qt::CaseSensitive) == 0) { foundMatch = true; break; } 40 | } else { 41 | if (text.compare(iFile->title(), Qt::CaseInsensitive) == 0) { foundMatch = true; break; } 42 | } 43 | } 44 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!foundMatch); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/ui/renamefiledialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "storage/folderitem.h" 7 | 8 | namespace Ui { class RenameFileDialog; } 9 | 10 | class RenameFileDialog : public QDialog { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit RenameFileDialog(QWidget* parent, FileItem* file); 15 | ~RenameFileDialog(); 16 | QString title() const; 17 | 18 | private: 19 | Ui::RenameFileDialog* ui; 20 | FileItem* _file; 21 | 22 | private slots: 23 | void onChanged(); 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /src/ui/renamefiledialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | RenameFileDialog 4 | 5 | 6 | Qt::WindowModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 300 13 | 79 14 | 15 | 16 | 17 | 18 | 300 19 | 0 20 | 21 | 22 | 23 | File Name 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | File name: 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Qt::Horizontal 44 | 45 | 46 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | buttonBox 56 | accepted() 57 | RenameFileDialog 58 | accept() 59 | 60 | 61 | 248 62 | 254 63 | 64 | 65 | 157 66 | 274 67 | 68 | 69 | 70 | 71 | buttonBox 72 | rejected() 73 | RenameFileDialog 74 | reject() 75 | 76 | 77 | 316 78 | 260 79 | 80 | 81 | 286 82 | 274 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /src/ui/settingsdialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "medo/hotkey.h" 5 | 6 | namespace Ui { 7 | class SettingsDialog; 8 | } 9 | 10 | class SettingsDialog : public QDialog { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit SettingsDialog(QWidget* parent = nullptr, Hotkey* hotkey = nullptr); 15 | ~SettingsDialog(); 16 | bool changedAlwaysOnTop() const { return _changedAlwaysOnTop; } 17 | bool changedAutostart() const { return _changedAutostart; } 18 | bool changedDataPath() const { return _changedDataPath; } 19 | bool changedFollowUrlWithCtrl() const { return _changedFollowUrlWithCtrl; } 20 | bool changedFollowUrlWithDoubleClick() const { return _changedFollowUrlWithDoubleClick; } 21 | bool changedFont() const { return _changedFont; } 22 | bool changedForceDarkMode() const { return _changedForceDarkMode; } 23 | bool changedForcePlainCopyPaste() const { return _changedForcePlainCopyPaste; } 24 | bool changedHotkey() const { return _changedHotkey; } 25 | bool changedHotkeyUseDConf() const { return _changedHotkeyUseDConf; } 26 | bool changedHotkeyTogglesVisibility() const { return _changedHotkeyTogglesVisibility; } 27 | bool changedMinimizeToTray() const { return _changedMinimizeToTray; } 28 | bool changedShowInTaskbar() const { return _changedShowInTaskbar; } 29 | bool changedShowMarkdown() const { return _changedShowMarkdown; } 30 | bool changedTabTextColorPerType() const { return _changedTabTextColorPerType; } 31 | bool changedUseHtmlByDefault() const { return _changedUseHtmlByDefault; } 32 | 33 | protected: 34 | void keyPressEvent(QKeyEvent* event); 35 | void accept(); 36 | 37 | private: 38 | Ui::SettingsDialog* ui; 39 | void reset(); 40 | void restoreDefaults(); 41 | bool _changedAlwaysOnTop; 42 | bool _changedAutostart; 43 | bool _changedDataPath; 44 | bool _changedFollowUrlWithCtrl; 45 | bool _changedFollowUrlWithDoubleClick; 46 | bool _changedFont; 47 | bool _changedForceDarkMode; 48 | bool _changedForcePlainCopyPaste; 49 | bool _changedHotkey; 50 | bool _changedHotkeyUseDConf; 51 | bool _changedHotkeyTogglesVisibility; 52 | bool _changedMinimizeToTray; 53 | bool _changedShowInTaskbar; 54 | bool _changedShowMarkdown; 55 | bool _changedTabTextColorPerType; 56 | bool _changedUseHtmlByDefault; 57 | bool _oldAlwaysOnTop; 58 | bool _oldAutostart; 59 | QString _oldDataPath; 60 | bool _oldFollowUrlWithCtrl; 61 | bool _oldFollowUrlWithDoubleClick; 62 | QString _oldFontName; 63 | int _oldFontSize; 64 | bool _oldForceDarkMode; 65 | bool _oldForcePlainCopyPaste; 66 | QKeySequence _oldHotkey; 67 | bool _oldHotkeyUseDConf; 68 | bool _oldHotkeyTogglesVisibility; 69 | bool _oldMinimizeToTray; 70 | bool _oldShowInTaskbar; 71 | bool _oldShowMarkdown; 72 | bool _oldTabTextColorPerType; 73 | bool _oldUseHtmlByDefault; 74 | 75 | private slots: 76 | void onButtonClicked(QAbstractButton* button); 77 | void onDataPathClicked(); 78 | void onFontClicked(); 79 | 80 | }; 81 | --------------------------------------------------------------------------------