mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-01-25 16:11:39 +00:00
Compare commits
444 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a36f15667 | ||
|
|
b96fae74b6 | ||
|
|
404743a27f | ||
|
|
58c8fd0f09 | ||
|
|
fb3d3a135d | ||
|
|
96bddd1995 | ||
|
|
6e60ea6984 | ||
|
|
e410f88926 | ||
|
|
1b52feb8b8 | ||
|
|
ec8e915830 | ||
|
|
0bdbbbdf16 | ||
|
|
92e0647f19 | ||
|
|
69498147a2 | ||
|
|
4249c528e9 | ||
|
|
084068852e | ||
|
|
c524a85897 | ||
|
|
d39d46be5a | ||
|
|
b8980b4667 | ||
|
|
e0adec7b2b | ||
|
|
eb8b9d663f | ||
|
|
fa4b0cf9ec | ||
|
|
f72db8dd1d | ||
|
|
c5bf0f228a | ||
|
|
e150b26cab | ||
|
|
da41d07dae | ||
|
|
c885cb35d8 | ||
|
|
7c38217308 | ||
|
|
a88519b814 | ||
|
|
0aa91b170c | ||
|
|
e9bb1c01f7 | ||
|
|
883875e88e | ||
|
|
4cab6b0ad2 | ||
|
|
91a2664830 | ||
|
|
6abbeaf987 | ||
|
|
21efef42f7 | ||
|
|
9d0e8d94ca | ||
|
|
0f57ca698c | ||
|
|
69c572e875 | ||
|
|
4083b60ff3 | ||
|
|
41fbeb7ec9 | ||
|
|
1162357b9b | ||
|
|
a2a526866f | ||
|
|
d3338b699e | ||
|
|
6c60e76b55 | ||
|
|
8a0d31f612 | ||
|
|
6fc7e5ace1 | ||
|
|
8175762e74 | ||
|
|
f48e14af8a | ||
|
|
cd2a61d926 | ||
|
|
f45997afe4 | ||
|
|
b6f56721cb | ||
|
|
f9e7e82772 | ||
|
|
dbcd7b63d8 | ||
|
|
bf807684dd | ||
|
|
f02fcb5e4b | ||
|
|
2c127adf59 | ||
|
|
7f8a357019 | ||
|
|
99daf5b7b7 | ||
|
|
42cff20710 | ||
|
|
04d7880a0c | ||
|
|
e7d26e3f82 | ||
|
|
19308bf686 | ||
|
|
92970489c5 | ||
|
|
d51f5184d7 | ||
|
|
30eb26af7d | ||
|
|
3ea43f8213 | ||
|
|
9833067ba7 | ||
|
|
ad3114c56b | ||
|
|
9da9c269c1 | ||
|
|
0a22bb8469 | ||
|
|
c9fd1b1a17 | ||
|
|
19b40d45c0 | ||
|
|
90e2a1cda0 | ||
|
|
5e47b9f4a7 | ||
|
|
50b6948250 | ||
|
|
3ef118c9fa | ||
|
|
064707db43 | ||
|
|
8f71a1318d | ||
|
|
1b8ab35fdd | ||
|
|
4a1fe2f8ab | ||
|
|
e6e4e14781 | ||
|
|
d139157234 | ||
|
|
94104f4e03 | ||
|
|
8bea978715 | ||
|
|
eefe464fba | ||
|
|
33c0ba808c | ||
|
|
e0cc8ecda2 | ||
|
|
2d423b2358 | ||
|
|
b5b27b141c | ||
|
|
800a879927 | ||
|
|
f6806e42db | ||
|
|
3aae21b810 | ||
|
|
75239d6a64 | ||
|
|
09082955a3 | ||
|
|
6a6f2d51aa | ||
|
|
7b0d3ea8ac | ||
|
|
1c88b6bb26 | ||
|
|
e5e8e5d908 | ||
|
|
92fadd26b7 | ||
|
|
45d783ac43 | ||
|
|
ea9e76e7ae | ||
|
|
28426c0e91 | ||
|
|
3a9f51b600 | ||
|
|
f1b4db368e | ||
|
|
95efac187b | ||
|
|
6770d22438 | ||
|
|
4ce97613c4 | ||
|
|
030eb8eb6e | ||
|
|
c9da8e26e6 | ||
|
|
7ddf9772df | ||
|
|
0382ad1534 | ||
|
|
1b6e1369a0 | ||
|
|
835050c337 | ||
|
|
ca6a42e6eb | ||
|
|
a2e4d893ac | ||
|
|
657520b0b3 | ||
|
|
ea4b87895c | ||
|
|
19db500a19 | ||
|
|
1366cfd478 | ||
|
|
56a6df1f68 | ||
|
|
a1b35a8abf | ||
|
|
8a8a181186 | ||
|
|
463a551f7d | ||
|
|
fc613fb325 | ||
|
|
4517bea664 | ||
|
|
81dcfbe6ae | ||
|
|
fa8e64d04a | ||
|
|
562123b219 | ||
|
|
b217309618 | ||
|
|
357a02c74b | ||
|
|
508eeffa6e | ||
|
|
31555aa473 | ||
|
|
d2f968def7 | ||
|
|
d574bc611b | ||
|
|
a50a3b0123 | ||
|
|
5b6891dd45 | ||
|
|
4886982d43 | ||
|
|
7360f57beb | ||
|
|
491279b7a8 | ||
|
|
05b79f81af | ||
|
|
96ef2f2dd3 | ||
|
|
2542af17b6 | ||
|
|
c86bc649ff | ||
|
|
4b8e48ed88 | ||
|
|
a1addfd416 | ||
|
|
a1a57d8933 | ||
|
|
864970b860 | ||
|
|
a056be0842 | ||
|
|
c672e75739 | ||
|
|
7b5dd3f964 | ||
|
|
a6072f608b | ||
|
|
06462c65a5 | ||
|
|
359f9c0680 | ||
|
|
01db7c4948 | ||
|
|
f67f14a78d | ||
|
|
0a64d653e1 | ||
|
|
456a835285 | ||
|
|
0d8ed92a68 | ||
|
|
9bd093a03c | ||
|
|
361d4698a9 | ||
|
|
b342b15011 | ||
|
|
95638a3a80 | ||
|
|
2204fe3355 | ||
|
|
abcd774c9d | ||
|
|
ee209f8f88 | ||
|
|
b1f2e1c191 | ||
|
|
33f372f6c6 | ||
|
|
8e5c2a8875 | ||
|
|
36f3638ae4 | ||
|
|
d10210011f | ||
|
|
e867840d81 | ||
|
|
fb7e3189a8 | ||
|
|
5733c0143b | ||
|
|
ac4881f231 | ||
|
|
939efd7dab | ||
|
|
a93d96d742 | ||
|
|
f21804c769 | ||
|
|
4bc05a8d46 | ||
|
|
eebe2b0e80 | ||
|
|
250a496a78 | ||
|
|
29163ed053 | ||
|
|
cc05661f9e | ||
|
|
89409c22d1 | ||
|
|
e2f240ebc9 | ||
|
|
8d56f4c33b | ||
|
|
36eccb7122 | ||
|
|
c8827769b4 | ||
|
|
12e6c400b9 | ||
|
|
4c273a7910 | ||
|
|
58da335b17 | ||
|
|
5b2d506462 | ||
|
|
531430d44a | ||
|
|
7450eec7eb | ||
|
|
3a5802435f | ||
|
|
1b6b058097 | ||
|
|
a5797a2350 | ||
|
|
e81a5147c5 | ||
|
|
565c990687 | ||
|
|
0ccdfe0e26 | ||
|
|
f8a558e3a7 | ||
|
|
c5fa195cc6 | ||
|
|
3a821edd45 | ||
|
|
854d194f88 | ||
|
|
fb79daad6a | ||
|
|
b2ae0e8759 | ||
|
|
09f73988b3 | ||
|
|
9e6f289319 | ||
|
|
d2a55ffd31 | ||
|
|
793c2aa423 | ||
|
|
5daa332b6c | ||
|
|
d5511a857c | ||
|
|
7fecd21331 | ||
|
|
88b79e512f | ||
|
|
853bf63777 | ||
|
|
ff16fea54a | ||
|
|
a03e2a69d4 | ||
|
|
56a39df635 | ||
|
|
ac1593ff75 | ||
|
|
4d66b4667c | ||
|
|
fdde538b66 | ||
|
|
de1147219c | ||
|
|
371426a08e | ||
|
|
75eb005ba0 | ||
|
|
601b67145c | ||
|
|
c65afbc057 | ||
|
|
378589a473 | ||
|
|
fa264972a4 | ||
|
|
6b10e01c03 | ||
|
|
5a6d74ab37 | ||
|
|
73f1bb6968 | ||
|
|
d1a7f51859 | ||
|
|
2ae16396a6 | ||
|
|
ef090a5dc5 | ||
|
|
5c0799e82b | ||
|
|
fa2ee01d3f | ||
|
|
d6ba80bd3f | ||
|
|
ee96d5f88c | ||
|
|
e96a917bef | ||
|
|
769b816998 | ||
|
|
ff891c210c | ||
|
|
3ed5e1bf95 | ||
|
|
5bc8581389 | ||
|
|
7346b422d5 | ||
|
|
5c80ac1c74 | ||
|
|
699023992c | ||
|
|
454ce604ad | ||
|
|
1e0f6bfecb | ||
|
|
7f10aa3de2 | ||
|
|
f8764ab85e | ||
|
|
aa8544308e | ||
|
|
31fc70e0f8 | ||
|
|
a16af4560b | ||
|
|
0782ba0dab | ||
|
|
83725667a4 | ||
|
|
f4b3163b04 | ||
|
|
6cd745f429 | ||
|
|
6131f7f6bf | ||
|
|
dd4faa030f | ||
|
|
ab8691f5ac | ||
|
|
77ab073cdb | ||
|
|
87e0011525 | ||
|
|
7af3bb7226 | ||
|
|
5573352ce6 | ||
|
|
e6486e08ab | ||
|
|
48badaa927 | ||
|
|
2f13bf677e | ||
|
|
e63abc1b4b | ||
|
|
88334acdef | ||
|
|
0491aa9f6e | ||
|
|
5be76d7c0f | ||
|
|
3b510389fc | ||
|
|
32d88e9249 | ||
|
|
7b1a1ff4bb | ||
|
|
19beb919d0 | ||
|
|
ba09e8bf4d | ||
|
|
26dd2d0e8e | ||
|
|
69b15d58a2 | ||
|
|
ba68789fb9 | ||
|
|
47a6ceffbc | ||
|
|
b17ca66f73 | ||
|
|
93bc609026 | ||
|
|
3ea51c2e15 | ||
|
|
1d9897ea60 | ||
|
|
b6cb00bc79 | ||
|
|
6dd53c6bfd | ||
|
|
07df5126b3 | ||
|
|
47b38c7d45 | ||
|
|
0e97bec7b2 | ||
|
|
b182585d46 | ||
|
|
e8f92535d3 | ||
|
|
d62c3663e9 | ||
|
|
6b0bfda9fb | ||
|
|
7477330961 | ||
|
|
1f71157063 | ||
|
|
905988c592 | ||
|
|
310951bfa8 | ||
|
|
64c1087856 | ||
|
|
cab6d924aa | ||
|
|
c3a972d39b | ||
|
|
33d44d4d24 | ||
|
|
fd89cf2482 | ||
|
|
112ffb981f | ||
|
|
514426b980 | ||
|
|
a4bf1c8be6 | ||
|
|
9b82e1478f | ||
|
|
d5f145d57e | ||
|
|
bab891ee74 | ||
|
|
a65fd7d0d0 | ||
|
|
46836cc805 | ||
|
|
42559f13d8 | ||
|
|
87351b5920 | ||
|
|
e68dcf189c | ||
|
|
5d62b8389c | ||
|
|
c50aebe76d | ||
|
|
a610f3fde7 | ||
|
|
626391a1d9 | ||
|
|
1bedfe75ea | ||
|
|
86ecc8d4d5 | ||
|
|
9eca84efe1 | ||
|
|
8a6fb6dcba | ||
|
|
e3706fa923 | ||
|
|
8193bc5f60 | ||
|
|
504ecaee5e | ||
|
|
7c9e836572 | ||
|
|
5db0f09b43 | ||
|
|
195bc4ef21 | ||
|
|
6b190bc184 | ||
|
|
39f1cac2c8 | ||
|
|
d193eed519 | ||
|
|
2d80b0e12f | ||
|
|
b50d99be9c | ||
|
|
af41876a5e | ||
|
|
76d351d8be | ||
|
|
b5dd9651c3 | ||
|
|
3e34502014 | ||
|
|
5e57f9cbd6 | ||
|
|
8edb869fdc | ||
|
|
37238c7f57 | ||
|
|
9edee82fa1 | ||
|
|
f7aaea79af | ||
|
|
3c75d2f8b7 | ||
|
|
64c67e19d2 | ||
|
|
d4db8faad8 | ||
|
|
7957b73b4a | ||
|
|
69838c44af | ||
|
|
8e2953aef6 | ||
|
|
8dda616502 | ||
|
|
484512e35b | ||
|
|
c8cd05c07d | ||
|
|
7ffefe6259 | ||
|
|
cd9b7f2f11 | ||
|
|
b372974437 | ||
|
|
7464e0f799 | ||
|
|
25e12f1775 | ||
|
|
6416469f78 | ||
|
|
922ce5ae36 | ||
|
|
9ca8a199c0 | ||
|
|
a570406ac8 | ||
|
|
719edb6b6e | ||
|
|
d075218621 | ||
|
|
7509943938 | ||
|
|
774da9d2f8 | ||
|
|
978fd383e8 | ||
|
|
8551fc23fe | ||
|
|
fb711edeeb | ||
|
|
352a21acaa | ||
|
|
0b9d936317 | ||
|
|
dc500243e9 | ||
|
|
21203b8341 | ||
|
|
5b03447640 | ||
|
|
d34158db2c | ||
|
|
65a17390c7 | ||
|
|
0e96f0917c | ||
|
|
3d62a7e64a | ||
|
|
962805936e | ||
|
|
967aeecf5b | ||
|
|
348b039fa3 | ||
|
|
6e9b1f4fa3 | ||
|
|
f1d447d1aa | ||
|
|
a7c6f47dbe | ||
|
|
0446e89bfe | ||
|
|
e41457913f | ||
|
|
cea1ec7641 | ||
|
|
cc362deb87 | ||
|
|
7ec64e8a3d | ||
|
|
ff2461df9d | ||
|
|
192cd2733c | ||
|
|
ecef95469d | ||
|
|
55d30d5e4b | ||
|
|
2d5502cc2f | ||
|
|
5cda4a1eb4 | ||
|
|
812b914b70 | ||
|
|
9b870ad863 | ||
|
|
0f250ac92d | ||
|
|
552e6b7836 | ||
|
|
28f70b281b | ||
|
|
32d9b573c0 | ||
|
|
fc76a843d5 | ||
|
|
06607aabb2 | ||
|
|
a1edc0e4f1 | ||
|
|
787c5d2189 | ||
|
|
492c577184 | ||
|
|
f5d0e22dc7 | ||
|
|
dc5ba01f1e | ||
|
|
a31f6e68aa | ||
|
|
c95b356a99 | ||
|
|
b5e645cb10 | ||
|
|
627e638251 | ||
|
|
d2e2f337f6 | ||
|
|
e6d4d44f15 | ||
|
|
55f4df19a9 | ||
|
|
9f006ec08a | ||
|
|
d62ff40bed | ||
|
|
da194007fb | ||
|
|
d06ce0c748 | ||
|
|
c14fecb415 | ||
|
|
99f7308a67 | ||
|
|
99ee45ba2d | ||
|
|
615f3f77a6 | ||
|
|
12e4c00c5d | ||
|
|
d954cb468f | ||
|
|
e0fadc7af5 | ||
|
|
c5e9fd99b8 | ||
|
|
7efbbb2153 | ||
|
|
4eb505e24a | ||
|
|
b6b08cccd7 | ||
|
|
70af8541da | ||
|
|
838f8ae352 | ||
|
|
5645515d90 | ||
|
|
d114ffb2c4 | ||
|
|
a9f9534ce6 | ||
|
|
7dee2c67c6 | ||
|
|
e18f8ba6d4 | ||
|
|
4d44753f6e | ||
|
|
f5accbfaed | ||
|
|
6eba99eba1 | ||
|
|
1e18a08998 | ||
|
|
2526380184 | ||
|
|
74dba7cb6c | ||
|
|
63aad8ca84 | ||
|
|
b8bb40de62 | ||
|
|
67dff7fbf2 | ||
|
|
6e226f32fd | ||
|
|
cf819dc0a8 |
23
.hgignore
Normal file
23
.hgignore
Normal file
@@ -0,0 +1,23 @@
|
||||
syntax: glob
|
||||
|
||||
.DS_Store
|
||||
run.py
|
||||
*.pyc
|
||||
*.so
|
||||
*.mode1v3
|
||||
*.pbxuser
|
||||
*.tm_build_errors
|
||||
*.pyd
|
||||
conf.json
|
||||
build
|
||||
dist
|
||||
install
|
||||
installer_tmp-cache
|
||||
cocoa/*/Info.plist
|
||||
cocoa/*/build
|
||||
cocoa/*/dg_cocoa.plugin
|
||||
qt/base/*_rc.py
|
||||
qt/lang/fr.qm
|
||||
qt/lang/en.qm
|
||||
help/*/conf.py
|
||||
help/*/changelog.rst
|
||||
47
.hgtags
Normal file
47
.hgtags
Normal file
@@ -0,0 +1,47 @@
|
||||
0ef0ca83b49ad009c896f55824189acc932bcf22 se2.8.2
|
||||
0ef0ca83b49ad009c896f55824189acc932bcf22 me5.6.6
|
||||
0ef0ca83b49ad009c896f55824189acc932bcf22 pe1.7.8
|
||||
a8f232f880b6f9ada565d472996a627ebf69b6e9 before-tiger-drop
|
||||
321d15e818cf9a3f1fc037543090bb2fca2cccd7 me5.7.0
|
||||
adc73ccd14b1386cb04dee773c53a2d126800e31 se2.9.0
|
||||
cbcf9c80fee4c908ef2efbf1c143c9e47676c9b2 pe1.8.0
|
||||
61c4101851bdea3cb37dfb76f0d404c78c7c594c se2.9.1
|
||||
0e923897a3389331d4ab3debbc40b8dd616199d9 pe1.8.1
|
||||
2c454eca9ebe93b6cf34916068f828a6a39e3eaf me5.7.1
|
||||
19e40bab20521d4256acf325dba9b32e95e135c5 pe1.8.2
|
||||
7b7c5a66ebee4e4b8125330d24fe9ce1a070ff25 se2.9.2
|
||||
1cef6d39855f85d4be728646bc78b860e6d4e398 pe1.8.3
|
||||
90ed56ee602666db2f267f73eac6f824347039b5 me5.7.2
|
||||
4c3cb1e671a333eabde1151c7c6ffb3609cab025 pe1.8.4
|
||||
0a71306434bca51bea9a5d5ae54fe1bf0e4900d8 pe1.8.5
|
||||
556baf4a410779e9bbf43129de133e4c4b26d679 pe1.8.6
|
||||
9149024283959a50fe9a47a5f175b905d1672c19 se2.10.0
|
||||
388a7e5aef6385e515189f4a15b4c4fed3ae2fcf me5.8.0
|
||||
27501167e3b9262ecb60c967941294f36d77eb25 pe1.9.0
|
||||
cb0a860430bacd712820bce426bcf47a4135efe1 se2.10.1
|
||||
cb0a860430bacd712820bce426bcf47a4135efe1 se2.10.1
|
||||
f71d405e62badcfdc1b037facaac043cece40ee5 se2.10.1
|
||||
3742e83edd9eadf44e1a501859f5e2462b1ef6fd me5.8.1
|
||||
724ff565dd785fb739774588c6ee652cfc0612d5 pe1.9.1
|
||||
634b66415c6529f46ae4f837318027cc9d70c3b5 before-py3k
|
||||
2b67955db2b0580a8b0854dc918b6ab0d1fa3b88 se2.11.0
|
||||
b56fe4dd8c95bca270b078a09e86848df77e2b2d me5.9.0
|
||||
618a7365457d56fdc6920c70843a244762e2ea00 pe1.10.0
|
||||
95b3a4b564c6222b414f2b40182dde2bd6d0e8a4 me5.9.1
|
||||
9735a5218d2b5b3b1e1dfe17f2f874177cf8f61c se2.11.1
|
||||
dbfee3ee2fa5cbb9e7ab36570659c17cd5b8561f se2.12.0
|
||||
d3fe0d0dcda1e0bf1100d02f117503d3bf6baacf me5.10.0
|
||||
b07ac1398703dd358912c1f3d20bd995633db9fe pe1.11.0
|
||||
96b6aee668398d663b04eafc8d5dae05e18500ee before-fairware
|
||||
22239f94589baf2a9fad2123045b8a718dbd68f5 se2.12.2
|
||||
f9cae82a0752191276b24ffb2cc4e4a8afb5d754 me5.10.2
|
||||
154c8cb6f018d446d88fa099490c900906e86386 pe1.11.2
|
||||
ca93352ce35184853ad9fcb881935a43a8b1e249 me5.10.3
|
||||
44f6ff67066c083f79daa18a9d2f1ab909e0a62e me5.10.4
|
||||
3f71a8f5bf8f6d0729748a27af9163e013723294 pe1.11.3
|
||||
0056293b0dade8b8230f68c1fe6f0c2d1e0b74d8 se2.12.3
|
||||
8d12cab3b12b723e3a86d02cf8002731a0f73f95 se3.0.0
|
||||
778876a8a9787658aa6adf6944b53aebcb7faeea se3.0.1
|
||||
f1d40b556c01f32c58f9ef9f9acac5b78e01ba7a pe2.0.0
|
||||
2fd901a516f8cb6b4438491f63f2ebfd52a57c13 me6.0.0
|
||||
ff43c6d9feb388f103b7857eaa6f7809185f78ec before-pluginbuilder
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2009 Hardcoded Software Inc. (http://www.hardcoded.net)
|
||||
Copyright 2010 Hardcoded Software Inc. (http://www.hardcoded.net)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
@@ -6,6 +6,5 @@ Redistribution and use in source and binary forms, with or without modification,
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Hardcoded Software Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
* If the source code has been published less than two years ago, any redistribution, in whole or in part, must retain full licensing functionality, without any attempt to change, obscure or in other ways circumvent its intent.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
73
README
Normal file
73
README
Normal file
@@ -0,0 +1,73 @@
|
||||
Contents
|
||||
========
|
||||
|
||||
This package contains the source for dupeGuru. To learn how to build it, refer to the "Build dupeGuru" section. Below is the description of the various subfolders:
|
||||
|
||||
- core: Contains the core logic code for dupeGuru. It's Python code written in TDD style.
|
||||
- core_*: Edition-specific-cross-toolkit code written in Python.
|
||||
- cocoa: UI code for the Cocoa toolkit. It's Objective-C code.
|
||||
- qt: UI code for the Qt toolkit. It's written in Python and uses PyQt.
|
||||
- images: Images used by the different UI codebases.
|
||||
- debian_*: Skeleton files required to create a .deb package
|
||||
- help: Help document, written for Sphinx.
|
||||
|
||||
There are also other sub-folder that comes from external repositories (automatically checked out
|
||||
with as mercurial subrepos):
|
||||
|
||||
- hscommon: A collection of helpers used across HS applications.
|
||||
- cocoalib: A collection of helpers used across Cocoa UI codebases of HS applications.
|
||||
- qtlib: A collection of helpers used across Qt UI codebases of HS applications.
|
||||
|
||||
dupeGuru Dependencies
|
||||
=====================
|
||||
|
||||
Before being able to build dupeGuru, a few dependencies have to be installed:
|
||||
|
||||
General dependencies
|
||||
--------------------
|
||||
|
||||
- Python 3.1 (3.2 on Mac OS X) (http://www.python.org)
|
||||
- Send2Trash3k (http://hg.hardcoded.net/send2trash)
|
||||
- hsaudiotag3k 1.1.0 (for ME) (http://hg.hardcoded.net/hsaudiotag)
|
||||
- jobprogress (http://hg.hardcoded.net/jobprogress)
|
||||
- Sphinx 1.0.6 (http://sphinx.pocoo.org/)
|
||||
- pytest 2.0.0, to run unit tests. (http://pytest.org/)
|
||||
|
||||
Note: Sphinx doesn't officially support Python 3.x yet, but it doesn't matter because it is invoked
|
||||
by the build system through command line, so you can build dupeGuru even if Sphinx is installed in
|
||||
your Python 2.x install.
|
||||
|
||||
OS X prerequisites
|
||||
------------------
|
||||
|
||||
- XCode 3.1 (http://developer.apple.com/TOOLS/xcode/)
|
||||
- Sparkle (http://sparkle.andymatuschak.org/)
|
||||
- PyObjC 2.3 (http://pyobjc.sourceforge.net/)
|
||||
- pluginbuilder 1.0.1 (http://bitbucket.org/hsoft/pluginbuilder)
|
||||
- appscript 1.0.0 for ME and PE (http://appscript.sourceforge.net/)
|
||||
|
||||
Windows prerequisites
|
||||
---------------------
|
||||
|
||||
- Visual Studio 2008 (Express is enough) is needed to build C extensions. (http://www.microsoft.com/Express/)
|
||||
- PyQt 4.7.5 (http://www.riverbankcomputing.co.uk/news)
|
||||
- cx_Freeze, if you want to build a exe. You don't need it if you just want to run dupeGuru. (http://cx-freeze.sourceforge.net/)
|
||||
- Advanced Installer, if you want to build the installer file. (http://www.advancedinstaller.com/)
|
||||
|
||||
Building dupeGuru
|
||||
=================
|
||||
|
||||
First, make sure you meet the dependencies listed in the section above. Then you need to configure your build with:
|
||||
|
||||
python configure.py
|
||||
|
||||
If you want, you can specify a UI to use with the `--ui` option. So, if you want to build dupeGuru with Qt on OS X, then you have to type `python configure.py --ui=qt`. You can also use the `--dev` flag to indicate a dev build (it will build `dg_cocoa.plugin` in alias mode and use the "dev" config in XCode).
|
||||
|
||||
Then, just build the thing and then run it with:
|
||||
|
||||
python build.py
|
||||
python run.py
|
||||
|
||||
If you want to create ready-to-upload package, run:
|
||||
|
||||
python package.py
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "RecentDirectories.h"
|
||||
#import "PyDupeGuru.h"
|
||||
#import "ResultWindow.h"
|
||||
#import "DetailsPanel.h"
|
||||
|
||||
@interface AppDelegateBase : NSObject
|
||||
{
|
||||
IBOutlet PyDupeGuruBase *py;
|
||||
IBOutlet RecentDirectories *recentDirectories;
|
||||
IBOutlet NSMenuItem *unlockMenuItem;
|
||||
IBOutlet ResultWindowBase *result;
|
||||
|
||||
NSString *_appName;
|
||||
DetailsPanelBase *_detailsPanel;
|
||||
}
|
||||
- (IBAction)unlockApp:(id)sender;
|
||||
|
||||
- (PyDupeGuruBase *)py;
|
||||
- (RecentDirectories *)recentDirectories;
|
||||
- (DetailsPanelBase *)detailsPanel; // Virtual
|
||||
@end
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "ProgressController.h"
|
||||
#import "RegistrationInterface.h"
|
||||
#import "Utils.h"
|
||||
#import "Consts.h"
|
||||
|
||||
@implementation AppDelegateBase
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
_appName = @"";
|
||||
return self;
|
||||
}
|
||||
|
||||
- (IBAction)unlockApp:(id)sender
|
||||
{
|
||||
if ([[self py] isRegistered])
|
||||
return;
|
||||
RegistrationInterface *ri = [[RegistrationInterface alloc] initWithApp:[self py] name:_appName limitDescription:LIMIT_DESC];
|
||||
if ([ri enterCode] == NSOKButton)
|
||||
{
|
||||
NSString *menuTitle = [NSString stringWithFormat:@"Thanks for buying %@!",_appName];
|
||||
[unlockMenuItem setTitle:menuTitle];
|
||||
}
|
||||
[ri release];
|
||||
}
|
||||
|
||||
- (PyDupeGuruBase *)py { return py; }
|
||||
- (RecentDirectories *)recentDirectories { return recentDirectories; }
|
||||
- (DetailsPanelBase *)detailsPanel { return nil; } // Virtual
|
||||
|
||||
/* Delegate */
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
[[ProgressController mainProgressController] setWorker:py];
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
//Restore Columns
|
||||
NSArray *columnsOrder = [ud arrayForKey:@"columnsOrder"];
|
||||
NSDictionary *columnsWidth = [ud dictionaryForKey:@"columnsWidth"];
|
||||
if ([columnsOrder count])
|
||||
[result restoreColumnsPosition:columnsOrder widths:columnsWidth];
|
||||
else
|
||||
[result resetColumnsToDefault:nil];
|
||||
//Reg stuff
|
||||
if ([RegistrationInterface showNagWithApp:[self py] name:_appName limitDescription:LIMIT_DESC])
|
||||
[unlockMenuItem setTitle:[NSString stringWithFormat:@"Thanks for buying %@!",_appName]];
|
||||
//Restore results
|
||||
[py loadIgnoreList];
|
||||
[py loadResults];
|
||||
}
|
||||
@end
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#define DuplicateSelectionChangedNotification @"DuplicateSelectionChangedNotification"
|
||||
/* ResultsChangedNotification happens on major changes, which requires a complete reload of the data*/
|
||||
#define ResultsChangedNotification @"ResultsChangedNotification"
|
||||
/* ResultsChangedNotification happens on minor changes, which requires buffer flush*/
|
||||
#define ResultsUpdatedNotification @"ResultsUpdatedNotification"
|
||||
#define ResultsMarkingChangedNotification @"ResultsMarkingChangedNotification"
|
||||
#define RegistrationRequired @"RegistrationRequired"
|
||||
#define JobStarted @"JobStarted"
|
||||
#define JobInProgress @"JobInProgress"
|
||||
|
||||
#define jobLoad @"job_load"
|
||||
#define jobScan @"job_scan"
|
||||
#define jobCopy @"job_copy"
|
||||
#define jobMove @"job_move"
|
||||
#define jobDelete @"job_delete"
|
||||
|
||||
#define DEMO_MAX_ACTION_COUNT 10
|
||||
#define LIMIT_DESC @"In the demo version, only 10 duplicates per session can be sent to Trash, moved or copied."
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyApp.h"
|
||||
#import "Table.h"
|
||||
|
||||
|
||||
@interface DetailsPanelBase : NSWindowController
|
||||
{
|
||||
IBOutlet TableView *detailsTable;
|
||||
}
|
||||
- (id)initWithPy:(PyApp *)aPy;
|
||||
|
||||
- (void)refresh;
|
||||
- (void)toggleVisibility;
|
||||
|
||||
/* Notifications */
|
||||
- (void)duplicateSelectionChanged:(NSNotification *)aNotification;
|
||||
@end
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import "DetailsPanel.h"
|
||||
#import "Consts.h"
|
||||
|
||||
@implementation DetailsPanelBase
|
||||
- (id)initWithPy:(PyApp *)aPy
|
||||
{
|
||||
self = [super initWithWindowNibName:@"DetailsPanel"];
|
||||
[self window]; //So the detailsTable is initialized.
|
||||
[detailsTable setPy:aPy];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(duplicateSelectionChanged:) name:DuplicateSelectionChangedNotification object:nil];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)refresh
|
||||
{
|
||||
[detailsTable reloadData];
|
||||
}
|
||||
|
||||
- (void)toggleVisibility
|
||||
{
|
||||
if ([[self window] isVisible])
|
||||
[[self window] close];
|
||||
else
|
||||
{
|
||||
[self refresh]; // selection might have changed since last time
|
||||
[[self window] orderFront:nil];
|
||||
}
|
||||
}
|
||||
|
||||
/* Notifications */
|
||||
- (void)duplicateSelectionChanged:(NSNotification *)aNotification
|
||||
{
|
||||
if ([[self window] isVisible])
|
||||
[self refresh];
|
||||
}
|
||||
@end
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "RecentDirectories.h"
|
||||
#import "Outline.h"
|
||||
#import "PyDupeGuru.h"
|
||||
|
||||
@interface DirectoryOutline : OutlineView
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
@protocol DirectoryOutlineDelegate
|
||||
- (void)outlineView:(NSOutlineView *)outlineView addDirectory:(NSString *)directory;
|
||||
@end
|
||||
|
||||
@interface DirectoryPanelBase : NSWindowController
|
||||
{
|
||||
IBOutlet NSPopUpButton *addButtonPopUp;
|
||||
IBOutlet DirectoryOutline *directories;
|
||||
IBOutlet NSButton *removeButton;
|
||||
|
||||
PyDupeGuruBase *_py;
|
||||
RecentDirectories *_recentDirectories;
|
||||
}
|
||||
- (id)initWithParentApp:(id)aParentApp;
|
||||
|
||||
- (IBAction)askForDirectory:(id)sender;
|
||||
- (IBAction)changeDirectoryState:(id)sender;
|
||||
- (IBAction)popupAddDirectoryMenu:(id)sender;
|
||||
- (IBAction)removeSelectedDirectory:(id)sender;
|
||||
- (IBAction)toggleVisible:(id)sender;
|
||||
|
||||
- (void)addDirectory:(NSString *)directory;
|
||||
- (void)refreshRemoveButtonText;
|
||||
@end
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import "DirectoryPanel.h"
|
||||
#import "Dialogs.h"
|
||||
#import "Utils.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@implementation DirectoryOutline
|
||||
- (void)doInit
|
||||
{
|
||||
[super doInit];
|
||||
[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
|
||||
}
|
||||
|
||||
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
|
||||
{
|
||||
NSPasteboard *pboard;
|
||||
NSDragOperation sourceDragMask;
|
||||
sourceDragMask = [info draggingSourceOperationMask];
|
||||
pboard = [info draggingPasteboard];
|
||||
if ([[pboard types] containsObject:NSFilenamesPboardType])
|
||||
{
|
||||
if (sourceDragMask & NSDragOperationLink)
|
||||
return NSDragOperationLink;
|
||||
}
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index
|
||||
{
|
||||
NSPasteboard *pboard;
|
||||
NSDragOperation sourceDragMask;
|
||||
sourceDragMask = [info draggingSourceOperationMask];
|
||||
pboard = [info draggingPasteboard];
|
||||
if ( [[pboard types] containsObject:NSFilenamesPboardType] )
|
||||
{
|
||||
NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
|
||||
if (!(sourceDragMask & NSDragOperationLink))
|
||||
return NO;
|
||||
if (([self delegate] == nil) || (![[self delegate] respondsToSelector:@selector(outlineView:addDirectory:)]))
|
||||
return NO;
|
||||
for (NSString *filename in filenames)
|
||||
[[self delegate] outlineView:self addDirectory:filename];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation DirectoryPanelBase
|
||||
- (id)initWithParentApp:(id)aParentApp
|
||||
{
|
||||
self = [super initWithWindowNibName:@"DirectoryPanel"];
|
||||
[self window];
|
||||
AppDelegateBase *app = aParentApp;
|
||||
_py = [app py];
|
||||
_recentDirectories = [app recentDirectories];
|
||||
[directories setPy:_py];
|
||||
NSPopUpButtonCell *cell = [[directories tableColumnWithIdentifier:@"1"] dataCell];
|
||||
[cell addItemWithTitle:@"Normal"];
|
||||
[cell addItemWithTitle:@"Reference"];
|
||||
[cell addItemWithTitle:@"Excluded"];
|
||||
for (int i=0;i<[[cell itemArray] count];i++)
|
||||
{
|
||||
NSMenuItem *mi = [[cell itemArray] objectAtIndex:i];
|
||||
[mi setTarget:self];
|
||||
[mi setAction:@selector(changeDirectoryState:)];
|
||||
[mi setTag:i];
|
||||
}
|
||||
[self refreshRemoveButtonText];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(directorySelectionChanged:) name:NSOutlineViewSelectionDidChangeNotification object:directories];
|
||||
return self;
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
|
||||
- (IBAction)askForDirectory:(id)sender
|
||||
{
|
||||
NSOpenPanel *op = [NSOpenPanel openPanel];
|
||||
[op setCanChooseFiles:YES];
|
||||
[op setCanChooseDirectories:YES];
|
||||
[op setAllowsMultipleSelection:NO];
|
||||
[op setTitle:@"Select a directory to add to the scanning list"];
|
||||
[op setDelegate:self];
|
||||
if ([op runModalForTypes:nil] == NSOKButton)
|
||||
{
|
||||
NSString *directory = [[op filenames] objectAtIndex:0];
|
||||
[self addDirectory:directory];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)changeDirectoryState:(id)sender
|
||||
{
|
||||
OVNode *node = [directories itemAtRow:[directories clickedRow]];
|
||||
[_py setDirectory:p2a([node indexPath]) state:i2n([sender tag])];
|
||||
[node resetAllBuffers];
|
||||
[directories reloadItem:node reloadChildren:YES];
|
||||
[directories display];
|
||||
}
|
||||
|
||||
- (IBAction)popupAddDirectoryMenu:(id)sender
|
||||
{
|
||||
if ([[_recentDirectories directories] count] == 0)
|
||||
{
|
||||
[self askForDirectory:sender];
|
||||
return;
|
||||
}
|
||||
NSMenu *m = [addButtonPopUp menu];
|
||||
while ([m numberOfItems] > 0)
|
||||
[m removeItemAtIndex:0];
|
||||
NSMenuItem *mi = [m addItemWithTitle:@"Add New Directory..." action:@selector(askForDirectory:) keyEquivalent:@""];
|
||||
[mi setTarget:self];
|
||||
[m addItem:[NSMenuItem separatorItem]];
|
||||
[_recentDirectories fillMenu:m];
|
||||
[addButtonPopUp selectItem:nil];
|
||||
[[addButtonPopUp cell] performClickWithFrame:[sender frame] inView:[sender superview]];
|
||||
}
|
||||
|
||||
- (IBAction)removeSelectedDirectory:(id)sender
|
||||
{
|
||||
[[self window] makeKeyAndOrderFront:nil];
|
||||
if ([directories selectedRow] < 0)
|
||||
return;
|
||||
OVNode *node = [directories itemAtRow:[directories selectedRow]];
|
||||
if ([node level] == 1)
|
||||
{
|
||||
[_py removeDirectory:i2n([node index])];
|
||||
[directories reloadData];
|
||||
}
|
||||
else
|
||||
{
|
||||
int state = n2i([[node buffer] objectAtIndex:1]);
|
||||
int newState = state == 2 ? 0 : 2; // If excluded, put it back
|
||||
[_py setDirectory:p2a([node indexPath]) state:i2n(newState)];
|
||||
[node resetAllBuffers];
|
||||
[directories display];
|
||||
}
|
||||
[self refreshRemoveButtonText];
|
||||
}
|
||||
|
||||
- (IBAction)toggleVisible:(id)sender
|
||||
{
|
||||
[[self window] makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
/* Public */
|
||||
|
||||
- (void)addDirectory:(NSString *)directory
|
||||
{
|
||||
int r = [[_py addDirectory:directory] intValue];
|
||||
if (r)
|
||||
{
|
||||
NSString *m;
|
||||
switch (r)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
m = @"This directory already is in the list.";
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
m = @"This directory does not exist.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
[Dialogs showMessage:m];
|
||||
}
|
||||
[directories reloadData];
|
||||
[_recentDirectories addDirectory:directory];
|
||||
[[self window] makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
- (void)refreshRemoveButtonText
|
||||
{
|
||||
if ([directories selectedRow] < 0)
|
||||
{
|
||||
[removeButton setEnabled:NO];
|
||||
return;
|
||||
}
|
||||
[removeButton setEnabled:YES];
|
||||
OVNode *node = [directories itemAtRow:[directories selectedRow]];
|
||||
int state = n2i([[node buffer] objectAtIndex:1]);
|
||||
NSString *buttonText = state == 2 ? @"Put Back" : @"Remove";
|
||||
[removeButton setTitle:buttonText];
|
||||
}
|
||||
|
||||
/* Delegate */
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)outlineView addDirectory:(NSString *)directory
|
||||
{
|
||||
[self addDirectory:directory];
|
||||
}
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||
{
|
||||
OVNode *node = item;
|
||||
int state = n2i([[node buffer] objectAtIndex:1]);
|
||||
if ([cell isKindOfClass:[NSTextFieldCell class]])
|
||||
{
|
||||
NSTextFieldCell *textCell = cell;
|
||||
if (state == 1)
|
||||
[textCell setTextColor:[NSColor blueColor]];
|
||||
else if (state == 2)
|
||||
[textCell setTextColor:[NSColor redColor]];
|
||||
else
|
||||
[textCell setTextColor:[NSColor blackColor]];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)path
|
||||
{
|
||||
BOOL isdir;
|
||||
[[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isdir];
|
||||
return isdir;
|
||||
}
|
||||
|
||||
/* Notifications */
|
||||
|
||||
- (void)directorySelectionChanged:(NSNotification *)aNotification
|
||||
{
|
||||
[self refreshRemoveButtonText];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyApp.h"
|
||||
|
||||
@interface PyDupeGuruBase : PyApp
|
||||
//Actions
|
||||
- (NSNumber *)addDirectory:(NSString *)name;
|
||||
- (void)removeDirectory:(NSNumber *)index;
|
||||
- (void)setDirectory:(NSArray *)indexPath state:(NSNumber *)state;
|
||||
- (void)loadResults;
|
||||
- (void)saveResults;
|
||||
- (void)loadIgnoreList;
|
||||
- (void)saveIgnoreList;
|
||||
- (void)clearIgnoreList;
|
||||
- (void)purgeIgnoreList;
|
||||
- (NSString *)exportToXHTMLwithColumns:(NSArray *)aColIds;
|
||||
|
||||
- (NSNumber *)doScan;
|
||||
|
||||
- (NSArray *)selectedPowerMarkerNodePaths;
|
||||
- (void)selectPowerMarkerNodePaths:(NSArray *)aIndexPaths;
|
||||
- (NSArray *)selectedResultNodePaths;
|
||||
- (void)selectResultNodePaths:(NSArray *)aIndexPaths;
|
||||
|
||||
- (void)toggleSelectedMark;
|
||||
- (void)markAll;
|
||||
- (void)markInvert;
|
||||
- (void)markNone;
|
||||
|
||||
- (void)addSelectedToIgnoreList;
|
||||
- (void)refreshDetailsWithSelected;
|
||||
- (void)removeSelected;
|
||||
- (void)openSelected;
|
||||
- (NSNumber *)renameSelected:(NSString *)aNewName;
|
||||
- (void)revealSelected;
|
||||
- (void)makeSelectedReference;
|
||||
- (void)applyFilter:(NSString *)filter;
|
||||
|
||||
- (void)sortGroupsBy:(NSNumber *)aIdentifier ascending:(NSNumber *)aAscending;
|
||||
- (void)sortDupesBy:(NSNumber *)aIdentifier ascending:(NSNumber *)aAscending;
|
||||
|
||||
- (void)copyOrMove:(NSNumber *)aCopy markedTo:(NSString *)destination recreatePath:(NSNumber *)aRecreateType;
|
||||
- (void)deleteMarked;
|
||||
- (void)removeMarked;
|
||||
|
||||
//Data
|
||||
- (NSNumber *)getIgnoreListCount;
|
||||
- (NSNumber *)getMarkCount;
|
||||
- (NSString *)getStatLine;
|
||||
- (NSNumber *)getOperationalErrorCount;
|
||||
|
||||
//Scanning options
|
||||
- (void)setMinMatchPercentage:(NSNumber *)percentage;
|
||||
- (void)setMixFileKind:(NSNumber *)mix_file_kind;
|
||||
- (void)setDisplayDeltaValues:(NSNumber *)display_delta_values;
|
||||
- (void)setEscapeFilterRegexp:(NSNumber *)escape_filter_regexp;
|
||||
- (void)setRemoveEmptyFolders:(NSNumber *)remove_empty_folders;
|
||||
- (void)setSizeThreshold:(int)size_threshold;
|
||||
@end
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "Outline.h"
|
||||
#import "PyDupeGuru.h"
|
||||
|
||||
@interface MatchesView : OutlineView
|
||||
- (void)keyDown:(NSEvent *)theEvent;
|
||||
@end
|
||||
|
||||
@interface ResultWindowBase : NSWindowController
|
||||
{
|
||||
@protected
|
||||
IBOutlet PyDupeGuruBase *py;
|
||||
IBOutlet id app;
|
||||
IBOutlet NSSegmentedControl *deltaSwitch;
|
||||
IBOutlet MatchesView *matches;
|
||||
IBOutlet NSSegmentedControl *pmSwitch;
|
||||
IBOutlet NSTextField *stats;
|
||||
IBOutlet NSMenu *columnsMenu;
|
||||
|
||||
BOOL _powerMode;
|
||||
BOOL _displayDelta;
|
||||
NSMutableArray *_resultColumns;
|
||||
NSWindowController *preferencesPanel;
|
||||
}
|
||||
/* Helpers */
|
||||
- (void)fillColumnsMenu;
|
||||
- (NSTableColumn *)getColumnForIdentifier:(int)aIdentifier title:(NSString *)aTitle width:(int)aWidth refCol:(NSTableColumn *)aColumn;
|
||||
- (NSArray *)getColumnsOrder;
|
||||
- (NSDictionary *)getColumnsWidth;
|
||||
- (NSArray *)getSelected:(BOOL)aDupesOnly;
|
||||
- (NSArray *)getSelectedPaths:(BOOL)aDupesOnly;
|
||||
- (void)initResultColumns;
|
||||
- (void)updatePySelection;
|
||||
- (void)performPySelection:(NSArray *)aIndexPaths;
|
||||
- (void)refreshStats;
|
||||
- (void)restoreColumnsPosition:(NSArray *)aColumnsOrder widths:(NSDictionary *)aColumnsWidth;
|
||||
|
||||
/* Actions */
|
||||
- (IBAction)changeDelta:(id)sender;
|
||||
- (IBAction)changePowerMarker:(id)sender;
|
||||
- (IBAction)copyMarked:(id)sender;
|
||||
- (IBAction)deleteMarked:(id)sender;
|
||||
- (IBAction)expandAll:(id)sender;
|
||||
- (IBAction)exportToXHTML:(id)sender;
|
||||
- (IBAction)moveMarked:(id)sender;
|
||||
- (IBAction)resetColumnsToDefault:(id)sender;
|
||||
- (IBAction)showPreferencesPanel:(id)sender;
|
||||
- (IBAction)switchSelected:(id)sender;
|
||||
- (IBAction)toggleColumn:(id)sender;
|
||||
- (IBAction)toggleDetailsPanel:(id)sender;
|
||||
- (IBAction)togglePowerMarker:(id)sender;
|
||||
|
||||
/* Notifications */
|
||||
- (void)jobCompleted:(NSNotification *)aNotification;
|
||||
@end
|
||||
@@ -1,464 +0,0 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
*/
|
||||
|
||||
#import "ResultWindow.h"
|
||||
#import "Dialogs.h"
|
||||
#import "ProgressController.h"
|
||||
#import "Utils.h"
|
||||
#import "RegistrationInterface.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "Consts.h"
|
||||
|
||||
@implementation MatchesView
|
||||
- (void)keyDown:(NSEvent *)theEvent
|
||||
{
|
||||
unichar key = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
||||
// get flags and strip the lower 16 (device dependant) bits
|
||||
unsigned int flags = ( [theEvent modifierFlags] & 0x00FF );
|
||||
if (((key == NSDeleteFunctionKey) || (key == NSDeleteCharacter)) && (flags == 0))
|
||||
[self sendAction:@selector(removeSelected:) to:[self delegate]];
|
||||
else
|
||||
if ((key == 0x20) && (flags == 0)) // Space
|
||||
[self sendAction:@selector(markSelected:) to:[self delegate]];
|
||||
else
|
||||
[super keyDown:theEvent];
|
||||
}
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
|
||||
{
|
||||
if (![[tableColumn identifier] isEqual:@"0"])
|
||||
return; //We only want to cover renames.
|
||||
OVNode *node = item;
|
||||
NSString *oldName = [[node buffer] objectAtIndex:0];
|
||||
NSString *newName = object;
|
||||
if (![newName isEqual:oldName])
|
||||
{
|
||||
BOOL renamed = n2b([(PyDupeGuruBase *)py renameSelected:newName]);
|
||||
if (renamed)
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
||||
else
|
||||
[Dialogs showMessage:[NSString stringWithFormat:@"The name '%@' already exists.",newName]];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ResultWindowBase
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[self window];
|
||||
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
||||
[self initResultColumns];
|
||||
[self fillColumnsMenu];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(registrationRequired:) name:RegistrationRequired object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobCompleted:) name:JobCompletedNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobStarted:) name:JobStarted object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobInProgress:) name:JobInProgress object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsChanged:) name:ResultsChangedNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsUpdated:) name:ResultsUpdatedNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[preferencesPanel release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
- (void)fillColumnsMenu
|
||||
{
|
||||
// The columns menu is supposed to be empty and initResultColumns must have been called
|
||||
for (NSTableColumn *col in _resultColumns)
|
||||
{
|
||||
NSMenuItem *mi = [columnsMenu addItemWithTitle:[[col headerCell] stringValue] action:@selector(toggleColumn:) keyEquivalent:@""];
|
||||
[mi setTag:[[col identifier] integerValue]];
|
||||
[mi setTarget:self];
|
||||
if ([[matches tableColumns] containsObject:col])
|
||||
[mi setState:NSOnState];
|
||||
}
|
||||
[columnsMenu addItem:[NSMenuItem separatorItem]];
|
||||
NSMenuItem *mi = [columnsMenu addItemWithTitle:@"Reset to Default" action:@selector(resetColumnsToDefault:) keyEquivalent:@""];
|
||||
[mi setTarget:self];
|
||||
}
|
||||
|
||||
- (NSTableColumn *)getColumnForIdentifier:(int)aIdentifier title:(NSString *)aTitle width:(int)aWidth refCol:(NSTableColumn *)aColumn
|
||||
{
|
||||
NSNumber *n = [NSNumber numberWithInt:aIdentifier];
|
||||
NSTableColumn *col = [[NSTableColumn alloc] initWithIdentifier:[n stringValue]];
|
||||
[col setWidth:aWidth];
|
||||
[col setEditable:NO];
|
||||
[[col dataCell] setFont:[[aColumn dataCell] font]];
|
||||
[[col headerCell] setStringValue:aTitle];
|
||||
[col setResizingMask:NSTableColumnUserResizingMask];
|
||||
[col setSortDescriptorPrototype:[[NSSortDescriptor alloc] initWithKey:[n stringValue] ascending:YES]];
|
||||
return col;
|
||||
}
|
||||
|
||||
//Returns an array of identifiers, in order.
|
||||
- (NSArray *)getColumnsOrder
|
||||
{
|
||||
NSTableColumn *col;
|
||||
NSString *colId;
|
||||
NSMutableArray *result = [NSMutableArray array];
|
||||
NSEnumerator *e = [[matches tableColumns] objectEnumerator];
|
||||
while (col = [e nextObject])
|
||||
{
|
||||
colId = [col identifier];
|
||||
[result addObject:colId];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSDictionary *)getColumnsWidth
|
||||
{
|
||||
NSMutableDictionary *result = [NSMutableDictionary dictionary];
|
||||
NSTableColumn *col;
|
||||
NSString *colId;
|
||||
NSNumber *width;
|
||||
NSEnumerator *e = [[matches tableColumns] objectEnumerator];
|
||||
while (col = [e nextObject])
|
||||
{
|
||||
colId = [col identifier];
|
||||
width = [NSNumber numberWithFloat:[col width]];
|
||||
[result setObject:width forKey:colId];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSArray *)getSelected:(BOOL)aDupesOnly
|
||||
{
|
||||
if (_powerMode)
|
||||
aDupesOnly = NO;
|
||||
NSIndexSet *indexes = [matches selectedRowIndexes];
|
||||
NSMutableArray *nodeList = [NSMutableArray array];
|
||||
OVNode *node;
|
||||
int i = [indexes firstIndex];
|
||||
while (i != NSNotFound)
|
||||
{
|
||||
node = [matches itemAtRow:i];
|
||||
if (!aDupesOnly || ([node level] > 1))
|
||||
[nodeList addObject:node];
|
||||
i = [indexes indexGreaterThanIndex:i];
|
||||
}
|
||||
return nodeList;
|
||||
}
|
||||
|
||||
- (NSArray *)getSelectedPaths:(BOOL)aDupesOnly
|
||||
{
|
||||
NSMutableArray *r = [NSMutableArray array];
|
||||
NSArray *selected = [self getSelected:aDupesOnly];
|
||||
NSEnumerator *e = [selected objectEnumerator];
|
||||
OVNode *node;
|
||||
while (node = [e nextObject])
|
||||
[r addObject:p2a([node indexPath])];
|
||||
return r;
|
||||
}
|
||||
|
||||
- (void)initResultColumns
|
||||
{
|
||||
// Virtual
|
||||
}
|
||||
|
||||
- (void)restoreColumnsPosition:(NSArray *)aColumnsOrder widths:(NSDictionary *)aColumnsWidth
|
||||
{
|
||||
NSTableColumn *col;
|
||||
NSString *colId;
|
||||
NSNumber *width;
|
||||
NSMenuItem *mi;
|
||||
//Remove all columns
|
||||
NSEnumerator *e = [[columnsMenu itemArray] objectEnumerator];
|
||||
while (mi = [e nextObject])
|
||||
{
|
||||
if ([mi state] == NSOnState)
|
||||
[self toggleColumn:mi];
|
||||
}
|
||||
//Add columns and set widths
|
||||
e = [aColumnsOrder objectEnumerator];
|
||||
while (colId = [e nextObject])
|
||||
{
|
||||
if (![colId isEqual:@"mark"])
|
||||
{
|
||||
col = [_resultColumns objectAtIndex:[colId intValue]];
|
||||
width = [aColumnsWidth objectForKey:[col identifier]];
|
||||
mi = [columnsMenu itemWithTag:[colId intValue]];
|
||||
if (width)
|
||||
[col setWidth:[width floatValue]];
|
||||
[self toggleColumn:mi];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updatePySelection
|
||||
{
|
||||
NSArray *selection;
|
||||
if (_powerMode)
|
||||
selection = [py selectedPowerMarkerNodePaths];
|
||||
else
|
||||
selection = [py selectedResultNodePaths];
|
||||
[matches selectNodePaths:selection];
|
||||
}
|
||||
|
||||
- (void)performPySelection:(NSArray *)aIndexPaths
|
||||
{
|
||||
if (_powerMode)
|
||||
[py selectPowerMarkerNodePaths:aIndexPaths];
|
||||
else
|
||||
[py selectResultNodePaths:aIndexPaths];
|
||||
}
|
||||
|
||||
- (void)refreshStats
|
||||
{
|
||||
[stats setStringValue:[py getStatLine]];
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
- (IBAction)changeDelta:(id)sender
|
||||
{
|
||||
_displayDelta = [deltaSwitch selectedSegment] == 1;
|
||||
[py setDisplayDeltaValues:b2n(_displayDelta)];
|
||||
[matches reloadData];
|
||||
[self expandAll:nil];
|
||||
}
|
||||
|
||||
- (IBAction)changePowerMarker:(id)sender
|
||||
{
|
||||
_powerMode = [pmSwitch selectedSegment] == 1;
|
||||
if (_powerMode)
|
||||
[matches setTag:2];
|
||||
else
|
||||
[matches setTag:0];
|
||||
[self expandAll:nil];
|
||||
[self outlineView:matches didClickTableColumn:nil];
|
||||
[self updatePySelection];
|
||||
}
|
||||
|
||||
- (IBAction)copyMarked:(id)sender
|
||||
{
|
||||
int mark_count = [[py getMarkCount] intValue];
|
||||
if (!mark_count)
|
||||
return;
|
||||
NSOpenPanel *op = [NSOpenPanel openPanel];
|
||||
[op setCanChooseFiles:NO];
|
||||
[op setCanChooseDirectories:YES];
|
||||
[op setCanCreateDirectories:YES];
|
||||
[op setAllowsMultipleSelection:NO];
|
||||
[op setTitle:@"Select a directory to copy marked files to"];
|
||||
if ([op runModalForTypes:nil] == NSOKButton)
|
||||
{
|
||||
NSString *directory = [[op filenames] objectAtIndex:0];
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
[py copyOrMove:b2n(YES) markedTo:directory recreatePath:[ud objectForKey:@"recreatePathType"]];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)deleteMarked:(id)sender
|
||||
{
|
||||
int mark_count = [[py getMarkCount] intValue];
|
||||
if (!mark_count)
|
||||
return;
|
||||
if ([Dialogs askYesNo:[NSString stringWithFormat:@"You are about to send %d files to Trash. Continue?",mark_count]] == NSAlertSecondButtonReturn) // NO
|
||||
return;
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
[py setRemoveEmptyFolders:[ud objectForKey:@"removeEmptyFolders"]];
|
||||
[py deleteMarked];
|
||||
}
|
||||
|
||||
- (IBAction)expandAll:(id)sender
|
||||
{
|
||||
for (int i=0;i < [matches numberOfRows];i++)
|
||||
[matches expandItem:[matches itemAtRow:i]];
|
||||
}
|
||||
|
||||
- (IBAction)exportToXHTML:(id)sender
|
||||
{
|
||||
NSString *exported = [py exportToXHTMLwithColumns:[self getColumnsOrder]];
|
||||
[[NSWorkspace sharedWorkspace] openFile:exported];
|
||||
}
|
||||
|
||||
- (IBAction)moveMarked:(id)sender
|
||||
{
|
||||
int mark_count = [[py getMarkCount] intValue];
|
||||
if (!mark_count)
|
||||
return;
|
||||
NSOpenPanel *op = [NSOpenPanel openPanel];
|
||||
[op setCanChooseFiles:NO];
|
||||
[op setCanChooseDirectories:YES];
|
||||
[op setCanCreateDirectories:YES];
|
||||
[op setAllowsMultipleSelection:NO];
|
||||
[op setTitle:@"Select a directory to move marked files to"];
|
||||
if ([op runModalForTypes:nil] == NSOKButton)
|
||||
{
|
||||
NSString *directory = [[op filenames] objectAtIndex:0];
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
[py setRemoveEmptyFolders:[ud objectForKey:@"removeEmptyFolders"]];
|
||||
[py copyOrMove:b2n(NO) markedTo:directory recreatePath:[ud objectForKey:@"recreatePathType"]];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)resetColumnsToDefault:(id)sender
|
||||
{
|
||||
// Virtual
|
||||
}
|
||||
|
||||
- (IBAction)showPreferencesPanel:(id)sender
|
||||
{
|
||||
[preferencesPanel showWindow:sender];
|
||||
}
|
||||
|
||||
- (IBAction)switchSelected:(id)sender
|
||||
{
|
||||
// It might look like a complicated way to get the length of the current dupe list on the py side
|
||||
// but after a lot of fussing around, believe it or not, it actually is.
|
||||
int matchesTag = _powerMode ? 2 : 0;
|
||||
int startLen = [[py getOutlineView:matchesTag childCountsForPath:[NSArray array]] count];
|
||||
[self performPySelection:[self getSelectedPaths:YES]];
|
||||
[py makeSelectedReference];
|
||||
// In some cases (when in a filtered view in Power Marker mode, it's possible that the demoted
|
||||
// ref is not a part of the filter, making the table smaller. In those cases, we want to do a
|
||||
// complete reload of the table to avoid a crash.
|
||||
if ([[py getOutlineView:matchesTag childCountsForPath:[NSArray array]] count] == startLen)
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsUpdatedNotification object:self];
|
||||
else
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
||||
}
|
||||
|
||||
- (IBAction)toggleColumn:(id)sender
|
||||
{
|
||||
NSMenuItem *mi = sender;
|
||||
NSString *colId = [NSString stringWithFormat:@"%d",[mi tag]];
|
||||
NSTableColumn *col = [matches tableColumnWithIdentifier:colId];
|
||||
if (col == nil)
|
||||
{
|
||||
//Add Column
|
||||
col = [_resultColumns objectAtIndex:[mi tag]];
|
||||
[matches addTableColumn:col];
|
||||
[mi setState:NSOnState];
|
||||
}
|
||||
else
|
||||
{
|
||||
//Remove column
|
||||
[matches removeTableColumn:col];
|
||||
[mi setState:NSOffState];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)toggleDetailsPanel:(id)sender
|
||||
{
|
||||
[[(AppDelegateBase *)app detailsPanel] toggleVisibility];
|
||||
}
|
||||
|
||||
- (IBAction)togglePowerMarker:(id)sender
|
||||
{
|
||||
if ([pmSwitch selectedSegment] == 1)
|
||||
[pmSwitch setSelectedSegment:0];
|
||||
else
|
||||
[pmSwitch setSelectedSegment:1];
|
||||
[self changePowerMarker:sender];
|
||||
}
|
||||
|
||||
/* Delegate */
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)outlineView didClickTableColumn:(NSTableColumn *)tableColumn
|
||||
{
|
||||
if ([[outlineView sortDescriptors] count] < 1)
|
||||
return;
|
||||
NSSortDescriptor *sd = [[outlineView sortDescriptors] objectAtIndex:0];
|
||||
if (_powerMode)
|
||||
[py sortDupesBy:i2n([[sd key] intValue]) ascending:b2n([sd ascending])];
|
||||
else
|
||||
[py sortGroupsBy:i2n([[sd key] intValue]) ascending:b2n([sd ascending])];
|
||||
[matches reloadData];
|
||||
[self expandAll:nil];
|
||||
}
|
||||
|
||||
/* Notifications */
|
||||
- (void)windowWillClose:(NSNotification *)aNotification
|
||||
{
|
||||
[NSApp hide:NSApp];
|
||||
}
|
||||
|
||||
- (void)jobCompleted:(NSNotification *)aNotification
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
||||
int r = n2i([py getOperationalErrorCount]);
|
||||
id lastAction = [[ProgressController mainProgressController] jobId];
|
||||
if ([lastAction isEqualTo:jobCopy])
|
||||
{
|
||||
if (r > 0)
|
||||
[Dialogs showMessage:[NSString stringWithFormat:@"%d file(s) couldn't be copied.",r]];
|
||||
else
|
||||
[Dialogs showMessage:@"All marked files were copied sucessfully."];
|
||||
}
|
||||
if ([lastAction isEqualTo:jobMove])
|
||||
{
|
||||
if (r > 0)
|
||||
[Dialogs showMessage:[NSString stringWithFormat:@"%d file(s) couldn't be moved. They were kept in the results, and still are marked.",r]];
|
||||
else
|
||||
[Dialogs showMessage:@"All marked files were moved sucessfully."];
|
||||
}
|
||||
if ([lastAction isEqualTo:jobDelete])
|
||||
{
|
||||
if (r > 0)
|
||||
{
|
||||
NSString *msg = @"%d file(s) couldn't be sent to Trash. They were kept in the results, "\
|
||||
"and still are marked. See the F.A.Q. section in the help file for details.";
|
||||
[Dialogs showMessage:[NSString stringWithFormat:msg,r]];
|
||||
}
|
||||
else
|
||||
[Dialogs showMessage:@"All marked files were sucessfully sent to Trash."];
|
||||
}
|
||||
// Re-activate toolbar items right after the progress bar stops showing instead of waiting until
|
||||
// a mouse-over is performed
|
||||
[[[self window] toolbar] validateVisibleItems];
|
||||
}
|
||||
|
||||
- (void)jobInProgress:(NSNotification *)aNotification
|
||||
{
|
||||
[Dialogs showMessage:@"A previous action is still hanging in there. You can't start a new one yet. Wait a few seconds, then try again."];
|
||||
}
|
||||
|
||||
- (void)jobStarted:(NSNotification *)aNotification
|
||||
{
|
||||
NSDictionary *ui = [aNotification userInfo];
|
||||
NSString *desc = [ui valueForKey:@"desc"];
|
||||
[[ProgressController mainProgressController] setJobDesc:desc];
|
||||
NSString *jobid = [ui valueForKey:@"jobid"];
|
||||
// NSLog(jobid);
|
||||
[[ProgressController mainProgressController] setJobId:jobid];
|
||||
[[ProgressController mainProgressController] showSheetForParent:[self window]];
|
||||
}
|
||||
|
||||
- (void)registrationRequired:(NSNotification *)aNotification
|
||||
{
|
||||
NSString *msg = @"This is a demo version, which only allows you 10 delete/copy/move actions per session. You cannot continue.";
|
||||
[Dialogs showMessage:msg];
|
||||
}
|
||||
|
||||
- (void)resultsChanged:(NSNotification *)aNotification
|
||||
{
|
||||
[matches reloadData];
|
||||
[self expandAll:nil];
|
||||
[self outlineViewSelectionDidChange:nil];
|
||||
[self refreshStats];
|
||||
}
|
||||
|
||||
- (void)resultsUpdated:(NSNotification *)aNotification
|
||||
{
|
||||
[matches invalidateBuffers];
|
||||
[matches invalidateMarkings];
|
||||
}
|
||||
|
||||
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
|
||||
{
|
||||
return ![[ProgressController mainProgressController] isShown];
|
||||
}
|
||||
|
||||
- (BOOL)validateMenuItem:(NSMenuItem *)item
|
||||
{
|
||||
return ![[ProgressController mainProgressController] isShown];
|
||||
}
|
||||
@end
|
||||
File diff suppressed because it is too large
Load Diff
249
base/py/app.py
249
base/py/app.py
@@ -1,249 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2006/11/11
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import os.path as op
|
||||
import logging
|
||||
|
||||
from hsutil import io, files
|
||||
from hsutil.path import Path
|
||||
from hsutil.reg import RegistrableApplication, RegistrationRequired
|
||||
from hsutil.misc import flatten, first
|
||||
from hsutil.str import escape
|
||||
|
||||
from . import directories, results, scanner, export, fs
|
||||
|
||||
JOB_SCAN = 'job_scan'
|
||||
JOB_LOAD = 'job_load'
|
||||
JOB_MOVE = 'job_move'
|
||||
JOB_COPY = 'job_copy'
|
||||
JOB_DELETE = 'job_delete'
|
||||
|
||||
class NoScannableFileError(Exception):
|
||||
pass
|
||||
|
||||
class AllFilesAreRefError(Exception):
|
||||
pass
|
||||
|
||||
class DupeGuru(RegistrableApplication):
|
||||
def __init__(self, data_module, appdata, appid):
|
||||
RegistrableApplication.__init__(self, appid)
|
||||
self.appdata = appdata
|
||||
if not op.exists(self.appdata):
|
||||
os.makedirs(self.appdata)
|
||||
self.data = data_module
|
||||
self.directories = directories.Directories()
|
||||
self.results = results.Results(data_module)
|
||||
self.scanner = scanner.Scanner()
|
||||
self.action_count = 0
|
||||
self.last_op_error_count = 0
|
||||
self.options = {
|
||||
'escape_filter_regexp': True,
|
||||
'clean_empty_dirs': False,
|
||||
}
|
||||
|
||||
def _demo_check(self):
|
||||
if self.registered:
|
||||
return
|
||||
count = self.results.mark_count
|
||||
if count + self.action_count > 10:
|
||||
raise RegistrationRequired()
|
||||
else:
|
||||
self.action_count += count
|
||||
|
||||
def _do_delete(self, j):
|
||||
def op(dupe):
|
||||
j.add_progress()
|
||||
return self._do_delete_dupe(dupe)
|
||||
|
||||
j.start_job(self.results.mark_count)
|
||||
self.last_op_error_count = self.results.perform_on_marked(op, True)
|
||||
|
||||
def _do_delete_dupe(self, dupe):
|
||||
if not io.exists(dupe.path):
|
||||
return True
|
||||
self._recycle_dupe(dupe)
|
||||
self.clean_empty_dirs(dupe.path[:-1])
|
||||
if not io.exists(dupe.path):
|
||||
return True
|
||||
logging.warning("Could not send {0} to trash.".format(unicode(dupe.path)))
|
||||
return False
|
||||
|
||||
def _do_load(self, j):
|
||||
self.directories.load_from_file(op.join(self.appdata, 'last_directories.xml'))
|
||||
j = j.start_subjob([1, 9])
|
||||
self.results.load_from_xml(op.join(self.appdata, 'last_results.xml'), self._get_file, j)
|
||||
files = flatten(g[:] for g in self.results.groups)
|
||||
for file in j.iter_with_progress(files, 'Reading metadata %d/%d'):
|
||||
file._read_all_info(attrnames=self.data.METADATA_TO_READ)
|
||||
|
||||
def _get_display_info(self, dupe, group, delta=False):
|
||||
if (dupe is None) or (group is None):
|
||||
return ['---'] * len(self.data.COLUMNS)
|
||||
try:
|
||||
return self.data.GetDisplayInfo(dupe, group, delta)
|
||||
except Exception as e:
|
||||
logging.warning("Exception on GetDisplayInfo for %s: %s", unicode(dupe.path), unicode(e))
|
||||
return ['---'] * len(self.data.COLUMNS)
|
||||
|
||||
def _get_file(self, str_path):
|
||||
path = Path(str_path)
|
||||
return fs.get_file(path, self.directories.fileclasses)
|
||||
|
||||
@staticmethod
|
||||
def _recycle_dupe(dupe):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _start_job(self, jobid, func):
|
||||
# func(j)
|
||||
raise NotImplementedError()
|
||||
|
||||
def add_directory(self, d):
|
||||
try:
|
||||
self.directories.add_path(Path(d))
|
||||
return 0
|
||||
except directories.AlreadyThereError:
|
||||
return 1
|
||||
except directories.InvalidPathError:
|
||||
return 2
|
||||
|
||||
def add_to_ignore_list(self, dupe):
|
||||
g = self.results.get_group_of_duplicate(dupe)
|
||||
for other in g:
|
||||
if other is not dupe:
|
||||
self.scanner.ignore_list.Ignore(unicode(other.path), unicode(dupe.path))
|
||||
|
||||
def apply_filter(self, filter):
|
||||
self.results.apply_filter(None)
|
||||
if self.options['escape_filter_regexp']:
|
||||
filter = escape(filter, '()[]\\.|+?^')
|
||||
filter = escape(filter, '*', '.')
|
||||
self.results.apply_filter(filter)
|
||||
|
||||
def clean_empty_dirs(self, path):
|
||||
if self.options['clean_empty_dirs']:
|
||||
while files.delete_if_empty(path, ['.DS_Store']):
|
||||
path = path[:-1]
|
||||
|
||||
def copy_or_move(self, dupe, copy, destination, dest_type):
|
||||
"""
|
||||
copy: True = Copy False = Move
|
||||
destination: string.
|
||||
dest_type: 0 = right in destination.
|
||||
1 = relative re-creation.
|
||||
2 = absolute re-creation.
|
||||
"""
|
||||
source_path = dupe.path
|
||||
location_path = first(p for p in self.directories if dupe.path in p)
|
||||
dest_path = Path(destination)
|
||||
if dest_type == 2:
|
||||
dest_path = dest_path + source_path[1:-1] #Remove drive letter and filename
|
||||
elif dest_type == 1:
|
||||
dest_path = dest_path + source_path[location_path:-1]
|
||||
try:
|
||||
if not io.exists(dest_path):
|
||||
io.makedirs(dest_path)
|
||||
if copy:
|
||||
files.copy(source_path, dest_path)
|
||||
else:
|
||||
files.move(source_path, dest_path)
|
||||
self.clean_empty_dirs(source_path[:-1])
|
||||
except EnvironmentError as e:
|
||||
operation = 'Copy' if copy else 'Move'
|
||||
logging.warning('%s operation failed on %s. Error: %s' % (operation, unicode(dupe.path), unicode(e)))
|
||||
return False
|
||||
return True
|
||||
|
||||
def copy_or_move_marked(self, copy, destination, recreate_path):
|
||||
def do(j):
|
||||
def op(dupe):
|
||||
j.add_progress()
|
||||
return self.copy_or_move(dupe, copy, destination, recreate_path)
|
||||
|
||||
j.start_job(self.results.mark_count)
|
||||
self.last_op_error_count = self.results.perform_on_marked(op, not copy)
|
||||
|
||||
self._demo_check()
|
||||
jobid = JOB_COPY if copy else JOB_MOVE
|
||||
self._start_job(jobid, do)
|
||||
|
||||
def delete_marked(self):
|
||||
self._demo_check()
|
||||
self._start_job(JOB_DELETE, self._do_delete)
|
||||
|
||||
def export_to_xhtml(self, column_ids):
|
||||
column_ids = [colid for colid in column_ids if colid.isdigit()]
|
||||
column_ids = map(int, column_ids)
|
||||
column_ids.sort()
|
||||
colnames = [col['display'] for i, col in enumerate(self.data.COLUMNS) if i in column_ids]
|
||||
rows = []
|
||||
for group in self.results.groups:
|
||||
for dupe in group:
|
||||
data = self._get_display_info(dupe, group)
|
||||
row = [data[colid] for colid in column_ids]
|
||||
row.insert(0, dupe is not group.ref)
|
||||
rows.append(row)
|
||||
return export.export_to_xhtml(colnames, rows)
|
||||
|
||||
def load(self):
|
||||
self._start_job(JOB_LOAD, self._do_load)
|
||||
self.load_ignore_list()
|
||||
|
||||
def load_ignore_list(self):
|
||||
p = op.join(self.appdata, 'ignore_list.xml')
|
||||
self.scanner.ignore_list.load_from_xml(p)
|
||||
|
||||
def make_reference(self, duplicates):
|
||||
changed_groups = set()
|
||||
for dupe in duplicates:
|
||||
g = self.results.get_group_of_duplicate(dupe)
|
||||
if g not in changed_groups:
|
||||
self.results.make_ref(dupe)
|
||||
changed_groups.add(g)
|
||||
|
||||
def save(self):
|
||||
try:
|
||||
self.directories.save_to_file(op.join(self.appdata, 'last_directories.xml'))
|
||||
self.results.save_to_xml(op.join(self.appdata, 'last_results.xml'))
|
||||
except LookupError:
|
||||
# This is that weird issue from #39 that sometimes happens when auto-updating with
|
||||
# Sparkle. Just ignore it.
|
||||
pass
|
||||
|
||||
def save_ignore_list(self):
|
||||
p = op.join(self.appdata, 'ignore_list.xml')
|
||||
self.scanner.ignore_list.save_to_xml(p)
|
||||
|
||||
def start_scanning(self):
|
||||
def do(j):
|
||||
j.set_progress(0, 'Collecting files to scan')
|
||||
files = list(self.directories.get_files())
|
||||
logging.info('Scanning %d files' % len(files))
|
||||
self.results.groups = self.scanner.GetDupeGroups(files, j)
|
||||
|
||||
files = self.directories.get_files()
|
||||
first_file = first(files)
|
||||
if first_file is None:
|
||||
raise NoScannableFileError()
|
||||
if first_file.is_ref and all(f.is_ref for f in files):
|
||||
raise AllFilesAreRefError()
|
||||
self.results.groups = []
|
||||
self._start_job(JOB_SCAN, do)
|
||||
|
||||
#--- Properties
|
||||
@property
|
||||
def stat_line(self):
|
||||
result = self.results.stat_line
|
||||
if self.scanner.discarded_file_count:
|
||||
result = '%s (%d discarded)' % (result, self.scanner.discarded_file_count)
|
||||
return result
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2006/11/11
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import objc
|
||||
from Foundation import *
|
||||
from AppKit import *
|
||||
import logging
|
||||
import os.path as op
|
||||
|
||||
from hsutil import io, cocoa, job
|
||||
from hsutil.cocoa import install_exception_hook
|
||||
from hsutil.misc import stripnone
|
||||
from hsutil.reg import RegistrationRequired
|
||||
|
||||
from . import app, fs
|
||||
|
||||
JOBID2TITLE = {
|
||||
app.JOB_SCAN: "Scanning for duplicates",
|
||||
app.JOB_LOAD: "Loading",
|
||||
app.JOB_MOVE: "Moving",
|
||||
app.JOB_COPY: "Copying",
|
||||
app.JOB_DELETE: "Sending to Trash",
|
||||
}
|
||||
|
||||
def demo_method(method):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return method(self, *args, **kwargs)
|
||||
except RegistrationRequired:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName_object_('RegistrationRequired', self)
|
||||
|
||||
return wrapper
|
||||
|
||||
class DupeGuru(app.DupeGuru):
|
||||
def __init__(self, data_module, appdata_subdir, appid):
|
||||
LOGGING_LEVEL = logging.DEBUG if NSUserDefaults.standardUserDefaults().boolForKey_('debug') else logging.WARNING
|
||||
logging.basicConfig(level=LOGGING_LEVEL, format='%(levelname)s %(message)s')
|
||||
logging.debug('started in debug mode')
|
||||
install_exception_hook()
|
||||
appsupport = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)[0]
|
||||
appdata = op.join(appsupport, appdata_subdir)
|
||||
app.DupeGuru.__init__(self, data_module, appdata, appid)
|
||||
self.progress = cocoa.ThreadedJobPerformer()
|
||||
self.display_delta_values = False
|
||||
self.selected_dupes = []
|
||||
self.RefreshDetailsTable(None,None)
|
||||
|
||||
#--- Override
|
||||
@staticmethod
|
||||
def _recycle_dupe(dupe):
|
||||
directory = unicode(dupe.path[:-1])
|
||||
filename = dupe.name
|
||||
if objc.__version__ == '1.4': # For a while, we have to support this.
|
||||
result, tag = NSWorkspace.sharedWorkspace().performFileOperation_source_destination_files_tag_(
|
||||
NSWorkspaceRecycleOperation, directory, '', [filename])
|
||||
else:
|
||||
result, tag = NSWorkspace.sharedWorkspace().performFileOperation_source_destination_files_tag_(
|
||||
NSWorkspaceRecycleOperation, directory, '', [filename], None)
|
||||
|
||||
def _start_job(self, jobid, func):
|
||||
try:
|
||||
j = self.progress.create_job()
|
||||
self.progress.run_threaded(func, args=(j, ))
|
||||
except job.JobInProgressError:
|
||||
NSNotificationCenter.defaultCenter().postNotificationName_object_('JobInProgress', self)
|
||||
else:
|
||||
ud = {'desc': JOBID2TITLE[jobid], 'jobid':jobid}
|
||||
NSNotificationCenter.defaultCenter().postNotificationName_object_userInfo_('JobStarted', self, ud)
|
||||
|
||||
#---Helpers
|
||||
def GetObjects(self,node_path):
|
||||
#returns a tuple g,d
|
||||
try:
|
||||
g = self.results.groups[node_path[0]]
|
||||
if len(node_path) == 2:
|
||||
return (g,self.results.groups[node_path[0]].dupes[node_path[1]])
|
||||
else:
|
||||
return (g,None)
|
||||
except IndexError:
|
||||
return (None,None)
|
||||
|
||||
def get_folder_path(self, node_path, curr_path=None):
|
||||
if not node_path:
|
||||
return curr_path
|
||||
current_index = node_path[0]
|
||||
if curr_path is None:
|
||||
curr_path = self.directories[current_index]
|
||||
else:
|
||||
curr_path = self.directories.get_subfolders(curr_path)[current_index]
|
||||
return self.get_folder_path(node_path[1:], curr_path)
|
||||
|
||||
def RefreshDetailsTable(self,dupe,group):
|
||||
l1 = self._get_display_info(dupe, group, False)
|
||||
# we don't want the two sides of the table to display the stats for the same file
|
||||
ref = group.ref if group is not None and group.ref is not dupe else None
|
||||
l2 = self._get_display_info(ref, group, False)
|
||||
names = [c['display'] for c in self.data.COLUMNS]
|
||||
self.details_table = zip(names,l1,l2)
|
||||
|
||||
#---Public
|
||||
def AddSelectedToIgnoreList(self):
|
||||
for dupe in self.selected_dupes:
|
||||
self.add_to_ignore_list(dupe)
|
||||
|
||||
copy_or_move_marked = demo_method(app.DupeGuru.copy_or_move_marked)
|
||||
delete_marked = demo_method(app.DupeGuru.delete_marked)
|
||||
|
||||
def MakeSelectedReference(self):
|
||||
self.make_reference(self.selected_dupes)
|
||||
|
||||
def OpenSelected(self):
|
||||
if self.selected_dupes:
|
||||
path = unicode(self.selected_dupes[0].path)
|
||||
NSWorkspace.sharedWorkspace().openFile_(path)
|
||||
|
||||
def PurgeIgnoreList(self):
|
||||
self.scanner.ignore_list.Filter(lambda f,s:op.exists(f) and op.exists(s))
|
||||
|
||||
def RefreshDetailsWithSelected(self):
|
||||
if self.selected_dupes:
|
||||
self.RefreshDetailsTable(
|
||||
self.selected_dupes[0],
|
||||
self.results.get_group_of_duplicate(self.selected_dupes[0])
|
||||
)
|
||||
else:
|
||||
self.RefreshDetailsTable(None,None)
|
||||
|
||||
def RemoveDirectory(self,index):
|
||||
try:
|
||||
del self.directories[index]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def RemoveSelected(self):
|
||||
self.results.remove_duplicates(self.selected_dupes)
|
||||
|
||||
def RenameSelected(self, newname):
|
||||
try:
|
||||
d = self.selected_dupes[0]
|
||||
d.rename(newname)
|
||||
return True
|
||||
except (IndexError, fs.FSError) as e:
|
||||
logging.warning("dupeGuru Warning: %s" % unicode(e))
|
||||
return False
|
||||
|
||||
def RevealSelected(self):
|
||||
if self.selected_dupes:
|
||||
path = unicode(self.selected_dupes[0].path)
|
||||
NSWorkspace.sharedWorkspace().selectFile_inFileViewerRootedAtPath_(path,'')
|
||||
|
||||
def start_scanning(self):
|
||||
self.RefreshDetailsTable(None, None)
|
||||
try:
|
||||
app.DupeGuru.start_scanning(self)
|
||||
return 0
|
||||
except app.NoScannableFileError:
|
||||
return 3
|
||||
except app.AllFilesAreRefError:
|
||||
return 1
|
||||
|
||||
def selected_result_node_paths(self):
|
||||
def get_path(dupe):
|
||||
try:
|
||||
group = self.results.get_group_of_duplicate(dupe)
|
||||
groupindex = self.results.groups.index(group)
|
||||
if dupe is group.ref:
|
||||
return [groupindex]
|
||||
dupeindex = group.dupes.index(dupe)
|
||||
return [groupindex, dupeindex]
|
||||
except ValueError: # dupe not in there
|
||||
return None
|
||||
|
||||
dupes = self.selected_dupes
|
||||
return stripnone(get_path(dupe) for dupe in dupes)
|
||||
|
||||
def selected_powermarker_node_paths(self):
|
||||
def get_path(dupe):
|
||||
try:
|
||||
dupeindex = self.results.dupes.index(dupe)
|
||||
return [dupeindex]
|
||||
except ValueError: # dupe not in there
|
||||
return None
|
||||
|
||||
dupes = self.selected_dupes
|
||||
return stripnone(get_path(dupe) for dupe in dupes)
|
||||
|
||||
def SelectResultNodePaths(self,node_paths):
|
||||
def extract_dupe(t):
|
||||
g,d = t
|
||||
if d is not None:
|
||||
return d
|
||||
else:
|
||||
if g is not None:
|
||||
return g.ref
|
||||
|
||||
selected = [extract_dupe(self.GetObjects(p)) for p in node_paths]
|
||||
self.selected_dupes = [dupe for dupe in selected if dupe is not None]
|
||||
|
||||
def SelectPowerMarkerNodePaths(self,node_paths):
|
||||
rows = [p[0] for p in node_paths]
|
||||
self.selected_dupes = [
|
||||
self.results.dupes[row] for row in rows if row in xrange(len(self.results.dupes))
|
||||
]
|
||||
|
||||
def SetDirectoryState(self, node_path, state):
|
||||
p = self.get_folder_path(node_path)
|
||||
self.directories.set_state(p, state)
|
||||
|
||||
def sort_dupes(self,key,asc):
|
||||
self.results.sort_dupes(key,asc,self.display_delta_values)
|
||||
|
||||
def sort_groups(self,key,asc):
|
||||
self.results.sort_groups(key,asc)
|
||||
|
||||
def ToggleSelectedMarkState(self):
|
||||
for dupe in self.selected_dupes:
|
||||
self.results.mark_toggle(dupe)
|
||||
|
||||
#---Data
|
||||
def GetOutlineViewMaxLevel(self, tag):
|
||||
if tag == 0:
|
||||
return 2
|
||||
elif tag == 1:
|
||||
return 0
|
||||
elif tag == 2:
|
||||
return 1
|
||||
|
||||
def GetOutlineViewChildCounts(self, tag, node_path):
|
||||
if self.progress._job_running:
|
||||
return []
|
||||
if tag == 0: #Normal results
|
||||
assert not node_path # no other value is possible
|
||||
return [len(g.dupes) for g in self.results.groups]
|
||||
elif tag == 1: #Directories
|
||||
try:
|
||||
if node_path:
|
||||
path = self.get_folder_path(node_path)
|
||||
subfolders = self.directories.get_subfolders(path)
|
||||
else:
|
||||
subfolders = self.directories
|
||||
return [len(self.directories.get_subfolders(path)) for path in subfolders]
|
||||
except IndexError: # node_path out of range
|
||||
return []
|
||||
else: #Power Marker
|
||||
assert not node_path # no other value is possible
|
||||
return [0 for d in self.results.dupes]
|
||||
|
||||
def GetOutlineViewValues(self, tag, node_path):
|
||||
if self.progress._job_running:
|
||||
return
|
||||
if not node_path:
|
||||
return
|
||||
if tag in (0,2): #Normal results / Power Marker
|
||||
if tag == 0:
|
||||
g, d = self.GetObjects(node_path)
|
||||
if d is None:
|
||||
d = g.ref
|
||||
else:
|
||||
d = self.results.dupes[node_path[0]]
|
||||
g = self.results.get_group_of_duplicate(d)
|
||||
result = self._get_display_info(d, g, self.display_delta_values)
|
||||
return result
|
||||
elif tag == 1: #Directories
|
||||
try:
|
||||
path = self.get_folder_path(node_path)
|
||||
name = unicode(path) if len(node_path) == 1 else path[-1]
|
||||
return [name, self.directories.get_state(path)]
|
||||
except IndexError: # node_path out of range
|
||||
return []
|
||||
|
||||
def GetOutlineViewMarked(self, tag, node_path):
|
||||
# 0=unmarked 1=marked 2=unmarkable
|
||||
if self.progress._job_running:
|
||||
return
|
||||
if not node_path:
|
||||
return 2
|
||||
if tag == 1: #Directories
|
||||
return 2
|
||||
if tag == 0: #Normal results
|
||||
g, d = self.GetObjects(node_path)
|
||||
else: #Power Marker
|
||||
d = self.results.dupes[node_path[0]]
|
||||
if (d is None) or (not self.results.is_markable(d)):
|
||||
return 2
|
||||
elif self.results.is_marked(d):
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def GetTableViewCount(self, tag):
|
||||
if self.progress._job_running:
|
||||
return 0
|
||||
return len(self.details_table)
|
||||
|
||||
def GetTableViewMarkedIndexes(self,tag):
|
||||
return []
|
||||
|
||||
def GetTableViewValues(self,tag,row):
|
||||
return self.details_table[row]
|
||||
|
||||
|
||||
@@ -1,366 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2006/11/11
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import tempfile
|
||||
import shutil
|
||||
import logging
|
||||
import os.path as op
|
||||
|
||||
from nose.tools import eq_
|
||||
|
||||
from hsutil.path import Path
|
||||
from hsutil.testcase import TestCase
|
||||
from hsutil.decorators import log_calls
|
||||
from hsutil import io
|
||||
|
||||
from . import data
|
||||
from .results_test import GetTestGroups
|
||||
from .. import engine, fs
|
||||
try:
|
||||
from ..app_cocoa import DupeGuru as DupeGuruBase
|
||||
except ImportError:
|
||||
from nose.plugins.skip import SkipTest
|
||||
raise SkipTest("These tests can only be run on OS X")
|
||||
|
||||
class DupeGuru(DupeGuruBase):
|
||||
def __init__(self):
|
||||
DupeGuruBase.__init__(self, data, '/tmp', appid=4)
|
||||
|
||||
def _start_job(self, jobid, func):
|
||||
func(nulljob)
|
||||
|
||||
def r2np(rows):
|
||||
#Transforms a list of rows [1,2,3] into a list of node paths [[1],[2],[3]]
|
||||
return [[i] for i in rows]
|
||||
|
||||
class TCDupeGuru(TestCase):
|
||||
def setUp(self):
|
||||
self.app = DupeGuru()
|
||||
self.objects,self.matches,self.groups = GetTestGroups()
|
||||
self.app.results.groups = self.groups
|
||||
tmppath = self.tmppath()
|
||||
io.mkdir(tmppath + 'foo')
|
||||
io.mkdir(tmppath + 'bar')
|
||||
self.app.directories.add_path(tmppath)
|
||||
|
||||
def test_GetObjects(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
groups = self.groups
|
||||
g,d = app.GetObjects([0])
|
||||
self.assert_(g is groups[0])
|
||||
self.assert_(d is None)
|
||||
g,d = app.GetObjects([0,0])
|
||||
self.assert_(g is groups[0])
|
||||
self.assert_(d is objects[1])
|
||||
g,d = app.GetObjects([1,0])
|
||||
self.assert_(g is groups[1])
|
||||
self.assert_(d is objects[4])
|
||||
|
||||
def test_GetObjects_after_sort(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
groups = self.groups[:] #To keep the old order in memory
|
||||
app.sort_groups(0,False) #0 = Filename
|
||||
#Now, the group order is supposed to be reversed
|
||||
g,d = app.GetObjects([0,0])
|
||||
self.assert_(g is groups[1])
|
||||
self.assert_(d is objects[4])
|
||||
|
||||
def test_GetObjects_out_of_range(self):
|
||||
app = self.app
|
||||
self.assertEqual((None,None),app.GetObjects([2]))
|
||||
self.assertEqual((None,None),app.GetObjects([]))
|
||||
self.assertEqual((None,None),app.GetObjects([1,2]))
|
||||
|
||||
def test_selected_result_node_paths(self):
|
||||
# app.selected_dupes is correctly converted into node paths
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
paths = [[0, 0], [0, 1], [1]]
|
||||
app.SelectResultNodePaths(paths)
|
||||
eq_(app.selected_result_node_paths(), paths)
|
||||
|
||||
def test_selected_result_node_paths_after_deletion(self):
|
||||
# cases where the selected dupes aren't there are correctly handled
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
paths = [[0, 0], [0, 1], [1]]
|
||||
app.SelectResultNodePaths(paths)
|
||||
app.RemoveSelected()
|
||||
# The first 2 dupes have been removed. The 3rd one is a ref. it stays there, in first pos.
|
||||
eq_(app.selected_result_node_paths(), [[0]]) # no exception
|
||||
|
||||
def test_selectResultNodePaths(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
app.SelectResultNodePaths([[0,0],[0,1]])
|
||||
self.assertEqual(2,len(app.selected_dupes))
|
||||
self.assert_(app.selected_dupes[0] is objects[1])
|
||||
self.assert_(app.selected_dupes[1] is objects[2])
|
||||
|
||||
def test_selectResultNodePaths_with_ref(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
app.SelectResultNodePaths([[0,0],[0,1],[1]])
|
||||
self.assertEqual(3,len(app.selected_dupes))
|
||||
self.assert_(app.selected_dupes[0] is objects[1])
|
||||
self.assert_(app.selected_dupes[1] is objects[2])
|
||||
self.assert_(app.selected_dupes[2] is self.groups[1].ref)
|
||||
|
||||
def test_selectResultNodePaths_empty(self):
|
||||
self.app.SelectResultNodePaths([])
|
||||
self.assertEqual(0,len(self.app.selected_dupes))
|
||||
|
||||
def test_selectResultNodePaths_after_sort(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
groups = self.groups[:] #To keep the old order in memory
|
||||
app.sort_groups(0,False) #0 = Filename
|
||||
#Now, the group order is supposed to be reversed
|
||||
app.SelectResultNodePaths([[0,0],[1],[1,0]])
|
||||
self.assertEqual(3,len(app.selected_dupes))
|
||||
self.assert_(app.selected_dupes[0] is objects[4])
|
||||
self.assert_(app.selected_dupes[1] is groups[0].ref)
|
||||
self.assert_(app.selected_dupes[2] is objects[1])
|
||||
|
||||
def test_selectResultNodePaths_out_of_range(self):
|
||||
app = self.app
|
||||
app.SelectResultNodePaths([[0,0],[0,1],[1],[1,1],[2]])
|
||||
self.assertEqual(3,len(app.selected_dupes))
|
||||
|
||||
def test_selected_powermarker_node_paths(self):
|
||||
# app.selected_dupes is correctly converted into paths
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
paths = r2np([0, 1, 2])
|
||||
app.SelectPowerMarkerNodePaths(paths)
|
||||
eq_(app.selected_powermarker_node_paths(), paths)
|
||||
|
||||
def test_selected_powermarker_node_paths_after_deletion(self):
|
||||
# cases where the selected dupes aren't there are correctly handled
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
paths = r2np([0, 1, 2])
|
||||
app.SelectPowerMarkerNodePaths(paths)
|
||||
app.RemoveSelected()
|
||||
eq_(app.selected_powermarker_node_paths(), []) # no exception
|
||||
|
||||
def test_selectPowerMarkerRows(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
app.SelectPowerMarkerNodePaths(r2np([0,1,2]))
|
||||
self.assertEqual(3,len(app.selected_dupes))
|
||||
self.assert_(app.selected_dupes[0] is objects[1])
|
||||
self.assert_(app.selected_dupes[1] is objects[2])
|
||||
self.assert_(app.selected_dupes[2] is objects[4])
|
||||
|
||||
def test_selectPowerMarkerRows_empty(self):
|
||||
self.app.SelectPowerMarkerNodePaths([])
|
||||
self.assertEqual(0,len(self.app.selected_dupes))
|
||||
|
||||
def test_selectPowerMarkerRows_after_sort(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
app.sort_dupes(0,False) #0 = Filename
|
||||
app.SelectPowerMarkerNodePaths(r2np([0,1,2]))
|
||||
self.assertEqual(3,len(app.selected_dupes))
|
||||
self.assert_(app.selected_dupes[0] is objects[4])
|
||||
self.assert_(app.selected_dupes[1] is objects[2])
|
||||
self.assert_(app.selected_dupes[2] is objects[1])
|
||||
|
||||
def test_selectPowerMarkerRows_out_of_range(self):
|
||||
app = self.app
|
||||
app.SelectPowerMarkerNodePaths(r2np([0,1,2,3]))
|
||||
self.assertEqual(3,len(app.selected_dupes))
|
||||
|
||||
def test_toggleSelectedMark(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
app.ToggleSelectedMarkState()
|
||||
self.assertEqual(0,app.results.mark_count)
|
||||
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
||||
app.ToggleSelectedMarkState()
|
||||
self.assertEqual(2,app.results.mark_count)
|
||||
self.assert_(not app.results.is_marked(objects[0]))
|
||||
self.assert_(app.results.is_marked(objects[1]))
|
||||
self.assert_(not app.results.is_marked(objects[2]))
|
||||
self.assert_(not app.results.is_marked(objects[3]))
|
||||
self.assert_(app.results.is_marked(objects[4]))
|
||||
|
||||
def test_refreshDetailsWithSelected(self):
|
||||
def mock_refresh(dupe,group):
|
||||
self.called = True
|
||||
if self.app.selected_dupes:
|
||||
self.assert_(dupe is self.app.selected_dupes[0])
|
||||
self.assert_(group is self.app.results.get_group_of_duplicate(dupe))
|
||||
else:
|
||||
self.assert_(dupe is None)
|
||||
self.assert_(group is None)
|
||||
|
||||
self.app.RefreshDetailsTable = mock_refresh
|
||||
self.called = False
|
||||
self.app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
||||
self.app.RefreshDetailsWithSelected()
|
||||
self.assert_(self.called)
|
||||
self.called = False
|
||||
self.app.SelectPowerMarkerNodePaths([])
|
||||
self.app.RefreshDetailsWithSelected()
|
||||
self.assert_(self.called)
|
||||
|
||||
def test_makeSelectedReference(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
groups = self.groups
|
||||
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
||||
app.MakeSelectedReference()
|
||||
self.assert_(groups[0].ref is objects[1])
|
||||
self.assert_(groups[1].ref is objects[4])
|
||||
|
||||
def test_makeSelectedReference_by_selecting_two_dupes_in_the_same_group(self):
|
||||
app = self.app
|
||||
objects = self.objects
|
||||
groups = self.groups
|
||||
app.SelectPowerMarkerNodePaths(r2np([0,1,2]))
|
||||
#Only 0 and 2 must go ref, not 1 because it is a part of the same group
|
||||
app.MakeSelectedReference()
|
||||
self.assert_(groups[0].ref is objects[1])
|
||||
self.assert_(groups[1].ref is objects[4])
|
||||
|
||||
def test_removeSelected(self):
|
||||
app = self.app
|
||||
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
||||
app.RemoveSelected()
|
||||
self.assertEqual(1,len(app.results.dupes))
|
||||
app.RemoveSelected()
|
||||
self.assertEqual(1,len(app.results.dupes))
|
||||
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
||||
app.RemoveSelected()
|
||||
self.assertEqual(0,len(app.results.dupes))
|
||||
|
||||
def test_addDirectory_simple(self):
|
||||
# There's already a directory in self.app, so adding another once makes 2 of em
|
||||
app = self.app
|
||||
eq_(app.add_directory(self.datadirpath()), 0)
|
||||
eq_(len(app.directories), 2)
|
||||
|
||||
def test_addDirectory_already_there(self):
|
||||
app = self.app
|
||||
self.assertEqual(0,app.add_directory(self.datadirpath()))
|
||||
self.assertEqual(1,app.add_directory(self.datadirpath()))
|
||||
|
||||
def test_addDirectory_does_not_exist(self):
|
||||
app = self.app
|
||||
self.assertEqual(2,app.add_directory('/does_not_exist'))
|
||||
|
||||
def test_ignore(self):
|
||||
app = self.app
|
||||
app.SelectPowerMarkerNodePaths(r2np([2])) #The dupe of the second, 2 sized group
|
||||
app.AddSelectedToIgnoreList()
|
||||
self.assertEqual(1,len(app.scanner.ignore_list))
|
||||
app.SelectPowerMarkerNodePaths(r2np([0])) #first dupe of the 3 dupes group
|
||||
app.AddSelectedToIgnoreList()
|
||||
#BOTH the ref and the other dupe should have been added
|
||||
self.assertEqual(3,len(app.scanner.ignore_list))
|
||||
|
||||
def test_purgeIgnoreList(self):
|
||||
app = self.app
|
||||
p1 = self.filepath('zerofile')
|
||||
p2 = self.filepath('zerofill')
|
||||
dne = '/does_not_exist'
|
||||
app.scanner.ignore_list.Ignore(dne,p1)
|
||||
app.scanner.ignore_list.Ignore(p2,dne)
|
||||
app.scanner.ignore_list.Ignore(p1,p2)
|
||||
app.PurgeIgnoreList()
|
||||
self.assertEqual(1,len(app.scanner.ignore_list))
|
||||
self.assert_(app.scanner.ignore_list.AreIgnored(p1,p2))
|
||||
self.assert_(not app.scanner.ignore_list.AreIgnored(dne,p1))
|
||||
|
||||
def test_only_unicode_is_added_to_ignore_list(self):
|
||||
def FakeIgnore(first,second):
|
||||
if not isinstance(first,unicode):
|
||||
self.fail()
|
||||
if not isinstance(second,unicode):
|
||||
self.fail()
|
||||
|
||||
app = self.app
|
||||
app.scanner.ignore_list.Ignore = FakeIgnore
|
||||
app.SelectPowerMarkerNodePaths(r2np([2])) #The dupe of the second, 2 sized group
|
||||
app.AddSelectedToIgnoreList()
|
||||
|
||||
def test_GetOutlineViewChildCounts_out_of_range(self):
|
||||
# Out of range requests don't crash and return an empty value
|
||||
app = self.app
|
||||
# [0, 2] is out of range
|
||||
eq_(app.GetOutlineViewChildCounts(1, [0, 2]), []) # no crash
|
||||
|
||||
def test_GetOutlineViewValues_out_of_range(self):
|
||||
# Out of range requests don't crash and return an empty value
|
||||
app = self.app
|
||||
# [0, 2] is out of range
|
||||
eq_(app.GetOutlineViewValues(1, [0, 2]), []) # no crash
|
||||
|
||||
|
||||
class TCDupeGuru_renameSelected(TestCase):
|
||||
def setUp(self):
|
||||
p = self.tmppath()
|
||||
fp = open(unicode(p + 'foo bar 1'),mode='w')
|
||||
fp.close()
|
||||
fp = open(unicode(p + 'foo bar 2'),mode='w')
|
||||
fp.close()
|
||||
fp = open(unicode(p + 'foo bar 3'),mode='w')
|
||||
fp.close()
|
||||
files = fs.get_files(p)
|
||||
matches = engine.getmatches(files)
|
||||
groups = engine.get_groups(matches)
|
||||
g = groups[0]
|
||||
g.prioritize(lambda x:x.name)
|
||||
app = DupeGuru()
|
||||
app.results.groups = groups
|
||||
self.app = app
|
||||
self.groups = groups
|
||||
self.p = p
|
||||
self.files = files
|
||||
|
||||
def test_simple(self):
|
||||
app = self.app
|
||||
g = self.groups[0]
|
||||
app.SelectPowerMarkerNodePaths(r2np([0]))
|
||||
assert app.RenameSelected('renamed')
|
||||
names = io.listdir(self.p)
|
||||
assert 'renamed' in names
|
||||
assert 'foo bar 2' not in names
|
||||
eq_(g.dupes[0].name, 'renamed')
|
||||
|
||||
def test_none_selected(self):
|
||||
app = self.app
|
||||
g = self.groups[0]
|
||||
app.SelectPowerMarkerNodePaths([])
|
||||
self.mock(logging, 'warning', log_calls(lambda msg: None))
|
||||
assert not app.RenameSelected('renamed')
|
||||
msg = logging.warning.calls[0]['msg']
|
||||
eq_('dupeGuru Warning: list index out of range', msg)
|
||||
names = io.listdir(self.p)
|
||||
assert 'renamed' not in names
|
||||
assert 'foo bar 2' in names
|
||||
eq_(g.dupes[0].name, 'foo bar 2')
|
||||
|
||||
def test_name_already_exists(self):
|
||||
app = self.app
|
||||
g = self.groups[0]
|
||||
app.SelectPowerMarkerNodePaths(r2np([0]))
|
||||
self.mock(logging, 'warning', log_calls(lambda msg: None))
|
||||
assert not app.RenameSelected('foo bar 1')
|
||||
msg = logging.warning.calls[0]['msg']
|
||||
assert msg.startswith('dupeGuru Warning: \'foo bar 1\' already exists in')
|
||||
names = io.listdir(self.p)
|
||||
assert 'foo bar 1' in names
|
||||
assert 'foo bar 2' in names
|
||||
eq_(g.dupes[0].name, 'foo bar 2')
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2007-06-23
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import os
|
||||
|
||||
from hsutil.testcase import TestCase
|
||||
from hsutil import io
|
||||
from hsutil.path import Path
|
||||
from hsutil.decorators import log_calls
|
||||
import hsutil.files
|
||||
from hsutil.job import nulljob
|
||||
|
||||
from . import data
|
||||
from .. import app, fs
|
||||
from ..app import DupeGuru as DupeGuruBase
|
||||
|
||||
class DupeGuru(DupeGuruBase):
|
||||
def __init__(self):
|
||||
DupeGuruBase.__init__(self, data, '/tmp', appid=4)
|
||||
|
||||
def _start_job(self, jobid, func):
|
||||
func(nulljob)
|
||||
|
||||
|
||||
class TCDupeGuru(TestCase):
|
||||
cls_tested_module = app
|
||||
def test_apply_filter_calls_results_apply_filter(self):
|
||||
app = DupeGuru()
|
||||
self.mock(app.results, 'apply_filter', log_calls(app.results.apply_filter))
|
||||
app.apply_filter('foo')
|
||||
self.assertEqual(2, len(app.results.apply_filter.calls))
|
||||
call = app.results.apply_filter.calls[0]
|
||||
self.assert_(call['filter_str'] is None)
|
||||
call = app.results.apply_filter.calls[1]
|
||||
self.assertEqual('foo', call['filter_str'])
|
||||
|
||||
def test_apply_filter_escapes_regexp(self):
|
||||
app = DupeGuru()
|
||||
self.mock(app.results, 'apply_filter', log_calls(app.results.apply_filter))
|
||||
app.apply_filter('()[]\\.|+?^abc')
|
||||
call = app.results.apply_filter.calls[1]
|
||||
self.assertEqual('\\(\\)\\[\\]\\\\\\.\\|\\+\\?\\^abc', call['filter_str'])
|
||||
app.apply_filter('(*)') # In "simple mode", we want the * to behave as a wilcard
|
||||
call = app.results.apply_filter.calls[3]
|
||||
self.assertEqual('\(.*\)', call['filter_str'])
|
||||
app.options['escape_filter_regexp'] = False
|
||||
app.apply_filter('(abc)')
|
||||
call = app.results.apply_filter.calls[5]
|
||||
self.assertEqual('(abc)', call['filter_str'])
|
||||
|
||||
def test_copy_or_move(self):
|
||||
# The goal here is just to have a test for a previous blowup I had. I know my test coverage
|
||||
# for this unit is pathetic. What's done is done. My approach now is to add tests for
|
||||
# every change I want to make. The blowup was caused by a missing import.
|
||||
p = self.tmppath()
|
||||
io.open(p + 'foo', 'w').close()
|
||||
self.mock(hsutil.files, 'copy', log_calls(lambda source_path, dest_path: None))
|
||||
self.mock(os, 'makedirs', lambda path: None) # We don't want the test to create that fake directory
|
||||
app = DupeGuru()
|
||||
app.directories.add_path(p)
|
||||
[f] = app.directories.get_files()
|
||||
app.copy_or_move(f, True, 'some_destination', 0)
|
||||
self.assertEqual(1, len(hsutil.files.copy.calls))
|
||||
call = hsutil.files.copy.calls[0]
|
||||
self.assertEqual('some_destination', call['dest_path'])
|
||||
self.assertEqual(f.path, call['source_path'])
|
||||
|
||||
def test_copy_or_move_clean_empty_dirs(self):
|
||||
tmppath = Path(self.tmpdir())
|
||||
sourcepath = tmppath + 'source'
|
||||
io.mkdir(sourcepath)
|
||||
io.open(sourcepath + 'myfile', 'w')
|
||||
app = DupeGuru()
|
||||
app.directories.add_path(tmppath)
|
||||
[myfile] = app.directories.get_files()
|
||||
self.mock(app, 'clean_empty_dirs', log_calls(lambda path: None))
|
||||
app.copy_or_move(myfile, False, tmppath + 'dest', 0)
|
||||
calls = app.clean_empty_dirs.calls
|
||||
self.assertEqual(1, len(calls))
|
||||
self.assertEqual(sourcepath, calls[0]['path'])
|
||||
|
||||
def test_Scan_with_objects_evaluating_to_false(self):
|
||||
class FakeFile(fs.File):
|
||||
def __nonzero__(self):
|
||||
return False
|
||||
|
||||
|
||||
# At some point, any() was used in a wrong way that made Scan() wrongly return 1
|
||||
app = DupeGuru()
|
||||
f1, f2 = [FakeFile('foo') for i in range(2)]
|
||||
f1.is_ref, f2.is_ref = (False, False)
|
||||
assert not (bool(f1) and bool(f2))
|
||||
app.directories.get_files = lambda: [f1, f2]
|
||||
app.directories._dirs.append('this is just so Scan() doesnt return 3')
|
||||
app.start_scanning() # no exception
|
||||
|
||||
|
||||
class TCDupeGuru_clean_empty_dirs(TestCase):
|
||||
cls_tested_module = app
|
||||
def setUp(self):
|
||||
self.mock(hsutil.files, 'delete_if_empty', log_calls(lambda path, files_to_delete=[]: None))
|
||||
self.app = DupeGuru()
|
||||
|
||||
def test_option_off(self):
|
||||
self.app.clean_empty_dirs(Path('/foo/bar'))
|
||||
self.assertEqual(0, len(hsutil.files.delete_if_empty.calls))
|
||||
|
||||
def test_option_on(self):
|
||||
self.app.options['clean_empty_dirs'] = True
|
||||
self.app.clean_empty_dirs(Path('/foo/bar'))
|
||||
calls = hsutil.files.delete_if_empty.calls
|
||||
self.assertEqual(1, len(calls))
|
||||
self.assertEqual(Path('/foo/bar'), calls[0]['path'])
|
||||
self.assertEqual(['.DS_Store'], calls[0]['files_to_delete'])
|
||||
|
||||
def test_recurse_up(self):
|
||||
# delete_if_empty must be recursively called up in the path until it returns False
|
||||
@log_calls
|
||||
def mock_delete_if_empty(path, files_to_delete=[]):
|
||||
return len(path) > 1
|
||||
|
||||
self.mock(hsutil.files, 'delete_if_empty', mock_delete_if_empty)
|
||||
self.app.options['clean_empty_dirs'] = True
|
||||
self.app.clean_empty_dirs(Path('not-empty/empty/empty'))
|
||||
calls = hsutil.files.delete_if_empty.calls
|
||||
self.assertEqual(3, len(calls))
|
||||
self.assertEqual(Path('not-empty/empty/empty'), calls[0]['path'])
|
||||
self.assertEqual(Path('not-empty/empty'), calls[1]['path'])
|
||||
self.assertEqual(Path('not-empty'), calls[2]['path'])
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-10-23
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
# data module for tests
|
||||
|
||||
from hsutil.str import format_size
|
||||
from dupeguru.data import format_path, cmp_value
|
||||
|
||||
COLUMNS = [
|
||||
{'attr':'name','display':'Filename'},
|
||||
{'attr':'path','display':'Directory'},
|
||||
{'attr':'size','display':'Size (KB)'},
|
||||
{'attr':'extension','display':'Kind'},
|
||||
]
|
||||
|
||||
METADATA_TO_READ = ['size']
|
||||
|
||||
def GetDisplayInfo(dupe, group, delta):
|
||||
size = dupe.size
|
||||
m = group.get_match_of(dupe)
|
||||
if m and delta:
|
||||
r = group.ref
|
||||
size -= r.size
|
||||
return [
|
||||
dupe.name,
|
||||
format_path(dupe.path),
|
||||
format_size(size, 0, 1, False),
|
||||
dupe.extension,
|
||||
]
|
||||
|
||||
def GetDupeSortKey(dupe, get_group, key, delta):
|
||||
r = cmp_value(getattr(dupe, COLUMNS[key]['attr']))
|
||||
if delta and (key == 2):
|
||||
r -= cmp_value(getattr(get_group().ref, COLUMNS[key]['attr']))
|
||||
return r
|
||||
|
||||
def GetGroupSortKey(group, key):
|
||||
return cmp_value(getattr(group.ref, COLUMNS[key]['attr']))
|
||||
@@ -1,279 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2006/02/27
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import os.path as op
|
||||
import os
|
||||
import time
|
||||
|
||||
from nose.tools import eq_
|
||||
|
||||
from hsutil import io
|
||||
from hsutil.path import Path
|
||||
from hsutil.testcase import TestCase
|
||||
|
||||
from ..directories import *
|
||||
|
||||
testpath = Path(TestCase.datadirpath())
|
||||
|
||||
def create_fake_fs(rootpath):
|
||||
rootpath = rootpath + 'fs'
|
||||
io.mkdir(rootpath)
|
||||
io.mkdir(rootpath + 'dir1')
|
||||
io.mkdir(rootpath + 'dir2')
|
||||
io.mkdir(rootpath + 'dir3')
|
||||
fp = io.open(rootpath + 'file1.test', 'w')
|
||||
fp.write('1')
|
||||
fp.close()
|
||||
fp = io.open(rootpath + 'file2.test', 'w')
|
||||
fp.write('12')
|
||||
fp.close()
|
||||
fp = io.open(rootpath + 'file3.test', 'w')
|
||||
fp.write('123')
|
||||
fp.close()
|
||||
fp = io.open(rootpath + ('dir1', 'file1.test'), 'w')
|
||||
fp.write('1')
|
||||
fp.close()
|
||||
fp = io.open(rootpath + ('dir2', 'file2.test'), 'w')
|
||||
fp.write('12')
|
||||
fp.close()
|
||||
fp = io.open(rootpath + ('dir3', 'file3.test'), 'w')
|
||||
fp.write('123')
|
||||
fp.close()
|
||||
return rootpath
|
||||
|
||||
class TCDirectories(TestCase):
|
||||
def test_empty(self):
|
||||
d = Directories()
|
||||
self.assertEqual(0,len(d))
|
||||
self.assert_('foobar' not in d)
|
||||
|
||||
def test_add_path(self):
|
||||
d = Directories()
|
||||
p = testpath + 'utils'
|
||||
d.add_path(p)
|
||||
self.assertEqual(1,len(d))
|
||||
self.assert_(p in d)
|
||||
self.assert_((p + 'foobar') in d)
|
||||
self.assert_(p[:-1] not in d)
|
||||
p = self.tmppath()
|
||||
d.add_path(p)
|
||||
self.assertEqual(2,len(d))
|
||||
self.assert_(p in d)
|
||||
|
||||
def test_AddPath_when_path_is_already_there(self):
|
||||
d = Directories()
|
||||
p = testpath + 'utils'
|
||||
d.add_path(p)
|
||||
self.assertRaises(AlreadyThereError, d.add_path, p)
|
||||
self.assertRaises(AlreadyThereError, d.add_path, p + 'foobar')
|
||||
self.assertEqual(1, len(d))
|
||||
|
||||
def test_add_path_containing_paths_already_there(self):
|
||||
d = Directories()
|
||||
d.add_path(testpath + 'utils')
|
||||
self.assertEqual(1, len(d))
|
||||
d.add_path(testpath)
|
||||
eq_(len(d), 1)
|
||||
eq_(d[0], testpath)
|
||||
|
||||
def test_AddPath_non_latin(self):
|
||||
p = Path(self.tmpdir())
|
||||
to_add = p + u'unicode\u201a'
|
||||
os.mkdir(unicode(to_add))
|
||||
d = Directories()
|
||||
try:
|
||||
d.add_path(to_add)
|
||||
except UnicodeDecodeError:
|
||||
self.fail()
|
||||
|
||||
def test_del(self):
|
||||
d = Directories()
|
||||
d.add_path(testpath + 'utils')
|
||||
try:
|
||||
del d[1]
|
||||
self.fail()
|
||||
except IndexError:
|
||||
pass
|
||||
d.add_path(self.tmppath())
|
||||
del d[1]
|
||||
self.assertEqual(1, len(d))
|
||||
|
||||
def test_states(self):
|
||||
d = Directories()
|
||||
p = testpath + 'utils'
|
||||
d.add_path(p)
|
||||
self.assertEqual(STATE_NORMAL,d.get_state(p))
|
||||
d.set_state(p,STATE_REFERENCE)
|
||||
self.assertEqual(STATE_REFERENCE,d.get_state(p))
|
||||
self.assertEqual(STATE_REFERENCE,d.get_state(p + 'dir1'))
|
||||
self.assertEqual(1,len(d.states))
|
||||
self.assertEqual(p,d.states.keys()[0])
|
||||
self.assertEqual(STATE_REFERENCE,d.states[p])
|
||||
|
||||
def test_get_state_with_path_not_there(self):
|
||||
# When the path's not there, just return STATE_NORMAL
|
||||
d = Directories()
|
||||
d.add_path(testpath + 'utils')
|
||||
eq_(d.get_state(testpath), STATE_NORMAL)
|
||||
|
||||
def test_states_remain_when_larger_directory_eat_smaller_ones(self):
|
||||
d = Directories()
|
||||
p = testpath + 'utils'
|
||||
d.add_path(p)
|
||||
d.set_state(p,STATE_EXCLUDED)
|
||||
d.add_path(testpath)
|
||||
d.set_state(testpath,STATE_REFERENCE)
|
||||
self.assertEqual(STATE_EXCLUDED,d.get_state(p))
|
||||
self.assertEqual(STATE_EXCLUDED,d.get_state(p + 'dir1'))
|
||||
self.assertEqual(STATE_REFERENCE,d.get_state(testpath))
|
||||
|
||||
def test_set_state_keep_state_dict_size_to_minimum(self):
|
||||
d = Directories()
|
||||
p = create_fake_fs(self.tmppath())
|
||||
d.add_path(p)
|
||||
d.set_state(p,STATE_REFERENCE)
|
||||
d.set_state(p + 'dir1',STATE_REFERENCE)
|
||||
self.assertEqual(1,len(d.states))
|
||||
self.assertEqual(STATE_REFERENCE,d.get_state(p + 'dir1'))
|
||||
d.set_state(p + 'dir1',STATE_NORMAL)
|
||||
self.assertEqual(2,len(d.states))
|
||||
self.assertEqual(STATE_NORMAL,d.get_state(p + 'dir1'))
|
||||
d.set_state(p + 'dir1',STATE_REFERENCE)
|
||||
self.assertEqual(1,len(d.states))
|
||||
self.assertEqual(STATE_REFERENCE,d.get_state(p + 'dir1'))
|
||||
|
||||
def test_get_files(self):
|
||||
d = Directories()
|
||||
p = create_fake_fs(self.tmppath())
|
||||
d.add_path(p)
|
||||
d.set_state(p + 'dir1',STATE_REFERENCE)
|
||||
d.set_state(p + 'dir2',STATE_EXCLUDED)
|
||||
files = list(d.get_files())
|
||||
self.assertEqual(5, len(files))
|
||||
for f in files:
|
||||
if f.path[:-1] == p + 'dir1':
|
||||
assert f.is_ref
|
||||
else:
|
||||
assert not f.is_ref
|
||||
|
||||
def test_get_files_with_inherited_exclusion(self):
|
||||
d = Directories()
|
||||
p = testpath + 'utils'
|
||||
d.add_path(p)
|
||||
d.set_state(p,STATE_EXCLUDED)
|
||||
self.assertEqual([], list(d.get_files()))
|
||||
|
||||
def test_save_and_load(self):
|
||||
d1 = Directories()
|
||||
d2 = Directories()
|
||||
p1 = self.tmppath()
|
||||
p2 = self.tmppath()
|
||||
d1.add_path(p1)
|
||||
d1.add_path(p2)
|
||||
d1.set_state(p1, STATE_REFERENCE)
|
||||
d1.set_state(p1 + 'dir1',STATE_EXCLUDED)
|
||||
tmpxml = op.join(self.tmpdir(), 'directories_testunit.xml')
|
||||
d1.save_to_file(tmpxml)
|
||||
d2.load_from_file(tmpxml)
|
||||
self.assertEqual(2, len(d2))
|
||||
self.assertEqual(STATE_REFERENCE,d2.get_state(p1))
|
||||
self.assertEqual(STATE_EXCLUDED,d2.get_state(p1 + 'dir1'))
|
||||
|
||||
def test_invalid_path(self):
|
||||
d = Directories()
|
||||
p = Path('does_not_exist')
|
||||
self.assertRaises(InvalidPathError, d.add_path, p)
|
||||
self.assertEqual(0, len(d))
|
||||
|
||||
def test_set_state_on_invalid_path(self):
|
||||
d = Directories()
|
||||
try:
|
||||
d.set_state(Path('foobar',),STATE_NORMAL)
|
||||
except LookupError:
|
||||
self.fail()
|
||||
|
||||
def test_load_from_file_with_invalid_path(self):
|
||||
#This test simulates a load from file resulting in a
|
||||
#InvalidPath raise. Other directories must be loaded.
|
||||
d1 = Directories()
|
||||
d1.add_path(testpath + 'utils')
|
||||
#Will raise InvalidPath upon loading
|
||||
p = self.tmppath()
|
||||
d1.add_path(p)
|
||||
io.rmdir(p)
|
||||
tmpxml = op.join(self.tmpdir(), 'directories_testunit.xml')
|
||||
d1.save_to_file(tmpxml)
|
||||
d2 = Directories()
|
||||
d2.load_from_file(tmpxml)
|
||||
self.assertEqual(1, len(d2))
|
||||
|
||||
def test_unicode_save(self):
|
||||
d = Directories()
|
||||
p1 = self.tmppath() + u'hello\xe9'
|
||||
io.mkdir(p1)
|
||||
io.mkdir(p1 + u'foo\xe9')
|
||||
d.add_path(p1)
|
||||
d.set_state(p1 + u'foo\xe9', STATE_EXCLUDED)
|
||||
tmpxml = op.join(self.tmpdir(), 'directories_testunit.xml')
|
||||
try:
|
||||
d.save_to_file(tmpxml)
|
||||
except UnicodeDecodeError:
|
||||
self.fail()
|
||||
|
||||
def test_get_files_refreshes_its_directories(self):
|
||||
d = Directories()
|
||||
p = create_fake_fs(self.tmppath())
|
||||
d.add_path(p)
|
||||
files = d.get_files()
|
||||
self.assertEqual(6, len(list(files)))
|
||||
time.sleep(1)
|
||||
os.remove(str(p + ('dir1','file1.test')))
|
||||
files = d.get_files()
|
||||
self.assertEqual(5, len(list(files)))
|
||||
|
||||
def test_get_files_does_not_choke_on_non_existing_directories(self):
|
||||
d = Directories()
|
||||
p = Path(self.tmpdir())
|
||||
d.add_path(p)
|
||||
io.rmtree(p)
|
||||
self.assertEqual([], list(d.get_files()))
|
||||
|
||||
def test_get_state_returns_excluded_by_default_for_hidden_directories(self):
|
||||
d = Directories()
|
||||
p = Path(self.tmpdir())
|
||||
hidden_dir_path = p + '.foo'
|
||||
io.mkdir(p + '.foo')
|
||||
d.add_path(p)
|
||||
self.assertEqual(d.get_state(hidden_dir_path), STATE_EXCLUDED)
|
||||
# But it can be overriden
|
||||
d.set_state(hidden_dir_path, STATE_NORMAL)
|
||||
self.assertEqual(d.get_state(hidden_dir_path), STATE_NORMAL)
|
||||
|
||||
def test_default_path_state_override(self):
|
||||
# It's possible for a subclass to override the default state of a path
|
||||
class MyDirectories(Directories):
|
||||
def _default_state_for_path(self, path):
|
||||
if 'foobar' in path:
|
||||
return STATE_EXCLUDED
|
||||
|
||||
d = MyDirectories()
|
||||
p1 = self.tmppath()
|
||||
io.mkdir(p1 + 'foobar')
|
||||
io.open(p1 + 'foobar/somefile', 'w').close()
|
||||
io.mkdir(p1 + 'foobaz')
|
||||
io.open(p1 + 'foobaz/somefile', 'w').close()
|
||||
d.add_path(p1)
|
||||
eq_(d.get_state(p1 + 'foobaz'), STATE_NORMAL)
|
||||
eq_(d.get_state(p1 + 'foobar'), STATE_EXCLUDED)
|
||||
eq_(len(list(d.get_files())), 1) # only the 'foobaz' file is there
|
||||
# However, the default state can be changed
|
||||
d.set_state(p1 + 'foobar', STATE_NORMAL)
|
||||
eq_(d.get_state(p1 + 'foobar'), STATE_NORMAL)
|
||||
eq_(len(list(d.get_files())), 2)
|
||||
|
||||
@@ -1,467 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2006/03/03
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from nose.tools import eq_
|
||||
|
||||
from hsutil import job, io
|
||||
from hsutil.path import Path
|
||||
from hsutil.testcase import TestCase
|
||||
|
||||
from .. import fs
|
||||
from ..engine import getwords, Match
|
||||
from ..ignore import IgnoreList
|
||||
from ..scanner import *
|
||||
|
||||
class NamedObject(object):
|
||||
def __init__(self, name="foobar", size=1):
|
||||
self.name = name
|
||||
self.size = size
|
||||
self.path = Path('')
|
||||
self.words = getwords(name)
|
||||
|
||||
|
||||
no = NamedObject
|
||||
|
||||
#--- Scanner
|
||||
class ScannerTestFakeFiles(TestCase):
|
||||
def setUp(self):
|
||||
# This is a hack to avoid invalidating all previous tests since the scanner started to test
|
||||
# for file existence before doing the match grouping.
|
||||
self.mock(io, 'exists', lambda _: True)
|
||||
|
||||
def test_empty(self):
|
||||
s = Scanner()
|
||||
r = s.GetDupeGroups([])
|
||||
eq_(r, [])
|
||||
|
||||
def test_default_settings(self):
|
||||
s = Scanner()
|
||||
eq_(s.min_match_percentage, 80)
|
||||
eq_(s.scan_type, SCAN_TYPE_FILENAME)
|
||||
eq_(s.mix_file_kind, True)
|
||||
eq_(s.word_weighting, False)
|
||||
eq_(s.match_similar_words, False)
|
||||
assert isinstance(s.ignore_list, IgnoreList)
|
||||
|
||||
def test_simple_with_default_settings(self):
|
||||
s = Scanner()
|
||||
f = [no('foo bar'), no('foo bar'), no('foo bleh')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
g = r[0]
|
||||
#'foo bleh' cannot be in the group because the default min match % is 80
|
||||
eq_(len(g), 2)
|
||||
assert g.ref in f[:2]
|
||||
assert g.dupes[0] in f[:2]
|
||||
|
||||
def test_simple_with_lower_min_match(self):
|
||||
s = Scanner()
|
||||
s.min_match_percentage = 50
|
||||
f = [no('foo bar'), no('foo bar'), no('foo bleh')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
g = r[0]
|
||||
eq_(len(g), 3)
|
||||
|
||||
def test_trim_all_ref_groups(self):
|
||||
# When all files of a group are ref, don't include that group in the results, but also don't
|
||||
# count the files from that group as discarded.
|
||||
s = Scanner()
|
||||
f = [no('foo'), no('foo'), no('bar'), no('bar')]
|
||||
f[2].is_ref = True
|
||||
f[3].is_ref = True
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
eq_(s.discarded_file_count, 0)
|
||||
|
||||
def test_priorize(self):
|
||||
s = Scanner()
|
||||
f = [no('foo'), no('foo'), no('bar'), no('bar')]
|
||||
f[1].size = 2
|
||||
f[2].size = 3
|
||||
f[3].is_ref = True
|
||||
r = s.GetDupeGroups(f)
|
||||
g1, g2 = r
|
||||
assert f[1] in (g1.ref,g2.ref)
|
||||
assert f[0] in (g1.dupes[0],g2.dupes[0])
|
||||
assert f[3] in (g1.ref,g2.ref)
|
||||
assert f[2] in (g1.dupes[0],g2.dupes[0])
|
||||
|
||||
def test_content_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
f = [no('foo'), no('bar'), no('bleh')]
|
||||
f[0].md5 = f[0].md5partial = 'foobar'
|
||||
f[1].md5 = f[1].md5partial = 'foobar'
|
||||
f[2].md5 = f[2].md5partial = 'bleh'
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
eq_(len(r[0]), 2)
|
||||
eq_(s.discarded_file_count, 0) # don't count the different md5 as discarded!
|
||||
|
||||
def test_content_scan_compare_sizes_first(self):
|
||||
class MyFile(no):
|
||||
@property
|
||||
def md5(file):
|
||||
raise AssertionError()
|
||||
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
f = [MyFile('foo', 1), MyFile('bar', 2)]
|
||||
eq_(len(s.GetDupeGroups(f)), 0)
|
||||
|
||||
def test_min_match_perc_doesnt_matter_for_content_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
f = [no('foo'), no('bar'), no('bleh')]
|
||||
f[0].md5 = f[0].md5partial = 'foobar'
|
||||
f[1].md5 = f[1].md5partial = 'foobar'
|
||||
f[2].md5 = f[2].md5partial = 'bleh'
|
||||
s.min_match_percentage = 101
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
eq_(len(r[0]), 2)
|
||||
s.min_match_percentage = 0
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
eq_(len(r[0]), 2)
|
||||
|
||||
def test_content_scan_doesnt_put_md5_in_words_at_the_end(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
f = [no('foo'),no('bar')]
|
||||
f[0].md5 = f[0].md5partial = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
|
||||
f[1].md5 = f[1].md5partial = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
|
||||
r = s.GetDupeGroups(f)
|
||||
g = r[0]
|
||||
|
||||
def test_extension_is_not_counted_in_filename_scan(self):
|
||||
s = Scanner()
|
||||
s.min_match_percentage = 100
|
||||
f = [no('foo.bar'), no('foo.bleh')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
eq_(len(r[0]), 2)
|
||||
|
||||
def test_job(self):
|
||||
def do_progress(progress, desc=''):
|
||||
log.append(progress)
|
||||
return True
|
||||
|
||||
s = Scanner()
|
||||
log = []
|
||||
f = [no('foo bar'), no('foo bar'), no('foo bleh')]
|
||||
r = s.GetDupeGroups(f, job.Job(1, do_progress))
|
||||
eq_(log[0], 0)
|
||||
eq_(log[-1], 100)
|
||||
|
||||
def test_mix_file_kind(self):
|
||||
s = Scanner()
|
||||
s.mix_file_kind = False
|
||||
f = [no('foo.1'), no('foo.2')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 0)
|
||||
|
||||
def test_word_weighting(self):
|
||||
s = Scanner()
|
||||
s.min_match_percentage = 75
|
||||
s.word_weighting = True
|
||||
f = [no('foo bar'), no('foo bar bleh')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
g = r[0]
|
||||
m = g.get_match_of(g.dupes[0])
|
||||
eq_(m.percentage, 75) # 16 letters, 12 matching
|
||||
|
||||
def test_similar_words(self):
|
||||
s = Scanner()
|
||||
s.match_similar_words = True
|
||||
f = [no('The White Stripes'), no('The Whites Stripe'), no('Limp Bizkit'), no('Limp Bizkitt')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 2)
|
||||
|
||||
def test_fields(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_FIELDS
|
||||
f = [no('The White Stripes - Little Ghost'), no('The White Stripes - Little Acorn')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 0)
|
||||
|
||||
def test_fields_no_order(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_FIELDS_NO_ORDER
|
||||
f = [no('The White Stripes - Little Ghost'), no('Little Ghost - The White Stripes')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
|
||||
def test_tag_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
o1.artist = 'The White Stripes'
|
||||
o1.title = 'The Air Near My Fingers'
|
||||
o2.artist = 'The White Stripes'
|
||||
o2.title = 'The Air Near My Fingers'
|
||||
r = s.GetDupeGroups([o1,o2])
|
||||
eq_(len(r), 1)
|
||||
|
||||
def test_tag_with_album_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scanned_tags = set(['artist', 'album', 'title'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
o3 = no('bleh')
|
||||
o1.artist = 'The White Stripes'
|
||||
o1.title = 'The Air Near My Fingers'
|
||||
o1.album = 'Elephant'
|
||||
o2.artist = 'The White Stripes'
|
||||
o2.title = 'The Air Near My Fingers'
|
||||
o2.album = 'Elephant'
|
||||
o3.artist = 'The White Stripes'
|
||||
o3.title = 'The Air Near My Fingers'
|
||||
o3.album = 'foobar'
|
||||
r = s.GetDupeGroups([o1,o2,o3])
|
||||
eq_(len(r), 1)
|
||||
|
||||
def test_that_dash_in_tags_dont_create_new_fields(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scanned_tags = set(['artist', 'album', 'title'])
|
||||
s.min_match_percentage = 50
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
o1.artist = 'The White Stripes - a'
|
||||
o1.title = 'The Air Near My Fingers - a'
|
||||
o1.album = 'Elephant - a'
|
||||
o2.artist = 'The White Stripes - b'
|
||||
o2.title = 'The Air Near My Fingers - b'
|
||||
o2.album = 'Elephant - b'
|
||||
r = s.GetDupeGroups([o1,o2])
|
||||
eq_(len(r), 1)
|
||||
|
||||
def test_tag_scan_with_different_scanned(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scanned_tags = set(['track', 'year'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
o1.artist = 'The White Stripes'
|
||||
o1.title = 'some title'
|
||||
o1.track = 'foo'
|
||||
o1.year = 'bar'
|
||||
o2.artist = 'The White Stripes'
|
||||
o2.title = 'another title'
|
||||
o2.track = 'foo'
|
||||
o2.year = 'bar'
|
||||
r = s.GetDupeGroups([o1, o2])
|
||||
eq_(len(r), 1)
|
||||
|
||||
def test_tag_scan_only_scans_existing_tags(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scanned_tags = set(['artist', 'foo'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
o1.artist = 'The White Stripes'
|
||||
o1.foo = 'foo'
|
||||
o2.artist = 'The White Stripes'
|
||||
o2.foo = 'bar'
|
||||
r = s.GetDupeGroups([o1, o2])
|
||||
eq_(len(r), 1) # Because 'foo' is not scanned, they match
|
||||
|
||||
def test_tag_scan_converts_to_str(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scanned_tags = set(['track'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
o1.track = 42
|
||||
o2.track = 42
|
||||
try:
|
||||
r = s.GetDupeGroups([o1, o2])
|
||||
except TypeError:
|
||||
raise AssertionError()
|
||||
eq_(len(r), 1)
|
||||
|
||||
def test_tag_scan_non_ascii(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scanned_tags = set(['title'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
o1.title = u'foobar\u00e9'
|
||||
o2.title = u'foobar\u00e9'
|
||||
try:
|
||||
r = s.GetDupeGroups([o1, o2])
|
||||
except UnicodeEncodeError:
|
||||
raise AssertionError()
|
||||
eq_(len(r), 1)
|
||||
|
||||
def test_audio_content_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT_AUDIO
|
||||
f = [no('foo'), no('bar'), no('bleh')]
|
||||
f[0].md5 = 'foo'
|
||||
f[1].md5 = 'bar'
|
||||
f[2].md5 = 'bleh'
|
||||
f[0].md5partial = 'foo'
|
||||
f[1].md5partial = 'foo'
|
||||
f[2].md5partial = 'bleh'
|
||||
f[0].audiosize = 1
|
||||
f[1].audiosize = 1
|
||||
f[2].audiosize = 1
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
eq_(len(r[0]), 2)
|
||||
|
||||
def test_audio_content_scan_compare_sizes_first(self):
|
||||
class MyFile(no):
|
||||
@property
|
||||
def md5partial(file):
|
||||
raise AssertionError()
|
||||
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT_AUDIO
|
||||
f = [MyFile('foo'), MyFile('bar')]
|
||||
f[0].audiosize = 1
|
||||
f[1].audiosize = 2
|
||||
eq_(len(s.GetDupeGroups(f)), 0)
|
||||
|
||||
def test_ignore_list(self):
|
||||
s = Scanner()
|
||||
f1 = no('foobar')
|
||||
f2 = no('foobar')
|
||||
f3 = no('foobar')
|
||||
f1.path = Path('dir1/foobar')
|
||||
f2.path = Path('dir2/foobar')
|
||||
f3.path = Path('dir3/foobar')
|
||||
s.ignore_list.Ignore(str(f1.path),str(f2.path))
|
||||
s.ignore_list.Ignore(str(f1.path),str(f3.path))
|
||||
r = s.GetDupeGroups([f1,f2,f3])
|
||||
eq_(len(r), 1)
|
||||
g = r[0]
|
||||
eq_(len(g.dupes), 1)
|
||||
assert f1 not in g
|
||||
assert f2 in g
|
||||
assert f3 in g
|
||||
# Ignored matches are not counted as discarded
|
||||
eq_(s.discarded_file_count, 0)
|
||||
|
||||
def test_ignore_list_checks_for_unicode(self):
|
||||
#scanner was calling path_str for ignore list checks. Since the Path changes, it must
|
||||
#be unicode(path)
|
||||
s = Scanner()
|
||||
f1 = no('foobar')
|
||||
f2 = no('foobar')
|
||||
f3 = no('foobar')
|
||||
f1.path = Path(u'foo1\u00e9')
|
||||
f2.path = Path(u'foo2\u00e9')
|
||||
f3.path = Path(u'foo3\u00e9')
|
||||
s.ignore_list.Ignore(unicode(f1.path),unicode(f2.path))
|
||||
s.ignore_list.Ignore(unicode(f1.path),unicode(f3.path))
|
||||
r = s.GetDupeGroups([f1,f2,f3])
|
||||
eq_(len(r), 1)
|
||||
g = r[0]
|
||||
eq_(len(g.dupes), 1)
|
||||
assert f1 not in g
|
||||
assert f2 in g
|
||||
assert f3 in g
|
||||
|
||||
def test_file_evaluates_to_false(self):
|
||||
# A very wrong way to use any() was added at some point, causing resulting group list
|
||||
# to be empty.
|
||||
class FalseNamedObject(NamedObject):
|
||||
def __nonzero__(self):
|
||||
return False
|
||||
|
||||
|
||||
s = Scanner()
|
||||
f1 = FalseNamedObject('foobar')
|
||||
f2 = FalseNamedObject('foobar')
|
||||
r = s.GetDupeGroups([f1, f2])
|
||||
eq_(len(r), 1)
|
||||
|
||||
def test_size_threshold(self):
|
||||
# Only file equal or higher than the size_threshold in size are scanned
|
||||
s = Scanner()
|
||||
f1 = no('foo', 1)
|
||||
f2 = no('foo', 2)
|
||||
f3 = no('foo', 3)
|
||||
s.size_threshold = 2
|
||||
groups = s.GetDupeGroups([f1,f2,f3])
|
||||
eq_(len(groups), 1)
|
||||
[group] = groups
|
||||
eq_(len(group), 2)
|
||||
assert f1 not in group
|
||||
assert f2 in group
|
||||
assert f3 in group
|
||||
|
||||
def test_tie_breaker_path_deepness(self):
|
||||
# If there is a tie in prioritization, path deepness is used as a tie breaker
|
||||
s = Scanner()
|
||||
o1, o2 = no('foo'), no('foo')
|
||||
o1.path = Path('foo')
|
||||
o2.path = Path('foo/bar')
|
||||
[group] = s.GetDupeGroups([o1, o2])
|
||||
assert group.ref is o2
|
||||
|
||||
def test_tie_breaker_copy(self):
|
||||
# if copy is in the words used (even if it has a deeper path), it becomes a dupe
|
||||
s = Scanner()
|
||||
o1, o2 = no('foo bar Copy'), no('foo bar')
|
||||
o1.path = Path('deeper/path')
|
||||
o2.path = Path('foo')
|
||||
[group] = s.GetDupeGroups([o1, o2])
|
||||
assert group.ref is o2
|
||||
|
||||
def test_tie_breaker_same_name_plus_digit(self):
|
||||
# if ref has the same words as dupe, but has some just one extra word which is a digit, it
|
||||
# becomes a dupe
|
||||
s = Scanner()
|
||||
o1, o2 = no('foo bar 42'), no('foo bar')
|
||||
o1.path = Path('deeper/path')
|
||||
o2.path = Path('foo')
|
||||
[group] = s.GetDupeGroups([o1, o2])
|
||||
assert group.ref is o2
|
||||
|
||||
def test_partial_group_match(self):
|
||||
# Count the number od discarded matches (when a file doesn't match all other dupes of the
|
||||
# group) in Scanner.discarded_file_count
|
||||
s = Scanner()
|
||||
o1, o2, o3 = no('a b'), no('a'), no('b')
|
||||
s.min_match_percentage = 50
|
||||
[group] = s.GetDupeGroups([o1, o2, o3])
|
||||
eq_(len(group), 2)
|
||||
assert o1 in group
|
||||
assert o2 in group
|
||||
assert o3 not in group
|
||||
eq_(s.discarded_file_count, 1)
|
||||
|
||||
|
||||
class ScannerTest(TestCase):
|
||||
def test_dont_group_files_that_dont_exist(self):
|
||||
# when creating groups, check that files exist first. It's possible that these files have
|
||||
# been moved during the scan by the user.
|
||||
# In this test, we have to delete one of the files between the get_matches() part and the
|
||||
# get_groups() part.
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
p = self.tmppath()
|
||||
io.open(p + 'file1', 'w').write('foo')
|
||||
io.open(p + 'file2', 'w').write('foo')
|
||||
file1, file2 = fs.get_files(p)
|
||||
def getmatches(*args, **kw):
|
||||
io.remove(file2.path)
|
||||
return [Match(file1, file2, 100)]
|
||||
s._getmatches = getmatches
|
||||
|
||||
assert not s.GetDupeGroups([file1, file2])
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
WARNING ABOUT THE HS LICENSE AND PyQt
|
||||
|
||||
Although Qt is now LGPL licensed, PyQt still is dual licensed. Until Nokia buys Riverbank and
|
||||
releases PyQt as LGPL, users of this part of the code (The PyQt-based GUI code) have to use the
|
||||
GPL version of PyQt, unless they possess a commercial license to it.
|
||||
|
||||
There is no problem to this AS LONG AS YOU DON'T REDISTRIBUTE HS LICENSED CODE. The GPL license, from the point of view of the user, is very permissive. You can do WHATEVER you want with the GPLed version of PyQt, as long as you don't redistribute any of the code, or code dependent on it. When you do, the code you distribute has to be GPL compliant. The HS license is NOT, I repeat, NOT compliant with the GPL.
|
||||
|
||||
So, what does it all mean? You have no restriction on the usage of the PyQt-dependent-HS-licensed code, but unless you possess a commercial PyQt license, Hardcoded Software (or anyone) cannot accept any contribution from you for this part of the code.
|
||||
|
||||
Note that this only affects the PyQt dependent code, and not any other part of HS licensed code (if it has "import PyQt4" in it, it's PyQt dependent code). For the rest of the code, the only restrictions that apply are the ones from the HS license.
|
||||
258
base/qt/app.py
258
base/qt/app.py
@@ -1,258 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-25
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import os
|
||||
import os.path as op
|
||||
|
||||
from PyQt4.QtCore import Qt, QTimer, QObject, QCoreApplication, QUrl, SIGNAL
|
||||
from PyQt4.QtGui import QProgressDialog, QDesktopServices, QFileDialog, QDialog, QMessageBox
|
||||
|
||||
from hsutil import job
|
||||
from hsutil.reg import RegistrationRequired
|
||||
|
||||
from dupeguru import fs
|
||||
from dupeguru.app import (DupeGuru as DupeGuruBase, JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_COPY,
|
||||
JOB_DELETE)
|
||||
|
||||
from qtlib.about_box import AboutBox
|
||||
from qtlib.progress import Progress
|
||||
from qtlib.reg import Registration
|
||||
|
||||
from . import platform
|
||||
|
||||
from .main_window import MainWindow
|
||||
from .directories_dialog import DirectoriesDialog
|
||||
|
||||
JOBID2TITLE = {
|
||||
JOB_SCAN: "Scanning for duplicates",
|
||||
JOB_LOAD: "Loading",
|
||||
JOB_MOVE: "Moving",
|
||||
JOB_COPY: "Copying",
|
||||
JOB_DELETE: "Sending files to the recycle bin",
|
||||
}
|
||||
|
||||
def demo_method(method):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return method(self, *args, **kwargs)
|
||||
except RegistrationRequired:
|
||||
msg = "The demo version of dupeGuru only allows 10 actions (delete/move/copy) per session."
|
||||
QMessageBox.information(self.main_window, 'Demo', msg)
|
||||
|
||||
return wrapper
|
||||
|
||||
class DupeGuru(DupeGuruBase, QObject):
|
||||
LOGO_NAME = '<replace this>'
|
||||
NAME = '<replace this>'
|
||||
DELTA_COLUMNS = frozenset()
|
||||
DEMO_LIMIT_DESC = "In the demo version, only 10 duplicates per session can be sent to the recycle bin, moved or copied."
|
||||
|
||||
def __init__(self, data_module, appid):
|
||||
appdata = unicode(QDesktopServices.storageLocation(QDesktopServices.DataLocation))
|
||||
if not op.exists(appdata):
|
||||
os.makedirs(appdata)
|
||||
# For basicConfig() to work, we have to be sure that no logging has taken place before this call.
|
||||
logging.basicConfig(filename=op.join(appdata, 'debug.log'), level=logging.WARNING)
|
||||
DupeGuruBase.__init__(self, data_module, appdata, appid)
|
||||
QObject.__init__(self)
|
||||
self._setup()
|
||||
|
||||
#--- Private
|
||||
def _setup(self):
|
||||
self.selected_dupe = None
|
||||
self.prefs = self._create_preferences()
|
||||
self.prefs.load()
|
||||
self._update_options()
|
||||
self.main_window = self._create_main_window()
|
||||
self._progress = Progress(self.main_window)
|
||||
self.directories_dialog = DirectoriesDialog(self.main_window, self)
|
||||
self.details_dialog = self._create_details_dialog(self.main_window)
|
||||
self.preferences_dialog = self._create_preferences_dialog(self.main_window)
|
||||
self.about_box = AboutBox(self.main_window, self)
|
||||
|
||||
self.reg = Registration(self)
|
||||
self.set_registration(self.prefs.registration_code, self.prefs.registration_email)
|
||||
if not self.registered:
|
||||
# The timer scheme is because if the nag is not shown before the application is
|
||||
# completely initialized, the nag will be shown before the app shows up in the task bar
|
||||
# In some circumstances, the nag is hidden by other window, which may make the user think
|
||||
# that the application haven't launched.
|
||||
self._nagTimer = QTimer()
|
||||
self.connect(self._nagTimer, SIGNAL('timeout()'), self.mustShowNag)
|
||||
self._nagTimer.start(0)
|
||||
self.main_window.show()
|
||||
self.load()
|
||||
|
||||
self.connect(QCoreApplication.instance(), SIGNAL('aboutToQuit()'), self.application_will_terminate)
|
||||
self.connect(self._progress, SIGNAL('finished(QString)'), self.job_finished)
|
||||
|
||||
def _setup_as_registered(self):
|
||||
self.prefs.registration_code = self.registration_code
|
||||
self.prefs.registration_email = self.registration_email
|
||||
self.main_window.actionRegister.setVisible(False)
|
||||
self.about_box.registerButton.hide()
|
||||
self.about_box.registeredEmailLabel.setText(self.prefs.registration_email)
|
||||
|
||||
def _update_options(self):
|
||||
self.scanner.mix_file_kind = self.prefs.mix_file_kind
|
||||
self.options['escape_filter_regexp'] = self.prefs.use_regexp
|
||||
self.options['clean_empty_dirs'] = self.prefs.remove_empty_folders
|
||||
|
||||
#--- Virtual
|
||||
def _create_details_dialog(self, parent):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _create_main_window(self):
|
||||
return MainWindow(app=self)
|
||||
|
||||
def _create_preferences(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _create_preferences_dialog(self, parent):
|
||||
raise NotImplementedError()
|
||||
|
||||
#--- Override
|
||||
@staticmethod
|
||||
def _recycle_dupe(dupe):
|
||||
platform.recycle_file(dupe.path)
|
||||
|
||||
def _start_job(self, jobid, func):
|
||||
title = JOBID2TITLE[jobid]
|
||||
try:
|
||||
j = self._progress.create_job()
|
||||
self._progress.run(jobid, title, func, args=(j, ))
|
||||
except job.JobInProgressError:
|
||||
msg = "A previous action is still hanging in there. You can't start a new one yet. Wait a few seconds, then try again."
|
||||
QMessageBox.information(self.main_window, 'Action in progress', msg)
|
||||
|
||||
#--- Public
|
||||
def add_dupes_to_ignore_list(self, duplicates):
|
||||
for dupe in duplicates:
|
||||
self.add_to_ignore_list(dupe)
|
||||
self.remove_duplicates(duplicates)
|
||||
|
||||
def apply_filter(self, filter):
|
||||
DupeGuruBase.apply_filter(self, filter)
|
||||
self.emit(SIGNAL('resultsChanged()'))
|
||||
|
||||
def askForRegCode(self):
|
||||
self.reg.ask_for_code()
|
||||
|
||||
@demo_method
|
||||
def copy_or_move_marked(self, copy):
|
||||
opname = 'copy' if copy else 'move'
|
||||
title = "Select a directory to {0} marked files to".format(opname)
|
||||
flags = QFileDialog.ShowDirsOnly
|
||||
destination = unicode(QFileDialog.getExistingDirectory(self.main_window, title, '', flags))
|
||||
if not destination:
|
||||
return
|
||||
recreate_path = self.prefs.destination_type
|
||||
DupeGuruBase.copy_or_move_marked(self, copy, destination, recreate_path)
|
||||
|
||||
delete_marked = demo_method(DupeGuruBase.delete_marked)
|
||||
|
||||
def make_reference(self, duplicates):
|
||||
DupeGuruBase.make_reference(self, duplicates)
|
||||
self.emit(SIGNAL('resultsChanged()'))
|
||||
|
||||
def mark_all(self):
|
||||
self.results.mark_all()
|
||||
self.emit(SIGNAL('dupeMarkingChanged()'))
|
||||
|
||||
def mark_invert(self):
|
||||
self.results.mark_invert()
|
||||
self.emit(SIGNAL('dupeMarkingChanged()'))
|
||||
|
||||
def mark_none(self):
|
||||
self.results.mark_none()
|
||||
self.emit(SIGNAL('dupeMarkingChanged()'))
|
||||
|
||||
def openDebugLog(self):
|
||||
debugLogPath = op.join(self.appdata, 'debug.log')
|
||||
url = QUrl.fromLocalFile(debugLogPath)
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
def open_selected(self):
|
||||
if self.selected_dupe is None:
|
||||
return
|
||||
url = QUrl.fromLocalFile(unicode(self.selected_dupe.path))
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
def remove_duplicates(self, duplicates):
|
||||
self.results.remove_duplicates(duplicates)
|
||||
self.emit(SIGNAL('resultsChanged()'))
|
||||
|
||||
def remove_marked_duplicates(self):
|
||||
marked = [d for d in self.results.dupes if self.results.is_marked(d)]
|
||||
self.remove_duplicates(marked)
|
||||
|
||||
def rename_dupe(self, dupe, newname):
|
||||
try:
|
||||
dupe.rename(newname)
|
||||
return True
|
||||
except (IndexError, fs.FSError) as e:
|
||||
logging.warning("dupeGuru Warning: %s" % unicode(e))
|
||||
return False
|
||||
|
||||
def reveal_selected(self):
|
||||
if self.selected_dupe is None:
|
||||
return
|
||||
url = QUrl.fromLocalFile(unicode(self.selected_dupe.path[:-1]))
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
def select_duplicate(self, dupe):
|
||||
self.selected_dupe = dupe
|
||||
self.emit(SIGNAL('duplicateSelected()'))
|
||||
|
||||
def show_about_box(self):
|
||||
self.about_box.show()
|
||||
|
||||
def show_details(self):
|
||||
self.details_dialog.show()
|
||||
|
||||
def show_directories(self):
|
||||
self.directories_dialog.show()
|
||||
|
||||
def show_help(self):
|
||||
url = QUrl.fromLocalFile(op.abspath('help/intro.htm'))
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
def show_preferences(self):
|
||||
self.preferences_dialog.load()
|
||||
result = self.preferences_dialog.exec_()
|
||||
if result == QDialog.Accepted:
|
||||
self.preferences_dialog.save()
|
||||
self.prefs.save()
|
||||
self._update_options()
|
||||
|
||||
def toggle_marking_for_dupes(self, dupes):
|
||||
for dupe in dupes:
|
||||
self.results.mark_toggle(dupe)
|
||||
self.emit(SIGNAL('dupeMarkingChanged()'))
|
||||
|
||||
#--- Events
|
||||
def application_will_terminate(self):
|
||||
self.save()
|
||||
self.save_ignore_list()
|
||||
|
||||
def mustShowNag(self):
|
||||
self._nagTimer.stop() # must be shown only once
|
||||
self.reg.show_nag()
|
||||
|
||||
def job_finished(self, jobid):
|
||||
self.emit(SIGNAL('resultsChanged()'))
|
||||
if jobid == JOB_LOAD:
|
||||
self.emit(SIGNAL('directoriesChanged()'))
|
||||
if jobid in (JOB_MOVE, JOB_COPY, JOB_DELETE) and self.last_op_error_count > 0:
|
||||
msg = "{0} files could not be processed.".format(self.results.mark_count)
|
||||
QMessageBox.warning(self.main_window, 'Warning', msg)
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file alias="details">images/details32.png</file>
|
||||
<file alias="logo_pe">images/dgpe_logo_32.png</file>
|
||||
<file alias="logo_pe_big">images/dgpe_logo_128.png</file>
|
||||
<file alias="logo_me">images/dgme_logo_32.png</file>
|
||||
<file alias="logo_me_big">images/dgme_logo_128.png</file>
|
||||
<file alias="logo_se">images/dgse_logo_32.png</file>
|
||||
<file alias="logo_se_big">images/dgse_logo_128.png</file>
|
||||
<file alias="folder">images/folderwin32.png</file>
|
||||
<file alias="preferences">images/preferences32.png</file>
|
||||
<file alias="actions">images/actions32.png</file>
|
||||
<file alias="delta">images/delta32.png</file>
|
||||
<file alias="power_marker">images/power_marker32.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -1,85 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-25
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from PyQt4.QtCore import SIGNAL, Qt
|
||||
from PyQt4.QtGui import QDialog, QFileDialog, QHeaderView
|
||||
|
||||
from . import platform
|
||||
from .directories_dialog_ui import Ui_DirectoriesDialog
|
||||
from .directories_model import DirectoriesModel, DirectoriesDelegate
|
||||
|
||||
class DirectoriesDialog(QDialog, Ui_DirectoriesDialog):
|
||||
def __init__(self, parent, app):
|
||||
flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint
|
||||
QDialog.__init__(self, parent, flags)
|
||||
self.app = app
|
||||
self.lastAddedFolder = platform.INITIAL_FOLDER_IN_DIALOGS
|
||||
self._setupUi()
|
||||
self._updateRemoveButton()
|
||||
|
||||
self.connect(self.doneButton, SIGNAL('clicked()'), self.doneButtonClicked)
|
||||
self.connect(self.addButton, SIGNAL('clicked()'), self.addButtonClicked)
|
||||
self.connect(self.removeButton, SIGNAL('clicked()'), self.removeButtonClicked)
|
||||
self.connect(self.treeView.selectionModel(), SIGNAL('selectionChanged(QItemSelection,QItemSelection)'), self.selectionChanged)
|
||||
self.connect(self.app, SIGNAL('directoriesChanged()'), self.directoriesChanged)
|
||||
|
||||
def _setupUi(self):
|
||||
self.setupUi(self)
|
||||
# Stuff that can't be done in the Designer
|
||||
self.directoriesModel = DirectoriesModel(self.app)
|
||||
self.directoriesDelegate = DirectoriesDelegate()
|
||||
self.treeView.setItemDelegate(self.directoriesDelegate)
|
||||
self.treeView.setModel(self.directoriesModel)
|
||||
|
||||
header = self.treeView.header()
|
||||
header.setStretchLastSection(False)
|
||||
header.setResizeMode(0, QHeaderView.Stretch)
|
||||
header.setResizeMode(1, QHeaderView.Fixed)
|
||||
header.resizeSection(1, 100)
|
||||
|
||||
def _updateRemoveButton(self):
|
||||
indexes = self.treeView.selectedIndexes()
|
||||
if not indexes:
|
||||
self.removeButton.setEnabled(False)
|
||||
return
|
||||
self.removeButton.setEnabled(True)
|
||||
index = indexes[0]
|
||||
node = index.internalPointer()
|
||||
# label = 'Remove' if node.parent is None else 'Exclude'
|
||||
|
||||
def addButtonClicked(self):
|
||||
title = u"Select a directory to add to the scanning list"
|
||||
flags = QFileDialog.ShowDirsOnly
|
||||
dirpath = unicode(QFileDialog.getExistingDirectory(self, title, self.lastAddedFolder, flags))
|
||||
if not dirpath:
|
||||
return
|
||||
self.lastAddedFolder = dirpath
|
||||
self.app.add_directory(dirpath)
|
||||
self.directoriesModel.reset()
|
||||
|
||||
def directoriesChanged(self):
|
||||
self.directoriesModel.reset()
|
||||
|
||||
def doneButtonClicked(self):
|
||||
self.hide()
|
||||
|
||||
def removeButtonClicked(self):
|
||||
indexes = self.treeView.selectedIndexes()
|
||||
if not indexes:
|
||||
return
|
||||
index = indexes[0]
|
||||
node = index.internalPointer()
|
||||
if node.parent is None:
|
||||
row = index.row()
|
||||
del self.app.directories[row]
|
||||
self.directoriesModel.reset()
|
||||
|
||||
def selectionChanged(self, selected, deselected):
|
||||
self._updateRemoveButton()
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DirectoriesDialog</class>
|
||||
<widget class="QDialog" name="DirectoriesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>420</width>
|
||||
<height>338</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Directories</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTreeView" name="treeView">
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
|
||||
</property>
|
||||
<property name="dragDropOverwriteMode">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="headerStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>91</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Del</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>91</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="doneButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>91</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Done</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,332 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-25
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from PyQt4.QtCore import Qt, QCoreApplication, QProcess, SIGNAL, QUrl
|
||||
from PyQt4.QtGui import (QMainWindow, QMenu, QPixmap, QIcon, QToolButton, QLabel, QHeaderView,
|
||||
QMessageBox, QInputDialog, QLineEdit, QItemSelectionModel, QDesktopServices)
|
||||
|
||||
from hsutil.misc import nonone
|
||||
|
||||
from dupeguru.app import NoScannableFileError, AllFilesAreRefError
|
||||
|
||||
import dg_rc
|
||||
from main_window_ui import Ui_MainWindow
|
||||
from results_model import ResultsDelegate, ResultsModel
|
||||
|
||||
class MainWindow(QMainWindow, Ui_MainWindow):
|
||||
def __init__(self, app):
|
||||
QMainWindow.__init__(self, None)
|
||||
self.app = app
|
||||
self._last_filter = None
|
||||
self._setupUi()
|
||||
self.resultsDelegate = ResultsDelegate()
|
||||
self.resultsModel = ResultsModel(self.app)
|
||||
self.resultsView.setModel(self.resultsModel)
|
||||
self.resultsView.setItemDelegate(self.resultsDelegate)
|
||||
self._load_columns()
|
||||
self._update_column_actions_status()
|
||||
self.resultsView.expandAll()
|
||||
self._update_status_line()
|
||||
|
||||
self.connect(self.app, SIGNAL('resultsChanged()'), self.resultsChanged)
|
||||
self.connect(self.app, SIGNAL('dupeMarkingChanged()'), self.dupeMarkingChanged)
|
||||
self.connect(self.actionQuit, SIGNAL('triggered()'), QCoreApplication.instance().quit)
|
||||
self.connect(self.resultsView.selectionModel(), SIGNAL('selectionChanged(QItemSelection,QItemSelection)'), self.selectionChanged)
|
||||
self.connect(self.menuColumns, SIGNAL('triggered(QAction*)'), self.columnToggled)
|
||||
self.connect(QCoreApplication.instance(), SIGNAL('aboutToQuit()'), self.application_will_terminate)
|
||||
self.connect(self.resultsModel, SIGNAL('modelReset()'), self.resultsReset)
|
||||
self.connect(self.resultsView, SIGNAL('doubleClicked()'), self.resultsDoubleClicked)
|
||||
|
||||
def _setupUi(self):
|
||||
self.setupUi(self)
|
||||
# Stuff that can't be setup in the Designer
|
||||
h = self.resultsView.header()
|
||||
h.setHighlightSections(False)
|
||||
h.setMovable(True)
|
||||
h.setStretchLastSection(False)
|
||||
h.setDefaultAlignment(Qt.AlignLeft)
|
||||
|
||||
self.setWindowTitle(QCoreApplication.instance().applicationName())
|
||||
self.actionScan.setIcon(QIcon(QPixmap(':/%s' % self.app.LOGO_NAME)))
|
||||
|
||||
# Columns menu
|
||||
menu = self.menuColumns
|
||||
self._column_actions = []
|
||||
for index, column in enumerate(self.app.data.COLUMNS):
|
||||
action = menu.addAction(column['display'])
|
||||
action.setCheckable(True)
|
||||
action.column_index = index
|
||||
self._column_actions.append(action)
|
||||
menu.addSeparator()
|
||||
action = menu.addAction("Reset to Defaults")
|
||||
action.column_index = -1
|
||||
|
||||
# Action menu
|
||||
actionMenu = QMenu('Actions', self.toolBar)
|
||||
actionMenu.setIcon(QIcon(QPixmap(":/actions")))
|
||||
actionMenu.addAction(self.actionDeleteMarked)
|
||||
actionMenu.addAction(self.actionMoveMarked)
|
||||
actionMenu.addAction(self.actionCopyMarked)
|
||||
actionMenu.addAction(self.actionRemoveMarked)
|
||||
actionMenu.addSeparator()
|
||||
actionMenu.addAction(self.actionRemoveSelected)
|
||||
actionMenu.addAction(self.actionIgnoreSelected)
|
||||
actionMenu.addAction(self.actionMakeSelectedReference)
|
||||
actionMenu.addSeparator()
|
||||
actionMenu.addAction(self.actionOpenSelected)
|
||||
actionMenu.addAction(self.actionRevealSelected)
|
||||
actionMenu.addAction(self.actionRenameSelected)
|
||||
self.actionActions.setMenu(actionMenu)
|
||||
button = QToolButton(self.toolBar)
|
||||
button.setDefaultAction(actionMenu.menuAction())
|
||||
button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||
self.actionsButton = button
|
||||
self.toolBar.insertWidget(self.actionActions, button) # the action is a placeholder
|
||||
self.toolBar.removeAction(self.actionActions)
|
||||
|
||||
self.statusLabel = QLabel(self)
|
||||
self.statusbar.addPermanentWidget(self.statusLabel, 1)
|
||||
|
||||
#--- Private
|
||||
def _confirm(self, title, msg, default_button=QMessageBox.Yes):
|
||||
buttons = QMessageBox.Yes | QMessageBox.No
|
||||
answer = QMessageBox.question(self, title, msg, buttons, default_button)
|
||||
return answer == QMessageBox.Yes
|
||||
|
||||
def _load_columns(self):
|
||||
h = self.resultsView.header()
|
||||
h.setResizeMode(QHeaderView.Interactive)
|
||||
prefs = self.app.prefs
|
||||
attrs = zip(prefs.columns_width, prefs.columns_visible)
|
||||
for index, (width, visible) in enumerate(attrs):
|
||||
h.resizeSection(index, width)
|
||||
h.setSectionHidden(index, not visible)
|
||||
h.setResizeMode(0, QHeaderView.Stretch)
|
||||
|
||||
def _redraw_results(self):
|
||||
# HACK. this is the only way I found to update the widget without reseting everything
|
||||
self.resultsView.scroll(0, 1)
|
||||
self.resultsView.scroll(0, -1)
|
||||
|
||||
def _save_columns(self):
|
||||
h = self.resultsView.header()
|
||||
widths = []
|
||||
visible = []
|
||||
for i in range(len(self.app.data.COLUMNS)):
|
||||
widths.append(h.sectionSize(i))
|
||||
visible.append(not h.isSectionHidden(i))
|
||||
prefs = self.app.prefs
|
||||
prefs.columns_width = widths
|
||||
prefs.columns_visible = visible
|
||||
prefs.save()
|
||||
|
||||
def _update_column_actions_status(self):
|
||||
h = self.resultsView.header()
|
||||
for action in self._column_actions:
|
||||
colid = action.column_index
|
||||
action.setChecked(not h.isSectionHidden(colid))
|
||||
|
||||
def _update_status_line(self):
|
||||
self.statusLabel.setText(self.app.stat_line)
|
||||
|
||||
#--- Actions
|
||||
def aboutTriggered(self):
|
||||
self.app.show_about_box()
|
||||
|
||||
def actionsTriggered(self):
|
||||
self.actionsButton.showMenu()
|
||||
|
||||
def addToIgnoreListTriggered(self):
|
||||
dupes = self.resultsView.selectedDupes()
|
||||
if not dupes:
|
||||
return
|
||||
title = "Add to Ignore List"
|
||||
msg = "All selected {0} matches are going to be ignored in all subsequent scans. Continue?".format(len(dupes))
|
||||
if self._confirm(title, msg):
|
||||
self.app.add_dupes_to_ignore_list(dupes)
|
||||
|
||||
def applyFilterTriggered(self):
|
||||
title = "Apply Filter"
|
||||
msg = "Type the filter you want to apply on your results. See help for details."
|
||||
text = nonone(self._last_filter, '[*]')
|
||||
answer, ok = QInputDialog.getText(self, title, msg, QLineEdit.Normal, text)
|
||||
if not ok:
|
||||
return
|
||||
answer = unicode(answer)
|
||||
self.app.apply_filter(answer)
|
||||
self._last_filter = answer
|
||||
|
||||
def cancelFilterTriggered(self):
|
||||
self.app.apply_filter('')
|
||||
|
||||
def checkForUpdateTriggered(self):
|
||||
QProcess.execute('updater.exe', ['/checknow'])
|
||||
|
||||
def clearIgnoreListTriggered(self):
|
||||
title = "Clear Ignore List"
|
||||
count = len(self.app.scanner.ignore_list)
|
||||
if not count:
|
||||
QMessageBox.information(self, title, "Nothing to clear.")
|
||||
return
|
||||
msg = "Do you really want to remove all {0} items from the ignore list?".format(count)
|
||||
if self._confirm(title, msg, QMessageBox.No):
|
||||
self.app.scanner.ignore_list.Clear()
|
||||
QMessageBox.information(self, title, "Ignore list cleared.")
|
||||
|
||||
def copyTriggered(self):
|
||||
self.app.copy_or_move_marked(True)
|
||||
|
||||
def deleteTriggered(self):
|
||||
count = self.app.results.mark_count
|
||||
if not count:
|
||||
return
|
||||
title = "Delete duplicates"
|
||||
msg = "You are about to send {0} files to the recycle bin. Continue?".format(count)
|
||||
if self._confirm(title, msg):
|
||||
self.app.delete_marked()
|
||||
|
||||
def deltaTriggered(self):
|
||||
self.resultsModel.delta = self.actionDelta.isChecked()
|
||||
self._redraw_results()
|
||||
|
||||
def detailsTriggered(self):
|
||||
self.app.show_details()
|
||||
|
||||
def directoriesTriggered(self):
|
||||
self.app.show_directories()
|
||||
|
||||
def exportTriggered(self):
|
||||
h = self.resultsView.header()
|
||||
column_ids = []
|
||||
for i in range(len(self.app.data.COLUMNS)):
|
||||
if not h.isSectionHidden(i):
|
||||
column_ids.append(str(i))
|
||||
exported_path = self.app.export_to_xhtml(column_ids)
|
||||
url = QUrl.fromLocalFile(exported_path)
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
def makeReferenceTriggered(self):
|
||||
self.app.make_reference(self.resultsView.selectedDupes())
|
||||
|
||||
def markAllTriggered(self):
|
||||
self.app.mark_all()
|
||||
|
||||
def markInvertTriggered(self):
|
||||
self.app.mark_invert()
|
||||
|
||||
def markNoneTriggered(self):
|
||||
self.app.mark_none()
|
||||
|
||||
def markSelectedTriggered(self):
|
||||
dupes = self.resultsView.selectedDupes()
|
||||
self.app.toggle_marking_for_dupes(dupes)
|
||||
|
||||
def moveTriggered(self):
|
||||
self.app.copy_or_move_marked(False)
|
||||
|
||||
def openDebugLogTriggered(self):
|
||||
self.app.openDebugLog()
|
||||
|
||||
def openTriggered(self):
|
||||
self.app.open_selected()
|
||||
|
||||
def powerMarkerTriggered(self):
|
||||
self.resultsModel.power_marker = self.actionPowerMarker.isChecked()
|
||||
|
||||
def preferencesTriggered(self):
|
||||
self.app.show_preferences()
|
||||
|
||||
def registerTrigerred(self):
|
||||
self.app.ask_for_reg_code()
|
||||
|
||||
def removeMarkedTriggered(self):
|
||||
count = self.app.results.mark_count
|
||||
if not count:
|
||||
return
|
||||
title = "Remove duplicates"
|
||||
msg = "You are about to remove {0} files from results. Continue?".format(count)
|
||||
if self._confirm(title, msg):
|
||||
self.app.remove_marked_duplicates()
|
||||
|
||||
def removeSelectedTriggered(self):
|
||||
dupes = self.resultsView.selectedDupes()
|
||||
if not dupes:
|
||||
return
|
||||
title = "Remove duplicates"
|
||||
msg = "You are about to remove {0} files from results. Continue?".format(len(dupes))
|
||||
if self._confirm(title, msg):
|
||||
self.app.remove_duplicates(dupes)
|
||||
|
||||
def renameTriggered(self):
|
||||
self.resultsView.edit(self.resultsView.selectionModel().currentIndex())
|
||||
|
||||
def revealTriggered(self):
|
||||
self.app.reveal_selected()
|
||||
|
||||
def scanTriggered(self):
|
||||
title = "Start a new scan"
|
||||
if len(self.app.results.groups) > 0:
|
||||
msg = "Are you sure you want to start a new duplicate scan?"
|
||||
if not self._confirm(title, msg):
|
||||
return
|
||||
try:
|
||||
self.app.start_scanning()
|
||||
except NoScannableFileError:
|
||||
msg = "The selected directories contain no scannable file."
|
||||
QMessageBox.warning(self, title, msg)
|
||||
self.app.show_directories()
|
||||
except AllFilesAreRefError:
|
||||
msg = "You cannot make a duplicate scan with only reference directories."
|
||||
QMessageBox.warning(self, title, msg)
|
||||
|
||||
def showHelpTriggered(self):
|
||||
self.app.show_help()
|
||||
|
||||
#--- Events
|
||||
def application_will_terminate(self):
|
||||
self._save_columns()
|
||||
|
||||
def columnToggled(self, action):
|
||||
colid = action.column_index
|
||||
if colid == -1:
|
||||
self.app.prefs.reset_columns()
|
||||
self._load_columns()
|
||||
else:
|
||||
h = self.resultsView.header()
|
||||
h.setSectionHidden(colid, not h.isSectionHidden(colid))
|
||||
self._update_column_actions_status()
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
self.actionActions.menu().exec_(event.globalPos())
|
||||
|
||||
def dupeMarkingChanged(self):
|
||||
self._redraw_results()
|
||||
self._update_status_line()
|
||||
|
||||
def resultsChanged(self):
|
||||
self.resultsView.model().reset()
|
||||
|
||||
def resultsDoubleClicked(self):
|
||||
self.app.open_selected()
|
||||
|
||||
def resultsReset(self):
|
||||
self.resultsView.expandAll()
|
||||
dupe = self.app.selected_dupe
|
||||
if dupe is not None:
|
||||
[modelIndex] = self.resultsModel.indexesForDupes([dupe])
|
||||
if modelIndex.isValid():
|
||||
flags = QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows
|
||||
self.resultsView.selectionModel().setCurrentIndex(modelIndex, flags)
|
||||
self._update_status_line()
|
||||
|
||||
def selectionChanged(self, selected, deselected):
|
||||
index = self.resultsView.selectionModel().currentIndex()
|
||||
dupe = index.internalPointer().dupe if index.isValid() else None
|
||||
self.app.select_duplicate(dupe)
|
||||
|
||||
@@ -1,957 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>630</width>
|
||||
<height>514</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>dupeGuru</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ResultsView" name="resultsView">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="itemsExpandable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="expandsOnDoubleClick">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="headerStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>630</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuColumns">
|
||||
<property name="title">
|
||||
<string>Columns</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuActions">
|
||||
<property name="title">
|
||||
<string>Actions</string>
|
||||
</property>
|
||||
<addaction name="actionDeleteMarked"/>
|
||||
<addaction name="actionMoveMarked"/>
|
||||
<addaction name="actionCopyMarked"/>
|
||||
<addaction name="actionRemoveMarked"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionRemoveSelected"/>
|
||||
<addaction name="actionIgnoreSelected"/>
|
||||
<addaction name="actionMakeSelectedReference"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionOpenSelected"/>
|
||||
<addaction name="actionRevealSelected"/>
|
||||
<addaction name="actionRenameSelected"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionApplyFilter"/>
|
||||
<addaction name="actionCancelFilter"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuMark">
|
||||
<property name="title">
|
||||
<string>Mark</string>
|
||||
</property>
|
||||
<addaction name="actionMarkAll"/>
|
||||
<addaction name="actionMarkNone"/>
|
||||
<addaction name="actionInvertMarking"/>
|
||||
<addaction name="actionMarkSelected"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuModes">
|
||||
<property name="title">
|
||||
<string>Modes</string>
|
||||
</property>
|
||||
<addaction name="actionPowerMarker"/>
|
||||
<addaction name="actionDelta"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuWindow">
|
||||
<property name="title">
|
||||
<string>Windows</string>
|
||||
</property>
|
||||
<addaction name="actionDetails"/>
|
||||
<addaction name="actionDirectories"/>
|
||||
<addaction name="actionPreferences"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionShowHelp"/>
|
||||
<addaction name="actionRegister"/>
|
||||
<addaction name="actionCheckForUpdate"/>
|
||||
<addaction name="actionOpenDebugLog"/>
|
||||
<addaction name="actionAbout"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionScan"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExport"/>
|
||||
<addaction name="actionClearIgnoreList"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionQuit"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuMark"/>
|
||||
<addaction name="menuActions"/>
|
||||
<addaction name="menuColumns"/>
|
||||
<addaction name="menuModes"/>
|
||||
<addaction name="menuWindow"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||
</property>
|
||||
<property name="floatable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionScan"/>
|
||||
<addaction name="actionActions"/>
|
||||
<addaction name="actionDirectories"/>
|
||||
<addaction name="actionDetails"/>
|
||||
<addaction name="actionPreferences"/>
|
||||
<addaction name="actionDelta"/>
|
||||
<addaction name="actionPowerMarker"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar">
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<action name="actionScan">
|
||||
<property name="icon">
|
||||
<iconset resource="dg.qrc">
|
||||
<normaloff>:/logo_pe</normaloff>:/logo_pe</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start Scan</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Start scanning for duplicates</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDirectories">
|
||||
<property name="icon">
|
||||
<iconset resource="dg.qrc">
|
||||
<normaloff>:/folder</normaloff>:/folder</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Directories</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+4</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDetails">
|
||||
<property name="icon">
|
||||
<iconset resource="dg.qrc">
|
||||
<normaloff>:/details</normaloff>:/details</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Details</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+3</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionActions">
|
||||
<property name="icon">
|
||||
<iconset resource="dg.qrc">
|
||||
<normaloff>:/actions</normaloff>:/actions</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Actions</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPreferences">
|
||||
<property name="icon">
|
||||
<iconset resource="dg.qrc">
|
||||
<normaloff>:/preferences</normaloff>:/preferences</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Preferences</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+5</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelta">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="dg.qrc">
|
||||
<normaloff>:/delta</normaloff>:/delta</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delta Values</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+2</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPowerMarker">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="dg.qrc">
|
||||
<normaloff>:/power_marker</normaloff>:/power_marker</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Power Marker</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+1</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDeleteMarked">
|
||||
<property name="text">
|
||||
<string>Send Marked to Recycle Bin</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+D</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMoveMarked">
|
||||
<property name="text">
|
||||
<string>Move Marked to...</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+M</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopyMarked">
|
||||
<property name="text">
|
||||
<string>Copy Marked to...</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+M</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRemoveMarked">
|
||||
<property name="text">
|
||||
<string>Remove Marked from Results</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+R</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRemoveSelected">
|
||||
<property name="text">
|
||||
<string>Remove Selected from Results</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Del</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionIgnoreSelected">
|
||||
<property name="text">
|
||||
<string>Add Selected to Ignore List</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+Del</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMakeSelectedReference">
|
||||
<property name="text">
|
||||
<string>Make Selected Reference</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Space</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpenSelected">
|
||||
<property name="text">
|
||||
<string>Open Selected with Default Application</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRevealSelected">
|
||||
<property name="text">
|
||||
<string>Open Containing Folder of Selected</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+O</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRenameSelected">
|
||||
<property name="text">
|
||||
<string>Rename Selected</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F2</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMarkAll">
|
||||
<property name="text">
|
||||
<string>Mark All</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+A</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMarkNone">
|
||||
<property name="text">
|
||||
<string>Mark None</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+A</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInvertMarking">
|
||||
<property name="text">
|
||||
<string>Invert Marking</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Alt+A</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMarkSelected">
|
||||
<property name="text">
|
||||
<string>Mark Selected</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClearIgnoreList">
|
||||
<property name="text">
|
||||
<string>Clear Ignore List</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionQuit">
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionApplyFilter">
|
||||
<property name="text">
|
||||
<string>Apply Filter</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+F</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCancelFilter">
|
||||
<property name="text">
|
||||
<string>Cancel Filter</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+F</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShowHelp">
|
||||
<property name="text">
|
||||
<string>dupeGuru Help</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F1</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout">
|
||||
<property name="text">
|
||||
<string>About dupeGuru</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRegister">
|
||||
<property name="text">
|
||||
<string>Register dupeGuru</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCheckForUpdate">
|
||||
<property name="text">
|
||||
<string>Check for Update</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport">
|
||||
<property name="text">
|
||||
<string>Export To XHTML</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpenDebugLog">
|
||||
<property name="text">
|
||||
<string>Open Debug Log</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ResultsView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>results_model</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="dg.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>actionDirectories</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>directoriesTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionActions</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>actionsTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionCopyMarked</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>copyTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionDeleteMarked</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>deleteTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionDelta</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>deltaTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionDetails</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>detailsTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionIgnoreSelected</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>addToIgnoreListTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionMakeSelectedReference</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>makeReferenceTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionMoveMarked</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>moveTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionOpenSelected</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>openTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionPowerMarker</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>powerMarkerTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionPreferences</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>preferencesTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionRemoveMarked</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>removeMarkedTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionRemoveSelected</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>removeSelectedTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionRevealSelected</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>revealTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionRenameSelected</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>renameTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionScan</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>scanTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionClearIgnoreList</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>clearIgnoreListTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionMarkAll</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>markAllTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionMarkNone</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>markNoneTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionMarkSelected</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>markSelectedTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionInvertMarking</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>markInvertTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionApplyFilter</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>applyFilterTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionCancelFilter</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>cancelFilterTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionShowHelp</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>showHelpTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionAbout</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>aboutTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionRegister</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>registerTrigerred()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionCheckForUpdate</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>checkForUpdateTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionExport</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>exportTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionOpenDebugLog</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>openDebugLogTriggered()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>314</x>
|
||||
<y>256</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>directoriesTriggered()</slot>
|
||||
<slot>scanTriggered()</slot>
|
||||
<slot>actionsTriggered()</slot>
|
||||
<slot>detailsTriggered()</slot>
|
||||
<slot>preferencesTriggered()</slot>
|
||||
<slot>deltaTriggered()</slot>
|
||||
<slot>powerMarkerTriggered()</slot>
|
||||
<slot>deleteTriggered()</slot>
|
||||
<slot>moveTriggered()</slot>
|
||||
<slot>copyTriggered()</slot>
|
||||
<slot>removeMarkedTriggered()</slot>
|
||||
<slot>removeSelectedTriggered()</slot>
|
||||
<slot>addToIgnoreListTriggered()</slot>
|
||||
<slot>makeReferenceTriggered()</slot>
|
||||
<slot>openTriggered()</slot>
|
||||
<slot>revealTriggered()</slot>
|
||||
<slot>renameTriggered()</slot>
|
||||
<slot>clearIgnoreListTriggered()</slot>
|
||||
<slot>clearPictureCacheTriggered()</slot>
|
||||
<slot>markAllTriggered()</slot>
|
||||
<slot>markNoneTriggered()</slot>
|
||||
<slot>markInvertTriggered()</slot>
|
||||
<slot>markSelectedTriggered()</slot>
|
||||
<slot>applyFilterTriggered()</slot>
|
||||
<slot>cancelFilterTriggered()</slot>
|
||||
<slot>showHelpTriggered()</slot>
|
||||
<slot>aboutTriggered()</slot>
|
||||
<slot>registerTrigerred()</slot>
|
||||
<slot>checkForUpdateTriggered()</slot>
|
||||
<slot>exportTriggered()</slot>
|
||||
<slot>openDebugLogTriggered()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
@@ -1,19 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-09-27
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
if sys.platform == 'win32':
|
||||
from platform_win import *
|
||||
elif sys.platform == 'darwin':
|
||||
from platform_osx import *
|
||||
else:
|
||||
pass # unsupported platform
|
||||
@@ -1,23 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-08-31
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
import winshell
|
||||
|
||||
INITIAL_FOLDER_IN_DIALOGS = 'C:\\'
|
||||
|
||||
def recycle_file(path):
|
||||
try:
|
||||
winshell.delete_file(unicode(path), no_confirm=True, silent=True)
|
||||
except winshell.x_winshell as e:
|
||||
logging.warning("winshell error: %s", e)
|
||||
@@ -1,116 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-05-03
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from PyQt4.QtCore import QSettings, QVariant
|
||||
|
||||
from hsutil.misc import tryint
|
||||
|
||||
def variant_to_py(v):
|
||||
value = None
|
||||
ok = False
|
||||
t = v.type()
|
||||
if t == QVariant.String:
|
||||
value = unicode(v.toString())
|
||||
ok = True # anyway
|
||||
# might be bool or int, try them
|
||||
if v == 'true':
|
||||
value = True
|
||||
elif value == 'false':
|
||||
value = False
|
||||
else:
|
||||
value = tryint(value, value)
|
||||
elif t == QVariant.Int:
|
||||
value, ok = v.toInt()
|
||||
elif t == QVariant.Bool:
|
||||
value, ok = v.toBool(), True
|
||||
elif t in (QVariant.List, QVariant.StringList):
|
||||
value, ok = map(variant_to_py, v.toList()), True
|
||||
if not ok:
|
||||
raise TypeError(u"Can't convert {0} of type {1}".format(repr(v), v.type()))
|
||||
return value
|
||||
|
||||
def py_to_variant(v):
|
||||
if isinstance(v, (list, tuple)):
|
||||
return QVariant(map(py_to_variant, v))
|
||||
return QVariant(v)
|
||||
|
||||
class Preferences(object):
|
||||
# (width, is_visible)
|
||||
COLUMNS_DEFAULT_ATTRS = []
|
||||
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
self.reset_columns()
|
||||
|
||||
def _load_specific(self, settings, get):
|
||||
# load prefs specific to the dg edition
|
||||
pass
|
||||
|
||||
def load(self):
|
||||
self.reset()
|
||||
settings = QSettings()
|
||||
def get(name, default):
|
||||
if settings.contains(name):
|
||||
return variant_to_py(settings.value(name))
|
||||
else:
|
||||
return default
|
||||
|
||||
self.filter_hardness = get('FilterHardness', self.filter_hardness)
|
||||
self.mix_file_kind = get('MixFileKind', self.mix_file_kind)
|
||||
self.use_regexp = get('UseRegexp', self.use_regexp)
|
||||
self.remove_empty_folders = get('RemoveEmptyFolders', self.remove_empty_folders)
|
||||
self.destination_type = get('DestinationType', self.destination_type)
|
||||
widths = get('ColumnsWidth', self.columns_width)
|
||||
# only set nonzero values
|
||||
for index, width in enumerate(widths[:len(self.columns_width)]):
|
||||
if width > 0:
|
||||
self.columns_width[index] = width
|
||||
self.columns_visible = get('ColumnsVisible', self.columns_visible)
|
||||
self.registration_code = get('RegistrationCode', self.registration_code)
|
||||
self.registration_email = get('RegistrationEmail', self.registration_email)
|
||||
self._load_specific(settings, get)
|
||||
|
||||
def _reset_specific(self):
|
||||
# reset prefs specific to the dg edition
|
||||
pass
|
||||
|
||||
def reset(self):
|
||||
self.filter_hardness = 95
|
||||
self.mix_file_kind = True
|
||||
self.use_regexp = False
|
||||
self.remove_empty_folders = False
|
||||
self.destination_type = 1
|
||||
self.registration_code = ''
|
||||
self.registration_email = ''
|
||||
self._reset_specific()
|
||||
|
||||
def reset_columns(self):
|
||||
self.columns_width = [width for width, _ in self.COLUMNS_DEFAULT_ATTRS]
|
||||
self.columns_visible = [visible for _, visible in self.COLUMNS_DEFAULT_ATTRS]
|
||||
|
||||
def _save_specific(self, settings, set_):
|
||||
# save prefs specific to the dg edition
|
||||
pass
|
||||
|
||||
def save(self):
|
||||
settings = QSettings()
|
||||
def set_(name, value):
|
||||
settings.setValue(name, py_to_variant(value))
|
||||
|
||||
set_('FilterHardness', self.filter_hardness)
|
||||
set_('MixFileKind', self.mix_file_kind)
|
||||
set_('UseRegexp', self.use_regexp)
|
||||
set_('RemoveEmptyFolders', self.remove_empty_folders)
|
||||
set_('DestinationType', self.destination_type)
|
||||
set_('ColumnsWidth', self.columns_width)
|
||||
set_('ColumnsVisible', self.columns_visible)
|
||||
set_('RegistrationCode', self.registration_code)
|
||||
set_('RegistrationEmail', self.registration_email)
|
||||
self._save_specific(settings, set_)
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-23
|
||||
# $Id$
|
||||
# Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from PyQt4.QtCore import SIGNAL, Qt, QAbstractItemModel, QModelIndex, QRect
|
||||
from PyQt4.QtGui import QBrush, QStyledItemDelegate, QFont, QTreeView, QColor
|
||||
|
||||
from qtlib.tree_model import TreeNode, TreeModel
|
||||
|
||||
class ResultNode(TreeNode):
|
||||
def __init__(self, model, parent, row, dupe, group):
|
||||
TreeNode.__init__(self, model, parent, row)
|
||||
self.dupe = dupe
|
||||
self.group = group
|
||||
self._normalData = None
|
||||
self._deltaData = None
|
||||
|
||||
def _createNode(self, ref, row):
|
||||
return ResultNode(self.model, self, row, ref, self.group)
|
||||
|
||||
def _getChildren(self):
|
||||
return self.group.dupes if self.dupe is self.group.ref else []
|
||||
|
||||
def invalidate(self):
|
||||
self._normalData = None
|
||||
self._deltaData = None
|
||||
TreeNode.invalidate(self)
|
||||
|
||||
@property
|
||||
def normalData(self):
|
||||
if self._normalData is None:
|
||||
self._normalData = self.model._app._get_display_info(self.dupe, self.group, delta=False)
|
||||
return self._normalData
|
||||
|
||||
@property
|
||||
def deltaData(self):
|
||||
if self._deltaData is None:
|
||||
self._deltaData = self.model._app._get_display_info(self.dupe, self.group, delta=True)
|
||||
return self._deltaData
|
||||
|
||||
|
||||
class ResultsDelegate(QStyledItemDelegate):
|
||||
def initStyleOption(self, option, index):
|
||||
QStyledItemDelegate.initStyleOption(self, option, index)
|
||||
node = index.internalPointer()
|
||||
if node.group.ref is node.dupe:
|
||||
newfont = QFont(option.font)
|
||||
newfont.setBold(True)
|
||||
option.font = newfont
|
||||
|
||||
|
||||
class ResultsModel(TreeModel):
|
||||
def __init__(self, app):
|
||||
self._app = app
|
||||
self._results = app.results
|
||||
self._data = app.data
|
||||
self._delta_columns = app.DELTA_COLUMNS
|
||||
self.delta = False
|
||||
self._power_marker = False
|
||||
TreeModel.__init__(self)
|
||||
|
||||
def _createNode(self, ref, row):
|
||||
if self.power_marker:
|
||||
# ref is a dupe
|
||||
group = self._results.get_group_of_duplicate(ref)
|
||||
return ResultNode(self, None, row, ref, group)
|
||||
else:
|
||||
# ref is a group
|
||||
return ResultNode(self, None, row, ref.ref, ref)
|
||||
|
||||
def _getChildren(self):
|
||||
return self._results.dupes if self.power_marker else self._results.groups
|
||||
|
||||
def columnCount(self, parent):
|
||||
return len(self._data.COLUMNS)
|
||||
|
||||
def data(self, index, role):
|
||||
if not index.isValid():
|
||||
return None
|
||||
node = index.internalPointer()
|
||||
if role == Qt.DisplayRole:
|
||||
data = node.deltaData if self.delta else node.normalData
|
||||
return data[index.column()]
|
||||
elif role == Qt.CheckStateRole:
|
||||
if index.column() == 0 and node.dupe is not node.group.ref:
|
||||
state = Qt.Checked if self._results.is_marked(node.dupe) else Qt.Unchecked
|
||||
return state
|
||||
elif role == Qt.ForegroundRole:
|
||||
if node.dupe is node.group.ref or node.dupe.is_ref:
|
||||
return QBrush(Qt.blue)
|
||||
elif self.delta and index.column() in self._delta_columns:
|
||||
return QBrush(QColor(255, 142, 40)) # orange
|
||||
elif role == Qt.EditRole:
|
||||
if index.column() == 0:
|
||||
return node.normalData[index.column()]
|
||||
return None
|
||||
|
||||
def dupesForIndexes(self, indexes):
|
||||
nodes = [index.internalPointer() for index in indexes]
|
||||
return [node.dupe for node in nodes]
|
||||
|
||||
def indexesForDupes(self, dupes):
|
||||
def index(dupe):
|
||||
try:
|
||||
if self.power_marker:
|
||||
row = self._results.dupes.index(dupe)
|
||||
node = self.subnodes[row]
|
||||
assert node.dupe is dupe
|
||||
return self.createIndex(row, 0, node)
|
||||
else:
|
||||
group = self._results.get_group_of_duplicate(dupe)
|
||||
row = self._results.groups.index(group)
|
||||
node = self.subnodes[row]
|
||||
if dupe is group.ref:
|
||||
assert node.dupe is dupe
|
||||
return self.createIndex(row, 0, node)
|
||||
subrow = group.dupes.index(dupe)
|
||||
subnode = node.subnodes[subrow]
|
||||
assert subnode.dupe is dupe
|
||||
return self.createIndex(subrow, 0, subnode)
|
||||
except ValueError: # the dupe is not there anymore
|
||||
return QModelIndex()
|
||||
|
||||
return map(index, dupes)
|
||||
|
||||
def flags(self, index):
|
||||
if not index.isValid():
|
||||
return Qt.ItemIsEnabled
|
||||
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
||||
if index.column() == 0:
|
||||
flags |= Qt.ItemIsUserCheckable | Qt.ItemIsEditable
|
||||
return flags
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
if orientation == Qt.Horizontal and role == Qt.DisplayRole and section < len(self._data.COLUMNS):
|
||||
return self._data.COLUMNS[section]['display']
|
||||
return None
|
||||
|
||||
def setData(self, index, value, role):
|
||||
if not index.isValid():
|
||||
return False
|
||||
node = index.internalPointer()
|
||||
if role == Qt.CheckStateRole:
|
||||
if index.column() == 0:
|
||||
self._app.toggle_marking_for_dupes([node.dupe])
|
||||
return True
|
||||
if role == Qt.EditRole:
|
||||
if index.column() == 0:
|
||||
value = unicode(value.toString())
|
||||
if self._app.rename_dupe(node.dupe, value):
|
||||
node.invalidate()
|
||||
return True
|
||||
return False
|
||||
|
||||
def sort(self, column, order):
|
||||
if self.power_marker:
|
||||
self._results.sort_dupes(column, order == Qt.AscendingOrder, self.delta)
|
||||
else:
|
||||
self._results.sort_groups(column, order == Qt.AscendingOrder)
|
||||
self.reset()
|
||||
|
||||
def toggleMarked(self, indexes):
|
||||
assert indexes
|
||||
dupes = self.dupesForIndexes(indexes)
|
||||
self._app.toggle_marking_for_dupes(dupes)
|
||||
|
||||
#--- Properties
|
||||
@property
|
||||
def power_marker(self):
|
||||
return self._power_marker
|
||||
|
||||
@power_marker.setter
|
||||
def power_marker(self, value):
|
||||
if value == self._power_marker:
|
||||
return
|
||||
self._power_marker = value
|
||||
self.reset()
|
||||
|
||||
|
||||
class ResultsView(QTreeView):
|
||||
#--- Override
|
||||
def keyPressEvent(self, event):
|
||||
if event.text() == ' ':
|
||||
self.model().toggleMarked(self.selectionModel().selectedRows())
|
||||
return
|
||||
QTreeView.keyPressEvent(self, event)
|
||||
|
||||
def mouseDoubleClickEvent(self, event):
|
||||
self.emit(SIGNAL('doubleClicked()'))
|
||||
# We don't call the superclass' method because the default behavior is to rename the cell.
|
||||
|
||||
def setModel(self, model):
|
||||
assert isinstance(model, ResultsModel)
|
||||
QTreeView.setModel(self, model)
|
||||
|
||||
#--- Public
|
||||
def selectedDupes(self):
|
||||
return self.model().dupesForIndexes(self.selectionModel().selectedRows())
|
||||
|
||||
174
build.py
Normal file
174
build.py
Normal file
@@ -0,0 +1,174 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-12-30
|
||||
# Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/bsd_license
|
||||
|
||||
import os
|
||||
import os.path as op
|
||||
from optparse import OptionParser
|
||||
import shutil
|
||||
import json
|
||||
|
||||
from setuptools import setup
|
||||
from distutils.extension import Extension
|
||||
|
||||
from hscommon import sphinxgen
|
||||
from hscommon.build import (add_to_pythonpath, print_and_do, copy_packages,
|
||||
filereplace, get_module_version, build_all_cocoa_locs, build_all_qt_locs)
|
||||
|
||||
def parse_args():
|
||||
usage = "usage: %prog [options]"
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option('--clean', action='store_true', dest='clean',
|
||||
help="Clean build folder before building")
|
||||
parser.add_option('--only-help', action='store_true', dest='only_help',
|
||||
help="Build only help file")
|
||||
(options, args) = parser.parse_args()
|
||||
return options
|
||||
|
||||
def build_cocoa(edition, dev):
|
||||
from pluginbuilder import build_plugin
|
||||
build_all_cocoa_locs('cocoalib')
|
||||
build_all_cocoa_locs(op.join('cocoa', 'base'))
|
||||
build_all_cocoa_locs(op.join('cocoa', edition))
|
||||
|
||||
print("Building dg_cocoa.plugin")
|
||||
if not dev:
|
||||
specific_packages = {
|
||||
'se': ['core_se'],
|
||||
'me': ['core_me'],
|
||||
'pe': ['core_pe'],
|
||||
}[edition]
|
||||
copy_packages(['core', 'hscommon'] + specific_packages, 'build')
|
||||
cocoa_project_path = 'cocoa/{0}'.format(edition)
|
||||
shutil.copy(op.join(cocoa_project_path, 'dg_cocoa.py'), 'build')
|
||||
os.chdir('build')
|
||||
# We have to exclude PyQt4 specifically because it's conditionally imported in hscommon.trans
|
||||
build_plugin('dg_cocoa.py', excludes=['PyQt4'], alias=dev)
|
||||
os.chdir('..')
|
||||
pluginpath = op.join(cocoa_project_path, 'dg_cocoa.plugin')
|
||||
if op.exists(pluginpath):
|
||||
shutil.rmtree(pluginpath)
|
||||
shutil.move('build/dist/dg_cocoa.plugin', pluginpath)
|
||||
if dev:
|
||||
# In alias mode, the tweakings we do to the pythonpath aren't counted in. We have to
|
||||
# manually put a .pth in the plugin
|
||||
pthpath = op.join(pluginpath, 'Contents/Resources/dev.pth')
|
||||
open(pthpath, 'w').write(op.abspath('.'))
|
||||
os.chdir(cocoa_project_path)
|
||||
print('Generating Info.plist')
|
||||
app_version = get_module_version('core_{}'.format(edition))
|
||||
filereplace('InfoTemplate.plist', 'Info.plist', version=app_version)
|
||||
print("Building the XCode project")
|
||||
args = []
|
||||
if dev:
|
||||
args.append('-configuration dev')
|
||||
else:
|
||||
args.append('-configuration release')
|
||||
args = ' '.join(args)
|
||||
os.system('xcodebuild {0}'.format(args))
|
||||
os.chdir('../..')
|
||||
print("Creating the run.py file")
|
||||
subfolder = 'dev' if dev else 'release'
|
||||
app_path = {
|
||||
'se': 'cocoa/se/build/{0}/dupeGuru.app',
|
||||
'me': 'cocoa/me/build/{0}/dupeGuru\\ ME.app',
|
||||
'pe': 'cocoa/pe/build/{0}/dupeGuru\\ PE.app',
|
||||
}[edition].format(subfolder)
|
||||
tmpl = open('run_template_cocoa.py', 'rt').read()
|
||||
run_contents = tmpl.replace('{{app_path}}', app_path)
|
||||
open('run.py', 'wt').write(run_contents)
|
||||
|
||||
def build_qt(edition, dev):
|
||||
print("Building .ts files")
|
||||
build_all_qt_locs(op.join('qt', 'lang'), extradirs=[op.join('qtlib', 'lang')])
|
||||
print("Building Qt stuff")
|
||||
print_and_do("pyrcc4 -py3 {0} > {1}".format(op.join('qt', 'base', 'dg.qrc'), op.join('qt', 'base', 'dg_rc.py')))
|
||||
print("Creating the run.py file")
|
||||
tmpl = open('run_template_qt.py', 'rt').read()
|
||||
run_contents = tmpl.replace('{{edition}}', edition)
|
||||
open('run.py', 'wt').write(run_contents)
|
||||
|
||||
def build_help(edition):
|
||||
print("Generating Help")
|
||||
current_path = op.abspath('.')
|
||||
help_basepath = op.join(current_path, 'help', 'en')
|
||||
help_destpath = op.join(current_path, 'build', 'help'.format(edition))
|
||||
changelog_path = op.join(current_path, 'help', 'changelog_{}'.format(edition))
|
||||
tixurl = "https://hardcoded.lighthouseapp.com/projects/31699-dupeguru/tickets/{0}"
|
||||
appname = {'se': 'dupeGuru', 'me': 'dupeGuru Music Edition', 'pe': 'dupeGuru Picture Edition'}[edition]
|
||||
homepage = 'http://www.hardcoded.net/dupeguru{}/'.format('_' + edition if edition != 'se' else '')
|
||||
confrepl = {'edition': edition, 'appname': appname, 'homepage': homepage}
|
||||
sphinxgen.gen(help_basepath, help_destpath, changelog_path, tixurl, confrepl)
|
||||
|
||||
def build_pe_modules(ui):
|
||||
def move(src, dst):
|
||||
if not op.exists(src):
|
||||
return
|
||||
if op.exists(dst):
|
||||
os.remove(dst)
|
||||
print('Moving %s --> %s' % (src, dst))
|
||||
os.rename(src, dst)
|
||||
|
||||
print("Building PE Modules")
|
||||
exts = [
|
||||
Extension("_block", [op.join('core_pe', 'modules', 'block.c'), op.join('core_pe', 'modules', 'common.c')]),
|
||||
Extension("_cache", [op.join('core_pe', 'modules', 'cache.c'), op.join('core_pe', 'modules', 'common.c')]),
|
||||
]
|
||||
if ui == 'qt':
|
||||
exts.append(Extension("_block_qt", [op.join('qt', 'pe', 'modules', 'block.c')]))
|
||||
elif ui == 'cocoa':
|
||||
exts.append(Extension(
|
||||
"_block_osx", [op.join('core_pe', 'modules', 'block_osx.m'), op.join('core_pe', 'modules', 'common.c')],
|
||||
extra_link_args=[
|
||||
"-framework", "CoreFoundation",
|
||||
"-framework", "Foundation",
|
||||
"-framework", "ApplicationServices",]
|
||||
))
|
||||
setup(
|
||||
script_args = ['build_ext', '--inplace'],
|
||||
ext_modules = exts,
|
||||
)
|
||||
move('_block.so', op.join('core_pe', '_block.so'))
|
||||
move('_block.pyd', op.join('core_pe', '_block.pyd'))
|
||||
move('_block_osx.so', op.join('core_pe', '_block_osx.so'))
|
||||
move('_cache.so', op.join('core_pe', '_cache.so'))
|
||||
move('_cache.pyd', op.join('core_pe', '_cache.pyd'))
|
||||
move('_block_qt.so', op.join('qt', 'pe', '_block_qt.so'))
|
||||
move('_block_qt.pyd', op.join('qt', 'pe', '_block_qt.pyd'))
|
||||
|
||||
def build_normal(edition, ui, dev):
|
||||
print("Building dupeGuru {0} with UI {1}".format(edition.upper(), ui))
|
||||
add_to_pythonpath('.')
|
||||
build_help(edition)
|
||||
print("Building dupeGuru")
|
||||
if edition == 'pe':
|
||||
build_pe_modules(ui)
|
||||
if ui == 'cocoa':
|
||||
build_cocoa(edition, dev)
|
||||
elif ui == 'qt':
|
||||
build_qt(edition, dev)
|
||||
|
||||
def main():
|
||||
options = parse_args()
|
||||
conf = json.load(open('conf.json'))
|
||||
edition = conf['edition']
|
||||
ui = conf['ui']
|
||||
dev = conf['dev']
|
||||
if dev:
|
||||
print("Building in Dev mode")
|
||||
if options.clean:
|
||||
if op.exists('build'):
|
||||
shutil.rmtree('build')
|
||||
if not op.exists('build'):
|
||||
os.mkdir('build')
|
||||
if options.only_help:
|
||||
build_help(edition)
|
||||
else:
|
||||
build_normal(edition, ui, dev)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
55
cocoa/base/AppDelegate.h
Normal file
55
cocoa/base/AppDelegate.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyDupeGuru.h"
|
||||
#import "ResultWindow.h"
|
||||
#import "DetailsPanel.h"
|
||||
#import "DirectoryPanel.h"
|
||||
#import "HSAboutBox.h"
|
||||
#import "HSRecentFiles.h"
|
||||
|
||||
@interface AppDelegateBase : NSObject
|
||||
{
|
||||
IBOutlet PyDupeGuruBase *py;
|
||||
IBOutlet NSMenu *recentResultsMenu;
|
||||
IBOutlet NSMenu *actionsMenu;
|
||||
IBOutlet NSMenu *columnsMenu;
|
||||
|
||||
ResultWindowBase *_resultWindow;
|
||||
DirectoryPanel *_directoryPanel;
|
||||
DetailsPanel *_detailsPanel;
|
||||
NSWindowController *_preferencesPanel;
|
||||
HSAboutBox *_aboutBox;
|
||||
HSRecentFiles *_recentResults;
|
||||
}
|
||||
|
||||
/* Virtual */
|
||||
- (PyDupeGuruBase *)py;
|
||||
- (ResultWindowBase *)createResultWindow;
|
||||
- (DirectoryPanel *)createDirectoryPanel;
|
||||
- (DetailsPanel *)createDetailsPanel;
|
||||
- (NSString *)homepageURL;
|
||||
|
||||
/* Public */
|
||||
- (ResultWindowBase *)resultWindow;
|
||||
- (DirectoryPanel *)directoryPanel;
|
||||
- (DetailsPanel *)detailsPanel;
|
||||
- (HSRecentFiles *)recentResults;
|
||||
- (NSMenu *)columnsMenu;
|
||||
|
||||
/* Actions */
|
||||
- (IBAction)loadResults:(id)sender;
|
||||
- (IBAction)openWebsite:(id)sender;
|
||||
- (IBAction)openHelp:(id)sender;
|
||||
- (IBAction)showAboutBox:(id)sender;
|
||||
- (IBAction)showDirectoryWindow:(id)sender;
|
||||
- (IBAction)showPreferencesPanel:(id)sender;
|
||||
- (IBAction)showResultWindow:(id)sender;
|
||||
- (IBAction)startScanning:(id)sender;
|
||||
@end
|
||||
217
cocoa/base/AppDelegate.m
Normal file
217
cocoa/base/AppDelegate.m
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "ProgressController.h"
|
||||
#import "HSFairwareReminder.h"
|
||||
#import "ExtraFairwareReminder.h"
|
||||
#import "Utils.h"
|
||||
#import "Consts.h"
|
||||
#import "Dialogs.h"
|
||||
#import <Sparkle/SUUpdater.h>
|
||||
|
||||
@implementation AppDelegateBase
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
/* Because the pref pane is lazily loaded, we have to manually do the update check if the
|
||||
preference is set.
|
||||
*/
|
||||
if ([ud boolForKey:@"SUEnableAutomaticChecks"]) {
|
||||
[[SUUpdater sharedUpdater] checkForUpdatesInBackground];
|
||||
}
|
||||
_recentResults = [[HSRecentFiles alloc] initWithName:@"recentResults" menu:recentResultsMenu];
|
||||
[_recentResults setDelegate:self];
|
||||
_resultWindow = [self createResultWindow];
|
||||
_directoryPanel = [self createDirectoryPanel];
|
||||
_detailsPanel = nil; // Lazily loaded
|
||||
_aboutBox = nil; // Lazily loaded
|
||||
_preferencesPanel = nil; // Lazily loaded
|
||||
[[[self directoryPanel] window] makeKeyAndOrderFront:self];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(showExtraFairwareReminder:) name:ShowExtraFairwareReminder object:nil];
|
||||
}
|
||||
|
||||
/* Virtual */
|
||||
|
||||
- (PyDupeGuruBase *)py { return py; }
|
||||
|
||||
- (ResultWindowBase *)createResultWindow
|
||||
{
|
||||
return nil; // must be overriden by all editions
|
||||
}
|
||||
|
||||
- (DirectoryPanel *)createDirectoryPanel
|
||||
{
|
||||
return [[DirectoryPanel alloc] initWithParentApp:self];
|
||||
}
|
||||
|
||||
- (DetailsPanel *)createDetailsPanel
|
||||
{
|
||||
return [[DetailsPanel alloc] initWithPy:py];
|
||||
}
|
||||
|
||||
- (NSString *)homepageURL
|
||||
{
|
||||
return @""; // must be overriden by all editions
|
||||
}
|
||||
|
||||
/* Public */
|
||||
- (ResultWindowBase *)resultWindow
|
||||
{
|
||||
return _resultWindow;
|
||||
}
|
||||
|
||||
- (DirectoryPanel *)directoryPanel
|
||||
{
|
||||
return _directoryPanel;
|
||||
}
|
||||
|
||||
- (DetailsPanel *)detailsPanel
|
||||
{
|
||||
if (!_detailsPanel)
|
||||
_detailsPanel = [self createDetailsPanel];
|
||||
return _detailsPanel;
|
||||
}
|
||||
|
||||
- (HSRecentFiles *)recentResults
|
||||
{
|
||||
return _recentResults;
|
||||
}
|
||||
|
||||
- (NSMenu *)columnsMenu { return columnsMenu; }
|
||||
|
||||
/* Actions */
|
||||
- (IBAction)loadResults:(id)sender
|
||||
{
|
||||
NSOpenPanel *op = [NSOpenPanel openPanel];
|
||||
[op setCanChooseFiles:YES];
|
||||
[op setCanChooseDirectories:NO];
|
||||
[op setCanCreateDirectories:NO];
|
||||
[op setAllowsMultipleSelection:NO];
|
||||
[op setAllowedFileTypes:[NSArray arrayWithObject:@"dupeguru"]];
|
||||
[op setTitle:TR(@"SelectResultToLoadMsg")];
|
||||
if ([op runModal] == NSOKButton) {
|
||||
NSString *filename = [[op filenames] objectAtIndex:0];
|
||||
[py loadResultsFrom:filename];
|
||||
[[self recentResults] addFile:filename];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)openWebsite:(id)sender
|
||||
{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[self homepageURL]]];
|
||||
}
|
||||
|
||||
- (IBAction)openHelp:(id)sender
|
||||
{
|
||||
NSBundle *b = [NSBundle mainBundle];
|
||||
NSString *p = [b pathForResource:@"index" ofType:@"html" inDirectory:@"help"];
|
||||
NSURL *u = [NSURL fileURLWithPath:p];
|
||||
[[NSWorkspace sharedWorkspace] openURL:u];
|
||||
}
|
||||
|
||||
- (IBAction)showAboutBox:(id)sender
|
||||
{
|
||||
if (_aboutBox == nil) {
|
||||
_aboutBox = [[HSAboutBox alloc] initWithApp:py];
|
||||
}
|
||||
[[_aboutBox window] makeKeyAndOrderFront:sender];
|
||||
}
|
||||
|
||||
- (IBAction)showDirectoryWindow:(id)sender
|
||||
{
|
||||
[[[self directoryPanel] window] makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
- (IBAction)showPreferencesPanel:(id)sender
|
||||
{
|
||||
if (_preferencesPanel == nil) {
|
||||
_preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
||||
}
|
||||
[_preferencesPanel showWindow:sender];
|
||||
}
|
||||
|
||||
- (IBAction)showResultWindow:(id)sender
|
||||
{
|
||||
[[[self resultWindow] window] makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
- (IBAction)startScanning:(id)sender
|
||||
{
|
||||
[[self resultWindow] startDuplicateScan:sender];
|
||||
}
|
||||
|
||||
|
||||
/* Delegate */
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
[[ProgressController mainProgressController] setWorker:py];
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
//Restore Columns
|
||||
NSArray *columnsOrder = [ud arrayForKey:@"columnsOrder"];
|
||||
NSDictionary *columnsWidth = [ud dictionaryForKey:@"columnsWidth"];
|
||||
if ([columnsOrder count])
|
||||
[[self resultWindow] restoreColumnsPosition:columnsOrder widths:columnsWidth];
|
||||
else
|
||||
[[self resultWindow] resetColumnsToDefault:nil];
|
||||
[HSFairwareReminder showNagWithApp:[self py]];
|
||||
[py loadSession];
|
||||
}
|
||||
|
||||
- (void)applicationWillBecomeActive:(NSNotification *)aNotification
|
||||
{
|
||||
if (![[[self directoryPanel] window] isVisible]) {
|
||||
[[self directoryPanel] showWindow:NSApp];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
if ([py resultsAreModified]) {
|
||||
NSString *msg = TR(@"ReallyWantToQuitMsg");
|
||||
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) { // NO
|
||||
return NSTerminateCancel;
|
||||
}
|
||||
}
|
||||
return NSTerminateNow;
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
[ud setObject: [[self resultWindow] getColumnsOrder] forKey:@"columnsOrder"];
|
||||
[ud setObject: [[self resultWindow] getColumnsWidth] forKey:@"columnsWidth"];
|
||||
NSInteger sc = [ud integerForKey:@"sessionCountSinceLastIgnorePurge"];
|
||||
if (sc >= 10) {
|
||||
sc = -1;
|
||||
[py purgeIgnoreList];
|
||||
}
|
||||
sc++;
|
||||
[py saveSession];
|
||||
[ud setInteger:sc forKey:@"sessionCountSinceLastIgnorePurge"];
|
||||
// NSApplication does not release nib instances objects, we must do it manually
|
||||
// Well, it isn't needed because the memory is freed anyway (we are quitting the application
|
||||
// But I need to release HSRecentFiles so it saves the user defaults
|
||||
[_directoryPanel release];
|
||||
[_recentResults release];
|
||||
}
|
||||
|
||||
- (void)recentFileClicked:(NSString *)path
|
||||
{
|
||||
[py loadResultsFrom:path];
|
||||
}
|
||||
|
||||
- (void)showExtraFairwareReminder:(NSNotification *)aNotification
|
||||
{
|
||||
ExtraFairwareReminder *dialog = [[ExtraFairwareReminder alloc] initWithPy:py];
|
||||
[dialog start];
|
||||
[NSApp runModalForWindow:[dialog window]];
|
||||
[dialog release];
|
||||
}
|
||||
@end
|
||||
21
cocoa/base/Consts.h
Normal file
21
cocoa/base/Consts.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#define JobStarted @"JobStarted"
|
||||
#define JobInProgress @"JobInProgress"
|
||||
#define ShowExtraFairwareReminder @"ShowExtraFairwareReminder"
|
||||
|
||||
#define jobLoad @"job_load"
|
||||
#define jobScan @"job_scan"
|
||||
#define jobCopy @"job_copy"
|
||||
#define jobMove @"job_move"
|
||||
#define jobDelete @"job_delete"
|
||||
|
||||
#define TR(s) NSLocalizedString(s, @"")
|
||||
26
cocoa/base/DetailsPanel.h
Normal file
26
cocoa/base/DetailsPanel.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "HSWindowController.h"
|
||||
#import "PyApp.h"
|
||||
#import "PyDetailsPanel.h"
|
||||
|
||||
@interface DetailsPanel : HSWindowController
|
||||
{
|
||||
IBOutlet NSTableView *detailsTable;
|
||||
}
|
||||
- (id)initWithPy:(PyApp *)aPy;
|
||||
- (PyDetailsPanel *)py;
|
||||
|
||||
- (BOOL)isVisible;
|
||||
- (void)toggleVisibility;
|
||||
|
||||
/* Python --> Cocoa */
|
||||
- (void)refresh;
|
||||
@end
|
||||
71
cocoa/base/DetailsPanel.m
Normal file
71
cocoa/base/DetailsPanel.m
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "DetailsPanel.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation DetailsPanel
|
||||
- (id)initWithPy:(PyApp *)aPy
|
||||
{
|
||||
self = [super initWithNibName:@"DetailsPanel" pyClassName:@"PyDetailsPanel" pyParent:aPy];
|
||||
[self window]; //So the detailsTable is initialized.
|
||||
[self connect];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self disconnect];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (PyDetailsPanel *)py
|
||||
{
|
||||
return (PyDetailsPanel *)py;
|
||||
}
|
||||
|
||||
- (void)refreshDetails
|
||||
{
|
||||
[detailsTable reloadData];
|
||||
}
|
||||
|
||||
- (BOOL)isVisible
|
||||
{
|
||||
return [[self window] isVisible];
|
||||
}
|
||||
|
||||
- (void)toggleVisibility
|
||||
{
|
||||
if ([self isVisible]) {
|
||||
[[self window] close];
|
||||
}
|
||||
else {
|
||||
[self refreshDetails]; // selection might have changed since last time
|
||||
[[self window] orderFront:nil];
|
||||
}
|
||||
}
|
||||
|
||||
/* NSTableView Delegate */
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
return [[self py] numberOfRows];
|
||||
}
|
||||
|
||||
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)column row:(NSInteger)row
|
||||
{
|
||||
return [[self py] valueForColumn:[column identifier] row:row];
|
||||
}
|
||||
|
||||
/* Python --> Cocoa */
|
||||
- (void)refresh
|
||||
{
|
||||
if ([[self window] isVisible]) {
|
||||
[self refreshDetails];
|
||||
}
|
||||
}
|
||||
@end
|
||||
18
cocoa/base/DirectoryOutline.h
Normal file
18
cocoa/base/DirectoryOutline.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "HSOutline.h"
|
||||
#import "PyDirectoryOutline.h"
|
||||
|
||||
#define DGAddedFoldersNotification @"DGAddedFoldersNotification"
|
||||
|
||||
@interface DirectoryOutline : HSOutline {}
|
||||
- (id)initWithPyParent:(id)aPyParent view:(HSOutlineView *)aOutlineView;
|
||||
- (PyDirectoryOutline *)py;
|
||||
@end;
|
||||
87
cocoa/base/DirectoryOutline.m
Normal file
87
cocoa/base/DirectoryOutline.m
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "DirectoryOutline.h"
|
||||
|
||||
@implementation DirectoryOutline
|
||||
- (id)initWithPyParent:(id)aPyParent view:(HSOutlineView *)aOutlineView
|
||||
{
|
||||
self = [super initWithPyClassName:@"PyDirectoryOutline" pyParent:aPyParent view:aOutlineView];
|
||||
[outlineView registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
|
||||
[self connect];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self disconnect];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (PyDirectoryOutline *)py
|
||||
{
|
||||
return (PyDirectoryOutline *)py;
|
||||
}
|
||||
|
||||
/* Delegate */
|
||||
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
|
||||
{
|
||||
NSPasteboard *pboard;
|
||||
NSDragOperation sourceDragMask;
|
||||
sourceDragMask = [info draggingSourceOperationMask];
|
||||
pboard = [info draggingPasteboard];
|
||||
if ([[pboard types] containsObject:NSFilenamesPboardType]) {
|
||||
if (sourceDragMask & NSDragOperationLink)
|
||||
return NSDragOperationLink;
|
||||
}
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index
|
||||
{
|
||||
NSPasteboard *pboard;
|
||||
NSDragOperation sourceDragMask;
|
||||
sourceDragMask = [info draggingSourceOperationMask];
|
||||
pboard = [info draggingPasteboard];
|
||||
if ([[pboard types] containsObject:NSFilenamesPboardType]) {
|
||||
NSArray *foldernames = [pboard propertyListForType:NSFilenamesPboardType];
|
||||
if (!(sourceDragMask & NSDragOperationLink))
|
||||
return NO;
|
||||
for (NSString *foldername in foldernames) {
|
||||
[[self py] addDirectory:foldername];
|
||||
}
|
||||
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:foldernames forKey:@"foldernames"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:DGAddedFoldersNotification
|
||||
object:self userInfo:userInfo];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)aOutlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||
{
|
||||
if ([cell isKindOfClass:[NSTextFieldCell class]]) {
|
||||
NSTextFieldCell *textCell = cell;
|
||||
NSIndexPath *path = item;
|
||||
BOOL selected = [path isEqualTo:[outlineView selectedPath]];
|
||||
if (selected) {
|
||||
[textCell setTextColor:[NSColor blackColor]];
|
||||
return;
|
||||
}
|
||||
NSInteger state = [self intProperty:@"state" valueAtPath:path];
|
||||
if (state == 1) {
|
||||
[textCell setTextColor:[NSColor blueColor]];
|
||||
}
|
||||
else if (state == 2) {
|
||||
[textCell setTextColor:[NSColor redColor]];
|
||||
}
|
||||
else {
|
||||
[textCell setTextColor:[NSColor blackColor]];
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
||||
41
cocoa/base/DirectoryPanel.h
Normal file
41
cocoa/base/DirectoryPanel.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "HSOutlineView.h"
|
||||
#import "HSRecentFiles.h"
|
||||
#import "DirectoryOutline.h"
|
||||
#import "PyDupeGuru.h"
|
||||
|
||||
@class AppDelegateBase;
|
||||
|
||||
@interface DirectoryPanel : NSWindowController
|
||||
{
|
||||
IBOutlet NSPopUpButton *addButtonPopUp;
|
||||
IBOutlet NSPopUpButton *loadRecentButtonPopUp;
|
||||
IBOutlet HSOutlineView *outlineView;
|
||||
IBOutlet NSButton *removeButton;
|
||||
|
||||
AppDelegateBase *_app;
|
||||
PyDupeGuruBase *_py;
|
||||
HSRecentFiles *_recentDirectories;
|
||||
DirectoryOutline *outline;
|
||||
BOOL _alwaysShowPopUp;
|
||||
}
|
||||
- (id)initWithParentApp:(AppDelegateBase *)aParentApp;
|
||||
|
||||
- (void)fillPopUpMenu; // Virtual
|
||||
|
||||
- (IBAction)askForDirectory:(id)sender;
|
||||
- (IBAction)popupAddDirectoryMenu:(id)sender;
|
||||
- (IBAction)popupLoadRecentMenu:(id)sender;
|
||||
- (IBAction)removeSelectedDirectory:(id)sender;
|
||||
|
||||
- (void)addDirectory:(NSString *)directory;
|
||||
- (void)refreshRemoveButtonText;
|
||||
@end
|
||||
175
cocoa/base/DirectoryPanel.m
Normal file
175
cocoa/base/DirectoryPanel.m
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "DirectoryPanel.h"
|
||||
#import "Dialogs.h"
|
||||
#import "Utils.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "Consts.h"
|
||||
|
||||
@implementation DirectoryPanel
|
||||
- (id)initWithParentApp:(AppDelegateBase *)aParentApp
|
||||
{
|
||||
self = [super initWithWindowNibName:@"DirectoryPanel"];
|
||||
[self window];
|
||||
_app = aParentApp;
|
||||
_py = [_app py];
|
||||
_alwaysShowPopUp = NO;
|
||||
[self fillPopUpMenu];
|
||||
_recentDirectories = [[HSRecentFiles alloc] initWithName:@"recentDirectories" menu:[addButtonPopUp menu]];
|
||||
[_recentDirectories setDelegate:self];
|
||||
outline = [[DirectoryOutline alloc] initWithPyParent:_py view:outlineView];
|
||||
[self refreshRemoveButtonText];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(directorySelectionChanged:)
|
||||
name:NSOutlineViewSelectionDidChangeNotification object:outlineView];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(outlineAddedFolders:)
|
||||
name:DGAddedFoldersNotification object:outline];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[outline release];
|
||||
[_recentDirectories release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* Virtual */
|
||||
|
||||
- (void)fillPopUpMenu
|
||||
{
|
||||
NSMenu *m = [addButtonPopUp menu];
|
||||
NSMenuItem *mi = [m addItemWithTitle:TR(@"Add New Folder...") action:@selector(askForDirectory:) keyEquivalent:@""];
|
||||
[mi setTarget:self];
|
||||
[m addItem:[NSMenuItem separatorItem]];
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
|
||||
- (IBAction)askForDirectory:(id)sender
|
||||
{
|
||||
NSOpenPanel *op = [NSOpenPanel openPanel];
|
||||
[op setCanChooseFiles:YES];
|
||||
[op setCanChooseDirectories:YES];
|
||||
[op setAllowsMultipleSelection:YES];
|
||||
[op setTitle:TR(@"SelectFolderToAddMsg")];
|
||||
[op setDelegate:self];
|
||||
if ([op runModal] == NSOKButton) {
|
||||
for (NSString *directory in [op filenames]) {
|
||||
[self addDirectory:directory];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)popupAddDirectoryMenu:(id)sender
|
||||
{
|
||||
if ((!_alwaysShowPopUp) && ([[_recentDirectories filepaths] count] == 0)) {
|
||||
[self askForDirectory:sender];
|
||||
}
|
||||
else {
|
||||
[addButtonPopUp selectItem:nil];
|
||||
[[addButtonPopUp cell] performClickWithFrame:[sender frame] inView:[sender superview]];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)popupLoadRecentMenu:(id)sender
|
||||
{
|
||||
if ([[[_app recentResults] filepaths] count] > 0) {
|
||||
NSMenu *m = [loadRecentButtonPopUp menu];
|
||||
while ([m numberOfItems] > 0) {
|
||||
[m removeItemAtIndex:0];
|
||||
}
|
||||
NSMenuItem *mi = [m addItemWithTitle:TR(@"Load from file...") action:@selector(loadResults:) keyEquivalent:@""];
|
||||
[mi setTarget:_app];
|
||||
[m addItem:[NSMenuItem separatorItem]];
|
||||
[[_app recentResults] fillMenu:m];
|
||||
[loadRecentButtonPopUp selectItem:nil];
|
||||
[[loadRecentButtonPopUp cell] performClickWithFrame:[sender frame] inView:[sender superview]];
|
||||
}
|
||||
else {
|
||||
[_app loadResults:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)removeSelectedDirectory:(id)sender
|
||||
{
|
||||
[[self window] makeKeyAndOrderFront:nil];
|
||||
if ([outlineView selectedRow] < 0)
|
||||
return;
|
||||
NSIndexPath *path = [outline selectedIndexPath];
|
||||
NSInteger state = [outline intProperty:@"state" valueAtPath:path];
|
||||
if (([path length] == 1) && (state != 2)) {
|
||||
[_py removeDirectory:i2n([path indexAtPosition:0])];
|
||||
}
|
||||
else {
|
||||
NSInteger newState = state == 2 ? 0 : 2; // If excluded, put it back
|
||||
[outline setIntProperty:@"state" value:newState atPath:path];
|
||||
[outlineView display];
|
||||
}
|
||||
[self refreshRemoveButtonText];
|
||||
}
|
||||
|
||||
/* Public */
|
||||
- (void)addDirectory:(NSString *)directory
|
||||
{
|
||||
NSInteger r = [[_py addDirectory:directory] intValue];
|
||||
if (r) {
|
||||
NSString *m = @"";
|
||||
if (r == 1) {
|
||||
m = TR(@"FolderAlreadyInListMsg");
|
||||
}
|
||||
else if (r == 2) {
|
||||
m = TR(@"FolderDoesNotExistMsg");
|
||||
}
|
||||
[Dialogs showMessage:[NSString stringWithFormat:m,directory]];
|
||||
}
|
||||
[_recentDirectories addFile:directory];
|
||||
[[self window] makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
- (void)refreshRemoveButtonText
|
||||
{
|
||||
if ([outlineView selectedRow] < 0) {
|
||||
[removeButton setEnabled:NO];
|
||||
return;
|
||||
}
|
||||
[removeButton setEnabled:YES];
|
||||
NSInteger state = [outline intProperty:@"state" valueAtPath:[outline selectedIndexPath]];
|
||||
NSString *imgName = state == 2 ? @"NSGoLeftTemplate" : @"NSRemoveTemplate";
|
||||
[removeButton setImage:[NSImage imageNamed:imgName]];
|
||||
}
|
||||
|
||||
/* Delegate */
|
||||
- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)path
|
||||
{
|
||||
BOOL isdir;
|
||||
[[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isdir];
|
||||
return isdir;
|
||||
}
|
||||
|
||||
- (void)recentFileClicked:(NSString *)path
|
||||
{
|
||||
[self addDirectory:path];
|
||||
}
|
||||
|
||||
/* Notifications */
|
||||
|
||||
- (void)directorySelectionChanged:(NSNotification *)aNotification
|
||||
{
|
||||
[self refreshRemoveButtonText];
|
||||
}
|
||||
|
||||
- (void)outlineAddedFolders:(NSNotification *)aNotification
|
||||
{
|
||||
NSArray *foldernames = [[aNotification userInfo] objectForKey:@"foldernames"];
|
||||
for (NSString *foldername in foldernames) {
|
||||
[_recentDirectories addFile:foldername];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
27
cocoa/base/ExtraFairwareReminder.h
Normal file
27
cocoa/base/ExtraFairwareReminder.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyExtraFairwareReminder.h"
|
||||
#import "HSWindowController.h"
|
||||
#import "PyApp.h"
|
||||
|
||||
@interface ExtraFairwareReminder : HSWindowController
|
||||
{
|
||||
IBOutlet NSButton *continueButton;
|
||||
|
||||
NSTimer *timer;
|
||||
}
|
||||
- (id)initWithPy:(PyApp *)aPy;
|
||||
- (PyExtraFairwareReminder *)py;
|
||||
|
||||
- (void)start;
|
||||
- (void)updateButton;
|
||||
- (IBAction)continue:(id)sender;
|
||||
- (IBAction)contribute:(id)sender;
|
||||
@end
|
||||
74
cocoa/base/ExtraFairwareReminder.m
Normal file
74
cocoa/base/ExtraFairwareReminder.m
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "ExtraFairwareReminder.h"
|
||||
|
||||
@implementation ExtraFairwareReminder
|
||||
- (id)initWithPy:(PyApp *)aPy
|
||||
{
|
||||
self = [super initWithNibName:@"ExtraFairwareReminder" pyClassName:@"PyExtraFairwareReminder" pyParent:aPy];
|
||||
[self window];
|
||||
[continueButton setEnabled:NO];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[timer release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (PyExtraFairwareReminder *)py
|
||||
{
|
||||
return (PyExtraFairwareReminder *)py;
|
||||
}
|
||||
|
||||
- (void)start
|
||||
{
|
||||
[[self py] start];
|
||||
}
|
||||
|
||||
- (void)updateButton
|
||||
{
|
||||
[[self py] updateButton];
|
||||
}
|
||||
|
||||
- (IBAction)continue:(id)sender
|
||||
{
|
||||
[NSApp stopModal];
|
||||
}
|
||||
|
||||
- (IBAction)contribute:(id)sender
|
||||
{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://open.hardcoded.net/contribute/"]];
|
||||
}
|
||||
|
||||
/* Model --> View */
|
||||
- (void)startTimer
|
||||
{
|
||||
timer = [[NSTimer timerWithTimeInterval:0.2 target:self selector:@selector(updateButton)
|
||||
userInfo:nil repeats:YES] retain];
|
||||
// Needed for the timer to work in modal mode.
|
||||
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSModalPanelRunLoopMode];
|
||||
}
|
||||
|
||||
- (void)stopTimer
|
||||
{
|
||||
[timer invalidate];
|
||||
}
|
||||
|
||||
- (void)setButtonText:(NSString *)text
|
||||
{
|
||||
[continueButton setTitle:text];
|
||||
}
|
||||
|
||||
- (void)enableButton
|
||||
{
|
||||
[continueButton setEnabled:YES];
|
||||
}
|
||||
@end
|
||||
25
cocoa/base/ProblemDialog.h
Normal file
25
cocoa/base/ProblemDialog.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "HSWindowController.h"
|
||||
#import "PyApp.h"
|
||||
#import "PyProblemDialog.h"
|
||||
#import "HSTable.h"
|
||||
|
||||
@interface ProblemDialog : HSWindowController
|
||||
{
|
||||
IBOutlet NSTableView *problemTableView;
|
||||
|
||||
HSTable *problemTable;
|
||||
}
|
||||
- (id)initWithPy:(PyApp *)aPy;
|
||||
- (PyProblemDialog *)py;
|
||||
|
||||
- (IBAction)revealSelected:(id)sender;
|
||||
@end
|
||||
40
cocoa/base/ProblemDialog.m
Normal file
40
cocoa/base/ProblemDialog.m
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "ProblemDialog.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation ProblemDialog
|
||||
- (id)initWithPy:(PyApp *)aPy
|
||||
{
|
||||
self = [super initWithNibName:@"ProblemDialog" pyClassName:@"PyProblemDialog" pyParent:aPy];
|
||||
[self window]; //So the detailsTable is initialized.
|
||||
problemTable = [[HSTable alloc] initWithPyClassName:@"PyProblemTable" pyParent:[self py] view:problemTableView];
|
||||
[self connect];
|
||||
[problemTable connect];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[problemTable disconnect];
|
||||
[self disconnect];
|
||||
[problemTable release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (PyProblemDialog *)py
|
||||
{
|
||||
return (PyProblemDialog *)py;
|
||||
}
|
||||
|
||||
- (IBAction)revealSelected:(id)sender
|
||||
{
|
||||
[[self py] revealSelected];
|
||||
}
|
||||
@end
|
||||
15
cocoa/base/PyDetailsPanel.h
Normal file
15
cocoa/base/PyDetailsPanel.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyGUI.h"
|
||||
|
||||
@interface PyDetailsPanel : PyGUI
|
||||
- (NSInteger)numberOfRows;
|
||||
- (id)valueForColumn:(NSString *)column row:(NSInteger)row;
|
||||
@end
|
||||
14
cocoa/base/PyDirectoryOutline.h
Normal file
14
cocoa/base/PyDirectoryOutline.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyOutline.h"
|
||||
|
||||
@interface PyDirectoryOutline : PyOutline
|
||||
- (void)addDirectory:(NSString *)directoryPath;
|
||||
@end
|
||||
57
cocoa/base/PyDupeGuru.h
Normal file
57
cocoa/base/PyDupeGuru.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyApp.h"
|
||||
|
||||
@interface PyDupeGuruBase : PyApp
|
||||
//Actions
|
||||
- (NSNumber *)addDirectory:(NSString *)name;
|
||||
- (void)removeDirectory:(NSNumber *)index;
|
||||
- (void)loadResultsFrom:(NSString *)filename;
|
||||
- (void)saveResultsAs:(NSString *)filename;
|
||||
- (void)loadSession;
|
||||
- (void)saveSession;
|
||||
- (void)clearIgnoreList;
|
||||
- (void)purgeIgnoreList;
|
||||
- (NSString *)exportToXHTMLwithColumns:(NSArray *)aColIds;
|
||||
- (void)invokeCommand:(NSString *)cmd;
|
||||
|
||||
- (NSNumber *)doScan;
|
||||
|
||||
- (void)toggleSelectedMark;
|
||||
- (void)markAll;
|
||||
- (void)markInvert;
|
||||
- (void)markNone;
|
||||
|
||||
- (void)addSelectedToIgnoreList;
|
||||
- (void)openSelected;
|
||||
- (void)revealSelected;
|
||||
- (void)makeSelectedReference;
|
||||
- (void)applyFilter:(NSString *)filter;
|
||||
|
||||
- (void)copyOrMove:(NSNumber *)aCopy markedTo:(NSString *)destination recreatePath:(NSNumber *)aRecreateType;
|
||||
- (void)deleteMarked;
|
||||
- (void)hardlinkMarked;
|
||||
- (void)removeMarked;
|
||||
|
||||
//Data
|
||||
- (NSNumber *)getIgnoreListCount;
|
||||
- (NSNumber *)getMarkCount;
|
||||
- (BOOL)scanWasProblematic;
|
||||
- (BOOL)resultsAreModified;
|
||||
- (NSArray *)deltaColumns;
|
||||
|
||||
//Scanning options
|
||||
- (void)setMinMatchPercentage:(NSNumber *)percentage;
|
||||
- (void)setMixFileKind:(BOOL)mix_file_kind;
|
||||
- (void)setEscapeFilterRegexp:(BOOL)escape_filter_regexp;
|
||||
- (void)setRemoveEmptyFolders:(BOOL)remove_empty_folders;
|
||||
- (void)setIgnoreHardlinkMatches:(BOOL)ignore_hardlink_matches;
|
||||
- (void)setSizeThreshold:(NSInteger)size_threshold;
|
||||
@end
|
||||
15
cocoa/base/PyExtraFairwareReminder.h
Normal file
15
cocoa/base/PyExtraFairwareReminder.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyGUI.h"
|
||||
|
||||
@interface PyExtraFairwareReminder : PyGUI
|
||||
- (void)start;
|
||||
- (void)updateButton;
|
||||
@end
|
||||
14
cocoa/base/PyProblemDialog.h
Normal file
14
cocoa/base/PyProblemDialog.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyGUI.h"
|
||||
|
||||
@interface PyProblemDialog : PyGUI
|
||||
- (void)revealSelected;
|
||||
@end
|
||||
24
cocoa/base/PyResultTable.h
Normal file
24
cocoa/base/PyResultTable.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyTable.h"
|
||||
|
||||
@interface PyResultTable : PyTable
|
||||
- (BOOL)powerMarkerMode;
|
||||
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode;
|
||||
- (BOOL)deltaValuesMode;
|
||||
- (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode;
|
||||
|
||||
- (NSString *)valueForRow:(NSInteger)rowIndex column:(NSInteger)aColumn;
|
||||
- (BOOL)renameSelected:(NSString *)aNewName;
|
||||
- (void)sortBy:(NSInteger)aIdentifier ascending:(BOOL)aAscending;
|
||||
- (void)markSelected;
|
||||
- (void)removeSelected;
|
||||
- (NSInteger)selectedDupeCount;
|
||||
@end
|
||||
14
cocoa/base/PyStatsLabel.h
Normal file
14
cocoa/base/PyStatsLabel.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "PyGUI.h"
|
||||
|
||||
@interface PyStatsLabel : PyGUI
|
||||
- (NSString *)display;
|
||||
@end
|
||||
26
cocoa/base/ResultTable.h
Normal file
26
cocoa/base/ResultTable.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "HSTable.h"
|
||||
#import "PyResultTable.h"
|
||||
|
||||
@interface ResultTable : HSTable
|
||||
{
|
||||
NSIndexSet *_deltaColumns;
|
||||
}
|
||||
- (id)initWithPyParent:(id)aPyParent view:(NSTableView *)aTableView;
|
||||
- (PyResultTable *)py;
|
||||
- (BOOL)powerMarkerMode;
|
||||
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode;
|
||||
- (BOOL)deltaValuesMode;
|
||||
- (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode;
|
||||
- (void)setDeltaColumns:(NSIndexSet *)aDeltaColumns;
|
||||
- (NSInteger)selectedDupeCount;
|
||||
- (void)removeSelected;
|
||||
@end;
|
||||
163
cocoa/base/ResultTable.m
Normal file
163
cocoa/base/ResultTable.m
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "ResultTable.h"
|
||||
#import "Dialogs.h"
|
||||
#import "Utils.h"
|
||||
#import "Consts.h"
|
||||
|
||||
@implementation ResultTable
|
||||
- (id)initWithPyParent:(id)aPyParent view:(NSTableView *)aTableView
|
||||
{
|
||||
self = [super initWithPyClassName:@"PyResultTable" pyParent:aPyParent view:aTableView];
|
||||
[self connect];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self disconnect];
|
||||
[_deltaColumns release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (PyResultTable *)py
|
||||
{
|
||||
return (PyResultTable *)py;
|
||||
}
|
||||
|
||||
/* Public */
|
||||
- (BOOL)powerMarkerMode
|
||||
{
|
||||
return [[self py] powerMarkerMode];
|
||||
}
|
||||
|
||||
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode
|
||||
{
|
||||
[[self py] setPowerMarkerMode:aPowerMarkerMode];
|
||||
}
|
||||
|
||||
- (BOOL)deltaValuesMode
|
||||
{
|
||||
return [[self py] deltaValuesMode];
|
||||
}
|
||||
|
||||
- (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode
|
||||
{
|
||||
[[self py] setDeltaValuesMode:aDeltaValuesMode];
|
||||
}
|
||||
|
||||
- (void)setDeltaColumns:(NSIndexSet *)aDeltaColumns
|
||||
{
|
||||
[_deltaColumns release];
|
||||
_deltaColumns = [aDeltaColumns retain];
|
||||
}
|
||||
|
||||
- (NSInteger)selectedDupeCount
|
||||
{
|
||||
return [[self py] selectedDupeCount];
|
||||
}
|
||||
|
||||
- (void)removeSelected
|
||||
{
|
||||
NSInteger selectedDupeCount = [self selectedDupeCount];
|
||||
if (!selectedDupeCount)
|
||||
return;
|
||||
NSString *msgFmt = TR(@"FileRemovalConfirmMsg");
|
||||
NSString *msg = [NSString stringWithFormat:msgFmt,selectedDupeCount];
|
||||
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
||||
return;
|
||||
[[self py] removeSelected];
|
||||
}
|
||||
|
||||
/* Datasource */
|
||||
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)column row:(NSInteger)row
|
||||
{
|
||||
NSString *identifier = [column identifier];
|
||||
if ([identifier isEqual:@"marked"]) {
|
||||
return [[self py] valueForColumn:@"marked" row:row];
|
||||
}
|
||||
NSInteger columnId = [identifier integerValue];
|
||||
return [[self py] valueForRow:row column:columnId];
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)column row:(NSInteger)row
|
||||
{
|
||||
NSString *identifier = [column identifier];
|
||||
if ([identifier isEqual:@"marked"]) {
|
||||
[[self py] setValue:object forColumn:identifier row:row];
|
||||
}
|
||||
else if ([identifier isEqual:@"0"]) {
|
||||
NSString *oldName = [[self py] valueForRow:row column:0];
|
||||
NSString *newName = object;
|
||||
if (![newName isEqual:oldName]) {
|
||||
BOOL renamed = [[self py] renameSelected:newName];
|
||||
if (!renamed) {
|
||||
[Dialogs showMessage:[NSString stringWithFormat:TR(@"FilenameAlreadyExistsMsg"), newName]];
|
||||
}
|
||||
else {
|
||||
[tableView setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Delegate */
|
||||
- (void)tableView:(NSTableView *)aTableView didClickTableColumn:(NSTableColumn *)tableColumn
|
||||
{
|
||||
if ([[tableView sortDescriptors] count] < 1)
|
||||
return;
|
||||
NSSortDescriptor *sd = [[tableView sortDescriptors] objectAtIndex:0];
|
||||
[[self py] sortBy:[[sd key] integerValue] ascending:[sd ascending]];
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)column row:(NSInteger)row
|
||||
{
|
||||
BOOL isMarkable = n2b([[self py] valueForColumn:@"markable" row:row]);
|
||||
if ([[column identifier] isEqual:@"marked"]) {
|
||||
[cell setEnabled:isMarkable];
|
||||
// Low-tech solution, for indentation, but it works...
|
||||
NSCellImagePosition pos = isMarkable ? NSImageRight : NSImageLeft;
|
||||
[cell setImagePosition:pos];
|
||||
}
|
||||
if ([cell isKindOfClass:[NSTextFieldCell class]]) {
|
||||
// Determine if the text color will be blue due to directory being reference.
|
||||
NSTextFieldCell *textCell = cell;
|
||||
if (isMarkable) {
|
||||
[textCell setTextColor:[NSColor blackColor]];
|
||||
if ([self deltaValuesMode]) {
|
||||
NSInteger i = [[column identifier] integerValue];
|
||||
if ([_deltaColumns containsIndex:i]) {
|
||||
[textCell setTextColor:[NSColor orangeColor]];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
[textCell setTextColor:[NSColor blueColor]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tableViewHadDeletePressed:(NSTableView *)tableView
|
||||
{
|
||||
[self removeSelected];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)tableViewHadSpacePressed:(NSTableView *)tableView
|
||||
{
|
||||
[[self py] markSelected];
|
||||
return YES;
|
||||
}
|
||||
|
||||
/* Python --> Cocoa */
|
||||
- (void)invalidateMarkings
|
||||
{
|
||||
[tableView setNeedsDisplay:YES];
|
||||
}
|
||||
@end
|
||||
82
cocoa/base/ResultWindow.h
Normal file
82
cocoa/base/ResultWindow.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "StatsLabel.h"
|
||||
#import "ResultTable.h"
|
||||
#import "ProblemDialog.h"
|
||||
#import "HSTableView.h"
|
||||
#import "PyDupeGuru.h"
|
||||
|
||||
@class AppDelegateBase;
|
||||
|
||||
@interface ResultWindowBase : NSWindowController
|
||||
{
|
||||
@protected
|
||||
IBOutlet NSSegmentedControl *optionsSwitch;
|
||||
IBOutlet HSTableView *matches;
|
||||
IBOutlet NSTextField *stats;
|
||||
IBOutlet NSSearchField *filterField;
|
||||
|
||||
AppDelegateBase *app;
|
||||
PyDupeGuruBase *py;
|
||||
NSMenu *columnsMenu;
|
||||
NSMutableArray *_resultColumns;
|
||||
ResultTable *table;
|
||||
StatsLabel *statsLabel;
|
||||
ProblemDialog *problemDialog;
|
||||
}
|
||||
- (id)initWithParentApp:(AppDelegateBase *)app;
|
||||
|
||||
/* Virtual */
|
||||
- (void)initResultColumns;
|
||||
- (void)setScanOptions;
|
||||
- (NSString *)getScanErrorMessageForCode:(NSInteger)errorCode;
|
||||
|
||||
/* Helpers */
|
||||
- (void)fillColumnsMenu;
|
||||
- (NSTableColumn *)getColumnForIdentifier:(NSInteger)aIdentifier title:(NSString *)aTitle width:(NSInteger)aWidth refCol:(NSTableColumn *)aColumn;
|
||||
- (NSArray *)getColumnsOrder;
|
||||
- (NSDictionary *)getColumnsWidth;
|
||||
- (void)restoreColumnsPosition:(NSArray *)aColumnsOrder widths:(NSDictionary *)aColumnsWidth;
|
||||
- (void)sendMarkedToTrash:(BOOL)hardlinkDeleted;
|
||||
- (void)updateOptionSegments;
|
||||
|
||||
/* Actions */
|
||||
- (IBAction)clearIgnoreList:(id)sender;
|
||||
- (IBAction)changeOptions:(id)sender;
|
||||
- (IBAction)copyMarked:(id)sender;
|
||||
- (IBAction)deleteMarked:(id)sender;
|
||||
- (IBAction)hardlinkMarked:(id)sender;
|
||||
- (IBAction)exportToXHTML:(id)sender;
|
||||
- (IBAction)filter:(id)sender;
|
||||
- (IBAction)ignoreSelected:(id)sender;
|
||||
- (IBAction)invokeCustomCommand:(id)sender;
|
||||
- (IBAction)markAll:(id)sender;
|
||||
- (IBAction)markInvert:(id)sender;
|
||||
- (IBAction)markNone:(id)sender;
|
||||
- (IBAction)markSelected:(id)sender;
|
||||
- (IBAction)moveMarked:(id)sender;
|
||||
- (IBAction)openClicked:(id)sender;
|
||||
- (IBAction)openSelected:(id)sender;
|
||||
- (IBAction)removeMarked:(id)sender;
|
||||
- (IBAction)removeSelected:(id)sender;
|
||||
- (IBAction)renameSelected:(id)sender;
|
||||
- (IBAction)resetColumnsToDefault:(id)sender;
|
||||
- (IBAction)revealSelected:(id)sender;
|
||||
- (IBAction)saveResults:(id)sender;
|
||||
- (IBAction)startDuplicateScan:(id)sender;
|
||||
- (IBAction)switchSelected:(id)sender;
|
||||
- (IBAction)toggleColumn:(id)sender;
|
||||
- (IBAction)toggleDelta:(id)sender;
|
||||
- (IBAction)toggleDetailsPanel:(id)sender;
|
||||
- (IBAction)togglePowerMarker:(id)sender;
|
||||
|
||||
/* Notifications */
|
||||
- (void)jobCompleted:(NSNotification *)aNotification;
|
||||
@end
|
||||
479
cocoa/base/ResultWindow.m
Normal file
479
cocoa/base/ResultWindow.m
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "ResultWindow.h"
|
||||
#import "Dialogs.h"
|
||||
#import "ProgressController.h"
|
||||
#import "Utils.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "Consts.h"
|
||||
|
||||
@implementation ResultWindowBase
|
||||
- (id)initWithParentApp:(AppDelegateBase *)aApp;
|
||||
{
|
||||
self = [super initWithWindowNibName:@"ResultWindow"];
|
||||
app = aApp;
|
||||
py = [app py];
|
||||
columnsMenu = [app columnsMenu];
|
||||
/* Put a cute iTunes-like bottom bar */
|
||||
[[self window] setContentBorderThickness:28 forEdge:NSMinYEdge];
|
||||
table = [[ResultTable alloc] initWithPyParent:py view:matches];
|
||||
statsLabel = [[StatsLabel alloc] initWithPyParent:py labelView:stats];
|
||||
problemDialog = [[ProblemDialog alloc] initWithPy:py];
|
||||
[self initResultColumns];
|
||||
[self fillColumnsMenu];
|
||||
[matches setTarget:self];
|
||||
[matches setDoubleAction:@selector(openClicked:)];
|
||||
[table setDeltaColumns:[Utils array2IndexSet:[py deltaColumns]]];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobCompleted:) name:JobCompletedNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobStarted:) name:JobStarted object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobInProgress:) name:JobInProgress object:nil];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[table release];
|
||||
[statsLabel release];
|
||||
[problemDialog release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* Virtual */
|
||||
- (void)initResultColumns
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setScanOptions
|
||||
{
|
||||
}
|
||||
|
||||
- (NSString *)getScanErrorMessageForCode:(NSInteger)errorCode
|
||||
{
|
||||
if (errorCode == 0) {
|
||||
return nil;
|
||||
}
|
||||
if (errorCode == 3) {
|
||||
return TR(@"NoScannableFileMsg");
|
||||
}
|
||||
return TR(@"UnknownErrorMsg");
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
- (void)fillColumnsMenu
|
||||
{
|
||||
// The columns menu is supposed to be empty and initResultColumns must have been called
|
||||
for (NSTableColumn *col in _resultColumns)
|
||||
{
|
||||
NSMenuItem *mi = [columnsMenu addItemWithTitle:[[col headerCell] stringValue] action:@selector(toggleColumn:) keyEquivalent:@""];
|
||||
[mi setTag:[[col identifier] integerValue]];
|
||||
[mi setTarget:self];
|
||||
if ([[matches tableColumns] containsObject:col])
|
||||
[mi setState:NSOnState];
|
||||
}
|
||||
[columnsMenu addItem:[NSMenuItem separatorItem]];
|
||||
NSMenuItem *mi = [columnsMenu addItemWithTitle:TR(@"Reset to Default")
|
||||
action:@selector(resetColumnsToDefault:) keyEquivalent:@""];
|
||||
[mi setTarget:self];
|
||||
}
|
||||
|
||||
- (NSTableColumn *)getColumnForIdentifier:(NSInteger)aIdentifier title:(NSString *)aTitle width:(NSInteger)aWidth refCol:(NSTableColumn *)aColumn
|
||||
{
|
||||
NSNumber *n = [NSNumber numberWithInteger:aIdentifier];
|
||||
NSTableColumn *col = [[NSTableColumn alloc] initWithIdentifier:[n stringValue]];
|
||||
[col setWidth:aWidth];
|
||||
[col setEditable:NO];
|
||||
[[col dataCell] setFont:[[aColumn dataCell] font]];
|
||||
[[col headerCell] setStringValue:aTitle];
|
||||
[col setResizingMask:NSTableColumnUserResizingMask];
|
||||
[col setSortDescriptorPrototype:[[NSSortDescriptor alloc] initWithKey:[n stringValue] ascending:YES]];
|
||||
return col;
|
||||
}
|
||||
|
||||
//Returns an array of identifiers, in order.
|
||||
- (NSArray *)getColumnsOrder
|
||||
{
|
||||
NSMutableArray *result = [NSMutableArray array];
|
||||
for (NSTableColumn *col in [matches tableColumns]) {
|
||||
NSString *colId = [col identifier];
|
||||
[result addObject:colId];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSDictionary *)getColumnsWidth
|
||||
{
|
||||
NSMutableDictionary *result = [NSMutableDictionary dictionary];
|
||||
for (NSTableColumn *col in [matches tableColumns]) {
|
||||
NSString *colId = [col identifier];
|
||||
NSNumber *width = [NSNumber numberWithDouble:[col width]];
|
||||
[result setObject:width forKey:colId];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)restoreColumnsPosition:(NSArray *)aColumnsOrder widths:(NSDictionary *)aColumnsWidth
|
||||
{
|
||||
for (NSMenuItem *mi in [columnsMenu itemArray]) {
|
||||
if ([mi state] == NSOnState) {
|
||||
[self toggleColumn:mi];
|
||||
}
|
||||
}
|
||||
//Add columns and set widths
|
||||
for (NSString *colId in aColumnsOrder) {
|
||||
NSInteger colIndex = [colId integerValue];
|
||||
if ((colIndex == 0) && (![colId isEqual:@"0"])) {
|
||||
continue;
|
||||
}
|
||||
NSTableColumn *col = [_resultColumns objectAtIndex:colIndex];
|
||||
NSNumber *width = [aColumnsWidth objectForKey:[col identifier]];
|
||||
NSMenuItem *mi = [columnsMenu itemWithTag:colIndex];
|
||||
if (width) {
|
||||
[col setWidth:[width floatValue]];
|
||||
}
|
||||
[self toggleColumn:mi];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendMarkedToTrash:(BOOL)hardlinkDeleted
|
||||
{
|
||||
NSInteger mark_count = [[py getMarkCount] intValue];
|
||||
if (!mark_count) {
|
||||
return;
|
||||
}
|
||||
NSString *msg = TR(@"SendToTrashConfirmMsg");
|
||||
if (hardlinkDeleted) {
|
||||
msg = TR(@"HardlinkConfirmMsg");
|
||||
}
|
||||
if ([Dialogs askYesNo:[NSString stringWithFormat:msg,mark_count]] == NSAlertSecondButtonReturn) { // NO
|
||||
return;
|
||||
}
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
[py setRemoveEmptyFolders:n2b([ud objectForKey:@"removeEmptyFolders"])];
|
||||
if (hardlinkDeleted) {
|
||||
[py hardlinkMarked];
|
||||
}
|
||||
else {
|
||||
[py deleteMarked];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateOptionSegments
|
||||
{
|
||||
[optionsSwitch setSelected:[[app detailsPanel] isVisible] forSegment:0];
|
||||
[optionsSwitch setSelected:[table powerMarkerMode] forSegment:1];
|
||||
[optionsSwitch setSelected:[table deltaValuesMode] forSegment:2];
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
- (IBAction)clearIgnoreList:(id)sender
|
||||
{
|
||||
NSInteger i = n2i([py getIgnoreListCount]);
|
||||
if (!i)
|
||||
return;
|
||||
NSString *msg = [NSString stringWithFormat:TR(@"ClearIgnoreListConfirmMsg"),i];
|
||||
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
||||
return;
|
||||
[py clearIgnoreList];
|
||||
}
|
||||
|
||||
- (IBAction)changeOptions:(id)sender
|
||||
{
|
||||
NSInteger seg = [optionsSwitch selectedSegment];
|
||||
if (seg == 0) {
|
||||
[self toggleDetailsPanel:sender];
|
||||
}
|
||||
else if (seg == 1) {
|
||||
[self togglePowerMarker:sender];
|
||||
}
|
||||
else if (seg == 2) {
|
||||
[self toggleDelta:sender];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)copyMarked:(id)sender
|
||||
{
|
||||
NSInteger mark_count = [[py getMarkCount] intValue];
|
||||
if (!mark_count)
|
||||
return;
|
||||
NSOpenPanel *op = [NSOpenPanel openPanel];
|
||||
[op setCanChooseFiles:NO];
|
||||
[op setCanChooseDirectories:YES];
|
||||
[op setCanCreateDirectories:YES];
|
||||
[op setAllowsMultipleSelection:NO];
|
||||
[op setTitle:TR(@"SelectCopyDestinationMsg")];
|
||||
if ([op runModal] == NSOKButton) {
|
||||
NSString *directory = [[op filenames] objectAtIndex:0];
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
[py copyOrMove:b2n(YES) markedTo:directory recreatePath:[ud objectForKey:@"recreatePathType"]];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)deleteMarked:(id)sender
|
||||
{
|
||||
[self sendMarkedToTrash:NO];
|
||||
}
|
||||
|
||||
- (IBAction)hardlinkMarked:(id)sender
|
||||
{
|
||||
[self sendMarkedToTrash:YES];
|
||||
}
|
||||
|
||||
- (IBAction)exportToXHTML:(id)sender
|
||||
{
|
||||
NSString *exported = [py exportToXHTMLwithColumns:[self getColumnsOrder]];
|
||||
[[NSWorkspace sharedWorkspace] openFile:exported];
|
||||
}
|
||||
|
||||
- (IBAction)filter:(id)sender
|
||||
{
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
[py setEscapeFilterRegexp:!n2b([ud objectForKey:@"useRegexpFilter"])];
|
||||
[py applyFilter:[filterField stringValue]];
|
||||
}
|
||||
|
||||
- (IBAction)ignoreSelected:(id)sender
|
||||
{
|
||||
NSInteger selectedDupeCount = [table selectedDupeCount];
|
||||
if (!selectedDupeCount)
|
||||
return;
|
||||
NSString *msg = [NSString stringWithFormat:TR(@"IgnoreConfirmMsg"),selectedDupeCount];
|
||||
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
||||
return;
|
||||
[py addSelectedToIgnoreList];
|
||||
}
|
||||
|
||||
- (IBAction)invokeCustomCommand:(id)sender
|
||||
{
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
NSString *cmd = [ud stringForKey:@"CustomCommand"];
|
||||
if ((cmd != nil) && ([cmd length] > 0)) {
|
||||
[py invokeCommand:cmd];
|
||||
}
|
||||
else {
|
||||
[Dialogs showMessage:TR(@"NoCustomCommandMsg")];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)markAll:(id)sender
|
||||
{
|
||||
[py markAll];
|
||||
}
|
||||
|
||||
- (IBAction)markInvert:(id)sender
|
||||
{
|
||||
[py markInvert];
|
||||
}
|
||||
|
||||
- (IBAction)markNone:(id)sender
|
||||
{
|
||||
[py markNone];
|
||||
}
|
||||
|
||||
- (IBAction)markSelected:(id)sender
|
||||
{
|
||||
[py toggleSelectedMark];
|
||||
}
|
||||
|
||||
- (IBAction)moveMarked:(id)sender
|
||||
{
|
||||
NSInteger mark_count = [[py getMarkCount] intValue];
|
||||
if (!mark_count)
|
||||
return;
|
||||
NSOpenPanel *op = [NSOpenPanel openPanel];
|
||||
[op setCanChooseFiles:NO];
|
||||
[op setCanChooseDirectories:YES];
|
||||
[op setCanCreateDirectories:YES];
|
||||
[op setAllowsMultipleSelection:NO];
|
||||
[op setTitle:TR(@"SelectMoveDestinationMsg")];
|
||||
if ([op runModal] == NSOKButton) {
|
||||
NSString *directory = [[op filenames] objectAtIndex:0];
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
[py setRemoveEmptyFolders:n2b([ud objectForKey:@"removeEmptyFolders"])];
|
||||
[py copyOrMove:b2n(NO) markedTo:directory recreatePath:[ud objectForKey:@"recreatePathType"]];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)openClicked:(id)sender
|
||||
{
|
||||
if ([matches clickedRow] < 0) {
|
||||
return;
|
||||
}
|
||||
[matches selectRowIndexes:[NSIndexSet indexSetWithIndex:[matches clickedRow]] byExtendingSelection:NO];
|
||||
[py openSelected];
|
||||
}
|
||||
|
||||
- (IBAction)openSelected:(id)sender
|
||||
{
|
||||
[py openSelected];
|
||||
}
|
||||
|
||||
- (IBAction)removeMarked:(id)sender
|
||||
{
|
||||
int mark_count = [[py getMarkCount] intValue];
|
||||
if (!mark_count)
|
||||
return;
|
||||
NSString *msg = [NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",mark_count];
|
||||
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
||||
return;
|
||||
[py removeMarked];
|
||||
}
|
||||
|
||||
- (IBAction)removeSelected:(id)sender
|
||||
{
|
||||
[table removeSelected];
|
||||
}
|
||||
|
||||
- (IBAction)renameSelected:(id)sender
|
||||
{
|
||||
NSInteger col = [matches columnWithIdentifier:@"0"];
|
||||
NSInteger row = [matches selectedRow];
|
||||
[matches editColumn:col row:row withEvent:[NSApp currentEvent] select:YES];
|
||||
}
|
||||
|
||||
- (IBAction)resetColumnsToDefault:(id)sender
|
||||
{
|
||||
// Virtual
|
||||
}
|
||||
|
||||
- (IBAction)revealSelected:(id)sender
|
||||
{
|
||||
[py revealSelected];
|
||||
}
|
||||
|
||||
- (IBAction)saveResults:(id)sender
|
||||
{
|
||||
NSSavePanel *sp = [NSSavePanel savePanel];
|
||||
[sp setCanCreateDirectories:YES];
|
||||
[sp setAllowedFileTypes:[NSArray arrayWithObject:@"dupeguru"]];
|
||||
[sp setTitle:TR(@"SelectResultToSaveMsg")];
|
||||
if ([sp runModal] == NSOKButton) {
|
||||
[py saveResultsAs:[sp filename]];
|
||||
[[app recentResults] addFile:[sp filename]];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)startDuplicateScan:(id)sender
|
||||
{
|
||||
if ([py resultsAreModified]) {
|
||||
if ([Dialogs askYesNo:TR(@"ReallyWantToContinueMsg")] == NSAlertSecondButtonReturn) // NO
|
||||
return;
|
||||
}
|
||||
[self setScanOptions];
|
||||
NSInteger r = n2i([py doScan]);
|
||||
NSString *errorMsg = [self getScanErrorMessageForCode:r];
|
||||
if (errorMsg != nil) {
|
||||
[[ProgressController mainProgressController] hide];
|
||||
[Dialogs showMessage:errorMsg];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)switchSelected:(id)sender
|
||||
{
|
||||
[py makeSelectedReference];
|
||||
}
|
||||
|
||||
- (IBAction)toggleColumn:(id)sender
|
||||
{
|
||||
NSMenuItem *mi = sender;
|
||||
NSString *colId = [NSString stringWithFormat:@"%d",[mi tag]];
|
||||
NSTableColumn *col = [matches tableColumnWithIdentifier:colId];
|
||||
if (col == nil) {
|
||||
//Add Column
|
||||
col = [_resultColumns objectAtIndex:[mi tag]];
|
||||
[matches addTableColumn:col];
|
||||
[mi setState:NSOnState];
|
||||
}
|
||||
else {
|
||||
//Remove column
|
||||
[matches removeTableColumn:col];
|
||||
[mi setState:NSOffState];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)toggleDetailsPanel:(id)sender
|
||||
{
|
||||
[[app detailsPanel] toggleVisibility];
|
||||
[self updateOptionSegments];
|
||||
}
|
||||
|
||||
- (IBAction)toggleDelta:(id)sender
|
||||
{
|
||||
[table setDeltaValuesMode:![table deltaValuesMode]];
|
||||
[self updateOptionSegments];
|
||||
}
|
||||
|
||||
- (IBAction)togglePowerMarker:(id)sender
|
||||
{
|
||||
[table setPowerMarkerMode:![table powerMarkerMode]];
|
||||
[self updateOptionSegments];
|
||||
}
|
||||
|
||||
/* Notifications */
|
||||
- (void)jobCompleted:(NSNotification *)aNotification
|
||||
{
|
||||
id lastAction = [[ProgressController mainProgressController] jobId];
|
||||
if ([lastAction isEqualTo:jobCopy]) {
|
||||
if ([py scanWasProblematic]) {
|
||||
[problemDialog showWindow:self];
|
||||
}
|
||||
else {
|
||||
[Dialogs showMessage:TR(@"CopySuccessMsg")];
|
||||
}
|
||||
}
|
||||
else if ([lastAction isEqualTo:jobMove]) {
|
||||
if ([py scanWasProblematic]) {
|
||||
[problemDialog showWindow:self];
|
||||
}
|
||||
else {
|
||||
[Dialogs showMessage:TR(@"MoveSuccessMsg")];
|
||||
}
|
||||
}
|
||||
else if ([lastAction isEqualTo:jobDelete]) {
|
||||
if ([py scanWasProblematic]) {
|
||||
[problemDialog showWindow:self];
|
||||
}
|
||||
else {
|
||||
[Dialogs showMessage:TR(@"SendToTrashSuccessMsg")];
|
||||
}
|
||||
}
|
||||
else if ([lastAction isEqualTo:jobScan]) {
|
||||
NSInteger rowCount = [[table py] numberOfRows];
|
||||
if (rowCount == 0) {
|
||||
[Dialogs showMessage:TR(@"NoDuplicateFoundMsg")];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)jobInProgress:(NSNotification *)aNotification
|
||||
{
|
||||
[Dialogs showMessage:TR(@"TaskHangingMsg")];
|
||||
}
|
||||
|
||||
- (void)jobStarted:(NSNotification *)aNotification
|
||||
{
|
||||
[[self window] makeKeyAndOrderFront:nil];
|
||||
NSDictionary *ui = [aNotification userInfo];
|
||||
NSString *desc = [ui valueForKey:@"desc"];
|
||||
[[ProgressController mainProgressController] setJobDesc:desc];
|
||||
NSString *jobid = [ui valueForKey:@"jobid"];
|
||||
[[ProgressController mainProgressController] setJobId:jobid];
|
||||
[[ProgressController mainProgressController] showSheetForParent:[self window]];
|
||||
}
|
||||
|
||||
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
|
||||
{
|
||||
return ![[ProgressController mainProgressController] isShown];
|
||||
}
|
||||
|
||||
- (BOOL)validateMenuItem:(NSMenuItem *)item
|
||||
{
|
||||
return ![[ProgressController mainProgressController] isShown];
|
||||
}
|
||||
@end
|
||||
19
cocoa/base/StatsLabel.h
Normal file
19
cocoa/base/StatsLabel.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "HSGUIController.h"
|
||||
#import "PyStatsLabel.h"
|
||||
|
||||
@interface StatsLabel : HSGUIController
|
||||
{
|
||||
NSTextField *labelView;
|
||||
}
|
||||
- (id)initWithPyParent:(id)aPyParent labelView:(NSTextField *)aLabelView;
|
||||
- (PyStatsLabel *)py;
|
||||
@end
|
||||
38
cocoa/base/StatsLabel.m
Normal file
38
cocoa/base/StatsLabel.m
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "StatsLabel.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation StatsLabel
|
||||
- (id)initWithPyParent:(id)aPyParent labelView:(NSTextField *)aLabelView
|
||||
{
|
||||
self = [super initWithPyClassName:@"PyStatsLabel" pyParent:aPyParent];
|
||||
labelView = [aLabelView retain];
|
||||
[self connect];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self disconnect];
|
||||
[labelView release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (PyStatsLabel *)py
|
||||
{
|
||||
return (PyStatsLabel *)py;
|
||||
}
|
||||
|
||||
/* Python --> Cocoa */
|
||||
- (void)refresh
|
||||
{
|
||||
[labelView setStringValue:[[self py] display]];
|
||||
}
|
||||
@end
|
||||
12
cocoa/base/en.lproj/DetailsPanel.strings
Normal file
12
cocoa/base/en.lproj/DetailsPanel.strings
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
/* Class = "NSPanel"; title = "Details of Selected File"; ObjectID = "5"; */
|
||||
"5.title" = "Details of Selected File";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Selected"; ObjectID = "9"; */
|
||||
"9.headerCell.title" = "Selected";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Reference"; ObjectID = "10"; */
|
||||
"10.headerCell.title" = "Reference";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Attribute"; ObjectID = "11"; */
|
||||
"11.headerCell.title" = "Attribute";
|
||||
@@ -2,17 +2,17 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">10B504</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.2</string>
|
||||
<string key="IBDocument.HIToolboxVersion">437.00</string>
|
||||
<string key="IBDocument.SystemVersion">10F569</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">788</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.29</string>
|
||||
<string key="IBDocument.HIToolboxVersion">461.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">740</string>
|
||||
<string key="NS.object.0">788</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<integer value="5"/>
|
||||
<integer value="6"/>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -41,7 +41,7 @@
|
||||
<object class="NSWindowTemplate" id="476890502">
|
||||
<int key="NSWindowStyleMask">155</int>
|
||||
<int key="NSWindowBacking">2</int>
|
||||
<string key="NSWindowRect">{{33, 261}, {451, 161}}</string>
|
||||
<string key="NSWindowRect">{{33, 261}, {451, 146}}</string>
|
||||
<int key="NSWTFlags">-260571136</int>
|
||||
<string key="NSWindowTitle">Details of Selected File</string>
|
||||
<object class="NSMutableString" key="NSWindowClass">
|
||||
@@ -51,7 +51,7 @@
|
||||
<characters key="NS.bytes">View</characters>
|
||||
</object>
|
||||
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
<string key="NSWindowContentMinSize">{451, 161}</string>
|
||||
<string key="NSWindowContentMinSize">{451, 146}</string>
|
||||
<object class="NSView" key="NSWindowView" id="1027711962">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
@@ -70,7 +70,7 @@
|
||||
<object class="NSTableView" id="251969872">
|
||||
<reference key="NSNextResponder" ref="488480549"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrameSize">{449, 143}</string>
|
||||
<string key="NSFrameSize">{449, 128}</string>
|
||||
<reference key="NSSuperview" ref="488480549"/>
|
||||
<int key="NSTag">2</int>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
@@ -224,7 +224,7 @@
|
||||
<int key="NSTableViewDraggingDestinationStyle">0</int>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrame">{{1, 17}, {449, 143}}</string>
|
||||
<string key="NSFrame">{{1, 17}, {449, 128}}</string>
|
||||
<reference key="NSSuperview" ref="362108788"/>
|
||||
<reference key="NSNextKeyView" ref="251969872"/>
|
||||
<reference key="NSDocView" ref="251969872"/>
|
||||
@@ -266,7 +266,7 @@
|
||||
</object>
|
||||
<reference ref="717380566"/>
|
||||
</object>
|
||||
<string key="NSFrameSize">{451, 161}</string>
|
||||
<string key="NSFrameSize">{451, 146}</string>
|
||||
<reference key="NSSuperview" ref="1027711962"/>
|
||||
<reference key="NSNextKeyView" ref="488480549"/>
|
||||
<int key="NSsFlags">530</int>
|
||||
@@ -278,12 +278,13 @@
|
||||
<bytes key="NSScrollAmts">QSAAAEEgAABBgAAAQYAAAA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{451, 161}</string>
|
||||
<string key="NSFrameSize">{451, 146}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
</object>
|
||||
<string key="NSScreenRect">{{0, 0}, {1024, 746}}</string>
|
||||
<string key="NSMinSize">{451, 177}</string>
|
||||
<string key="NSMinSize">{451, 162}</string>
|
||||
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
<string key="NSFrameAutosaveName">DetailsPanel</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
@@ -297,13 +298,21 @@
|
||||
</object>
|
||||
<int key="connectionID">12</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">dataSource</string>
|
||||
<reference key="source" ref="251969872"/>
|
||||
<reference key="destination" ref="449947658"/>
|
||||
</object>
|
||||
<int key="connectionID">21</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">detailsTable</string>
|
||||
<reference key="source" ref="449947658"/>
|
||||
<reference key="destination" ref="251969872"/>
|
||||
</object>
|
||||
<int key="connectionID">13</int>
|
||||
<int key="connectionID">22</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
@@ -438,15 +447,22 @@
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-3.IBPluginDependency</string>
|
||||
<string>10.IBPluginDependency</string>
|
||||
<string>10.ImportedFromIB2</string>
|
||||
<string>11.IBPluginDependency</string>
|
||||
<string>11.ImportedFromIB2</string>
|
||||
<string>15.IBPluginDependency</string>
|
||||
<string>15.IBShouldRemoveOnLegacySave</string>
|
||||
<string>16.IBPluginDependency</string>
|
||||
<string>16.IBShouldRemoveOnLegacySave</string>
|
||||
<string>17.IBPluginDependency</string>
|
||||
<string>17.IBShouldRemoveOnLegacySave</string>
|
||||
<string>18.IBPluginDependency</string>
|
||||
<string>18.IBShouldRemoveOnLegacySave</string>
|
||||
<string>19.IBPluginDependency</string>
|
||||
<string>19.IBShouldRemoveOnLegacySave</string>
|
||||
<string>20.IBPluginDependency</string>
|
||||
<string>20.IBShouldRemoveOnLegacySave</string>
|
||||
<string>5.IBEditorWindowLastContentRect</string>
|
||||
<string>5.IBPluginDependency</string>
|
||||
@@ -458,7 +474,6 @@
|
||||
<string>6.ImportedFromIB2</string>
|
||||
<string>7.IBPluginDependency</string>
|
||||
<string>7.ImportedFromIB2</string>
|
||||
<string>8.CustomClassName</string>
|
||||
<string>8.IBPluginDependency</string>
|
||||
<string>8.ImportedFromIB2</string>
|
||||
<string>9.IBPluginDependency</string>
|
||||
@@ -467,26 +482,32 @@
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<string>{{109, 656}, {451, 161}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{109, 656}, {451, 161}}</string>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<string>{451, 161}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>TableView</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{109, 671}, {451, 146}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{109, 671}, {451, 146}}</string>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<string>{451, 146}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
@@ -509,86 +530,72 @@
|
||||
</object>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">20</int>
|
||||
<int key="maxID">22</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">DetailsPanel</string>
|
||||
<string key="superclassName">DetailsPanelBase</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">DetailsPanel.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">DetailsPanel</string>
|
||||
<string key="superclassName">DetailsPanelBase</string>
|
||||
<string key="superclassName">HSWindowController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">detailsTable</string>
|
||||
<string key="NS.object.0">NSTableView</string>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBUserSource</string>
|
||||
<string key="minorKey"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">DetailsPanelBase</string>
|
||||
<string key="superclassName">NSWindowController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">detailsTable</string>
|
||||
<string key="NS.object.0">TableView</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">detailsTable</string>
|
||||
<string key="candidateClassName">NSTableView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">dgbase/DetailsPanel.h</string>
|
||||
<string key="minorKey">../base/DetailsPanel.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">DetailsPanel</string>
|
||||
<string key="superclassName">HSWindowController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBUserSource</string>
|
||||
<string key="minorKey"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">FirstResponder</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBUserSource</string>
|
||||
<string key="minorKey"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">PyApp</string>
|
||||
<string key="superclassName">PyRegistrable</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">cocoalib/PyApp.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">PyRegistrable</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">cocoalib/PyRegistrable.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">TableView</string>
|
||||
<string key="superclassName">NSTableView</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">py</string>
|
||||
<string key="NS.object.0">PyApp</string>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">cocoalib/Table.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">TableView</string>
|
||||
<string key="superclassName">NSTableView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBUserSource</string>
|
||||
<string key="minorKey"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">HSWindowController</string>
|
||||
<string key="superclassName">NSWindowController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../controllers/HSWindowController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="111130406">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSTableView</string>
|
||||
<reference key="sourceIdentifier" ref="111130406"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -1056,6 +1063,13 @@
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">showWindow:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
|
||||
@@ -1064,6 +1078,7 @@
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
23
cocoa/base/en.lproj/DirectoryPanel.strings
Normal file
23
cocoa/base/en.lproj/DirectoryPanel.strings
Normal file
@@ -0,0 +1,23 @@
|
||||
/* Class = "NSTableColumn"; headerCell.title = "State"; ObjectID = "13"; */
|
||||
"13.headerCell.title" = "State";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "15"; */
|
||||
"15.headerCell.title" = "Name";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Scan"; ObjectID = "48"; */
|
||||
"48.title" = "Scan";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "55"; */
|
||||
"55.title" = "Normal";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Reference"; ObjectID = "56"; */
|
||||
"56.title" = "Reference";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Excluded"; ObjectID = "57"; */
|
||||
"57.title" = "Excluded";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Select folders to scan and press \"Scan\"."; ObjectID = "71"; */
|
||||
"71.title" = "Select folders to scan and press \"Scan\".";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Load Results"; ObjectID = "73"; */
|
||||
"73.title" = "Load Results";
|
||||
File diff suppressed because it is too large
Load Diff
11
cocoa/base/en.lproj/ExtraFairwareReminder.strings
Normal file
11
cocoa/base/en.lproj/ExtraFairwareReminder.strings
Normal file
@@ -0,0 +1,11 @@
|
||||
/* Class = "NSWindow"; title = "Sorry, I must insist"; ObjectID = "1"; */
|
||||
"1.title" = "Sorry, I must insist";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "This reminder showed up because:
1. You are processing more than 100 duplicates
2. You have not yet contributed to dupeGuru
3. There are unpaid hours in the project"; ObjectID = "4"; */
|
||||
"4.title" = "This reminder showed up because:\n\n1. You are processing more than 100 duplicates\n2. You have not yet contributed to dupeGuru\n3. There are unpaid hours in the project";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "It seems that you found a lot of duplicates. Nice! I must insist, however, that contributions are expected when there are unpaid hours on the project.
You might think \"but I'm only going to use this once, I don't have to contribute\". The problem is that most people use dupeGuru only once in a while. If everyone thinks like that, dupeGuru development cannot be funded.
If you can't afford to contribute, you can ignore this reminder or send me an e-mail at hsoft@hardcoded.net so I can give you a key to remove this popup."; ObjectID = "6"; */
|
||||
"6.title" = "It seems that you found a lot of duplicates. Nice! I must insist, however, that contributions are expected when there are unpaid hours on the project.\n\nYou might think \"but I'm only going to use this once, I don't have to contribute\". The problem is that most people use dupeGuru only once in a while. If everyone thinks like that, dupeGuru development cannot be funded. It's because of this tendency inherent to dupeGuru's nature that I have to insist here.\n\nIf you can't afford to contribute, you can ignore this reminder or send me an e-mail at hsoft@hardcoded.net so I can give you a key to remove this popup.";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Contribute"; ObjectID = "10"; */
|
||||
"10.title" = "Contribute";
|
||||
945
cocoa/base/en.lproj/ExtraFairwareReminder.xib
Normal file
945
cocoa/base/en.lproj/ExtraFairwareReminder.xib
Normal file
@@ -0,0 +1,945 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">10J567</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">823</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.35</string>
|
||||
<string key="IBDocument.HIToolboxVersion">462.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">823</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<integer value="2"/>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSCustomObject" id="1001">
|
||||
<string key="NSClassName">ExtraFairwareReminder</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1003">
|
||||
<string key="NSClassName">FirstResponder</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1004">
|
||||
<string key="NSClassName">NSApplication</string>
|
||||
</object>
|
||||
<object class="NSWindowTemplate" id="1005">
|
||||
<int key="NSWindowStyleMask">1</int>
|
||||
<int key="NSWindowBacking">2</int>
|
||||
<string key="NSWindowRect">{{418, 295}, {480, 390}}</string>
|
||||
<int key="NSWTFlags">1081606144</int>
|
||||
<string key="NSWindowTitle">Sorry, I must insist</string>
|
||||
<string key="NSWindowClass">NSWindow</string>
|
||||
<nil key="NSViewClass"/>
|
||||
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
<object class="NSView" key="NSWindowView" id="1006">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSTextField" id="359672030">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{17, 48}, {446, 85}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="855705720">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">272629760</int>
|
||||
<string key="NSContents">This reminder showed up because:
1. You are processing more than 100 duplicates
2. You have not yet contributed to dupeGuru
3. There are unpaid hours in the project</string>
|
||||
<object class="NSFont" key="NSSupport">
|
||||
<string key="NSName">LucidaGrande-Bold</string>
|
||||
<double key="NSSize">12</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
<reference key="NSControlView" ref="359672030"/>
|
||||
<object class="NSColor" key="NSBackgroundColor" id="732565682">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">controlColor</string>
|
||||
<object class="NSColor" key="NSColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSColor" key="NSTextColor" id="873511993">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">controlTextColor</string>
|
||||
<object class="NSColor" key="NSColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MAA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSTextField" id="450147645">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{17, 141}, {446, 229}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="307619415">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">205520896</int>
|
||||
<string key="NSContents">It seems that you found a lot of duplicates. Nice! I must insist, however, that contributions are expected when there are unpaid hours on the project.
You might think "but I'm only going to use this once, I don't have to contribute". The problem is that most people use dupeGuru only once in a while. If everyone thinks like that, dupeGuru development cannot be funded. It's because of this tendency inherent to dupeGuru's nature that I have to insist here.
If you can't afford to contribute, you can ignore this reminder or send me an e-mail at hsoft@hardcoded.net so I can give you a key to remove this popup.</string>
|
||||
<object class="NSFont" key="NSSupport">
|
||||
<string key="NSName">LucidaGrande</string>
|
||||
<double key="NSSize">12</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
<reference key="NSControlView" ref="450147645"/>
|
||||
<reference key="NSBackgroundColor" ref="732565682"/>
|
||||
<reference key="NSTextColor" ref="873511993"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="858267836">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{338, 12}, {128, 32}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="444055328">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">134217728</int>
|
||||
<string key="NSContents">Continue</string>
|
||||
<object class="NSFont" key="NSSupport" id="534597488">
|
||||
<string key="NSName">LucidaGrande</string>
|
||||
<double key="NSSize">13</double>
|
||||
<int key="NSfFlags">1044</int>
|
||||
</object>
|
||||
<reference key="NSControlView" ref="858267836"/>
|
||||
<int key="NSButtonFlags">-2038284033</int>
|
||||
<int key="NSButtonFlags2">129</int>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="789504727">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{210, 12}, {128, 32}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="639557916">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">134217728</int>
|
||||
<string key="NSContents">Contribute</string>
|
||||
<reference key="NSSupport" ref="534597488"/>
|
||||
<reference key="NSControlView" ref="789504727"/>
|
||||
<int key="NSButtonFlags">-2038284033</int>
|
||||
<int key="NSButtonFlags2">129</int>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{480, 390}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
</object>
|
||||
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
|
||||
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">contribute:</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="789504727"/>
|
||||
</object>
|
||||
<int key="connectionID">11</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">continue:</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="858267836"/>
|
||||
</object>
|
||||
<int key="connectionID">12</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">window</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="1005"/>
|
||||
</object>
|
||||
<int key="connectionID">13</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">continueButton</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="858267836"/>
|
||||
</object>
|
||||
<int key="connectionID">14</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<reference key="object" ref="0"/>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="1001"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="1003"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">First Responder</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-3</int>
|
||||
<reference key="object" ref="1004"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">Application</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1</int>
|
||||
<reference key="object" ref="1005"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="1006"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">2</int>
|
||||
<reference key="object" ref="1006"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="450147645"/>
|
||||
<reference ref="359672030"/>
|
||||
<reference ref="858267836"/>
|
||||
<reference ref="789504727"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1005"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">3</int>
|
||||
<reference key="object" ref="359672030"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="855705720"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="855705720"/>
|
||||
<reference key="parent" ref="359672030"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">5</int>
|
||||
<reference key="object" ref="450147645"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="307619415"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">6</int>
|
||||
<reference key="object" ref="307619415"/>
|
||||
<reference key="parent" ref="450147645"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">7</int>
|
||||
<reference key="object" ref="858267836"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="444055328"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">8</int>
|
||||
<reference key="object" ref="444055328"/>
|
||||
<reference key="parent" ref="858267836"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">9</int>
|
||||
<reference key="object" ref="789504727"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="639557916"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">10</int>
|
||||
<reference key="object" ref="639557916"/>
|
||||
<reference key="parent" ref="789504727"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>-3.IBPluginDependency</string>
|
||||
<string>1.IBEditorWindowLastContentRect</string>
|
||||
<string>1.IBPluginDependency</string>
|
||||
<string>1.IBWindowTemplateEditedContentRect</string>
|
||||
<string>1.NSWindowTemplate.visibleAtLaunch</string>
|
||||
<string>1.WindowOrigin</string>
|
||||
<string>1.editorWindowContentRectSynchronizationRect</string>
|
||||
<string>10.IBPluginDependency</string>
|
||||
<string>2.IBPluginDependency</string>
|
||||
<string>3.IBPluginDependency</string>
|
||||
<string>3.IBViewBoundsToFrameTransform</string>
|
||||
<string>4.IBPluginDependency</string>
|
||||
<string>5.IBPluginDependency</string>
|
||||
<string>5.IBViewBoundsToFrameTransform</string>
|
||||
<string>6.IBPluginDependency</string>
|
||||
<string>7.IBPluginDependency</string>
|
||||
<string>7.IBViewBoundsToFrameTransform</string>
|
||||
<string>8.IBPluginDependency</string>
|
||||
<string>9.IBPluginDependency</string>
|
||||
<string>9.IBViewBoundsToFrameTransform</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{418, 295}, {480, 390}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{418, 295}, {480, 390}}</string>
|
||||
<boolean value="NO"/>
|
||||
<string>{196, 240}</string>
|
||||
<string>{{357, 418}, {480, 270}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSAffineTransform">
|
||||
<bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwxwAAA</bytes>
|
||||
</object>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSAffineTransform">
|
||||
<bytes key="NSTransformStruct">P4AAAL+AAABAoAAAw3gAAA</bytes>
|
||||
</object>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSAffineTransform">
|
||||
<bytes key="NSTransformStruct">P4AAAL+AAABDqQAAwigAAA</bytes>
|
||||
</object>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSAffineTransform">
|
||||
<bytes key="NSTransformStruct">P4AAAL+AAABDUgAAwigAAA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">14</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">ExtraFairwareReminder</string>
|
||||
<string key="superclassName">HSWindowController</string>
|
||||
<object class="NSMutableDictionary" key="actions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>continue:</string>
|
||||
<string>contribute:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>id</string>
|
||||
<string>id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>continue:</string>
|
||||
<string>contribute:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">continue:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">contribute:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">continueButton</string>
|
||||
<string key="NS.object.0">NSButton</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">continueButton</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">continueButton</string>
|
||||
<string key="candidateClassName">NSButton</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../base/ExtraFairwareReminder.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">HSWindowController</string>
|
||||
<string key="superclassName">NSWindowController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../controllers/HSWindowController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/HSTableView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSActionCell</string>
|
||||
<string key="superclassName">NSCell</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSActionCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<string key="superclassName">NSResponder</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="131375392">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSApplication.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="645066809">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="295119366">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSButton</string>
|
||||
<string key="superclassName">NSControl</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSButton.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSButtonCell</string>
|
||||
<string key="superclassName">NSActionCell</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSButtonCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSCell</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSControl</string>
|
||||
<string key="superclassName">NSView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="947202395">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSControl.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSFormatter</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSMenu</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="754383277">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSMenu.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="131375392"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="645066809"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="295119366"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="947202395"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSDragging.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="754383277"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSTableView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="756921129">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSError.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Sparkle.framework/Headers/SUAppcast.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Sparkle.framework/Headers/SUUpdater.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSResponder</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSResponder</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSResponder.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSTextField</string>
|
||||
<string key="superclassName">NSControl</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSTextField.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSTextFieldCell</string>
|
||||
<string key="superclassName">NSActionCell</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSTextFieldCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSClipView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSView</string>
|
||||
<string key="superclassName">NSResponder</string>
|
||||
<reference key="sourceIdentifier" ref="756921129"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSWindow</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSWindow</string>
|
||||
<string key="superclassName">NSResponder</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindow.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSWindow</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSWindowController</string>
|
||||
<string key="superclassName">NSResponder</string>
|
||||
<object class="NSMutableDictionary" key="actions">
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">showWindow:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<string key="IBDocument.LastKnownRelativeProjectPath">../../pe/dupeguru.xcodeproj</string>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
</data>
|
||||
</archive>
|
||||
63
cocoa/base/en.lproj/Localizable.strings
Normal file
63
cocoa/base/en.lproj/Localizable.strings
Normal file
@@ -0,0 +1,63 @@
|
||||
"Add New Folder..." = "Add New Folder...";
|
||||
"Load from file..." = "Load from file...";
|
||||
"Reset to Default" = "Reset to Default";
|
||||
|
||||
"Add iTunes Directory" = "Add iTunes Directory";
|
||||
"Remove Dead Tracks in iTunes" = "Remove Dead Tracks in iTunes";
|
||||
|
||||
"Add iPhoto Library" = "Add iPhoto Library";
|
||||
"Clear Picture Cache" = "Clear Picture Cache";
|
||||
|
||||
/* Columns */
|
||||
"Folder" = "Folder";
|
||||
"Size (KB)" = "Size (KB)";
|
||||
"Size (MB)" = "Size (MB)";
|
||||
"Kind" = "Kind";
|
||||
"Modification" = "Modification";
|
||||
"Match %" = "Match %";
|
||||
"Words Used" = "Words Used";
|
||||
"Dupe Count" = "Dupe Count";
|
||||
|
||||
"Time" = "Time";
|
||||
"Bitrate" = "Bitrate";
|
||||
"Sample Rate" = "Sample Rate";
|
||||
"Title" = "Title";
|
||||
"Artist" = "Artist";
|
||||
"Album" = "Album";
|
||||
"Genre" = "Genre";
|
||||
"Year" = "Year";
|
||||
"Track Number" = "Track Number";
|
||||
"Comment" = "Comment";
|
||||
|
||||
"Dimensions" = "Dimensions";
|
||||
|
||||
/* Messages */
|
||||
"SelectResultToLoadMsg" = "Select a results file to load";
|
||||
"SelectCopyDestinationMsg" = "Select a directory to copy marked files to";
|
||||
"SelectMoveDestinationMsg" = "Select a directory to move marked files to";
|
||||
"SelectResultToSaveMsg" = "Select a file to save your results to";
|
||||
"SelectFolderToAddMsg" = "Select a folder to add to the scanning list";
|
||||
"ReallyWantToQuitMsg" = "You have unsaved results, do you really want to quit?";
|
||||
"ReallyWantToContinueMsg" = "You have unsaved results, do you really want to continue?";
|
||||
"FolderAlreadyInListMsg" = "'%@' already is in the list.";
|
||||
"FolderDoesNotExistMsg" = "'%@' does not exist.";
|
||||
"FileRemovalConfirmMsg" = "You are about to remove %d files from results. Continue?";
|
||||
"FilenameAlreadyExistsMsg" = "The name '%@' already exists.";
|
||||
"NoScannableFileMsg" = "The selected directories contain no scannable file.";
|
||||
"UnknownErrorMsg" = "Unknown Error.";
|
||||
"SendToTrashConfirmMsg" = "You are about to send %d files to Trash. Continue?";
|
||||
"HardlinkConfirmMsg" = "You are about to send %d files to Trash (and hardlink them afterwards). Continue?";
|
||||
"ClearIgnoreListConfirmMsg" = "Do you really want to remove all %d items from the ignore list?";
|
||||
"IgnoreConfirmMsg" = "All selected %d matches are going to be ignored in all subsequent scans. Continue?";
|
||||
"NoCustomCommandMsg" = "You have no custom command set up. Set it up in your preferences.";
|
||||
"CopySuccessMsg" = "All marked files were copied sucessfully.";
|
||||
"MoveSuccessMsg" = "All marked files were moved sucessfully.";
|
||||
"SendToTrashSuccessMsg" = "All marked files were sucessfully sent to Trash.";
|
||||
"NoDuplicateFoundMsg" = "No duplicates found.";
|
||||
"TaskHangingMsg" = "A previous action is still hanging in there. You can't start a new one yet. Wait a few seconds, then try again.";
|
||||
|
||||
"RemoveDeadTracksConfirmMsg" = "Your iTunes Library contains %d dead tracks ready to be removed. Continue?";
|
||||
"NoDeadTrackMsg" = "You have no dead tracks in your iTunes Library";
|
||||
|
||||
"IPhotoAppNotFoundMsg" = "The iPhoto application couldn't be found.";
|
||||
"ClearPictureCacheConfirmMsg" = "Do you really want to remove all your cached picture analysis?";
|
||||
174
cocoa/base/en.lproj/MainMenu.strings
Normal file
174
cocoa/base/en.lproj/MainMenu.strings
Normal file
@@ -0,0 +1,174 @@
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Bring All to Front"; ObjectID = "5"; */
|
||||
"5.title" = "Bring All to Front";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Window"; ObjectID = "19"; */
|
||||
"19.title" = "Window";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Minimize"; ObjectID = "23"; */
|
||||
"23.title" = "Minimize";
|
||||
|
||||
/* Class = "NSMenu"; title = "Window"; ObjectID = "24"; */
|
||||
"24.title" = "Window";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "About dupeGuru"; ObjectID = "58"; */
|
||||
"58.title" = "About dupeGuru";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Help"; ObjectID = "103"; */
|
||||
"103.title" = "Help";
|
||||
|
||||
/* Class = "NSMenu"; title = "Help"; ObjectID = "106"; */
|
||||
"106.title" = "Help";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "dupeGuru Help"; ObjectID = "111"; */
|
||||
"111.title" = "dupeGuru Help";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hide dupeGuru"; ObjectID = "134"; */
|
||||
"134.title" = "Hide dupeGuru";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Quit dupeGuru"; ObjectID = "136"; */
|
||||
"136.title" = "Quit dupeGuru";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hide Others"; ObjectID = "145"; */
|
||||
"145.title" = "Hide Others";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show All"; ObjectID = "150"; */
|
||||
"150.title" = "Show All";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Zoom"; ObjectID = "197"; */
|
||||
"197.title" = "Zoom";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Details Panel"; ObjectID = "398"; */
|
||||
"398.title" = "Details Panel";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Preferences..."; ObjectID = "541"; */
|
||||
"541.title" = "Preferences...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Folder Selection Window"; ObjectID = "579"; */
|
||||
"579.title" = "Folder Selection Window";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Actions"; ObjectID = "597"; */
|
||||
"597.title" = "Actions";
|
||||
|
||||
/* Class = "NSMenu"; title = "Actions"; ObjectID = "598"; */
|
||||
"598.title" = "Actions";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Send Marked to Trash"; ObjectID = "599"; */
|
||||
"599.title" = "Send Marked to Trash";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Move Marked to..."; ObjectID = "600"; */
|
||||
"600.title" = "Move Marked to...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Copy Marked to..."; ObjectID = "601"; */
|
||||
"601.title" = "Copy Marked to...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Make Selected Reference"; ObjectID = "602"; */
|
||||
"602.title" = "Make Selected Reference";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Marked from Results"; ObjectID = "603"; */
|
||||
"603.title" = "Remove Marked from Results";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Selected from Results"; ObjectID = "605"; */
|
||||
"605.title" = "Remove Selected from Results";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Columns"; ObjectID = "618"; */
|
||||
"618.title" = "Columns";
|
||||
|
||||
/* Class = "NSMenu"; title = "Columns"; ObjectID = "619"; */
|
||||
"619.title" = "Columns";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Open Selected with Default Application"; ObjectID = "708"; */
|
||||
"708.title" = "Open Selected with Default Application";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Reveal Selected in Finder"; ObjectID = "710"; */
|
||||
"710.title" = "Reveal Selected in Finder";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Add Selected to Ignore List"; ObjectID = "922"; */
|
||||
"922.title" = "Add Selected to Ignore List";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Close Window"; ObjectID = "924"; */
|
||||
"924.title" = "Close Window";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Start Duplicate Scan"; ObjectID = "926"; */
|
||||
"926.title" = "Start Duplicate Scan";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Clear Ignore List"; ObjectID = "927"; */
|
||||
"927.title" = "Clear Ignore List";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Rename Selected"; ObjectID = "933"; */
|
||||
"933.title" = "Rename Selected";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Export Results to XHTML"; ObjectID = "947"; */
|
||||
"947.title" = "Export Results to XHTML";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Check for update..."; ObjectID = "950"; */
|
||||
"950.title" = "Check for update...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Mode"; ObjectID = "959"; */
|
||||
"959.title" = "Mode";
|
||||
|
||||
/* Class = "NSMenu"; title = "Mode"; ObjectID = "960"; */
|
||||
"960.title" = "Mode";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show Dupes Only"; ObjectID = "961"; */
|
||||
"961.title" = "Show Dupes Only";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show Delta Values"; ObjectID = "962"; */
|
||||
"962.title" = "Show Delta Values";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Edit"; ObjectID = "965"; */
|
||||
"965.title" = "Edit";
|
||||
|
||||
/* Class = "NSMenu"; title = "Edit"; ObjectID = "966"; */
|
||||
"966.title" = "Edit";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Cut"; ObjectID = "985"; */
|
||||
"985.title" = "Cut";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Copy"; ObjectID = "986"; */
|
||||
"986.title" = "Copy";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Paste"; ObjectID = "991"; */
|
||||
"991.title" = "Paste";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Mark All"; ObjectID = "1011"; */
|
||||
"1011.title" = "Mark All";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Mark None"; ObjectID = "1012"; */
|
||||
"1012.title" = "Mark None";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Invert Marking"; ObjectID = "1013"; */
|
||||
"1013.title" = "Invert Marking";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Mark Selected"; ObjectID = "1014"; */
|
||||
"1014.title" = "Mark Selected";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "dupeGuru Website"; ObjectID = "1023"; */
|
||||
"1023.title" = "dupeGuru Website";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Invoke Custom Command"; ObjectID = "1177"; */
|
||||
"1177.title" = "Invoke Custom Command";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "File"; ObjectID = "1203"; */
|
||||
"1203.title" = "File";
|
||||
|
||||
/* Class = "NSMenu"; title = "File"; ObjectID = "1204"; */
|
||||
"1204.title" = "File";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Load Results..."; ObjectID = "1205"; */
|
||||
"1205.title" = "Load Results...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Save Results..."; ObjectID = "1206"; */
|
||||
"1206.title" = "Save Results...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Delete Marked and Replace with Hardlinks"; ObjectID = "1227"; */
|
||||
"1227.title" = "Delete Marked and Replace with Hardlinks";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Load Recent Results"; ObjectID = "1239"; */
|
||||
"1239.title" = "Load Recent Results";
|
||||
|
||||
/* Class = "NSMenu"; title = "Load Recent Results"; ObjectID = "1240"; */
|
||||
"1240.title" = "Load Recent Results";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Results Window"; ObjectID = "1272"; */
|
||||
"1272.title" = "Results Window";
|
||||
2987
cocoa/base/en.lproj/MainMenu.xib
Normal file
2987
cocoa/base/en.lproj/MainMenu.xib
Normal file
File diff suppressed because it is too large
Load Diff
18
cocoa/base/en.lproj/ProblemDialog.strings
Normal file
18
cocoa/base/en.lproj/ProblemDialog.strings
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
/* Class = "NSWindow"; title = "Problems!"; ObjectID = "1"; */
|
||||
"1.title" = "Problems!";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "There were problems processing some (or all) of the files. The cause of these problems are described in the table below. Those files were not removed from your results."; ObjectID = "4"; */
|
||||
"4.title" = "There were problems processing some (or all) of the files. The cause of these problems are described in the table below. Those files were not removed from your results.";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "File Path"; ObjectID = "10"; */
|
||||
"10.headerCell.title" = "File Path";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Error Message"; ObjectID = "11"; */
|
||||
"11.headerCell.title" = "Error Message";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Close"; ObjectID = "19"; */
|
||||
"19.title" = "Close";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Reveal Selected"; ObjectID = "21"; */
|
||||
"21.title" = "Reveal Selected";
|
||||
1142
cocoa/base/en.lproj/ProblemDialog.xib
Normal file
1142
cocoa/base/en.lproj/ProblemDialog.xib
Normal file
File diff suppressed because it is too large
Load Diff
99
cocoa/base/en.lproj/ResultWindow.strings
Normal file
99
cocoa/base/en.lproj/ResultWindow.strings
Normal file
@@ -0,0 +1,99 @@
|
||||
|
||||
/* Class = "NSWindow"; title = "dupeGuru Results"; ObjectID = "1"; */
|
||||
"1.title" = "dupeGuru Results";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Marked: 0 files, 0 B. Total: 0 files, 0 B."; ObjectID = "6"; */
|
||||
"6.title" = "Marked: 0 files, 0 B. Total: 0 files, 0 B.";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "11"; */
|
||||
"11.headerCell.title" = "Name";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Options"; ObjectID = "15"; */
|
||||
"15.label" = "Options";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "Options"; ObjectID = "15"; */
|
||||
"15.paletteLabel" = "Options";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Filter"; ObjectID = "16"; */
|
||||
"16.label" = "Filter";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "Filter"; ObjectID = "16"; */
|
||||
"16.paletteLabel" = "Filter";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Action"; ObjectID = "17"; */
|
||||
"17.label" = "Action";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "Action"; ObjectID = "17"; */
|
||||
"17.paletteLabel" = "Action";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Directories"; ObjectID = "19"; */
|
||||
"19.label" = "Directories";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "Directories"; ObjectID = "19"; */
|
||||
"19.paletteLabel" = "Directories";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Delete Marked and Replace with Hardlinks"; ObjectID = "27"; */
|
||||
"27.title" = "Delete Marked and Replace with Hardlinks";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Send Marked to Trash"; ObjectID = "29"; */
|
||||
"29.title" = "Send Marked to Trash";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Move Marked to..."; ObjectID = "30"; */
|
||||
"30.title" = "Move Marked to...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Copy Marked to..."; ObjectID = "31"; */
|
||||
"31.title" = "Copy Marked to...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Marked from Results"; ObjectID = "32"; */
|
||||
"32.title" = "Remove Marked from Results";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Selected from Results"; ObjectID = "34"; */
|
||||
"34.title" = "Remove Selected from Results";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Add Selected to Ignore List"; ObjectID = "35"; */
|
||||
"35.title" = "Add Selected to Ignore List";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Make Selected Reference"; ObjectID = "36"; */
|
||||
"36.title" = "Make Selected Reference";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Open Selected with Default Application"; ObjectID = "38"; */
|
||||
"38.title" = "Open Selected with Default Application";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Reveal Selected in Finder"; ObjectID = "39"; */
|
||||
"39.title" = "Reveal Selected in Finder";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Rename Selected"; ObjectID = "40"; */
|
||||
"40.title" = "Rename Selected";
|
||||
|
||||
/* Class = "NSSearchFieldCell"; placeholderString = "Filter"; ObjectID = "42"; */
|
||||
"42.placeholderString" = "Filter";
|
||||
|
||||
/* Class = "NSSegmentedCell"; 44.labels[0] = "Details"; ObjectID = "44"; */
|
||||
"44.labels[0]" = "Details";
|
||||
|
||||
/* Class = "NSSegmentedCell"; 44.labels[1] = "Dupes Only"; ObjectID = "44"; */
|
||||
"44.labels[1]" = "Dupes Only";
|
||||
|
||||
/* Class = "NSSegmentedCell"; 44.labels[2] = "Delta"; ObjectID = "44"; */
|
||||
"44.labels[2]" = "Delta";
|
||||
|
||||
/* Class = "NSMenu"; title = "Menu"; ObjectID = "67"; */
|
||||
"67.title" = "Menu";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Add Selected to Ignore List"; ObjectID = "68"; */
|
||||
"68.title" = "Add Selected to Ignore List";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Rename Selected"; ObjectID = "70"; */
|
||||
"70.title" = "Rename Selected";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Selected from Results"; ObjectID = "71"; */
|
||||
"71.title" = "Remove Selected from Results";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Make Selected Reference"; ObjectID = "72"; */
|
||||
"72.title" = "Make Selected Reference";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Reveal Selected in Finder"; ObjectID = "73"; */
|
||||
"73.title" = "Reveal Selected in Finder";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Open Selected with Default Application"; ObjectID = "74"; */
|
||||
"74.title" = "Open Selected with Default Application";
|
||||
2742
cocoa/base/en.lproj/ResultWindow.xib
Normal file
2742
cocoa/base/en.lproj/ResultWindow.xib
Normal file
File diff suppressed because it is too large
Load Diff
31
cocoa/base/en.lproj/core.strings
Normal file
31
cocoa/base/en.lproj/core.strings
Normal file
@@ -0,0 +1,31 @@
|
||||
"Collecting files to scan" = "Collecting files to scan";
|
||||
"%s (%d discarded)" = "%s (%d discarded)";
|
||||
"Scanning for duplicates" = "Scanning for duplicates";
|
||||
"Loading" = "Loading";
|
||||
"Moving" = "Moving";
|
||||
"Copying" = "Copying";
|
||||
"Sending to Trash" = "Sending to Trash";
|
||||
"0 matches found" = "0 matches found";
|
||||
"%d matches found" = "%d matches found";
|
||||
"Read size of %d/%d files" = "Read size of %d/%d files";
|
||||
"Grouped %d/%d matches" = "Grouped %d/%d matches";
|
||||
"%d / %d (%s / %s) duplicates marked." = "%d / %d (%s / %s) duplicates marked.";
|
||||
" filter: %s" = " filter: %s";
|
||||
"Read metadata of %d/%d files" = "Read metadata of %d/%d files";
|
||||
"Removing false matches" = "Removing false matches";
|
||||
"Processed %d/%d matches against the ignore list" = "Processed %d/%d matches against the ignore list";
|
||||
"Doing group prioritization" = "Doing group prioritization";
|
||||
|
||||
"Continue" = "Continue";
|
||||
"Continue ({})" = "Continue ({})";
|
||||
|
||||
"Analyzed %d/%d pictures" = "Analyzed %d/%d pictures";
|
||||
"Preparing for matching" = "Preparing for matching";
|
||||
"Performed %d/%d chunk matches" = "Performed %d/%d chunk matches";
|
||||
"Verified %d/%d matches" = "Verified %d/%d matches";
|
||||
|
||||
"Removing dead tracks from your iTunes Library" = "Removing dead tracks from your iTunes Library";
|
||||
"Scanning the iTunes Library" = "Scanning the iTunes Library";
|
||||
|
||||
"Probing iPhoto. Don't touch it during the operation!" = "Probing iPhoto. Don't touch it during the operation!";
|
||||
"Sending dupes to the Trash" = "Sending dupes to the Trash";
|
||||
12
cocoa/base/fr.lproj/DetailsPanel.strings
Normal file
12
cocoa/base/fr.lproj/DetailsPanel.strings
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
/* Class = "NSPanel"; title = "Details of Selected File"; ObjectID = "5"; */
|
||||
"5.title" = "Détails du fichier sélectionné";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Selected"; ObjectID = "9"; */
|
||||
"9.headerCell.title" = "Sélectionné";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Reference"; ObjectID = "10"; */
|
||||
"10.headerCell.title" = "Référence";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Attribute"; ObjectID = "11"; */
|
||||
"11.headerCell.title" = "Attribut";
|
||||
1095
cocoa/base/fr.lproj/DetailsPanel.xib
Normal file
1095
cocoa/base/fr.lproj/DetailsPanel.xib
Normal file
File diff suppressed because it is too large
Load Diff
23
cocoa/base/fr.lproj/DirectoryPanel.strings
Normal file
23
cocoa/base/fr.lproj/DirectoryPanel.strings
Normal file
@@ -0,0 +1,23 @@
|
||||
/* Class = "NSTableColumn"; headerCell.title = "State"; ObjectID = "13"; */
|
||||
"13.headerCell.title" = "Type";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "15"; */
|
||||
"15.headerCell.title" = "Nom";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Scan"; ObjectID = "48"; */
|
||||
"48.title" = "Scan";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "55"; */
|
||||
"55.title" = "Normal";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Reference"; ObjectID = "56"; */
|
||||
"56.title" = "Référence";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Excluded"; ObjectID = "57"; */
|
||||
"57.title" = "Exclu";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Select folders to scan and press \"Scan\"."; ObjectID = "71"; */
|
||||
"71.title" = "Sélectionnez les dossiers à scanner et cliquez sur Scan.";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Load Results"; ObjectID = "73"; */
|
||||
"73.title" = "Charger";
|
||||
1872
cocoa/base/fr.lproj/DirectoryPanel.xib
Normal file
1872
cocoa/base/fr.lproj/DirectoryPanel.xib
Normal file
File diff suppressed because it is too large
Load Diff
11
cocoa/base/fr.lproj/ExtraFairwareReminder.strings
Normal file
11
cocoa/base/fr.lproj/ExtraFairwareReminder.strings
Normal file
@@ -0,0 +1,11 @@
|
||||
/* Class = "NSWindow"; title = "Sorry, I must insist"; ObjectID = "1"; */
|
||||
"1.title" = "Désolé, je dois insister";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "This reminder showed up because:
1. You are processing more than 100 duplicates
2. You have not yet contributed to dupeGuru
3. There are unpaid hours in the project"; ObjectID = "4"; */
|
||||
"4.title" = "Ce rappel apparaît parce que:\n\n1. Plus de 100 doublons sont traités\n2. Vous n'avez pas encore contribué à dupeGuru\n3. Il y a des heures non-payées au projet";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "It seems that you found a lot of duplicates. Nice! I must insist, however, that contributions are expected when there are unpaid hours on the project.
You might think \"but I'm only going to use this once, I don't have to contribute\". The problem is that most people use dupeGuru only once in a while. If everyone thinks like that, dupeGuru development cannot be funded.
If you can't afford to contribute, you can ignore this reminder or send me an e-mail at hsoft@hardcoded.net so I can give you a key to remove this popup."; ObjectID = "6"; */
|
||||
"6.title" = "Il semble que vous ayez trouvé beaucoup de doublons. Super! Je dois par contre insister que des contributions sont attendues lorsqu'il y'a des heures non-payées au projet.\n\nVous pensez peut-être \"je n'utiliserai ce programme qu'une fois, pas besoin de contribuer\". Le problème c'est que la plupart des utilisateurs de dupeGuru ne l'utilisent qu'une fois. Si tous suivent ce raisonnement, le développement de dupeGuru ne peut pas continuer. C'est à cause de cette tendance inhérente à la nature de dupeGuru que je me vois contraint d'insister ici.\n\nSi vous n'avez pas les moyens de contribuer, ignorez ce message ou envoyez moi un message à hsoft@hardcoded.net pour que je vous envoie une clé d'enregistrement.";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Contribute"; ObjectID = "10"; */
|
||||
"10.title" = "Contribuer";
|
||||
962
cocoa/base/fr.lproj/ExtraFairwareReminder.xib
Normal file
962
cocoa/base/fr.lproj/ExtraFairwareReminder.xib
Normal file
@@ -0,0 +1,962 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">10J567</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">823</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.35</string>
|
||||
<string key="IBDocument.HIToolboxVersion">462.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">823</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<integer value="1"/>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSCustomObject" id="1001">
|
||||
<string key="NSClassName">ExtraFairwareReminder</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1003">
|
||||
<string key="NSClassName">FirstResponder</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1004">
|
||||
<string key="NSClassName">NSApplication</string>
|
||||
</object>
|
||||
<object class="NSWindowTemplate" id="1005">
|
||||
<int key="NSWindowStyleMask">1</int>
|
||||
<int key="NSWindowBacking">2</int>
|
||||
<string key="NSWindowRect">{{418, 295}, {480, 390}}</string>
|
||||
<int key="NSWTFlags">1081606144</int>
|
||||
<string key="NSWindowTitle">Désolé, je dois insister</string>
|
||||
<string key="NSWindowClass">NSWindow</string>
|
||||
<nil key="NSViewClass"/>
|
||||
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
<object class="NSView" key="NSWindowView" id="1006">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSTextField" id="359672030">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{17, 48}, {446, 85}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="855705720">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">272629760</int>
|
||||
<string type="base64-UTF8" key="NSContents">Q2UgcmFwcGVsIGFwcGFyYcOudCBwYXJjZSBxdWU6CgoxLiBQbHVzIGRlIDEwMCBkb3VibG9ucyBzb250
|
||||
IHRyYWl0w6lzCjIuIFZvdXMgbidhdmV6IHBhcyBlbmNvcmUgY29udHJpYnXDqSDDoCBkdXBlR3VydQoz
|
||||
LiBJbCB5IGEgZGVzIGhldXJlcyBub24tcGF5w6llcyBhdSBwcm9qZXQ</string>
|
||||
<object class="NSFont" key="NSSupport">
|
||||
<string key="NSName">LucidaGrande-Bold</string>
|
||||
<double key="NSSize">12</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
<reference key="NSControlView" ref="359672030"/>
|
||||
<object class="NSColor" key="NSBackgroundColor" id="732565682">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">controlColor</string>
|
||||
<object class="NSColor" key="NSColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSColor" key="NSTextColor" id="873511993">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">controlTextColor</string>
|
||||
<object class="NSColor" key="NSColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MAA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSTextField" id="450147645">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{17, 141}, {446, 229}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="307619415">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">205520896</int>
|
||||
<string type="base64-UTF8" key="NSContents">SWwgc2VtYmxlIHF1ZSB2b3VzIGF5ZXogdHJvdXbDqSBiZWF1Y291cCBkZSBkb3VibG9ucy4gU3VwZXIh
|
||||
IEplIGRvaXMgcGFyIGNvbnRyZSBpbnNpc3RlciBxdWUgZGVzIGNvbnRyaWJ1dGlvbnMgc29udCBhdHRl
|
||||
bmR1ZXMgbG9yc3F1J2lsIHknYSBkZXMgaGV1cmVzIG5vbi1wYXnDqWVzIGF1IHByb2pldC4KClZvdXMg
|
||||
cGVuc2V6IHBldXQtw6p0cmUgImplIG4ndXRpbGlzZXJhaSBjZSBwcm9ncmFtbWUgcXUndW5lIGZvaXMs
|
||||
IHBhcyBiZXNvaW4gZGUgY29udHJpYnVlciIuIExlIHByb2Jsw6htZSBjJ2VzdCBxdWUgbGEgcGx1cGFy
|
||||
dCBkZXMgdXRpbGlzYXRldXJzIGRlIGR1cGVHdXJ1IG5lIGwndXRpbGlzZW50IHF1J3VuZSBmb2lzLiBT
|
||||
aSB0b3VzIHN1aXZlbnQgY2UgcmFpc29ubmVtZW50LCBsZSBkw6l2ZWxvcHBlbWVudCBkZSBkdXBlR3Vy
|
||||
dSBuZSBwZXV0IHBhcyBjb250aW51ZXIuIEMnZXN0IMOgIGNhdXNlIGRlIGNldHRlIHRlbmRhbmNlIGlu
|
||||
aMOpcmVudGUgw6AgbGEgbmF0dXJlIGRlIGR1cGVHdXJ1IHF1ZSBqZSBtZSB2b2lzIGNvbnRyYWludCBk
|
||||
J2luc2lzdGVyIGljaS4KClNpIHZvdXMgbidhdmV6IHBhcyBsZXMgbW95ZW5zIGRlIGNvbnRyaWJ1ZXIs
|
||||
IGlnbm9yZXogY2UgbWVzc2FnZSBvdSBlbnZveWV6IG1vaSB1biBtZXNzYWdlIMOgIGhzb2Z0QGhhcmRj
|
||||
b2RlZC5uZXQgcG91ciBxdWUgamUgdm91cyBlbnZvaWUgdW5lIGNsw6kgZCdlbnJlZ2lzdHJlbWVudC4</string>
|
||||
<object class="NSFont" key="NSSupport">
|
||||
<string key="NSName">LucidaGrande</string>
|
||||
<double key="NSSize">12</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
<reference key="NSControlView" ref="450147645"/>
|
||||
<reference key="NSBackgroundColor" ref="732565682"/>
|
||||
<reference key="NSTextColor" ref="873511993"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="858267836">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{338, 12}, {128, 32}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="444055328">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">134217728</int>
|
||||
<string key="NSContents">Continue</string>
|
||||
<object class="NSFont" key="NSSupport" id="534597488">
|
||||
<string key="NSName">LucidaGrande</string>
|
||||
<double key="NSSize">13</double>
|
||||
<int key="NSfFlags">1044</int>
|
||||
</object>
|
||||
<reference key="NSControlView" ref="858267836"/>
|
||||
<int key="NSButtonFlags">-2038284033</int>
|
||||
<int key="NSButtonFlags2">129</int>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="789504727">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{210, 12}, {128, 32}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="639557916">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">134217728</int>
|
||||
<string key="NSContents">Contribuer</string>
|
||||
<reference key="NSSupport" ref="534597488"/>
|
||||
<reference key="NSControlView" ref="789504727"/>
|
||||
<int key="NSButtonFlags">-2038284033</int>
|
||||
<int key="NSButtonFlags2">129</int>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{480, 390}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
</object>
|
||||
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
|
||||
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">contribute:</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="789504727"/>
|
||||
</object>
|
||||
<int key="connectionID">11</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">continue:</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="858267836"/>
|
||||
</object>
|
||||
<int key="connectionID">12</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">window</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="1005"/>
|
||||
</object>
|
||||
<int key="connectionID">13</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">continueButton</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="858267836"/>
|
||||
</object>
|
||||
<int key="connectionID">14</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<reference key="object" ref="0"/>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="1001"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="1003"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">First Responder</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-3</int>
|
||||
<reference key="object" ref="1004"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">Application</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1</int>
|
||||
<reference key="object" ref="1005"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="1006"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">2</int>
|
||||
<reference key="object" ref="1006"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="450147645"/>
|
||||
<reference ref="359672030"/>
|
||||
<reference ref="858267836"/>
|
||||
<reference ref="789504727"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1005"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">3</int>
|
||||
<reference key="object" ref="359672030"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="855705720"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="855705720"/>
|
||||
<reference key="parent" ref="359672030"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">5</int>
|
||||
<reference key="object" ref="450147645"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="307619415"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">6</int>
|
||||
<reference key="object" ref="307619415"/>
|
||||
<reference key="parent" ref="450147645"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">7</int>
|
||||
<reference key="object" ref="858267836"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="444055328"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">8</int>
|
||||
<reference key="object" ref="444055328"/>
|
||||
<reference key="parent" ref="858267836"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">9</int>
|
||||
<reference key="object" ref="789504727"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="639557916"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">10</int>
|
||||
<reference key="object" ref="639557916"/>
|
||||
<reference key="parent" ref="789504727"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>-3.IBPluginDependency</string>
|
||||
<string>1.IBEditorWindowLastContentRect</string>
|
||||
<string>1.IBPluginDependency</string>
|
||||
<string>1.IBWindowTemplateEditedContentRect</string>
|
||||
<string>1.NSWindowTemplate.visibleAtLaunch</string>
|
||||
<string>1.WindowOrigin</string>
|
||||
<string>1.editorWindowContentRectSynchronizationRect</string>
|
||||
<string>1.windowTemplate.maxSize</string>
|
||||
<string>1.windowTemplate.minSize</string>
|
||||
<string>10.IBPluginDependency</string>
|
||||
<string>2.IBPluginDependency</string>
|
||||
<string>3.IBPluginDependency</string>
|
||||
<string>3.IBViewBoundsToFrameTransform</string>
|
||||
<string>4.IBPluginDependency</string>
|
||||
<string>5.IBPluginDependency</string>
|
||||
<string>5.IBViewBoundsToFrameTransform</string>
|
||||
<string>6.IBPluginDependency</string>
|
||||
<string>7.IBPluginDependency</string>
|
||||
<string>7.IBViewBoundsToFrameTransform</string>
|
||||
<string>8.IBPluginDependency</string>
|
||||
<string>9.IBPluginDependency</string>
|
||||
<string>9.IBViewBoundsToFrameTransform</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{418, 295}, {480, 390}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{418, 295}, {480, 390}}</string>
|
||||
<boolean value="NO"/>
|
||||
<string>{196, 240}</string>
|
||||
<string>{{357, 418}, {480, 270}}</string>
|
||||
<string>{1.79769e+308, 1.79769e+308}</string>
|
||||
<string>{0, 0}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSAffineTransform">
|
||||
<bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwxwAAA</bytes>
|
||||
</object>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSAffineTransform">
|
||||
<bytes key="NSTransformStruct">P4AAAL+AAABAoAAAw3gAAA</bytes>
|
||||
</object>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSAffineTransform">
|
||||
<bytes key="NSTransformStruct">P4AAAL+AAABDqQAAwigAAA</bytes>
|
||||
</object>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSAffineTransform">
|
||||
<bytes key="NSTransformStruct">P4AAAL+AAABDUgAAwigAAA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">14</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">ExtraFairwareReminder</string>
|
||||
<string key="superclassName">HSWindowController</string>
|
||||
<object class="NSMutableDictionary" key="actions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>continue:</string>
|
||||
<string>contribute:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>id</string>
|
||||
<string>id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>continue:</string>
|
||||
<string>contribute:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">continue:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">contribute:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">continueButton</string>
|
||||
<string key="NS.object.0">NSButton</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">continueButton</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">continueButton</string>
|
||||
<string key="candidateClassName">NSButton</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../base/ExtraFairwareReminder.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">HSWindowController</string>
|
||||
<string key="superclassName">NSWindowController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../controllers/HSWindowController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/HSTableView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSActionCell</string>
|
||||
<string key="superclassName">NSCell</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSActionCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<string key="superclassName">NSResponder</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="131375392">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSApplication.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="645066809">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="295119366">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSApplication</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSButton</string>
|
||||
<string key="superclassName">NSControl</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSButton.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSButtonCell</string>
|
||||
<string key="superclassName">NSActionCell</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSButtonCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSCell</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSControl</string>
|
||||
<string key="superclassName">NSView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="947202395">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSControl.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSFormatter</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSMenu</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="754383277">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSMenu.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="131375392"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="645066809"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="295119366"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="947202395"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSDragging.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="754383277"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSTableView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="756921129">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSError.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Sparkle.framework/Headers/SUAppcast.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Sparkle.framework/Headers/SUUpdater.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSResponder</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSResponder</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSResponder.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSTextField</string>
|
||||
<string key="superclassName">NSControl</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSTextField.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSTextFieldCell</string>
|
||||
<string key="superclassName">NSActionCell</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSTextFieldCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSClipView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSView</string>
|
||||
<string key="superclassName">NSResponder</string>
|
||||
<reference key="sourceIdentifier" ref="756921129"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSWindow</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSWindow</string>
|
||||
<string key="superclassName">NSResponder</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindow.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSWindow</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSWindowController</string>
|
||||
<string key="superclassName">NSResponder</string>
|
||||
<object class="NSMutableDictionary" key="actions">
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">showWindow:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<string key="IBDocument.LastKnownRelativeProjectPath">../../pe/dupeguru.xcodeproj</string>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
</data>
|
||||
</archive>
|
||||
63
cocoa/base/fr.lproj/Localizable.strings
Normal file
63
cocoa/base/fr.lproj/Localizable.strings
Normal file
@@ -0,0 +1,63 @@
|
||||
"Add New Folder..." = "Ajouter dossier...";
|
||||
"Load from file..." = "Charger un fichier...";
|
||||
"Reset to Default" = "Colonnes par défault";
|
||||
|
||||
"Add iTunes Directory" = "Ajouter librairie iTunes";
|
||||
"Remove Dead Tracks in iTunes" = "Retirer les tracks mortes dans iTunes";
|
||||
|
||||
"Add iPhoto Library" = "Ajouter librairie iPhoto";
|
||||
"Clear Picture Cache" = "Vider la cache d'images";
|
||||
|
||||
/* Columns */
|
||||
"Folder" = "Dossier";
|
||||
"Size (KB)" = "Taille (KB)";
|
||||
"Size (MB)" = "Taille (MB)";
|
||||
"Kind" = "Type";
|
||||
"Modification" = "Modification";
|
||||
"Match %" = "Match %";
|
||||
"Words Used" = "Mots";
|
||||
"Dupe Count" = "# Doublons";
|
||||
|
||||
"Time" = "Temps";
|
||||
"Bitrate" = "Bitrate";
|
||||
"Sample Rate" = "Sample Rate";
|
||||
"Title" = "Titre";
|
||||
"Artist" = "Artiste";
|
||||
"Album" = "Album";
|
||||
"Genre" = "Genre";
|
||||
"Year" = "Année";
|
||||
"Track Number" = "Track";
|
||||
"Comment" = "Commentaire";
|
||||
|
||||
"Dimensions" = "Dimensions";
|
||||
|
||||
/* Messages */
|
||||
"SelectResultToLoadMsg" = "Sélectionnez un fichier résultats à charger";
|
||||
"SelectCopyDestinationMsg" = "Sélectionnez un dossier vers lequel copier les fichiers";
|
||||
"SelectMoveDestinationMsg" = "Sélectionnez un dossier vers lequel déplacer les fichiers";
|
||||
"SelectResultToSaveMsg" = "Sélectionnez un fichier résultats dans lequel sauvegarder";
|
||||
"SelectFolderToAddMsg" = "Sélectionnez un dossier à ajouter à la liste";
|
||||
"ReallyWantToQuitMsg" = "Vos résultats ne sont pas sauvegardés. Voulez-vous vraiment quitter?";
|
||||
"ReallyWantToContinueMsg" = "Vos résultats ne sont pas sauvegardés. Voulez-vous vraiment continuer?";
|
||||
"FolderAlreadyInListMsg" = "'%@' est déjà dans la liste.";
|
||||
"FolderDoesNotExistMsg" = "'%@' n'existe pas.";
|
||||
"FileRemovalConfirmMsg" = "%d fichiers seront retirés des résultats. Continuer?";
|
||||
"FilenameAlreadyExistsMsg" = "Le nom '%@' existe déjà.";
|
||||
"NoScannableFileMsg" = "Les dossiers sélectionnés ne continnent pas de fichiers valides.";
|
||||
"UnknownErrorMsg" = "Erreur inconnue.";
|
||||
"SendToTrashConfirmMsg" = "%d fichiers seront envoyés à la corbeille. Continuer?";
|
||||
"HardlinkConfirmMsg" = "%d fichiers seront envoyés à la corbeille (puis 'hardlinkés'). Continuer?";
|
||||
"ClearIgnoreListConfirmMsg" = "Voulez-vous vider la liste de fichiers ignorés des %d items qu'elle contient?";
|
||||
"IgnoreConfirmMsg" = "%d fichiers seront ignorés des prochains scans. Continuer?";
|
||||
"NoCustomCommandMsg" = "Vous n'avez pas de commande personnalisée. Ajoutez-la dans vos préférences.";
|
||||
"CopySuccessMsg" = "Tous les fichiers marqués ont été copiés correctement.";
|
||||
"MoveSuccessMsg" = "Tous les fichiers déplacés ont été copiés correctement.";
|
||||
"SendToTrashSuccessMsg" = "Tous les fichiers marqués ont été correctement envoyés à la corbeille.";
|
||||
"NoDuplicateFoundMsg" = "Aucun doublon trouvé.";
|
||||
"TaskHangingMsg" = "Une action précédente est encore en cours. Attendez quelques secondes avant d'en repartir une nouvelle.";
|
||||
|
||||
"RemoveDeadTracksConfirmMsg" = "Votre librairie iTunes contient %d tracks mortes qui seront retirées. Continuer?";
|
||||
"NoDeadTrackMsg" = "Votre librairie iTunes ne contient aucune track morte.";
|
||||
|
||||
"IPhotoAppNotFoundMsg" = "iPhoto n'a pas pu être trouvée dans vos applications.";
|
||||
"ClearPictureCacheConfirmMsg" = "Voulez-vous vraiment vider la cache de vos analyses précédentes?";
|
||||
174
cocoa/base/fr.lproj/MainMenu.strings
Normal file
174
cocoa/base/fr.lproj/MainMenu.strings
Normal file
@@ -0,0 +1,174 @@
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Bring All to Front"; ObjectID = "5"; */
|
||||
"5.title" = "Tout ramener au premier plan";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Window"; ObjectID = "19"; */
|
||||
"19.title" = "Fenêtre";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Minimize"; ObjectID = "23"; */
|
||||
"23.title" = "Placer dans le Dock";
|
||||
|
||||
/* Class = "NSMenu"; title = "Window"; ObjectID = "24"; */
|
||||
"24.title" = "Fenêtre";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "About dupeGuru"; ObjectID = "58"; */
|
||||
"58.title" = "À propos de dupeGuru";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Help"; ObjectID = "103"; */
|
||||
"103.title" = "Aide";
|
||||
|
||||
/* Class = "NSMenu"; title = "Help"; ObjectID = "106"; */
|
||||
"106.title" = "Aide";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "dupeGuru Help"; ObjectID = "111"; */
|
||||
"111.title" = "Aide dupeGuru";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hide dupeGuru"; ObjectID = "134"; */
|
||||
"134.title" = "Masquer dupeGuru";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Quit dupeGuru"; ObjectID = "136"; */
|
||||
"136.title" = "Quitter dupeGuru";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hide Others"; ObjectID = "145"; */
|
||||
"145.title" = "Masquer les autres";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show All"; ObjectID = "150"; */
|
||||
"150.title" = "Tout afficher";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Zoom"; ObjectID = "197"; */
|
||||
"197.title" = "Réduire/agrandir";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Details Panel"; ObjectID = "398"; */
|
||||
"398.title" = "Fenêtre de détails";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Preferences..."; ObjectID = "541"; */
|
||||
"541.title" = "Préférences...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Folder Selection Window"; ObjectID = "579"; */
|
||||
"579.title" = "Fenêtre de sélection de dossiers";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Actions"; ObjectID = "597"; */
|
||||
"597.title" = "Actions";
|
||||
|
||||
/* Class = "NSMenu"; title = "Actions"; ObjectID = "598"; */
|
||||
"598.title" = "Actions";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Send Marked to Trash"; ObjectID = "599"; */
|
||||
"599.title" = "Envoyer marqués à la corbeille";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Move Marked to..."; ObjectID = "600"; */
|
||||
"600.title" = "Déplacer marqués vers...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Copy Marked to..."; ObjectID = "601"; */
|
||||
"601.title" = "Copier marqués vers...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Make Selected Reference"; ObjectID = "602"; */
|
||||
"602.title" = "Transformer sélectionnés en références";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Marked from Results"; ObjectID = "603"; */
|
||||
"603.title" = "Retirer marqués des résultats";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Selected from Results"; ObjectID = "605"; */
|
||||
"605.title" = "Retirer sélectionnés des résultats";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Columns"; ObjectID = "618"; */
|
||||
"618.title" = "Colonnes";
|
||||
|
||||
/* Class = "NSMenu"; title = "Columns"; ObjectID = "619"; */
|
||||
"619.title" = "Colonnes";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Open Selected with Default Application"; ObjectID = "708"; */
|
||||
"708.title" = "Ouvrir sélectionné avec l'application par défaut";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Reveal Selected in Finder"; ObjectID = "710"; */
|
||||
"710.title" = "Révéler sélectionné dans Finder";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Add Selected to Ignore List"; ObjectID = "922"; */
|
||||
"922.title" = "Ajouter sélectionnés à la liste de fichiers ignorés";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Close Window"; ObjectID = "924"; */
|
||||
"924.title" = "Fermer";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Start Duplicate Scan"; ObjectID = "926"; */
|
||||
"926.title" = "Commencer à scanner";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Clear Ignore List"; ObjectID = "927"; */
|
||||
"927.title" = "Vider la liste de fichiers ignorés";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Rename Selected"; ObjectID = "933"; */
|
||||
"933.title" = "Renommer sélectionné";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Export Results to XHTML"; ObjectID = "947"; */
|
||||
"947.title" = "Exporter les résultats vers HTML";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Check for update..."; ObjectID = "950"; */
|
||||
"950.title" = "Mise à jour...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Mode"; ObjectID = "959"; */
|
||||
"959.title" = "Mode";
|
||||
|
||||
/* Class = "NSMenu"; title = "Mode"; ObjectID = "960"; */
|
||||
"960.title" = "Mode";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show Dupes Only"; ObjectID = "961"; */
|
||||
"961.title" = "Ne pas montrer les références";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show Delta Values"; ObjectID = "962"; */
|
||||
"962.title" = "Montrer les valeurs en tant que delta";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Edit"; ObjectID = "965"; */
|
||||
"965.title" = "Édition";
|
||||
|
||||
/* Class = "NSMenu"; title = "Edit"; ObjectID = "966"; */
|
||||
"966.title" = "Édition";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Cut"; ObjectID = "985"; */
|
||||
"985.title" = "Couper";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Copy"; ObjectID = "986"; */
|
||||
"986.title" = "Copier";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Paste"; ObjectID = "991"; */
|
||||
"991.title" = "Coller";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Mark All"; ObjectID = "1011"; */
|
||||
"1011.title" = "Tout marquer";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Mark None"; ObjectID = "1012"; */
|
||||
"1012.title" = "Tout démarquer";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Invert Marking"; ObjectID = "1013"; */
|
||||
"1013.title" = "Inverser le marquage";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Mark Selected"; ObjectID = "1014"; */
|
||||
"1014.title" = "Marquer sélectionnés";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "dupeGuru Website"; ObjectID = "1023"; */
|
||||
"1023.title" = "Site web de dupeGuru";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Invoke Custom Command"; ObjectID = "1177"; */
|
||||
"1177.title" = "Invoquer commande personnalisée";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "File"; ObjectID = "1203"; */
|
||||
"1203.title" = "Fichier";
|
||||
|
||||
/* Class = "NSMenu"; title = "File"; ObjectID = "1204"; */
|
||||
"1204.title" = "Fichier";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Load Results..."; ObjectID = "1205"; */
|
||||
"1205.title" = "Charger résultats...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Save Results..."; ObjectID = "1206"; */
|
||||
"1206.title" = "Sauvegarder résultats...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Delete Marked and Replace with Hardlinks"; ObjectID = "1227"; */
|
||||
"1227.title" = "Remplacer marqués par des hardlinks";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Load Recent Results"; ObjectID = "1239"; */
|
||||
"1239.title" = "Charger résultats récents";
|
||||
|
||||
/* Class = "NSMenu"; title = "Load Recent Results"; ObjectID = "1240"; */
|
||||
"1240.title" = "Charger résultats récents";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Results Window"; ObjectID = "1272"; */
|
||||
"1272.title" = "Fenêtre de résultats";
|
||||
2984
cocoa/base/fr.lproj/MainMenu.xib
Normal file
2984
cocoa/base/fr.lproj/MainMenu.xib
Normal file
File diff suppressed because it is too large
Load Diff
19
cocoa/base/fr.lproj/ProblemDialog.strings
Normal file
19
cocoa/base/fr.lproj/ProblemDialog.strings
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
/* Class = "NSWindow"; title = "Problems!"; ObjectID = "1"; */
|
||||
"1.title" = "Problèmes!";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "There were problems processing some (or all) of the files. The cause of these problems are described in the table below. Those files were not removed from your results."; ObjectID = "4"; */
|
||||
"4.title" = "There were problems processing some (or all) of the files. The cause of these problems are described in the table below. Those files were not removed from your results.";
|
||||
"4.title" = "Il y a eu des problèmes lors du traitement de certain (ou tous) fichiers. La cause de ces problèmes est décrite ci-dessous. Ces fichiers n'ont pas été enlevés des résultats.";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "File Path"; ObjectID = "10"; */
|
||||
"10.headerCell.title" = "Chemin du fichier";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Error Message"; ObjectID = "11"; */
|
||||
"11.headerCell.title" = "Message d'erreur";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Close"; ObjectID = "19"; */
|
||||
"19.title" = "Fermer";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Reveal Selected"; ObjectID = "21"; */
|
||||
"21.title" = "Révéler Fichier";
|
||||
1166
cocoa/base/fr.lproj/ProblemDialog.xib
Normal file
1166
cocoa/base/fr.lproj/ProblemDialog.xib
Normal file
File diff suppressed because it is too large
Load Diff
96
cocoa/base/fr.lproj/ResultWindow.strings
Normal file
96
cocoa/base/fr.lproj/ResultWindow.strings
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
/* Class = "NSWindow"; title = "dupeGuru Results"; ObjectID = "1"; */
|
||||
"1.title" = "dupeGuru (Résultats)";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Marked: 0 files, 0 B. Total: 0 files, 0 B."; ObjectID = "6"; */
|
||||
"6.title" = "Marqués: 0 fichiers, 0 B. Total: 0 fichiers, 0 B.";
|
||||
|
||||
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "11"; */
|
||||
"11.headerCell.title" = "Nom";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Options"; ObjectID = "15"; */
|
||||
"15.label" = "Options";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "Options"; ObjectID = "15"; */
|
||||
"15.paletteLabel" = "Options";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Filter"; ObjectID = "16"; */
|
||||
"16.label" = "Filtre";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "Filter"; ObjectID = "16"; */
|
||||
"16.paletteLabel" = "Filtre";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Action"; ObjectID = "17"; */
|
||||
"17.label" = "Action";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "Action"; ObjectID = "17"; */
|
||||
"17.paletteLabel" = "Action";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Directories"; ObjectID = "19"; */
|
||||
"19.label" = "Dossiers";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "Directories"; ObjectID = "19"; */
|
||||
"19.paletteLabel" = "Dossiers";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Delete Marked and Replace with Hardlinks"; ObjectID = "27"; */
|
||||
"27.title" = "Remplacer marqués par des hardlinks";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Send Marked to Trash"; ObjectID = "29"; */
|
||||
"29.title" = "Envoyer marqués à la corbeille";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Move Marked to..."; ObjectID = "30"; */
|
||||
"30.title" = "Déplacer marqués vers...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Copy Marked to..."; ObjectID = "31"; */
|
||||
"31.title" = "Copier marqués vers...";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Marked from Results"; ObjectID = "32"; */
|
||||
"32.title" = "Retirer marqués des résultats";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Selected from Results"; ObjectID = "34"; */
|
||||
"34.title" = "Retirer sélectionnés des résultats";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Add Selected to Ignore List"; ObjectID = "35"; */
|
||||
"35.title" = "Ajouter sélectionnés à la liste de fichiers ignorés";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Make Selected Reference"; ObjectID = "36"; */
|
||||
"36.title" = "Transformer sélectionnés en références";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Open Selected with Default Application"; ObjectID = "38"; */
|
||||
"38.title" = "Ouvrir sélectionné avec l'application par défaut";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Reveal Selected in Finder"; ObjectID = "39"; */
|
||||
"39.title" = "Révéler sélectionné dans Finder";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Rename Selected"; ObjectID = "40"; */
|
||||
"40.title" = "Renommer sélectionné";
|
||||
|
||||
/* Class = "NSSearchFieldCell"; placeholderString = "Filter"; ObjectID = "42"; */
|
||||
"42.placeholderString" = "Filtre";
|
||||
|
||||
/* Class = "NSSegmentedCell"; 44.labels[0] = "Details"; ObjectID = "44"; */
|
||||
"44.labels[0]" = "Détails";
|
||||
|
||||
/* Class = "NSSegmentedCell"; 44.labels[1] = "Dupes Only"; ObjectID = "44"; */
|
||||
"44.labels[1]" = "Sans réf.";
|
||||
|
||||
/* Class = "NSSegmentedCell"; 44.labels[2] = "Delta"; ObjectID = "44"; */
|
||||
"44.labels[2]" = "Delta";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Add Selected to Ignore List"; ObjectID = "68"; */
|
||||
"68.title" = "Ajouter sélectionnés à la liste de fichiers ignorés";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Rename Selected"; ObjectID = "70"; */
|
||||
"70.title" = "Renommer sélectionné";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Remove Selected from Results"; ObjectID = "71"; */
|
||||
"71.title" = "Retirer sélectionnés des résultats";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Make Selected Reference"; ObjectID = "72"; */
|
||||
"72.title" = "Transformer sélectionnés en références";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Reveal Selected in Finder"; ObjectID = "73"; */
|
||||
"73.title" = "Révéler sélectionné dans Finder";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Open Selected with Default Application"; ObjectID = "74"; */
|
||||
"74.title" = "Ouvrir sélectionné avec l'application par défaut";
|
||||
2742
cocoa/base/fr.lproj/ResultWindow.xib
Normal file
2742
cocoa/base/fr.lproj/ResultWindow.xib
Normal file
File diff suppressed because it is too large
Load Diff
31
cocoa/base/fr.lproj/core.strings
Normal file
31
cocoa/base/fr.lproj/core.strings
Normal file
@@ -0,0 +1,31 @@
|
||||
"Collecting files to scan" = "Collecte des fichiers à scanner";
|
||||
"%s (%d discarded)" = "%s (%d hors-groupe)";
|
||||
"Scanning for duplicates" = "Scan de doublons en cours";
|
||||
"Loading" = "Chargement en cours";
|
||||
"Moving" = "Déplacement en cours";
|
||||
"Copying" = "Copie en cours";
|
||||
"Sending to Trash" = "Envoi vers corbeille";
|
||||
"0 matches found" = "0 paires trouvées";
|
||||
"%d matches found" = "%d paires trouvées";
|
||||
"Read size of %d/%d files" = "Lu la taille de %d/%d fichiers";
|
||||
"Grouped %d/%d matches" = "%d/%d paires groupées";
|
||||
"%d / %d (%s / %s) duplicates marked." = "%d / %d (%s / %s) doublons marqués.";
|
||||
" filter: %s" = " filtre: %s";
|
||||
"Read metadata of %d/%d files" = "Lu les métadonnées de %d/%d fichiers";
|
||||
"Removing false matches" = "Retrait des paires invalides";
|
||||
"Processed %d/%d matches against the ignore list" = "Vérification de %d/%d paires dans la ignore list";
|
||||
"Doing group prioritization" = "Prioritization des groupes";
|
||||
|
||||
"Continue" = "Continuer";
|
||||
"Continue ({})" = "Continuer ({})";
|
||||
|
||||
"Analyzed %d/%d pictures" = "Analyzé %d/%d images";
|
||||
"Preparing for matching" = "Préparation pour la comparaison";
|
||||
"Performed %d/%d chunk matches" = "%d/%d blocs d'images comparés";
|
||||
"Verified %d/%d matches" = "Vérifié %d/%d paires";
|
||||
|
||||
"Removing dead tracks from your iTunes Library" = "Retrait des tracks mortes de votre librairie iTunes";
|
||||
"Scanning the iTunes Library" = "Scan de la librairie iTunes en cours";
|
||||
|
||||
"Probing iPhoto. Don't touch it during the operation!" = "Communication avec iPhoto en cours. N'y touchez pas!";
|
||||
"Sending dupes to the Trash" = "Envoi de doublons à la corbeille en cours";
|
||||
16
cocoa/me/AppDelegate.h
Normal file
16
cocoa/me/AppDelegate.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "../base/AppDelegate.h"
|
||||
#import "ResultWindow.h"
|
||||
#import "PyDupeGuru.h"
|
||||
|
||||
@interface AppDelegate : AppDelegateBase {}
|
||||
- (PyDupeGuru *)py;
|
||||
@end
|
||||
@@ -1,18 +1,19 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "cocoalib/ProgressController.h"
|
||||
#import "cocoalib/RegistrationInterface.h"
|
||||
#import "cocoalib/Utils.h"
|
||||
#import "cocoalib/ValueTransformers.h"
|
||||
#import "cocoalib/Dialogs.h"
|
||||
#import "ProgressController.h"
|
||||
#import "Utils.h"
|
||||
#import "ValueTransformers.h"
|
||||
#import "Dialogs.h"
|
||||
#import "DetailsPanel.h"
|
||||
#import "DirectoryPanel.h"
|
||||
#import "ResultWindow.h"
|
||||
#import "Consts.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
@@ -27,6 +28,7 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[d setObject:b2n(NO) forKey:@"matchSimilarWords"];
|
||||
[d setObject:b2n(YES) forKey:@"mixFileKind"];
|
||||
[d setObject:b2n(NO) forKey:@"useRegexpFilter"];
|
||||
[d setObject:b2n(NO) forKey:@"ignoreHardlinkMatches"];
|
||||
[d setObject:b2n(NO) forKey:@"removeEmptyFolders"];
|
||||
[d setObject:b2n(NO) forKey:@"debug"];
|
||||
[d setObject:b2n(NO) forKey:@"scanTagTrack"];
|
||||
@@ -52,66 +54,33 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
VTIsIntIn *vtScanTypeIsTag = [[[VTIsIntIn alloc] initWithValues:[NSIndexSet indexSetWithIndex:3] reverse:NO] autorelease];
|
||||
[NSValueTransformer setValueTransformer:vtScanTypeIsTag forName:@"vtScanTypeIsTag"];
|
||||
_directoryPanel = nil;
|
||||
_appName = APPNAME;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (IBAction)openWebsite:(id)sender
|
||||
- (NSString *)homepageURL
|
||||
{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.hardcoded.net/dupeguru_me"]];
|
||||
return @"http://www.hardcoded.net/dupeguru_me/";
|
||||
}
|
||||
|
||||
- (IBAction)toggleDirectories:(id)sender
|
||||
- (ResultWindowBase *)createResultWindow
|
||||
{
|
||||
[[self directoryPanel] toggleVisible:sender];
|
||||
return [[ResultWindow alloc] initWithParentApp:self];
|
||||
}
|
||||
|
||||
|
||||
- (DetailsPanelBase *)detailsPanel
|
||||
- (DirectoryPanel *)createDirectoryPanel
|
||||
{
|
||||
if (!_detailsPanel)
|
||||
_detailsPanel = [[DetailsPanel alloc] initWithPy:py];
|
||||
return _detailsPanel;
|
||||
return [[DirectoryPanelME alloc] initWithParentApp:self];
|
||||
}
|
||||
|
||||
- (DirectoryPanel *)directoryPanel
|
||||
{
|
||||
if (!_directoryPanel)
|
||||
_directoryPanel = [[DirectoryPanel alloc] initWithParentApp:self];
|
||||
return _directoryPanel;
|
||||
}
|
||||
- (PyDupeGuru *)py { return (PyDupeGuru *)py; }
|
||||
|
||||
//Delegate
|
||||
- (void)applicationWillBecomeActive:(NSNotification *)aNotification
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
if (![[result window] isVisible])
|
||||
[result showWindow:NSApp];
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
[ud setObject: [result getColumnsOrder] forKey:@"columnsOrder"];
|
||||
[ud setObject: [result getColumnsWidth] forKey:@"columnsWidth"];
|
||||
[py saveIgnoreList];
|
||||
[py saveResults];
|
||||
int sc = [ud integerForKey:@"sessionCountSinceLastIgnorePurge"];
|
||||
if (sc >= 10)
|
||||
{
|
||||
sc = -1;
|
||||
[py purgeIgnoreList];
|
||||
}
|
||||
sc++;
|
||||
[ud setInteger:sc forKey:@"sessionCountSinceLastIgnorePurge"];
|
||||
// NSApplication does not release nib instances objects, we must do it manually
|
||||
// Well, it isn't needed because the memory is freed anyway (we are quitting the application
|
||||
// But I need to release RecentDirectories so it saves the user defaults
|
||||
[recentDirectories release];
|
||||
}
|
||||
|
||||
- (void)recentDirecoryClicked:(NSString *)directory
|
||||
{
|
||||
[[self directoryPanel] addDirectory:directory];
|
||||
// index 3 is just after "Export Results to XHTML"
|
||||
NSMenuItem *mi = [actionsMenu insertItemWithTitle:TR(@"Remove Dead Tracks in iTunes")
|
||||
action:@selector(removeDeadTracks:) keyEquivalent:@"" atIndex:3];
|
||||
[mi setTarget:[self resultWindow]];
|
||||
[super applicationDidFinishLaunching:aNotification];
|
||||
}
|
||||
@end
|
||||
11
cocoa/me/Consts.h
Normal file
11
cocoa/me/Consts.h
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "../base/Consts.h"
|
||||
|
||||
#define jobScanDeadTracks @"jobScanDeadTracks"
|
||||
16
cocoa/me/DirectoryPanel.h
Normal file
16
cocoa/me/DirectoryPanel.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "../base/DirectoryPanel.h"
|
||||
|
||||
@interface DirectoryPanelME : DirectoryPanel
|
||||
{
|
||||
}
|
||||
- (IBAction)addiTunes:(id)sender;
|
||||
@end
|
||||
34
cocoa/me/DirectoryPanel.m
Normal file
34
cocoa/me/DirectoryPanel.m
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "DirectoryPanel.h"
|
||||
#import "Consts.h"
|
||||
|
||||
@implementation DirectoryPanelME
|
||||
- (id)initWithParentApp:(id)aParentApp
|
||||
{
|
||||
self = [super initWithParentApp:aParentApp];
|
||||
[[self window] setTitle:@"dupeGuru Music Edition"];
|
||||
_alwaysShowPopUp = YES;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)fillPopUpMenu
|
||||
{
|
||||
[super fillPopUpMenu];
|
||||
NSMenu *m = [addButtonPopUp menu];
|
||||
NSMenuItem *mi = [m insertItemWithTitle:TR(@"Add iTunes Directory") action:@selector(addiTunes:)
|
||||
keyEquivalent:@"" atIndex:1];
|
||||
[mi setTarget:self];
|
||||
}
|
||||
|
||||
- (IBAction)addiTunes:(id)sender
|
||||
{
|
||||
[self addDirectory:[@"~/Music/iTunes/iTunes Music" stringByExpandingTildeInPath]];
|
||||
}
|
||||
@end
|
||||
@@ -23,13 +23,13 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>hsft</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.6.6</string>
|
||||
<string>{version}</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>© Hardcoded Software, 2009</string>
|
||||
<string>© Hardcoded Software, 2010</string>
|
||||
<key>SUFeedURL</key>
|
||||
<string>http://www.hardcoded.net/updates/dupeguru_me.appcast</string>
|
||||
<key>SUPublicDSAKeyFile</key>
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/hs_license
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "dgbase/PyDupeGuru.h"
|
||||
#import "../base/PyDupeGuru.h"
|
||||
|
||||
@interface PyDupeGuru : PyDupeGuruBase
|
||||
//Scanning options
|
||||
@@ -19,5 +19,5 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
- (void)enable:(NSNumber *)enable scanForTag:(NSString *)tag;
|
||||
- (void)scanDeadTracks;
|
||||
- (void)removeDeadTracks;
|
||||
- (int)deadTrackCount;
|
||||
- (NSInteger)deadTrackCount;
|
||||
@end
|
||||
14
cocoa/me/ResultWindow.h
Normal file
14
cocoa/me/ResultWindow.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "../base/ResultWindow.h"
|
||||
|
||||
@interface ResultWindow : ResultWindowBase {}
|
||||
- (IBAction)removeDeadTracks:(id)sender;
|
||||
@end
|
||||
107
cocoa/me/ResultWindow.m
Normal file
107
cocoa/me/ResultWindow.m
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
|
||||
This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
which should be included with this package. The terms are also available at
|
||||
http://www.hardcoded.net/licenses/bsd_license
|
||||
*/
|
||||
|
||||
#import "ResultWindow.h"
|
||||
#import "Dialogs.h"
|
||||
#import "Utils.h"
|
||||
#import "PyDupeGuru.h"
|
||||
#import "Consts.h"
|
||||
|
||||
@implementation ResultWindow
|
||||
/* Override */
|
||||
- (void)setScanOptions
|
||||
{
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
PyDupeGuru *_py = (PyDupeGuru *)py;
|
||||
[_py setScanType:[ud objectForKey:@"scanType"]];
|
||||
[_py enable:[ud objectForKey:@"scanTagTrack"] scanForTag:@"track"];
|
||||
[_py enable:[ud objectForKey:@"scanTagArtist"] scanForTag:@"artist"];
|
||||
[_py enable:[ud objectForKey:@"scanTagAlbum"] scanForTag:@"album"];
|
||||
[_py enable:[ud objectForKey:@"scanTagTitle"] scanForTag:@"title"];
|
||||
[_py enable:[ud objectForKey:@"scanTagGenre"] scanForTag:@"genre"];
|
||||
[_py enable:[ud objectForKey:@"scanTagYear"] scanForTag:@"year"];
|
||||
[_py setMinMatchPercentage:[ud objectForKey:@"minMatchPercentage"]];
|
||||
[_py setWordWeighting:[ud objectForKey:@"wordWeighting"]];
|
||||
[_py setMixFileKind:n2b([ud objectForKey:@"mixFileKind"])];
|
||||
[_py setIgnoreHardlinkMatches:n2b([ud objectForKey:@"ignoreHardlinkMatches"])];
|
||||
[_py setMatchSimilarWords:[ud objectForKey:@"matchSimilarWords"]];
|
||||
}
|
||||
|
||||
- (void)initResultColumns
|
||||
{
|
||||
NSTableColumn *refCol = [matches tableColumnWithIdentifier:@"0"];
|
||||
_resultColumns = [[NSMutableArray alloc] init];
|
||||
[_resultColumns addObject:[matches tableColumnWithIdentifier:@"0"]]; // File Name
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:1 title:TR(@"Folder") width:120 refCol:refCol]];
|
||||
NSTableColumn *sizeCol = [self getColumnForIdentifier:2 title:TR(@"Size (MB)") width:63 refCol:refCol];
|
||||
[[sizeCol dataCell] setAlignment:NSRightTextAlignment];
|
||||
[_resultColumns addObject:sizeCol];
|
||||
NSTableColumn *timeCol = [self getColumnForIdentifier:3 title:TR(@"Time") width:50 refCol:refCol];
|
||||
[[timeCol dataCell] setAlignment:NSRightTextAlignment];
|
||||
[_resultColumns addObject:timeCol];
|
||||
NSTableColumn *brCol = [self getColumnForIdentifier:4 title:TR(@"Bitrate") width:50 refCol:refCol];
|
||||
[[brCol dataCell] setAlignment:NSRightTextAlignment];
|
||||
[_resultColumns addObject:brCol];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:5 title:TR(@"Sample Rate") width:60 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:6 title:TR(@"Kind") width:40 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:7 title:TR(@"Modification") width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:8 title:TR(@"Title") width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:9 title:TR(@"Artist") width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:10 title:TR(@"Album") width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:11 title:TR(@"Genre") width:80 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:12 title:TR(@"Year") width:40 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:13 title:TR(@"Track Number") width:40 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:14 title:TR(@"Comment") width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:15 title:TR(@"Match %") width:57 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:16 title:TR(@"Words Used") width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:17 title:TR(@"Dupe Count") width:80 refCol:refCol]];
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
- (IBAction)removeDeadTracks:(id)sender
|
||||
{
|
||||
[(PyDupeGuru *)py scanDeadTracks];
|
||||
}
|
||||
|
||||
- (IBAction)resetColumnsToDefault:(id)sender
|
||||
{
|
||||
NSMutableArray *columnsOrder = [NSMutableArray array];
|
||||
[columnsOrder addObject:@"0"];
|
||||
[columnsOrder addObject:@"2"];
|
||||
[columnsOrder addObject:@"3"];
|
||||
[columnsOrder addObject:@"4"];
|
||||
[columnsOrder addObject:@"6"];
|
||||
[columnsOrder addObject:@"15"];
|
||||
NSMutableDictionary *columnsWidth = [NSMutableDictionary dictionary];
|
||||
[columnsWidth setObject:i2n(235) forKey:@"0"];
|
||||
[columnsWidth setObject:i2n(63) forKey:@"2"];
|
||||
[columnsWidth setObject:i2n(50) forKey:@"3"];
|
||||
[columnsWidth setObject:i2n(50) forKey:@"4"];
|
||||
[columnsWidth setObject:i2n(40) forKey:@"6"];
|
||||
[columnsWidth setObject:i2n(57) forKey:@"15"];
|
||||
[self restoreColumnsPosition:columnsOrder widths:columnsWidth];
|
||||
}
|
||||
|
||||
/* Notifications */
|
||||
- (void)jobCompleted:(NSNotification *)aNotification
|
||||
{
|
||||
[super jobCompleted:aNotification];
|
||||
id lastAction = [[ProgressController mainProgressController] jobId];
|
||||
if ([lastAction isEqualTo:jobScanDeadTracks]) {
|
||||
NSInteger deadTrackCount = [(PyDupeGuru *)py deadTrackCount];
|
||||
if (deadTrackCount > 0) {
|
||||
NSString *msg = TR(@"RemoveDeadTracksConfirmMsg");
|
||||
if ([Dialogs askYesNo:[NSString stringWithFormat:msg,deadTrackCount]] == NSAlertFirstButtonReturn)
|
||||
[(PyDupeGuru *)py removeDeadTracks];
|
||||
}
|
||||
else {
|
||||
[Dialogs showMessage:TR(@"NoDeadTrackMsg")];
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
||||
66
cocoa/me/dg_cocoa.py
Normal file
66
cocoa/me/dg_cocoa.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/bsd_license
|
||||
|
||||
from hscommon.trans import install_cocoa_trans
|
||||
install_cocoa_trans()
|
||||
|
||||
from hscommon.cocoa import signature
|
||||
|
||||
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||
from core_me.app_cocoa import DupeGuruME
|
||||
from core_me import __appname__
|
||||
from core.scanner import ScanType
|
||||
|
||||
class PyDupeGuru(PyDupeGuruBase):
|
||||
def init(self):
|
||||
self = super(PyDupeGuru,self).init()
|
||||
self.py = DupeGuruME()
|
||||
return self
|
||||
|
||||
def removeDeadTracks(self):
|
||||
self.py.remove_dead_tracks()
|
||||
|
||||
def scanDeadTracks(self):
|
||||
self.py.scan_dead_tracks()
|
||||
|
||||
#---Information
|
||||
@signature('i@:')
|
||||
def deadTrackCount(self):
|
||||
return len(self.py.dead_tracks)
|
||||
|
||||
#---Properties
|
||||
def setMinMatchPercentage_(self, percentage):
|
||||
self.py.scanner.min_match_percentage = int(percentage)
|
||||
|
||||
def setScanType_(self, scan_type):
|
||||
try:
|
||||
self.py.scanner.scan_type = [
|
||||
ScanType.Filename,
|
||||
ScanType.Fields,
|
||||
ScanType.FieldsNoOrder,
|
||||
ScanType.Tag,
|
||||
ScanType.Contents,
|
||||
ScanType.ContentsAudio,
|
||||
][scan_type]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def setWordWeighting_(self, words_are_weighted):
|
||||
self.py.scanner.word_weighting = words_are_weighted
|
||||
|
||||
def setMatchSimilarWords_(self, match_similar_words):
|
||||
self.py.scanner.match_similar_words = match_similar_words
|
||||
|
||||
def enable_scanForTag_(self, enable, scan_tag):
|
||||
if enable:
|
||||
self.py.scanner.scanned_tags.add(scan_tag)
|
||||
else:
|
||||
self.py.scanner.scanned_tags.discard(scan_tag)
|
||||
|
||||
#---Registration
|
||||
def appName(self):
|
||||
return __appname__
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user