mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-01-25 08:01:39 +00:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
8
.hgtags
8
.hgtags
@@ -14,3 +14,11 @@ cbcf9c80fee4c908ef2efbf1c143c9e47676c9b2 pe1.8.0
|
|||||||
90ed56ee602666db2f267f73eac6f824347039b5 me5.7.2
|
90ed56ee602666db2f267f73eac6f824347039b5 me5.7.2
|
||||||
4c3cb1e671a333eabde1151c7c6ffb3609cab025 pe1.8.4
|
4c3cb1e671a333eabde1151c7c6ffb3609cab025 pe1.8.4
|
||||||
0a71306434bca51bea9a5d5ae54fe1bf0e4900d8 pe1.8.5
|
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
|
||||||
|
|||||||
7
README
7
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
|
There are also other sub-folder that comes from external repositories (automatically checked out
|
||||||
with svn:externals):
|
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)
|
- 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.
|
- 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.
|
- qtlib: A collection of helpers used across Qt UI codebases of HS applications.
|
||||||
|
|
||||||
@@ -28,10 +27,12 @@ General dependencies
|
|||||||
|
|
||||||
- Python 2.6 (http://www.python.org)
|
- Python 2.6 (http://www.python.org)
|
||||||
- Send2Trash (http://hg.hardcoded.net/send2trash)
|
- Send2Trash (http://hg.hardcoded.net/send2trash)
|
||||||
|
- hsutil (http://hg.hardcoded.net/hsutil)
|
||||||
|
- hsaudiotag (for ME) (http://hg.hardcoded.net/hsaudiotag)
|
||||||
- lxml, to read and write XML files. (http://codespeak.net/lxml/)
|
- lxml, to read and write XML files. (http://codespeak.net/lxml/)
|
||||||
- Mako, to generate help files. (http://www.makotemplates.org/)
|
- Mako, to generate help files. (http://www.makotemplates.org/)
|
||||||
- PyYaml, for help files and the build system. (http://pyyaml.org/)
|
- 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
|
OS X prerequisites
|
||||||
-----
|
-----
|
||||||
|
|||||||
13
build.py
13
build.py
@@ -15,8 +15,8 @@ import shutil
|
|||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from hsdocgen import generate_help, filters
|
from hscommon import helpgen
|
||||||
from hsutil.build import add_to_pythonpath, print_and_do, build_all_qt_ui, copy_packages
|
from hscommon.build import add_to_pythonpath, print_and_do, build_all_qt_ui, copy_packages
|
||||||
|
|
||||||
def build_cocoa(edition, dev, help_destpath):
|
def build_cocoa(edition, dev, help_destpath):
|
||||||
if not dev:
|
if not dev:
|
||||||
@@ -30,10 +30,10 @@ def build_cocoa(edition, dev, help_destpath):
|
|||||||
if not dev:
|
if not dev:
|
||||||
specific_packages = {
|
specific_packages = {
|
||||||
'se': ['core_se'],
|
'se': ['core_se'],
|
||||||
'me': ['core_me', 'hsmedia'],
|
'me': ['core_me'],
|
||||||
'pe': ['core_pe'],
|
'pe': ['core_pe'],
|
||||||
}[edition]
|
}[edition]
|
||||||
copy_packages(['core', 'hsutil'] + specific_packages, 'build')
|
copy_packages(['core', 'hscommon'] + specific_packages, 'build')
|
||||||
cocoa_project_path = 'cocoa/{0}'.format(edition)
|
cocoa_project_path = 'cocoa/{0}'.format(edition)
|
||||||
shutil.copy(op.join(cocoa_project_path, 'dg_cocoa.py'), 'build')
|
shutil.copy(op.join(cocoa_project_path, 'dg_cocoa.py'), 'build')
|
||||||
os.chdir('build')
|
os.chdir('build')
|
||||||
@@ -85,13 +85,12 @@ def main():
|
|||||||
add_to_pythonpath('.')
|
add_to_pythonpath('.')
|
||||||
print "Generating Help"
|
print "Generating Help"
|
||||||
windows = sys.platform == 'win32'
|
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)
|
help_dir = 'help_{0}'.format(edition)
|
||||||
dest_dir = 'dupeguru_{0}_help'.format(edition) if edition != 'se' else 'dupeguru_help'
|
dest_dir = 'dupeguru_{0}_help'.format(edition) if edition != 'se' else 'dupeguru_help'
|
||||||
help_basepath = op.abspath(help_dir)
|
help_basepath = op.abspath(help_dir)
|
||||||
help_destpath = op.abspath(op.join(help_dir, dest_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)
|
helpgen.gen(help_basepath, help_destpath, profile=profile)
|
||||||
|
|
||||||
print "Building dupeGuru"
|
print "Building dupeGuru"
|
||||||
if edition == 'pe':
|
if edition == 'pe':
|
||||||
os.chdir('core_pe')
|
os.chdir('core_pe')
|
||||||
|
|||||||
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
|
||||||
@@ -20,6 +20,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
- (void)clearIgnoreList;
|
- (void)clearIgnoreList;
|
||||||
- (void)purgeIgnoreList;
|
- (void)purgeIgnoreList;
|
||||||
- (NSString *)exportToXHTMLwithColumns:(NSArray *)aColIds;
|
- (NSString *)exportToXHTMLwithColumns:(NSArray *)aColIds;
|
||||||
|
- (void)invokeCommand:(NSString *)cmd;
|
||||||
|
|
||||||
- (NSNumber *)doScan;
|
- (NSNumber *)doScan;
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
//Data
|
//Data
|
||||||
- (NSNumber *)getIgnoreListCount;
|
- (NSNumber *)getIgnoreListCount;
|
||||||
- (NSNumber *)getMarkCount;
|
- (NSNumber *)getMarkCount;
|
||||||
- (NSNumber *)getOperationalErrorCount;
|
- (BOOL)scanWasProblematic;
|
||||||
|
|
||||||
//Scanning options
|
//Scanning options
|
||||||
- (void)setMinMatchPercentage:(NSNumber *)percentage;
|
- (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 "HSOutlineView.h"
|
||||||
#import "StatsLabel.h"
|
#import "StatsLabel.h"
|
||||||
#import "ResultOutline.h"
|
#import "ResultOutline.h"
|
||||||
|
#import "ProblemDialog.h"
|
||||||
#import "PyDupeGuru.h"
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
@interface ResultWindowBase : NSWindowController
|
@interface ResultWindowBase : NSWindowController
|
||||||
@@ -28,6 +29,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
NSWindowController *preferencesPanel;
|
NSWindowController *preferencesPanel;
|
||||||
ResultOutline *outline;
|
ResultOutline *outline;
|
||||||
StatsLabel *statsLabel;
|
StatsLabel *statsLabel;
|
||||||
|
ProblemDialog *problemDialog;
|
||||||
}
|
}
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
- (void)fillColumnsMenu;
|
- (void)fillColumnsMenu;
|
||||||
@@ -46,6 +48,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
- (IBAction)exportToXHTML:(id)sender;
|
- (IBAction)exportToXHTML:(id)sender;
|
||||||
- (IBAction)filter:(id)sender;
|
- (IBAction)filter:(id)sender;
|
||||||
- (IBAction)ignoreSelected:(id)sender;
|
- (IBAction)ignoreSelected:(id)sender;
|
||||||
|
- (IBAction)invokeCustomCommand:(id)sender;
|
||||||
- (IBAction)markAll:(id)sender;
|
- (IBAction)markAll:(id)sender;
|
||||||
- (IBAction)markInvert:(id)sender;
|
- (IBAction)markInvert:(id)sender;
|
||||||
- (IBAction)markNone:(id)sender;
|
- (IBAction)markNone:(id)sender;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
||||||
outline = [[ResultOutline alloc] initWithPyParent:py view:matches];
|
outline = [[ResultOutline alloc] initWithPyParent:py view:matches];
|
||||||
statsLabel = [[StatsLabel alloc] initWithPyParent:py labelView:stats];
|
statsLabel = [[StatsLabel alloc] initWithPyParent:py labelView:stats];
|
||||||
|
problemDialog = [[ProblemDialog alloc] initWithPy:py];
|
||||||
[self initResultColumns];
|
[self initResultColumns];
|
||||||
[self fillColumnsMenu];
|
[self fillColumnsMenu];
|
||||||
[deltaSwitch setSelectedSegment:0];
|
[deltaSwitch setSelectedSegment:0];
|
||||||
@@ -38,6 +39,8 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
{
|
{
|
||||||
[outline release];
|
[outline release];
|
||||||
[preferencesPanel release];
|
[preferencesPanel release];
|
||||||
|
[statsLabel release];
|
||||||
|
[problemDialog release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +200,18 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[py addSelectedToIgnoreList];
|
[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)markAll:(id)sender
|
- (IBAction)markAll:(id)sender
|
||||||
{
|
{
|
||||||
[py markAll];
|
[py markAll];
|
||||||
@@ -349,28 +364,30 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (void)jobCompleted:(NSNotification *)aNotification
|
- (void)jobCompleted:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
NSInteger r = n2i([py getOperationalErrorCount]);
|
|
||||||
id lastAction = [[ProgressController mainProgressController] jobId];
|
id lastAction = [[ProgressController mainProgressController] jobId];
|
||||||
if ([lastAction isEqualTo:jobCopy]) {
|
if ([lastAction isEqualTo:jobCopy]) {
|
||||||
if (r > 0)
|
if ([py scanWasProblematic]) {
|
||||||
[Dialogs showMessage:[NSString stringWithFormat:@"%d file(s) couldn't be copied.",r]];
|
[problemDialog showWindow:self];
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
[Dialogs showMessage:@"All marked files were copied sucessfully."];
|
[Dialogs showMessage:@"All marked files were copied sucessfully."];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ([lastAction isEqualTo:jobMove]) {
|
else if ([lastAction isEqualTo:jobMove]) {
|
||||||
if (r > 0)
|
if ([py scanWasProblematic]) {
|
||||||
[Dialogs showMessage:[NSString stringWithFormat:@"%d file(s) couldn't be moved. They were kept in the results, and still are marked.",r]];
|
[problemDialog showWindow:self];
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
[Dialogs showMessage:@"All marked files were moved sucessfully."];
|
[Dialogs showMessage:@"All marked files were moved sucessfully."];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ([lastAction isEqualTo:jobDelete]) {
|
else if ([lastAction isEqualTo:jobDelete]) {
|
||||||
if (r > 0) {
|
if ([py scanWasProblematic]) {
|
||||||
NSString *msg = @"%d file(s) couldn't be sent to Trash. They were kept in the results, "\
|
[problemDialog showWindow:self];
|
||||||
"and still are marked. See the F.A.Q. section in the help file for details.";
|
|
||||||
[Dialogs showMessage:[NSString stringWithFormat:msg,r]];
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
[Dialogs showMessage:@"All marked files were sucessfully sent to Trash."];
|
[Dialogs showMessage:@"All marked files were sucessfully sent to Trash."];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ([lastAction isEqualTo:jobScan]) {
|
else if ([lastAction isEqualTo:jobScan]) {
|
||||||
NSInteger groupCount = [outline intProperty:@"children_count" valueAtPath:nil];
|
NSInteger groupCount = [outline intProperty:@"children_count" valueAtPath:nil];
|
||||||
|
|||||||
@@ -2,18 +2,18 @@
|
|||||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||||
<data>
|
<data>
|
||||||
<int key="IBDocument.SystemTarget">1050</int>
|
<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.InterfaceBuilderVersion">740</string>
|
||||||
<string key="IBDocument.AppKitVersion">1038.25</string>
|
<string key="IBDocument.AppKitVersion">1038.29</string>
|
||||||
<string key="IBDocument.HIToolboxVersion">458.00</string>
|
<string key="IBDocument.HIToolboxVersion">460.00</string>
|
||||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string key="NS.object.0">740</string>
|
<string key="NS.object.0">740</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<integer value="598"/>
|
||||||
<integer value="219"/>
|
<integer value="219"/>
|
||||||
<integer value="29"/>
|
|
||||||
</object>
|
</object>
|
||||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
@@ -1146,7 +1146,7 @@
|
|||||||
<object class="NSMenuItem" id="578499792">
|
<object class="NSMenuItem" id="578499792">
|
||||||
<reference key="NSMenu" ref="600111647"/>
|
<reference key="NSMenu" ref="600111647"/>
|
||||||
<string key="NSTitle">Clear Ignore List</string>
|
<string key="NSTitle">Clear Ignore List</string>
|
||||||
<string key="NSKeyEquiv">I</string>
|
<string key="NSKeyEquiv">G</string>
|
||||||
<int key="NSKeyEquivModMask">1048576</int>
|
<int key="NSKeyEquivModMask">1048576</int>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<int key="NSMnemonicLoc">2147483647</int>
|
||||||
<reference key="NSOnImage" ref="852972005"/>
|
<reference key="NSOnImage" ref="852972005"/>
|
||||||
@@ -1231,7 +1231,7 @@
|
|||||||
<object class="NSMenuItem" id="904423169">
|
<object class="NSMenuItem" id="904423169">
|
||||||
<reference key="NSMenu" ref="600111647"/>
|
<reference key="NSMenu" ref="600111647"/>
|
||||||
<string key="NSTitle">Add Selected to Ignore List</string>
|
<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="NSKeyEquivModMask">1048576</int>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<int key="NSMnemonicLoc">2147483647</int>
|
||||||
<reference key="NSOnImage" ref="852972005"/>
|
<reference key="NSOnImage" ref="852972005"/>
|
||||||
@@ -1275,6 +1275,15 @@
|
|||||||
<reference key="NSOnImage" ref="852972005"/>
|
<reference key="NSOnImage" ref="852972005"/>
|
||||||
<reference key="NSMixedImage" ref="218295580"/>
|
<reference key="NSMixedImage" ref="218295580"/>
|
||||||
</object>
|
</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">
|
<object class="NSMenuItem" id="564101661">
|
||||||
<reference key="NSMenu" ref="600111647"/>
|
<reference key="NSMenu" ref="600111647"/>
|
||||||
<string key="NSTitle">Rename Selected</string>
|
<string key="NSTitle">Rename Selected</string>
|
||||||
@@ -2204,6 +2213,14 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">1176</int>
|
<int key="connectionID">1176</int>
|
||||||
</object>
|
</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>
|
</object>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<object class="NSArray" key="orderedObjects">
|
<object class="NSArray" key="orderedObjects">
|
||||||
@@ -2530,6 +2547,7 @@
|
|||||||
<reference ref="564101661"/>
|
<reference ref="564101661"/>
|
||||||
<reference ref="630362403"/>
|
<reference ref="630362403"/>
|
||||||
<reference ref="747820446"/>
|
<reference ref="747820446"/>
|
||||||
|
<reference ref="517397504"/>
|
||||||
</object>
|
</object>
|
||||||
<reference key="parent" ref="528113253"/>
|
<reference key="parent" ref="528113253"/>
|
||||||
</object>
|
</object>
|
||||||
@@ -3066,6 +3084,11 @@
|
|||||||
<reference key="object" ref="747820446"/>
|
<reference key="object" ref="747820446"/>
|
||||||
<reference key="parent" ref="600111647"/>
|
<reference key="parent" ref="600111647"/>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">1177</int>
|
||||||
|
<reference key="object" ref="517397504"/>
|
||||||
|
<reference key="parent" ref="600111647"/>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||||
@@ -3117,6 +3140,7 @@
|
|||||||
<string>1171.IBPluginDependency</string>
|
<string>1171.IBPluginDependency</string>
|
||||||
<string>1172.IBPluginDependency</string>
|
<string>1172.IBPluginDependency</string>
|
||||||
<string>1173.IBPluginDependency</string>
|
<string>1173.IBPluginDependency</string>
|
||||||
|
<string>1177.IBPluginDependency</string>
|
||||||
<string>134.IBPluginDependency</string>
|
<string>134.IBPluginDependency</string>
|
||||||
<string>134.ImportedFromIB2</string>
|
<string>134.ImportedFromIB2</string>
|
||||||
<string>136.IBPluginDependency</string>
|
<string>136.IBPluginDependency</string>
|
||||||
@@ -3355,6 +3379,7 @@
|
|||||||
<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>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
@@ -3374,9 +3399,9 @@
|
|||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<boolean value="YES"/>
|
<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>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"/>
|
<boolean value="YES"/>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
@@ -3423,7 +3448,7 @@
|
|||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<string>{{286, 475}, {361, 293}}</string>
|
<string>{{286, 455}, {361, 313}}</string>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
@@ -3561,7 +3586,7 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">1176</int>
|
<int key="maxID">1178</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
@@ -3776,8 +3801,17 @@
|
|||||||
<string key="className">ResultWindow</string>
|
<string key="className">ResultWindow</string>
|
||||||
<string key="superclassName">ResultWindowBase</string>
|
<string key="superclassName">ResultWindowBase</string>
|
||||||
<object class="NSMutableDictionary" key="actions">
|
<object class="NSMutableDictionary" key="actions">
|
||||||
<string key="NS.key.0">removeDeadTracks:</string>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<string key="NS.object.0">id</string>
|
<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>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
<string key="majorKey">IBProjectSource</string>
|
<string key="majorKey">IBProjectSource</string>
|
||||||
@@ -3799,6 +3833,7 @@
|
|||||||
<string>exportToXHTML:</string>
|
<string>exportToXHTML:</string>
|
||||||
<string>filter:</string>
|
<string>filter:</string>
|
||||||
<string>ignoreSelected:</string>
|
<string>ignoreSelected:</string>
|
||||||
|
<string>invokeCustomCommand:</string>
|
||||||
<string>markAll:</string>
|
<string>markAll:</string>
|
||||||
<string>markInvert:</string>
|
<string>markInvert:</string>
|
||||||
<string>markNone:</string>
|
<string>markNone:</string>
|
||||||
@@ -3848,6 +3883,7 @@
|
|||||||
<string>id</string>
|
<string>id</string>
|
||||||
<string>id</string>
|
<string>id</string>
|
||||||
<string>id</string>
|
<string>id</string>
|
||||||
|
<string>id</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSMutableDictionary" key="outlets">
|
<object class="NSMutableDictionary" key="outlets">
|
||||||
@@ -4500,7 +4536,7 @@
|
|||||||
<integer value="3000" key="NS.object.0"/>
|
<integer value="3000" key="NS.object.0"/>
|
||||||
</object>
|
</object>
|
||||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
<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>
|
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||||
</data>
|
</data>
|
||||||
</archive>
|
</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>
|
<key>CFBundleSignature</key>
|
||||||
<string>hsft</string>
|
<string>hsft</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>5.7.2</string>
|
<string>5.8.1</string>
|
||||||
<key>NSMainNibFile</key>
|
<key>NSMainNibFile</key>
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
from hsutil.cocoa import signature
|
from hscommon.cocoa import signature
|
||||||
|
|
||||||
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||||
from core_me.app_cocoa import DupeGuruME
|
from core_me.app_cocoa import DupeGuruME
|
||||||
@@ -13,7 +13,7 @@ from core.scanner import (SCAN_TYPE_FILENAME, SCAN_TYPE_FIELDS, SCAN_TYPE_FIELDS
|
|||||||
|
|
||||||
# Fix py2app imports which chokes on relative imports and other stuff
|
# Fix py2app imports which chokes on relative imports and other stuff
|
||||||
from core_me import app_cocoa, data, fs, scanner
|
from core_me import app_cocoa, data, fs, scanner
|
||||||
from hsmedia import aiff, flac, genres, id3v1, id3v2, mp4, mpeg, ogg, wma
|
from hsaudiotag import aiff, flac, genres, id3v1, id3v2, mp4, mpeg, ogg, wma
|
||||||
from lxml import etree, _elementpath
|
from lxml import etree, _elementpath
|
||||||
import gzip
|
import gzip
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,9 @@
|
|||||||
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */; };
|
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */; };
|
||||||
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */; };
|
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */; };
|
||||||
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */; };
|
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */; };
|
||||||
|
CE0A0C001175A1C000DCA3C6 /* HSTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0A0BFF1175A1C000DCA3C6 /* HSTable.m */; };
|
||||||
|
CE0A0C041175A1DE00DCA3C6 /* ProblemDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0A0C021175A1DE00DCA3C6 /* ProblemDialog.m */; };
|
||||||
|
CE0A0C061175A24800DCA3C6 /* ProblemDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE0A0C051175A24800DCA3C6 /* ProblemDialog.xib */; };
|
||||||
CE0B3D6711243F83009A7A30 /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0B3D6611243F83009A7A30 /* ResultOutline.m */; };
|
CE0B3D6711243F83009A7A30 /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0B3D6611243F83009A7A30 /* ResultOutline.m */; };
|
||||||
CE1425890AFB718500BD5167 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
CE1425890AFB718500BD5167 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
||||||
CE14259F0AFB719300BD5167 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
CE14259F0AFB719300BD5167 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
||||||
@@ -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; };
|
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; };
|
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>"; };
|
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; };
|
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; };
|
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; };
|
CE0B3D6611243F83009A7A30 /* ResultOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultOutline.m; path = ../base/ResultOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -155,8 +165,6 @@
|
|||||||
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
||||||
CE900AD1109B238600754048 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Preferences.xib; 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>"; };
|
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>"; };
|
|
||||||
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; 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; };
|
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; };
|
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 */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
080E96DDFE201D6D7F000001 /* DGME */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
||||||
CE381C9409914ACE003581CE /* AppDelegate.m */,
|
CE381C9409914ACE003581CE /* AppDelegate.m */,
|
||||||
CE848A1809DD85810004CB44 /* Consts.h */,
|
CE848A1809DD85810004CB44 /* Consts.h */,
|
||||||
CECA899A09DB132E00A3D774 /* DetailsPanel.h */,
|
|
||||||
CECA899B09DB132E00A3D774 /* DetailsPanel.m */,
|
|
||||||
CE68EE6509ABC48000971085 /* DirectoryPanel.h */,
|
CE68EE6509ABC48000971085 /* DirectoryPanel.h */,
|
||||||
CE68EE6609ABC48000971085 /* DirectoryPanel.m */,
|
CE68EE6609ABC48000971085 /* DirectoryPanel.m */,
|
||||||
CEFF18A009A4D387005E6321 /* PyDupeGuru.h */,
|
CEFF18A009A4D387005E6321 /* PyDupeGuru.h */,
|
||||||
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
||||||
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
||||||
);
|
);
|
||||||
name = Classes;
|
name = DGME;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
||||||
@@ -228,7 +234,7 @@
|
|||||||
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
080E96DDFE201D6D7F000001 /* Classes */,
|
080E96DDFE201D6D7F000001 /* DGME */,
|
||||||
CE515E140FC6C17900EC695D /* dgbase */,
|
CE515E140FC6C17900EC695D /* dgbase */,
|
||||||
CE515DDD0FC6C09400EC695D /* cocoalib */,
|
CE515DDD0FC6C09400EC695D /* cocoalib */,
|
||||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||||
@@ -277,6 +283,8 @@
|
|||||||
CE003CB411242D00004B0AA7 /* HSGUIController.m */,
|
CE003CB411242D00004B0AA7 /* HSGUIController.m */,
|
||||||
CE003CB511242D00004B0AA7 /* HSOutline.h */,
|
CE003CB511242D00004B0AA7 /* HSOutline.h */,
|
||||||
CE003CB611242D00004B0AA7 /* HSOutline.m */,
|
CE003CB611242D00004B0AA7 /* HSOutline.m */,
|
||||||
|
CE0A0BFE1175A1C000DCA3C6 /* HSTable.h */,
|
||||||
|
CE0A0BFF1175A1C000DCA3C6 /* HSTable.m */,
|
||||||
CE003CB711242D00004B0AA7 /* HSWindowController.h */,
|
CE003CB711242D00004B0AA7 /* HSWindowController.h */,
|
||||||
CE003CB811242D00004B0AA7 /* HSWindowController.m */,
|
CE003CB811242D00004B0AA7 /* HSWindowController.m */,
|
||||||
);
|
);
|
||||||
@@ -289,6 +297,7 @@
|
|||||||
children = (
|
children = (
|
||||||
CE003CBC11242D00004B0AA7 /* PyGUI.h */,
|
CE003CBC11242D00004B0AA7 /* PyGUI.h */,
|
||||||
CE003CBD11242D00004B0AA7 /* PyOutline.h */,
|
CE003CBD11242D00004B0AA7 /* PyOutline.h */,
|
||||||
|
CE0A0C131175A28100DCA3C6 /* PyTable.h */,
|
||||||
);
|
);
|
||||||
name = proxies;
|
name = proxies;
|
||||||
path = ../../cocoalib/proxies;
|
path = ../../cocoalib/proxies;
|
||||||
@@ -315,6 +324,7 @@
|
|||||||
CE3FBDD11094637800B72D77 /* DetailsPanel.xib */,
|
CE3FBDD11094637800B72D77 /* DetailsPanel.xib */,
|
||||||
CE3FBDD21094637800B72D77 /* DirectoryPanel.xib */,
|
CE3FBDD21094637800B72D77 /* DirectoryPanel.xib */,
|
||||||
CE900AD1109B238600754048 /* Preferences.xib */,
|
CE900AD1109B238600754048 /* Preferences.xib */,
|
||||||
|
CE0A0C051175A24800DCA3C6 /* ProblemDialog.xib */,
|
||||||
);
|
);
|
||||||
path = xib;
|
path = xib;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -383,6 +393,8 @@
|
|||||||
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */,
|
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */,
|
||||||
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
|
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
|
||||||
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
|
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
|
||||||
|
CE0A0C011175A1DE00DCA3C6 /* ProblemDialog.h */,
|
||||||
|
CE0A0C021175A1DE00DCA3C6 /* ProblemDialog.m */,
|
||||||
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
|
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
|
||||||
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
|
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
|
||||||
CE0B3D6511243F83009A7A30 /* ResultOutline.h */,
|
CE0B3D6511243F83009A7A30 /* ResultOutline.h */,
|
||||||
@@ -391,6 +403,7 @@
|
|||||||
CEDF07A2112493B200EE5BC0 /* StatsLabel.m */,
|
CEDF07A2112493B200EE5BC0 /* StatsLabel.m */,
|
||||||
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
|
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
|
||||||
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */,
|
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */,
|
||||||
|
CE0A0C031175A1DE00DCA3C6 /* PyProblemDialog.h */,
|
||||||
CE0B3D6411243F83009A7A30 /* PyResultTree.h */,
|
CE0B3D6411243F83009A7A30 /* PyResultTree.h */,
|
||||||
CEDF07A0112493B200EE5BC0 /* PyStatsLabel.h */,
|
CEDF07A0112493B200EE5BC0 /* PyStatsLabel.h */,
|
||||||
);
|
);
|
||||||
@@ -466,6 +479,7 @@
|
|||||||
CE4B59C81119919700C06C9E /* ErrorReportWindow.xib in Resources */,
|
CE4B59C81119919700C06C9E /* ErrorReportWindow.xib in Resources */,
|
||||||
CE4B59C91119919700C06C9E /* progress.xib in Resources */,
|
CE4B59C91119919700C06C9E /* progress.xib in Resources */,
|
||||||
CE4B59CA1119919700C06C9E /* registration.xib in Resources */,
|
CE4B59CA1119919700C06C9E /* registration.xib in Resources */,
|
||||||
|
CE0A0C061175A24800DCA3C6 /* ProblemDialog.xib in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -502,6 +516,8 @@
|
|||||||
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */,
|
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */,
|
||||||
CE0B3D6711243F83009A7A30 /* ResultOutline.m in Sources */,
|
CE0B3D6711243F83009A7A30 /* ResultOutline.m in Sources */,
|
||||||
CEDF07A3112493B200EE5BC0 /* StatsLabel.m in Sources */,
|
CEDF07A3112493B200EE5BC0 /* StatsLabel.m in Sources */,
|
||||||
|
CE0A0C001175A1C000DCA3C6 /* HSTable.m in Sources */,
|
||||||
|
CE0A0C041175A1DE00DCA3C6 /* ProblemDialog.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>hsft</string>
|
<string>hsft</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.8.6</string>
|
<string>1.9.1</string>
|
||||||
<key>NSMainNibFile</key>
|
<key>NSMainNibFile</key>
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
CE031751109B340A00517EE6 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE031750109B340A00517EE6 /* Preferences.xib */; };
|
CE031751109B340A00517EE6 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE031750109B340A00517EE6 /* Preferences.xib */; };
|
||||||
CE031754109B345200517EE6 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE031753109B345200517EE6 /* MainMenu.xib */; };
|
CE031754109B345200517EE6 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE031753109B345200517EE6 /* MainMenu.xib */; };
|
||||||
CE073F6309CAE1A3005C1D2F /* dupeguru_pe_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */; };
|
CE073F6309CAE1A3005C1D2F /* dupeguru_pe_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */; };
|
||||||
|
CE0C2AB61177011000BC749F /* HSTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0C2AB51177011000BC749F /* HSTable.m */; };
|
||||||
|
CE0C2ABD1177014200BC749F /* ProblemDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0C2ABB1177014200BC749F /* ProblemDialog.m */; };
|
||||||
|
CE0C2AC81177021600BC749F /* ProblemDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE0C2AC71177021600BC749F /* ProblemDialog.xib */; };
|
||||||
CE15C8A80ADEB8B50061D4A5 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */; };
|
CE15C8A80ADEB8B50061D4A5 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */; };
|
||||||
CE15C8C00ADEB8D40061D4A5 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */; };
|
CE15C8C00ADEB8D40061D4A5 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */; };
|
||||||
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
||||||
@@ -84,6 +87,13 @@
|
|||||||
CE031750109B340A00517EE6 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Preferences.xib; sourceTree = "<group>"; };
|
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>"; };
|
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; };
|
CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_pe_help; path = ../../help_pe/dupeguru_pe_help; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0C2AAA117700E700BC749F /* PyTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyTable.h; sourceTree = "<group>"; };
|
||||||
|
CE0C2AB41177011000BC749F /* HSTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSTable.h; sourceTree = "<group>"; };
|
||||||
|
CE0C2AB51177011000BC749F /* HSTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSTable.m; sourceTree = "<group>"; };
|
||||||
|
CE0C2ABA1177014200BC749F /* ProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProblemDialog.h; path = ../base/ProblemDialog.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0C2ABB1177014200BC749F /* ProblemDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProblemDialog.m; path = ../base/ProblemDialog.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0C2ABC1177014200BC749F /* PyProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyProblemDialog.h; path = ../base/PyProblemDialog.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0C2AC71177021600BC749F /* ProblemDialog.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ProblemDialog.xib; path = ../base/xib/ProblemDialog.xib; sourceTree = SOURCE_ROOT; };
|
||||||
CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
||||||
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; sourceTree = SOURCE_ROOT; };
|
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; };
|
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -180,7 +190,7 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
080E96DDFE201D6D7F000001 /* DGPE */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
CE381C9509914ACE003581CE /* AppDelegate.h */,
|
||||||
@@ -194,7 +204,7 @@
|
|||||||
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
CE381C9B09914ADF003581CE /* ResultWindow.h */,
|
||||||
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
CE381C9A09914ADF003581CE /* ResultWindow.m */,
|
||||||
);
|
);
|
||||||
name = Classes;
|
name = DGPE;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
|
||||||
@@ -227,7 +237,7 @@
|
|||||||
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
29B97314FDCFA39411CA2CEA /* dupeguru */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
080E96DDFE201D6D7F000001 /* Classes */,
|
080E96DDFE201D6D7F000001 /* DGPE */,
|
||||||
CE80DB1A0FC192AB0086DCA6 /* cocoalib */,
|
CE80DB1A0FC192AB0086DCA6 /* cocoalib */,
|
||||||
CE80DB810FC194BD0086DCA6 /* dgbase */,
|
CE80DB810FC194BD0086DCA6 /* dgbase */,
|
||||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||||
@@ -276,6 +286,7 @@
|
|||||||
CE77C8A710946CE20078B0DB /* DetailsPanel.xib */,
|
CE77C8A710946CE20078B0DB /* DetailsPanel.xib */,
|
||||||
CE77C89C10946C6D0078B0DB /* DirectoryPanel.xib */,
|
CE77C89C10946C6D0078B0DB /* DirectoryPanel.xib */,
|
||||||
CE031750109B340A00517EE6 /* Preferences.xib */,
|
CE031750109B340A00517EE6 /* Preferences.xib */,
|
||||||
|
CE0C2AC71177021600BC749F /* ProblemDialog.xib */,
|
||||||
);
|
);
|
||||||
path = xib;
|
path = xib;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -335,19 +346,22 @@
|
|||||||
CE6044EB0FE6796200B71262 /* DetailsPanel.m */,
|
CE6044EB0FE6796200B71262 /* DetailsPanel.m */,
|
||||||
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */,
|
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */,
|
||||||
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */,
|
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */,
|
||||||
CE9EA7711122CA0B008CD2BC /* PyDirectoryOutline.h */,
|
|
||||||
CE9EA76F1122CA0B008CD2BC /* DirectoryOutline.h */,
|
CE9EA76F1122CA0B008CD2BC /* DirectoryOutline.h */,
|
||||||
CE9EA7701122CA0B008CD2BC /* DirectoryOutline.m */,
|
CE9EA7701122CA0B008CD2BC /* DirectoryOutline.m */,
|
||||||
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */,
|
CE0C2ABA1177014200BC749F /* ProblemDialog.h */,
|
||||||
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */,
|
CE0C2ABB1177014200BC749F /* ProblemDialog.m */,
|
||||||
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */,
|
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */,
|
||||||
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */,
|
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */,
|
||||||
CE958658112C516400F95FD2 /* PyResultTree.h */,
|
CE958658112C516400F95FD2 /* PyResultTree.h */,
|
||||||
CE95865A112C516400F95FD2 /* ResultOutline.h */,
|
CE95865A112C516400F95FD2 /* ResultOutline.h */,
|
||||||
CE95865B112C516400F95FD2 /* ResultOutline.m */,
|
CE95865B112C516400F95FD2 /* ResultOutline.m */,
|
||||||
CE958659112C516400F95FD2 /* PyStatsLabel.h */,
|
|
||||||
CE95865C112C516400F95FD2 /* StatsLabel.h */,
|
CE95865C112C516400F95FD2 /* StatsLabel.h */,
|
||||||
CE95865D112C516400F95FD2 /* StatsLabel.m */,
|
CE95865D112C516400F95FD2 /* StatsLabel.m */,
|
||||||
|
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */,
|
||||||
|
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */,
|
||||||
|
CE9EA7711122CA0B008CD2BC /* PyDirectoryOutline.h */,
|
||||||
|
CE0C2ABC1177014200BC749F /* PyProblemDialog.h */,
|
||||||
|
CE958659112C516400F95FD2 /* PyStatsLabel.h */,
|
||||||
);
|
);
|
||||||
name = dgbase;
|
name = dgbase;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -359,6 +373,8 @@
|
|||||||
CE9EA7441122C96C008CD2BC /* HSGUIController.m */,
|
CE9EA7441122C96C008CD2BC /* HSGUIController.m */,
|
||||||
CE9EA7451122C96C008CD2BC /* HSOutline.h */,
|
CE9EA7451122C96C008CD2BC /* HSOutline.h */,
|
||||||
CE9EA7461122C96C008CD2BC /* HSOutline.m */,
|
CE9EA7461122C96C008CD2BC /* HSOutline.m */,
|
||||||
|
CE0C2AB41177011000BC749F /* HSTable.h */,
|
||||||
|
CE0C2AB51177011000BC749F /* HSTable.m */,
|
||||||
CE9EA7471122C96C008CD2BC /* HSWindowController.h */,
|
CE9EA7471122C96C008CD2BC /* HSWindowController.h */,
|
||||||
CE9EA7481122C96C008CD2BC /* HSWindowController.m */,
|
CE9EA7481122C96C008CD2BC /* HSWindowController.m */,
|
||||||
);
|
);
|
||||||
@@ -371,6 +387,7 @@
|
|||||||
children = (
|
children = (
|
||||||
CE9EA74C1122C96C008CD2BC /* PyGUI.h */,
|
CE9EA74C1122C96C008CD2BC /* PyGUI.h */,
|
||||||
CE9EA74D1122C96C008CD2BC /* PyOutline.h */,
|
CE9EA74D1122C96C008CD2BC /* PyOutline.h */,
|
||||||
|
CE0C2AAA117700E700BC749F /* PyTable.h */,
|
||||||
);
|
);
|
||||||
name = proxies;
|
name = proxies;
|
||||||
path = ../../cocoalib/proxies;
|
path = ../../cocoalib/proxies;
|
||||||
@@ -470,6 +487,7 @@
|
|||||||
CE7AC9181119911200D02F6C /* ErrorReportWindow.xib in Resources */,
|
CE7AC9181119911200D02F6C /* ErrorReportWindow.xib in Resources */,
|
||||||
CE7AC9191119911200D02F6C /* progress.xib in Resources */,
|
CE7AC9191119911200D02F6C /* progress.xib in Resources */,
|
||||||
CE7AC91A1119911200D02F6C /* registration.xib in Resources */,
|
CE7AC91A1119911200D02F6C /* registration.xib in Resources */,
|
||||||
|
CE0C2AC81177021600BC749F /* ProblemDialog.xib in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -509,6 +527,8 @@
|
|||||||
CE9EA7721122CA0B008CD2BC /* DirectoryOutline.m in Sources */,
|
CE9EA7721122CA0B008CD2BC /* DirectoryOutline.m in Sources */,
|
||||||
CE95865E112C516400F95FD2 /* ResultOutline.m in Sources */,
|
CE95865E112C516400F95FD2 /* ResultOutline.m in Sources */,
|
||||||
CE95865F112C516400F95FD2 /* StatsLabel.m in Sources */,
|
CE95865F112C516400F95FD2 /* StatsLabel.m in Sources */,
|
||||||
|
CE0C2AB61177011000BC749F /* HSTable.m in Sources */,
|
||||||
|
CE0C2ABD1177014200BC749F /* ProblemDialog.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>hsft</string>
|
<string>hsft</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2.9.2</string>
|
<string>2.10.1</string>
|
||||||
<key>NSMainNibFile</key>
|
<key>NSMainNibFile</key>
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
from hsutil.cocoa import signature
|
from hscommon.cocoa import signature
|
||||||
|
|
||||||
from core import scanner
|
from core import scanner
|
||||||
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
CE3A46FA109B212E002ABFD5 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE3A46F9109B212E002ABFD5 /* MainMenu.xib */; };
|
CE3A46FA109B212E002ABFD5 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE3A46F9109B212E002ABFD5 /* MainMenu.xib */; };
|
||||||
CE45579B0AE3BC2B005A9546 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE45579A0AE3BC2B005A9546 /* Sparkle.framework */; };
|
CE45579B0AE3BC2B005A9546 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE45579A0AE3BC2B005A9546 /* Sparkle.framework */; };
|
||||||
CE4557B40AE3BC50005A9546 /* Sparkle.framework in CopyFiles */ = {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 */; };
|
CE6E0DFE1054E9EF008D9390 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = CE6E0DFD1054E9EF008D9390 /* dsa_pub.pem */; };
|
||||||
CE76FDC4111EE37C006618EA /* HSOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDBF111EE37C006618EA /* HSOutlineView.m */; };
|
CE76FDC4111EE37C006618EA /* HSOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDBF111EE37C006618EA /* HSOutlineView.m */; };
|
||||||
CE76FDC5111EE37C006618EA /* NSIndexPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDC1111EE37C006618EA /* NSIndexPathAdditions.m */; };
|
CE76FDC5111EE37C006618EA /* NSIndexPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDC1111EE37C006618EA /* NSIndexPathAdditions.m */; };
|
||||||
@@ -27,6 +29,7 @@
|
|||||||
CE76FDD4111EE3A7006618EA /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDD2111EE3A7006618EA /* DirectoryOutline.m */; };
|
CE76FDD4111EE3A7006618EA /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDD2111EE3A7006618EA /* DirectoryOutline.m */; };
|
||||||
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDDE111EE42F006618EA /* HSOutline.m */; };
|
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDDE111EE42F006618EA /* HSOutline.m */; };
|
||||||
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDF6111EE561006618EA /* NSEventAdditions.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 */; };
|
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F212113BC22D0010360B /* ResultOutline.m */; };
|
||||||
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F214113BC22D0010360B /* StatsLabel.m */; };
|
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F214113BC22D0010360B /* StatsLabel.m */; };
|
||||||
CEAC6811109B0B7E00B43C85 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEAC6810109B0B7E00B43C85 /* Preferences.xib */; };
|
CEAC6811109B0B7E00B43C85 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEAC6810109B0B7E00B43C85 /* Preferences.xib */; };
|
||||||
@@ -83,6 +86,10 @@
|
|||||||
CE381CF509915304003581CE /* dg_cocoa.plugin */ = {isa = PBXFileReference; lastKnownFileType = folder; path = dg_cocoa.plugin; sourceTree = SOURCE_ROOT; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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; };
|
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>"; };
|
CE76FDBE111EE37C006618EA /* HSOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutlineView.h; sourceTree = "<group>"; };
|
||||||
@@ -102,6 +109,8 @@
|
|||||||
CE76FDDE111EE42F006618EA /* HSOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutline.m; sourceTree = "<group>"; };
|
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; };
|
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; };
|
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; };
|
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; };
|
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; };
|
CE91F211113BC22D0010360B /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -271,6 +280,7 @@
|
|||||||
CE76FDDE111EE42F006618EA /* HSOutline.m */,
|
CE76FDDE111EE42F006618EA /* HSOutline.m */,
|
||||||
CE76FDC8111EE38E006618EA /* HSGUIController.h */,
|
CE76FDC8111EE38E006618EA /* HSGUIController.h */,
|
||||||
CE76FDC9111EE38E006618EA /* HSGUIController.m */,
|
CE76FDC9111EE38E006618EA /* HSGUIController.m */,
|
||||||
|
CE8C53BB117324CE0011B41F /* HSTable.m */,
|
||||||
);
|
);
|
||||||
name = controllers;
|
name = controllers;
|
||||||
path = ../../cocoalib/controllers;
|
path = ../../cocoalib/controllers;
|
||||||
@@ -281,6 +291,7 @@
|
|||||||
children = (
|
children = (
|
||||||
CE76FDCD111EE38E006618EA /* PyGUI.h */,
|
CE76FDCD111EE38E006618EA /* PyGUI.h */,
|
||||||
CE76FDCE111EE38E006618EA /* PyOutline.h */,
|
CE76FDCE111EE38E006618EA /* PyOutline.h */,
|
||||||
|
CE8C53B61173248F0011B41F /* PyTable.h */,
|
||||||
);
|
);
|
||||||
name = proxies;
|
name = proxies;
|
||||||
path = ../../cocoalib/proxies;
|
path = ../../cocoalib/proxies;
|
||||||
@@ -299,6 +310,7 @@
|
|||||||
CEEFC0CA10943849001F3A39 /* xib */ = {
|
CEEFC0CA10943849001F3A39 /* xib */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE647E581173026F006D28BA /* ProblemDialog.xib */,
|
||||||
CE3A46F9109B212E002ABFD5 /* MainMenu.xib */,
|
CE3A46F9109B212E002ABFD5 /* MainMenu.xib */,
|
||||||
CEAC6810109B0B7E00B43C85 /* Preferences.xib */,
|
CEAC6810109B0B7E00B43C85 /* Preferences.xib */,
|
||||||
CEEFC0F710945D9F001F3A39 /* DirectoryPanel.xib */,
|
CEEFC0F710945D9F001F3A39 /* DirectoryPanel.xib */,
|
||||||
@@ -370,6 +382,9 @@
|
|||||||
CE6E7407111C997500C350E3 /* PyDetailsPanel.h */,
|
CE6E7407111C997500C350E3 /* PyDetailsPanel.h */,
|
||||||
CEFC7FB70FC951A700CD5728 /* ResultWindow.h */,
|
CEFC7FB70FC951A700CD5728 /* ResultWindow.h */,
|
||||||
CEFC7FB80FC951A700CD5728 /* ResultWindow.m */,
|
CEFC7FB80FC951A700CD5728 /* ResultWindow.m */,
|
||||||
|
CE647E541173024A006D28BA /* ProblemDialog.h */,
|
||||||
|
CE647E551173024A006D28BA /* ProblemDialog.m */,
|
||||||
|
CE647E561173024A006D28BA /* PyProblemDialog.h */,
|
||||||
);
|
);
|
||||||
name = dgbase;
|
name = dgbase;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -435,6 +450,7 @@
|
|||||||
CE19BC6311199231007CCEB0 /* ErrorReportWindow.xib in Resources */,
|
CE19BC6311199231007CCEB0 /* ErrorReportWindow.xib in Resources */,
|
||||||
CE19BC6411199231007CCEB0 /* progress.xib in Resources */,
|
CE19BC6411199231007CCEB0 /* progress.xib in Resources */,
|
||||||
CE19BC6511199231007CCEB0 /* registration.xib in Resources */,
|
CE19BC6511199231007CCEB0 /* registration.xib in Resources */,
|
||||||
|
CE647E591173026F006D28BA /* ProblemDialog.xib in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -470,6 +486,8 @@
|
|||||||
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */,
|
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */,
|
||||||
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */,
|
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */,
|
||||||
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */,
|
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */,
|
||||||
|
CE647E571173024A006D28BA /* ProblemDialog.m in Sources */,
|
||||||
|
CE8C53BC117324CE0011B41F /* HSTable.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
78
core/app.py
78
core/app.py
@@ -11,13 +11,15 @@ from __future__ import unicode_literals
|
|||||||
import os
|
import os
|
||||||
import os.path as op
|
import os.path as op
|
||||||
import logging
|
import logging
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
|
||||||
from send2trash import send2trash
|
from send2trash import send2trash
|
||||||
|
from hscommon.reg import RegistrableApplication, RegistrationRequired
|
||||||
|
from hscommon.notify import Broadcaster
|
||||||
from hsutil import io, files
|
from hsutil import io, files
|
||||||
from hsutil.path import Path
|
from hsutil.path import Path
|
||||||
from hsutil.reg import RegistrableApplication, RegistrationRequired
|
|
||||||
from hsutil.misc import flatten, first
|
from hsutil.misc import flatten, first
|
||||||
from hsutil.notify import Broadcaster
|
|
||||||
from hsutil.str import escape
|
from hsutil.str import escape
|
||||||
|
|
||||||
from . import directories, results, scanner, export, fs
|
from . import directories, results, scanner, export, fs
|
||||||
@@ -48,7 +50,6 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
self.results = results.Results(data_module)
|
self.results = results.Results(data_module)
|
||||||
self.scanner = scanner.Scanner()
|
self.scanner = scanner.Scanner()
|
||||||
self.action_count = 0
|
self.action_count = 0
|
||||||
self.last_op_error_count = 0
|
|
||||||
self.options = {
|
self.options = {
|
||||||
'escape_filter_regexp': True,
|
'escape_filter_regexp': True,
|
||||||
'clean_empty_dirs': False,
|
'clean_empty_dirs': False,
|
||||||
@@ -70,19 +71,13 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
return self._do_delete_dupe(dupe)
|
return self._do_delete_dupe(dupe)
|
||||||
|
|
||||||
j.start_job(self.results.mark_count)
|
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):
|
def _do_delete_dupe(self, dupe):
|
||||||
if not io.exists(dupe.path):
|
if not io.exists(dupe.path):
|
||||||
return True
|
return
|
||||||
try:
|
send2trash(unicode(dupe.path)) # Raises OSError when there's a problem
|
||||||
send2trash(unicode(dupe.path))
|
|
||||||
except OSError as e:
|
|
||||||
msg = "Could not send {0} to trash: {1}"
|
|
||||||
logging.warning(msg.format(unicode(dupe.path), unicode(e)))
|
|
||||||
return False
|
|
||||||
self.clean_empty_dirs(dupe.path[:-1])
|
self.clean_empty_dirs(dupe.path[:-1])
|
||||||
return True
|
|
||||||
|
|
||||||
def _do_load(self, j):
|
def _do_load(self, j):
|
||||||
self.directories.load_from_file(op.join(self.appdata, 'last_directories.xml'))
|
self.directories.load_from_file(op.join(self.appdata, 'last_directories.xml'))
|
||||||
@@ -93,7 +88,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
try:
|
try:
|
||||||
for file in j.iter_with_progress(files, 'Reading metadata %d/%d'):
|
for file in j.iter_with_progress(files, 'Reading metadata %d/%d'):
|
||||||
file._read_all_info(attrnames=self.data.METADATA_TO_READ)
|
file._read_all_info(attrnames=self.data.METADATA_TO_READ)
|
||||||
except OSError:
|
except (OSError, IOError):
|
||||||
# If this error is raised, it means that a file was deleted while we were reading
|
# If this error is raised, it means that a file was deleted while we were reading
|
||||||
# metadata. Proper handling of this rare occurrence is complex because there's no easy
|
# metadata. Proper handling of this rare occurrence is complex because there's no easy
|
||||||
# way to remove an arbitrary file from the Results. Thus, we simply clear them.
|
# way to remove an arbitrary file from the Results. Thus, we simply clear them.
|
||||||
@@ -114,8 +109,11 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
|
|
||||||
def _job_completed(self, jobid):
|
def _job_completed(self, jobid):
|
||||||
# Must be called by subclasses when they detect that an async job is completed.
|
# 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')
|
self.notify('results_changed')
|
||||||
|
elif jobid in (JOB_LOAD, JOB_MOVE, JOB_DELETE):
|
||||||
|
self.notify('results_changed')
|
||||||
|
self.notify('problems_changed')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _open_path(path):
|
def _open_path(path):
|
||||||
@@ -182,28 +180,23 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
dest_path = dest_path + source_path[1:-1] #Remove drive letter and filename
|
dest_path = dest_path + source_path[1:-1] #Remove drive letter and filename
|
||||||
elif dest_type == 1:
|
elif dest_type == 1:
|
||||||
dest_path = dest_path + source_path[location_path:-1]
|
dest_path = dest_path + source_path[location_path:-1]
|
||||||
try:
|
if not io.exists(dest_path):
|
||||||
if not io.exists(dest_path):
|
io.makedirs(dest_path)
|
||||||
io.makedirs(dest_path)
|
# Raises an EnvironmentError if there's a problem
|
||||||
if copy:
|
if copy:
|
||||||
files.copy(source_path, dest_path)
|
files.copy(source_path, dest_path)
|
||||||
else:
|
else:
|
||||||
files.move(source_path, dest_path)
|
files.move(source_path, dest_path)
|
||||||
self.clean_empty_dirs(source_path[:-1])
|
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 copy_or_move_marked(self, copy, destination, recreate_path):
|
||||||
def do(j):
|
def do(j):
|
||||||
def op(dupe):
|
def op(dupe):
|
||||||
j.add_progress()
|
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)
|
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()
|
self._demo_check()
|
||||||
jobid = JOB_COPY if copy else JOB_MOVE
|
jobid = JOB_COPY if copy else JOB_MOVE
|
||||||
@@ -227,6 +220,31 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
rows.append(row)
|
rows.append(row)
|
||||||
return export.export_to_xhtml(colnames, rows)
|
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', unicode(dupe.path))
|
||||||
|
cmd = cmd.replace('%r', unicode(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):
|
def load(self):
|
||||||
self._start_job(JOB_LOAD, self._do_load)
|
self._start_job(JOB_LOAD, self._do_load)
|
||||||
self.load_ignore_list()
|
self.load_ignore_list()
|
||||||
@@ -283,7 +301,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
self.notify('results_changed_but_keep_selection')
|
self.notify('results_changed_but_keep_selection')
|
||||||
|
|
||||||
def remove_marked(self):
|
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')
|
self.notify('results_changed')
|
||||||
|
|
||||||
def remove_selected(self):
|
def remove_selected(self):
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
import logging
|
import logging
|
||||||
import os.path as op
|
import os.path as op
|
||||||
|
|
||||||
from hsutil import cocoa, job
|
from hscommon import cocoa, job
|
||||||
from hsutil.cocoa import install_exception_hook
|
from hscommon.cocoa import install_exception_hook
|
||||||
from hsutil.cocoa.objcmin import (NSNotificationCenter, NSUserDefaults,
|
from hscommon.cocoa.objcmin import (NSNotificationCenter, NSUserDefaults,
|
||||||
NSSearchPathForDirectoriesInDomains, NSApplicationSupportDirectory, NSUserDomainMask,
|
NSSearchPathForDirectoriesInDomains, NSApplicationSupportDirectory, NSUserDomainMask,
|
||||||
NSWorkspace)
|
NSWorkspace)
|
||||||
from hsutil.reg import RegistrationRequired
|
from hscommon.reg import RegistrationRequired
|
||||||
|
|
||||||
from . import app
|
from . import app
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,12 @@
|
|||||||
|
|
||||||
# Common interface for all editions' dg_cocoa unit.
|
# 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.details_panel import DetailsPanel
|
||||||
from .gui.directory_tree import DirectoryTree
|
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.result_tree import ResultTree
|
||||||
from .gui.stats_label import StatsLabel
|
from .gui.stats_label import StatsLabel
|
||||||
|
|
||||||
@@ -93,6 +95,9 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
def revealSelected(self):
|
def revealSelected(self):
|
||||||
self.py.reveal_selected()
|
self.py.reveal_selected()
|
||||||
|
|
||||||
|
def invokeCommand_(self, cmd):
|
||||||
|
self.py.invoke_command(cmd)
|
||||||
|
|
||||||
#---Information
|
#---Information
|
||||||
def getIgnoreListCount(self):
|
def getIgnoreListCount(self):
|
||||||
return len(self.py.scanner.ignore_list)
|
return len(self.py.scanner.ignore_list)
|
||||||
@@ -100,8 +105,9 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
def getMarkCount(self):
|
def getMarkCount(self):
|
||||||
return self.py.results.mark_count
|
return self.py.results.mark_count
|
||||||
|
|
||||||
def getOperationalErrorCount(self):
|
@signature('i@:')
|
||||||
return self.py.last_op_error_count
|
def scanWasProblematic(self):
|
||||||
|
return bool(self.py.results.problems)
|
||||||
|
|
||||||
#---Properties
|
#---Properties
|
||||||
def setMixFileKind_(self, mix_file_kind):
|
def setMixFileKind_(self, mix_file_kind):
|
||||||
@@ -196,3 +202,13 @@ class PyStatsLabel(PyGUIObject):
|
|||||||
def display(self):
|
def display(self):
|
||||||
return self.py.display
|
return self.py.display
|
||||||
|
|
||||||
|
|
||||||
|
class PyProblemDialog(PyGUIObject):
|
||||||
|
py_class = ProblemDialog
|
||||||
|
|
||||||
|
def revealSelected(self):
|
||||||
|
self.py.reveal_selected_dupe()
|
||||||
|
|
||||||
|
|
||||||
|
class PyProblemTable(PyTable):
|
||||||
|
py_class = ProblemTable
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from unicodedata import normalize
|
|||||||
|
|
||||||
from hsutil.misc import flatten
|
from hsutil.misc import flatten
|
||||||
from hsutil.str import multi_replace
|
from hsutil.str import multi_replace
|
||||||
from hsutil import job
|
from hscommon import job
|
||||||
|
|
||||||
(WEIGHT_WORDS,
|
(WEIGHT_WORDS,
|
||||||
MATCH_SIMILAR_WORDS,
|
MATCH_SIMILAR_WORDS,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
from hsutil.notify import Listener
|
from hscommon.notify import Listener
|
||||||
|
|
||||||
class GUIObject(Listener):
|
class GUIObject(Listener):
|
||||||
def __init__(self, view, app):
|
def __init__(self, view, app):
|
||||||
@@ -24,6 +24,9 @@ class GUIObject(Listener):
|
|||||||
def marking_changed(self):
|
def marking_changed(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def problems_changed(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def results_changed(self):
|
def results_changed(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
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 = unicode(dupe.path)
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ import re
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from . import engine
|
from . import engine
|
||||||
from hsutil.job import nulljob
|
from hscommon.job import nulljob
|
||||||
from hsutil.markable import Markable
|
from hscommon.markable import Markable
|
||||||
from hsutil.misc import flatten, nonone
|
from hsutil.misc import flatten, nonone
|
||||||
from hsutil.str import format_size
|
from hsutil.str import format_size
|
||||||
from hsutil.files import FileOrPath
|
from hsutil.files import FileOrPath
|
||||||
@@ -32,6 +32,7 @@ class Results(Markable):
|
|||||||
self.__recalculate_stats()
|
self.__recalculate_stats()
|
||||||
self.__marked_size = 0
|
self.__marked_size = 0
|
||||||
self.data = data_module
|
self.data = data_module
|
||||||
|
self.problems = [] # (dupe, error_msg)
|
||||||
|
|
||||||
def _did_mark(self, dupe):
|
def _did_mark(self, dupe):
|
||||||
self.__marked_size += dupe.size
|
self.__marked_size += dupe.size
|
||||||
@@ -146,7 +147,7 @@ class Results(Markable):
|
|||||||
self.__filters.append(filter_str)
|
self.__filters.append(filter_str)
|
||||||
if self.__filtered_dupes is None:
|
if self.__filtered_dupes is None:
|
||||||
self.__filtered_dupes = flatten(g[:] for g in self.groups)
|
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(unicode(dupe.path)))
|
||||||
filtered_groups = set()
|
filtered_groups = set()
|
||||||
for dupe in self.__filtered_dupes:
|
for dupe in self.__filtered_dupes:
|
||||||
filtered_groups.add(self.get_group_of_duplicate(dupe))
|
filtered_groups.add(self.get_group_of_duplicate(dupe))
|
||||||
@@ -230,17 +231,22 @@ class Results(Markable):
|
|||||||
self.__dupes = None
|
self.__dupes = None
|
||||||
|
|
||||||
def perform_on_marked(self, func, remove_from_results):
|
def perform_on_marked(self, func, remove_from_results):
|
||||||
problems = []
|
# Performs `func` on all marked dupes. If an EnvironmentError is raised during the call,
|
||||||
for d in self.dupes:
|
# the problematic dupe is added to self.problems.
|
||||||
if self.is_marked(d) and (not func(d)):
|
self.problems = []
|
||||||
problems.append(d)
|
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, unicode(e)))
|
||||||
if remove_from_results:
|
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.remove_duplicates(to_remove)
|
||||||
self.mark_none()
|
self.mark_none()
|
||||||
for d in problems:
|
for dupe, _ in self.problems:
|
||||||
self.mark(d)
|
self.mark(dupe)
|
||||||
return len(problems)
|
|
||||||
|
|
||||||
def remove_duplicates(self, dupes):
|
def remove_duplicates(self, dupes):
|
||||||
'''Remove 'dupes' from their respective group, and remove the group is it ends up empty.
|
'''Remove 'dupes' from their respective group, and remove the group is it ends up empty.
|
||||||
@@ -278,9 +284,12 @@ class Results(Markable):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
words = ()
|
words = ()
|
||||||
file_elem = etree.SubElement(group_elem, 'file')
|
file_elem = etree.SubElement(group_elem, 'file')
|
||||||
file_elem.set('path', unicode(d.path))
|
try:
|
||||||
|
file_elem.set('path', unicode(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('is_ref', ('y' if d.is_ref else 'n'))
|
||||||
file_elem.set('words', ','.join(words))
|
|
||||||
file_elem.set('marked', ('y' if self.is_marked(d) else 'n'))
|
file_elem.set('marked', ('y' if self.is_marked(d) else 'n'))
|
||||||
for match in g.matches:
|
for match in g.matches:
|
||||||
match_elem = etree.SubElement(group_elem, 'match')
|
match_elem = etree.SubElement(group_elem, 'match')
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
from hsutil import job, io
|
from hscommon import job
|
||||||
|
from hsutil import io
|
||||||
from hsutil.misc import dedupe
|
from hsutil.misc import dedupe
|
||||||
from hsutil.str import get_file_ext, rem_file_ext
|
from hsutil.str import get_file_ext, rem_file_ext
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,13 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from nose.tools import eq_
|
from hsutil.testutil import eq_
|
||||||
|
|
||||||
from hsutil.testcase import TestCase
|
from hsutil.testcase import TestCase
|
||||||
from hsutil import io
|
from hsutil import io
|
||||||
from hsutil.path import Path
|
from hsutil.path import Path
|
||||||
from hsutil.decorators import log_calls
|
from hsutil.decorators import log_calls
|
||||||
import hsutil.files
|
import hsutil.files
|
||||||
from hsutil.job import nulljob
|
from hscommon.job import nulljob
|
||||||
|
|
||||||
from . import data
|
from . import data
|
||||||
from .results_test import GetTestGroups
|
from .results_test import GetTestGroups
|
||||||
|
|||||||
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 os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from nose.tools import eq_
|
|
||||||
|
|
||||||
from hsutil import io
|
from hsutil import io
|
||||||
from hsutil.path import Path
|
from hsutil.path import Path
|
||||||
|
from hsutil.testutil import eq_
|
||||||
from hsutil.testcase import TestCase
|
from hsutil.testcase import TestCase
|
||||||
|
|
||||||
from ..directories import *
|
from ..directories import *
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from nose.tools import eq_
|
from hscommon import job
|
||||||
|
|
||||||
from hsutil import job
|
|
||||||
from hsutil.decorators import log_calls
|
from hsutil.decorators import log_calls
|
||||||
|
from hsutil.misc import first
|
||||||
|
from hsutil.testutil import eq_
|
||||||
from hsutil.testcase import TestCase
|
from hsutil.testcase import TestCase
|
||||||
|
|
||||||
from .. import engine, fs
|
from .. import engine
|
||||||
from ..engine import *
|
from ..engine import *
|
||||||
|
|
||||||
class NamedObject(object):
|
class NamedObject(object):
|
||||||
@@ -46,6 +46,15 @@ def get_test_group():
|
|||||||
result.add_match(m3)
|
result.add_match(m3)
|
||||||
return result
|
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):
|
class TCgetwords(TestCase):
|
||||||
def test_spaces(self):
|
def test_spaces(self):
|
||||||
self.assertEqual(['a', 'b', 'c', 'd'], getwords("a b c d"))
|
self.assertEqual(['a', 'b', 'c', 'd'], getwords("a b c d"))
|
||||||
@@ -351,23 +360,18 @@ class GetMatches(TestCase):
|
|||||||
l = [NamedObject("foo bar"),NamedObject("bar bleh"),NamedObject("a b c foo")]
|
l = [NamedObject("foo bar"),NamedObject("bar bleh"),NamedObject("a b c foo")]
|
||||||
r = getmatches(l)
|
r = getmatches(l)
|
||||||
self.assertEqual(2,len(r))
|
self.assertEqual(2,len(r))
|
||||||
seek = [m for m in r if m.percentage == 50] #"foo bar" and "bar bleh"
|
m = first(m for m in r if m.percentage == 50) #"foo bar" and "bar bleh"
|
||||||
m = seek[0]
|
assert_match(m, 'foo bar', 'bar bleh')
|
||||||
self.assertEqual(['foo','bar'],m.first.words)
|
m = first(m for m in r if m.percentage == 33) #"foo bar" and "a b c foo"
|
||||||
self.assertEqual(['bar','bleh'],m.second.words)
|
assert_match(m, 'foo bar', 'a b c foo')
|
||||||
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)
|
|
||||||
|
|
||||||
def test_null_and_unrelated_objects(self):
|
def test_null_and_unrelated_objects(self):
|
||||||
l = [NamedObject("foo bar"),NamedObject("bar bleh"),NamedObject(""),NamedObject("unrelated object")]
|
l = [NamedObject("foo bar"),NamedObject("bar bleh"),NamedObject(""),NamedObject("unrelated object")]
|
||||||
r = getmatches(l)
|
r = getmatches(l)
|
||||||
self.assertEqual(1,len(r))
|
eq_(len(r), 1)
|
||||||
m = r[0]
|
m = r[0]
|
||||||
self.assertEqual(50,m.percentage)
|
eq_(m.percentage, 50)
|
||||||
self.assertEqual(['foo','bar'],m.first.words)
|
assert_match(m, 'foo bar', 'bar bleh')
|
||||||
self.assertEqual(['bar','bleh'],m.second.words)
|
|
||||||
|
|
||||||
def test_twice_the_same_word(self):
|
def test_twice_the_same_word(self):
|
||||||
l = [NamedObject("foo foo bar"),NamedObject("bar bleh")]
|
l = [NamedObject("foo foo bar"),NamedObject("bar bleh")]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
import cStringIO
|
import cStringIO
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from nose.tools import eq_
|
from hsutil.testutil import eq_
|
||||||
|
|
||||||
from ..ignore import *
|
from ..ignore import *
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,11 @@
|
|||||||
|
|
||||||
import StringIO
|
import StringIO
|
||||||
import os.path as op
|
import os.path as op
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from hsutil.path import Path
|
from hsutil.path import Path
|
||||||
|
from hsutil.testutil import eq_
|
||||||
from hsutil.testcase import TestCase
|
from hsutil.testcase import TestCase
|
||||||
from hsutil.misc import first
|
from hsutil.misc import first
|
||||||
|
|
||||||
@@ -252,18 +254,23 @@ class TCResultsMarkings(TestCase):
|
|||||||
def test_perform_on_marked_with_problems(self):
|
def test_perform_on_marked_with_problems(self):
|
||||||
def log_object(o):
|
def log_object(o):
|
||||||
log.append(o)
|
log.append(o)
|
||||||
return o is not self.objects[1]
|
if o is self.objects[1]:
|
||||||
|
raise EnvironmentError('foobar')
|
||||||
|
|
||||||
log = []
|
log = []
|
||||||
self.results.mark_all()
|
self.results.mark_all()
|
||||||
self.assert_(self.results.is_marked(self.objects[1]))
|
assert self.results.is_marked(self.objects[1])
|
||||||
self.assertEqual(1,self.results.perform_on_marked(log_object, True))
|
self.results.perform_on_marked(log_object, True)
|
||||||
self.assertEqual(3,len(log))
|
eq_(len(log), 3)
|
||||||
self.assertEqual(1,len(self.results.groups))
|
eq_(len(self.results.groups), 1)
|
||||||
self.assertEqual(2,len(self.results.groups[0]))
|
eq_(len(self.results.groups[0]), 2)
|
||||||
self.assert_(self.objects[1] in self.results.groups[0])
|
assert self.objects[1] in self.results.groups[0]
|
||||||
self.assert_(not self.results.is_marked(self.objects[2]))
|
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])
|
||||||
|
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 test_perform_on_marked_with_ref(self):
|
||||||
def log_object(o):
|
def log_object(o):
|
||||||
@@ -563,6 +570,16 @@ class TCResultsXML(TestCase):
|
|||||||
self.results.load_from_xml(f, self.get_file)
|
self.results.load_from_xml(f, self.get_file)
|
||||||
first(self.results.groups[0].matches).percentage
|
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(u'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 = u'foo\x19'
|
||||||
|
self.results.save_to_xml(StringIO.StringIO()) # don't crash
|
||||||
|
|
||||||
|
|
||||||
class TCResultsFilter(TestCase):
|
class TCResultsFilter(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
@@ -6,10 +6,11 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/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.path import Path
|
||||||
|
from hsutil.testutil import eq_
|
||||||
from hsutil.testcase import TestCase
|
from hsutil.testcase import TestCase
|
||||||
|
|
||||||
from .. import fs
|
from .. import fs
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import logging
|
|||||||
from appscript import app, k, CommandError
|
from appscript import app, k, CommandError
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from hsutil.cocoa import as_fetch
|
from hscommon.cocoa import as_fetch
|
||||||
|
|
||||||
from core.app_cocoa import JOBID2TITLE, DupeGuru as DupeGuruBase
|
from core.app_cocoa import JOBID2TITLE, DupeGuru as DupeGuruBase
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/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 hsutil.str import get_file_ext
|
||||||
from core import fs
|
from core import fs
|
||||||
|
|
||||||
|
|||||||
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,9 +7,7 @@
|
|||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
import os.path as op
|
import os.path as op
|
||||||
import logging
|
|
||||||
import plistlib
|
import plistlib
|
||||||
import re
|
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from appscript import app, k, CommandError
|
from appscript import app, k, CommandError
|
||||||
@@ -17,8 +15,8 @@ from appscript import app, k, CommandError
|
|||||||
from hsutil import io
|
from hsutil import io
|
||||||
from hsutil.str import get_file_ext
|
from hsutil.str import get_file_ext
|
||||||
from hsutil.path import Path
|
from hsutil.path import Path
|
||||||
from hsutil.cocoa import as_fetch
|
from hscommon.cocoa import as_fetch
|
||||||
from hsutil.cocoa.objcmin import NSUserDefaults, NSURL
|
from hscommon.cocoa.objcmin import NSUserDefaults, NSURL
|
||||||
|
|
||||||
from core import fs
|
from core import fs
|
||||||
from core import app_cocoa, directories
|
from core import app_cocoa, directories
|
||||||
@@ -148,7 +146,7 @@ class DupeGuruPE(app_cocoa.DupeGuru):
|
|||||||
except (CommandError, RuntimeError):
|
except (CommandError, RuntimeError):
|
||||||
pass
|
pass
|
||||||
j.start_job(self.results.mark_count, "Sending dupes to the Trash")
|
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
|
del self.path2iphoto
|
||||||
|
|
||||||
def _do_delete_dupe(self, dupe):
|
def _do_delete_dupe(self, dupe):
|
||||||
@@ -158,14 +156,13 @@ class DupeGuruPE(app_cocoa.DupeGuru):
|
|||||||
try:
|
try:
|
||||||
a = app('iPhoto')
|
a = app('iPhoto')
|
||||||
a.remove(photo, timeout=0)
|
a.remove(photo, timeout=0)
|
||||||
return True
|
except (CommandError, RuntimeError) as e:
|
||||||
except (CommandError, RuntimeError):
|
raise EnvironmentError(unicode(e))
|
||||||
return False
|
|
||||||
else:
|
else:
|
||||||
logging.warning(u"Could not find photo %s in iPhoto Library", unicode(dupe.path))
|
msg = u"Could not find photo %s in iPhoto Library" % unicode(dupe.path)
|
||||||
return False
|
raise EnvironmentError(msg)
|
||||||
else:
|
else:
|
||||||
return app_cocoa.DupeGuru._do_delete_dupe(self, dupe)
|
app_cocoa.DupeGuru._do_delete_dupe(self, dupe)
|
||||||
|
|
||||||
def _do_load(self, j):
|
def _do_load(self, j):
|
||||||
self.directories.load_from_file(op.join(self.appdata, 'last_directories.xml'))
|
self.directories.load_from_file(op.join(self.appdata, 'last_directories.xml'))
|
||||||
|
|||||||
@@ -8,11 +8,9 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
from Queue import Empty
|
from collections import defaultdict, deque
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
from hsutil import job
|
from hscommon import job
|
||||||
from hsutil.misc import dedupe
|
|
||||||
|
|
||||||
from core.engine import Match
|
from core.engine import Match
|
||||||
from .block import avgdiff, DifferentBlockCountError, NoBlocksError
|
from .block import avgdiff, DifferentBlockCountError, NoBlocksError
|
||||||
@@ -42,7 +40,7 @@ def prepare_pictures(pictures, cache_path, j=job.nulljob):
|
|||||||
blocks = picture.get_blocks(BLOCK_COUNT_PER_SIDE)
|
blocks = picture.get_blocks(BLOCK_COUNT_PER_SIDE)
|
||||||
cache[picture.unicode_path] = blocks
|
cache[picture.unicode_path] = blocks
|
||||||
prepared.append(picture)
|
prepared.append(picture)
|
||||||
except IOError as e:
|
except (IOError, ValueError) as e:
|
||||||
logging.warning(unicode(e))
|
logging.warning(unicode(e))
|
||||||
except MemoryError:
|
except MemoryError:
|
||||||
logging.warning(u'Ran out of memory while reading %s of size %d' % (picture.unicode_path, picture.size))
|
logging.warning(u'Ran out of memory while reading %s of size %d' % (picture.unicode_path, picture.size))
|
||||||
@@ -76,13 +74,6 @@ def async_compare(ref_id, other_ids, dbname, threshold):
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
def getmatches(pictures, cache_path, threshold=75, match_scaled=False, j=job.nulljob):
|
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])
|
j = j.start_subjob([3, 7])
|
||||||
pictures = prepare_pictures(pictures, cache_path, j)
|
pictures = prepare_pictures(pictures, cache_path, j)
|
||||||
j = j.start_subjob([9, 1], 'Preparing for matching')
|
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()
|
cache.close()
|
||||||
pictures = [p for p in pictures if hasattr(p, 'cache_id')]
|
pictures = [p for p in pictures if hasattr(p, 'cache_id')]
|
||||||
pool = multiprocessing.Pool()
|
pool = multiprocessing.Pool()
|
||||||
async_results = []
|
async_results = deque()
|
||||||
matches = []
|
matches = []
|
||||||
pictures_copy = set(pictures)
|
pictures_copy = set(pictures)
|
||||||
for ref in j.iter_with_progress(pictures, 'Matched %d/%d pictures'):
|
for ref in j.iter_with_progress(pictures, 'Matched %d/%d pictures'):
|
||||||
@@ -118,8 +109,10 @@ def getmatches(pictures, cache_path, threshold=75, match_scaled=False, j=job.nul
|
|||||||
args = (ref.cache_id, cache_ids[:ARG_LIMIT], cache_path, threshold)
|
args = (ref.cache_id, cache_ids[:ARG_LIMIT], cache_path, threshold)
|
||||||
async_results.append(pool.apply_async(async_compare, args))
|
async_results.append(pool.apply_async(async_compare, args))
|
||||||
cache_ids = cache_ids[ARG_LIMIT:]
|
cache_ids = cache_ids[ARG_LIMIT:]
|
||||||
if len(async_results) > RESULTS_QUEUE_LIMIT:
|
# We use a while here because it's possible that more than one result has been added if
|
||||||
result = async_results.pop(0)
|
# ARG_LIMIT has been reached.
|
||||||
|
while len(async_results) > RESULTS_QUEUE_LIMIT:
|
||||||
|
result = async_results.popleft()
|
||||||
matches.extend(result.get())
|
matches.extend(result.get())
|
||||||
for result in async_results: # process the rest of the results
|
for result in async_results: # process the rest of the results
|
||||||
matches.extend(result.get())
|
matches.extend(result.get())
|
||||||
|
|||||||
@@ -158,6 +158,11 @@ static PyObject* block_osx_getblocks(PyObject *self, PyObject *args)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PySequence_Length(path) == 0) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "empty path");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
image_path = pystring2cfstring(path);
|
image_path = pystring2cfstring(path);
|
||||||
if (image_path == NULL) {
|
if (image_path == NULL) {
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
|
|||||||
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()
|
||||||
@@ -12,7 +12,7 @@ import logging
|
|||||||
|
|
||||||
from hsutil import io
|
from hsutil import io
|
||||||
from hsutil.path import Path
|
from hsutil.path import Path
|
||||||
from hsutil.cocoa.objcmin import NSWorkspace
|
from hscommon.cocoa.objcmin import NSWorkspace
|
||||||
|
|
||||||
from core import fs
|
from core import fs
|
||||||
from core.app_cocoa import DupeGuru as DupeGuruBase
|
from core.app_cocoa import DupeGuru as DupeGuruBase
|
||||||
|
|||||||
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
|
import hashlib
|
||||||
|
|
||||||
from nose.tools import eq_
|
|
||||||
|
|
||||||
from hsutil.testcase import TestCase
|
from hsutil.testcase import TestCase
|
||||||
|
from hsutil.testutil import eq_
|
||||||
from core.fs import File
|
from core.fs import File
|
||||||
from core.tests.directories_test import create_fake_fs
|
from core.tests.directories_test import create_fake_fs
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
Copyright 2010 Hardcoded Software Inc. (http://www.hardcoded.net)
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of Hardcoded Software Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
||||||
* If the source code has been published less than two years ago, any redistribution, in whole or in part, must retain full licensing functionality, without any attempt to change, obscure or in other ways circumvent its intent.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
|
- 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
|
- date: 2010-02-13
|
||||||
version: 5.7.2
|
version: 5.7.2
|
||||||
description: |
|
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 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**.
|
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.
|
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?
|
### 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.
|
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 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.
|
If all of this fail, [contact HS support](http://www.hardcoded.net/support), we'll figure it out.
|
||||||
</%text>
|
|
||||||
@@ -1,13 +1,5 @@
|
|||||||
<%!
|
|
||||||
title = 'Introduction to dupeGuru ME'
|
|
||||||
selected_menu_item = 'introduction'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
dupeGuru Music Edition is a tool to find duplicate files on your computer. It can scan either filenames or contents. The filename scan features a fuzzy matching algorithm that can find duplicate filenames even when they are not exactly the same.
|
dupeGuru Music Edition is a tool to find duplicate files on your computer. It can scan either filenames or contents. The filename scan features a fuzzy matching algorithm that can find duplicate filenames even when they are not exactly the same.
|
||||||
|
|
||||||
Although dupeGuru can easily be used without documentation, reading this file will help you to master it. If you are looking for guidance for your first duplicate scan, you can take a look at the [Quick Start](quick_start.htm) section.
|
Although dupeGuru can easily be used without documentation, reading this file will help you to master it. If you are looking for guidance for your first duplicate scan, you can take a look at the [Quick Start](quick_start.htm) section.
|
||||||
|
|
||||||
It is a good idea to keep dupeGuru updated. You can download the latest version on the [dupeGuru ME homepage](http://www.hardcoded.net/dupeguru_me/).
|
It is a good idea to keep dupeGuru updated. You can download the latest version on the [dupeGuru ME homepage](http://www.hardcoded.net/dupeguru_me/).
|
||||||
|
|
||||||
<%def name="meta()"><meta name="AppleTitle" content="dupeGuru ME Help"></meta></%def>
|
|
||||||
45
help_me/en/pages.yaml
Normal file
45
help_me/en/pages.yaml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
-
|
||||||
|
name: intro
|
||||||
|
title: Introduction to dupeGuru ME
|
||||||
|
menutitle: Introduction
|
||||||
|
menudesc: Introduction to dupeGuru
|
||||||
|
-
|
||||||
|
name: quick_start
|
||||||
|
title: Quick Start
|
||||||
|
menutitle: Quick Start
|
||||||
|
menudesc: Quickly get into the action
|
||||||
|
-
|
||||||
|
name: directories
|
||||||
|
title: Directories
|
||||||
|
menutitle: Directories
|
||||||
|
menudesc: Managing dupeGuru directories
|
||||||
|
-
|
||||||
|
name: preferences
|
||||||
|
title: Preferences
|
||||||
|
menutitle: Preferences
|
||||||
|
menudesc: Setting dupeGuru preferences
|
||||||
|
-
|
||||||
|
name: results
|
||||||
|
title: Results
|
||||||
|
menutitle: Results
|
||||||
|
menudesc: Time to delete these duplicates!
|
||||||
|
-
|
||||||
|
name: power_marker
|
||||||
|
title: Power Marker
|
||||||
|
menutitle: Power Marker
|
||||||
|
menudesc: Take control of your duplicates
|
||||||
|
-
|
||||||
|
name: faq
|
||||||
|
title: Frequently Asked Questions
|
||||||
|
menutitle: F.A.Q.
|
||||||
|
menudesc: Frequently Asked Questions
|
||||||
|
-
|
||||||
|
name: versions
|
||||||
|
title: Version History
|
||||||
|
menutitle: Version History
|
||||||
|
menudesc: Changes moneyGuru went through
|
||||||
|
-
|
||||||
|
name: credits
|
||||||
|
title: Credits
|
||||||
|
menutitle: Credits
|
||||||
|
menudesc: People who contributed to dupeGuru
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Power Marker'
|
|
||||||
selected_menu_item = 'Power Marker'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
You will probably not use the Power Marker feature very often, but if you get into a situation where you need it, you will be pretty happy that this feature exists.
|
You will probably not use the Power Marker feature very often, but if you get into a situation where you need it, you will be pretty happy that this feature exists.
|
||||||
|
|
||||||
What is it?
|
What is it?
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Preferences'
|
|
||||||
selected_menu_item = 'Preferences'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
**Scan Type:** This option determines what aspect of the files will be compared in the duplicate scan. The nature of the duplicate scan varies greatly depending on what you select for this option.
|
**Scan Type:** This option determines what aspect of the files will be compared in the duplicate scan. The nature of the duplicate scan varies greatly depending on what you select for this option.
|
||||||
|
|
||||||
* **Filename:** Every song will have its filename split into words, and then every word will be compared to compute a matching percentage. If this percentage is higher or equal to the **Filter Hardness** (see below for more details), dupeGuru will consider the 2 songs duplicates.
|
* **Filename:** Every song will have its filename split into words, and then every word will be compared to compute a matching percentage. If this percentage is higher or equal to the **Filter Hardness** (see below for more details), dupeGuru will consider the 2 songs duplicates.
|
||||||
@@ -34,3 +28,11 @@
|
|||||||
* **Recreate absolute path:** The source file's path will be re-created in the destination directory in it's entirety. For example, if you move "/Users/foobar/Music/Artist/Album/the_song.mp3" to the destination "/Users/foobar/MyDestination", the final destination for the file will be "/Users/foobar/MyDestination/Users/foobar/Music/Artist/Album".
|
* **Recreate absolute path:** The source file's path will be re-created in the destination directory in it's entirety. For example, if you move "/Users/foobar/Music/Artist/Album/the_song.mp3" to the destination "/Users/foobar/MyDestination", the final destination for the file will be "/Users/foobar/MyDestination/Users/foobar/Music/Artist/Album".
|
||||||
|
|
||||||
In all cases, dupeGuru nicely handles naming conflicts by prepending a number to the destination filename if the filename already exists in the destination.
|
In all cases, dupeGuru nicely handles naming conflicts by prepending a number to the destination filename if the filename already exists in the destination.
|
||||||
|
|
||||||
|
**Custom Command:** This preference determines the command that will be invoked by the "Invoke Custom Command" action. You can invoke any external application through this action. This can be useful if, for example, you have a nice diffing application installed.
|
||||||
|
|
||||||
|
The format of the command is the same as what you would write in the command line, except that there are 2 placeholders: **%d** and **%r**. These placeholders will be replaced by the path of the selected dupe (%d) and the path of the selected dupe's reference file (%r).
|
||||||
|
|
||||||
|
If the path to your executable contains space characters, you should enclose it in "" quotes. You should also enclose placeholders in quotes because it's very possible that paths to dupes and refs will contain spaces. Here's an example custom command:
|
||||||
|
|
||||||
|
"C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r"
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Quick Start'
|
|
||||||
selected_menu_item = 'Quick Start'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
To get you quickly started with dupeGuru, let's just make a standard scan using default preferences.
|
To get you quickly started with dupeGuru, let's just make a standard scan using default preferences.
|
||||||
|
|
||||||
* Click on **Directories**.
|
* Click on **Directories**.
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Results'
|
|
||||||
selected_menu_item = 'Results'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
When dupeGuru is finished scanning for duplicates, it will show its results in the form of duplicate group list.
|
When dupeGuru is finished scanning for duplicates, it will show its results in the form of duplicate group list.
|
||||||
|
|
||||||
About duplicate groups
|
About duplicate groups
|
||||||
@@ -70,4 +64,5 @@ Action Menu
|
|||||||
* **Add Selected to Ignore List:** This first removes all selected duplicates from results, and then add the match of that duplicate and the current reference in the ignore list. This match will not come up again in further scan. The duplicate itself might come back, but it will be matched with another reference file. You can clear the ignore list with the Clear Ignore List command.
|
* **Add Selected to Ignore List:** This first removes all selected duplicates from results, and then add the match of that duplicate and the current reference in the ignore list. This match will not come up again in further scan. The duplicate itself might come back, but it will be matched with another reference file. You can clear the ignore list with the Clear Ignore List command.
|
||||||
* **Open Selected with Default Application:** Open the file with the application associated with selected file's type.
|
* **Open Selected with Default Application:** Open the file with the application associated with selected file's type.
|
||||||
* **Reveal Selected in Finder:** Open the folder containing selected file.
|
* **Reveal Selected in Finder:** Open the folder containing selected file.
|
||||||
|
* **Invoke Custom Command:** Invokes the external application you've set up in your preferences using the current selection as arguments in the invocation.
|
||||||
* **Rename Selected:** Prompts you for a new name, and then rename the selected file.
|
* **Rename Selected:** Prompts you for a new name, and then rename the selected file.
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'dupeGuru ME version history'
|
|
||||||
selected_menu_item = 'Version History'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
A large part of this version history is not serious (especially before v3), but it is always interesting to remember that I learnt most of what I know about designing/implementing/supporting a software through that.
|
A large part of this version history is not serious (especially before v3), but it is always interesting to remember that I learnt most of what I know about designing/implementing/supporting a software through that.
|
||||||
|
|
||||||
${self.output_changelogs(changelog)}
|
{changelog}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<%inherit file="/base_help.mako"/>
|
|
||||||
${next.body()}
|
|
||||||
|
|
||||||
<%def name="menu()"><%
|
|
||||||
self.menuitem('intro.htm', 'Introduction', 'Introduction to dupeGuru')
|
|
||||||
self.menuitem('quick_start.htm', 'Quick Start', 'Quickly get into the action')
|
|
||||||
self.menuitem('directories.htm', 'Directories', 'Managing dupeGuru directories')
|
|
||||||
self.menuitem('preferences.htm', 'Preferences', 'Setting dupeGuru preferences')
|
|
||||||
self.menuitem('results.htm', 'Results', 'Time to delete these duplicates!')
|
|
||||||
self.menuitem('power_marker.htm', 'Power Marker', 'Take control of your duplicates')
|
|
||||||
self.menuitem('faq.htm', 'F.A.Q.', 'Frequently Asked Questions')
|
|
||||||
self.menuitem('versions.htm', 'Version History', 'Changes dupeGuru went through')
|
|
||||||
self.menuitem('credits.htm', 'Credits', 'People who contributed to dupeGuru')
|
|
||||||
%></%def>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<%!
|
|
||||||
title = 'Credits'
|
|
||||||
selected_menu_item = 'Credits'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
Below is the list of people who contributed, directly or indirectly to dupeGuru.
|
|
||||||
|
|
||||||
${self.credit('Virgil Dupras', 'Developer', "That's me, Hardcoded Software founder", 'www.hardcoded.net', 'hsoft@hardcoded.net')}
|
|
||||||
|
|
||||||
${self.credit('Python', 'Programming language', "The bestest of the bests", 'www.python.org')}
|
|
||||||
|
|
||||||
${self.credit('PyObjC', 'Python-to-Cocoa bridge', "Used for the Mac OS X version", 'pyobjc.sourceforge.net')}
|
|
||||||
|
|
||||||
${self.credit('PyQt', 'Python-to-Qt bridge', "Used for the Windows version", 'www.riverbankcomputing.co.uk')}
|
|
||||||
|
|
||||||
${self.credit('Qt', 'GUI Toolkit', "Used for the Windows version", 'www.qtsoftware.com')}
|
|
||||||
|
|
||||||
${self.credit('Sparkle', 'Auto-update library', "Used for the Mac OS X version", 'andymatuschak.org/pages/sparkle')}
|
|
||||||
|
|
||||||
${self.credit('You', 'dupeGuru user', "What would I do without you?")}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
Copyright 2010 Hardcoded Software Inc. (http://www.hardcoded.net)
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of Hardcoded Software Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
||||||
* If the source code has been published less than two years ago, any redistribution, in whole or in part, must retain full licensing functionality, without any attempt to change, obscure or in other ways circumvent its intent.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
|
- date: 2010-07-17
|
||||||
|
version: 1.9.1
|
||||||
|
description: |
|
||||||
|
* Fixed a couple of crashes. (#95, #96, #97, #100)
|
||||||
|
- date: 2010-04-15
|
||||||
|
version: 1.9.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-04-08
|
- date: 2010-04-08
|
||||||
version: 1.8.6
|
version: 1.8.6
|
||||||
description: |
|
description: |
|
||||||
|
|||||||
6
help_pe/conf.yaml
Normal file
6
help_pe/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 Help\"></meta>"
|
||||||
30
help_pe/en/credits.md
Normal file
30
help_pe/en/credits.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
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>
|
||||||
|
|
||||||
|
**Python Imaging Library, Picture analyzer**<br/>
|
||||||
|
Used for the Windows version<br/>
|
||||||
|
<http://www.pythonware.com/products/pil/>
|
||||||
|
|
||||||
|
**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**.
|
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.
|
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 F.A.Q.'
|
|
||||||
selected_menu_item = 'F.A.Q.'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
<%text filter="md">
|
|
||||||
### What is dupeGuru PE?
|
### What is dupeGuru PE?
|
||||||
|
|
||||||
dupeGuru Picture Edition (PE for short) is a tool to find duplicate pictures on your computer. Not only can it find exact matches, but it can also find duplicates among pictures of different kind (PNG, JPG, GIF etc..) and quality.
|
dupeGuru Picture Edition (PE for short) is a tool to find duplicate pictures on your computer. Not only can it find exact matches, but it can also find duplicates among pictures of different kind (PNG, JPG, GIF etc..) and quality.
|
||||||
@@ -71,4 +64,3 @@ If dupeGuru still gives you troubles after fixing your permissions, there have b
|
|||||||
If you're trying to delete *iPhoto* pictures, then the reason for the failure is different. The deletion fails because dupeGuru can't communicate with iPhoto. Be aware that for the deletion to work correctly, you're not supposed to play around iPhoto while dupeGuru is working. Also, sometimes, the Applescript system doesn't seem to know where to find iPhoto to launch it. It might help in these cases to launch iPhoto *before* you send your duplicates to Trash.
|
If you're trying to delete *iPhoto* pictures, then the reason for the failure is different. The deletion fails because dupeGuru can't communicate with iPhoto. Be aware that for the deletion to work correctly, you're not supposed to play around iPhoto while dupeGuru is working. Also, sometimes, the Applescript system doesn't seem to know where to find iPhoto to launch it. It might help in these cases to launch iPhoto *before* you send your duplicates to Trash.
|
||||||
|
|
||||||
If all of this fail, [contact HS support](http://www.hardcoded.net/support), we'll figure it out.
|
If all of this fail, [contact HS support](http://www.hardcoded.net/support), we'll figure it out.
|
||||||
</%text>
|
|
||||||
@@ -1,13 +1,5 @@
|
|||||||
<%!
|
|
||||||
title = 'Introduction to dupeGuru PE'
|
|
||||||
selected_menu_item = 'introduction'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
dupeGuru Picture Edition (PE for short) is a tool to find duplicate pictures on your computer. Not only can it find exact matches, but it can also find duplicates among pictures of different kind (PNG, JPG, GIF etc..) and quality.
|
dupeGuru Picture Edition (PE for short) is a tool to find duplicate pictures on your computer. Not only can it find exact matches, but it can also find duplicates among pictures of different kind (PNG, JPG, GIF etc..) and quality.
|
||||||
|
|
||||||
Although dupeGuru can easily be used without documentation, reading this file will help you to master it. If you are looking for guidance for your first duplicate scan, you can take a look at the [Quick Start](quick_start.htm) section.
|
Although dupeGuru can easily be used without documentation, reading this file will help you to master it. If you are looking for guidance for your first duplicate scan, you can take a look at the [Quick Start](quick_start.htm) section.
|
||||||
|
|
||||||
It is a good idea to keep dupeGuru PE updated. You can download the latest version on the [dupeGuru PE homepage](http://www.hardcoded.net/dupeguru_pe/).
|
It is a good idea to keep dupeGuru PE updated. You can download the latest version on the [dupeGuru PE homepage](http://www.hardcoded.net/dupeguru_pe/).
|
||||||
|
|
||||||
<%def name="meta()"><meta name="AppleTitle" content="dupeGuru PE Help"></meta></%def>
|
|
||||||
45
help_pe/en/pages.yaml
Normal file
45
help_pe/en/pages.yaml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
-
|
||||||
|
name: intro
|
||||||
|
title: Introduction to dupeGuru PE
|
||||||
|
menutitle: Introduction
|
||||||
|
menudesc: Introduction to dupeGuru
|
||||||
|
-
|
||||||
|
name: quick_start
|
||||||
|
title: Quick Start
|
||||||
|
menutitle: Quick Start
|
||||||
|
menudesc: Quickly get into the action
|
||||||
|
-
|
||||||
|
name: directories
|
||||||
|
title: Directories
|
||||||
|
menutitle: Directories
|
||||||
|
menudesc: Managing dupeGuru directories
|
||||||
|
-
|
||||||
|
name: preferences
|
||||||
|
title: Preferences
|
||||||
|
menutitle: Preferences
|
||||||
|
menudesc: Setting dupeGuru preferences
|
||||||
|
-
|
||||||
|
name: results
|
||||||
|
title: Results
|
||||||
|
menutitle: Results
|
||||||
|
menudesc: Time to delete these duplicates!
|
||||||
|
-
|
||||||
|
name: power_marker
|
||||||
|
title: Power Marker
|
||||||
|
menutitle: Power Marker
|
||||||
|
menudesc: Take control of your duplicates
|
||||||
|
-
|
||||||
|
name: faq
|
||||||
|
title: Frequently Asked Questions
|
||||||
|
menutitle: F.A.Q.
|
||||||
|
menudesc: Frequently Asked Questions
|
||||||
|
-
|
||||||
|
name: versions
|
||||||
|
title: Version History
|
||||||
|
menutitle: Version History
|
||||||
|
menudesc: Changes moneyGuru went through
|
||||||
|
-
|
||||||
|
name: credits
|
||||||
|
title: Credits
|
||||||
|
menutitle: Credits
|
||||||
|
menudesc: People who contributed to dupeGuru
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Power Marker'
|
|
||||||
selected_menu_item = 'Power Marker'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
You will probably not use the Power Marker feature very often, but if you get into a situation where you need it, you will be pretty happy that this feature exists.
|
You will probably not use the Power Marker feature very often, but if you get into a situation where you need it, you will be pretty happy that this feature exists.
|
||||||
|
|
||||||
What is it?
|
What is it?
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Preferences'
|
|
||||||
selected_menu_item = 'Preferences'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
**Filter Hardness:** The higher is this setting, the "harder" is the filter (In other words, the less results you get). Most pictures of the same quality match at 100% even if the format is different (PNG and JPG for example.). However, if you want to make a PNG match with a lower quality JPG, you will have to set the filer hardness to lower than 100. The default, 95, is a sweet spot.
|
**Filter Hardness:** The higher is this setting, the "harder" is the filter (In other words, the less results you get). Most pictures of the same quality match at 100% even if the format is different (PNG and JPG for example.). However, if you want to make a PNG match with a lower quality JPG, you will have to set the filer hardness to lower than 100. The default, 95, is a sweet spot.
|
||||||
|
|
||||||
**Match scaled pictures together:** If you check this box, pictures of different dimensions will be allowed in the same duplicate group.
|
**Match scaled pictures together:** If you check this box, pictures of different dimensions will be allowed in the same duplicate group.
|
||||||
@@ -21,3 +15,11 @@
|
|||||||
* **Recreate absolute path:** The source file's path will be re-created in the destination directory in it's entirety. For example, if you move "/Users/foobar/Picture/2006/06/photo.jpg" to the destination "/Users/foobar/MyDestination", the final destination for the file will be "/Users/foobar/MyDestination/Users/foobar/Picture/2006/06".
|
* **Recreate absolute path:** The source file's path will be re-created in the destination directory in it's entirety. For example, if you move "/Users/foobar/Picture/2006/06/photo.jpg" to the destination "/Users/foobar/MyDestination", the final destination for the file will be "/Users/foobar/MyDestination/Users/foobar/Picture/2006/06".
|
||||||
|
|
||||||
In all cases, dupeGuru PE nicely handles naming conflicts by prepending a number to the destination filename if the filename already exists in the destination.
|
In all cases, dupeGuru PE nicely handles naming conflicts by prepending a number to the destination filename if the filename already exists in the destination.
|
||||||
|
|
||||||
|
**Custom Command:** This preference determines the command that will be invoked by the "Invoke Custom Command" action. You can invoke any external application through this action. This can be useful if, for example, you have a nice diffing application installed.
|
||||||
|
|
||||||
|
The format of the command is the same as what you would write in the command line, except that there are 2 placeholders: **%d** and **%r**. These placeholders will be replaced by the path of the selected dupe (%d) and the path of the selected dupe's reference file (%r).
|
||||||
|
|
||||||
|
If the path to your executable contains space characters, you should enclose it in "" quotes. You should also enclose placeholders in quotes because it's very possible that paths to dupes and refs will contain spaces. Here's an example custom command:
|
||||||
|
|
||||||
|
"C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r"
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Quick Start'
|
|
||||||
selected_menu_item = 'Quick Start'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
To get you quickly started with dupeGuru, let's just make a standard scan using default preferences.
|
To get you quickly started with dupeGuru, let's just make a standard scan using default preferences.
|
||||||
|
|
||||||
* Click on **Directories**.
|
* Click on **Directories**.
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Results'
|
|
||||||
selected_menu_item = 'Results'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
When dupeGuru is finished scanning for duplicates, it will show its results in the form of duplicate group list.
|
When dupeGuru is finished scanning for duplicates, it will show its results in the form of duplicate group list.
|
||||||
|
|
||||||
About duplicate groups
|
About duplicate groups
|
||||||
@@ -70,4 +64,5 @@ Action Menu
|
|||||||
* **Add Selected to Ignore List:** This first removes all selected duplicates from results, and then add the match of that duplicate and the current reference in the ignore list. This match will not come up again in further scan. The duplicate itself might come back, but it will be matched with another reference file. You can clear the ignore list with the Clear Ignore List command.
|
* **Add Selected to Ignore List:** This first removes all selected duplicates from results, and then add the match of that duplicate and the current reference in the ignore list. This match will not come up again in further scan. The duplicate itself might come back, but it will be matched with another reference file. You can clear the ignore list with the Clear Ignore List command.
|
||||||
* **Open Selected with Default Application:** Open the file with the application associated with selected file's type.
|
* **Open Selected with Default Application:** Open the file with the application associated with selected file's type.
|
||||||
* **Reveal Selected in Finder:** Open the folder containing selected file.
|
* **Reveal Selected in Finder:** Open the folder containing selected file.
|
||||||
|
* **Invoke Custom Command:** Invokes the external application you've set up in your preferences using the current selection as arguments in the invocation.
|
||||||
* **Rename Selected:** Prompts you for a new name, and then rename the selected file.
|
* **Rename Selected:** Prompts you for a new name, and then rename the selected file.
|
||||||
1
help_pe/en/versions.md
Normal file
1
help_pe/en/versions.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{changelog}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<%inherit file="/base_help.mako"/>
|
|
||||||
${next.body()}
|
|
||||||
|
|
||||||
<%def name="menu()"><%
|
|
||||||
self.menuitem('intro.htm', 'Introduction', 'Introduction to dupeGuru')
|
|
||||||
self.menuitem('quick_start.htm', 'Quick Start', 'Quickly get into the action')
|
|
||||||
self.menuitem('directories.htm', 'Directories', 'Managing dupeGuru directories')
|
|
||||||
self.menuitem('preferences.htm', 'Preferences', 'Setting dupeGuru preferences')
|
|
||||||
self.menuitem('results.htm', 'Results', 'Time to delete these duplicates!')
|
|
||||||
self.menuitem('power_marker.htm', 'Power Marker', 'Take control of your duplicates')
|
|
||||||
self.menuitem('faq.htm', 'F.A.Q.', 'Frequently Asked Questions')
|
|
||||||
self.menuitem('versions.htm', 'Version History', 'Changes dupeGuru went through')
|
|
||||||
self.menuitem('credits.htm', 'Credits', 'People who contributed to dupeGuru')
|
|
||||||
%></%def>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
## -*- coding: utf-8 -*-
|
|
||||||
<%!
|
|
||||||
title = 'Credits'
|
|
||||||
selected_menu_item = 'Credits'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
Below is the list of people who contributed, directly or indirectly to dupeGuru.
|
|
||||||
|
|
||||||
${self.credit('Virgil Dupras', 'Developer', "That's me, Hardcoded Software founder", 'www.hardcoded.net', 'hsoft@hardcoded.net')}
|
|
||||||
|
|
||||||
${self.credit(u'Jérôme Cantin', u'Icon designer', u"Icons in dupeGuru are from him")}
|
|
||||||
|
|
||||||
${self.credit('Python', 'Programming language', "The bestest of the bests", 'www.python.org')}
|
|
||||||
|
|
||||||
${self.credit('PyObjC', 'Python-to-Cocoa bridge', "Used for the Mac OS X version", 'pyobjc.sourceforge.net')}
|
|
||||||
|
|
||||||
${self.credit('PyQt', 'Python-to-Qt bridge', "Used for the Windows version", 'www.riverbankcomputing.co.uk')}
|
|
||||||
|
|
||||||
${self.credit('Qt', 'GUI Toolkit', "Used for the Windows version", 'www.qtsoftware.com')}
|
|
||||||
|
|
||||||
${self.credit('Sparkle', 'Auto-update library', "Used for the Mac OS X version", 'andymatuschak.org/pages/sparkle')}
|
|
||||||
|
|
||||||
${self.credit('Python Imaging Library', 'Picture analyzer', "Used for the Windows version", 'www.pythonware.com/products/pil/')}
|
|
||||||
|
|
||||||
${self.credit('You', 'dupeGuru user', "What would I do without you?")}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<%!
|
|
||||||
title = 'dupeGuru PE version history'
|
|
||||||
selected_menu_item = 'Version History'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
${self.output_changelogs(changelog)}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
Copyright 2010 Hardcoded Software Inc. (http://www.hardcoded.net)
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of Hardcoded Software Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
||||||
* If the source code has been published less than two years ago, any redistribution, in whole or in part, must retain full licensing functionality, without any attempt to change, obscure or in other ways circumvent its intent.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
|
- date: 2010-07-15
|
||||||
|
version: 2.10.1
|
||||||
|
description: |
|
||||||
|
* Fixed a couple of crashes. (#95, #97, #100)
|
||||||
|
- date: 2010-04-13
|
||||||
|
version: 2.10.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-10
|
- date: 2010-02-10
|
||||||
version: 2.9.2
|
version: 2.9.2
|
||||||
description: |
|
description: |
|
||||||
|
|||||||
6
help_se/conf.yaml
Normal file
6
help_se/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 Help\"></meta>"
|
||||||
26
help_se/en/credits.md
Normal file
26
help_se/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**.
|
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.
|
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 F.A.Q.'
|
|
||||||
selected_menu_item = 'F.A.Q.'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
<%text filter="md">
|
|
||||||
### What is dupeGuru?
|
### What is dupeGuru?
|
||||||
|
|
||||||
dupeGuru is a tool to find duplicate files on your computer. It can scan either filenames or content. The filename scan features a fuzzy matching algorithm that can find duplicate filenames even when they are not exactly the same.
|
dupeGuru is a tool to find duplicate files on your computer. It can scan either filenames or content. The filename scan features a fuzzy matching algorithm that can find duplicate filenames even when they are not exactly the same.
|
||||||
@@ -69,4 +62,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 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.
|
If all of this fail, [contact HS support](http://www.hardcoded.net/support), we'll figure it out.
|
||||||
</%text>
|
|
||||||
@@ -1,13 +1,5 @@
|
|||||||
<%!
|
|
||||||
title = 'Introduction to dupeGuru'
|
|
||||||
selected_menu_item = 'introduction'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
dupeGuru is a tool to find duplicate files on your computer. It can scan either filenames or contents. The filename scan features a fuzzy matching algorithm that can find duplicate filenames even when they are not exactly the same.
|
dupeGuru is a tool to find duplicate files on your computer. It can scan either filenames or contents. The filename scan features a fuzzy matching algorithm that can find duplicate filenames even when they are not exactly the same.
|
||||||
|
|
||||||
Although dupeGuru can easily be used without documentation, reading this file will help you to master it. If you are looking for guidance for your first duplicate scan, you can take a look at the [Quick Start](quick_start.htm) section.
|
Although dupeGuru can easily be used without documentation, reading this file will help you to master it. If you are looking for guidance for your first duplicate scan, you can take a look at the [Quick Start](quick_start.htm) section.
|
||||||
|
|
||||||
It is a good idea to keep dupeGuru updated. You can download the latest version on the [dupeGuru homepage](http://www.hardcoded.net/dupeguru/).
|
It is a good idea to keep dupeGuru updated. You can download the latest version on the [dupeGuru homepage](http://www.hardcoded.net/dupeguru/).
|
||||||
|
|
||||||
<%def name="meta()"><meta name="AppleTitle" content="dupeGuru Help"></meta></%def>
|
|
||||||
45
help_se/en/pages.yaml
Normal file
45
help_se/en/pages.yaml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
-
|
||||||
|
name: intro
|
||||||
|
title: Introduction to dupeGuru
|
||||||
|
menutitle: Introduction
|
||||||
|
menudesc: Introduction to dupeGuru
|
||||||
|
-
|
||||||
|
name: quick_start
|
||||||
|
title: Quick Start
|
||||||
|
menutitle: Quick Start
|
||||||
|
menudesc: Quickly get into the action
|
||||||
|
-
|
||||||
|
name: directories
|
||||||
|
title: Directories
|
||||||
|
menutitle: Directories
|
||||||
|
menudesc: Managing dupeGuru directories
|
||||||
|
-
|
||||||
|
name: preferences
|
||||||
|
title: Preferences
|
||||||
|
menutitle: Preferences
|
||||||
|
menudesc: Setting dupeGuru preferences
|
||||||
|
-
|
||||||
|
name: results
|
||||||
|
title: Results
|
||||||
|
menutitle: Results
|
||||||
|
menudesc: Time to delete these duplicates!
|
||||||
|
-
|
||||||
|
name: power_marker
|
||||||
|
title: Power Marker
|
||||||
|
menutitle: Power Marker
|
||||||
|
menudesc: Take control of your duplicates
|
||||||
|
-
|
||||||
|
name: faq
|
||||||
|
title: Frequently Asked Questions
|
||||||
|
menutitle: F.A.Q.
|
||||||
|
menudesc: Frequently Asked Questions
|
||||||
|
-
|
||||||
|
name: versions
|
||||||
|
title: Version History
|
||||||
|
menutitle: Version History
|
||||||
|
menudesc: Changes moneyGuru went through
|
||||||
|
-
|
||||||
|
name: credits
|
||||||
|
title: Credits
|
||||||
|
menutitle: Credits
|
||||||
|
menudesc: People who contributed to dupeGuru
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Power Marker'
|
|
||||||
selected_menu_item = 'Power Marker'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
You will probably not use the Power Marker feature very often, but if you get into a situation where you need it, you will be pretty happy that this feature exists.
|
You will probably not use the Power Marker feature very often, but if you get into a situation where you need it, you will be pretty happy that this feature exists.
|
||||||
|
|
||||||
What is it?
|
What is it?
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Preferences'
|
|
||||||
selected_menu_item = 'Preferences'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
**Scan Type:** This option determines what aspect of the files will be compared in the duplicate scan. If you select **Filename**, dupeGuru will compare every filenames word-by-word and, depending on the other settings below, it will determine if enough words are matching to consider 2 files duplicates. If you select **Content**, only files with the exact same content will match.
|
**Scan Type:** This option determines what aspect of the files will be compared in the duplicate scan. If you select **Filename**, dupeGuru will compare every filenames word-by-word and, depending on the other settings below, it will determine if enough words are matching to consider 2 files duplicates. If you select **Content**, only files with the exact same content will match.
|
||||||
|
|
||||||
**Filter Hardness:** If you chose the **Filename** scan type, this option determines how similar two filenames must be for dupeGuru to consider them duplicates. If the filter hardness is, for example 80, it means that 80% of the words of two filenames must match. To determine the matching percentage, dupeGuru first counts the total number of words in **both** filenames, then count the number of words matching (every word matching count as 2), and then divide the number of words matching by the total number of words. If the result is higher or equal to the filter hardness, we have a duplicate match. For example, "a b c d" and "c d e" have a matching percentage of 57 (4 words matching, 7 total words).
|
**Filter Hardness:** If you chose the **Filename** scan type, this option determines how similar two filenames must be for dupeGuru to consider them duplicates. If the filter hardness is, for example 80, it means that 80% of the words of two filenames must match. To determine the matching percentage, dupeGuru first counts the total number of words in **both** filenames, then count the number of words matching (every word matching count as 2), and then divide the number of words matching by the total number of words. If the result is higher or equal to the filter hardness, we have a duplicate match. For example, "a b c d" and "c d e" have a matching percentage of 57 (4 words matching, 7 total words).
|
||||||
@@ -25,3 +19,11 @@
|
|||||||
* **Recreate absolute path:** The source file's path will be re-created in the destination directory in it's entirety. For example, if you move "/Users/foobar/Music/Artist/Album/the_song.mp3" to the destination "/Users/foobar/MyDestination", the final destination for the file will be "/Users/foobar/MyDestination/Users/foobar/Music/Artist/Album".
|
* **Recreate absolute path:** The source file's path will be re-created in the destination directory in it's entirety. For example, if you move "/Users/foobar/Music/Artist/Album/the_song.mp3" to the destination "/Users/foobar/MyDestination", the final destination for the file will be "/Users/foobar/MyDestination/Users/foobar/Music/Artist/Album".
|
||||||
|
|
||||||
In all cases, dupeGuru nicely handles naming conflicts by prepending a number to the destination filename if the filename already exists in the destination.
|
In all cases, dupeGuru nicely handles naming conflicts by prepending a number to the destination filename if the filename already exists in the destination.
|
||||||
|
|
||||||
|
**Custom Command:** This preference determines the command that will be invoked by the "Invoke Custom Command" action. You can invoke any external application through this action. This can be useful if, for example, you have a nice diffing application installed.
|
||||||
|
|
||||||
|
The format of the command is the same as what you would write in the command line, except that there are 2 placeholders: **%d** and **%r**. These placeholders will be replaced by the path of the selected dupe (%d) and the path of the selected dupe's reference file (%r).
|
||||||
|
|
||||||
|
If the path to your executable contains space characters, you should enclose it in "" quotes. You should also enclose placeholders in quotes because it's very possible that paths to dupes and refs will contain spaces. Here's an example custom command:
|
||||||
|
|
||||||
|
"C:\Program Files\SuperDiffProg\SuperDiffProg.exe" "%d" "%r"
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Quick Start'
|
|
||||||
selected_menu_item = 'Quick Start'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
To get you quickly started with dupeGuru, let's just make a standard scan using default preferences.
|
To get you quickly started with dupeGuru, let's just make a standard scan using default preferences.
|
||||||
|
|
||||||
* Click on **Directories**.
|
* Click on **Directories**.
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
<%!
|
|
||||||
title = 'Results'
|
|
||||||
selected_menu_item = 'Results'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
|
|
||||||
When dupeGuru is finished scanning for duplicates, it will show its results in the form of duplicate group list.
|
When dupeGuru is finished scanning for duplicates, it will show its results in the form of duplicate group list.
|
||||||
|
|
||||||
About duplicate groups
|
About duplicate groups
|
||||||
@@ -70,4 +64,5 @@ Action Menu
|
|||||||
* **Add Selected to Ignore List:** This first removes all selected duplicates from results, and then add the match of that duplicate and the current reference in the ignore list. This match will not come up again in further scan. The duplicate itself might come back, but it will be matched with another reference file. You can clear the ignore list with the Clear Ignore List command.
|
* **Add Selected to Ignore List:** This first removes all selected duplicates from results, and then add the match of that duplicate and the current reference in the ignore list. This match will not come up again in further scan. The duplicate itself might come back, but it will be matched with another reference file. You can clear the ignore list with the Clear Ignore List command.
|
||||||
* **Open Selected with Default Application:** Open the file with the application associated with selected file's type.
|
* **Open Selected with Default Application:** Open the file with the application associated with selected file's type.
|
||||||
* **Reveal Selected in Finder:** Open the folder containing selected file.
|
* **Reveal Selected in Finder:** Open the folder containing selected file.
|
||||||
|
* **Invoke Custom Command:** Invokes the external application you've set up in your preferences using the current selection as arguments in the invocation.
|
||||||
* **Rename Selected:** Prompts you for a new name, and then rename the selected file.
|
* **Rename Selected:** Prompts you for a new name, and then rename the selected file.
|
||||||
1
help_se/en/versions.md
Normal file
1
help_se/en/versions.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{changelog}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<%inherit file="/base_help.mako"/>
|
|
||||||
${next.body()}
|
|
||||||
|
|
||||||
<%def name="menu()"><%
|
|
||||||
self.menuitem('intro.htm', 'Introduction', 'Introduction to dupeGuru')
|
|
||||||
self.menuitem('quick_start.htm', 'Quick Start', 'Quickly get into the action')
|
|
||||||
self.menuitem('directories.htm', 'Directories', 'Managing dupeGuru directories')
|
|
||||||
self.menuitem('preferences.htm', 'Preferences', 'Setting dupeGuru preferences')
|
|
||||||
self.menuitem('results.htm', 'Results', 'Time to delete these duplicates!')
|
|
||||||
self.menuitem('power_marker.htm', 'Power Marker', 'Take control of your duplicates')
|
|
||||||
self.menuitem('faq.htm', 'F.A.Q.', 'Frequently Asked Questions')
|
|
||||||
self.menuitem('versions.htm', 'Version History', 'Changes dupeGuru went through')
|
|
||||||
self.menuitem('credits.htm', 'Credits', 'People who contributed to dupeGuru')
|
|
||||||
%></%def>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<%!
|
|
||||||
title = 'Credits'
|
|
||||||
selected_menu_item = 'Credits'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
Below is the list of people who contributed, directly or indirectly to dupeGuru.
|
|
||||||
|
|
||||||
${self.credit('Virgil Dupras', 'Developer', "That's me, Hardcoded Software founder", 'www.hardcoded.net', 'hsoft@hardcoded.net')}
|
|
||||||
|
|
||||||
${self.credit('Jerome', 'Icon designer', "Icons in dupeGuru are from him")}
|
|
||||||
|
|
||||||
${self.credit('Python', 'Programming language', "The bestest of the bests", 'www.python.org')}
|
|
||||||
|
|
||||||
${self.credit('PyObjC', 'Python-to-Cocoa bridge', "Used for the Mac OS X version", 'pyobjc.sourceforge.net')}
|
|
||||||
|
|
||||||
${self.credit('Python for .NET', 'Python-to-.NET bridge', "Used for the Windows version", 'sourceforge.net/projects/pythonnet/')}
|
|
||||||
|
|
||||||
${self.credit('Sparkle', 'Auto-update library', "Used for the Mac OS X version", 'andymatuschak.org/pages/sparkle')}
|
|
||||||
|
|
||||||
${self.credit('You', 'dupeGuru user', "What would I do without you?")}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<%!
|
|
||||||
title = 'dupeGuru version history'
|
|
||||||
selected_menu_item = 'Version History'
|
|
||||||
%>
|
|
||||||
<%inherit file="/base_dg.mako"/>
|
|
||||||
${self.output_changelogs(changelog)}
|
|
||||||
16
package.py
16
package.py
@@ -15,7 +15,7 @@ import shutil
|
|||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from hsutil.build import (build_dmg, add_to_pythonpath, print_and_do, copy_packages,
|
from hscommon.build import (build_dmg, add_to_pythonpath, print_and_do, copy_packages,
|
||||||
build_debian_changelog, copy_qt_plugins)
|
build_debian_changelog, copy_qt_plugins)
|
||||||
|
|
||||||
def package_cocoa(edition):
|
def package_cocoa(edition):
|
||||||
@@ -57,7 +57,11 @@ def package_windows(edition, dev):
|
|||||||
for lib in libs:
|
for lib in libs:
|
||||||
print_and_do("upx --best \"dist\\{0}\"".format(lib))
|
print_and_do("upx --best \"dist\\{0}\"".format(lib))
|
||||||
|
|
||||||
print_and_do("xcopy /Y /S /I ..\\..\\help_{0}\\dupeguru_{0}_help dist\\help".format(edition))
|
help_basedir = '..\\..\\help_{0}'.format(edition)
|
||||||
|
help_dir = 'dupeguru_{0}_help'.format(edition) if edition != 'se' else 'dupeguru_help'
|
||||||
|
help_path = op.join(help_basedir, help_dir)
|
||||||
|
print "Copying {0} to dist\\help".format(help_path)
|
||||||
|
shutil.copytree(help_path, 'dist\\help')
|
||||||
|
|
||||||
# AdvancedInstaller.com has to be in your PATH
|
# AdvancedInstaller.com has to be in your PATH
|
||||||
# this is so we don'a have to re-commit installer.aip at every version change
|
# this is so we don'a have to re-commit installer.aip at every version change
|
||||||
@@ -80,14 +84,10 @@ def package_debian(edition):
|
|||||||
help_src = ed('help_{0}')
|
help_src = ed('help_{0}')
|
||||||
os.makedirs(destpath)
|
os.makedirs(destpath)
|
||||||
shutil.copytree(ed('qt/{0}'), srcpath)
|
shutil.copytree(ed('qt/{0}'), srcpath)
|
||||||
packages = ['hsutil', 'hsgui', 'core', ed('core_{0}'), 'qtlib', 'qt/base']
|
packages = ['hscommon', 'hsgui', 'core', ed('core_{0}'), 'qtlib', 'qt/base', 'hsutil', 'send2trash']
|
||||||
if edition == 'me':
|
if edition == 'me':
|
||||||
packages.append('hsmedia')
|
packages.append('hsaudiotag')
|
||||||
copy_packages(packages, srcpath)
|
copy_packages(packages, srcpath)
|
||||||
# We also have to copy the Send2Trash package
|
|
||||||
import send2trash
|
|
||||||
pkg_path = op.dirname(send2trash.__file__)
|
|
||||||
shutil.copytree(pkg_path, op.join(srcpath, 'send2trash'))
|
|
||||||
shutil.copytree(ed('debian_{0}'), op.join(destpath, 'debian'))
|
shutil.copytree(ed('debian_{0}'), op.join(destpath, 'debian'))
|
||||||
yaml_path = op.join(help_src, 'changelog.yaml')
|
yaml_path = op.join(help_src, 'changelog.yaml')
|
||||||
changelog_dest = op.join(destpath, 'debian', 'changelog')
|
changelog_dest = op.join(destpath, 'debian', 'changelog')
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import os.path as op
|
|||||||
from PyQt4.QtCore import QTimer, QObject, QCoreApplication, QUrl, SIGNAL
|
from PyQt4.QtCore import QTimer, QObject, QCoreApplication, QUrl, SIGNAL
|
||||||
from PyQt4.QtGui import QDesktopServices, QFileDialog, QDialog, QMessageBox
|
from PyQt4.QtGui import QDesktopServices, QFileDialog, QDialog, QMessageBox
|
||||||
|
|
||||||
from hsutil import job
|
from hscommon import job
|
||||||
from hsutil.reg import RegistrationRequired
|
from hscommon.reg import RegistrationRequired
|
||||||
|
|
||||||
from core.app import DupeGuru as DupeGuruBase, JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_COPY, JOB_DELETE
|
from core.app import DupeGuru as DupeGuruBase, JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_COPY, JOB_DELETE
|
||||||
|
|
||||||
@@ -28,6 +28,7 @@ from . import platform
|
|||||||
|
|
||||||
from .main_window import MainWindow
|
from .main_window import MainWindow
|
||||||
from .directories_dialog import DirectoriesDialog
|
from .directories_dialog import DirectoriesDialog
|
||||||
|
from .problem_dialog import ProblemDialog
|
||||||
|
|
||||||
JOBID2TITLE = {
|
JOBID2TITLE = {
|
||||||
JOB_SCAN: "Scanning for duplicates",
|
JOB_SCAN: "Scanning for duplicates",
|
||||||
@@ -71,6 +72,7 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
self._progress = Progress(self.main_window)
|
self._progress = Progress(self.main_window)
|
||||||
self.directories_dialog = DirectoriesDialog(self.main_window, self)
|
self.directories_dialog = DirectoriesDialog(self.main_window, self)
|
||||||
self.details_dialog = self._create_details_dialog(self.main_window)
|
self.details_dialog = self._create_details_dialog(self.main_window)
|
||||||
|
self.problemDialog = ProblemDialog(parent=self.main_window, app=self)
|
||||||
self.preferences_dialog = self._create_preferences_dialog(self.main_window)
|
self.preferences_dialog = self._create_preferences_dialog(self.main_window)
|
||||||
self.about_box = AboutBox(self.main_window, self)
|
self.about_box = AboutBox(self.main_window, self)
|
||||||
|
|
||||||
@@ -169,6 +171,14 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
def askForRegCode(self):
|
def askForRegCode(self):
|
||||||
self.reg.ask_for_code()
|
self.reg.ask_for_code()
|
||||||
|
|
||||||
|
def invokeCustomCommand(self):
|
||||||
|
cmd = self.prefs.custom_command
|
||||||
|
if cmd:
|
||||||
|
self.invoke_command(cmd)
|
||||||
|
else:
|
||||||
|
msg = "You have no custom command set up. Please, set it up in your preferences."
|
||||||
|
QMessageBox.warning(self.main_window, 'Custom Command', msg)
|
||||||
|
|
||||||
def openDebugLog(self):
|
def openDebugLog(self):
|
||||||
debugLogPath = op.join(self.appdata, 'debug.log')
|
debugLogPath = op.join(self.appdata, 'debug.log')
|
||||||
self._open_path(debugLogPath)
|
self._open_path(debugLogPath)
|
||||||
@@ -206,9 +216,12 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
|
|
||||||
def job_finished(self, jobid):
|
def job_finished(self, jobid):
|
||||||
self._job_completed(jobid)
|
self._job_completed(jobid)
|
||||||
if jobid in (JOB_MOVE, JOB_COPY, JOB_DELETE) and self.last_op_error_count > 0:
|
if jobid in (JOB_MOVE, JOB_COPY, JOB_DELETE):
|
||||||
msg = "{0} files could not be processed.".format(self.results.mark_count)
|
if self.results.problems:
|
||||||
QMessageBox.warning(self.main_window, 'Warning', msg)
|
self.problemDialog.show()
|
||||||
|
else:
|
||||||
|
msg = "All files were processed successfully."
|
||||||
|
QMessageBox.information(self.main_window, 'Operation Complete', msg)
|
||||||
elif jobid == JOB_SCAN:
|
elif jobid == JOB_SCAN:
|
||||||
if not self.results.groups:
|
if not self.results.groups:
|
||||||
title = "Scanning complete"
|
title = "Scanning complete"
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.connect(QCoreApplication.instance(), SIGNAL('aboutToQuit()'), self.application_will_terminate)
|
self.connect(QCoreApplication.instance(), SIGNAL('aboutToQuit()'), self.application_will_terminate)
|
||||||
self.connect(self.resultsView, SIGNAL('doubleClicked()'), self.resultsDoubleClicked)
|
self.connect(self.resultsView, SIGNAL('doubleClicked()'), self.resultsDoubleClicked)
|
||||||
self.connect(self.resultsView, SIGNAL('spacePressed()'), self.resultsSpacePressed)
|
self.connect(self.resultsView, SIGNAL('spacePressed()'), self.resultsSpacePressed)
|
||||||
|
self.actionInvokeCustomCommand.triggered.connect(self.app.invokeCustomCommand)
|
||||||
|
|
||||||
def _setupUi(self):
|
def _setupUi(self):
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
@@ -76,6 +77,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
actionMenu.addSeparator()
|
actionMenu.addSeparator()
|
||||||
actionMenu.addAction(self.actionOpenSelected)
|
actionMenu.addAction(self.actionOpenSelected)
|
||||||
actionMenu.addAction(self.actionRevealSelected)
|
actionMenu.addAction(self.actionRevealSelected)
|
||||||
|
actionMenu.addAction(self.actionInvokeCustomCommand)
|
||||||
actionMenu.addAction(self.actionRenameSelected)
|
actionMenu.addAction(self.actionRenameSelected)
|
||||||
self.actionActions.setMenu(actionMenu)
|
self.actionActions.setMenu(actionMenu)
|
||||||
button = QToolButton(self.toolBar)
|
button = QToolButton(self.toolBar)
|
||||||
|
|||||||
@@ -44,6 +44,9 @@
|
|||||||
<attribute name="headerStretchLastSection">
|
<attribute name="headerStretchLastSection">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
|
<attribute name="headerStretchLastSection">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@@ -54,7 +57,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>630</width>
|
<width>630</width>
|
||||||
<height>22</height>
|
<height>20</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuColumns">
|
<widget class="QMenu" name="menuColumns">
|
||||||
@@ -77,6 +80,7 @@
|
|||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionOpenSelected"/>
|
<addaction name="actionOpenSelected"/>
|
||||||
<addaction name="actionRevealSelected"/>
|
<addaction name="actionRevealSelected"/>
|
||||||
|
<addaction name="actionInvokeCustomCommand"/>
|
||||||
<addaction name="actionRenameSelected"/>
|
<addaction name="actionRenameSelected"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionApplyFilter"/>
|
<addaction name="actionApplyFilter"/>
|
||||||
@@ -428,6 +432,14 @@
|
|||||||
<string>Open Debug Log</string>
|
<string>Open Debug Log</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionInvokeCustomCommand">
|
||||||
|
<property name="text">
|
||||||
|
<string>Invoke Custom Command</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+I</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class Preferences(PreferencesBase):
|
|||||||
self.use_regexp = get('UseRegexp', self.use_regexp)
|
self.use_regexp = get('UseRegexp', self.use_regexp)
|
||||||
self.remove_empty_folders = get('RemoveEmptyFolders', self.remove_empty_folders)
|
self.remove_empty_folders = get('RemoveEmptyFolders', self.remove_empty_folders)
|
||||||
self.destination_type = get('DestinationType', self.destination_type)
|
self.destination_type = get('DestinationType', self.destination_type)
|
||||||
|
self.custom_command = get('CustomCommand', self.custom_command)
|
||||||
widths = get('ColumnsWidth', self.columns_width)
|
widths = get('ColumnsWidth', self.columns_width)
|
||||||
# only set nonzero values
|
# only set nonzero values
|
||||||
for index, width in enumerate(widths[:len(self.columns_width)]):
|
for index, width in enumerate(widths[:len(self.columns_width)]):
|
||||||
@@ -46,6 +47,7 @@ class Preferences(PreferencesBase):
|
|||||||
self.use_regexp = False
|
self.use_regexp = False
|
||||||
self.remove_empty_folders = False
|
self.remove_empty_folders = False
|
||||||
self.destination_type = 1
|
self.destination_type = 1
|
||||||
|
self.custom_command = ''
|
||||||
self.registration_code = ''
|
self.registration_code = ''
|
||||||
self.registration_email = ''
|
self.registration_email = ''
|
||||||
self._reset_specific()
|
self._reset_specific()
|
||||||
@@ -64,6 +66,7 @@ class Preferences(PreferencesBase):
|
|||||||
set_('UseRegexp', self.use_regexp)
|
set_('UseRegexp', self.use_regexp)
|
||||||
set_('RemoveEmptyFolders', self.remove_empty_folders)
|
set_('RemoveEmptyFolders', self.remove_empty_folders)
|
||||||
set_('DestinationType', self.destination_type)
|
set_('DestinationType', self.destination_type)
|
||||||
|
set_('CustomCommand', self.custom_command)
|
||||||
set_('ColumnsWidth', self.columns_width)
|
set_('ColumnsWidth', self.columns_width)
|
||||||
set_('ColumnsVisible', self.columns_visible)
|
set_('ColumnsVisible', self.columns_visible)
|
||||||
set_('RegistrationCode', self.registration_code)
|
set_('RegistrationCode', self.registration_code)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user