mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-01-24 23:51:38 +00:00
Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
14
.hgtags
14
.hgtags
@@ -13,3 +13,17 @@ cbcf9c80fee4c908ef2efbf1c143c9e47676c9b2 pe1.8.0
|
||||
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
|
||||
|
||||
27
README
27
README
@@ -12,9 +12,8 @@ This package contains the source for dupeGuru. To learns how to build it, refer
|
||||
There are also other sub-folder that comes from external repositories (automatically checked out
|
||||
with svn:externals):
|
||||
|
||||
- hsutil: A collection of helpers used across HS applications.
|
||||
- hscommon: A collection of helpers used across HS applications.
|
||||
- hsdocgen: An ad-hoc document generation used across HS project (used for help files)
|
||||
- hsmedia: A library to read audio file metadata, used in dupeGuru ME.
|
||||
- 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.
|
||||
|
||||
@@ -26,27 +25,28 @@ Before being able to build dupeGuru, a few dependencies have to be installed:
|
||||
General dependencies
|
||||
-----
|
||||
|
||||
- Python 2.6 (http://www.python.org)
|
||||
- lxml, to read and write XML files. (http://codespeak.net/lxml/)
|
||||
- Mako, to generate help files. (http://www.makotemplates.org/)
|
||||
- Python 3.1 (http://www.python.org)
|
||||
- Send2Trash3k (http://hg.hardcoded.net/send2trash3k)
|
||||
- hsutil3k (http://hg.hardcoded.net/hsutil3k)
|
||||
- hsaudiotag3k (for ME) (http://hg.hardcoded.net/hsaudiotag3k)
|
||||
- Markdown, to generate help files. (http://pypi.python.org/pypi/Markdown)
|
||||
- PyYaml, for help files and the build system. (http://pyyaml.org/)
|
||||
- Nose, to run unit tests. (http://somethingaboutorange.com/mrl/projects/nose/)
|
||||
- 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.2. (http://pyobjc.sourceforge.net/)
|
||||
- py2app (http://svn.pythonmac.org/py2app/py2app/trunk/doc/index.html)
|
||||
- PyObjC 2.3. (http://pyobjc.sourceforge.net/)
|
||||
- py2app 0.5.4 (http://svn.pythonmac.org/py2app/py2app/trunk/doc/index.html)
|
||||
|
||||
Windows prerequisites
|
||||
---
|
||||
|
||||
- Visual Studio 2008 (Express is enough) is needed to build C extensions. (http://www.microsoft.com/Express/)
|
||||
- PyQt 4.6 (http://www.riverbankcomputing.co.uk/news)
|
||||
- Python Imaging Library for dupeGuru PE. (http://www.pythonware.com/products/pil/)
|
||||
- PyInstaller, if you want to build a exe. You don't need it if you just want to run dupeGuru. (http://www.pyinstaller.org/)
|
||||
- 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
|
||||
@@ -66,8 +66,3 @@ Then, just build the thing and then run it with:
|
||||
If you want to create ready-to-upload package, run:
|
||||
|
||||
python package.py
|
||||
|
||||
64-bit on OS X
|
||||
---
|
||||
|
||||
The "release" configuration of dupeGuru's XCode project build with archs "i386 x86_64 ppc". However there are currently problems with py2app and 64 bit. If you want to correctly build 64-bit apps, refer to http://www.hardcoded.net/articles/building-64-bit-pyobjc-applications-with-py2app.htm .
|
||||
75
build.py
75
build.py
@@ -13,27 +13,28 @@ import os.path as op
|
||||
import shutil
|
||||
|
||||
from setuptools import setup
|
||||
from distutils.extension import Extension
|
||||
import yaml
|
||||
|
||||
from hsdocgen import generate_help, filters
|
||||
from hsutil.build import add_to_pythonpath, print_and_do, build_all_qt_ui, copy_packages
|
||||
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"
|
||||
print("Building help index")
|
||||
os.system('open -a /Developer/Applications/Utilities/Help\\ Indexer.app {0}'.format(help_destpath))
|
||||
|
||||
print "Building dg_cocoa.plugin"
|
||||
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', 'hsmedia'],
|
||||
'me': ['core_me'],
|
||||
'pe': ['core_pe'],
|
||||
}[edition]
|
||||
copy_packages(['core', 'hsutil'] + specific_packages, 'build')
|
||||
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')
|
||||
@@ -54,7 +55,7 @@ def build_cocoa(edition, dev, help_destpath):
|
||||
pthpath = op.join(pluginpath, 'Contents/Resources/dev.pth')
|
||||
open(pthpath, 'w').write(op.abspath('.'))
|
||||
os.chdir(cocoa_project_path)
|
||||
print "Building the XCode project"
|
||||
print("Building the XCode project")
|
||||
args = []
|
||||
if dev:
|
||||
args.append('-configuration dev')
|
||||
@@ -65,38 +66,68 @@ def build_cocoa(edition, dev, help_destpath):
|
||||
os.chdir('..')
|
||||
|
||||
def build_qt(edition, dev):
|
||||
print("Building Qt stuff")
|
||||
build_all_qt_ui(op.join('qtlib', 'ui'))
|
||||
build_all_qt_ui(op.join('qt', 'base'))
|
||||
build_all_qt_ui(op.join('qt', edition))
|
||||
print_and_do("pyrcc4 {0} > {1}".format(op.join('qt', 'base', 'dg.qrc'), op.join('qt', 'base', 'dg_rc.py')))
|
||||
if edition == 'pe':
|
||||
os.chdir(op.join('qt', edition))
|
||||
os.system('python gen.py')
|
||||
os.chdir(op.join('..', '..'))
|
||||
print_and_do("pyrcc4 -py3 {0} > {1}".format(op.join('qt', 'base', 'dg.qrc'), op.join('qt', 'base', 'dg_rc.py')))
|
||||
|
||||
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)
|
||||
print("Building dupeGuru {0} with UI {1}".format(edition.upper(), ui))
|
||||
if dev:
|
||||
print "Building in Dev mode"
|
||||
print("Building in Dev mode")
|
||||
add_to_pythonpath('.')
|
||||
print "Generating Help"
|
||||
print("Generating Help")
|
||||
windows = sys.platform == 'win32'
|
||||
tix = filters.tixgen("https://hardcoded.lighthouseapp.com/projects/31699-dupeguru/tickets/{0}")
|
||||
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))
|
||||
generate_help.main(help_basepath, help_destpath, force_render=not dev, tix=tix, windows=windows)
|
||||
|
||||
print "Building dupeGuru"
|
||||
helpgen.gen(help_basepath, help_destpath, profile=profile)
|
||||
print("Building dupeGuru")
|
||||
if edition == 'pe':
|
||||
os.chdir('core_pe')
|
||||
os.system('python gen.py')
|
||||
os.chdir('..')
|
||||
build_pe_modules(ui)
|
||||
if ui == 'cocoa':
|
||||
build_cocoa(edition, dev, help_destpath)
|
||||
elif ui == 'qt':
|
||||
|
||||
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 "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 "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 "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 "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
|
||||
@@ -14,12 +14,15 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
- (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;
|
||||
|
||||
@@ -41,7 +44,7 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
//Data
|
||||
- (NSNumber *)getIgnoreListCount;
|
||||
- (NSNumber *)getMarkCount;
|
||||
- (NSNumber *)getOperationalErrorCount;
|
||||
- (BOOL)scanWasProblematic;
|
||||
|
||||
//Scanning options
|
||||
- (void)setMinMatchPercentage:(NSNumber *)percentage;
|
||||
|
||||
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 "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 "PyGUI.h"
|
||||
|
||||
@interface PyProblemDialog : PyGUI
|
||||
- (void)revealSelected;
|
||||
@end
|
||||
@@ -10,6 +10,7 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
#import "HSOutlineView.h"
|
||||
#import "StatsLabel.h"
|
||||
#import "ResultOutline.h"
|
||||
#import "ProblemDialog.h"
|
||||
#import "PyDupeGuru.h"
|
||||
|
||||
@interface ResultWindowBase : NSWindowController
|
||||
@@ -28,6 +29,7 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
NSWindowController *preferencesPanel;
|
||||
ResultOutline *outline;
|
||||
StatsLabel *statsLabel;
|
||||
ProblemDialog *problemDialog;
|
||||
}
|
||||
/* Helpers */
|
||||
- (void)fillColumnsMenu;
|
||||
@@ -46,6 +48,8 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
- (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;
|
||||
@@ -58,6 +62,7 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
- (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;
|
||||
|
||||
@@ -21,6 +21,7 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
||||
outline = [[ResultOutline alloc] initWithPyParent:py view:matches];
|
||||
statsLabel = [[StatsLabel alloc] initWithPyParent:py labelView:stats];
|
||||
problemDialog = [[ProblemDialog alloc] initWithPy:py];
|
||||
[self initResultColumns];
|
||||
[self fillColumnsMenu];
|
||||
[deltaSwitch setSelectedSegment:0];
|
||||
@@ -38,6 +39,8 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
{
|
||||
[outline release];
|
||||
[preferencesPanel release];
|
||||
[statsLabel release];
|
||||
[problemDialog release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -197,6 +200,33 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[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];
|
||||
@@ -288,6 +318,17 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[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
|
||||
@@ -349,29 +390,31 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
- (void)jobCompleted:(NSNotification *)aNotification
|
||||
{
|
||||
NSInteger 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
|
||||
if ([py scanWasProblematic]) {
|
||||
[problemDialog showWindow:self];
|
||||
}
|
||||
else {
|
||||
[Dialogs showMessage:@"All marked files were copied sucessfully."];
|
||||
}
|
||||
}
|
||||
else 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
|
||||
if ([py scanWasProblematic]) {
|
||||
[problemDialog showWindow:self];
|
||||
}
|
||||
else {
|
||||
[Dialogs showMessage:@"All marked files were moved sucessfully."];
|
||||
}
|
||||
else if ([lastAction isEqualTo:jobDelete]) {
|
||||
if (r > 0) {
|
||||
NSString *msg = @"%d file(s) couldn't be sent to Trash. They were kept in the results, "\
|
||||
"and still are marked. See the F.A.Q. section in the help file for details.";
|
||||
[Dialogs showMessage:[NSString stringWithFormat:msg,r]];
|
||||
}
|
||||
else
|
||||
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 groupCount = [outline intProperty:@"children_count" valueAtPath:nil];
|
||||
if (groupCount == 0)
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">10C540</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.25</string>
|
||||
<string key="IBDocument.HIToolboxVersion">458.00</string>
|
||||
<string key="IBDocument.SystemVersion">10F569</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">788</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.29</string>
|
||||
<string key="IBDocument.HIToolboxVersion">461.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">740</string>
|
||||
<string key="NS.object.0">788</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -41,7 +41,7 @@
|
||||
<object class="NSWindowTemplate" id="476890502">
|
||||
<int key="NSWindowStyleMask">155</int>
|
||||
<int key="NSWindowBacking">2</int>
|
||||
<string key="NSWindowRect">{{33, 261}, {451, 161}}</string>
|
||||
<string key="NSWindowRect">{{33, 261}, {451, 146}}</string>
|
||||
<int key="NSWTFlags">-260571136</int>
|
||||
<string key="NSWindowTitle">Details of Selected File</string>
|
||||
<object class="NSMutableString" key="NSWindowClass">
|
||||
@@ -51,7 +51,7 @@
|
||||
<characters key="NS.bytes">View</characters>
|
||||
</object>
|
||||
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
<string key="NSWindowContentMinSize">{451, 161}</string>
|
||||
<string key="NSWindowContentMinSize">{451, 146}</string>
|
||||
<object class="NSView" key="NSWindowView" id="1027711962">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
@@ -70,7 +70,7 @@
|
||||
<object class="NSTableView" id="251969872">
|
||||
<reference key="NSNextResponder" ref="488480549"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrameSize">{449, 143}</string>
|
||||
<string key="NSFrameSize">{449, 128}</string>
|
||||
<reference key="NSSuperview" ref="488480549"/>
|
||||
<int key="NSTag">2</int>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
@@ -224,7 +224,7 @@
|
||||
<int key="NSTableViewDraggingDestinationStyle">0</int>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrame">{{1, 17}, {449, 143}}</string>
|
||||
<string key="NSFrame">{{1, 17}, {449, 128}}</string>
|
||||
<reference key="NSSuperview" ref="362108788"/>
|
||||
<reference key="NSNextKeyView" ref="251969872"/>
|
||||
<reference key="NSDocView" ref="251969872"/>
|
||||
@@ -266,7 +266,7 @@
|
||||
</object>
|
||||
<reference ref="717380566"/>
|
||||
</object>
|
||||
<string key="NSFrameSize">{451, 161}</string>
|
||||
<string key="NSFrameSize">{451, 146}</string>
|
||||
<reference key="NSSuperview" ref="1027711962"/>
|
||||
<reference key="NSNextKeyView" ref="488480549"/>
|
||||
<int key="NSsFlags">530</int>
|
||||
@@ -278,12 +278,13 @@
|
||||
<bytes key="NSScrollAmts">QSAAAEEgAABBgAAAQYAAAA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{451, 161}</string>
|
||||
<string key="NSFrameSize">{451, 146}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
</object>
|
||||
<string key="NSScreenRect">{{0, 0}, {1024, 746}}</string>
|
||||
<string key="NSMinSize">{451, 177}</string>
|
||||
<string key="NSMinSize">{451, 162}</string>
|
||||
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
<string key="NSFrameAutosaveName">DetailsPanel</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
@@ -497,12 +498,12 @@
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{109, 656}, {451, 161}}</string>
|
||||
<string>{{109, 671}, {451, 146}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{109, 656}, {451, 161}}</string>
|
||||
<string>{{109, 671}, {451, 146}}</string>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<string>{451, 161}</string>
|
||||
<string>{451, 146}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
@@ -536,11 +537,18 @@
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">DetailsPanel</string>
|
||||
<string key="superclassName">NSWindowController</string>
|
||||
<string key="superclassName">HSWindowController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">detailsTable</string>
|
||||
<string key="NS.object.0">NSTableView</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">detailsTable</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">detailsTable</string>
|
||||
<string key="candidateClassName">NSTableView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../base/DetailsPanel.h</string>
|
||||
@@ -548,7 +556,7 @@
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">DetailsPanel</string>
|
||||
<string key="superclassName">NSWindowController</string>
|
||||
<string key="superclassName">HSWindowController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBUserSource</string>
|
||||
<string key="minorKey"/>
|
||||
@@ -562,6 +570,32 @@
|
||||
<string key="minorKey"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">HSWindowController</string>
|
||||
<string key="superclassName">NSWindowController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../controllers/HSWindowController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="111130406">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSTableView</string>
|
||||
<reference key="sourceIdentifier" ref="111130406"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -1029,6 +1063,13 @@
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">showWindow:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
|
||||
@@ -1037,6 +1078,7 @@
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">10C540</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.25</string>
|
||||
<string key="IBDocument.HIToolboxVersion">458.00</string>
|
||||
<string key="IBDocument.SystemVersion">10F569</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">788</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.29</string>
|
||||
<string key="IBDocument.HIToolboxVersion">461.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">740</string>
|
||||
<string key="NS.object.0">788</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -428,6 +428,7 @@
|
||||
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
|
||||
<string key="NSMinSize">{369, 291}</string>
|
||||
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
<string key="NSFrameAutosaveName">DirectoryPanel</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
@@ -869,6 +870,35 @@
|
||||
<string>id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>askForDirectory:</string>
|
||||
<string>popupAddDirectoryMenu:</string>
|
||||
<string>removeSelectedDirectory:</string>
|
||||
<string>toggleVisible:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">askForDirectory:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">popupAddDirectoryMenu:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">removeSelectedDirectory:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">toggleVisible:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
@@ -884,6 +914,30 @@
|
||||
<string>NSButton</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>addButtonPopUp</string>
|
||||
<string>outlineView</string>
|
||||
<string>removeButton</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">addButtonPopUp</string>
|
||||
<string key="candidateClassName">NSPopUpButton</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">outlineView</string>
|
||||
<string key="candidateClassName">HSOutlineView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">removeButton</string>
|
||||
<string key="candidateClassName">NSButton</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../base/DirectoryPanel.h</string>
|
||||
@@ -1437,6 +1491,13 @@
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">showWindow:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
|
||||
@@ -1445,6 +1506,7 @@
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
@@ -1460,5 +1522,18 @@
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<string key="IBDocument.LastKnownRelativeProjectPath">../../se/dupeguru.xcodeproj</string>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSMenuCheckmark</string>
|
||||
<string>NSMenuMixedState</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>{9, 8}</string>
|
||||
<string>{7, 2}</string>
|
||||
</object>
|
||||
</object>
|
||||
</data>
|
||||
</archive>
|
||||
|
||||
@@ -2,18 +2,17 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">10C540</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.25</string>
|
||||
<string key="IBDocument.HIToolboxVersion">458.00</string>
|
||||
<string key="IBDocument.SystemVersion">10F569</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">788</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.29</string>
|
||||
<string key="IBDocument.HIToolboxVersion">461.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">740</string>
|
||||
<string key="NS.object.0">788</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<integer value="219"/>
|
||||
<integer value="29"/>
|
||||
<integer value="1204"/>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -83,9 +82,11 @@
|
||||
<string key="NSToolbarItemPaletteLabel">Power Marker</string>
|
||||
<nil key="NSToolbarItemToolTip"/>
|
||||
<object class="NSSegmentedControl" key="NSToolbarItemView" id="35398541">
|
||||
<nil key="NSNextResponder"/>
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{7, 14}, {67, 24}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSSegmentedCell" key="NSCell" id="431579725">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
@@ -176,9 +177,11 @@
|
||||
<string key="NSToolbarItemPaletteLabel">Filter</string>
|
||||
<nil key="NSToolbarItemToolTip"/>
|
||||
<object class="NSSearchField" key="NSToolbarItemView" id="1013657232">
|
||||
<nil key="NSNextResponder"/>
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">258</int>
|
||||
<string key="NSFrame">{{0, 14}, {81, 22}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSSearchFieldCell" key="NSCell" id="484816507">
|
||||
<int key="NSCellFlags">343014976</int>
|
||||
@@ -320,9 +323,11 @@
|
||||
<string key="NSToolbarItemPaletteLabel">Action</string>
|
||||
<nil key="NSToolbarItemToolTip"/>
|
||||
<object class="NSPopUpButton" key="NSToolbarItemView" id="165812138">
|
||||
<nil key="NSNextResponder"/>
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{0, 14}, {58, 26}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSPopUpButtonCell" key="NSCell" id="436420677">
|
||||
<int key="NSCellFlags">-2076049856</int>
|
||||
@@ -525,9 +530,11 @@
|
||||
<string key="NSToolbarItemPaletteLabel">Delta Values</string>
|
||||
<nil key="NSToolbarItemToolTip"/>
|
||||
<object class="NSSegmentedControl" key="NSToolbarItemView" id="311230297">
|
||||
<nil key="NSNextResponder"/>
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{4, 14}, {67, 24}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSSegmentedCell" key="NSCell" id="211272396">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
@@ -674,7 +681,7 @@
|
||||
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
<string key="NSWindowContentMinSize">{340, 340}</string>
|
||||
<object class="NSView" key="NSWindowView" id="455829030">
|
||||
<reference key="NSNextResponder"/>
|
||||
<nil key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -823,7 +830,6 @@
|
||||
</object>
|
||||
<string key="NSFrame">{{1, 17}, {515, 317}}</string>
|
||||
<reference key="NSSuperview" ref="417210994"/>
|
||||
<reference key="NSNextKeyView" ref="40047569"/>
|
||||
<reference key="NSDocView" ref="40047569"/>
|
||||
<reference key="NSBGColor" ref="91259834"/>
|
||||
<int key="NScvFlags">4</int>
|
||||
@@ -856,7 +862,6 @@
|
||||
</object>
|
||||
<string key="NSFrame">{{1, 0}, {515, 17}}</string>
|
||||
<reference key="NSSuperview" ref="417210994"/>
|
||||
<reference key="NSNextKeyView" ref="837301452"/>
|
||||
<reference key="NSDocView" ref="837301452"/>
|
||||
<reference key="NSBGColor" ref="91259834"/>
|
||||
<int key="NScvFlags">4</int>
|
||||
@@ -865,7 +870,6 @@
|
||||
</object>
|
||||
<string key="NSFrame">{{20, 45}, {517, 335}}</string>
|
||||
<reference key="NSSuperview" ref="455829030"/>
|
||||
<reference key="NSNextKeyView" ref="948758365"/>
|
||||
<int key="NSsFlags">562</int>
|
||||
<reference key="NSVScroller" ref="167459243"/>
|
||||
<reference key="NSHScroller" ref="916628114"/>
|
||||
@@ -897,7 +901,6 @@
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{557, 400}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
</object>
|
||||
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
|
||||
<string key="NSMinSize">{340, 418}</string>
|
||||
@@ -1029,6 +1032,48 @@
|
||||
<string key="NSName">_NSAppleMenu</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="252491888">
|
||||
<reference key="NSMenu" ref="133452984"/>
|
||||
<string key="NSTitle">File</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
<reference key="NSMixedImage" ref="218295580"/>
|
||||
<string key="NSAction">submenuAction:</string>
|
||||
<object class="NSMenu" key="NSSubmenu" id="948321368">
|
||||
<string key="NSTitle">File</string>
|
||||
<object class="NSMutableArray" key="NSMenuItems">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMenuItem" id="777321316">
|
||||
<reference key="NSMenu" ref="948321368"/>
|
||||
<string key="NSTitle">Load Results...</string>
|
||||
<string key="NSKeyEquiv">o</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
<reference key="NSMixedImage" ref="218295580"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="975401896">
|
||||
<reference key="NSMenu" ref="948321368"/>
|
||||
<string key="NSTitle">Save Results...</string>
|
||||
<string key="NSKeyEquiv">s</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
<reference key="NSMixedImage" ref="218295580"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="630362403">
|
||||
<reference key="NSMenu" ref="948321368"/>
|
||||
<string key="NSTitle">Export Results to XHTML</string>
|
||||
<string key="NSKeyEquiv">E</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
<reference key="NSMixedImage" ref="218295580"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="551331186">
|
||||
<reference key="NSMenu" ref="133452984"/>
|
||||
<string key="NSTitle">Edit</string>
|
||||
@@ -1137,7 +1182,7 @@
|
||||
<object class="NSMenuItem" id="1035429435">
|
||||
<reference key="NSMenu" ref="600111647"/>
|
||||
<string key="NSTitle">Start Duplicate Scan</string>
|
||||
<string key="NSKeyEquiv">s</string>
|
||||
<string key="NSKeyEquiv">d</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
@@ -1146,16 +1191,7 @@
|
||||
<object class="NSMenuItem" id="578499792">
|
||||
<reference key="NSMenu" ref="600111647"/>
|
||||
<string key="NSTitle">Clear Ignore List</string>
|
||||
<string key="NSKeyEquiv">I</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
<reference key="NSMixedImage" ref="218295580"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="630362403">
|
||||
<reference key="NSMenu" ref="600111647"/>
|
||||
<string key="NSTitle">Export Results to XHTML</string>
|
||||
<string key="NSKeyEquiv">E</string>
|
||||
<string key="NSKeyEquiv">G</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
@@ -1231,7 +1267,7 @@
|
||||
<object class="NSMenuItem" id="904423169">
|
||||
<reference key="NSMenu" ref="600111647"/>
|
||||
<string key="NSTitle">Add Selected to Ignore List</string>
|
||||
<string key="NSKeyEquiv">i</string>
|
||||
<string key="NSKeyEquiv">g</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
@@ -1275,6 +1311,15 @@
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
<reference key="NSMixedImage" ref="218295580"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="517397504">
|
||||
<reference key="NSMenu" ref="600111647"/>
|
||||
<string key="NSTitle">Invoke Custom Command</string>
|
||||
<string key="NSKeyEquiv">i</string>
|
||||
<int key="NSKeyEquivModMask">1048576</int>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="852972005"/>
|
||||
<reference key="NSMixedImage" ref="218295580"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="564101661">
|
||||
<reference key="NSMenu" ref="600111647"/>
|
||||
<string key="NSTitle">Rename Selected</string>
|
||||
@@ -2204,6 +2249,30 @@
|
||||
</object>
|
||||
<int key="connectionID">1176</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">invokeCustomCommand:</string>
|
||||
<reference key="source" ref="339936126"/>
|
||||
<reference key="destination" ref="517397504"/>
|
||||
</object>
|
||||
<int key="connectionID">1178</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">saveResults:</string>
|
||||
<reference key="source" ref="339936126"/>
|
||||
<reference key="destination" ref="975401896"/>
|
||||
</object>
|
||||
<int key="connectionID">1207</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">loadResults:</string>
|
||||
<reference key="source" ref="339936126"/>
|
||||
<reference key="destination" ref="777321316"/>
|
||||
</object>
|
||||
<int key="connectionID">1208</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
@@ -2319,6 +2388,7 @@
|
||||
<reference ref="385797557"/>
|
||||
<reference ref="958594216"/>
|
||||
<reference ref="551331186"/>
|
||||
<reference ref="252491888"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">MainMenu</string>
|
||||
@@ -2528,8 +2598,8 @@
|
||||
<reference ref="578499792"/>
|
||||
<reference ref="189815600"/>
|
||||
<reference ref="564101661"/>
|
||||
<reference ref="630362403"/>
|
||||
<reference ref="747820446"/>
|
||||
<reference ref="517397504"/>
|
||||
</object>
|
||||
<reference key="parent" ref="528113253"/>
|
||||
</object>
|
||||
@@ -2603,11 +2673,6 @@
|
||||
<reference key="object" ref="564101661"/>
|
||||
<reference key="parent" ref="600111647"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">947</int>
|
||||
<reference key="object" ref="630362403"/>
|
||||
<reference key="parent" ref="600111647"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">618</int>
|
||||
<reference key="object" ref="385797557"/>
|
||||
@@ -3066,6 +3131,46 @@
|
||||
<reference key="object" ref="747820446"/>
|
||||
<reference key="parent" ref="600111647"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1177</int>
|
||||
<reference key="object" ref="517397504"/>
|
||||
<reference key="parent" ref="600111647"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1203</int>
|
||||
<reference key="object" ref="252491888"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="948321368"/>
|
||||
</object>
|
||||
<reference key="parent" ref="133452984"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1204</int>
|
||||
<reference key="object" ref="948321368"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="777321316"/>
|
||||
<reference ref="975401896"/>
|
||||
<reference ref="630362403"/>
|
||||
</object>
|
||||
<reference key="parent" ref="252491888"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1205</int>
|
||||
<reference key="object" ref="777321316"/>
|
||||
<reference key="parent" ref="948321368"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1206</int>
|
||||
<reference key="object" ref="975401896"/>
|
||||
<reference key="parent" ref="948321368"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">947</int>
|
||||
<reference key="object" ref="630362403"/>
|
||||
<reference key="parent" ref="948321368"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
@@ -3090,6 +3195,7 @@
|
||||
<string>1028.ImportedFromIB2</string>
|
||||
<string>103.IBPluginDependency</string>
|
||||
<string>103.ImportedFromIB2</string>
|
||||
<string>106.IBEditorWindowLastContentRect</string>
|
||||
<string>106.IBPluginDependency</string>
|
||||
<string>106.ImportedFromIB2</string>
|
||||
<string>111.IBPluginDependency</string>
|
||||
@@ -3117,6 +3223,12 @@
|
||||
<string>1171.IBPluginDependency</string>
|
||||
<string>1172.IBPluginDependency</string>
|
||||
<string>1173.IBPluginDependency</string>
|
||||
<string>1177.IBPluginDependency</string>
|
||||
<string>1203.IBPluginDependency</string>
|
||||
<string>1204.IBEditorWindowLastContentRect</string>
|
||||
<string>1204.IBPluginDependency</string>
|
||||
<string>1205.IBPluginDependency</string>
|
||||
<string>1206.IBPluginDependency</string>
|
||||
<string>134.IBPluginDependency</string>
|
||||
<string>134.ImportedFromIB2</string>
|
||||
<string>136.IBPluginDependency</string>
|
||||
@@ -3153,6 +3265,7 @@
|
||||
<string>222.ImportedFromIB2</string>
|
||||
<string>23.IBPluginDependency</string>
|
||||
<string>23.ImportedFromIB2</string>
|
||||
<string>24.IBEditorWindowLastContentRect</string>
|
||||
<string>24.IBPluginDependency</string>
|
||||
<string>24.ImportedFromIB2</string>
|
||||
<string>29.IBEditorWindowLastContentRect</string>
|
||||
@@ -3290,6 +3403,7 @@
|
||||
<string>955.ImportedFromIB2</string>
|
||||
<string>959.IBPluginDependency</string>
|
||||
<string>959.ImportedFromIB2</string>
|
||||
<string>960.IBEditorWindowLastContentRect</string>
|
||||
<string>960.IBPluginDependency</string>
|
||||
<string>960.ImportedFromIB2</string>
|
||||
<string>961.IBPluginDependency</string>
|
||||
@@ -3298,6 +3412,7 @@
|
||||
<string>962.ImportedFromIB2</string>
|
||||
<string>965.IBPluginDependency</string>
|
||||
<string>965.ImportedFromIB2</string>
|
||||
<string>966.IBEditorWindowLastContentRect</string>
|
||||
<string>966.IBPluginDependency</string>
|
||||
<string>966.ImportedFromIB2</string>
|
||||
<string>985.IBPluginDependency</string>
|
||||
@@ -3327,6 +3442,7 @@
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{602, 725}, {196, 43}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
@@ -3344,7 +3460,7 @@
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{79, 766}, {617, 0}}</string>
|
||||
<string>{{409, 745}, {617, 0}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
@@ -3355,6 +3471,12 @@
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{242, 705}, {258, 63}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
@@ -3374,9 +3496,9 @@
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<string>{{109, 366}, {557, 400}}</string>
|
||||
<string>{{439, 345}, {557, 400}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{109, 366}, {557, 400}}</string>
|
||||
<string>{{439, 345}, {557, 400}}</string>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
@@ -3390,9 +3512,10 @@
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{531, 625}, {193, 143}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{140, 768}, {481, 20}}</string>
|
||||
<string>{{140, 768}, {523, 20}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
@@ -3423,7 +3546,7 @@
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{286, 475}, {361, 293}}</string>
|
||||
<string>{{328, 475}, {361, 293}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
@@ -3443,7 +3566,7 @@
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{355, 762}, {64, 6}}</string>
|
||||
<string>{{397, 762}, {64, 6}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{182, 609}, {331, 133}}</string>
|
||||
@@ -3527,6 +3650,7 @@
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{475, 725}, {167, 43}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
@@ -3535,6 +3659,7 @@
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>{{284, 615}, {188, 153}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
@@ -3561,7 +3686,7 @@
|
||||
</object>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">1176</int>
|
||||
<int key="maxID">1208</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
@@ -3582,6 +3707,25 @@
|
||||
<string>id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>openWebsite:</string>
|
||||
<string>toggleDirectories:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">openWebsite:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">toggleDirectories:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">AppDelegate.h</string>
|
||||
@@ -3594,6 +3738,13 @@
|
||||
<string key="NS.key.0">unlockApp:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">unlockApp:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">unlockApp:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
@@ -3609,6 +3760,30 @@
|
||||
<string>NSMenuItem</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>py</string>
|
||||
<string>recentDirectories</string>
|
||||
<string>unlockMenuItem</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">py</string>
|
||||
<string key="candidateClassName">PyDupeGuru</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">recentDirectories</string>
|
||||
<string key="candidateClassName">RecentDirectories</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">unlockMenuItem</string>
|
||||
<string key="candidateClassName">NSMenuItem</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBUserSource</string>
|
||||
<string key="minorKey"/>
|
||||
@@ -3621,6 +3796,13 @@
|
||||
<string key="NS.key.0">unlockApp:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">unlockApp:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">unlockApp:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
@@ -3638,6 +3820,35 @@
|
||||
<string>NSMenuItem</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>py</string>
|
||||
<string>recentDirectories</string>
|
||||
<string>result</string>
|
||||
<string>unlockMenuItem</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">py</string>
|
||||
<string key="candidateClassName">PyDupeGuruBase</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">recentDirectories</string>
|
||||
<string key="candidateClassName">RecentDirectories</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">result</string>
|
||||
<string key="candidateClassName">ResultWindowBase</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">unlockMenuItem</string>
|
||||
<string key="candidateClassName">NSMenuItem</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../base/AppDelegate.h</string>
|
||||
@@ -3746,6 +3957,25 @@
|
||||
<string>id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>clearMenu:</string>
|
||||
<string>menuClick:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">clearMenu:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">menuClick:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
@@ -3759,6 +3989,25 @@
|
||||
<string>NSMenu</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>delegate</string>
|
||||
<string>menu</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">delegate</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">menu</string>
|
||||
<string key="candidateClassName">NSMenu</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../RecentDirectories.h</string>
|
||||
@@ -3776,8 +4025,36 @@
|
||||
<string key="className">ResultWindow</string>
|
||||
<string key="superclassName">ResultWindowBase</string>
|
||||
<object class="NSMutableDictionary" key="actions">
|
||||
<string key="NS.key.0">removeDeadTracks:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>resetColumnsToDefault:</string>
|
||||
<string>startDuplicateScan:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>id</string>
|
||||
<string>id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>resetColumnsToDefault:</string>
|
||||
<string>startDuplicateScan:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">resetColumnsToDefault:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">startDuplicateScan:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
@@ -3799,6 +4076,8 @@
|
||||
<string>exportToXHTML:</string>
|
||||
<string>filter:</string>
|
||||
<string>ignoreSelected:</string>
|
||||
<string>invokeCustomCommand:</string>
|
||||
<string>loadResults:</string>
|
||||
<string>markAll:</string>
|
||||
<string>markInvert:</string>
|
||||
<string>markNone:</string>
|
||||
@@ -3811,6 +4090,7 @@
|
||||
<string>renameSelected:</string>
|
||||
<string>resetColumnsToDefault:</string>
|
||||
<string>revealSelected:</string>
|
||||
<string>saveResults:</string>
|
||||
<string>showPreferencesPanel:</string>
|
||||
<string>startDuplicateScan:</string>
|
||||
<string>switchSelected:</string>
|
||||
@@ -3848,6 +4128,168 @@
|
||||
<string>id</string>
|
||||
<string>id</string>
|
||||
<string>id</string>
|
||||
<string>id</string>
|
||||
<string>id</string>
|
||||
<string>id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>changeDelta:</string>
|
||||
<string>changePowerMarker:</string>
|
||||
<string>clearIgnoreList:</string>
|
||||
<string>copyMarked:</string>
|
||||
<string>deleteMarked:</string>
|
||||
<string>exportToXHTML:</string>
|
||||
<string>filter:</string>
|
||||
<string>ignoreSelected:</string>
|
||||
<string>invokeCustomCommand:</string>
|
||||
<string>loadResults:</string>
|
||||
<string>markAll:</string>
|
||||
<string>markInvert:</string>
|
||||
<string>markNone:</string>
|
||||
<string>markSelected:</string>
|
||||
<string>moveMarked:</string>
|
||||
<string>openClicked:</string>
|
||||
<string>openSelected:</string>
|
||||
<string>removeMarked:</string>
|
||||
<string>removeSelected:</string>
|
||||
<string>renameSelected:</string>
|
||||
<string>resetColumnsToDefault:</string>
|
||||
<string>revealSelected:</string>
|
||||
<string>saveResults:</string>
|
||||
<string>showPreferencesPanel:</string>
|
||||
<string>startDuplicateScan:</string>
|
||||
<string>switchSelected:</string>
|
||||
<string>toggleColumn:</string>
|
||||
<string>toggleDelta:</string>
|
||||
<string>toggleDetailsPanel:</string>
|
||||
<string>togglePowerMarker:</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">changeDelta:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">changePowerMarker:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">clearIgnoreList:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">copyMarked:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">deleteMarked:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">exportToXHTML:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">filter:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">ignoreSelected:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">invokeCustomCommand:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">loadResults:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">markAll:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">markInvert:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">markNone:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">markSelected:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">moveMarked:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">openClicked:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">openSelected:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">removeMarked:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">removeSelected:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">renameSelected:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">resetColumnsToDefault:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">revealSelected:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">saveResults:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">showPreferencesPanel:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">startDuplicateScan:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">switchSelected:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">toggleColumn:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">toggleDelta:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">toggleDetailsPanel:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBActionInfo">
|
||||
<string key="name">togglePowerMarker:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
@@ -3875,6 +4317,55 @@
|
||||
<string>NSTextField</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>app</string>
|
||||
<string>columnsMenu</string>
|
||||
<string>deltaSwitch</string>
|
||||
<string>filterField</string>
|
||||
<string>matches</string>
|
||||
<string>pmSwitch</string>
|
||||
<string>py</string>
|
||||
<string>stats</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">app</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">columnsMenu</string>
|
||||
<string key="candidateClassName">NSMenu</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">deltaSwitch</string>
|
||||
<string key="candidateClassName">NSSegmentedControl</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">filterField</string>
|
||||
<string key="candidateClassName">NSSearchField</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">matches</string>
|
||||
<string key="candidateClassName">HSOutlineView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">pmSwitch</string>
|
||||
<string key="candidateClassName">NSSegmentedControl</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">py</string>
|
||||
<string key="candidateClassName">PyDupeGuruBase</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">stats</string>
|
||||
<string key="candidateClassName">NSTextField</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../base/ResultWindow.h</string>
|
||||
@@ -4466,6 +4957,13 @@
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">showWindow:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
|
||||
@@ -4478,15 +4976,30 @@
|
||||
<string key="NS.key.0">checkForUpdates:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">checkForUpdates:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">checkForUpdates:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">delegate</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">delegate</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">delegate</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<reference key="sourceIdentifier" ref="311396825"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
@@ -4500,7 +5013,30 @@
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<string key="IBDocument.LastKnownRelativeProjectPath">../../me/dupeguru.xcodeproj</string>
|
||||
<string key="IBDocument.LastKnownRelativeProjectPath">../../se/dupeguru.xcodeproj</string>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSActionTemplate</string>
|
||||
<string>NSApplicationIcon</string>
|
||||
<string>NSMenuCheckmark</string>
|
||||
<string>NSMenuMixedState</string>
|
||||
<string>details32</string>
|
||||
<string>folder32</string>
|
||||
<string>preferences32</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>{15, 15}</string>
|
||||
<string>{128, 128}</string>
|
||||
<string>{9, 8}</string>
|
||||
<string>{7, 2}</string>
|
||||
<string>{48, 48}</string>
|
||||
<string>{32, 32}</string>
|
||||
<string>{32, 32}</string>
|
||||
</object>
|
||||
</object>
|
||||
</data>
|
||||
</archive>
|
||||
|
||||
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
@@ -23,7 +23,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>hsft</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.7.2</string>
|
||||
<string>5.9.1</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -20,7 +20,7 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
{
|
||||
[super awakeFromNib];
|
||||
[[self window] setTitle:@"dupeGuru Music Edition"];
|
||||
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,7)];
|
||||
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,6)];
|
||||
[deltaColumns removeIndex:6];
|
||||
[outline setDeltaColumns:deltaColumns];
|
||||
}
|
||||
@@ -38,13 +38,13 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[columnsOrder addObject:@"2"];
|
||||
[columnsOrder addObject:@"3"];
|
||||
[columnsOrder addObject:@"4"];
|
||||
[columnsOrder addObject:@"16"];
|
||||
[columnsOrder addObject:@"15"];
|
||||
NSMutableDictionary *columnsWidth = [NSMutableDictionary dictionary];
|
||||
[columnsWidth setObject:i2n(214) forKey:@"0"];
|
||||
[columnsWidth setObject:i2n(63) forKey:@"2"];
|
||||
[columnsWidth setObject:i2n(50) forKey:@"3"];
|
||||
[columnsWidth setObject:i2n(50) forKey:@"4"];
|
||||
[columnsWidth setObject:i2n(57) forKey:@"16"];
|
||||
[columnsWidth setObject:i2n(57) forKey:@"15"];
|
||||
[self restoreColumnsPosition:columnsOrder widths:columnsWidth];
|
||||
}
|
||||
|
||||
@@ -69,8 +69,6 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[_py setMixFileKind:[ud objectForKey:@"mixFileKind"]];
|
||||
[_py setMatchSimilarWords:[ud objectForKey:@"matchSimilarWords"]];
|
||||
NSInteger r = n2i([py doScan]);
|
||||
if (r == 1)
|
||||
[Dialogs showMessage:@"You cannot make a duplicate scan with only reference directories."];
|
||||
if (r == 3)
|
||||
{
|
||||
[Dialogs showMessage:@"The selected directories contain no scannable file."];
|
||||
@@ -96,18 +94,17 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[_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:@"Creation" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:8 title:@"Modification" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:9 title:@"Title" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:10 title:@"Artist" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:11 title:@"Album" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:12 title:@"Genre" width:80 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:13 title:@"Year" width:40 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:14 title:@"Track Number" width:40 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:15 title:@"Comment" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:16 title:@"Match %" width:57 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:17 title:@"Words Used" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:18 title:@"Dupe Count" width:80 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 */
|
||||
|
||||
@@ -4,18 +4,23 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from hsutil.cocoa import signature
|
||||
from hscommon.cocoa import signature
|
||||
|
||||
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||
from core_me.app_cocoa import DupeGuruME
|
||||
from core.scanner import (SCAN_TYPE_FILENAME, SCAN_TYPE_FIELDS, SCAN_TYPE_FIELDS_NO_ORDER,
|
||||
SCAN_TYPE_TAG, SCAN_TYPE_CONTENT, SCAN_TYPE_CONTENT_AUDIO)
|
||||
from core.scanner import ScanType
|
||||
|
||||
# Fix py2app imports which chokes on relative imports and other stuff
|
||||
from core_me import app_cocoa, data, fs, scanner
|
||||
from hsmedia import aiff, flac, genres, id3v1, id3v2, mp4, mpeg, ogg, wma
|
||||
from lxml import etree, _elementpath
|
||||
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):
|
||||
@@ -41,12 +46,12 @@ class PyDupeGuru(PyDupeGuruBase):
|
||||
def setScanType_(self, scan_type):
|
||||
try:
|
||||
self.py.scanner.scan_type = [
|
||||
SCAN_TYPE_FILENAME,
|
||||
SCAN_TYPE_FIELDS,
|
||||
SCAN_TYPE_FIELDS_NO_ORDER,
|
||||
SCAN_TYPE_TAG,
|
||||
SCAN_TYPE_CONTENT,
|
||||
SCAN_TYPE_CONTENT_AUDIO
|
||||
ScanType.Filename,
|
||||
ScanType.Fields,
|
||||
ScanType.FieldsNoOrder,
|
||||
ScanType.Tag,
|
||||
ScanType.Contents,
|
||||
ScanType.ContentsAudio,
|
||||
][scan_type]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
CE0B3D6711243F83009A7A30 /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0B3D6611243F83009A7A30 /* ResultOutline.m */; };
|
||||
CE1425890AFB718500BD5167 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
||||
CE14259F0AFB719300BD5167 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
||||
@@ -41,7 +44,6 @@
|
||||
CE49DEF60FDFEB810098617B /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CE49DEF30FDFEB810098617B /* BRSingleLineFormatter.m */; };
|
||||
CE4B59C81119919700C06C9E /* ErrorReportWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4B59C51119919700C06C9E /* ErrorReportWindow.xib */; };
|
||||
CE4B59C91119919700C06C9E /* progress.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4B59C61119919700C06C9E /* progress.xib */; };
|
||||
CE4B59CA1119919700C06C9E /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4B59C71119919700C06C9E /* registration.xib */; };
|
||||
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE10FC6C12E00EC695D /* Dialogs.m */; };
|
||||
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */; };
|
||||
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE70FC6C12E00EC695D /* ProgressController.m */; };
|
||||
@@ -58,6 +60,7 @@
|
||||
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
||||
CE900AD2109B238600754048 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE900AD1109B238600754048 /* Preferences.xib */; };
|
||||
CE900AD7109B2A9B00754048 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE900AD6109B2A9B00754048 /* MainMenu.xib */; };
|
||||
CECC563B12144A9000ABF262 /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CECC563912144A9000ABF262 /* registration.xib */; };
|
||||
CEDF07A3112493B200EE5BC0 /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDF07A2112493B200EE5BC0 /* StatsLabel.m */; };
|
||||
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */ = {isa = PBXBuildFile; fileRef = CEEB135109C837A2004D2330 /* dupeguru.icns */; };
|
||||
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC294509C89E3D00D9F998 /* folder32.png */; };
|
||||
@@ -108,6 +111,13 @@
|
||||
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>"; };
|
||||
CE0B3D6411243F83009A7A30 /* PyResultTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTree.h; path = ../base/PyResultTree.h; sourceTree = SOURCE_ROOT; };
|
||||
CE0B3D6511243F83009A7A30 /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
|
||||
CE0B3D6611243F83009A7A30 /* ResultOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultOutline.m; path = ../base/ResultOutline.m; sourceTree = SOURCE_ROOT; };
|
||||
@@ -123,7 +133,6 @@
|
||||
CE49DEF30FDFEB810098617B /* BRSingleLineFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BRSingleLineFormatter.m; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.m; sourceTree = SOURCE_ROOT; };
|
||||
CE4B59C51119919700C06C9E /* ErrorReportWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ErrorReportWindow.xib; sourceTree = "<group>"; };
|
||||
CE4B59C61119919700C06C9E /* progress.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = progress.xib; sourceTree = "<group>"; };
|
||||
CE4B59C71119919700C06C9E /* registration.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = registration.xib; sourceTree = "<group>"; };
|
||||
CE515DE00FC6C12E00EC695D /* Dialogs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Dialogs.h; path = ../../cocoalib/Dialogs.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; };
|
||||
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
||||
@@ -155,8 +164,7 @@
|
||||
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
||||
CE900AD1109B238600754048 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Preferences.xib; 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>"; };
|
||||
CECA899B09DB132E00A3D774 /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DetailsPanel.m; sourceTree = "<group>"; };
|
||||
CECC563A12144A9000ABF262 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = ../../cocoalib/en.lproj/registration.xib; 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; };
|
||||
@@ -181,21 +189,19 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
||||
080E96DDFE201D6D7F000001 /* DGME */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
||||
CE381C9409914ACE003581CE /* AppDelegate.m */,
|
||||
CE848A1809DD85810004CB44 /* Consts.h */,
|
||||
CECA899A09DB132E00A3D774 /* DetailsPanel.h */,
|
||||
CECA899B09DB132E00A3D774 /* DetailsPanel.m */,
|
||||
CE68EE6509ABC48000971085 /* DirectoryPanel.h */,
|
||||
CE68EE6609ABC48000971085 /* DirectoryPanel.m */,
|
||||
CEFF18A009A4D387005E6321 /* PyDupeGuru.h */,
|
||||
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
||||
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
||||
);
|
||||
name = Classes;
|
||||
name = DGME;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
||||
@@ -228,7 +234,7 @@
|
||||
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
080E96DDFE201D6D7F000001 /* Classes */,
|
||||
080E96DDFE201D6D7F000001 /* DGME */,
|
||||
CE515E140FC6C17900EC695D /* dgbase */,
|
||||
CE515DDD0FC6C09400EC695D /* cocoalib */,
|
||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||
@@ -277,6 +283,8 @@
|
||||
CE003CB411242D00004B0AA7 /* HSGUIController.m */,
|
||||
CE003CB511242D00004B0AA7 /* HSOutline.h */,
|
||||
CE003CB611242D00004B0AA7 /* HSOutline.m */,
|
||||
CE0A0BFE1175A1C000DCA3C6 /* HSTable.h */,
|
||||
CE0A0BFF1175A1C000DCA3C6 /* HSTable.m */,
|
||||
CE003CB711242D00004B0AA7 /* HSWindowController.h */,
|
||||
CE003CB811242D00004B0AA7 /* HSWindowController.m */,
|
||||
);
|
||||
@@ -289,6 +297,7 @@
|
||||
children = (
|
||||
CE003CBC11242D00004B0AA7 /* PyGUI.h */,
|
||||
CE003CBD11242D00004B0AA7 /* PyOutline.h */,
|
||||
CE0A0C131175A28100DCA3C6 /* PyTable.h */,
|
||||
);
|
||||
name = proxies;
|
||||
path = ../../cocoalib/proxies;
|
||||
@@ -315,6 +324,7 @@
|
||||
CE3FBDD11094637800B72D77 /* DetailsPanel.xib */,
|
||||
CE3FBDD21094637800B72D77 /* DirectoryPanel.xib */,
|
||||
CE900AD1109B238600754048 /* Preferences.xib */,
|
||||
CE0A0C051175A24800DCA3C6 /* ProblemDialog.xib */,
|
||||
);
|
||||
path = xib;
|
||||
sourceTree = "<group>";
|
||||
@@ -332,9 +342,9 @@
|
||||
CE4B59C41119919700C06C9E /* xib */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CECC563912144A9000ABF262 /* registration.xib */,
|
||||
CE4B59C51119919700C06C9E /* ErrorReportWindow.xib */,
|
||||
CE4B59C61119919700C06C9E /* progress.xib */,
|
||||
CE4B59C71119919700C06C9E /* registration.xib */,
|
||||
);
|
||||
name = xib;
|
||||
path = ../../cocoalib/xib;
|
||||
@@ -383,6 +393,8 @@
|
||||
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */,
|
||||
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
|
||||
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
|
||||
CE0A0C011175A1DE00DCA3C6 /* ProblemDialog.h */,
|
||||
CE0A0C021175A1DE00DCA3C6 /* ProblemDialog.m */,
|
||||
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
|
||||
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
|
||||
CE0B3D6511243F83009A7A30 /* ResultOutline.h */,
|
||||
@@ -391,6 +403,7 @@
|
||||
CEDF07A2112493B200EE5BC0 /* StatsLabel.m */,
|
||||
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
|
||||
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */,
|
||||
CE0A0C031175A1DE00DCA3C6 /* PyProblemDialog.h */,
|
||||
CE0B3D6411243F83009A7A30 /* PyResultTree.h */,
|
||||
CEDF07A0112493B200EE5BC0 /* PyStatsLabel.h */,
|
||||
);
|
||||
@@ -438,6 +451,13 @@
|
||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */;
|
||||
compatibilityVersion = "Xcode 3.0";
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
English,
|
||||
Japanese,
|
||||
French,
|
||||
German,
|
||||
en,
|
||||
);
|
||||
mainGroup = 29B97314FDCFA39411CA2CEA /* dupeguru */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@@ -465,7 +485,8 @@
|
||||
CE900AD7109B2A9B00754048 /* MainMenu.xib in Resources */,
|
||||
CE4B59C81119919700C06C9E /* ErrorReportWindow.xib in Resources */,
|
||||
CE4B59C91119919700C06C9E /* progress.xib in Resources */,
|
||||
CE4B59CA1119919700C06C9E /* registration.xib in Resources */,
|
||||
CE0A0C061175A24800DCA3C6 /* ProblemDialog.xib in Resources */,
|
||||
CECC563B12144A9000ABF262 /* registration.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -502,11 +523,25 @@
|
||||
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */,
|
||||
CE0B3D6711243F83009A7A30 /* ResultOutline.m in Sources */,
|
||||
CEDF07A3112493B200EE5BC0 /* StatsLabel.m in Sources */,
|
||||
CE0A0C001175A1C000DCA3C6 /* HSTable.m in Sources */,
|
||||
CE0A0C041175A1DE00DCA3C6 /* ProblemDialog.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
CECC563912144A9000ABF262 /* registration.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
CECC563A12144A9000ABF262 /* en */,
|
||||
);
|
||||
name = registration.xib;
|
||||
path = ../../cocoalib/xib;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
C01FCF4C08A954540054247B /* release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>hsft</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.8.5</string>
|
||||
<string>1.10.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -20,9 +20,8 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
{
|
||||
[super awakeFromNib];
|
||||
[[self window] setTitle:@"dupeGuru Picture Edition"];
|
||||
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,5)];
|
||||
[deltaColumns removeIndex:3];
|
||||
[deltaColumns removeIndex:4];
|
||||
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndex:2];
|
||||
[deltaColumns addIndex:5];
|
||||
[outline setDeltaColumns:deltaColumns];
|
||||
}
|
||||
|
||||
@@ -41,13 +40,13 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[columnsOrder addObject:@"1"];
|
||||
[columnsOrder addObject:@"2"];
|
||||
[columnsOrder addObject:@"4"];
|
||||
[columnsOrder addObject:@"7"];
|
||||
[columnsOrder addObject:@"6"];
|
||||
NSMutableDictionary *columnsWidth = [NSMutableDictionary dictionary];
|
||||
[columnsWidth setObject:i2n(121) forKey:@"0"];
|
||||
[columnsWidth setObject:i2n(120) forKey:@"1"];
|
||||
[columnsWidth setObject:i2n(63) forKey:@"2"];
|
||||
[columnsWidth setObject:i2n(73) forKey:@"4"];
|
||||
[columnsWidth setObject:i2n(58) forKey:@"7"];
|
||||
[columnsWidth setObject:i2n(58) forKey:@"6"];
|
||||
[self restoreColumnsPosition:columnsOrder widths:columnsWidth];
|
||||
}
|
||||
|
||||
@@ -66,8 +65,6 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
int r = n2i([py doScan]);
|
||||
if (r != 0)
|
||||
[[ProgressController mainProgressController] hide];
|
||||
if (r == 1)
|
||||
[Dialogs showMessage:@"You cannot make a duplicate scan with only reference directories."];
|
||||
if (r == 3)
|
||||
{
|
||||
[Dialogs showMessage:@"The selected directories contain no scannable file."];
|
||||
@@ -92,9 +89,8 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[_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:@"Creation" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:6 title:@"Modification" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:7 title:@"Match %" width:58 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:8 title:@"Dupe Count" 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
|
||||
@@ -8,9 +8,13 @@ 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
|
||||
from core_pe import block, cache, matchbase, data, _block_osx
|
||||
from lxml import etree, _elementpath
|
||||
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):
|
||||
@@ -23,10 +27,10 @@ class PyDupeGuru(PyDupeGuruBase):
|
||||
|
||||
#---Information
|
||||
def getSelectedDupePath(self):
|
||||
return unicode(self.py.selected_dupe_path())
|
||||
return str(self.py.selected_dupe_path())
|
||||
|
||||
def getSelectedDupeRefPath(self):
|
||||
return unicode(self.py.selected_dupe_ref_path())
|
||||
return str(self.py.selected_dupe_ref_path())
|
||||
|
||||
#---Properties
|
||||
def setMatchScaled_(self,match_scaled):
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
CE15C8C00ADEB8D40061D4A5 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */; };
|
||||
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
||||
@@ -24,7 +27,6 @@
|
||||
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 */; };
|
||||
CE7AC91A1119911200D02F6C /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE7AC9171119911200D02F6C /* registration.xib */; };
|
||||
CE80DB2E0FC192D60086DCA6 /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1C0FC192D60086DCA6 /* Dialogs.m */; };
|
||||
CE80DB2F0FC192D60086DCA6 /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */; };
|
||||
CE80DB310FC192D60086DCA6 /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB220FC192D60086DCA6 /* ProgressController.m */; };
|
||||
@@ -38,6 +40,7 @@
|
||||
CE80DB8B0FC1951C0086DCA6 /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */; };
|
||||
CE80DB8C0FC1951C0086DCA6 /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB890FC1951C0086DCA6 /* ResultWindow.m */; };
|
||||
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
||||
CE895D7B12144A7800E74705 /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE895D7912144A7800E74705 /* registration.xib */; };
|
||||
CE95865E112C516400F95FD2 /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE95865B112C516400F95FD2 /* ResultOutline.m */; };
|
||||
CE95865F112C516400F95FD2 /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE95865D112C516400F95FD2 /* StatsLabel.m */; };
|
||||
CE9EA7561122C96C008CD2BC /* HSGUIController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7441122C96C008CD2BC /* HSGUIController.m */; };
|
||||
@@ -84,6 +87,13 @@
|
||||
CE031750109B340A00517EE6 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Preferences.xib; sourceTree = "<group>"; };
|
||||
CE031753109B345200517EE6 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MainMenu.xib; path = ../../base/xib/MainMenu.xib; 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>"; };
|
||||
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; sourceTree = SOURCE_ROOT; };
|
||||
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
||||
@@ -100,7 +110,6 @@
|
||||
CE77C8A710946CE20078B0DB /* DetailsPanel.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DetailsPanel.xib; sourceTree = "<group>"; };
|
||||
CE7AC9151119911200D02F6C /* ErrorReportWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ErrorReportWindow.xib; sourceTree = "<group>"; };
|
||||
CE7AC9161119911200D02F6C /* progress.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = progress.xib; sourceTree = "<group>"; };
|
||||
CE7AC9171119911200D02F6C /* registration.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = registration.xib; sourceTree = "<group>"; };
|
||||
CE80DB1B0FC192D60086DCA6 /* Dialogs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Dialogs.h; path = ../../cocoalib/Dialogs.h; sourceTree = SOURCE_ROOT; };
|
||||
CE80DB1C0FC192D60086DCA6 /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
||||
CE80DB1D0FC192D60086DCA6 /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
||||
@@ -129,6 +138,7 @@
|
||||
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultWindow.h; path = ../base/ResultWindow.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; };
|
||||
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
||||
CE895D7A12144A7800E74705 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = ../../cocoalib/en.lproj/registration.xib; sourceTree = SOURCE_ROOT; };
|
||||
CE958658112C516400F95FD2 /* PyResultTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTree.h; path = ../base/PyResultTree.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; };
|
||||
CE95865A112C516400F95FD2 /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
|
||||
@@ -180,7 +190,7 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
||||
080E96DDFE201D6D7F000001 /* DGPE */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
||||
@@ -194,7 +204,7 @@
|
||||
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
||||
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
||||
);
|
||||
name = Classes;
|
||||
name = DGPE;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
||||
@@ -227,7 +237,7 @@
|
||||
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
080E96DDFE201D6D7F000001 /* Classes */,
|
||||
080E96DDFE201D6D7F000001 /* DGPE */,
|
||||
CE80DB1A0FC192AB0086DCA6 /* cocoalib */,
|
||||
CE80DB810FC194BD0086DCA6 /* dgbase */,
|
||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||
@@ -276,6 +286,7 @@
|
||||
CE77C8A710946CE20078B0DB /* DetailsPanel.xib */,
|
||||
CE77C89C10946C6D0078B0DB /* DirectoryPanel.xib */,
|
||||
CE031750109B340A00517EE6 /* Preferences.xib */,
|
||||
CE0C2AC71177021600BC749F /* ProblemDialog.xib */,
|
||||
);
|
||||
path = xib;
|
||||
sourceTree = "<group>";
|
||||
@@ -283,9 +294,9 @@
|
||||
CE7AC9141119911200D02F6C /* xib */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CE895D7912144A7800E74705 /* registration.xib */,
|
||||
CE7AC9151119911200D02F6C /* ErrorReportWindow.xib */,
|
||||
CE7AC9161119911200D02F6C /* progress.xib */,
|
||||
CE7AC9171119911200D02F6C /* registration.xib */,
|
||||
);
|
||||
name = xib;
|
||||
path = ../../cocoalib/xib;
|
||||
@@ -335,19 +346,22 @@
|
||||
CE6044EB0FE6796200B71262 /* DetailsPanel.m */,
|
||||
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */,
|
||||
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */,
|
||||
CE9EA7711122CA0B008CD2BC /* PyDirectoryOutline.h */,
|
||||
CE9EA76F1122CA0B008CD2BC /* DirectoryOutline.h */,
|
||||
CE9EA7701122CA0B008CD2BC /* DirectoryOutline.m */,
|
||||
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */,
|
||||
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */,
|
||||
CE0C2ABA1177014200BC749F /* ProblemDialog.h */,
|
||||
CE0C2ABB1177014200BC749F /* ProblemDialog.m */,
|
||||
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */,
|
||||
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */,
|
||||
CE958658112C516400F95FD2 /* PyResultTree.h */,
|
||||
CE95865A112C516400F95FD2 /* ResultOutline.h */,
|
||||
CE95865B112C516400F95FD2 /* ResultOutline.m */,
|
||||
CE958659112C516400F95FD2 /* PyStatsLabel.h */,
|
||||
CE95865C112C516400F95FD2 /* StatsLabel.h */,
|
||||
CE95865D112C516400F95FD2 /* StatsLabel.m */,
|
||||
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */,
|
||||
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */,
|
||||
CE9EA7711122CA0B008CD2BC /* PyDirectoryOutline.h */,
|
||||
CE0C2ABC1177014200BC749F /* PyProblemDialog.h */,
|
||||
CE958659112C516400F95FD2 /* PyStatsLabel.h */,
|
||||
);
|
||||
name = dgbase;
|
||||
sourceTree = "<group>";
|
||||
@@ -359,6 +373,8 @@
|
||||
CE9EA7441122C96C008CD2BC /* HSGUIController.m */,
|
||||
CE9EA7451122C96C008CD2BC /* HSOutline.h */,
|
||||
CE9EA7461122C96C008CD2BC /* HSOutline.m */,
|
||||
CE0C2AB41177011000BC749F /* HSTable.h */,
|
||||
CE0C2AB51177011000BC749F /* HSTable.m */,
|
||||
CE9EA7471122C96C008CD2BC /* HSWindowController.h */,
|
||||
CE9EA7481122C96C008CD2BC /* HSWindowController.m */,
|
||||
);
|
||||
@@ -371,6 +387,7 @@
|
||||
children = (
|
||||
CE9EA74C1122C96C008CD2BC /* PyGUI.h */,
|
||||
CE9EA74D1122C96C008CD2BC /* PyOutline.h */,
|
||||
CE0C2AAA117700E700BC749F /* PyTable.h */,
|
||||
);
|
||||
name = proxies;
|
||||
path = ../../cocoalib/proxies;
|
||||
@@ -441,6 +458,13 @@
|
||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */;
|
||||
compatibilityVersion = "Xcode 3.0";
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
English,
|
||||
Japanese,
|
||||
French,
|
||||
German,
|
||||
en,
|
||||
);
|
||||
mainGroup = 29B97314FDCFA39411CA2CEA /* dupeguru */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@@ -469,7 +493,8 @@
|
||||
CE031754109B345200517EE6 /* MainMenu.xib in Resources */,
|
||||
CE7AC9181119911200D02F6C /* ErrorReportWindow.xib in Resources */,
|
||||
CE7AC9191119911200D02F6C /* progress.xib in Resources */,
|
||||
CE7AC91A1119911200D02F6C /* registration.xib in Resources */,
|
||||
CE0C2AC81177021600BC749F /* ProblemDialog.xib in Resources */,
|
||||
CE895D7B12144A7800E74705 /* registration.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -509,11 +534,25 @@
|
||||
CE9EA7721122CA0B008CD2BC /* DirectoryOutline.m in Sources */,
|
||||
CE95865E112C516400F95FD2 /* ResultOutline.m in Sources */,
|
||||
CE95865F112C516400F95FD2 /* StatsLabel.m in Sources */,
|
||||
CE0C2AB61177011000BC749F /* HSTable.m in Sources */,
|
||||
CE0C2ABD1177014200BC749F /* ProblemDialog.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
CE895D7912144A7800E74705 /* registration.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
CE895D7A12144A7800E74705 /* en */,
|
||||
);
|
||||
name = registration.xib;
|
||||
path = ../../cocoalib/xib;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
C01FCF4C08A954540054247B /* release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">10C540</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.25</string>
|
||||
<string key="IBDocument.HIToolboxVersion">458.00</string>
|
||||
<string key="IBDocument.SystemVersion">10F569</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">788</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.29</string>
|
||||
<string key="IBDocument.HIToolboxVersion">461.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">740</string>
|
||||
<string key="NS.object.0">788</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -434,6 +434,7 @@
|
||||
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
|
||||
<string key="NSMinSize">{451, 177}</string>
|
||||
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||
<string key="NSFrameAutosaveName">DetailsPanel</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
@@ -866,6 +867,13 @@
|
||||
<string key="NS.key.0">detailsTable</string>
|
||||
<string key="NS.object.0">NSTableView</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">detailsTable</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">detailsTable</string>
|
||||
<string key="candidateClassName">NSTableView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">../base/DetailsPanel.h</string>
|
||||
@@ -891,6 +899,35 @@
|
||||
<string>NSProgressIndicator</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>dupeImage</string>
|
||||
<string>dupeProgressIndicator</string>
|
||||
<string>refImage</string>
|
||||
<string>refProgressIndicator</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">dupeImage</string>
|
||||
<string key="candidateClassName">NSImageView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">dupeProgressIndicator</string>
|
||||
<string key="candidateClassName">NSProgressIndicator</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">refImage</string>
|
||||
<string key="candidateClassName">NSImageView</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">refProgressIndicator</string>
|
||||
<string key="candidateClassName">NSProgressIndicator</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">DetailsPanel.h</string>
|
||||
@@ -903,6 +940,13 @@
|
||||
<string key="NS.key.0">detailsTable</string>
|
||||
<string key="NS.object.0">NSTableView</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">detailsTable</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">detailsTable</string>
|
||||
<string key="candidateClassName">NSTableView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBUserSource</string>
|
||||
<string key="minorKey"/>
|
||||
@@ -1423,6 +1467,13 @@
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">showWindow:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">showWindow:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
|
||||
@@ -1431,6 +1482,7 @@
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<integer value="1050" key="NS.object.0"/>
|
||||
@@ -1446,5 +1498,9 @@
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<nil key="IBDocument.LastKnownRelativeProjectPath"/>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
|
||||
<string key="NS.key.0">NSApplicationIcon</string>
|
||||
<string key="NS.object.0">{128, 128}</string>
|
||||
</object>
|
||||
</data>
|
||||
</archive>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">10C540</string>
|
||||
<string key="IBDocument.SystemVersion">10D573</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.25</string>
|
||||
<string key="IBDocument.HIToolboxVersion">458.00</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.29</string>
|
||||
<string key="IBDocument.HIToolboxVersion">460.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">740</string>
|
||||
@@ -41,14 +41,14 @@
|
||||
<object class="NSUserDefaultsController" id="455472712">
|
||||
<object class="NSMutableArray" key="NSDeclaredKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>SUEnableAutomaticChecks</string>
|
||||
<string>CustomCommand</string>
|
||||
</object>
|
||||
<bool key="NSSharedInstance">YES</bool>
|
||||
</object>
|
||||
<object class="NSWindowTemplate" id="809668081">
|
||||
<int key="NSWindowStyleMask">3</int>
|
||||
<int key="NSWindowBacking">2</int>
|
||||
<string key="NSWindowRect">{{92, 350}, {352, 252}}</string>
|
||||
<string key="NSWindowRect">{{92, 371}, {392, 231}}</string>
|
||||
<int key="NSWTFlags">1886912512</int>
|
||||
<string key="NSWindowTitle">dupeGuru PE Preferences</string>
|
||||
<object class="NSMutableString" key="NSWindowClass">
|
||||
@@ -64,12 +64,53 @@
|
||||
<int key="NSvFlags">256</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSSlider" id="266372855">
|
||||
<object class="NSButton" id="789691362">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{120, 213}, {181, 21}}</string>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{230, 12}, {148, 32}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="173995265">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">134217728</int>
|
||||
<string key="NSContents">Reset to Defaults</string>
|
||||
<object class="NSFont" key="NSSupport" id="882799568">
|
||||
<string key="NSName">LucidaGrande</string>
|
||||
<double key="NSSize">13</double>
|
||||
<int key="NSfFlags">1044</int>
|
||||
</object>
|
||||
<reference key="NSControlView" ref="789691362"/>
|
||||
<int key="NSButtonFlags">-2038284033</int>
|
||||
<int key="NSButtonFlags2">1</int>
|
||||
<reference key="NSAlternateImage" ref="882799568"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<object class="NSMutableString" key="NSKeyEquivalent">
|
||||
<characters key="NS.bytes"/>
|
||||
</object>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSTabView" id="211771207">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<int key="NSvFlags">12</int>
|
||||
<string key="NSFrame">{{13, 40}, {366, 185}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<object class="NSMutableArray" key="NSTabViewItems">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSTabViewItem" id="700068878">
|
||||
<string key="NSIdentifier">1</string>
|
||||
<object class="NSView" key="NSView" id="1073354031">
|
||||
<reference key="NSNextResponder" ref="211771207"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSSlider" id="266372855">
|
||||
<reference key="NSNextResponder" ref="1073354031"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{117, 117}, {181, 21}}</string>
|
||||
<reference key="NSSuperview" ref="1073354031"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSSliderCell" key="NSCell" id="453640282">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
@@ -93,10 +134,10 @@
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSTextField" id="869007847">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<reference key="NSNextResponder" ref="1073354031"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{122, 196}, {80, 13}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<string key="NSFrame">{{119, 100}, {80, 13}}</string>
|
||||
<reference key="NSSuperview" ref="1073354031"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="106025161">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
@@ -121,7 +162,7 @@
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">controlTextColor</string>
|
||||
<object class="NSColor" key="NSColor">
|
||||
<object class="NSColor" key="NSColor" id="736922190">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MAA</bytes>
|
||||
</object>
|
||||
@@ -129,10 +170,10 @@
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSTextField" id="171701149">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<reference key="NSNextResponder" ref="1073354031"/>
|
||||
<int key="NSvFlags">289</int>
|
||||
<string key="NSFrame">{{219, 196}, {80, 13}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<string key="NSFrame">{{216, 100}, {80, 13}}</string>
|
||||
<reference key="NSSuperview" ref="1073354031"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="397705219">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
@@ -145,10 +186,10 @@
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSTextField" id="638371207">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<reference key="NSNextResponder" ref="1073354031"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{17, 218}, {100, 14}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<string key="NSFrame">{{14, 122}, {100, 14}}</string>
|
||||
<reference key="NSSuperview" ref="1073354031"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="812365472">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
@@ -165,10 +206,10 @@
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="488256664">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<reference key="NSNextResponder" ref="1073354031"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{18, 152}, {214, 18}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<string key="NSFrame">{{15, 56}, {214, 18}}</string>
|
||||
<reference key="NSSuperview" ref="1073354031"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="401283671">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
@@ -187,11 +228,74 @@
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSTextField" id="403531548">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<object class="NSButton" id="722670516">
|
||||
<reference key="NSNextResponder" ref="1073354031"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{304, 218}, {31, 14}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<string key="NSFrame">{{15, 76}, {214, 18}}</string>
|
||||
<reference key="NSSuperview" ref="1073354031"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="911281323">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Match scaled pictures together</string>
|
||||
<reference key="NSSupport" ref="26"/>
|
||||
<reference key="NSControlView" ref="722670516"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSAlternateImage" ref="990345653"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="472028782">
|
||||
<reference key="NSNextResponder" ref="1073354031"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{15, 14}, {283, 18}}</string>
|
||||
<reference key="NSSuperview" ref="1073354031"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="2297113">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Automatically check for updates</string>
|
||||
<reference key="NSSupport" ref="26"/>
|
||||
<reference key="NSControlView" ref="472028782"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSAlternateImage" ref="990345653"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="279087998">
|
||||
<reference key="NSNextResponder" ref="1073354031"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{15, 36}, {242, 18}}</string>
|
||||
<reference key="NSSuperview" ref="1073354031"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="287383961">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Remove empty folders on delete or move</string>
|
||||
<reference key="NSSupport" ref="26"/>
|
||||
<reference key="NSControlView" ref="279087998"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSAlternateImage" ref="990345653"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSTextField" id="403531548">
|
||||
<reference key="NSNextResponder" ref="1073354031"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{301, 122}, {31, 14}}</string>
|
||||
<reference key="NSSuperview" ref="1073354031"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="983190380">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
@@ -266,38 +370,47 @@
|
||||
<reference key="NSTextColor" ref="538152464"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="789691362">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
</object>
|
||||
<string key="NSFrame">{{10, 33}, {346, 139}}</string>
|
||||
<reference key="NSSuperview" ref="211771207"/>
|
||||
</object>
|
||||
<string key="NSLabel">Basic</string>
|
||||
<reference key="NSColor" ref="71910056"/>
|
||||
<reference key="NSTabView" ref="211771207"/>
|
||||
</object>
|
||||
<object class="NSTabViewItem" id="1045400351">
|
||||
<string key="NSIdentifier">2</string>
|
||||
<object class="NSView" key="NSView" id="581039403">
|
||||
<nil key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{190, 16}, {148, 32}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSButton" id="1018598123">
|
||||
<reference key="NSNextResponder" ref="581039403"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{15, 120}, {228, 18}}</string>
|
||||
<reference key="NSSuperview" ref="581039403"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="173995265">
|
||||
<object class="NSButtonCell" key="NSCell" id="42276474">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">134217728</int>
|
||||
<string key="NSContents">Reset to Defaults</string>
|
||||
<object class="NSFont" key="NSSupport" id="882799568">
|
||||
<string key="NSName">LucidaGrande</string>
|
||||
<double key="NSSize">13</double>
|
||||
<int key="NSfFlags">1044</int>
|
||||
</object>
|
||||
<reference key="NSControlView" ref="789691362"/>
|
||||
<int key="NSButtonFlags">-2038284033</int>
|
||||
<int key="NSButtonFlags2">1</int>
|
||||
<reference key="NSAlternateImage" ref="882799568"/>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Use regular expressions when filtering</string>
|
||||
<reference key="NSSupport" ref="26"/>
|
||||
<reference key="NSControlView" ref="1018598123"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSAlternateImage" ref="990345653"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<object class="NSMutableString" key="NSKeyEquivalent">
|
||||
<characters key="NS.bytes"/>
|
||||
</object>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSTextField" id="748076392">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<reference key="NSNextResponder" ref="581039403"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{20, 71}, {85, 13}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<string key="NSFrame">{{14, 97}, {85, 13}}</string>
|
||||
<reference key="NSSuperview" ref="581039403"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="936873031">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
@@ -309,11 +422,27 @@
|
||||
<reference key="NSTextColor" ref="538152464"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSPopUpButton" id="724953200">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<object class="NSTextField" id="526155835">
|
||||
<reference key="NSNextResponder" ref="581039403"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{110, 60}, {216, 26}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<string key="NSFrame">{{14, 69}, {306, 17}}</string>
|
||||
<reference key="NSSuperview" ref="581039403"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="765798142">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">272629760</int>
|
||||
<string key="NSContents">Custom Command (arguments: %d for dupe, %r for ref):</string>
|
||||
<reference key="NSSupport" ref="649492068"/>
|
||||
<reference key="NSControlView" ref="526155835"/>
|
||||
<reference key="NSBackgroundColor" ref="71910056"/>
|
||||
<reference key="NSTextColor" ref="538152464"/>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSPopUpButton" id="724953200">
|
||||
<reference key="NSNextResponder" ref="581039403"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{104, 90}, {216, 26}}</string>
|
||||
<reference key="NSSuperview" ref="581039403"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSPopUpButtonCell" key="NSCell" id="601288025">
|
||||
<int key="NSCellFlags">-2076049856</int>
|
||||
@@ -385,92 +514,56 @@
|
||||
<int key="NSArrowPosition">1</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="722670516">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{18, 172}, {214, 18}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<object class="NSTextField" id="590530357">
|
||||
<reference key="NSNextResponder" ref="581039403"/>
|
||||
<int key="NSvFlags">266</int>
|
||||
<string key="NSFrame">{{17, 47}, {312, 22}}</string>
|
||||
<reference key="NSSuperview" ref="581039403"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="911281323">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Match scaled pictures together</string>
|
||||
<reference key="NSSupport" ref="26"/>
|
||||
<reference key="NSControlView" ref="722670516"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSAlternateImage" ref="990345653"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="922246764">
|
||||
<int key="NSCellFlags">-1804468671</int>
|
||||
<int key="NSCellFlags2">272630784</int>
|
||||
<string key="NSContents"/>
|
||||
<reference key="NSSupport" ref="882799568"/>
|
||||
<reference key="NSControlView" ref="590530357"/>
|
||||
<bool key="NSDrawsBackground">YES</bool>
|
||||
<object class="NSColor" key="NSBackgroundColor">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">textBackgroundColor</string>
|
||||
<object class="NSColor" key="NSColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="472028782">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{18, 90}, {283, 18}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="2297113">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Automatically check for updates</string>
|
||||
<reference key="NSSupport" ref="26"/>
|
||||
<reference key="NSControlView" ref="472028782"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSAlternateImage" ref="990345653"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="279087998">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{18, 112}, {242, 18}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="287383961">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Remove empty folders on delete or move</string>
|
||||
<reference key="NSSupport" ref="26"/>
|
||||
<reference key="NSControlView" ref="279087998"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSAlternateImage" ref="990345653"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="1018598123">
|
||||
<reference key="NSNextResponder" ref="905655072"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{18, 132}, {228, 18}}</string>
|
||||
<reference key="NSSuperview" ref="905655072"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="42276474">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Use regular expressions when filtering</string>
|
||||
<reference key="NSSupport" ref="26"/>
|
||||
<reference key="NSControlView" ref="1018598123"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSAlternateImage" ref="990345653"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
<object class="NSColor" key="NSTextColor">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">textColor</string>
|
||||
<reference key="NSColor" ref="736922190"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{352, 252}</string>
|
||||
</object>
|
||||
<string key="NSFrame">{{10, 33}, {346, 139}}</string>
|
||||
</object>
|
||||
<string key="NSLabel">Advanced</string>
|
||||
<reference key="NSColor" ref="71910056"/>
|
||||
<reference key="NSTabView" ref="211771207"/>
|
||||
</object>
|
||||
</object>
|
||||
<reference key="NSSelectedTabViewItem" ref="700068878"/>
|
||||
<reference key="NSFont" ref="882799568"/>
|
||||
<int key="NSTvFlags">0</int>
|
||||
<bool key="NSAllowTruncatedLabels">YES</bool>
|
||||
<bool key="NSDrawsBackground">YES</bool>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="1073354031"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{392, 231}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
</object>
|
||||
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
|
||||
@@ -681,6 +774,22 @@
|
||||
</object>
|
||||
<int key="connectionID">58</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBBindingConnection" key="connection">
|
||||
<string key="label">value: values.CustomCommand</string>
|
||||
<reference key="source" ref="590530357"/>
|
||||
<reference key="destination" ref="455472712"/>
|
||||
<object class="NSNibBindingConnector" key="connector">
|
||||
<reference key="NSSource" ref="590530357"/>
|
||||
<reference key="NSDestination" ref="455472712"/>
|
||||
<string key="NSLabel">value: values.CustomCommand</string>
|
||||
<string key="NSBinding">value</string>
|
||||
<string key="NSKeyPath">values.CustomCommand</string>
|
||||
<int key="NSNibBindingConnectorVersion">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<int key="connectionID">68</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
@@ -730,76 +839,11 @@
|
||||
<reference key="object" ref="905655072"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="1018598123"/>
|
||||
<reference ref="279087998"/>
|
||||
<reference ref="472028782"/>
|
||||
<reference ref="722670516"/>
|
||||
<reference ref="724953200"/>
|
||||
<reference ref="748076392"/>
|
||||
<reference ref="211771207"/>
|
||||
<reference ref="789691362"/>
|
||||
<reference ref="403531548"/>
|
||||
<reference ref="488256664"/>
|
||||
<reference ref="638371207"/>
|
||||
<reference ref="171701149"/>
|
||||
<reference ref="869007847"/>
|
||||
<reference ref="266372855"/>
|
||||
</object>
|
||||
<reference key="parent" ref="809668081"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="1018598123"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="42276474"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">5</int>
|
||||
<reference key="object" ref="279087998"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="287383961"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">6</int>
|
||||
<reference key="object" ref="472028782"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="2297113"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">7</int>
|
||||
<reference key="object" ref="722670516"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="911281323"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">8</int>
|
||||
<reference key="object" ref="724953200"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="601288025"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">9</int>
|
||||
<reference key="object" ref="748076392"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="936873031"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">10</int>
|
||||
<reference key="object" ref="789691362"/>
|
||||
@@ -810,49 +854,67 @@
|
||||
<reference key="parent" ref="905655072"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">11</int>
|
||||
<reference key="object" ref="403531548"/>
|
||||
<int key="objectID">24</int>
|
||||
<reference key="object" ref="173995265"/>
|
||||
<reference key="parent" ref="789691362"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">59</int>
|
||||
<reference key="object" ref="211771207"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="983190380"/>
|
||||
<reference ref="700068878"/>
|
||||
<reference ref="1045400351"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">12</int>
|
||||
<reference key="object" ref="488256664"/>
|
||||
<int key="objectID">60</int>
|
||||
<reference key="object" ref="700068878"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="401283671"/>
|
||||
<reference ref="1073354031"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
<reference key="parent" ref="211771207"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">13</int>
|
||||
<reference key="object" ref="638371207"/>
|
||||
<int key="objectID">61</int>
|
||||
<reference key="object" ref="1045400351"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="812365472"/>
|
||||
<reference ref="581039403"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
<reference key="parent" ref="211771207"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">14</int>
|
||||
<reference key="object" ref="171701149"/>
|
||||
<int key="objectID">62</int>
|
||||
<reference key="object" ref="581039403"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="397705219"/>
|
||||
<reference ref="1018598123"/>
|
||||
<reference ref="724953200"/>
|
||||
<reference ref="748076392"/>
|
||||
<reference ref="526155835"/>
|
||||
<reference ref="590530357"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
<reference key="parent" ref="1045400351"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">15</int>
|
||||
<reference key="object" ref="869007847"/>
|
||||
<int key="objectID">63</int>
|
||||
<reference key="object" ref="1073354031"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="106025161"/>
|
||||
<reference ref="722670516"/>
|
||||
<reference ref="488256664"/>
|
||||
<reference ref="638371207"/>
|
||||
<reference ref="171701149"/>
|
||||
<reference ref="869007847"/>
|
||||
<reference ref="266372855"/>
|
||||
<reference ref="472028782"/>
|
||||
<reference ref="279087998"/>
|
||||
<reference ref="403531548"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
<reference key="parent" ref="700068878"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">16</int>
|
||||
@@ -861,33 +923,120 @@
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="453640282"/>
|
||||
</object>
|
||||
<reference key="parent" ref="905655072"/>
|
||||
<reference key="parent" ref="1073354031"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">17</int>
|
||||
<reference key="object" ref="453640282"/>
|
||||
<reference key="parent" ref="266372855"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">15</int>
|
||||
<reference key="object" ref="869007847"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="106025161"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1073354031"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">18</int>
|
||||
<reference key="object" ref="106025161"/>
|
||||
<reference key="parent" ref="869007847"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">14</int>
|
||||
<reference key="object" ref="171701149"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="397705219"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1073354031"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">19</int>
|
||||
<reference key="object" ref="397705219"/>
|
||||
<reference key="parent" ref="171701149"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">13</int>
|
||||
<reference key="object" ref="638371207"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="812365472"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1073354031"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">20</int>
|
||||
<reference key="object" ref="812365472"/>
|
||||
<reference key="parent" ref="638371207"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">12</int>
|
||||
<reference key="object" ref="488256664"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="401283671"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1073354031"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">21</int>
|
||||
<reference key="object" ref="401283671"/>
|
||||
<reference key="parent" ref="488256664"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">7</int>
|
||||
<reference key="object" ref="722670516"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="911281323"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1073354031"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">31</int>
|
||||
<reference key="object" ref="911281323"/>
|
||||
<reference key="parent" ref="722670516"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">6</int>
|
||||
<reference key="object" ref="472028782"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="2297113"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1073354031"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">32</int>
|
||||
<reference key="object" ref="2297113"/>
|
||||
<reference key="parent" ref="472028782"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">5</int>
|
||||
<reference key="object" ref="279087998"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="287383961"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1073354031"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">33</int>
|
||||
<reference key="object" ref="287383961"/>
|
||||
<reference key="parent" ref="279087998"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">11</int>
|
||||
<reference key="object" ref="403531548"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="983190380"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1073354031"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">22</int>
|
||||
<reference key="object" ref="983190380"/>
|
||||
@@ -903,15 +1052,42 @@
|
||||
<reference key="parent" ref="983190380"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">24</int>
|
||||
<reference key="object" ref="173995265"/>
|
||||
<reference key="parent" ref="789691362"/>
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="1018598123"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="42276474"/>
|
||||
</object>
|
||||
<reference key="parent" ref="581039403"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">34</int>
|
||||
<reference key="object" ref="42276474"/>
|
||||
<reference key="parent" ref="1018598123"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">9</int>
|
||||
<reference key="object" ref="748076392"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="936873031"/>
|
||||
</object>
|
||||
<reference key="parent" ref="581039403"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">25</int>
|
||||
<reference key="object" ref="936873031"/>
|
||||
<reference key="parent" ref="748076392"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">8</int>
|
||||
<reference key="object" ref="724953200"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="601288025"/>
|
||||
</object>
|
||||
<reference key="parent" ref="581039403"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">26</int>
|
||||
<reference key="object" ref="601288025"/>
|
||||
@@ -926,15 +1102,15 @@
|
||||
<reference key="object" ref="968539421"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="509553711"/>
|
||||
<reference ref="169587822"/>
|
||||
<reference ref="899286415"/>
|
||||
<reference ref="169587822"/>
|
||||
<reference ref="509553711"/>
|
||||
</object>
|
||||
<reference key="parent" ref="601288025"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">28</int>
|
||||
<reference key="object" ref="509553711"/>
|
||||
<int key="objectID">30</int>
|
||||
<reference key="object" ref="899286415"/>
|
||||
<reference key="parent" ref="968539421"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
@@ -943,29 +1119,37 @@
|
||||
<reference key="parent" ref="968539421"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">30</int>
|
||||
<reference key="object" ref="899286415"/>
|
||||
<int key="objectID">28</int>
|
||||
<reference key="object" ref="509553711"/>
|
||||
<reference key="parent" ref="968539421"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">31</int>
|
||||
<reference key="object" ref="911281323"/>
|
||||
<reference key="parent" ref="722670516"/>
|
||||
<int key="objectID">64</int>
|
||||
<reference key="object" ref="526155835"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="765798142"/>
|
||||
</object>
|
||||
<reference key="parent" ref="581039403"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">32</int>
|
||||
<reference key="object" ref="2297113"/>
|
||||
<reference key="parent" ref="472028782"/>
|
||||
<int key="objectID">65</int>
|
||||
<reference key="object" ref="765798142"/>
|
||||
<reference key="parent" ref="526155835"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">33</int>
|
||||
<reference key="object" ref="287383961"/>
|
||||
<reference key="parent" ref="279087998"/>
|
||||
<int key="objectID">66</int>
|
||||
<reference key="object" ref="590530357"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="922246764"/>
|
||||
</object>
|
||||
<reference key="parent" ref="581039403"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">34</int>
|
||||
<reference key="object" ref="42276474"/>
|
||||
<reference key="parent" ref="1018598123"/>
|
||||
<int key="objectID">67</int>
|
||||
<reference key="object" ref="922246764"/>
|
||||
<reference key="parent" ref="590530357"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
@@ -1025,8 +1209,18 @@
|
||||
<string>4.ImportedFromIB2</string>
|
||||
<string>5.IBPluginDependency</string>
|
||||
<string>5.ImportedFromIB2</string>
|
||||
<string>59.IBPluginDependency</string>
|
||||
<string>6.IBPluginDependency</string>
|
||||
<string>6.ImportedFromIB2</string>
|
||||
<string>60.IBPluginDependency</string>
|
||||
<string>61.IBPluginDependency</string>
|
||||
<string>62.IBPluginDependency</string>
|
||||
<string>63.IBPluginDependency</string>
|
||||
<string>64.IBPluginDependency</string>
|
||||
<string>64.ImportedFromIB2</string>
|
||||
<string>65.IBPluginDependency</string>
|
||||
<string>66.IBPluginDependency</string>
|
||||
<string>67.IBPluginDependency</string>
|
||||
<string>7.IBPluginDependency</string>
|
||||
<string>7.ImportedFromIB2</string>
|
||||
<string>8.IBPluginDependency</string>
|
||||
@@ -1056,9 +1250,9 @@
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{88, 593}, {352, 252}}</string>
|
||||
<string>{{88, 614}, {392, 231}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{88, 593}, {352, 252}}</string>
|
||||
<string>{{88, 614}, {392, 231}}</string>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<string>{213, 107}</string>
|
||||
@@ -1089,8 +1283,18 @@
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<boolean value="YES"/>
|
||||
@@ -1114,7 +1318,7 @@
|
||||
</object>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">58</int>
|
||||
<int key="maxID">68</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
@@ -1572,6 +1776,22 @@
|
||||
<string key="minorKey">AppKit.framework/Headers/NSSliderCell.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSTabView</string>
|
||||
<string key="superclassName">NSView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSTabView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSTabViewItem</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">AppKit.framework/Headers/NSTabViewItem.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSTextField</string>
|
||||
<string key="superclassName">NSControl</string>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>hsft</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.9.2</string>
|
||||
<string>2.11.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -18,8 +18,8 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,4)];
|
||||
[deltaColumns removeIndex:3];
|
||||
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndex:2];
|
||||
[deltaColumns addIndex:4];
|
||||
[outline setDeltaColumns:deltaColumns];
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[columnsOrder addObject:@"0"];
|
||||
[columnsOrder addObject:@"1"];
|
||||
[columnsOrder addObject:@"2"];
|
||||
[columnsOrder addObject:@"6"];
|
||||
[columnsOrder addObject:@"5"];
|
||||
NSMutableDictionary *columnsWidth = [NSMutableDictionary dictionary];
|
||||
[columnsWidth setObject:i2n(195) forKey:@"0"];
|
||||
[columnsWidth setObject:i2n(120) forKey:@"1"];
|
||||
[columnsWidth setObject:i2n(63) forKey:@"2"];
|
||||
[columnsWidth setObject:i2n(60) forKey:@"6"];
|
||||
[columnsWidth setObject:i2n(60) forKey:@"5"];
|
||||
[self restoreColumnsPosition:columnsOrder widths:columnsWidth];
|
||||
}
|
||||
|
||||
@@ -57,12 +57,8 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
int sizeThreshold = [ud boolForKey:@"ignoreSmallFiles"] ? smallFileThreshold * 1024 : 0; // The py side wants bytes
|
||||
[_py setSizeThreshold:sizeThreshold];
|
||||
int r = n2i([py doScan]);
|
||||
[matches reloadData];
|
||||
[self refreshStats];
|
||||
if (r != 0)
|
||||
[[ProgressController mainProgressController] hide];
|
||||
if (r == 1)
|
||||
[Dialogs showMessage:@"You cannot make a duplicate scan with only reference directories."];
|
||||
if (r == 3)
|
||||
{
|
||||
[Dialogs showMessage:@"The selected directories contain no scannable file."];
|
||||
@@ -82,10 +78,9 @@ http://www.hardcoded.net/licenses/hs_license
|
||||
[[sizeCol dataCell] setAlignment:NSRightTextAlignment];
|
||||
[_resultColumns addObject:sizeCol];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:3 title:@"Kind" width:40 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:4 title:@"Creation" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:5 title:@"Modification" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:6 title:@"Match %" width:60 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:7 title:@"Words Used" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:8 title:@"Dupe Count" width:80 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:4 title:@"Modification" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:5 title:@"Match %" width:60 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:6 title:@"Words Used" width:120 refCol:refCol]];
|
||||
[_resultColumns addObject:[self getColumnForIdentifier:7 title:@"Dupe Count" width:80 refCol:refCol]];
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -4,15 +4,17 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from hsutil.cocoa import signature
|
||||
from hscommon.cocoa import signature
|
||||
|
||||
from core import scanner
|
||||
from core.scanner import ScanType
|
||||
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||
from core_se.app_cocoa import DupeGuru
|
||||
|
||||
# Fix py2app imports with chokes on relative imports and other stuff
|
||||
from core_se import fs, data
|
||||
from lxml import etree, _elementpath
|
||||
import hsutil.conflict
|
||||
import core.engine, core.fs, core.app
|
||||
import core_se.fs, core_se.data
|
||||
import xml.etree.ElementPath
|
||||
import gzip
|
||||
|
||||
class PyDupeGuru(PyDupeGuruBase):
|
||||
@@ -28,8 +30,8 @@ class PyDupeGuru(PyDupeGuruBase):
|
||||
def setScanType_(self,scan_type):
|
||||
try:
|
||||
self.py.scanner.scan_type = [
|
||||
scanner.SCAN_TYPE_FILENAME,
|
||||
scanner.SCAN_TYPE_CONTENT
|
||||
ScanType.Filename,
|
||||
ScanType.Contents,
|
||||
][scan_type]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
@@ -12,13 +12,14 @@
|
||||
CE073F6309CAE1A3005C1D2F /* dupeguru_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_help */; };
|
||||
CE19BC6311199231007CCEB0 /* ErrorReportWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE19BC6011199231007CCEB0 /* ErrorReportWindow.xib */; };
|
||||
CE19BC6411199231007CCEB0 /* progress.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE19BC6111199231007CCEB0 /* progress.xib */; };
|
||||
CE19BC6511199231007CCEB0 /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE19BC6211199231007CCEB0 /* registration.xib */; };
|
||||
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.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 */; };
|
||||
CE3A46FA109B212E002ABFD5 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE3A46F9109B212E002ABFD5 /* MainMenu.xib */; };
|
||||
CE45579B0AE3BC2B005A9546 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE45579A0AE3BC2B005A9546 /* Sparkle.framework */; };
|
||||
CE4557B40AE3BC50005A9546 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE45579A0AE3BC2B005A9546 /* Sparkle.framework */; };
|
||||
CE647E571173024A006D28BA /* ProblemDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = CE647E551173024A006D28BA /* ProblemDialog.m */; };
|
||||
CE647E591173026F006D28BA /* ProblemDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE647E581173026F006D28BA /* ProblemDialog.xib */; };
|
||||
CE6E0DFE1054E9EF008D9390 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = CE6E0DFD1054E9EF008D9390 /* dsa_pub.pem */; };
|
||||
CE76FDC4111EE37C006618EA /* HSOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDBF111EE37C006618EA /* HSOutlineView.m */; };
|
||||
CE76FDC5111EE37C006618EA /* NSIndexPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDC1111EE37C006618EA /* NSIndexPathAdditions.m */; };
|
||||
@@ -27,9 +28,11 @@
|
||||
CE76FDD4111EE3A7006618EA /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDD2111EE3A7006618EA /* DirectoryOutline.m */; };
|
||||
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDDE111EE42F006618EA /* HSOutline.m */; };
|
||||
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDF6111EE561006618EA /* NSEventAdditions.m */; };
|
||||
CE8C53BC117324CE0011B41F /* HSTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CE8C53BB117324CE0011B41F /* HSTable.m */; };
|
||||
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F212113BC22D0010360B /* ResultOutline.m */; };
|
||||
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F214113BC22D0010360B /* StatsLabel.m */; };
|
||||
CEAC6811109B0B7E00B43C85 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEAC6810109B0B7E00B43C85 /* Preferences.xib */; };
|
||||
CEBC6C3912144A4B007B43AE /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEBC6C3712144A4B007B43AE /* registration.xib */; };
|
||||
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */; };
|
||||
CEDD92DA0FDD01640031C7B7 /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDD92D70FDD01640031C7B7 /* BRSingleLineFormatter.m */; };
|
||||
CEE7EA130FE675C80004E467 /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CEE7EA120FE675C80004E467 /* DetailsPanel.m */; };
|
||||
@@ -75,7 +78,6 @@
|
||||
CE073F5409CAE1A3005C1D2F /* dupeguru_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_help; path = ../../help_se/dupeguru_help; sourceTree = "<group>"; };
|
||||
CE19BC6011199231007CCEB0 /* ErrorReportWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ErrorReportWindow.xib; sourceTree = "<group>"; };
|
||||
CE19BC6111199231007CCEB0 /* progress.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = progress.xib; sourceTree = "<group>"; };
|
||||
CE19BC6211199231007CCEB0 /* registration.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = registration.xib; sourceTree = "<group>"; };
|
||||
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; };
|
||||
CE381C9A09914ADF003581CE /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
||||
@@ -83,6 +85,10 @@
|
||||
CE381CF509915304003581CE /* dg_cocoa.plugin */ = {isa = PBXFileReference; lastKnownFileType = folder; path = dg_cocoa.plugin; sourceTree = SOURCE_ROOT; };
|
||||
CE3A46F9109B212E002ABFD5 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MainMenu.xib; path = ../base/xib/MainMenu.xib; sourceTree = "<group>"; };
|
||||
CE45579A0AE3BC2B005A9546 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
||||
CE647E541173024A006D28BA /* ProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProblemDialog.h; path = ../base/ProblemDialog.h; sourceTree = SOURCE_ROOT; };
|
||||
CE647E551173024A006D28BA /* ProblemDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProblemDialog.m; path = ../base/ProblemDialog.m; sourceTree = SOURCE_ROOT; };
|
||||
CE647E561173024A006D28BA /* PyProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyProblemDialog.h; path = ../base/PyProblemDialog.h; sourceTree = SOURCE_ROOT; };
|
||||
CE647E581173026F006D28BA /* ProblemDialog.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ProblemDialog.xib; path = ../base/xib/ProblemDialog.xib; sourceTree = SOURCE_ROOT; };
|
||||
CE6E0DFD1054E9EF008D9390 /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dsa_pub.pem; path = ../base/dsa_pub.pem; sourceTree = "<group>"; };
|
||||
CE6E7407111C997500C350E3 /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; sourceTree = SOURCE_ROOT; };
|
||||
CE76FDBE111EE37C006618EA /* HSOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutlineView.h; sourceTree = "<group>"; };
|
||||
@@ -102,6 +108,8 @@
|
||||
CE76FDDE111EE42F006618EA /* HSOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutline.m; sourceTree = "<group>"; };
|
||||
CE76FDF5111EE561006618EA /* NSEventAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSEventAdditions.h; path = ../../cocoalib/NSEventAdditions.h; sourceTree = SOURCE_ROOT; };
|
||||
CE76FDF6111EE561006618EA /* NSEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSEventAdditions.m; path = ../../cocoalib/NSEventAdditions.m; sourceTree = SOURCE_ROOT; };
|
||||
CE8C53B61173248F0011B41F /* PyTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyTable.h; sourceTree = "<group>"; };
|
||||
CE8C53BB117324CE0011B41F /* HSTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSTable.m; sourceTree = "<group>"; };
|
||||
CE91F20F113BC22D0010360B /* PyResultTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTree.h; path = ../base/PyResultTree.h; sourceTree = SOURCE_ROOT; };
|
||||
CE91F210113BC22D0010360B /* PyStatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyStatsLabel.h; path = ../base/PyStatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||
CE91F211113BC22D0010360B /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
|
||||
@@ -109,6 +117,7 @@
|
||||
CE91F213113BC22D0010360B /* StatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatsLabel.h; path = ../base/StatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||
CE91F214113BC22D0010360B /* StatsLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatsLabel.m; path = ../base/StatsLabel.m; sourceTree = SOURCE_ROOT; };
|
||||
CEAC6810109B0B7E00B43C85 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Preferences.xib; path = xib/Preferences.xib; sourceTree = "<group>"; };
|
||||
CEBC6C3812144A4B007B43AE /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = ../../cocoalib/en.lproj/registration.xib; sourceTree = SOURCE_ROOT; };
|
||||
CEBE4D72111F0EE1009AAC6D /* HSWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSWindowController.h; sourceTree = "<group>"; };
|
||||
CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSWindowController.m; sourceTree = "<group>"; };
|
||||
CEDD92D60FDD01640031C7B7 /* BRSingleLineFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BRSingleLineFormatter.h; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.h; sourceTree = SOURCE_ROOT; };
|
||||
@@ -240,9 +249,9 @@
|
||||
CE19BC5F11199231007CCEB0 /* xib */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CEBC6C3712144A4B007B43AE /* registration.xib */,
|
||||
CE19BC6011199231007CCEB0 /* ErrorReportWindow.xib */,
|
||||
CE19BC6111199231007CCEB0 /* progress.xib */,
|
||||
CE19BC6211199231007CCEB0 /* registration.xib */,
|
||||
);
|
||||
name = xib;
|
||||
path = ../../cocoalib/xib;
|
||||
@@ -271,6 +280,7 @@
|
||||
CE76FDDE111EE42F006618EA /* HSOutline.m */,
|
||||
CE76FDC8111EE38E006618EA /* HSGUIController.h */,
|
||||
CE76FDC9111EE38E006618EA /* HSGUIController.m */,
|
||||
CE8C53BB117324CE0011B41F /* HSTable.m */,
|
||||
);
|
||||
name = controllers;
|
||||
path = ../../cocoalib/controllers;
|
||||
@@ -281,6 +291,7 @@
|
||||
children = (
|
||||
CE76FDCD111EE38E006618EA /* PyGUI.h */,
|
||||
CE76FDCE111EE38E006618EA /* PyOutline.h */,
|
||||
CE8C53B61173248F0011B41F /* PyTable.h */,
|
||||
);
|
||||
name = proxies;
|
||||
path = ../../cocoalib/proxies;
|
||||
@@ -299,6 +310,7 @@
|
||||
CEEFC0CA10943849001F3A39 /* xib */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CE647E581173026F006D28BA /* ProblemDialog.xib */,
|
||||
CE3A46F9109B212E002ABFD5 /* MainMenu.xib */,
|
||||
CEAC6810109B0B7E00B43C85 /* Preferences.xib */,
|
||||
CEEFC0F710945D9F001F3A39 /* DirectoryPanel.xib */,
|
||||
@@ -370,6 +382,9 @@
|
||||
CE6E7407111C997500C350E3 /* PyDetailsPanel.h */,
|
||||
CEFC7FB70FC951A700CD5728 /* ResultWindow.h */,
|
||||
CEFC7FB80FC951A700CD5728 /* ResultWindow.m */,
|
||||
CE647E541173024A006D28BA /* ProblemDialog.h */,
|
||||
CE647E551173024A006D28BA /* ProblemDialog.m */,
|
||||
CE647E561173024A006D28BA /* PyProblemDialog.h */,
|
||||
);
|
||||
name = dgbase;
|
||||
sourceTree = "<group>";
|
||||
@@ -407,6 +422,13 @@
|
||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "dupeguru" */;
|
||||
compatibilityVersion = "Xcode 3.0";
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
English,
|
||||
Japanese,
|
||||
French,
|
||||
German,
|
||||
en,
|
||||
);
|
||||
mainGroup = 29B97314FDCFA39411CA2CEA /* dupeguru */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@@ -434,7 +456,8 @@
|
||||
CE3A46FA109B212E002ABFD5 /* MainMenu.xib in Resources */,
|
||||
CE19BC6311199231007CCEB0 /* ErrorReportWindow.xib in Resources */,
|
||||
CE19BC6411199231007CCEB0 /* progress.xib in Resources */,
|
||||
CE19BC6511199231007CCEB0 /* registration.xib in Resources */,
|
||||
CE647E591173026F006D28BA /* ProblemDialog.xib in Resources */,
|
||||
CEBC6C3912144A4B007B43AE /* registration.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -470,11 +493,25 @@
|
||||
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */,
|
||||
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */,
|
||||
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */,
|
||||
CE647E571173024A006D28BA /* ProblemDialog.m in Sources */,
|
||||
CE8C53BC117324CE0011B41F /* HSTable.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
CEBC6C3712144A4B007B43AE /* registration.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
CEBC6C3812144A4B007B43AE /* en */,
|
||||
);
|
||||
name = registration.xib;
|
||||
path = ../../cocoalib/xib;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
C01FCF4C08A954540054247B /* release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ def main(edition, ui, dev):
|
||||
if ui not in ('cocoa', 'qt'):
|
||||
ui = 'cocoa' if sys.platform == 'darwin' else 'qt'
|
||||
build_type = 'Dev' if dev else 'Release'
|
||||
print "Configuring dupeGuru {0} for UI {1} ({2})".format(edition.upper(), ui, build_type)
|
||||
print("Configuring dupeGuru {0} for UI {1} ({2})".format(edition.upper(), ui, build_type))
|
||||
conf = {
|
||||
'edition': edition,
|
||||
'ui': ui,
|
||||
|
||||
109
core/app.py
109
core/app.py
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2006/11/11
|
||||
# Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||
@@ -7,17 +6,20 @@
|
||||
# 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
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
from send2trash import send2trash
|
||||
from hscommon.reg import RegistrableApplication, RegistrationRequired
|
||||
from hscommon.notify import Broadcaster
|
||||
from hsutil import io, files
|
||||
from hsutil.path import Path
|
||||
from hsutil.reg import RegistrableApplication, RegistrationRequired
|
||||
from hsutil.misc import flatten, first
|
||||
from hsutil.notify import Broadcaster
|
||||
from hsutil.str import escape
|
||||
|
||||
from . import directories, results, scanner, export, fs
|
||||
@@ -31,9 +33,6 @@ JOB_DELETE = 'job_delete'
|
||||
class NoScannableFileError(Exception):
|
||||
pass
|
||||
|
||||
class AllFilesAreRefError(Exception):
|
||||
pass
|
||||
|
||||
class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
DEMO_LIMIT_DESC = "In the demo version, only 10 duplicates per session can be sent to the recycle bin, moved or copied."
|
||||
|
||||
@@ -48,7 +47,6 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
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,
|
||||
@@ -70,26 +68,18 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
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)
|
||||
self.results.perform_on_marked(op, True)
|
||||
|
||||
def _do_delete_dupe(self, dupe):
|
||||
if not io.exists(dupe.path):
|
||||
return True
|
||||
self._recycle_dupe(dupe)
|
||||
return
|
||||
send2trash(str(dupe.path)) # Raises OSError when there's a problem
|
||||
self.clean_empty_dirs(dupe.path[:-1])
|
||||
if not io.exists(dupe.path):
|
||||
return True
|
||||
logging.warning("Could not send {0} to trash.".format(unicode(dupe.path)))
|
||||
return False
|
||||
|
||||
def _do_load(self, j):
|
||||
self.directories.load_from_file(op.join(self.appdata, 'last_directories.xml'))
|
||||
self.notify('directories_changed')
|
||||
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):
|
||||
@@ -97,26 +87,32 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
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))
|
||||
logging.warning("Exception on GetDisplayInfo for %s: %s", str(dupe.path), str(e))
|
||||
return ['---'] * len(self.data.COLUMNS)
|
||||
|
||||
def _get_file(self, str_path):
|
||||
path = Path(str_path)
|
||||
return fs.get_file(path, self.directories.fileclasses)
|
||||
f = fs.get_file(path, self.directories.fileclasses)
|
||||
if f is None:
|
||||
return None
|
||||
try:
|
||||
f._read_all_info(attrnames=self.data.METADATA_TO_READ)
|
||||
return f
|
||||
except EnvironmentError:
|
||||
return None
|
||||
|
||||
def _job_completed(self, jobid):
|
||||
# Must be called by subclasses when they detect that an async job is completed.
|
||||
if jobid in (JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_DELETE):
|
||||
if jobid == JOB_SCAN:
|
||||
self.notify('results_changed')
|
||||
elif jobid in (JOB_LOAD, JOB_MOVE, JOB_DELETE):
|
||||
self.notify('results_changed')
|
||||
self.notify('problems_changed')
|
||||
|
||||
@staticmethod
|
||||
def _open_path(path):
|
||||
raise NotImplementedError()
|
||||
|
||||
@staticmethod
|
||||
def _recycle_dupe(dupe):
|
||||
raise NotImplementedError()
|
||||
|
||||
@staticmethod
|
||||
def _reveal_path(path):
|
||||
raise NotImplementedError()
|
||||
@@ -147,7 +143,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
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))
|
||||
self.scanner.ignore_list.Ignore(str(other.path), str(dupe.path))
|
||||
self.remove_duplicates(dupes)
|
||||
|
||||
def apply_filter(self, filter):
|
||||
@@ -178,28 +174,23 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
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)
|
||||
# Raises an EnvironmentError if there's a problem
|
||||
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)
|
||||
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.results.perform_on_marked(op, not copy)
|
||||
|
||||
self._demo_check()
|
||||
jobid = JOB_COPY if copy else JOB_MOVE
|
||||
@@ -211,7 +202,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
|
||||
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 = list(map(int, column_ids))
|
||||
column_ids.sort()
|
||||
colnames = [col['display'] for i, col in enumerate(self.data.COLUMNS) if i in column_ids]
|
||||
rows = []
|
||||
@@ -223,10 +214,40 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
rows.append(row)
|
||||
return export.export_to_xhtml(colnames, rows)
|
||||
|
||||
def invoke_command(self, cmd):
|
||||
"""Calls command `cmd` with %d and %r placeholders replaced.
|
||||
|
||||
Using the current selection, %d is replaced with the currently selected dupe and %r is
|
||||
replaced with that dupe's ref file. If there's no selection, the command is not invoked.
|
||||
If the dupe is a ref, %d and %r will be the same.
|
||||
"""
|
||||
if not self.selected_dupes:
|
||||
return
|
||||
dupe = self.selected_dupes[0]
|
||||
group = self.results.get_group_of_duplicate(dupe)
|
||||
ref = group.ref
|
||||
cmd = cmd.replace('%d', str(dupe.path))
|
||||
cmd = cmd.replace('%r', str(ref.path))
|
||||
match = re.match(r'"([^"]+)"(.*)', cmd)
|
||||
if match is not None:
|
||||
# This code here is because subprocess. Popen doesn't seem to accept, under Windows,
|
||||
# executable paths with spaces in it, *even* when they're enclosed in "". So this is
|
||||
# a workaround to make the damn thing work.
|
||||
exepath, args = match.groups()
|
||||
path, exename = op.split(exepath)
|
||||
subprocess.Popen(exename + args, shell=True, cwd=path)
|
||||
else:
|
||||
subprocess.Popen(cmd, shell=True)
|
||||
|
||||
def load(self):
|
||||
self._start_job(JOB_LOAD, self._do_load)
|
||||
self.load_ignore_list()
|
||||
|
||||
def load_from(self, filename):
|
||||
def do(j):
|
||||
self.results.load_from_xml(filename, self._get_file, j)
|
||||
self._start_job(JOB_LOAD, do)
|
||||
|
||||
def load_ignore_list(self):
|
||||
p = op.join(self.appdata, 'ignore_list.xml')
|
||||
self.scanner.ignore_list.load_from_xml(p)
|
||||
@@ -279,7 +300,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
self.notify('results_changed_but_keep_selection')
|
||||
|
||||
def remove_marked(self):
|
||||
self.results.perform_on_marked(lambda x:True, True)
|
||||
self.results.perform_on_marked(lambda x:None, True)
|
||||
self.notify('results_changed')
|
||||
|
||||
def remove_selected(self):
|
||||
@@ -291,7 +312,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
d.rename(newname)
|
||||
return True
|
||||
except (IndexError, fs.FSError) as e:
|
||||
logging.warning("dupeGuru Warning: %s" % unicode(e))
|
||||
logging.warning("dupeGuru Warning: %s" % str(e))
|
||||
return False
|
||||
|
||||
def reveal_selected(self):
|
||||
@@ -302,8 +323,14 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
if not op.exists(self.appdata):
|
||||
os.makedirs(self.appdata)
|
||||
self.directories.save_to_file(op.join(self.appdata, 'last_directories.xml'))
|
||||
if self.results.is_modified:
|
||||
self.results.save_to_xml(op.join(self.appdata, 'last_results.xml'))
|
||||
|
||||
def save_as(self, filename):
|
||||
self.results.save_to_xml(filename)
|
||||
# It's not because we saved it here that we don't want to save it in appdata when we quit
|
||||
self.results.is_modified = True
|
||||
|
||||
def save_ignore_list(self):
|
||||
if not op.exists(self.appdata):
|
||||
os.makedirs(self.appdata)
|
||||
@@ -317,12 +344,8 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
||||
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:
|
||||
if not self.directories.has_any_file():
|
||||
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)
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
import logging
|
||||
import os.path as op
|
||||
|
||||
from hsutil import cocoa, job
|
||||
from hsutil.cocoa import install_exception_hook
|
||||
from hsutil.cocoa.objcmin import (NSNotificationCenter, NSUserDefaults,
|
||||
from hscommon import cocoa, job
|
||||
from hscommon.cocoa import install_exception_hook
|
||||
from hscommon.cocoa.objcmin import (NSNotificationCenter, NSUserDefaults,
|
||||
NSSearchPathForDirectoriesInDomains, NSApplicationSupportDirectory, NSUserDomainMask,
|
||||
NSWorkspace, NSWorkspaceRecycleOperation)
|
||||
from hsutil.reg import RegistrationRequired
|
||||
NSWorkspace)
|
||||
from hscommon.reg import RegistrationRequired
|
||||
|
||||
from . import app, fs
|
||||
from . import app
|
||||
|
||||
JOBID2TITLE = {
|
||||
app.JOB_SCAN: "Scanning for duplicates",
|
||||
@@ -49,19 +49,11 @@ class DupeGuru(app.DupeGuru):
|
||||
#--- Override
|
||||
@staticmethod
|
||||
def _open_path(path):
|
||||
NSWorkspace.sharedWorkspace().openFile_(unicode(path))
|
||||
|
||||
@staticmethod
|
||||
def _recycle_dupe(dupe):
|
||||
# local import because first appkit import takes a lot of memory. we want to avoid it.
|
||||
directory = unicode(dupe.path[:-1])
|
||||
filename = dupe.name
|
||||
result, tag = NSWorkspace.sharedWorkspace().performFileOperation_source_destination_files_tag_(
|
||||
NSWorkspaceRecycleOperation, directory, '', [filename], None)
|
||||
NSWorkspace.sharedWorkspace().openFile_(str(path))
|
||||
|
||||
@staticmethod
|
||||
def _reveal_path(path):
|
||||
NSWorkspace.sharedWorkspace().selectFile_inFileViewerRootedAtPath_(unicode(path), '')
|
||||
NSWorkspace.sharedWorkspace().selectFile_inFileViewerRootedAtPath_(str(path), '')
|
||||
|
||||
def _start_job(self, jobid, func):
|
||||
try:
|
||||
@@ -84,6 +76,4 @@ class DupeGuru(app.DupeGuru):
|
||||
return 0
|
||||
except app.NoScannableFileError:
|
||||
return 3
|
||||
except app.AllFilesAreRefError:
|
||||
return 1
|
||||
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
# Common interface for all editions' dg_cocoa unit.
|
||||
|
||||
from hsutil.cocoa.inter import signature, PyOutline, PyGUIObject, PyRegistrable
|
||||
from hscommon.cocoa.inter import signature, PyTable, PyOutline, PyGUIObject, PyRegistrable
|
||||
|
||||
from .gui.details_panel import DetailsPanel
|
||||
from .gui.directory_tree import DirectoryTree
|
||||
from .gui.problem_dialog import ProblemDialog
|
||||
from .gui.problem_table import ProblemTable
|
||||
from .gui.result_tree import ResultTree
|
||||
from .gui.stats_label import StatsLabel
|
||||
|
||||
@@ -44,6 +46,9 @@ class PyDupeGuruBase(PyRegistrable):
|
||||
def loadResults(self):
|
||||
self.py.load()
|
||||
|
||||
def loadResultsFrom_(self, filename):
|
||||
self.py.load_from(filename)
|
||||
|
||||
def markAll(self):
|
||||
self.py.mark_all()
|
||||
|
||||
@@ -65,6 +70,9 @@ class PyDupeGuruBase(PyRegistrable):
|
||||
def saveResults(self):
|
||||
self.py.save()
|
||||
|
||||
def saveResultsAs_(self, filename):
|
||||
self.py.save_as(filename)
|
||||
|
||||
#---Actions
|
||||
def addSelectedToIgnoreList(self):
|
||||
self.py.add_selected_to_ignore_list()
|
||||
@@ -93,6 +101,9 @@ class PyDupeGuruBase(PyRegistrable):
|
||||
def revealSelected(self):
|
||||
self.py.reveal_selected()
|
||||
|
||||
def invokeCommand_(self, cmd):
|
||||
self.py.invoke_command(cmd)
|
||||
|
||||
#---Information
|
||||
def getIgnoreListCount(self):
|
||||
return len(self.py.scanner.ignore_list)
|
||||
@@ -100,8 +111,9 @@ class PyDupeGuruBase(PyRegistrable):
|
||||
def getMarkCount(self):
|
||||
return self.py.results.mark_count
|
||||
|
||||
def getOperationalErrorCount(self):
|
||||
return self.py.last_op_error_count
|
||||
@signature('i@:')
|
||||
def scanWasProblematic(self):
|
||||
return bool(self.py.results.problems)
|
||||
|
||||
#---Properties
|
||||
def setMixFileKind_(self, mix_file_kind):
|
||||
@@ -196,3 +208,13 @@ class PyStatsLabel(PyGUIObject):
|
||||
def display(self):
|
||||
return self.py.display
|
||||
|
||||
|
||||
class PyProblemDialog(PyGUIObject):
|
||||
py_class = ProblemDialog
|
||||
|
||||
def revealSelected(self):
|
||||
self.py.reveal_selected_dupe()
|
||||
|
||||
|
||||
class PyProblemTable(PyTable):
|
||||
py_class = ProblemTable
|
||||
|
||||
@@ -11,7 +11,7 @@ from hsutil.str import format_time, FT_DECIMAL, format_size
|
||||
import time
|
||||
|
||||
def format_path(p):
|
||||
return unicode(p[:-1])
|
||||
return str(p[:-1])
|
||||
|
||||
def format_timestamp(t, delta):
|
||||
if delta:
|
||||
@@ -38,4 +38,4 @@ def format_dupe_count(c):
|
||||
return str(c) if c else '---'
|
||||
|
||||
def cmp_value(value):
|
||||
return value.lower() if isinstance(value, basestring) else value
|
||||
return value.lower() if isinstance(value, str) else value
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from lxml import etree
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from hsutil import io
|
||||
from hsutil.files import FileOrPath
|
||||
@@ -124,12 +124,19 @@ class Directories(object):
|
||||
else:
|
||||
return STATE_NORMAL
|
||||
|
||||
def has_any_file(self):
|
||||
try:
|
||||
next(self.get_files())
|
||||
return True
|
||||
except StopIteration:
|
||||
return False
|
||||
|
||||
def load_from_file(self, infile):
|
||||
try:
|
||||
root = etree.parse(infile).getroot()
|
||||
except:
|
||||
root = ET.parse(infile).getroot()
|
||||
except Exception:
|
||||
return
|
||||
for rdn in root.iterchildren('root_directory'):
|
||||
for rdn in root.getiterator('root_directory'):
|
||||
attrib = rdn.attrib
|
||||
if 'path' not in attrib:
|
||||
continue
|
||||
@@ -138,7 +145,7 @@ class Directories(object):
|
||||
self.add_path(Path(path))
|
||||
except (AlreadyThereError, InvalidPathError):
|
||||
pass
|
||||
for sn in root.iterchildren('state'):
|
||||
for sn in root.getiterator('state'):
|
||||
attrib = sn.attrib
|
||||
if not ('path' in attrib and 'value' in attrib):
|
||||
continue
|
||||
@@ -148,15 +155,15 @@ class Directories(object):
|
||||
|
||||
def save_to_file(self, outfile):
|
||||
with FileOrPath(outfile, 'wb') as fp:
|
||||
root = etree.Element('directories')
|
||||
root = ET.Element('directories')
|
||||
for root_path in self:
|
||||
root_path_node = etree.SubElement(root, 'root_directory')
|
||||
root_path_node.set('path', unicode(root_path))
|
||||
for path, state in self.states.iteritems():
|
||||
state_node = etree.SubElement(root, 'state')
|
||||
state_node.set('path', unicode(path))
|
||||
state_node.set('value', unicode(state))
|
||||
tree = etree.ElementTree(root)
|
||||
root_path_node = ET.SubElement(root, 'root_directory')
|
||||
root_path_node.set('path', str(root_path))
|
||||
for path, state in self.states.items():
|
||||
state_node = ET.SubElement(root, 'state')
|
||||
state_node.set('path', str(path))
|
||||
state_node.set('value', str(state))
|
||||
tree = ET.ElementTree(root)
|
||||
tree.write(fp, encoding='utf-8')
|
||||
|
||||
def set_state(self, path, state):
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import difflib
|
||||
import itertools
|
||||
import logging
|
||||
@@ -16,7 +16,7 @@ from unicodedata import normalize
|
||||
|
||||
from hsutil.misc import flatten
|
||||
from hsutil.str import multi_replace
|
||||
from hsutil import job
|
||||
from hscommon import job
|
||||
|
||||
(WEIGHT_WORDS,
|
||||
MATCH_SIMILAR_WORDS,
|
||||
@@ -25,15 +25,15 @@ NO_FIELD_ORDER) = range(3)
|
||||
JOB_REFRESH_RATE = 100
|
||||
|
||||
def getwords(s):
|
||||
if isinstance(s, unicode):
|
||||
if isinstance(s, str):
|
||||
s = normalize('NFD', s)
|
||||
s = multi_replace(s, "-_&+():;\\[]{}.,<>/?~!@#$*", ' ').lower()
|
||||
s = ''.join(c for c in s if c in string.ascii_letters + string.digits + string.whitespace)
|
||||
return filter(None, s.split(' ')) # filter() is to remove empty elements
|
||||
return [_f for _f in s.split(' ') if _f] # remove empty elements
|
||||
|
||||
def getfields(s):
|
||||
fields = [getwords(field) for field in s.split(' - ')]
|
||||
return filter(None, fields)
|
||||
return [_f for _f in fields if _f]
|
||||
|
||||
def unpack_fields(fields):
|
||||
result = []
|
||||
@@ -118,7 +118,7 @@ def build_word_dict(objects, j=job.nulljob):
|
||||
def merge_similar_words(word_dict):
|
||||
"""Take all keys in word_dict that are similar, and merge them together.
|
||||
"""
|
||||
keys = word_dict.keys()
|
||||
keys = list(word_dict.keys())
|
||||
keys.sort(key=len)# we want the shortest word to stay
|
||||
while keys:
|
||||
key = keys.pop(0)
|
||||
@@ -138,7 +138,7 @@ def reduce_common_words(word_dict, threshold):
|
||||
Because if we remove them, we will miss some duplicates!
|
||||
"""
|
||||
uncommon_words = set(word for word, objects in word_dict.items() if len(objects) < threshold)
|
||||
for word, objects in word_dict.items():
|
||||
for word, objects in list(word_dict.items()):
|
||||
if len(objects) < threshold:
|
||||
continue
|
||||
reduced = set()
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import tempfile
|
||||
import os.path as op
|
||||
from tempfile import mkdtemp
|
||||
|
||||
# Yes, this is a very low-tech solution, but at least it doesn't have all these annoying dependency
|
||||
# and resource problems.
|
||||
|
||||
MAIN_TEMPLATE = u"""
|
||||
MAIN_TEMPLATE = """
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
@@ -104,34 +103,34 @@ $rows
|
||||
</html>
|
||||
"""
|
||||
|
||||
COLHEADERS_TEMPLATE = u"<th>{name}</th>"
|
||||
COLHEADERS_TEMPLATE = "<th>{name}</th>"
|
||||
|
||||
ROW_TEMPLATE = u"""
|
||||
ROW_TEMPLATE = """
|
||||
<tr>
|
||||
<td class="{indented}">{filename}</td>{cells}
|
||||
</tr>
|
||||
"""
|
||||
|
||||
CELL_TEMPLATE = u"""<td>{value}</td>"""
|
||||
CELL_TEMPLATE = """<td>{value}</td>"""
|
||||
|
||||
def export_to_xhtml(colnames, rows):
|
||||
# a row is a list of values with the first value being a flag indicating if the row should be indented
|
||||
if rows:
|
||||
assert len(rows[0]) == len(colnames) + 1 # + 1 is for the "indented" flag
|
||||
colheaders = u''.join(COLHEADERS_TEMPLATE.format(name=name) for name in colnames)
|
||||
colheaders = ''.join(COLHEADERS_TEMPLATE.format(name=name) for name in colnames)
|
||||
rendered_rows = []
|
||||
for row in rows:
|
||||
# [2:] is to remove the indented flag + filename
|
||||
indented = u'indented' if row[0] else u''
|
||||
indented = 'indented' if row[0] else ''
|
||||
filename = row[1]
|
||||
cells = u''.join(CELL_TEMPLATE.format(value=value) for value in row[2:])
|
||||
cells = ''.join(CELL_TEMPLATE.format(value=value) for value in row[2:])
|
||||
rendered_rows.append(ROW_TEMPLATE.format(indented=indented, filename=filename, cells=cells))
|
||||
rendered_rows = u''.join(rendered_rows)
|
||||
rendered_rows = ''.join(rendered_rows)
|
||||
# The main template can't use format because the css code uses {}
|
||||
content = MAIN_TEMPLATE.replace('$colheaders', colheaders).replace('$rows', rendered_rows)
|
||||
folder = mkdtemp()
|
||||
destpath = op.join(folder, u'export.htm')
|
||||
fp = open(destpath, 'w')
|
||||
fp.write(content.encode('utf-8'))
|
||||
destpath = op.join(folder, 'export.htm')
|
||||
fp = open(destpath, 'wt', encoding='utf-8')
|
||||
fp.write(content)
|
||||
fp.close()
|
||||
return destpath
|
||||
|
||||
12
core/fs.py
12
core/fs.py
@@ -12,7 +12,7 @@
|
||||
# resulting needless complexity and memory usage. It's been a while since I wanted to do that fork,
|
||||
# and I'm doing it now.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
@@ -25,13 +25,13 @@ class FSError(Exception):
|
||||
cls_message = "An error has occured on '{name}' in '{parent}'"
|
||||
def __init__(self, fsobject, parent=None):
|
||||
message = self.cls_message
|
||||
if isinstance(fsobject, basestring):
|
||||
if isinstance(fsobject, str):
|
||||
name = fsobject
|
||||
elif isinstance(fsobject, File):
|
||||
name = fsobject.name
|
||||
else:
|
||||
name = ''
|
||||
parentname = unicode(parent) if parent is not None else ''
|
||||
parentname = str(parent) if parent is not None else ''
|
||||
Exception.__init__(self, message.format(name=name, parent=parentname))
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ class OperationError(FSError):
|
||||
class File(object):
|
||||
INITIAL_INFO = {
|
||||
'size': 0,
|
||||
'ctime': 0,
|
||||
'mtime': 0,
|
||||
'md5': '',
|
||||
'md5partial': '',
|
||||
@@ -82,10 +81,9 @@ class File(object):
|
||||
raise AttributeError()
|
||||
|
||||
def _read_info(self, field):
|
||||
if field in ('size', 'ctime', 'mtime'):
|
||||
if field in ('size', 'mtime'):
|
||||
stats = io.stat(self.path)
|
||||
self.size = nonone(stats.st_size, 0)
|
||||
self.ctime = nonone(stats.st_ctime, 0)
|
||||
self.mtime = nonone(stats.st_mtime, 0)
|
||||
elif field == 'md5partial':
|
||||
try:
|
||||
@@ -119,7 +117,7 @@ class File(object):
|
||||
If `attrnames` is not None, caches only attrnames.
|
||||
"""
|
||||
if attrnames is None:
|
||||
attrnames = self.INITIAL_INFO.keys()
|
||||
attrnames = list(self.INITIAL_INFO.keys())
|
||||
for attrname in attrnames:
|
||||
if attrname not in self.__dict__:
|
||||
self._read_info(attrname)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from hsutil.notify import Listener
|
||||
from hscommon.notify import Listener
|
||||
|
||||
class GUIObject(Listener):
|
||||
def __init__(self, view, app):
|
||||
@@ -24,6 +24,9 @@ class GUIObject(Listener):
|
||||
def marking_changed(self):
|
||||
pass
|
||||
|
||||
def problems_changed(self):
|
||||
pass
|
||||
|
||||
def results_changed(self):
|
||||
pass
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class DetailsPanel(GUIObject):
|
||||
ref = group.ref if group is not None and group.ref is not dupe else None
|
||||
l2 = self.app._get_display_info(ref, group, False)
|
||||
names = [c['display'] for c in self.app.data.COLUMNS]
|
||||
self._table = zip(names, l1, l2)
|
||||
self._table = list(zip(names, l1, l2))
|
||||
|
||||
#--- Public
|
||||
def row_count(self):
|
||||
|
||||
@@ -62,7 +62,7 @@ class DirectoryTree(GUIObject, Tree):
|
||||
def _refresh(self):
|
||||
self.clear()
|
||||
for path in self.app.directories:
|
||||
self.append(DirectoryNode(self.app, path, unicode(path)))
|
||||
self.append(DirectoryNode(self.app, path, str(path)))
|
||||
|
||||
def add_directory(self, path):
|
||||
self.app.add_directory(path)
|
||||
|
||||
31
core/gui/problem_dialog.py
Normal file
31
core/gui/problem_dialog.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2010-04-12
|
||||
# Copyright 2010 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 hscommon.notify import Broadcaster
|
||||
|
||||
from .base import GUIObject
|
||||
|
||||
class ProblemDialog(GUIObject, Broadcaster):
|
||||
def __init__(self, view, app):
|
||||
GUIObject.__init__(self, view, app)
|
||||
Broadcaster.__init__(self)
|
||||
self._selected_dupe = None
|
||||
|
||||
def reveal_selected_dupe(self):
|
||||
if self._selected_dupe is not None:
|
||||
self.app._reveal_path(self._selected_dupe.path)
|
||||
|
||||
def select_dupe(self, dupe):
|
||||
self._selected_dupe = dupe
|
||||
|
||||
#--- Event Handlers
|
||||
def problems_changed(self):
|
||||
self._selected_dupe = None
|
||||
self.notify('problems_changed')
|
||||
|
||||
43
core/gui/problem_table.py
Normal file
43
core/gui/problem_table.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2010-04-12
|
||||
# Copyright 2010 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 hscommon.notify import Listener
|
||||
from hsgui.table import GUITable, Row
|
||||
|
||||
class ProblemTable(GUITable, Listener):
|
||||
def __init__(self, view, problem_dialog):
|
||||
GUITable.__init__(self)
|
||||
Listener.__init__(self, problem_dialog)
|
||||
self.view = view
|
||||
self.dialog = problem_dialog
|
||||
|
||||
#--- Override
|
||||
def _update_selection(self):
|
||||
row = self.selected_row
|
||||
dupe = row.dupe if row is not None else None
|
||||
self.dialog.select_dupe(dupe)
|
||||
|
||||
def _fill(self):
|
||||
problems = self.dialog.app.results.problems
|
||||
for dupe, msg in problems:
|
||||
self.append(ProblemRow(self, dupe, msg))
|
||||
|
||||
#--- Event handlers
|
||||
def problems_changed(self):
|
||||
self.refresh()
|
||||
self.view.refresh()
|
||||
|
||||
|
||||
class ProblemRow(Row):
|
||||
def __init__(self, table, dupe, msg):
|
||||
Row.__init__(self, table)
|
||||
self.dupe = dupe
|
||||
self.msg = msg
|
||||
self.path = str(dupe.path)
|
||||
|
||||
@@ -63,7 +63,7 @@ class ResultTree(GUIObject, Tree):
|
||||
|
||||
def _select_nodes(self, nodes):
|
||||
Tree._select_nodes(self, nodes)
|
||||
self.app._select_dupes(map(attrgetter('_dupe'), nodes))
|
||||
self.app._select_dupes(list(map(attrgetter('_dupe'), nodes)))
|
||||
|
||||
#--- Private
|
||||
def _refresh(self):
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from lxml import etree
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from hsutil.files import FileOrPath
|
||||
|
||||
@@ -22,7 +22,7 @@ class IgnoreList(object):
|
||||
self._count = 0
|
||||
|
||||
def __iter__(self):
|
||||
for first,seconds in self._ignored.iteritems():
|
||||
for first,seconds in self._ignored.items():
|
||||
for second in seconds:
|
||||
yield (first,second)
|
||||
|
||||
@@ -77,14 +77,16 @@ class IgnoreList(object):
|
||||
infile can be a file object or a filename.
|
||||
"""
|
||||
try:
|
||||
root = etree.parse(infile).getroot()
|
||||
root = ET.parse(infile).getroot()
|
||||
except Exception:
|
||||
return
|
||||
for fn in root.iterchildren('file'):
|
||||
file_elems = (e for e in root if e.tag == 'file')
|
||||
for fn in file_elems:
|
||||
file_path = fn.get('path')
|
||||
if not file_path:
|
||||
continue
|
||||
for sfn in fn.iterchildren('file'):
|
||||
subfile_elems = (e for e in fn if e.tag == 'file')
|
||||
for sfn in subfile_elems:
|
||||
subfile_path = sfn.get('path')
|
||||
if subfile_path:
|
||||
self.Ignore(file_path, subfile_path)
|
||||
@@ -94,14 +96,14 @@ class IgnoreList(object):
|
||||
|
||||
outfile can be a file object or a filename.
|
||||
"""
|
||||
root = etree.Element('ignore_list')
|
||||
root = ET.Element('ignore_list')
|
||||
for filename, subfiles in self._ignored.items():
|
||||
file_node = etree.SubElement(root, 'file')
|
||||
file_node = ET.SubElement(root, 'file')
|
||||
file_node.set('path', filename)
|
||||
for subfilename in subfiles:
|
||||
subfile_node = etree.SubElement(file_node, 'file')
|
||||
subfile_node = ET.SubElement(file_node, 'file')
|
||||
subfile_node.set('path', subfilename)
|
||||
tree = etree.ElementTree(root)
|
||||
tree = ET.ElementTree(root)
|
||||
with FileOrPath(outfile, 'wb') as fp:
|
||||
tree.write(fp, encoding='utf-8')
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
import logging
|
||||
import re
|
||||
from lxml import etree
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from . import engine
|
||||
from hsutil.job import nulljob
|
||||
from hsutil.markable import Markable
|
||||
from hscommon.job import nulljob
|
||||
from hscommon.markable import Markable
|
||||
from hsutil.misc import flatten, nonone
|
||||
from hsutil.str import format_size
|
||||
from hsutil.files import FileOrPath
|
||||
@@ -32,6 +32,8 @@ class Results(Markable):
|
||||
self.__recalculate_stats()
|
||||
self.__marked_size = 0
|
||||
self.data = data_module
|
||||
self.problems = [] # (dupe, error_msg)
|
||||
self.is_modified = False
|
||||
|
||||
def _did_mark(self, dupe):
|
||||
self.__marked_size += dupe.size
|
||||
@@ -114,6 +116,7 @@ class Results(Markable):
|
||||
self.__group_of_duplicate[dupe] = g
|
||||
if not hasattr(dupe, 'is_ref'):
|
||||
dupe.is_ref = False
|
||||
self.is_modified = True
|
||||
old_filters = nonone(self.__filters, [])
|
||||
self.apply_filter(None)
|
||||
for filter_str in old_filters:
|
||||
@@ -146,7 +149,7 @@ class Results(Markable):
|
||||
self.__filters.append(filter_str)
|
||||
if self.__filtered_dupes is None:
|
||||
self.__filtered_dupes = flatten(g[:] for g in self.groups)
|
||||
self.__filtered_dupes = set(dupe for dupe in self.__filtered_dupes if filter_re.search(dupe.name))
|
||||
self.__filtered_dupes = set(dupe for dupe in self.__filtered_dupes if filter_re.search(str(dupe.path)))
|
||||
filtered_groups = set()
|
||||
for dupe in self.__filtered_dupes:
|
||||
filtered_groups.add(self.get_group_of_duplicate(dupe))
|
||||
@@ -175,16 +178,16 @@ class Results(Markable):
|
||||
|
||||
self.apply_filter(None)
|
||||
try:
|
||||
root = etree.parse(infile).getroot()
|
||||
root = ET.parse(infile).getroot()
|
||||
except Exception:
|
||||
return
|
||||
group_elems = list(root.iterchildren('group'))
|
||||
group_elems = list(root.getiterator('group'))
|
||||
groups = []
|
||||
marked = set()
|
||||
for group_elem in j.iter_with_progress(group_elems, every=100):
|
||||
group = engine.Group()
|
||||
dupes = []
|
||||
for file_elem in group_elem.iterchildren('file'):
|
||||
for file_elem in group_elem.getiterator('file'):
|
||||
path = file_elem.get('path')
|
||||
words = file_elem.get('words', '')
|
||||
if not path:
|
||||
@@ -197,7 +200,7 @@ class Results(Markable):
|
||||
dupes.append(file)
|
||||
if file_elem.get('marked') == 'y':
|
||||
marked.add(file)
|
||||
for match_elem in group_elem.iterchildren('match'):
|
||||
for match_elem in group_elem.getiterator('match'):
|
||||
try:
|
||||
attrs = match_elem.attrib
|
||||
first_file = dupes[int(attrs['first'])]
|
||||
@@ -215,6 +218,7 @@ class Results(Markable):
|
||||
self.groups = groups
|
||||
for dupe_file in marked:
|
||||
self.mark(dupe_file)
|
||||
self.is_modified = False
|
||||
|
||||
def make_ref(self, dupe):
|
||||
g = self.get_group_of_duplicate(dupe)
|
||||
@@ -228,19 +232,25 @@ class Results(Markable):
|
||||
self.__total_count -= 1
|
||||
self.__total_size -= dupe.size
|
||||
self.__dupes = None
|
||||
self.is_modified = True
|
||||
|
||||
def perform_on_marked(self, func, remove_from_results):
|
||||
problems = []
|
||||
for d in self.dupes:
|
||||
if self.is_marked(d) and (not func(d)):
|
||||
problems.append(d)
|
||||
# Performs `func` on all marked dupes. If an EnvironmentError is raised during the call,
|
||||
# the problematic dupe is added to self.problems.
|
||||
self.problems = []
|
||||
to_remove = []
|
||||
marked = (dupe for dupe in self.dupes if self.is_marked(dupe))
|
||||
for dupe in marked:
|
||||
try:
|
||||
func(dupe)
|
||||
to_remove.append(dupe)
|
||||
except EnvironmentError as e:
|
||||
self.problems.append((dupe, str(e)))
|
||||
if remove_from_results:
|
||||
to_remove = [d for d in self.dupes if self.is_marked(d) and (d not in problems)]
|
||||
self.remove_duplicates(to_remove)
|
||||
self.mark_none()
|
||||
for d in problems:
|
||||
self.mark(d)
|
||||
return len(problems)
|
||||
for dupe, _ in self.problems:
|
||||
self.mark(dupe)
|
||||
|
||||
def remove_duplicates(self, dupes):
|
||||
'''Remove 'dupes' from their respective group, and remove the group is it ends up empty.
|
||||
@@ -263,13 +273,14 @@ class Results(Markable):
|
||||
for group in affected_groups:
|
||||
group.discard_matches()
|
||||
self.__dupes = None
|
||||
self.is_modified = True
|
||||
|
||||
def save_to_xml(self, outfile):
|
||||
self.apply_filter(None)
|
||||
root = etree.Element('results')
|
||||
root = ET.Element('results')
|
||||
# writer = XMLGenerator(outfile, 'utf-8')
|
||||
for g in self.groups:
|
||||
group_elem = etree.SubElement(root, 'group')
|
||||
group_elem = ET.SubElement(root, 'group')
|
||||
dupe2index = {}
|
||||
for index, d in enumerate(g):
|
||||
dupe2index[d] = index
|
||||
@@ -277,19 +288,23 @@ class Results(Markable):
|
||||
words = engine.unpack_fields(d.words)
|
||||
except AttributeError:
|
||||
words = ()
|
||||
file_elem = etree.SubElement(group_elem, 'file')
|
||||
file_elem.set('path', unicode(d.path))
|
||||
file_elem.set('is_ref', ('y' if d.is_ref else 'n'))
|
||||
file_elem = ET.SubElement(group_elem, 'file')
|
||||
try:
|
||||
file_elem.set('path', str(d.path))
|
||||
file_elem.set('words', ','.join(words))
|
||||
except ValueError: # If there's an invalid character, just skip the file
|
||||
file_elem.set('path', '')
|
||||
file_elem.set('is_ref', ('y' if d.is_ref else 'n'))
|
||||
file_elem.set('marked', ('y' if self.is_marked(d) else 'n'))
|
||||
for match in g.matches:
|
||||
match_elem = etree.SubElement(group_elem, 'match')
|
||||
match_elem.set('first', unicode(dupe2index[match.first]))
|
||||
match_elem.set('second', unicode(dupe2index[match.second]))
|
||||
match_elem.set('percentage', unicode(int(match.percentage)))
|
||||
tree = etree.ElementTree(root)
|
||||
match_elem = ET.SubElement(group_elem, 'match')
|
||||
match_elem.set('first', str(dupe2index[match.first]))
|
||||
match_elem.set('second', str(dupe2index[match.second]))
|
||||
match_elem.set('percentage', str(int(match.percentage)))
|
||||
tree = ET.ElementTree(root)
|
||||
with FileOrPath(outfile, 'wb') as fp:
|
||||
tree.write(fp, encoding='utf-8')
|
||||
self.is_modified = False
|
||||
|
||||
def sort_dupes(self, key, asc=True, delta=False):
|
||||
if not self.__dupes:
|
||||
|
||||
@@ -7,25 +7,36 @@
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
|
||||
from hsutil import job, io
|
||||
from hscommon import job
|
||||
from hsutil import io
|
||||
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)
|
||||
class ScanType:
|
||||
Filename = 0
|
||||
Fields = 1
|
||||
FieldsNoOrder = 2
|
||||
Tag = 3
|
||||
# number 4 is obsolete
|
||||
Contents = 5
|
||||
ContentsAudio = 6
|
||||
|
||||
SCANNABLE_TAGS = ['track', 'artist', 'album', 'title', 'genre', 'year']
|
||||
|
||||
RE_DIGIT_ENDING = re.compile(r'\d+|\(\d+\)|\[\d+\]|{\d+}')
|
||||
|
||||
def is_same_with_digit(name, refname):
|
||||
# Returns True if name is the same as refname, but with digits (with brackets or not) at the end
|
||||
if not name.startswith(refname):
|
||||
return False
|
||||
end = name[len(refname):].strip()
|
||||
return RE_DIGIT_ENDING.match(end) is not None
|
||||
|
||||
class Scanner(object):
|
||||
def __init__(self):
|
||||
self.ignore_list = IgnoreList()
|
||||
@@ -37,22 +48,22 @@ class Scanner(object):
|
||||
for f in j.iter_with_progress(files, 'Read size of %d/%d files'):
|
||||
f.size # pre-read, makes a smoother progress if read here (especially for bundles)
|
||||
files = [f for f in files if f.size >= self.size_threshold]
|
||||
if self.scan_type in (SCAN_TYPE_CONTENT, SCAN_TYPE_CONTENT_AUDIO):
|
||||
sizeattr = 'size' if self.scan_type == SCAN_TYPE_CONTENT else 'audiosize'
|
||||
return engine.getmatches_by_contents(files, sizeattr, partial=self.scan_type==SCAN_TYPE_CONTENT_AUDIO, j=j)
|
||||
if self.scan_type in (ScanType.Contents, ScanType.ContentsAudio):
|
||||
sizeattr = 'size' if self.scan_type == ScanType.Contents else 'audiosize'
|
||||
return engine.getmatches_by_contents(files, sizeattr, partial=self.scan_type==ScanType.ContentsAudio, j=j)
|
||||
else:
|
||||
j = j.start_subjob([2, 8])
|
||||
kw = {}
|
||||
kw['match_similar_words'] = self.match_similar_words
|
||||
kw['weight_words'] = self.word_weighting
|
||||
kw['min_match_percentage'] = self.min_match_percentage
|
||||
if self.scan_type == SCAN_TYPE_FIELDS_NO_ORDER:
|
||||
self.scan_type = SCAN_TYPE_FIELDS
|
||||
if self.scan_type == ScanType.FieldsNoOrder:
|
||||
self.scan_type = ScanType.Fields
|
||||
kw['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],
|
||||
ScanType.Filename: lambda f: engine.getwords(rem_file_ext(f.name)),
|
||||
ScanType.Fields: lambda f: engine.getfields(rem_file_ext(f.name)),
|
||||
ScanType.Tag: lambda f: [engine.getwords(str(getattr(f, attrname))) for attrname in SCANNABLE_TAGS if attrname in self.scanned_tags],
|
||||
}[self.scan_type]
|
||||
for f in j.iter_with_progress(files, 'Read metadata of %d/%d files'):
|
||||
f.words = func(f)
|
||||
@@ -66,9 +77,13 @@ class Scanner(object):
|
||||
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:
|
||||
if 'copy' in dupename:
|
||||
return False
|
||||
if 'copy' in refname:
|
||||
return True
|
||||
if refname.startswith(dupename) and (refname[len(dupename):].strip().isdigit()):
|
||||
if is_same_with_digit(dupename, refname):
|
||||
return False
|
||||
if is_same_with_digit(refname, dupename):
|
||||
return True
|
||||
return len(dupe.path) > len(ref.path)
|
||||
|
||||
@@ -87,7 +102,7 @@ class Scanner(object):
|
||||
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 not self.ignore_list.AreIgnored(str(m.first.path), str(m.second.path))]
|
||||
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])
|
||||
@@ -102,7 +117,7 @@ class Scanner(object):
|
||||
match_similar_words = False
|
||||
min_match_percentage = 80
|
||||
mix_file_kind = True
|
||||
scan_type = SCAN_TYPE_FILENAME
|
||||
scan_type = ScanType.Filename
|
||||
scanned_tags = set(['artist', 'title'])
|
||||
size_threshold = 0
|
||||
word_weighting = False
|
||||
|
||||
@@ -9,14 +9,13 @@
|
||||
import os
|
||||
import logging
|
||||
|
||||
from nose.tools import eq_
|
||||
|
||||
from hsutil.testutil import eq_
|
||||
from hsutil.testcase import TestCase
|
||||
from hsutil import io
|
||||
from hsutil.path import Path
|
||||
from hsutil.decorators import log_calls
|
||||
import hsutil.files
|
||||
from hsutil.job import nulljob
|
||||
from hscommon.job import nulljob
|
||||
|
||||
from . import data
|
||||
from .results_test import GetTestGroups
|
||||
@@ -110,7 +109,7 @@ class TCDupeGuru(TestCase):
|
||||
|
||||
def test_Scan_with_objects_evaluating_to_false(self):
|
||||
class FakeFile(fs.File):
|
||||
def __nonzero__(self):
|
||||
def __bool__(self):
|
||||
return False
|
||||
|
||||
|
||||
@@ -119,7 +118,7 @@ class TCDupeGuru(TestCase):
|
||||
f1, f2 = [FakeFile('foo') for i in range(2)]
|
||||
f1.is_ref, f2.is_ref = (False, False)
|
||||
assert not (bool(f1) and bool(f2))
|
||||
app.directories.get_files = lambda: [f1, f2]
|
||||
app.directories.get_files = lambda: iter([f1, f2])
|
||||
app.directories._dirs.append('this is just so Scan() doesnt return 3')
|
||||
app.start_scanning() # no exception
|
||||
|
||||
@@ -201,11 +200,11 @@ class TCDupeGuruWithResults(TestCase):
|
||||
if expected is not None:
|
||||
expected = set(expected)
|
||||
not_called = expected - calls
|
||||
assert not not_called, u"These calls haven't been made: {0}".format(not_called)
|
||||
assert not not_called, "These calls haven't been made: {0}".format(not_called)
|
||||
if not_expected is not None:
|
||||
not_expected = set(not_expected)
|
||||
called = not_expected & calls
|
||||
assert not called, u"These calls shouldn't have been made: {0}".format(called)
|
||||
assert not called, "These calls shouldn't have been made: {0}".format(called)
|
||||
gui.clear_calls()
|
||||
|
||||
def clear_gui_calls(self):
|
||||
@@ -410,9 +409,9 @@ class TCDupeGuruWithResults(TestCase):
|
||||
|
||||
def test_only_unicode_is_added_to_ignore_list(self):
|
||||
def FakeIgnore(first,second):
|
||||
if not isinstance(first,unicode):
|
||||
if not isinstance(first,str):
|
||||
self.fail()
|
||||
if not isinstance(second,unicode):
|
||||
if not isinstance(second,str):
|
||||
self.fail()
|
||||
|
||||
app = self.app
|
||||
@@ -424,11 +423,11 @@ class TCDupeGuruWithResults(TestCase):
|
||||
class TCDupeGuru_renameSelected(TestCase):
|
||||
def setUp(self):
|
||||
p = self.tmppath()
|
||||
fp = open(unicode(p + 'foo bar 1'),mode='w')
|
||||
fp = open(str(p + 'foo bar 1'),mode='w')
|
||||
fp.close()
|
||||
fp = open(unicode(p + 'foo bar 2'),mode='w')
|
||||
fp = open(str(p + 'foo bar 2'),mode='w')
|
||||
fp.close()
|
||||
fp = open(unicode(p + 'foo bar 3'),mode='w')
|
||||
fp = open(str(p + 'foo bar 3'),mode='w')
|
||||
fp.close()
|
||||
files = fs.get_files(p)
|
||||
matches = engine.getmatches(files)
|
||||
|
||||
28
core/tests/conftest.py
Normal file
28
core/tests/conftest.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2010-07-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
|
||||
|
||||
# This unit is required to make tests work with py.test. When running
|
||||
|
||||
import py
|
||||
|
||||
def get_testunit(item):
|
||||
if hasattr(item, 'obj'):
|
||||
testunit = py.builtin._getimself(item.obj)
|
||||
if hasattr(testunit, 'global_setup'):
|
||||
return testunit
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
testunit = get_testunit(item)
|
||||
if testunit is not None:
|
||||
testunit.global_setup()
|
||||
|
||||
def pytest_runtest_teardown(item):
|
||||
testunit = get_testunit(item)
|
||||
if testunit is not None:
|
||||
testunit.global_teardown()
|
||||
@@ -10,10 +10,9 @@ import os.path as op
|
||||
import os
|
||||
import time
|
||||
|
||||
from nose.tools import eq_
|
||||
|
||||
from hsutil import io
|
||||
from hsutil.path import Path
|
||||
from hsutil.testutil import eq_
|
||||
from hsutil.testcase import TestCase
|
||||
|
||||
from ..directories import *
|
||||
@@ -83,8 +82,8 @@ class TCDirectories(TestCase):
|
||||
|
||||
def test_AddPath_non_latin(self):
|
||||
p = Path(self.tmpdir())
|
||||
to_add = p + u'unicode\u201a'
|
||||
os.mkdir(unicode(to_add))
|
||||
to_add = p + 'unicode\u201a'
|
||||
os.mkdir(str(to_add))
|
||||
d = Directories()
|
||||
try:
|
||||
d.add_path(to_add)
|
||||
@@ -112,7 +111,7 @@ class TCDirectories(TestCase):
|
||||
self.assertEqual(STATE_REFERENCE,d.get_state(p))
|
||||
self.assertEqual(STATE_REFERENCE,d.get_state(p + 'dir1'))
|
||||
self.assertEqual(1,len(d.states))
|
||||
self.assertEqual(p,d.states.keys()[0])
|
||||
self.assertEqual(p,list(d.states.keys())[0])
|
||||
self.assertEqual(STATE_REFERENCE,d.states[p])
|
||||
|
||||
def test_get_state_with_path_not_there(self):
|
||||
@@ -214,11 +213,11 @@ class TCDirectories(TestCase):
|
||||
|
||||
def test_unicode_save(self):
|
||||
d = Directories()
|
||||
p1 = self.tmppath() + u'hello\xe9'
|
||||
p1 = self.tmppath() + 'hello\xe9'
|
||||
io.mkdir(p1)
|
||||
io.mkdir(p1 + u'foo\xe9')
|
||||
io.mkdir(p1 + 'foo\xe9')
|
||||
d.add_path(p1)
|
||||
d.set_state(p1 + u'foo\xe9', STATE_EXCLUDED)
|
||||
d.set_state(p1 + 'foo\xe9', STATE_EXCLUDED)
|
||||
tmpxml = op.join(self.tmpdir(), 'directories_testunit.xml')
|
||||
try:
|
||||
d.save_to_file(tmpxml)
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
import sys
|
||||
|
||||
from nose.tools import eq_
|
||||
|
||||
from hsutil import job
|
||||
from hscommon import job
|
||||
from hsutil.decorators import log_calls
|
||||
from hsutil.misc import first
|
||||
from hsutil.testutil import eq_
|
||||
from hsutil.testcase import TestCase
|
||||
|
||||
from .. import engine, fs
|
||||
from .. import engine
|
||||
from ..engine import *
|
||||
|
||||
class NamedObject(object):
|
||||
@@ -46,6 +46,15 @@ def get_test_group():
|
||||
result.add_match(m3)
|
||||
return result
|
||||
|
||||
def assert_match(m, name1, name2):
|
||||
# When testing matches, whether objects are in first or second position very often doesn't
|
||||
# matter. This function makes this test more convenient.
|
||||
if m.first.name == name1:
|
||||
eq_(m.second.name, name2)
|
||||
else:
|
||||
eq_(m.first.name, name2)
|
||||
eq_(m.second.name, name1)
|
||||
|
||||
class TCgetwords(TestCase):
|
||||
def test_spaces(self):
|
||||
self.assertEqual(['a', 'b', 'c', 'd'], getwords("a b c d"))
|
||||
@@ -53,12 +62,12 @@ class TCgetwords(TestCase):
|
||||
|
||||
def test_splitter_chars(self):
|
||||
self.assertEqual(
|
||||
[chr(i) for i in xrange(ord('a'),ord('z')+1)],
|
||||
[chr(i) for i in range(ord('a'),ord('z')+1)],
|
||||
getwords("a-b_c&d+e(f)g;h\\i[j]k{l}m:n.o,p<q>r/s?t~u!v@w#x$y*z")
|
||||
)
|
||||
|
||||
def test_joiner_chars(self):
|
||||
self.assertEqual(["aec"], getwords(u"a'e\u0301c"))
|
||||
self.assertEqual(["aec"], getwords("a'e\u0301c"))
|
||||
|
||||
def test_empty(self):
|
||||
self.assertEqual([], getwords(''))
|
||||
@@ -67,7 +76,7 @@ class TCgetwords(TestCase):
|
||||
self.assertEqual(['foo', 'bar'], getwords('FOO BAR'))
|
||||
|
||||
def test_decompose_unicode(self):
|
||||
self.assertEqual(getwords(u'foo\xe9bar'), ['fooebar'])
|
||||
self.assertEqual(getwords('foo\xe9bar'), ['fooebar'])
|
||||
|
||||
|
||||
class TCgetfields(TestCase):
|
||||
@@ -351,23 +360,18 @@ class GetMatches(TestCase):
|
||||
l = [NamedObject("foo bar"),NamedObject("bar bleh"),NamedObject("a b c foo")]
|
||||
r = getmatches(l)
|
||||
self.assertEqual(2,len(r))
|
||||
seek = [m for m in r if m.percentage == 50] #"foo bar" and "bar bleh"
|
||||
m = seek[0]
|
||||
self.assertEqual(['foo','bar'],m.first.words)
|
||||
self.assertEqual(['bar','bleh'],m.second.words)
|
||||
seek = [m for m in r if m.percentage == 33] #"foo bar" and "a b c foo"
|
||||
m = seek[0]
|
||||
self.assertEqual(['foo','bar'],m.first.words)
|
||||
self.assertEqual(['a','b','c','foo'],m.second.words)
|
||||
m = first(m for m in r if m.percentage == 50) #"foo bar" and "bar bleh"
|
||||
assert_match(m, 'foo bar', 'bar bleh')
|
||||
m = first(m for m in r if m.percentage == 33) #"foo bar" and "a b c foo"
|
||||
assert_match(m, 'foo bar', 'a b c foo')
|
||||
|
||||
def test_null_and_unrelated_objects(self):
|
||||
l = [NamedObject("foo bar"),NamedObject("bar bleh"),NamedObject(""),NamedObject("unrelated object")]
|
||||
r = getmatches(l)
|
||||
self.assertEqual(1,len(r))
|
||||
eq_(len(r), 1)
|
||||
m = r[0]
|
||||
self.assertEqual(50,m.percentage)
|
||||
self.assertEqual(['foo','bar'],m.first.words)
|
||||
self.assertEqual(['bar','bleh'],m.second.words)
|
||||
eq_(m.percentage, 50)
|
||||
assert_match(m, 'foo bar', 'bar bleh')
|
||||
|
||||
def test_twice_the_same_word(self):
|
||||
l = [NamedObject("foo foo bar"),NamedObject("bar bleh")]
|
||||
@@ -764,7 +768,7 @@ class TCget_groups(TestCase):
|
||||
self.assert_(o3 in g)
|
||||
|
||||
def test_four_sized_group(self):
|
||||
l = [NamedObject("foobar") for i in xrange(4)]
|
||||
l = [NamedObject("foobar") for i in range(4)]
|
||||
m = getmatches(l)
|
||||
r = get_groups(m)
|
||||
self.assertEqual(1,len(r))
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import cStringIO
|
||||
from lxml import etree
|
||||
import io
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from nose.tools import eq_
|
||||
from hsutil.testutil import eq_
|
||||
|
||||
from ..ignore import *
|
||||
|
||||
@@ -59,10 +59,10 @@ def test_save_to_xml():
|
||||
il.Ignore('foo','bar')
|
||||
il.Ignore('foo','bleh')
|
||||
il.Ignore('bleh','bar')
|
||||
f = cStringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
il.save_to_xml(f)
|
||||
f.seek(0)
|
||||
doc = etree.parse(f)
|
||||
doc = ET.parse(f)
|
||||
root = doc.getroot()
|
||||
eq_(root.tag, 'ignore_list')
|
||||
eq_(len(root), 2)
|
||||
@@ -76,19 +76,18 @@ def test_SaveThenLoad():
|
||||
il.Ignore('foo', 'bar')
|
||||
il.Ignore('foo', 'bleh')
|
||||
il.Ignore('bleh', 'bar')
|
||||
il.Ignore(u'\u00e9', 'bar')
|
||||
f = cStringIO.StringIO()
|
||||
il.Ignore('\u00e9', 'bar')
|
||||
f = io.BytesIO()
|
||||
il.save_to_xml(f)
|
||||
f.seek(0)
|
||||
f.seek(0)
|
||||
il = IgnoreList()
|
||||
il.load_from_xml(f)
|
||||
eq_(4,len(il))
|
||||
assert il.AreIgnored(u'\u00e9','bar')
|
||||
assert il.AreIgnored('\u00e9','bar')
|
||||
|
||||
def test_LoadXML_with_empty_file_tags():
|
||||
f = cStringIO.StringIO()
|
||||
f.write('<?xml version="1.0" encoding="utf-8"?><ignore_list><file><file/></file></ignore_list>')
|
||||
f = io.BytesIO()
|
||||
f.write(b'<?xml version="1.0" encoding="utf-8"?><ignore_list><file><file/></file></ignore_list>')
|
||||
f.seek(0)
|
||||
il = IgnoreList()
|
||||
il.load_from_xml(f)
|
||||
@@ -130,12 +129,12 @@ def test_filter():
|
||||
|
||||
def test_save_with_non_ascii_items():
|
||||
il = IgnoreList()
|
||||
il.Ignore(u'\xac', u'\xbf')
|
||||
f = cStringIO.StringIO()
|
||||
il.Ignore('\xac', '\xbf')
|
||||
f = io.BytesIO()
|
||||
try:
|
||||
il.save_to_xml(f)
|
||||
except Exception as e:
|
||||
raise AssertionError(unicode(e))
|
||||
raise AssertionError(str(e))
|
||||
|
||||
def test_len():
|
||||
il = IgnoreList()
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import StringIO
|
||||
import io
|
||||
import os.path as op
|
||||
from lxml import etree
|
||||
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from hsutil.path import Path
|
||||
from hsutil.testutil import eq_
|
||||
from hsutil.testcase import TestCase
|
||||
from hsutil.misc import first
|
||||
|
||||
@@ -23,7 +25,7 @@ class NamedObject(engine_test.NamedObject):
|
||||
path = property(lambda x:Path('basepath') + x.name)
|
||||
is_ref = False
|
||||
|
||||
def __nonzero__(self):
|
||||
def __bool__(self):
|
||||
return False #Make sure that operations are made correctly when the bool value of files is false.
|
||||
|
||||
# Returns a group set that looks like that:
|
||||
@@ -52,21 +54,24 @@ class TCResultsEmpty(TestCase):
|
||||
self.test_stat_line() # make sure that the stats line isn't saying we applied a '[' filter
|
||||
|
||||
def test_stat_line(self):
|
||||
self.assertEqual("0 / 0 (0.00 B / 0.00 B) duplicates marked.",self.results.stat_line)
|
||||
eq_("0 / 0 (0.00 B / 0.00 B) duplicates marked.",self.results.stat_line)
|
||||
|
||||
def test_groups(self):
|
||||
self.assertEqual(0,len(self.results.groups))
|
||||
eq_(0,len(self.results.groups))
|
||||
|
||||
def test_get_group_of_duplicate(self):
|
||||
self.assert_(self.results.get_group_of_duplicate('foo') is None)
|
||||
assert self.results.get_group_of_duplicate('foo') is None
|
||||
|
||||
def test_save_to_xml(self):
|
||||
f = StringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
self.results.save_to_xml(f)
|
||||
f.seek(0)
|
||||
doc = etree.parse(f)
|
||||
doc = ET.parse(f)
|
||||
root = doc.getroot()
|
||||
self.assertEqual('results', root.tag)
|
||||
eq_('results', root.tag)
|
||||
|
||||
def test_is_modified(self):
|
||||
assert not self.results.is_modified
|
||||
|
||||
|
||||
class TCResultsWithSomeGroups(TestCase):
|
||||
@@ -76,57 +81,57 @@ class TCResultsWithSomeGroups(TestCase):
|
||||
self.results.groups = self.groups
|
||||
|
||||
def test_stat_line(self):
|
||||
self.assertEqual("0 / 3 (0.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("0 / 3 (0.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
|
||||
def test_groups(self):
|
||||
self.assertEqual(2,len(self.results.groups))
|
||||
eq_(2,len(self.results.groups))
|
||||
|
||||
def test_get_group_of_duplicate(self):
|
||||
for o in self.objects:
|
||||
g = self.results.get_group_of_duplicate(o)
|
||||
self.assert_(isinstance(g, engine.Group))
|
||||
self.assert_(o in g)
|
||||
self.assert_(self.results.get_group_of_duplicate(self.groups[0]) is None)
|
||||
assert isinstance(g, engine.Group)
|
||||
assert o in g
|
||||
assert self.results.get_group_of_duplicate(self.groups[0]) is None
|
||||
|
||||
def test_remove_duplicates(self):
|
||||
g1,g2 = self.results.groups
|
||||
self.results.remove_duplicates([g1.dupes[0]])
|
||||
self.assertEqual(2,len(g1))
|
||||
self.assert_(g1 in self.results.groups)
|
||||
eq_(2,len(g1))
|
||||
assert g1 in self.results.groups
|
||||
self.results.remove_duplicates([g1.ref])
|
||||
self.assertEqual(2,len(g1))
|
||||
self.assert_(g1 in self.results.groups)
|
||||
eq_(2,len(g1))
|
||||
assert g1 in self.results.groups
|
||||
self.results.remove_duplicates([g1.dupes[0]])
|
||||
self.assertEqual(0,len(g1))
|
||||
self.assert_(g1 not in self.results.groups)
|
||||
eq_(0,len(g1))
|
||||
assert g1 not in self.results.groups
|
||||
self.results.remove_duplicates([g2.dupes[0]])
|
||||
self.assertEqual(0,len(g2))
|
||||
self.assert_(g2 not in self.results.groups)
|
||||
self.assertEqual(0,len(self.results.groups))
|
||||
eq_(0,len(g2))
|
||||
assert g2 not in self.results.groups
|
||||
eq_(0,len(self.results.groups))
|
||||
|
||||
def test_remove_duplicates_with_ref_files(self):
|
||||
g1,g2 = self.results.groups
|
||||
self.objects[0].is_ref = True
|
||||
self.objects[1].is_ref = True
|
||||
self.results.remove_duplicates([self.objects[2]])
|
||||
self.assertEqual(0,len(g1))
|
||||
self.assert_(g1 not in self.results.groups)
|
||||
eq_(0,len(g1))
|
||||
assert g1 not in self.results.groups
|
||||
|
||||
def test_make_ref(self):
|
||||
g = self.results.groups[0]
|
||||
d = g.dupes[0]
|
||||
self.results.make_ref(d)
|
||||
self.assert_(d is g.ref)
|
||||
assert d is g.ref
|
||||
|
||||
def test_sort_groups(self):
|
||||
self.results.make_ref(self.objects[1]) #We want to make the 1024 sized object to go ref.
|
||||
g1,g2 = self.groups
|
||||
self.results.sort_groups(2) #2 is the key for size
|
||||
self.assert_(self.results.groups[0] is g2)
|
||||
self.assert_(self.results.groups[1] is g1)
|
||||
assert self.results.groups[0] is g2
|
||||
assert self.results.groups[1] is g1
|
||||
self.results.sort_groups(2,False)
|
||||
self.assert_(self.results.groups[0] is g1)
|
||||
self.assert_(self.results.groups[1] is g2)
|
||||
assert self.results.groups[0] is g1
|
||||
assert self.results.groups[1] is g2
|
||||
|
||||
def test_set_groups_when_sorted(self):
|
||||
self.results.make_ref(self.objects[1]) #We want to make the 1024 sized object to go ref.
|
||||
@@ -135,24 +140,24 @@ class TCResultsWithSomeGroups(TestCase):
|
||||
g1,g2 = groups
|
||||
g1.switch_ref(objects[1])
|
||||
self.results.groups = groups
|
||||
self.assert_(self.results.groups[0] is g2)
|
||||
self.assert_(self.results.groups[1] is g1)
|
||||
assert self.results.groups[0] is g2
|
||||
assert self.results.groups[1] is g1
|
||||
|
||||
def test_get_dupe_list(self):
|
||||
self.assertEqual([self.objects[1],self.objects[2],self.objects[4]],self.results.dupes)
|
||||
eq_([self.objects[1],self.objects[2],self.objects[4]],self.results.dupes)
|
||||
|
||||
def test_dupe_list_is_cached(self):
|
||||
self.assert_(self.results.dupes is self.results.dupes)
|
||||
assert self.results.dupes is self.results.dupes
|
||||
|
||||
def test_dupe_list_cache_is_invalidated_when_needed(self):
|
||||
o1,o2,o3,o4,o5 = self.objects
|
||||
self.assertEqual([o2,o3,o5],self.results.dupes)
|
||||
eq_([o2,o3,o5],self.results.dupes)
|
||||
self.results.make_ref(o2)
|
||||
self.assertEqual([o1,o3,o5],self.results.dupes)
|
||||
eq_([o1,o3,o5],self.results.dupes)
|
||||
objects,matches,groups = GetTestGroups()
|
||||
o1,o2,o3,o4,o5 = objects
|
||||
self.results.groups = groups
|
||||
self.assertEqual([o2,o3,o5],self.results.dupes)
|
||||
eq_([o2,o3,o5],self.results.dupes)
|
||||
|
||||
def test_dupe_list_sort(self):
|
||||
o1,o2,o3,o4,o5 = self.objects
|
||||
@@ -162,9 +167,9 @@ class TCResultsWithSomeGroups(TestCase):
|
||||
o4.size = 2
|
||||
o5.size = 1
|
||||
self.results.sort_dupes(2)
|
||||
self.assertEqual([o5,o3,o2],self.results.dupes)
|
||||
eq_([o5,o3,o2],self.results.dupes)
|
||||
self.results.sort_dupes(2,False)
|
||||
self.assertEqual([o2,o3,o5],self.results.dupes)
|
||||
eq_([o2,o3,o5],self.results.dupes)
|
||||
|
||||
def test_dupe_list_remember_sort(self):
|
||||
o1,o2,o3,o4,o5 = self.objects
|
||||
@@ -175,7 +180,7 @@ class TCResultsWithSomeGroups(TestCase):
|
||||
o5.size = 1
|
||||
self.results.sort_dupes(2)
|
||||
self.results.make_ref(o2)
|
||||
self.assertEqual([o5,o3,o1],self.results.dupes)
|
||||
eq_([o5,o3,o1],self.results.dupes)
|
||||
|
||||
def test_dupe_list_sort_delta_values(self):
|
||||
o1,o2,o3,o4,o5 = self.objects
|
||||
@@ -185,19 +190,69 @@ class TCResultsWithSomeGroups(TestCase):
|
||||
o4.size = 20
|
||||
o5.size = 1 #-19
|
||||
self.results.sort_dupes(2,delta=True)
|
||||
self.assertEqual([o5,o2,o3],self.results.dupes)
|
||||
eq_([o5,o2,o3],self.results.dupes)
|
||||
|
||||
def test_sort_empty_list(self):
|
||||
#There was an infinite loop when sorting an empty list.
|
||||
r = Results(data)
|
||||
r.sort_dupes(0)
|
||||
self.assertEqual([],r.dupes)
|
||||
eq_([],r.dupes)
|
||||
|
||||
def test_dupe_list_update_on_remove_duplicates(self):
|
||||
o1,o2,o3,o4,o5 = self.objects
|
||||
self.assertEqual(3,len(self.results.dupes))
|
||||
eq_(3,len(self.results.dupes))
|
||||
self.results.remove_duplicates([o2])
|
||||
self.assertEqual(2,len(self.results.dupes))
|
||||
eq_(2,len(self.results.dupes))
|
||||
|
||||
def test_is_modified(self):
|
||||
# Changing the groups sets the modified flag
|
||||
assert self.results.is_modified
|
||||
|
||||
def test_is_modified_after_save_and_load(self):
|
||||
# Saving/Loading a file sets the modified flag back to False
|
||||
def get_file(path):
|
||||
return [f for f in self.objects if str(f.path) == path][0]
|
||||
|
||||
f = io.BytesIO()
|
||||
self.results.save_to_xml(f)
|
||||
assert not self.results.is_modified
|
||||
self.results.groups = self.groups # sets the flag back
|
||||
f.seek(0)
|
||||
self.results.load_from_xml(f, get_file)
|
||||
assert not self.results.is_modified
|
||||
|
||||
|
||||
class ResultsWithSavedResults(TestCase):
|
||||
def setUp(self):
|
||||
self.results = Results(data)
|
||||
self.objects,self.matches,self.groups = GetTestGroups()
|
||||
self.results.groups = self.groups
|
||||
self.f = io.BytesIO()
|
||||
self.results.save_to_xml(self.f)
|
||||
self.f.seek(0)
|
||||
|
||||
def test_is_modified(self):
|
||||
# Saving a file sets the modified flag back to False
|
||||
assert not self.results.is_modified
|
||||
|
||||
def test_is_modified_after_load(self):
|
||||
# Loading a file sets the modified flag back to False
|
||||
def get_file(path):
|
||||
return [f for f in self.objects if str(f.path) == path][0]
|
||||
|
||||
self.results.groups = self.groups # sets the flag back
|
||||
self.results.load_from_xml(self.f, get_file)
|
||||
assert not self.results.is_modified
|
||||
|
||||
def test_is_modified_after_remove(self):
|
||||
# Removing dupes sets the modified flag
|
||||
self.results.remove_duplicates([self.results.groups[0].dupes[0]])
|
||||
assert self.results.is_modified
|
||||
|
||||
def test_is_modified_after_make_ref(self):
|
||||
# Making a dupe ref sets the modified flag
|
||||
self.results.make_ref(self.results.groups[0].dupes[0])
|
||||
assert self.results.is_modified
|
||||
|
||||
|
||||
class TCResultsMarkings(TestCase):
|
||||
@@ -207,27 +262,27 @@ class TCResultsMarkings(TestCase):
|
||||
self.results.groups = self.groups
|
||||
|
||||
def test_stat_line(self):
|
||||
self.assertEqual("0 / 3 (0.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("0 / 3 (0.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
self.results.mark(self.objects[1])
|
||||
self.assertEqual("1 / 3 (1.00 KB / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("1 / 3 (1.00 KB / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
self.results.mark_invert()
|
||||
self.assertEqual("2 / 3 (2.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("2 / 3 (2.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
self.results.mark_invert()
|
||||
self.results.unmark(self.objects[1])
|
||||
self.results.mark(self.objects[2])
|
||||
self.results.mark(self.objects[4])
|
||||
self.assertEqual("2 / 3 (2.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("2 / 3 (2.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
self.results.mark(self.objects[0]) #this is a ref, it can't be counted
|
||||
self.assertEqual("2 / 3 (2.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("2 / 3 (2.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
self.results.groups = self.groups
|
||||
self.assertEqual("0 / 3 (0.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("0 / 3 (0.00 B / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
|
||||
def test_with_ref_duplicate(self):
|
||||
self.objects[1].is_ref = True
|
||||
self.results.groups = self.groups
|
||||
self.assert_(not self.results.mark(self.objects[1]))
|
||||
assert not self.results.mark(self.objects[1])
|
||||
self.results.mark(self.objects[2])
|
||||
self.assertEqual("1 / 2 (1.00 B / 2.00 B) duplicates marked.",self.results.stat_line)
|
||||
eq_("1 / 2 (1.00 B / 2.00 B) duplicates marked.",self.results.stat_line)
|
||||
|
||||
def test_perform_on_marked(self):
|
||||
def log_object(o):
|
||||
@@ -237,33 +292,38 @@ class TCResultsMarkings(TestCase):
|
||||
log = []
|
||||
self.results.mark_all()
|
||||
self.results.perform_on_marked(log_object,False)
|
||||
self.assert_(self.objects[1] in log)
|
||||
self.assert_(self.objects[2] in log)
|
||||
self.assert_(self.objects[4] in log)
|
||||
self.assertEqual(3,len(log))
|
||||
assert self.objects[1] in log
|
||||
assert self.objects[2] in log
|
||||
assert self.objects[4] in log
|
||||
eq_(3,len(log))
|
||||
log = []
|
||||
self.results.mark_none()
|
||||
self.results.mark(self.objects[4])
|
||||
self.results.perform_on_marked(log_object,True)
|
||||
self.assertEqual(1,len(log))
|
||||
self.assert_(self.objects[4] in log)
|
||||
self.assertEqual(1,len(self.results.groups))
|
||||
eq_(1,len(log))
|
||||
assert self.objects[4] in log
|
||||
eq_(1,len(self.results.groups))
|
||||
|
||||
def test_perform_on_marked_with_problems(self):
|
||||
def log_object(o):
|
||||
log.append(o)
|
||||
return o is not self.objects[1]
|
||||
if o is self.objects[1]:
|
||||
raise EnvironmentError('foobar')
|
||||
|
||||
log = []
|
||||
self.results.mark_all()
|
||||
self.assert_(self.results.is_marked(self.objects[1]))
|
||||
self.assertEqual(1,self.results.perform_on_marked(log_object, True))
|
||||
self.assertEqual(3,len(log))
|
||||
self.assertEqual(1,len(self.results.groups))
|
||||
self.assertEqual(2,len(self.results.groups[0]))
|
||||
self.assert_(self.objects[1] in self.results.groups[0])
|
||||
self.assert_(not self.results.is_marked(self.objects[2]))
|
||||
self.assert_(self.results.is_marked(self.objects[1]))
|
||||
assert self.results.is_marked(self.objects[1])
|
||||
self.results.perform_on_marked(log_object, True)
|
||||
eq_(len(log), 3)
|
||||
eq_(len(self.results.groups), 1)
|
||||
eq_(len(self.results.groups[0]), 2)
|
||||
assert self.objects[1] in self.results.groups[0]
|
||||
assert not self.results.is_marked(self.objects[2])
|
||||
assert self.results.is_marked(self.objects[1])
|
||||
eq_(len(self.results.problems), 1)
|
||||
dupe, msg = self.results.problems[0]
|
||||
assert dupe is self.objects[1]
|
||||
eq_(msg, 'foobar')
|
||||
|
||||
def test_perform_on_marked_with_ref(self):
|
||||
def log_object(o):
|
||||
@@ -275,61 +335,61 @@ class TCResultsMarkings(TestCase):
|
||||
self.objects[1].is_ref = True
|
||||
self.results.mark_all()
|
||||
self.results.perform_on_marked(log_object,True)
|
||||
self.assert_(self.objects[1] not in log)
|
||||
self.assert_(self.objects[2] in log)
|
||||
self.assert_(self.objects[4] in log)
|
||||
self.assertEqual(2,len(log))
|
||||
self.assertEqual(0,len(self.results.groups))
|
||||
assert self.objects[1] not in log
|
||||
assert self.objects[2] in log
|
||||
assert self.objects[4] in log
|
||||
eq_(2,len(log))
|
||||
eq_(0,len(self.results.groups))
|
||||
|
||||
def test_perform_on_marked_remove_objects_only_at_the_end(self):
|
||||
def check_groups(o):
|
||||
self.assertEqual(3,len(g1))
|
||||
self.assertEqual(2,len(g2))
|
||||
eq_(3,len(g1))
|
||||
eq_(2,len(g2))
|
||||
return True
|
||||
|
||||
g1,g2 = self.results.groups
|
||||
self.results.mark_all()
|
||||
self.results.perform_on_marked(check_groups,True)
|
||||
self.assertEqual(0,len(g1))
|
||||
self.assertEqual(0,len(g2))
|
||||
self.assertEqual(0,len(self.results.groups))
|
||||
eq_(0,len(g1))
|
||||
eq_(0,len(g2))
|
||||
eq_(0,len(self.results.groups))
|
||||
|
||||
def test_remove_duplicates(self):
|
||||
g1 = self.results.groups[0]
|
||||
g2 = self.results.groups[1]
|
||||
self.results.mark(g1.dupes[0])
|
||||
self.assertEqual("1 / 3 (1.00 KB / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("1 / 3 (1.00 KB / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
self.results.remove_duplicates([g1.dupes[1]])
|
||||
self.assertEqual("1 / 2 (1.00 KB / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("1 / 2 (1.00 KB / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
self.results.remove_duplicates([g1.dupes[0]])
|
||||
self.assertEqual("0 / 1 (0.00 B / 1.00 B) duplicates marked.",self.results.stat_line)
|
||||
eq_("0 / 1 (0.00 B / 1.00 B) duplicates marked.",self.results.stat_line)
|
||||
|
||||
def test_make_ref(self):
|
||||
g = self.results.groups[0]
|
||||
d = g.dupes[0]
|
||||
self.results.mark(d)
|
||||
self.assertEqual("1 / 3 (1.00 KB / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
eq_("1 / 3 (1.00 KB / 1.01 KB) duplicates marked.",self.results.stat_line)
|
||||
self.results.make_ref(d)
|
||||
self.assertEqual("0 / 3 (0.00 B / 3.00 B) duplicates marked.",self.results.stat_line)
|
||||
eq_("0 / 3 (0.00 B / 3.00 B) duplicates marked.",self.results.stat_line)
|
||||
self.results.make_ref(d)
|
||||
self.assertEqual("0 / 3 (0.00 B / 3.00 B) duplicates marked.",self.results.stat_line)
|
||||
eq_("0 / 3 (0.00 B / 3.00 B) duplicates marked.",self.results.stat_line)
|
||||
|
||||
def test_SaveXML(self):
|
||||
self.results.mark(self.objects[1])
|
||||
self.results.mark_invert()
|
||||
f = StringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
self.results.save_to_xml(f)
|
||||
f.seek(0)
|
||||
doc = etree.parse(f)
|
||||
doc = ET.parse(f)
|
||||
root = doc.getroot()
|
||||
g1, g2 = root.iterchildren('group')
|
||||
d1, d2, d3 = g1.iterchildren('file')
|
||||
self.assertEqual('n', d1.get('marked'))
|
||||
self.assertEqual('n', d2.get('marked'))
|
||||
self.assertEqual('y', d3.get('marked'))
|
||||
d1, d2 = g2.iterchildren('file')
|
||||
self.assertEqual('n', d1.get('marked'))
|
||||
self.assertEqual('y', d2.get('marked'))
|
||||
g1, g2 = root.getiterator('group')
|
||||
d1, d2, d3 = g1.getiterator('file')
|
||||
eq_('n', d1.get('marked'))
|
||||
eq_('n', d2.get('marked'))
|
||||
eq_('y', d3.get('marked'))
|
||||
d1, d2 = g2.getiterator('file')
|
||||
eq_('n', d1.get('marked'))
|
||||
eq_('y', d2.get('marked'))
|
||||
|
||||
def test_LoadXML(self):
|
||||
def get_file(path):
|
||||
@@ -338,16 +398,16 @@ class TCResultsMarkings(TestCase):
|
||||
self.objects[4].name = 'ibabtu 2' #we can't have 2 files with the same path
|
||||
self.results.mark(self.objects[1])
|
||||
self.results.mark_invert()
|
||||
f = StringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
self.results.save_to_xml(f)
|
||||
f.seek(0)
|
||||
r = Results(data)
|
||||
r.load_from_xml(f,get_file)
|
||||
self.assert_(not r.is_marked(self.objects[0]))
|
||||
self.assert_(not r.is_marked(self.objects[1]))
|
||||
self.assert_(r.is_marked(self.objects[2]))
|
||||
self.assert_(not r.is_marked(self.objects[3]))
|
||||
self.assert_(r.is_marked(self.objects[4]))
|
||||
assert not r.is_marked(self.objects[0])
|
||||
assert not r.is_marked(self.objects[1])
|
||||
assert r.is_marked(self.objects[2])
|
||||
assert not r.is_marked(self.objects[3])
|
||||
assert r.is_marked(self.objects[4])
|
||||
|
||||
|
||||
class TCResultsXML(TestCase):
|
||||
@@ -362,38 +422,38 @@ class TCResultsXML(TestCase):
|
||||
def test_save_to_xml(self):
|
||||
self.objects[0].is_ref = True
|
||||
self.objects[0].words = [['foo','bar']]
|
||||
f = StringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
self.results.save_to_xml(f)
|
||||
f.seek(0)
|
||||
doc = etree.parse(f)
|
||||
doc = ET.parse(f)
|
||||
root = doc.getroot()
|
||||
self.assertEqual('results', root.tag)
|
||||
self.assertEqual(2, len(root))
|
||||
self.assertEqual(2, len([c for c in root if c.tag == 'group']))
|
||||
eq_('results', root.tag)
|
||||
eq_(2, len(root))
|
||||
eq_(2, len([c for c in root if c.tag == 'group']))
|
||||
g1, g2 = root
|
||||
self.assertEqual(6,len(g1))
|
||||
self.assertEqual(3,len([c for c in g1 if c.tag == 'file']))
|
||||
self.assertEqual(3,len([c for c in g1 if c.tag == 'match']))
|
||||
eq_(6,len(g1))
|
||||
eq_(3,len([c for c in g1 if c.tag == 'file']))
|
||||
eq_(3,len([c for c in g1 if c.tag == 'match']))
|
||||
d1, d2, d3 = [c for c in g1 if c.tag == 'file']
|
||||
self.assertEqual(op.join('basepath','foo bar'),d1.get('path'))
|
||||
self.assertEqual(op.join('basepath','bar bleh'),d2.get('path'))
|
||||
self.assertEqual(op.join('basepath','foo bleh'),d3.get('path'))
|
||||
self.assertEqual('y',d1.get('is_ref'))
|
||||
self.assertEqual('n',d2.get('is_ref'))
|
||||
self.assertEqual('n',d3.get('is_ref'))
|
||||
self.assertEqual('foo,bar',d1.get('words'))
|
||||
self.assertEqual('bar,bleh',d2.get('words'))
|
||||
self.assertEqual('foo,bleh',d3.get('words'))
|
||||
self.assertEqual(3,len(g2))
|
||||
self.assertEqual(2,len([c for c in g2 if c.tag == 'file']))
|
||||
self.assertEqual(1,len([c for c in g2 if c.tag == 'match']))
|
||||
eq_(op.join('basepath','foo bar'),d1.get('path'))
|
||||
eq_(op.join('basepath','bar bleh'),d2.get('path'))
|
||||
eq_(op.join('basepath','foo bleh'),d3.get('path'))
|
||||
eq_('y',d1.get('is_ref'))
|
||||
eq_('n',d2.get('is_ref'))
|
||||
eq_('n',d3.get('is_ref'))
|
||||
eq_('foo,bar',d1.get('words'))
|
||||
eq_('bar,bleh',d2.get('words'))
|
||||
eq_('foo,bleh',d3.get('words'))
|
||||
eq_(3,len(g2))
|
||||
eq_(2,len([c for c in g2 if c.tag == 'file']))
|
||||
eq_(1,len([c for c in g2 if c.tag == 'match']))
|
||||
d1, d2 = [c for c in g2 if c.tag == 'file']
|
||||
self.assertEqual(op.join('basepath','ibabtu'),d1.get('path'))
|
||||
self.assertEqual(op.join('basepath','ibabtu'),d2.get('path'))
|
||||
self.assertEqual('n',d1.get('is_ref'))
|
||||
self.assertEqual('n',d2.get('is_ref'))
|
||||
self.assertEqual('ibabtu',d1.get('words'))
|
||||
self.assertEqual('ibabtu',d2.get('words'))
|
||||
eq_(op.join('basepath','ibabtu'),d1.get('path'))
|
||||
eq_(op.join('basepath','ibabtu'),d2.get('path'))
|
||||
eq_('n',d1.get('is_ref'))
|
||||
eq_('n',d2.get('is_ref'))
|
||||
eq_('ibabtu',d1.get('words'))
|
||||
eq_('ibabtu',d2.get('words'))
|
||||
|
||||
def test_LoadXML(self):
|
||||
def get_file(path):
|
||||
@@ -401,30 +461,30 @@ class TCResultsXML(TestCase):
|
||||
|
||||
self.objects[0].is_ref = True
|
||||
self.objects[4].name = 'ibabtu 2' #we can't have 2 files with the same path
|
||||
f = StringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
self.results.save_to_xml(f)
|
||||
f.seek(0)
|
||||
r = Results(data)
|
||||
r.load_from_xml(f,get_file)
|
||||
self.assertEqual(2,len(r.groups))
|
||||
eq_(2,len(r.groups))
|
||||
g1,g2 = r.groups
|
||||
self.assertEqual(3,len(g1))
|
||||
self.assert_(g1[0].is_ref)
|
||||
self.assert_(not g1[1].is_ref)
|
||||
self.assert_(not g1[2].is_ref)
|
||||
self.assert_(g1[0] is self.objects[0])
|
||||
self.assert_(g1[1] is self.objects[1])
|
||||
self.assert_(g1[2] is self.objects[2])
|
||||
self.assertEqual(['foo','bar'],g1[0].words)
|
||||
self.assertEqual(['bar','bleh'],g1[1].words)
|
||||
self.assertEqual(['foo','bleh'],g1[2].words)
|
||||
self.assertEqual(2,len(g2))
|
||||
self.assert_(not g2[0].is_ref)
|
||||
self.assert_(not g2[1].is_ref)
|
||||
self.assert_(g2[0] is self.objects[3])
|
||||
self.assert_(g2[1] is self.objects[4])
|
||||
self.assertEqual(['ibabtu'],g2[0].words)
|
||||
self.assertEqual(['ibabtu'],g2[1].words)
|
||||
eq_(3,len(g1))
|
||||
assert g1[0].is_ref
|
||||
assert not g1[1].is_ref
|
||||
assert not g1[2].is_ref
|
||||
assert g1[0] is self.objects[0]
|
||||
assert g1[1] is self.objects[1]
|
||||
assert g1[2] is self.objects[2]
|
||||
eq_(['foo','bar'],g1[0].words)
|
||||
eq_(['bar','bleh'],g1[1].words)
|
||||
eq_(['foo','bleh'],g1[2].words)
|
||||
eq_(2,len(g2))
|
||||
assert not g2[0].is_ref
|
||||
assert not g2[1].is_ref
|
||||
assert g2[0] is self.objects[3]
|
||||
assert g2[1] is self.objects[4]
|
||||
eq_(['ibabtu'],g2[0].words)
|
||||
eq_(['ibabtu'],g2[1].words)
|
||||
|
||||
def test_LoadXML_with_filename(self):
|
||||
def get_file(path):
|
||||
@@ -435,7 +495,7 @@ class TCResultsXML(TestCase):
|
||||
self.results.save_to_xml(filename)
|
||||
r = Results(data)
|
||||
r.load_from_xml(filename,get_file)
|
||||
self.assertEqual(2,len(r.groups))
|
||||
eq_(2,len(r.groups))
|
||||
|
||||
def test_LoadXML_with_some_files_that_dont_exist_anymore(self):
|
||||
def get_file(path):
|
||||
@@ -444,84 +504,84 @@ class TCResultsXML(TestCase):
|
||||
return [f for f in self.objects if str(f.path) == path][0]
|
||||
|
||||
self.objects[4].name = 'ibabtu 2' #we can't have 2 files with the same path
|
||||
f = StringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
self.results.save_to_xml(f)
|
||||
f.seek(0)
|
||||
r = Results(data)
|
||||
r.load_from_xml(f,get_file)
|
||||
self.assertEqual(1,len(r.groups))
|
||||
self.assertEqual(3,len(r.groups[0]))
|
||||
eq_(1,len(r.groups))
|
||||
eq_(3,len(r.groups[0]))
|
||||
|
||||
def test_LoadXML_missing_attributes_and_bogus_elements(self):
|
||||
def get_file(path):
|
||||
return [f for f in self.objects if str(f.path) == path][0]
|
||||
|
||||
root = etree.Element('foobar') #The root element shouldn't matter, really.
|
||||
group_node = etree.SubElement(root, 'group')
|
||||
dupe_node = etree.SubElement(group_node, 'file') #Perfectly correct file
|
||||
root = ET.Element('foobar') #The root element shouldn't matter, really.
|
||||
group_node = ET.SubElement(root, 'group')
|
||||
dupe_node = ET.SubElement(group_node, 'file') #Perfectly correct file
|
||||
dupe_node.set('path', op.join('basepath','foo bar'))
|
||||
dupe_node.set('is_ref', 'y')
|
||||
dupe_node.set('words', 'foo,bar')
|
||||
dupe_node = etree.SubElement(group_node, 'file') #is_ref missing, default to 'n'
|
||||
dupe_node = ET.SubElement(group_node, 'file') #is_ref missing, default to 'n'
|
||||
dupe_node.set('path',op.join('basepath','foo bleh'))
|
||||
dupe_node.set('words','foo,bleh')
|
||||
dupe_node = etree.SubElement(group_node, 'file') #words are missing, valid.
|
||||
dupe_node = ET.SubElement(group_node, 'file') #words are missing, valid.
|
||||
dupe_node.set('path',op.join('basepath','bar bleh'))
|
||||
dupe_node = etree.SubElement(group_node, 'file') #path is missing, invalid.
|
||||
dupe_node = ET.SubElement(group_node, 'file') #path is missing, invalid.
|
||||
dupe_node.set('words','foo,bleh')
|
||||
dupe_node = etree.SubElement(group_node, 'foobar') #Invalid element name
|
||||
dupe_node = ET.SubElement(group_node, 'foobar') #Invalid element name
|
||||
dupe_node.set('path',op.join('basepath','bar bleh'))
|
||||
dupe_node.set('is_ref','y')
|
||||
dupe_node.set('words','bar,bleh')
|
||||
match_node = etree.SubElement(group_node, 'match') # match pointing to a bad index
|
||||
match_node = ET.SubElement(group_node, 'match') # match pointing to a bad index
|
||||
match_node.set('first', '42')
|
||||
match_node.set('second', '45')
|
||||
match_node = etree.SubElement(group_node, 'match') # match with missing attrs
|
||||
match_node = etree.SubElement(group_node, 'match') # match with non-int values
|
||||
match_node = ET.SubElement(group_node, 'match') # match with missing attrs
|
||||
match_node = ET.SubElement(group_node, 'match') # match with non-int values
|
||||
match_node.set('first', 'foo')
|
||||
match_node.set('second', 'bar')
|
||||
match_node.set('percentage', 'baz')
|
||||
group_node = etree.SubElement(root, 'foobar') #invalid group
|
||||
group_node = etree.SubElement(root, 'group') #empty group
|
||||
f = StringIO.StringIO()
|
||||
tree = etree.ElementTree(root)
|
||||
group_node = ET.SubElement(root, 'foobar') #invalid group
|
||||
group_node = ET.SubElement(root, 'group') #empty group
|
||||
f = io.BytesIO()
|
||||
tree = ET.ElementTree(root)
|
||||
tree.write(f, encoding='utf-8')
|
||||
f.seek(0)
|
||||
r = Results(data)
|
||||
r.load_from_xml(f, get_file)
|
||||
self.assertEqual(1,len(r.groups))
|
||||
self.assertEqual(3,len(r.groups[0]))
|
||||
eq_(1,len(r.groups))
|
||||
eq_(3,len(r.groups[0]))
|
||||
|
||||
def test_xml_non_ascii(self):
|
||||
def get_file(path):
|
||||
if path == op.join('basepath',u'\xe9foo bar'):
|
||||
if path == op.join('basepath','\xe9foo bar'):
|
||||
return objects[0]
|
||||
if path == op.join('basepath',u'bar bleh'):
|
||||
if path == op.join('basepath','bar bleh'):
|
||||
return objects[1]
|
||||
|
||||
objects = [NamedObject(u"\xe9foo bar",True),NamedObject("bar bleh",True)]
|
||||
objects = [NamedObject("\xe9foo bar",True),NamedObject("bar bleh",True)]
|
||||
matches = engine.getmatches(objects) #we should have 5 matches
|
||||
groups = engine.get_groups(matches) #We should have 2 groups
|
||||
for g in groups:
|
||||
g.prioritize(lambda x:objects.index(x)) #We want the dupes to be in the same order as the list is
|
||||
results = Results(data)
|
||||
results.groups = groups
|
||||
f = StringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
results.save_to_xml(f)
|
||||
f.seek(0)
|
||||
r = Results(data)
|
||||
r.load_from_xml(f,get_file)
|
||||
g = r.groups[0]
|
||||
self.assertEqual(u"\xe9foo bar",g[0].name)
|
||||
self.assertEqual(['efoo','bar'],g[0].words)
|
||||
eq_("\xe9foo bar",g[0].name)
|
||||
eq_(['efoo','bar'],g[0].words)
|
||||
|
||||
def test_load_invalid_xml(self):
|
||||
f = StringIO.StringIO()
|
||||
f.write('<this is invalid')
|
||||
f = io.BytesIO()
|
||||
f.write(b'<this is invalid')
|
||||
f.seek(0)
|
||||
r = Results(data)
|
||||
r.load_from_xml(f,None)
|
||||
self.assertEqual(0,len(r.groups))
|
||||
eq_(0,len(r.groups))
|
||||
|
||||
def test_load_non_existant_xml(self):
|
||||
r = Results(data)
|
||||
@@ -529,7 +589,7 @@ class TCResultsXML(TestCase):
|
||||
r.load_from_xml('does_not_exist.xml', None)
|
||||
except IOError:
|
||||
self.fail()
|
||||
self.assertEqual(0,len(r.groups))
|
||||
eq_(0,len(r.groups))
|
||||
|
||||
def test_remember_match_percentage(self):
|
||||
group = self.groups[0]
|
||||
@@ -539,7 +599,7 @@ class TCResultsXML(TestCase):
|
||||
fake_matches.add(engine.Match(d1, d3, 43))
|
||||
fake_matches.add(engine.Match(d2, d3, 46))
|
||||
group.matches = fake_matches
|
||||
f = StringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
results = self.results
|
||||
results.save_to_xml(f)
|
||||
f.seek(0)
|
||||
@@ -548,21 +608,31 @@ class TCResultsXML(TestCase):
|
||||
group = results.groups[0]
|
||||
d1, d2, d3 = group
|
||||
match = group.get_match_of(d2) #d1 - d2
|
||||
self.assertEqual(42, match[2])
|
||||
eq_(42, match[2])
|
||||
match = group.get_match_of(d3) #d1 - d3
|
||||
self.assertEqual(43, match[2])
|
||||
eq_(43, match[2])
|
||||
group.switch_ref(d2)
|
||||
match = group.get_match_of(d3) #d2 - d3
|
||||
self.assertEqual(46, match[2])
|
||||
eq_(46, match[2])
|
||||
|
||||
def test_save_and_load(self):
|
||||
# previously, when reloading matches, they wouldn't be reloaded as namedtuples
|
||||
f = StringIO.StringIO()
|
||||
f = io.BytesIO()
|
||||
self.results.save_to_xml(f)
|
||||
f.seek(0)
|
||||
self.results.load_from_xml(f, self.get_file)
|
||||
first(self.results.groups[0].matches).percentage
|
||||
|
||||
def test_apply_filter_works_on_paths(self):
|
||||
# apply_filter() searches on the whole path, not just on the filename.
|
||||
self.results.apply_filter('basepath')
|
||||
eq_(len(self.results.groups), 2)
|
||||
|
||||
def test_save_xml_with_invalid_characters(self):
|
||||
# Don't crash when saving files that have invalid xml characters in their path
|
||||
self.objects[0].name = 'foo\x19'
|
||||
self.results.save_to_xml(io.BytesIO()) # don't crash
|
||||
|
||||
|
||||
class TCResultsFilter(TestCase):
|
||||
def setUp(self):
|
||||
@@ -572,47 +642,47 @@ class TCResultsFilter(TestCase):
|
||||
self.results.apply_filter(r'foo')
|
||||
|
||||
def test_groups(self):
|
||||
self.assertEqual(1, len(self.results.groups))
|
||||
self.assert_(self.results.groups[0] is self.groups[0])
|
||||
eq_(1, len(self.results.groups))
|
||||
assert self.results.groups[0] is self.groups[0]
|
||||
|
||||
def test_dupes(self):
|
||||
# There are 2 objects matching. The first one is ref. Only the 3rd one is supposed to be in dupes.
|
||||
self.assertEqual(1, len(self.results.dupes))
|
||||
self.assert_(self.results.dupes[0] is self.objects[2])
|
||||
eq_(1, len(self.results.dupes))
|
||||
assert self.results.dupes[0] is self.objects[2]
|
||||
|
||||
def test_cancel_filter(self):
|
||||
self.results.apply_filter(None)
|
||||
self.assertEqual(3, len(self.results.dupes))
|
||||
self.assertEqual(2, len(self.results.groups))
|
||||
eq_(3, len(self.results.dupes))
|
||||
eq_(2, len(self.results.groups))
|
||||
|
||||
def test_dupes_reconstructed_filtered(self):
|
||||
# make_ref resets self.__dupes to None. When it's reconstructed, we want it filtered
|
||||
dupe = self.results.dupes[0] #3rd object
|
||||
self.results.make_ref(dupe)
|
||||
self.assertEqual(1, len(self.results.dupes))
|
||||
self.assert_(self.results.dupes[0] is self.objects[0])
|
||||
eq_(1, len(self.results.dupes))
|
||||
assert self.results.dupes[0] is self.objects[0]
|
||||
|
||||
def test_include_ref_dupes_in_filter(self):
|
||||
# When only the ref of a group match the filter, include it in the group
|
||||
self.results.apply_filter(None)
|
||||
self.results.apply_filter(r'foo bar')
|
||||
self.assertEqual(1, len(self.results.groups))
|
||||
self.assertEqual(0, len(self.results.dupes))
|
||||
eq_(1, len(self.results.groups))
|
||||
eq_(0, len(self.results.dupes))
|
||||
|
||||
def test_filters_build_on_one_another(self):
|
||||
self.results.apply_filter(r'bar')
|
||||
self.assertEqual(1, len(self.results.groups))
|
||||
self.assertEqual(0, len(self.results.dupes))
|
||||
eq_(1, len(self.results.groups))
|
||||
eq_(0, len(self.results.dupes))
|
||||
|
||||
def test_stat_line(self):
|
||||
expected = '0 / 1 (0.00 B / 1.00 B) duplicates marked. filter: foo'
|
||||
self.assertEqual(expected, self.results.stat_line)
|
||||
eq_(expected, self.results.stat_line)
|
||||
self.results.apply_filter(r'bar')
|
||||
expected = '0 / 0 (0.00 B / 0.00 B) duplicates marked. filter: foo --> bar'
|
||||
self.assertEqual(expected, self.results.stat_line)
|
||||
eq_(expected, self.results.stat_line)
|
||||
self.results.apply_filter(None)
|
||||
expected = '0 / 3 (0.00 B / 1.01 KB) duplicates marked.'
|
||||
self.assertEqual(expected, self.results.stat_line)
|
||||
eq_(expected, self.results.stat_line)
|
||||
|
||||
def test_mark_count_is_filtered_as_well(self):
|
||||
self.results.apply_filter(None)
|
||||
@@ -621,7 +691,7 @@ class TCResultsFilter(TestCase):
|
||||
self.results.mark(dupe)
|
||||
self.results.apply_filter(r'foo')
|
||||
expected = '1 / 1 (1.00 B / 1.00 B) duplicates marked. filter: foo'
|
||||
self.assertEqual(expected, self.results.stat_line)
|
||||
eq_(expected, self.results.stat_line)
|
||||
|
||||
def test_sort_groups(self):
|
||||
self.results.apply_filter(None)
|
||||
@@ -629,22 +699,22 @@ class TCResultsFilter(TestCase):
|
||||
g1,g2 = self.groups
|
||||
self.results.apply_filter('a') # Matches both group
|
||||
self.results.sort_groups(2) #2 is the key for size
|
||||
self.assert_(self.results.groups[0] is g2)
|
||||
self.assert_(self.results.groups[1] is g1)
|
||||
assert self.results.groups[0] is g2
|
||||
assert self.results.groups[1] is g1
|
||||
self.results.apply_filter(None)
|
||||
self.assert_(self.results.groups[0] is g2)
|
||||
self.assert_(self.results.groups[1] is g1)
|
||||
assert self.results.groups[0] is g2
|
||||
assert self.results.groups[1] is g1
|
||||
self.results.sort_groups(2, False)
|
||||
self.results.apply_filter('a')
|
||||
self.assert_(self.results.groups[1] is g2)
|
||||
self.assert_(self.results.groups[0] is g1)
|
||||
assert self.results.groups[1] is g2
|
||||
assert self.results.groups[0] is g1
|
||||
|
||||
def test_set_group(self):
|
||||
#We want the new group to be filtered
|
||||
self.objects, self.matches, self.groups = GetTestGroups()
|
||||
self.results.groups = self.groups
|
||||
self.assertEqual(1, len(self.results.groups))
|
||||
self.assert_(self.results.groups[0] is self.groups[0])
|
||||
eq_(1, len(self.results.groups))
|
||||
assert self.results.groups[0] is self.groups[0]
|
||||
|
||||
def test_load_cancels_filter(self):
|
||||
def get_file(path):
|
||||
@@ -656,23 +726,23 @@ class TCResultsFilter(TestCase):
|
||||
r = Results(data)
|
||||
r.apply_filter('foo')
|
||||
r.load_from_xml(filename,get_file)
|
||||
self.assertEqual(2,len(r.groups))
|
||||
eq_(2,len(r.groups))
|
||||
|
||||
def test_remove_dupe(self):
|
||||
self.results.remove_duplicates([self.results.dupes[0]])
|
||||
self.results.apply_filter(None)
|
||||
self.assertEqual(2,len(self.results.groups))
|
||||
self.assertEqual(2,len(self.results.dupes))
|
||||
eq_(2,len(self.results.groups))
|
||||
eq_(2,len(self.results.dupes))
|
||||
self.results.apply_filter('ibabtu')
|
||||
self.results.remove_duplicates([self.results.dupes[0]])
|
||||
self.results.apply_filter(None)
|
||||
self.assertEqual(1,len(self.results.groups))
|
||||
self.assertEqual(1,len(self.results.dupes))
|
||||
eq_(1,len(self.results.groups))
|
||||
eq_(1,len(self.results.dupes))
|
||||
|
||||
def test_filter_is_case_insensitive(self):
|
||||
self.results.apply_filter(None)
|
||||
self.results.apply_filter('FOO')
|
||||
self.assertEqual(1, len(self.results.dupes))
|
||||
eq_(1, len(self.results.dupes))
|
||||
|
||||
def test_make_ref_on_filtered_out_doesnt_mess_stats(self):
|
||||
# When filtered, a group containing filtered out dupes will display them as being reference.
|
||||
@@ -683,10 +753,10 @@ class TCResultsFilter(TestCase):
|
||||
self.results.make_ref(bar_bleh)
|
||||
# Now the stats should display *2* markable dupes (instead of 1)
|
||||
expected = '0 / 2 (0.00 B / 2.00 B) duplicates marked. filter: foo'
|
||||
self.assertEqual(expected, self.results.stat_line)
|
||||
eq_(expected, self.results.stat_line)
|
||||
self.results.apply_filter(None) # Now let's make sure our unfiltered results aren't fucked up
|
||||
expected = '0 / 3 (0.00 B / 3.00 B) duplicates marked.'
|
||||
self.assertEqual(expected, self.results.stat_line)
|
||||
eq_(expected, self.results.stat_line)
|
||||
|
||||
|
||||
class TCResultsRefFile(TestCase):
|
||||
@@ -699,15 +769,15 @@ class TCResultsRefFile(TestCase):
|
||||
|
||||
def test_stat_line(self):
|
||||
expected = '0 / 2 (0.00 B / 2.00 B) duplicates marked.'
|
||||
self.assertEqual(expected, self.results.stat_line)
|
||||
eq_(expected, self.results.stat_line)
|
||||
|
||||
def test_make_ref(self):
|
||||
d = self.results.groups[0].dupes[1] #non-ref
|
||||
r = self.results.groups[0].ref
|
||||
self.results.make_ref(d)
|
||||
expected = '0 / 1 (0.00 B / 1.00 B) duplicates marked.'
|
||||
self.assertEqual(expected, self.results.stat_line)
|
||||
eq_(expected, self.results.stat_line)
|
||||
self.results.make_ref(r)
|
||||
expected = '0 / 2 (0.00 B / 2.00 B) duplicates marked.'
|
||||
self.assertEqual(expected, self.results.stat_line)
|
||||
eq_(expected, self.results.stat_line)
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from nose.tools import eq_
|
||||
|
||||
from hsutil import job, io
|
||||
from hscommon import job
|
||||
from hsutil import io
|
||||
from hsutil.path import Path
|
||||
from hsutil.testutil import eq_
|
||||
from hsutil.testcase import TestCase
|
||||
|
||||
from .. import fs
|
||||
@@ -24,6 +25,9 @@ class NamedObject(object):
|
||||
self.path = Path('')
|
||||
self.words = getwords(name)
|
||||
|
||||
def __repr__(self):
|
||||
return '<NamedObject %r>' % self.name
|
||||
|
||||
|
||||
no = NamedObject
|
||||
|
||||
@@ -42,7 +46,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
def test_default_settings(self):
|
||||
s = Scanner()
|
||||
eq_(s.min_match_percentage, 80)
|
||||
eq_(s.scan_type, SCAN_TYPE_FILENAME)
|
||||
eq_(s.scan_type, ScanType.Filename)
|
||||
eq_(s.mix_file_kind, True)
|
||||
eq_(s.word_weighting, False)
|
||||
eq_(s.match_similar_words, False)
|
||||
@@ -94,7 +98,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_content_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
s.scan_type = ScanType.Contents
|
||||
f = [no('foo'), no('bar'), no('bleh')]
|
||||
f[0].md5 = f[0].md5partial = 'foobar'
|
||||
f[1].md5 = f[1].md5partial = 'foobar'
|
||||
@@ -111,13 +115,13 @@ class ScannerTestFakeFiles(TestCase):
|
||||
raise AssertionError()
|
||||
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
s.scan_type = ScanType.Contents
|
||||
f = [MyFile('foo', 1), MyFile('bar', 2)]
|
||||
eq_(len(s.GetDupeGroups(f)), 0)
|
||||
|
||||
def test_min_match_perc_doesnt_matter_for_content_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
s.scan_type = ScanType.Contents
|
||||
f = [no('foo'), no('bar'), no('bleh')]
|
||||
f[0].md5 = f[0].md5partial = 'foobar'
|
||||
f[1].md5 = f[1].md5partial = 'foobar'
|
||||
@@ -133,7 +137,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_content_scan_doesnt_put_md5_in_words_at_the_end(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
s.scan_type = ScanType.Contents
|
||||
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'
|
||||
@@ -187,21 +191,21 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_fields(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_FIELDS
|
||||
s.scan_type = ScanType.Fields
|
||||
f = [no('The White Stripes - Little Ghost'), no('The White Stripes - Little Acorn')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 0)
|
||||
|
||||
def test_fields_no_order(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_FIELDS_NO_ORDER
|
||||
s.scan_type = ScanType.FieldsNoOrder
|
||||
f = [no('The White Stripes - Little Ghost'), no('Little Ghost - The White Stripes')]
|
||||
r = s.GetDupeGroups(f)
|
||||
eq_(len(r), 1)
|
||||
|
||||
def test_tag_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scan_type = ScanType.Tag
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
o1.artist = 'The White Stripes'
|
||||
@@ -213,7 +217,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_tag_with_album_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scan_type = ScanType.Tag
|
||||
s.scanned_tags = set(['artist', 'album', 'title'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
@@ -232,7 +236,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_that_dash_in_tags_dont_create_new_fields(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scan_type = ScanType.Tag
|
||||
s.scanned_tags = set(['artist', 'album', 'title'])
|
||||
s.min_match_percentage = 50
|
||||
o1 = no('foo')
|
||||
@@ -248,7 +252,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_tag_scan_with_different_scanned(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scan_type = ScanType.Tag
|
||||
s.scanned_tags = set(['track', 'year'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
@@ -265,7 +269,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_tag_scan_only_scans_existing_tags(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scan_type = ScanType.Tag
|
||||
s.scanned_tags = set(['artist', 'foo'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
@@ -278,7 +282,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_tag_scan_converts_to_str(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scan_type = ScanType.Tag
|
||||
s.scanned_tags = set(['track'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
@@ -292,12 +296,12 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_tag_scan_non_ascii(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_TAG
|
||||
s.scan_type = ScanType.Tag
|
||||
s.scanned_tags = set(['title'])
|
||||
o1 = no('foo')
|
||||
o2 = no('bar')
|
||||
o1.title = u'foobar\u00e9'
|
||||
o2.title = u'foobar\u00e9'
|
||||
o1.title = 'foobar\u00e9'
|
||||
o2.title = 'foobar\u00e9'
|
||||
try:
|
||||
r = s.GetDupeGroups([o1, o2])
|
||||
except UnicodeEncodeError:
|
||||
@@ -306,7 +310,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
|
||||
def test_audio_content_scan(self):
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT_AUDIO
|
||||
s.scan_type = ScanType.ContentsAudio
|
||||
f = [no('foo'), no('bar'), no('bleh')]
|
||||
f[0].md5 = 'foo'
|
||||
f[1].md5 = 'bar'
|
||||
@@ -328,7 +332,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
raise AssertionError()
|
||||
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT_AUDIO
|
||||
s.scan_type = ScanType.ContentsAudio
|
||||
f = [MyFile('foo'), MyFile('bar')]
|
||||
f[0].audiosize = 1
|
||||
f[1].audiosize = 2
|
||||
@@ -361,11 +365,11 @@ class ScannerTestFakeFiles(TestCase):
|
||||
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))
|
||||
f1.path = Path('foo1\u00e9')
|
||||
f2.path = Path('foo2\u00e9')
|
||||
f3.path = Path('foo3\u00e9')
|
||||
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]
|
||||
@@ -378,7 +382,7 @@ class ScannerTestFakeFiles(TestCase):
|
||||
# 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):
|
||||
def __bool__(self):
|
||||
return False
|
||||
|
||||
|
||||
@@ -425,11 +429,20 @@ class ScannerTestFakeFiles(TestCase):
|
||||
# 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 = no('foo bar 42')
|
||||
o2 = no('foo bar [42]')
|
||||
o3 = no('foo bar (42)')
|
||||
o4 = no('foo bar {42}')
|
||||
o5 = no('foo bar')
|
||||
# all numbered names have deeper paths, so they'll end up ref if the digits aren't correctly
|
||||
# used as tie breakers
|
||||
o1.path = Path('deeper/path')
|
||||
o2.path = Path('foo')
|
||||
[group] = s.GetDupeGroups([o1, o2])
|
||||
assert group.ref is o2
|
||||
o2.path = Path('deeper/path')
|
||||
o3.path = Path('deeper/path')
|
||||
o4.path = Path('deeper/path')
|
||||
o5.path = Path('foo')
|
||||
[group] = s.GetDupeGroups([o1, o2, o3, o4, o5])
|
||||
assert group.ref is o5
|
||||
|
||||
def test_partial_group_match(self):
|
||||
# Count the number od discarded matches (when a file doesn't match all other dupes of the
|
||||
@@ -452,7 +465,7 @@ class ScannerTest(TestCase):
|
||||
# In this test, we have to delete one of the files between the get_matches() part and the
|
||||
# get_groups() part.
|
||||
s = Scanner()
|
||||
s.scan_type = SCAN_TYPE_CONTENT
|
||||
s.scan_type = ScanType.Contents
|
||||
p = self.tmppath()
|
||||
io.open(p + 'file1', 'w').write('foo')
|
||||
io.open(p + 'file2', 'w').write('foo')
|
||||
|
||||
@@ -10,7 +10,7 @@ import logging
|
||||
from appscript import app, k, CommandError
|
||||
import time
|
||||
|
||||
from hsutil.cocoa import as_fetch
|
||||
from hscommon.cocoa import as_fetch
|
||||
|
||||
from core.app_cocoa import JOBID2TITLE, DupeGuru as DupeGuruBase
|
||||
|
||||
@@ -41,7 +41,7 @@ class DupeGuruME(DupeGuruBase):
|
||||
try:
|
||||
track.delete(timeout=0)
|
||||
except CommandError as e:
|
||||
logging.warning('Error while trying to remove a track from iTunes: %s' % unicode(e))
|
||||
logging.warning('Error while trying to remove a track from iTunes: %s' % str(e))
|
||||
|
||||
self._start_job(JOB_REMOVE_DEAD_TRACKS, do)
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ COLUMNS = [
|
||||
{'attr':'bitrate','display':'Bitrate'},
|
||||
{'attr':'samplerate','display':'Sample Rate'},
|
||||
{'attr':'extension','display':'Kind'},
|
||||
{'attr':'ctime','display':'Creation'},
|
||||
{'attr':'mtime','display':'Modification'},
|
||||
{'attr':'title','display':'Title'},
|
||||
{'attr':'artist','display':'Artist'},
|
||||
@@ -32,7 +31,7 @@ COLUMNS = [
|
||||
{'attr':'dupe_count','display':'Dupe Count'},
|
||||
]
|
||||
|
||||
METADATA_TO_READ = ['size', 'ctime', 'mtime', 'duration', 'bitrate', 'samplerate', 'title', 'artist',
|
||||
METADATA_TO_READ = ['size', 'mtime', 'duration', 'bitrate', 'samplerate', 'title', 'artist',
|
||||
'album', 'genre', 'year', 'track', 'comment']
|
||||
|
||||
def GetDisplayInfo(dupe, group, delta):
|
||||
@@ -40,7 +39,6 @@ def GetDisplayInfo(dupe, group, delta):
|
||||
duration = dupe.duration
|
||||
bitrate = dupe.bitrate
|
||||
samplerate = dupe.samplerate
|
||||
ctime = dupe.ctime
|
||||
mtime = dupe.mtime
|
||||
m = group.get_match_of(dupe)
|
||||
if m:
|
||||
@@ -52,7 +50,6 @@ def GetDisplayInfo(dupe, group, delta):
|
||||
duration -= r.duration
|
||||
bitrate -= r.bitrate
|
||||
samplerate -= r.samplerate
|
||||
ctime -= r.ctime
|
||||
mtime -= r.mtime
|
||||
else:
|
||||
percentage = group.percentage
|
||||
@@ -65,7 +62,6 @@ def GetDisplayInfo(dupe, group, delta):
|
||||
str(bitrate),
|
||||
str(samplerate),
|
||||
dupe.extension,
|
||||
format_timestamp(ctime,delta and m),
|
||||
format_timestamp(mtime,delta and m),
|
||||
dupe.title,
|
||||
dupe.artist,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from hsmedia import mpeg, wma, mp4, ogg, flac, aiff
|
||||
from hsaudiotag import mpeg, wma, mp4, ogg, flac, aiff
|
||||
from hsutil.str import get_file_ext
|
||||
from core import fs
|
||||
|
||||
@@ -42,12 +42,12 @@ class Mp3File(MusicFile):
|
||||
HANDLED_EXTS = set(['mp3'])
|
||||
def _read_info(self, field):
|
||||
if field == 'md5partial':
|
||||
fileinfo = mpeg.Mpeg(unicode(self.path))
|
||||
fileinfo = mpeg.Mpeg(str(self.path))
|
||||
self._md5partial_offset = fileinfo.audio_offset
|
||||
self._md5partial_size = fileinfo.audio_size
|
||||
MusicFile._read_info(self, field)
|
||||
if field in TAG_FIELDS:
|
||||
fileinfo = mpeg.Mpeg(unicode(self.path))
|
||||
fileinfo = mpeg.Mpeg(str(self.path))
|
||||
self.audiosize = fileinfo.audio_size
|
||||
self.bitrate = fileinfo.bitrate
|
||||
self.duration = fileinfo.duration
|
||||
@@ -70,12 +70,12 @@ class WmaFile(MusicFile):
|
||||
HANDLED_EXTS = set(['wma'])
|
||||
def _read_info(self, field):
|
||||
if field == 'md5partial':
|
||||
dec = wma.WMADecoder(unicode(self.path))
|
||||
dec = wma.WMADecoder(str(self.path))
|
||||
self._md5partial_offset = dec.audio_offset
|
||||
self._md5partial_size = dec.audio_size
|
||||
MusicFile._read_info(self, field)
|
||||
if field in TAG_FIELDS:
|
||||
dec = wma.WMADecoder(unicode(self.path))
|
||||
dec = wma.WMADecoder(str(self.path))
|
||||
self.audiosize = dec.audio_size
|
||||
self.bitrate = dec.bitrate
|
||||
self.duration = dec.duration
|
||||
@@ -92,13 +92,13 @@ class Mp4File(MusicFile):
|
||||
HANDLED_EXTS = set(['m4a', 'm4p'])
|
||||
def _read_info(self, field):
|
||||
if field == 'md5partial':
|
||||
dec = mp4.File(unicode(self.path))
|
||||
dec = mp4.File(str(self.path))
|
||||
self._md5partial_offset = dec.audio_offset
|
||||
self._md5partial_size = dec.audio_size
|
||||
dec.close()
|
||||
MusicFile._read_info(self, field)
|
||||
if field in TAG_FIELDS:
|
||||
dec = mp4.File(unicode(self.path))
|
||||
dec = mp4.File(str(self.path))
|
||||
self.audiosize = dec.audio_size
|
||||
self.bitrate = dec.bitrate
|
||||
self.duration = dec.duration
|
||||
@@ -116,12 +116,12 @@ class OggFile(MusicFile):
|
||||
HANDLED_EXTS = set(['ogg'])
|
||||
def _read_info(self, field):
|
||||
if field == 'md5partial':
|
||||
dec = ogg.Vorbis(unicode(self.path))
|
||||
dec = ogg.Vorbis(str(self.path))
|
||||
self._md5partial_offset = dec.audio_offset
|
||||
self._md5partial_size = dec.audio_size
|
||||
MusicFile._read_info(self, field)
|
||||
if field in TAG_FIELDS:
|
||||
dec = ogg.Vorbis(unicode(self.path))
|
||||
dec = ogg.Vorbis(str(self.path))
|
||||
self.audiosize = dec.audio_size
|
||||
self.bitrate = dec.bitrate
|
||||
self.duration = dec.duration
|
||||
@@ -138,12 +138,12 @@ class FlacFile(MusicFile):
|
||||
HANDLED_EXTS = set(['flac'])
|
||||
def _read_info(self, field):
|
||||
if field == 'md5partial':
|
||||
dec = flac.FLAC(unicode(self.path))
|
||||
dec = flac.FLAC(str(self.path))
|
||||
self._md5partial_offset = dec.audio_offset
|
||||
self._md5partial_size = dec.audio_size
|
||||
MusicFile._read_info(self, field)
|
||||
if field in TAG_FIELDS:
|
||||
dec = flac.FLAC(unicode(self.path))
|
||||
dec = flac.FLAC(str(self.path))
|
||||
self.audiosize = dec.audio_size
|
||||
self.bitrate = dec.bitrate
|
||||
self.duration = dec.duration
|
||||
@@ -160,12 +160,12 @@ class AiffFile(MusicFile):
|
||||
HANDLED_EXTS = set(['aif', 'aiff', 'aifc'])
|
||||
def _read_info(self, field):
|
||||
if field == 'md5partial':
|
||||
dec = aiff.File(unicode(self.path))
|
||||
dec = aiff.File(str(self.path))
|
||||
self._md5partial_offset = dec.audio_offset
|
||||
self._md5partial_size = dec.audio_size
|
||||
MusicFile._read_info(self, field)
|
||||
if field in TAG_FIELDS:
|
||||
dec = aiff.File(unicode(self.path))
|
||||
dec = aiff.File(str(self.path))
|
||||
self.audiosize = dec.audio_size
|
||||
self.bitrate = dec.bitrate
|
||||
self.duration = dec.duration
|
||||
|
||||
28
core_me/tests/conftest.py
Normal file
28
core_me/tests/conftest.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2010-07-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
|
||||
|
||||
# This unit is required to make tests work with py.test. When running
|
||||
|
||||
import py
|
||||
|
||||
def get_testunit(item):
|
||||
if hasattr(item, 'obj'):
|
||||
testunit = py.builtin._getimself(item.obj)
|
||||
if hasattr(testunit, 'global_setup'):
|
||||
return testunit
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
testunit = get_testunit(item)
|
||||
if testunit is not None:
|
||||
testunit.global_setup()
|
||||
|
||||
def pytest_runtest_teardown(item):
|
||||
testunit = get_testunit(item)
|
||||
if testunit is not None:
|
||||
testunit.global_teardown()
|
||||
@@ -7,18 +7,17 @@
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
import os.path as op
|
||||
import logging
|
||||
import plistlib
|
||||
import logging
|
||||
import re
|
||||
|
||||
from lxml import etree
|
||||
from appscript import app, k, CommandError
|
||||
|
||||
from hsutil import io
|
||||
from hsutil.str import get_file_ext
|
||||
from hsutil.str import get_file_ext, remove_invalid_xml
|
||||
from hsutil.path import Path
|
||||
from hsutil.cocoa import as_fetch
|
||||
from hsutil.cocoa.objcmin import NSUserDefaults, NSURL
|
||||
from hscommon.cocoa import as_fetch
|
||||
from hscommon.cocoa.objcmin import NSUserDefaults, NSURL
|
||||
|
||||
from core import fs
|
||||
from core import app_cocoa, directories
|
||||
@@ -39,15 +38,15 @@ class Photo(fs.File):
|
||||
def _read_info(self, field):
|
||||
fs.File._read_info(self, field)
|
||||
if field == 'dimensions':
|
||||
self.dimensions = _block_osx.get_image_size(unicode(self.path))
|
||||
self.dimensions = _block_osx.get_image_size(str(self.path))
|
||||
|
||||
def get_blocks(self, block_count_per_side):
|
||||
try:
|
||||
blocks = _block_osx.getblocks(unicode(self.path), block_count_per_side)
|
||||
blocks = _block_osx.getblocks(str(self.path), block_count_per_side)
|
||||
except Exception as e:
|
||||
raise IOError('The reading of "%s" failed with "%s"' % (unicode(self.path), unicode(e)))
|
||||
raise IOError('The reading of "%s" failed with "%s"' % (str(self.path), str(e)))
|
||||
if not blocks:
|
||||
raise IOError('The picture %s could not be read' % unicode(self.path))
|
||||
raise IOError('The picture %s could not be read' % str(self.path))
|
||||
return blocks
|
||||
|
||||
|
||||
@@ -69,11 +68,16 @@ def get_iphoto_database_path():
|
||||
def get_iphoto_pictures(plistpath):
|
||||
if not io.exists(plistpath):
|
||||
return []
|
||||
# We make the xml go through lxml so that it can fix broken xml which iPhoto sometimes produces.
|
||||
parser = etree.XMLParser(recover=True)
|
||||
root = etree.parse(io.open(plistpath), parser=parser).getroot()
|
||||
s = etree.tostring(root)
|
||||
plist = plistlib.readPlistFromString(s)
|
||||
s = io.open(plistpath, 'rt', encoding='utf-8').read()
|
||||
# There was a case where a guy had 0x10 chars in his plist, causing expat errors on loading
|
||||
s = remove_invalid_xml(s, replace_with='')
|
||||
# It seems that iPhoto sometimes doesn't properly escape & chars. The regexp below is to find
|
||||
# any & char that is not a &-based entity (&, ", etc.). based on TextMate's XML
|
||||
# bundle's regexp
|
||||
s, count = re.subn(r'&(?![a-zA-Z0-9_-]+|#[0-9]+|#x[0-9a-fA-F]+;)', '', s)
|
||||
if count:
|
||||
logging.warning("%d invalid XML entities replacement made", count)
|
||||
plist = plistlib.readPlistFromBytes(s.encode('utf-8'))
|
||||
result = []
|
||||
for photo_data in plist['Master Image List'].values():
|
||||
if photo_data['MediaType'] != 'Image':
|
||||
@@ -118,6 +122,15 @@ class Directories(directories.Directories):
|
||||
else:
|
||||
directories.Directories.add_path(self, path)
|
||||
|
||||
def has_any_file(self):
|
||||
# If we don't do that, it causes a hangup in the GUI when we click Start Scanning because
|
||||
# checking if there's any file to scan involves reading the whole library. If we have the
|
||||
# iPhoto library, we assume we have at least one file.
|
||||
if any(path == Path('iPhoto Library') for path in self._dirs):
|
||||
return True
|
||||
else:
|
||||
return directories.Directories.has_any_file(self)
|
||||
|
||||
|
||||
class DupeGuruPE(app_cocoa.DupeGuru):
|
||||
def __init__(self):
|
||||
@@ -142,34 +155,29 @@ class DupeGuruPE(app_cocoa.DupeGuru):
|
||||
photos = as_fetch(a.photo_library_album().photos, k.item)
|
||||
for photo in j.iter_with_progress(photos):
|
||||
try:
|
||||
self.path2iphoto[unicode(photo.image_path(timeout=0))] = photo
|
||||
self.path2iphoto[str(photo.image_path(timeout=0))] = photo
|
||||
except CommandError:
|
||||
pass
|
||||
except (CommandError, RuntimeError):
|
||||
pass
|
||||
j.start_job(self.results.mark_count, "Sending dupes to the Trash")
|
||||
self.last_op_error_count = self.results.perform_on_marked(op, True)
|
||||
self.results.perform_on_marked(op, True)
|
||||
del self.path2iphoto
|
||||
|
||||
def _do_delete_dupe(self, dupe):
|
||||
if isinstance(dupe, IPhoto):
|
||||
if unicode(dupe.path) in self.path2iphoto:
|
||||
photo = self.path2iphoto[unicode(dupe.path)]
|
||||
if str(dupe.path) in self.path2iphoto:
|
||||
photo = self.path2iphoto[str(dupe.path)]
|
||||
try:
|
||||
a = app('iPhoto')
|
||||
a.remove(photo, timeout=0)
|
||||
return True
|
||||
except (CommandError, RuntimeError):
|
||||
return False
|
||||
except (CommandError, RuntimeError) as e:
|
||||
raise EnvironmentError(str(e))
|
||||
else:
|
||||
logging.warning(u"Could not find photo %s in iPhoto Library", unicode(dupe.path))
|
||||
return False
|
||||
msg = "Could not find photo %s in iPhoto Library" % str(dupe.path)
|
||||
raise EnvironmentError(msg)
|
||||
else:
|
||||
return app_cocoa.DupeGuru._do_delete_dupe(self, dupe)
|
||||
|
||||
def _do_load(self, j):
|
||||
self.directories.load_from_file(op.join(self.appdata, 'last_directories.xml'))
|
||||
self.results.load_from_xml(op.join(self.appdata, 'last_results.xml'), self._get_file, j)
|
||||
app_cocoa.DupeGuru._do_delete_dupe(self, dupe)
|
||||
|
||||
def _get_file(self, str_path):
|
||||
p = Path(str_path)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from _block import NoBlocksError, DifferentBlockCountError, avgdiff, getblocks2
|
||||
from ._block import NoBlocksError, DifferentBlockCountError, avgdiff, getblocks2
|
||||
|
||||
# Converted to C
|
||||
# def getblock(image):
|
||||
|
||||
@@ -10,7 +10,7 @@ import os
|
||||
import logging
|
||||
import sqlite3 as sqlite
|
||||
|
||||
from _cache import string_to_colors
|
||||
from ._cache import string_to_colors
|
||||
|
||||
def colors_to_string(colors):
|
||||
"""Transform the 3 sized tuples 'colors' into a hex string.
|
||||
@@ -82,7 +82,7 @@ class Cache(object):
|
||||
self.con.execute(sql, [value, key])
|
||||
except sqlite.OperationalError:
|
||||
logging.warning('Picture cache could not set %r for key %r', value, key)
|
||||
except sqlite.DatabaseError, e:
|
||||
except sqlite.DatabaseError as e:
|
||||
logging.warning('DatabaseError while setting %r for key %r: %s', value, key, str(e))
|
||||
|
||||
def _create_con(self, second_try=False):
|
||||
@@ -97,7 +97,7 @@ class Cache(object):
|
||||
self.con.execute("select * from pictures where 1=2")
|
||||
except sqlite.OperationalError: # new db
|
||||
create_tables()
|
||||
except sqlite.DatabaseError, e: # corrupted db
|
||||
except sqlite.DatabaseError as e: # corrupted db
|
||||
if second_try:
|
||||
raise # Something really strange is happening
|
||||
logging.warning('Could not create picture cache because of an error: %s', str(e))
|
||||
|
||||
@@ -18,19 +18,17 @@ COLUMNS = [
|
||||
{'attr':'size','display':'Size (KB)'},
|
||||
{'attr':'extension','display':'Kind'},
|
||||
{'attr':'dimensions','display':'Dimensions'},
|
||||
{'attr':'ctime','display':'Creation'},
|
||||
{'attr':'mtime','display':'Modification'},
|
||||
{'attr':'percentage','display':'Match %'},
|
||||
{'attr':'dupe_count','display':'Dupe Count'},
|
||||
]
|
||||
|
||||
METADATA_TO_READ = ['size', 'ctime', 'mtime', 'dimensions']
|
||||
METADATA_TO_READ = ['size', 'mtime', 'dimensions']
|
||||
|
||||
def GetDisplayInfo(dupe,group,delta=False):
|
||||
if (dupe is None) or (group is None):
|
||||
return ['---'] * len(COLUMNS)
|
||||
size = dupe.size
|
||||
ctime = dupe.ctime
|
||||
mtime = dupe.mtime
|
||||
m = group.get_match_of(dupe)
|
||||
if m:
|
||||
@@ -39,7 +37,6 @@ def GetDisplayInfo(dupe,group,delta=False):
|
||||
if delta:
|
||||
r = group.ref
|
||||
size -= r.size
|
||||
ctime -= r.ctime
|
||||
mtime -= r.mtime
|
||||
else:
|
||||
percentage = group.percentage
|
||||
@@ -51,7 +48,6 @@ def GetDisplayInfo(dupe,group,delta=False):
|
||||
format_size(size, 0, 1, False),
|
||||
dupe.extension,
|
||||
format_dimensions(dupe.dimensions),
|
||||
format_timestamp(ctime, delta and m),
|
||||
format_timestamp(mtime, delta and m),
|
||||
format_perc(percentage),
|
||||
format_dupe_count(dupe_count)
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-05-26
|
||||
# Copyright 2010 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
|
||||
import os.path as op
|
||||
|
||||
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)
|
||||
|
||||
os.chdir('modules')
|
||||
os.system('python setup.py build_ext --inplace')
|
||||
os.chdir('..')
|
||||
move(op.join('modules', '_block.so'), '_block.so')
|
||||
move(op.join('modules', '_block.pyd'), '_block.pyd')
|
||||
move(op.join('modules', '_block_osx.so'), '_block_osx.so')
|
||||
move(op.join('modules', '_cache.so'), '_cache.so')
|
||||
move(op.join('modules', '_cache.pyd'), '_cache.pyd')
|
||||
@@ -8,11 +8,9 @@
|
||||
|
||||
import logging
|
||||
import multiprocessing
|
||||
from Queue import Empty
|
||||
from collections import defaultdict
|
||||
from collections import defaultdict, deque
|
||||
|
||||
from hsutil import job
|
||||
from hsutil.misc import dedupe
|
||||
from hscommon import job
|
||||
|
||||
from core.engine import Match
|
||||
from .block import avgdiff, DifferentBlockCountError, NoBlocksError
|
||||
@@ -36,16 +34,16 @@ def prepare_pictures(pictures, cache_path, j=job.nulljob):
|
||||
try:
|
||||
for picture in j.iter_with_progress(pictures, 'Analyzed %d/%d pictures'):
|
||||
picture.dimensions
|
||||
picture.unicode_path = unicode(picture.path)
|
||||
picture.unicode_path = str(picture.path)
|
||||
try:
|
||||
if picture.unicode_path not in cache:
|
||||
blocks = picture.get_blocks(BLOCK_COUNT_PER_SIDE)
|
||||
cache[picture.unicode_path] = blocks
|
||||
prepared.append(picture)
|
||||
except IOError as e:
|
||||
logging.warning(unicode(e))
|
||||
except (IOError, ValueError) as e:
|
||||
logging.warning(str(e))
|
||||
except MemoryError:
|
||||
logging.warning(u'Ran out of memory while reading %s of size %d' % (picture.unicode_path, picture.size))
|
||||
logging.warning('Ran out of memory while reading %s of size %d' % (picture.unicode_path, picture.size))
|
||||
if picture.size < 10 * 1024 * 1024: # We're really running out of memory
|
||||
raise
|
||||
except MemoryError:
|
||||
@@ -76,13 +74,6 @@ def async_compare(ref_id, other_ids, dbname, threshold):
|
||||
return results
|
||||
|
||||
def getmatches(pictures, cache_path, threshold=75, match_scaled=False, j=job.nulljob):
|
||||
def empty_out_queue(queue, into):
|
||||
try:
|
||||
while True:
|
||||
into.append(queue.get(block=False))
|
||||
except Empty:
|
||||
pass
|
||||
|
||||
j = j.start_subjob([3, 7])
|
||||
pictures = prepare_pictures(pictures, cache_path, j)
|
||||
j = j.start_subjob([9, 1], 'Preparing for matching')
|
||||
@@ -100,7 +91,7 @@ def getmatches(pictures, cache_path, threshold=75, match_scaled=False, j=job.nul
|
||||
cache.close()
|
||||
pictures = [p for p in pictures if hasattr(p, 'cache_id')]
|
||||
pool = multiprocessing.Pool()
|
||||
async_results = []
|
||||
async_results = deque()
|
||||
matches = []
|
||||
pictures_copy = set(pictures)
|
||||
for ref in j.iter_with_progress(pictures, 'Matched %d/%d pictures'):
|
||||
@@ -111,10 +102,17 @@ def getmatches(pictures, cache_path, threshold=75, match_scaled=False, j=job.nul
|
||||
others = [pic for pic in others if not pic.is_ref]
|
||||
if others:
|
||||
cache_ids = [f.cache_id for f in others]
|
||||
args = (ref.cache_id, cache_ids, cache_path, threshold)
|
||||
# We limit the number of cache_ids we send for multi-processing because otherwise, we
|
||||
# might get an error saying "String or BLOB exceeded size limit"
|
||||
ARG_LIMIT = 1000
|
||||
while cache_ids:
|
||||
args = (ref.cache_id, cache_ids[:ARG_LIMIT], cache_path, threshold)
|
||||
async_results.append(pool.apply_async(async_compare, args))
|
||||
if len(async_results) > RESULTS_QUEUE_LIMIT:
|
||||
result = async_results.pop(0)
|
||||
cache_ids = cache_ids[ARG_LIMIT:]
|
||||
# We use a while here because it's possible that more than one result has been added if
|
||||
# ARG_LIMIT has been reached.
|
||||
while len(async_results) > RESULTS_QUEUE_LIMIT:
|
||||
result = async_results.popleft()
|
||||
matches.extend(result.get())
|
||||
for result in async_results: # process the rest of the results
|
||||
matches.extend(result.get())
|
||||
|
||||
@@ -39,9 +39,9 @@ static PyObject* getblock(PyObject *image)
|
||||
pg = PySequence_ITEM(ppixel, 1);
|
||||
pb = PySequence_ITEM(ppixel, 2);
|
||||
Py_DECREF(ppixel);
|
||||
r = PyInt_AsSsize_t(pr);
|
||||
g = PyInt_AsSsize_t(pg);
|
||||
b = PyInt_AsSsize_t(pb);
|
||||
r = PyLong_AsLong(pr);
|
||||
g = PyLong_AsLong(pg);
|
||||
b = PyLong_AsLong(pb);
|
||||
Py_DECREF(pr);
|
||||
Py_DECREF(pg);
|
||||
Py_DECREF(pb);
|
||||
@@ -67,14 +67,14 @@ static PyObject* getblock(PyObject *image)
|
||||
*/
|
||||
static int diff(PyObject *first, PyObject *second)
|
||||
{
|
||||
Py_ssize_t r1, g1, b1, r2, b2, g2;
|
||||
int r1, g1, b1, r2, b2, g2;
|
||||
PyObject *pr, *pg, *pb;
|
||||
pr = PySequence_ITEM(first, 0);
|
||||
pg = PySequence_ITEM(first, 1);
|
||||
pb = PySequence_ITEM(first, 2);
|
||||
r1 = PyInt_AsSsize_t(pr);
|
||||
g1 = PyInt_AsSsize_t(pg);
|
||||
b1 = PyInt_AsSsize_t(pb);
|
||||
r1 = PyLong_AsLong(pr);
|
||||
g1 = PyLong_AsLong(pg);
|
||||
b1 = PyLong_AsLong(pb);
|
||||
Py_DECREF(pr);
|
||||
Py_DECREF(pg);
|
||||
Py_DECREF(pb);
|
||||
@@ -82,9 +82,9 @@ static int diff(PyObject *first, PyObject *second)
|
||||
pr = PySequence_ITEM(second, 0);
|
||||
pg = PySequence_ITEM(second, 1);
|
||||
pb = PySequence_ITEM(second, 2);
|
||||
r2 = PyInt_AsSsize_t(pr);
|
||||
g2 = PyInt_AsSsize_t(pg);
|
||||
b2 = PyInt_AsSsize_t(pb);
|
||||
r2 = PyLong_AsLong(pr);
|
||||
g2 = PyLong_AsLong(pg);
|
||||
b2 = PyLong_AsLong(pb);
|
||||
Py_DECREF(pr);
|
||||
Py_DECREF(pg);
|
||||
Py_DECREF(pb);
|
||||
@@ -115,8 +115,8 @@ static PyObject* block_getblocks2(PyObject *self, PyObject *args)
|
||||
pimage_size = PyObject_GetAttrString(image, "size");
|
||||
pwidth = PySequence_ITEM(pimage_size, 0);
|
||||
pheight = PySequence_ITEM(pimage_size, 1);
|
||||
width = PyInt_AsSsize_t(pwidth);
|
||||
height = PyInt_AsSsize_t(pheight);
|
||||
width = PyLong_AsLong(pwidth);
|
||||
height = PyLong_AsLong(pheight);
|
||||
Py_DECREF(pimage_size);
|
||||
Py_DECREF(pwidth);
|
||||
Py_DECREF(pheight);
|
||||
@@ -147,8 +147,8 @@ static PyObject* block_getblocks2(PyObject *self, PyObject *args)
|
||||
left = min(iw*block_width, width-block_width);
|
||||
right = left + block_width;
|
||||
pbox = inttuple(4, left, top, right, bottom);
|
||||
pmethodname = PyString_FromString("crop");
|
||||
pcrop = PyObject_CallMethodObjArgs(image, pmethodname, pbox);
|
||||
pmethodname = PyUnicode_FromString("crop");
|
||||
pcrop = PyObject_CallMethodObjArgs(image, pmethodname, pbox, NULL);
|
||||
Py_DECREF(pmethodname);
|
||||
Py_DECREF(pbox);
|
||||
if (pcrop == NULL) {
|
||||
@@ -207,7 +207,7 @@ static PyObject* block_avgdiff(PyObject *self, PyObject *args)
|
||||
Py_DECREF(item1);
|
||||
Py_DECREF(item2);
|
||||
if ((sum > limit*iteration_count) && (iteration_count >= min_iterations)) {
|
||||
return PyInt_FromSsize_t(limit + 1);
|
||||
return PyLong_FromLong(limit + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ static PyObject* block_avgdiff(PyObject *self, PyObject *args)
|
||||
if (!result && sum) {
|
||||
result = 1;
|
||||
}
|
||||
return PyInt_FromSsize_t(result);
|
||||
return PyLong_FromLong(result);
|
||||
}
|
||||
|
||||
static PyMethodDef BlockMethods[] = {
|
||||
@@ -224,16 +224,30 @@ static PyMethodDef BlockMethods[] = {
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_block(void)
|
||||
static struct PyModuleDef BlockDef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_block",
|
||||
NULL,
|
||||
-1,
|
||||
BlockMethods,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyObject *
|
||||
PyInit__block(void)
|
||||
{
|
||||
PyObject *m = Py_InitModule("_block", BlockMethods);
|
||||
PyObject *m = PyModule_Create(&BlockDef);
|
||||
if (m == NULL) {
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NoBlocksError = PyErr_NewException("_block.NoBlocksError", NULL, NULL);
|
||||
PyModule_AddObject(m, "NoBlocksError", NoBlocksError);
|
||||
DifferentBlockCountError = PyErr_NewException("_block.DifferentBlockCountError", NULL, NULL);
|
||||
PyModule_AddObject(m, "DifferentBlockCountError", DifferentBlockCountError);
|
||||
|
||||
return m;
|
||||
}
|
||||
@@ -29,8 +29,8 @@ pystring2cfstring(PyObject *pystring)
|
||||
Py_INCREF(encoded);
|
||||
}
|
||||
|
||||
s = (UInt8*)PyString_AS_STRING(encoded);
|
||||
size = PyString_GET_SIZE(encoded);
|
||||
s = (UInt8*)PyBytes_AS_STRING(encoded);
|
||||
size = PyUnicode_GET_SIZE(encoded);
|
||||
result = CFStringCreateWithBytes(NULL, s, size, kCFStringEncodingUTF8, FALSE);
|
||||
Py_DECREF(encoded);
|
||||
return result;
|
||||
@@ -43,7 +43,7 @@ static PyObject* block_osx_get_image_size(PyObject *self, PyObject *args)
|
||||
CFURLRef image_url;
|
||||
CGImageSourceRef source;
|
||||
CGImageRef image;
|
||||
size_t width, height;
|
||||
long width, height;
|
||||
PyObject *pwidth, *pheight;
|
||||
PyObject *result;
|
||||
|
||||
@@ -72,11 +72,11 @@ static PyObject* block_osx_get_image_size(PyObject *self, PyObject *args)
|
||||
CFRelease(source);
|
||||
}
|
||||
|
||||
pwidth = PyInt_FromSsize_t(width);
|
||||
pwidth = PyLong_FromLong(width);
|
||||
if (pwidth == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
pheight = PyInt_FromSsize_t(height);
|
||||
pheight = PyLong_FromLong(height);
|
||||
if (pheight == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -158,6 +158,11 @@ static PyObject* block_osx_getblocks(PyObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PySequence_Length(path) == 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "empty path");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image_path = pystring2cfstring(path);
|
||||
if (image_path == NULL) {
|
||||
return PyErr_NoMemory();
|
||||
@@ -223,8 +228,24 @@ static PyMethodDef BlockOsxMethods[] = {
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_block_osx(void)
|
||||
static struct PyModuleDef BlockOsxDef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_block_osx",
|
||||
NULL,
|
||||
-1,
|
||||
BlockOsxMethods,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyObject *
|
||||
PyInit__block_osx(void)
|
||||
{
|
||||
Py_InitModule("_block_osx", BlockOsxMethods);
|
||||
PyObject *m = PyModule_Create(&BlockOsxDef);
|
||||
if (m == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
@@ -72,8 +72,24 @@ static PyMethodDef CacheMethods[] = {
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
init_cache(void)
|
||||
static struct PyModuleDef CacheDef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_cache",
|
||||
NULL,
|
||||
-1,
|
||||
CacheMethods,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyObject *
|
||||
PyInit__cache(void)
|
||||
{
|
||||
(void)Py_InitModule("_cache", CacheMethods);
|
||||
PyObject *m = PyModule_Create(&CacheDef);
|
||||
if (m == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ PyObject* inttuple(int n, ...)
|
||||
result = PyTuple_New(n);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
pnumber = PyInt_FromLong(va_arg(numbers, int));
|
||||
pnumber = PyLong_FromLong(va_arg(numbers, long));
|
||||
if (pnumber == NULL) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2009-04-23
|
||||
# Copyright 2010 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 sys
|
||||
|
||||
from distutils.core import setup
|
||||
from distutils.extension import Extension
|
||||
|
||||
exts = []
|
||||
|
||||
exts.append(Extension("_block", ["block.c", "common.c"]))
|
||||
exts.append(Extension("_cache", ["cache.c", "common.c"]))
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
exts.append(Extension(
|
||||
"_block_osx", ["block_osx.m", "common.c"],
|
||||
extra_link_args=[
|
||||
"-framework", "CoreFoundation",
|
||||
"-framework", "Foundation",
|
||||
"-framework", "ApplicationServices",
|
||||
]))
|
||||
|
||||
setup(
|
||||
ext_modules = exts,
|
||||
)
|
||||
@@ -258,8 +258,8 @@ class TCavgdiff(unittest.TestCase):
|
||||
def test_return_at_least_1_at_the_slightest_difference(self):
|
||||
ref = (0,0,0)
|
||||
b1 = (1,0,0)
|
||||
blocks1 = [ref for i in xrange(250)]
|
||||
blocks2 = [ref for i in xrange(250)]
|
||||
blocks1 = [ref for i in range(250)]
|
||||
blocks2 = [ref for i in range(250)]
|
||||
blocks2[0] = b1
|
||||
self.assertEqual(1,my_avgdiff(blocks1,blocks2))
|
||||
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/hs_license
|
||||
|
||||
from StringIO import StringIO
|
||||
import os.path as op
|
||||
import os
|
||||
import threading
|
||||
|
||||
from hsutil.testcase import TestCase
|
||||
|
||||
|
||||
28
core_pe/tests/conftest.py
Normal file
28
core_pe/tests/conftest.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2010-07-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
|
||||
|
||||
# This unit is required to make tests work with py.test. When running
|
||||
|
||||
import py
|
||||
|
||||
def get_testunit(item):
|
||||
if hasattr(item, 'obj'):
|
||||
testunit = py.builtin._getimself(item.obj)
|
||||
if hasattr(testunit, 'global_setup'):
|
||||
return testunit
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
testunit = get_testunit(item)
|
||||
if testunit is not None:
|
||||
testunit.global_setup()
|
||||
|
||||
def pytest_runtest_teardown(item):
|
||||
testunit = get_testunit(item)
|
||||
if testunit is not None:
|
||||
testunit.global_teardown()
|
||||
@@ -6,13 +6,13 @@
|
||||
# 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
|
||||
|
||||
from hsutil import io
|
||||
from hsutil.path import Path
|
||||
from hsutil.cocoa.objcmin import NSWorkspace
|
||||
from hscommon.cocoa.objcmin import NSWorkspace
|
||||
|
||||
from core import fs
|
||||
from core.app_cocoa import DupeGuru as DupeGuruBase
|
||||
@@ -24,17 +24,17 @@ def is_bundle(str_path):
|
||||
sw = NSWorkspace.sharedWorkspace()
|
||||
uti, error = sw.typeOfFile_error_(str_path, None)
|
||||
if error is not None:
|
||||
logging.warning(u'There was an error trying to detect the UTI of %s', str_path)
|
||||
logging.warning('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')
|
||||
|
||||
class Bundle(BundleBase):
|
||||
@classmethod
|
||||
def can_handle(cls, path):
|
||||
return not io.islink(path) and io.isdir(path) and is_bundle(unicode(path))
|
||||
return not io.islink(path) and io.isdir(path) and is_bundle(str(path))
|
||||
|
||||
|
||||
class Directories(DirectoriesBase):
|
||||
ROOT_PATH_TO_EXCLUDE = map(Path, ['/Library', '/Volumes', '/System', '/bin', '/sbin', '/opt', '/private', '/dev'])
|
||||
ROOT_PATH_TO_EXCLUDE = list(map(Path, ['/Library', '/Volumes', '/System', '/bin', '/sbin', '/opt', '/private', '/dev']))
|
||||
HOME_PATH_TO_EXCLUDE = [Path('Library')]
|
||||
def __init__(self):
|
||||
DirectoriesBase.__init__(self, fileclasses=[Bundle, fs.File])
|
||||
|
||||
@@ -15,18 +15,16 @@ COLUMNS = [
|
||||
{'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']
|
||||
METADATA_TO_READ = ['size', 'mtime']
|
||||
|
||||
def GetDisplayInfo(dupe, group, delta):
|
||||
size = dupe.size
|
||||
ctime = dupe.ctime
|
||||
mtime = dupe.mtime
|
||||
m = group.get_match_of(dupe)
|
||||
if m:
|
||||
@@ -35,7 +33,6 @@ def GetDisplayInfo(dupe, group, delta):
|
||||
if delta:
|
||||
r = group.ref
|
||||
size -= r.size
|
||||
ctime -= r.ctime
|
||||
mtime -= r.mtime
|
||||
else:
|
||||
percentage = group.percentage
|
||||
@@ -45,7 +42,6 @@ def GetDisplayInfo(dupe, group, delta):
|
||||
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) if hasattr(dupe, 'words') else '',
|
||||
|
||||
@@ -20,12 +20,11 @@ class Bundle(fs.File):
|
||||
to see them as files.
|
||||
"""
|
||||
def _read_info(self, field):
|
||||
if field in ('size', 'ctime', 'mtime'):
|
||||
if field in ('size', 'mtime'):
|
||||
files = fs.get_all_files(self.path)
|
||||
size = sum((file.size for file in files), 0)
|
||||
self.size = size
|
||||
stats = io.stat(self.path)
|
||||
self.ctime = nonone(stats.st_ctime, 0)
|
||||
self.mtime = nonone(stats.st_mtime, 0)
|
||||
elif field in ('md5', 'md5partial'):
|
||||
# What's sensitive here is that we must make sure that subfiles'
|
||||
@@ -35,7 +34,7 @@ class Bundle(fs.File):
|
||||
files = fs.get_all_files(self.path)
|
||||
files.sort(key=lambda f:f.path)
|
||||
md5s = [getattr(f, field) for f in files]
|
||||
return ''.join(md5s)
|
||||
return b''.join(md5s)
|
||||
|
||||
md5 = hashlib.md5(get_dir_md5_concat())
|
||||
digest = md5.digest()
|
||||
|
||||
28
core_se/tests/conftest.py
Normal file
28
core_se/tests/conftest.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created By: Virgil Dupras
|
||||
# Created On: 2010-07-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
|
||||
|
||||
# This unit is required to make tests work with py.test. When running
|
||||
|
||||
import py
|
||||
|
||||
def get_testunit(item):
|
||||
if hasattr(item, 'obj'):
|
||||
testunit = py.builtin._getimself(item.obj)
|
||||
if hasattr(testunit, 'global_setup'):
|
||||
return testunit
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
testunit = get_testunit(item)
|
||||
if testunit is not None:
|
||||
testunit.global_setup()
|
||||
|
||||
def pytest_runtest_teardown(item):
|
||||
testunit = get_testunit(item)
|
||||
if testunit is not None:
|
||||
testunit.global_teardown()
|
||||
@@ -9,9 +9,8 @@
|
||||
|
||||
import hashlib
|
||||
|
||||
from nose.tools import eq_
|
||||
|
||||
from hsutil.testcase import TestCase
|
||||
from hsutil.testutil import eq_
|
||||
from core.fs import File
|
||||
from core.tests.directories_test import create_fake_fs
|
||||
|
||||
@@ -39,9 +38,8 @@ class TCBundle(TestCase):
|
||||
eq_(b.md5, md5.digest())
|
||||
|
||||
def test_has_file_attrs(self):
|
||||
#a Bundle must behave like a file, so it must have ctime and mtime attributes
|
||||
#a Bundle must behave like a file, so it must have mtime attributes
|
||||
b = fs.Bundle(self.tmppath())
|
||||
assert b.mtime > 0
|
||||
assert b.ctime > 0
|
||||
eq_(b.extension, '')
|
||||
|
||||
1
debian_me/compat
Normal file
1
debian_me/compat
Normal file
@@ -0,0 +1 @@
|
||||
7
|
||||
12
debian_me/control
Normal file
12
debian_me/control
Normal file
@@ -0,0 +1,12 @@
|
||||
Source: dupeguru-me
|
||||
Section: devel
|
||||
Priority: extra
|
||||
Maintainer: Virgil Dupras <hsoft@hardcoded.net>
|
||||
Build-Depends: debhelper (>= 7)
|
||||
Standards-Version: 3.8.1
|
||||
Homepage: http://www.hardcoded.net
|
||||
|
||||
Package: dupeguru-me
|
||||
Architecture: any
|
||||
Depends: python3 (>= 3.1)
|
||||
Description: dupeGuru Music Edition
|
||||
3
debian_me/dirs
Normal file
3
debian_me/dirs
Normal file
@@ -0,0 +1,3 @@
|
||||
usr/local/bin
|
||||
usr/local/share
|
||||
usr/share/applications
|
||||
10
debian_me/dupeguru_me.desktop
Normal file
10
debian_me/dupeguru_me.desktop
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=dupeGuru Music Edition
|
||||
Comment=Find duplicate songs in your collection.
|
||||
Exec=dupeguru_me
|
||||
Icon=/usr/local/share/dupeguru_me/dgme_logo_128.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility
|
||||
86
debian_me/rules
Executable file
86
debian_me/rules
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
# Add here commands to configure the package.
|
||||
|
||||
touch configure-stamp
|
||||
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp: configure-stamp
|
||||
dh_testdir
|
||||
|
||||
# Add here commands to compile the package.
|
||||
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
|
||||
# Add here commands to clean up after the build process.
|
||||
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_prep
|
||||
dh_installdirs
|
||||
|
||||
chmod +x src/start.py
|
||||
cp -R src/ $(CURDIR)/debian/dupeguru-me/usr/local/share/dupeguru_me
|
||||
cp $(CURDIR)/debian/dupeguru_me.desktop $(CURDIR)/debian/dupeguru-me/usr/share/applications
|
||||
ln -s /usr/local/share/dupeguru_me/start.py $(CURDIR)/debian/dupeguru-me/usr/local/bin/dupeguru_me
|
||||
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installchangelogs
|
||||
dh_installdocs
|
||||
dh_installexamples
|
||||
dh_install
|
||||
dh_installmenu
|
||||
# dh_installdebconf
|
||||
# dh_installlogrotate
|
||||
# dh_installemacsen
|
||||
# dh_installpam
|
||||
# dh_installmime
|
||||
# dh_python
|
||||
# dh_installinit
|
||||
# dh_installcron
|
||||
# dh_installinfo
|
||||
dh_installman
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
# dh_perl
|
||||
# dh_makeshlibs
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install configure
|
||||
1
debian_pe/compat
Normal file
1
debian_pe/compat
Normal file
@@ -0,0 +1 @@
|
||||
7
|
||||
12
debian_pe/control
Normal file
12
debian_pe/control
Normal file
@@ -0,0 +1,12 @@
|
||||
Source: dupeguru-pe
|
||||
Section: devel
|
||||
Priority: extra
|
||||
Maintainer: Virgil Dupras <hsoft@hardcoded.net>
|
||||
Build-Depends: debhelper (>= 7)
|
||||
Standards-Version: 3.8.1
|
||||
Homepage: http://www.hardcoded.net
|
||||
|
||||
Package: dupeguru-pe
|
||||
Architecture: any
|
||||
Depends: python3 (>= 3.1)
|
||||
Description: dupeGuru Picture Edition
|
||||
3
debian_pe/dirs
Normal file
3
debian_pe/dirs
Normal file
@@ -0,0 +1,3 @@
|
||||
usr/local/bin
|
||||
usr/local/share
|
||||
usr/share/applications
|
||||
9
debian_pe/dupeguru_pe.desktop
Normal file
9
debian_pe/dupeguru_pe.desktop
Normal file
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=dupeGuru Picture Edition
|
||||
Comment=Find duplicate pictures in your library.
|
||||
Exec=dupeguru_pe
|
||||
Icon=/usr/local/share/dupeguru_pe/dgpe_logo_128.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility
|
||||
86
debian_pe/rules
Executable file
86
debian_pe/rules
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
# Add here commands to configure the package.
|
||||
|
||||
touch configure-stamp
|
||||
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp: configure-stamp
|
||||
dh_testdir
|
||||
|
||||
# Add here commands to compile the package.
|
||||
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
|
||||
# Add here commands to clean up after the build process.
|
||||
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_prep
|
||||
dh_installdirs
|
||||
|
||||
chmod +x src/start.py
|
||||
cp -R src/ $(CURDIR)/debian/dupeguru-pe/usr/local/share/dupeguru_pe
|
||||
cp $(CURDIR)/debian/dupeguru_pe.desktop $(CURDIR)/debian/dupeguru-pe/usr/share/applications
|
||||
ln -s /usr/local/share/dupeguru_pe/start.py $(CURDIR)/debian/dupeguru-pe/usr/local/bin/dupeguru_pe
|
||||
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installchangelogs
|
||||
dh_installdocs
|
||||
dh_installexamples
|
||||
dh_install
|
||||
dh_installmenu
|
||||
# dh_installdebconf
|
||||
# dh_installlogrotate
|
||||
# dh_installemacsen
|
||||
# dh_installpam
|
||||
# dh_installmime
|
||||
# dh_python
|
||||
# dh_installinit
|
||||
# dh_installcron
|
||||
# dh_installinfo
|
||||
dh_installman
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
# dh_perl
|
||||
# dh_makeshlibs
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install configure
|
||||
1
debian_se/compat
Normal file
1
debian_se/compat
Normal file
@@ -0,0 +1 @@
|
||||
7
|
||||
12
debian_se/control
Normal file
12
debian_se/control
Normal file
@@ -0,0 +1,12 @@
|
||||
Source: dupeguru-se
|
||||
Section: devel
|
||||
Priority: extra
|
||||
Maintainer: Virgil Dupras <hsoft@hardcoded.net>
|
||||
Build-Depends: debhelper (>= 7)
|
||||
Standards-Version: 3.8.1
|
||||
Homepage: http://www.hardcoded.net
|
||||
|
||||
Package: dupeguru-se
|
||||
Architecture: any
|
||||
Depends: python3 (>= 3.1)
|
||||
Description: dupeGuru
|
||||
3
debian_se/dirs
Normal file
3
debian_se/dirs
Normal file
@@ -0,0 +1,3 @@
|
||||
usr/local/bin
|
||||
usr/local/share
|
||||
usr/share/applications
|
||||
9
debian_se/dupeguru_se.desktop
Normal file
9
debian_se/dupeguru_se.desktop
Normal file
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=dupeGuru
|
||||
Comment=Find duplicate files.
|
||||
Exec=dupeguru_se
|
||||
Icon=/usr/local/share/dupeguru_se/dgse_logo_128.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility
|
||||
86
debian_se/rules
Executable file
86
debian_se/rules
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
# Add here commands to configure the package.
|
||||
|
||||
touch configure-stamp
|
||||
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp: configure-stamp
|
||||
dh_testdir
|
||||
|
||||
# Add here commands to compile the package.
|
||||
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
|
||||
# Add here commands to clean up after the build process.
|
||||
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_prep
|
||||
dh_installdirs
|
||||
|
||||
chmod +x src/start.py
|
||||
cp -R src/ $(CURDIR)/debian/dupeguru-se/usr/local/share/dupeguru_se
|
||||
cp $(CURDIR)/debian/dupeguru_se.desktop $(CURDIR)/debian/dupeguru-se/usr/share/applications
|
||||
ln -s /usr/local/share/dupeguru_se/start.py $(CURDIR)/debian/dupeguru-se/usr/local/bin/dupeguru_se
|
||||
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installchangelogs
|
||||
dh_installdocs
|
||||
dh_installexamples
|
||||
dh_install
|
||||
dh_installmenu
|
||||
# dh_installdebconf
|
||||
# dh_installlogrotate
|
||||
# dh_installemacsen
|
||||
# dh_installpam
|
||||
# dh_installmime
|
||||
# dh_python
|
||||
# dh_installinit
|
||||
# dh_installcron
|
||||
# dh_installinfo
|
||||
dh_installman
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
# dh_perl
|
||||
# dh_makeshlibs
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install configure
|
||||
@@ -1,3 +1,27 @@
|
||||
- date: 2010-08-24
|
||||
version: 5.9.1
|
||||
description: |
|
||||
* Fixed HTML exporting which was broken in 5.9.0.
|
||||
* Fixed Xing-encoded mpeg decoding which was broken in 5.9.0.
|
||||
- date: 2010-08-20
|
||||
version: 5.9.0
|
||||
description: |
|
||||
* Added the ability to save results (and reload them) at arbitrary locations.
|
||||
* Improved the way reference files in dupe groups are chosen. (#15)
|
||||
* Remember size/position of all windows between launches. (#102)
|
||||
* Fixed a bug sometimes preventing dupeGuru from reloading previous results.
|
||||
* Fixed a bug sometimes causing the progress dialog to be stuck there. [Mac OS X] (#103)
|
||||
* Removed the Creation Date column, which wasn't displaying the correct value anyway. (#101)
|
||||
- date: 2010-07-16
|
||||
version: 5.8.1
|
||||
description: |
|
||||
* Fixed a couple of crashes. (#95, #97, #100)
|
||||
- date: 2010-04-14
|
||||
version: 5.8.0
|
||||
description: |
|
||||
* Improved error messages when files can't be sent to trash, moved or copied.
|
||||
* Added a custom command invocation action. (#12)
|
||||
* Filters are now applied on whole paths. (#4)
|
||||
- date: 2010-02-13
|
||||
version: 5.7.2
|
||||
description: |
|
||||
|
||||
6
help_me/conf.yaml
Normal file
6
help_me/conf.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
base:
|
||||
pages: en/pages.yaml
|
||||
skeleton: skeleton
|
||||
changelog: changelog.yaml
|
||||
tixurl: "https://hardcoded.lighthouseapp.com/projects/31699-dupeguru/tickets/{0}"
|
||||
firstpage_meta: "<meta name=\"AppleTitle\" content=\"dupeGuru ME Help\"></meta>"
|
||||
26
help_me/en/credits.md
Normal file
26
help_me/en/credits.md
Normal file
@@ -0,0 +1,26 @@
|
||||
Below is the list of people who contributed, directly or indirectly to dupeGuru.
|
||||
|
||||
**Virgil Dupras, Developer**<br/>
|
||||
<http://www.hardcoded.net>
|
||||
|
||||
**Jérôme Cantin, Icon designer**<br/>
|
||||
Icons in dupeGuru are from him
|
||||
|
||||
**Python, Programming language**<br/>
|
||||
The bestest of the bests<br/>
|
||||
<http://www.python.org>
|
||||
|
||||
**PyObjC, Python-to-Cocoa bridge**<br/>
|
||||
Used for the Mac OS X version<br/>
|
||||
<http://pyobjc.sourceforge.net>
|
||||
|
||||
**PyQt, Python-to-Qt bridge**<br/>
|
||||
Used for the Windows version<br/>
|
||||
<http://www.riverbankcomputing.co.uk>
|
||||
|
||||
**Sparkle, Auto-update library**<br/>
|
||||
Used for the Mac OS X version<br/>
|
||||
<http://andymatuschak.org/pages/sparkle>
|
||||
|
||||
**You, dupeGuru user**<br/>
|
||||
You rock.
|
||||
@@ -1,9 +1,3 @@
|
||||
<%!
|
||||
title = 'Directories'
|
||||
selected_menu_item = 'Directories'
|
||||
%>
|
||||
<%inherit file="/base_dg.mako"/>
|
||||
|
||||
There is a panel in dupeGuru called **Directories**. You can open it by clicking on the **Directories** button. This directory contains the list of the directories that will be scanned when you click on **Start Scanning**.
|
||||
|
||||
This panel is quite straightforward to use. If you want to add a directory, click on **Add**. If you added directories before, a popup menu with a list of recent directories you added will pop. You can click on one of them to add it directly to your list. If you click on the first item of the popup menu, **Add New Directory...**, you will be prompted for a directory to add. If you never added a directory, no menu will pop and you will directly be prompted for a new directory to add.
|
||||
@@ -1,10 +1,3 @@
|
||||
<%!
|
||||
title = 'dupeGuru ME F.A.Q.'
|
||||
selected_menu_item = 'F.A.Q.'
|
||||
%>
|
||||
<%inherit file="/base_dg.mako"/>
|
||||
|
||||
<%text filter="md">
|
||||
### What is dupeGuru Music Edition?
|
||||
|
||||
dupeGuru Music Edition is a tool to find duplicate songs in your music collection. It can base its scan on filenames, tags or content. The filename and tag scans feature a fuzzy matching algorithm that can find duplicate filenames or tags even when they are not exactly the same.
|
||||
@@ -72,4 +65,3 @@ Most of the time, the reason why dupeGuru can't send files to Trash is because o
|
||||
If dupeGuru still gives you troubles after fixing your permissions, there have been some cases where using "Move Marked to..." as a workaround did the trick. So instead of sending your files to Trash, you send them to a temporary folder with the "Move Marked to..." action, and then you delete that temporary folder manually.
|
||||
|
||||
If all of this fail, [contact HS support](http://www.hardcoded.net/support), we'll figure it out.
|
||||
</%text>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user