mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-12-04 15:39:34 +01:00
Compare commits
483 Commits
2.0-alpha6
...
2.0.3-http
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e19559fe81 | ||
|
|
7dd30d4db1 | ||
|
|
9b8b7b490a | ||
|
|
5ec9d0685d | ||
|
|
004c412501 | ||
|
|
f05caf7623 | ||
|
|
7d165f133a | ||
|
|
fff9e7ac46 | ||
|
|
ad834f0f58 | ||
|
|
8a50ee8b22 | ||
|
|
cf8186312a | ||
|
|
8f87b5cfd4 | ||
|
|
61ce733c6f | ||
|
|
c78822f6e6 | ||
|
|
a10a30f390 | ||
|
|
7c7014d951 | ||
|
|
dee331d52d | ||
|
|
2146392a2f | ||
|
|
e011a6eb25 | ||
|
|
5eadd10612 | ||
|
|
c2a80ce570 | ||
|
|
3415073051 | ||
|
|
ba68e0a4a1 | ||
|
|
8a7e98820a | ||
|
|
d61e4d69b5 | ||
|
|
9b8912c483 | ||
|
|
878995366a | ||
|
|
1635a5211f | ||
|
|
595b1011dd | ||
|
|
9bb291235d | ||
|
|
7d4ef0b8d0 | ||
|
|
8d16522d39 | ||
|
|
cd1192b409 | ||
|
|
bf2fd63131 | ||
|
|
029da87346 | ||
|
|
9532bedd7d | ||
|
|
e9c8363b70 | ||
|
|
fb57ed2bcd | ||
|
|
57ec558396 | ||
|
|
6e2de1cd79 | ||
|
|
8ace3ab7f2 | ||
|
|
18e4dca6c9 | ||
|
|
99bb5d33f2 | ||
|
|
d4ed4f9325 | ||
|
|
bb2e1ee8da | ||
|
|
51bfbc964e | ||
|
|
48eca3e11f | ||
|
|
57c1a0f4b6 | ||
|
|
bde4d63fdb | ||
|
|
cbb1269b39 | ||
|
|
175167b311 | ||
|
|
029052fa18 | ||
|
|
a454469949 | ||
|
|
0562ed720b | ||
|
|
cbe8a9649c | ||
|
|
f48fdc1d71 | ||
|
|
7f7753a004 | ||
|
|
aba4fa94be | ||
|
|
4eea7c8297 | ||
|
|
4867d26f7d | ||
|
|
9bd3ab717e | ||
|
|
d6d92ce90a | ||
|
|
3679b21701 | ||
|
|
49f58b4ed8 | ||
|
|
235361faf4 | ||
|
|
208b803fbe | ||
|
|
8a92cec03f | ||
|
|
00f068b93e | ||
|
|
654353e26b | ||
|
|
d670ef2638 | ||
|
|
aff935b3c7 | ||
|
|
107c0673c7 | ||
|
|
c14d04b3e8 | ||
|
|
7a017041bf | ||
|
|
bfae81ec70 | ||
|
|
71d4cb781d | ||
|
|
eb56bd8973 | ||
|
|
93585aded7 | ||
|
|
38245aa2a9 | ||
|
|
1f33e6f044 | ||
|
|
4752adf9d3 | ||
|
|
2d741afe3e | ||
|
|
5e6b17aba4 | ||
|
|
c51098e2cf | ||
|
|
ecfbf72a57 | ||
|
|
24275d8dc4 | ||
|
|
94d82948f6 | ||
|
|
54fb1abb96 | ||
|
|
a3b936fcd0 | ||
|
|
efc4cd5969 | ||
|
|
17ab438c5a | ||
|
|
77b4bfb14e | ||
|
|
7839280cb3 | ||
|
|
9e1ea264e2 | ||
|
|
b02ec98ec6 | ||
|
|
2fa531745f | ||
|
|
0c36c40a5d | ||
|
|
6337e673f9 | ||
|
|
e800892cc1 | ||
|
|
a21e893749 | ||
|
|
dff3fc0572 | ||
|
|
5de0ec94e0 | ||
|
|
a408b01111 | ||
|
|
6e45cf0dab | ||
|
|
dc7b6623a9 | ||
|
|
820941fd40 | ||
|
|
862941abf6 | ||
|
|
e98c30f633 | ||
|
|
316a7e6fb7 | ||
|
|
58ed99d562 | ||
|
|
840642394f | ||
|
|
9484af5329 | ||
|
|
3cf1a16398 | ||
|
|
0f0af12353 | ||
|
|
7cb9a4ee4a | ||
|
|
28a1eb86da | ||
|
|
86f12d9e83 | ||
|
|
539f86fd0b | ||
|
|
c93b12ff05 | ||
|
|
319edca870 | ||
|
|
ebeedba072 | ||
|
|
568dfde074 | ||
|
|
5a59287927 | ||
|
|
b8c1829857 | ||
|
|
4f2d56a55f | ||
|
|
6b49f8f26b | ||
|
|
fc8cb7cd14 | ||
|
|
727094abc6 | ||
|
|
20726ae75c | ||
|
|
3b2a39fd38 | ||
|
|
bcb54bc38a | ||
|
|
14aac09318 | ||
|
|
9d42db9849 | ||
|
|
ee81c7c00e | ||
|
|
2edf414aa4 | ||
|
|
54f44f5267 | ||
|
|
6ab54bc95a | ||
|
|
c8ae31a248 | ||
|
|
66a01e4fef | ||
|
|
d559db4fb1 | ||
|
|
673dff2268 | ||
|
|
6f5871434d | ||
|
|
685f249fd0 | ||
|
|
26ccd577b5 | ||
|
|
bb38be40f6 | ||
|
|
f236c32063 | ||
|
|
236edae60b | ||
|
|
5a13402b51 | ||
|
|
82aa02a980 | ||
|
|
3dd98deecc | ||
|
|
2e23fb203a | ||
|
|
625e9a2547 | ||
|
|
aab2b7df1c | ||
|
|
31bd44bec5 | ||
|
|
11532b603a | ||
|
|
523c88b80d | ||
|
|
7cf1bb7e38 | ||
|
|
eb9fdb43c1 | ||
|
|
0362f45547 | ||
|
|
31f55fdb26 | ||
|
|
26928a63e8 | ||
|
|
abacec5787 | ||
|
|
d84af2def0 | ||
|
|
7fa0eddc5f | ||
|
|
0e85c98d02 | ||
|
|
ae2b27d400 | ||
|
|
7c424e1b85 | ||
|
|
ba1ca4ec08 | ||
|
|
20b13a4a2e | ||
|
|
460b23b1eb | ||
|
|
9882f16614 | ||
|
|
60daa2b41b | ||
|
|
d81565df55 | ||
|
|
e2ac176d3c | ||
|
|
ec8c0bb3e7 | ||
|
|
b904fe5acd | ||
|
|
3b07098731 | ||
|
|
03a330a4dd | ||
|
|
6502da549b | ||
|
|
a71e25a8ba | ||
|
|
9e05f41747 | ||
|
|
208b0f39e6 | ||
|
|
5ad9edc3fd | ||
|
|
c714fc89f1 | ||
|
|
e3cde7b55e | ||
|
|
5a745da07b | ||
|
|
531018e58d | ||
|
|
813c64a055 | ||
|
|
a954e9a4d8 | ||
|
|
95c449481e | ||
|
|
0b43607aa1 | ||
|
|
e75efb8bfb | ||
|
|
d83fee89bd | ||
|
|
b773dbe645 | ||
|
|
5c7c7f54fa | ||
|
|
98417d6465 | ||
|
|
0ea64afe92 | ||
|
|
a862f62fe8 | ||
|
|
5bd525a6dd | ||
|
|
af3d896bdf | ||
|
|
ceeb72a277 | ||
|
|
2c17fdcff0 | ||
|
|
41a7c96968 | ||
|
|
98d9dae087 | ||
|
|
2033174d95 | ||
|
|
606e36acf3 | ||
|
|
0422943d52 | ||
|
|
0024f2e30f | ||
|
|
abe5e8ecea | ||
|
|
61503a8047 | ||
|
|
fcb5deff0a | ||
|
|
fdec16c3a0 | ||
|
|
84ee8b993f | ||
|
|
3d1c27ceb7 | ||
|
|
7d3fb58cf5 | ||
|
|
df5da2fcef | ||
|
|
1226d1dbd5 | ||
|
|
607007f94f | ||
|
|
6327eaf587 | ||
|
|
b1fd99f4c4 | ||
|
|
d1331053c8 | ||
|
|
c6fe0da569 | ||
|
|
b9fe2c1bf9 | ||
|
|
3efc8f457a | ||
|
|
65e8732eeb | ||
|
|
e82015d419 | ||
|
|
fa0fe6d33d | ||
|
|
8be135adf9 | ||
|
|
d04927ce7f | ||
|
|
6889cc2f20 | ||
|
|
8325b20d36 | ||
|
|
826cd472c8 | ||
|
|
8ecab15c33 | ||
|
|
c9520214e2 | ||
|
|
6d1ca363af | ||
|
|
2170794d9c | ||
|
|
719ac64851 | ||
|
|
d3a7e0dee9 | ||
|
|
240919335f | ||
|
|
ceb6a0383e | ||
|
|
0185b112e1 | ||
|
|
af84261eb6 | ||
|
|
274f86fd04 | ||
|
|
bcc3108c3d | ||
|
|
5f1b286630 | ||
|
|
8ad48d6774 | ||
|
|
721bec9794 | ||
|
|
c6105a08ab | ||
|
|
154f1673e9 | ||
|
|
577609b3e3 | ||
|
|
f22069bb11 | ||
|
|
280a1aceb9 | ||
|
|
0390c67c4d | ||
|
|
1f6161132e | ||
|
|
fc74e16097 | ||
|
|
b03f54ffcd | ||
|
|
26f33a1c12 | ||
|
|
6e8aeea76d | ||
|
|
c736ba7059 | ||
|
|
3eb4b3b208 | ||
|
|
5982763bed | ||
|
|
6b7f7bb777 | ||
|
|
5b9338e40e | ||
|
|
eab4861383 | ||
|
|
bcd3de1180 | ||
|
|
f4361dd4d5 | ||
|
|
4008e6ab58 | ||
|
|
a115bbdc6f | ||
|
|
fc43aa1717 | ||
|
|
d553698b20 | ||
|
|
7db9c78855 | ||
|
|
7a2c02f0df | ||
|
|
c535736853 | ||
|
|
a8bf6a9782 | ||
|
|
0458dad6dc | ||
|
|
68373730bf | ||
|
|
5d9039ea89 | ||
|
|
7e1faadd11 | ||
|
|
fceb93061d | ||
|
|
c9d007fcdf | ||
|
|
eeb940c0dc | ||
|
|
05b5446e94 | ||
|
|
b45437d502 | ||
|
|
a599787a25 | ||
|
|
58061af959 | ||
|
|
33ed4fd7cf | ||
|
|
8bf1bb0517 | ||
|
|
d26cff520f | ||
|
|
04aa10cee7 | ||
|
|
ade684d501 | ||
|
|
4362c3ea38 | ||
|
|
e0d4b4b625 | ||
|
|
cfffdae573 | ||
|
|
f6243675c9 | ||
|
|
a762cef0a9 | ||
|
|
a7f4e2d0cd | ||
|
|
ae013c2196 | ||
|
|
eefe844dcd | ||
|
|
94111c3662 | ||
|
|
3fca61dc24 | ||
|
|
e41bf008e9 | ||
|
|
6c9c0fd5c5 | ||
|
|
f3d956ceed | ||
|
|
b9c9c56059 | ||
|
|
bed58cde84 | ||
|
|
855d79e28f | ||
|
|
a044467d10 | ||
|
|
ecb2e337ef | ||
|
|
2dde18b179 | ||
|
|
6411b9bd66 | ||
|
|
d70ee509b4 | ||
|
|
cf0bc32b27 | ||
|
|
93ab7eb058 | ||
|
|
bd3ae05fcf | ||
|
|
b055d524e8 | ||
|
|
9e051e835b | ||
|
|
e20968bdfe | ||
|
|
3ab1072e9e | ||
|
|
00df73ced0 | ||
|
|
940a5026c1 | ||
|
|
2631277184 | ||
|
|
b86b640860 | ||
|
|
2dfc740782 | ||
|
|
e4985f4ff7 | ||
|
|
22f579a59e | ||
|
|
c9d12e93c2 | ||
|
|
778f01bcf1 | ||
|
|
ccb7a4c96d | ||
|
|
9e124e4a75 | ||
|
|
db37b7b933 | ||
|
|
2e94066e50 | ||
|
|
61c6962bf2 | ||
|
|
9cbdd58af5 | ||
|
|
eea9d7db97 | ||
|
|
235baa3dcc | ||
|
|
f04f4302a2 | ||
|
|
33650c4a04 | ||
|
|
019cf9684c | ||
|
|
835c411d12 | ||
|
|
e4758c1984 | ||
|
|
eb22f0a2d8 | ||
|
|
3ea0592b53 | ||
|
|
876a75b572 | ||
|
|
c39898dad9 | ||
|
|
07a3d7a696 | ||
|
|
7f412fbd7f | ||
|
|
2adc64939f | ||
|
|
71d39865b3 | ||
|
|
226c061c01 | ||
|
|
dd2fbebb81 | ||
|
|
889c742a33 | ||
|
|
5cc3334325 | ||
|
|
e58be44523 | ||
|
|
34a7321786 | ||
|
|
07e4fbacd4 | ||
|
|
8fd69e084e | ||
|
|
dd79105baa | ||
|
|
b1c3814972 | ||
|
|
57107ea560 | ||
|
|
4b3a82592c | ||
|
|
6ecb8690f2 | ||
|
|
1c365b8417 | ||
|
|
315df0b8a8 | ||
|
|
87468b648b | ||
|
|
4cdb9a645d | ||
|
|
870d7355ca | ||
|
|
f1aa6aca26 | ||
|
|
72b59d541a | ||
|
|
0e8aa0bc6c | ||
|
|
3a0648cf25 | ||
|
|
2e76385cae | ||
|
|
867d14f7aa | ||
|
|
0d6117bf4c | ||
|
|
b417bf9187 | ||
|
|
7137990a21 | ||
|
|
916ab99d62 | ||
|
|
5a31e055cf | ||
|
|
28694ae687 | ||
|
|
becd3a0019 | ||
|
|
8cc1e6008e | ||
|
|
910788c038 | ||
|
|
9391de74c7 | ||
|
|
c806f9ebf4 | ||
|
|
e776de8eeb | ||
|
|
a25b28ffee | ||
|
|
0e75e6ff03 | ||
|
|
76da4a6cd4 | ||
|
|
8a4100adbd | ||
|
|
584f4b50bf | ||
|
|
9ac01c930d | ||
|
|
d874f58a39 | ||
|
|
05de45dadb | ||
|
|
4ab887c773 | ||
|
|
552ca7bf71 | ||
|
|
2d8ba2b394 | ||
|
|
a6d44034a4 | ||
|
|
77af79498c | ||
|
|
ea3375490c | ||
|
|
204cd8d971 | ||
|
|
c2940a8f18 | ||
|
|
4f60df029d | ||
|
|
819cfd459a | ||
|
|
c90ac914bb | ||
|
|
8bf4826003 | ||
|
|
e361b0dd81 | ||
|
|
ce7e01a1b1 | ||
|
|
cda5e990ac | ||
|
|
50cbd80925 | ||
|
|
75d3e6261b | ||
|
|
bf39d0b1be | ||
|
|
147cd4ed7b | ||
|
|
9363d23e09 | ||
|
|
b718e9d8f2 | ||
|
|
65eb71e645 | ||
|
|
d6c30b0886 | ||
|
|
7c7f0b93ae | ||
|
|
e263c475c9 | ||
|
|
c917096d3c | ||
|
|
5de62a5ef4 | ||
|
|
7893a2e84d | ||
|
|
47e885ddbf | ||
|
|
65626f0da2 | ||
|
|
8584901f9e | ||
|
|
ad26d962dc | ||
|
|
967a9f0195 | ||
|
|
6c663a19bf | ||
|
|
b194c29166 | ||
|
|
0b9167c78b | ||
|
|
63ae460a80 | ||
|
|
e2d446e446 | ||
|
|
54306473f3 | ||
|
|
c7158234dc | ||
|
|
b28cb19ae3 | ||
|
|
86a01b6984 | ||
|
|
b432103b82 | ||
|
|
75564c8fb5 | ||
|
|
b87097a7ab | ||
|
|
6ef5f34070 | ||
|
|
b953ea9042 | ||
|
|
61ada66e3a | ||
|
|
a9a724714f | ||
|
|
612ef0ef9b | ||
|
|
a627870bbb | ||
|
|
fae4f69b8c | ||
|
|
b27ba03d42 | ||
|
|
2cd6787141 | ||
|
|
21204971ff | ||
|
|
c570a13a1f | ||
|
|
5c71260c12 | ||
|
|
e105970945 | ||
|
|
0c33019f93 | ||
|
|
16598a8386 | ||
|
|
f52f6e2d44 | ||
|
|
304cebefe4 | ||
|
|
d7a8a43024 | ||
|
|
73f91db939 | ||
|
|
41be9e8178 | ||
|
|
be24872bba | ||
|
|
db56546871 | ||
|
|
53b30e267c | ||
|
|
8f33c5235b | ||
|
|
d8857bf42d | ||
|
|
a85ac07576 | ||
|
|
d2ab008aa0 | ||
|
|
f4ff8b17f7 | ||
|
|
d5c8787451 | ||
|
|
850c7c7ecf | ||
|
|
7ff475977e | ||
|
|
478d30b529 | ||
|
|
d6597400de | ||
|
|
af394ff65c | ||
|
|
f6fa6d6563 | ||
|
|
fd7a49f4a6 | ||
|
|
47d7598e99 | ||
|
|
e2ba754f91 | ||
|
|
c98aad698a | ||
|
|
75f0d132e5 | ||
|
|
f82725139a | ||
|
|
b9e58c77af | ||
|
|
ad67eac257 | ||
|
|
eef51f26f0 | ||
|
|
ea992bc3e6 | ||
|
|
20f3f23576 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
src/version.h.cmake export-subst
|
||||
33
.travis.yml
Normal file
33
.travis.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
language: cpp
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
os:
|
||||
- linux
|
||||
# - osx
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
# - clang
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq update; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install cmake libmicrohttpd10 libmicrohttpd-dev libxi-dev qtbase5-dev libqt5x11extras5-dev qttools5-dev qttools5-dev-tools libgcrypt20-dev zlib1g-dev libxtst-dev xvfb; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew ls | grep -wq cmake || brew install cmake; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew ls | grep -wq qt5 || brew install qt5; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew ls | grep -wq libgcrypt || brew install libgcrypt; fi
|
||||
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then CMAKE_ARGS="-DCMAKE_PREFIX_PATH=/usr/local/opt/qt5"; fi
|
||||
- mkdir build && pushd build
|
||||
|
||||
script:
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUI_TESTS=ON $CMAKE_ARGS ..
|
||||
- make
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then make test ARGS+="-E testgui --output-on-failure"; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then xvfb-run -a --server-args="-screen 0 800x600x24" make test ARGS+="-R testgui --output-on-failure"; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then make test ARGS+="--output-on-failure"; fi
|
||||
8
.tx/config
Normal file
8
.tx/config
Normal file
@@ -0,0 +1,8 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[keepassx.keepassx_ents]
|
||||
source_file = share/translations/keepassx_en.ts
|
||||
file_filter = share/translations/keepassx_<lang>.ts
|
||||
source_lang = en
|
||||
type = QT
|
||||
67
CHANGELOG
67
CHANGELOG
@@ -1,4 +1,69 @@
|
||||
2.0 Alpha 6 (2014-04-06)
|
||||
2.0.3 (2016-09-04)
|
||||
=========================
|
||||
|
||||
- Improved error reporting when reading / writing databases fails. [#450, #462]
|
||||
- Display an error message when opening a custom icon fails.
|
||||
- Detect custom icon format based on contents instead of the filename. [#512]
|
||||
- Keep symlink intact when saving databases. [#442].
|
||||
- Fix a crash when deleting parent group of recycle bin. [#520]
|
||||
- Display a confirm dialog before moving an entry to the recycle bin. [#447]
|
||||
- Repair UUIDs of inconsistent history items. [#130]
|
||||
- Only include top-level windows in auto-type window list when using gnome-shell.
|
||||
- Update translations.
|
||||
|
||||
2.0.2 (2016-02-02)
|
||||
=========================
|
||||
|
||||
- Fix regression in database writer that caused it to strip certain special
|
||||
characters (characters from Unicode plane > 0).
|
||||
- Fix bug in repair function that caused it to strip non-ASCII characters.
|
||||
|
||||
2.0.1 (2016-01-31)
|
||||
=========================
|
||||
|
||||
- Flush temporary file before opening attachment. [#390]
|
||||
- Disable password generator when showing entry in history mode. [#422]
|
||||
- Strip invalid XML chars when writing databases. [#392]
|
||||
- Add repair function to fix databases with invalid XML chars. [#392]
|
||||
- Display custom icons scaled. [#322]
|
||||
- Allow opening databases that have no password and keyfile. [#391]
|
||||
- Fix crash when importing .kdb files with invalid icon ids. [#425]
|
||||
- Update translations.
|
||||
|
||||
2.0 (2015-12-06)
|
||||
=========================
|
||||
|
||||
- Improve UI of the search edit.
|
||||
- Clear clipboard when locking databases. [#342]
|
||||
- Enable Ctrl+M shortcut to minimize the window on all platforms. [#329]
|
||||
- Show a better message when trying to open an old database format. [#338]
|
||||
- Fix global auto-type behavior with some window managers.
|
||||
- Show global auto-type window on the active desktop. [#359]
|
||||
- Disable systray on OS X. [#326]
|
||||
- Restore main window when clicking on the OS X docker icon. [#326]
|
||||
|
||||
2.0 Beta 2 (2015-09-06)
|
||||
=========================
|
||||
|
||||
- Fix crash when locking with search UI open [#309]
|
||||
- Fix file locking on Mac OS X [#327]
|
||||
- Set default extension when saving a database [#79, #308]
|
||||
|
||||
2.0 Beta 1 (2015-07-18)
|
||||
=========================
|
||||
|
||||
- Remember entry column sizes [#159]
|
||||
- Add translations
|
||||
- Support opening attachments directly
|
||||
- Support cmd:// URLs [#244]
|
||||
- Protect opened databases with a file lock [#18]
|
||||
- Export to csv files [#57]
|
||||
- Add optional tray icon [#153]
|
||||
- Allow setting the default auto-type sequence for groups [#175]
|
||||
- Make the kdbx parser more lenient
|
||||
- Remove --password command line option [#285]
|
||||
|
||||
2.0 Alpha 6 (2014-04-12)
|
||||
=========================
|
||||
|
||||
- Add option to lock databases after user inactivity [#62]
|
||||
|
||||
@@ -21,7 +21,7 @@ endif()
|
||||
|
||||
project(KeePassX)
|
||||
|
||||
cmake_minimum_required(VERSION 2.6.4)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
@@ -31,11 +31,10 @@ include(CheckCXXSourceCompiles)
|
||||
|
||||
option(WITH_TESTS "Enable building of unit tests" ON)
|
||||
option(WITH_GUI_TESTS "Enable building of GUI tests" OFF)
|
||||
option(WITH_LTO "Enable Link Time Optimization (LTO)" OFF)
|
||||
option(WITH_CXX11 "Build with the C++ 11 standard" OFF)
|
||||
option(WITH_DEV_BUILD "Use only for development. Disables/warns about deprecated methods." OFF)
|
||||
|
||||
set(KEEPASSX_VERSION "2.0 alpha 6")
|
||||
set(KEEPASSX_VERSION_NUM "1.9.85")
|
||||
set(KEEPASSX_VERSION "2.0.3")
|
||||
set(KEEPASSX_VERSION_NUM "2.0.3")
|
||||
|
||||
if("${CMAKE_C_COMPILER}" MATCHES "clang$" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
|
||||
set(CMAKE_COMPILER_IS_CLANG 1)
|
||||
@@ -62,7 +61,7 @@ macro(add_gcc_compiler_flags FLAGS)
|
||||
add_gcc_compiler_cflags("${FLAGS}")
|
||||
endmacro(add_gcc_compiler_flags)
|
||||
|
||||
add_definitions(-DQT_NO_KEYWORDS -DQT_NO_EXCEPTIONS -DQT_NO_STL -DQT_STRICT_ITERATORS -DQT_NO_CAST_TO_ASCII)
|
||||
add_definitions(-DQT_NO_KEYWORDS -DQT_NO_EXCEPTIONS -DQT_STRICT_ITERATORS -DQT_NO_CAST_TO_ASCII)
|
||||
|
||||
add_gcc_compiler_flags("-fno-common -fstack-protector --param=ssp-buffer-size=4")
|
||||
add_gcc_compiler_flags("-Wall -Wextra -Wundef -Wpointer-arith -Wno-long-long")
|
||||
@@ -101,25 +100,16 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,relro")
|
||||
endif()
|
||||
|
||||
if(WITH_LTO)
|
||||
if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_COMPILER_IS_GNUCXX)
|
||||
check_cxx_compiler_flag("-flto -fuse-linker-plugin" LTO_AVAILABLE)
|
||||
add_gcc_compiler_cxxflags("-std=c++11")
|
||||
|
||||
if(LTO_AVAILABLE)
|
||||
add_gcc_compiler_flags("-flto -fuse-linker-plugin")
|
||||
else()
|
||||
message(FATAL_ERROR "This version of gcc doesn't support LTO")
|
||||
endif(LTO_AVAILABLE)
|
||||
else()
|
||||
message(FATAL_ERROR "LTO is only supported with gcc")
|
||||
endif()
|
||||
if(APPLE)
|
||||
add_gcc_compiler_cxxflags("-stdlib=libc++")
|
||||
endif()
|
||||
|
||||
if (WITH_CXX11)
|
||||
add_gcc_compiler_cxxflags("-std=c++0x")
|
||||
add_gcc_compiler_cflags("-ansi")
|
||||
else()
|
||||
add_gcc_compiler_flags("-ansi")
|
||||
add_gcc_compiler_cflags("-ansi")
|
||||
|
||||
if(WITH_DEV_BUILD)
|
||||
add_definitions(-DQT_DEPRECATED_WARNINGS -DGCRYPT_NO_DEPRECATED)
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
@@ -151,26 +141,28 @@ else()
|
||||
|
||||
set(BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}")
|
||||
set(PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/keepassx")
|
||||
set(DATA_INSTALL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/keepassx")
|
||||
set(DATA_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/keepassx")
|
||||
endif()
|
||||
|
||||
if(WITH_TESTS)
|
||||
enable_testing()
|
||||
endif(WITH_TESTS)
|
||||
|
||||
set(QT_REQUIRED_MODULES QtCore QtGui QtTest)
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(QT_REQUIRED_MODULES ${QT_REQUIRED_MODULES} QtDBus)
|
||||
endif()
|
||||
find_package(Qt5Core 5.2 REQUIRED)
|
||||
find_package(Qt5Concurrent 5.2 REQUIRED)
|
||||
find_package(Qt5Widgets 5.2 REQUIRED)
|
||||
find_package(Qt5Test 5.2 REQUIRED)
|
||||
find_package(Qt5LinguistTools 5.2 REQUIRED)
|
||||
find_package(Qt5Network 5.2 REQUIRED)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
find_package(Qt4 4.6.0 REQUIRED ${QT_REQUIRED_MODULES})
|
||||
include(${QT_USE_FILE})
|
||||
# Debian sets the the build type to None for package builds.
|
||||
# Make sure we don't enable asserts there.
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_NONE QT_NO_DEBUG)
|
||||
|
||||
find_package(Gcrypt REQUIRED)
|
||||
if(NOT (${GCRYPT_VERSION_STRING} VERSION_LESS "1.6.0"))
|
||||
message(STATUS "Gcrypt ${GCRYPT_VERSION_STRING} supports the SALSA20 cipher")
|
||||
set(GCRYPT_HAS_SALSA20 1)
|
||||
endif()
|
||||
find_package(Gcrypt 1.6.0 REQUIRED)
|
||||
|
||||
find_package(LibMicroHTTPD REQUIRED)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
@@ -211,10 +203,7 @@ endif()
|
||||
|
||||
include_directories(SYSTEM ${GCRYPT_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
|
||||
|
||||
if(NOT (${CMAKE_VERSION} VERSION_LESS 2.8.3))
|
||||
set(PRINT_SUMMARY ON)
|
||||
include(FeatureSummary)
|
||||
endif()
|
||||
include(FeatureSummary)
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(share)
|
||||
|
||||
6
COPYING
6
COPYING
@@ -139,10 +139,10 @@ Files: share/icons/application/*/actions/application-exit.png
|
||||
share/icons/application/*/actions/password-copy.png
|
||||
share/icons/application/*/actions/password-show-*.png
|
||||
share/icons/application/*/actions/system-search.png
|
||||
share/icons/application/*/actions/username-copy.png
|
||||
share/icons/application/*/status/dialog-error.png
|
||||
share/icons/application/*/status/dialog-information.png
|
||||
share/icons/application/*/status/dialog-warning.png
|
||||
share/icons/application/*/status/username-copy.png
|
||||
share/icons/svg/*.svgz
|
||||
Copyright: 2007, Nuno Pinheiro <nuno@oxygen-icons.org>
|
||||
2007, David Vignoni <david@icon-king.com>
|
||||
@@ -183,3 +183,7 @@ Files: src/streams/qtiocompressor.*
|
||||
tests/modeltest.*
|
||||
Copyright: 2009-2012, Nokia Corporation and/or its subsidiary(-ies)
|
||||
License: LGPL-2.1 or GPL-3
|
||||
|
||||
Files: cmake/GetGitRevisionDescription.cmake*
|
||||
Copyright: 2009-2010, Iowa State University
|
||||
License: Boost-1.0
|
||||
|
||||
2
INSTALL
2
INSTALL
@@ -2,7 +2,7 @@ Building:
|
||||
=========
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. [CMAKE PARAMETERS]
|
||||
cmake [CMAKE PARAMETERS] ..
|
||||
make [-jX]
|
||||
|
||||
Common cmake parameters:
|
||||
|
||||
23
LICENSE.BOOST-1.0
Normal file
23
LICENSE.BOOST-1.0
Normal file
@@ -0,0 +1,23 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
96
README.md
Normal file
96
README.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# KeePassX v2.0.2 + keepasshttp
|
||||
|
||||

|
||||
|
||||
## About
|
||||
|
||||
Fork of [KeePassX](https://www.keepassx.org/) with keepasshttp support for use with [PassIFox](https://addons.mozilla.org/en-us/firefox/addon/passifox/) for Mozilla Firefox and [chromeIPass](https://chrome.google.com/webstore/detail/chromeipass/ompiailgknfdndiefoaoiligalphfdae) for Google Chrome.
|
||||
|
||||
KeePassHttp implementation has been forked from jdachtera's repository, which in turn was based on code from code with Francois Ferrand's [keepassx-http](https://gitorious.org/keepassx/keepassx-http/source/master:) repository.
|
||||
|
||||
This is a rebuild from [denk-mal's keepasshttp](https://github.com/denk-mal/keepassx.git) that brings it forward to Qt5 and KeePassX v2.0.2.
|
||||
|
||||
#### Build Dependencies
|
||||
|
||||
The following tools must exist within your PATH:
|
||||
|
||||
* make
|
||||
* cmake (>= 2.8.12)
|
||||
* g++ (>= 4.7) or clang++ (>= 3.0)
|
||||
|
||||
The following libraries are required:
|
||||
|
||||
* Qt 5 (>= 5.2): qtbase and qttools5
|
||||
* libgcrypt (>= 1.6)
|
||||
* zlib
|
||||
* libmicrohttpd
|
||||
* libxi, libxtst, qtx11extras (optional for auto-type on X11)
|
||||
|
||||
On Debian you can install them with:
|
||||
|
||||
```bash
|
||||
sudo apt-get install build-essential cmake libmicrohttpd-dev libxi-dev qtbase5-dev libqt5x11extras5-dev qttools5-dev qttools5-dev-tools libgcrypt20-dev zlib1g-dev
|
||||
```
|
||||
|
||||
#### Build Steps
|
||||
|
||||
To compile from source:
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DWITH_TESTS=OFF ..
|
||||
make [-jX]
|
||||
```
|
||||
|
||||
You will have the compiled KeePassX binary inside the `./build/src/` directory.
|
||||
|
||||
To install this binary execute the following:
|
||||
|
||||
```bash
|
||||
sudo make install
|
||||
```
|
||||
|
||||
More detailed instructions available in the INSTALL file.
|
||||
|
||||
## Contribute
|
||||
|
||||
Coordination of work between developers is handled through the [KeePassX development](https://www.keepassx.org/dev/) site.
|
||||
Requests for enhancements, or reports of bugs encountered, can also be reported through the KeePassX development site.
|
||||
However, members of the open-source community are encouraged to submit pull requests directly through GitHub.
|
||||
|
||||
### Clone Repository
|
||||
|
||||
Clone the repository to a suitable location where you can extend and build this project.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/keepassx/keepassx.git
|
||||
```
|
||||
|
||||
**Note:** This will clone the entire contents of the repository at the HEAD revision.
|
||||
|
||||
To update the project from within the project's folder you can run the following command:
|
||||
|
||||
```bash
|
||||
git pull
|
||||
```
|
||||
|
||||
### Feature Requests
|
||||
|
||||
We're always looking for suggestions to improve our application. If you have a suggestion for improving an existing feature,
|
||||
or would like to suggest a completely new feature for KeePassX, please file a ticket on the [KeePassX development](https://www.keepassx.org/dev/) site.
|
||||
|
||||
### Bug Reports
|
||||
|
||||
Our software isn't always perfect, but we strive to always improve our work. You may file bug reports on the [KeePassX development](https://www.keepassx.org/dev/) site.
|
||||
|
||||
### Pull Requests
|
||||
|
||||
Along with our desire to hear your feedback and suggestions, we're also interested in accepting direct assistance in the form of code.
|
||||
|
||||
Issue merge requests against our [GitHub repository](https://github.com/keepassxreboot/keepassx).
|
||||
|
||||
### Translations
|
||||
|
||||
Translations are managed on [Transifex](https://www.transifex.com/projects/p/keepassx/) which offers a web interface.
|
||||
Please join an existing language team or request a new one if there is none.
|
||||
9
cmake/FindLibMicroHTTPD.cmake
Normal file
9
cmake/FindLibMicroHTTPD.cmake
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
find_path(MHD_INCLUDE_DIR microhttpd.h)
|
||||
|
||||
find_library(MHD_LIBRARIES microhttpd)
|
||||
|
||||
mark_as_advanced(MHD_LIBRARIES MHD_INCLUDE_DIR)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LibMicroHTTPD DEFAULT_MSG MHD_LIBRARIES MHD_INCLUDE_DIR)
|
||||
130
cmake/GetGitRevisionDescription.cmake
Normal file
130
cmake/GetGitRevisionDescription.cmake
Normal file
@@ -0,0 +1,130 @@
|
||||
# - Returns a version string from Git
|
||||
#
|
||||
# These functions force a re-configure on each git commit so that you can
|
||||
# trust the values of the variables in your build system.
|
||||
#
|
||||
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the refspec and sha hash of the current head revision
|
||||
#
|
||||
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe on the source tree, and adjusting
|
||||
# the output so that it tests false if an error occurs.
|
||||
#
|
||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe --exact-match on the source tree,
|
||||
# and adjusting the output so that it tests false if there was no exact
|
||||
# matching tag.
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE.BOOST-1.0 or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
if(__get_git_revision_description)
|
||||
return()
|
||||
endif()
|
||||
set(__get_git_revision_description YES)
|
||||
|
||||
# We must run the following at "include" time, not at function call time,
|
||||
# to find the path to this module rather than the path to a calling list file
|
||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
function(get_git_head_revision _refspecvar _hashvar)
|
||||
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
||||
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
||||
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
||||
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
||||
# We have reached the root directory, we are not in git
|
||||
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
endwhile()
|
||||
# check if this is a submodule
|
||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||
endif()
|
||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||
if(NOT EXISTS "${GIT_DATA}")
|
||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
||||
return()
|
||||
endif()
|
||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
||||
|
||||
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||
"${GIT_DATA}/grabRef.cmake"
|
||||
@ONLY)
|
||||
include("${GIT_DATA}/grabRef.cmake")
|
||||
|
||||
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
||||
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_describe _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO sanitize
|
||||
#if((${ARGN}" MATCHES "&&") OR
|
||||
# (ARGN MATCHES "||") OR
|
||||
# (ARGN MATCHES "\\;"))
|
||||
# message("Please report the following error to the project!")
|
||||
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||
#endif()
|
||||
|
||||
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
describe
|
||||
${hash}
|
||||
${ARGN}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_get_exact_tag _var)
|
||||
git_describe(out --exact-match ${ARGN})
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
41
cmake/GetGitRevisionDescription.cmake.in
Normal file
41
cmake/GetGitRevisionDescription.cmake.in
Normal file
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# Internal file for GetGitRevisionDescription.cmake
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE.BOOST-1.0 or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set(HEAD_HASH)
|
||||
|
||||
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||
|
||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||
if(HEAD_CONTENTS MATCHES "ref")
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
else()
|
||||
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
endif()
|
||||
|
||||
if(NOT HEAD_HASH)
|
||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
endif()
|
||||
@@ -13,17 +13,19 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
add_subdirectory(translations)
|
||||
|
||||
file(GLOB DATABASE_ICONS icons/database/*.png)
|
||||
|
||||
install(FILES ${DATABASE_ICONS} DESTINATION ${DATA_INSTALL_DIR}/icons/database)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
install(DIRECTORY icons/application/ DESTINATION share/icons/hicolor
|
||||
install(DIRECTORY icons/application/ DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor
|
||||
FILES_MATCHING PATTERN "keepassx.png" PATTERN "keepassx.svgz")
|
||||
install(DIRECTORY icons/application/ DESTINATION share/icons/hicolor
|
||||
install(DIRECTORY icons/application/ DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor
|
||||
FILES_MATCHING PATTERN "application-x-keepassx.png" PATTERN "application-x-keepassx.svgz")
|
||||
install(FILES linux/keepassx.desktop DESTINATION share/applications)
|
||||
install(FILES linux/keepassx.xml DESTINATION share/mime/packages)
|
||||
install(FILES linux/keepassx.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
||||
install(FILES linux/keepassx.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages)
|
||||
endif(UNIX AND NOT APPLE)
|
||||
|
||||
if(APPLE)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Name=KeePassX
|
||||
GenericName=Cross Platform Password Manager
|
||||
GenericName=Password Manager
|
||||
GenericName[de]=Passwortverwaltung
|
||||
GenericName[es]=Gestor de contraseñas multiplataforma
|
||||
GenericName[es]=Gestor de contraseñas
|
||||
GenericName[fr]=Gestionnaire de mot de passe
|
||||
GenericName[ru]=менеджер паролей
|
||||
Exec=keepassx %f
|
||||
Icon=keepassx
|
||||
Terminal=false
|
||||
|
||||
26
share/translations/CMakeLists.txt
Normal file
26
share/translations/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 or (at your option)
|
||||
# version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
file(GLOB TRANSLATION_FILES *.ts)
|
||||
get_filename_component(TRANSLATION_EN_ABS keepassx_en.ts ABSOLUTE)
|
||||
list(REMOVE_ITEM TRANSLATION_FILES keepassx_en.ts)
|
||||
list(REMOVE_ITEM TRANSLATION_FILES ${TRANSLATION_EN_ABS})
|
||||
message(STATUS "${TRANSLATION_FILES}")
|
||||
|
||||
qt5_add_translation(QM_FILES ${TRANSLATION_FILES})
|
||||
|
||||
install(FILES ${QM_FILES} DESTINATION ${DATA_INSTALL_DIR}/translations)
|
||||
add_custom_target(translations DEPENDS ${QM_FILES})
|
||||
add_dependencies(${PROGNAME} translations)
|
||||
1366
share/translations/keepassx_cs.ts
Normal file
1366
share/translations/keepassx_cs.ts
Normal file
File diff suppressed because it is too large
Load Diff
1361
share/translations/keepassx_da.ts
Normal file
1361
share/translations/keepassx_da.ts
Normal file
File diff suppressed because it is too large
Load Diff
1367
share/translations/keepassx_de.ts
Normal file
1367
share/translations/keepassx_de.ts
Normal file
File diff suppressed because it is too large
Load Diff
1286
share/translations/keepassx_el.ts
Normal file
1286
share/translations/keepassx_el.ts
Normal file
File diff suppressed because it is too large
Load Diff
1394
share/translations/keepassx_en.ts
Normal file
1394
share/translations/keepassx_en.ts
Normal file
File diff suppressed because it is too large
Load Diff
41
share/translations/keepassx_en_plurals.ts
Normal file
41
share/translations/keepassx_en_plurals.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.0" language="en_US">
|
||||
<context>
|
||||
<name>DatabaseWidget</name>
|
||||
<message numerus="yes">
|
||||
<source>Do you really want to move %n entry(s) to the recycle bin?</source>
|
||||
<translation>
|
||||
<numerusform>Do you really want to move %n entry to the recycle bin?</numerusform>
|
||||
<numerusform>Do you really want to move %n entries to the recycle bin?</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>EditEntryWidget</name>
|
||||
<message numerus="yes">
|
||||
<source>%n week(s)</source>
|
||||
<translation>
|
||||
<numerusform>%n week</numerusform>
|
||||
<numerusform>%n weeks</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>%n month(s)</source>
|
||||
<translation>
|
||||
<numerusform>%n month</numerusform>
|
||||
<numerusform>%n months</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>EditWidgetIcons</name>
|
||||
<message numerus="yes">
|
||||
<source>Can't delete icon. Still used by %n item(s).</source>
|
||||
<translation>
|
||||
<numerusform>Can't delete icon. Still used by %n item.</numerusform>
|
||||
<numerusform>Can't delete icon. Still used by %n items.</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
1362
share/translations/keepassx_es.ts
Normal file
1362
share/translations/keepassx_es.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_fr.ts
Normal file
1362
share/translations/keepassx_fr.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_id.ts
Normal file
1362
share/translations/keepassx_id.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_it.ts
Normal file
1362
share/translations/keepassx_it.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_ja.ts
Normal file
1362
share/translations/keepassx_ja.ts
Normal file
File diff suppressed because it is too large
Load Diff
1359
share/translations/keepassx_ko.ts
Normal file
1359
share/translations/keepassx_ko.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_lt.ts
Normal file
1362
share/translations/keepassx_lt.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_nl_NL.ts
Normal file
1362
share/translations/keepassx_nl_NL.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_pl.ts
Normal file
1362
share/translations/keepassx_pl.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_pt_BR.ts
Normal file
1362
share/translations/keepassx_pt_BR.ts
Normal file
File diff suppressed because it is too large
Load Diff
1356
share/translations/keepassx_pt_PT.ts
Normal file
1356
share/translations/keepassx_pt_PT.ts
Normal file
File diff suppressed because it is too large
Load Diff
1361
share/translations/keepassx_ru.ts
Normal file
1361
share/translations/keepassx_ru.ts
Normal file
File diff suppressed because it is too large
Load Diff
1356
share/translations/keepassx_sl_SI.ts
Normal file
1356
share/translations/keepassx_sl_SI.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_sv.ts
Normal file
1362
share/translations/keepassx_sv.ts
Normal file
File diff suppressed because it is too large
Load Diff
1360
share/translations/keepassx_uk.ts
Normal file
1360
share/translations/keepassx_uk.ts
Normal file
File diff suppressed because it is too large
Load Diff
1361
share/translations/keepassx_zh_CN.ts
Normal file
1361
share/translations/keepassx_zh_CN.ts
Normal file
File diff suppressed because it is too large
Load Diff
1362
share/translations/keepassx_zh_TW.ts
Normal file
1362
share/translations/keepassx_zh_TW.ts
Normal file
File diff suppressed because it is too large
Load Diff
12
share/translations/update.sh
Executable file
12
share/translations/update.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
BASEDIR=$(dirname $0)
|
||||
|
||||
cd $BASEDIR/../..
|
||||
|
||||
echo Updating source file
|
||||
lupdate -no-ui-lines -disable-heuristic similartext -locations none -no-obsolete src -ts share/translations/keepassx_en.ts
|
||||
lupdate -no-ui-lines -disable-heuristic similartext -locations none -pluralonly src -ts share/translations/keepassx_en_plurals.ts
|
||||
|
||||
echo Pulling translations from Transifex
|
||||
tx pull -a --minimum-perc=80
|
||||
@@ -17,6 +17,17 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
configure_file(config-keepassx.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-keepassx.h)
|
||||
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_head_revision(GIT_REFSPEC GIT_HEAD)
|
||||
git_describe(GIT_DESCRIBE --long)
|
||||
|
||||
if (NOT GIT_HEAD OR NOT GIT_DESCRIBE)
|
||||
set(GIT_HEAD "")
|
||||
set(GIT_DESCRIBE "")
|
||||
endif()
|
||||
|
||||
configure_file(version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/version.h @ONLY)
|
||||
|
||||
set(keepassx_SOURCES
|
||||
autotype/AutoType.cpp
|
||||
autotype/AutoTypeAction.cpp
|
||||
@@ -35,6 +46,7 @@ set(keepassx_SOURCES
|
||||
core/Entry.cpp
|
||||
core/EntryAttachments.cpp
|
||||
core/EntryAttributes.cpp
|
||||
core/EntrySearcher.cpp
|
||||
core/FilePath.cpp
|
||||
core/Global.h
|
||||
core/Group.cpp
|
||||
@@ -42,26 +54,26 @@ set(keepassx_SOURCES
|
||||
core/ListDeleter.h
|
||||
core/Metadata.cpp
|
||||
core/PasswordGenerator.cpp
|
||||
core/qsavefile.cpp
|
||||
core/qsavefile_p.h
|
||||
core/SignalMultiplexer.cpp
|
||||
core/TimeDelta.cpp
|
||||
core/TimeInfo.cpp
|
||||
core/ToDbExporter.cpp
|
||||
core/Tools.cpp
|
||||
core/Translator.cpp
|
||||
core/Uuid.cpp
|
||||
core/qcommandlineoption.cpp
|
||||
core/qcommandlineparser.cpp
|
||||
crypto/Crypto.cpp
|
||||
crypto/CryptoHash.cpp
|
||||
crypto/Random.cpp
|
||||
crypto/SymmetricCipher.cpp
|
||||
crypto/SymmetricCipherBackend.h
|
||||
crypto/SymmetricCipherGcrypt.cpp
|
||||
format/CsvExporter.cpp
|
||||
format/KeePass1.h
|
||||
format/KeePass1Reader.cpp
|
||||
format/KeePass2.h
|
||||
format/KeePass2RandomStream.cpp
|
||||
format/KeePass2Reader.cpp
|
||||
format/KeePass2Repair.cpp
|
||||
format/KeePass2Writer.cpp
|
||||
format/KeePass2XmlReader.cpp
|
||||
format/KeePass2XmlWriter.cpp
|
||||
@@ -70,9 +82,11 @@ set(keepassx_SOURCES
|
||||
gui/ChangeMasterKeyWidget.cpp
|
||||
gui/Clipboard.cpp
|
||||
gui/DatabaseOpenWidget.cpp
|
||||
gui/DatabaseRepairWidget.cpp
|
||||
gui/DatabaseSettingsWidget.cpp
|
||||
gui/DatabaseTabWidget.cpp
|
||||
gui/DatabaseWidget.cpp
|
||||
gui/DatabaseWidgetStateSync.cpp
|
||||
gui/DialogyWidget.cpp
|
||||
gui/DragTabBar.cpp
|
||||
gui/EditWidget.cpp
|
||||
@@ -102,6 +116,14 @@ set(keepassx_SOURCES
|
||||
gui/group/EditGroupWidget.cpp
|
||||
gui/group/GroupModel.cpp
|
||||
gui/group/GroupView.cpp
|
||||
http/AccessControlDialog.cpp
|
||||
http/EntryConfig.cpp
|
||||
http/HttpPasswordGeneratorWidget.cpp
|
||||
http/HttpSettings.cpp
|
||||
http/OptionDialog.cpp
|
||||
http/Protocol.cpp
|
||||
http/Server.cpp
|
||||
http/Service.cpp
|
||||
keys/CompositeKey.cpp
|
||||
keys/CompositeKey_p.h
|
||||
keys/FileKey.cpp
|
||||
@@ -114,80 +136,10 @@ set(keepassx_SOURCES
|
||||
streams/SymmetricCipherStream.cpp
|
||||
)
|
||||
|
||||
if(NOT GCRYPT_HAS_SALSA20)
|
||||
set(keepassx_SOURCES
|
||||
${keepassx_SOURCES}
|
||||
crypto/salsa20/ecrypt-config.h
|
||||
crypto/salsa20/ecrypt-machine.h
|
||||
crypto/salsa20/ecrypt-portable.h
|
||||
crypto/salsa20/ecrypt-sync.h
|
||||
crypto/salsa20/salsa20.c
|
||||
crypto/SymmetricCipherSalsa20.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
set(keepassx_SOURCES_MAINEXE
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set(keepassx_MOC
|
||||
autotype/AutoType.h
|
||||
autotype/AutoTypeSelectDialog.h
|
||||
autotype/AutoTypeSelectView.h
|
||||
autotype/ShortcutWidget.h
|
||||
autotype/WindowSelectComboBox.h
|
||||
core/AutoTypeAssociations.h
|
||||
core/Config.h
|
||||
core/Database.h
|
||||
core/Entry.h
|
||||
core/EntryAttachments.h
|
||||
core/EntryAttributes.h
|
||||
core/Group.h
|
||||
core/InactivityTimer.h
|
||||
core/Metadata.h
|
||||
core/qsavefile.h
|
||||
gui/AboutDialog.h
|
||||
gui/Application.h
|
||||
gui/ChangeMasterKeyWidget.h
|
||||
gui/Clipboard.h
|
||||
gui/DatabaseOpenWidget.h
|
||||
gui/DatabaseSettingsWidget.h
|
||||
gui/DatabaseTabWidget.h
|
||||
gui/DatabaseWidget.h
|
||||
gui/DialogyWidget.h
|
||||
gui/DragTabBar.h
|
||||
gui/EditWidget.h
|
||||
gui/EditWidgetIcons.h
|
||||
gui/EditWidgetProperties.h
|
||||
gui/IconModels.h
|
||||
gui/KeePass1OpenWidget.h
|
||||
gui/LineEdit.h
|
||||
gui/MainWindow.h
|
||||
gui/PasswordEdit.h
|
||||
gui/PasswordGeneratorWidget.h
|
||||
gui/PasswordComboBox.h
|
||||
gui/SettingsWidget.h
|
||||
gui/SortFilterHideProxyModel.h
|
||||
gui/UnlockDatabaseWidget.h
|
||||
gui/WelcomeWidget.h
|
||||
gui/entry/AutoTypeAssociationsModel.h
|
||||
gui/entry/EditEntryWidget.h
|
||||
gui/entry/EntryAttachmentsModel.h
|
||||
gui/entry/EntryAttributesModel.h
|
||||
gui/entry/EntryHistoryModel.h
|
||||
gui/entry/EntryModel.h
|
||||
gui/entry/EntryView.h
|
||||
gui/group/EditGroupWidget.h
|
||||
gui/group/GroupModel.h
|
||||
gui/group/GroupView.h
|
||||
keys/CompositeKey_p.h
|
||||
streams/HashedBlockStream.h
|
||||
streams/LayeredStream.h
|
||||
streams/qtiocompressor.h
|
||||
streams/StoreDataStream.h
|
||||
streams/SymmetricCipherStream.h
|
||||
)
|
||||
|
||||
set(keepassx_FORMS
|
||||
gui/AboutDialog.ui
|
||||
gui/ChangeMasterKeyWidget.ui
|
||||
@@ -207,6 +159,9 @@ set(keepassx_FORMS
|
||||
gui/entry/EditEntryWidgetHistory.ui
|
||||
gui/entry/EditEntryWidgetMain.ui
|
||||
gui/group/EditGroupWidgetMain.ui
|
||||
http/AccessControlDialog.ui
|
||||
http/HttpPasswordGeneratorWidget.ui
|
||||
http/OptionDialog.ui
|
||||
)
|
||||
|
||||
if(MINGW)
|
||||
@@ -215,24 +170,23 @@ if(MINGW)
|
||||
${CMAKE_SOURCE_DIR}/share/windows/icon.rc)
|
||||
endif()
|
||||
|
||||
qt4_wrap_ui(keepassx_SOURCES ${keepassx_FORMS})
|
||||
qt4_wrap_cpp(keepassx_SOURCES ${keepassx_MOC})
|
||||
qt5_wrap_ui(keepassx_SOURCES ${keepassx_FORMS})
|
||||
|
||||
add_library(keepassx_core STATIC ${keepassx_SOURCES})
|
||||
set_target_properties(keepassx_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE)
|
||||
target_link_libraries(keepassx_core Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network)
|
||||
|
||||
add_executable(${PROGNAME} WIN32 MACOSX_BUNDLE ${keepassx_SOURCES_MAINEXE})
|
||||
target_link_libraries(${PROGNAME}
|
||||
keepassx_core
|
||||
${QT_QTCORE_LIBRARY}
|
||||
${QT_QTGUI_LIBRARY}
|
||||
${MHD_LIBRARIES}
|
||||
Qt5::Core
|
||||
Qt5::Concurrent
|
||||
Qt5::Widgets
|
||||
Qt5::Network
|
||||
${GCRYPT_LIBRARIES}
|
||||
${ZLIB_LIBRARIES})
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(${PROGNAME} ${QT_QTDBUS_LIBRARY})
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROGNAME} PROPERTIES ENABLE_EXPORTS ON)
|
||||
|
||||
if(APPLE)
|
||||
@@ -247,7 +201,7 @@ install(TARGETS ${PROGNAME}
|
||||
|
||||
add_subdirectory(autotype)
|
||||
|
||||
if(APPLE AND NOT (${CMAKE_VERSION} VERSION_LESS 2.8.8))
|
||||
if(APPLE)
|
||||
if(QT_MAC_USE_COCOA AND EXISTS "${QT_LIBRARY_DIR}/Resources/qt_menu.nib")
|
||||
install(DIRECTORY "${QT_LIBRARY_DIR}/Resources/qt_menu.nib"
|
||||
DESTINATION "${DATA_INSTALL_DIR}")
|
||||
@@ -265,7 +219,7 @@ if(APPLE AND NOT (${CMAKE_VERSION} VERSION_LESS 2.8.8))
|
||||
install_qt4_executable(${PROGNAME}.app "qjpeg;qgif;qico;qtaccessiblewidgets")
|
||||
endif()
|
||||
|
||||
if(MINGW AND NOT (${CMAKE_VERSION} VERSION_LESS 2.8.8))
|
||||
if(MINGW )
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
set(CPACK_STRIP_FILES ON)
|
||||
set(CPACK_PACKAGE_FILE_NAME "${PROGNAME}-${KEEPASSX_VERSION_NUM}")
|
||||
|
||||
@@ -23,14 +23,16 @@
|
||||
#include "autotype/AutoTypePlatformPlugin.h"
|
||||
#include "autotype/AutoTypeSelectDialog.h"
|
||||
#include "autotype/WildcardMatcher.h"
|
||||
#include "core/Config.h"
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/FilePath.h"
|
||||
#include "core/Group.h"
|
||||
#include "core/ListDeleter.h"
|
||||
#include "core/Tools.h"
|
||||
#include "gui/MessageBox.h"
|
||||
|
||||
AutoType* AutoType::m_instance = Q_NULLPTR;
|
||||
AutoType* AutoType::m_instance = nullptr;
|
||||
|
||||
AutoType::AutoType(QObject* parent, bool test)
|
||||
: QObject(parent)
|
||||
@@ -38,8 +40,8 @@ AutoType::AutoType(QObject* parent, bool test)
|
||||
, m_currentGlobalKey(static_cast<Qt::Key>(0))
|
||||
, m_currentGlobalModifiers(0)
|
||||
, m_pluginLoader(new QPluginLoader(this))
|
||||
, m_plugin(Q_NULLPTR)
|
||||
, m_executor(Q_NULLPTR)
|
||||
, m_plugin(nullptr)
|
||||
, m_executor(nullptr)
|
||||
, m_windowFromGlobal(0)
|
||||
{
|
||||
// prevent crash when the plugin has unresolved symbols
|
||||
@@ -47,7 +49,7 @@ AutoType::AutoType(QObject* parent, bool test)
|
||||
|
||||
QString pluginName = "keepassx-autotype-";
|
||||
if (!test) {
|
||||
pluginName += Tools::platform();
|
||||
pluginName += QApplication::platformName();
|
||||
}
|
||||
else {
|
||||
pluginName += "test";
|
||||
@@ -66,7 +68,7 @@ AutoType::~AutoType()
|
||||
{
|
||||
if (m_executor) {
|
||||
delete m_executor;
|
||||
m_executor = Q_NULLPTR;
|
||||
m_executor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +79,16 @@ void AutoType::loadPlugin(const QString& pluginPath)
|
||||
QObject* pluginInstance = m_pluginLoader->instance();
|
||||
if (pluginInstance) {
|
||||
m_plugin = qobject_cast<AutoTypePlatformInterface*>(pluginInstance);
|
||||
m_executor = nullptr;
|
||||
|
||||
if (m_plugin) {
|
||||
m_executor = m_plugin->createExecutor();
|
||||
connect(pluginInstance, SIGNAL(globalShortcutTriggered()), SIGNAL(globalShortcutTriggered()));
|
||||
if (m_plugin->isAvailable()) {
|
||||
m_executor = m_plugin->createExecutor();
|
||||
connect(pluginInstance, SIGNAL(globalShortcutTriggered()), SIGNAL(globalShortcutTriggered()));
|
||||
}
|
||||
else {
|
||||
unloadPlugin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +155,9 @@ void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QS
|
||||
window = m_plugin->activeWindow();
|
||||
}
|
||||
|
||||
Q_FOREACH (AutoTypeAction* action, actions) {
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 10);
|
||||
|
||||
for (AutoTypeAction* action : asConst(actions)) {
|
||||
if (m_plugin->activeWindow() != window) {
|
||||
qWarning("Active window changed, interrupting auto-type.");
|
||||
break;
|
||||
@@ -176,8 +187,9 @@ void AutoType::performGlobalAutoType(const QList<Database*>& dbList)
|
||||
QList<Entry*> entryList;
|
||||
QHash<Entry*, QString> sequenceHash;
|
||||
|
||||
Q_FOREACH (Database* db, dbList) {
|
||||
Q_FOREACH (Entry* entry, db->rootGroup()->entriesRecursive()) {
|
||||
for (Database* db : dbList) {
|
||||
const QList<Entry*> dbEntries = db->rootGroup()->entriesRecursive();
|
||||
for (Entry* entry : dbEntries) {
|
||||
QString sequence = autoTypeSequence(entry, windowTitle);
|
||||
if (!sequence.isEmpty()) {
|
||||
entryList << entry;
|
||||
@@ -188,10 +200,14 @@ void AutoType::performGlobalAutoType(const QList<Database*>& dbList)
|
||||
|
||||
if (entryList.isEmpty()) {
|
||||
m_inAutoType = false;
|
||||
QString message = tr("Couldn't find an entry that matches the window title:");
|
||||
message.append("\n\n");
|
||||
message.append(windowTitle);
|
||||
MessageBox::information(nullptr, tr("Auto-Type - KeePassX"), message);
|
||||
}
|
||||
else if (entryList.size() == 1) {
|
||||
else if ((entryList.size() == 1) && !config()->get("security/autotypeask").toBool()) {
|
||||
m_inAutoType = false;
|
||||
performAutoType(entryList.first(), Q_NULLPTR, sequenceHash[entryList.first()]);
|
||||
performAutoType(entryList.first(), nullptr, sequenceHash[entryList.first()]);
|
||||
}
|
||||
else {
|
||||
m_windowFromGlobal = m_plugin->activeWindow();
|
||||
@@ -210,8 +226,10 @@ void AutoType::performAutoTypeFromGlobal(Entry* entry, const QString& sequence)
|
||||
{
|
||||
Q_ASSERT(m_inAutoType);
|
||||
|
||||
m_plugin->raiseWindow(m_windowFromGlobal);
|
||||
|
||||
m_inAutoType = false;
|
||||
performAutoType(entry, Q_NULLPTR, sequence, m_windowFromGlobal);
|
||||
performAutoType(entry, nullptr, sequence, m_windowFromGlobal);
|
||||
}
|
||||
|
||||
void AutoType::resetInAutoType()
|
||||
@@ -225,12 +243,12 @@ void AutoType::unloadPlugin()
|
||||
{
|
||||
if (m_executor) {
|
||||
delete m_executor;
|
||||
m_executor = Q_NULLPTR;
|
||||
m_executor = nullptr;
|
||||
}
|
||||
|
||||
if (m_plugin) {
|
||||
m_plugin->unload();
|
||||
m_plugin = Q_NULLPTR;
|
||||
m_plugin = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +301,7 @@ bool AutoType::parseActions(const QString& sequence, const Entry* entry, QList<A
|
||||
QString tmpl;
|
||||
bool inTmpl = false;
|
||||
|
||||
Q_FOREACH (const QChar& ch, sequence) {
|
||||
for (const QChar& ch : sequence) {
|
||||
// TODO: implement support for {{}, {}} and {DELAY=X}
|
||||
|
||||
if (inTmpl) {
|
||||
@@ -465,11 +483,19 @@ QList<AutoTypeAction*> AutoType::createActionFromTemplate(const QString& tmpl, c
|
||||
}
|
||||
|
||||
|
||||
QString placeholder = QString("{%1}").arg(tmplName);
|
||||
QString resolved = entry->resolvePlaceholders(placeholder);
|
||||
const QString placeholder = QString("{%1}").arg(tmplName);
|
||||
const QString resolved = entry->resolvePlaceholders(placeholder);
|
||||
if (placeholder != resolved) {
|
||||
Q_FOREACH (const QChar& ch, resolved) {
|
||||
list.append(new AutoTypeChar(ch));
|
||||
for (const QChar& ch : resolved) {
|
||||
if (ch == '\n') {
|
||||
list.append(new AutoTypeKey(Qt::Key_Enter));
|
||||
}
|
||||
else if (ch == '\t') {
|
||||
list.append(new AutoTypeKey(Qt::Key_Tab));
|
||||
}
|
||||
else {
|
||||
list.append(new AutoTypeChar(ch));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,7 +512,8 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl
|
||||
QString sequence;
|
||||
if (!windowTitle.isEmpty()) {
|
||||
bool match = false;
|
||||
Q_FOREACH (const AutoTypeAssociations::Association& assoc, entry->autoTypeAssociations()->getAll()) {
|
||||
const QList<AutoTypeAssociations::Association> assocList = entry->autoTypeAssociations()->getAll();
|
||||
for (const AutoTypeAssociations::Association& assoc : assocList) {
|
||||
if (windowMatches(windowTitle, assoc.window)) {
|
||||
if (!assoc.sequence.isEmpty()) {
|
||||
sequence = assoc.sequence;
|
||||
@@ -499,6 +526,12 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl
|
||||
}
|
||||
}
|
||||
|
||||
if (!match && config()->get("AutoTypeEntryTitleMatch").toBool() && !entry->title().isEmpty()
|
||||
&& windowTitle.contains(entry->title(), Qt::CaseInsensitive)) {
|
||||
sequence = entry->defaultAutoTypeSequence();
|
||||
match = true;
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
return QString();
|
||||
}
|
||||
@@ -544,7 +577,7 @@ bool AutoType::windowMatches(const QString& windowTitle, const QString& windowPa
|
||||
{
|
||||
if (windowPattern.startsWith("//") && windowPattern.endsWith("//") && windowPattern.size() >= 4) {
|
||||
QRegExp regExp(windowPattern.mid(2, windowPattern.size() - 4), Qt::CaseInsensitive, QRegExp::RegExp2);
|
||||
return regExp.exactMatch(windowTitle);
|
||||
return (regExp.indexIn(windowTitle) != -1);
|
||||
}
|
||||
else {
|
||||
return WildcardMatcher(windowTitle).match(windowPattern);
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include <QStringList>
|
||||
#include <QWidget>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class AutoTypeAction;
|
||||
class AutoTypeExecutor;
|
||||
class AutoTypePlatformInterface;
|
||||
@@ -37,7 +35,7 @@ class AutoType : public QObject
|
||||
|
||||
public:
|
||||
QStringList windowTitles();
|
||||
void performAutoType(const Entry* entry, QWidget* hideWindow = Q_NULLPTR,
|
||||
void performAutoType(const Entry* entry, QWidget* hideWindow = nullptr,
|
||||
const QString& customSequence = QString(), WId window = 0);
|
||||
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||
void unregisterGlobalShortcut();
|
||||
@@ -62,7 +60,7 @@ private Q_SLOTS:
|
||||
void unloadPlugin();
|
||||
|
||||
private:
|
||||
explicit AutoType(QObject* parent = Q_NULLPTR, bool test = false);
|
||||
explicit AutoType(QObject* parent = nullptr, bool test = false);
|
||||
~AutoType();
|
||||
void loadPlugin(const QString& pluginPath);
|
||||
bool parseActions(const QString& sequence, const Entry* entry, QList<AutoTypeAction*>& actions);
|
||||
|
||||
@@ -89,5 +89,7 @@ void AutoTypeExecutor::execDelay(AutoTypeDelay* action)
|
||||
|
||||
void AutoTypeExecutor::execClearField(AutoTypeClearField* action)
|
||||
{
|
||||
Q_UNUSED(action);
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
class KEEPASSX_EXPORT AutoTypeClearField : public AutoTypeAction
|
||||
{
|
||||
public:
|
||||
explicit AutoTypeClearField();
|
||||
AutoTypeClearField();
|
||||
AutoTypeAction* clone();
|
||||
void accept(AutoTypeExecutor* executor);
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@ class AutoTypePlatformInterface
|
||||
{
|
||||
public:
|
||||
virtual ~AutoTypePlatformInterface() {}
|
||||
virtual bool isAvailable() = 0;
|
||||
virtual QStringList windowTitles() = 0;
|
||||
virtual WId activeWindow() = 0;
|
||||
virtual QString activeWindowTitle() = 0;
|
||||
@@ -33,6 +34,7 @@ public:
|
||||
virtual void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) = 0;
|
||||
virtual int platformEventFilter(void* event) = 0;
|
||||
virtual int initialTimeout() = 0;
|
||||
virtual bool raiseWindow(WId window) = 0;
|
||||
virtual void unload() {}
|
||||
|
||||
virtual AutoTypeExecutor* createExecutor() = 0;
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "autotype/AutoTypeSelectView.h"
|
||||
#include "core/Config.h"
|
||||
#include "core/FilePath.h"
|
||||
#include "gui/entry/EntryModel.h"
|
||||
|
||||
@@ -33,15 +35,20 @@ AutoTypeSelectDialog::AutoTypeSelectDialog(QWidget* parent)
|
||||
, m_entryActivatedEmitted(false)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
// Places the window on the active (virtual) desktop instead of where the main window is.
|
||||
setAttribute(Qt::WA_X11BypassTransientForHint);
|
||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
setWindowTitle(tr("Auto-Type - KeePassX"));
|
||||
setWindowIcon(filePath()->applicationIcon());
|
||||
|
||||
QSize size(400, 250);
|
||||
QRect screenGeometry = QApplication::desktop()->availableGeometry(QCursor::pos());
|
||||
QSize size = config()->get("GUI/AutoTypeSelectDialogSize", QSize(400, 250)).toSize();
|
||||
size.setWidth(qMin(size.width(), screenGeometry.width()));
|
||||
size.setHeight(qMin(size.height(), screenGeometry.height()));
|
||||
resize(size);
|
||||
|
||||
// move dialog to the center of the screen
|
||||
QPoint screenCenter = QApplication::desktop()->screenGeometry(QCursor::pos()).center();
|
||||
QPoint screenCenter = screenGeometry.center();
|
||||
move(screenCenter.x() - (size.width() / 2), screenCenter.y() - (size.height() / 2));
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
@@ -63,6 +70,15 @@ void AutoTypeSelectDialog::setEntries(const QList<Entry*>& entries, const QHash<
|
||||
{
|
||||
m_sequences = sequences;
|
||||
m_view->setEntryList(entries);
|
||||
|
||||
m_view->header()->resizeSections(QHeaderView::ResizeToContents);
|
||||
}
|
||||
|
||||
void AutoTypeSelectDialog::done(int r)
|
||||
{
|
||||
config()->set("GUI/AutoTypeSelectDialogSize", size());
|
||||
|
||||
QDialog::done(r);
|
||||
}
|
||||
|
||||
void AutoTypeSelectDialog::emitEntryActivated(const QModelIndex& index)
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include <QDialog>
|
||||
#include <QHash>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class AutoTypeSelectView;
|
||||
class Entry;
|
||||
|
||||
@@ -32,12 +30,15 @@ class AutoTypeSelectDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoTypeSelectDialog(QWidget* parent = Q_NULLPTR);
|
||||
explicit AutoTypeSelectDialog(QWidget* parent = nullptr);
|
||||
void setEntries(const QList<Entry*>& entries, const QHash<Entry*, QString>& sequences);
|
||||
|
||||
Q_SIGNALS:
|
||||
void entryActivated(Entry* entry, const QString& sequence);
|
||||
|
||||
public Q_SLOTS:
|
||||
void done(int r) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void emitEntryActivated(const QModelIndex& index);
|
||||
void entryRemoved();
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#ifndef KEEPASSX_AUTOTYPESELECTVIEW_H
|
||||
#define KEEPASSX_AUTOTYPESELECTVIEW_H
|
||||
|
||||
#include "core/Global.h"
|
||||
#include "gui/entry/EntryView.h"
|
||||
|
||||
class Entry;
|
||||
@@ -28,10 +27,10 @@ class AutoTypeSelectView : public EntryView
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoTypeSelectView(QWidget* parent = Q_NULLPTR);
|
||||
explicit AutoTypeSelectView(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void selectFirstEntry();
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
if(Q_WS_X11)
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(X11)
|
||||
find_package(Qt5X11Extras 5.2)
|
||||
if(PRINT_SUMMARY)
|
||||
add_feature_info(libXtest X11_XTest_FOUND "The X11 XTEST Protocol library is required for auto-type")
|
||||
add_feature_info(libXi X11_Xi_FOUND "The X11 Xi Protocol library is required for auto-type")
|
||||
add_feature_info(libXtst X11_XTest_FOUND "The X11 XTEST Protocol library is required for auto-type")
|
||||
add_feature_info(Qt5X11Extras Qt5X11Extras_FOUND "The Qt5X11Extras library is required for auto-type")
|
||||
endif()
|
||||
|
||||
if(X11_FOUND AND X11_XTest_FOUND)
|
||||
add_subdirectory(x11)
|
||||
if(X11_FOUND AND X11_Xi_FOUND AND X11_XTest_FOUND AND Qt5X11Extras_FOUND)
|
||||
add_subdirectory(xcb)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -20,21 +20,19 @@
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class ShortcutWidget : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ShortcutWidget(QWidget* parent = Q_NULLPTR);
|
||||
explicit ShortcutWidget(QWidget* parent = nullptr);
|
||||
Qt::Key key() const;
|
||||
Qt::KeyboardModifiers modifiers() const;
|
||||
void setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) Q_DECL_OVERRIDE;
|
||||
void keyReleaseEvent(QKeyEvent* event) Q_DECL_OVERRIDE;
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
void keyReleaseEvent(QKeyEvent* event) override;
|
||||
|
||||
private:
|
||||
void keyEvent(QKeyEvent* event);
|
||||
|
||||
@@ -70,7 +70,7 @@ bool WildcardMatcher::startOrEndDoesNotMatch(const QStringList& parts)
|
||||
bool WildcardMatcher::partsMatch(const QStringList& parts)
|
||||
{
|
||||
int index = 0;
|
||||
Q_FOREACH (const QString& part, parts) {
|
||||
for (const QString& part : parts) {
|
||||
int matchIndex = getMatchIndex(part, index);
|
||||
if (noMatchFound(matchIndex)) {
|
||||
return false;
|
||||
|
||||
@@ -20,19 +20,17 @@
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class WindowSelectComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WindowSelectComboBox(QWidget* parent = Q_NULLPTR);
|
||||
explicit WindowSelectComboBox(QWidget* parent = nullptr);
|
||||
void refreshWindowList();
|
||||
|
||||
void showPopup() Q_DECL_OVERRIDE;
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
QSize minimumSizeHint() const Q_DECL_OVERRIDE;
|
||||
void showPopup() override;
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_WINDOWSELECTCOMBOBOX_H
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
|
||||
#include "AutoTypeTest.h"
|
||||
|
||||
bool AutoTypePlatformTest::isAvailable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QString AutoTypePlatformTest::keyToString(Qt::Key key)
|
||||
{
|
||||
return QString("[Key0x%1]").arg(key, 0, 16);
|
||||
@@ -103,6 +108,13 @@ int AutoTypePlatformTest::initialTimeout()
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AutoTypePlatformTest::raiseWindow(WId window)
|
||||
{
|
||||
Q_UNUSED(window);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoTypeExecturorTest::AutoTypeExecturorTest(AutoTypePlatformTest* platform)
|
||||
: m_platform(platform)
|
||||
{
|
||||
@@ -117,5 +129,3 @@ void AutoTypeExecturorTest::execKey(AutoTypeKey* action)
|
||||
{
|
||||
m_platform->addActionKey(action);
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN2(keepassx-autotype-test, AutoTypePlatformTest)
|
||||
|
||||
@@ -23,32 +23,34 @@
|
||||
#include "autotype/AutoTypePlatformPlugin.h"
|
||||
#include "autotype/AutoTypeAction.h"
|
||||
#include "autotype/test/AutoTypeTestInterface.h"
|
||||
#include "core/Global.h"
|
||||
|
||||
class AutoTypePlatformTest : public QObject,
|
||||
public AutoTypePlatformInterface,
|
||||
public AutoTypeTestInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.keepassx.AutoTypePlatformInterface")
|
||||
Q_INTERFACES(AutoTypePlatformInterface AutoTypeTestInterface)
|
||||
|
||||
public:
|
||||
QString keyToString(Qt::Key key);
|
||||
QString keyToString(Qt::Key key) override;
|
||||
|
||||
QStringList windowTitles();
|
||||
WId activeWindow();
|
||||
QString activeWindowTitle();
|
||||
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||
void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||
int platformEventFilter(void* event);
|
||||
int initialTimeout();
|
||||
AutoTypeExecutor* createExecutor();
|
||||
bool isAvailable() override;
|
||||
QStringList windowTitles() override;
|
||||
WId activeWindow() override;
|
||||
QString activeWindowTitle() override;
|
||||
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) override;
|
||||
void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) override;
|
||||
int platformEventFilter(void* event) override;
|
||||
int initialTimeout() override;
|
||||
bool raiseWindow(WId window) override;
|
||||
AutoTypeExecutor* createExecutor() override;
|
||||
|
||||
void setActiveWindowTitle(const QString& title);
|
||||
void setActiveWindowTitle(const QString& title) override;
|
||||
|
||||
QString actionChars();
|
||||
int actionCount();
|
||||
void clearActions();
|
||||
QString actionChars() override;
|
||||
int actionCount() override;
|
||||
void clearActions() override;
|
||||
|
||||
void addActionChar(AutoTypeChar* action);
|
||||
void addActionKey(AutoTypeKey* action);
|
||||
@@ -67,8 +69,8 @@ class AutoTypeExecturorTest : public AutoTypeExecutor
|
||||
public:
|
||||
explicit AutoTypeExecturorTest(AutoTypePlatformTest* platform);
|
||||
|
||||
void execChar(AutoTypeChar* action);
|
||||
void execKey(AutoTypeKey* action);
|
||||
void execChar(AutoTypeChar* action) override;
|
||||
void execKey(AutoTypeKey* action) override;
|
||||
|
||||
private:
|
||||
AutoTypePlatformTest* const m_platform;
|
||||
|
||||
@@ -2,11 +2,5 @@ set(autotype_test_SOURCES
|
||||
AutoTypeTest.cpp
|
||||
)
|
||||
|
||||
set(autotype_test_MOC
|
||||
AutoTypeTest.h
|
||||
)
|
||||
|
||||
qt4_wrap_cpp(autotype_test_SOURCES ${autotype_test_MOC})
|
||||
|
||||
add_library(keepassx-autotype-test MODULE ${autotype_test_SOURCES})
|
||||
target_link_libraries(keepassx-autotype-test testautotype ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
|
||||
target_link_libraries(keepassx-autotype-test testautotype Qt5::Core Qt5::Widgets)
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
include_directories(SYSTEM ${X11_X11_INCLUDE_PATH})
|
||||
|
||||
set(autotype_X11_SOURCES
|
||||
AutoTypeX11.cpp
|
||||
)
|
||||
|
||||
set(autotype_X11_MOC
|
||||
AutoTypeX11.h
|
||||
)
|
||||
|
||||
qt4_wrap_cpp(autotype_X11_SOURCES ${autotype_X11_MOC})
|
||||
|
||||
add_library(keepassx-autotype-x11 MODULE ${autotype_X11_SOURCES})
|
||||
target_link_libraries(keepassx-autotype-x11 ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${X11_X11_LIB} ${X11_XTest_LIB})
|
||||
install(TARGETS keepassx-autotype-x11
|
||||
BUNDLE DESTINATION . COMPONENT Runtime
|
||||
LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime)
|
||||
@@ -16,36 +16,40 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AutoTypeX11.h"
|
||||
#include "AutoTypeXCB.h"
|
||||
#include "KeySymMap.h"
|
||||
#include "core/Tools.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
bool AutoTypePlatformX11::m_catchXErrors = false;
|
||||
bool AutoTypePlatformX11::m_xErrorOccured = false;
|
||||
int (*AutoTypePlatformX11::m_oldXErrorHandler)(Display*, XErrorEvent*) = Q_NULLPTR;
|
||||
int (*AutoTypePlatformX11::m_oldXErrorHandler)(Display*, XErrorEvent*) = nullptr;
|
||||
|
||||
AutoTypePlatformX11::AutoTypePlatformX11()
|
||||
{
|
||||
m_dpy = QX11Info::display();
|
||||
m_rootWindow = QX11Info::appRootWindow();
|
||||
|
||||
m_atomWmState = XInternAtom(m_dpy, "WM_STATE", true);
|
||||
m_atomWmName = XInternAtom(m_dpy, "WM_NAME", true);
|
||||
m_atomNetWmName = XInternAtom(m_dpy, "_NET_WM_NAME", true);
|
||||
m_atomString = XInternAtom(m_dpy, "STRING", true);
|
||||
m_atomUtf8String = XInternAtom(m_dpy, "UTF8_STRING", true);
|
||||
m_atomWmState = XInternAtom(m_dpy, "WM_STATE", True);
|
||||
m_atomWmName = XInternAtom(m_dpy, "WM_NAME", True);
|
||||
m_atomNetWmName = XInternAtom(m_dpy, "_NET_WM_NAME", True);
|
||||
m_atomString = XInternAtom(m_dpy, "STRING", True);
|
||||
m_atomUtf8String = XInternAtom(m_dpy, "UTF8_STRING", True);
|
||||
m_atomNetActiveWindow = XInternAtom(m_dpy, "_NET_ACTIVE_WINDOW", True);
|
||||
|
||||
m_classBlacklist << "desktop_window" << "gnome-panel"; // Gnome
|
||||
m_classBlacklist << "kdesktop" << "kicker"; // KDE 3
|
||||
m_classBlacklist << "Plasma"; // KDE 4
|
||||
m_classBlacklist << "plasmashell"; // KDE 5
|
||||
m_classBlacklist << "xfdesktop" << "xfce4-panel"; // Xfce 4
|
||||
|
||||
m_currentGlobalKey = static_cast<Qt::Key>(0);
|
||||
m_currentGlobalModifiers = 0;
|
||||
|
||||
m_keysymTable = Q_NULLPTR;
|
||||
m_xkb = Q_NULLPTR;
|
||||
m_keysymTable = nullptr;
|
||||
m_xkb = nullptr;
|
||||
m_remapKeycode = 0;
|
||||
m_currentRemapKeysym = NoSymbol;
|
||||
m_modifierMask = ControlMask | ShiftMask | Mod1Mask | Mod4Mask;
|
||||
@@ -55,10 +59,37 @@ AutoTypePlatformX11::AutoTypePlatformX11()
|
||||
updateKeymap();
|
||||
}
|
||||
|
||||
bool AutoTypePlatformX11::isAvailable()
|
||||
{
|
||||
int ignore;
|
||||
|
||||
if (!XQueryExtension(m_dpy, "XInputExtension", &ignore, &ignore, &ignore)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!XQueryExtension(m_dpy, "XTEST", &ignore, &ignore, &ignore)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_xkb) {
|
||||
XkbDescPtr kbd = getKeyboard();
|
||||
|
||||
if (!kbd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
XkbFreeKeyboard(kbd, XkbAllComponentsMask, True);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AutoTypePlatformX11::unload()
|
||||
{
|
||||
// Restore the KeyboardMapping to its original state.
|
||||
AddKeysym(NoSymbol);
|
||||
if (m_currentRemapKeysym != NoSymbol) {
|
||||
AddKeysym(NoSymbol);
|
||||
}
|
||||
|
||||
if (m_keysymTable) {
|
||||
XFree(m_keysymTable);
|
||||
@@ -90,7 +121,7 @@ WId AutoTypePlatformX11::activeWindow()
|
||||
|
||||
Window root;
|
||||
Window parent;
|
||||
Window* children = Q_NULLPTR;
|
||||
Window* children = nullptr;
|
||||
unsigned int numChildren;
|
||||
tree = XQueryTree(m_dpy, window, &root, &parent, &children, &numChildren);
|
||||
window = parent;
|
||||
@@ -113,12 +144,12 @@ bool AutoTypePlatformX11::registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifi
|
||||
uint nativeModifiers = qtToNativeModifiers(modifiers);
|
||||
|
||||
startCatchXErrors();
|
||||
XGrabKey(m_dpy, keycode, nativeModifiers, m_rootWindow, true, GrabModeAsync, GrabModeAsync);
|
||||
XGrabKey(m_dpy, keycode, nativeModifiers | Mod2Mask, m_rootWindow, true, GrabModeAsync,
|
||||
XGrabKey(m_dpy, keycode, nativeModifiers, m_rootWindow, True, GrabModeAsync, GrabModeAsync);
|
||||
XGrabKey(m_dpy, keycode, nativeModifiers | Mod2Mask, m_rootWindow, True, GrabModeAsync,
|
||||
GrabModeAsync);
|
||||
XGrabKey(m_dpy, keycode, nativeModifiers | LockMask, m_rootWindow, true, GrabModeAsync,
|
||||
XGrabKey(m_dpy, keycode, nativeModifiers | LockMask, m_rootWindow, True, GrabModeAsync,
|
||||
GrabModeAsync);
|
||||
XGrabKey(m_dpy, keycode, nativeModifiers | Mod2Mask | LockMask, m_rootWindow, true,
|
||||
XGrabKey(m_dpy, keycode, nativeModifiers | Mod2Mask | LockMask, m_rootWindow, True,
|
||||
GrabModeAsync, GrabModeAsync);
|
||||
stopCatchXErrors();
|
||||
|
||||
@@ -157,7 +188,7 @@ uint AutoTypePlatformX11::qtToNativeModifiers(Qt::KeyboardModifiers modifiers)
|
||||
|
||||
void AutoTypePlatformX11::unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
KeyCode keycode = XKeysymToKeycode(m_dpy, keyToKeySym(key));
|
||||
KeyCode keycode = XKeysymToKeycode(m_dpy, charToKeySym(key));
|
||||
uint nativeModifiers = qtToNativeModifiers(modifiers);
|
||||
|
||||
XUngrabKey(m_dpy, keycode, nativeModifiers, m_rootWindow);
|
||||
@@ -173,22 +204,42 @@ void AutoTypePlatformX11::unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModi
|
||||
|
||||
int AutoTypePlatformX11::platformEventFilter(void* event)
|
||||
{
|
||||
XEvent* xevent = static_cast<XEvent*>(event);
|
||||
xcb_generic_event_t* genericEvent = static_cast<xcb_generic_event_t*>(event);
|
||||
quint8 type = genericEvent->response_type & 0x7f;
|
||||
|
||||
if ((xevent->type == KeyPress || xevent->type == KeyRelease)
|
||||
&& m_currentGlobalKey
|
||||
&& xevent->xkey.keycode == m_currentGlobalKeycode
|
||||
&& (xevent->xkey.state & m_modifierMask) == m_currentGlobalNativeModifiers
|
||||
&& !QApplication::focusWidget()
|
||||
&& m_loaded) {
|
||||
if (xevent->type == KeyPress) {
|
||||
Q_EMIT globalShortcutTriggered();
|
||||
if (type == XCB_KEY_PRESS || type == XCB_KEY_RELEASE) {
|
||||
xcb_key_press_event_t* keyPressEvent = static_cast<xcb_key_press_event_t*>(event);
|
||||
if (keyPressEvent->detail == m_currentGlobalKeycode
|
||||
&& (keyPressEvent->state & m_modifierMask) == m_currentGlobalNativeModifiers
|
||||
&& (!QApplication::activeWindow() || QApplication::activeWindow()->isMinimized())
|
||||
&& m_loaded) {
|
||||
if (type == XCB_KEY_PRESS) {
|
||||
Q_EMIT globalShortcutTriggered();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (xevent->type == MappingNotify && m_loaded) {
|
||||
XRefreshKeyboardMapping(reinterpret_cast<XMappingEvent*>(xevent));
|
||||
updateKeymap();
|
||||
else if (type == XCB_MAPPING_NOTIFY) {
|
||||
xcb_mapping_notify_event_t* mappingNotifyEvent = static_cast<xcb_mapping_notify_event_t*>(event);
|
||||
if (mappingNotifyEvent->request == XCB_MAPPING_KEYBOARD
|
||||
|| mappingNotifyEvent->request == XCB_MAPPING_MODIFIER)
|
||||
{
|
||||
XMappingEvent xMappingEvent;
|
||||
memset(&xMappingEvent, 0, sizeof(xMappingEvent));
|
||||
xMappingEvent.type = MappingNotify;
|
||||
xMappingEvent.display = m_dpy;
|
||||
if (mappingNotifyEvent->request == XCB_MAPPING_KEYBOARD) {
|
||||
xMappingEvent.request = MappingKeyboard;
|
||||
}
|
||||
else {
|
||||
xMappingEvent.request = MappingModifier;
|
||||
}
|
||||
xMappingEvent.first_keycode = mappingNotifyEvent->first_keycode;
|
||||
xMappingEvent.count = mappingNotifyEvent->count;
|
||||
XRefreshKeyboardMapping(&xMappingEvent);
|
||||
updateKeymap();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
@@ -207,25 +258,28 @@ QString AutoTypePlatformX11::windowTitle(Window window, bool useBlacklist)
|
||||
int format;
|
||||
unsigned long nitems;
|
||||
unsigned long after;
|
||||
unsigned char* data = Q_NULLPTR;
|
||||
unsigned char* data = nullptr;
|
||||
|
||||
int retVal = XGetWindowProperty(m_dpy, window, m_atomNetWmName, 0, 1000, false, m_atomUtf8String,
|
||||
// the window manager spec says we should read _NET_WM_NAME first, then fall back to WM_NAME
|
||||
|
||||
int retVal = XGetWindowProperty(m_dpy, window, m_atomNetWmName, 0, 1000, False, m_atomUtf8String,
|
||||
&type, &format, &nitems, &after, &data);
|
||||
|
||||
if (retVal != 0 && data) {
|
||||
if ((retVal == 0) && data) {
|
||||
title = QString::fromUtf8(reinterpret_cast<char*>(data));
|
||||
}
|
||||
else {
|
||||
XTextProperty textProp;
|
||||
retVal = XGetTextProperty(m_dpy, window, &textProp, m_atomWmName);
|
||||
if (retVal != 0 && textProp.value) {
|
||||
char** textList = Q_NULLPTR;
|
||||
if ((retVal != 0) && textProp.value) {
|
||||
char** textList = nullptr;
|
||||
int count;
|
||||
|
||||
if (textProp.encoding == m_atomUtf8String) {
|
||||
title = QString::fromUtf8(reinterpret_cast<char*>(textProp.value));
|
||||
}
|
||||
else if (XmbTextPropertyToTextList(m_dpy, &textProp, &textList, &count) == 0 && textList && count > 0) {
|
||||
else if ((XmbTextPropertyToTextList(m_dpy, &textProp, &textList, &count) == 0)
|
||||
&& textList && (count > 0)) {
|
||||
title = QString::fromLocal8Bit(textList[0]);
|
||||
}
|
||||
else if (textProp.encoding == m_atomString) {
|
||||
@@ -270,8 +324,8 @@ QString AutoTypePlatformX11::windowClassName(Window window)
|
||||
QString className;
|
||||
|
||||
XClassHint wmClass;
|
||||
wmClass.res_name = Q_NULLPTR;
|
||||
wmClass.res_class = Q_NULLPTR;
|
||||
wmClass.res_name = nullptr;
|
||||
wmClass.res_class = nullptr;
|
||||
|
||||
if (XGetClassHint(m_dpy, window, &wmClass) && wmClass.res_name) {
|
||||
className = QString::fromLocal8Bit(wmClass.res_name);
|
||||
@@ -290,7 +344,7 @@ QList<Window> AutoTypePlatformX11::widgetsToX11Windows(const QWidgetList& widget
|
||||
{
|
||||
QList<Window> windows;
|
||||
|
||||
Q_FOREACH (const QWidget* widget, widgetList) {
|
||||
for (const QWidget* widget : widgetList) {
|
||||
windows.append(widget->effectiveWinId());
|
||||
}
|
||||
|
||||
@@ -310,7 +364,7 @@ QStringList AutoTypePlatformX11::windowTitlesRecursive(Window window)
|
||||
|
||||
Window root;
|
||||
Window parent;
|
||||
Window* children = Q_NULLPTR;
|
||||
Window* children = nullptr;
|
||||
unsigned int numChildren;
|
||||
if (XQueryTree(m_dpy, window, &root, &parent, &children, &numChildren) && children) {
|
||||
for (uint i = 0; i < numChildren; i++) {
|
||||
@@ -331,13 +385,21 @@ bool AutoTypePlatformX11::isTopLevelWindow(Window window)
|
||||
unsigned long nitems;
|
||||
unsigned long after;
|
||||
unsigned char* data = Q_NULLPTR;
|
||||
int retVal = XGetWindowProperty(m_dpy, window, m_atomWmState, 0, 0, false, AnyPropertyType, &type, &format,
|
||||
int retVal = XGetWindowProperty(m_dpy, window, m_atomWmState, 0, 2, False, m_atomWmState, &type, &format,
|
||||
&nitems, &after, &data);
|
||||
if (data) {
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (retVal == 0 && data) {
|
||||
if (type == m_atomWmState && format == 32 && nitems > 0) {
|
||||
qint32 state = static_cast<qint32>(*data);
|
||||
result = (state != WithdrawnState);
|
||||
}
|
||||
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
return (retVal == 0) && type;
|
||||
return result;
|
||||
}
|
||||
|
||||
KeySym AutoTypePlatformX11::charToKeySym(const QChar& ch)
|
||||
@@ -351,9 +413,9 @@ KeySym AutoTypePlatformX11::charToKeySym(const QChar& ch)
|
||||
}
|
||||
|
||||
/* mapping table generated from keysymdef.h */
|
||||
const uint* match = qBinaryFind(m_unicodeToKeysymKeys,
|
||||
m_unicodeToKeysymKeys + m_unicodeToKeysymLen,
|
||||
unicode);
|
||||
const uint* match = Tools::binaryFind(m_unicodeToKeysymKeys,
|
||||
m_unicodeToKeysymKeys + m_unicodeToKeysymLen,
|
||||
unicode);
|
||||
int index = match - m_unicodeToKeysymKeys;
|
||||
if (index != m_unicodeToKeysymLen) {
|
||||
return m_unicodeToKeysymValues[index];
|
||||
@@ -430,9 +492,10 @@ void AutoTypePlatformX11::updateKeymap()
|
||||
int mod_index, mod_key;
|
||||
XModifierKeymap *modifiers;
|
||||
|
||||
/* read keyboard map */
|
||||
if (m_xkb != NULL) XkbFreeKeyboard(m_xkb, XkbAllComponentsMask, True);
|
||||
m_xkb = XkbGetKeyboard (m_dpy, XkbCompatMapMask | XkbGeometryMask, XkbUseCoreKbd);
|
||||
if (m_xkb) {
|
||||
XkbFreeKeyboard(m_xkb, XkbAllComponentsMask, True);
|
||||
}
|
||||
m_xkb = getKeyboard();
|
||||
|
||||
XDisplayKeycodes(m_dpy, &m_minKeycode, &m_maxKeycode);
|
||||
if (m_keysymTable != NULL) XFree(m_keysymTable);
|
||||
@@ -466,6 +529,14 @@ void AutoTypePlatformX11::updateKeymap()
|
||||
}
|
||||
}
|
||||
XFreeModifiermap(modifiers);
|
||||
|
||||
/* Xlib needs some time until the mapping is distributed to
|
||||
all clients */
|
||||
// TODO: we should probably only sleep while in the middle of typing something
|
||||
timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 30 * 1000 * 1000;
|
||||
nanosleep(&ts, nullptr);
|
||||
}
|
||||
|
||||
bool AutoTypePlatformX11::isRemapKeycodeValid()
|
||||
@@ -493,7 +564,7 @@ void AutoTypePlatformX11::stopCatchXErrors()
|
||||
{
|
||||
Q_ASSERT(m_catchXErrors);
|
||||
|
||||
XSync(m_dpy, false);
|
||||
XSync(m_dpy, False);
|
||||
XSetErrorHandler(m_oldXErrorHandler);
|
||||
m_catchXErrors = false;
|
||||
}
|
||||
@@ -510,6 +581,27 @@ int AutoTypePlatformX11::x11ErrorHandler(Display* display, XErrorEvent* error)
|
||||
return 1;
|
||||
}
|
||||
|
||||
XkbDescPtr AutoTypePlatformX11::getKeyboard()
|
||||
{
|
||||
int num_devices;
|
||||
XID keyboard_id = XkbUseCoreKbd;
|
||||
XDeviceInfo* devices = XListInputDevices(m_dpy, &num_devices);
|
||||
if (!devices) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_devices; i++) {
|
||||
if (QString(devices[i].name) == "Virtual core XTEST keyboard") {
|
||||
keyboard_id = devices[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XFreeDeviceList(devices);
|
||||
|
||||
return XkbGetKeyboard(m_dpy, XkbCompatMapMask | XkbGeometryMask, keyboard_id);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// The following code is taken from xvkbd 3.0 and has been slightly modified.
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -532,13 +624,6 @@ int AutoTypePlatformX11::AddKeysym(KeySym keysym)
|
||||
XFlush(m_dpy);
|
||||
updateKeymap();
|
||||
|
||||
/* Xlib needs some time until the mapping is distributed to
|
||||
all clients */
|
||||
timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 10 * 1000 * 1000;
|
||||
nanosleep(&ts, Q_NULLPTR);
|
||||
|
||||
return m_remapKeycode;
|
||||
}
|
||||
|
||||
@@ -549,11 +634,18 @@ int AutoTypePlatformX11::AddKeysym(KeySym keysym)
|
||||
*/
|
||||
void AutoTypePlatformX11::SendEvent(XKeyEvent* event, int event_type)
|
||||
{
|
||||
XSync(event->display, FALSE);
|
||||
XSync(event->display, False);
|
||||
int (*oldHandler) (Display*, XErrorEvent*) = XSetErrorHandler(MyErrorHandler);
|
||||
|
||||
event->type = event_type;
|
||||
XTestFakeKeyEvent(event->display, event->keycode, event->type == KeyPress, 0);
|
||||
Bool press;
|
||||
if (event->type == KeyPress) {
|
||||
press = True;
|
||||
}
|
||||
else {
|
||||
press = False;
|
||||
}
|
||||
XTestFakeKeyEvent(event->display, event->keycode, press, 0);
|
||||
XFlush(event->display);
|
||||
|
||||
XSetErrorHandler(oldHandler);
|
||||
@@ -636,7 +728,7 @@ void AutoTypePlatformX11::SendKeyPressedEvent(KeySym keysym)
|
||||
int keycode;
|
||||
|
||||
if (keysym == NoSymbol) {
|
||||
qWarning("No such key: keysym=0x%lX", static_cast<long>(keysym));
|
||||
qWarning("No such key: keysym=0x%lX", keysym);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -651,27 +743,60 @@ void AutoTypePlatformX11::SendKeyPressedEvent(KeySym keysym)
|
||||
event.y = 1;
|
||||
event.x_root = 1;
|
||||
event.y_root = 1;
|
||||
event.same_screen = TRUE;
|
||||
event.same_screen = True;
|
||||
|
||||
Window root, child;
|
||||
int root_x, root_y, x, y;
|
||||
unsigned int mask;
|
||||
unsigned int saved_mask;
|
||||
unsigned int wanted_mask = 0;
|
||||
unsigned int original_mask;
|
||||
|
||||
XQueryPointer(m_dpy, event.root, &root, &child, &root_x, &root_y, &x, &y, &mask);
|
||||
saved_mask = mask;
|
||||
XQueryPointer(m_dpy, event.root, &root, &child, &root_x, &root_y, &x, &y, &original_mask);
|
||||
|
||||
/* determine keycode and mask for the given keysym */
|
||||
keycode = GetKeycode(keysym, &mask);
|
||||
keycode = GetKeycode(keysym, &wanted_mask);
|
||||
if (keycode < 8 || keycode > 255) {
|
||||
qWarning("Unable to get valid keycode for key: keysym=0x%lX", static_cast<long>(keysym));
|
||||
qWarning("Unable to get valid keycode for key: keysym=0x%lX", keysym);
|
||||
return;
|
||||
}
|
||||
|
||||
/* release all modifiers */
|
||||
SendModifier(&event, mask, KeyRelease);
|
||||
event.state = original_mask;
|
||||
|
||||
SendModifier(&event, mask, KeyPress);
|
||||
// modifiers that need to be pressed but aren't
|
||||
unsigned int press_mask = wanted_mask & ~original_mask;
|
||||
|
||||
// modifiers that are pressed but maybe shouldn't
|
||||
unsigned int release_check_mask = original_mask & ~wanted_mask;
|
||||
|
||||
// modifiers we need to release before sending the keycode
|
||||
unsigned int release_mask = 0;
|
||||
|
||||
// check every release_check_mask individually if it affects the keysym we would generate
|
||||
// if it doesn't we probably don't need to release it
|
||||
for (int mod_index = ShiftMapIndex; mod_index <= Mod5MapIndex; mod_index ++) {
|
||||
if (release_check_mask & (1 << mod_index)) {
|
||||
unsigned int mods_rtrn;
|
||||
KeySym keysym_rtrn;
|
||||
XkbTranslateKeyCode(m_xkb, keycode, wanted_mask | (1 << mod_index), &mods_rtrn, &keysym_rtrn);
|
||||
|
||||
if (keysym_rtrn != keysym) {
|
||||
release_mask |= (1 << mod_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally check if the combination of pressed modifiers that we chose to ignore affects the keysym
|
||||
unsigned int mods_rtrn;
|
||||
KeySym keysym_rtrn;
|
||||
XkbTranslateKeyCode(m_xkb, keycode, wanted_mask | (release_check_mask & ~release_mask), &mods_rtrn, &keysym_rtrn);
|
||||
if (keysym_rtrn != keysym) {
|
||||
// oh well, release all the modifiers we don't want
|
||||
release_mask = release_check_mask;
|
||||
}
|
||||
|
||||
/* release all modifiers */
|
||||
SendModifier(&event, release_mask, KeyRelease);
|
||||
|
||||
SendModifier(&event, press_mask, KeyPress);
|
||||
|
||||
/* press and release key */
|
||||
event.keycode = keycode;
|
||||
@@ -679,10 +804,10 @@ void AutoTypePlatformX11::SendKeyPressedEvent(KeySym keysym)
|
||||
SendEvent(&event, KeyRelease);
|
||||
|
||||
/* release the modifiers */
|
||||
SendModifier(&event, mask, KeyRelease);
|
||||
SendModifier(&event, press_mask, KeyRelease);
|
||||
|
||||
/* restore the old keyboard mask */
|
||||
SendModifier(&event, saved_mask, KeyPress);
|
||||
SendModifier(&event, release_mask, KeyPress);
|
||||
}
|
||||
|
||||
int AutoTypePlatformX11::MyErrorHandler(Display* my_dpy, XErrorEvent* event)
|
||||
@@ -718,4 +843,36 @@ int AutoTypePlatformX11::initialTimeout()
|
||||
return 500;
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN2(keepassx-autotype-x11, AutoTypePlatformX11)
|
||||
bool AutoTypePlatformX11::raiseWindow(WId window)
|
||||
{
|
||||
if (m_atomNetActiveWindow == None) {
|
||||
return false;
|
||||
}
|
||||
|
||||
XRaiseWindow(m_dpy, window);
|
||||
|
||||
XEvent event;
|
||||
event.xclient.type = ClientMessage;
|
||||
event.xclient.serial = 0;
|
||||
event.xclient.send_event = True;
|
||||
event.xclient.window = window;
|
||||
event.xclient.message_type = m_atomNetActiveWindow;
|
||||
event.xclient.format = 32;
|
||||
event.xclient.data.l[0] = 1; // FromApplication
|
||||
event.xclient.data.l[1] = QX11Info::appUserTime();
|
||||
QWidget* activeWindow = QApplication::activeWindow();
|
||||
if (activeWindow) {
|
||||
event.xclient.data.l[2] = activeWindow->internalWinId();
|
||||
}
|
||||
else {
|
||||
event.xclient.data.l[2] = 0;
|
||||
}
|
||||
event.xclient.data.l[3] = 0;
|
||||
event.xclient.data.l[4] = 0;
|
||||
XSendEvent(m_dpy, m_rootWindow, False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
&event);
|
||||
XFlush(m_dpy);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -16,8 +16,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSX_AUTOTYPEX11_H
|
||||
#define KEEPASSX_AUTOTYPEX11_H
|
||||
#ifndef KEEPASSX_AUTOTYPEXCB_H
|
||||
#define KEEPASSX_AUTOTYPEXCB_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QSet>
|
||||
@@ -31,26 +31,28 @@
|
||||
|
||||
#include "autotype/AutoTypePlatformPlugin.h"
|
||||
#include "autotype/AutoTypeAction.h"
|
||||
#include "core/Global.h"
|
||||
|
||||
#define N_MOD_INDICES (Mod5MapIndex + 1)
|
||||
|
||||
class AutoTypePlatformX11 : public QObject, public AutoTypePlatformInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.keepassx.AutoTypePlatformX11")
|
||||
Q_INTERFACES(AutoTypePlatformInterface)
|
||||
|
||||
public:
|
||||
AutoTypePlatformX11();
|
||||
void unload() Q_DECL_OVERRIDE;
|
||||
QStringList windowTitles();
|
||||
WId activeWindow();
|
||||
QString activeWindowTitle();
|
||||
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||
void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||
int platformEventFilter(void* event);
|
||||
int initialTimeout();
|
||||
AutoTypeExecutor* createExecutor();
|
||||
bool isAvailable() override;
|
||||
void unload() override;
|
||||
QStringList windowTitles() override;
|
||||
WId activeWindow() override;
|
||||
QString activeWindowTitle() override;
|
||||
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) override;
|
||||
void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) override;
|
||||
int platformEventFilter(void* event) override;
|
||||
int initialTimeout() override;
|
||||
bool raiseWindow(WId window) override;
|
||||
AutoTypeExecutor* createExecutor() override;
|
||||
|
||||
KeySym charToKeySym(const QChar& ch);
|
||||
KeySym keyToKeySym(Qt::Key key);
|
||||
@@ -71,6 +73,7 @@ private:
|
||||
void stopCatchXErrors();
|
||||
static int x11ErrorHandler(Display* display, XErrorEvent* error);
|
||||
|
||||
XkbDescPtr getKeyboard();
|
||||
void updateKeymap();
|
||||
bool isRemapKeycodeValid();
|
||||
int AddKeysym(KeySym keysym);
|
||||
@@ -89,6 +92,7 @@ private:
|
||||
Atom m_atomNetWmName;
|
||||
Atom m_atomString;
|
||||
Atom m_atomUtf8String;
|
||||
Atom m_atomNetActiveWindow;
|
||||
QSet<QString> m_classBlacklist;
|
||||
Qt::Key m_currentGlobalKey;
|
||||
Qt::KeyboardModifiers m_currentGlobalModifiers;
|
||||
@@ -120,11 +124,11 @@ class AutoTypeExecturorX11 : public AutoTypeExecutor
|
||||
public:
|
||||
explicit AutoTypeExecturorX11(AutoTypePlatformX11* platform);
|
||||
|
||||
void execChar(AutoTypeChar* action);
|
||||
void execKey(AutoTypeKey* action);
|
||||
void execChar(AutoTypeChar* action) override;
|
||||
void execKey(AutoTypeKey* action) override;
|
||||
|
||||
private:
|
||||
AutoTypePlatformX11* const m_platform;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_AUTOTYPEX11_H
|
||||
#endif // KEEPASSX_AUTOTYPEXCB_H
|
||||
11
src/autotype/xcb/CMakeLists.txt
Normal file
11
src/autotype/xcb/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
include_directories(SYSTEM ${X11_X11_INCLUDE_PATH})
|
||||
|
||||
set(autotype_XCB_SOURCES
|
||||
AutoTypeXCB.cpp
|
||||
)
|
||||
|
||||
add_library(keepassx-autotype-xcb MODULE ${autotype_XCB_SOURCES})
|
||||
target_link_libraries(keepassx-autotype-xcb Qt5::Core Qt5::Widgets Qt5::X11Extras ${X11_X11_LIB} ${X11_Xi_LIB} ${X11_XTest_LIB})
|
||||
install(TARGETS keepassx-autotype-xcb
|
||||
BUNDLE DESTINATION . COMPONENT Runtime
|
||||
LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime)
|
||||
@@ -6,13 +6,14 @@
|
||||
#define KEEPASSX_VERSION "${KEEPASSX_VERSION}"
|
||||
|
||||
#define KEEPASSX_SOURCE_DIR "${CMAKE_SOURCE_DIR}"
|
||||
#define KEEPASSX_BINARY_DIR "${CMAKE_BINARY_DIR}"
|
||||
|
||||
#define KEEPASSX_PREFIX_DIR "${CMAKE_INSTALL_PREFIX}"
|
||||
#define KEEPASSX_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}"
|
||||
#define KEEPASSX_DATA_DIR "${DATA_INSTALL_DIR}"
|
||||
|
||||
#cmakedefine HAVE_PR_SET_DUMPABLE 1
|
||||
#cmakedefine HAVE_RLIMIT_CORE 1
|
||||
#cmakedefine HAVE_PT_DENY_ATTACH 1
|
||||
|
||||
#cmakedefine GCRYPT_HAS_SALSA20
|
||||
|
||||
#endif // KEEPASSX_CONFIG_KEEPASSX_H
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class AutoTypeAssociations : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -36,7 +34,7 @@ public:
|
||||
bool operator!=(const AutoTypeAssociations::Association& other) const;
|
||||
};
|
||||
|
||||
explicit AutoTypeAssociations(QObject* parent = Q_NULLPTR);
|
||||
explicit AutoTypeAssociations(QObject* parent = nullptr);
|
||||
void copyDataFrom(const AutoTypeAssociations* other);
|
||||
void add(const AutoTypeAssociations::Association& association);
|
||||
void remove(int index);
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
#include "Config.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDesktopServices>
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
#include <QStandardPaths>
|
||||
#include <QTemporaryFile>
|
||||
|
||||
Config* Config::m_instance(Q_NULLPTR);
|
||||
Config* Config::m_instance(nullptr);
|
||||
|
||||
QVariant Config::get(const QString& key)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ Config::Config(QObject* parent)
|
||||
QString homePath = QDir::homePath();
|
||||
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
||||
// we can't use QDesktopServices on X11 as it uses XDG_DATA_HOME instead of XDG_CONFIG_HOME
|
||||
// we can't use QStandardPaths on X11 as it uses XDG_DATA_HOME instead of XDG_CONFIG_HOME
|
||||
QByteArray env = qgetenv("XDG_CONFIG_HOME");
|
||||
if (env.isEmpty()) {
|
||||
userPath = homePath;
|
||||
@@ -70,8 +70,9 @@ Config::Config(QObject* parent)
|
||||
|
||||
userPath += "/keepassx/";
|
||||
#else
|
||||
userPath = QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
|
||||
// storageLocation() appends the application name ("/keepassx/") to the end
|
||||
userPath = QDir::fromNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
|
||||
// storageLocation() appends the application name ("/keepassx") to the end
|
||||
userPath += "/";
|
||||
#endif
|
||||
|
||||
userPath += "keepassx2.ini";
|
||||
@@ -88,17 +89,24 @@ void Config::init(const QString& fileName)
|
||||
m_settings.reset(new QSettings(fileName, QSettings::IniFormat));
|
||||
|
||||
m_defaults.insert("RememberLastDatabases", true);
|
||||
m_defaults.insert("RememberLastKeyFiles", true);
|
||||
m_defaults.insert("OpenPreviousDatabasesOnStartup", true);
|
||||
m_defaults.insert("ModifiedOnExpandedStateChanges", true);
|
||||
m_defaults.insert("AutoSaveAfterEveryChange", false);
|
||||
m_defaults.insert("AutoSaveOnExit", false);
|
||||
m_defaults.insert("ShowToolbar", true);
|
||||
m_defaults.insert("MinimizeOnCopy", false);
|
||||
m_defaults.insert("UseGroupIconOnEntryCreation", false);
|
||||
m_defaults.insert("AutoTypeEntryTitleMatch", true);
|
||||
m_defaults.insert("security/clearclipboard", true);
|
||||
m_defaults.insert("security/clearclipboardtimeout", 10);
|
||||
m_defaults.insert("security/lockdatabaseidle", false);
|
||||
m_defaults.insert("security/lockdatabaseidlesec", 10);
|
||||
m_defaults.insert("security/passwordscleartext", false);
|
||||
m_defaults.insert("security/autotypeask", true);
|
||||
m_defaults.insert("GUI/Language", "system");
|
||||
m_defaults.insert("GUI/ShowTrayIcon", false);
|
||||
m_defaults.insert("GUI/MinimizeToTray", false);
|
||||
m_defaults.insert("GUI/MinimizeOnClose", false);
|
||||
}
|
||||
|
||||
Config* Config::instance()
|
||||
@@ -110,7 +118,7 @@ Config* Config::instance()
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void Config::createConfigFromFile(QString file)
|
||||
void Config::createConfigFromFile(const QString& file)
|
||||
{
|
||||
Q_ASSERT(!m_instance);
|
||||
m_instance = new Config(file, qApp);
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <QScopedPointer>
|
||||
#include <QVariant>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class QSettings;
|
||||
|
||||
class Config : public QObject
|
||||
@@ -36,7 +34,7 @@ public:
|
||||
void set(const QString& key, const QVariant& value);
|
||||
|
||||
static Config* instance();
|
||||
static void createConfigFromFile(QString file);
|
||||
static void createConfigFromFile(const QString& file);
|
||||
static void createTempFileInstance();
|
||||
|
||||
private:
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include "core/Group.h"
|
||||
#include "core/Metadata.h"
|
||||
#include "core/Tools.h"
|
||||
#include "crypto/Random.h"
|
||||
#include "format/KeePass2.h"
|
||||
|
||||
@@ -37,7 +36,7 @@ Database::Database()
|
||||
{
|
||||
m_data.cipher = KeePass2::CIPHER_AES;
|
||||
m_data.compressionAlgo = CompressionGZip;
|
||||
m_data.transformRounds = 50000;
|
||||
m_data.transformRounds = 100000;
|
||||
m_data.hasKey = false;
|
||||
|
||||
setRootGroup(new Group());
|
||||
@@ -92,20 +91,22 @@ Entry* Database::resolveEntry(const Uuid& uuid)
|
||||
|
||||
Entry* Database::recFindEntry(const Uuid& uuid, Group* group)
|
||||
{
|
||||
Q_FOREACH (Entry* entry, group->entries()) {
|
||||
const QList<Entry*> entryList = group->entries();
|
||||
for (Entry* entry : entryList) {
|
||||
if (entry->uuid() == uuid) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
Q_FOREACH (Group* child, group->children()) {
|
||||
const QList<Group*> children = group->children();
|
||||
for (Group* child : children) {
|
||||
Entry* result = recFindEntry(uuid, child);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return Q_NULLPTR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Group* Database::resolveGroup(const Uuid& uuid)
|
||||
@@ -119,14 +120,15 @@ Group* Database::recFindGroup(const Uuid& uuid, Group* group)
|
||||
return group;
|
||||
}
|
||||
|
||||
Q_FOREACH (Group* child, group->children()) {
|
||||
const QList<Group*> children = group->children();
|
||||
for (Group* child : children) {
|
||||
Group* result = recFindGroup(uuid, child);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return Q_NULLPTR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QList<DeletedObject> Database::deletedObjects()
|
||||
@@ -143,7 +145,7 @@ void Database::addDeletedObject(const DeletedObject& delObj)
|
||||
void Database::addDeletedObject(const Uuid& uuid)
|
||||
{
|
||||
DeletedObject delObj;
|
||||
delObj.deletionTime = Tools::currentDateTimeUtc();
|
||||
delObj.deletionTime = QDateTime::currentDateTimeUtc();
|
||||
delObj.uuid = uuid;
|
||||
|
||||
addDeletedObject(delObj);
|
||||
@@ -188,32 +190,51 @@ void Database::setCompressionAlgo(Database::CompressionAlgorithm algo)
|
||||
m_data.compressionAlgo = algo;
|
||||
}
|
||||
|
||||
void Database::setTransformRounds(quint64 rounds)
|
||||
bool Database::setTransformRounds(quint64 rounds)
|
||||
{
|
||||
if (m_data.transformRounds != rounds) {
|
||||
quint64 oldRounds = m_data.transformRounds;
|
||||
|
||||
m_data.transformRounds = rounds;
|
||||
|
||||
if (m_data.hasKey) {
|
||||
setKey(m_data.key);
|
||||
if (!setKey(m_data.key)) {
|
||||
m_data.transformRounds = oldRounds;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Database::setKey(const CompositeKey& key, const QByteArray& transformSeed, bool updateChangedTime)
|
||||
bool Database::setKey(const CompositeKey& key, const QByteArray& transformSeed,
|
||||
bool updateChangedTime)
|
||||
{
|
||||
bool ok;
|
||||
QString errorString;
|
||||
|
||||
QByteArray transformedMasterKey =
|
||||
key.transform(transformSeed, transformRounds(), &ok, &errorString);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_data.key = key;
|
||||
m_data.transformSeed = transformSeed;
|
||||
m_data.transformedMasterKey = key.transform(transformSeed, transformRounds());
|
||||
m_data.transformedMasterKey = transformedMasterKey;
|
||||
m_data.hasKey = true;
|
||||
if (updateChangedTime) {
|
||||
m_metadata->setMasterKeyChanged(Tools::currentDateTimeUtc());
|
||||
m_metadata->setMasterKeyChanged(QDateTime::currentDateTimeUtc());
|
||||
}
|
||||
Q_EMIT modifiedImmediate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Database::setKey(const CompositeKey& key)
|
||||
bool Database::setKey(const CompositeKey& key)
|
||||
{
|
||||
setKey(key, randomGen()->randomArray(32));
|
||||
return setKey(key, randomGen()->randomArray(32));
|
||||
}
|
||||
|
||||
bool Database::hasKey() const
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
|
||||
#include "core/Uuid.h"
|
||||
#include "keys/CompositeKey.h"
|
||||
@@ -69,7 +70,7 @@ public:
|
||||
* Sets group as the root group and takes ownership of it.
|
||||
* Warning: Be careful when calling this method as it doesn't
|
||||
* emit any notifications so e.g. models aren't updated.
|
||||
* The caller is responsible for cleaning up the pervious
|
||||
* The caller is responsible for cleaning up the previous
|
||||
root group.
|
||||
*/
|
||||
void setRootGroup(Group* group);
|
||||
@@ -90,13 +91,14 @@ public:
|
||||
|
||||
void setCipher(const Uuid& cipher);
|
||||
void setCompressionAlgo(Database::CompressionAlgorithm algo);
|
||||
void setTransformRounds(quint64 rounds);
|
||||
void setKey(const CompositeKey& key, const QByteArray& transformSeed, bool updateChangedTime = true);
|
||||
bool setTransformRounds(quint64 rounds);
|
||||
bool setKey(const CompositeKey& key, const QByteArray& transformSeed,
|
||||
bool updateChangedTime = true);
|
||||
|
||||
/**
|
||||
* Sets the database key and generates a random transform seed.
|
||||
*/
|
||||
void setKey(const CompositeKey& key);
|
||||
bool setKey(const CompositeKey& key);
|
||||
bool hasKey() const;
|
||||
bool verifyKey(const CompositeKey& key) const;
|
||||
void recycleEntry(Entry* entry);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "core/FilePath.h"
|
||||
|
||||
DatabaseIcons* DatabaseIcons::m_instance(Q_NULLPTR);
|
||||
DatabaseIcons* DatabaseIcons::m_instance(nullptr);
|
||||
const int DatabaseIcons::IconCount(69);
|
||||
const int DatabaseIcons::ExpiredIconIndex(45);
|
||||
const char* const DatabaseIcons::m_indexToName[] = {
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
#include <QPixmapCache>
|
||||
#include <QVector>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class DatabaseIcons
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "core/DatabaseIcons.h"
|
||||
#include "core/Group.h"
|
||||
#include "core/Metadata.h"
|
||||
#include "core/Tools.h"
|
||||
|
||||
const int Entry::DefaultIconNumber = 0;
|
||||
|
||||
@@ -29,7 +28,7 @@ Entry::Entry()
|
||||
: m_attributes(new EntryAttributes(this))
|
||||
, m_attachments(new EntryAttachments(this))
|
||||
, m_autoTypeAssociations(new AutoTypeAssociations(this))
|
||||
, m_tmpHistoryItem(Q_NULLPTR)
|
||||
, m_tmpHistoryItem(nullptr)
|
||||
, m_modifiedSinceBegin(false)
|
||||
, m_updateTimeinfo(true)
|
||||
{
|
||||
@@ -74,8 +73,8 @@ template <class T> inline bool Entry::set(T& property, const T& value)
|
||||
void Entry::updateTimeinfo()
|
||||
{
|
||||
if (m_updateTimeinfo) {
|
||||
m_data.timeInfo.setLastModificationTime(Tools::currentDateTimeUtc());
|
||||
m_data.timeInfo.setLastAccessTime(Tools::currentDateTimeUtc());
|
||||
m_data.timeInfo.setLastModificationTime(QDateTime::currentDateTimeUtc());
|
||||
m_data.timeInfo.setLastAccessTime(QDateTime::currentDateTimeUtc());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,13 +113,25 @@ QPixmap Entry::iconPixmap() const
|
||||
else {
|
||||
Q_ASSERT(database());
|
||||
|
||||
QPixmap pixmap;
|
||||
if (database() && !QPixmapCache::find(m_pixmapCacheKey, &pixmap)) {
|
||||
pixmap = QPixmap::fromImage(database()->metadata()->customIcon(m_data.customIcon));
|
||||
m_pixmapCacheKey = QPixmapCache::insert(pixmap);
|
||||
if (database()) {
|
||||
return database()->metadata()->customIconPixmap(m_data.customIcon);
|
||||
}
|
||||
else {
|
||||
return QPixmap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pixmap;
|
||||
QPixmap Entry::iconScaledPixmap() const
|
||||
{
|
||||
if (m_data.customIcon.isNull()) {
|
||||
// built-in icons are 16x16 so don't need to be scaled
|
||||
return databaseIcons()->iconPixmap(m_data.iconNumber);
|
||||
}
|
||||
else {
|
||||
Q_ASSERT(database());
|
||||
|
||||
return database()->metadata()->customIconScaledPixmap(m_data.customIcon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +222,7 @@ QString Entry::notes() const
|
||||
|
||||
bool Entry::isExpired() const
|
||||
{
|
||||
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < Tools::currentDateTimeUtc();
|
||||
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
|
||||
EntryAttributes* Entry::attributes()
|
||||
@@ -248,8 +259,6 @@ void Entry::setIcon(int iconNumber)
|
||||
m_data.iconNumber = iconNumber;
|
||||
m_data.customIcon = Uuid();
|
||||
|
||||
m_pixmapCacheKey = QPixmapCache::Key();
|
||||
|
||||
Q_EMIT modified();
|
||||
emitDataChanged();
|
||||
}
|
||||
@@ -263,8 +272,6 @@ void Entry::setIcon(const Uuid& uuid)
|
||||
m_data.customIcon = uuid;
|
||||
m_data.iconNumber = 0;
|
||||
|
||||
m_pixmapCacheKey = QPixmapCache::Key();
|
||||
|
||||
Q_EMIT modified();
|
||||
emitDataChanged();
|
||||
}
|
||||
@@ -364,7 +371,6 @@ const QList<Entry*>& Entry::historyItems() const
|
||||
void Entry::addHistoryItem(Entry* entry)
|
||||
{
|
||||
Q_ASSERT(!entry->parent());
|
||||
Q_ASSERT(entry->uuid() == uuid());
|
||||
|
||||
m_history.append(entry);
|
||||
Q_EMIT modified();
|
||||
@@ -376,7 +382,7 @@ void Entry::removeHistoryItems(const QList<Entry*>& historyEntries)
|
||||
return;
|
||||
}
|
||||
|
||||
Q_FOREACH (Entry* entry, historyEntries) {
|
||||
for (Entry* entry : historyEntries) {
|
||||
Q_ASSERT(!entry->parent());
|
||||
Q_ASSERT(entry->uuid() == uuid());
|
||||
Q_ASSERT(m_history.contains(entry));
|
||||
@@ -425,8 +431,8 @@ void Entry::truncateHistory()
|
||||
if (size <= histMaxSize) {
|
||||
size += historyItem->attributes()->attributesSize();
|
||||
|
||||
QSet<QByteArray> newAttachments = historyItem->attachments()->values().toSet() - foundAttachements;
|
||||
Q_FOREACH (const QByteArray& attachment, newAttachments) {
|
||||
const QSet<QByteArray> newAttachments = historyItem->attachments()->values().toSet() - foundAttachements;
|
||||
for (const QByteArray& attachment : newAttachments) {
|
||||
size += attachment.size();
|
||||
}
|
||||
foundAttachements += newAttachments;
|
||||
@@ -455,7 +461,7 @@ Entry* Entry::clone(CloneFlags flags) const
|
||||
entry->m_attachments->copyDataFrom(m_attachments);
|
||||
entry->m_autoTypeAssociations->copyDataFrom(this->m_autoTypeAssociations);
|
||||
if (flags & CloneIncludeHistory) {
|
||||
Q_FOREACH (Entry* historyItem, m_history) {
|
||||
for (Entry* historyItem : m_history) {
|
||||
Entry* historyItemClone = historyItem->clone(flags & ~CloneIncludeHistory & ~CloneNewUuid);
|
||||
historyItemClone->setUpdateTimeinfo(false);
|
||||
historyItemClone->setUuid(entry->uuid());
|
||||
@@ -466,7 +472,7 @@ Entry* Entry::clone(CloneFlags flags) const
|
||||
entry->setUpdateTimeinfo(true);
|
||||
|
||||
if (flags & CloneResetTimeInfo) {
|
||||
QDateTime now = Tools::currentDateTimeUtc();
|
||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||
entry->m_data.timeInfo.setCreationTime(now);
|
||||
entry->m_data.timeInfo.setLastModificationTime(now);
|
||||
entry->m_data.timeInfo.setLastAccessTime(now);
|
||||
@@ -502,7 +508,7 @@ void Entry::beginUpdate()
|
||||
m_modifiedSinceBegin = false;
|
||||
}
|
||||
|
||||
void Entry::endUpdate()
|
||||
bool Entry::endUpdate()
|
||||
{
|
||||
Q_ASSERT(m_tmpHistoryItem);
|
||||
if (m_modifiedSinceBegin) {
|
||||
@@ -514,7 +520,9 @@ void Entry::endUpdate()
|
||||
delete m_tmpHistoryItem;
|
||||
}
|
||||
|
||||
m_tmpHistoryItem = Q_NULLPTR;
|
||||
m_tmpHistoryItem = nullptr;
|
||||
|
||||
return m_modifiedSinceBegin;
|
||||
}
|
||||
|
||||
void Entry::updateModifiedSinceBegin()
|
||||
@@ -560,7 +568,7 @@ void Entry::setGroup(Group* group)
|
||||
QObject::setParent(group);
|
||||
|
||||
if (m_updateTimeinfo) {
|
||||
m_data.timeInfo.setLocationChanged(Tools::currentDateTimeUtc());
|
||||
m_data.timeInfo.setLocationChanged(QDateTime::currentDateTimeUtc());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,29 +583,10 @@ const Database* Entry::database() const
|
||||
return m_group->database();
|
||||
}
|
||||
else {
|
||||
return Q_NULLPTR;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Entry::match(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts);
|
||||
Q_FOREACH (const QString& word, wordList) {
|
||||
if (!wordMatch(word, caseSensitivity)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Entry::wordMatch(const QString& word, Qt::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
return title().contains(word, caseSensitivity) ||
|
||||
username().contains(word, caseSensitivity) ||
|
||||
url().contains(word, caseSensitivity) ||
|
||||
notes().contains(word, caseSensitivity);
|
||||
}
|
||||
|
||||
QString Entry::resolvePlaceholders(const QString& str) const
|
||||
{
|
||||
QString result = str;
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <QImage>
|
||||
#include <QMap>
|
||||
#include <QPixmap>
|
||||
#include <QPixmapCache>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QUrl>
|
||||
@@ -30,7 +29,6 @@
|
||||
#include "core/AutoTypeAssociations.h"
|
||||
#include "core/EntryAttachments.h"
|
||||
#include "core/EntryAttributes.h"
|
||||
#include "core/Global.h"
|
||||
#include "core/TimeInfo.h"
|
||||
#include "core/Uuid.h"
|
||||
|
||||
@@ -61,6 +59,7 @@ public:
|
||||
Uuid uuid() const;
|
||||
QImage icon() const;
|
||||
QPixmap iconPixmap() const;
|
||||
QPixmap iconScaledPixmap() const;
|
||||
int iconNumber() const;
|
||||
Uuid iconUuid() const;
|
||||
QColor foregroundColor() const;
|
||||
@@ -134,14 +133,13 @@ public:
|
||||
* if the entry has been changed.
|
||||
*/
|
||||
void beginUpdate();
|
||||
void endUpdate();
|
||||
bool endUpdate();
|
||||
|
||||
Group* group();
|
||||
const Group* group() const;
|
||||
void setGroup(Group* group);
|
||||
|
||||
void setUpdateTimeinfo(bool value);
|
||||
bool match(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
@@ -157,7 +155,6 @@ private Q_SLOTS:
|
||||
void updateModifiedSinceBegin();
|
||||
|
||||
private:
|
||||
bool wordMatch(const QString& word, Qt::CaseSensitivity caseSensitivity);
|
||||
const Database* database() const;
|
||||
template <class T> bool set(T& property, const T& value);
|
||||
|
||||
@@ -171,7 +168,6 @@ private:
|
||||
Entry* m_tmpHistoryItem;
|
||||
bool m_modifiedSinceBegin;
|
||||
QPointer<Group> m_group;
|
||||
mutable QPixmapCache::Key m_pixmapCacheKey;
|
||||
bool m_updateTimeinfo;
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@ QList<QString> EntryAttachments::keys() const
|
||||
return m_attachments.keys();
|
||||
}
|
||||
|
||||
bool EntryAttachments::hasKey(const QString& key) const
|
||||
{
|
||||
return m_attachments.keys().contains(key);
|
||||
}
|
||||
|
||||
QList<QByteArray> EntryAttachments::values() const
|
||||
{
|
||||
return m_attachments.values();
|
||||
|
||||
@@ -21,15 +21,14 @@
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class EntryAttachments : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EntryAttachments(QObject* parent = Q_NULLPTR);
|
||||
explicit EntryAttachments(QObject* parent = nullptr);
|
||||
QList<QString> keys() const;
|
||||
bool hasKey(const QString& key) const;
|
||||
QList<QByteArray> values() const;
|
||||
QByteArray value(const QString& key) const;
|
||||
void set(const QString& key, const QByteArray& value);
|
||||
|
||||
@@ -36,10 +36,16 @@ QList<QString> EntryAttributes::keys() const
|
||||
return m_attributes.keys();
|
||||
}
|
||||
|
||||
bool EntryAttributes::hasKey(const QString& key) const
|
||||
{
|
||||
return m_attributes.keys().contains(key);
|
||||
}
|
||||
|
||||
QList<QString> EntryAttributes::customKeys()
|
||||
{
|
||||
QList<QString> customKeys;
|
||||
Q_FOREACH (const QString& key, keys()) {
|
||||
const QList<QString> keyList = keys();
|
||||
for (const QString& key : keyList) {
|
||||
if (!isDefaultAttribute(key)) {
|
||||
customKeys.append(key);
|
||||
}
|
||||
@@ -52,6 +58,11 @@ QString EntryAttributes::value(const QString& key) const
|
||||
return m_attributes.value(key);
|
||||
}
|
||||
|
||||
bool EntryAttributes::contains(const QString &key) const
|
||||
{
|
||||
return m_attributes.contains(key);
|
||||
}
|
||||
|
||||
bool EntryAttributes::isProtected(const QString& key) const
|
||||
{
|
||||
return m_protectedAttributes.contains(key);
|
||||
@@ -157,14 +168,16 @@ void EntryAttributes::copyCustomKeysFrom(const EntryAttributes* other)
|
||||
Q_EMIT aboutToBeReset();
|
||||
|
||||
// remove all non-default keys
|
||||
Q_FOREACH (const QString& key, keys()) {
|
||||
const QList<QString> keyList = keys();
|
||||
for (const QString& key : keyList) {
|
||||
if (!isDefaultAttribute(key)) {
|
||||
m_attributes.remove(key);
|
||||
m_protectedAttributes.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
Q_FOREACH (const QString& key, other->keys()) {
|
||||
const QList<QString> otherKeyList = other->keys();
|
||||
for (const QString& key : otherKeyList) {
|
||||
if (!isDefaultAttribute(key)) {
|
||||
m_attributes.insert(key, other->value(key));
|
||||
if (other->isProtected(key)) {
|
||||
@@ -184,7 +197,8 @@ bool EntryAttributes::areCustomKeysDifferent(const EntryAttributes* other)
|
||||
return true;
|
||||
}
|
||||
|
||||
Q_FOREACH (const QString& key, keys()) {
|
||||
const QList<QString> keyList = keys();
|
||||
for (const QString& key : keyList) {
|
||||
if (isDefaultAttribute(key)) {
|
||||
continue;
|
||||
}
|
||||
@@ -229,7 +243,7 @@ void EntryAttributes::clear()
|
||||
m_attributes.clear();
|
||||
m_protectedAttributes.clear();
|
||||
|
||||
Q_FOREACH (const QString& key, DefaultAttributes) {
|
||||
for (const QString& key : DefaultAttributes) {
|
||||
m_attributes.insert(key, "");
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,17 @@
|
||||
#include <QSet>
|
||||
#include <QStringList>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class EntryAttributes : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EntryAttributes(QObject* parent = Q_NULLPTR);
|
||||
explicit EntryAttributes(QObject* parent = nullptr);
|
||||
QList<QString> keys() const;
|
||||
bool hasKey(const QString& key) const;
|
||||
QList<QString> customKeys();
|
||||
QString value(const QString& key) const;
|
||||
bool contains(const QString& key) const;
|
||||
bool isProtected(const QString& key) const;
|
||||
void set(const QString& key, const QString& value, bool protect = false);
|
||||
void remove(const QString& key);
|
||||
|
||||
71
src/core/EntrySearcher.cpp
Normal file
71
src/core/EntrySearcher.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Florian Geyer <blueice@fobos.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 or (at your option)
|
||||
* version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "EntrySearcher.h"
|
||||
|
||||
#include "core/Group.h"
|
||||
|
||||
QList<Entry*> EntrySearcher::search(const QString& searchTerm, const Group* group,
|
||||
Qt::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
if (!group->resolveSearchingEnabled()) {
|
||||
return QList<Entry*>();
|
||||
}
|
||||
|
||||
return searchEntries(searchTerm, group, caseSensitivity);
|
||||
}
|
||||
|
||||
QList<Entry*> EntrySearcher::searchEntries(const QString& searchTerm, const Group* group,
|
||||
Qt::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
QList<Entry*> searchResult;
|
||||
|
||||
const QList<Entry*> entryList = group->entries();
|
||||
for (Entry* entry : entryList) {
|
||||
searchResult.append(matchEntry(searchTerm, entry, caseSensitivity));
|
||||
}
|
||||
|
||||
const QList<Group*> children = group->children();
|
||||
for (Group* childGroup : children) {
|
||||
if (childGroup->searchingEnabled() != Group::Disable) {
|
||||
searchResult.append(searchEntries(searchTerm, childGroup, caseSensitivity));
|
||||
}
|
||||
}
|
||||
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
QList<Entry*> EntrySearcher::matchEntry(const QString& searchTerm, Entry* entry,
|
||||
Qt::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
const QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts);
|
||||
for (const QString& word : wordList) {
|
||||
if (!wordMatch(word, entry, caseSensitivity)) {
|
||||
return QList<Entry*>();
|
||||
}
|
||||
}
|
||||
|
||||
return QList<Entry*>() << entry;
|
||||
}
|
||||
|
||||
bool EntrySearcher::wordMatch(const QString& word, Entry* entry, Qt::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
return entry->title().contains(word, caseSensitivity) ||
|
||||
entry->username().contains(word, caseSensitivity) ||
|
||||
entry->url().contains(word, caseSensitivity) ||
|
||||
entry->notes().contains(word, caseSensitivity);
|
||||
}
|
||||
38
src/core/EntrySearcher.h
Normal file
38
src/core/EntrySearcher.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Florian Geyer <debfx@fobos.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 or (at your option)
|
||||
* version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSX_ENTRYSEARCHER_H
|
||||
#define KEEPASSX_ENTRYSEARCHER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
|
||||
class Group;
|
||||
class Entry;
|
||||
|
||||
class EntrySearcher
|
||||
{
|
||||
public:
|
||||
QList<Entry*> search(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity);
|
||||
|
||||
private:
|
||||
QList<Entry*> searchEntries(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity);
|
||||
QList<Entry*> matchEntry(const QString& searchTerm, Entry* entry, Qt::CaseSensitivity caseSensitivity);
|
||||
bool wordMatch(const QString& word, Entry* entry, Qt::CaseSensitivity caseSensitivity);
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_ENTRYSEARCHER_H
|
||||
14
src/core/Exporter.h
Normal file
14
src/core/Exporter.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef KEEPASSX_EXPORTER_H
|
||||
#define KEEPASSX_EXPORTER_H
|
||||
|
||||
class Database;
|
||||
class Group;
|
||||
|
||||
class Exporter
|
||||
{
|
||||
public:
|
||||
virtual Database* exportGroup(Group* group) = 0;
|
||||
virtual ~Exporter() {}
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_EXPORTER_H
|
||||
@@ -22,8 +22,9 @@
|
||||
#include <QLibrary>
|
||||
|
||||
#include "config-keepassx.h"
|
||||
#include "core/Global.h"
|
||||
|
||||
FilePath* FilePath::m_instance(Q_NULLPTR);
|
||||
FilePath* FilePath::m_instance(nullptr);
|
||||
|
||||
QString FilePath::dataPath(const QString& name)
|
||||
{
|
||||
@@ -40,7 +41,8 @@ QString FilePath::pluginPath(const QString& name)
|
||||
QStringList pluginPaths;
|
||||
|
||||
QDir buildDir(QCoreApplication::applicationDirPath() + "/autotype");
|
||||
Q_FOREACH (const QString& dir, buildDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||
const QStringList buildDirEntryList = buildDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (const QString& dir : buildDirEntryList) {
|
||||
pluginPaths << QCoreApplication::applicationDirPath() + "/autotype/" + dir;
|
||||
}
|
||||
|
||||
@@ -49,22 +51,29 @@ QString FilePath::pluginPath(const QString& name)
|
||||
|
||||
pluginPaths << QCoreApplication::applicationDirPath();
|
||||
|
||||
QString systemPluginDir = KEEPASSX_PLUGIN_DIR;
|
||||
if (systemPluginDir != ".") {
|
||||
if (!QDir(systemPluginDir).isAbsolute()) {
|
||||
systemPluginDir = QCoreApplication::applicationDirPath() + "/../" + systemPluginDir;
|
||||
systemPluginDir = QDir(systemPluginDir).canonicalPath();
|
||||
QString configuredPluginDir = KEEPASSX_PLUGIN_DIR;
|
||||
if (configuredPluginDir != ".") {
|
||||
if (QDir(configuredPluginDir).isAbsolute()) {
|
||||
pluginPaths << configuredPluginDir;
|
||||
}
|
||||
else {
|
||||
QString relativePluginDir = QString("%1/../%2")
|
||||
.arg(QCoreApplication::applicationDirPath(), configuredPluginDir);
|
||||
pluginPaths << QDir(relativePluginDir).canonicalPath();
|
||||
|
||||
QString absolutePluginDir = QString("%1/%2")
|
||||
.arg(KEEPASSX_PREFIX_DIR, configuredPluginDir);
|
||||
pluginPaths << QDir(absolutePluginDir).canonicalPath();
|
||||
}
|
||||
pluginPaths << systemPluginDir;
|
||||
}
|
||||
|
||||
QStringList dirFilter;
|
||||
dirFilter << QString("*%1*").arg(name);
|
||||
|
||||
Q_FOREACH (const QString& path, pluginPaths) {
|
||||
QStringList fileCandidates = QDir(path).entryList(dirFilter, QDir::Files);
|
||||
for (const QString& path : asConst(pluginPaths)) {
|
||||
const QStringList fileCandidates = QDir(path).entryList(dirFilter, QDir::Files);
|
||||
|
||||
Q_FOREACH (const QString& file, fileCandidates) {
|
||||
for (const QString& file : fileCandidates) {
|
||||
QString filePath = path + "/" + file;
|
||||
|
||||
if (QLibrary::isLibrary(filePath)) {
|
||||
@@ -96,17 +105,16 @@ QIcon FilePath::icon(const QString& category, const QString& name, bool fromThem
|
||||
}
|
||||
|
||||
if (icon.isNull()) {
|
||||
QList<int> pngSizes;
|
||||
pngSizes << 16 << 22 << 24 << 32 << 48 << 64 << 128;
|
||||
const QList<int> pngSizes = { 16, 22, 24, 32, 48, 64, 128 };
|
||||
QString filename;
|
||||
Q_FOREACH (int size, pngSizes) {
|
||||
for (int size : pngSizes) {
|
||||
filename = QString("%1/icons/application/%2x%2/%3.png").arg(m_dataPath, QString::number(size),
|
||||
combinedName);
|
||||
if (QFile::exists(filename)) {
|
||||
icon.addFile(filename, QSize(size, size));
|
||||
}
|
||||
}
|
||||
filename = QString("%1/icons/application/scalable/%3.svgz").arg(m_dataPath, combinedName);
|
||||
filename = QString("%1/icons/application/scalable/%2.svgz").arg(m_dataPath, combinedName);
|
||||
if (QFile::exists(filename)) {
|
||||
icon.addFile(filename);
|
||||
}
|
||||
@@ -141,17 +149,16 @@ QIcon FilePath::onOffIcon(const QString& category, const QString& name)
|
||||
stateName = "on";
|
||||
}
|
||||
|
||||
QList<int> pngSizes;
|
||||
pngSizes << 16 << 22 << 24 << 32 << 48 << 64 << 128;
|
||||
const QList<int> pngSizes = { 16, 22, 24, 32, 48, 64, 128 };
|
||||
QString filename;
|
||||
Q_FOREACH (int size, pngSizes) {
|
||||
for (int size : pngSizes) {
|
||||
filename = QString("%1/icons/application/%2x%2/%3-%4.png").arg(m_dataPath, QString::number(size),
|
||||
combinedName, stateName);
|
||||
if (QFile::exists(filename)) {
|
||||
icon.addFile(filename, QSize(size, size), QIcon::Normal, state);
|
||||
}
|
||||
}
|
||||
filename = QString("%1/icons/application/scalable/%3-%4.svgz").arg(m_dataPath, combinedName, stateName);
|
||||
filename = QString("%1/icons/application/scalable/%2-%3.svgz").arg(m_dataPath, combinedName, stateName);
|
||||
if (QFile::exists(filename)) {
|
||||
icon.addFile(filename, QSize(), QIcon::Normal, state);
|
||||
}
|
||||
@@ -164,6 +171,10 @@ QIcon FilePath::onOffIcon(const QString& category, const QString& name)
|
||||
|
||||
FilePath::FilePath()
|
||||
{
|
||||
const QString appDirPath = QCoreApplication::applicationDirPath();
|
||||
bool isDataDirAbsolute = QDir::isAbsolutePath(KEEPASSX_DATA_DIR);
|
||||
Q_UNUSED(isDataDirAbsolute);
|
||||
|
||||
if (false) {
|
||||
}
|
||||
#ifdef QT_DEBUG
|
||||
@@ -171,15 +182,19 @@ FilePath::FilePath()
|
||||
}
|
||||
#endif
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
||||
else if (testSetDir(QCoreApplication::applicationDirPath() + "/../share/keepassx")) {
|
||||
else if (isDataDirAbsolute && testSetDir(KEEPASSX_DATA_DIR)) {
|
||||
}
|
||||
else if (!isDataDirAbsolute && testSetDir(QString("%1/../%2").arg(appDirPath, KEEPASSX_DATA_DIR))) {
|
||||
}
|
||||
else if (!isDataDirAbsolute && testSetDir(QString("%1/%2").arg(KEEPASSX_PREFIX_DIR, KEEPASSX_DATA_DIR))) {
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
else if (testSetDir(QCoreApplication::applicationDirPath() + "/../Resources")) {
|
||||
else if (testSetDir(appDirPath + "/../Resources")) {
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_WIN
|
||||
else if (testSetDir(QCoreApplication::applicationDirPath() + "/share")) {
|
||||
else if (testSetDir(appDirPath + "/share")) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include <QIcon>
|
||||
#include <QString>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class FilePath
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -20,104 +20,8 @@
|
||||
#ifndef KEEPASSX_GLOBAL_H
|
||||
#define KEEPASSX_GLOBAL_H
|
||||
|
||||
// mostly copied from qcompilerdetection.h which is part of Qt 5
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_CC_CLANG
|
||||
# if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# if __has_feature(cxx_strong_enums)
|
||||
# define COMPILER_CLASS_ENUM
|
||||
# endif
|
||||
# if __has_feature(cxx_constexpr)
|
||||
# define COMPILER_CONSTEXPR
|
||||
# endif
|
||||
# if __has_feature(cxx_decltype) /* && __has_feature(cxx_decltype_incomplete_return_types) */
|
||||
# define COMPILER_DECLTYPE
|
||||
# endif
|
||||
# if __has_feature(cxx_override_control)
|
||||
# define COMPILER_EXPLICIT_OVERRIDES
|
||||
# endif
|
||||
# if __has_feature(cxx_nullptr)
|
||||
# define COMPILER_NULLPTR
|
||||
# endif
|
||||
# if __has_feature(cxx_static_assert)
|
||||
# define COMPILER_STATIC_ASSERT
|
||||
# endif
|
||||
# endif
|
||||
#endif // Q_CC_CLANG
|
||||
|
||||
#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)
|
||||
# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
|
||||
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 403
|
||||
# define COMPILER_DECLTYPE
|
||||
# define COMPILER_STATIC_ASSERT
|
||||
# endif
|
||||
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 404
|
||||
# define COMPILER_CLASS_ENUM
|
||||
# endif
|
||||
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
|
||||
# define COMPILER_CONSTEXPR
|
||||
# define COMPILER_NULLPTR
|
||||
# endif
|
||||
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407
|
||||
# define COMPILER_EXPLICIT_OVERRIDES
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* C++11 keywords and expressions
|
||||
*/
|
||||
#if !defined(Q_NULLPTR)
|
||||
# ifdef COMPILER_NULLPTR
|
||||
# define Q_NULLPTR nullptr
|
||||
# else
|
||||
# define Q_NULLPTR 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(Q_DECL_CONSTEXPR)
|
||||
# ifdef COMPILER_CONSTEXPR
|
||||
# define Q_DECL_CONSTEXPR constexpr
|
||||
# else
|
||||
# define Q_DECL_CONSTEXPR
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(Q_DECL_OVERRIDE) && !defined(Q_DECL_FINAL) && !defined(Q_DECL_FINAL_CLASS)
|
||||
# ifdef COMPILER_EXPLICIT_OVERRIDES
|
||||
# define Q_DECL_OVERRIDE override
|
||||
# define Q_DECL_FINAL final
|
||||
# ifdef COMPILER_DECLTYPE
|
||||
# define Q_DECL_FINAL_CLASS final
|
||||
# else
|
||||
# define Q_DECL_FINAL_CLASS
|
||||
# endif
|
||||
# else
|
||||
# define Q_DECL_OVERRIDE
|
||||
# define Q_DECL_FINAL
|
||||
# define Q_DECL_FINAL_CLASS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(Q_STATIC_ASSERT) && !defined(Q_STATIC_ASSERT_X)
|
||||
#ifdef COMPILER_STATIC_ASSERT
|
||||
#define Q_STATIC_ASSERT(Condition) static_assert(static_cast<bool>(Condition), #Condition)
|
||||
#define Q_STATIC_ASSERT_X(Condition, Message) static_assert(static_cast<bool>(Condition), Message)
|
||||
#else
|
||||
// Intentionally undefined
|
||||
template <bool Test> class QStaticAssertFailure;
|
||||
template <> class QStaticAssertFailure<true> {};
|
||||
|
||||
#define Q_STATIC_ASSERT_PRIVATE_JOIN(A, B) Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B)
|
||||
#define Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B) A ## B
|
||||
#define Q_STATIC_ASSERT(Condition) \
|
||||
enum {Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __LINE__) = sizeof(QStaticAssertFailure<!!(Condition)>)}
|
||||
#define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition)
|
||||
#endif // COMPILER_STATIC_ASSERT
|
||||
#endif // !defined(Q_STATIC_ASSERT) && !defined(Q_STATIC_ASSERT_X)
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
# if defined(KEEPASSX_BUILDING_CORE)
|
||||
# define KEEPASSX_EXPORT Q_DECL_EXPORT
|
||||
@@ -132,4 +36,13 @@ template <> class QStaticAssertFailure<true> {};
|
||||
#define QUINT32_MAX 4294967295U
|
||||
#endif
|
||||
|
||||
template <typename T> struct AddConst { typedef const T Type; };
|
||||
|
||||
// this adds const to non-const objects (like std::as_const)
|
||||
template <typename T>
|
||||
constexpr typename AddConst<T>::Type& asConst(T &t) noexcept { return t; }
|
||||
// prevent rvalue arguments:
|
||||
template <typename T>
|
||||
void asConst(const T&&) = delete;
|
||||
|
||||
#endif // KEEPASSX_GLOBAL_H
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
#include "Group.h"
|
||||
|
||||
#include "core/Config.h"
|
||||
#include "core/Global.h"
|
||||
#include "core/DatabaseIcons.h"
|
||||
#include "core/Metadata.h"
|
||||
#include "core/Tools.h"
|
||||
|
||||
const int Group::DefaultIconNumber = 48;
|
||||
const int Group::RecycleBinIconNumber = 43;
|
||||
@@ -38,19 +38,19 @@ Group::~Group()
|
||||
{
|
||||
// Destroy entries and children manually so DeletedObjects can be added
|
||||
// to database.
|
||||
QList<Entry*> entries = m_entries;
|
||||
Q_FOREACH (Entry* entry, entries) {
|
||||
const QList<Entry*> entries = m_entries;
|
||||
for (Entry* entry : entries) {
|
||||
delete entry;
|
||||
}
|
||||
|
||||
QList<Group*> children = m_children;
|
||||
Q_FOREACH (Group* group, children) {
|
||||
const QList<Group*> children = m_children;
|
||||
for (Group* group : children) {
|
||||
delete group;
|
||||
}
|
||||
|
||||
if (m_db && m_parent) {
|
||||
DeletedObject delGroup;
|
||||
delGroup.deletionTime = Tools::currentDateTimeUtc();
|
||||
delGroup.deletionTime = QDateTime::currentDateTimeUtc();
|
||||
delGroup.uuid = m_uuid;
|
||||
m_db->addDeletedObject(delGroup);
|
||||
}
|
||||
@@ -84,8 +84,8 @@ template <class P, class V> inline bool Group::set(P& property, const V& value)
|
||||
void Group::updateTimeinfo()
|
||||
{
|
||||
if (m_updateTimeinfo) {
|
||||
m_data.timeInfo.setLastModificationTime(Tools::currentDateTimeUtc());
|
||||
m_data.timeInfo.setLastAccessTime(Tools::currentDateTimeUtc());
|
||||
m_data.timeInfo.setLastModificationTime(QDateTime::currentDateTimeUtc());
|
||||
m_data.timeInfo.setLastAccessTime(QDateTime::currentDateTimeUtc());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,13 +134,30 @@ QPixmap Group::iconPixmap() const
|
||||
else {
|
||||
Q_ASSERT(m_db);
|
||||
|
||||
QPixmap pixmap;
|
||||
if (m_db && !QPixmapCache::find(m_pixmapCacheKey, &pixmap)) {
|
||||
pixmap = QPixmap::fromImage(m_db->metadata()->customIcon(m_data.customIcon));
|
||||
m_pixmapCacheKey = QPixmapCache::insert(pixmap);
|
||||
if (m_db) {
|
||||
return m_db->metadata()->customIconPixmap(m_data.customIcon);
|
||||
}
|
||||
else {
|
||||
return QPixmap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pixmap;
|
||||
QPixmap Group::iconScaledPixmap() const
|
||||
{
|
||||
if (m_data.customIcon.isNull()) {
|
||||
// built-in icons are 16x16 so don't need to be scaled
|
||||
return databaseIcons()->iconPixmap(m_data.iconNumber);
|
||||
}
|
||||
else {
|
||||
Q_ASSERT(m_db);
|
||||
|
||||
if (m_db) {
|
||||
return m_db->metadata()->customIconScaledPixmap(m_data.customIcon);
|
||||
}
|
||||
else {
|
||||
return QPixmap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +203,7 @@ Entry* Group::lastTopVisibleEntry() const
|
||||
|
||||
bool Group::isExpired() const
|
||||
{
|
||||
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < Tools::currentDateTimeUtc();
|
||||
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
|
||||
void Group::setUuid(const Uuid& uuid)
|
||||
@@ -214,8 +231,6 @@ void Group::setIcon(int iconNumber)
|
||||
m_data.iconNumber = iconNumber;
|
||||
m_data.customIcon = Uuid();
|
||||
|
||||
m_pixmapCacheKey = QPixmapCache::Key();
|
||||
|
||||
updateTimeinfo();
|
||||
Q_EMIT modified();
|
||||
Q_EMIT dataChanged(this);
|
||||
@@ -230,8 +245,6 @@ void Group::setIcon(const Uuid& uuid)
|
||||
m_data.customIcon = uuid;
|
||||
m_data.iconNumber = 0;
|
||||
|
||||
m_pixmapCacheKey = QPixmapCache::Key();
|
||||
|
||||
updateTimeinfo();
|
||||
Q_EMIT modified();
|
||||
Q_EMIT dataChanged(this);
|
||||
@@ -248,9 +261,7 @@ void Group::setExpanded(bool expanded)
|
||||
if (m_data.isExpanded != expanded) {
|
||||
m_data.isExpanded = expanded;
|
||||
updateTimeinfo();
|
||||
if (config()->get("ModifiedOnExpandedStateChanges").toBool()) {
|
||||
Q_EMIT modified();
|
||||
}
|
||||
Q_EMIT modified();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,7 +365,7 @@ void Group::setParent(Group* parent, int index)
|
||||
}
|
||||
|
||||
if (m_updateTimeinfo) {
|
||||
m_data.timeInfo.setLocationChanged(Tools::currentDateTimeUtc());
|
||||
m_data.timeInfo.setLocationChanged(QDateTime::currentDateTimeUtc());
|
||||
}
|
||||
|
||||
Q_EMIT modified();
|
||||
@@ -374,7 +385,7 @@ void Group::setParent(Database* db)
|
||||
|
||||
cleanupParent();
|
||||
|
||||
m_parent = Q_NULLPTR;
|
||||
m_parent = nullptr;
|
||||
recSetDatabase(db);
|
||||
|
||||
QObject::setParent(db);
|
||||
@@ -417,12 +428,12 @@ QList<Entry*> Group::entriesRecursive(bool includeHistoryItems) const
|
||||
entryList.append(m_entries);
|
||||
|
||||
if (includeHistoryItems) {
|
||||
Q_FOREACH (Entry* entry, m_entries) {
|
||||
for (Entry* entry : m_entries) {
|
||||
entryList.append(entry->historyItems());
|
||||
}
|
||||
}
|
||||
|
||||
Q_FOREACH (Group* group, m_children) {
|
||||
for (Group* group : m_children) {
|
||||
entryList.append(group->entriesRecursive(includeHistoryItems));
|
||||
}
|
||||
|
||||
@@ -436,7 +447,21 @@ QList<const Group*> Group::groupsRecursive(bool includeSelf) const
|
||||
groupList.append(this);
|
||||
}
|
||||
|
||||
Q_FOREACH (Group* group, m_children) {
|
||||
for (const Group* group : m_children) {
|
||||
groupList.append(group->groupsRecursive(true));
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
QList<Group*> Group::groupsRecursive(bool includeSelf)
|
||||
{
|
||||
QList<Group*> groupList;
|
||||
if (includeSelf) {
|
||||
groupList.append(this);
|
||||
}
|
||||
|
||||
for (Group* group : asConst(m_children)) {
|
||||
groupList.append(group->groupsRecursive(true));
|
||||
}
|
||||
|
||||
@@ -451,13 +476,14 @@ QSet<Uuid> Group::customIconsRecursive() const
|
||||
result.insert(iconUuid());
|
||||
}
|
||||
|
||||
Q_FOREACH (Entry* entry, entriesRecursive(true)) {
|
||||
const QList<Entry*> entryList = entriesRecursive(true);
|
||||
for (Entry* entry : entryList) {
|
||||
if (!entry->iconUuid().isNull()) {
|
||||
result.insert(entry->iconUuid());
|
||||
}
|
||||
}
|
||||
|
||||
Q_FOREACH (Group* group, m_children) {
|
||||
for (Group* group : m_children) {
|
||||
result.unite(group->customIconsRecursive());
|
||||
}
|
||||
|
||||
@@ -473,19 +499,21 @@ Group* Group::clone(Entry::CloneFlags entryFlags) const
|
||||
clonedGroup->setUuid(Uuid::random());
|
||||
clonedGroup->m_data = m_data;
|
||||
|
||||
Q_FOREACH (Entry* entry, entries()) {
|
||||
const QList<Entry*> entryList = entries();
|
||||
for (Entry* entry : entryList) {
|
||||
Entry* clonedEntry = entry->clone(entryFlags);
|
||||
clonedEntry->setGroup(clonedGroup);
|
||||
}
|
||||
|
||||
Q_FOREACH (Group* groupChild, children()) {
|
||||
Group* clonedGroupChild = groupChild->clone();
|
||||
const QList<Group*> childrenGroups = children();
|
||||
for (Group* groupChild : childrenGroups) {
|
||||
Group* clonedGroupChild = groupChild->clone(entryFlags);
|
||||
clonedGroupChild->setParent(clonedGroup);
|
||||
}
|
||||
|
||||
clonedGroup->setUpdateTimeinfo(true);
|
||||
|
||||
QDateTime now = Tools::currentDateTimeUtc();
|
||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||
clonedGroup->m_data.timeInfo.setCreationTime(now);
|
||||
clonedGroup->m_data.timeInfo.setLastModificationTime(now);
|
||||
clonedGroup->m_data.timeInfo.setLastAccessTime(now);
|
||||
@@ -500,22 +528,6 @@ void Group::copyDataFrom(const Group* other)
|
||||
m_lastTopVisibleEntry = other->m_lastTopVisibleEntry;
|
||||
}
|
||||
|
||||
Database* Group::exportToDb()
|
||||
{
|
||||
Q_ASSERT(database());
|
||||
|
||||
Database* db = new Database();
|
||||
Group* clonedGroup = clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory);
|
||||
clonedGroup->setParent(db->rootGroup());
|
||||
|
||||
QSet<Uuid> customIcons = customIconsRecursive();
|
||||
db->metadata()->copyCustomIcons(customIcons, database()->metadata());
|
||||
|
||||
db->copyAttributesFrom(database());
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
void Group::addEntry(Entry* entry)
|
||||
{
|
||||
Q_ASSERT(entry);
|
||||
@@ -561,7 +573,7 @@ void Group::recSetDatabase(Database* db)
|
||||
disconnect(SIGNAL(modified()), m_db);
|
||||
}
|
||||
|
||||
Q_FOREACH (Entry* entry, m_entries) {
|
||||
for (Entry* entry : asConst(m_entries)) {
|
||||
if (m_db) {
|
||||
entry->disconnect(m_db);
|
||||
}
|
||||
@@ -583,7 +595,7 @@ void Group::recSetDatabase(Database* db)
|
||||
|
||||
m_db = db;
|
||||
|
||||
Q_FOREACH (Group* group, m_children) {
|
||||
for (Group* group : asConst(m_children)) {
|
||||
group->recSetDatabase(db);
|
||||
}
|
||||
}
|
||||
@@ -601,35 +613,18 @@ void Group::cleanupParent()
|
||||
void Group::recCreateDelObjects()
|
||||
{
|
||||
if (m_db) {
|
||||
Q_FOREACH (Entry* entry, m_entries) {
|
||||
for (Entry* entry : asConst(m_entries)) {
|
||||
m_db->addDeletedObject(entry->uuid());
|
||||
}
|
||||
|
||||
Q_FOREACH (Group* group, m_children) {
|
||||
for (Group* group : asConst(m_children)) {
|
||||
group->recCreateDelObjects();
|
||||
}
|
||||
m_db->addDeletedObject(m_uuid);
|
||||
}
|
||||
}
|
||||
|
||||
QList<Entry*> Group::search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity,
|
||||
bool resolveInherit)
|
||||
{
|
||||
QList<Entry*> searchResult;
|
||||
if (includeInSearch(resolveInherit)) {
|
||||
Q_FOREACH (Entry* entry, m_entries) {
|
||||
if (entry->match(searchTerm, caseSensitivity)) {
|
||||
searchResult.append(entry);
|
||||
}
|
||||
}
|
||||
Q_FOREACH (Group* group, m_children) {
|
||||
searchResult.append(group->search(searchTerm, caseSensitivity, false));
|
||||
}
|
||||
}
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
bool Group::includeInSearch(bool resolveInherit)
|
||||
bool Group::resolveSearchingEnabled() const
|
||||
{
|
||||
switch (m_data.searchingEnabled) {
|
||||
case Inherit:
|
||||
@@ -637,12 +632,27 @@ bool Group::includeInSearch(bool resolveInherit)
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (resolveInherit) {
|
||||
return m_parent->includeInSearch(true);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
return m_parent->resolveSearchingEnabled();
|
||||
}
|
||||
case Enable:
|
||||
return true;
|
||||
case Disable:
|
||||
return false;
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Group::resolveAutoTypeEnabled() const
|
||||
{
|
||||
switch (m_data.autoTypeEnabled) {
|
||||
case Inherit:
|
||||
if (!m_parent) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return m_parent->resolveAutoTypeEnabled();
|
||||
}
|
||||
case Enable:
|
||||
return true;
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
QString notes() const;
|
||||
QImage icon() const;
|
||||
QPixmap iconPixmap() const;
|
||||
QPixmap iconScaledPixmap() const;
|
||||
int iconNumber() const;
|
||||
Uuid iconUuid() const;
|
||||
TimeInfo timeInfo() const;
|
||||
@@ -65,6 +66,8 @@ public:
|
||||
QString defaultAutoTypeSequence() const;
|
||||
Group::TriState autoTypeEnabled() const;
|
||||
Group::TriState searchingEnabled() const;
|
||||
bool resolveSearchingEnabled() const;
|
||||
bool resolveAutoTypeEnabled() const;
|
||||
Entry* lastTopVisibleEntry() const;
|
||||
bool isExpired() const;
|
||||
|
||||
@@ -99,6 +102,7 @@ public:
|
||||
const QList<Entry*>& entries() const;
|
||||
QList<Entry*> entriesRecursive(bool includeHistoryItems = false) const;
|
||||
QList<const Group*> groupsRecursive(bool includeSelf) const;
|
||||
QList<Group*> groupsRecursive(bool includeSelf);
|
||||
QSet<Uuid> customIconsRecursive() const;
|
||||
/**
|
||||
* Creates a duplicate of this group including all child entries and groups.
|
||||
@@ -109,10 +113,6 @@ public:
|
||||
*/
|
||||
Group* clone(Entry::CloneFlags entryFlags = Entry::CloneNewUuid | Entry::CloneResetTimeInfo) const;
|
||||
void copyDataFrom(const Group* other);
|
||||
Database* exportToDb();
|
||||
|
||||
QList<Entry*> search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity,
|
||||
bool resolveInherit = true);
|
||||
|
||||
Q_SIGNALS:
|
||||
void dataChanged(Group* group);
|
||||
@@ -147,7 +147,6 @@ private:
|
||||
void cleanupParent();
|
||||
void recCreateDelObjects();
|
||||
void updateTimeinfo();
|
||||
bool includeInSearch(bool resolveInherit);
|
||||
|
||||
QPointer<Database> m_db;
|
||||
Uuid m_uuid;
|
||||
@@ -157,7 +156,6 @@ private:
|
||||
QList<Entry*> m_entries;
|
||||
|
||||
QPointer<Group> m_parent;
|
||||
mutable QPixmapCache::Key m_pixmapCacheKey;
|
||||
|
||||
bool m_updateTimeinfo;
|
||||
|
||||
|
||||
@@ -67,7 +67,14 @@ bool InactivityTimer::eventFilter(QObject* watched, QEvent* event)
|
||||
|
||||
void InactivityTimer::timeout()
|
||||
{
|
||||
// make sure we don't emit the signal a second time while it's still processed
|
||||
if (!m_emitMutx.tryLock()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_active && !m_timer->isActive()) {
|
||||
Q_EMIT inactivityDetected();
|
||||
}
|
||||
|
||||
m_emitMutx.unlock();
|
||||
}
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
#ifndef KEEPASSX_INACTIVITYTIMER_H
|
||||
#define KEEPASSX_INACTIVITYTIMER_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class QTimer;
|
||||
|
||||
class InactivityTimer : public QObject
|
||||
@@ -29,7 +28,7 @@ class InactivityTimer : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InactivityTimer(QObject* parent = Q_NULLPTR);
|
||||
explicit InactivityTimer(QObject* parent = nullptr);
|
||||
void setInactivityTimeout(int inactivityTimeout);
|
||||
void activate();
|
||||
void deactivate();
|
||||
@@ -46,6 +45,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
QTimer* m_timer;
|
||||
bool m_active;
|
||||
QMutex m_emitMutx;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_INACTIVITYTIMER_H
|
||||
|
||||
@@ -42,7 +42,7 @@ Metadata::Metadata(QObject* parent)
|
||||
m_data.protectNotes = false;
|
||||
// m_data.autoEnableVisualHiding = false;
|
||||
|
||||
QDateTime now = Tools::currentDateTimeUtc();
|
||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||
m_data.nameChanged = now;
|
||||
m_data.descriptionChanged = now;
|
||||
m_data.defaultUserNameChanged = now;
|
||||
@@ -67,7 +67,7 @@ template <class P, class V> bool Metadata::set(P& property, const V& value, QDat
|
||||
if (property != value) {
|
||||
property = value;
|
||||
if (m_updateDatetime) {
|
||||
dateTime = Tools::currentDateTimeUtc();
|
||||
dateTime = QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
Q_EMIT modified();
|
||||
return true;
|
||||
@@ -167,6 +167,43 @@ QImage Metadata::customIcon(const Uuid& uuid) const
|
||||
return m_customIcons.value(uuid);
|
||||
}
|
||||
|
||||
QPixmap Metadata::customIconPixmap(const Uuid& uuid) const
|
||||
{
|
||||
QPixmap pixmap;
|
||||
|
||||
if (!m_customIcons.contains(uuid)) {
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
QPixmapCache::Key& cacheKey = m_customIconCacheKeys[uuid];
|
||||
|
||||
if (!QPixmapCache::find(cacheKey, &pixmap)) {
|
||||
pixmap = QPixmap::fromImage(m_customIcons.value(uuid));
|
||||
cacheKey = QPixmapCache::insert(pixmap);
|
||||
}
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
QPixmap Metadata::customIconScaledPixmap(const Uuid& uuid) const
|
||||
{
|
||||
QPixmap pixmap;
|
||||
|
||||
if (!m_customIcons.contains(uuid)) {
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
QPixmapCache::Key& cacheKey = m_customIconScaledCacheKeys[uuid];
|
||||
|
||||
if (!QPixmapCache::find(cacheKey, &pixmap)) {
|
||||
QImage image = m_customIcons.value(uuid).scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
pixmap = QPixmap::fromImage(image);
|
||||
cacheKey = QPixmapCache::insert(pixmap);
|
||||
}
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
bool Metadata::containsCustomIcon(const Uuid& uuid) const
|
||||
{
|
||||
return m_customIcons.contains(uuid);
|
||||
@@ -177,6 +214,17 @@ QHash<Uuid, QImage> Metadata::customIcons() const
|
||||
return m_customIcons;
|
||||
}
|
||||
|
||||
QHash<Uuid, QPixmap> Metadata::customIconsScaledPixmaps() const
|
||||
{
|
||||
QHash<Uuid, QPixmap> result;
|
||||
|
||||
for (const Uuid& uuid : m_customIconsOrder) {
|
||||
result.insert(uuid, customIconScaledPixmap(uuid));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<Uuid> Metadata::customIconsOrder() const
|
||||
{
|
||||
return m_customIconsOrder;
|
||||
@@ -338,17 +386,40 @@ void Metadata::addCustomIcon(const Uuid& uuid, const QImage& icon)
|
||||
Q_ASSERT(!m_customIcons.contains(uuid));
|
||||
|
||||
m_customIcons.insert(uuid, icon);
|
||||
// reset cache in case there is also an icon with that uuid
|
||||
m_customIconCacheKeys[uuid] = QPixmapCache::Key();
|
||||
m_customIconScaledCacheKeys[uuid] = QPixmapCache::Key();
|
||||
m_customIconsOrder.append(uuid);
|
||||
Q_ASSERT(m_customIcons.count() == m_customIconsOrder.count());
|
||||
Q_EMIT modified();
|
||||
}
|
||||
|
||||
void Metadata::addCustomIconScaled(const Uuid& uuid, const QImage& icon)
|
||||
{
|
||||
QImage iconScaled;
|
||||
|
||||
// scale down to 128x128 if icon is larger
|
||||
if (icon.width() > 128 || icon.height() > 128) {
|
||||
iconScaled = icon.scaled(QSize(128, 128), Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
}
|
||||
else {
|
||||
iconScaled = icon;
|
||||
}
|
||||
|
||||
addCustomIcon(uuid, iconScaled);
|
||||
}
|
||||
|
||||
void Metadata::removeCustomIcon(const Uuid& uuid)
|
||||
{
|
||||
Q_ASSERT(!uuid.isNull());
|
||||
Q_ASSERT(m_customIcons.contains(uuid));
|
||||
|
||||
m_customIcons.remove(uuid);
|
||||
QPixmapCache::remove(m_customIconCacheKeys.value(uuid));
|
||||
m_customIconCacheKeys.remove(uuid);
|
||||
QPixmapCache::remove(m_customIconScaledCacheKeys.value(uuid));
|
||||
m_customIconScaledCacheKeys.remove(uuid);
|
||||
m_customIconsOrder.removeAll(uuid);
|
||||
Q_ASSERT(m_customIcons.count() == m_customIconsOrder.count());
|
||||
Q_EMIT modified();
|
||||
@@ -356,7 +427,7 @@ void Metadata::removeCustomIcon(const Uuid& uuid)
|
||||
|
||||
void Metadata::copyCustomIcons(const QSet<Uuid>& iconList, const Metadata* otherMetadata)
|
||||
{
|
||||
Q_FOREACH (const Uuid& uuid, iconList) {
|
||||
for (const Uuid& uuid : iconList) {
|
||||
Q_ASSERT(otherMetadata->containsCustomIcon(uuid));
|
||||
|
||||
if (!containsCustomIcon(uuid) && otherMetadata->containsCustomIcon(uuid)) {
|
||||
|
||||
@@ -22,9 +22,10 @@
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QPixmapCache>
|
||||
#include <QPointer>
|
||||
|
||||
#include "core/Global.h"
|
||||
#include "core/Uuid.h"
|
||||
|
||||
class Database;
|
||||
@@ -35,7 +36,7 @@ class Metadata : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Metadata(QObject* parent = Q_NULLPTR);
|
||||
explicit Metadata(QObject* parent = nullptr);
|
||||
|
||||
struct MetadataData
|
||||
{
|
||||
@@ -78,10 +79,13 @@ public:
|
||||
bool protectNotes() const;
|
||||
// bool autoEnableVisualHiding() const;
|
||||
QImage customIcon(const Uuid& uuid) const;
|
||||
QPixmap customIconPixmap(const Uuid& uuid) const;
|
||||
QPixmap customIconScaledPixmap(const Uuid& uuid) const;
|
||||
bool containsCustomIcon(const Uuid& uuid) const;
|
||||
QHash<Uuid, QImage> customIcons() const;
|
||||
QList<Uuid> customIconsOrder() const;
|
||||
bool recycleBinEnabled() const;
|
||||
QHash<Uuid, QPixmap> customIconsScaledPixmaps() const;
|
||||
Group* recycleBin();
|
||||
const Group* recycleBin() const;
|
||||
QDateTime recycleBinChanged() const;
|
||||
@@ -115,6 +119,7 @@ public:
|
||||
void setProtectNotes(bool value);
|
||||
// void setAutoEnableVisualHiding(bool value);
|
||||
void addCustomIcon(const Uuid& uuid, const QImage& icon);
|
||||
void addCustomIconScaled(const Uuid& uuid, const QImage& icon);
|
||||
void removeCustomIcon(const Uuid& uuid);
|
||||
void copyCustomIcons(const QSet<Uuid>& iconList, const Metadata* otherMetadata);
|
||||
void setRecycleBinEnabled(bool value);
|
||||
@@ -152,6 +157,8 @@ private:
|
||||
MetadataData m_data;
|
||||
|
||||
QHash<Uuid, QImage> m_customIcons;
|
||||
mutable QHash<Uuid, QPixmapCache::Key> m_customIconCacheKeys;
|
||||
mutable QHash<Uuid, QPixmapCache::Key> m_customIconScaledCacheKeys;
|
||||
QList<Uuid> m_customIconsOrder;
|
||||
|
||||
QPointer<Group> m_recycleBin;
|
||||
|
||||
@@ -45,11 +45,11 @@ QString PasswordGenerator::generatePassword() const
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
|
||||
QVector<PasswordGroup> groups = passwordGroups();
|
||||
const QVector<PasswordGroup> groups = passwordGroups();
|
||||
|
||||
QVector<QChar> passwordChars;
|
||||
Q_FOREACH (const PasswordGroup& group, groups) {
|
||||
Q_FOREACH (QChar ch, group) {
|
||||
for (const PasswordGroup& group : groups) {
|
||||
for (QChar ch : group) {
|
||||
passwordChars.append(ch);
|
||||
}
|
||||
}
|
||||
@@ -89,6 +89,22 @@ QString PasswordGenerator::generatePassword() const
|
||||
return password;
|
||||
}
|
||||
|
||||
int PasswordGenerator::getbits() const
|
||||
{
|
||||
QVector<PasswordGroup> groups = passwordGroups();
|
||||
|
||||
int bits = 0;
|
||||
QVector<QChar> passwordChars;
|
||||
Q_FOREACH (const PasswordGroup& group, groups) {
|
||||
bits += group.size();
|
||||
}
|
||||
|
||||
bits *= m_length;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
|
||||
bool PasswordGenerator::isValid() const
|
||||
{
|
||||
if (m_classes == 0) {
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
typedef QVector<QChar> PasswordGroup;
|
||||
|
||||
class PasswordGenerator
|
||||
@@ -55,6 +53,7 @@ public:
|
||||
bool isValid() const;
|
||||
|
||||
QString generatePassword() const;
|
||||
int getbits() const;
|
||||
|
||||
private:
|
||||
QVector<PasswordGroup> passwordGroups() const;
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "SignalMultiplexer.h"
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
SignalMultiplexer::SignalMultiplexer()
|
||||
{
|
||||
}
|
||||
@@ -24,7 +26,7 @@ SignalMultiplexer::SignalMultiplexer()
|
||||
SignalMultiplexer::~SignalMultiplexer()
|
||||
{
|
||||
// disconnect all connections
|
||||
setCurrentObject(Q_NULLPTR);
|
||||
setCurrentObject(nullptr);
|
||||
}
|
||||
|
||||
QObject* SignalMultiplexer::currentObject() const
|
||||
@@ -45,7 +47,7 @@ void SignalMultiplexer::setCurrentObject(QObject* object)
|
||||
}
|
||||
|
||||
if (m_currentObject) {
|
||||
Q_FOREACH (const Connection& con, m_connections) {
|
||||
for (const Connection& con : asConst(m_connections)) {
|
||||
disconnect(con);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +55,7 @@ void SignalMultiplexer::setCurrentObject(QObject* object)
|
||||
m_currentObject = object;
|
||||
|
||||
if (object) {
|
||||
Q_FOREACH (const Connection& con, m_connections) {
|
||||
for (const Connection& con : asConst(m_connections)) {
|
||||
connect(con);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class SignalMultiplexer
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -23,7 +23,7 @@ TimeInfo::TimeInfo()
|
||||
: m_expires(false)
|
||||
, m_usageCount(0)
|
||||
{
|
||||
QDateTime now = Tools::currentDateTimeUtc();
|
||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||
m_lastModificationTime = now;
|
||||
m_creationTime = now;
|
||||
m_lastAccessTime = now;
|
||||
|
||||
39
src/core/ToDbExporter.cpp
Normal file
39
src/core/ToDbExporter.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
|
||||
* Copyright (C) 2014 Florian Geyer <blueice@fobos.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 or (at your option)
|
||||
* version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ToDbExporter.h"
|
||||
#include "core/Database.h"
|
||||
#include "core/Group.h"
|
||||
#include "core/Metadata.h"
|
||||
|
||||
Database* ToDbExporter::exportGroup(Group* group)
|
||||
{
|
||||
Database* oldDb = group->database();
|
||||
Q_ASSERT(oldDb);
|
||||
|
||||
Database* db = new Database();
|
||||
Group* clonedGroup = group->clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory);
|
||||
clonedGroup->setParent(db->rootGroup());
|
||||
|
||||
QSet<Uuid> customIcons = group->customIconsRecursive();
|
||||
db->metadata()->copyCustomIcons(customIcons, oldDb->metadata());
|
||||
|
||||
db->copyAttributesFrom(oldDb);
|
||||
|
||||
return db;
|
||||
}
|
||||
33
src/core/ToDbExporter.h
Normal file
33
src/core/ToDbExporter.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
|
||||
* Copyright (C) 2014 Florian Geyer <blueice@fobos.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 or (at your option)
|
||||
* version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSX_TODBEXPORTER_H
|
||||
#define KEEPASSX_TODBEXPORTER_H
|
||||
|
||||
#include "core/Exporter.h"
|
||||
|
||||
class Database;
|
||||
class Group;
|
||||
|
||||
class ToDbExporter : Exporter
|
||||
{
|
||||
public:
|
||||
Database* exportGroup(Group* group);
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_TODBEXPORTER_H
|
||||
@@ -23,14 +23,10 @@
|
||||
#include <QLocale>
|
||||
#include <QStringList>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
#include <QElapsedTimer>
|
||||
#else
|
||||
#include <QTime>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h> // for Sleep()
|
||||
#include <windows.h> // for Sleep(), SetDllDirectoryA() and SetSearchPathMode()
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
@@ -39,10 +35,12 @@
|
||||
|
||||
#include "config-keepassx.h"
|
||||
|
||||
#if defined(HAVE_RLIMIT_CORE)
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PR_SET_DUMPABLE)
|
||||
#include <sys/prctl.h>
|
||||
#elif defined(HAVE_RLIMIT_CORE)
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PT_DENY_ATTACH
|
||||
@@ -73,7 +71,9 @@ bool hasChild(const QObject* parent, const QObject* child)
|
||||
if (!parent || !child) {
|
||||
return false;
|
||||
}
|
||||
Q_FOREACH (QObject* c, parent->children()) {
|
||||
|
||||
const QObjectList children = parent->children();
|
||||
for (QObject* c : children) {
|
||||
if (child == c || hasChild(c, child)) {
|
||||
return true;
|
||||
}
|
||||
@@ -120,21 +120,12 @@ bool readAllFromDevice(QIODevice* device, QByteArray& data)
|
||||
}
|
||||
}
|
||||
|
||||
QDateTime currentDateTimeUtc()
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
return QDateTime::currentDateTimeUtc();
|
||||
#else
|
||||
return QDateTime::currentDateTime().toUTC();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString imageReaderFilter()
|
||||
{
|
||||
QList<QByteArray> formats = QImageReader::supportedImageFormats();
|
||||
const QList<QByteArray> formats = QImageReader::supportedImageFormats();
|
||||
QStringList formatsStringList;
|
||||
|
||||
Q_FOREACH (const QByteArray& format, formats) {
|
||||
for (const QByteArray& format : formats) {
|
||||
for (int i = 0; i < format.size(); i++) {
|
||||
if (!QChar(format.at(i)).isLetterOrNumber()) {
|
||||
continue;
|
||||
@@ -149,7 +140,7 @@ QString imageReaderFilter()
|
||||
|
||||
bool isHex(const QByteArray& ba)
|
||||
{
|
||||
Q_FOREACH (char c, ba) {
|
||||
for (char c : ba) {
|
||||
if ( !( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) ) {
|
||||
return false;
|
||||
}
|
||||
@@ -158,6 +149,16 @@ bool isHex(const QByteArray& ba)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isBase64(const QByteArray& ba)
|
||||
{
|
||||
QRegExp regexp("^(?:[a-z0-9+/]{4})*(?:[a-z0-9+/]{3}=|[a-z0-9+/]{2}==)?$",
|
||||
Qt::CaseInsensitive, QRegExp::RegExp2);
|
||||
|
||||
QString base64 = QString::fromLatin1(ba.constData(), ba.size());
|
||||
|
||||
return regexp.exactMatch(base64);
|
||||
}
|
||||
|
||||
void sleep(int ms)
|
||||
{
|
||||
Q_ASSERT(ms >= 0);
|
||||
@@ -172,7 +173,7 @@ void sleep(int ms)
|
||||
timespec ts;
|
||||
ts.tv_sec = ms / 1000;
|
||||
ts.tv_nsec = (ms % 1000) * 1000 * 1000;
|
||||
nanosleep(&ts, Q_NULLPTR);
|
||||
nanosleep(&ts, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -184,11 +185,7 @@ void wait(int ms)
|
||||
return;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
QElapsedTimer timer;
|
||||
#else
|
||||
QTime timer;
|
||||
#endif
|
||||
timer.start();
|
||||
|
||||
if (ms <= 50) {
|
||||
@@ -203,40 +200,29 @@ void wait(int ms)
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, timeLeft);
|
||||
sleep(10);
|
||||
}
|
||||
} while (timer.elapsed() < ms);
|
||||
} while (!timer.hasExpired(ms));
|
||||
}
|
||||
}
|
||||
|
||||
QString platform()
|
||||
{
|
||||
#if defined(Q_WS_X11)
|
||||
return "x11";
|
||||
#elif defined(Q_WS_MAC)
|
||||
return "mac";
|
||||
#elif defined(Q_WS_WIN)
|
||||
return "win";
|
||||
#else
|
||||
return QString();
|
||||
#endif
|
||||
}
|
||||
|
||||
void disableCoreDumps()
|
||||
{
|
||||
bool success = false;
|
||||
// default to true
|
||||
// there is no point in printing a warning if this is not implemented on the platform
|
||||
bool success = true;
|
||||
|
||||
// prefer PR_SET_DUMPABLE since that also prevents ptrace
|
||||
#if defined(HAVE_PR_SET_DUMPABLE)
|
||||
success = (prctl(PR_SET_DUMPABLE, 0) == 0);
|
||||
#elif defined(HAVE_RLIMIT_CORE)
|
||||
#if defined(HAVE_RLIMIT_CORE)
|
||||
struct rlimit limit;
|
||||
limit.rlim_cur = 0;
|
||||
limit.rlim_max = 0;
|
||||
success = (setrlimit(RLIMIT_CORE, &limit) == 0);
|
||||
success = success && (setrlimit(RLIMIT_CORE, &limit) == 0);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PR_SET_DUMPABLE)
|
||||
success = success && (prctl(PR_SET_DUMPABLE, 0) == 0);
|
||||
#endif
|
||||
|
||||
// Mac OS X
|
||||
#ifdef HAVE_PT_DENY_ATTACH
|
||||
// make sure setrlimit() and ptrace() succeeded
|
||||
success = success && (ptrace(PT_DENY_ATTACH, 0, 0, 0) == 0);
|
||||
#endif
|
||||
|
||||
@@ -245,4 +231,13 @@ void disableCoreDumps()
|
||||
}
|
||||
}
|
||||
|
||||
void setupSearchPaths()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
// Make sure Windows doesn't load DLLs from the current working directory
|
||||
SetDllDirectoryA("");
|
||||
SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Tools
|
||||
|
||||
@@ -18,11 +18,13 @@
|
||||
#ifndef KEEPASSX_TOOLS_H
|
||||
#define KEEPASSX_TOOLS_H
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "core/Global.h"
|
||||
#include <algorithm>
|
||||
|
||||
class QIODevice;
|
||||
|
||||
@@ -32,13 +34,26 @@ QString humanReadableFileSize(qint64 bytes);
|
||||
bool hasChild(const QObject* parent, const QObject* child);
|
||||
bool readFromDevice(QIODevice* device, QByteArray& data, int size = 16384);
|
||||
bool readAllFromDevice(QIODevice* device, QByteArray& data);
|
||||
QDateTime currentDateTimeUtc();
|
||||
QString imageReaderFilter();
|
||||
bool isHex(const QByteArray& ba);
|
||||
bool isBase64(const QByteArray& ba);
|
||||
void sleep(int ms);
|
||||
void wait(int ms);
|
||||
QString platform();
|
||||
void disableCoreDumps();
|
||||
void setupSearchPaths();
|
||||
|
||||
template <typename RandomAccessIterator, typename T>
|
||||
RandomAccessIterator binaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T& value)
|
||||
{
|
||||
RandomAccessIterator it = std::lower_bound(begin, end, value);
|
||||
|
||||
if ((it == end) || (value < *it)) {
|
||||
return end;
|
||||
}
|
||||
else {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Tools
|
||||
|
||||
|
||||
130
src/core/Translator.cpp
Normal file
130
src/core/Translator.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 or (at your option)
|
||||
* version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Translator.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QLibraryInfo>
|
||||
#include <QLocale>
|
||||
#include <QRegExp>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "config-keepassx.h"
|
||||
#include "core/Config.h"
|
||||
#include "core/FilePath.h"
|
||||
|
||||
void Translator::installTranslator()
|
||||
{
|
||||
QString language = config()->get("GUI/Language").toString();
|
||||
if (language == "system" || language.isEmpty()) {
|
||||
language = QLocale::system().name();
|
||||
}
|
||||
|
||||
if (!installTranslator(language)) {
|
||||
// English fallback still needs translations for plurals
|
||||
if (!installTranslator("en_plurals")) {
|
||||
qWarning("Couldn't load translations.");
|
||||
}
|
||||
}
|
||||
|
||||
installQtTranslator(language);
|
||||
|
||||
availableLanguages();
|
||||
}
|
||||
|
||||
QList<QPair<QString, QString> > Translator::availableLanguages()
|
||||
{
|
||||
const QStringList paths = {
|
||||
#ifdef QT_DEBUG
|
||||
QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR),
|
||||
#endif
|
||||
filePath()->dataPath("translations")
|
||||
};
|
||||
|
||||
QList<QPair<QString, QString> > languages;
|
||||
languages.append(QPair<QString, QString>("system", "System default"));
|
||||
|
||||
QRegExp regExp("keepassx_([a-zA-Z_]+)\\.qm", Qt::CaseInsensitive, QRegExp::RegExp2);
|
||||
for (const QString& path : paths) {
|
||||
const QStringList fileList = QDir(path).entryList();
|
||||
for (const QString& filename : fileList) {
|
||||
if (regExp.exactMatch(filename)) {
|
||||
QString langcode = regExp.cap(1);
|
||||
if (langcode == "en_plurals") {
|
||||
langcode = "en";
|
||||
}
|
||||
|
||||
QLocale locale(langcode);
|
||||
QString languageStr = QLocale::languageToString(locale.language());
|
||||
QString countryStr;
|
||||
if (langcode.contains("_")) {
|
||||
countryStr = QString(" (%1)").arg(QLocale::countryToString(locale.country()));
|
||||
}
|
||||
|
||||
QPair<QString, QString> language(langcode, languageStr + countryStr);
|
||||
languages.append(language);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return languages;
|
||||
}
|
||||
|
||||
bool Translator::installTranslator(const QString& language)
|
||||
{
|
||||
const QStringList paths = {
|
||||
#ifdef QT_DEBUG
|
||||
QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR),
|
||||
#endif
|
||||
filePath()->dataPath("translations")
|
||||
};
|
||||
|
||||
for (const QString& path : paths) {
|
||||
if (installTranslator(language, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Translator::installTranslator(const QString& language, const QString& path)
|
||||
{
|
||||
QTranslator* translator = new QTranslator(qApp);
|
||||
if (translator->load(QString("keepassx_").append(language), path)) {
|
||||
QCoreApplication::installTranslator(translator);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
delete translator;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::installQtTranslator(const QString& language)
|
||||
{
|
||||
QTranslator* qtTranslator = new QTranslator(qApp);
|
||||
if (qtTranslator->load(QString("%1/qtbase_%2").arg(QLibraryInfo::location(QLibraryInfo::TranslationsPath), language))) {
|
||||
QCoreApplication::installTranslator(qtTranslator);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
delete qtTranslator;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
36
src/core/Translator.h
Normal file
36
src/core/Translator.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 or (at your option)
|
||||
* version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSX_TRANSLATOR_H
|
||||
#define KEEPASSX_TRANSLATOR_H
|
||||
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
|
||||
class Translator
|
||||
{
|
||||
public:
|
||||
static void installTranslator();
|
||||
static QList<QPair<QString, QString> > availableLanguages();
|
||||
|
||||
private:
|
||||
static bool installTranslator(const QString& language);
|
||||
static bool installTranslator(const QString& language, const QString& path);
|
||||
static bool installQtTranslator(const QString& language);
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_TRANSLATOR_H
|
||||
@@ -89,6 +89,12 @@ Uuid Uuid::fromBase64(const QString& str)
|
||||
return Uuid(data);
|
||||
}
|
||||
|
||||
Uuid Uuid::fromHex(const QString& str)
|
||||
{
|
||||
QByteArray data = QByteArray::fromHex(str.toLatin1());
|
||||
return Uuid(data);
|
||||
}
|
||||
|
||||
uint qHash(const Uuid& key)
|
||||
{
|
||||
return qHash(key.toByteArray());
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
bool operator!=(const Uuid& other) const;
|
||||
static const int Length;
|
||||
static Uuid fromBase64(const QString& str);
|
||||
static Uuid fromHex(const QString& str);
|
||||
|
||||
private:
|
||||
QByteArray m_data;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user