mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-01-25 16:11:39 +00:00
Compare commits
404 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
4f6af6e4dc | ||
|
|
a6d2a9b7b3 | ||
|
|
cf34164191 | ||
|
|
9a7bb30df4 | ||
|
|
5dc78809b6 | ||
|
|
2b53a6e7d6 | ||
|
|
eb82a35e5b | ||
|
|
51b14435e0 | ||
|
|
59de033523 | ||
|
|
c9b0a278ca | ||
|
|
b487189742 | ||
|
|
d5a60b1580 | ||
|
|
e2665610e9 | ||
|
|
3262ee9938 | ||
|
|
2f153003b3 | ||
|
|
6724e710d8 | ||
|
|
9729e05fe8 | ||
|
|
686c60b83b | ||
|
|
5fe11f3b3a | ||
|
|
30d29c6b34 | ||
|
|
fbfb16e77a | ||
|
|
7aea384f86 | ||
|
|
78bef5c3c6 | ||
|
|
5c8d90a57c | ||
|
|
13dc9ff76d | ||
|
|
eb3645d493 | ||
|
|
0a06e52d65 | ||
|
|
e004c0c2d4 | ||
|
|
6d5f6a0c3c | ||
|
|
024e3c380f | ||
|
|
06859fe9cd | ||
|
|
6392d08584 | ||
|
|
80a5290bc8 | ||
|
|
6b30c88fba | ||
|
|
6adce9bf03 | ||
|
|
3c90ad81a7 | ||
|
|
484529add0 | ||
|
|
600c7906a4 | ||
|
|
f070e90347 | ||
|
|
88127d8b8d | ||
|
|
607ab86188 | ||
|
|
c936f9ccc6 | ||
|
|
d4d8917956 | ||
|
|
89bce95c27 | ||
|
|
f0a38a2b3f | ||
|
|
911521d8e0 | ||
|
|
b25c1c3a3b | ||
|
|
37a40040b3 | ||
|
|
25dadc83eb | ||
|
|
b8c11b5aae | ||
|
|
a3ab314378 | ||
|
|
794192835d | ||
|
|
385768a69b | ||
|
|
a281931b16 | ||
|
|
085311d559 | ||
|
|
4d7f032889 | ||
|
|
cf44c93013 | ||
|
|
787cbcd01f | ||
|
|
b2b316b642 | ||
|
|
49165125e4 | ||
|
|
54ac0fd19e | ||
|
|
0aff7f16e5 | ||
|
|
f9abc3b35d | ||
|
|
b167a51243 | ||
|
|
371cdda911 | ||
|
|
11977c6533 | ||
|
|
7228adf433 |
22
.hgignore
Normal file
22
.hgignore
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
syntax: glob
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
run.py
|
||||||
|
*.pyc
|
||||||
|
*.so
|
||||||
|
*.mode1v3
|
||||||
|
*.pbxuser
|
||||||
|
*.tm_build_errors
|
||||||
|
*.pyd
|
||||||
|
conf.yaml
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
install
|
||||||
|
installer_tmp-cache
|
||||||
|
cocoa/*/Info.plist
|
||||||
|
cocoa/*/build
|
||||||
|
cocoa/*/dg_cocoa.plugin
|
||||||
|
qt/base/*_rc.py
|
||||||
|
help_se/dupeguru_help
|
||||||
|
help_me/dupeguru_me_help
|
||||||
|
help_pe/dupeguru_pe_help
|
||||||
38
.hgtags
Normal file
38
.hgtags
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
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
|
||||||
@@ -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.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
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 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.
|
* 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.
|
* 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.
|
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.
|
||||||
69
README
Normal file
69
README
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
Contents
|
||||||
|
=====
|
||||||
|
|
||||||
|
This package contains the source for dupeGuru. To learns 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. Before redistributing changes in this part of the code, read the "qt/WARNING" file.
|
||||||
|
- images: Images used by the different UI codebases.
|
||||||
|
|
||||||
|
There are also other sub-folder that comes from external repositories (automatically checked out
|
||||||
|
with svn:externals):
|
||||||
|
|
||||||
|
- hscommon: A collection of helpers used across HS applications.
|
||||||
|
- hsgui: Cross-toolkit GUI-related helper classes.
|
||||||
|
- 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 (http://www.python.org)
|
||||||
|
- Send2Trash3k (http://hg.hardcoded.net/send2trash)
|
||||||
|
- hsutil3k (http://hg.hardcoded.net/hsutil)
|
||||||
|
- hsaudiotag3k (for ME) (http://hg.hardcoded.net/hsaudiotag)
|
||||||
|
- jobprogress (http://hg.hardcoded.net/jobprogress)
|
||||||
|
- Markdown, to generate help files. (http://pypi.python.org/pypi/Markdown)
|
||||||
|
- PyYaml, for help files and the build system. (http://pyyaml.org/)
|
||||||
|
- py.test, to run unit tests. (http://codespeak.net/py/dist/test/)
|
||||||
|
|
||||||
|
OS X prerequisites
|
||||||
|
-----
|
||||||
|
|
||||||
|
- XCode 3.1 (http://developer.apple.com/TOOLS/xcode/)
|
||||||
|
- Sparkle (http://sparkle.andymatuschak.org/)
|
||||||
|
- PyObjC 2.3. (http://pyobjc.sourceforge.net/)
|
||||||
|
- py2app 0.5.4 (http://bitbucket.org/ronaldoussoren/py2app)
|
||||||
|
|
||||||
|
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,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 "RecentDirectories.h"
|
|
||||||
#import "PyDupeGuru.h"
|
|
||||||
|
|
||||||
@interface AppDelegateBase : NSObject
|
|
||||||
{
|
|
||||||
IBOutlet PyDupeGuruBase *py;
|
|
||||||
IBOutlet RecentDirectories *recentDirectories;
|
|
||||||
IBOutlet NSMenuItem *unlockMenuItem;
|
|
||||||
|
|
||||||
NSString *_appName;
|
|
||||||
}
|
|
||||||
- (IBAction)unlockApp:(id)sender;
|
|
||||||
|
|
||||||
- (PyDupeGuruBase *)py;
|
|
||||||
- (RecentDirectories *)recentDirectories;
|
|
||||||
@end
|
|
||||||
@@ -1,38 +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; }
|
|
||||||
@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,24 +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;
|
|
||||||
|
|
||||||
/* Notifications */
|
|
||||||
- (void)duplicateSelectionChanged:(NSNotification *)aNotification;
|
|
||||||
@end
|
|
||||||
@@ -1,33 +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:@"Details"];
|
|
||||||
[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];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Notifications */
|
|
||||||
- (void)duplicateSelectionChanged:(NSNotification *)aNotification
|
|
||||||
{
|
|
||||||
if ([[self window] isVisible])
|
|
||||||
[self refresh];
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
@@ -1,187 +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 DirectoryPanelBase
|
|
||||||
- (id)initWithParentApp:(id)aParentApp
|
|
||||||
{
|
|
||||||
self = [super initWithWindowNibName:@"Directories"];
|
|
||||||
[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
|
|
||||||
{
|
|
||||||
if ([[self window] isVisible])
|
|
||||||
[[self window] close];
|
|
||||||
else
|
|
||||||
[[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 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,60 +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 "DirectoryPanel.h"
|
|
||||||
#import "PyDupeGuru.h"
|
|
||||||
|
|
||||||
@interface MatchesView : OutlineView
|
|
||||||
- (void)keyDown:(NSEvent *)theEvent;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface ResultWindowBase : NSWindowController
|
|
||||||
{
|
|
||||||
@protected
|
|
||||||
IBOutlet PyDupeGuruBase *py;
|
|
||||||
IBOutlet id app;
|
|
||||||
IBOutlet NSView *actionMenuView;
|
|
||||||
IBOutlet NSSegmentedControl *deltaSwitch;
|
|
||||||
IBOutlet NSView *deltaSwitchView;
|
|
||||||
IBOutlet NSView *filterFieldView;
|
|
||||||
IBOutlet MatchesView *matches;
|
|
||||||
IBOutlet NSSegmentedControl *pmSwitch;
|
|
||||||
IBOutlet NSView *pmSwitchView;
|
|
||||||
IBOutlet NSTextField *stats;
|
|
||||||
|
|
||||||
BOOL _powerMode;
|
|
||||||
BOOL _displayDelta;
|
|
||||||
}
|
|
||||||
/* Override */
|
|
||||||
- (NSString *)logoImageName;
|
|
||||||
|
|
||||||
/* Helpers */
|
|
||||||
- (NSArray *)getColumnsOrder;
|
|
||||||
- (NSDictionary *)getColumnsWidth;
|
|
||||||
- (NSArray *)getSelected:(BOOL)aDupesOnly;
|
|
||||||
- (NSArray *)getSelectedPaths:(BOOL)aDupesOnly;
|
|
||||||
- (void)updatePySelection;
|
|
||||||
- (void)performPySelection:(NSArray *)aIndexPaths;
|
|
||||||
- (void)refreshStats;
|
|
||||||
|
|
||||||
/* 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)switchSelected:(id)sender;
|
|
||||||
- (IBAction)togglePowerMarker:(id)sender;
|
|
||||||
|
|
||||||
/* Notifications */
|
|
||||||
- (void)jobCompleted:(NSNotification *)aNotification;
|
|
||||||
@end
|
|
||||||
@@ -1,468 +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"
|
|
||||||
|
|
||||||
#define tbbDirectories @"tbbDirectories"
|
|
||||||
#define tbbDetails @"tbbDetail"
|
|
||||||
#define tbbPreferences @"tbbPreferences"
|
|
||||||
#define tbbPowerMarker @"tbbPowerMarker"
|
|
||||||
#define tbbScan @"tbbScan"
|
|
||||||
#define tbbAction @"tbbAction"
|
|
||||||
#define tbbDelta @"tbbDelta"
|
|
||||||
#define tbbFilter @"tbbFilter"
|
|
||||||
|
|
||||||
@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];
|
|
||||||
[[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];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Virtual */
|
|
||||||
- (NSString *)logoImageName
|
|
||||||
{
|
|
||||||
return @"dg_logo32";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Helpers */
|
|
||||||
//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)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)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)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)
|
|
||||||
[Dialogs showMessage:[NSString stringWithFormat:@"%d file(s) couldn't be sent to Trash. They were kept in the results, and still are marked.",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];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Toolbar */
|
|
||||||
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
|
|
||||||
{
|
|
||||||
NSToolbarItem *tbi = [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier] autorelease];
|
|
||||||
if ([itemIdentifier isEqualTo:tbbDirectories])
|
|
||||||
{
|
|
||||||
[tbi setLabel: @"Directories"];
|
|
||||||
[tbi setToolTip: @"Show/Hide the directories panel."];
|
|
||||||
[tbi setImage: [NSImage imageNamed: @"folder32"]];
|
|
||||||
[tbi setTarget: app];
|
|
||||||
[tbi setAction: @selector(toggleDirectories:)];
|
|
||||||
}
|
|
||||||
else if ([itemIdentifier isEqualTo:tbbDetails])
|
|
||||||
{
|
|
||||||
[tbi setLabel: @"Details"];
|
|
||||||
[tbi setToolTip: @"Show/Hide the details panel."];
|
|
||||||
[tbi setImage: [NSImage imageNamed: @"details32"]];
|
|
||||||
[tbi setTarget: self];
|
|
||||||
[tbi setAction: @selector(toggleDetailsPanel:)];
|
|
||||||
}
|
|
||||||
else if ([itemIdentifier isEqualTo:tbbPreferences])
|
|
||||||
{
|
|
||||||
[tbi setLabel: @"Preferences"];
|
|
||||||
[tbi setToolTip: @"Show the preferences panel."];
|
|
||||||
[tbi setImage: [NSImage imageNamed: @"preferences32"]];
|
|
||||||
[tbi setTarget: self];
|
|
||||||
[tbi setAction: @selector(showPreferencesPanel:)];
|
|
||||||
}
|
|
||||||
else if ([itemIdentifier isEqualTo:tbbPowerMarker])
|
|
||||||
{
|
|
||||||
[tbi setLabel: @"Power Marker"];
|
|
||||||
[tbi setToolTip: @"When enabled, only the duplicates are shown, not the references."];
|
|
||||||
[tbi setView:pmSwitchView];
|
|
||||||
[tbi setMinSize:[pmSwitchView frame].size];
|
|
||||||
[tbi setMaxSize:[pmSwitchView frame].size];
|
|
||||||
}
|
|
||||||
else if ([itemIdentifier isEqualTo:tbbScan])
|
|
||||||
{
|
|
||||||
[tbi setLabel: @"Start Scanning"];
|
|
||||||
[tbi setToolTip: @"Start scanning for duplicates in the selected directories."];
|
|
||||||
[tbi setImage: [NSImage imageNamed:[self logoImageName]]];
|
|
||||||
[tbi setTarget: self];
|
|
||||||
[tbi setAction: @selector(startDuplicateScan:)];
|
|
||||||
}
|
|
||||||
else if ([itemIdentifier isEqualTo:tbbAction])
|
|
||||||
{
|
|
||||||
[tbi setLabel: @"Action"];
|
|
||||||
[tbi setView:actionMenuView];
|
|
||||||
[tbi setMinSize:[actionMenuView frame].size];
|
|
||||||
[tbi setMaxSize:[actionMenuView frame].size];
|
|
||||||
}
|
|
||||||
else if ([itemIdentifier isEqualTo:tbbDelta])
|
|
||||||
{
|
|
||||||
[tbi setLabel: @"Delta Values"];
|
|
||||||
[tbi setToolTip: @"When enabled, this option makes dupeGuru display, where applicable, delta values instead of absolute values."];
|
|
||||||
[tbi setView:deltaSwitchView];
|
|
||||||
[tbi setMinSize:[deltaSwitchView frame].size];
|
|
||||||
[tbi setMaxSize:[deltaSwitchView frame].size];
|
|
||||||
}
|
|
||||||
else if ([itemIdentifier isEqualTo:tbbFilter])
|
|
||||||
{
|
|
||||||
[tbi setLabel: @"Filter"];
|
|
||||||
[tbi setToolTip: @"Filters the results using regular expression."];
|
|
||||||
[tbi setView:filterFieldView];
|
|
||||||
[tbi setMinSize:[filterFieldView frame].size];
|
|
||||||
[tbi setMaxSize:NSMakeSize(1000, [filterFieldView frame].size.height)];
|
|
||||||
}
|
|
||||||
[tbi setPaletteLabel: [tbi label]];
|
|
||||||
return tbi;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
|
|
||||||
{
|
|
||||||
return [NSArray arrayWithObjects:
|
|
||||||
tbbDirectories,
|
|
||||||
tbbDetails,
|
|
||||||
tbbPreferences,
|
|
||||||
tbbPowerMarker,
|
|
||||||
tbbScan,
|
|
||||||
tbbAction,
|
|
||||||
tbbDelta,
|
|
||||||
tbbFilter,
|
|
||||||
NSToolbarSeparatorItemIdentifier,
|
|
||||||
NSToolbarSpaceItemIdentifier,
|
|
||||||
NSToolbarFlexibleSpaceItemIdentifier,
|
|
||||||
nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
|
|
||||||
{
|
|
||||||
return [NSArray arrayWithObjects:
|
|
||||||
tbbScan,
|
|
||||||
tbbAction,
|
|
||||||
tbbDirectories,
|
|
||||||
tbbDetails,
|
|
||||||
tbbPowerMarker,
|
|
||||||
tbbDelta,
|
|
||||||
tbbFilter,
|
|
||||||
nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
|
|
||||||
{
|
|
||||||
return ![[ProgressController mainProgressController] isShown];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)validateMenuItem:(NSMenuItem *)item
|
|
||||||
{
|
|
||||||
return ![[ProgressController mainProgressController] isShown];
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
256
base/py/app.py
256
base/py/app.py
@@ -1,256 +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 job, 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
|
|
||||||
|
|
||||||
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):
|
|
||||||
dupe.parent = None
|
|
||||||
return True
|
|
||||||
self._recycle_dupe(dupe)
|
|
||||||
self.clean_empty_dirs(dupe.path[:-1])
|
|
||||||
if not io.exists(dupe.path):
|
|
||||||
dupe.parent = None
|
|
||||||
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):
|
|
||||||
p = Path(str_path)
|
|
||||||
for d in self.directories:
|
|
||||||
if p not in d.path:
|
|
||||||
continue
|
|
||||||
result = d.find_path(p[d.path:])
|
|
||||||
if result is not None:
|
|
||||||
return result
|
|
||||||
|
|
||||||
@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 = dupe.root.path
|
|
||||||
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,308 +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
|
|
||||||
|
|
||||||
from Foundation import *
|
|
||||||
from AppKit import *
|
|
||||||
import logging
|
|
||||||
import os.path as op
|
|
||||||
|
|
||||||
import hsfs as fs
|
|
||||||
from hsutil import io, cocoa, job
|
|
||||||
from hsutil.cocoa import install_exception_hook
|
|
||||||
from hsutil.misc import stripnone
|
|
||||||
from hsutil.reg import RegistrationRequired
|
|
||||||
|
|
||||||
import app, data
|
|
||||||
|
|
||||||
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()
|
|
||||||
if data_module is None:
|
|
||||||
data_module = data
|
|
||||||
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):
|
|
||||||
if not io.exists(dupe.path):
|
|
||||||
dupe.parent = None
|
|
||||||
return True
|
|
||||||
directory = unicode(dupe.parent.path)
|
|
||||||
filename = dupe.name
|
|
||||||
result, tag = NSWorkspace.sharedWorkspace().performFileOperation_source_destination_files_tag_(
|
|
||||||
NSWorkspaceRecycleOperation, directory, '', [filename])
|
|
||||||
if not io.exists(dupe.path):
|
|
||||||
dupe.parent = None
|
|
||||||
return True
|
|
||||||
logging.warning('Could not send %s to trash. tag: %d' % (unicode(dupe.path), tag))
|
|
||||||
return False
|
|
||||||
|
|
||||||
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 GetDirectory(self,node_path,curr_dir=None):
|
|
||||||
if not node_path:
|
|
||||||
return curr_dir
|
|
||||||
if curr_dir is not None:
|
|
||||||
l = curr_dir.dirs
|
|
||||||
else:
|
|
||||||
l = self.directories
|
|
||||||
d = l[node_path[0]]
|
|
||||||
return self.GetDirectory(node_path[1:],d)
|
|
||||||
|
|
||||||
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 = d.move(d.parent,newname)
|
|
||||||
return True
|
|
||||||
except (IndexError,fs.FSError),e:
|
|
||||||
logging.warning("dupeGuru Warning: %s" % str(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):
|
|
||||||
d = self.GetDirectory(node_path)
|
|
||||||
self.directories.set_state(d.path,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:
|
|
||||||
dirs = self.GetDirectory(node_path).dirs if node_path else self.directories
|
|
||||||
return [d.dircount for d in dirs]
|
|
||||||
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:
|
|
||||||
d = self.GetDirectory(node_path)
|
|
||||||
return [d.name, self.directories.get_state(d.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,70 +0,0 @@
|
|||||||
# Created By: Virgil Dupras
|
|
||||||
# Created On: 2009-05-24
|
|
||||||
# $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
|
|
||||||
|
|
||||||
from AppKit import *
|
|
||||||
|
|
||||||
from hsfs.phys import Directory as DirectoryBase
|
|
||||||
from hsfs.phys.bundle import Bundle
|
|
||||||
from hsutil.path import Path
|
|
||||||
from hsutil.misc import extract
|
|
||||||
from hsutil.str import get_file_ext
|
|
||||||
|
|
||||||
from . import app_cocoa, data
|
|
||||||
from .directories import Directories as DirectoriesBase, STATE_EXCLUDED
|
|
||||||
|
|
||||||
if NSWorkspace.sharedWorkspace().respondsToSelector_('typeOfFile:error:'): # Only from 10.5
|
|
||||||
def is_bundle(str_path):
|
|
||||||
sw = NSWorkspace.sharedWorkspace()
|
|
||||||
uti, error = sw.typeOfFile_error_(str_path)
|
|
||||||
if error is not None:
|
|
||||||
logging.warning(u'There was an error trying to detect the UTI of %s', str_path)
|
|
||||||
return sw.type_conformsToType_(uti, 'com.apple.bundle') or sw.type_conformsToType_(uti, 'com.apple.package')
|
|
||||||
else: # Tiger
|
|
||||||
def is_bundle(str_path): # just return a list of a few known bundle extensions.
|
|
||||||
return get_file_ext(str_path) in ('app', 'pages', 'numbers')
|
|
||||||
|
|
||||||
class DGDirectory(DirectoryBase):
|
|
||||||
def _create_sub_file(self, name, with_parent=True):
|
|
||||||
if is_bundle(unicode(self.path + name)):
|
|
||||||
parent = self if with_parent else None
|
|
||||||
return Bundle(parent, name)
|
|
||||||
else:
|
|
||||||
return super(DGDirectory, self)._create_sub_file(name, with_parent)
|
|
||||||
|
|
||||||
def _fetch_subitems(self):
|
|
||||||
subdirs, subfiles = super(DGDirectory, self)._fetch_subitems()
|
|
||||||
apps, normal_dirs = extract(lambda name: is_bundle(unicode(self.path + name)), subdirs)
|
|
||||||
subfiles += apps
|
|
||||||
return normal_dirs, subfiles
|
|
||||||
|
|
||||||
|
|
||||||
class Directories(DirectoriesBase):
|
|
||||||
ROOT_PATH_TO_EXCLUDE = map(Path, ['/Library', '/Volumes', '/System', '/bin', '/sbin', '/opt', '/private', '/dev'])
|
|
||||||
HOME_PATH_TO_EXCLUDE = [Path('Library')]
|
|
||||||
def __init__(self):
|
|
||||||
DirectoriesBase.__init__(self)
|
|
||||||
self.dirclass = DGDirectory
|
|
||||||
|
|
||||||
def _default_state_for_path(self, path):
|
|
||||||
result = DirectoriesBase._default_state_for_path(self, path)
|
|
||||||
if result is not None:
|
|
||||||
return result
|
|
||||||
if path in self.ROOT_PATH_TO_EXCLUDE:
|
|
||||||
return STATE_EXCLUDED
|
|
||||||
if path[:2] == Path('/Users') and path[3:] in self.HOME_PATH_TO_EXCLUDE:
|
|
||||||
return STATE_EXCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
class DupeGuru(app_cocoa.DupeGuru):
|
|
||||||
def __init__(self):
|
|
||||||
app_cocoa.DupeGuru.__init__(self, data, 'dupeGuru', appid=4)
|
|
||||||
self.directories = Directories()
|
|
||||||
|
|
||||||
102
base/py/data.py
102
base/py/data.py
@@ -1,102 +0,0 @@
|
|||||||
# Created By: Virgil Dupras
|
|
||||||
# Created On: 2006/03/15
|
|
||||||
# $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 hsutil.str import format_time, FT_DECIMAL, format_size
|
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
def format_path(p):
|
|
||||||
return unicode(p[:-1])
|
|
||||||
|
|
||||||
def format_timestamp(t, delta):
|
|
||||||
if delta:
|
|
||||||
return format_time(t, FT_DECIMAL)
|
|
||||||
else:
|
|
||||||
if t > 0:
|
|
||||||
return time.strftime('%Y/%m/%d %H:%M:%S', time.localtime(t))
|
|
||||||
else:
|
|
||||||
return '---'
|
|
||||||
|
|
||||||
def format_words(w):
|
|
||||||
def do_format(w):
|
|
||||||
if isinstance(w, list):
|
|
||||||
return '(%s)' % ', '.join(do_format(item) for item in w)
|
|
||||||
else:
|
|
||||||
return w.replace('\n', ' ')
|
|
||||||
|
|
||||||
return ', '.join(do_format(item) for item in w)
|
|
||||||
|
|
||||||
def format_perc(p):
|
|
||||||
return "%0.0f" % p
|
|
||||||
|
|
||||||
def format_dupe_count(c):
|
|
||||||
return str(c) if c else '---'
|
|
||||||
|
|
||||||
def cmp_value(value):
|
|
||||||
return value.lower() if isinstance(value, basestring) else value
|
|
||||||
|
|
||||||
COLUMNS = [
|
|
||||||
{'attr':'name','display':'Filename'},
|
|
||||||
{'attr':'path','display':'Directory'},
|
|
||||||
{'attr':'size','display':'Size (KB)'},
|
|
||||||
{'attr':'extension','display':'Kind'},
|
|
||||||
{'attr':'ctime','display':'Creation'},
|
|
||||||
{'attr':'mtime','display':'Modification'},
|
|
||||||
{'attr':'percentage','display':'Match %'},
|
|
||||||
{'attr':'words','display':'Words Used'},
|
|
||||||
{'attr':'dupe_count','display':'Dupe Count'},
|
|
||||||
]
|
|
||||||
|
|
||||||
METADATA_TO_READ = ['size', 'ctime', 'mtime']
|
|
||||||
|
|
||||||
def GetDisplayInfo(dupe, group, delta):
|
|
||||||
size = dupe.size
|
|
||||||
ctime = dupe.ctime
|
|
||||||
mtime = dupe.mtime
|
|
||||||
m = group.get_match_of(dupe)
|
|
||||||
if m:
|
|
||||||
percentage = m.percentage
|
|
||||||
dupe_count = 0
|
|
||||||
if delta:
|
|
||||||
r = group.ref
|
|
||||||
size -= r.size
|
|
||||||
ctime -= r.ctime
|
|
||||||
mtime -= r.mtime
|
|
||||||
else:
|
|
||||||
percentage = group.percentage
|
|
||||||
dupe_count = len(group.dupes)
|
|
||||||
return [
|
|
||||||
dupe.name,
|
|
||||||
format_path(dupe.path),
|
|
||||||
format_size(size, 0, 1, False),
|
|
||||||
dupe.extension,
|
|
||||||
format_timestamp(ctime, delta and m),
|
|
||||||
format_timestamp(mtime, delta and m),
|
|
||||||
format_perc(percentage),
|
|
||||||
format_words(dupe.words),
|
|
||||||
format_dupe_count(dupe_count)
|
|
||||||
]
|
|
||||||
|
|
||||||
def GetDupeSortKey(dupe, get_group, key, delta):
|
|
||||||
if key == 6:
|
|
||||||
m = get_group().get_match_of(dupe)
|
|
||||||
return m.percentage
|
|
||||||
if key == 8:
|
|
||||||
return 0
|
|
||||||
r = cmp_value(getattr(dupe, COLUMNS[key]['attr']))
|
|
||||||
if delta and (key in (2, 4, 5)):
|
|
||||||
r -= cmp_value(getattr(get_group().ref, COLUMNS[key]['attr']))
|
|
||||||
return r
|
|
||||||
|
|
||||||
def GetGroupSortKey(group, key):
|
|
||||||
if key == 6:
|
|
||||||
return group.percentage
|
|
||||||
if key == 8:
|
|
||||||
return len(group)
|
|
||||||
return cmp_value(getattr(group.ref, COLUMNS[key]['attr']))
|
|
||||||
@@ -1,134 +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
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
from hsutil import job
|
|
||||||
from hsutil.misc import dedupe
|
|
||||||
from hsutil.str import get_file_ext, rem_file_ext
|
|
||||||
|
|
||||||
from . import engine
|
|
||||||
from .ignore import IgnoreList
|
|
||||||
|
|
||||||
(SCAN_TYPE_FILENAME,
|
|
||||||
SCAN_TYPE_FIELDS,
|
|
||||||
SCAN_TYPE_FIELDS_NO_ORDER,
|
|
||||||
SCAN_TYPE_TAG,
|
|
||||||
UNUSED, # Must not be removed. Constants here are what scan_type in the prefs are.
|
|
||||||
SCAN_TYPE_CONTENT,
|
|
||||||
SCAN_TYPE_CONTENT_AUDIO) = range(7)
|
|
||||||
|
|
||||||
SCANNABLE_TAGS = ['track', 'artist', 'album', 'title', 'genre', 'year']
|
|
||||||
|
|
||||||
class Scanner(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.ignore_list = IgnoreList()
|
|
||||||
self.discarded_file_count = 0
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _filter_matches_by_content(matches, partial, j):
|
|
||||||
matched_files = dedupe([m.first for m in matches] + [m.second for m in matches])
|
|
||||||
md5attrname = 'md5partial' if partial else 'md5'
|
|
||||||
md5 = lambda f: getattr(f, md5attrname)
|
|
||||||
for matched_file in j.iter_with_progress(matched_files, 'Analyzed %d/%d matching files'):
|
|
||||||
md5(matched_file)
|
|
||||||
j.set_progress(100, 'Removing false matches')
|
|
||||||
return [m for m in matches if md5(m.first) == md5(m.second)]
|
|
||||||
|
|
||||||
def _getmatches(self, files, j):
|
|
||||||
j = j.start_subjob(2)
|
|
||||||
mf = engine.MatchFactory()
|
|
||||||
if self.scan_type != SCAN_TYPE_CONTENT:
|
|
||||||
mf.match_similar_words = self.match_similar_words
|
|
||||||
mf.weight_words = self.word_weighting
|
|
||||||
mf.min_match_percentage = self.min_match_percentage
|
|
||||||
if self.scan_type == SCAN_TYPE_FIELDS_NO_ORDER:
|
|
||||||
self.scan_type = SCAN_TYPE_FIELDS
|
|
||||||
mf.no_field_order = True
|
|
||||||
func = {
|
|
||||||
SCAN_TYPE_FILENAME: lambda f: engine.getwords(rem_file_ext(f.name)),
|
|
||||||
SCAN_TYPE_FIELDS: lambda f: engine.getfields(rem_file_ext(f.name)),
|
|
||||||
SCAN_TYPE_TAG: lambda f: [engine.getwords(unicode(getattr(f, attrname))) for attrname in SCANNABLE_TAGS if attrname in self.scanned_tags],
|
|
||||||
SCAN_TYPE_CONTENT: lambda f: [str(f.size)],
|
|
||||||
SCAN_TYPE_CONTENT_AUDIO: lambda f: [str(f.audiosize)]
|
|
||||||
}[self.scan_type]
|
|
||||||
for f in j.iter_with_progress(files, 'Read metadata of %d/%d files'):
|
|
||||||
if self.size_threshold:
|
|
||||||
f.size # pre-read, makes a smoother progress if read here (especially for bundles)
|
|
||||||
f.words = func(f)
|
|
||||||
if self.size_threshold:
|
|
||||||
files = [f for f in files if f.size >= self.size_threshold]
|
|
||||||
return mf.getmatches(files, j)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _key_func(dupe):
|
|
||||||
return (not dupe.is_ref, -dupe.size)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _tie_breaker(ref, dupe):
|
|
||||||
refname = rem_file_ext(ref.name).lower()
|
|
||||||
dupename = rem_file_ext(dupe.name).lower()
|
|
||||||
if 'copy' in refname and 'copy' not in dupename:
|
|
||||||
return True
|
|
||||||
if refname.startswith(dupename) and (refname[len(dupename):].strip().isdigit()):
|
|
||||||
return True
|
|
||||||
return len(dupe.path) > len(ref.path)
|
|
||||||
|
|
||||||
def GetDupeGroups(self, files, j=job.nulljob):
|
|
||||||
j = j.start_subjob([8, 2])
|
|
||||||
for f in [f for f in files if not hasattr(f, 'is_ref')]:
|
|
||||||
f.is_ref = False
|
|
||||||
logging.info('Getting matches')
|
|
||||||
if self.match_factory is None:
|
|
||||||
matches = self._getmatches(files, j)
|
|
||||||
else:
|
|
||||||
matches = self.match_factory.getmatches(files, j)
|
|
||||||
logging.info('Found %d matches' % len(matches))
|
|
||||||
if not self.mix_file_kind:
|
|
||||||
j.set_progress(100, 'Removing false matches')
|
|
||||||
matches = [m for m in matches if get_file_ext(m.first.name) == get_file_ext(m.second.name)]
|
|
||||||
if self.ignore_list:
|
|
||||||
j = j.start_subjob(2)
|
|
||||||
iter_matches = j.iter_with_progress(matches, 'Processed %d/%d matches against the ignore list')
|
|
||||||
matches = [m for m in iter_matches
|
|
||||||
if not self.ignore_list.AreIgnored(unicode(m.first.path), unicode(m.second.path))]
|
|
||||||
if self.scan_type in (SCAN_TYPE_CONTENT, SCAN_TYPE_CONTENT_AUDIO):
|
|
||||||
j = j.start_subjob(3 if self.scan_type == SCAN_TYPE_CONTENT else 2)
|
|
||||||
matches = self._filter_matches_by_content(matches, partial=True, j=j)
|
|
||||||
if self.scan_type == SCAN_TYPE_CONTENT:
|
|
||||||
matches = self._filter_matches_by_content(matches, partial=False, j=j)
|
|
||||||
# We compared md5. No words were involved.
|
|
||||||
for m in matches:
|
|
||||||
m.first.words = m.second.words = ['--']
|
|
||||||
logging.info('Grouping matches')
|
|
||||||
groups = engine.get_groups(matches, j)
|
|
||||||
matched_files = dedupe([m.first for m in matches] + [m.second for m in matches])
|
|
||||||
self.discarded_file_count = len(matched_files) - sum(len(g) for g in groups)
|
|
||||||
groups = [g for g in groups if any(not f.is_ref for f in g)]
|
|
||||||
logging.info('Created %d groups' % len(groups))
|
|
||||||
j.set_progress(100, 'Doing group prioritization')
|
|
||||||
for g in groups:
|
|
||||||
g.prioritize(self._key_func, self._tie_breaker)
|
|
||||||
return groups
|
|
||||||
|
|
||||||
match_factory = None
|
|
||||||
match_similar_words = False
|
|
||||||
min_match_percentage = 80
|
|
||||||
mix_file_kind = True
|
|
||||||
scan_type = SCAN_TYPE_FILENAME
|
|
||||||
scanned_tags = set(['artist', 'title'])
|
|
||||||
size_threshold = 0
|
|
||||||
word_weighting = False
|
|
||||||
|
|
||||||
class ScannerME(Scanner): # Scanner for Music Edition
|
|
||||||
@staticmethod
|
|
||||||
def _key_func(dupe):
|
|
||||||
return (not dupe.is_ref, -dupe.bitrate, -dupe.size)
|
|
||||||
|
|
||||||
@@ -1,371 +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
|
|
||||||
import hsfs.phys
|
|
||||||
|
|
||||||
from .results_test import GetTestGroups
|
|
||||||
from .. import engine, data
|
|
||||||
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 = Path(tempfile.mkdtemp())
|
|
||||||
fp = open(str(p + 'foo bar 1'),mode='w')
|
|
||||||
fp.close()
|
|
||||||
fp = open(str(p + 'foo bar 2'),mode='w')
|
|
||||||
fp.close()
|
|
||||||
fp = open(str(p + 'foo bar 3'),mode='w')
|
|
||||||
fp.close()
|
|
||||||
refdir = hsfs.phys.Directory(None,str(p))
|
|
||||||
matches = engine.MatchFactory().getmatches(refdir.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.refdir = refdir
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
shutil.rmtree(str(self.p))
|
|
||||||
|
|
||||||
def test_simple(self):
|
|
||||||
app = self.app
|
|
||||||
refdir = self.refdir
|
|
||||||
g = self.groups[0]
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0]))
|
|
||||||
self.assert_(app.RenameSelected('renamed'))
|
|
||||||
self.assert_('renamed' in refdir)
|
|
||||||
self.assert_('foo bar 2' not in refdir)
|
|
||||||
self.assert_(g.dupes[0] is refdir['renamed'])
|
|
||||||
self.assert_(g.dupes[0] in refdir)
|
|
||||||
|
|
||||||
def test_none_selected(self):
|
|
||||||
app = self.app
|
|
||||||
refdir = self.refdir
|
|
||||||
g = self.groups[0]
|
|
||||||
app.SelectPowerMarkerNodePaths([])
|
|
||||||
self.mock(logging, 'warning', log_calls(lambda msg: None))
|
|
||||||
self.assert_(not app.RenameSelected('renamed'))
|
|
||||||
msg = logging.warning.calls[0]['msg']
|
|
||||||
self.assertEqual('dupeGuru Warning: list index out of range', msg)
|
|
||||||
self.assert_('renamed' not in refdir)
|
|
||||||
self.assert_('foo bar 2' in refdir)
|
|
||||||
self.assert_(g.dupes[0] is refdir['foo bar 2'])
|
|
||||||
|
|
||||||
def test_name_already_exists(self):
|
|
||||||
app = self.app
|
|
||||||
refdir = self.refdir
|
|
||||||
g = self.groups[0]
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0]))
|
|
||||||
self.mock(logging, 'warning', log_calls(lambda msg: None))
|
|
||||||
self.assert_(not app.RenameSelected('foo bar 1'))
|
|
||||||
msg = logging.warning.calls[0]['msg']
|
|
||||||
self.assert_(msg.startswith('dupeGuru Warning: \'foo bar 2\' already exists in'))
|
|
||||||
self.assert_('foo bar 1' in refdir)
|
|
||||||
self.assert_('foo bar 2' in refdir)
|
|
||||||
self.assert_(g.dupes[0] is refdir['foo bar 2'])
|
|
||||||
|
|
||||||
@@ -1,132 +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 hsfs as fs
|
|
||||||
import hsfs.phys
|
|
||||||
import hsutil.files
|
|
||||||
from hsutil.job import nulljob
|
|
||||||
|
|
||||||
from .. import data, app
|
|
||||||
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.
|
|
||||||
dupe_parent = fs.Directory(None, 'foo')
|
|
||||||
dupe = fs.File(dupe_parent, 'bar')
|
|
||||||
dupe.copy = log_calls(lambda dest, newname: None)
|
|
||||||
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
|
|
||||||
self.mock(fs.phys, 'Directory', fs.Directory) # We don't want an error because makedirs didn't work
|
|
||||||
app = DupeGuru()
|
|
||||||
app.copy_or_move(dupe, 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(dupe.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')
|
|
||||||
tmpdir = hsfs.phys.Directory(None, unicode(tmppath))
|
|
||||||
myfile = tmpdir['source']['myfile']
|
|
||||||
app = DupeGuru()
|
|
||||||
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):
|
|
||||||
# At some point, any() was used in a wrong way that made Scan() wrongly return 1
|
|
||||||
app = DupeGuru()
|
|
||||||
f1, f2 = [fs.File(None, '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,469 +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
|
|
||||||
from hsutil.path import Path
|
|
||||||
|
|
||||||
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
|
|
||||||
def test_empty():
|
|
||||||
s = Scanner()
|
|
||||||
r = s.GetDupeGroups([])
|
|
||||||
eq_(r, [])
|
|
||||||
|
|
||||||
def test_default_settings():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
# 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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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]
|
|
||||||
eq_(g.ref.words, ['--'])
|
|
||||||
eq_(g.dupes[0].words, ['--'])
|
|
||||||
|
|
||||||
def test_extension_is_not_counted_in_filename_scan():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
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():
|
|
||||||
#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_custom_match_factory():
|
|
||||||
class MatchFactory(object):
|
|
||||||
def getmatches(self, objects, j=None):
|
|
||||||
return [Match(objects[0], objects[1], 420)]
|
|
||||||
|
|
||||||
|
|
||||||
s = Scanner()
|
|
||||||
s.match_factory = MatchFactory()
|
|
||||||
o1, o2 = no('foo'), no('bar')
|
|
||||||
groups = s.GetDupeGroups([o1, o2])
|
|
||||||
eq_(len(groups), 1)
|
|
||||||
g = groups[0]
|
|
||||||
eq_(len(g), 2)
|
|
||||||
g.switch_ref(o1)
|
|
||||||
m = g.get_match_of(o2)
|
|
||||||
eq_(m, (o1, o2, 420))
|
|
||||||
|
|
||||||
def test_file_evaluates_to_false():
|
|
||||||
# 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():
|
|
||||||
# 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():
|
|
||||||
# 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():
|
|
||||||
# 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():
|
|
||||||
# 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():
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
|
|
||||||
#--- Scanner ME
|
|
||||||
def test_priorize_me():
|
|
||||||
# in ScannerME, bitrate goes first (right after is_ref) in priorization
|
|
||||||
s = ScannerME()
|
|
||||||
o1, o2 = no('foo'), no('foo')
|
|
||||||
o1.bitrate = 1
|
|
||||||
o2.bitrate = 2
|
|
||||||
[group] = s.GetDupeGroups([o1, o2])
|
|
||||||
assert group.ref is o2
|
|
||||||
|
|
||||||
@@ -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.
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# Created By: Virgil Dupras
|
|
||||||
# Created On: 2009-05-09
|
|
||||||
# $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, SIGNAL
|
|
||||||
from PyQt4.QtGui import QDialog, QDialogButtonBox, QPixmap
|
|
||||||
|
|
||||||
from about_box_ui import Ui_AboutBox
|
|
||||||
|
|
||||||
class AboutBox(QDialog, Ui_AboutBox):
|
|
||||||
def __init__(self, parent, app):
|
|
||||||
flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.MSWindowsFixedSizeDialogHint
|
|
||||||
QDialog.__init__(self, parent, flags)
|
|
||||||
self.app = app
|
|
||||||
self._setupUi()
|
|
||||||
|
|
||||||
self.connect(self.buttonBox, SIGNAL('clicked(QAbstractButton*)'), self.buttonClicked)
|
|
||||||
|
|
||||||
def _setupUi(self):
|
|
||||||
self.setupUi(self)
|
|
||||||
# Stuff that can't be done in the Designer
|
|
||||||
self.setWindowTitle(u"About %s" % QCoreApplication.instance().applicationName())
|
|
||||||
self.nameLabel.setText(QCoreApplication.instance().applicationName())
|
|
||||||
self.versionLabel.setText('Version ' + QCoreApplication.instance().applicationVersion())
|
|
||||||
self.logoLabel.setPixmap(QPixmap(':/%s_big' % self.app.LOGO_NAME))
|
|
||||||
self.registerButton = self.buttonBox.addButton("Register", QDialogButtonBox.ActionRole)
|
|
||||||
|
|
||||||
#--- Events
|
|
||||||
def buttonClicked(self, button):
|
|
||||||
if button is self.registerButton:
|
|
||||||
self.app.ask_for_reg_code()
|
|
||||||
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>AboutBox</class>
|
|
||||||
<widget class="QDialog" name="AboutBox">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>190</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>About dupeGuru</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="logoLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="pixmap">
|
|
||||||
<pixmap resource="dg.qrc">:/logo_me_big</pixmap>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="nameLabel">
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>dupeGuru</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="versionLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Version</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>Copyright Hardcoded Software 2009</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Registered To:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="registeredEmailLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>UNREGISTERED</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="standardButtons">
|
|
||||||
<set>QDialogButtonBox::Ok</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources>
|
|
||||||
<include location="dg.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections>
|
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>accepted()</signal>
|
|
||||||
<receiver>AboutBox</receiver>
|
|
||||||
<slot>accept()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>248</x>
|
|
||||||
<y>254</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>157</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>rejected()</signal>
|
|
||||||
<receiver>AboutBox</receiver>
|
|
||||||
<slot>reject()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>316</x>
|
|
||||||
<y>260</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>286</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
|
||||||
@@ -1,17 +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="gear">images/gear.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,133 +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="editTriggers">
|
|
||||||
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
|
|
||||||
</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>
|
|
||||||
</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,106 +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 QModelIndex, Qt, QRect, QEvent, QPoint
|
|
||||||
from PyQt4.QtGui import QComboBox, QStyledItemDelegate, QMouseEvent, QApplication, QBrush
|
|
||||||
|
|
||||||
from qtlib.tree_model import TreeNode, TreeModel
|
|
||||||
|
|
||||||
HEADERS = ['Name', 'State']
|
|
||||||
STATES = ['Normal', 'Reference', 'Excluded']
|
|
||||||
|
|
||||||
class DirectoriesDelegate(QStyledItemDelegate):
|
|
||||||
def createEditor(self, parent, option, index):
|
|
||||||
editor = QComboBox(parent);
|
|
||||||
editor.addItems(STATES)
|
|
||||||
return editor
|
|
||||||
|
|
||||||
def setEditorData(self, editor, index):
|
|
||||||
value = index.model().data(index, Qt.EditRole)
|
|
||||||
editor.setCurrentIndex(value);
|
|
||||||
press = QMouseEvent(QEvent.MouseButtonPress, QPoint(0, 0), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
|
|
||||||
release = QMouseEvent(QEvent.MouseButtonRelease, QPoint(0, 0), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
|
|
||||||
QApplication.sendEvent(editor, press)
|
|
||||||
QApplication.sendEvent(editor, release)
|
|
||||||
# editor.showPopup() # this causes a weird glitch. the ugly workaround is above.
|
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
|
||||||
value = editor.currentIndex()
|
|
||||||
model.setData(index, value, Qt.EditRole)
|
|
||||||
|
|
||||||
def updateEditorGeometry(self, editor, option, index):
|
|
||||||
editor.setGeometry(option.rect)
|
|
||||||
|
|
||||||
|
|
||||||
class DirectoryNode(TreeNode):
|
|
||||||
def __init__(self, model, parent, ref, row):
|
|
||||||
TreeNode.__init__(self, model, parent, row)
|
|
||||||
self.ref = ref
|
|
||||||
|
|
||||||
def _createNode(self, ref, row):
|
|
||||||
return DirectoryNode(self.model, self, ref, row)
|
|
||||||
|
|
||||||
def _getChildren(self):
|
|
||||||
return self.ref.dirs
|
|
||||||
|
|
||||||
|
|
||||||
class DirectoriesModel(TreeModel):
|
|
||||||
def __init__(self, app):
|
|
||||||
self._dirs = app.directories
|
|
||||||
TreeModel.__init__(self)
|
|
||||||
|
|
||||||
def _createNode(self, ref, row):
|
|
||||||
return DirectoryNode(self, None, ref, row)
|
|
||||||
|
|
||||||
def _getChildren(self):
|
|
||||||
return self._dirs
|
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return 2
|
|
||||||
|
|
||||||
def data(self, index, role):
|
|
||||||
if not index.isValid():
|
|
||||||
return None
|
|
||||||
node = index.internalPointer()
|
|
||||||
if role == Qt.DisplayRole:
|
|
||||||
if index.column() == 0:
|
|
||||||
return node.ref.name
|
|
||||||
else:
|
|
||||||
return STATES[self._dirs.get_state(node.ref.path)]
|
|
||||||
elif role == Qt.EditRole and index.column() == 1:
|
|
||||||
return self._dirs.get_state(node.ref.path)
|
|
||||||
elif role == Qt.ForegroundRole:
|
|
||||||
state = self._dirs.get_state(node.ref.path)
|
|
||||||
if state == 1:
|
|
||||||
return QBrush(Qt.blue)
|
|
||||||
elif state == 2:
|
|
||||||
return QBrush(Qt.red)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
if not index.isValid():
|
|
||||||
return 0
|
|
||||||
result = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
||||||
if index.column() == 1:
|
|
||||||
result |= Qt.ItemIsEditable
|
|
||||||
return result
|
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if orientation == Qt.Horizontal:
|
|
||||||
if role == Qt.DisplayRole and section < len(HEADERS):
|
|
||||||
return HEADERS[section]
|
|
||||||
return None
|
|
||||||
|
|
||||||
def setData(self, index, value, role):
|
|
||||||
if not index.isValid() or role != Qt.EditRole or index.column() != 1:
|
|
||||||
return False
|
|
||||||
node = index.internalPointer()
|
|
||||||
self._dirs.set_state(node.ref.path, value)
|
|
||||||
return True
|
|
||||||
|
|
||||||
@@ -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,36 +0,0 @@
|
|||||||
# Created By: Virgil Dupras
|
|
||||||
# Created On: 2009-05-09
|
|
||||||
# $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 hashlib import md5
|
|
||||||
|
|
||||||
from PyQt4.QtGui import QDialog
|
|
||||||
|
|
||||||
from reg_submit_dialog import RegSubmitDialog
|
|
||||||
from reg_demo_dialog import RegDemoDialog
|
|
||||||
|
|
||||||
class Registration(object):
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
|
|
||||||
def ask_for_code(self):
|
|
||||||
dialog = RegSubmitDialog(self.app.main_window, self.app.is_code_valid)
|
|
||||||
result = dialog.exec_()
|
|
||||||
code = unicode(dialog.codeEdit.text())
|
|
||||||
email = unicode(dialog.emailEdit.text())
|
|
||||||
dialog.setParent(None) # free it
|
|
||||||
if result == QDialog.Accepted and self.app.is_code_valid(code, email):
|
|
||||||
self.app.set_registration(code, email)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def show_nag(self):
|
|
||||||
dialog = RegDemoDialog(self.app.main_window, self)
|
|
||||||
dialog.exec_()
|
|
||||||
dialog.setParent(None) # free it
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
# Created By: Virgil Dupras
|
|
||||||
# Created On: 2009-05-10
|
|
||||||
# $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, QUrl, QCoreApplication
|
|
||||||
from PyQt4.QtGui import QDialog, QMessageBox, QDesktopServices
|
|
||||||
|
|
||||||
from reg_demo_dialog_ui import Ui_RegDemoDialog
|
|
||||||
|
|
||||||
class RegDemoDialog(QDialog, Ui_RegDemoDialog):
|
|
||||||
def __init__(self, parent, reg):
|
|
||||||
flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint
|
|
||||||
QDialog.__init__(self, parent, flags)
|
|
||||||
self.reg = reg
|
|
||||||
self._setupUi()
|
|
||||||
|
|
||||||
self.connect(self.enterCodeButton, SIGNAL('clicked()'), self.enterCodeClicked)
|
|
||||||
self.connect(self.purchaseButton, SIGNAL('clicked()'), self.purchaseClicked)
|
|
||||||
|
|
||||||
def _setupUi(self):
|
|
||||||
self.setupUi(self)
|
|
||||||
# Stuff that can't be setup in the Designer
|
|
||||||
appname = QCoreApplication.instance().applicationName()
|
|
||||||
title = self.windowTitle()
|
|
||||||
title = title.replace('$appname', appname)
|
|
||||||
self.setWindowTitle(title)
|
|
||||||
title = self.titleLabel.text()
|
|
||||||
title = title.replace('$appname', appname)
|
|
||||||
self.titleLabel.setText(title)
|
|
||||||
desc = self.demoDescLabel.text()
|
|
||||||
desc = desc.replace('$appname', appname)
|
|
||||||
self.demoDescLabel.setText(desc)
|
|
||||||
|
|
||||||
#--- Events
|
|
||||||
def enterCodeClicked(self):
|
|
||||||
if self.reg.ask_for_code():
|
|
||||||
self.accept()
|
|
||||||
|
|
||||||
def purchaseClicked(self):
|
|
||||||
url = QUrl('http://www.hardcoded.net/purchase.htm')
|
|
||||||
QDesktopServices.openUrl(url)
|
|
||||||
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>RegDemoDialog</class>
|
|
||||||
<widget class="QDialog" name="RegDemoDialog">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>387</width>
|
|
||||||
<height>161</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>$appname Demo Version</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="titleLabel">
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>$appname Demo Version</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="demoDescLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>You are currently running a demo version of $appname. This version has limited functionalities, and you need to buy it to have access to these functionalities.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>In the demo version, only 10 duplicates per session can be sent to the recycle bin, moved or copied.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</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="tryButton">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>110</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Try Demo</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="enterCodeButton">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>110</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Enter Code</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="purchaseButton">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>110</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Purchase</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections>
|
|
||||||
<connection>
|
|
||||||
<sender>tryButton</sender>
|
|
||||||
<signal>clicked()</signal>
|
|
||||||
<receiver>RegDemoDialog</receiver>
|
|
||||||
<slot>accept()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>112</x>
|
|
||||||
<y>161</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>201</x>
|
|
||||||
<y>94</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
# Created By: Virgil Dupras
|
|
||||||
# Created On: 2009-05-09
|
|
||||||
# $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, QUrl, QCoreApplication
|
|
||||||
from PyQt4.QtGui import QDialog, QMessageBox, QDesktopServices
|
|
||||||
|
|
||||||
from reg_submit_dialog_ui import Ui_RegSubmitDialog
|
|
||||||
|
|
||||||
class RegSubmitDialog(QDialog, Ui_RegSubmitDialog):
|
|
||||||
def __init__(self, parent, is_valid_func):
|
|
||||||
flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint
|
|
||||||
QDialog.__init__(self, parent, flags)
|
|
||||||
self._setupUi()
|
|
||||||
self.is_valid_func = is_valid_func
|
|
||||||
|
|
||||||
self.connect(self.submitButton, SIGNAL('clicked()'), self.submitClicked)
|
|
||||||
self.connect(self.purchaseButton, SIGNAL('clicked()'), self.purchaseClicked)
|
|
||||||
|
|
||||||
def _setupUi(self):
|
|
||||||
self.setupUi(self)
|
|
||||||
# Stuff that can't be setup in the Designer
|
|
||||||
appname = QCoreApplication.instance().applicationName()
|
|
||||||
prompt = self.promptLabel.text()
|
|
||||||
prompt = prompt.replace('$appname', appname)
|
|
||||||
self.promptLabel.setText(prompt)
|
|
||||||
|
|
||||||
#--- Events
|
|
||||||
def purchaseClicked(self):
|
|
||||||
url = QUrl('http://www.hardcoded.net/purchase.htm')
|
|
||||||
QDesktopServices.openUrl(url)
|
|
||||||
|
|
||||||
def submitClicked(self):
|
|
||||||
code = unicode(self.codeEdit.text())
|
|
||||||
email = unicode(self.emailEdit.text())
|
|
||||||
title = "Registration"
|
|
||||||
if self.is_valid_func(code, email):
|
|
||||||
msg = "This code is valid. Thanks!"
|
|
||||||
QMessageBox.information(self, title, msg)
|
|
||||||
self.accept()
|
|
||||||
else:
|
|
||||||
msg = "This code is invalid"
|
|
||||||
QMessageBox.warning(self, title, msg)
|
|
||||||
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>RegSubmitDialog</class>
|
|
||||||
<widget class="QDialog" name="RegSubmitDialog">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>365</width>
|
|
||||||
<height>134</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Enter your registration code</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="promptLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Please enter your $appname registration code and registered e-mail (the e-mail you used for the purchase), then press "Submit".</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QFormLayout" name="formLayout">
|
|
||||||
<property name="sizeConstraint">
|
|
||||||
<enum>QLayout::SetNoConstraint</enum>
|
|
||||||
</property>
|
|
||||||
<property name="fieldGrowthPolicy">
|
|
||||||
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
|
||||||
</property>
|
|
||||||
<property name="labelAlignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
<property name="formAlignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
|
||||||
</property>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Registration code:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>Registered e-mail:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLineEdit" name="codeEdit"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLineEdit" name="emailEdit"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="purchaseButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Purchase</string>
|
|
||||||
</property>
|
|
||||||
<property name="autoDefault">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<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="cancelButton">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Cancel</string>
|
|
||||||
</property>
|
|
||||||
<property name="autoDefault">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="submitButton">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Submit</string>
|
|
||||||
</property>
|
|
||||||
<property name="autoDefault">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="default">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections>
|
|
||||||
<connection>
|
|
||||||
<sender>cancelButton</sender>
|
|
||||||
<signal>clicked()</signal>
|
|
||||||
<receiver>RegSubmitDialog</receiver>
|
|
||||||
<slot>reject()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>260</x>
|
|
||||||
<y>159</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>198</x>
|
|
||||||
<y>97</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
|
||||||
@@ -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.reset()
|
|
||||||
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())
|
|
||||||
|
|
||||||
148
build.py
Normal file
148
build.py
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# 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 sys
|
||||||
|
import os
|
||||||
|
import os.path as op
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
from distutils.extension import Extension
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from hscommon import helpgen
|
||||||
|
from hscommon.build import add_to_pythonpath, print_and_do, build_all_qt_ui, copy_packages
|
||||||
|
|
||||||
|
def build_cocoa(edition, dev, help_destpath):
|
||||||
|
if not dev:
|
||||||
|
print("Building help index")
|
||||||
|
os.system('open -a /Developer/Applications/Utilities/Help\\ Indexer.app {0}'.format(help_destpath))
|
||||||
|
|
||||||
|
print("Building dg_cocoa.plugin")
|
||||||
|
if op.exists('build'):
|
||||||
|
shutil.rmtree('build')
|
||||||
|
os.mkdir('build')
|
||||||
|
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')
|
||||||
|
script_args = ['py2app', '-A'] if dev else ['py2app']
|
||||||
|
setup(
|
||||||
|
script_args = script_args,
|
||||||
|
plugin = ['dg_cocoa.py'],
|
||||||
|
setup_requires = ['py2app'],
|
||||||
|
)
|
||||||
|
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("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 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_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 main():
|
||||||
|
conf = yaml.load(open('conf.yaml'))
|
||||||
|
edition = conf['edition']
|
||||||
|
ui = conf['ui']
|
||||||
|
dev = conf['dev']
|
||||||
|
print("Building dupeGuru {0} with UI {1}".format(edition.upper(), ui))
|
||||||
|
if dev:
|
||||||
|
print("Building in Dev mode")
|
||||||
|
add_to_pythonpath('.')
|
||||||
|
print("Generating Help")
|
||||||
|
windows = sys.platform == 'win32'
|
||||||
|
profile = 'win_en' if windows else 'osx_en'
|
||||||
|
help_dir = 'help_{0}'.format(edition)
|
||||||
|
dest_dir = 'dupeguru_{0}_help'.format(edition) if edition != 'se' else 'dupeguru_help'
|
||||||
|
help_basepath = op.abspath(help_dir)
|
||||||
|
help_destpath = op.abspath(op.join(help_dir, dest_dir))
|
||||||
|
helpgen.gen(help_basepath, help_destpath, profile=profile)
|
||||||
|
print("Building dupeGuru")
|
||||||
|
if edition == 'pe':
|
||||||
|
build_pe_modules(ui)
|
||||||
|
if ui == 'cocoa':
|
||||||
|
build_cocoa(edition, dev, help_destpath)
|
||||||
|
elif ui == 'qt':
|
||||||
|
build_qt(edition, dev)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
31
cocoa/base/AppDelegate.h
Normal file
31
cocoa/base/AppDelegate.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
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 "RecentDirectories.h"
|
||||||
|
#import "PyDupeGuru.h"
|
||||||
|
#import "ResultWindow.h"
|
||||||
|
#import "DetailsPanel.h"
|
||||||
|
#import "DirectoryPanel.h"
|
||||||
|
|
||||||
|
@interface AppDelegateBase : NSObject
|
||||||
|
{
|
||||||
|
IBOutlet PyDupeGuruBase *py;
|
||||||
|
IBOutlet RecentDirectories *recentDirectories;
|
||||||
|
IBOutlet ResultWindowBase *result;
|
||||||
|
|
||||||
|
DirectoryPanel *_directoryPanel;
|
||||||
|
DetailsPanel *_detailsPanel;
|
||||||
|
BOOL _savedResults;
|
||||||
|
}
|
||||||
|
- (PyDupeGuruBase *)py;
|
||||||
|
- (RecentDirectories *)recentDirectories;
|
||||||
|
- (DirectoryPanel *)directoryPanel;
|
||||||
|
- (DetailsPanel *)detailsPanel;
|
||||||
|
- (void)saveResults;
|
||||||
|
@end
|
||||||
102
cocoa/base/AppDelegate.m
Normal file
102
cocoa/base/AppDelegate.m
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
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 "Utils.h"
|
||||||
|
#import "Consts.h"
|
||||||
|
#import <Sparkle/SUUpdater.h>
|
||||||
|
|
||||||
|
@implementation AppDelegateBase
|
||||||
|
- (PyDupeGuruBase *)py { return py; }
|
||||||
|
- (RecentDirectories *)recentDirectories { return recentDirectories; }
|
||||||
|
- (DirectoryPanel *)directoryPanel
|
||||||
|
{
|
||||||
|
if (!_directoryPanel)
|
||||||
|
_directoryPanel = [[DirectoryPanel alloc] initWithParentApp:self];
|
||||||
|
return _directoryPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (DetailsPanel *)detailsPanel
|
||||||
|
{
|
||||||
|
if (!_detailsPanel)
|
||||||
|
_detailsPanel = [[DetailsPanel alloc] initWithPy:py];
|
||||||
|
return _detailsPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)saveResults
|
||||||
|
{
|
||||||
|
if (_savedResults) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[py saveIgnoreList];
|
||||||
|
[py saveResults];
|
||||||
|
_savedResults = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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];
|
||||||
|
[HSFairwareReminder showNagWithApp:[self py]];
|
||||||
|
//Restore results
|
||||||
|
[py loadIgnoreList];
|
||||||
|
[py loadResults];
|
||||||
|
_savedResults = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillBecomeActive:(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"];
|
||||||
|
[self saveResults];
|
||||||
|
NSInteger 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SUUpdater delegate */
|
||||||
|
|
||||||
|
- (BOOL)updater:(SUUpdater *)updater shouldPostponeRelaunchForUpdate:(SUAppcastItem *)update untilInvoking:(NSInvocation *)invocation;
|
||||||
|
{
|
||||||
|
/* If results aren't saved now, we might get a weird utf-8 lookup error when saving later.
|
||||||
|
**/
|
||||||
|
[self saveResults];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
@end
|
||||||
18
cocoa/base/Consts.h
Normal file
18
cocoa/base/Consts.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>
|
||||||
|
|
||||||
|
#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"
|
||||||
25
cocoa/base/DetailsPanel.h
Normal file
25
cocoa/base/DetailsPanel.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 "PyDetailsPanel.h"
|
||||||
|
|
||||||
|
@interface DetailsPanel : HSWindowController
|
||||||
|
{
|
||||||
|
IBOutlet NSTableView *detailsTable;
|
||||||
|
}
|
||||||
|
- (id)initWithPy:(PyApp *)aPy;
|
||||||
|
- (PyDetailsPanel *)py;
|
||||||
|
|
||||||
|
- (void)toggleVisibility;
|
||||||
|
|
||||||
|
/* Python --> Cocoa */
|
||||||
|
- (void)refresh;
|
||||||
|
@end
|
||||||
66
cocoa/base/DetailsPanel.m
Normal file
66
cocoa/base/DetailsPanel.m
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)toggleVisibility
|
||||||
|
{
|
||||||
|
if ([[self window] 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
|
||||||
16
cocoa/base/DirectoryOutline.h
Normal file
16
cocoa/base/DirectoryOutline.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 "HSOutline.h"
|
||||||
|
#import "PyDirectoryOutline.h"
|
||||||
|
|
||||||
|
@interface DirectoryOutline : HSOutline {}
|
||||||
|
- (id)initWithPyParent:(id)aPyParent view:(HSOutlineView *)aOutlineView;
|
||||||
|
- (PyDirectoryOutline *)py;
|
||||||
|
@end;
|
||||||
84
cocoa/base/DirectoryOutline.m
Normal file
84
cocoa/base/DirectoryOutline.m
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
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 *filenames = [pboard propertyListForType:NSFilenamesPboardType];
|
||||||
|
if (!(sourceDragMask & NSDragOperationLink))
|
||||||
|
return NO;
|
||||||
|
for (NSString *filename in filenames) {
|
||||||
|
[[self py] addDirectory:filename];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
@@ -1,29 +1,30 @@
|
|||||||
/*
|
/*
|
||||||
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
|
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 <Cocoa/Cocoa.h>
|
||||||
#import "RecentDirectories.h"
|
#import "RecentDirectories.h"
|
||||||
#import "Outline.h"
|
#import "HSOutlineView.h"
|
||||||
|
#import "DirectoryOutline.h"
|
||||||
#import "PyDupeGuru.h"
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
@interface DirectoryPanelBase : NSWindowController
|
@interface DirectoryPanel : NSWindowController
|
||||||
{
|
{
|
||||||
IBOutlet NSPopUpButton *addButtonPopUp;
|
IBOutlet NSPopUpButton *addButtonPopUp;
|
||||||
IBOutlet OutlineView *directories;
|
IBOutlet HSOutlineView *outlineView;
|
||||||
IBOutlet NSButton *removeButton;
|
IBOutlet NSButton *removeButton;
|
||||||
|
|
||||||
PyDupeGuruBase *_py;
|
PyDupeGuruBase *_py;
|
||||||
RecentDirectories *_recentDirectories;
|
RecentDirectories *_recentDirectories;
|
||||||
|
DirectoryOutline *outline;
|
||||||
}
|
}
|
||||||
- (id)initWithParentApp:(id)aParentApp;
|
- (id)initWithParentApp:(id)aParentApp;
|
||||||
|
|
||||||
- (IBAction)askForDirectory:(id)sender;
|
- (IBAction)askForDirectory:(id)sender;
|
||||||
- (IBAction)changeDirectoryState:(id)sender;
|
|
||||||
- (IBAction)popupAddDirectoryMenu:(id)sender;
|
- (IBAction)popupAddDirectoryMenu:(id)sender;
|
||||||
- (IBAction)removeSelectedDirectory:(id)sender;
|
- (IBAction)removeSelectedDirectory:(id)sender;
|
||||||
- (IBAction)toggleVisible:(id)sender;
|
- (IBAction)toggleVisible:(id)sender;
|
||||||
138
cocoa/base/DirectoryPanel.m
Normal file
138
cocoa/base/DirectoryPanel.m
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
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"
|
||||||
|
|
||||||
|
@implementation DirectoryPanel
|
||||||
|
- (id)initWithParentApp:(id)aParentApp
|
||||||
|
{
|
||||||
|
self = [super initWithWindowNibName:@"DirectoryPanel"];
|
||||||
|
[self window];
|
||||||
|
AppDelegateBase *app = aParentApp;
|
||||||
|
_py = [app py];
|
||||||
|
_recentDirectories = [app recentDirectories];
|
||||||
|
outline = [[DirectoryOutline alloc] initWithPyParent:_py view:outlineView];
|
||||||
|
[self refreshRemoveButtonText];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(directorySelectionChanged:)
|
||||||
|
name:NSOutlineViewSelectionDidChangeNotification object:outlineView];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[outline release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actions */
|
||||||
|
|
||||||
|
- (IBAction)askForDirectory:(id)sender
|
||||||
|
{
|
||||||
|
NSOpenPanel *op = [NSOpenPanel openPanel];
|
||||||
|
[op setCanChooseFiles:YES];
|
||||||
|
[op setCanChooseDirectories:YES];
|
||||||
|
[op setAllowsMultipleSelection:YES];
|
||||||
|
[op setTitle:@"Select a directory to add to the scanning list"];
|
||||||
|
[op setDelegate:self];
|
||||||
|
if ([op runModal] == NSOKButton) {
|
||||||
|
for (NSString *directory in [op filenames]) {
|
||||||
|
[self addDirectory:directory];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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 ([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];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)toggleVisible:(id)sender
|
||||||
|
{
|
||||||
|
[[self window] makeKeyAndOrderFront:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public */
|
||||||
|
- (void)addDirectory:(NSString *)directory
|
||||||
|
{
|
||||||
|
NSInteger r = [[_py addDirectory:directory] intValue];
|
||||||
|
if (r) {
|
||||||
|
NSString *m = @"";
|
||||||
|
if (r == 1) {
|
||||||
|
m = @"'%@' already is in the list.";
|
||||||
|
}
|
||||||
|
else if (r == 2) {
|
||||||
|
m = @"'%@' does not exist.";
|
||||||
|
}
|
||||||
|
[Dialogs showMessage:[NSString stringWithFormat:m,directory]];
|
||||||
|
}
|
||||||
|
[_recentDirectories addDirectory: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 *buttonText = state == 2 ? @"Put Back" : @"Remove";
|
||||||
|
[removeButton setTitle:buttonText];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delegate */
|
||||||
|
- (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
|
||||||
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)loadResults;
|
||||||
|
- (void)loadResultsFrom:(NSString *)filename;
|
||||||
|
- (void)saveResults;
|
||||||
|
- (void)saveResultsAs:(NSString *)filename;
|
||||||
|
- (void)loadIgnoreList;
|
||||||
|
- (void)saveIgnoreList;
|
||||||
|
- (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;
|
||||||
|
|
||||||
|
//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
|
||||||
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;
|
||||||
162
cocoa/base/ResultTable.m
Normal file
162
cocoa/base/ResultTable.m
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
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 *msg = [NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",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:@"The name '%@' already exists.", 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
|
||||||
78
cocoa/base/ResultWindow.h
Normal file
78
cocoa/base/ResultWindow.h
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
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"
|
||||||
|
|
||||||
|
@interface ResultWindowBase : NSWindowController
|
||||||
|
{
|
||||||
|
@protected
|
||||||
|
IBOutlet PyDupeGuruBase *py;
|
||||||
|
IBOutlet id app;
|
||||||
|
IBOutlet NSSegmentedControl *deltaSwitch;
|
||||||
|
IBOutlet HSTableView *matches;
|
||||||
|
IBOutlet NSSegmentedControl *pmSwitch;
|
||||||
|
IBOutlet NSTextField *stats;
|
||||||
|
IBOutlet NSMenu *columnsMenu;
|
||||||
|
IBOutlet NSSearchField *filterField;
|
||||||
|
|
||||||
|
NSMutableArray *_resultColumns;
|
||||||
|
NSWindowController *preferencesPanel;
|
||||||
|
ResultTable *table;
|
||||||
|
StatsLabel *statsLabel;
|
||||||
|
ProblemDialog *problemDialog;
|
||||||
|
}
|
||||||
|
/* Helpers */
|
||||||
|
- (void)fillColumnsMenu;
|
||||||
|
- (NSTableColumn *)getColumnForIdentifier:(NSInteger)aIdentifier title:(NSString *)aTitle width:(NSInteger)aWidth refCol:(NSTableColumn *)aColumn;
|
||||||
|
- (NSArray *)getColumnsOrder;
|
||||||
|
- (NSDictionary *)getColumnsWidth;
|
||||||
|
- (void)initResultColumns;
|
||||||
|
- (void)restoreColumnsPosition:(NSArray *)aColumnsOrder widths:(NSDictionary *)aColumnsWidth;
|
||||||
|
- (void)sendMarkedToTrash:(BOOL)hardlinkDeleted;
|
||||||
|
|
||||||
|
/* Actions */
|
||||||
|
- (IBAction)clearIgnoreList:(id)sender;
|
||||||
|
- (IBAction)changeDelta:(id)sender;
|
||||||
|
- (IBAction)changePowerMarker:(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)loadResults:(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)showPreferencesPanel:(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
|
||||||
474
cocoa/base/ResultWindow.m
Normal file
474
cocoa/base/ResultWindow.m
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
- (void)awakeFromNib
|
||||||
|
{
|
||||||
|
[self window];
|
||||||
|
/* Put a cute iTunes-like bottom bar */
|
||||||
|
[[self window] setContentBorderThickness:28 forEdge:NSMinYEdge];
|
||||||
|
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
||||||
|
table = [[ResultTable alloc] initWithPyParent:py view:matches];
|
||||||
|
statsLabel = [[StatsLabel alloc] initWithPyParent:py labelView:stats];
|
||||||
|
problemDialog = [[ProblemDialog alloc] initWithPy:py];
|
||||||
|
[self initResultColumns];
|
||||||
|
[self fillColumnsMenu];
|
||||||
|
[deltaSwitch setSelectedSegment:0];
|
||||||
|
[pmSwitch setSelectedSegment:0];
|
||||||
|
[matches setTarget:self];
|
||||||
|
[matches setDoubleAction:@selector(openClicked:)];
|
||||||
|
|
||||||
|
[[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];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[table release];
|
||||||
|
[preferencesPanel release];
|
||||||
|
[statsLabel release];
|
||||||
|
[problemDialog 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:(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)initResultColumns
|
||||||
|
{
|
||||||
|
// Virtual
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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 = @"You are about to send %d files to Trash. Continue?";
|
||||||
|
if (hardlinkDeleted) {
|
||||||
|
msg = @"You are about to send %d files to Trash (and hardlink them afterwards). Continue?";
|
||||||
|
}
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actions */
|
||||||
|
- (IBAction)clearIgnoreList:(id)sender
|
||||||
|
{
|
||||||
|
NSInteger i = n2i([py getIgnoreListCount]);
|
||||||
|
if (!i)
|
||||||
|
return;
|
||||||
|
if ([Dialogs askYesNo:[NSString stringWithFormat:@"Do you really want to remove all %d items from the ignore list?",i]] == NSAlertSecondButtonReturn) // NO
|
||||||
|
return;
|
||||||
|
[py clearIgnoreList];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)changeDelta:(id)sender
|
||||||
|
{
|
||||||
|
[table setDeltaValuesMode:[deltaSwitch selectedSegment] == 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)changePowerMarker:(id)sender
|
||||||
|
{
|
||||||
|
[table setPowerMarkerMode:[pmSwitch selectedSegment] == 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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:@"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
|
||||||
|
{
|
||||||
|
[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:@"All selected %d matches are going to be ignored in all subsequent scans. Continue?",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:@"You have no custom command set up. Set it up in your preferences."];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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:@"Select a results file to load"];
|
||||||
|
if ([op runModal] == NSOKButton) {
|
||||||
|
NSString *filename = [[op filenames] objectAtIndex:0];
|
||||||
|
[py loadResultsFrom:filename];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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:@"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: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;
|
||||||
|
if ([Dialogs askYesNo:[NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",mark_count]] == 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)showPreferencesPanel:(id)sender
|
||||||
|
{
|
||||||
|
[preferencesPanel showWindow:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)saveResults:(id)sender
|
||||||
|
{
|
||||||
|
NSSavePanel *sp = [NSSavePanel savePanel];
|
||||||
|
[sp setCanCreateDirectories:YES];
|
||||||
|
[sp setAllowedFileTypes:[NSArray arrayWithObject:@"dupeguru"]];
|
||||||
|
[sp setTitle:@"Select a file to save your results to"];
|
||||||
|
if ([sp runModal] == NSOKButton) {
|
||||||
|
[py saveResultsAs:[sp filename]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)startDuplicateScan:(id)sender
|
||||||
|
{
|
||||||
|
// Virtual
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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)toggleDelta:(id)sender
|
||||||
|
{
|
||||||
|
if ([deltaSwitch selectedSegment] == 1)
|
||||||
|
[deltaSwitch setSelectedSegment:0];
|
||||||
|
else
|
||||||
|
[deltaSwitch setSelectedSegment:1];
|
||||||
|
[self changeDelta:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notifications */
|
||||||
|
- (void)windowWillClose:(NSNotification *)aNotification
|
||||||
|
{
|
||||||
|
[NSApp hide:NSApp];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)jobCompleted:(NSNotification *)aNotification
|
||||||
|
{
|
||||||
|
id lastAction = [[ProgressController mainProgressController] jobId];
|
||||||
|
if ([lastAction isEqualTo:jobCopy]) {
|
||||||
|
if ([py scanWasProblematic]) {
|
||||||
|
[problemDialog showWindow:self];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[Dialogs showMessage:@"All marked files were copied sucessfully."];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ([lastAction isEqualTo:jobMove]) {
|
||||||
|
if ([py scanWasProblematic]) {
|
||||||
|
[problemDialog showWindow:self];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[Dialogs showMessage:@"All marked files were moved sucessfully."];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ([lastAction isEqualTo:jobDelete]) {
|
||||||
|
if ([py scanWasProblematic]) {
|
||||||
|
[problemDialog showWindow:self];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[Dialogs showMessage:@"All marked files were sucessfully sent to Trash."];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ([lastAction isEqualTo:jobScan]) {
|
||||||
|
NSInteger rowCount = [[table py] numberOfRows];
|
||||||
|
if (rowCount == 0)
|
||||||
|
[Dialogs showMessage:@"No duplicates found."];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"];
|
||||||
|
[[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
|
||||||
1098
cocoa/base/xib/DetailsPanel.xib
Normal file
1098
cocoa/base/xib/DetailsPanel.xib
Normal file
File diff suppressed because it is too large
Load Diff
1539
cocoa/base/xib/DirectoryPanel.xib
Normal file
1539
cocoa/base/xib/DirectoryPanel.xib
Normal file
File diff suppressed because it is too large
Load Diff
5030
cocoa/base/xib/MainMenu.xib
Normal file
5030
cocoa/base/xib/MainMenu.xib
Normal file
File diff suppressed because it is too large
Load Diff
1142
cocoa/base/xib/ProblemDialog.xib
Normal file
1142
cocoa/base/xib/ProblemDialog.xib
Normal file
File diff suppressed because it is too large
Load Diff
19
cocoa/me/AppDelegate.h
Normal file
19
cocoa/me/AppDelegate.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 "../base/AppDelegate.h"
|
||||||
|
#import "ResultWindow.h"
|
||||||
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
|
@interface AppDelegate : AppDelegateBase {}
|
||||||
|
- (IBAction)openWebsite:(id)sender;
|
||||||
|
- (IBAction)toggleDirectories:(id)sender;
|
||||||
|
|
||||||
|
- (PyDupeGuru *)py;
|
||||||
|
@end
|
||||||
87
cocoa/me/AppDelegate.m
Normal file
87
cocoa/me/AppDelegate.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 "AppDelegate.h"
|
||||||
|
#import "../../cocoalib/ProgressController.h"
|
||||||
|
#import "../../cocoalib/Utils.h"
|
||||||
|
#import "../../cocoalib/ValueTransformers.h"
|
||||||
|
#import "../../cocoalib/Dialogs.h"
|
||||||
|
#import "DetailsPanel.h"
|
||||||
|
#import "DirectoryPanel.h"
|
||||||
|
#import "Consts.h"
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:10];
|
||||||
|
[d setObject:i2n(3) forKey:@"scanType"];
|
||||||
|
[d setObject:i2n(80) forKey:@"minMatchPercentage"];
|
||||||
|
[d setObject:i2n(1) forKey:@"recreatePathType"];
|
||||||
|
[d setObject:b2n(NO) forKey:@"wordWeighting"];
|
||||||
|
[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"];
|
||||||
|
[d setObject:b2n(YES) forKey:@"scanTagArtist"];
|
||||||
|
[d setObject:b2n(YES) forKey:@"scanTagAlbum"];
|
||||||
|
[d setObject:b2n(YES) forKey:@"scanTagTitle"];
|
||||||
|
[d setObject:b2n(NO) forKey:@"scanTagGenre"];
|
||||||
|
[d setObject:b2n(NO) forKey:@"scanTagYear"];
|
||||||
|
[d setObject:[NSArray array] forKey:@"recentDirectories"];
|
||||||
|
[d setObject:[NSArray array] forKey:@"columnsOrder"];
|
||||||
|
[d setObject:[NSDictionary dictionary] forKey:@"columnsWidth"];
|
||||||
|
[[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:d];
|
||||||
|
[ud registerDefaults:d];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
NSMutableIndexSet *i = [NSMutableIndexSet indexSetWithIndex:4];
|
||||||
|
[i addIndex:5];
|
||||||
|
VTIsIntIn *vtScanTypeIsNotContent = [[[VTIsIntIn alloc] initWithValues:i reverse:YES] autorelease];
|
||||||
|
[NSValueTransformer setValueTransformer:vtScanTypeIsNotContent forName:@"vtScanTypeIsNotContent"];
|
||||||
|
VTIsIntIn *vtScanTypeIsTag = [[[VTIsIntIn alloc] initWithValues:[NSIndexSet indexSetWithIndex:3] reverse:NO] autorelease];
|
||||||
|
[NSValueTransformer setValueTransformer:vtScanTypeIsTag forName:@"vtScanTypeIsTag"];
|
||||||
|
_directoryPanel = nil;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)openWebsite:(id)sender
|
||||||
|
{
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.hardcoded.net/dupeguru_me"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)toggleDirectories:(id)sender
|
||||||
|
{
|
||||||
|
[[self directoryPanel] toggleVisible:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (DirectoryPanel *)directoryPanel
|
||||||
|
{
|
||||||
|
if (!_directoryPanel)
|
||||||
|
_directoryPanel = [[DirectoryPanelME alloc] initWithParentApp:self];
|
||||||
|
return _directoryPanel;
|
||||||
|
}
|
||||||
|
- (PyDupeGuru *)py { return (PyDupeGuru *)py; }
|
||||||
|
|
||||||
|
//Delegate
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||||
|
{
|
||||||
|
NSMenu *actionsMenu = [[[NSApp mainMenu] itemWithTitle:@"Actions"] submenu];
|
||||||
|
// index 3 is just after "Export Results to XHTML"
|
||||||
|
NSMenuItem *mi = [actionsMenu insertItemWithTitle:@"Remove Dead Tracks in iTunes"
|
||||||
|
action:@selector(removeDeadTracks:) keyEquivalent:@"" atIndex:3];
|
||||||
|
[mi setTarget:result];
|
||||||
|
[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
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
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
|
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 "DirectoryPanel.h"
|
#import "DirectoryPanel.h"
|
||||||
|
|
||||||
@implementation DirectoryPanel
|
@implementation DirectoryPanelME
|
||||||
- (IBAction)addiTunes:(id)sender
|
- (IBAction)addiTunes:(id)sender
|
||||||
{
|
{
|
||||||
[self addDirectory:[@"~/Music/iTunes/iTunes Music" stringByExpandingTildeInPath]];
|
[self addDirectory:[@"~/Music/iTunes/iTunes Music" stringByExpandingTildeInPath]];
|
||||||
@@ -23,11 +23,13 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>hsft</string>
|
<string>hsft</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>5.6.6</string>
|
<string>5.10.3</string>
|
||||||
<key>NSMainNibFile</key>
|
<key>NSMainNibFile</key>
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>© Hardcoded Software, 2010</string>
|
||||||
<key>SUFeedURL</key>
|
<key>SUFeedURL</key>
|
||||||
<string>http://www.hardcoded.net/updates/dupeguru_me.appcast</string>
|
<string>http://www.hardcoded.net/updates/dupeguru_me.appcast</string>
|
||||||
<key>SUPublicDSAKeyFile</key>
|
<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
|
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 <Cocoa/Cocoa.h>
|
||||||
#import "dgbase/PyDupeGuru.h"
|
#import "../base/PyDupeGuru.h"
|
||||||
|
|
||||||
@interface PyDupeGuru : PyDupeGuruBase
|
@interface PyDupeGuru : PyDupeGuruBase
|
||||||
//Scanning options
|
//Scanning options
|
||||||
@@ -19,5 +19,5 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
- (void)enable:(NSNumber *)enable scanForTag:(NSString *)tag;
|
- (void)enable:(NSNumber *)enable scanForTag:(NSString *)tag;
|
||||||
- (void)scanDeadTracks;
|
- (void)scanDeadTracks;
|
||||||
- (void)removeDeadTracks;
|
- (void)removeDeadTracks;
|
||||||
- (int)deadTrackCount;
|
- (NSInteger)deadTrackCount;
|
||||||
@end
|
@end
|
||||||
15
cocoa/me/ResultWindow.h
Normal file
15
cocoa/me/ResultWindow.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 "../base/ResultWindow.h"
|
||||||
|
#import "DirectoryPanel.h"
|
||||||
|
|
||||||
|
@interface ResultWindow : ResultWindowBase {}
|
||||||
|
- (IBAction)removeDeadTracks:(id)sender;
|
||||||
|
@end
|
||||||
132
cocoa/me/ResultWindow.m
Normal file
132
cocoa/me/ResultWindow.m
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
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 "../../cocoalib/Dialogs.h"
|
||||||
|
#import "../../cocoalib/ProgressController.h"
|
||||||
|
#import "../../cocoalib/Utils.h"
|
||||||
|
#import "AppDelegate.h"
|
||||||
|
#import "Consts.h"
|
||||||
|
|
||||||
|
@implementation ResultWindow
|
||||||
|
/* Override */
|
||||||
|
- (void)awakeFromNib
|
||||||
|
{
|
||||||
|
[super awakeFromNib];
|
||||||
|
[[self window] setTitle:@"dupeGuru Music Edition"];
|
||||||
|
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,6)];
|
||||||
|
[deltaColumns removeIndex:6];
|
||||||
|
[table setDeltaColumns:deltaColumns];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)startDuplicateScan:(id)sender
|
||||||
|
{
|
||||||
|
if ([matches numberOfRows] > 0)
|
||||||
|
{
|
||||||
|
if ([Dialogs askYesNo:@"Are you sure you want to start a new duplicate scan?"] == NSAlertSecondButtonReturn) // NO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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"]];
|
||||||
|
NSInteger r = n2i([py doScan]);
|
||||||
|
if (r == 3)
|
||||||
|
{
|
||||||
|
[Dialogs showMessage:@"The selected directories contain no scannable file."];
|
||||||
|
[app toggleDirectories:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public */
|
||||||
|
- (void)initResultColumns
|
||||||
|
{
|
||||||
|
NSTableColumn *refCol = [matches tableColumnWithIdentifier:@"0"];
|
||||||
|
_resultColumns = [[NSMutableArray alloc] init];
|
||||||
|
[_resultColumns addObject:[matches tableColumnWithIdentifier:@"0"]]; // File Name
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:1 title:@"Directory" width:120 refCol:refCol]];
|
||||||
|
NSTableColumn *sizeCol = [self getColumnForIdentifier:2 title:@"Size (MB)" width:63 refCol:refCol];
|
||||||
|
[[sizeCol dataCell] setAlignment:NSRightTextAlignment];
|
||||||
|
[_resultColumns addObject:sizeCol];
|
||||||
|
NSTableColumn *timeCol = [self getColumnForIdentifier:3 title:@"Time" width:50 refCol:refCol];
|
||||||
|
[[timeCol dataCell] setAlignment:NSRightTextAlignment];
|
||||||
|
[_resultColumns addObject:timeCol];
|
||||||
|
NSTableColumn *brCol = [self getColumnForIdentifier:4 title:@"Bitrate" width:50 refCol:refCol];
|
||||||
|
[[brCol dataCell] setAlignment:NSRightTextAlignment];
|
||||||
|
[_resultColumns addObject:brCol];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:5 title:@"Sample Rate" width:60 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:6 title:@"Kind" width:40 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:7 title:@"Modification" width:120 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:8 title:@"Title" width:120 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:9 title:@"Artist" width:120 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:10 title:@"Album" width:120 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:11 title:@"Genre" width:80 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:12 title:@"Year" width:40 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:13 title:@"Track Number" width:40 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:14 title:@"Comment" width:120 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:15 title:@"Match %" width:57 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:16 title:@"Words Used" width:120 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:17 title:@"Dupe Count" width:80 refCol:refCol]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 = @"Your iTunes Library contains %d dead tracks ready to be removed. Continue?";
|
||||||
|
if ([Dialogs askYesNo:[NSString stringWithFormat:msg,deadTrackCount]] == NSAlertFirstButtonReturn)
|
||||||
|
[(PyDupeGuru *)py removeDeadTracks];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[Dialogs showMessage:@"You have no dead tracks in your iTunes Library"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
74
cocoa/me/dg_cocoa.py
Normal file
74
cocoa/me/dg_cocoa.py
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
|
||||||
|
|
||||||
|
from hscommon.cocoa import signature
|
||||||
|
|
||||||
|
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||||
|
from core_me.app_cocoa import DupeGuruME
|
||||||
|
from core.scanner import ScanType
|
||||||
|
|
||||||
|
# Fix py2app imports which chokes on relative imports and other stuff
|
||||||
|
import core_me.app_cocoa, core_me.data, core_me.fs, core_me.scanner
|
||||||
|
import hsaudiotag.aiff, hsaudiotag.flac, hsaudiotag.genres, hsaudiotag.id3v1,\
|
||||||
|
hsaudiotag.id3v2, hsaudiotag.mp4, hsaudiotag.mpeg, hsaudiotag.ogg, hsaudiotag.wma
|
||||||
|
from hsaudiotag import aiff, flac, genres, id3v1, id3v2, mp4, mpeg, ogg, wma
|
||||||
|
import hsutil.conflict
|
||||||
|
import core.engine, core.fs, core.app
|
||||||
|
import xml.etree.ElementPath
|
||||||
|
import gzip
|
||||||
|
import aem.kae
|
||||||
|
import appscript.defaultterminology
|
||||||
|
|
||||||
|
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 "dupeGuru Music Edition"
|
||||||
|
|
||||||
@@ -19,45 +19,51 @@
|
|||||||
/* End PBXAppleScriptBuildPhase section */
|
/* End PBXAppleScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
|
|
||||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
|
|
||||||
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
||||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
||||||
|
CE003CC611242D00004B0AA7 /* HSGUIController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CB411242D00004B0AA7 /* HSGUIController.m */; };
|
||||||
|
CE003CC711242D00004B0AA7 /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CB611242D00004B0AA7 /* HSOutline.m */; };
|
||||||
|
CE003CC811242D00004B0AA7 /* HSWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CB811242D00004B0AA7 /* HSWindowController.m */; };
|
||||||
|
CE003CC911242D00004B0AA7 /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CBA11242D00004B0AA7 /* NSEventAdditions.m */; };
|
||||||
|
CE003CCA11242D00004B0AA7 /* HSOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC111242D00004B0AA7 /* HSOutlineView.m */; };
|
||||||
|
CE003CCB11242D00004B0AA7 /* NSIndexPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC311242D00004B0AA7 /* NSIndexPathAdditions.m */; };
|
||||||
|
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */; };
|
||||||
|
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */; };
|
||||||
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */; };
|
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */; };
|
||||||
|
CE0A0C001175A1C000DCA3C6 /* HSTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0A0BFF1175A1C000DCA3C6 /* HSTable.m */; };
|
||||||
|
CE0A0C041175A1DE00DCA3C6 /* ProblemDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0A0C021175A1DE00DCA3C6 /* ProblemDialog.m */; };
|
||||||
|
CE0A0C061175A24800DCA3C6 /* ProblemDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE0A0C051175A24800DCA3C6 /* ProblemDialog.xib */; };
|
||||||
CE1425890AFB718500BD5167 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
CE1425890AFB718500BD5167 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
||||||
CE14259F0AFB719300BD5167 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
CE14259F0AFB719300BD5167 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
||||||
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
||||||
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9A09914ADF003581CE /* ResultWindow.m */; };
|
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9A09914ADF003581CE /* ResultWindow.m */; };
|
||||||
CE381D0509915304003581CE /* dg_cocoa.plugin in Resources */ = {isa = PBXBuildFile; fileRef = CE381CF509915304003581CE /* dg_cocoa.plugin */; };
|
CE381D0509915304003581CE /* dg_cocoa.plugin in Resources */ = {isa = PBXBuildFile; fileRef = CE381CF509915304003581CE /* dg_cocoa.plugin */; };
|
||||||
CE3AA46709DB207900DB3A21 /* Directories.nib in Resources */ = {isa = PBXBuildFile; fileRef = CE3AA46509DB207900DB3A21 /* Directories.nib */; };
|
CE3FBDD31094637800B72D77 /* DetailsPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE3FBDD11094637800B72D77 /* DetailsPanel.xib */; };
|
||||||
|
CE3FBDD41094637800B72D77 /* DirectoryPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE3FBDD21094637800B72D77 /* DirectoryPanel.xib */; };
|
||||||
CE49DEF60FDFEB810098617B /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CE49DEF30FDFEB810098617B /* BRSingleLineFormatter.m */; };
|
CE49DEF60FDFEB810098617B /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CE49DEF30FDFEB810098617B /* BRSingleLineFormatter.m */; };
|
||||||
CE49DEF70FDFEB810098617B /* NSCharacterSet_Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE49DEF50FDFEB810098617B /* NSCharacterSet_Extensions.m */; };
|
CE4B59C81119919700C06C9E /* ErrorReportWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4B59C51119919700C06C9E /* ErrorReportWindow.xib */; };
|
||||||
|
CE4B59C91119919700C06C9E /* progress.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4B59C61119919700C06C9E /* progress.xib */; };
|
||||||
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE10FC6C12E00EC695D /* Dialogs.m */; };
|
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE10FC6C12E00EC695D /* Dialogs.m */; };
|
||||||
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */; };
|
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */; };
|
||||||
CE515DF50FC6C12E00EC695D /* Outline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE50FC6C12E00EC695D /* Outline.m */; };
|
|
||||||
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE70FC6C12E00EC695D /* ProgressController.m */; };
|
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE70FC6C12E00EC695D /* ProgressController.m */; };
|
||||||
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */; };
|
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */; };
|
||||||
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEC0FC6C12E00EC695D /* RegistrationInterface.m */; };
|
|
||||||
CE515DF90FC6C12E00EC695D /* Table.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEE0FC6C12E00EC695D /* Table.m */; };
|
|
||||||
CE515DFA0FC6C12E00EC695D /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DF00FC6C12E00EC695D /* Utils.m */; };
|
CE515DFA0FC6C12E00EC695D /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DF00FC6C12E00EC695D /* Utils.m */; };
|
||||||
CE515DFB0FC6C12E00EC695D /* ValueTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DF20FC6C12E00EC695D /* ValueTransformers.m */; };
|
CE515DFB0FC6C12E00EC695D /* ValueTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DF20FC6C12E00EC695D /* ValueTransformers.m */; };
|
||||||
CE515E020FC6C13E00EC695D /* ErrorReportWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE515DFC0FC6C13E00EC695D /* ErrorReportWindow.xib */; };
|
|
||||||
CE515E030FC6C13E00EC695D /* progress.nib in Resources */ = {isa = PBXBuildFile; fileRef = CE515DFE0FC6C13E00EC695D /* progress.nib */; };
|
|
||||||
CE515E040FC6C13E00EC695D /* registration.nib in Resources */ = {isa = PBXBuildFile; fileRef = CE515E000FC6C13E00EC695D /* registration.nib */; };
|
|
||||||
CE515E1D0FC6C19300EC695D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515E160FC6C19300EC695D /* AppDelegate.m */; };
|
CE515E1D0FC6C19300EC695D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515E160FC6C19300EC695D /* AppDelegate.m */; };
|
||||||
CE515E1E0FC6C19300EC695D /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515E190FC6C19300EC695D /* DirectoryPanel.m */; };
|
CE515E1E0FC6C19300EC695D /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515E190FC6C19300EC695D /* DirectoryPanel.m */; };
|
||||||
CE515E1F0FC6C19300EC695D /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515E1C0FC6C19300EC695D /* ResultWindow.m */; };
|
CE515E1F0FC6C19300EC695D /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515E1C0FC6C19300EC695D /* ResultWindow.m */; };
|
||||||
|
CE578303124DFC660004769C /* HSTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE578302124DFC660004769C /* HSTableView.m */; };
|
||||||
CE6032C00FE6784C007E33FF /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE6032BF0FE6784C007E33FF /* DetailsPanel.m */; };
|
CE6032C00FE6784C007E33FF /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE6032BF0FE6784C007E33FF /* DetailsPanel.m */; };
|
||||||
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE68EE6609ABC48000971085 /* DirectoryPanel.m */; };
|
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE68EE6609ABC48000971085 /* DirectoryPanel.m */; };
|
||||||
CE6E0E9F1054EB97008D9390 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = CE6E0E9E1054EB97008D9390 /* dsa_pub.pem */; };
|
CE6E0E9F1054EB97008D9390 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = CE6E0E9E1054EB97008D9390 /* dsa_pub.pem */; };
|
||||||
|
CE74A12412537F06008A8DF0 /* HSFairwareReminder.m in Sources */ = {isa = PBXBuildFile; fileRef = CE74A12212537F06008A8DF0 /* HSFairwareReminder.m */; };
|
||||||
|
CE74A12712537F2E008A8DF0 /* FairwareReminder.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE74A12512537F2E008A8DF0 /* FairwareReminder.xib */; };
|
||||||
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
||||||
CEA7D2C50FDFED340037CD8C /* dgme_logo_32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEA7D2C40FDFED340037CD8C /* dgme_logo_32.png */; };
|
CE900AD2109B238600754048 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE900AD1109B238600754048 /* Preferences.xib */; };
|
||||||
CECA899909DB12CA00A3D774 /* Details.nib in Resources */ = {isa = PBXBuildFile; fileRef = CECA899709DB12CA00A3D774 /* Details.nib */; };
|
CE900AD7109B2A9B00754048 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE900AD6109B2A9B00754048 /* MainMenu.xib */; };
|
||||||
CECA899C09DB132E00A3D774 /* DetailsPanel.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CECA899A09DB132E00A3D774 /* DetailsPanel.h */; };
|
CEB14D29124DFC2800FA7481 /* ResultTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB14D28124DFC2800FA7481 /* ResultTable.m */; };
|
||||||
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CECA899B09DB132E00A3D774 /* DetailsPanel.m */; };
|
CEDF07A3112493B200EE5BC0 /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDF07A2112493B200EE5BC0 /* StatsLabel.m */; };
|
||||||
CED2A6880A05102700AC4C3F /* power_marker32.png in Resources */ = {isa = PBXBuildFile; fileRef = CED2A6870A05102600AC4C3F /* power_marker32.png */; };
|
|
||||||
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */ = {isa = PBXBuildFile; fileRef = CEEB135109C837A2004D2330 /* dupeguru.icns */; };
|
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */ = {isa = PBXBuildFile; fileRef = CEEB135109C837A2004D2330 /* dupeguru.icns */; };
|
||||||
CEF7823809C8AA0200EF38FF /* gear.png in Resources */ = {isa = PBXBuildFile; fileRef = CEF7823709C8AA0200EF38FF /* gear.png */; };
|
|
||||||
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC294509C89E3D00D9F998 /* folder32.png */; };
|
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC294509C89E3D00D9F998 /* folder32.png */; };
|
||||||
CEFC295509C89FF200D9F998 /* details32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295309C89FF200D9F998 /* details32.png */; };
|
CEFC295509C89FF200D9F998 /* details32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295309C89FF200D9F998 /* details32.png */; };
|
||||||
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295409C89FF200D9F998 /* preferences32.png */; };
|
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295409C89FF200D9F998 /* preferences32.png */; };
|
||||||
@@ -71,7 +77,6 @@
|
|||||||
dstSubfolderSpec = 10;
|
dstSubfolderSpec = 10;
|
||||||
files = (
|
files = (
|
||||||
CE14259F0AFB719300BD5167 /* Sparkle.framework in CopyFiles */,
|
CE14259F0AFB719300BD5167 /* Sparkle.framework in CopyFiles */,
|
||||||
CECA899C09DB132E00A3D774 /* DetailsPanel.h in CopyFiles */,
|
|
||||||
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */,
|
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -79,73 +84,98 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
|
||||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||||
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
||||||
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; };
|
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; };
|
||||||
29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
|
|
||||||
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
||||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||||
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
|
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
|
||||||
8D1107320486CEB800E47090 /* dupeGuru ME.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "dupeGuru ME.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
8D1107320486CEB800E47090 /* dupeGuru ME.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "dupeGuru ME.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_me_help; path = help/dupeguru_me_help; sourceTree = "<group>"; };
|
CE003CB311242D00004B0AA7 /* HSGUIController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSGUIController.h; sourceTree = "<group>"; };
|
||||||
|
CE003CB411242D00004B0AA7 /* HSGUIController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSGUIController.m; sourceTree = "<group>"; };
|
||||||
|
CE003CB511242D00004B0AA7 /* HSOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutline.h; sourceTree = "<group>"; };
|
||||||
|
CE003CB611242D00004B0AA7 /* HSOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutline.m; sourceTree = "<group>"; };
|
||||||
|
CE003CB711242D00004B0AA7 /* HSWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSWindowController.h; sourceTree = "<group>"; };
|
||||||
|
CE003CB811242D00004B0AA7 /* HSWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSWindowController.m; sourceTree = "<group>"; };
|
||||||
|
CE003CB911242D00004B0AA7 /* NSEventAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSEventAdditions.h; path = ../../cocoalib/NSEventAdditions.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE003CBA11242D00004B0AA7 /* NSEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSEventAdditions.m; path = ../../cocoalib/NSEventAdditions.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE003CBC11242D00004B0AA7 /* PyGUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyGUI.h; sourceTree = "<group>"; };
|
||||||
|
CE003CBD11242D00004B0AA7 /* PyOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyOutline.h; sourceTree = "<group>"; };
|
||||||
|
CE003CC011242D00004B0AA7 /* HSOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutlineView.h; sourceTree = "<group>"; };
|
||||||
|
CE003CC111242D00004B0AA7 /* HSOutlineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutlineView.m; sourceTree = "<group>"; };
|
||||||
|
CE003CC211242D00004B0AA7 /* NSIndexPathAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSIndexPathAdditions.h; sourceTree = "<group>"; };
|
||||||
|
CE003CC311242D00004B0AA7 /* NSIndexPathAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSIndexPathAdditions.m; sourceTree = "<group>"; };
|
||||||
|
CE003CC411242D00004B0AA7 /* NSTableViewAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSTableViewAdditions.h; sourceTree = "<group>"; };
|
||||||
|
CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSTableViewAdditions.m; sourceTree = "<group>"; };
|
||||||
|
CE003CCD11242D2C004B0AA7 /* DirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryOutline.h; path = ../base/DirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryOutline.m; path = ../base/DirectoryOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE003CCF11242D2C004B0AA7 /* PyDirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDirectoryOutline.h; path = ../base/PyDirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_me_help; path = ../../help_me/dupeguru_me_help; sourceTree = "<group>"; };
|
||||||
|
CE0A0BFE1175A1C000DCA3C6 /* HSTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSTable.h; sourceTree = "<group>"; };
|
||||||
|
CE0A0BFF1175A1C000DCA3C6 /* HSTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSTable.m; sourceTree = "<group>"; };
|
||||||
|
CE0A0C011175A1DE00DCA3C6 /* ProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProblemDialog.h; path = ../base/ProblemDialog.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0A0C021175A1DE00DCA3C6 /* ProblemDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProblemDialog.m; path = ../base/ProblemDialog.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0A0C031175A1DE00DCA3C6 /* PyProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyProblemDialog.h; path = ../base/PyProblemDialog.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0A0C051175A24800DCA3C6 /* ProblemDialog.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ProblemDialog.xib; path = ../base/xib/ProblemDialog.xib; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0A0C131175A28100DCA3C6 /* PyTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyTable.h; sourceTree = "<group>"; };
|
||||||
CE1425880AFB718500BD5167 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
CE1425880AFB718500BD5167 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
||||||
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE381C9A09914ADF003581CE /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
CE381C9A09914ADF003581CE /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE381C9B09914ADF003581CE /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
CE381C9B09914ADF003581CE /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE381CF509915304003581CE /* dg_cocoa.plugin */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dg_cocoa.plugin; path = py/dist/dg_cocoa.plugin; sourceTree = SOURCE_ROOT; };
|
CE381CF509915304003581CE /* dg_cocoa.plugin */ = {isa = PBXFileReference; lastKnownFileType = folder; path = dg_cocoa.plugin; sourceTree = SOURCE_ROOT; };
|
||||||
CE3AA46609DB207900DB3A21 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/Directories.nib; sourceTree = "<group>"; };
|
CE3FBDD11094637800B72D77 /* DetailsPanel.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = DetailsPanel.xib; path = ../../base/xib/DetailsPanel.xib; sourceTree = "<group>"; };
|
||||||
CE49DEF20FDFEB810098617B /* BRSingleLineFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BRSingleLineFormatter.h; path = cocoalib/brsinglelineformatter/BRSingleLineFormatter.h; sourceTree = SOURCE_ROOT; };
|
CE3FBDD21094637800B72D77 /* DirectoryPanel.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = DirectoryPanel.xib; path = ../../base/xib/DirectoryPanel.xib; sourceTree = "<group>"; };
|
||||||
CE49DEF30FDFEB810098617B /* BRSingleLineFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BRSingleLineFormatter.m; path = cocoalib/brsinglelineformatter/BRSingleLineFormatter.m; sourceTree = SOURCE_ROOT; };
|
CE49DEF20FDFEB810098617B /* BRSingleLineFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BRSingleLineFormatter.h; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE49DEF40FDFEB810098617B /* NSCharacterSet_Extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSCharacterSet_Extensions.h; path = cocoalib/brsinglelineformatter/NSCharacterSet_Extensions.h; sourceTree = SOURCE_ROOT; };
|
CE49DEF30FDFEB810098617B /* BRSingleLineFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BRSingleLineFormatter.m; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE49DEF50FDFEB810098617B /* NSCharacterSet_Extensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSCharacterSet_Extensions.m; path = cocoalib/brsinglelineformatter/NSCharacterSet_Extensions.m; sourceTree = SOURCE_ROOT; };
|
CE4B59C51119919700C06C9E /* ErrorReportWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ErrorReportWindow.xib; sourceTree = "<group>"; };
|
||||||
CE515DE00FC6C12E00EC695D /* Dialogs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Dialogs.h; path = cocoalib/Dialogs.h; sourceTree = SOURCE_ROOT; };
|
CE4B59C61119919700C06C9E /* progress.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = progress.xib; sourceTree = "<group>"; };
|
||||||
CE515DE10FC6C12E00EC695D /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
CE515DE00FC6C12E00EC695D /* Dialogs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Dialogs.h; path = ../../cocoalib/Dialogs.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
CE515DE10FC6C12E00EC695D /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE40FC6C12E00EC695D /* Outline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Outline.h; path = cocoalib/Outline.h; sourceTree = SOURCE_ROOT; };
|
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE50FC6C12E00EC695D /* Outline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Outline.m; path = cocoalib/Outline.m; sourceTree = SOURCE_ROOT; };
|
CE515DE60FC6C12E00EC695D /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE60FC6C12E00EC695D /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
CE515DE70FC6C12E00EC695D /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE70FC6C12E00EC695D /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
CE515DE80FC6C12E00EC695D /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE80FC6C12E00EC695D /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
CE515DE90FC6C12E00EC695D /* RecentDirectories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecentDirectories.h; path = ../../cocoalib/RecentDirectories.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE90FC6C12E00EC695D /* RecentDirectories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecentDirectories.h; path = cocoalib/RecentDirectories.h; sourceTree = SOURCE_ROOT; };
|
CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RecentDirectories.m; path = ../../cocoalib/RecentDirectories.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RecentDirectories.m; path = cocoalib/RecentDirectories.m; sourceTree = SOURCE_ROOT; };
|
CE515DEF0FC6C12E00EC695D /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = ../../cocoalib/Utils.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DEB0FC6C12E00EC695D /* RegistrationInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegistrationInterface.h; path = cocoalib/RegistrationInterface.h; sourceTree = SOURCE_ROOT; };
|
CE515DF00FC6C12E00EC695D /* Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Utils.m; path = ../../cocoalib/Utils.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DEC0FC6C12E00EC695D /* RegistrationInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RegistrationInterface.m; path = cocoalib/RegistrationInterface.m; sourceTree = SOURCE_ROOT; };
|
CE515DF10FC6C12E00EC695D /* ValueTransformers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueTransformers.h; path = ../../cocoalib/ValueTransformers.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DED0FC6C12E00EC695D /* Table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Table.h; path = cocoalib/Table.h; sourceTree = SOURCE_ROOT; };
|
CE515DF20FC6C12E00EC695D /* ValueTransformers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ValueTransformers.m; path = ../../cocoalib/ValueTransformers.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DEE0FC6C12E00EC695D /* Table.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Table.m; path = cocoalib/Table.m; sourceTree = SOURCE_ROOT; };
|
CE515E150FC6C19300EC695D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ../base/AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DEF0FC6C12E00EC695D /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = cocoalib/Utils.h; sourceTree = SOURCE_ROOT; };
|
CE515E160FC6C19300EC695D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = ../base/AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DF00FC6C12E00EC695D /* Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Utils.m; path = cocoalib/Utils.m; sourceTree = SOURCE_ROOT; };
|
CE515E170FC6C19300EC695D /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Consts.h; path = ../base/Consts.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DF10FC6C12E00EC695D /* ValueTransformers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueTransformers.h; path = cocoalib/ValueTransformers.h; sourceTree = SOURCE_ROOT; };
|
CE515E180FC6C19300EC695D /* DirectoryPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryPanel.h; path = ../base/DirectoryPanel.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DF20FC6C12E00EC695D /* ValueTransformers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ValueTransformers.m; path = cocoalib/ValueTransformers.m; sourceTree = SOURCE_ROOT; };
|
CE515E190FC6C19300EC695D /* DirectoryPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryPanel.m; path = ../base/DirectoryPanel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DFD0FC6C13E00EC695D /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = cocoalib/English.lproj/ErrorReportWindow.xib; sourceTree = "<group>"; };
|
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDupeGuru.h; path = ../base/PyDupeGuru.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DFF0FC6C13E00EC695D /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = cocoalib/English.lproj/progress.nib; sourceTree = "<group>"; };
|
CE515E1B0FC6C19300EC695D /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultWindow.h; path = ../base/ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515E010FC6C13E00EC695D /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = cocoalib/English.lproj/registration.nib; sourceTree = "<group>"; };
|
CE515E1C0FC6C19300EC695D /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultWindow.m; path = ../base/ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515E150FC6C19300EC695D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = dgbase/AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
CE578301124DFC660004769C /* HSTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSTableView.h; path = ../../cocoalib/views/HSTableView.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515E160FC6C19300EC695D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = dgbase/AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
CE578302124DFC660004769C /* HSTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSTableView.m; path = ../../cocoalib/views/HSTableView.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515E170FC6C19300EC695D /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Consts.h; path = dgbase/Consts.h; sourceTree = SOURCE_ROOT; };
|
CE6032BE0FE6784C007E33FF /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DetailsPanel.h; path = ../base/DetailsPanel.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515E180FC6C19300EC695D /* DirectoryPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryPanel.h; path = dgbase/DirectoryPanel.h; sourceTree = SOURCE_ROOT; };
|
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DetailsPanel.m; path = ../base/DetailsPanel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515E190FC6C19300EC695D /* DirectoryPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryPanel.m; path = dgbase/DirectoryPanel.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDupeGuru.h; path = dgbase/PyDupeGuru.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE515E1B0FC6C19300EC695D /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultWindow.h; path = dgbase/ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE515E1C0FC6C19300EC695D /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultWindow.m; path = dgbase/ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE6032BE0FE6784C007E33FF /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DetailsPanel.h; path = dgbase/DetailsPanel.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DetailsPanel.m; path = dgbase/DetailsPanel.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE68EE6509ABC48000971085 /* DirectoryPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DirectoryPanel.h; sourceTree = SOURCE_ROOT; };
|
CE68EE6509ABC48000971085 /* DirectoryPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DirectoryPanel.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE68EE6609ABC48000971085 /* DirectoryPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DirectoryPanel.m; sourceTree = SOURCE_ROOT; };
|
CE68EE6609ABC48000971085 /* DirectoryPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DirectoryPanel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE6E0E9E1054EB97008D9390 /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dsa_pub.pem; path = dgbase/dsa_pub.pem; sourceTree = "<group>"; };
|
CE6E0E9E1054EB97008D9390 /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dsa_pub.pem; path = ../base/dsa_pub.pem; sourceTree = "<group>"; };
|
||||||
|
CE74A12112537F06008A8DF0 /* HSFairwareReminder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSFairwareReminder.h; path = ../../cocoalib/HSFairwareReminder.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE74A12212537F06008A8DF0 /* HSFairwareReminder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSFairwareReminder.m; path = ../../cocoalib/HSFairwareReminder.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE74A12312537F06008A8DF0 /* PyFairware.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyFairware.h; path = ../../cocoalib/PyFairware.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE74A12612537F2E008A8DF0 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = ../../cocoalib/en.lproj/FairwareReminder.xib; sourceTree = SOURCE_ROOT; };
|
||||||
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
||||||
CEA7D2C40FDFED340037CD8C /* dgme_logo_32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dgme_logo_32.png; path = images/dgme_logo_32.png; sourceTree = SOURCE_ROOT; };
|
CE900AD1109B238600754048 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Preferences.xib; sourceTree = "<group>"; };
|
||||||
CECA899809DB12CA00A3D774 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/Details.nib; sourceTree = "<group>"; };
|
CE900AD6109B2A9B00754048 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MainMenu.xib; path = ../../base/xib/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
CECA899A09DB132E00A3D774 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DetailsPanel.h; sourceTree = "<group>"; };
|
CEB14D26124DFC2800FA7481 /* PyResultTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTable.h; path = ../base/PyResultTable.h; sourceTree = SOURCE_ROOT; };
|
||||||
CECA899B09DB132E00A3D774 /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DetailsPanel.m; sourceTree = "<group>"; };
|
CEB14D27124DFC2800FA7481 /* ResultTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultTable.h; path = ../base/ResultTable.h; sourceTree = SOURCE_ROOT; };
|
||||||
CED2A6870A05102600AC4C3F /* power_marker32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = power_marker32.png; path = images/power_marker32.png; sourceTree = SOURCE_ROOT; };
|
CEB14D28124DFC2800FA7481 /* ResultTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultTable.m; path = ../base/ResultTable.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEDF07A0112493B200EE5BC0 /* PyStatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyStatsLabel.h; path = ../base/PyStatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEDF07A1112493B200EE5BC0 /* StatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatsLabel.h; path = ../base/StatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEDF07A2112493B200EE5BC0 /* StatsLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatsLabel.m; path = ../base/StatsLabel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEEB135109C837A2004D2330 /* dupeguru.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = dupeguru.icns; sourceTree = "<group>"; };
|
CEEB135109C837A2004D2330 /* dupeguru.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = dupeguru.icns; sourceTree = "<group>"; };
|
||||||
CEF7823709C8AA0200EF38FF /* gear.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gear.png; path = images/gear.png; sourceTree = "<group>"; };
|
CEFC294509C89E3D00D9F998 /* folder32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = folder32.png; path = ../../images/folder32.png; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC294509C89E3D00D9F998 /* folder32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = folder32.png; path = images/folder32.png; sourceTree = SOURCE_ROOT; };
|
CEFC295309C89FF200D9F998 /* details32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = details32.png; path = ../../images/details32.png; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC295309C89FF200D9F998 /* details32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = details32.png; path = images/details32.png; sourceTree = SOURCE_ROOT; };
|
CEFC295409C89FF200D9F998 /* preferences32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = preferences32.png; path = ../../images/preferences32.png; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC295409C89FF200D9F998 /* preferences32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = preferences32.png; path = images/preferences32.png; sourceTree = SOURCE_ROOT; };
|
|
||||||
CEFF18A009A4D387005E6321 /* PyDupeGuru.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = PyDupeGuru.h; sourceTree = SOURCE_ROOT; };
|
CEFF18A009A4D387005E6321 /* PyDupeGuru.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = PyDupeGuru.h; sourceTree = SOURCE_ROOT; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@@ -162,21 +192,19 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
080E96DDFE201D6D7F000001 /* DGME */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
||||||
CE381C9409914ACE003581CE /* AppDelegate.m */,
|
CE381C9409914ACE003581CE /* AppDelegate.m */,
|
||||||
CE848A1809DD85810004CB44 /* Consts.h */,
|
CE848A1809DD85810004CB44 /* Consts.h */,
|
||||||
CECA899A09DB132E00A3D774 /* DetailsPanel.h */,
|
|
||||||
CECA899B09DB132E00A3D774 /* DetailsPanel.m */,
|
|
||||||
CE68EE6509ABC48000971085 /* DirectoryPanel.h */,
|
CE68EE6509ABC48000971085 /* DirectoryPanel.h */,
|
||||||
CE68EE6609ABC48000971085 /* DirectoryPanel.m */,
|
CE68EE6609ABC48000971085 /* DirectoryPanel.m */,
|
||||||
CEFF18A009A4D387005E6321 /* PyDupeGuru.h */,
|
CEFF18A009A4D387005E6321 /* PyDupeGuru.h */,
|
||||||
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
||||||
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
||||||
);
|
);
|
||||||
name = Classes;
|
name = DGME;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
||||||
@@ -209,7 +237,7 @@
|
|||||||
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
080E96DDFE201D6D7F000001 /* Classes */,
|
080E96DDFE201D6D7F000001 /* DGME */,
|
||||||
CE515E140FC6C17900EC695D /* dgbase */,
|
CE515E140FC6C17900EC695D /* dgbase */,
|
||||||
CE515DDD0FC6C09400EC695D /* cocoalib */,
|
CE515DDD0FC6C09400EC695D /* cocoalib */,
|
||||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||||
@@ -231,16 +259,13 @@
|
|||||||
29B97317FDCFA39411CA2CEA /* Resources */ = {
|
29B97317FDCFA39411CA2CEA /* Resources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE3FBDD01094637800B72D77 /* xib */,
|
||||||
CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */,
|
CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */,
|
||||||
CE381CF509915304003581CE /* dg_cocoa.plugin */,
|
CE381CF509915304003581CE /* dg_cocoa.plugin */,
|
||||||
CEFC294309C89E0000D9F998 /* images */,
|
CEFC294309C89E0000D9F998 /* images */,
|
||||||
CEEB135109C837A2004D2330 /* dupeguru.icns */,
|
CEEB135109C837A2004D2330 /* dupeguru.icns */,
|
||||||
8D1107310486CEB800E47090 /* Info.plist */,
|
8D1107310486CEB800E47090 /* Info.plist */,
|
||||||
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
|
|
||||||
CE6E0E9E1054EB97008D9390 /* dsa_pub.pem */,
|
CE6E0E9E1054EB97008D9390 /* dsa_pub.pem */,
|
||||||
CECA899709DB12CA00A3D774 /* Details.nib */,
|
|
||||||
CE3AA46509DB207900DB3A21 /* Directories.nib */,
|
|
||||||
29B97318FDCFA39411CA2CEA /* MainMenu.nib */,
|
|
||||||
);
|
);
|
||||||
name = Resources;
|
name = Resources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -254,40 +279,104 @@
|
|||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
CE003CB211242D00004B0AA7 /* controllers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE003CB311242D00004B0AA7 /* HSGUIController.h */,
|
||||||
|
CE003CB411242D00004B0AA7 /* HSGUIController.m */,
|
||||||
|
CE003CB511242D00004B0AA7 /* HSOutline.h */,
|
||||||
|
CE003CB611242D00004B0AA7 /* HSOutline.m */,
|
||||||
|
CE0A0BFE1175A1C000DCA3C6 /* HSTable.h */,
|
||||||
|
CE0A0BFF1175A1C000DCA3C6 /* HSTable.m */,
|
||||||
|
CE003CB711242D00004B0AA7 /* HSWindowController.h */,
|
||||||
|
CE003CB811242D00004B0AA7 /* HSWindowController.m */,
|
||||||
|
);
|
||||||
|
name = controllers;
|
||||||
|
path = ../../cocoalib/controllers;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE003CBB11242D00004B0AA7 /* proxies */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE003CBC11242D00004B0AA7 /* PyGUI.h */,
|
||||||
|
CE003CBD11242D00004B0AA7 /* PyOutline.h */,
|
||||||
|
CE0A0C131175A28100DCA3C6 /* PyTable.h */,
|
||||||
|
);
|
||||||
|
name = proxies;
|
||||||
|
path = ../../cocoalib/proxies;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE003CBF11242D00004B0AA7 /* views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE578301124DFC660004769C /* HSTableView.h */,
|
||||||
|
CE578302124DFC660004769C /* HSTableView.m */,
|
||||||
|
CE003CC011242D00004B0AA7 /* HSOutlineView.h */,
|
||||||
|
CE003CC111242D00004B0AA7 /* HSOutlineView.m */,
|
||||||
|
CE003CC211242D00004B0AA7 /* NSIndexPathAdditions.h */,
|
||||||
|
CE003CC311242D00004B0AA7 /* NSIndexPathAdditions.m */,
|
||||||
|
CE003CC411242D00004B0AA7 /* NSTableViewAdditions.h */,
|
||||||
|
CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */,
|
||||||
|
);
|
||||||
|
name = views;
|
||||||
|
path = ../../cocoalib/views;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE3FBDD01094637800B72D77 /* xib */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE900AD6109B2A9B00754048 /* MainMenu.xib */,
|
||||||
|
CE3FBDD11094637800B72D77 /* DetailsPanel.xib */,
|
||||||
|
CE3FBDD21094637800B72D77 /* DirectoryPanel.xib */,
|
||||||
|
CE900AD1109B238600754048 /* Preferences.xib */,
|
||||||
|
CE0A0C051175A24800DCA3C6 /* ProblemDialog.xib */,
|
||||||
|
);
|
||||||
|
path = xib;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
CE49DEF10FDFEB810098617B /* brsinglelineformatter */ = {
|
CE49DEF10FDFEB810098617B /* brsinglelineformatter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CE49DEF20FDFEB810098617B /* BRSingleLineFormatter.h */,
|
CE49DEF20FDFEB810098617B /* BRSingleLineFormatter.h */,
|
||||||
CE49DEF30FDFEB810098617B /* BRSingleLineFormatter.m */,
|
CE49DEF30FDFEB810098617B /* BRSingleLineFormatter.m */,
|
||||||
CE49DEF40FDFEB810098617B /* NSCharacterSet_Extensions.h */,
|
|
||||||
CE49DEF50FDFEB810098617B /* NSCharacterSet_Extensions.m */,
|
|
||||||
);
|
);
|
||||||
name = brsinglelineformatter;
|
name = brsinglelineformatter;
|
||||||
path = cocoalib/brsinglelineformatter;
|
path = ../../cocoalib/brsinglelineformatter;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE4B59C41119919700C06C9E /* xib */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE74A12512537F2E008A8DF0 /* FairwareReminder.xib */,
|
||||||
|
CE4B59C51119919700C06C9E /* ErrorReportWindow.xib */,
|
||||||
|
CE4B59C61119919700C06C9E /* progress.xib */,
|
||||||
|
);
|
||||||
|
name = xib;
|
||||||
|
path = ../../cocoalib/xib;
|
||||||
sourceTree = SOURCE_ROOT;
|
sourceTree = SOURCE_ROOT;
|
||||||
};
|
};
|
||||||
CE515DDD0FC6C09400EC695D /* cocoalib */ = {
|
CE515DDD0FC6C09400EC695D /* cocoalib */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE003CB211242D00004B0AA7 /* controllers */,
|
||||||
|
CE003CBB11242D00004B0AA7 /* proxies */,
|
||||||
|
CE003CBF11242D00004B0AA7 /* views */,
|
||||||
|
CE4B59C41119919700C06C9E /* xib */,
|
||||||
CE49DEF10FDFEB810098617B /* brsinglelineformatter */,
|
CE49DEF10FDFEB810098617B /* brsinglelineformatter */,
|
||||||
CE515DFC0FC6C13E00EC695D /* ErrorReportWindow.xib */,
|
|
||||||
CE515DFE0FC6C13E00EC695D /* progress.nib */,
|
|
||||||
CE515E000FC6C13E00EC695D /* registration.nib */,
|
|
||||||
CE515DE00FC6C12E00EC695D /* Dialogs.h */,
|
CE515DE00FC6C12E00EC695D /* Dialogs.h */,
|
||||||
CE515DE10FC6C12E00EC695D /* Dialogs.m */,
|
CE515DE10FC6C12E00EC695D /* Dialogs.m */,
|
||||||
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */,
|
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */,
|
||||||
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */,
|
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */,
|
||||||
CE515DE40FC6C12E00EC695D /* Outline.h */,
|
CE74A12112537F06008A8DF0 /* HSFairwareReminder.h */,
|
||||||
CE515DE50FC6C12E00EC695D /* Outline.m */,
|
CE74A12212537F06008A8DF0 /* HSFairwareReminder.m */,
|
||||||
|
CE74A12312537F06008A8DF0 /* PyFairware.h */,
|
||||||
|
CE003CB911242D00004B0AA7 /* NSEventAdditions.h */,
|
||||||
|
CE003CBA11242D00004B0AA7 /* NSEventAdditions.m */,
|
||||||
CE515DE60FC6C12E00EC695D /* ProgressController.h */,
|
CE515DE60FC6C12E00EC695D /* ProgressController.h */,
|
||||||
CE515DE70FC6C12E00EC695D /* ProgressController.m */,
|
CE515DE70FC6C12E00EC695D /* ProgressController.m */,
|
||||||
CE515DE80FC6C12E00EC695D /* PyApp.h */,
|
CE515DE80FC6C12E00EC695D /* PyApp.h */,
|
||||||
CE515DE90FC6C12E00EC695D /* RecentDirectories.h */,
|
CE515DE90FC6C12E00EC695D /* RecentDirectories.h */,
|
||||||
CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */,
|
CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */,
|
||||||
CE515DEB0FC6C12E00EC695D /* RegistrationInterface.h */,
|
|
||||||
CE515DEC0FC6C12E00EC695D /* RegistrationInterface.m */,
|
|
||||||
CE515DED0FC6C12E00EC695D /* Table.h */,
|
|
||||||
CE515DEE0FC6C12E00EC695D /* Table.m */,
|
|
||||||
CE515DEF0FC6C12E00EC695D /* Utils.h */,
|
CE515DEF0FC6C12E00EC695D /* Utils.h */,
|
||||||
CE515DF00FC6C12E00EC695D /* Utils.m */,
|
CE515DF00FC6C12E00EC695D /* Utils.m */,
|
||||||
CE515DF10FC6C12E00EC695D /* ValueTransformers.h */,
|
CE515DF10FC6C12E00EC695D /* ValueTransformers.h */,
|
||||||
@@ -299,6 +388,12 @@
|
|||||||
CE515E140FC6C17900EC695D /* dgbase */ = {
|
CE515E140FC6C17900EC695D /* dgbase */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CEB14D26124DFC2800FA7481 /* PyResultTable.h */,
|
||||||
|
CEB14D27124DFC2800FA7481 /* ResultTable.h */,
|
||||||
|
CEB14D28124DFC2800FA7481 /* ResultTable.m */,
|
||||||
|
CE003CCD11242D2C004B0AA7 /* DirectoryOutline.h */,
|
||||||
|
CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */,
|
||||||
|
CE003CCF11242D2C004B0AA7 /* PyDirectoryOutline.h */,
|
||||||
CE515E150FC6C19300EC695D /* AppDelegate.h */,
|
CE515E150FC6C19300EC695D /* AppDelegate.h */,
|
||||||
CE515E160FC6C19300EC695D /* AppDelegate.m */,
|
CE515E160FC6C19300EC695D /* AppDelegate.m */,
|
||||||
CE515E170FC6C19300EC695D /* Consts.h */,
|
CE515E170FC6C19300EC695D /* Consts.h */,
|
||||||
@@ -306,9 +401,16 @@
|
|||||||
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */,
|
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */,
|
||||||
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
|
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
|
||||||
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
|
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
|
||||||
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
|
CE0A0C011175A1DE00DCA3C6 /* ProblemDialog.h */,
|
||||||
|
CE0A0C021175A1DE00DCA3C6 /* ProblemDialog.m */,
|
||||||
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
|
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
|
||||||
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
|
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
|
||||||
|
CEDF07A1112493B200EE5BC0 /* StatsLabel.h */,
|
||||||
|
CEDF07A2112493B200EE5BC0 /* StatsLabel.m */,
|
||||||
|
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
|
||||||
|
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */,
|
||||||
|
CE0A0C031175A1DE00DCA3C6 /* PyProblemDialog.h */,
|
||||||
|
CEDF07A0112493B200EE5BC0 /* PyStatsLabel.h */,
|
||||||
);
|
);
|
||||||
name = dgbase;
|
name = dgbase;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -316,9 +418,6 @@
|
|||||||
CEFC294309C89E0000D9F998 /* images */ = {
|
CEFC294309C89E0000D9F998 /* images */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CEA7D2C40FDFED340037CD8C /* dgme_logo_32.png */,
|
|
||||||
CED2A6870A05102600AC4C3F /* power_marker32.png */,
|
|
||||||
CEF7823709C8AA0200EF38FF /* gear.png */,
|
|
||||||
CEFC295309C89FF200D9F998 /* details32.png */,
|
CEFC295309C89FF200D9F998 /* details32.png */,
|
||||||
CEFC295409C89FF200D9F998 /* preferences32.png */,
|
CEFC295409C89FF200D9F998 /* preferences32.png */,
|
||||||
CEFC294509C89E3D00D9F998 /* folder32.png */,
|
CEFC294509C89E3D00D9F998 /* folder32.png */,
|
||||||
@@ -357,6 +456,13 @@
|
|||||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */;
|
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */;
|
||||||
compatibilityVersion = "Xcode 3.0";
|
compatibilityVersion = "Xcode 3.0";
|
||||||
hasScannedForEncodings = 1;
|
hasScannedForEncodings = 1;
|
||||||
|
knownRegions = (
|
||||||
|
English,
|
||||||
|
Japanese,
|
||||||
|
French,
|
||||||
|
German,
|
||||||
|
en,
|
||||||
|
);
|
||||||
mainGroup = 29B97314FDCFA39411CA2CEA /* dupeguru */;
|
mainGroup = 29B97314FDCFA39411CA2CEA /* dupeguru */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
@@ -371,23 +477,21 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */,
|
|
||||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
|
|
||||||
CE381D0509915304003581CE /* dg_cocoa.plugin in Resources */,
|
CE381D0509915304003581CE /* dg_cocoa.plugin in Resources */,
|
||||||
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */,
|
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */,
|
||||||
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */,
|
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */,
|
||||||
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */,
|
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */,
|
||||||
CEFC295509C89FF200D9F998 /* details32.png in Resources */,
|
CEFC295509C89FF200D9F998 /* details32.png in Resources */,
|
||||||
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */,
|
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */,
|
||||||
CEF7823809C8AA0200EF38FF /* gear.png in Resources */,
|
|
||||||
CECA899909DB12CA00A3D774 /* Details.nib in Resources */,
|
|
||||||
CE3AA46709DB207900DB3A21 /* Directories.nib in Resources */,
|
|
||||||
CED2A6880A05102700AC4C3F /* power_marker32.png in Resources */,
|
|
||||||
CE515E020FC6C13E00EC695D /* ErrorReportWindow.xib in Resources */,
|
|
||||||
CE515E030FC6C13E00EC695D /* progress.nib in Resources */,
|
|
||||||
CE515E040FC6C13E00EC695D /* registration.nib in Resources */,
|
|
||||||
CEA7D2C50FDFED340037CD8C /* dgme_logo_32.png in Resources */,
|
|
||||||
CE6E0E9F1054EB97008D9390 /* dsa_pub.pem in Resources */,
|
CE6E0E9F1054EB97008D9390 /* dsa_pub.pem in Resources */,
|
||||||
|
CE3FBDD31094637800B72D77 /* DetailsPanel.xib in Resources */,
|
||||||
|
CE3FBDD41094637800B72D77 /* DirectoryPanel.xib in Resources */,
|
||||||
|
CE900AD2109B238600754048 /* Preferences.xib in Resources */,
|
||||||
|
CE900AD7109B2A9B00754048 /* MainMenu.xib in Resources */,
|
||||||
|
CE4B59C81119919700C06C9E /* ErrorReportWindow.xib in Resources */,
|
||||||
|
CE4B59C91119919700C06C9E /* progress.xib in Resources */,
|
||||||
|
CE0A0C061175A24800DCA3C6 /* ProblemDialog.xib in Resources */,
|
||||||
|
CE74A12712537F2E008A8DF0 /* FairwareReminder.xib in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -402,153 +506,97 @@
|
|||||||
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */,
|
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */,
|
||||||
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */,
|
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */,
|
||||||
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */,
|
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */,
|
||||||
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */,
|
|
||||||
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */,
|
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */,
|
||||||
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */,
|
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */,
|
||||||
CE515DF50FC6C12E00EC695D /* Outline.m in Sources */,
|
|
||||||
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */,
|
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */,
|
||||||
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */,
|
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */,
|
||||||
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */,
|
|
||||||
CE515DF90FC6C12E00EC695D /* Table.m in Sources */,
|
|
||||||
CE515DFA0FC6C12E00EC695D /* Utils.m in Sources */,
|
CE515DFA0FC6C12E00EC695D /* Utils.m in Sources */,
|
||||||
CE515DFB0FC6C12E00EC695D /* ValueTransformers.m in Sources */,
|
CE515DFB0FC6C12E00EC695D /* ValueTransformers.m in Sources */,
|
||||||
CE515E1D0FC6C19300EC695D /* AppDelegate.m in Sources */,
|
CE515E1D0FC6C19300EC695D /* AppDelegate.m in Sources */,
|
||||||
CE515E1E0FC6C19300EC695D /* DirectoryPanel.m in Sources */,
|
CE515E1E0FC6C19300EC695D /* DirectoryPanel.m in Sources */,
|
||||||
CE515E1F0FC6C19300EC695D /* ResultWindow.m in Sources */,
|
CE515E1F0FC6C19300EC695D /* ResultWindow.m in Sources */,
|
||||||
CE49DEF60FDFEB810098617B /* BRSingleLineFormatter.m in Sources */,
|
CE49DEF60FDFEB810098617B /* BRSingleLineFormatter.m in Sources */,
|
||||||
CE49DEF70FDFEB810098617B /* NSCharacterSet_Extensions.m in Sources */,
|
|
||||||
CE6032C00FE6784C007E33FF /* DetailsPanel.m in Sources */,
|
CE6032C00FE6784C007E33FF /* DetailsPanel.m in Sources */,
|
||||||
|
CE003CC611242D00004B0AA7 /* HSGUIController.m in Sources */,
|
||||||
|
CE003CC711242D00004B0AA7 /* HSOutline.m in Sources */,
|
||||||
|
CE003CC811242D00004B0AA7 /* HSWindowController.m in Sources */,
|
||||||
|
CE003CC911242D00004B0AA7 /* NSEventAdditions.m in Sources */,
|
||||||
|
CE003CCA11242D00004B0AA7 /* HSOutlineView.m in Sources */,
|
||||||
|
CE003CCB11242D00004B0AA7 /* NSIndexPathAdditions.m in Sources */,
|
||||||
|
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */,
|
||||||
|
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */,
|
||||||
|
CEDF07A3112493B200EE5BC0 /* StatsLabel.m in Sources */,
|
||||||
|
CE0A0C001175A1C000DCA3C6 /* HSTable.m in Sources */,
|
||||||
|
CE0A0C041175A1DE00DCA3C6 /* ProblemDialog.m in Sources */,
|
||||||
|
CEB14D29124DFC2800FA7481 /* ResultTable.m in Sources */,
|
||||||
|
CE578303124DFC660004769C /* HSTableView.m in Sources */,
|
||||||
|
CE74A12412537F06008A8DF0 /* HSFairwareReminder.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = {
|
CE74A12512537F2E008A8DF0 /* FairwareReminder.xib */ = {
|
||||||
isa = PBXVariantGroup;
|
isa = PBXVariantGroup;
|
||||||
children = (
|
children = (
|
||||||
089C165DFE840E0CC02AAC07 /* English */,
|
CE74A12612537F2E008A8DF0 /* en */,
|
||||||
);
|
);
|
||||||
name = InfoPlist.strings;
|
name = FairwareReminder.xib;
|
||||||
sourceTree = "<group>";
|
path = ../../cocoalib/xib;
|
||||||
};
|
|
||||||
29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
29B97319FDCFA39411CA2CEA /* English */,
|
|
||||||
);
|
|
||||||
name = MainMenu.nib;
|
|
||||||
sourceTree = SOURCE_ROOT;
|
sourceTree = SOURCE_ROOT;
|
||||||
};
|
};
|
||||||
CE3AA46509DB207900DB3A21 /* Directories.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CE3AA46609DB207900DB3A21 /* English */,
|
|
||||||
);
|
|
||||||
name = Directories.nib;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
CE515DFC0FC6C13E00EC695D /* ErrorReportWindow.xib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CE515DFD0FC6C13E00EC695D /* English */,
|
|
||||||
);
|
|
||||||
name = ErrorReportWindow.xib;
|
|
||||||
sourceTree = SOURCE_ROOT;
|
|
||||||
};
|
|
||||||
CE515DFE0FC6C13E00EC695D /* progress.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CE515DFF0FC6C13E00EC695D /* English */,
|
|
||||||
);
|
|
||||||
name = progress.nib;
|
|
||||||
sourceTree = SOURCE_ROOT;
|
|
||||||
};
|
|
||||||
CE515E000FC6C13E00EC695D /* registration.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CE515E010FC6C13E00EC695D /* English */,
|
|
||||||
);
|
|
||||||
name = registration.nib;
|
|
||||||
sourceTree = SOURCE_ROOT;
|
|
||||||
};
|
|
||||||
CECA899709DB12CA00A3D774 /* Details.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CECA899809DB12CA00A3D774 /* English */,
|
|
||||||
);
|
|
||||||
name = Details.nib;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
C01FCF4B08A954540054247B /* Debug */ = {
|
C01FCF4C08A954540054247B /* release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(FRAMEWORK_SEARCH_PATHS)",
|
|
||||||
"$(SRCROOT)/../../../cocoalib/build/Release",
|
|
||||||
"\"$(SRCROOT)/../../base/cocoa/build/Release\"",
|
|
||||||
);
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
|
||||||
GCC_MODEL_TUNING = G5;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
INFOPLIST_FILE = Info.plist;
|
|
||||||
INSTALL_PATH = "$(HOME)/Applications";
|
|
||||||
PRODUCT_NAME = dupeGuru;
|
|
||||||
WRAPPER_EXTENSION = app;
|
|
||||||
ZERO_LINK = YES;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
C01FCF4C08A954540054247B /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(FRAMEWORK_SEARCH_PATHS)",
|
|
||||||
"$(SRCROOT)/../../../cocoalib/build/Release",
|
|
||||||
"\"$(SRCROOT)/../../base/cocoa/build/Release\"",
|
|
||||||
);
|
|
||||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||||
GCC_MODEL_TUNING = G5;
|
|
||||||
INFOPLIST_FILE = Info.plist;
|
INFOPLIST_FILE = Info.plist;
|
||||||
INSTALL_PATH = "$(HOME)/Applications";
|
INSTALL_PATH = "$(HOME)/Applications";
|
||||||
PRODUCT_NAME = "dupeGuru ME";
|
PRODUCT_NAME = "dupeGuru ME";
|
||||||
WRAPPER_EXTENSION = app;
|
WRAPPER_EXTENSION = app;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = release;
|
||||||
};
|
};
|
||||||
C01FCF4F08A954540054247B /* Debug */ = {
|
C01FCF5008A954540054247B /* release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ARCHS = (
|
||||||
|
i386,
|
||||||
|
x86_64,
|
||||||
|
ppc,
|
||||||
|
);
|
||||||
GCC_C_LANGUAGE_STANDARD = c99;
|
GCC_C_LANGUAGE_STANDARD = c99;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.4;
|
MACOSX_DEPLOYMENT_TARGET = 10.5;
|
||||||
PREBINDING = NO;
|
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
|
||||||
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk";
|
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = release;
|
||||||
};
|
};
|
||||||
C01FCF5008A954540054247B /* Release */ = {
|
CED596C5111AF56D00C0CF2B /* dev */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)";
|
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
|
||||||
ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = c99;
|
GCC_C_LANGUAGE_STANDARD = c99;
|
||||||
GCC_VERSION = 4.0;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.4;
|
MACOSX_DEPLOYMENT_TARGET = 10.5;
|
||||||
PREBINDING = NO;
|
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
|
||||||
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk";
|
|
||||||
STRIP_INSTALLED_PRODUCT = NO;
|
|
||||||
};
|
};
|
||||||
name = Release;
|
name = dev;
|
||||||
|
};
|
||||||
|
CED596C6111AF56D00C0CF2B /* dev */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(HOME)/Applications";
|
||||||
|
PRODUCT_NAME = "dupeGuru ME";
|
||||||
|
WRAPPER_EXTENSION = app;
|
||||||
|
};
|
||||||
|
name = dev;
|
||||||
};
|
};
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
@@ -556,20 +604,20 @@
|
|||||||
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "dupeguru" */ = {
|
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "dupeguru" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
C01FCF4B08A954540054247B /* Debug */,
|
C01FCF4C08A954540054247B /* release */,
|
||||||
C01FCF4C08A954540054247B /* Release */,
|
CED596C6111AF56D00C0CF2B /* dev */,
|
||||||
);
|
);
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = release;
|
||||||
};
|
};
|
||||||
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */ = {
|
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
C01FCF4F08A954540054247B /* Debug */,
|
C01FCF5008A954540054247B /* release */,
|
||||||
C01FCF5008A954540054247B /* Release */,
|
CED596C5111AF56D00C0CF2B /* dev */,
|
||||||
);
|
);
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
};
|
};
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
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
|
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 <Cocoa/Cocoa.h>
|
||||||
|
#import "Utils.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
[Utils setPluginName:@"dg_cocoa"];
|
||||||
NSString *pluginPath = [[NSBundle mainBundle]
|
NSString *pluginPath = [[NSBundle mainBundle]
|
||||||
pathForResource:@"dg_cocoa"
|
pathForResource:@"dg_cocoa"
|
||||||
ofType:@"plugin"];
|
ofType:@"plugin"];
|
||||||
2927
cocoa/me/xib/Preferences.xib
Normal file
2927
cocoa/me/xib/Preferences.xib
Normal file
File diff suppressed because it is too large
Load Diff
18
cocoa/pe/AppDelegate.h
Normal file
18
cocoa/pe/AppDelegate.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 "../base/AppDelegate.h"
|
||||||
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
|
@interface AppDelegate : AppDelegateBase {}
|
||||||
|
- (IBAction)openWebsite:(id)sender;
|
||||||
|
- (IBAction)toggleDirectories:(id)sender;
|
||||||
|
|
||||||
|
- (PyDupeGuru *)py;
|
||||||
|
@end
|
||||||
79
cocoa/pe/AppDelegate.m
Normal file
79
cocoa/pe/AppDelegate.m
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
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 "Utils.h"
|
||||||
|
#import "ValueTransformers.h"
|
||||||
|
#import "Consts.h"
|
||||||
|
#import "DetailsPanel.h"
|
||||||
|
#import "DirectoryPanel.h"
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:10];
|
||||||
|
[d setObject:[NSNumber numberWithInt:95] forKey:@"minMatchPercentage"];
|
||||||
|
[d setObject:[NSNumber numberWithInt:1] forKey:@"recreatePathType"];
|
||||||
|
[d setObject:[NSNumber numberWithBool:NO] forKey:@"matchScaled"];
|
||||||
|
[d setObject:[NSNumber numberWithBool:YES] forKey:@"mixFileKind"];
|
||||||
|
[d setObject:[NSNumber numberWithBool:NO] forKey:@"useRegexpFilter"];
|
||||||
|
[d setObject:[NSNumber numberWithBool:NO] forKey:@"ignoreHardlinkMatches"];
|
||||||
|
[d setObject:[NSNumber numberWithBool:NO] forKey:@"removeEmptyFolders"];
|
||||||
|
[d setObject:[NSNumber numberWithBool:NO] forKey:@"debug"];
|
||||||
|
[d setObject:[NSArray array] forKey:@"recentDirectories"];
|
||||||
|
[d setObject:[NSArray array] forKey:@"columnsOrder"];
|
||||||
|
[d setObject:[NSDictionary dictionary] forKey:@"columnsWidth"];
|
||||||
|
[[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:d];
|
||||||
|
[ud registerDefaults:d];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
_directoryPanel = nil;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (DetailsPanel *)detailsPanel
|
||||||
|
{
|
||||||
|
if (!_detailsPanel)
|
||||||
|
_detailsPanel = [[DetailsPanelPE alloc] initWithPy:py];
|
||||||
|
return _detailsPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)openWebsite:(id)sender
|
||||||
|
{
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.hardcoded.net/dupeguru_pe"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)toggleDirectories:(id)sender
|
||||||
|
{
|
||||||
|
[[self directoryPanel] toggleVisible:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (DirectoryPanel *)directoryPanel
|
||||||
|
{
|
||||||
|
if (!_directoryPanel)
|
||||||
|
_directoryPanel = [[DirectoryPanelPE alloc] initWithParentApp:self];
|
||||||
|
return _directoryPanel;
|
||||||
|
}
|
||||||
|
- (PyDupeGuru *)py { return (PyDupeGuru *)py; }
|
||||||
|
|
||||||
|
//Delegate
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||||
|
{
|
||||||
|
NSMenu *actionsMenu = [[[NSApp mainMenu] itemWithTitle:@"Actions"] submenu];
|
||||||
|
// index 2 is just after "Clear Ingore List"
|
||||||
|
NSMenuItem *mi = [actionsMenu insertItemWithTitle:@"Clear Picture Cache" action:@selector(clearPictureCache:) keyEquivalent:@"P" atIndex:2];
|
||||||
|
[mi setTarget:result];
|
||||||
|
[mi setKeyEquivalentModifierMask:NSCommandKeyMask|NSShiftKeyMask];
|
||||||
|
[super applicationDidFinishLaunching:aNotification];
|
||||||
|
}
|
||||||
|
@end
|
||||||
11
cocoa/pe/Consts.h
Normal file
11
cocoa/pe/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 ImageLoadedNotification @"ImageLoadedNotification"
|
||||||
@@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
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
|
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 <Cocoa/Cocoa.h>
|
||||||
#import "dgbase/DetailsPanel.h"
|
#import "../base/DetailsPanel.h"
|
||||||
|
|
||||||
@interface DetailsPanel : DetailsPanelBase
|
@interface DetailsPanelPE : DetailsPanel
|
||||||
{
|
{
|
||||||
IBOutlet NSImageView *dupeImage;
|
IBOutlet NSImageView *dupeImage;
|
||||||
IBOutlet NSProgressIndicator *dupeProgressIndicator;
|
IBOutlet NSProgressIndicator *dupeProgressIndicator;
|
||||||
IBOutlet NSImageView *refImage;
|
IBOutlet NSImageView *refImage;
|
||||||
IBOutlet NSProgressIndicator *refProgressIndicator;
|
IBOutlet NSProgressIndicator *refProgressIndicator;
|
||||||
|
|
||||||
PyApp *py;
|
PyApp *pyApp;
|
||||||
BOOL _needsRefresh;
|
BOOL _needsRefresh;
|
||||||
NSString *_dupePath;
|
NSString *_dupePath;
|
||||||
NSString *_refPath;
|
NSString *_refPath;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
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
|
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 "Utils.h"
|
#import "Utils.h"
|
||||||
@@ -13,11 +13,11 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
#import "DetailsPanel.h"
|
#import "DetailsPanel.h"
|
||||||
#import "Consts.h"
|
#import "Consts.h"
|
||||||
|
|
||||||
@implementation DetailsPanel
|
@implementation DetailsPanelPE
|
||||||
- (id)initWithPy:(PyApp *)aPy
|
- (id)initWithPy:(PyApp *)aPy
|
||||||
{
|
{
|
||||||
self = [super initWithPy:aPy];
|
self = [super initWithPy:aPy];
|
||||||
py = aPy;
|
pyApp = aPy;
|
||||||
_needsRefresh = YES;
|
_needsRefresh = YES;
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(imageLoaded:) name:ImageLoadedNotification object:self];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(imageLoaded:) name:ImageLoadedNotification object:self];
|
||||||
return self;
|
return self;
|
||||||
@@ -36,18 +36,18 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[pool release];
|
[pool release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)refresh
|
- (void)refreshDetails
|
||||||
{
|
{
|
||||||
if (!_needsRefresh)
|
if (!_needsRefresh)
|
||||||
return;
|
return;
|
||||||
[detailsTable reloadData];
|
[detailsTable reloadData];
|
||||||
|
|
||||||
NSString *refPath = [(PyDupeGuru *)py getSelectedDupeRefPath];
|
NSString *refPath = [(PyDupeGuru *)pyApp getSelectedDupeRefPath];
|
||||||
if (_refPath != nil)
|
if (_refPath != nil)
|
||||||
[_refPath autorelease];
|
[_refPath autorelease];
|
||||||
_refPath = [refPath retain];
|
_refPath = [refPath retain];
|
||||||
[NSThread detachNewThreadSelector:@selector(loadImageAsync:) toTarget:self withObject:refPath];
|
[NSThread detachNewThreadSelector:@selector(loadImageAsync:) toTarget:self withObject:refPath];
|
||||||
NSString *dupePath = [(PyDupeGuru *)py getSelectedDupePath];
|
NSString *dupePath = [(PyDupeGuru *)pyApp getSelectedDupePath];
|
||||||
if (_dupePath != nil)
|
if (_dupePath != nil)
|
||||||
[_dupePath autorelease];
|
[_dupePath autorelease];
|
||||||
_dupePath = [dupePath retain];
|
_dupePath = [dupePath retain];
|
||||||
@@ -59,12 +59,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Notifications */
|
/* Notifications */
|
||||||
- (void)duplicateSelectionChanged:(NSNotification *)aNotification
|
|
||||||
{
|
|
||||||
_needsRefresh = YES;
|
|
||||||
[super duplicateSelectionChanged:aNotification];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)imageLoaded:(NSNotification *)aNotification
|
- (void)imageLoaded:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
NSString *imagePath = [[aNotification userInfo] valueForKey:@"imagePath"];
|
NSString *imagePath = [[aNotification userInfo] valueForKey:@"imagePath"];
|
||||||
@@ -80,4 +74,11 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[dupeProgressIndicator stopAnimation:nil];
|
[dupeProgressIndicator stopAnimation:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Python --> Cocoa */
|
||||||
|
- (void)refresh
|
||||||
|
{
|
||||||
|
_needsRefresh = YES;
|
||||||
|
[super refresh];
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
16
cocoa/pe/DirectoryPanel.h
Normal file
16
cocoa/pe/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 DirectoryPanelPE : DirectoryPanel
|
||||||
|
{
|
||||||
|
}
|
||||||
|
- (IBAction)addiPhoto:(id)sender;
|
||||||
|
@end
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
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
|
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 "DirectoryPanel.h"
|
#import "DirectoryPanel.h"
|
||||||
@@ -11,7 +11,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
static NSString* jobAddIPhoto = @"jobAddIPhoto";
|
static NSString* jobAddIPhoto = @"jobAddIPhoto";
|
||||||
|
|
||||||
@implementation DirectoryPanel
|
@implementation DirectoryPanelPE
|
||||||
- (id)initWithParentApp:(id)aParentApp
|
- (id)initWithParentApp:(id)aParentApp
|
||||||
{
|
{
|
||||||
self = [super initWithParentApp:aParentApp];
|
self = [super initWithParentApp:aParentApp];
|
||||||
@@ -44,9 +44,8 @@ static NSString* jobAddIPhoto = @"jobAddIPhoto";
|
|||||||
|
|
||||||
- (void)jobCompleted:(NSNotification *)aNotification
|
- (void)jobCompleted:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
if ([[ProgressController mainProgressController] jobId] == jobAddIPhoto)
|
if ([[ProgressController mainProgressController] jobId] == jobAddIPhoto) {
|
||||||
{
|
[outlineView reloadData];
|
||||||
[directories reloadData];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
@@ -23,11 +23,13 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>hsft</string>
|
<string>hsft</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.7.7</string>
|
<string>1.11.2</string>
|
||||||
<key>NSMainNibFile</key>
|
<key>NSMainNibFile</key>
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>© Hardcoded Software, 2010</string>
|
||||||
<key>SUFeedURL</key>
|
<key>SUFeedURL</key>
|
||||||
<string>http://www.hardcoded.net/updates/dupeguru_pe.appcast</string>
|
<string>http://www.hardcoded.net/updates/dupeguru_pe.appcast</string>
|
||||||
<key>SUPublicDSAKeyFile</key>
|
<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
|
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 <Cocoa/Cocoa.h>
|
||||||
#import "dgbase/PyDupeGuru.h"
|
#import "../base/PyDupeGuru.h"
|
||||||
|
|
||||||
@interface PyDupeGuru : PyDupeGuruBase
|
@interface PyDupeGuru : PyDupeGuruBase
|
||||||
- (void)clearPictureCache;
|
- (void)clearPictureCache;
|
||||||
16
cocoa/pe/ResultWindow.h
Normal file
16
cocoa/pe/ResultWindow.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/ResultWindow.h"
|
||||||
|
|
||||||
|
@interface ResultWindow : ResultWindowBase {}
|
||||||
|
- (IBAction)clearPictureCache:(id)sender;
|
||||||
|
- (IBAction)startDuplicateScan:(id)sender;
|
||||||
|
- (IBAction)toggleDirectories:(id)sender;
|
||||||
|
@end
|
||||||
96
cocoa/pe/ResultWindow.m
Normal file
96
cocoa/pe/ResultWindow.m
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
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 ResultWindow
|
||||||
|
/* Override */
|
||||||
|
- (void)awakeFromNib
|
||||||
|
{
|
||||||
|
[super awakeFromNib];
|
||||||
|
[[self window] setTitle:@"dupeGuru Picture Edition"];
|
||||||
|
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndex:2];
|
||||||
|
[deltaColumns addIndex:5];
|
||||||
|
[table setDeltaColumns:deltaColumns];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actions */
|
||||||
|
- (IBAction)clearPictureCache:(id)sender
|
||||||
|
{
|
||||||
|
if ([Dialogs askYesNo:@"Do you really want to remove all your cached picture analysis?"] == NSAlertSecondButtonReturn) // NO
|
||||||
|
return;
|
||||||
|
[(PyDupeGuru *)py clearPictureCache];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)resetColumnsToDefault:(id)sender
|
||||||
|
{
|
||||||
|
NSMutableArray *columnsOrder = [NSMutableArray array];
|
||||||
|
[columnsOrder addObject:@"0"];
|
||||||
|
[columnsOrder addObject:@"1"];
|
||||||
|
[columnsOrder addObject:@"2"];
|
||||||
|
[columnsOrder addObject:@"4"];
|
||||||
|
[columnsOrder addObject:@"6"];
|
||||||
|
NSMutableDictionary *columnsWidth = [NSMutableDictionary dictionary];
|
||||||
|
[columnsWidth setObject:i2n(162) forKey:@"0"];
|
||||||
|
[columnsWidth setObject:i2n(142) forKey:@"1"];
|
||||||
|
[columnsWidth setObject:i2n(63) forKey:@"2"];
|
||||||
|
[columnsWidth setObject:i2n(73) forKey:@"4"];
|
||||||
|
[columnsWidth setObject:i2n(58) forKey:@"6"];
|
||||||
|
[self restoreColumnsPosition:columnsOrder widths:columnsWidth];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)startDuplicateScan:(id)sender
|
||||||
|
{
|
||||||
|
if ([matches numberOfRows] > 0)
|
||||||
|
{
|
||||||
|
if ([Dialogs askYesNo:@"Are you sure you want to start a new duplicate scan?"] == NSAlertSecondButtonReturn) // NO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||||
|
PyDupeGuru *_py = (PyDupeGuru *)py;
|
||||||
|
[_py setMinMatchPercentage:[ud objectForKey:@"minMatchPercentage"]];
|
||||||
|
[_py setMixFileKind:n2b([ud objectForKey:@"mixFileKind"])];
|
||||||
|
[_py setIgnoreHardlinkMatches:n2b([ud objectForKey:@"ignoreHardlinkMatches"])];
|
||||||
|
[_py setMatchScaled:[ud objectForKey:@"matchScaled"]];
|
||||||
|
int r = n2i([py doScan]);
|
||||||
|
if (r != 0)
|
||||||
|
[[ProgressController mainProgressController] hide];
|
||||||
|
if (r == 3)
|
||||||
|
{
|
||||||
|
[Dialogs showMessage:@"The selected directories contain no scannable file."];
|
||||||
|
[app toggleDirectories:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)toggleDirectories:(id)sender
|
||||||
|
{
|
||||||
|
[(AppDelegate *)app toggleDirectories:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public */
|
||||||
|
- (void)initResultColumns
|
||||||
|
{
|
||||||
|
NSTableColumn *refCol = [matches tableColumnWithIdentifier:@"0"];
|
||||||
|
_resultColumns = [[NSMutableArray alloc] init];
|
||||||
|
[_resultColumns addObject:[matches tableColumnWithIdentifier:@"0"]]; // File Name
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:1 title:@"Directory" width:120 refCol:refCol]];
|
||||||
|
NSTableColumn *sizeCol = [self getColumnForIdentifier:2 title:@"Size (KB)" width:63 refCol:refCol];
|
||||||
|
[[sizeCol dataCell] setAlignment:NSRightTextAlignment];
|
||||||
|
[_resultColumns addObject:sizeCol];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:3 title:@"Kind" width:40 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:4 title:@"Dimensions" width:80 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:5 title:@"Modification" width:120 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:6 title:@"Match %" width:58 refCol:refCol]];
|
||||||
|
[_resultColumns addObject:[self getColumnForIdentifier:7 title:@"Dupe Count" width:80 refCol:refCol]];
|
||||||
|
}
|
||||||
|
@end
|
||||||
45
cocoa/pe/dg_cocoa.py
Normal file
45
cocoa/pe/dg_cocoa.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# 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 core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||||
|
from core_pe import app_cocoa as app_pe_cocoa
|
||||||
|
|
||||||
|
# Fix py2app imports which chokes on relative imports and other stuff
|
||||||
|
import hsutil.conflict
|
||||||
|
import core.engine, core.fs, core.app
|
||||||
|
import core_pe.block, core_pe.cache, core_pe.matchbase, core_pe.data, core_pe._block_osx
|
||||||
|
import xml.etree.ElementPath
|
||||||
|
import gzip
|
||||||
|
import aem.kae
|
||||||
|
import appscript.defaultterminology
|
||||||
|
|
||||||
|
class PyDupeGuru(PyDupeGuruBase):
|
||||||
|
def init(self):
|
||||||
|
self = super(PyDupeGuru, self).init()
|
||||||
|
self.py = app_pe_cocoa.DupeGuruPE()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def clearPictureCache(self):
|
||||||
|
self.py.scanner.clear_picture_cache()
|
||||||
|
|
||||||
|
#---Information
|
||||||
|
def getSelectedDupePath(self):
|
||||||
|
return str(self.py.selected_dupe_path())
|
||||||
|
|
||||||
|
def getSelectedDupeRefPath(self):
|
||||||
|
return str(self.py.selected_dupe_ref_path())
|
||||||
|
|
||||||
|
#---Properties
|
||||||
|
def setMatchScaled_(self,match_scaled):
|
||||||
|
self.py.scanner.match_scaled = match_scaled
|
||||||
|
|
||||||
|
def setMinMatchPercentage_(self,percentage):
|
||||||
|
self.py.scanner.threshold = int(percentage)
|
||||||
|
|
||||||
|
#---Registration
|
||||||
|
def appName(self):
|
||||||
|
return "dupeGuru Picture Edition"
|
||||||
|
|
||||||
@@ -3,50 +3,59 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 42;
|
objectVersion = 44;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
|
|
||||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
|
|
||||||
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
||||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
||||||
|
CE031751109B340A00517EE6 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE031750109B340A00517EE6 /* Preferences.xib */; };
|
||||||
|
CE031754109B345200517EE6 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE031753109B345200517EE6 /* MainMenu.xib */; };
|
||||||
CE073F6309CAE1A3005C1D2F /* dupeguru_pe_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */; };
|
CE073F6309CAE1A3005C1D2F /* dupeguru_pe_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */; };
|
||||||
CE0C46AA0FA0647E000BE99B /* PictureBlocks.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0C46A90FA0647E000BE99B /* PictureBlocks.m */; };
|
CE0C2AB61177011000BC749F /* HSTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0C2AB51177011000BC749F /* HSTable.m */; };
|
||||||
|
CE0C2ABD1177014200BC749F /* ProblemDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0C2ABB1177014200BC749F /* ProblemDialog.m */; };
|
||||||
|
CE0C2AC81177021600BC749F /* ProblemDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE0C2AC71177021600BC749F /* ProblemDialog.xib */; };
|
||||||
CE15C8A80ADEB8B50061D4A5 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */; };
|
CE15C8A80ADEB8B50061D4A5 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */; };
|
||||||
CE15C8C00ADEB8D40061D4A5 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */; };
|
CE15C8C00ADEB8D40061D4A5 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */; };
|
||||||
|
CE1EB5FE12537F9D0034AABB /* HSFairwareReminder.m in Sources */ = {isa = PBXBuildFile; fileRef = CE1EB5FC12537F9D0034AABB /* HSFairwareReminder.m */; };
|
||||||
|
CE1EB60112537FB90034AABB /* FairwareReminder.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE1EB5FF12537FB90034AABB /* FairwareReminder.xib */; };
|
||||||
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
||||||
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9A09914ADF003581CE /* ResultWindow.m */; };
|
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9A09914ADF003581CE /* ResultWindow.m */; };
|
||||||
CE381D0509915304003581CE /* dg_cocoa.plugin in Resources */ = {isa = PBXBuildFile; fileRef = CE381CF509915304003581CE /* dg_cocoa.plugin */; };
|
CE381D0509915304003581CE /* dg_cocoa.plugin in Resources */ = {isa = PBXBuildFile; fileRef = CE381CF509915304003581CE /* dg_cocoa.plugin */; };
|
||||||
CE3AA46709DB207900DB3A21 /* Directories.nib in Resources */ = {isa = PBXBuildFile; fileRef = CE3AA46509DB207900DB3A21 /* Directories.nib */; };
|
|
||||||
CE6044EC0FE6796200B71262 /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE6044EB0FE6796200B71262 /* DetailsPanel.m */; };
|
CE6044EC0FE6796200B71262 /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE6044EB0FE6796200B71262 /* DetailsPanel.m */; };
|
||||||
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE68EE6609ABC48000971085 /* DirectoryPanel.m */; };
|
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE68EE6609ABC48000971085 /* DirectoryPanel.m */; };
|
||||||
CE6E0F3D1054EC62008D9390 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = CE6E0F3C1054EC62008D9390 /* dsa_pub.pem */; };
|
CE6E0F3D1054EC62008D9390 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = CE6E0F3C1054EC62008D9390 /* dsa_pub.pem */; };
|
||||||
|
CE77C89E10946C6D0078B0DB /* DirectoryPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE77C89C10946C6D0078B0DB /* DirectoryPanel.xib */; };
|
||||||
|
CE77C8A810946CE20078B0DB /* DetailsPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE77C8A710946CE20078B0DB /* DetailsPanel.xib */; };
|
||||||
|
CE7AC9181119911200D02F6C /* ErrorReportWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE7AC9151119911200D02F6C /* ErrorReportWindow.xib */; };
|
||||||
|
CE7AC9191119911200D02F6C /* progress.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE7AC9161119911200D02F6C /* progress.xib */; };
|
||||||
CE80DB2E0FC192D60086DCA6 /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1C0FC192D60086DCA6 /* Dialogs.m */; };
|
CE80DB2E0FC192D60086DCA6 /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1C0FC192D60086DCA6 /* Dialogs.m */; };
|
||||||
CE80DB2F0FC192D60086DCA6 /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */; };
|
CE80DB2F0FC192D60086DCA6 /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */; };
|
||||||
CE80DB300FC192D60086DCA6 /* Outline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB200FC192D60086DCA6 /* Outline.m */; };
|
|
||||||
CE80DB310FC192D60086DCA6 /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB220FC192D60086DCA6 /* ProgressController.m */; };
|
CE80DB310FC192D60086DCA6 /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB220FC192D60086DCA6 /* ProgressController.m */; };
|
||||||
CE80DB320FC192D60086DCA6 /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB250FC192D60086DCA6 /* RecentDirectories.m */; };
|
CE80DB320FC192D60086DCA6 /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB250FC192D60086DCA6 /* RecentDirectories.m */; };
|
||||||
CE80DB330FC192D60086DCA6 /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB270FC192D60086DCA6 /* RegistrationInterface.m */; };
|
|
||||||
CE80DB340FC192D60086DCA6 /* Table.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB290FC192D60086DCA6 /* Table.m */; };
|
|
||||||
CE80DB350FC192D60086DCA6 /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB2B0FC192D60086DCA6 /* Utils.m */; };
|
CE80DB350FC192D60086DCA6 /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB2B0FC192D60086DCA6 /* Utils.m */; };
|
||||||
CE80DB360FC192D60086DCA6 /* ValueTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB2D0FC192D60086DCA6 /* ValueTransformers.m */; };
|
CE80DB360FC192D60086DCA6 /* ValueTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB2D0FC192D60086DCA6 /* ValueTransformers.m */; };
|
||||||
CE80DB470FC193650086DCA6 /* NSNotificationAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB460FC193650086DCA6 /* NSNotificationAdditions.m */; };
|
CE80DB470FC193650086DCA6 /* NSNotificationAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB460FC193650086DCA6 /* NSNotificationAdditions.m */; };
|
||||||
CE80DB4A0FC193770086DCA6 /* NSImageAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB490FC193770086DCA6 /* NSImageAdditions.m */; };
|
CE80DB4A0FC193770086DCA6 /* NSImageAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB490FC193770086DCA6 /* NSImageAdditions.m */; };
|
||||||
CE80DB760FC194760086DCA6 /* ErrorReportWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE80DB700FC194760086DCA6 /* ErrorReportWindow.xib */; };
|
|
||||||
CE80DB770FC194760086DCA6 /* progress.nib in Resources */ = {isa = PBXBuildFile; fileRef = CE80DB720FC194760086DCA6 /* progress.nib */; };
|
|
||||||
CE80DB780FC194760086DCA6 /* registration.nib in Resources */ = {isa = PBXBuildFile; fileRef = CE80DB740FC194760086DCA6 /* registration.nib */; };
|
|
||||||
CE80DB8A0FC1951C0086DCA6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB830FC1951C0086DCA6 /* AppDelegate.m */; };
|
CE80DB8A0FC1951C0086DCA6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB830FC1951C0086DCA6 /* AppDelegate.m */; };
|
||||||
CE80DB8B0FC1951C0086DCA6 /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */; };
|
CE80DB8B0FC1951C0086DCA6 /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */; };
|
||||||
CE80DB8C0FC1951C0086DCA6 /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB890FC1951C0086DCA6 /* ResultWindow.m */; };
|
CE80DB8C0FC1951C0086DCA6 /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB890FC1951C0086DCA6 /* ResultWindow.m */; };
|
||||||
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
||||||
|
CE95865F112C516400F95FD2 /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE95865D112C516400F95FD2 /* StatsLabel.m */; };
|
||||||
|
CE9EA7561122C96C008CD2BC /* HSGUIController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7441122C96C008CD2BC /* HSGUIController.m */; };
|
||||||
|
CE9EA7571122C96C008CD2BC /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7461122C96C008CD2BC /* HSOutline.m */; };
|
||||||
|
CE9EA7581122C96C008CD2BC /* HSWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7481122C96C008CD2BC /* HSWindowController.m */; };
|
||||||
|
CE9EA7591122C96C008CD2BC /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA74A1122C96C008CD2BC /* NSEventAdditions.m */; };
|
||||||
|
CE9EA75A1122C96C008CD2BC /* HSOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7511122C96C008CD2BC /* HSOutlineView.m */; };
|
||||||
|
CE9EA75B1122C96C008CD2BC /* NSIndexPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7531122C96C008CD2BC /* NSIndexPathAdditions.m */; };
|
||||||
|
CE9EA75C1122C96C008CD2BC /* NSTableViewAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7551122C96C008CD2BC /* NSTableViewAdditions.m */; };
|
||||||
|
CE9EA7721122CA0B008CD2BC /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7701122CA0B008CD2BC /* DirectoryOutline.m */; };
|
||||||
CEBAE4270FDA97E000B7887D /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */; };
|
CEBAE4270FDA97E000B7887D /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */; };
|
||||||
CEBAE4280FDA97E000B7887D /* NSCharacterSet_Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBAE4260FDA97E000B7887D /* NSCharacterSet_Extensions.m */; };
|
|
||||||
CECA899909DB12CA00A3D774 /* Details.nib in Resources */ = {isa = PBXBuildFile; fileRef = CECA899709DB12CA00A3D774 /* Details.nib */; };
|
|
||||||
CECA899C09DB132E00A3D774 /* DetailsPanel.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CECA899A09DB132E00A3D774 /* DetailsPanel.h */; };
|
CECA899C09DB132E00A3D774 /* DetailsPanel.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CECA899A09DB132E00A3D774 /* DetailsPanel.h */; };
|
||||||
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CECA899B09DB132E00A3D774 /* DetailsPanel.m */; };
|
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CECA899B09DB132E00A3D774 /* DetailsPanel.m */; };
|
||||||
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */ = {isa = PBXBuildFile; fileRef = CEEB135109C837A2004D2330 /* dupeguru.icns */; };
|
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */ = {isa = PBXBuildFile; fileRef = CEEB135109C837A2004D2330 /* dupeguru.icns */; };
|
||||||
CEF7823809C8AA0200EF38FF /* gear.png in Resources */ = {isa = PBXBuildFile; fileRef = CEF7823709C8AA0200EF38FF /* gear.png */; };
|
CEF12A7E124DFD400087B51D /* HSTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = CEF12A7D124DFD400087B51D /* HSTableView.m */; };
|
||||||
|
CEF12A84124DFD620087B51D /* ResultTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CEF12A83124DFD620087B51D /* ResultTable.m */; };
|
||||||
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC294509C89E3D00D9F998 /* folder32.png */; };
|
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC294509C89E3D00D9F998 /* folder32.png */; };
|
||||||
CEFC295509C89FF200D9F998 /* details32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295309C89FF200D9F998 /* details32.png */; };
|
CEFC295509C89FF200D9F998 /* details32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295309C89FF200D9F998 /* details32.png */; };
|
||||||
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295409C89FF200D9F998 /* preferences32.png */; };
|
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295409C89FF200D9F998 /* preferences32.png */; };
|
||||||
@@ -69,78 +78,105 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
|
||||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||||
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
||||||
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; };
|
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; };
|
||||||
29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
|
|
||||||
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
||||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||||
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
|
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
|
||||||
8D1107320486CEB800E47090 /* dupeGuru PE.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "dupeGuru PE.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
8D1107320486CEB800E47090 /* dupeGuru PE.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "dupeGuru PE.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_pe_help; path = help/dupeguru_pe_help; sourceTree = SOURCE_ROOT; };
|
CE031750109B340A00517EE6 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Preferences.xib; sourceTree = "<group>"; };
|
||||||
CE0C46A80FA0647E000BE99B /* PictureBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PictureBlocks.h; sourceTree = "<group>"; };
|
CE031753109B345200517EE6 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MainMenu.xib; path = ../../base/xib/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
CE0C46A90FA0647E000BE99B /* PictureBlocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PictureBlocks.m; sourceTree = "<group>"; };
|
CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_pe_help; path = ../../help_pe/dupeguru_pe_help; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0C2AAA117700E700BC749F /* PyTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyTable.h; sourceTree = "<group>"; };
|
||||||
|
CE0C2AB41177011000BC749F /* HSTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSTable.h; sourceTree = "<group>"; };
|
||||||
|
CE0C2AB51177011000BC749F /* HSTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSTable.m; sourceTree = "<group>"; };
|
||||||
|
CE0C2ABA1177014200BC749F /* ProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProblemDialog.h; path = ../base/ProblemDialog.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0C2ABB1177014200BC749F /* ProblemDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProblemDialog.m; path = ../base/ProblemDialog.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0C2ABC1177014200BC749F /* PyProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyProblemDialog.h; path = ../base/PyProblemDialog.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0C2AC71177021600BC749F /* ProblemDialog.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ProblemDialog.xib; path = ../base/xib/ProblemDialog.xib; sourceTree = SOURCE_ROOT; };
|
||||||
CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
||||||
|
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE1EB5FB12537F9D0034AABB /* HSFairwareReminder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSFairwareReminder.h; path = ../../cocoalib/HSFairwareReminder.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE1EB5FC12537F9D0034AABB /* HSFairwareReminder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSFairwareReminder.m; path = ../../cocoalib/HSFairwareReminder.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE1EB5FD12537F9D0034AABB /* PyFairware.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyFairware.h; path = ../../cocoalib/PyFairware.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE1EB60012537FB90034AABB /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = ../../cocoalib/en.lproj/FairwareReminder.xib; sourceTree = SOURCE_ROOT; };
|
||||||
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE381C9A09914ADF003581CE /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
CE381C9A09914ADF003581CE /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE381C9B09914ADF003581CE /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
CE381C9B09914ADF003581CE /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE381CF509915304003581CE /* dg_cocoa.plugin */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dg_cocoa.plugin; path = py/dist/dg_cocoa.plugin; sourceTree = SOURCE_ROOT; };
|
CE381CF509915304003581CE /* dg_cocoa.plugin */ = {isa = PBXFileReference; lastKnownFileType = folder; path = dg_cocoa.plugin; sourceTree = SOURCE_ROOT; };
|
||||||
CE3AA46609DB207900DB3A21 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/Directories.nib; sourceTree = "<group>"; };
|
CE6044EA0FE6796200B71262 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DetailsPanel.h; path = ../base/DetailsPanel.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE6044EA0FE6796200B71262 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DetailsPanel.h; path = dgbase/DetailsPanel.h; sourceTree = SOURCE_ROOT; };
|
CE6044EB0FE6796200B71262 /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DetailsPanel.m; path = ../base/DetailsPanel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE6044EB0FE6796200B71262 /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DetailsPanel.m; path = dgbase/DetailsPanel.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE68EE6509ABC48000971085 /* DirectoryPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DirectoryPanel.h; sourceTree = SOURCE_ROOT; };
|
CE68EE6509ABC48000971085 /* DirectoryPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DirectoryPanel.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE68EE6609ABC48000971085 /* DirectoryPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DirectoryPanel.m; sourceTree = SOURCE_ROOT; };
|
CE68EE6609ABC48000971085 /* DirectoryPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DirectoryPanel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE6E0F3C1054EC62008D9390 /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dsa_pub.pem; path = dgbase/dsa_pub.pem; sourceTree = "<group>"; };
|
CE6E0F3C1054EC62008D9390 /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dsa_pub.pem; path = ../base/dsa_pub.pem; sourceTree = "<group>"; };
|
||||||
CE80DB1B0FC192D60086DCA6 /* Dialogs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Dialogs.h; path = cocoalib/Dialogs.h; sourceTree = SOURCE_ROOT; };
|
CE77C89C10946C6D0078B0DB /* DirectoryPanel.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = DirectoryPanel.xib; path = ../../base/xib/DirectoryPanel.xib; sourceTree = "<group>"; };
|
||||||
CE80DB1C0FC192D60086DCA6 /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
CE77C8A710946CE20078B0DB /* DetailsPanel.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DetailsPanel.xib; sourceTree = "<group>"; };
|
||||||
CE80DB1D0FC192D60086DCA6 /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
CE7AC9151119911200D02F6C /* ErrorReportWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ErrorReportWindow.xib; sourceTree = "<group>"; };
|
||||||
CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
CE7AC9161119911200D02F6C /* progress.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = progress.xib; sourceTree = "<group>"; };
|
||||||
CE80DB1F0FC192D60086DCA6 /* Outline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Outline.h; path = cocoalib/Outline.h; sourceTree = SOURCE_ROOT; };
|
CE80DB1B0FC192D60086DCA6 /* Dialogs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Dialogs.h; path = ../../cocoalib/Dialogs.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB200FC192D60086DCA6 /* Outline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Outline.m; path = cocoalib/Outline.m; sourceTree = SOURCE_ROOT; };
|
CE80DB1C0FC192D60086DCA6 /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB210FC192D60086DCA6 /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
CE80DB1D0FC192D60086DCA6 /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB220FC192D60086DCA6 /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB230FC192D60086DCA6 /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
CE80DB210FC192D60086DCA6 /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB240FC192D60086DCA6 /* RecentDirectories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecentDirectories.h; path = cocoalib/RecentDirectories.h; sourceTree = SOURCE_ROOT; };
|
CE80DB220FC192D60086DCA6 /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB250FC192D60086DCA6 /* RecentDirectories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RecentDirectories.m; path = cocoalib/RecentDirectories.m; sourceTree = SOURCE_ROOT; };
|
CE80DB230FC192D60086DCA6 /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB260FC192D60086DCA6 /* RegistrationInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegistrationInterface.h; path = cocoalib/RegistrationInterface.h; sourceTree = SOURCE_ROOT; };
|
CE80DB240FC192D60086DCA6 /* RecentDirectories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecentDirectories.h; path = ../../cocoalib/RecentDirectories.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB270FC192D60086DCA6 /* RegistrationInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RegistrationInterface.m; path = cocoalib/RegistrationInterface.m; sourceTree = SOURCE_ROOT; };
|
CE80DB250FC192D60086DCA6 /* RecentDirectories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RecentDirectories.m; path = ../../cocoalib/RecentDirectories.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB280FC192D60086DCA6 /* Table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Table.h; path = cocoalib/Table.h; sourceTree = SOURCE_ROOT; };
|
CE80DB2A0FC192D60086DCA6 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = ../../cocoalib/Utils.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB290FC192D60086DCA6 /* Table.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Table.m; path = cocoalib/Table.m; sourceTree = SOURCE_ROOT; };
|
CE80DB2B0FC192D60086DCA6 /* Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Utils.m; path = ../../cocoalib/Utils.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB2A0FC192D60086DCA6 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = cocoalib/Utils.h; sourceTree = SOURCE_ROOT; };
|
CE80DB2C0FC192D60086DCA6 /* ValueTransformers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueTransformers.h; path = ../../cocoalib/ValueTransformers.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB2B0FC192D60086DCA6 /* Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Utils.m; path = cocoalib/Utils.m; sourceTree = SOURCE_ROOT; };
|
CE80DB2D0FC192D60086DCA6 /* ValueTransformers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ValueTransformers.m; path = ../../cocoalib/ValueTransformers.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB2C0FC192D60086DCA6 /* ValueTransformers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueTransformers.h; path = cocoalib/ValueTransformers.h; sourceTree = SOURCE_ROOT; };
|
CE80DB450FC193650086DCA6 /* NSNotificationAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSNotificationAdditions.h; path = ../../cocoalib/NSNotificationAdditions.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB2D0FC192D60086DCA6 /* ValueTransformers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ValueTransformers.m; path = cocoalib/ValueTransformers.m; sourceTree = SOURCE_ROOT; };
|
CE80DB460FC193650086DCA6 /* NSNotificationAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSNotificationAdditions.m; path = ../../cocoalib/NSNotificationAdditions.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB450FC193650086DCA6 /* NSNotificationAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSNotificationAdditions.h; path = cocoalib/NSNotificationAdditions.h; sourceTree = SOURCE_ROOT; };
|
CE80DB480FC193770086DCA6 /* NSImageAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSImageAdditions.h; path = ../../cocoalib/NSImageAdditions.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB460FC193650086DCA6 /* NSNotificationAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSNotificationAdditions.m; path = cocoalib/NSNotificationAdditions.m; sourceTree = SOURCE_ROOT; };
|
CE80DB490FC193770086DCA6 /* NSImageAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSImageAdditions.m; path = ../../cocoalib/NSImageAdditions.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB480FC193770086DCA6 /* NSImageAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSImageAdditions.h; path = cocoalib/NSImageAdditions.h; sourceTree = SOURCE_ROOT; };
|
CE80DB820FC1951C0086DCA6 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ../base/AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB490FC193770086DCA6 /* NSImageAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSImageAdditions.m; path = cocoalib/NSImageAdditions.m; sourceTree = SOURCE_ROOT; };
|
CE80DB830FC1951C0086DCA6 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = ../base/AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB710FC194760086DCA6 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = cocoalib/English.lproj/ErrorReportWindow.xib; sourceTree = SOURCE_ROOT; };
|
CE80DB840FC1951C0086DCA6 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Consts.h; path = ../base/Consts.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB730FC194760086DCA6 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = cocoalib/English.lproj/progress.nib; sourceTree = SOURCE_ROOT; };
|
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryPanel.h; path = ../base/DirectoryPanel.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB750FC194760086DCA6 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = cocoalib/English.lproj/registration.nib; sourceTree = SOURCE_ROOT; };
|
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryPanel.m; path = ../base/DirectoryPanel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB820FC1951C0086DCA6 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = dgbase/AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDupeGuru.h; path = ../base/PyDupeGuru.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB830FC1951C0086DCA6 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = dgbase/AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultWindow.h; path = ../base/ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB840FC1951C0086DCA6 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Consts.h; path = dgbase/Consts.h; sourceTree = SOURCE_ROOT; };
|
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultWindow.m; path = ../base/ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryPanel.h; path = dgbase/DirectoryPanel.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryPanel.m; path = dgbase/DirectoryPanel.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDupeGuru.h; path = dgbase/PyDupeGuru.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultWindow.h; path = dgbase/ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultWindow.m; path = dgbase/ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
||||||
CEBAE4230FDA97E000B7887D /* BRSingleLineFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BRSingleLineFormatter.h; path = cocoalib/brsinglelineformatter/BRSingleLineFormatter.h; sourceTree = SOURCE_ROOT; };
|
CE958659112C516400F95FD2 /* PyStatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyStatsLabel.h; path = ../base/PyStatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BRSingleLineFormatter.m; path = cocoalib/brsinglelineformatter/BRSingleLineFormatter.m; sourceTree = SOURCE_ROOT; };
|
CE95865C112C516400F95FD2 /* StatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatsLabel.h; path = ../base/StatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEBAE4250FDA97E000B7887D /* NSCharacterSet_Extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSCharacterSet_Extensions.h; path = cocoalib/brsinglelineformatter/NSCharacterSet_Extensions.h; sourceTree = SOURCE_ROOT; };
|
CE95865D112C516400F95FD2 /* StatsLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatsLabel.m; path = ../base/StatsLabel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEBAE4260FDA97E000B7887D /* NSCharacterSet_Extensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSCharacterSet_Extensions.m; path = cocoalib/brsinglelineformatter/NSCharacterSet_Extensions.m; sourceTree = SOURCE_ROOT; };
|
CE9EA7431122C96C008CD2BC /* HSGUIController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSGUIController.h; sourceTree = "<group>"; };
|
||||||
CECA899809DB12CA00A3D774 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/Details.nib; sourceTree = "<group>"; };
|
CE9EA7441122C96C008CD2BC /* HSGUIController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSGUIController.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7451122C96C008CD2BC /* HSOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutline.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7461122C96C008CD2BC /* HSOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutline.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7471122C96C008CD2BC /* HSWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSWindowController.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7481122C96C008CD2BC /* HSWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSWindowController.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7491122C96C008CD2BC /* NSEventAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSEventAdditions.h; path = ../../cocoalib/NSEventAdditions.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA74A1122C96C008CD2BC /* NSEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSEventAdditions.m; path = ../../cocoalib/NSEventAdditions.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA74C1122C96C008CD2BC /* PyGUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyGUI.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA74D1122C96C008CD2BC /* PyOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyOutline.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7501122C96C008CD2BC /* HSOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutlineView.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7511122C96C008CD2BC /* HSOutlineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutlineView.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7521122C96C008CD2BC /* NSIndexPathAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSIndexPathAdditions.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7531122C96C008CD2BC /* NSIndexPathAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSIndexPathAdditions.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7541122C96C008CD2BC /* NSTableViewAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSTableViewAdditions.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7551122C96C008CD2BC /* NSTableViewAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSTableViewAdditions.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA76F1122CA0B008CD2BC /* DirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryOutline.h; path = ../base/DirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA7701122CA0B008CD2BC /* DirectoryOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryOutline.m; path = ../base/DirectoryOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA7711122CA0B008CD2BC /* PyDirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDirectoryOutline.h; path = ../base/PyDirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEBAE4230FDA97E000B7887D /* BRSingleLineFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BRSingleLineFormatter.h; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BRSingleLineFormatter.m; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.m; sourceTree = SOURCE_ROOT; };
|
||||||
CECA899A09DB132E00A3D774 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DetailsPanel.h; sourceTree = "<group>"; };
|
CECA899A09DB132E00A3D774 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DetailsPanel.h; sourceTree = "<group>"; };
|
||||||
CECA899B09DB132E00A3D774 /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DetailsPanel.m; sourceTree = "<group>"; };
|
CECA899B09DB132E00A3D774 /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DetailsPanel.m; sourceTree = "<group>"; };
|
||||||
CEEB135109C837A2004D2330 /* dupeguru.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = dupeguru.icns; sourceTree = "<group>"; };
|
CEEB135109C837A2004D2330 /* dupeguru.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = dupeguru.icns; sourceTree = "<group>"; };
|
||||||
CEF7823709C8AA0200EF38FF /* gear.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gear.png; path = images/gear.png; sourceTree = "<group>"; };
|
CEF12A7C124DFD400087B51D /* HSTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSTableView.h; path = ../../cocoalib/views/HSTableView.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC294509C89E3D00D9F998 /* folder32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = folder32.png; path = images/folder32.png; sourceTree = SOURCE_ROOT; };
|
CEF12A7D124DFD400087B51D /* HSTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSTableView.m; path = ../../cocoalib/views/HSTableView.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC295309C89FF200D9F998 /* details32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = details32.png; path = images/details32.png; sourceTree = SOURCE_ROOT; };
|
CEF12A81124DFD620087B51D /* PyResultTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTable.h; path = ../base/PyResultTable.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC295409C89FF200D9F998 /* preferences32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = preferences32.png; path = images/preferences32.png; sourceTree = SOURCE_ROOT; };
|
CEF12A82124DFD620087B51D /* ResultTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultTable.h; path = ../base/ResultTable.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEFCDE2C0AB0418600C33A93 /* dgpe_logo_32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dgpe_logo_32.png; path = images/dgpe_logo_32.png; sourceTree = SOURCE_ROOT; };
|
CEF12A83124DFD620087B51D /* ResultTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultTable.m; path = ../base/ResultTable.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEFC294509C89E3D00D9F998 /* folder32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = folder32.png; path = ../../images/folder32.png; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEFC295309C89FF200D9F998 /* details32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = details32.png; path = ../../images/details32.png; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEFC295409C89FF200D9F998 /* preferences32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = preferences32.png; path = ../../images/preferences32.png; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEFCDE2C0AB0418600C33A93 /* dgpe_logo_32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dgpe_logo_32.png; path = ../../images/dgpe_logo_32.png; sourceTree = SOURCE_ROOT; };
|
||||||
CEFF18A009A4D387005E6321 /* PyDupeGuru.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = PyDupeGuru.h; sourceTree = SOURCE_ROOT; };
|
CEFF18A009A4D387005E6321 /* PyDupeGuru.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = PyDupeGuru.h; sourceTree = SOURCE_ROOT; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@@ -157,11 +193,9 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
080E96DDFE201D6D7F000001 /* DGPE */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CE0C46A80FA0647E000BE99B /* PictureBlocks.h */,
|
|
||||||
CE0C46A90FA0647E000BE99B /* PictureBlocks.m */,
|
|
||||||
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
||||||
CE381C9409914ACE003581CE /* AppDelegate.m */,
|
CE381C9409914ACE003581CE /* AppDelegate.m */,
|
||||||
CE848A1809DD85810004CB44 /* Consts.h */,
|
CE848A1809DD85810004CB44 /* Consts.h */,
|
||||||
@@ -173,7 +207,7 @@
|
|||||||
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
||||||
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
||||||
);
|
);
|
||||||
name = Classes;
|
name = DGPE;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
||||||
@@ -206,7 +240,7 @@
|
|||||||
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
080E96DDFE201D6D7F000001 /* Classes */,
|
080E96DDFE201D6D7F000001 /* DGPE */,
|
||||||
CE80DB1A0FC192AB0086DCA6 /* cocoalib */,
|
CE80DB1A0FC192AB0086DCA6 /* cocoalib */,
|
||||||
CE80DB810FC194BD0086DCA6 /* dgbase */,
|
CE80DB810FC194BD0086DCA6 /* dgbase */,
|
||||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||||
@@ -228,16 +262,13 @@
|
|||||||
29B97317FDCFA39411CA2CEA /* Resources */ = {
|
29B97317FDCFA39411CA2CEA /* Resources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE77C89A10946C6D0078B0DB /* xib */,
|
||||||
CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */,
|
CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */,
|
||||||
CE381CF509915304003581CE /* dg_cocoa.plugin */,
|
CE381CF509915304003581CE /* dg_cocoa.plugin */,
|
||||||
CEFC294309C89E0000D9F998 /* images */,
|
CEFC294309C89E0000D9F998 /* images */,
|
||||||
CEEB135109C837A2004D2330 /* dupeguru.icns */,
|
CEEB135109C837A2004D2330 /* dupeguru.icns */,
|
||||||
8D1107310486CEB800E47090 /* Info.plist */,
|
8D1107310486CEB800E47090 /* Info.plist */,
|
||||||
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
|
|
||||||
CE6E0F3C1054EC62008D9390 /* dsa_pub.pem */,
|
CE6E0F3C1054EC62008D9390 /* dsa_pub.pem */,
|
||||||
CECA899709DB12CA00A3D774 /* Details.nib */,
|
|
||||||
CE3AA46509DB207900DB3A21 /* Directories.nib */,
|
|
||||||
29B97318FDCFA39411CA2CEA /* MainMenu.nib */,
|
|
||||||
);
|
);
|
||||||
name = Resources;
|
name = Resources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -251,32 +282,55 @@
|
|||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
CE77C89A10946C6D0078B0DB /* xib */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE031753109B345200517EE6 /* MainMenu.xib */,
|
||||||
|
CE77C8A710946CE20078B0DB /* DetailsPanel.xib */,
|
||||||
|
CE77C89C10946C6D0078B0DB /* DirectoryPanel.xib */,
|
||||||
|
CE031750109B340A00517EE6 /* Preferences.xib */,
|
||||||
|
CE0C2AC71177021600BC749F /* ProblemDialog.xib */,
|
||||||
|
);
|
||||||
|
path = xib;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
CE7AC9141119911200D02F6C /* xib */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE1EB5FF12537FB90034AABB /* FairwareReminder.xib */,
|
||||||
|
CE7AC9151119911200D02F6C /* ErrorReportWindow.xib */,
|
||||||
|
CE7AC9161119911200D02F6C /* progress.xib */,
|
||||||
|
);
|
||||||
|
name = xib;
|
||||||
|
path = ../../cocoalib/xib;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
CE80DB1A0FC192AB0086DCA6 /* cocoalib */ = {
|
CE80DB1A0FC192AB0086DCA6 /* cocoalib */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE9EA7421122C96C008CD2BC /* controllers */,
|
||||||
|
CE9EA74B1122C96C008CD2BC /* proxies */,
|
||||||
|
CE9EA74F1122C96C008CD2BC /* views */,
|
||||||
|
CE7AC9141119911200D02F6C /* xib */,
|
||||||
CEBAE4220FDA97E000B7887D /* brsinglelineformatter */,
|
CEBAE4220FDA97E000B7887D /* brsinglelineformatter */,
|
||||||
CE80DB700FC194760086DCA6 /* ErrorReportWindow.xib */,
|
|
||||||
CE80DB720FC194760086DCA6 /* progress.nib */,
|
|
||||||
CE80DB740FC194760086DCA6 /* registration.nib */,
|
|
||||||
CE80DB480FC193770086DCA6 /* NSImageAdditions.h */,
|
CE80DB480FC193770086DCA6 /* NSImageAdditions.h */,
|
||||||
CE80DB490FC193770086DCA6 /* NSImageAdditions.m */,
|
CE80DB490FC193770086DCA6 /* NSImageAdditions.m */,
|
||||||
CE80DB450FC193650086DCA6 /* NSNotificationAdditions.h */,
|
CE80DB450FC193650086DCA6 /* NSNotificationAdditions.h */,
|
||||||
CE80DB460FC193650086DCA6 /* NSNotificationAdditions.m */,
|
CE80DB460FC193650086DCA6 /* NSNotificationAdditions.m */,
|
||||||
|
CE9EA7491122C96C008CD2BC /* NSEventAdditions.h */,
|
||||||
|
CE9EA74A1122C96C008CD2BC /* NSEventAdditions.m */,
|
||||||
CE80DB1B0FC192D60086DCA6 /* Dialogs.h */,
|
CE80DB1B0FC192D60086DCA6 /* Dialogs.h */,
|
||||||
CE80DB1C0FC192D60086DCA6 /* Dialogs.m */,
|
CE80DB1C0FC192D60086DCA6 /* Dialogs.m */,
|
||||||
CE80DB1D0FC192D60086DCA6 /* HSErrorReportWindow.h */,
|
CE80DB1D0FC192D60086DCA6 /* HSErrorReportWindow.h */,
|
||||||
CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */,
|
CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */,
|
||||||
CE80DB1F0FC192D60086DCA6 /* Outline.h */,
|
CE1EB5FB12537F9D0034AABB /* HSFairwareReminder.h */,
|
||||||
CE80DB200FC192D60086DCA6 /* Outline.m */,
|
CE1EB5FC12537F9D0034AABB /* HSFairwareReminder.m */,
|
||||||
|
CE1EB5FD12537F9D0034AABB /* PyFairware.h */,
|
||||||
CE80DB210FC192D60086DCA6 /* ProgressController.h */,
|
CE80DB210FC192D60086DCA6 /* ProgressController.h */,
|
||||||
CE80DB220FC192D60086DCA6 /* ProgressController.m */,
|
CE80DB220FC192D60086DCA6 /* ProgressController.m */,
|
||||||
CE80DB230FC192D60086DCA6 /* PyApp.h */,
|
CE80DB230FC192D60086DCA6 /* PyApp.h */,
|
||||||
CE80DB240FC192D60086DCA6 /* RecentDirectories.h */,
|
CE80DB240FC192D60086DCA6 /* RecentDirectories.h */,
|
||||||
CE80DB250FC192D60086DCA6 /* RecentDirectories.m */,
|
CE80DB250FC192D60086DCA6 /* RecentDirectories.m */,
|
||||||
CE80DB260FC192D60086DCA6 /* RegistrationInterface.h */,
|
|
||||||
CE80DB270FC192D60086DCA6 /* RegistrationInterface.m */,
|
|
||||||
CE80DB280FC192D60086DCA6 /* Table.h */,
|
|
||||||
CE80DB290FC192D60086DCA6 /* Table.m */,
|
|
||||||
CE80DB2A0FC192D60086DCA6 /* Utils.h */,
|
CE80DB2A0FC192D60086DCA6 /* Utils.h */,
|
||||||
CE80DB2B0FC192D60086DCA6 /* Utils.m */,
|
CE80DB2B0FC192D60086DCA6 /* Utils.m */,
|
||||||
CE80DB2C0FC192D60086DCA6 /* ValueTransformers.h */,
|
CE80DB2C0FC192D60086DCA6 /* ValueTransformers.h */,
|
||||||
@@ -288,6 +342,9 @@
|
|||||||
CE80DB810FC194BD0086DCA6 /* dgbase */ = {
|
CE80DB810FC194BD0086DCA6 /* dgbase */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CEF12A81124DFD620087B51D /* PyResultTable.h */,
|
||||||
|
CEF12A82124DFD620087B51D /* ResultTable.h */,
|
||||||
|
CEF12A83124DFD620087B51D /* ResultTable.m */,
|
||||||
CE80DB820FC1951C0086DCA6 /* AppDelegate.h */,
|
CE80DB820FC1951C0086DCA6 /* AppDelegate.h */,
|
||||||
CE80DB830FC1951C0086DCA6 /* AppDelegate.m */,
|
CE80DB830FC1951C0086DCA6 /* AppDelegate.m */,
|
||||||
CE80DB840FC1951C0086DCA6 /* Consts.h */,
|
CE80DB840FC1951C0086DCA6 /* Consts.h */,
|
||||||
@@ -295,30 +352,80 @@
|
|||||||
CE6044EB0FE6796200B71262 /* DetailsPanel.m */,
|
CE6044EB0FE6796200B71262 /* DetailsPanel.m */,
|
||||||
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */,
|
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */,
|
||||||
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */,
|
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */,
|
||||||
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */,
|
CE9EA76F1122CA0B008CD2BC /* DirectoryOutline.h */,
|
||||||
|
CE9EA7701122CA0B008CD2BC /* DirectoryOutline.m */,
|
||||||
|
CE0C2ABA1177014200BC749F /* ProblemDialog.h */,
|
||||||
|
CE0C2ABB1177014200BC749F /* ProblemDialog.m */,
|
||||||
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */,
|
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */,
|
||||||
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */,
|
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */,
|
||||||
|
CE95865C112C516400F95FD2 /* StatsLabel.h */,
|
||||||
|
CE95865D112C516400F95FD2 /* StatsLabel.m */,
|
||||||
|
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */,
|
||||||
|
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */,
|
||||||
|
CE9EA7711122CA0B008CD2BC /* PyDirectoryOutline.h */,
|
||||||
|
CE0C2ABC1177014200BC749F /* PyProblemDialog.h */,
|
||||||
|
CE958659112C516400F95FD2 /* PyStatsLabel.h */,
|
||||||
);
|
);
|
||||||
name = dgbase;
|
name = dgbase;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
CE9EA7421122C96C008CD2BC /* controllers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE9EA7431122C96C008CD2BC /* HSGUIController.h */,
|
||||||
|
CE9EA7441122C96C008CD2BC /* HSGUIController.m */,
|
||||||
|
CE9EA7451122C96C008CD2BC /* HSOutline.h */,
|
||||||
|
CE9EA7461122C96C008CD2BC /* HSOutline.m */,
|
||||||
|
CE0C2AB41177011000BC749F /* HSTable.h */,
|
||||||
|
CE0C2AB51177011000BC749F /* HSTable.m */,
|
||||||
|
CE9EA7471122C96C008CD2BC /* HSWindowController.h */,
|
||||||
|
CE9EA7481122C96C008CD2BC /* HSWindowController.m */,
|
||||||
|
);
|
||||||
|
name = controllers;
|
||||||
|
path = ../../cocoalib/controllers;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE9EA74B1122C96C008CD2BC /* proxies */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE9EA74C1122C96C008CD2BC /* PyGUI.h */,
|
||||||
|
CE9EA74D1122C96C008CD2BC /* PyOutline.h */,
|
||||||
|
CE0C2AAA117700E700BC749F /* PyTable.h */,
|
||||||
|
);
|
||||||
|
name = proxies;
|
||||||
|
path = ../../cocoalib/proxies;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE9EA74F1122C96C008CD2BC /* views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CEF12A7C124DFD400087B51D /* HSTableView.h */,
|
||||||
|
CEF12A7D124DFD400087B51D /* HSTableView.m */,
|
||||||
|
CE9EA7501122C96C008CD2BC /* HSOutlineView.h */,
|
||||||
|
CE9EA7511122C96C008CD2BC /* HSOutlineView.m */,
|
||||||
|
CE9EA7521122C96C008CD2BC /* NSIndexPathAdditions.h */,
|
||||||
|
CE9EA7531122C96C008CD2BC /* NSIndexPathAdditions.m */,
|
||||||
|
CE9EA7541122C96C008CD2BC /* NSTableViewAdditions.h */,
|
||||||
|
CE9EA7551122C96C008CD2BC /* NSTableViewAdditions.m */,
|
||||||
|
);
|
||||||
|
name = views;
|
||||||
|
path = ../../cocoalib/views;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
CEBAE4220FDA97E000B7887D /* brsinglelineformatter */ = {
|
CEBAE4220FDA97E000B7887D /* brsinglelineformatter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CEBAE4230FDA97E000B7887D /* BRSingleLineFormatter.h */,
|
CEBAE4230FDA97E000B7887D /* BRSingleLineFormatter.h */,
|
||||||
CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */,
|
CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */,
|
||||||
CEBAE4250FDA97E000B7887D /* NSCharacterSet_Extensions.h */,
|
|
||||||
CEBAE4260FDA97E000B7887D /* NSCharacterSet_Extensions.m */,
|
|
||||||
);
|
);
|
||||||
name = brsinglelineformatter;
|
name = brsinglelineformatter;
|
||||||
path = cocoalib/brsinglelineformatter;
|
path = ../../cocoalib/brsinglelineformatter;
|
||||||
sourceTree = SOURCE_ROOT;
|
sourceTree = SOURCE_ROOT;
|
||||||
};
|
};
|
||||||
CEFC294309C89E0000D9F998 /* images */ = {
|
CEFC294309C89E0000D9F998 /* images */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CEFCDE2C0AB0418600C33A93 /* dgpe_logo_32.png */,
|
CEFCDE2C0AB0418600C33A93 /* dgpe_logo_32.png */,
|
||||||
CEF7823709C8AA0200EF38FF /* gear.png */,
|
|
||||||
CEFC295309C89FF200D9F998 /* details32.png */,
|
CEFC295309C89FF200D9F998 /* details32.png */,
|
||||||
CEFC295409C89FF200D9F998 /* preferences32.png */,
|
CEFC295409C89FF200D9F998 /* preferences32.png */,
|
||||||
CEFC294509C89E3D00D9F998 /* folder32.png */,
|
CEFC294509C89E3D00D9F998 /* folder32.png */,
|
||||||
@@ -354,8 +461,15 @@
|
|||||||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */;
|
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */;
|
||||||
compatibilityVersion = "Xcode 2.4";
|
compatibilityVersion = "Xcode 3.0";
|
||||||
hasScannedForEncodings = 1;
|
hasScannedForEncodings = 1;
|
||||||
|
knownRegions = (
|
||||||
|
English,
|
||||||
|
Japanese,
|
||||||
|
French,
|
||||||
|
German,
|
||||||
|
en,
|
||||||
|
);
|
||||||
mainGroup = 29B97314FDCFA39411CA2CEA /* dupeguru */;
|
mainGroup = 29B97314FDCFA39411CA2CEA /* dupeguru */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
@@ -370,22 +484,22 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */,
|
|
||||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
|
|
||||||
CE381D0509915304003581CE /* dg_cocoa.plugin in Resources */,
|
CE381D0509915304003581CE /* dg_cocoa.plugin in Resources */,
|
||||||
CE073F6309CAE1A3005C1D2F /* dupeguru_pe_help in Resources */,
|
CE073F6309CAE1A3005C1D2F /* dupeguru_pe_help in Resources */,
|
||||||
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */,
|
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */,
|
||||||
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */,
|
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */,
|
||||||
CEFC295509C89FF200D9F998 /* details32.png in Resources */,
|
CEFC295509C89FF200D9F998 /* details32.png in Resources */,
|
||||||
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */,
|
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */,
|
||||||
CEF7823809C8AA0200EF38FF /* gear.png in Resources */,
|
|
||||||
CECA899909DB12CA00A3D774 /* Details.nib in Resources */,
|
|
||||||
CE3AA46709DB207900DB3A21 /* Directories.nib in Resources */,
|
|
||||||
CEFCDE2D0AB0418600C33A93 /* dgpe_logo_32.png in Resources */,
|
CEFCDE2D0AB0418600C33A93 /* dgpe_logo_32.png in Resources */,
|
||||||
CE80DB760FC194760086DCA6 /* ErrorReportWindow.xib in Resources */,
|
|
||||||
CE80DB770FC194760086DCA6 /* progress.nib in Resources */,
|
|
||||||
CE80DB780FC194760086DCA6 /* registration.nib in Resources */,
|
|
||||||
CE6E0F3D1054EC62008D9390 /* dsa_pub.pem in Resources */,
|
CE6E0F3D1054EC62008D9390 /* dsa_pub.pem in Resources */,
|
||||||
|
CE77C89E10946C6D0078B0DB /* DirectoryPanel.xib in Resources */,
|
||||||
|
CE77C8A810946CE20078B0DB /* DetailsPanel.xib in Resources */,
|
||||||
|
CE031751109B340A00517EE6 /* Preferences.xib in Resources */,
|
||||||
|
CE031754109B345200517EE6 /* MainMenu.xib in Resources */,
|
||||||
|
CE7AC9181119911200D02F6C /* ErrorReportWindow.xib in Resources */,
|
||||||
|
CE7AC9191119911200D02F6C /* progress.xib in Resources */,
|
||||||
|
CE0C2AC81177021600BC749F /* ProblemDialog.xib in Resources */,
|
||||||
|
CE1EB60112537FB90034AABB /* FairwareReminder.xib in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -401,14 +515,10 @@
|
|||||||
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */,
|
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */,
|
||||||
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */,
|
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */,
|
||||||
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */,
|
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */,
|
||||||
CE0C46AA0FA0647E000BE99B /* PictureBlocks.m in Sources */,
|
|
||||||
CE80DB2E0FC192D60086DCA6 /* Dialogs.m in Sources */,
|
CE80DB2E0FC192D60086DCA6 /* Dialogs.m in Sources */,
|
||||||
CE80DB2F0FC192D60086DCA6 /* HSErrorReportWindow.m in Sources */,
|
CE80DB2F0FC192D60086DCA6 /* HSErrorReportWindow.m in Sources */,
|
||||||
CE80DB300FC192D60086DCA6 /* Outline.m in Sources */,
|
|
||||||
CE80DB310FC192D60086DCA6 /* ProgressController.m in Sources */,
|
CE80DB310FC192D60086DCA6 /* ProgressController.m in Sources */,
|
||||||
CE80DB320FC192D60086DCA6 /* RecentDirectories.m in Sources */,
|
CE80DB320FC192D60086DCA6 /* RecentDirectories.m in Sources */,
|
||||||
CE80DB330FC192D60086DCA6 /* RegistrationInterface.m in Sources */,
|
|
||||||
CE80DB340FC192D60086DCA6 /* Table.m in Sources */,
|
|
||||||
CE80DB350FC192D60086DCA6 /* Utils.m in Sources */,
|
CE80DB350FC192D60086DCA6 /* Utils.m in Sources */,
|
||||||
CE80DB360FC192D60086DCA6 /* ValueTransformers.m in Sources */,
|
CE80DB360FC192D60086DCA6 /* ValueTransformers.m in Sources */,
|
||||||
CE80DB470FC193650086DCA6 /* NSNotificationAdditions.m in Sources */,
|
CE80DB470FC193650086DCA6 /* NSNotificationAdditions.m in Sources */,
|
||||||
@@ -417,142 +527,87 @@
|
|||||||
CE80DB8B0FC1951C0086DCA6 /* DirectoryPanel.m in Sources */,
|
CE80DB8B0FC1951C0086DCA6 /* DirectoryPanel.m in Sources */,
|
||||||
CE80DB8C0FC1951C0086DCA6 /* ResultWindow.m in Sources */,
|
CE80DB8C0FC1951C0086DCA6 /* ResultWindow.m in Sources */,
|
||||||
CEBAE4270FDA97E000B7887D /* BRSingleLineFormatter.m in Sources */,
|
CEBAE4270FDA97E000B7887D /* BRSingleLineFormatter.m in Sources */,
|
||||||
CEBAE4280FDA97E000B7887D /* NSCharacterSet_Extensions.m in Sources */,
|
|
||||||
CE6044EC0FE6796200B71262 /* DetailsPanel.m in Sources */,
|
CE6044EC0FE6796200B71262 /* DetailsPanel.m in Sources */,
|
||||||
|
CE9EA7561122C96C008CD2BC /* HSGUIController.m in Sources */,
|
||||||
|
CE9EA7571122C96C008CD2BC /* HSOutline.m in Sources */,
|
||||||
|
CE9EA7581122C96C008CD2BC /* HSWindowController.m in Sources */,
|
||||||
|
CE9EA7591122C96C008CD2BC /* NSEventAdditions.m in Sources */,
|
||||||
|
CE9EA75A1122C96C008CD2BC /* HSOutlineView.m in Sources */,
|
||||||
|
CE9EA75B1122C96C008CD2BC /* NSIndexPathAdditions.m in Sources */,
|
||||||
|
CE9EA75C1122C96C008CD2BC /* NSTableViewAdditions.m in Sources */,
|
||||||
|
CE9EA7721122CA0B008CD2BC /* DirectoryOutline.m in Sources */,
|
||||||
|
CE95865F112C516400F95FD2 /* StatsLabel.m in Sources */,
|
||||||
|
CE0C2AB61177011000BC749F /* HSTable.m in Sources */,
|
||||||
|
CE0C2ABD1177014200BC749F /* ProblemDialog.m in Sources */,
|
||||||
|
CEF12A7E124DFD400087B51D /* HSTableView.m in Sources */,
|
||||||
|
CEF12A84124DFD620087B51D /* ResultTable.m in Sources */,
|
||||||
|
CE1EB5FE12537F9D0034AABB /* HSFairwareReminder.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = {
|
CE1EB5FF12537FB90034AABB /* FairwareReminder.xib */ = {
|
||||||
isa = PBXVariantGroup;
|
isa = PBXVariantGroup;
|
||||||
children = (
|
children = (
|
||||||
089C165DFE840E0CC02AAC07 /* English */,
|
CE1EB60012537FB90034AABB /* en */,
|
||||||
);
|
);
|
||||||
name = InfoPlist.strings;
|
name = FairwareReminder.xib;
|
||||||
sourceTree = "<group>";
|
path = ../../cocoalib/xib;
|
||||||
};
|
|
||||||
29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
29B97319FDCFA39411CA2CEA /* English */,
|
|
||||||
);
|
|
||||||
name = MainMenu.nib;
|
|
||||||
sourceTree = SOURCE_ROOT;
|
sourceTree = SOURCE_ROOT;
|
||||||
};
|
};
|
||||||
CE3AA46509DB207900DB3A21 /* Directories.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CE3AA46609DB207900DB3A21 /* English */,
|
|
||||||
);
|
|
||||||
name = Directories.nib;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
CE80DB700FC194760086DCA6 /* ErrorReportWindow.xib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CE80DB710FC194760086DCA6 /* English */,
|
|
||||||
);
|
|
||||||
name = ErrorReportWindow.xib;
|
|
||||||
sourceTree = SOURCE_ROOT;
|
|
||||||
};
|
|
||||||
CE80DB720FC194760086DCA6 /* progress.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CE80DB730FC194760086DCA6 /* English */,
|
|
||||||
);
|
|
||||||
name = progress.nib;
|
|
||||||
sourceTree = SOURCE_ROOT;
|
|
||||||
};
|
|
||||||
CE80DB740FC194760086DCA6 /* registration.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CE80DB750FC194760086DCA6 /* English */,
|
|
||||||
);
|
|
||||||
name = registration.nib;
|
|
||||||
sourceTree = SOURCE_ROOT;
|
|
||||||
};
|
|
||||||
CECA899709DB12CA00A3D774 /* Details.nib */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
CECA899809DB12CA00A3D774 /* English */,
|
|
||||||
);
|
|
||||||
name = Details.nib;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
C01FCF4B08A954540054247B /* Debug */ = {
|
C01FCF4C08A954540054247B /* release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(FRAMEWORK_SEARCH_PATHS)",
|
|
||||||
"$(SRCROOT)/cocoalib/build/Release",
|
|
||||||
"$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
|
|
||||||
);
|
|
||||||
FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/dgbase/build/Release\"";
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
|
||||||
GCC_MODEL_TUNING = G5;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
INFOPLIST_FILE = Info.plist;
|
|
||||||
INSTALL_PATH = "$(HOME)/Applications";
|
|
||||||
PRODUCT_NAME = dupeGuru;
|
|
||||||
WRAPPER_EXTENSION = app;
|
|
||||||
ZERO_LINK = YES;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
C01FCF4C08A954540054247B /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ARCHS = (
|
|
||||||
ppc,
|
|
||||||
i386,
|
|
||||||
);
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(FRAMEWORK_SEARCH_PATHS)",
|
|
||||||
"$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
|
|
||||||
);
|
|
||||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||||
GCC_MODEL_TUNING = G5;
|
|
||||||
INFOPLIST_FILE = Info.plist;
|
INFOPLIST_FILE = Info.plist;
|
||||||
INSTALL_PATH = "$(HOME)/Applications";
|
INSTALL_PATH = "$(HOME)/Applications";
|
||||||
PRODUCT_NAME = "dupeGuru PE";
|
PRODUCT_NAME = "dupeGuru PE";
|
||||||
WRAPPER_EXTENSION = app;
|
WRAPPER_EXTENSION = app;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = release;
|
||||||
};
|
};
|
||||||
C01FCF4F08A954540054247B /* Debug */ = {
|
C01FCF5008A954540054247B /* release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ARCHS = (
|
||||||
|
i386,
|
||||||
|
x86_64,
|
||||||
|
ppc,
|
||||||
|
);
|
||||||
GCC_C_LANGUAGE_STANDARD = c99;
|
GCC_C_LANGUAGE_STANDARD = c99;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.4;
|
MACOSX_DEPLOYMENT_TARGET = 10.5;
|
||||||
PREBINDING = NO;
|
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
|
||||||
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = release;
|
||||||
};
|
};
|
||||||
C01FCF5008A954540054247B /* Release */ = {
|
CEE00FF0111AF37400BC1A77 /* dev */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)";
|
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
|
||||||
ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386";
|
|
||||||
FRAMEWORK_SEARCH_PATHS = "";
|
|
||||||
GCC_C_LANGUAGE_STANDARD = c99;
|
GCC_C_LANGUAGE_STANDARD = c99;
|
||||||
GCC_VERSION = 4.0;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.4;
|
MACOSX_DEPLOYMENT_TARGET = 10.5;
|
||||||
PREBINDING = NO;
|
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
|
||||||
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
|
||||||
};
|
};
|
||||||
name = Release;
|
name = dev;
|
||||||
|
};
|
||||||
|
CEE00FF1111AF37400BC1A77 /* dev */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(HOME)/Applications";
|
||||||
|
PRODUCT_NAME = "dupeGuru PE";
|
||||||
|
WRAPPER_EXTENSION = app;
|
||||||
|
};
|
||||||
|
name = dev;
|
||||||
};
|
};
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
@@ -560,20 +615,20 @@
|
|||||||
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "dupeguru" */ = {
|
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "dupeguru" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
C01FCF4B08A954540054247B /* Debug */,
|
C01FCF4C08A954540054247B /* release */,
|
||||||
C01FCF4C08A954540054247B /* Release */,
|
CEE00FF1111AF37400BC1A77 /* dev */,
|
||||||
);
|
);
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = release;
|
||||||
};
|
};
|
||||||
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */ = {
|
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
C01FCF4F08A954540054247B /* Debug */,
|
C01FCF5008A954540054247B /* release */,
|
||||||
C01FCF5008A954540054247B /* Release */,
|
CEE00FF0111AF37400BC1A77 /* dev */,
|
||||||
);
|
);
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
};
|
};
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
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
|
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 <Cocoa/Cocoa.h>
|
||||||
|
#import "Utils.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
[Utils setPluginName:@"dg_cocoa"];
|
||||||
NSString *pluginPath = [[NSBundle mainBundle]
|
NSString *pluginPath = [[NSBundle mainBundle]
|
||||||
pathForResource:@"dg_cocoa"
|
pathForResource:@"dg_cocoa"
|
||||||
ofType:@"plugin"];
|
ofType:@"plugin"];
|
||||||
1506
cocoa/pe/xib/DetailsPanel.xib
Normal file
1506
cocoa/pe/xib/DetailsPanel.xib
Normal file
File diff suppressed because it is too large
Load Diff
1985
cocoa/pe/xib/Preferences.xib
Normal file
1985
cocoa/pe/xib/Preferences.xib
Normal file
File diff suppressed because it is too large
Load Diff
18
cocoa/se/AppDelegate.h
Normal file
18
cocoa/se/AppDelegate.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 "../base/AppDelegate.h"
|
||||||
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
|
@interface AppDelegate : AppDelegateBase {}
|
||||||
|
- (IBAction)openWebsite:(id)sender;
|
||||||
|
- (IBAction)toggleDirectories:(id)sender;
|
||||||
|
|
||||||
|
- (PyDupeGuru *)py;
|
||||||
|
@end
|
||||||
61
cocoa/se/AppDelegate.m
Normal file
61
cocoa/se/AppDelegate.m
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
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 "../../cocoalib/ProgressController.h"
|
||||||
|
#import "../../cocoalib/Utils.h"
|
||||||
|
#import "../../cocoalib/ValueTransformers.h"
|
||||||
|
#import "DetailsPanel.h"
|
||||||
|
#import "DirectoryPanel.h"
|
||||||
|
#import "Consts.h"
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSMutableDictionary *d = [NSMutableDictionary dictionary];
|
||||||
|
[d setObject:i2n(1) forKey:@"scanType"];
|
||||||
|
[d setObject:i2n(80) forKey:@"minMatchPercentage"];
|
||||||
|
[d setObject:i2n(30) forKey:@"smallFileThreshold"];
|
||||||
|
[d setObject:i2n(1) forKey:@"recreatePathType"];
|
||||||
|
[d setObject:b2n(YES) forKey:@"wordWeighting"];
|
||||||
|
[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(YES) forKey:@"ignoreSmallFiles"];
|
||||||
|
[d setObject:b2n(NO) forKey:@"debug"];
|
||||||
|
[d setObject:[NSArray array] forKey:@"recentDirectories"];
|
||||||
|
[d setObject:[NSArray array] forKey:@"columnsOrder"];
|
||||||
|
[d setObject:[NSDictionary dictionary] forKey:@"columnsWidth"];
|
||||||
|
[[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:d];
|
||||||
|
[ud registerDefaults:d];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
VTIsIntIn *vt = [[[VTIsIntIn alloc] initWithValues:[NSIndexSet indexSetWithIndex:1] reverse:YES] autorelease];
|
||||||
|
[NSValueTransformer setValueTransformer:vt forName:@"vtScanTypeIsNotContent"];
|
||||||
|
_directoryPanel = nil;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)openWebsite:(id)sender
|
||||||
|
{
|
||||||
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.hardcoded.net/dupeguru"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)toggleDirectories:(id)sender
|
||||||
|
{
|
||||||
|
[[self directoryPanel] toggleVisible:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (PyDupeGuru *)py { return (PyDupeGuru *)py; }
|
||||||
|
@end
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user