mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-01-25 08:01:39 +00:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31fc70e0f8 | ||
|
|
a16af4560b | ||
|
|
0782ba0dab | ||
|
|
83725667a4 | ||
|
|
f4b3163b04 | ||
|
|
6cd745f429 | ||
|
|
6131f7f6bf | ||
|
|
dd4faa030f | ||
|
|
ab8691f5ac | ||
|
|
77ab073cdb | ||
|
|
87e0011525 | ||
|
|
7af3bb7226 | ||
|
|
5573352ce6 | ||
|
|
e6486e08ab | ||
|
|
48badaa927 | ||
|
|
2f13bf677e | ||
|
|
e63abc1b4b | ||
|
|
88334acdef | ||
|
|
0491aa9f6e | ||
|
|
5be76d7c0f | ||
|
|
3b510389fc | ||
|
|
32d88e9249 | ||
|
|
7b1a1ff4bb | ||
|
|
19beb919d0 | ||
|
|
ba09e8bf4d | ||
|
|
26dd2d0e8e | ||
|
|
69b15d58a2 | ||
|
|
ba68789fb9 | ||
|
|
47a6ceffbc | ||
|
|
b17ca66f73 | ||
|
|
93bc609026 | ||
|
|
3ea51c2e15 | ||
|
|
1d9897ea60 | ||
|
|
b6cb00bc79 | ||
|
|
6dd53c6bfd | ||
|
|
07df5126b3 | ||
|
|
47b38c7d45 | ||
|
|
0e97bec7b2 | ||
|
|
b182585d46 | ||
|
|
e8f92535d3 | ||
|
|
d62c3663e9 | ||
|
|
6b0bfda9fb | ||
|
|
7477330961 | ||
|
|
1f71157063 | ||
|
|
905988c592 | ||
|
|
310951bfa8 | ||
|
|
64c1087856 | ||
|
|
cab6d924aa | ||
|
|
c3a972d39b | ||
|
|
33d44d4d24 | ||
|
|
fd89cf2482 | ||
|
|
112ffb981f | ||
|
|
514426b980 | ||
|
|
a4bf1c8be6 | ||
|
|
9b82e1478f | ||
|
|
d5f145d57e | ||
|
|
bab891ee74 | ||
|
|
a65fd7d0d0 | ||
|
|
46836cc805 | ||
|
|
42559f13d8 | ||
|
|
87351b5920 | ||
|
|
e68dcf189c | ||
|
|
5d62b8389c | ||
|
|
c50aebe76d | ||
|
|
a610f3fde7 | ||
|
|
626391a1d9 | ||
|
|
1bedfe75ea |
5
.hgtags
5
.hgtags
@@ -9,3 +9,8 @@ cbcf9c80fee4c908ef2efbf1c143c9e47676c9b2 pe1.8.0
|
|||||||
0e923897a3389331d4ab3debbc40b8dd616199d9 pe1.8.1
|
0e923897a3389331d4ab3debbc40b8dd616199d9 pe1.8.1
|
||||||
2c454eca9ebe93b6cf34916068f828a6a39e3eaf me5.7.1
|
2c454eca9ebe93b6cf34916068f828a6a39e3eaf me5.7.1
|
||||||
19e40bab20521d4256acf325dba9b32e95e135c5 pe1.8.2
|
19e40bab20521d4256acf325dba9b32e95e135c5 pe1.8.2
|
||||||
|
7b7c5a66ebee4e4b8125330d24fe9ce1a070ff25 se2.9.2
|
||||||
|
1cef6d39855f85d4be728646bc78b860e6d4e398 pe1.8.3
|
||||||
|
90ed56ee602666db2f267f73eac6f824347039b5 me5.7.2
|
||||||
|
4c3cb1e671a333eabde1151c7c6ffb3609cab025 pe1.8.4
|
||||||
|
0a71306434bca51bea9a5d5ae54fe1bf0e4900d8 pe1.8.5
|
||||||
|
|||||||
4
README
4
README
@@ -27,6 +27,8 @@ General dependencies
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
- Python 2.6 (http://www.python.org)
|
- Python 2.6 (http://www.python.org)
|
||||||
|
- Send2Trash (http://hg.hardcoded.net/send2trash)
|
||||||
|
- 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/)
|
- Nose, to run unit tests. (http://somethingaboutorange.com/mrl/projects/nose/)
|
||||||
@@ -45,7 +47,7 @@ Windows prerequisites
|
|||||||
- Visual Studio 2008 (Express is enough) is needed to build C extensions. (http://www.microsoft.com/Express/)
|
- Visual Studio 2008 (Express is enough) is needed to build C extensions. (http://www.microsoft.com/Express/)
|
||||||
- PyQt 4.6 (http://www.riverbankcomputing.co.uk/news)
|
- PyQt 4.6 (http://www.riverbankcomputing.co.uk/news)
|
||||||
- Python Imaging Library for dupeGuru PE. (http://www.pythonware.com/products/pil/)
|
- Python Imaging Library for dupeGuru PE. (http://www.pythonware.com/products/pil/)
|
||||||
- PyInstaller, if you want to build a exe. You don't need it if you just want to run dupeGuru. (http://www.pyinstaller.org/)
|
- cx_Freeze, if you want to build a exe. You don't need it if you just want to run dupeGuru. (http://cx-freeze.sourceforge.net/)
|
||||||
- Advanced Installer, if you want to build the installer file. (http://www.advancedinstaller.com/)
|
- Advanced Installer, if you want to build the installer file. (http://www.advancedinstaller.com/)
|
||||||
|
|
||||||
Building dupeGuru
|
Building dupeGuru
|
||||||
|
|||||||
@@ -8,11 +8,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
/* ResultsChangedNotification happens on major changes, which requires a complete reload of the data*/
|
|
||||||
#define ResultsChangedNotification @"ResultsChangedNotification"
|
|
||||||
/* ResultsChangedNotification happens on minor changes, which requires buffer flush*/
|
|
||||||
#define ResultsUpdatedNotification @"ResultsUpdatedNotification"
|
|
||||||
#define ResultsMarkingChangedNotification @"ResultsMarkingChangedNotification"
|
|
||||||
#define RegistrationRequired @"RegistrationRequired"
|
#define RegistrationRequired @"RegistrationRequired"
|
||||||
#define JobStarted @"JobStarted"
|
#define JobStarted @"JobStarted"
|
||||||
#define JobInProgress @"JobInProgress"
|
#define JobInProgress @"JobInProgress"
|
||||||
|
|||||||
@@ -14,9 +14,16 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
{
|
{
|
||||||
self = [super initWithNibName:@"DetailsPanel" pyClassName:@"PyDetailsPanel" pyParent:aPy];
|
self = [super initWithNibName:@"DetailsPanel" pyClassName:@"PyDetailsPanel" pyParent:aPy];
|
||||||
[self window]; //So the detailsTable is initialized.
|
[self window]; //So the detailsTable is initialized.
|
||||||
|
[self connect];
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[self disconnect];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
- (PyDetailsPanel *)py
|
- (PyDetailsPanel *)py
|
||||||
{
|
{
|
||||||
return (PyDetailsPanel *)py;
|
return (PyDetailsPanel *)py;
|
||||||
|
|||||||
@@ -13,9 +13,16 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
{
|
{
|
||||||
self = [super initWithPyClassName:@"PyDirectoryOutline" pyParent:aPyParent view:aOutlineView];
|
self = [super initWithPyClassName:@"PyDirectoryOutline" pyParent:aPyParent view:aOutlineView];
|
||||||
[outlineView registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
|
[outlineView registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
|
||||||
|
[self connect];
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[self disconnect];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
- (PyDirectoryOutline *)py
|
- (PyDirectoryOutline *)py
|
||||||
{
|
{
|
||||||
return (PyDirectoryOutline *)py;
|
return (PyDirectoryOutline *)py;
|
||||||
|
|||||||
@@ -23,27 +23,17 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (NSNumber *)doScan;
|
- (NSNumber *)doScan;
|
||||||
|
|
||||||
- (NSArray *)selectedPowerMarkerNodePaths;
|
|
||||||
- (void)selectPowerMarkerNodePaths:(NSArray *)aIndexPaths;
|
|
||||||
- (NSArray *)selectedResultNodePaths;
|
|
||||||
- (void)selectResultNodePaths:(NSArray *)aIndexPaths;
|
|
||||||
|
|
||||||
- (void)toggleSelectedMark;
|
- (void)toggleSelectedMark;
|
||||||
- (void)markAll;
|
- (void)markAll;
|
||||||
- (void)markInvert;
|
- (void)markInvert;
|
||||||
- (void)markNone;
|
- (void)markNone;
|
||||||
|
|
||||||
- (void)addSelectedToIgnoreList;
|
- (void)addSelectedToIgnoreList;
|
||||||
- (void)removeSelected;
|
|
||||||
- (void)openSelected;
|
- (void)openSelected;
|
||||||
- (NSNumber *)renameSelected:(NSString *)aNewName;
|
|
||||||
- (void)revealSelected;
|
- (void)revealSelected;
|
||||||
- (void)makeSelectedReference;
|
- (void)makeSelectedReference;
|
||||||
- (void)applyFilter:(NSString *)filter;
|
- (void)applyFilter:(NSString *)filter;
|
||||||
|
|
||||||
- (void)sortGroupsBy:(NSNumber *)aIdentifier ascending:(NSNumber *)aAscending;
|
|
||||||
- (void)sortDupesBy:(NSNumber *)aIdentifier ascending:(NSNumber *)aAscending;
|
|
||||||
|
|
||||||
- (void)copyOrMove:(NSNumber *)aCopy markedTo:(NSString *)destination recreatePath:(NSNumber *)aRecreateType;
|
- (void)copyOrMove:(NSNumber *)aCopy markedTo:(NSString *)destination recreatePath:(NSNumber *)aRecreateType;
|
||||||
- (void)deleteMarked;
|
- (void)deleteMarked;
|
||||||
- (void)removeMarked;
|
- (void)removeMarked;
|
||||||
@@ -51,13 +41,11 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
//Data
|
//Data
|
||||||
- (NSNumber *)getIgnoreListCount;
|
- (NSNumber *)getIgnoreListCount;
|
||||||
- (NSNumber *)getMarkCount;
|
- (NSNumber *)getMarkCount;
|
||||||
- (NSString *)getStatLine;
|
|
||||||
- (NSNumber *)getOperationalErrorCount;
|
- (NSNumber *)getOperationalErrorCount;
|
||||||
|
|
||||||
//Scanning options
|
//Scanning options
|
||||||
- (void)setMinMatchPercentage:(NSNumber *)percentage;
|
- (void)setMinMatchPercentage:(NSNumber *)percentage;
|
||||||
- (void)setMixFileKind:(NSNumber *)mix_file_kind;
|
- (void)setMixFileKind:(NSNumber *)mix_file_kind;
|
||||||
- (void)setDisplayDeltaValues:(NSNumber *)display_delta_values;
|
|
||||||
- (void)setEscapeFilterRegexp:(NSNumber *)escape_filter_regexp;
|
- (void)setEscapeFilterRegexp:(NSNumber *)escape_filter_regexp;
|
||||||
- (void)setRemoveEmptyFolders:(NSNumber *)remove_empty_folders;
|
- (void)setRemoveEmptyFolders:(NSNumber *)remove_empty_folders;
|
||||||
- (void)setSizeThreshold:(NSInteger)size_threshold;
|
- (void)setSizeThreshold:(NSInteger)size_threshold;
|
||||||
|
|||||||
24
cocoa/base/PyResultTree.h
Normal file
24
cocoa/base/PyResultTree.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
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 "PyOutline.h"
|
||||||
|
|
||||||
|
@interface PyResultTree : PyOutline
|
||||||
|
- (BOOL)powerMarkerMode;
|
||||||
|
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode;
|
||||||
|
- (BOOL)deltaValuesMode;
|
||||||
|
- (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode;
|
||||||
|
|
||||||
|
- (NSString *)valueForPath:(NSArray *)aPath column:(NSInteger)aColumn;
|
||||||
|
- (BOOL)renameSelected:(NSString *)aNewName;
|
||||||
|
- (void)sortBy:(NSInteger)aIdentifier ascending:(BOOL)aAscending;
|
||||||
|
- (void)markSelected;
|
||||||
|
- (void)removeSelected;
|
||||||
|
- (NSArray *)rootChildrenCounts;
|
||||||
|
@end
|
||||||
14
cocoa/base/PyStatsLabel.h
Normal file
14
cocoa/base/PyStatsLabel.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||||
|
|
||||||
|
This software is licensed under the "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 PyStatsLabel : PyGUI
|
||||||
|
- (NSString *)display;
|
||||||
|
@end
|
||||||
26
cocoa/base/ResultOutline.h
Normal file
26
cocoa/base/ResultOutline.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||||
|
|
||||||
|
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||||
|
which should be included with this package. The terms are also available at
|
||||||
|
http://www.hardcoded.net/licenses/hs_license
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import "HSOutline.h"
|
||||||
|
#import "PyResultTree.h"
|
||||||
|
|
||||||
|
@interface ResultOutline : HSOutline
|
||||||
|
{
|
||||||
|
NSIndexSet *_deltaColumns;
|
||||||
|
NSArray *_rootChildrenCounts;
|
||||||
|
}
|
||||||
|
- (PyResultTree *)py;
|
||||||
|
- (BOOL)powerMarkerMode;
|
||||||
|
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode;
|
||||||
|
- (BOOL)deltaValuesMode;
|
||||||
|
- (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode;
|
||||||
|
- (void)setDeltaColumns:(NSIndexSet *)aDeltaColumns;
|
||||||
|
- (NSInteger)selectedDupeCount;
|
||||||
|
- (void)removeSelected;
|
||||||
|
@end;
|
||||||
207
cocoa/base/ResultOutline.m
Normal file
207
cocoa/base/ResultOutline.m
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
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 "ResultOutline.h"
|
||||||
|
#import "Dialogs.h"
|
||||||
|
#import "Utils.h"
|
||||||
|
#import "Consts.h"
|
||||||
|
|
||||||
|
@implementation ResultOutline
|
||||||
|
- (id)initWithPyParent:(id)aPyParent view:(HSOutlineView *)aOutlineView
|
||||||
|
{
|
||||||
|
self = [super initWithPyClassName:@"PyResultOutline" pyParent:aPyParent view:aOutlineView];
|
||||||
|
_rootChildrenCounts = nil;
|
||||||
|
[self connect];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[self disconnect];
|
||||||
|
[_deltaColumns release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (PyResultTree *)py
|
||||||
|
{
|
||||||
|
return (PyResultTree *)py;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public */
|
||||||
|
- (BOOL)powerMarkerMode
|
||||||
|
{
|
||||||
|
return [[self py] powerMarkerMode];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode
|
||||||
|
{
|
||||||
|
[[self py] setPowerMarkerMode:aPowerMarkerMode];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)deltaValuesMode
|
||||||
|
{
|
||||||
|
return [[self py] deltaValuesMode];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode
|
||||||
|
{
|
||||||
|
[[self py] setDeltaValuesMode:aDeltaValuesMode];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDeltaColumns:(NSIndexSet *)aDeltaColumns
|
||||||
|
{
|
||||||
|
[_deltaColumns release];
|
||||||
|
_deltaColumns = [aDeltaColumns retain];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)selectedDupeCount
|
||||||
|
{
|
||||||
|
NSArray *selected = [self selectedIndexPaths];
|
||||||
|
if ([self powerMarkerMode]) {
|
||||||
|
return [selected count];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NSInteger r = 0;
|
||||||
|
for (NSIndexPath *path in selected) {
|
||||||
|
if ([path length] == 2) {
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeSelected
|
||||||
|
{
|
||||||
|
NSInteger selectedDupeCount = [self selectedDupeCount];
|
||||||
|
if (!selectedDupeCount)
|
||||||
|
return;
|
||||||
|
NSString *msg = [NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",selectedDupeCount];
|
||||||
|
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
||||||
|
return;
|
||||||
|
[[self py] removeSelected];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Datasource */
|
||||||
|
- (NSInteger)outlineView:(NSOutlineView *)aOutlineView numberOfChildrenOfItem:(id)item
|
||||||
|
{
|
||||||
|
NSIndexPath *path = item;
|
||||||
|
if ((path != nil) && ([path length] == 1)) {
|
||||||
|
if (_rootChildrenCounts == nil) {
|
||||||
|
_rootChildrenCounts = [[[self py] rootChildrenCounts] retain];
|
||||||
|
}
|
||||||
|
NSInteger index = [path indexAtPosition:0];
|
||||||
|
return n2i([_rootChildrenCounts objectAtIndex:index]);
|
||||||
|
}
|
||||||
|
return [super outlineView:aOutlineView numberOfChildrenOfItem:item];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)column byItem:(id)item
|
||||||
|
{
|
||||||
|
NSIndexPath *path = item;
|
||||||
|
NSString *identifier = [column identifier];
|
||||||
|
if ([identifier isEqual:@"marked"]) {
|
||||||
|
return b2n([self boolProperty:@"marked" valueAtPath:path]);
|
||||||
|
}
|
||||||
|
NSInteger columnId = [identifier integerValue];
|
||||||
|
return [[self py] valueForPath:p2a(path) column:columnId];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)outlineView:(NSOutlineView *)aOutlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
|
||||||
|
{
|
||||||
|
if ([[tableColumn identifier] isEqual:@"0"]) {
|
||||||
|
NSIndexPath *path = item;
|
||||||
|
NSString *oldName = [[self py] valueForPath:p2a(path) column:0];
|
||||||
|
NSString *newName = object;
|
||||||
|
if (![newName isEqual:oldName]) {
|
||||||
|
BOOL renamed = [[self py] renameSelected:newName];
|
||||||
|
if (!renamed) {
|
||||||
|
[Dialogs showMessage:[NSString stringWithFormat:@"The name '%@' already exists.", newName]];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[self refreshItemAtPath:path];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[super outlineView:aOutlineView setObjectValue:object forTableColumn:tableColumn byItem:item];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delegate */
|
||||||
|
- (void)outlineView:(NSOutlineView *)aOutlineView didClickTableColumn:(NSTableColumn *)tableColumn
|
||||||
|
{
|
||||||
|
if ([[outlineView sortDescriptors] count] < 1)
|
||||||
|
return;
|
||||||
|
NSSortDescriptor *sd = [[outlineView sortDescriptors] objectAtIndex:0];
|
||||||
|
[[self py] sortBy:[[sd key] integerValue] ascending:[sd ascending]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||||
|
{
|
||||||
|
NSIndexPath *path = item;
|
||||||
|
BOOL isMarkable = [self boolProperty:@"markable" valueAtPath:path];
|
||||||
|
if ([[tableColumn identifier] isEqual:@"marked"]) {
|
||||||
|
[cell setEnabled:isMarkable];
|
||||||
|
}
|
||||||
|
if ([cell isKindOfClass:[NSTextFieldCell class]]) {
|
||||||
|
// Determine if the text color will be blue due to directory being reference.
|
||||||
|
NSTextFieldCell *textCell = cell;
|
||||||
|
if (isMarkable) {
|
||||||
|
[textCell setTextColor:[NSColor blackColor]];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[textCell setTextColor:[NSColor blueColor]];
|
||||||
|
}
|
||||||
|
if (([self deltaValuesMode]) && ([self powerMarkerMode] || ([path length] > 1))) {
|
||||||
|
NSInteger i = [[tableColumn identifier] integerValue];
|
||||||
|
if ([_deltaColumns containsIndex:i]) {
|
||||||
|
[textCell setTextColor:[NSColor orangeColor]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableViewHadDeletePressed:(NSTableView *)tableView
|
||||||
|
{
|
||||||
|
[self removeSelected];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableViewHadSpacePressed:(NSTableView *)tableView
|
||||||
|
{
|
||||||
|
[[self py] markSelected];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* don't calls saveEdits and cancelEdits */
|
||||||
|
- (void)outlineViewDidEndEditing:(HSOutlineView *)outlineView
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)outlineViewCancelsEdition:(HSOutlineView *)outlineView
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python --> Cocoa */
|
||||||
|
- (void)refresh /* Override */
|
||||||
|
{
|
||||||
|
[_rootChildrenCounts release];
|
||||||
|
_rootChildrenCounts = nil;
|
||||||
|
[super refresh];
|
||||||
|
[outlineView expandItem:nil expandChildren:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)invalidateMarkings
|
||||||
|
{
|
||||||
|
for (NSMutableDictionary *props in [itemData objectEnumerator]) {
|
||||||
|
[props removeObjectForKey:@"marked"];
|
||||||
|
}
|
||||||
|
[outlineView setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
@end
|
||||||
@@ -7,43 +7,34 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "Outline.h"
|
#import "HSOutlineView.h"
|
||||||
|
#import "StatsLabel.h"
|
||||||
|
#import "ResultOutline.h"
|
||||||
#import "PyDupeGuru.h"
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
@interface MatchesView : OutlineView
|
|
||||||
- (void)keyDown:(NSEvent *)theEvent;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface ResultWindowBase : NSWindowController
|
@interface ResultWindowBase : NSWindowController
|
||||||
{
|
{
|
||||||
@protected
|
@protected
|
||||||
IBOutlet PyDupeGuruBase *py;
|
IBOutlet PyDupeGuruBase *py;
|
||||||
IBOutlet id app;
|
IBOutlet id app;
|
||||||
IBOutlet NSSegmentedControl *deltaSwitch;
|
IBOutlet NSSegmentedControl *deltaSwitch;
|
||||||
IBOutlet MatchesView *matches;
|
IBOutlet HSOutlineView *matches;
|
||||||
IBOutlet NSSegmentedControl *pmSwitch;
|
IBOutlet NSSegmentedControl *pmSwitch;
|
||||||
IBOutlet NSTextField *stats;
|
IBOutlet NSTextField *stats;
|
||||||
IBOutlet NSMenu *columnsMenu;
|
IBOutlet NSMenu *columnsMenu;
|
||||||
IBOutlet NSSearchField *filterField;
|
IBOutlet NSSearchField *filterField;
|
||||||
|
|
||||||
BOOL _powerMode;
|
|
||||||
BOOL _displayDelta;
|
|
||||||
NSMutableArray *_resultColumns;
|
NSMutableArray *_resultColumns;
|
||||||
NSMutableIndexSet *_deltaColumns;
|
|
||||||
NSWindowController *preferencesPanel;
|
NSWindowController *preferencesPanel;
|
||||||
|
ResultOutline *outline;
|
||||||
|
StatsLabel *statsLabel;
|
||||||
}
|
}
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
- (void)fillColumnsMenu;
|
- (void)fillColumnsMenu;
|
||||||
- (NSTableColumn *)getColumnForIdentifier:(NSInteger)aIdentifier title:(NSString *)aTitle width:(NSInteger)aWidth refCol:(NSTableColumn *)aColumn;
|
- (NSTableColumn *)getColumnForIdentifier:(NSInteger)aIdentifier title:(NSString *)aTitle width:(NSInteger)aWidth refCol:(NSTableColumn *)aColumn;
|
||||||
- (NSArray *)getColumnsOrder;
|
- (NSArray *)getColumnsOrder;
|
||||||
- (NSDictionary *)getColumnsWidth;
|
- (NSDictionary *)getColumnsWidth;
|
||||||
- (NSArray *)getSelected:(BOOL)aDupesOnly;
|
|
||||||
- (NSArray *)getSelectedPaths:(BOOL)aDupesOnly;
|
|
||||||
- (void)initResultColumns;
|
- (void)initResultColumns;
|
||||||
- (void)updatePySelection;
|
|
||||||
- (void)performPySelection:(NSArray *)aIndexPaths;
|
|
||||||
- (void)refreshStats;
|
|
||||||
- (void)reloadMatches;
|
|
||||||
- (void)restoreColumnsPosition:(NSArray *)aColumnsOrder widths:(NSDictionary *)aColumnsWidth;
|
- (void)restoreColumnsPosition:(NSArray *)aColumnsOrder widths:(NSDictionary *)aColumnsWidth;
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
@@ -59,7 +50,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
- (IBAction)markInvert:(id)sender;
|
- (IBAction)markInvert:(id)sender;
|
||||||
- (IBAction)markNone:(id)sender;
|
- (IBAction)markNone:(id)sender;
|
||||||
- (IBAction)markSelected:(id)sender;
|
- (IBAction)markSelected:(id)sender;
|
||||||
- (IBAction)markToggle:(id)sender;
|
|
||||||
- (IBAction)moveMarked:(id)sender;
|
- (IBAction)moveMarked:(id)sender;
|
||||||
- (IBAction)openClicked:(id)sender;
|
- (IBAction)openClicked:(id)sender;
|
||||||
- (IBAction)openSelected:(id)sender;
|
- (IBAction)openSelected:(id)sender;
|
||||||
@@ -69,6 +59,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
- (IBAction)resetColumnsToDefault:(id)sender;
|
- (IBAction)resetColumnsToDefault:(id)sender;
|
||||||
- (IBAction)revealSelected:(id)sender;
|
- (IBAction)revealSelected:(id)sender;
|
||||||
- (IBAction)showPreferencesPanel:(id)sender;
|
- (IBAction)showPreferencesPanel:(id)sender;
|
||||||
|
- (IBAction)startDuplicateScan:(id)sender;
|
||||||
- (IBAction)switchSelected:(id)sender;
|
- (IBAction)switchSelected:(id)sender;
|
||||||
- (IBAction)toggleColumn:(id)sender;
|
- (IBAction)toggleColumn:(id)sender;
|
||||||
- (IBAction)toggleDelta:(id)sender;
|
- (IBAction)toggleDelta:(id)sender;
|
||||||
|
|||||||
@@ -14,66 +14,29 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
#import "Consts.h"
|
#import "Consts.h"
|
||||||
|
|
||||||
@implementation MatchesView
|
|
||||||
- (void)keyDown:(NSEvent *)theEvent
|
|
||||||
{
|
|
||||||
unichar key = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
|
||||||
// get flags and strip the lower 16 (device dependant) bits
|
|
||||||
NSUInteger flags = ( [theEvent modifierFlags] & 0x00FF );
|
|
||||||
if (((key == NSDeleteFunctionKey) || (key == NSDeleteCharacter)) && (flags == 0))
|
|
||||||
[self sendAction:@selector(removeSelected:) to:[self delegate]];
|
|
||||||
else
|
|
||||||
if ((key == 0x20) && (flags == 0)) // Space
|
|
||||||
[self sendAction:@selector(markSelected:) to:[self delegate]];
|
|
||||||
else
|
|
||||||
[super keyDown:theEvent];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
|
|
||||||
{
|
|
||||||
if (![[tableColumn identifier] isEqual:@"0"])
|
|
||||||
return; //We only want to cover renames.
|
|
||||||
OVNode *node = item;
|
|
||||||
NSString *oldName = [[node buffer] objectAtIndex:0];
|
|
||||||
NSString *newName = object;
|
|
||||||
if (![newName isEqual:oldName])
|
|
||||||
{
|
|
||||||
BOOL renamed = n2b([(PyDupeGuruBase *)py renameSelected:newName]);
|
|
||||||
if (renamed)
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
else
|
|
||||||
[Dialogs showMessage:[NSString stringWithFormat:@"The name '%@' already exists.",newName]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation ResultWindowBase
|
@implementation ResultWindowBase
|
||||||
- (void)awakeFromNib
|
- (void)awakeFromNib
|
||||||
{
|
{
|
||||||
_displayDelta = NO;
|
|
||||||
_powerMode = NO;
|
|
||||||
[self window];
|
[self window];
|
||||||
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
||||||
|
outline = [[ResultOutline alloc] initWithPyParent:py view:matches];
|
||||||
|
statsLabel = [[StatsLabel alloc] initWithPyParent:py labelView:stats];
|
||||||
[self initResultColumns];
|
[self initResultColumns];
|
||||||
[self fillColumnsMenu];
|
[self fillColumnsMenu];
|
||||||
[deltaSwitch setSelectedSegment:0];
|
[deltaSwitch setSelectedSegment:0];
|
||||||
[pmSwitch setSelectedSegment:0];
|
[pmSwitch setSelectedSegment:0];
|
||||||
[py setDisplayDeltaValues:b2n(_displayDelta)];
|
|
||||||
[matches setTarget:self];
|
[matches setTarget:self];
|
||||||
[matches setDoubleAction:@selector(openClicked:)];
|
[matches setDoubleAction:@selector(openClicked:)];
|
||||||
[self refreshStats];
|
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(registrationRequired:) name:RegistrationRequired object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(registrationRequired:) name:RegistrationRequired object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobCompleted:) name:JobCompletedNotification object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobCompleted:) name:JobCompletedNotification object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobStarted:) name:JobStarted object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobStarted:) name:JobStarted object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobInProgress:) name:JobInProgress object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobInProgress:) name:JobInProgress object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsMarkingChanged:) name:ResultsMarkingChangedNotification object:nil];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsChanged:) name:ResultsChangedNotification object:nil];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsUpdated:) name:ResultsUpdatedNotification object:nil];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
|
[outline release];
|
||||||
[preferencesPanel release];
|
[preferencesPanel release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
@@ -130,34 +93,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)getSelected:(BOOL)aDupesOnly
|
|
||||||
{
|
|
||||||
if (_powerMode)
|
|
||||||
aDupesOnly = NO;
|
|
||||||
NSIndexSet *indexes = [matches selectedRowIndexes];
|
|
||||||
NSMutableArray *nodeList = [NSMutableArray array];
|
|
||||||
OVNode *node;
|
|
||||||
NSInteger i = [indexes firstIndex];
|
|
||||||
while (i != NSNotFound)
|
|
||||||
{
|
|
||||||
node = [matches itemAtRow:i];
|
|
||||||
if (!aDupesOnly || ([node level] > 1))
|
|
||||||
[nodeList addObject:node];
|
|
||||||
i = [indexes indexGreaterThanIndex:i];
|
|
||||||
}
|
|
||||||
return nodeList;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *)getSelectedPaths:(BOOL)aDupesOnly
|
|
||||||
{
|
|
||||||
NSMutableArray *r = [NSMutableArray array];
|
|
||||||
NSArray *selected = [self getSelected:aDupesOnly];
|
|
||||||
for (OVNode *node in selected) {
|
|
||||||
[r addObject:p2a([node indexPath])];
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)initResultColumns
|
- (void)initResultColumns
|
||||||
{
|
{
|
||||||
// Virtual
|
// Virtual
|
||||||
@@ -172,12 +107,13 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
}
|
}
|
||||||
//Add columns and set widths
|
//Add columns and set widths
|
||||||
for (NSString *colId in aColumnsOrder) {
|
for (NSString *colId in aColumnsOrder) {
|
||||||
if ([colId isEqual:@"mark"]) {
|
NSInteger colIndex = [colId integerValue];
|
||||||
|
if ((colIndex == 0) && (![colId isEqual:@"0"])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
NSTableColumn *col = [_resultColumns objectAtIndex:[colId intValue]];
|
NSTableColumn *col = [_resultColumns objectAtIndex:colIndex];
|
||||||
NSNumber *width = [aColumnsWidth objectForKey:[col identifier]];
|
NSNumber *width = [aColumnsWidth objectForKey:[col identifier]];
|
||||||
NSMenuItem *mi = [columnsMenu itemWithTag:[colId intValue]];
|
NSMenuItem *mi = [columnsMenu itemWithTag:colIndex];
|
||||||
if (width) {
|
if (width) {
|
||||||
[col setWidth:[width floatValue]];
|
[col setWidth:[width floatValue]];
|
||||||
}
|
}
|
||||||
@@ -185,43 +121,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updatePySelection
|
|
||||||
{
|
|
||||||
NSArray *selection;
|
|
||||||
if (_powerMode) {
|
|
||||||
selection = [py selectedPowerMarkerNodePaths];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
selection = [py selectedResultNodePaths];
|
|
||||||
}
|
|
||||||
[matches selectNodePaths:selection];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)performPySelection:(NSArray *)aIndexPaths
|
|
||||||
{
|
|
||||||
if (_powerMode) {
|
|
||||||
[py selectPowerMarkerNodePaths:aIndexPaths];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
[py selectResultNodePaths:aIndexPaths];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)refreshStats
|
|
||||||
{
|
|
||||||
[stats setStringValue:[py getStatLine]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reload the matches outline and restore selection from py */
|
|
||||||
- (void)reloadMatches
|
|
||||||
{
|
|
||||||
[matches setDelegate:nil];
|
|
||||||
[matches reloadData];
|
|
||||||
[matches expandItem:nil expandChildren:YES];
|
|
||||||
[matches setDelegate:self];
|
|
||||||
[self updatePySelection];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
- (IBAction)clearIgnoreList:(id)sender
|
- (IBAction)clearIgnoreList:(id)sender
|
||||||
{
|
{
|
||||||
@@ -235,21 +134,12 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (IBAction)changeDelta:(id)sender
|
- (IBAction)changeDelta:(id)sender
|
||||||
{
|
{
|
||||||
_displayDelta = [deltaSwitch selectedSegment] == 1;
|
[outline setDeltaValuesMode:[deltaSwitch selectedSegment] == 1];
|
||||||
[py setDisplayDeltaValues:b2n(_displayDelta)];
|
|
||||||
[self reloadMatches];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)changePowerMarker:(id)sender
|
- (IBAction)changePowerMarker:(id)sender
|
||||||
{
|
{
|
||||||
_powerMode = [pmSwitch selectedSegment] == 1;
|
[outline setPowerMarkerMode:[pmSwitch selectedSegment] == 1];
|
||||||
if (_powerMode)
|
|
||||||
[matches setTag:2];
|
|
||||||
else
|
|
||||||
[matches setTag:0];
|
|
||||||
[matches expandItem:nil expandChildren:YES];
|
|
||||||
[self outlineView:matches didClickTableColumn:nil];
|
|
||||||
[self updatePySelection];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)copyMarked:(id)sender
|
- (IBAction)copyMarked:(id)sender
|
||||||
@@ -294,52 +184,37 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||||
[py setEscapeFilterRegexp:b2n(!n2b([ud objectForKey:@"useRegexpFilter"]))];
|
[py setEscapeFilterRegexp:b2n(!n2b([ud objectForKey:@"useRegexpFilter"]))];
|
||||||
[py applyFilter:[filterField stringValue]];
|
[py applyFilter:[filterField stringValue]];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)ignoreSelected:(id)sender
|
- (IBAction)ignoreSelected:(id)sender
|
||||||
{
|
{
|
||||||
NSArray *nodeList = [self getSelected:YES];
|
NSInteger selectedDupeCount = [outline selectedDupeCount];
|
||||||
if (![nodeList count])
|
if (!selectedDupeCount)
|
||||||
return;
|
return;
|
||||||
NSString *msg = [NSString stringWithFormat:@"All selected %d matches are going to be ignored in all subsequent scans. Continue?",[nodeList count]];
|
NSString *msg = [NSString stringWithFormat:@"All selected %d matches are going to be ignored in all subsequent scans. Continue?",selectedDupeCount];
|
||||||
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
||||||
return;
|
return;
|
||||||
[py addSelectedToIgnoreList];
|
[py addSelectedToIgnoreList];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)markAll:(id)sender
|
- (IBAction)markAll:(id)sender
|
||||||
{
|
{
|
||||||
[py markAll];
|
[py markAll];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsMarkingChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)markInvert:(id)sender
|
- (IBAction)markInvert:(id)sender
|
||||||
{
|
{
|
||||||
[py markInvert];
|
[py markInvert];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsMarkingChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)markNone:(id)sender
|
- (IBAction)markNone:(id)sender
|
||||||
{
|
{
|
||||||
[py markNone];
|
[py markNone];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsMarkingChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)markSelected:(id)sender
|
- (IBAction)markSelected:(id)sender
|
||||||
{
|
{
|
||||||
[self performPySelection:[self getSelectedPaths:YES]];
|
|
||||||
[py toggleSelectedMark];
|
[py toggleSelectedMark];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsMarkingChangedNotification object:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (IBAction)markToggle:(id)sender
|
|
||||||
{
|
|
||||||
OVNode *node = [matches itemAtRow:[matches clickedRow]];
|
|
||||||
[self performPySelection:[NSArray arrayWithObject:p2a([node indexPath])]];
|
|
||||||
[py toggleSelectedMark];
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsMarkingChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)moveMarked:(id)sender
|
- (IBAction)moveMarked:(id)sender
|
||||||
@@ -373,15 +248,9 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (IBAction)openSelected:(id)sender
|
- (IBAction)openSelected:(id)sender
|
||||||
{
|
{
|
||||||
[self performPySelection:[self getSelectedPaths:NO]];
|
|
||||||
[py openSelected];
|
[py openSelected];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)refresh:(id)sender
|
|
||||||
{
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (IBAction)removeMarked:(id)sender
|
- (IBAction)removeMarked:(id)sender
|
||||||
{
|
{
|
||||||
int mark_count = [[py getMarkCount] intValue];
|
int mark_count = [[py getMarkCount] intValue];
|
||||||
@@ -390,19 +259,11 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
if ([Dialogs askYesNo:[NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",mark_count]] == NSAlertSecondButtonReturn) // NO
|
if ([Dialogs askYesNo:[NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",mark_count]] == NSAlertSecondButtonReturn) // NO
|
||||||
return;
|
return;
|
||||||
[py removeMarked];
|
[py removeMarked];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)removeSelected:(id)sender
|
- (IBAction)removeSelected:(id)sender
|
||||||
{
|
{
|
||||||
NSArray *nodeList = [self getSelected:YES];
|
[outline removeSelected];
|
||||||
if (![nodeList count])
|
|
||||||
return;
|
|
||||||
if ([Dialogs askYesNo:[NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",[nodeList count]]] == NSAlertSecondButtonReturn) // NO
|
|
||||||
return;
|
|
||||||
[self performPySelection:[self getSelectedPaths:YES]];
|
|
||||||
[py removeSelected];
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)renameSelected:(id)sender
|
- (IBAction)renameSelected:(id)sender
|
||||||
@@ -419,7 +280,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (IBAction)revealSelected:(id)sender
|
- (IBAction)revealSelected:(id)sender
|
||||||
{
|
{
|
||||||
[self performPySelection:[self getSelectedPaths:NO]];
|
|
||||||
[py revealSelected];
|
[py revealSelected];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,21 +288,14 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[preferencesPanel showWindow:sender];
|
[preferencesPanel showWindow:sender];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (IBAction)startDuplicateScan:(id)sender
|
||||||
|
{
|
||||||
|
// Virtual
|
||||||
|
}
|
||||||
|
|
||||||
- (IBAction)switchSelected:(id)sender
|
- (IBAction)switchSelected:(id)sender
|
||||||
{
|
{
|
||||||
// It might look like a complicated way to get the length of the current dupe list on the py side
|
|
||||||
// but after a lot of fussing around, believe it or not, it actually is.
|
|
||||||
NSInteger matchesTag = _powerMode ? 2 : 0;
|
|
||||||
NSInteger startLen = [[py getOutlineView:matchesTag childCountsForPath:[NSArray array]] count];
|
|
||||||
[py makeSelectedReference];
|
[py makeSelectedReference];
|
||||||
[self performPySelection:[self getSelectedPaths:NO]];
|
|
||||||
// In some cases (when in a filtered view in Power Marker mode, it's possible that the demoted
|
|
||||||
// ref is not a part of the filter, making the table smaller. In those cases, we want to do a
|
|
||||||
// complete reload of the table to avoid a crash.
|
|
||||||
if ([[py getOutlineView:matchesTag childCountsForPath:[NSArray array]] count] == startLen)
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsUpdatedNotification object:self];
|
|
||||||
else
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)toggleColumn:(id)sender
|
- (IBAction)toggleColumn:(id)sender
|
||||||
@@ -488,43 +341,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[self changePowerMarker:sender];
|
[self changePowerMarker:sender];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delegate */
|
|
||||||
- (void)outlineView:(NSOutlineView *)outlineView didClickTableColumn:(NSTableColumn *)tableColumn
|
|
||||||
{
|
|
||||||
if ([[outlineView sortDescriptors] count] < 1)
|
|
||||||
return;
|
|
||||||
NSSortDescriptor *sd = [[outlineView sortDescriptors] objectAtIndex:0];
|
|
||||||
if (_powerMode)
|
|
||||||
[py sortDupesBy:i2n([[sd key] intValue]) ascending:b2n([sd ascending])];
|
|
||||||
else
|
|
||||||
[py sortGroupsBy:i2n([[sd key] intValue]) ascending:b2n([sd ascending])];
|
|
||||||
[self reloadMatches];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
|
||||||
{
|
|
||||||
OVNode *node = item;
|
|
||||||
if ([[tableColumn identifier] isEqual:@"mark"]) {
|
|
||||||
[cell setEnabled: [node isMarkable]];
|
|
||||||
}
|
|
||||||
if ([cell isKindOfClass:[NSTextFieldCell class]]) {
|
|
||||||
// Determine if the text color will be blue due to directory being reference.
|
|
||||||
NSTextFieldCell *textCell = cell;
|
|
||||||
if ([node isMarkable]) {
|
|
||||||
[textCell setTextColor:[NSColor blackColor]];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
[textCell setTextColor:[NSColor blueColor]];
|
|
||||||
}
|
|
||||||
if ((_displayDelta) && (_powerMode || ([node level] > 1))) {
|
|
||||||
NSInteger i = [[tableColumn identifier] integerValue];
|
|
||||||
if ([_deltaColumns containsIndex:i]) {
|
|
||||||
[textCell setTextColor:[NSColor orangeColor]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Notifications */
|
/* Notifications */
|
||||||
- (void)windowWillClose:(NSNotification *)aNotification
|
- (void)windowWillClose:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
@@ -533,7 +349,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (void)jobCompleted:(NSNotification *)aNotification
|
- (void)jobCompleted:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
NSInteger r = n2i([py getOperationalErrorCount]);
|
NSInteger r = n2i([py getOperationalErrorCount]);
|
||||||
id lastAction = [[ProgressController mainProgressController] jobId];
|
id lastAction = [[ProgressController mainProgressController] jobId];
|
||||||
if ([lastAction isEqualTo:jobCopy]) {
|
if ([lastAction isEqualTo:jobCopy]) {
|
||||||
@@ -558,7 +373,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[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 = [[py getOutlineView:0 childCountsForPath:[NSArray array]] count];
|
NSInteger groupCount = [outline intProperty:@"children_count" valueAtPath:nil];
|
||||||
if (groupCount == 0)
|
if (groupCount == 0)
|
||||||
[Dialogs showMessage:@"No duplicates found."];
|
[Dialogs showMessage:@"No duplicates found."];
|
||||||
}
|
}
|
||||||
@@ -589,29 +404,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[Dialogs showMessage:msg];
|
[Dialogs showMessage:msg];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
|
|
||||||
{
|
|
||||||
[self performPySelection:[self getSelectedPaths:NO]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resultsChanged:(NSNotification *)aNotification
|
|
||||||
{
|
|
||||||
[self reloadMatches];
|
|
||||||
[self refreshStats];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resultsMarkingChanged:(NSNotification *)aNotification
|
|
||||||
{
|
|
||||||
[matches invalidateMarkings];
|
|
||||||
[self refreshStats];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resultsUpdated:(NSNotification *)aNotification
|
|
||||||
{
|
|
||||||
[matches invalidateBuffers];
|
|
||||||
[matches invalidateMarkings];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
|
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
|
||||||
{
|
{
|
||||||
return ![[ProgressController mainProgressController] isShown];
|
return ![[ProgressController mainProgressController] isShown];
|
||||||
|
|||||||
19
cocoa/base/StatsLabel.h
Normal file
19
cocoa/base/StatsLabel.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||||
|
|
||||||
|
This software is licensed under the "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 "HSGUIController.h"
|
||||||
|
#import "PyStatsLabel.h"
|
||||||
|
|
||||||
|
@interface StatsLabel : HSGUIController
|
||||||
|
{
|
||||||
|
NSTextField *labelView;
|
||||||
|
}
|
||||||
|
- (id)initWithPyParent:(id)aPyParent labelView:(NSTextField *)aLabelView;
|
||||||
|
- (PyStatsLabel *)py;
|
||||||
|
@end
|
||||||
38
cocoa/base/StatsLabel.m
Normal file
38
cocoa/base/StatsLabel.m
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||||
|
|
||||||
|
This software is licensed under the "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 "StatsLabel.h"
|
||||||
|
#import "Utils.h"
|
||||||
|
|
||||||
|
@implementation StatsLabel
|
||||||
|
- (id)initWithPyParent:(id)aPyParent labelView:(NSTextField *)aLabelView
|
||||||
|
{
|
||||||
|
self = [super initWithPyClassName:@"PyStatsLabel" pyParent:aPyParent];
|
||||||
|
labelView = [aLabelView retain];
|
||||||
|
[self connect];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[self disconnect];
|
||||||
|
[labelView release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (PyStatsLabel *)py
|
||||||
|
{
|
||||||
|
return (PyStatsLabel *)py;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python --> Cocoa */
|
||||||
|
- (void)refresh
|
||||||
|
{
|
||||||
|
[labelView setStringValue:[[self py] display]];
|
||||||
|
}
|
||||||
|
@end
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
</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="219"/>
|
||||||
<integer value="29"/>
|
<integer value="29"/>
|
||||||
<integer value="21"/>
|
|
||||||
</object>
|
</object>
|
||||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
@@ -710,7 +710,7 @@
|
|||||||
<object class="NSMutableArray" key="NSTableColumns">
|
<object class="NSMutableArray" key="NSTableColumns">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSTableColumn" id="430098394">
|
<object class="NSTableColumn" id="430098394">
|
||||||
<string key="NSIdentifier">mark</string>
|
<string key="NSIdentifier">marked</string>
|
||||||
<double key="NSWidth">47</double>
|
<double key="NSWidth">47</double>
|
||||||
<double key="NSMinWidth">16</double>
|
<double key="NSMinWidth">16</double>
|
||||||
<double key="NSMaxWidth">1000</double>
|
<double key="NSMaxWidth">1000</double>
|
||||||
@@ -752,6 +752,7 @@
|
|||||||
<int key="NSPeriodicDelay">400</int>
|
<int key="NSPeriodicDelay">400</int>
|
||||||
<int key="NSPeriodicInterval">75</int>
|
<int key="NSPeriodicInterval">75</int>
|
||||||
</object>
|
</object>
|
||||||
|
<bool key="NSIsEditable">YES</bool>
|
||||||
<reference key="NSTableView" ref="40047569"/>
|
<reference key="NSTableView" ref="40047569"/>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSTableColumn" id="932540235">
|
<object class="NSTableColumn" id="932540235">
|
||||||
@@ -1667,14 +1668,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">212</int>
|
<int key="connectionID">212</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">matches</string>
|
|
||||||
<reference key="source" ref="339936126"/>
|
|
||||||
<reference key="destination" ref="40047569"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">245</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBOutletConnection" key="connection">
|
<object class="IBOutletConnection" key="connection">
|
||||||
<string key="label">initialFirstResponder</string>
|
<string key="label">initialFirstResponder</string>
|
||||||
@@ -1683,22 +1676,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">279</int>
|
<int key="connectionID">279</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">delegate</string>
|
|
||||||
<reference key="source" ref="40047569"/>
|
|
||||||
<reference key="destination" ref="339936126"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">410</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">markToggle:</string>
|
|
||||||
<reference key="source" ref="339936126"/>
|
|
||||||
<reference key="destination" ref="705360835"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">414</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBOutletConnection" key="connection">
|
<object class="IBOutletConnection" key="connection">
|
||||||
<string key="label">stats</string>
|
<string key="label">stats</string>
|
||||||
@@ -1939,14 +1916,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">758</int>
|
<int key="connectionID">758</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">py</string>
|
|
||||||
<reference key="source" ref="40047569"/>
|
|
||||||
<reference key="destination" ref="875360857"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">764</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBActionConnection" key="connection">
|
<object class="IBActionConnection" key="connection">
|
||||||
<string key="label">removeSelected:</string>
|
<string key="label">removeSelected:</string>
|
||||||
@@ -2227,6 +2196,14 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">1175</int>
|
<int key="connectionID">1175</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBOutletConnection" key="connection">
|
||||||
|
<string key="label">matches</string>
|
||||||
|
<reference key="source" ref="339936126"/>
|
||||||
|
<reference key="destination" ref="40047569"/>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">1176</int>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<object class="NSArray" key="orderedObjects">
|
<object class="NSArray" key="orderedObjects">
|
||||||
@@ -3406,7 +3383,7 @@
|
|||||||
<string>{340, 340}</string>
|
<string>{340, 340}</string>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<string>MatchesView</string>
|
<string>HSOutlineView</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>
|
||||||
@@ -3584,7 +3561,7 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">1175</int>
|
<int key="maxID">1176</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">
|
||||||
@@ -3663,7 +3640,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
<string key="majorKey">IBProjectSource</string>
|
<string key="majorKey">IBProjectSource</string>
|
||||||
<string key="minorKey">dgbase/AppDelegate.h</string>
|
<string key="minorKey">../base/AppDelegate.h</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
@@ -3675,19 +3652,22 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
<string key="className">MatchesView</string>
|
<string key="className">HSOutlineView</string>
|
||||||
<string key="superclassName">OutlineView</string>
|
<string key="superclassName">NSOutlineView</string>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="417275989">
|
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="384069338">
|
||||||
<string key="majorKey">IBProjectSource</string>
|
<string key="majorKey">IBProjectSource</string>
|
||||||
<string key="minorKey">dgbase/ResultWindow.h</string>
|
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
<string key="className">MatchesView</string>
|
<string key="className">NSObject</string>
|
||||||
<string key="superclassName">OutlineView</string>
|
<reference key="sourceIdentifier" ref="384069338"/>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
</object>
|
||||||
<string key="majorKey">IBUserSource</string>
|
<object class="IBPartialClassDescription">
|
||||||
<string key="minorKey"/>
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="653924221">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
@@ -3699,31 +3679,15 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
<string key="className">OutlineView</string>
|
<string key="className">NSTableView</string>
|
||||||
<string key="superclassName">NSOutlineView</string>
|
<reference key="sourceIdentifier" ref="653924221"/>
|
||||||
<object class="NSMutableDictionary" key="outlets">
|
|
||||||
<string key="NS.key.0">py</string>
|
|
||||||
<string key="NS.object.0">PyApp</string>
|
|
||||||
</object>
|
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
|
||||||
<string key="majorKey">IBProjectSource</string>
|
|
||||||
<string key="minorKey">cocoalib/Outline.h</string>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<object class="IBPartialClassDescription">
|
|
||||||
<string key="className">OutlineView</string>
|
|
||||||
<string key="superclassName">NSOutlineView</string>
|
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
|
||||||
<string key="majorKey">IBUserSource</string>
|
|
||||||
<string key="minorKey"/>
|
|
||||||
</object>
|
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
<string key="className">PyApp</string>
|
<string key="className">PyApp</string>
|
||||||
<string key="superclassName">PyRegistrable</string>
|
<string key="superclassName">PyRegistrable</string>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
<string key="majorKey">IBProjectSource</string>
|
<string key="majorKey">IBProjectSource</string>
|
||||||
<string key="minorKey">cocoalib/PyApp.h</string>
|
<string key="minorKey">../PyApp.h</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
@@ -3755,7 +3719,7 @@
|
|||||||
<string key="superclassName">PyApp</string>
|
<string key="superclassName">PyApp</string>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
<string key="majorKey">IBProjectSource</string>
|
<string key="majorKey">IBProjectSource</string>
|
||||||
<string key="minorKey">dgbase/PyDupeGuru.h</string>
|
<string key="minorKey">../base/PyDupeGuru.h</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
@@ -3763,7 +3727,7 @@
|
|||||||
<string key="superclassName">NSObject</string>
|
<string key="superclassName">NSObject</string>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
<string key="majorKey">IBProjectSource</string>
|
<string key="majorKey">IBProjectSource</string>
|
||||||
<string key="minorKey">cocoalib/PyRegistrable.h</string>
|
<string key="minorKey">../PyRegistrable.h</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
@@ -3797,7 +3761,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
<string key="majorKey">IBProjectSource</string>
|
<string key="majorKey">IBProjectSource</string>
|
||||||
<string key="minorKey">cocoalib/RecentDirectories.h</string>
|
<string key="minorKey">../RecentDirectories.h</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
@@ -3812,123 +3776,14 @@
|
|||||||
<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">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<string key="NS.key.0">removeDeadTracks:</string>
|
||||||
<object class="NSArray" key="dict.sortedKeys">
|
<string key="NS.object.0">id</string>
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<string>clearIgnoreList:</string>
|
|
||||||
<string>filter:</string>
|
|
||||||
<string>ignoreSelected:</string>
|
|
||||||
<string>markAll:</string>
|
|
||||||
<string>markInvert:</string>
|
|
||||||
<string>markNone:</string>
|
|
||||||
<string>markSelected:</string>
|
|
||||||
<string>markToggle:</string>
|
|
||||||
<string>openSelected:</string>
|
|
||||||
<string>refresh:</string>
|
|
||||||
<string>removeMarked:</string>
|
|
||||||
<string>removeSelected:</string>
|
|
||||||
<string>renameSelected:</string>
|
|
||||||
<string>resetColumnsToDefault:</string>
|
|
||||||
<string>revealSelected:</string>
|
|
||||||
<string>startDuplicateScan:</string>
|
|
||||||
<string>toggleDelta:</string>
|
|
||||||
</object>
|
|
||||||
<object class="NSMutableArray" key="dict.values">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<object class="NSMutableDictionary" key="outlets">
|
|
||||||
<string key="NS.key.0">filterField</string>
|
|
||||||
<string key="NS.object.0">NSSearchField</string>
|
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
<string key="majorKey">IBProjectSource</string>
|
<string key="majorKey">IBProjectSource</string>
|
||||||
<string key="minorKey">ResultWindow.h</string>
|
<string key="minorKey">ResultWindow.h</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
|
||||||
<string key="className">ResultWindow</string>
|
|
||||||
<string key="superclassName">ResultWindowBase</string>
|
|
||||||
<object class="NSMutableDictionary" key="actions">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<object class="NSArray" key="dict.sortedKeys">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<string>changeDelta:</string>
|
|
||||||
<string>changePowerMarker:</string>
|
|
||||||
<string>collapseAll:</string>
|
|
||||||
<string>copyMarked:</string>
|
|
||||||
<string>deleteMarked:</string>
|
|
||||||
<string>expandAll:</string>
|
|
||||||
<string>exportToXHTML:</string>
|
|
||||||
<string>moveMarked:</string>
|
|
||||||
<string>switchSelected:</string>
|
|
||||||
<string>togglePowerMarker:</string>
|
|
||||||
</object>
|
|
||||||
<object class="NSMutableArray" key="dict.values">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>id</string>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<object class="NSMutableDictionary" key="outlets">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<object class="NSArray" key="dict.sortedKeys">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<string>actionMenuView</string>
|
|
||||||
<string>app</string>
|
|
||||||
<string>deltaSwitch</string>
|
|
||||||
<string>deltaSwitchView</string>
|
|
||||||
<string>filterFieldView</string>
|
|
||||||
<string>matches</string>
|
|
||||||
<string>pmSwitch</string>
|
|
||||||
<string>pmSwitchView</string>
|
|
||||||
<string>py</string>
|
|
||||||
<string>stats</string>
|
|
||||||
</object>
|
|
||||||
<object class="NSMutableArray" key="dict.values">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<string>NSView</string>
|
|
||||||
<string>id</string>
|
|
||||||
<string>NSSegmentedControl</string>
|
|
||||||
<string>NSView</string>
|
|
||||||
<string>NSView</string>
|
|
||||||
<string>MatchesView</string>
|
|
||||||
<string>NSSegmentedControl</string>
|
|
||||||
<string>NSView</string>
|
|
||||||
<string>PyDupeGuru</string>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
|
||||||
<string key="majorKey">IBUserSource</string>
|
|
||||||
<string key="minorKey"/>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
<string key="className">ResultWindowBase</string>
|
<string key="className">ResultWindowBase</string>
|
||||||
<string key="superclassName">NSWindowController</string>
|
<string key="superclassName">NSWindowController</string>
|
||||||
@@ -3938,15 +3793,29 @@
|
|||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<string>changeDelta:</string>
|
<string>changeDelta:</string>
|
||||||
<string>changePowerMarker:</string>
|
<string>changePowerMarker:</string>
|
||||||
|
<string>clearIgnoreList:</string>
|
||||||
<string>copyMarked:</string>
|
<string>copyMarked:</string>
|
||||||
<string>deleteMarked:</string>
|
<string>deleteMarked:</string>
|
||||||
<string>expandAll:</string>
|
|
||||||
<string>exportToXHTML:</string>
|
<string>exportToXHTML:</string>
|
||||||
|
<string>filter:</string>
|
||||||
|
<string>ignoreSelected:</string>
|
||||||
|
<string>markAll:</string>
|
||||||
|
<string>markInvert:</string>
|
||||||
|
<string>markNone:</string>
|
||||||
|
<string>markSelected:</string>
|
||||||
<string>moveMarked:</string>
|
<string>moveMarked:</string>
|
||||||
|
<string>openClicked:</string>
|
||||||
|
<string>openSelected:</string>
|
||||||
|
<string>removeMarked:</string>
|
||||||
|
<string>removeSelected:</string>
|
||||||
|
<string>renameSelected:</string>
|
||||||
<string>resetColumnsToDefault:</string>
|
<string>resetColumnsToDefault:</string>
|
||||||
|
<string>revealSelected:</string>
|
||||||
<string>showPreferencesPanel:</string>
|
<string>showPreferencesPanel:</string>
|
||||||
|
<string>startDuplicateScan:</string>
|
||||||
<string>switchSelected:</string>
|
<string>switchSelected:</string>
|
||||||
<string>toggleColumn:</string>
|
<string>toggleColumn:</string>
|
||||||
|
<string>toggleDelta:</string>
|
||||||
<string>toggleDetailsPanel:</string>
|
<string>toggleDetailsPanel:</string>
|
||||||
<string>togglePowerMarker:</string>
|
<string>togglePowerMarker:</string>
|
||||||
</object>
|
</object>
|
||||||
@@ -3965,6 +3834,20 @@
|
|||||||
<string>id</string>
|
<string>id</string>
|
||||||
<string>id</string>
|
<string>id</string>
|
||||||
<string>id</string>
|
<string>id</string>
|
||||||
|
<string>id</string>
|
||||||
|
<string>id</string>
|
||||||
|
<string>id</string>
|
||||||
|
<string>id</string>
|
||||||
|
<string>id</string>
|
||||||
|
<string>id</string>
|
||||||
|
<string>id</string>
|
||||||
|
<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">
|
||||||
@@ -3974,6 +3857,7 @@
|
|||||||
<string>app</string>
|
<string>app</string>
|
||||||
<string>columnsMenu</string>
|
<string>columnsMenu</string>
|
||||||
<string>deltaSwitch</string>
|
<string>deltaSwitch</string>
|
||||||
|
<string>filterField</string>
|
||||||
<string>matches</string>
|
<string>matches</string>
|
||||||
<string>pmSwitch</string>
|
<string>pmSwitch</string>
|
||||||
<string>py</string>
|
<string>py</string>
|
||||||
@@ -3984,13 +3868,17 @@
|
|||||||
<string>id</string>
|
<string>id</string>
|
||||||
<string>NSMenu</string>
|
<string>NSMenu</string>
|
||||||
<string>NSSegmentedControl</string>
|
<string>NSSegmentedControl</string>
|
||||||
<string>MatchesView</string>
|
<string>NSSearchField</string>
|
||||||
|
<string>HSOutlineView</string>
|
||||||
<string>NSSegmentedControl</string>
|
<string>NSSegmentedControl</string>
|
||||||
<string>PyDupeGuruBase</string>
|
<string>PyDupeGuruBase</string>
|
||||||
<string>NSTextField</string>
|
<string>NSTextField</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<reference key="sourceIdentifier" ref="417275989"/>
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../base/ResultWindow.h</string>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
<string key="className">SUUpdater</string>
|
<string key="className">SUUpdater</string>
|
||||||
@@ -4612,7 +4500,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">../../dupeguru.xcodeproj</string>
|
<string key="IBDocument.LastKnownRelativeProjectPath">../../me/dupeguru.xcodeproj</string>
|
||||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||||
</data>
|
</data>
|
||||||
</archive>
|
</archive>
|
||||||
|
|||||||
@@ -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.1</string>
|
<string>5.7.2</string>
|
||||||
<key>NSMainNibFile</key>
|
<key>NSMainNibFile</key>
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|||||||
@@ -7,14 +7,9 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "../../cocoalib/Outline.h"
|
|
||||||
#import "../base/ResultWindow.h"
|
#import "../base/ResultWindow.h"
|
||||||
#import "DirectoryPanel.h"
|
#import "DirectoryPanel.h"
|
||||||
|
|
||||||
@interface ResultWindow : ResultWindowBase
|
@interface ResultWindow : ResultWindowBase {}
|
||||||
{
|
|
||||||
NSString *_lastAction;
|
|
||||||
}
|
|
||||||
- (IBAction)removeDeadTracks:(id)sender;
|
- (IBAction)removeDeadTracks:(id)sender;
|
||||||
- (IBAction)startDuplicateScan:(id)sender;
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
{
|
{
|
||||||
[super awakeFromNib];
|
[super awakeFromNib];
|
||||||
[[self window] setTitle:@"dupeGuru Music Edition"];
|
[[self window] setTitle:@"dupeGuru Music Edition"];
|
||||||
_deltaColumns = [[NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,7)] retain];
|
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,7)];
|
||||||
[_deltaColumns removeIndex:6];
|
[deltaColumns removeIndex:6];
|
||||||
|
[outline setDeltaColumns:deltaColumns];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
@@ -68,8 +69,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[_py setMixFileKind:[ud objectForKey:@"mixFileKind"]];
|
[_py setMixFileKind:[ud objectForKey:@"mixFileKind"]];
|
||||||
[_py setMatchSimilarWords:[ud objectForKey:@"matchSimilarWords"]];
|
[_py setMatchSimilarWords:[ud objectForKey:@"matchSimilarWords"]];
|
||||||
NSInteger r = n2i([py doScan]);
|
NSInteger r = n2i([py doScan]);
|
||||||
[matches reloadData];
|
|
||||||
[self refreshStats];
|
|
||||||
if (r == 1)
|
if (r == 1)
|
||||||
[Dialogs showMessage:@"You cannot make a duplicate scan with only reference directories."];
|
[Dialogs showMessage:@"You cannot make a duplicate scan with only reference directories."];
|
||||||
if (r == 3)
|
if (r == 3)
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ from core_me.app_cocoa import DupeGuruME
|
|||||||
from core.scanner import (SCAN_TYPE_FILENAME, SCAN_TYPE_FIELDS, SCAN_TYPE_FIELDS_NO_ORDER,
|
from core.scanner import (SCAN_TYPE_FILENAME, SCAN_TYPE_FIELDS, SCAN_TYPE_FIELDS_NO_ORDER,
|
||||||
SCAN_TYPE_TAG, SCAN_TYPE_CONTENT, SCAN_TYPE_CONTENT_AUDIO)
|
SCAN_TYPE_TAG, SCAN_TYPE_CONTENT, SCAN_TYPE_CONTENT_AUDIO)
|
||||||
|
|
||||||
# Fix py2app imports which chokes on relative imports
|
# 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 hsmedia import aiff, flac, genres, id3v1, id3v2, mp4, mpeg, ogg, wma
|
||||||
|
from lxml import etree, _elementpath
|
||||||
|
import gzip
|
||||||
|
|
||||||
class PyDupeGuru(PyDupeGuruBase):
|
class PyDupeGuru(PyDupeGuruBase):
|
||||||
def init(self):
|
def init(self):
|
||||||
|
|||||||
@@ -21,7 +21,16 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
||||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
||||||
|
CE003CC611242D00004B0AA7 /* HSGUIController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CB411242D00004B0AA7 /* HSGUIController.m */; };
|
||||||
|
CE003CC711242D00004B0AA7 /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CB611242D00004B0AA7 /* HSOutline.m */; };
|
||||||
|
CE003CC811242D00004B0AA7 /* HSWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CB811242D00004B0AA7 /* HSWindowController.m */; };
|
||||||
|
CE003CC911242D00004B0AA7 /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CBA11242D00004B0AA7 /* NSEventAdditions.m */; };
|
||||||
|
CE003CCA11242D00004B0AA7 /* HSOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC111242D00004B0AA7 /* HSOutlineView.m */; };
|
||||||
|
CE003CCB11242D00004B0AA7 /* NSIndexPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC311242D00004B0AA7 /* NSIndexPathAdditions.m */; };
|
||||||
|
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */; };
|
||||||
|
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */; };
|
||||||
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */; };
|
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */; };
|
||||||
|
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 */; };
|
||||||
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
||||||
@@ -35,7 +44,6 @@
|
|||||||
CE4B59CA1119919700C06C9E /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4B59C71119919700C06C9E /* registration.xib */; };
|
CE4B59CA1119919700C06C9E /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4B59C71119919700C06C9E /* registration.xib */; };
|
||||||
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE10FC6C12E00EC695D /* Dialogs.m */; };
|
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE10FC6C12E00EC695D /* Dialogs.m */; };
|
||||||
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */; };
|
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */; };
|
||||||
CE515DF50FC6C12E00EC695D /* Outline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE50FC6C12E00EC695D /* Outline.m */; };
|
|
||||||
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE70FC6C12E00EC695D /* ProgressController.m */; };
|
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE70FC6C12E00EC695D /* ProgressController.m */; };
|
||||||
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */; };
|
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */; };
|
||||||
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEC0FC6C12E00EC695D /* RegistrationInterface.m */; };
|
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEC0FC6C12E00EC695D /* RegistrationInterface.m */; };
|
||||||
@@ -50,6 +58,7 @@
|
|||||||
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
||||||
CE900AD2109B238600754048 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE900AD1109B238600754048 /* Preferences.xib */; };
|
CE900AD2109B238600754048 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE900AD1109B238600754048 /* Preferences.xib */; };
|
||||||
CE900AD7109B2A9B00754048 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE900AD6109B2A9B00754048 /* MainMenu.xib */; };
|
CE900AD7109B2A9B00754048 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE900AD6109B2A9B00754048 /* MainMenu.xib */; };
|
||||||
|
CEDF07A3112493B200EE5BC0 /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDF07A2112493B200EE5BC0 /* StatsLabel.m */; };
|
||||||
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */ = {isa = PBXBuildFile; fileRef = CEEB135109C837A2004D2330 /* dupeguru.icns */; };
|
CEEB135209C837A2004D2330 /* dupeguru.icns in Resources */ = {isa = PBXBuildFile; fileRef = CEEB135109C837A2004D2330 /* dupeguru.icns */; };
|
||||||
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC294509C89E3D00D9F998 /* folder32.png */; };
|
CEFC294609C89E3D00D9F998 /* folder32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC294509C89E3D00D9F998 /* folder32.png */; };
|
||||||
CEFC295509C89FF200D9F998 /* details32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295309C89FF200D9F998 /* details32.png */; };
|
CEFC295509C89FF200D9F998 /* details32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295309C89FF200D9F998 /* details32.png */; };
|
||||||
@@ -78,7 +87,30 @@
|
|||||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||||
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
|
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
|
||||||
8D1107320486CEB800E47090 /* dupeGuru ME.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "dupeGuru ME.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
8D1107320486CEB800E47090 /* dupeGuru ME.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "dupeGuru ME.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
CE003CB311242D00004B0AA7 /* HSGUIController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSGUIController.h; sourceTree = "<group>"; };
|
||||||
|
CE003CB411242D00004B0AA7 /* HSGUIController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSGUIController.m; sourceTree = "<group>"; };
|
||||||
|
CE003CB511242D00004B0AA7 /* HSOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutline.h; sourceTree = "<group>"; };
|
||||||
|
CE003CB611242D00004B0AA7 /* HSOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutline.m; sourceTree = "<group>"; };
|
||||||
|
CE003CB711242D00004B0AA7 /* HSWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSWindowController.h; sourceTree = "<group>"; };
|
||||||
|
CE003CB811242D00004B0AA7 /* HSWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSWindowController.m; sourceTree = "<group>"; };
|
||||||
|
CE003CB911242D00004B0AA7 /* NSEventAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSEventAdditions.h; path = ../../cocoalib/NSEventAdditions.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE003CBA11242D00004B0AA7 /* NSEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSEventAdditions.m; path = ../../cocoalib/NSEventAdditions.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE003CBC11242D00004B0AA7 /* PyGUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyGUI.h; sourceTree = "<group>"; };
|
||||||
|
CE003CBD11242D00004B0AA7 /* PyOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyOutline.h; sourceTree = "<group>"; };
|
||||||
|
CE003CBE11242D00004B0AA7 /* PyRegistrable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyRegistrable.h; path = ../../cocoalib/PyRegistrable.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE003CC011242D00004B0AA7 /* HSOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutlineView.h; sourceTree = "<group>"; };
|
||||||
|
CE003CC111242D00004B0AA7 /* HSOutlineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutlineView.m; sourceTree = "<group>"; };
|
||||||
|
CE003CC211242D00004B0AA7 /* NSIndexPathAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSIndexPathAdditions.h; sourceTree = "<group>"; };
|
||||||
|
CE003CC311242D00004B0AA7 /* NSIndexPathAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSIndexPathAdditions.m; sourceTree = "<group>"; };
|
||||||
|
CE003CC411242D00004B0AA7 /* NSTableViewAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSTableViewAdditions.h; sourceTree = "<group>"; };
|
||||||
|
CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSTableViewAdditions.m; sourceTree = "<group>"; };
|
||||||
|
CE003CCD11242D2C004B0AA7 /* DirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryOutline.h; path = ../base/DirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryOutline.m; path = ../base/DirectoryOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE003CCF11242D2C004B0AA7 /* PyDirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDirectoryOutline.h; path = ../base/PyDirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_me_help; path = ../../help_me/dupeguru_me_help; sourceTree = "<group>"; };
|
CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_me_help; path = ../../help_me/dupeguru_me_help; sourceTree = "<group>"; };
|
||||||
|
CE0B3D6411243F83009A7A30 /* PyResultTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTree.h; path = ../base/PyResultTree.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0B3D6511243F83009A7A30 /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0B3D6611243F83009A7A30 /* ResultOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultOutline.m; path = ../base/ResultOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE1425880AFB718500BD5167 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
CE1425880AFB718500BD5167 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
||||||
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -96,8 +128,6 @@
|
|||||||
CE515DE10FC6C12E00EC695D /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
CE515DE10FC6C12E00EC695D /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE40FC6C12E00EC695D /* Outline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Outline.h; path = ../../cocoalib/Outline.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE515DE50FC6C12E00EC695D /* Outline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Outline.m; path = ../../cocoalib/Outline.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE515DE60FC6C12E00EC695D /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
CE515DE60FC6C12E00EC695D /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE70FC6C12E00EC695D /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
CE515DE70FC6C12E00EC695D /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE80FC6C12E00EC695D /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
CE515DE80FC6C12E00EC695D /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -128,6 +158,9 @@
|
|||||||
CECA899A09DB132E00A3D774 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DetailsPanel.h; sourceTree = "<group>"; };
|
CECA899A09DB132E00A3D774 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DetailsPanel.h; sourceTree = "<group>"; };
|
||||||
CECA899B09DB132E00A3D774 /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DetailsPanel.m; sourceTree = "<group>"; };
|
CECA899B09DB132E00A3D774 /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DetailsPanel.m; sourceTree = "<group>"; };
|
||||||
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; };
|
||||||
|
CEDF07A1112493B200EE5BC0 /* StatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatsLabel.h; path = ../base/StatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CEDF07A2112493B200EE5BC0 /* StatsLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatsLabel.m; path = ../base/StatsLabel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEEB135109C837A2004D2330 /* dupeguru.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = dupeguru.icns; sourceTree = "<group>"; };
|
CEEB135109C837A2004D2330 /* dupeguru.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = dupeguru.icns; sourceTree = "<group>"; };
|
||||||
CEFC294509C89E3D00D9F998 /* folder32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = folder32.png; path = ../../images/folder32.png; sourceTree = SOURCE_ROOT; };
|
CEFC294509C89E3D00D9F998 /* folder32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = folder32.png; path = ../../images/folder32.png; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC295309C89FF200D9F998 /* details32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = details32.png; path = ../../images/details32.png; sourceTree = SOURCE_ROOT; };
|
CEFC295309C89FF200D9F998 /* details32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = details32.png; path = ../../images/details32.png; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -237,6 +270,44 @@
|
|||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
CE003CB211242D00004B0AA7 /* controllers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE003CB311242D00004B0AA7 /* HSGUIController.h */,
|
||||||
|
CE003CB411242D00004B0AA7 /* HSGUIController.m */,
|
||||||
|
CE003CB511242D00004B0AA7 /* HSOutline.h */,
|
||||||
|
CE003CB611242D00004B0AA7 /* HSOutline.m */,
|
||||||
|
CE003CB711242D00004B0AA7 /* HSWindowController.h */,
|
||||||
|
CE003CB811242D00004B0AA7 /* HSWindowController.m */,
|
||||||
|
);
|
||||||
|
name = controllers;
|
||||||
|
path = ../../cocoalib/controllers;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE003CBB11242D00004B0AA7 /* proxies */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE003CBC11242D00004B0AA7 /* PyGUI.h */,
|
||||||
|
CE003CBD11242D00004B0AA7 /* PyOutline.h */,
|
||||||
|
);
|
||||||
|
name = proxies;
|
||||||
|
path = ../../cocoalib/proxies;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE003CBF11242D00004B0AA7 /* views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE003CC011242D00004B0AA7 /* HSOutlineView.h */,
|
||||||
|
CE003CC111242D00004B0AA7 /* HSOutlineView.m */,
|
||||||
|
CE003CC211242D00004B0AA7 /* NSIndexPathAdditions.h */,
|
||||||
|
CE003CC311242D00004B0AA7 /* NSIndexPathAdditions.m */,
|
||||||
|
CE003CC411242D00004B0AA7 /* NSTableViewAdditions.h */,
|
||||||
|
CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */,
|
||||||
|
);
|
||||||
|
name = views;
|
||||||
|
path = ../../cocoalib/views;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
CE3FBDD01094637800B72D77 /* xib */ = {
|
CE3FBDD01094637800B72D77 /* xib */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -272,17 +343,21 @@
|
|||||||
CE515DDD0FC6C09400EC695D /* cocoalib */ = {
|
CE515DDD0FC6C09400EC695D /* cocoalib */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE003CB211242D00004B0AA7 /* controllers */,
|
||||||
|
CE003CBB11242D00004B0AA7 /* proxies */,
|
||||||
|
CE003CBF11242D00004B0AA7 /* views */,
|
||||||
CE4B59C41119919700C06C9E /* xib */,
|
CE4B59C41119919700C06C9E /* xib */,
|
||||||
CE49DEF10FDFEB810098617B /* brsinglelineformatter */,
|
CE49DEF10FDFEB810098617B /* brsinglelineformatter */,
|
||||||
CE515DE00FC6C12E00EC695D /* Dialogs.h */,
|
CE515DE00FC6C12E00EC695D /* Dialogs.h */,
|
||||||
CE515DE10FC6C12E00EC695D /* Dialogs.m */,
|
CE515DE10FC6C12E00EC695D /* Dialogs.m */,
|
||||||
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */,
|
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */,
|
||||||
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */,
|
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */,
|
||||||
CE515DE40FC6C12E00EC695D /* Outline.h */,
|
CE003CB911242D00004B0AA7 /* NSEventAdditions.h */,
|
||||||
CE515DE50FC6C12E00EC695D /* Outline.m */,
|
CE003CBA11242D00004B0AA7 /* NSEventAdditions.m */,
|
||||||
CE515DE60FC6C12E00EC695D /* ProgressController.h */,
|
CE515DE60FC6C12E00EC695D /* ProgressController.h */,
|
||||||
CE515DE70FC6C12E00EC695D /* ProgressController.m */,
|
CE515DE70FC6C12E00EC695D /* ProgressController.m */,
|
||||||
CE515DE80FC6C12E00EC695D /* PyApp.h */,
|
CE515DE80FC6C12E00EC695D /* PyApp.h */,
|
||||||
|
CE003CBE11242D00004B0AA7 /* PyRegistrable.h */,
|
||||||
CE515DE90FC6C12E00EC695D /* RecentDirectories.h */,
|
CE515DE90FC6C12E00EC695D /* RecentDirectories.h */,
|
||||||
CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */,
|
CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */,
|
||||||
CE515DEB0FC6C12E00EC695D /* RegistrationInterface.h */,
|
CE515DEB0FC6C12E00EC695D /* RegistrationInterface.h */,
|
||||||
@@ -298,6 +373,9 @@
|
|||||||
CE515E140FC6C17900EC695D /* dgbase */ = {
|
CE515E140FC6C17900EC695D /* dgbase */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE003CCD11242D2C004B0AA7 /* DirectoryOutline.h */,
|
||||||
|
CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */,
|
||||||
|
CE003CCF11242D2C004B0AA7 /* PyDirectoryOutline.h */,
|
||||||
CE515E150FC6C19300EC695D /* AppDelegate.h */,
|
CE515E150FC6C19300EC695D /* AppDelegate.h */,
|
||||||
CE515E160FC6C19300EC695D /* AppDelegate.m */,
|
CE515E160FC6C19300EC695D /* AppDelegate.m */,
|
||||||
CE515E170FC6C19300EC695D /* Consts.h */,
|
CE515E170FC6C19300EC695D /* Consts.h */,
|
||||||
@@ -305,10 +383,16 @@
|
|||||||
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */,
|
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */,
|
||||||
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
|
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
|
||||||
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
|
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
|
||||||
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
|
|
||||||
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */,
|
|
||||||
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
|
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
|
||||||
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
|
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
|
||||||
|
CE0B3D6511243F83009A7A30 /* ResultOutline.h */,
|
||||||
|
CE0B3D6611243F83009A7A30 /* ResultOutline.m */,
|
||||||
|
CEDF07A1112493B200EE5BC0 /* StatsLabel.h */,
|
||||||
|
CEDF07A2112493B200EE5BC0 /* StatsLabel.m */,
|
||||||
|
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
|
||||||
|
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */,
|
||||||
|
CE0B3D6411243F83009A7A30 /* PyResultTree.h */,
|
||||||
|
CEDF07A0112493B200EE5BC0 /* PyStatsLabel.h */,
|
||||||
);
|
);
|
||||||
name = dgbase;
|
name = dgbase;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -398,7 +482,6 @@
|
|||||||
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */,
|
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */,
|
||||||
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */,
|
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */,
|
||||||
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */,
|
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */,
|
||||||
CE515DF50FC6C12E00EC695D /* Outline.m in Sources */,
|
|
||||||
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */,
|
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */,
|
||||||
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */,
|
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */,
|
||||||
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */,
|
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */,
|
||||||
@@ -409,6 +492,16 @@
|
|||||||
CE515E1F0FC6C19300EC695D /* ResultWindow.m in Sources */,
|
CE515E1F0FC6C19300EC695D /* ResultWindow.m in Sources */,
|
||||||
CE49DEF60FDFEB810098617B /* BRSingleLineFormatter.m in Sources */,
|
CE49DEF60FDFEB810098617B /* BRSingleLineFormatter.m in Sources */,
|
||||||
CE6032C00FE6784C007E33FF /* DetailsPanel.m in Sources */,
|
CE6032C00FE6784C007E33FF /* DetailsPanel.m in Sources */,
|
||||||
|
CE003CC611242D00004B0AA7 /* HSGUIController.m in Sources */,
|
||||||
|
CE003CC711242D00004B0AA7 /* HSOutline.m in Sources */,
|
||||||
|
CE003CC811242D00004B0AA7 /* HSWindowController.m in Sources */,
|
||||||
|
CE003CC911242D00004B0AA7 /* NSEventAdditions.m in Sources */,
|
||||||
|
CE003CCA11242D00004B0AA7 /* HSOutlineView.m in Sources */,
|
||||||
|
CE003CCB11242D00004B0AA7 /* NSIndexPathAdditions.m in Sources */,
|
||||||
|
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */,
|
||||||
|
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */,
|
||||||
|
CE0B3D6711243F83009A7A30 /* ResultOutline.m in Sources */,
|
||||||
|
CEDF07A3112493B200EE5BC0 /* StatsLabel.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
<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">10B504</string>
|
<string key="IBDocument.SystemVersion">10C540</string>
|
||||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||||
<string key="IBDocument.AppKitVersion">1038.2</string>
|
<string key="IBDocument.AppKitVersion">1038.25</string>
|
||||||
<string key="IBDocument.HIToolboxVersion">437.00</string>
|
<string key="IBDocument.HIToolboxVersion">458.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>
|
||||||
@@ -39,6 +39,10 @@
|
|||||||
<string key="NSClassName">NSApplication</string>
|
<string key="NSClassName">NSApplication</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSUserDefaultsController" id="579641073">
|
<object class="NSUserDefaultsController" id="579641073">
|
||||||
|
<object class="NSMutableArray" key="NSDeclaredKeys">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<string>SUEnableAutomaticChecks</string>
|
||||||
|
</object>
|
||||||
<bool key="NSSharedInstance">YES</bool>
|
<bool key="NSSharedInstance">YES</bool>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSWindowTemplate" id="793317856">
|
<object class="NSWindowTemplate" id="793317856">
|
||||||
@@ -552,7 +556,7 @@
|
|||||||
<object class="NSButtonCell" key="NSCell" id="58676792">
|
<object class="NSButtonCell" key="NSCell" id="58676792">
|
||||||
<int key="NSCellFlags">67239424</int>
|
<int key="NSCellFlags">67239424</int>
|
||||||
<int key="NSCellFlags2">0</int>
|
<int key="NSCellFlags2">0</int>
|
||||||
<string key="NSContents">Check for update on startup</string>
|
<string key="NSContents">Automatically check for updates</string>
|
||||||
<reference key="NSSupport" ref="26"/>
|
<reference key="NSSupport" ref="26"/>
|
||||||
<reference key="NSControlView" ref="147113892"/>
|
<reference key="NSControlView" ref="147113892"/>
|
||||||
<int key="NSButtonFlags">1211912703</int>
|
<int key="NSButtonFlags">1211912703</int>
|
||||||
@@ -980,22 +984,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">84</int>
|
<int key="connectionID">84</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBBindingConnection" key="connection">
|
|
||||||
<string key="label">value: values.SUCheckAtStartup</string>
|
|
||||||
<reference key="source" ref="147113892"/>
|
|
||||||
<reference key="destination" ref="579641073"/>
|
|
||||||
<object class="NSNibBindingConnector" key="connector">
|
|
||||||
<reference key="NSSource" ref="147113892"/>
|
|
||||||
<reference key="NSDestination" ref="579641073"/>
|
|
||||||
<string key="NSLabel">value: values.SUCheckAtStartup</string>
|
|
||||||
<string key="NSBinding">value</string>
|
|
||||||
<string key="NSKeyPath">values.SUCheckAtStartup</string>
|
|
||||||
<int key="NSNibBindingConnectorVersion">2</int>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">85</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBOutletConnection" key="connection">
|
<object class="IBOutletConnection" key="connection">
|
||||||
<string key="label">nextKeyView</string>
|
<string key="label">nextKeyView</string>
|
||||||
@@ -1348,6 +1336,22 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">113</int>
|
<int key="connectionID">113</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBBindingConnection" key="connection">
|
||||||
|
<string key="label">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<reference key="source" ref="147113892"/>
|
||||||
|
<reference key="destination" ref="579641073"/>
|
||||||
|
<object class="NSNibBindingConnector" key="connector">
|
||||||
|
<reference key="NSSource" ref="147113892"/>
|
||||||
|
<reference key="NSDestination" ref="579641073"/>
|
||||||
|
<string key="NSLabel">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<string key="NSBinding">value</string>
|
||||||
|
<string key="NSKeyPath">values.SUEnableAutomaticChecks</string>
|
||||||
|
<int key="NSNibBindingConnectorVersion">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">114</int>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<object class="NSArray" key="orderedObjects">
|
<object class="NSArray" key="orderedObjects">
|
||||||
@@ -1838,8 +1842,6 @@
|
|||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSArray" key="dict.sortedKeys">
|
<object class="NSArray" key="dict.sortedKeys">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<string>-1.IBPluginDependency</string>
|
|
||||||
<string>-2.IBPluginDependency</string>
|
|
||||||
<string>-3.IBPluginDependency</string>
|
<string>-3.IBPluginDependency</string>
|
||||||
<string>1.IBPluginDependency</string>
|
<string>1.IBPluginDependency</string>
|
||||||
<string>1.ImportedFromIB2</string>
|
<string>1.ImportedFromIB2</string>
|
||||||
@@ -1949,8 +1951,6 @@
|
|||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<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"/>
|
||||||
@@ -2071,9 +2071,26 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">113</int>
|
<int key="maxID">114</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
|
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
|
|||||||
@@ -44,9 +44,8 @@ static NSString* jobAddIPhoto = @"jobAddIPhoto";
|
|||||||
|
|
||||||
- (void)jobCompleted:(NSNotification *)aNotification
|
- (void)jobCompleted:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
if ([[ProgressController mainProgressController] jobId] == jobAddIPhoto)
|
if ([[ProgressController mainProgressController] jobId] == jobAddIPhoto) {
|
||||||
{
|
[outlineView reloadData];
|
||||||
[directories reloadData];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>hsft</string>
|
<string>hsft</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.8.2</string>
|
<string>1.8.6</string>
|
||||||
<key>NSMainNibFile</key>
|
<key>NSMainNibFile</key>
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "Outline.h"
|
|
||||||
#import "../base/ResultWindow.h"
|
#import "../base/ResultWindow.h"
|
||||||
|
|
||||||
@interface ResultWindow : ResultWindowBase {}
|
@interface ResultWindow : ResultWindowBase {}
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
{
|
{
|
||||||
[super awakeFromNib];
|
[super awakeFromNib];
|
||||||
[[self window] setTitle:@"dupeGuru Picture Edition"];
|
[[self window] setTitle:@"dupeGuru Picture Edition"];
|
||||||
_deltaColumns = [[NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,5)] retain];
|
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,5)];
|
||||||
[_deltaColumns removeIndex:3];
|
[deltaColumns removeIndex:3];
|
||||||
[_deltaColumns removeIndex:4];
|
[deltaColumns removeIndex:4];
|
||||||
|
[outline setDeltaColumns:deltaColumns];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
@@ -63,8 +64,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[_py setMixFileKind:[ud objectForKey:@"mixFileKind"]];
|
[_py setMixFileKind:[ud objectForKey:@"mixFileKind"]];
|
||||||
[_py setMatchScaled:[ud objectForKey:@"matchScaled"]];
|
[_py setMatchScaled:[ud objectForKey:@"matchScaled"]];
|
||||||
int r = n2i([py doScan]);
|
int r = n2i([py doScan]);
|
||||||
[matches reloadData];
|
|
||||||
[self refreshStats];
|
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
[[ProgressController mainProgressController] hide];
|
[[ProgressController mainProgressController] hide];
|
||||||
if (r == 1)
|
if (r == 1)
|
||||||
|
|||||||
@@ -7,8 +7,10 @@
|
|||||||
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||||
from core_pe import app_cocoa as app_pe_cocoa
|
from core_pe import app_cocoa as app_pe_cocoa
|
||||||
|
|
||||||
# Fix py2app imports which chokes on relative imports
|
# Fix py2app imports which chokes on relative imports and other stuff
|
||||||
from core_pe import block, cache, matchbase, data, _block_osx
|
from core_pe import block, cache, matchbase, data, _block_osx
|
||||||
|
from lxml import etree, _elementpath
|
||||||
|
import gzip
|
||||||
|
|
||||||
class PyDupeGuru(PyDupeGuruBase):
|
class PyDupeGuru(PyDupeGuruBase):
|
||||||
def init(self):
|
def init(self):
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
CE7AC91A1119911200D02F6C /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE7AC9171119911200D02F6C /* registration.xib */; };
|
CE7AC91A1119911200D02F6C /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE7AC9171119911200D02F6C /* registration.xib */; };
|
||||||
CE80DB2E0FC192D60086DCA6 /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1C0FC192D60086DCA6 /* Dialogs.m */; };
|
CE80DB2E0FC192D60086DCA6 /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1C0FC192D60086DCA6 /* Dialogs.m */; };
|
||||||
CE80DB2F0FC192D60086DCA6 /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */; };
|
CE80DB2F0FC192D60086DCA6 /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */; };
|
||||||
CE80DB300FC192D60086DCA6 /* Outline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB200FC192D60086DCA6 /* Outline.m */; };
|
|
||||||
CE80DB310FC192D60086DCA6 /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB220FC192D60086DCA6 /* ProgressController.m */; };
|
CE80DB310FC192D60086DCA6 /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB220FC192D60086DCA6 /* ProgressController.m */; };
|
||||||
CE80DB320FC192D60086DCA6 /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB250FC192D60086DCA6 /* RecentDirectories.m */; };
|
CE80DB320FC192D60086DCA6 /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB250FC192D60086DCA6 /* RecentDirectories.m */; };
|
||||||
CE80DB330FC192D60086DCA6 /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB270FC192D60086DCA6 /* RegistrationInterface.m */; };
|
CE80DB330FC192D60086DCA6 /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB270FC192D60086DCA6 /* RegistrationInterface.m */; };
|
||||||
@@ -39,6 +38,16 @@
|
|||||||
CE80DB8B0FC1951C0086DCA6 /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */; };
|
CE80DB8B0FC1951C0086DCA6 /* DirectoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */; };
|
||||||
CE80DB8C0FC1951C0086DCA6 /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB890FC1951C0086DCA6 /* ResultWindow.m */; };
|
CE80DB8C0FC1951C0086DCA6 /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE80DB890FC1951C0086DCA6 /* ResultWindow.m */; };
|
||||||
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
CE848A1909DD85810004CB44 /* Consts.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE848A1809DD85810004CB44 /* Consts.h */; };
|
||||||
|
CE95865E112C516400F95FD2 /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE95865B112C516400F95FD2 /* ResultOutline.m */; };
|
||||||
|
CE95865F112C516400F95FD2 /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE95865D112C516400F95FD2 /* StatsLabel.m */; };
|
||||||
|
CE9EA7561122C96C008CD2BC /* HSGUIController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7441122C96C008CD2BC /* HSGUIController.m */; };
|
||||||
|
CE9EA7571122C96C008CD2BC /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7461122C96C008CD2BC /* HSOutline.m */; };
|
||||||
|
CE9EA7581122C96C008CD2BC /* HSWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7481122C96C008CD2BC /* HSWindowController.m */; };
|
||||||
|
CE9EA7591122C96C008CD2BC /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA74A1122C96C008CD2BC /* NSEventAdditions.m */; };
|
||||||
|
CE9EA75A1122C96C008CD2BC /* HSOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7511122C96C008CD2BC /* HSOutlineView.m */; };
|
||||||
|
CE9EA75B1122C96C008CD2BC /* NSIndexPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7531122C96C008CD2BC /* NSIndexPathAdditions.m */; };
|
||||||
|
CE9EA75C1122C96C008CD2BC /* NSTableViewAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7551122C96C008CD2BC /* NSTableViewAdditions.m */; };
|
||||||
|
CE9EA7721122CA0B008CD2BC /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9EA7701122CA0B008CD2BC /* DirectoryOutline.m */; };
|
||||||
CEBAE4270FDA97E000B7887D /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */; };
|
CEBAE4270FDA97E000B7887D /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */; };
|
||||||
CECA899C09DB132E00A3D774 /* DetailsPanel.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CECA899A09DB132E00A3D774 /* DetailsPanel.h */; };
|
CECA899C09DB132E00A3D774 /* DetailsPanel.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CECA899A09DB132E00A3D774 /* DetailsPanel.h */; };
|
||||||
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CECA899B09DB132E00A3D774 /* DetailsPanel.m */; };
|
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = CECA899B09DB132E00A3D774 /* DetailsPanel.m */; };
|
||||||
@@ -96,8 +105,6 @@
|
|||||||
CE80DB1C0FC192D60086DCA6 /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
CE80DB1C0FC192D60086DCA6 /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB1D0FC192D60086DCA6 /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
CE80DB1D0FC192D60086DCA6 /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB1F0FC192D60086DCA6 /* Outline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Outline.h; path = ../../cocoalib/Outline.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE80DB200FC192D60086DCA6 /* Outline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Outline.m; path = ../../cocoalib/Outline.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE80DB210FC192D60086DCA6 /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
CE80DB210FC192D60086DCA6 /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB220FC192D60086DCA6 /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
CE80DB220FC192D60086DCA6 /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB230FC192D60086DCA6 /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
CE80DB230FC192D60086DCA6 /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -122,6 +129,32 @@
|
|||||||
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultWindow.h; path = ../base/ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultWindow.h; path = ../base/ResultWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultWindow.m; path = ../base/ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultWindow.m; path = ../base/ResultWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
CE848A1809DD85810004CB44 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = "<group>"; };
|
||||||
|
CE958658112C516400F95FD2 /* PyResultTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTree.h; path = ../base/PyResultTree.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE958659112C516400F95FD2 /* PyStatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyStatsLabel.h; path = ../base/PyStatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE95865A112C516400F95FD2 /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE95865B112C516400F95FD2 /* ResultOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultOutline.m; path = ../base/ResultOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE95865C112C516400F95FD2 /* StatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatsLabel.h; path = ../base/StatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE95865D112C516400F95FD2 /* StatsLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatsLabel.m; path = ../base/StatsLabel.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA7431122C96C008CD2BC /* HSGUIController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSGUIController.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7441122C96C008CD2BC /* HSGUIController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSGUIController.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7451122C96C008CD2BC /* HSOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutline.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7461122C96C008CD2BC /* HSOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutline.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7471122C96C008CD2BC /* HSWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSWindowController.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7481122C96C008CD2BC /* HSWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSWindowController.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7491122C96C008CD2BC /* NSEventAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSEventAdditions.h; path = ../../cocoalib/NSEventAdditions.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA74A1122C96C008CD2BC /* NSEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSEventAdditions.m; path = ../../cocoalib/NSEventAdditions.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA74C1122C96C008CD2BC /* PyGUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyGUI.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA74D1122C96C008CD2BC /* PyOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyOutline.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA74E1122C96C008CD2BC /* PyRegistrable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyRegistrable.h; path = ../../cocoalib/PyRegistrable.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA7501122C96C008CD2BC /* HSOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutlineView.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7511122C96C008CD2BC /* HSOutlineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutlineView.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7521122C96C008CD2BC /* NSIndexPathAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSIndexPathAdditions.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7531122C96C008CD2BC /* NSIndexPathAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSIndexPathAdditions.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA7541122C96C008CD2BC /* NSTableViewAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSTableViewAdditions.h; sourceTree = "<group>"; };
|
||||||
|
CE9EA7551122C96C008CD2BC /* NSTableViewAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSTableViewAdditions.m; sourceTree = "<group>"; };
|
||||||
|
CE9EA76F1122CA0B008CD2BC /* DirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryOutline.h; path = ../base/DirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA7701122CA0B008CD2BC /* DirectoryOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryOutline.m; path = ../base/DirectoryOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE9EA7711122CA0B008CD2BC /* PyDirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDirectoryOutline.h; path = ../base/PyDirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEBAE4230FDA97E000B7887D /* BRSingleLineFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BRSingleLineFormatter.h; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.h; sourceTree = SOURCE_ROOT; };
|
CEBAE4230FDA97E000B7887D /* BRSingleLineFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BRSingleLineFormatter.h; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BRSingleLineFormatter.m; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.m; sourceTree = SOURCE_ROOT; };
|
CEBAE4240FDA97E000B7887D /* BRSingleLineFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BRSingleLineFormatter.m; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.m; sourceTree = SOURCE_ROOT; };
|
||||||
CECA899A09DB132E00A3D774 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DetailsPanel.h; sourceTree = "<group>"; };
|
CECA899A09DB132E00A3D774 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DetailsPanel.h; sourceTree = "<group>"; };
|
||||||
@@ -261,21 +294,25 @@
|
|||||||
CE80DB1A0FC192AB0086DCA6 /* cocoalib */ = {
|
CE80DB1A0FC192AB0086DCA6 /* cocoalib */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE9EA7421122C96C008CD2BC /* controllers */,
|
||||||
|
CE9EA74B1122C96C008CD2BC /* proxies */,
|
||||||
|
CE9EA74F1122C96C008CD2BC /* views */,
|
||||||
CE7AC9141119911200D02F6C /* xib */,
|
CE7AC9141119911200D02F6C /* xib */,
|
||||||
CEBAE4220FDA97E000B7887D /* brsinglelineformatter */,
|
CEBAE4220FDA97E000B7887D /* brsinglelineformatter */,
|
||||||
CE80DB480FC193770086DCA6 /* NSImageAdditions.h */,
|
CE80DB480FC193770086DCA6 /* NSImageAdditions.h */,
|
||||||
CE80DB490FC193770086DCA6 /* NSImageAdditions.m */,
|
CE80DB490FC193770086DCA6 /* NSImageAdditions.m */,
|
||||||
CE80DB450FC193650086DCA6 /* NSNotificationAdditions.h */,
|
CE80DB450FC193650086DCA6 /* NSNotificationAdditions.h */,
|
||||||
CE80DB460FC193650086DCA6 /* NSNotificationAdditions.m */,
|
CE80DB460FC193650086DCA6 /* NSNotificationAdditions.m */,
|
||||||
|
CE9EA7491122C96C008CD2BC /* NSEventAdditions.h */,
|
||||||
|
CE9EA74A1122C96C008CD2BC /* NSEventAdditions.m */,
|
||||||
CE80DB1B0FC192D60086DCA6 /* Dialogs.h */,
|
CE80DB1B0FC192D60086DCA6 /* Dialogs.h */,
|
||||||
CE80DB1C0FC192D60086DCA6 /* Dialogs.m */,
|
CE80DB1C0FC192D60086DCA6 /* Dialogs.m */,
|
||||||
CE80DB1D0FC192D60086DCA6 /* HSErrorReportWindow.h */,
|
CE80DB1D0FC192D60086DCA6 /* HSErrorReportWindow.h */,
|
||||||
CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */,
|
CE80DB1E0FC192D60086DCA6 /* HSErrorReportWindow.m */,
|
||||||
CE80DB1F0FC192D60086DCA6 /* Outline.h */,
|
|
||||||
CE80DB200FC192D60086DCA6 /* Outline.m */,
|
|
||||||
CE80DB210FC192D60086DCA6 /* ProgressController.h */,
|
CE80DB210FC192D60086DCA6 /* ProgressController.h */,
|
||||||
CE80DB220FC192D60086DCA6 /* ProgressController.m */,
|
CE80DB220FC192D60086DCA6 /* ProgressController.m */,
|
||||||
CE80DB230FC192D60086DCA6 /* PyApp.h */,
|
CE80DB230FC192D60086DCA6 /* PyApp.h */,
|
||||||
|
CE9EA74E1122C96C008CD2BC /* PyRegistrable.h */,
|
||||||
CE80DB240FC192D60086DCA6 /* RecentDirectories.h */,
|
CE80DB240FC192D60086DCA6 /* RecentDirectories.h */,
|
||||||
CE80DB250FC192D60086DCA6 /* RecentDirectories.m */,
|
CE80DB250FC192D60086DCA6 /* RecentDirectories.m */,
|
||||||
CE80DB260FC192D60086DCA6 /* RegistrationInterface.h */,
|
CE80DB260FC192D60086DCA6 /* RegistrationInterface.h */,
|
||||||
@@ -298,14 +335,61 @@
|
|||||||
CE6044EB0FE6796200B71262 /* DetailsPanel.m */,
|
CE6044EB0FE6796200B71262 /* DetailsPanel.m */,
|
||||||
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */,
|
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */,
|
||||||
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */,
|
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */,
|
||||||
|
CE9EA7711122CA0B008CD2BC /* PyDirectoryOutline.h */,
|
||||||
|
CE9EA76F1122CA0B008CD2BC /* DirectoryOutline.h */,
|
||||||
|
CE9EA7701122CA0B008CD2BC /* DirectoryOutline.m */,
|
||||||
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */,
|
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */,
|
||||||
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */,
|
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */,
|
||||||
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */,
|
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */,
|
||||||
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */,
|
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */,
|
||||||
|
CE958658112C516400F95FD2 /* PyResultTree.h */,
|
||||||
|
CE95865A112C516400F95FD2 /* ResultOutline.h */,
|
||||||
|
CE95865B112C516400F95FD2 /* ResultOutline.m */,
|
||||||
|
CE958659112C516400F95FD2 /* PyStatsLabel.h */,
|
||||||
|
CE95865C112C516400F95FD2 /* StatsLabel.h */,
|
||||||
|
CE95865D112C516400F95FD2 /* StatsLabel.m */,
|
||||||
);
|
);
|
||||||
name = dgbase;
|
name = dgbase;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
CE9EA7421122C96C008CD2BC /* controllers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE9EA7431122C96C008CD2BC /* HSGUIController.h */,
|
||||||
|
CE9EA7441122C96C008CD2BC /* HSGUIController.m */,
|
||||||
|
CE9EA7451122C96C008CD2BC /* HSOutline.h */,
|
||||||
|
CE9EA7461122C96C008CD2BC /* HSOutline.m */,
|
||||||
|
CE9EA7471122C96C008CD2BC /* HSWindowController.h */,
|
||||||
|
CE9EA7481122C96C008CD2BC /* HSWindowController.m */,
|
||||||
|
);
|
||||||
|
name = controllers;
|
||||||
|
path = ../../cocoalib/controllers;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE9EA74B1122C96C008CD2BC /* proxies */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE9EA74C1122C96C008CD2BC /* PyGUI.h */,
|
||||||
|
CE9EA74D1122C96C008CD2BC /* PyOutline.h */,
|
||||||
|
);
|
||||||
|
name = proxies;
|
||||||
|
path = ../../cocoalib/proxies;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
CE9EA74F1122C96C008CD2BC /* views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CE9EA7501122C96C008CD2BC /* HSOutlineView.h */,
|
||||||
|
CE9EA7511122C96C008CD2BC /* HSOutlineView.m */,
|
||||||
|
CE9EA7521122C96C008CD2BC /* NSIndexPathAdditions.h */,
|
||||||
|
CE9EA7531122C96C008CD2BC /* NSIndexPathAdditions.m */,
|
||||||
|
CE9EA7541122C96C008CD2BC /* NSTableViewAdditions.h */,
|
||||||
|
CE9EA7551122C96C008CD2BC /* NSTableViewAdditions.m */,
|
||||||
|
);
|
||||||
|
name = views;
|
||||||
|
path = ../../cocoalib/views;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
CEBAE4220FDA97E000B7887D /* brsinglelineformatter */ = {
|
CEBAE4220FDA97E000B7887D /* brsinglelineformatter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -403,7 +487,6 @@
|
|||||||
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */,
|
CECA899D09DB132E00A3D774 /* DetailsPanel.m in Sources */,
|
||||||
CE80DB2E0FC192D60086DCA6 /* Dialogs.m in Sources */,
|
CE80DB2E0FC192D60086DCA6 /* Dialogs.m in Sources */,
|
||||||
CE80DB2F0FC192D60086DCA6 /* HSErrorReportWindow.m in Sources */,
|
CE80DB2F0FC192D60086DCA6 /* HSErrorReportWindow.m in Sources */,
|
||||||
CE80DB300FC192D60086DCA6 /* Outline.m in Sources */,
|
|
||||||
CE80DB310FC192D60086DCA6 /* ProgressController.m in Sources */,
|
CE80DB310FC192D60086DCA6 /* ProgressController.m in Sources */,
|
||||||
CE80DB320FC192D60086DCA6 /* RecentDirectories.m in Sources */,
|
CE80DB320FC192D60086DCA6 /* RecentDirectories.m in Sources */,
|
||||||
CE80DB330FC192D60086DCA6 /* RegistrationInterface.m in Sources */,
|
CE80DB330FC192D60086DCA6 /* RegistrationInterface.m in Sources */,
|
||||||
@@ -416,6 +499,16 @@
|
|||||||
CE80DB8C0FC1951C0086DCA6 /* ResultWindow.m in Sources */,
|
CE80DB8C0FC1951C0086DCA6 /* ResultWindow.m in Sources */,
|
||||||
CEBAE4270FDA97E000B7887D /* BRSingleLineFormatter.m in Sources */,
|
CEBAE4270FDA97E000B7887D /* BRSingleLineFormatter.m in Sources */,
|
||||||
CE6044EC0FE6796200B71262 /* DetailsPanel.m in Sources */,
|
CE6044EC0FE6796200B71262 /* DetailsPanel.m in Sources */,
|
||||||
|
CE9EA7561122C96C008CD2BC /* HSGUIController.m in Sources */,
|
||||||
|
CE9EA7571122C96C008CD2BC /* HSOutline.m in Sources */,
|
||||||
|
CE9EA7581122C96C008CD2BC /* HSWindowController.m in Sources */,
|
||||||
|
CE9EA7591122C96C008CD2BC /* NSEventAdditions.m in Sources */,
|
||||||
|
CE9EA75A1122C96C008CD2BC /* HSOutlineView.m in Sources */,
|
||||||
|
CE9EA75B1122C96C008CD2BC /* NSIndexPathAdditions.m in Sources */,
|
||||||
|
CE9EA75C1122C96C008CD2BC /* NSTableViewAdditions.m in Sources */,
|
||||||
|
CE9EA7721122CA0B008CD2BC /* DirectoryOutline.m in Sources */,
|
||||||
|
CE95865E112C516400F95FD2 /* ResultOutline.m in Sources */,
|
||||||
|
CE95865F112C516400F95FD2 /* StatsLabel.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,17 +2,17 @@
|
|||||||
<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">10B504</string>
|
<string key="IBDocument.SystemVersion">10C540</string>
|
||||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||||
<string key="IBDocument.AppKitVersion">1038.2</string>
|
<string key="IBDocument.AppKitVersion">1038.25</string>
|
||||||
<string key="IBDocument.HIToolboxVersion">437.00</string>
|
<string key="IBDocument.HIToolboxVersion">458.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="2"/>
|
<integer value="3"/>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
@@ -39,6 +39,10 @@
|
|||||||
<string key="NSClassName">NSApplication</string>
|
<string key="NSClassName">NSApplication</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSUserDefaultsController" id="455472712">
|
<object class="NSUserDefaultsController" id="455472712">
|
||||||
|
<object class="NSMutableArray" key="NSDeclaredKeys">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<string>SUEnableAutomaticChecks</string>
|
||||||
|
</object>
|
||||||
<bool key="NSSharedInstance">YES</bool>
|
<bool key="NSSharedInstance">YES</bool>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSWindowTemplate" id="809668081">
|
<object class="NSWindowTemplate" id="809668081">
|
||||||
@@ -411,7 +415,7 @@
|
|||||||
<object class="NSButtonCell" key="NSCell" id="2297113">
|
<object class="NSButtonCell" key="NSCell" id="2297113">
|
||||||
<int key="NSCellFlags">67239424</int>
|
<int key="NSCellFlags">67239424</int>
|
||||||
<int key="NSCellFlags2">0</int>
|
<int key="NSCellFlags2">0</int>
|
||||||
<string key="NSContents">Check for update on startup</string>
|
<string key="NSContents">Automatically check for updates</string>
|
||||||
<reference key="NSSupport" ref="26"/>
|
<reference key="NSSupport" ref="26"/>
|
||||||
<reference key="NSControlView" ref="472028782"/>
|
<reference key="NSControlView" ref="472028782"/>
|
||||||
<int key="NSButtonFlags">1211912703</int>
|
<int key="NSButtonFlags">1211912703</int>
|
||||||
@@ -541,22 +545,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">39</int>
|
<int key="connectionID">39</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBBindingConnection" key="connection">
|
|
||||||
<string key="label">value: values.SUCheckAtStartup</string>
|
|
||||||
<reference key="source" ref="472028782"/>
|
|
||||||
<reference key="destination" ref="455472712"/>
|
|
||||||
<object class="NSNibBindingConnector" key="connector">
|
|
||||||
<reference key="NSSource" ref="472028782"/>
|
|
||||||
<reference key="NSDestination" ref="455472712"/>
|
|
||||||
<string key="NSLabel">value: values.SUCheckAtStartup</string>
|
|
||||||
<string key="NSBinding">value</string>
|
|
||||||
<string key="NSKeyPath">values.SUCheckAtStartup</string>
|
|
||||||
<int key="NSNibBindingConnectorVersion">2</int>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">40</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBActionConnection" key="connection">
|
<object class="IBActionConnection" key="connection">
|
||||||
<string key="label">revertToInitialValues:</string>
|
<string key="label">revertToInitialValues:</string>
|
||||||
@@ -677,6 +665,22 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">51</int>
|
<int key="connectionID">51</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBBindingConnection" key="connection">
|
||||||
|
<string key="label">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<reference key="source" ref="472028782"/>
|
||||||
|
<reference key="destination" ref="455472712"/>
|
||||||
|
<object class="NSNibBindingConnector" key="connector">
|
||||||
|
<reference key="NSSource" ref="472028782"/>
|
||||||
|
<reference key="NSDestination" ref="455472712"/>
|
||||||
|
<string key="NSLabel">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<string key="NSBinding">value</string>
|
||||||
|
<string key="NSKeyPath">values.SUEnableAutomaticChecks</string>
|
||||||
|
<int key="NSNibBindingConnectorVersion">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">58</int>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<object class="NSArray" key="orderedObjects">
|
<object class="NSArray" key="orderedObjects">
|
||||||
@@ -1110,9 +1114,26 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">51</int>
|
<int key="maxID">58</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
|
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "../../cocoalib/Outline.h"
|
|
||||||
#import "../base/ResultWindow.h"
|
#import "../base/ResultWindow.h"
|
||||||
#import "DirectoryPanel.h"
|
#import "DirectoryPanel.h"
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
- (void)awakeFromNib
|
- (void)awakeFromNib
|
||||||
{
|
{
|
||||||
[super awakeFromNib];
|
[super awakeFromNib];
|
||||||
_deltaColumns = [[NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,4)] retain];
|
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,4)];
|
||||||
[_deltaColumns removeIndex:3];
|
[deltaColumns removeIndex:3];
|
||||||
|
[outline setDeltaColumns:deltaColumns];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
@@ -56,8 +57,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
int sizeThreshold = [ud boolForKey:@"ignoreSmallFiles"] ? smallFileThreshold * 1024 : 0; // The py side wants bytes
|
int sizeThreshold = [ud boolForKey:@"ignoreSmallFiles"] ? smallFileThreshold * 1024 : 0; // The py side wants bytes
|
||||||
[_py setSizeThreshold:sizeThreshold];
|
[_py setSizeThreshold:sizeThreshold];
|
||||||
int r = n2i([py doScan]);
|
int r = n2i([py doScan]);
|
||||||
[matches reloadData];
|
|
||||||
[self refreshStats];
|
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
[[ProgressController mainProgressController] hide];
|
[[ProgressController mainProgressController] hide];
|
||||||
if (r == 1)
|
if (r == 1)
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ from core import scanner
|
|||||||
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||||
from core_se.app_cocoa import DupeGuru
|
from core_se.app_cocoa import DupeGuru
|
||||||
|
|
||||||
# Fix py2app imports with chokes on relative imports
|
# Fix py2app imports with chokes on relative imports and other stuff
|
||||||
from core_se import fs, data
|
from core_se import fs, data
|
||||||
|
from lxml import etree, _elementpath
|
||||||
|
import gzip
|
||||||
|
|
||||||
class PyDupeGuru(PyDupeGuruBase):
|
class PyDupeGuru(PyDupeGuruBase):
|
||||||
def init(self):
|
def init(self):
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
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 */; };
|
||||||
|
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F212113BC22D0010360B /* ResultOutline.m */; };
|
||||||
|
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F214113BC22D0010360B /* StatsLabel.m */; };
|
||||||
CEAC6811109B0B7E00B43C85 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEAC6810109B0B7E00B43C85 /* Preferences.xib */; };
|
CEAC6811109B0B7E00B43C85 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEAC6810109B0B7E00B43C85 /* Preferences.xib */; };
|
||||||
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */; };
|
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */; };
|
||||||
CEDD92DA0FDD01640031C7B7 /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDD92D70FDD01640031C7B7 /* BRSingleLineFormatter.m */; };
|
CEDD92DA0FDD01640031C7B7 /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDD92D70FDD01640031C7B7 /* BRSingleLineFormatter.m */; };
|
||||||
@@ -39,7 +41,6 @@
|
|||||||
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295409C89FF200D9F998 /* preferences32.png */; };
|
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295409C89FF200D9F998 /* preferences32.png */; };
|
||||||
CEFC7F9E0FC9517500CD5728 /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8B0FC9517500CD5728 /* Dialogs.m */; };
|
CEFC7F9E0FC9517500CD5728 /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8B0FC9517500CD5728 /* Dialogs.m */; };
|
||||||
CEFC7F9F0FC9517500CD5728 /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */; };
|
CEFC7F9F0FC9517500CD5728 /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */; };
|
||||||
CEFC7FA00FC9517500CD5728 /* Outline.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8F0FC9517500CD5728 /* Outline.m */; };
|
|
||||||
CEFC7FA10FC9517500CD5728 /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F910FC9517500CD5728 /* ProgressController.m */; };
|
CEFC7FA10FC9517500CD5728 /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F910FC9517500CD5728 /* ProgressController.m */; };
|
||||||
CEFC7FA20FC9517500CD5728 /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F950FC9517500CD5728 /* RecentDirectories.m */; };
|
CEFC7FA20FC9517500CD5728 /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F950FC9517500CD5728 /* RecentDirectories.m */; };
|
||||||
CEFC7FA30FC9517500CD5728 /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F970FC9517500CD5728 /* RegistrationInterface.m */; };
|
CEFC7FA30FC9517500CD5728 /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F970FC9517500CD5728 /* RegistrationInterface.m */; };
|
||||||
@@ -101,6 +102,12 @@
|
|||||||
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; };
|
||||||
|
CE91F20F113BC22D0010360B /* PyResultTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTree.h; path = ../base/PyResultTree.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F210113BC22D0010360B /* PyStatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyStatsLabel.h; path = ../base/PyStatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F211113BC22D0010360B /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F212113BC22D0010360B /* ResultOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultOutline.m; path = ../base/ResultOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F213113BC22D0010360B /* StatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatsLabel.h; path = ../base/StatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F214113BC22D0010360B /* StatsLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatsLabel.m; path = ../base/StatsLabel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEAC6810109B0B7E00B43C85 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Preferences.xib; path = xib/Preferences.xib; sourceTree = "<group>"; };
|
CEAC6810109B0B7E00B43C85 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Preferences.xib; path = xib/Preferences.xib; sourceTree = "<group>"; };
|
||||||
CEBE4D72111F0EE1009AAC6D /* HSWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSWindowController.h; sourceTree = "<group>"; };
|
CEBE4D72111F0EE1009AAC6D /* HSWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSWindowController.h; sourceTree = "<group>"; };
|
||||||
CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSWindowController.m; sourceTree = "<group>"; };
|
CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSWindowController.m; sourceTree = "<group>"; };
|
||||||
@@ -118,8 +125,6 @@
|
|||||||
CEFC7F8B0FC9517500CD5728 /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
CEFC7F8B0FC9517500CD5728 /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F8C0FC9517500CD5728 /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
CEFC7F8C0FC9517500CD5728 /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F8E0FC9517500CD5728 /* Outline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Outline.h; path = ../../cocoalib/Outline.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CEFC7F8F0FC9517500CD5728 /* Outline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Outline.m; path = ../../cocoalib/Outline.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CEFC7F900FC9517500CD5728 /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
CEFC7F900FC9517500CD5728 /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F910FC9517500CD5728 /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
CEFC7F910FC9517500CD5728 /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F920FC9517500CD5728 /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
CEFC7F920FC9517500CD5728 /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -326,8 +331,6 @@
|
|||||||
CEFC7F8B0FC9517500CD5728 /* Dialogs.m */,
|
CEFC7F8B0FC9517500CD5728 /* Dialogs.m */,
|
||||||
CEFC7F8C0FC9517500CD5728 /* HSErrorReportWindow.h */,
|
CEFC7F8C0FC9517500CD5728 /* HSErrorReportWindow.h */,
|
||||||
CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */,
|
CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */,
|
||||||
CEFC7F8E0FC9517500CD5728 /* Outline.h */,
|
|
||||||
CEFC7F8F0FC9517500CD5728 /* Outline.m */,
|
|
||||||
CEFC7F900FC9517500CD5728 /* ProgressController.h */,
|
CEFC7F900FC9517500CD5728 /* ProgressController.h */,
|
||||||
CEFC7F910FC9517500CD5728 /* ProgressController.m */,
|
CEFC7F910FC9517500CD5728 /* ProgressController.m */,
|
||||||
CEFC7F920FC9517500CD5728 /* PyApp.h */,
|
CEFC7F920FC9517500CD5728 /* PyApp.h */,
|
||||||
@@ -347,6 +350,12 @@
|
|||||||
CEFC7FB00FC9518F00CD5728 /* dgbase */ = {
|
CEFC7FB00FC9518F00CD5728 /* dgbase */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE91F20F113BC22D0010360B /* PyResultTree.h */,
|
||||||
|
CE91F210113BC22D0010360B /* PyStatsLabel.h */,
|
||||||
|
CE91F211113BC22D0010360B /* ResultOutline.h */,
|
||||||
|
CE91F212113BC22D0010360B /* ResultOutline.m */,
|
||||||
|
CE91F213113BC22D0010360B /* StatsLabel.h */,
|
||||||
|
CE91F214113BC22D0010360B /* StatsLabel.m */,
|
||||||
CE76FDD1111EE3A7006618EA /* DirectoryOutline.h */,
|
CE76FDD1111EE3A7006618EA /* DirectoryOutline.h */,
|
||||||
CE76FDD2111EE3A7006618EA /* DirectoryOutline.m */,
|
CE76FDD2111EE3A7006618EA /* DirectoryOutline.m */,
|
||||||
CE76FDD3111EE3A7006618EA /* PyDirectoryOutline.h */,
|
CE76FDD3111EE3A7006618EA /* PyDirectoryOutline.h */,
|
||||||
@@ -441,7 +450,6 @@
|
|||||||
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */,
|
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */,
|
||||||
CEFC7F9E0FC9517500CD5728 /* Dialogs.m in Sources */,
|
CEFC7F9E0FC9517500CD5728 /* Dialogs.m in Sources */,
|
||||||
CEFC7F9F0FC9517500CD5728 /* HSErrorReportWindow.m in Sources */,
|
CEFC7F9F0FC9517500CD5728 /* HSErrorReportWindow.m in Sources */,
|
||||||
CEFC7FA00FC9517500CD5728 /* Outline.m in Sources */,
|
|
||||||
CEFC7FA10FC9517500CD5728 /* ProgressController.m in Sources */,
|
CEFC7FA10FC9517500CD5728 /* ProgressController.m in Sources */,
|
||||||
CEFC7FA20FC9517500CD5728 /* RecentDirectories.m in Sources */,
|
CEFC7FA20FC9517500CD5728 /* RecentDirectories.m in Sources */,
|
||||||
CEFC7FA30FC9517500CD5728 /* RegistrationInterface.m in Sources */,
|
CEFC7FA30FC9517500CD5728 /* RegistrationInterface.m in Sources */,
|
||||||
@@ -460,6 +468,8 @@
|
|||||||
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */,
|
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */,
|
||||||
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */,
|
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */,
|
||||||
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */,
|
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */,
|
||||||
|
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */,
|
||||||
|
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,6 +39,10 @@
|
|||||||
<string key="NSClassName">NSApplication</string>
|
<string key="NSClassName">NSApplication</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSUserDefaultsController" id="75941798">
|
<object class="NSUserDefaultsController" id="75941798">
|
||||||
|
<object class="NSMutableArray" key="NSDeclaredKeys">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<string>SUEnableAutomaticChecks</string>
|
||||||
|
</object>
|
||||||
<bool key="NSSharedInstance">YES</bool>
|
<bool key="NSSharedInstance">YES</bool>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSWindowTemplate" id="489014306">
|
<object class="NSWindowTemplate" id="489014306">
|
||||||
@@ -507,7 +511,7 @@
|
|||||||
<object class="NSButtonCell" key="NSCell" id="456303302">
|
<object class="NSButtonCell" key="NSCell" id="456303302">
|
||||||
<int key="NSCellFlags">67239424</int>
|
<int key="NSCellFlags">67239424</int>
|
||||||
<int key="NSCellFlags2">0</int>
|
<int key="NSCellFlags2">0</int>
|
||||||
<string key="NSContents">Check for update on startup</string>
|
<string key="NSContents">Automatically check for updates</string>
|
||||||
<reference key="NSSupport" ref="26"/>
|
<reference key="NSSupport" ref="26"/>
|
||||||
<reference key="NSControlView" ref="551239185"/>
|
<reference key="NSControlView" ref="551239185"/>
|
||||||
<int key="NSButtonFlags">1211912703</int>
|
<int key="NSButtonFlags">1211912703</int>
|
||||||
@@ -844,22 +848,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">110</int>
|
<int key="connectionID">110</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBBindingConnection" key="connection">
|
|
||||||
<string key="label">value: values.SUCheckAtStartup</string>
|
|
||||||
<reference key="source" ref="551239185"/>
|
|
||||||
<reference key="destination" ref="75941798"/>
|
|
||||||
<object class="NSNibBindingConnector" key="connector">
|
|
||||||
<reference key="NSSource" ref="551239185"/>
|
|
||||||
<reference key="NSDestination" ref="75941798"/>
|
|
||||||
<string key="NSLabel">value: values.SUCheckAtStartup</string>
|
|
||||||
<string key="NSBinding">value</string>
|
|
||||||
<string key="NSKeyPath">values.SUCheckAtStartup</string>
|
|
||||||
<int key="NSNibBindingConnectorVersion">2</int>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">111</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBBindingConnection" key="connection">
|
<object class="IBBindingConnection" key="connection">
|
||||||
<string key="label">value: values.removeEmptyFolders</string>
|
<string key="label">value: values.removeEmptyFolders</string>
|
||||||
@@ -972,6 +960,22 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">121</int>
|
<int key="connectionID">121</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBBindingConnection" key="connection">
|
||||||
|
<string key="label">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<reference key="source" ref="551239185"/>
|
||||||
|
<reference key="destination" ref="75941798"/>
|
||||||
|
<object class="NSNibBindingConnector" key="connector">
|
||||||
|
<reference key="NSSource" ref="551239185"/>
|
||||||
|
<reference key="NSDestination" ref="75941798"/>
|
||||||
|
<string key="NSLabel">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<string key="NSBinding">value</string>
|
||||||
|
<string key="NSKeyPath">values.SUEnableAutomaticChecks</string>
|
||||||
|
<int key="NSNibBindingConnectorVersion">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">122</int>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<object class="NSArray" key="orderedObjects">
|
<object class="NSArray" key="orderedObjects">
|
||||||
@@ -1582,9 +1586,26 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">121</int>
|
<int key="maxID">122</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
|
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
|
|||||||
74
core/app.py
74
core/app.py
@@ -1,4 +1,3 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# Created By: Virgil Dupras
|
# Created By: Virgil Dupras
|
||||||
# Created On: 2006/11/11
|
# Created On: 2006/11/11
|
||||||
# Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
# Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||||
@@ -13,6 +12,7 @@ import os
|
|||||||
import os.path as op
|
import os.path as op
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from send2trash import send2trash
|
||||||
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.reg import RegistrableApplication, RegistrationRequired
|
||||||
@@ -75,12 +75,14 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
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 True
|
||||||
self._recycle_dupe(dupe)
|
try:
|
||||||
self.clean_empty_dirs(dupe.path[:-1])
|
send2trash(unicode(dupe.path))
|
||||||
if not io.exists(dupe.path):
|
except OSError as e:
|
||||||
return True
|
msg = "Could not send {0} to trash: {1}"
|
||||||
logging.warning("Could not send {0} to trash.".format(unicode(dupe.path)))
|
logging.warning(msg.format(unicode(dupe.path), unicode(e)))
|
||||||
return False
|
return False
|
||||||
|
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'))
|
||||||
@@ -88,8 +90,14 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
j = j.start_subjob([1, 9])
|
j = j.start_subjob([1, 9])
|
||||||
self.results.load_from_xml(op.join(self.appdata, 'last_results.xml'), self._get_file, j)
|
self.results.load_from_xml(op.join(self.appdata, 'last_results.xml'), self._get_file, j)
|
||||||
files = flatten(g[:] for g in self.results.groups)
|
files = flatten(g[:] for g in self.results.groups)
|
||||||
|
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:
|
||||||
|
# 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
|
||||||
|
# way to remove an arbitrary file from the Results. Thus, we simply clear them.
|
||||||
|
self.results.groups = []
|
||||||
|
|
||||||
def _get_display_info(self, dupe, group, delta=False):
|
def _get_display_info(self, dupe, group, delta=False):
|
||||||
if (dupe is None) or (group is None):
|
if (dupe is None) or (group is None):
|
||||||
@@ -104,12 +112,13 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
path = Path(str_path)
|
path = Path(str_path)
|
||||||
return fs.get_file(path, self.directories.fileclasses)
|
return fs.get_file(path, self.directories.fileclasses)
|
||||||
|
|
||||||
@staticmethod
|
def _job_completed(self, jobid):
|
||||||
def _open_path(path):
|
# Must be called by subclasses when they detect that an async job is completed.
|
||||||
raise NotImplementedError()
|
if jobid in (JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_DELETE):
|
||||||
|
self.notify('results_changed')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _recycle_dupe(dupe):
|
def _open_path(path):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -151,6 +160,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
filter = escape(filter, '()[]\\.|+?^')
|
filter = escape(filter, '()[]\\.|+?^')
|
||||||
filter = escape(filter, '*', '.')
|
filter = escape(filter, '*', '.')
|
||||||
self.results.apply_filter(filter)
|
self.results.apply_filter(filter)
|
||||||
|
self.notify('results_changed')
|
||||||
|
|
||||||
def clean_empty_dirs(self, path):
|
def clean_empty_dirs(self, path):
|
||||||
if self.options['clean_empty_dirs']:
|
if self.options['clean_empty_dirs']:
|
||||||
@@ -233,11 +243,34 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
if g not in changed_groups:
|
if g not in changed_groups:
|
||||||
self.results.make_ref(dupe)
|
self.results.make_ref(dupe)
|
||||||
changed_groups.add(g)
|
changed_groups.add(g)
|
||||||
|
self.notify('results_changed_but_keep_selection')
|
||||||
|
|
||||||
|
def mark_all(self):
|
||||||
|
self.results.mark_all()
|
||||||
|
self.notify('marking_changed')
|
||||||
|
|
||||||
|
def mark_none(self):
|
||||||
|
self.results.mark_none()
|
||||||
|
self.notify('marking_changed')
|
||||||
|
|
||||||
|
def mark_invert(self):
|
||||||
|
self.results.mark_invert()
|
||||||
|
self.notify('marking_changed')
|
||||||
|
|
||||||
|
def mark_dupe(self, dupe, marked):
|
||||||
|
if marked:
|
||||||
|
self.results.mark(dupe)
|
||||||
|
else:
|
||||||
|
self.results.unmark(dupe)
|
||||||
|
self.notify('marking_changed')
|
||||||
|
|
||||||
def open_selected(self):
|
def open_selected(self):
|
||||||
if self.selected_dupes:
|
if self.selected_dupes:
|
||||||
self._open_path(self.selected_dupes[0].path)
|
self._open_path(self.selected_dupes[0].path)
|
||||||
|
|
||||||
|
def purge_ignore_list(self):
|
||||||
|
self.scanner.ignore_list.Filter(lambda f,s:op.exists(f) and op.exists(s))
|
||||||
|
|
||||||
def remove_directory(self,index):
|
def remove_directory(self,index):
|
||||||
try:
|
try:
|
||||||
del self.directories[index]
|
del self.directories[index]
|
||||||
@@ -246,11 +279,25 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def remove_duplicates(self, duplicates):
|
def remove_duplicates(self, duplicates):
|
||||||
self.results.remove_duplicates(duplicates)
|
self.results.remove_duplicates(self.without_ref(duplicates))
|
||||||
|
self.notify('results_changed_but_keep_selection')
|
||||||
|
|
||||||
|
def remove_marked(self):
|
||||||
|
self.results.perform_on_marked(lambda x:True, True)
|
||||||
|
self.notify('results_changed')
|
||||||
|
|
||||||
def remove_selected(self):
|
def remove_selected(self):
|
||||||
self.remove_duplicates(self.selected_dupes)
|
self.remove_duplicates(self.selected_dupes)
|
||||||
|
|
||||||
|
def rename_selected(self, newname):
|
||||||
|
try:
|
||||||
|
d = self.selected_dupes[0]
|
||||||
|
d.rename(newname)
|
||||||
|
return True
|
||||||
|
except (IndexError, fs.FSError) as e:
|
||||||
|
logging.warning("dupeGuru Warning: %s" % unicode(e))
|
||||||
|
return False
|
||||||
|
|
||||||
def reveal_selected(self):
|
def reveal_selected(self):
|
||||||
if self.selected_dupes:
|
if self.selected_dupes:
|
||||||
self._reveal_path(self.selected_dupes[0].path)
|
self._reveal_path(self.selected_dupes[0].path)
|
||||||
@@ -283,6 +330,11 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
self.results.groups = []
|
self.results.groups = []
|
||||||
self._start_job(JOB_SCAN, do)
|
self._start_job(JOB_SCAN, do)
|
||||||
|
|
||||||
|
def toggle_selected_mark_state(self):
|
||||||
|
for dupe in self.selected_dupes:
|
||||||
|
self.results.mark_toggle(dupe)
|
||||||
|
self.notify('marking_changed')
|
||||||
|
|
||||||
def without_ref(self, dupes):
|
def without_ref(self, dupes):
|
||||||
return [dupe for dupe in dupes if self.results.get_group_of_duplicate(dupe).ref is not dupe]
|
return [dupe for dupe in dupes if self.results.get_group_of_duplicate(dupe).ref is not dupe]
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,10 @@ from hsutil import cocoa, job
|
|||||||
from hsutil.cocoa import install_exception_hook
|
from hsutil.cocoa import install_exception_hook
|
||||||
from hsutil.cocoa.objcmin import (NSNotificationCenter, NSUserDefaults,
|
from hsutil.cocoa.objcmin import (NSNotificationCenter, NSUserDefaults,
|
||||||
NSSearchPathForDirectoriesInDomains, NSApplicationSupportDirectory, NSUserDomainMask,
|
NSSearchPathForDirectoriesInDomains, NSApplicationSupportDirectory, NSUserDomainMask,
|
||||||
NSWorkspace, NSWorkspaceRecycleOperation)
|
NSWorkspace)
|
||||||
from hsutil.misc import stripnone
|
|
||||||
from hsutil.reg import RegistrationRequired
|
from hsutil.reg import RegistrationRequired
|
||||||
|
|
||||||
from . import app, fs
|
from . import app
|
||||||
|
|
||||||
JOBID2TITLE = {
|
JOBID2TITLE = {
|
||||||
app.JOB_SCAN: "Scanning for duplicates",
|
app.JOB_SCAN: "Scanning for duplicates",
|
||||||
@@ -46,21 +45,12 @@ class DupeGuru(app.DupeGuru):
|
|||||||
appdata = op.join(appsupport, appdata_subdir)
|
appdata = op.join(appsupport, appdata_subdir)
|
||||||
app.DupeGuru.__init__(self, data_module, appdata, appid)
|
app.DupeGuru.__init__(self, data_module, appdata, appid)
|
||||||
self.progress = cocoa.ThreadedJobPerformer()
|
self.progress = cocoa.ThreadedJobPerformer()
|
||||||
self.display_delta_values = False
|
|
||||||
|
|
||||||
#--- Override
|
#--- Override
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _open_path(path):
|
def _open_path(path):
|
||||||
NSWorkspace.sharedWorkspace().openFile_(unicode(path))
|
NSWorkspace.sharedWorkspace().openFile_(unicode(path))
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _recycle_dupe(dupe):
|
|
||||||
# local import because first appkit import takes a lot of memory. we want to avoid it.
|
|
||||||
directory = unicode(dupe.path[:-1])
|
|
||||||
filename = dupe.name
|
|
||||||
result, tag = NSWorkspace.sharedWorkspace().performFileOperation_source_destination_files_tag_(
|
|
||||||
NSWorkspaceRecycleOperation, directory, '', [filename], None)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _reveal_path(path):
|
def _reveal_path(path):
|
||||||
NSWorkspace.sharedWorkspace().selectFile_inFileViewerRootedAtPath_(unicode(path), '')
|
NSWorkspace.sharedWorkspace().selectFile_inFileViewerRootedAtPath_(unicode(path), '')
|
||||||
@@ -75,34 +65,10 @@ class DupeGuru(app.DupeGuru):
|
|||||||
ud = {'desc': JOBID2TITLE[jobid], 'jobid':jobid}
|
ud = {'desc': JOBID2TITLE[jobid], 'jobid':jobid}
|
||||||
NSNotificationCenter.defaultCenter().postNotificationName_object_userInfo_('JobStarted', self, ud)
|
NSNotificationCenter.defaultCenter().postNotificationName_object_userInfo_('JobStarted', self, ud)
|
||||||
|
|
||||||
#---Helpers
|
|
||||||
def GetObjects(self,node_path):
|
|
||||||
#returns a tuple g,d
|
|
||||||
try:
|
|
||||||
g = self.results.groups[node_path[0]]
|
|
||||||
if len(node_path) == 2:
|
|
||||||
return (g,self.results.groups[node_path[0]].dupes[node_path[1]])
|
|
||||||
else:
|
|
||||||
return (g,None)
|
|
||||||
except IndexError:
|
|
||||||
return (None,None)
|
|
||||||
|
|
||||||
#---Public
|
#---Public
|
||||||
copy_or_move_marked = demo_method(app.DupeGuru.copy_or_move_marked)
|
copy_or_move_marked = demo_method(app.DupeGuru.copy_or_move_marked)
|
||||||
delete_marked = demo_method(app.DupeGuru.delete_marked)
|
delete_marked = demo_method(app.DupeGuru.delete_marked)
|
||||||
|
|
||||||
def PurgeIgnoreList(self):
|
|
||||||
self.scanner.ignore_list.Filter(lambda f,s:op.exists(f) and op.exists(s))
|
|
||||||
|
|
||||||
def RenameSelected(self, newname):
|
|
||||||
try:
|
|
||||||
d = self.selected_dupes[0]
|
|
||||||
d.rename(newname)
|
|
||||||
return True
|
|
||||||
except (IndexError, fs.FSError) as e:
|
|
||||||
logging.warning("dupeGuru Warning: %s" % unicode(e))
|
|
||||||
return False
|
|
||||||
|
|
||||||
def start_scanning(self):
|
def start_scanning(self):
|
||||||
self._select_dupes([])
|
self._select_dupes([])
|
||||||
try:
|
try:
|
||||||
@@ -113,106 +79,3 @@ class DupeGuru(app.DupeGuru):
|
|||||||
except app.AllFilesAreRefError:
|
except app.AllFilesAreRefError:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def selected_result_node_paths(self):
|
|
||||||
def get_path(dupe):
|
|
||||||
try:
|
|
||||||
group = self.results.get_group_of_duplicate(dupe)
|
|
||||||
groupindex = self.results.groups.index(group)
|
|
||||||
if dupe is group.ref:
|
|
||||||
return [groupindex]
|
|
||||||
dupeindex = group.dupes.index(dupe)
|
|
||||||
return [groupindex, dupeindex]
|
|
||||||
except ValueError: # dupe not in there
|
|
||||||
return None
|
|
||||||
|
|
||||||
dupes = self.selected_dupes
|
|
||||||
return stripnone(get_path(dupe) for dupe in dupes)
|
|
||||||
|
|
||||||
def selected_powermarker_node_paths(self):
|
|
||||||
def get_path(dupe):
|
|
||||||
try:
|
|
||||||
dupeindex = self.results.dupes.index(dupe)
|
|
||||||
return [dupeindex]
|
|
||||||
except ValueError: # dupe not in there
|
|
||||||
return None
|
|
||||||
|
|
||||||
dupes = self.selected_dupes
|
|
||||||
return stripnone(get_path(dupe) for dupe in dupes)
|
|
||||||
|
|
||||||
def SelectResultNodePaths(self,node_paths):
|
|
||||||
def extract_dupe(t):
|
|
||||||
g,d = t
|
|
||||||
if d is not None:
|
|
||||||
return d
|
|
||||||
else:
|
|
||||||
if g is not None:
|
|
||||||
return g.ref
|
|
||||||
|
|
||||||
selected = [extract_dupe(self.GetObjects(p)) for p in node_paths]
|
|
||||||
self._select_dupes([dupe for dupe in selected if dupe is not None])
|
|
||||||
|
|
||||||
def SelectPowerMarkerNodePaths(self,node_paths):
|
|
||||||
rows = [p[0] for p in node_paths]
|
|
||||||
dupes = [self.results.dupes[row] for row in rows if row in xrange(len(self.results.dupes))]
|
|
||||||
self._select_dupes(dupes)
|
|
||||||
|
|
||||||
def sort_dupes(self,key,asc):
|
|
||||||
self.results.sort_dupes(key,asc,self.display_delta_values)
|
|
||||||
|
|
||||||
def sort_groups(self,key,asc):
|
|
||||||
self.results.sort_groups(key,asc)
|
|
||||||
|
|
||||||
def ToggleSelectedMarkState(self):
|
|
||||||
for dupe in self.selected_dupes:
|
|
||||||
self.results.mark_toggle(dupe)
|
|
||||||
|
|
||||||
#---Data
|
|
||||||
def GetOutlineViewMaxLevel(self, tag):
|
|
||||||
if tag == 0:
|
|
||||||
return 2
|
|
||||||
elif tag == 2:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
def GetOutlineViewChildCounts(self, tag, node_path):
|
|
||||||
if self.progress._job_running:
|
|
||||||
return []
|
|
||||||
if tag == 0: #Normal results
|
|
||||||
assert not node_path # no other value is possible
|
|
||||||
return [len(g.dupes) for g in self.results.groups]
|
|
||||||
else: #Power Marker
|
|
||||||
assert not node_path # no other value is possible
|
|
||||||
return [0 for d in self.results.dupes]
|
|
||||||
|
|
||||||
def GetOutlineViewValues(self, tag, node_path):
|
|
||||||
if self.progress._job_running:
|
|
||||||
return
|
|
||||||
if not node_path:
|
|
||||||
return
|
|
||||||
if tag in (0,2): #Normal results / Power Marker
|
|
||||||
if tag == 0:
|
|
||||||
g, d = self.GetObjects(node_path)
|
|
||||||
if (d is None) and (g is not None):
|
|
||||||
d = g.ref
|
|
||||||
else:
|
|
||||||
d = self.results.dupes[node_path[0]]
|
|
||||||
g = self.results.get_group_of_duplicate(d)
|
|
||||||
result = self._get_display_info(d, g, self.display_delta_values)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def GetOutlineViewMarked(self, tag, node_path):
|
|
||||||
# 0=unmarked 1=marked 2=unmarkable
|
|
||||||
if self.progress._job_running:
|
|
||||||
return
|
|
||||||
if not node_path:
|
|
||||||
return 2
|
|
||||||
if tag == 0: #Normal results
|
|
||||||
g, d = self.GetObjects(node_path)
|
|
||||||
else: #Power Marker
|
|
||||||
d = self.results.dupes[node_path[0]]
|
|
||||||
if (d is None) or (not self.results.is_markable(d)):
|
|
||||||
return 2
|
|
||||||
elif self.results.is_marked(d):
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ from hsutil.cocoa.inter import signature, 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.result_tree import ResultTree
|
||||||
|
from .gui.stats_label import StatsLabel
|
||||||
|
|
||||||
# Fix py2app's problems on relative imports
|
# Fix py2app's problems on relative imports
|
||||||
from core import app, app_cocoa, data, directories, engine, export, ignore, results, fs, scanner
|
from core import app, app_cocoa, data, directories, engine, export, ignore, results, fs, scanner
|
||||||
@@ -43,19 +45,19 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
self.py.load()
|
self.py.load()
|
||||||
|
|
||||||
def markAll(self):
|
def markAll(self):
|
||||||
self.py.results.mark_all()
|
self.py.mark_all()
|
||||||
|
|
||||||
def markNone(self):
|
def markNone(self):
|
||||||
self.py.results.mark_none()
|
self.py.mark_none()
|
||||||
|
|
||||||
def markInvert(self):
|
def markInvert(self):
|
||||||
self.py.results.mark_invert()
|
self.py.mark_invert()
|
||||||
|
|
||||||
def purgeIgnoreList(self):
|
def purgeIgnoreList(self):
|
||||||
self.py.PurgeIgnoreList()
|
self.py.purge_ignore_list()
|
||||||
|
|
||||||
def toggleSelectedMark(self):
|
def toggleSelectedMark(self):
|
||||||
self.py.ToggleSelectedMarkState()
|
self.py.toggle_selected_mark_state()
|
||||||
|
|
||||||
def saveIgnoreList(self):
|
def saveIgnoreList(self):
|
||||||
self.py.save_ignore_list()
|
self.py.save_ignore_list()
|
||||||
@@ -63,18 +65,6 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
def saveResults(self):
|
def saveResults(self):
|
||||||
self.py.save()
|
self.py.save()
|
||||||
|
|
||||||
def selectedResultNodePaths(self):
|
|
||||||
return self.py.selected_result_node_paths()
|
|
||||||
|
|
||||||
def selectResultNodePaths_(self,node_paths):
|
|
||||||
self.py.SelectResultNodePaths(node_paths)
|
|
||||||
|
|
||||||
def selectedPowerMarkerNodePaths(self):
|
|
||||||
return self.py.selected_powermarker_node_paths()
|
|
||||||
|
|
||||||
def selectPowerMarkerNodePaths_(self,node_paths):
|
|
||||||
self.py.SelectPowerMarkerNodePaths(node_paths)
|
|
||||||
|
|
||||||
#---Actions
|
#---Actions
|
||||||
def addSelectedToIgnoreList(self):
|
def addSelectedToIgnoreList(self):
|
||||||
self.py.add_selected_to_ignore_list()
|
self.py.add_selected_to_ignore_list()
|
||||||
@@ -95,24 +85,14 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
self.py.open_selected()
|
self.py.open_selected()
|
||||||
|
|
||||||
def removeMarked(self):
|
def removeMarked(self):
|
||||||
self.py.results.perform_on_marked(lambda x:True, True)
|
self.py.remove_marked()
|
||||||
|
|
||||||
def removeSelected(self):
|
|
||||||
self.py.remove_selected()
|
|
||||||
|
|
||||||
def renameSelected_(self,newname):
|
def renameSelected_(self,newname):
|
||||||
return self.py.RenameSelected(newname)
|
return self.py.rename_selected(newname)
|
||||||
|
|
||||||
def revealSelected(self):
|
def revealSelected(self):
|
||||||
self.py.reveal_selected()
|
self.py.reveal_selected()
|
||||||
|
|
||||||
#---Misc
|
|
||||||
def sortDupesBy_ascending_(self, key, asc):
|
|
||||||
self.py.sort_dupes(key, asc)
|
|
||||||
|
|
||||||
def sortGroupsBy_ascending_(self, key, asc):
|
|
||||||
self.py.sort_groups(key, asc)
|
|
||||||
|
|
||||||
#---Information
|
#---Information
|
||||||
def getIgnoreListCount(self):
|
def getIgnoreListCount(self):
|
||||||
return len(self.py.scanner.ignore_list)
|
return len(self.py.scanner.ignore_list)
|
||||||
@@ -120,34 +100,13 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
def getMarkCount(self):
|
def getMarkCount(self):
|
||||||
return self.py.results.mark_count
|
return self.py.results.mark_count
|
||||||
|
|
||||||
def getStatLine(self):
|
|
||||||
return self.py.stat_line
|
|
||||||
|
|
||||||
def getOperationalErrorCount(self):
|
def getOperationalErrorCount(self):
|
||||||
return self.py.last_op_error_count
|
return self.py.last_op_error_count
|
||||||
|
|
||||||
#---Data
|
|
||||||
@signature('i@:i')
|
|
||||||
def getOutlineViewMaxLevel_(self, tag):
|
|
||||||
return self.py.GetOutlineViewMaxLevel(tag)
|
|
||||||
|
|
||||||
@signature('@@:i@')
|
|
||||||
def getOutlineView_childCountsForPath_(self, tag, node_path):
|
|
||||||
return self.py.GetOutlineViewChildCounts(tag, node_path)
|
|
||||||
|
|
||||||
def getOutlineView_valuesForIndexes_(self, tag, node_path):
|
|
||||||
return self.py.GetOutlineViewValues(tag, node_path)
|
|
||||||
|
|
||||||
def getOutlineView_markedAtIndexes_(self, tag, node_path):
|
|
||||||
return self.py.GetOutlineViewMarked(tag, node_path)
|
|
||||||
|
|
||||||
#---Properties
|
#---Properties
|
||||||
def setMixFileKind_(self, mix_file_kind):
|
def setMixFileKind_(self, mix_file_kind):
|
||||||
self.py.scanner.mix_file_kind = mix_file_kind
|
self.py.scanner.mix_file_kind = mix_file_kind
|
||||||
|
|
||||||
def setDisplayDeltaValues_(self, display_delta_values):
|
|
||||||
self.py.display_delta_values= display_delta_values
|
|
||||||
|
|
||||||
def setEscapeFilterRegexp_(self, escape_filter_regexp):
|
def setEscapeFilterRegexp_(self, escape_filter_regexp):
|
||||||
self.py.options['escape_filter_regexp'] = escape_filter_regexp
|
self.py.options['escape_filter_regexp'] = escape_filter_regexp
|
||||||
|
|
||||||
@@ -164,6 +123,9 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
def cancelJob(self):
|
def cancelJob(self):
|
||||||
self.py.progress.job_cancelled = True
|
self.py.progress.job_cancelled = True
|
||||||
|
|
||||||
|
def jobCompleted_(self, jobid):
|
||||||
|
self.py._job_completed(jobid)
|
||||||
|
|
||||||
|
|
||||||
class PyDetailsPanel(PyGUIObject):
|
class PyDetailsPanel(PyGUIObject):
|
||||||
py_class = DetailsPanel
|
py_class = DetailsPanel
|
||||||
@@ -182,3 +144,55 @@ class PyDirectoryOutline(PyOutline):
|
|||||||
def addDirectory_(self, path):
|
def addDirectory_(self, path):
|
||||||
self.py.add_directory(path)
|
self.py.add_directory(path)
|
||||||
|
|
||||||
|
|
||||||
|
class PyResultOutline(PyOutline):
|
||||||
|
py_class = ResultTree
|
||||||
|
|
||||||
|
@signature('c@:')
|
||||||
|
def powerMarkerMode(self):
|
||||||
|
return self.py.power_marker
|
||||||
|
|
||||||
|
@signature('v@:c')
|
||||||
|
def setPowerMarkerMode_(self, value):
|
||||||
|
self.py.power_marker = value
|
||||||
|
|
||||||
|
@signature('c@:')
|
||||||
|
def deltaValuesMode(self):
|
||||||
|
return self.py.delta_values
|
||||||
|
|
||||||
|
@signature('v@:c')
|
||||||
|
def setDeltaValuesMode_(self, value):
|
||||||
|
self.py.delta_values = value
|
||||||
|
|
||||||
|
@signature('@@:@i')
|
||||||
|
def valueForPath_column_(self, path, column):
|
||||||
|
return self.py.get_node_value(path, column)
|
||||||
|
|
||||||
|
@signature('c@:@')
|
||||||
|
def renameSelected_(self, newname):
|
||||||
|
return self.py.rename_selected(newname)
|
||||||
|
|
||||||
|
@signature('v@:ic')
|
||||||
|
def sortBy_ascending_(self, key, asc):
|
||||||
|
self.py.sort(key, asc)
|
||||||
|
|
||||||
|
def markSelected(self):
|
||||||
|
self.py.app.toggle_selected_mark_state()
|
||||||
|
|
||||||
|
def removeSelected(self):
|
||||||
|
self.py.app.remove_selected()
|
||||||
|
|
||||||
|
def rootChildrenCounts(self):
|
||||||
|
return self.py.root_children_counts()
|
||||||
|
|
||||||
|
# python --> cocoa
|
||||||
|
def invalidate_markings(self):
|
||||||
|
self.cocoa.invalidateMarkings()
|
||||||
|
|
||||||
|
|
||||||
|
class PyStatsLabel(PyGUIObject):
|
||||||
|
py_class = StatsLabel
|
||||||
|
|
||||||
|
def display(self):
|
||||||
|
return self.py.display
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,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
|
||||||
|
|
||||||
import xml.dom.minidom
|
from lxml import etree
|
||||||
|
|
||||||
from hsutil import io
|
from hsutil import io
|
||||||
from hsutil.files import FileOrPath
|
from hsutil.files import FileOrPath
|
||||||
@@ -126,38 +126,38 @@ class Directories(object):
|
|||||||
|
|
||||||
def load_from_file(self, infile):
|
def load_from_file(self, infile):
|
||||||
try:
|
try:
|
||||||
doc = xml.dom.minidom.parse(infile)
|
root = etree.parse(infile).getroot()
|
||||||
except:
|
except:
|
||||||
return
|
return
|
||||||
root_path_nodes = doc.getElementsByTagName('root_directory')
|
for rdn in root.iterchildren('root_directory'):
|
||||||
for rdn in root_path_nodes:
|
attrib = rdn.attrib
|
||||||
if not rdn.getAttributeNode('path'):
|
if 'path' not in attrib:
|
||||||
continue
|
continue
|
||||||
path = rdn.getAttributeNode('path').nodeValue
|
path = attrib['path']
|
||||||
try:
|
try:
|
||||||
self.add_path(Path(path))
|
self.add_path(Path(path))
|
||||||
except (AlreadyThereError, InvalidPathError):
|
except (AlreadyThereError, InvalidPathError):
|
||||||
pass
|
pass
|
||||||
state_nodes = doc.getElementsByTagName('state')
|
for sn in root.iterchildren('state'):
|
||||||
for sn in state_nodes:
|
attrib = sn.attrib
|
||||||
if not (sn.getAttributeNode('path') and sn.getAttributeNode('value')):
|
if not ('path' in attrib and 'value' in attrib):
|
||||||
continue
|
continue
|
||||||
path = sn.getAttributeNode('path').nodeValue
|
path = attrib['path']
|
||||||
state = sn.getAttributeNode('value').nodeValue
|
state = attrib['value']
|
||||||
self.set_state(Path(path), int(state))
|
self.set_state(Path(path), int(state))
|
||||||
|
|
||||||
def save_to_file(self,outfile):
|
def save_to_file(self, outfile):
|
||||||
with FileOrPath(outfile, 'wb') as fp:
|
with FileOrPath(outfile, 'wb') as fp:
|
||||||
doc = xml.dom.minidom.Document()
|
root = etree.Element('directories')
|
||||||
root = doc.appendChild(doc.createElement('directories'))
|
|
||||||
for root_path in self:
|
for root_path in self:
|
||||||
root_path_node = root.appendChild(doc.createElement('root_directory'))
|
root_path_node = etree.SubElement(root, 'root_directory')
|
||||||
root_path_node.setAttribute('path', unicode(root_path).encode('utf-8'))
|
root_path_node.set('path', unicode(root_path))
|
||||||
for path, state in self.states.iteritems():
|
for path, state in self.states.iteritems():
|
||||||
state_node = root.appendChild(doc.createElement('state'))
|
state_node = etree.SubElement(root, 'state')
|
||||||
state_node.setAttribute('path', unicode(path).encode('utf-8'))
|
state_node.set('path', unicode(path))
|
||||||
state_node.setAttribute('value', str(state))
|
state_node.set('value', unicode(state))
|
||||||
doc.writexml(fp, '\t', '\t', '\n', encoding='utf-8')
|
tree = etree.ElementTree(root)
|
||||||
|
tree.write(fp, encoding='utf-8')
|
||||||
|
|
||||||
def set_state(self, path, state):
|
def set_state(self, path, state):
|
||||||
if self.get_state(path) == state:
|
if self.get_state(path) == state:
|
||||||
|
|||||||
@@ -21,3 +21,12 @@ class GUIObject(Listener):
|
|||||||
def dupes_selected(self):
|
def dupes_selected(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def marking_changed(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def results_changed(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def results_changed_but_keep_selection(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,11 @@ class DetailsPanel(GUIObject):
|
|||||||
def __init__(self, view, app):
|
def __init__(self, view, app):
|
||||||
GUIObject.__init__(self, view, app)
|
GUIObject.__init__(self, view, app)
|
||||||
self._table = []
|
self._table = []
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
GUIObject.connect(self)
|
||||||
self._refresh()
|
self._refresh()
|
||||||
self.connect()
|
self.view.refresh()
|
||||||
|
|
||||||
#--- Private
|
#--- Private
|
||||||
def _refresh(self):
|
def _refresh(self):
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ class DirectoryTree(GUIObject, Tree):
|
|||||||
def __init__(self, view, app):
|
def __init__(self, view, app):
|
||||||
GUIObject.__init__(self, view, app)
|
GUIObject.__init__(self, view, app)
|
||||||
Tree.__init__(self)
|
Tree.__init__(self)
|
||||||
self.connect()
|
|
||||||
|
def connect(self):
|
||||||
|
GUIObject.connect(self)
|
||||||
self._refresh()
|
self._refresh()
|
||||||
self.view.refresh()
|
self.view.refresh()
|
||||||
|
|
||||||
|
|||||||
159
core/gui/result_tree.py
Normal file
159
core/gui/result_tree.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Created By: Virgil Dupras
|
||||||
|
# Created On: 2010-02-11
|
||||||
|
# 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 operator import attrgetter
|
||||||
|
|
||||||
|
from hsgui.tree import Tree, Node
|
||||||
|
|
||||||
|
from .base import GUIObject
|
||||||
|
|
||||||
|
class DupeNode(Node):
|
||||||
|
def __init__(self, app, group, dupe):
|
||||||
|
Node.__init__(self, '')
|
||||||
|
self._app = app
|
||||||
|
self._group = group
|
||||||
|
self._dupe = dupe
|
||||||
|
self._data = None
|
||||||
|
self._data_delta = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
if self._data is None:
|
||||||
|
self._data = self._app._get_display_info(self._dupe, self._group, False)
|
||||||
|
return self._data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data_delta(self):
|
||||||
|
if self._data_delta is None:
|
||||||
|
self._data_delta = self._app._get_display_info(self._dupe, self._group, True)
|
||||||
|
return self._data_delta
|
||||||
|
|
||||||
|
@property
|
||||||
|
def markable(self):
|
||||||
|
return self._app.results.is_markable(self._dupe)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def marked(self):
|
||||||
|
return self._app.results.is_marked(self._dupe)
|
||||||
|
|
||||||
|
@marked.setter
|
||||||
|
def marked(self, value):
|
||||||
|
self._app.mark_dupe(self._dupe, value)
|
||||||
|
|
||||||
|
|
||||||
|
class ResultTree(GUIObject, Tree):
|
||||||
|
def __init__(self, view, app):
|
||||||
|
GUIObject.__init__(self, view, app)
|
||||||
|
Tree.__init__(self)
|
||||||
|
self._power_marker = False
|
||||||
|
self._delta_values = False
|
||||||
|
self._sort_descriptors = (0, True)
|
||||||
|
|
||||||
|
#--- Override
|
||||||
|
def connect(self):
|
||||||
|
GUIObject.connect(self)
|
||||||
|
self._refresh()
|
||||||
|
self.view.refresh()
|
||||||
|
|
||||||
|
def _select_nodes(self, nodes):
|
||||||
|
Tree._select_nodes(self, nodes)
|
||||||
|
self.app._select_dupes(map(attrgetter('_dupe'), nodes))
|
||||||
|
|
||||||
|
#--- Private
|
||||||
|
def _refresh(self):
|
||||||
|
self.clear()
|
||||||
|
if not self.power_marker:
|
||||||
|
for group in self.app.results.groups:
|
||||||
|
group_node = DupeNode(self.app, group, group.ref)
|
||||||
|
self.append(group_node)
|
||||||
|
for dupe in group.dupes:
|
||||||
|
group_node.append(DupeNode(self.app, group, dupe))
|
||||||
|
else:
|
||||||
|
for dupe in self.app.results.dupes:
|
||||||
|
group = self.app.results.get_group_of_duplicate(dupe)
|
||||||
|
self.append(DupeNode(self.app, group, dupe))
|
||||||
|
if self.app.selected_dupes:
|
||||||
|
to_find = set(self.app.selected_dupes)
|
||||||
|
nodes = list(self.findall(lambda n: n is not self and n._dupe in to_find))
|
||||||
|
self.selected_nodes = nodes
|
||||||
|
|
||||||
|
#--- Public
|
||||||
|
def get_node_value(self, path, column):
|
||||||
|
try:
|
||||||
|
node = self.get_node(path)
|
||||||
|
except IndexError:
|
||||||
|
return '---'
|
||||||
|
if self.delta_values:
|
||||||
|
return node.data_delta[column]
|
||||||
|
else:
|
||||||
|
return node.data[column]
|
||||||
|
|
||||||
|
def rename_selected(self, newname):
|
||||||
|
node = self.selected_node
|
||||||
|
node._data = None
|
||||||
|
node._data_delta = None
|
||||||
|
return self.app.rename_selected(newname)
|
||||||
|
|
||||||
|
def root_children_counts(self):
|
||||||
|
# This is a speed optimization for cases where there's a lot of results so that there is
|
||||||
|
# not thousands of children_count queries when expandAll is called.
|
||||||
|
return [len(node) for node in self]
|
||||||
|
|
||||||
|
def sort(self, key, asc):
|
||||||
|
if self.power_marker:
|
||||||
|
self.app.results.sort_dupes(key, asc, self.delta_values)
|
||||||
|
else:
|
||||||
|
self.app.results.sort_groups(key, asc)
|
||||||
|
self._sort_descriptors = (key, asc)
|
||||||
|
self._refresh()
|
||||||
|
self.view.refresh()
|
||||||
|
|
||||||
|
#--- Properties
|
||||||
|
@property
|
||||||
|
def power_marker(self):
|
||||||
|
return self._power_marker
|
||||||
|
|
||||||
|
@power_marker.setter
|
||||||
|
def power_marker(self, value):
|
||||||
|
if value == self._power_marker:
|
||||||
|
return
|
||||||
|
self._power_marker = value
|
||||||
|
key, asc = self._sort_descriptors
|
||||||
|
self.sort(key, asc)
|
||||||
|
self._refresh()
|
||||||
|
self.view.refresh()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def delta_values(self):
|
||||||
|
return self._delta_values
|
||||||
|
|
||||||
|
@delta_values.setter
|
||||||
|
def delta_values(self, value):
|
||||||
|
if value == self._delta_values:
|
||||||
|
return
|
||||||
|
self._delta_values = value
|
||||||
|
self._refresh()
|
||||||
|
self.view.refresh()
|
||||||
|
|
||||||
|
#--- Event Handlers
|
||||||
|
def marking_changed(self):
|
||||||
|
self.view.invalidate_markings()
|
||||||
|
|
||||||
|
def results_changed(self):
|
||||||
|
self._refresh()
|
||||||
|
self.view.refresh()
|
||||||
|
|
||||||
|
def results_changed_but_keep_selection(self):
|
||||||
|
# What we want to to here is that instead of restoring selected *dupes* after refresh, we
|
||||||
|
# restore selected *paths*.
|
||||||
|
paths = self.selected_paths
|
||||||
|
self._refresh()
|
||||||
|
self.selected_paths = paths
|
||||||
|
self.view.refresh()
|
||||||
|
|
||||||
23
core/gui/stats_label.py
Normal file
23
core/gui/stats_label.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Created By: Virgil Dupras
|
||||||
|
# Created On: 2010-02-11
|
||||||
|
# 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 .base import GUIObject
|
||||||
|
|
||||||
|
class StatsLabel(GUIObject):
|
||||||
|
def connect(self):
|
||||||
|
GUIObject.connect(self)
|
||||||
|
self.view.refresh()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def display(self):
|
||||||
|
return self.app.stat_line
|
||||||
|
|
||||||
|
def results_changed(self):
|
||||||
|
self.view.refresh()
|
||||||
|
marking_changed = results_changed
|
||||||
@@ -6,9 +6,9 @@
|
|||||||
# 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.files import FileOrPath
|
from lxml import etree
|
||||||
|
|
||||||
import xml.dom.minidom
|
from hsutil.files import FileOrPath
|
||||||
|
|
||||||
class IgnoreList(object):
|
class IgnoreList(object):
|
||||||
"""An ignore list implementation that is iterable, filterable and exportable to XML.
|
"""An ignore list implementation that is iterable, filterable and exportable to XML.
|
||||||
@@ -71,45 +71,38 @@ class IgnoreList(object):
|
|||||||
self._ignored[first] = matches
|
self._ignored[first] = matches
|
||||||
self._count += 1
|
self._count += 1
|
||||||
|
|
||||||
def load_from_xml(self,infile):
|
def load_from_xml(self, infile):
|
||||||
"""Loads the ignore list from a XML created with save_to_xml.
|
"""Loads the ignore list from a XML created with save_to_xml.
|
||||||
|
|
||||||
infile can be a file object or a filename.
|
infile can be a file object or a filename.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
doc = xml.dom.minidom.parse(infile)
|
root = etree.parse(infile).getroot()
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
file_nodes = doc.getElementsByTagName('file')
|
for fn in root.iterchildren('file'):
|
||||||
for fn in file_nodes:
|
file_path = fn.get('path')
|
||||||
if not fn.getAttributeNode('path'):
|
if not file_path:
|
||||||
continue
|
continue
|
||||||
file_path = fn.getAttributeNode('path').nodeValue
|
for sfn in fn.iterchildren('file'):
|
||||||
subfile_nodes = fn.getElementsByTagName('file')
|
subfile_path = sfn.get('path')
|
||||||
for sfn in subfile_nodes:
|
if subfile_path:
|
||||||
if not sfn.getAttributeNode('path'):
|
self.Ignore(file_path, subfile_path)
|
||||||
continue
|
|
||||||
subfile_path = sfn.getAttributeNode('path').nodeValue
|
|
||||||
self.Ignore(file_path,subfile_path)
|
|
||||||
|
|
||||||
def save_to_xml(self,outfile):
|
def save_to_xml(self, outfile):
|
||||||
"""Create a XML file that can be used by load_from_xml.
|
"""Create a XML file that can be used by load_from_xml.
|
||||||
|
|
||||||
outfile can be a file object or a filename.
|
outfile can be a file object or a filename.
|
||||||
"""
|
"""
|
||||||
doc = xml.dom.minidom.Document()
|
root = etree.Element('ignore_list')
|
||||||
root = doc.appendChild(doc.createElement('ignore_list'))
|
for filename, subfiles in self._ignored.items():
|
||||||
for file,subfiles in self._ignored.items():
|
file_node = etree.SubElement(root, 'file')
|
||||||
file_node = root.appendChild(doc.createElement('file'))
|
file_node.set('path', filename)
|
||||||
if isinstance(file,unicode):
|
for subfilename in subfiles:
|
||||||
file = file.encode('utf-8')
|
subfile_node = etree.SubElement(file_node, 'file')
|
||||||
file_node.setAttribute('path',file)
|
subfile_node.set('path', subfilename)
|
||||||
for subfile in subfiles:
|
tree = etree.ElementTree(root)
|
||||||
subfile_node = file_node.appendChild(doc.createElement('file'))
|
|
||||||
if isinstance(subfile,unicode):
|
|
||||||
subfile = subfile.encode('utf-8')
|
|
||||||
subfile_node.setAttribute('path',subfile)
|
|
||||||
with FileOrPath(outfile, 'wb') as fp:
|
with FileOrPath(outfile, 'wb') as fp:
|
||||||
doc.writexml(fp,'\t','\t','\n',encoding='utf-8')
|
tree.write(fp, encoding='utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
180
core/results.py
180
core/results.py
@@ -8,16 +8,14 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from xml.sax import handler, make_parser, SAXException
|
from lxml import etree
|
||||||
from xml.sax.saxutils import XMLGenerator
|
|
||||||
from xml.sax.xmlreader import AttributesImpl
|
|
||||||
|
|
||||||
from . import engine
|
from . import engine
|
||||||
from hsutil.job import nulljob
|
from hsutil.job import nulljob
|
||||||
from hsutil.markable import Markable
|
from hsutil.markable import Markable
|
||||||
from hsutil.misc import flatten, cond, nonone
|
from hsutil.misc import flatten, nonone
|
||||||
from hsutil.str import format_size
|
from hsutil.str import format_size
|
||||||
from hsutil.files import open_if_filename
|
from hsutil.files import FileOrPath
|
||||||
|
|
||||||
class Results(Markable):
|
class Results(Markable):
|
||||||
#---Override
|
#---Override
|
||||||
@@ -168,42 +166,54 @@ class Results(Markable):
|
|||||||
is_markable = _is_markable
|
is_markable = _is_markable
|
||||||
|
|
||||||
def load_from_xml(self, infile, get_file, j=nulljob):
|
def load_from_xml(self, infile, get_file, j=nulljob):
|
||||||
|
def do_match(ref_file, other_files, group):
|
||||||
|
if not other_files:
|
||||||
|
return
|
||||||
|
for other_file in other_files:
|
||||||
|
group.add_match(engine.get_match(ref_file, other_file))
|
||||||
|
do_match(other_files[0], other_files[1:], group)
|
||||||
|
|
||||||
self.apply_filter(None)
|
self.apply_filter(None)
|
||||||
handler = _ResultsHandler(get_file)
|
|
||||||
try:
|
try:
|
||||||
parser = make_parser()
|
root = etree.parse(infile).getroot()
|
||||||
except Exception as e:
|
except Exception:
|
||||||
# This special handling is to try to figure out the cause of #47
|
|
||||||
# We don't silently return, because we want the user to send error report.
|
|
||||||
logging.exception(e)
|
|
||||||
try:
|
|
||||||
import xml.parsers.expat
|
|
||||||
logging.warning('importing xml.parsers.expat went ok, WTF?')
|
|
||||||
except Exception as e:
|
|
||||||
# This log should give a little more details about the cause of this all
|
|
||||||
logging.exception(e)
|
|
||||||
raise
|
|
||||||
raise
|
|
||||||
parser.setContentHandler(handler)
|
|
||||||
try:
|
|
||||||
infile, must_close = open_if_filename(infile)
|
|
||||||
except IOError:
|
|
||||||
return
|
return
|
||||||
BUFSIZE = 1024 * 1024 # 1mb buffer
|
group_elems = list(root.iterchildren('group'))
|
||||||
infile.seek(0, 2)
|
groups = []
|
||||||
j.start_job(infile.tell() // BUFSIZE)
|
marked = set()
|
||||||
infile.seek(0, 0)
|
for group_elem in j.iter_with_progress(group_elems, every=100):
|
||||||
|
group = engine.Group()
|
||||||
|
dupes = []
|
||||||
|
for file_elem in group_elem.iterchildren('file'):
|
||||||
|
path = file_elem.get('path')
|
||||||
|
words = file_elem.get('words', '')
|
||||||
|
if not path:
|
||||||
|
continue
|
||||||
|
file = get_file(path)
|
||||||
|
if file is None:
|
||||||
|
continue
|
||||||
|
file.words = words.split(',')
|
||||||
|
file.is_ref = file_elem.get('is_ref') == 'y'
|
||||||
|
dupes.append(file)
|
||||||
|
if file_elem.get('marked') == 'y':
|
||||||
|
marked.add(file)
|
||||||
|
for match_elem in group_elem.iterchildren('match'):
|
||||||
try:
|
try:
|
||||||
while True:
|
attrs = match_elem.attrib
|
||||||
data = infile.read(BUFSIZE)
|
first_file = dupes[int(attrs['first'])]
|
||||||
if not data:
|
second_file = dupes[int(attrs['second'])]
|
||||||
break
|
percentage = int(attrs['percentage'])
|
||||||
parser.feed(data)
|
group.add_match(engine.Match(first_file, second_file, percentage))
|
||||||
|
except (IndexError, KeyError, ValueError): # Covers missing attr, non-int values and indexes out of bounds
|
||||||
|
pass
|
||||||
|
if (not group.matches) and (len(dupes) >= 2):
|
||||||
|
do_match(dupes[0], dupes[1:], group)
|
||||||
|
group.prioritize(lambda x: dupes.index(x))
|
||||||
|
if len(group):
|
||||||
|
groups.append(group)
|
||||||
j.add_progress()
|
j.add_progress()
|
||||||
except SAXException:
|
self.groups = groups
|
||||||
return
|
for dupe_file in marked:
|
||||||
self.groups = handler.groups
|
|
||||||
for dupe_file in handler.marked:
|
|
||||||
self.mark(dupe_file)
|
self.mark(dupe_file)
|
||||||
|
|
||||||
def make_ref(self, dupe):
|
def make_ref(self, dupe):
|
||||||
@@ -256,13 +266,10 @@ class Results(Markable):
|
|||||||
|
|
||||||
def save_to_xml(self, outfile):
|
def save_to_xml(self, outfile):
|
||||||
self.apply_filter(None)
|
self.apply_filter(None)
|
||||||
outfile, must_close = open_if_filename(outfile, 'wb')
|
root = etree.Element('results')
|
||||||
writer = XMLGenerator(outfile, 'utf-8')
|
# writer = XMLGenerator(outfile, 'utf-8')
|
||||||
writer.startDocument()
|
|
||||||
empty_attrs = AttributesImpl({})
|
|
||||||
writer.startElement('results', empty_attrs)
|
|
||||||
for g in self.groups:
|
for g in self.groups:
|
||||||
writer.startElement('group', empty_attrs)
|
group_elem = etree.SubElement(root, 'group')
|
||||||
dupe2index = {}
|
dupe2index = {}
|
||||||
for index, d in enumerate(g):
|
for index, d in enumerate(g):
|
||||||
dupe2index[d] = index
|
dupe2index[d] = index
|
||||||
@@ -270,27 +277,19 @@ class Results(Markable):
|
|||||||
words = engine.unpack_fields(d.words)
|
words = engine.unpack_fields(d.words)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
words = ()
|
words = ()
|
||||||
attrs = AttributesImpl({
|
file_elem = etree.SubElement(group_elem, 'file')
|
||||||
'path': unicode(d.path),
|
file_elem.set('path', unicode(d.path))
|
||||||
'is_ref': cond(d.is_ref, 'y', 'n'),
|
file_elem.set('is_ref', ('y' if d.is_ref else 'n'))
|
||||||
'words': ','.join(words),
|
file_elem.set('words', ','.join(words))
|
||||||
'marked': cond(self.is_marked(d), 'y', 'n')
|
file_elem.set('marked', ('y' if self.is_marked(d) else 'n'))
|
||||||
})
|
|
||||||
writer.startElement('file', attrs)
|
|
||||||
writer.endElement('file')
|
|
||||||
for match in g.matches:
|
for match in g.matches:
|
||||||
attrs = AttributesImpl({
|
match_elem = etree.SubElement(group_elem, 'match')
|
||||||
'first': str(dupe2index[match.first]),
|
match_elem.set('first', unicode(dupe2index[match.first]))
|
||||||
'second': str(dupe2index[match.second]),
|
match_elem.set('second', unicode(dupe2index[match.second]))
|
||||||
'percentage': str(int(match.percentage)),
|
match_elem.set('percentage', unicode(int(match.percentage)))
|
||||||
})
|
tree = etree.ElementTree(root)
|
||||||
writer.startElement('match', attrs)
|
with FileOrPath(outfile, 'wb') as fp:
|
||||||
writer.endElement('match')
|
tree.write(fp, encoding='utf-8')
|
||||||
writer.endElement('group')
|
|
||||||
writer.endElement('results')
|
|
||||||
writer.endDocument()
|
|
||||||
if must_close:
|
|
||||||
outfile.close()
|
|
||||||
|
|
||||||
def sort_dupes(self, key, asc=True, delta=False):
|
def sort_dupes(self, key, asc=True, delta=False):
|
||||||
if not self.__dupes:
|
if not self.__dupes:
|
||||||
@@ -310,60 +309,3 @@ class Results(Markable):
|
|||||||
dupes = property(__get_dupe_list)
|
dupes = property(__get_dupe_list)
|
||||||
groups = property(__get_groups, __set_groups)
|
groups = property(__get_groups, __set_groups)
|
||||||
stat_line = property(__get_stat_line)
|
stat_line = property(__get_stat_line)
|
||||||
|
|
||||||
class _ResultsHandler(handler.ContentHandler):
|
|
||||||
def __init__(self, get_file):
|
|
||||||
self.group = None
|
|
||||||
self.dupes = None
|
|
||||||
self.marked = set()
|
|
||||||
self.groups = []
|
|
||||||
self.get_file = get_file
|
|
||||||
|
|
||||||
def startElement(self, name, attrs):
|
|
||||||
if name == 'group':
|
|
||||||
self.group = engine.Group()
|
|
||||||
self.dupes = []
|
|
||||||
return
|
|
||||||
if (name == 'file') and (self.group is not None):
|
|
||||||
if not (('path' in attrs) and ('words' in attrs)):
|
|
||||||
return
|
|
||||||
path = attrs['path']
|
|
||||||
file = self.get_file(path)
|
|
||||||
if file is None:
|
|
||||||
return
|
|
||||||
file.words = attrs['words'].split(',')
|
|
||||||
file.is_ref = attrs.get('is_ref') == 'y'
|
|
||||||
self.dupes.append(file)
|
|
||||||
if attrs.get('marked') == 'y':
|
|
||||||
self.marked.add(file)
|
|
||||||
if (name == 'match') and (self.group is not None):
|
|
||||||
try:
|
|
||||||
first_file = self.dupes[int(attrs['first'])]
|
|
||||||
second_file = self.dupes[int(attrs['second'])]
|
|
||||||
percentage = int(attrs['percentage'])
|
|
||||||
self.group.add_match(engine.Match(first_file, second_file, percentage))
|
|
||||||
except (IndexError, KeyError, ValueError): # Covers missing attr, non-int values and indexes out of bounds
|
|
||||||
pass
|
|
||||||
|
|
||||||
def endElement(self, name):
|
|
||||||
def do_match(ref_file, other_files, group):
|
|
||||||
if not other_files:
|
|
||||||
return
|
|
||||||
for other_file in other_files:
|
|
||||||
group.add_match(engine.get_match(ref_file, other_file))
|
|
||||||
do_match(other_files[0], other_files[1:], group)
|
|
||||||
|
|
||||||
if name == 'group':
|
|
||||||
group = self.group
|
|
||||||
self.group = None
|
|
||||||
dupes = self.dupes
|
|
||||||
self.dupes = []
|
|
||||||
if group is None:
|
|
||||||
return
|
|
||||||
if len(dupes) < 2:
|
|
||||||
return
|
|
||||||
if not group.matches: # <match> elements not present, do it manually, without %
|
|
||||||
do_match(dupes[0], dupes[1:], group)
|
|
||||||
group.prioritize(lambda x: dupes.index(x))
|
|
||||||
self.groups.append(group)
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,402 +0,0 @@
|
|||||||
# Created By: Virgil Dupras
|
|
||||||
# Created On: 2006/11/11
|
|
||||||
# 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 tempfile
|
|
||||||
import shutil
|
|
||||||
import logging
|
|
||||||
import os.path as op
|
|
||||||
|
|
||||||
from nose.tools import eq_
|
|
||||||
|
|
||||||
from hsutil.path import Path
|
|
||||||
from hsutil.testcase import TestCase
|
|
||||||
from hsutil.decorators import log_calls
|
|
||||||
from hsutil import io
|
|
||||||
|
|
||||||
from . import data
|
|
||||||
from .results_test import GetTestGroups
|
|
||||||
from .. import engine, fs
|
|
||||||
try:
|
|
||||||
from ..app_cocoa import DupeGuru as DupeGuruBase
|
|
||||||
except ImportError:
|
|
||||||
from nose.plugins.skip import SkipTest
|
|
||||||
raise SkipTest("These tests can only be run on OS X")
|
|
||||||
from ..gui.details_panel import DetailsPanel
|
|
||||||
from ..gui.directory_tree import DirectoryTree
|
|
||||||
|
|
||||||
class DupeGuru(DupeGuruBase):
|
|
||||||
def __init__(self):
|
|
||||||
DupeGuruBase.__init__(self, data, '/tmp', appid=4)
|
|
||||||
|
|
||||||
def _start_job(self, jobid, func):
|
|
||||||
func(nulljob)
|
|
||||||
|
|
||||||
def r2np(rows):
|
|
||||||
#Transforms a list of rows [1,2,3] into a list of node paths [[1],[2],[3]]
|
|
||||||
return [[i] for i in rows]
|
|
||||||
|
|
||||||
class CallLogger(object):
|
|
||||||
"""This is a dummy object that logs all calls made to it.
|
|
||||||
|
|
||||||
It is used to simulate the GUI layer.
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self.calls = []
|
|
||||||
|
|
||||||
def __getattr__(self, func_name):
|
|
||||||
def func(*args, **kw):
|
|
||||||
self.calls.append(func_name)
|
|
||||||
return func
|
|
||||||
|
|
||||||
def clear_calls(self):
|
|
||||||
del self.calls[:]
|
|
||||||
|
|
||||||
|
|
||||||
class TCDupeGuru(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.app = DupeGuru()
|
|
||||||
self.dpanel_gui = CallLogger()
|
|
||||||
self.dpanel = DetailsPanel(self.dpanel_gui, self.app)
|
|
||||||
self.dtree_gui = CallLogger()
|
|
||||||
self.dtree = DirectoryTree(self.dtree_gui, self.app)
|
|
||||||
self.objects,self.matches,self.groups = GetTestGroups()
|
|
||||||
self.app.results.groups = self.groups
|
|
||||||
tmppath = self.tmppath()
|
|
||||||
io.mkdir(tmppath + 'foo')
|
|
||||||
io.mkdir(tmppath + 'bar')
|
|
||||||
self.app.directories.add_path(tmppath)
|
|
||||||
|
|
||||||
def check_gui_calls(self, gui, expected, verify_order=False):
|
|
||||||
"""Checks that the expected calls have been made to 'gui', then clears the log.
|
|
||||||
|
|
||||||
`expected` is an iterable of strings representing method names.
|
|
||||||
If `verify_order` is True, the order of the calls matters.
|
|
||||||
"""
|
|
||||||
if verify_order:
|
|
||||||
eq_(gui.calls, expected)
|
|
||||||
else:
|
|
||||||
eq_(set(gui.calls), set(expected))
|
|
||||||
gui.clear_calls()
|
|
||||||
|
|
||||||
def check_gui_calls_partial(self, gui, expected=None, not_expected=None):
|
|
||||||
"""Checks that the expected calls have been made to 'gui', then clears the log.
|
|
||||||
|
|
||||||
`expected` is an iterable of strings representing method names. Order doesn't matter.
|
|
||||||
Moreover, if calls have been made that are not in expected, no failure occur.
|
|
||||||
`not_expected` can be used for a more explicit check (rather than calling `check_gui_calls`
|
|
||||||
with an empty `expected`) to assert that calls have *not* been made.
|
|
||||||
"""
|
|
||||||
calls = set(gui.calls)
|
|
||||||
if expected is not None:
|
|
||||||
expected = set(expected)
|
|
||||||
not_called = expected - calls
|
|
||||||
assert not not_called, u"These calls haven't been made: {0}".format(not_called)
|
|
||||||
if not_expected is not None:
|
|
||||||
not_expected = set(not_expected)
|
|
||||||
called = not_expected & calls
|
|
||||||
assert not called, u"These calls shouldn't have been made: {0}".format(called)
|
|
||||||
gui.clear_calls()
|
|
||||||
|
|
||||||
def clear_gui_calls(self):
|
|
||||||
for attr in dir(self):
|
|
||||||
if attr.endswith('_gui'):
|
|
||||||
gui = getattr(self, attr)
|
|
||||||
if hasattr(gui, 'calls'): # We might have test methods ending with '_gui'
|
|
||||||
gui.clear_calls()
|
|
||||||
|
|
||||||
def test_GetObjects(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
groups = self.groups
|
|
||||||
g,d = app.GetObjects([0])
|
|
||||||
self.assert_(g is groups[0])
|
|
||||||
self.assert_(d is None)
|
|
||||||
g,d = app.GetObjects([0,0])
|
|
||||||
self.assert_(g is groups[0])
|
|
||||||
self.assert_(d is objects[1])
|
|
||||||
g,d = app.GetObjects([1,0])
|
|
||||||
self.assert_(g is groups[1])
|
|
||||||
self.assert_(d is objects[4])
|
|
||||||
|
|
||||||
def test_GetObjects_after_sort(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
groups = self.groups[:] #To keep the old order in memory
|
|
||||||
app.sort_groups(0,False) #0 = Filename
|
|
||||||
#Now, the group order is supposed to be reversed
|
|
||||||
g,d = app.GetObjects([0,0])
|
|
||||||
self.assert_(g is groups[1])
|
|
||||||
self.assert_(d is objects[4])
|
|
||||||
|
|
||||||
def test_GetObjects_out_of_range(self):
|
|
||||||
app = self.app
|
|
||||||
self.assertEqual((None,None),app.GetObjects([2]))
|
|
||||||
self.assertEqual((None,None),app.GetObjects([]))
|
|
||||||
self.assertEqual((None,None),app.GetObjects([1,2]))
|
|
||||||
|
|
||||||
def test_selected_result_node_paths(self):
|
|
||||||
# app.selected_dupes is correctly converted into node paths
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
paths = [[0, 0], [0, 1], [1]]
|
|
||||||
app.SelectResultNodePaths(paths)
|
|
||||||
eq_(app.selected_result_node_paths(), paths)
|
|
||||||
|
|
||||||
def test_selected_result_node_paths_after_deletion(self):
|
|
||||||
# cases where the selected dupes aren't there are correctly handled
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
paths = [[0, 0], [0, 1], [1]]
|
|
||||||
app.SelectResultNodePaths(paths)
|
|
||||||
app.remove_selected()
|
|
||||||
# The first 2 dupes have been removed. The 3rd one is a ref. it stays there, in first pos.
|
|
||||||
eq_(app.selected_result_node_paths(), [[0]]) # no exception
|
|
||||||
|
|
||||||
def test_selectResultNodePaths(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
app.SelectResultNodePaths([[0,0],[0,1]])
|
|
||||||
self.assertEqual(2,len(app.selected_dupes))
|
|
||||||
self.assert_(app.selected_dupes[0] is objects[1])
|
|
||||||
self.assert_(app.selected_dupes[1] is objects[2])
|
|
||||||
|
|
||||||
def test_selectResultNodePaths_with_ref(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
app.SelectResultNodePaths([[0,0],[0,1],[1]])
|
|
||||||
self.assertEqual(3,len(app.selected_dupes))
|
|
||||||
self.assert_(app.selected_dupes[0] is objects[1])
|
|
||||||
self.assert_(app.selected_dupes[1] is objects[2])
|
|
||||||
self.assert_(app.selected_dupes[2] is self.groups[1].ref)
|
|
||||||
|
|
||||||
def test_selectResultNodePaths_empty(self):
|
|
||||||
self.app.SelectResultNodePaths([])
|
|
||||||
self.assertEqual(0,len(self.app.selected_dupes))
|
|
||||||
|
|
||||||
def test_selectResultNodePaths_after_sort(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
groups = self.groups[:] #To keep the old order in memory
|
|
||||||
app.sort_groups(0,False) #0 = Filename
|
|
||||||
#Now, the group order is supposed to be reversed
|
|
||||||
app.SelectResultNodePaths([[0,0],[1],[1,0]])
|
|
||||||
self.assertEqual(3,len(app.selected_dupes))
|
|
||||||
self.assert_(app.selected_dupes[0] is objects[4])
|
|
||||||
self.assert_(app.selected_dupes[1] is groups[0].ref)
|
|
||||||
self.assert_(app.selected_dupes[2] is objects[1])
|
|
||||||
|
|
||||||
def test_selectResultNodePaths_out_of_range(self):
|
|
||||||
app = self.app
|
|
||||||
app.SelectResultNodePaths([[0,0],[0,1],[1],[1,1],[2]])
|
|
||||||
self.assertEqual(3,len(app.selected_dupes))
|
|
||||||
|
|
||||||
def test_selected_powermarker_node_paths(self):
|
|
||||||
# app.selected_dupes is correctly converted into paths
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
paths = r2np([0, 1, 2])
|
|
||||||
app.SelectPowerMarkerNodePaths(paths)
|
|
||||||
eq_(app.selected_powermarker_node_paths(), paths)
|
|
||||||
|
|
||||||
def test_selected_powermarker_node_paths_after_deletion(self):
|
|
||||||
# cases where the selected dupes aren't there are correctly handled
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
paths = r2np([0, 1, 2])
|
|
||||||
app.SelectPowerMarkerNodePaths(paths)
|
|
||||||
app.remove_selected()
|
|
||||||
eq_(app.selected_powermarker_node_paths(), []) # no exception
|
|
||||||
|
|
||||||
def test_selectPowerMarkerRows(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0,1,2]))
|
|
||||||
self.assertEqual(3,len(app.selected_dupes))
|
|
||||||
self.assert_(app.selected_dupes[0] is objects[1])
|
|
||||||
self.assert_(app.selected_dupes[1] is objects[2])
|
|
||||||
self.assert_(app.selected_dupes[2] is objects[4])
|
|
||||||
|
|
||||||
def test_selectPowerMarkerRows_empty(self):
|
|
||||||
self.app.SelectPowerMarkerNodePaths([])
|
|
||||||
self.assertEqual(0,len(self.app.selected_dupes))
|
|
||||||
|
|
||||||
def test_selectPowerMarkerRows_after_sort(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
app.sort_dupes(0,False) #0 = Filename
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0,1,2]))
|
|
||||||
self.assertEqual(3,len(app.selected_dupes))
|
|
||||||
self.assert_(app.selected_dupes[0] is objects[4])
|
|
||||||
self.assert_(app.selected_dupes[1] is objects[2])
|
|
||||||
self.assert_(app.selected_dupes[2] is objects[1])
|
|
||||||
|
|
||||||
def test_selectPowerMarkerRows_out_of_range(self):
|
|
||||||
app = self.app
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0,1,2,3]))
|
|
||||||
self.assertEqual(3,len(app.selected_dupes))
|
|
||||||
|
|
||||||
def test_toggleSelectedMark(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
app.ToggleSelectedMarkState()
|
|
||||||
self.assertEqual(0,app.results.mark_count)
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
|
||||||
app.ToggleSelectedMarkState()
|
|
||||||
self.assertEqual(2,app.results.mark_count)
|
|
||||||
self.assert_(not app.results.is_marked(objects[0]))
|
|
||||||
self.assert_(app.results.is_marked(objects[1]))
|
|
||||||
self.assert_(not app.results.is_marked(objects[2]))
|
|
||||||
self.assert_(not app.results.is_marked(objects[3]))
|
|
||||||
self.assert_(app.results.is_marked(objects[4]))
|
|
||||||
|
|
||||||
def test_refreshDetailsWithSelected(self):
|
|
||||||
self.app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
|
||||||
eq_(self.dpanel.row(0), ('Filename', 'bar bleh', 'foo bar'))
|
|
||||||
self.check_gui_calls(self.dpanel_gui, ['refresh'])
|
|
||||||
self.app.SelectPowerMarkerNodePaths([])
|
|
||||||
eq_(self.dpanel.row(0), ('Filename', '---', '---'))
|
|
||||||
self.check_gui_calls(self.dpanel_gui, ['refresh'])
|
|
||||||
|
|
||||||
def test_makeSelectedReference(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
groups = self.groups
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
|
||||||
app.make_selected_reference()
|
|
||||||
assert groups[0].ref is objects[1]
|
|
||||||
assert groups[1].ref is objects[4]
|
|
||||||
|
|
||||||
def test_makeSelectedReference_by_selecting_two_dupes_in_the_same_group(self):
|
|
||||||
app = self.app
|
|
||||||
objects = self.objects
|
|
||||||
groups = self.groups
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0,1,2]))
|
|
||||||
#Only 0 and 2 must go ref, not 1 because it is a part of the same group
|
|
||||||
app.make_selected_reference()
|
|
||||||
assert groups[0].ref is objects[1]
|
|
||||||
assert groups[1].ref is objects[4]
|
|
||||||
|
|
||||||
def test_removeSelected(self):
|
|
||||||
app = self.app
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
|
||||||
app.remove_selected()
|
|
||||||
eq_(len(app.results.dupes), 1)
|
|
||||||
app.remove_selected()
|
|
||||||
eq_(len(app.results.dupes), 1)
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
|
||||||
app.remove_selected()
|
|
||||||
eq_(len(app.results.dupes), 0)
|
|
||||||
|
|
||||||
def test_addDirectory_simple(self):
|
|
||||||
# There's already a directory in self.app, so adding another once makes 2 of em
|
|
||||||
app = self.app
|
|
||||||
eq_(app.add_directory(self.datadirpath()), 0)
|
|
||||||
eq_(len(app.directories), 2)
|
|
||||||
|
|
||||||
def test_addDirectory_already_there(self):
|
|
||||||
app = self.app
|
|
||||||
self.assertEqual(0,app.add_directory(self.datadirpath()))
|
|
||||||
self.assertEqual(1,app.add_directory(self.datadirpath()))
|
|
||||||
|
|
||||||
def test_addDirectory_does_not_exist(self):
|
|
||||||
app = self.app
|
|
||||||
self.assertEqual(2,app.add_directory('/does_not_exist'))
|
|
||||||
|
|
||||||
def test_ignore(self):
|
|
||||||
app = self.app
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([2])) #The dupe of the second, 2 sized group
|
|
||||||
app.add_selected_to_ignore_list()
|
|
||||||
self.assertEqual(1,len(app.scanner.ignore_list))
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0])) #first dupe of the 3 dupes group
|
|
||||||
app.add_selected_to_ignore_list()
|
|
||||||
#BOTH the ref and the other dupe should have been added
|
|
||||||
self.assertEqual(3,len(app.scanner.ignore_list))
|
|
||||||
|
|
||||||
def test_purgeIgnoreList(self):
|
|
||||||
app = self.app
|
|
||||||
p1 = self.filepath('zerofile')
|
|
||||||
p2 = self.filepath('zerofill')
|
|
||||||
dne = '/does_not_exist'
|
|
||||||
app.scanner.ignore_list.Ignore(dne,p1)
|
|
||||||
app.scanner.ignore_list.Ignore(p2,dne)
|
|
||||||
app.scanner.ignore_list.Ignore(p1,p2)
|
|
||||||
app.PurgeIgnoreList()
|
|
||||||
self.assertEqual(1,len(app.scanner.ignore_list))
|
|
||||||
self.assert_(app.scanner.ignore_list.AreIgnored(p1,p2))
|
|
||||||
self.assert_(not app.scanner.ignore_list.AreIgnored(dne,p1))
|
|
||||||
|
|
||||||
def test_only_unicode_is_added_to_ignore_list(self):
|
|
||||||
def FakeIgnore(first,second):
|
|
||||||
if not isinstance(first,unicode):
|
|
||||||
self.fail()
|
|
||||||
if not isinstance(second,unicode):
|
|
||||||
self.fail()
|
|
||||||
|
|
||||||
app = self.app
|
|
||||||
app.scanner.ignore_list.Ignore = FakeIgnore
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([2])) #The dupe of the second, 2 sized group
|
|
||||||
app.add_selected_to_ignore_list()
|
|
||||||
|
|
||||||
|
|
||||||
class TCDupeGuru_renameSelected(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
p = self.tmppath()
|
|
||||||
fp = open(unicode(p + 'foo bar 1'),mode='w')
|
|
||||||
fp.close()
|
|
||||||
fp = open(unicode(p + 'foo bar 2'),mode='w')
|
|
||||||
fp.close()
|
|
||||||
fp = open(unicode(p + 'foo bar 3'),mode='w')
|
|
||||||
fp.close()
|
|
||||||
files = fs.get_files(p)
|
|
||||||
matches = engine.getmatches(files)
|
|
||||||
groups = engine.get_groups(matches)
|
|
||||||
g = groups[0]
|
|
||||||
g.prioritize(lambda x:x.name)
|
|
||||||
app = DupeGuru()
|
|
||||||
app.results.groups = groups
|
|
||||||
self.app = app
|
|
||||||
self.groups = groups
|
|
||||||
self.p = p
|
|
||||||
self.files = files
|
|
||||||
|
|
||||||
def test_simple(self):
|
|
||||||
app = self.app
|
|
||||||
g = self.groups[0]
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0]))
|
|
||||||
assert app.RenameSelected('renamed')
|
|
||||||
names = io.listdir(self.p)
|
|
||||||
assert 'renamed' in names
|
|
||||||
assert 'foo bar 2' not in names
|
|
||||||
eq_(g.dupes[0].name, 'renamed')
|
|
||||||
|
|
||||||
def test_none_selected(self):
|
|
||||||
app = self.app
|
|
||||||
g = self.groups[0]
|
|
||||||
app.SelectPowerMarkerNodePaths([])
|
|
||||||
self.mock(logging, 'warning', log_calls(lambda msg: None))
|
|
||||||
assert not app.RenameSelected('renamed')
|
|
||||||
msg = logging.warning.calls[0]['msg']
|
|
||||||
eq_('dupeGuru Warning: list index out of range', msg)
|
|
||||||
names = io.listdir(self.p)
|
|
||||||
assert 'renamed' not in names
|
|
||||||
assert 'foo bar 2' in names
|
|
||||||
eq_(g.dupes[0].name, 'foo bar 2')
|
|
||||||
|
|
||||||
def test_name_already_exists(self):
|
|
||||||
app = self.app
|
|
||||||
g = self.groups[0]
|
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0]))
|
|
||||||
self.mock(logging, 'warning', log_calls(lambda msg: None))
|
|
||||||
assert not app.RenameSelected('foo bar 1')
|
|
||||||
msg = logging.warning.calls[0]['msg']
|
|
||||||
assert msg.startswith('dupeGuru Warning: \'foo bar 1\' already exists in')
|
|
||||||
names = io.listdir(self.p)
|
|
||||||
assert 'foo bar 1' in names
|
|
||||||
assert 'foo bar 2' in names
|
|
||||||
eq_(g.dupes[0].name, 'foo bar 2')
|
|
||||||
|
|
||||||
@@ -7,6 +7,9 @@
|
|||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from nose.tools import eq_
|
||||||
|
|
||||||
from hsutil.testcase import TestCase
|
from hsutil.testcase import TestCase
|
||||||
from hsutil import io
|
from hsutil import io
|
||||||
@@ -16,8 +19,12 @@ import hsutil.files
|
|||||||
from hsutil.job import nulljob
|
from hsutil.job import nulljob
|
||||||
|
|
||||||
from . import data
|
from . import data
|
||||||
from .. import app, fs
|
from .results_test import GetTestGroups
|
||||||
|
from .. import app, fs, engine
|
||||||
from ..app import DupeGuru as DupeGuruBase
|
from ..app import DupeGuru as DupeGuruBase
|
||||||
|
from ..gui.details_panel import DetailsPanel
|
||||||
|
from ..gui.directory_tree import DirectoryTree
|
||||||
|
from ..gui.result_tree import ResultTree
|
||||||
|
|
||||||
class DupeGuru(DupeGuruBase):
|
class DupeGuru(DupeGuruBase):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -27,6 +34,23 @@ class DupeGuru(DupeGuruBase):
|
|||||||
func(nulljob)
|
func(nulljob)
|
||||||
|
|
||||||
|
|
||||||
|
class CallLogger(object):
|
||||||
|
"""This is a dummy object that logs all calls made to it.
|
||||||
|
|
||||||
|
It is used to simulate the GUI layer.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.calls = []
|
||||||
|
|
||||||
|
def __getattr__(self, func_name):
|
||||||
|
def func(*args, **kw):
|
||||||
|
self.calls.append(func_name)
|
||||||
|
return func
|
||||||
|
|
||||||
|
def clear_calls(self):
|
||||||
|
del self.calls[:]
|
||||||
|
|
||||||
|
|
||||||
class TCDupeGuru(TestCase):
|
class TCDupeGuru(TestCase):
|
||||||
cls_tested_module = app
|
cls_tested_module = app
|
||||||
def test_apply_filter_calls_results_apply_filter(self):
|
def test_apply_filter_calls_results_apply_filter(self):
|
||||||
@@ -133,3 +157,327 @@ class TCDupeGuru_clean_empty_dirs(TestCase):
|
|||||||
self.assertEqual(Path('not-empty/empty'), calls[1]['path'])
|
self.assertEqual(Path('not-empty/empty'), calls[1]['path'])
|
||||||
self.assertEqual(Path('not-empty'), calls[2]['path'])
|
self.assertEqual(Path('not-empty'), calls[2]['path'])
|
||||||
|
|
||||||
|
|
||||||
|
class TCDupeGuruWithResults(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.app = DupeGuru()
|
||||||
|
self.objects,self.matches,self.groups = GetTestGroups()
|
||||||
|
self.app.results.groups = self.groups
|
||||||
|
self.dpanel_gui = CallLogger()
|
||||||
|
self.dpanel = DetailsPanel(self.dpanel_gui, self.app)
|
||||||
|
self.dtree_gui = CallLogger()
|
||||||
|
self.dtree = DirectoryTree(self.dtree_gui, self.app)
|
||||||
|
self.rtree_gui = CallLogger()
|
||||||
|
self.rtree = ResultTree(self.rtree_gui, self.app)
|
||||||
|
self.dpanel.connect()
|
||||||
|
self.dtree.connect()
|
||||||
|
self.rtree.connect()
|
||||||
|
tmppath = self.tmppath()
|
||||||
|
io.mkdir(tmppath + 'foo')
|
||||||
|
io.mkdir(tmppath + 'bar')
|
||||||
|
self.app.directories.add_path(tmppath)
|
||||||
|
|
||||||
|
def check_gui_calls(self, gui, expected, verify_order=False):
|
||||||
|
"""Checks that the expected calls have been made to 'gui', then clears the log.
|
||||||
|
|
||||||
|
`expected` is an iterable of strings representing method names.
|
||||||
|
If `verify_order` is True, the order of the calls matters.
|
||||||
|
"""
|
||||||
|
if verify_order:
|
||||||
|
eq_(gui.calls, expected)
|
||||||
|
else:
|
||||||
|
eq_(set(gui.calls), set(expected))
|
||||||
|
gui.clear_calls()
|
||||||
|
|
||||||
|
def check_gui_calls_partial(self, gui, expected=None, not_expected=None):
|
||||||
|
"""Checks that the expected calls have been made to 'gui', then clears the log.
|
||||||
|
|
||||||
|
`expected` is an iterable of strings representing method names. Order doesn't matter.
|
||||||
|
Moreover, if calls have been made that are not in expected, no failure occur.
|
||||||
|
`not_expected` can be used for a more explicit check (rather than calling `check_gui_calls`
|
||||||
|
with an empty `expected`) to assert that calls have *not* been made.
|
||||||
|
"""
|
||||||
|
calls = set(gui.calls)
|
||||||
|
if expected is not None:
|
||||||
|
expected = set(expected)
|
||||||
|
not_called = expected - calls
|
||||||
|
assert not not_called, u"These calls haven't been made: {0}".format(not_called)
|
||||||
|
if not_expected is not None:
|
||||||
|
not_expected = set(not_expected)
|
||||||
|
called = not_expected & calls
|
||||||
|
assert not called, u"These calls shouldn't have been made: {0}".format(called)
|
||||||
|
gui.clear_calls()
|
||||||
|
|
||||||
|
def clear_gui_calls(self):
|
||||||
|
for attr in dir(self):
|
||||||
|
if attr.endswith('_gui'):
|
||||||
|
gui = getattr(self, attr)
|
||||||
|
if hasattr(gui, 'calls'): # We might have test methods ending with '_gui'
|
||||||
|
gui.clear_calls()
|
||||||
|
|
||||||
|
def test_GetObjects(self):
|
||||||
|
objects = self.objects
|
||||||
|
groups = self.groups
|
||||||
|
n = self.rtree.get_node([0])
|
||||||
|
assert n._group is groups[0]
|
||||||
|
assert n._dupe is objects[0]
|
||||||
|
n = self.rtree.get_node([0, 0])
|
||||||
|
assert n._group is groups[0]
|
||||||
|
assert n._dupe is objects[1]
|
||||||
|
n = self.rtree.get_node([1, 0])
|
||||||
|
assert n._group is groups[1]
|
||||||
|
assert n._dupe is objects[4]
|
||||||
|
|
||||||
|
def test_GetObjects_after_sort(self):
|
||||||
|
objects = self.objects
|
||||||
|
groups = self.groups[:] # we need an un-sorted reference
|
||||||
|
self.rtree.sort(0, False) #0 = Filename
|
||||||
|
n = self.rtree.get_node([0, 0])
|
||||||
|
assert n._group is groups[1]
|
||||||
|
assert n._dupe is objects[4]
|
||||||
|
|
||||||
|
def test_selected_result_node_paths(self):
|
||||||
|
# app.selected_dupes is correctly converted into node paths
|
||||||
|
paths = [[0, 0], [0, 1], [1]]
|
||||||
|
self.rtree.selected_paths = paths
|
||||||
|
eq_(self.rtree.selected_paths, paths)
|
||||||
|
|
||||||
|
def test_selected_result_node_paths_after_deletion(self):
|
||||||
|
# cases where the selected dupes aren't there are correctly handled
|
||||||
|
paths = [[0, 0], [0, 1], [1]]
|
||||||
|
self.rtree.selected_paths = paths
|
||||||
|
self.app.remove_selected()
|
||||||
|
# The first 2 dupes have been removed. The 3rd one is a ref. it stays there, in first pos.
|
||||||
|
eq_(self.rtree.selected_paths, [[0, 0]]) # no exception
|
||||||
|
|
||||||
|
def test_selectResultNodePaths(self):
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
self.rtree.selected_paths = [[0, 0], [0, 1]]
|
||||||
|
eq_(len(app.selected_dupes), 2)
|
||||||
|
assert app.selected_dupes[0] is objects[1]
|
||||||
|
assert app.selected_dupes[1] is objects[2]
|
||||||
|
|
||||||
|
def test_selectResultNodePaths_with_ref(self):
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
self.rtree.selected_paths = [[0, 0], [0, 1], [1]]
|
||||||
|
eq_(len(app.selected_dupes), 3)
|
||||||
|
assert app.selected_dupes[0] is objects[1]
|
||||||
|
assert app.selected_dupes[1] is objects[2]
|
||||||
|
assert app.selected_dupes[2] is self.groups[1].ref
|
||||||
|
|
||||||
|
def test_selectResultNodePaths_after_sort(self):
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
groups = self.groups[:] #To keep the old order in memory
|
||||||
|
self.rtree.sort(0, False) #0 = Filename
|
||||||
|
#Now, the group order is supposed to be reversed
|
||||||
|
self.rtree.selected_paths = [[0, 0], [1], [1, 0]]
|
||||||
|
eq_(len(app.selected_dupes), 3)
|
||||||
|
assert app.selected_dupes[0] is objects[4]
|
||||||
|
assert app.selected_dupes[1] is groups[0].ref
|
||||||
|
assert app.selected_dupes[2] is objects[1]
|
||||||
|
|
||||||
|
def test_selected_powermarker_node_paths(self):
|
||||||
|
# app.selected_dupes is correctly converted into paths
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
self.rtree.power_marker = True
|
||||||
|
self.rtree.selected_paths = [[0], [1], [2]]
|
||||||
|
self.rtree.power_marker = False
|
||||||
|
eq_(self.rtree.selected_paths, [[0, 0], [0, 1], [1, 0]])
|
||||||
|
|
||||||
|
def test_selected_powermarker_node_paths_after_deletion(self):
|
||||||
|
# cases where the selected dupes aren't there are correctly handled
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
self.rtree.power_marker = True
|
||||||
|
self.rtree.selected_paths = [[0], [1], [2]]
|
||||||
|
app.remove_selected()
|
||||||
|
eq_(self.rtree.selected_paths, []) # no exception
|
||||||
|
|
||||||
|
def test_selectPowerMarkerRows(self):
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
self.rtree.selected_paths = [[0, 0], [0, 1], [1, 0]]
|
||||||
|
eq_(len(app.selected_dupes), 3)
|
||||||
|
assert app.selected_dupes[0] is objects[1]
|
||||||
|
assert app.selected_dupes[1] is objects[2]
|
||||||
|
assert app.selected_dupes[2] is objects[4]
|
||||||
|
|
||||||
|
def test_selectPowerMarkerRows_empty(self):
|
||||||
|
self.rtree.selected_paths = []
|
||||||
|
eq_(len(self.app.selected_dupes), 0)
|
||||||
|
|
||||||
|
def test_selectPowerMarkerRows_after_sort(self):
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
self.rtree.power_marker = True
|
||||||
|
self.rtree.sort(0, False) #0 = Filename
|
||||||
|
self.rtree.selected_paths = [[0], [1], [2]]
|
||||||
|
eq_(len(app.selected_dupes), 3)
|
||||||
|
assert app.selected_dupes[0] is objects[4]
|
||||||
|
assert app.selected_dupes[1] is objects[2]
|
||||||
|
assert app.selected_dupes[2] is objects[1]
|
||||||
|
|
||||||
|
def test_toggleSelectedMark(self):
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
app.toggle_selected_mark_state()
|
||||||
|
eq_(app.results.mark_count, 0)
|
||||||
|
self.rtree.selected_paths = [[0, 0], [1, 0]]
|
||||||
|
app.toggle_selected_mark_state()
|
||||||
|
eq_(app.results.mark_count, 2)
|
||||||
|
assert not app.results.is_marked(objects[0])
|
||||||
|
assert app.results.is_marked(objects[1])
|
||||||
|
assert not app.results.is_marked(objects[2])
|
||||||
|
assert not app.results.is_marked(objects[3])
|
||||||
|
assert app.results.is_marked(objects[4])
|
||||||
|
|
||||||
|
def test_refreshDetailsWithSelected(self):
|
||||||
|
self.rtree.selected_paths = [[0, 0], [1, 0]]
|
||||||
|
eq_(self.dpanel.row(0), ('Filename', 'bar bleh', 'foo bar'))
|
||||||
|
self.check_gui_calls(self.dpanel_gui, ['refresh'])
|
||||||
|
self.rtree.selected_paths = []
|
||||||
|
eq_(self.dpanel.row(0), ('Filename', '---', '---'))
|
||||||
|
self.check_gui_calls(self.dpanel_gui, ['refresh'])
|
||||||
|
|
||||||
|
def test_makeSelectedReference(self):
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
groups = self.groups
|
||||||
|
self.rtree.selected_paths = [[0, 0], [1, 0]]
|
||||||
|
app.make_selected_reference()
|
||||||
|
assert groups[0].ref is objects[1]
|
||||||
|
assert groups[1].ref is objects[4]
|
||||||
|
|
||||||
|
def test_makeSelectedReference_by_selecting_two_dupes_in_the_same_group(self):
|
||||||
|
app = self.app
|
||||||
|
objects = self.objects
|
||||||
|
groups = self.groups
|
||||||
|
self.rtree.selected_paths = [[0, 0], [0, 1], [1, 0]]
|
||||||
|
#Only [0, 0] and [1, 0] must go ref, not [0, 1] because it is a part of the same group
|
||||||
|
app.make_selected_reference()
|
||||||
|
assert groups[0].ref is objects[1]
|
||||||
|
assert groups[1].ref is objects[4]
|
||||||
|
|
||||||
|
def test_removeSelected(self):
|
||||||
|
app = self.app
|
||||||
|
self.rtree.selected_paths = [[0, 0], [1, 0]]
|
||||||
|
app.remove_selected()
|
||||||
|
eq_(len(app.results.dupes), 1) # the first path is now selected
|
||||||
|
app.remove_selected()
|
||||||
|
eq_(len(app.results.dupes), 0)
|
||||||
|
|
||||||
|
def test_addDirectory_simple(self):
|
||||||
|
# There's already a directory in self.app, so adding another once makes 2 of em
|
||||||
|
app = self.app
|
||||||
|
eq_(app.add_directory(self.datadirpath()), 0)
|
||||||
|
eq_(len(app.directories), 2)
|
||||||
|
|
||||||
|
def test_addDirectory_already_there(self):
|
||||||
|
app = self.app
|
||||||
|
self.assertEqual(0,app.add_directory(self.datadirpath()))
|
||||||
|
self.assertEqual(1,app.add_directory(self.datadirpath()))
|
||||||
|
|
||||||
|
def test_addDirectory_does_not_exist(self):
|
||||||
|
app = self.app
|
||||||
|
self.assertEqual(2,app.add_directory('/does_not_exist'))
|
||||||
|
|
||||||
|
def test_ignore(self):
|
||||||
|
app = self.app
|
||||||
|
self.rtree.selected_path = [1, 0] #The dupe of the second, 2 sized group
|
||||||
|
app.add_selected_to_ignore_list()
|
||||||
|
eq_(len(app.scanner.ignore_list), 1)
|
||||||
|
self.rtree.selected_path = [0, 0] #first dupe of the 3 dupes group
|
||||||
|
app.add_selected_to_ignore_list()
|
||||||
|
#BOTH the ref and the other dupe should have been added
|
||||||
|
eq_(len(app.scanner.ignore_list), 3)
|
||||||
|
|
||||||
|
def test_purgeIgnoreList(self):
|
||||||
|
app = self.app
|
||||||
|
p1 = self.filepath('zerofile')
|
||||||
|
p2 = self.filepath('zerofill')
|
||||||
|
dne = '/does_not_exist'
|
||||||
|
app.scanner.ignore_list.Ignore(dne,p1)
|
||||||
|
app.scanner.ignore_list.Ignore(p2,dne)
|
||||||
|
app.scanner.ignore_list.Ignore(p1,p2)
|
||||||
|
app.purge_ignore_list()
|
||||||
|
self.assertEqual(1,len(app.scanner.ignore_list))
|
||||||
|
self.assert_(app.scanner.ignore_list.AreIgnored(p1,p2))
|
||||||
|
self.assert_(not app.scanner.ignore_list.AreIgnored(dne,p1))
|
||||||
|
|
||||||
|
def test_only_unicode_is_added_to_ignore_list(self):
|
||||||
|
def FakeIgnore(first,second):
|
||||||
|
if not isinstance(first,unicode):
|
||||||
|
self.fail()
|
||||||
|
if not isinstance(second,unicode):
|
||||||
|
self.fail()
|
||||||
|
|
||||||
|
app = self.app
|
||||||
|
app.scanner.ignore_list.Ignore = FakeIgnore
|
||||||
|
self.rtree.selected_path = [1, 0]
|
||||||
|
app.add_selected_to_ignore_list()
|
||||||
|
|
||||||
|
|
||||||
|
class TCDupeGuru_renameSelected(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
p = self.tmppath()
|
||||||
|
fp = open(unicode(p + 'foo bar 1'),mode='w')
|
||||||
|
fp.close()
|
||||||
|
fp = open(unicode(p + 'foo bar 2'),mode='w')
|
||||||
|
fp.close()
|
||||||
|
fp = open(unicode(p + 'foo bar 3'),mode='w')
|
||||||
|
fp.close()
|
||||||
|
files = fs.get_files(p)
|
||||||
|
matches = engine.getmatches(files)
|
||||||
|
groups = engine.get_groups(matches)
|
||||||
|
g = groups[0]
|
||||||
|
g.prioritize(lambda x:x.name)
|
||||||
|
app = DupeGuru()
|
||||||
|
app.results.groups = groups
|
||||||
|
self.app = app
|
||||||
|
self.groups = groups
|
||||||
|
self.p = p
|
||||||
|
self.files = files
|
||||||
|
self.rtree_gui = CallLogger()
|
||||||
|
self.rtree = ResultTree(self.rtree_gui, self.app)
|
||||||
|
self.rtree.connect()
|
||||||
|
|
||||||
|
def test_simple(self):
|
||||||
|
app = self.app
|
||||||
|
g = self.groups[0]
|
||||||
|
self.rtree.selected_path = [0, 0]
|
||||||
|
assert app.rename_selected('renamed')
|
||||||
|
names = io.listdir(self.p)
|
||||||
|
assert 'renamed' in names
|
||||||
|
assert 'foo bar 2' not in names
|
||||||
|
eq_(g.dupes[0].name, 'renamed')
|
||||||
|
|
||||||
|
def test_none_selected(self):
|
||||||
|
app = self.app
|
||||||
|
g = self.groups[0]
|
||||||
|
self.rtree.selected_paths = []
|
||||||
|
self.mock(logging, 'warning', log_calls(lambda msg: None))
|
||||||
|
assert not app.rename_selected('renamed')
|
||||||
|
msg = logging.warning.calls[0]['msg']
|
||||||
|
eq_('dupeGuru Warning: list index out of range', msg)
|
||||||
|
names = io.listdir(self.p)
|
||||||
|
assert 'renamed' not in names
|
||||||
|
assert 'foo bar 2' in names
|
||||||
|
eq_(g.dupes[0].name, 'foo bar 2')
|
||||||
|
|
||||||
|
def test_name_already_exists(self):
|
||||||
|
app = self.app
|
||||||
|
g = self.groups[0]
|
||||||
|
self.rtree.selected_path = [0, 0]
|
||||||
|
self.mock(logging, 'warning', log_calls(lambda msg: None))
|
||||||
|
assert not app.rename_selected('foo bar 1')
|
||||||
|
msg = logging.warning.calls[0]['msg']
|
||||||
|
assert msg.startswith('dupeGuru Warning: \'foo bar 1\' already exists in')
|
||||||
|
names = io.listdir(self.p)
|
||||||
|
assert 'foo bar 1' in names
|
||||||
|
assert 'foo bar 2' in names
|
||||||
|
eq_(g.dupes[0].name, 'foo bar 2')
|
||||||
|
|
||||||
|
|||||||
@@ -229,10 +229,9 @@ class TCbuild_word_dict(TestCase):
|
|||||||
self.log = []
|
self.log = []
|
||||||
s = "foo bar"
|
s = "foo bar"
|
||||||
build_word_dict([NamedObject(s, True), NamedObject(s, True), NamedObject(s, True)], j)
|
build_word_dict([NamedObject(s, True), NamedObject(s, True), NamedObject(s, True)], j)
|
||||||
|
# We don't have intermediate log because iter_with_progress is called with every > 1
|
||||||
self.assertEqual(0,self.log[0])
|
self.assertEqual(0,self.log[0])
|
||||||
self.assertEqual(33,self.log[1])
|
self.assertEqual(100,self.log[1])
|
||||||
self.assertEqual(66,self.log[2])
|
|
||||||
self.assertEqual(100,self.log[3])
|
|
||||||
|
|
||||||
|
|
||||||
class TCmerge_similar_words(TestCase):
|
class TCmerge_similar_words(TestCase):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
import cStringIO
|
import cStringIO
|
||||||
import xml.dom.minidom
|
from lxml import etree
|
||||||
|
|
||||||
from nose.tools import eq_
|
from nose.tools import eq_
|
||||||
|
|
||||||
@@ -62,26 +62,25 @@ def test_save_to_xml():
|
|||||||
f = cStringIO.StringIO()
|
f = cStringIO.StringIO()
|
||||||
il.save_to_xml(f)
|
il.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
doc = xml.dom.minidom.parse(f)
|
doc = etree.parse(f)
|
||||||
root = doc.documentElement
|
root = doc.getroot()
|
||||||
eq_('ignore_list',root.nodeName)
|
eq_(root.tag, 'ignore_list')
|
||||||
children = [c for c in root.childNodes if c.localName]
|
eq_(len(root), 2)
|
||||||
eq_(2,len(children))
|
eq_(len([c for c in root if c.tag == 'file']), 2)
|
||||||
eq_(2,len([c for c in children if c.nodeName == 'file']))
|
f1, f2 = root[:]
|
||||||
f1,f2 = children
|
subchildren = [c for c in f1 if c.tag == 'file'] + [c for c in f2 if c.tag == 'file']
|
||||||
subchildren = [c for c in f1.childNodes if c.localName == 'file'] +\
|
eq_(len(subchildren), 3)
|
||||||
[c for c in f2.childNodes if c.localName == 'file']
|
|
||||||
eq_(3,len(subchildren))
|
|
||||||
|
|
||||||
def test_SaveThenLoad():
|
def test_SaveThenLoad():
|
||||||
il = IgnoreList()
|
il = IgnoreList()
|
||||||
il.Ignore('foo','bar')
|
il.Ignore('foo', 'bar')
|
||||||
il.Ignore('foo','bleh')
|
il.Ignore('foo', 'bleh')
|
||||||
il.Ignore('bleh','bar')
|
il.Ignore('bleh', 'bar')
|
||||||
il.Ignore(u'\u00e9','bar')
|
il.Ignore(u'\u00e9', 'bar')
|
||||||
f = cStringIO.StringIO()
|
f = cStringIO.StringIO()
|
||||||
il.save_to_xml(f)
|
il.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
|
f.seek(0)
|
||||||
il = IgnoreList()
|
il = IgnoreList()
|
||||||
il.load_from_xml(f)
|
il.load_from_xml(f)
|
||||||
eq_(4,len(il))
|
eq_(4,len(il))
|
||||||
@@ -129,9 +128,9 @@ def test_filter():
|
|||||||
assert not il.AreIgnored('foo','bar')
|
assert not il.AreIgnored('foo','bar')
|
||||||
assert il.AreIgnored('bar','baz')
|
assert il.AreIgnored('bar','baz')
|
||||||
|
|
||||||
def test_save_with_non_ascii_non_unicode_items():
|
def test_save_with_non_ascii_items():
|
||||||
il = IgnoreList()
|
il = IgnoreList()
|
||||||
il.Ignore('\xac','\xbf')
|
il.Ignore(u'\xac', u'\xbf')
|
||||||
f = cStringIO.StringIO()
|
f = cStringIO.StringIO()
|
||||||
try:
|
try:
|
||||||
il.save_to_xml(f)
|
il.save_to_xml(f)
|
||||||
|
|||||||
@@ -7,10 +7,9 @@
|
|||||||
# 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
|
||||||
|
|
||||||
import unittest
|
|
||||||
import StringIO
|
import StringIO
|
||||||
import xml.dom.minidom
|
|
||||||
import os.path as op
|
import os.path as op
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
from hsutil.path import Path
|
from hsutil.path import Path
|
||||||
from hsutil.testcase import TestCase
|
from hsutil.testcase import TestCase
|
||||||
@@ -18,7 +17,7 @@ from hsutil.misc import first
|
|||||||
|
|
||||||
from . import engine_test, data
|
from . import engine_test, data
|
||||||
from .. import engine
|
from .. import engine
|
||||||
from ..results import *
|
from ..results import Results
|
||||||
|
|
||||||
class NamedObject(engine_test.NamedObject):
|
class NamedObject(engine_test.NamedObject):
|
||||||
path = property(lambda x:Path('basepath') + x.name)
|
path = property(lambda x:Path('basepath') + x.name)
|
||||||
@@ -65,9 +64,9 @@ class TCResultsEmpty(TestCase):
|
|||||||
f = StringIO.StringIO()
|
f = StringIO.StringIO()
|
||||||
self.results.save_to_xml(f)
|
self.results.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
doc = xml.dom.minidom.parse(f)
|
doc = etree.parse(f)
|
||||||
root = doc.documentElement
|
root = doc.getroot()
|
||||||
self.assertEqual('results',root.nodeName)
|
self.assertEqual('results', root.tag)
|
||||||
|
|
||||||
|
|
||||||
class TCResultsWithSomeGroups(TestCase):
|
class TCResultsWithSomeGroups(TestCase):
|
||||||
@@ -321,16 +320,16 @@ class TCResultsMarkings(TestCase):
|
|||||||
f = StringIO.StringIO()
|
f = StringIO.StringIO()
|
||||||
self.results.save_to_xml(f)
|
self.results.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
doc = xml.dom.minidom.parse(f)
|
doc = etree.parse(f)
|
||||||
root = doc.documentElement
|
root = doc.getroot()
|
||||||
g1,g2 = root.getElementsByTagName('group')
|
g1, g2 = root.iterchildren('group')
|
||||||
d1,d2,d3 = g1.getElementsByTagName('file')
|
d1, d2, d3 = g1.iterchildren('file')
|
||||||
self.assertEqual('n',d1.getAttributeNode('marked').nodeValue)
|
self.assertEqual('n', d1.get('marked'))
|
||||||
self.assertEqual('n',d2.getAttributeNode('marked').nodeValue)
|
self.assertEqual('n', d2.get('marked'))
|
||||||
self.assertEqual('y',d3.getAttributeNode('marked').nodeValue)
|
self.assertEqual('y', d3.get('marked'))
|
||||||
d1,d2 = g2.getElementsByTagName('file')
|
d1, d2 = g2.iterchildren('file')
|
||||||
self.assertEqual('n',d1.getAttributeNode('marked').nodeValue)
|
self.assertEqual('n', d1.get('marked'))
|
||||||
self.assertEqual('y',d2.getAttributeNode('marked').nodeValue)
|
self.assertEqual('y', d2.get('marked'))
|
||||||
|
|
||||||
def test_LoadXML(self):
|
def test_LoadXML(self):
|
||||||
def get_file(path):
|
def get_file(path):
|
||||||
@@ -366,38 +365,35 @@ class TCResultsXML(TestCase):
|
|||||||
f = StringIO.StringIO()
|
f = StringIO.StringIO()
|
||||||
self.results.save_to_xml(f)
|
self.results.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
doc = xml.dom.minidom.parse(f)
|
doc = etree.parse(f)
|
||||||
root = doc.documentElement
|
root = doc.getroot()
|
||||||
self.assertEqual('results',root.nodeName)
|
self.assertEqual('results', root.tag)
|
||||||
children = [c for c in root.childNodes if c.localName]
|
self.assertEqual(2, len(root))
|
||||||
self.assertEqual(2,len(children))
|
self.assertEqual(2, len([c for c in root if c.tag == 'group']))
|
||||||
self.assertEqual(2,len([c for c in children if c.nodeName == 'group']))
|
g1, g2 = root
|
||||||
g1,g2 = children
|
self.assertEqual(6,len(g1))
|
||||||
children = [c for c in g1.childNodes if c.localName]
|
self.assertEqual(3,len([c for c in g1 if c.tag == 'file']))
|
||||||
self.assertEqual(6,len(children))
|
self.assertEqual(3,len([c for c in g1 if c.tag == 'match']))
|
||||||
self.assertEqual(3,len([c for c in children if c.nodeName == 'file']))
|
d1, d2, d3 = [c for c in g1 if c.tag == 'file']
|
||||||
self.assertEqual(3,len([c for c in children if c.nodeName == 'match']))
|
self.assertEqual(op.join('basepath','foo bar'),d1.get('path'))
|
||||||
d1,d2,d3 = [c for c in children if c.nodeName == 'file']
|
self.assertEqual(op.join('basepath','bar bleh'),d2.get('path'))
|
||||||
self.assertEqual(op.join('basepath','foo bar'),d1.getAttributeNode('path').nodeValue)
|
self.assertEqual(op.join('basepath','foo bleh'),d3.get('path'))
|
||||||
self.assertEqual(op.join('basepath','bar bleh'),d2.getAttributeNode('path').nodeValue)
|
self.assertEqual('y',d1.get('is_ref'))
|
||||||
self.assertEqual(op.join('basepath','foo bleh'),d3.getAttributeNode('path').nodeValue)
|
self.assertEqual('n',d2.get('is_ref'))
|
||||||
self.assertEqual('y',d1.getAttributeNode('is_ref').nodeValue)
|
self.assertEqual('n',d3.get('is_ref'))
|
||||||
self.assertEqual('n',d2.getAttributeNode('is_ref').nodeValue)
|
self.assertEqual('foo,bar',d1.get('words'))
|
||||||
self.assertEqual('n',d3.getAttributeNode('is_ref').nodeValue)
|
self.assertEqual('bar,bleh',d2.get('words'))
|
||||||
self.assertEqual('foo,bar',d1.getAttributeNode('words').nodeValue)
|
self.assertEqual('foo,bleh',d3.get('words'))
|
||||||
self.assertEqual('bar,bleh',d2.getAttributeNode('words').nodeValue)
|
self.assertEqual(3,len(g2))
|
||||||
self.assertEqual('foo,bleh',d3.getAttributeNode('words').nodeValue)
|
self.assertEqual(2,len([c for c in g2 if c.tag == 'file']))
|
||||||
children = [c for c in g2.childNodes if c.localName]
|
self.assertEqual(1,len([c for c in g2 if c.tag == 'match']))
|
||||||
self.assertEqual(3,len(children))
|
d1, d2 = [c for c in g2 if c.tag == 'file']
|
||||||
self.assertEqual(2,len([c for c in children if c.nodeName == 'file']))
|
self.assertEqual(op.join('basepath','ibabtu'),d1.get('path'))
|
||||||
self.assertEqual(1,len([c for c in children if c.nodeName == 'match']))
|
self.assertEqual(op.join('basepath','ibabtu'),d2.get('path'))
|
||||||
d1,d2 = [c for c in children if c.nodeName == 'file']
|
self.assertEqual('n',d1.get('is_ref'))
|
||||||
self.assertEqual(op.join('basepath','ibabtu'),d1.getAttributeNode('path').nodeValue)
|
self.assertEqual('n',d2.get('is_ref'))
|
||||||
self.assertEqual(op.join('basepath','ibabtu'),d2.getAttributeNode('path').nodeValue)
|
self.assertEqual('ibabtu',d1.get('words'))
|
||||||
self.assertEqual('n',d1.getAttributeNode('is_ref').nodeValue)
|
self.assertEqual('ibabtu',d2.get('words'))
|
||||||
self.assertEqual('n',d2.getAttributeNode('is_ref').nodeValue)
|
|
||||||
self.assertEqual('ibabtu',d1.getAttributeNode('words').nodeValue)
|
|
||||||
self.assertEqual('ibabtu',d2.getAttributeNode('words').nodeValue)
|
|
||||||
|
|
||||||
def test_LoadXML(self):
|
def test_LoadXML(self):
|
||||||
def get_file(path):
|
def get_file(path):
|
||||||
@@ -460,41 +456,41 @@ class TCResultsXML(TestCase):
|
|||||||
def get_file(path):
|
def get_file(path):
|
||||||
return [f for f in self.objects if str(f.path) == path][0]
|
return [f for f in self.objects if str(f.path) == path][0]
|
||||||
|
|
||||||
doc = xml.dom.minidom.Document()
|
root = etree.Element('foobar') #The root element shouldn't matter, really.
|
||||||
root = doc.appendChild(doc.createElement('foobar')) #The root element shouldn't matter, really.
|
group_node = etree.SubElement(root, 'group')
|
||||||
group_node = root.appendChild(doc.createElement('group'))
|
dupe_node = etree.SubElement(group_node, 'file') #Perfectly correct file
|
||||||
dupe_node = group_node.appendChild(doc.createElement('file')) #Perfectly correct file
|
dupe_node.set('path', op.join('basepath','foo bar'))
|
||||||
dupe_node.setAttribute('path',op.join('basepath','foo bar'))
|
dupe_node.set('is_ref', 'y')
|
||||||
dupe_node.setAttribute('is_ref','y')
|
dupe_node.set('words', 'foo,bar')
|
||||||
dupe_node.setAttribute('words','foo,bar')
|
dupe_node = etree.SubElement(group_node, 'file') #is_ref missing, default to 'n'
|
||||||
dupe_node = group_node.appendChild(doc.createElement('file')) #is_ref missing, default to 'n'
|
dupe_node.set('path',op.join('basepath','foo bleh'))
|
||||||
dupe_node.setAttribute('path',op.join('basepath','foo bleh'))
|
dupe_node.set('words','foo,bleh')
|
||||||
dupe_node.setAttribute('words','foo,bleh')
|
dupe_node = etree.SubElement(group_node, 'file') #words are missing, valid.
|
||||||
dupe_node = group_node.appendChild(doc.createElement('file')) #words are missing, invalid.
|
dupe_node.set('path',op.join('basepath','bar bleh'))
|
||||||
dupe_node.setAttribute('path',op.join('basepath','bar bleh'))
|
dupe_node = etree.SubElement(group_node, 'file') #path is missing, invalid.
|
||||||
dupe_node = group_node.appendChild(doc.createElement('file')) #path is missing, invalid.
|
dupe_node.set('words','foo,bleh')
|
||||||
dupe_node.setAttribute('words','foo,bleh')
|
dupe_node = etree.SubElement(group_node, 'foobar') #Invalid element name
|
||||||
dupe_node = group_node.appendChild(doc.createElement('foobar')) #Invalid element name
|
dupe_node.set('path',op.join('basepath','bar bleh'))
|
||||||
dupe_node.setAttribute('path',op.join('basepath','bar bleh'))
|
dupe_node.set('is_ref','y')
|
||||||
dupe_node.setAttribute('is_ref','y')
|
dupe_node.set('words','bar,bleh')
|
||||||
dupe_node.setAttribute('words','bar,bleh')
|
match_node = etree.SubElement(group_node, 'match') # match pointing to a bad index
|
||||||
match_node = group_node.appendChild(doc.createElement('match')) # match pointing to a bad index
|
match_node.set('first', '42')
|
||||||
match_node.setAttribute('first', '42')
|
match_node.set('second', '45')
|
||||||
match_node.setAttribute('second', '45')
|
match_node = etree.SubElement(group_node, 'match') # match with missing attrs
|
||||||
match_node = group_node.appendChild(doc.createElement('match')) # match with missing attrs
|
match_node = etree.SubElement(group_node, 'match') # match with non-int values
|
||||||
match_node = group_node.appendChild(doc.createElement('match')) # match with non-int values
|
match_node.set('first', 'foo')
|
||||||
match_node.setAttribute('first', 'foo')
|
match_node.set('second', 'bar')
|
||||||
match_node.setAttribute('second', 'bar')
|
match_node.set('percentage', 'baz')
|
||||||
match_node.setAttribute('percentage', 'baz')
|
group_node = etree.SubElement(root, 'foobar') #invalid group
|
||||||
group_node = root.appendChild(doc.createElement('foobar')) #invalid group
|
group_node = etree.SubElement(root, 'group') #empty group
|
||||||
group_node = root.appendChild(doc.createElement('group')) #empty group
|
|
||||||
f = StringIO.StringIO()
|
f = StringIO.StringIO()
|
||||||
doc.writexml(f,'\t','\t','\n',encoding='utf-8')
|
tree = etree.ElementTree(root)
|
||||||
|
tree.write(f, encoding='utf-8')
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
r = Results(data)
|
r = Results(data)
|
||||||
r.load_from_xml(f,get_file)
|
r.load_from_xml(f, get_file)
|
||||||
self.assertEqual(1,len(r.groups))
|
self.assertEqual(1,len(r.groups))
|
||||||
self.assertEqual(2,len(r.groups[0]))
|
self.assertEqual(3,len(r.groups[0]))
|
||||||
|
|
||||||
def test_xml_non_ascii(self):
|
def test_xml_non_ascii(self):
|
||||||
def get_file(path):
|
def get_file(path):
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import logging
|
|||||||
import plistlib
|
import plistlib
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from lxml import etree
|
||||||
from appscript import app, k, CommandError
|
from appscript import app, k, CommandError
|
||||||
|
|
||||||
from hsutil import io
|
from hsutil import io
|
||||||
@@ -68,15 +69,10 @@ def get_iphoto_database_path():
|
|||||||
def get_iphoto_pictures(plistpath):
|
def get_iphoto_pictures(plistpath):
|
||||||
if not io.exists(plistpath):
|
if not io.exists(plistpath):
|
||||||
return []
|
return []
|
||||||
s = io.open(plistpath).read()
|
# We make the xml go through lxml so that it can fix broken xml which iPhoto sometimes produces.
|
||||||
# There was a case where a guy had 0x10 chars in his plist, causing expat errors on loading
|
parser = etree.XMLParser(recover=True)
|
||||||
s = s.replace('\x10', '')
|
root = etree.parse(io.open(plistpath), parser=parser).getroot()
|
||||||
# It seems that iPhoto sometimes doesn't properly escape & chars. The regexp below is to find
|
s = etree.tostring(root)
|
||||||
# any & char that is not a &-based entity (&, ", etc.). based on TextMate's XML
|
|
||||||
# bundle's regexp
|
|
||||||
s, count = re.subn(r'&(?![a-zA-Z0-9_-]+|#[0-9]+|#x[0-9a-fA-F]+;)', '', s)
|
|
||||||
if count:
|
|
||||||
logging.warning("%d invalid XML entities replacement made", count)
|
|
||||||
plist = plistlib.readPlistFromString(s)
|
plist = plistlib.readPlistFromString(s)
|
||||||
result = []
|
result = []
|
||||||
for photo_data in plist['Master Image List'].values():
|
for photo_data in plist['Master Image List'].values():
|
||||||
|
|||||||
@@ -111,8 +111,13 @@ def getmatches(pictures, cache_path, threshold=75, match_scaled=False, j=job.nul
|
|||||||
others = [pic for pic in others if not pic.is_ref]
|
others = [pic for pic in others if not pic.is_ref]
|
||||||
if others:
|
if others:
|
||||||
cache_ids = [f.cache_id for f in others]
|
cache_ids = [f.cache_id for f in others]
|
||||||
args = (ref.cache_id, cache_ids, cache_path, threshold)
|
# We limit the number of cache_ids we send for multi-processing because otherwise, we
|
||||||
|
# might get an error saying "String or BLOB exceeded size limit"
|
||||||
|
ARG_LIMIT = 1000
|
||||||
|
while cache_ids:
|
||||||
|
args = (ref.cache_id, cache_ids[:ARG_LIMIT], cache_path, threshold)
|
||||||
async_results.append(pool.apply_async(async_compare, args))
|
async_results.append(pool.apply_async(async_compare, args))
|
||||||
|
cache_ids = cache_ids[ARG_LIMIT:]
|
||||||
if len(async_results) > RESULTS_QUEUE_LIMIT:
|
if len(async_results) > RESULTS_QUEUE_LIMIT:
|
||||||
result = async_results.pop(0)
|
result = async_results.pop(0)
|
||||||
matches.extend(result.get())
|
matches.extend(result.get())
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ static PyObject* block_osx_getblocks(PyObject *self, PyObject *args)
|
|||||||
CGImageSourceRef source;
|
CGImageSourceRef source;
|
||||||
CGImageRef image;
|
CGImageRef image;
|
||||||
size_t width, height;
|
size_t width, height;
|
||||||
int block_count, block_width, block_height, block_xcount, block_ycount, i;
|
int block_count, block_width, block_height, i;
|
||||||
|
|
||||||
width = 0;
|
width = 0;
|
||||||
height = 0;
|
height = 0;
|
||||||
@@ -192,23 +192,24 @@ static PyObject* block_osx_getblocks(PyObject *self, PyObject *args)
|
|||||||
|
|
||||||
block_width = max(width/block_count, 1);
|
block_width = max(width/block_count, 1);
|
||||||
block_height = max(height/block_count, 1);
|
block_height = max(height/block_count, 1);
|
||||||
/* block_count might have changed */
|
|
||||||
block_xcount = (width / block_width);
|
|
||||||
block_ycount = (height / block_height);
|
|
||||||
|
|
||||||
result = PyList_New(block_xcount * block_ycount);
|
result = PyList_New(block_count * block_count);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0; i<block_ycount; i++)
|
for(i=0; i<block_count; i++) {
|
||||||
{
|
int j, top;
|
||||||
int j;
|
top = min(i*block_height, height-block_height);
|
||||||
for(j=0; j<block_xcount; j++)
|
for(j=0; j<block_count; j++) {
|
||||||
{
|
int left;
|
||||||
PyObject *block = getblock(bitmapData, width, height, j*block_width, i*block_height,
|
left = min(j*block_width, width-block_width);
|
||||||
block_width, block_height);
|
PyObject *block = getblock(bitmapData, width, height, left, top, block_width, block_height);
|
||||||
PyList_SET_ITEM(result, i*block_ycount+j, block);
|
if (block == NULL) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyList_SET_ITEM(result, i*block_count+j, block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
debian_me/control
Normal file
12
debian_me/control
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Source: dupeguru-me
|
||||||
|
Section: devel
|
||||||
|
Priority: extra
|
||||||
|
Maintainer: Virgil Dupras <hsoft@hardcoded.net>
|
||||||
|
Build-Depends: debhelper (>= 7)
|
||||||
|
Standards-Version: 3.8.1
|
||||||
|
Homepage: http://www.hardcoded.net
|
||||||
|
|
||||||
|
Package: dupeguru-me
|
||||||
|
Architecture: any
|
||||||
|
Depends: python (>= 2.6), python-qt4 (>= 4.6), python-lxml (>= 2.1)
|
||||||
|
Description: dupeGuru Music Edition
|
||||||
11
debian_me/copyright
Normal file
11
debian_me/copyright
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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.
|
||||||
3
debian_me/dirs
Normal file
3
debian_me/dirs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
usr/local/bin
|
||||||
|
usr/local/share
|
||||||
|
usr/share/applications
|
||||||
10
debian_me/dupeguru_me.desktop
Normal file
10
debian_me/dupeguru_me.desktop
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
[Desktop Entry]
|
||||||
|
Encoding=UTF-8
|
||||||
|
Name=dupeGuru Music Edition
|
||||||
|
Comment=Find duplicate songs in your collection.
|
||||||
|
Exec=dupeguru_me
|
||||||
|
Icon=/usr/local/share/dupeguru_me/dgme_logo_128.png
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Utility
|
||||||
86
debian_me/rules
Executable file
86
debian_me/rules
Executable file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# -*- makefile -*-
|
||||||
|
# Sample debian/rules that uses debhelper.
|
||||||
|
# This file was originally written by Joey Hess and Craig Small.
|
||||||
|
# As a special exception, when this file is copied by dh-make into a
|
||||||
|
# dh-make output file, you may use that output file without restriction.
|
||||||
|
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||||
|
|
||||||
|
# Uncomment this to turn on verbose mode.
|
||||||
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
|
configure: configure-stamp
|
||||||
|
configure-stamp:
|
||||||
|
dh_testdir
|
||||||
|
# Add here commands to configure the package.
|
||||||
|
|
||||||
|
touch configure-stamp
|
||||||
|
|
||||||
|
|
||||||
|
build: build-stamp
|
||||||
|
|
||||||
|
build-stamp: configure-stamp
|
||||||
|
dh_testdir
|
||||||
|
|
||||||
|
# Add here commands to compile the package.
|
||||||
|
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
rm -f build-stamp configure-stamp
|
||||||
|
|
||||||
|
# Add here commands to clean up after the build process.
|
||||||
|
|
||||||
|
dh_clean
|
||||||
|
|
||||||
|
install: build
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_prep
|
||||||
|
dh_installdirs
|
||||||
|
|
||||||
|
chmod +x src/start.py
|
||||||
|
cp -R src/ $(CURDIR)/debian/tmp/usr/local/share/dupeguru_me
|
||||||
|
cp $(CURDIR)/debian/dupeguru_me.desktop $(CURDIR)/debian/tmp/usr/share/applications
|
||||||
|
ln -s /usr/local/share/dupeguru_me/start.py $(CURDIR)/debian/tmp/usr/local/bin/dupeguru_me
|
||||||
|
|
||||||
|
|
||||||
|
# Build architecture-independent files here.
|
||||||
|
binary-indep: install
|
||||||
|
# We have nothing to do by default.
|
||||||
|
|
||||||
|
# Build architecture-dependent files here.
|
||||||
|
binary-arch: install
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_installchangelogs
|
||||||
|
dh_installdocs
|
||||||
|
dh_installexamples
|
||||||
|
dh_install
|
||||||
|
dh_installmenu
|
||||||
|
# dh_installdebconf
|
||||||
|
# dh_installlogrotate
|
||||||
|
# dh_installemacsen
|
||||||
|
# dh_installpam
|
||||||
|
# dh_installmime
|
||||||
|
# dh_python
|
||||||
|
# dh_installinit
|
||||||
|
# dh_installcron
|
||||||
|
# dh_installinfo
|
||||||
|
dh_installman
|
||||||
|
dh_link
|
||||||
|
dh_strip
|
||||||
|
dh_compress
|
||||||
|
dh_fixperms
|
||||||
|
# dh_perl
|
||||||
|
# dh_makeshlibs
|
||||||
|
dh_installdeb
|
||||||
|
dh_shlibdeps
|
||||||
|
dh_gencontrol
|
||||||
|
dh_md5sums
|
||||||
|
dh_builddeb
|
||||||
|
|
||||||
|
binary: binary-indep binary-arch
|
||||||
|
.PHONY: build clean binary-indep binary-arch binary install configure
|
||||||
12
debian_pe/control
Normal file
12
debian_pe/control
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Source: dupeguru-pe
|
||||||
|
Section: devel
|
||||||
|
Priority: extra
|
||||||
|
Maintainer: Virgil Dupras <hsoft@hardcoded.net>
|
||||||
|
Build-Depends: debhelper (>= 7)
|
||||||
|
Standards-Version: 3.8.1
|
||||||
|
Homepage: http://www.hardcoded.net
|
||||||
|
|
||||||
|
Package: dupeguru-pe
|
||||||
|
Architecture: any
|
||||||
|
Depends: python (>= 2.6), python-qt4 (>= 4.6), python-lxml (>= 2.1), python-imaging (>= 1.1.6)
|
||||||
|
Description: dupeGuru Picture Edition
|
||||||
11
debian_pe/copyright
Normal file
11
debian_pe/copyright
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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.
|
||||||
3
debian_pe/dirs
Normal file
3
debian_pe/dirs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
usr/local/bin
|
||||||
|
usr/local/share
|
||||||
|
usr/share/applications
|
||||||
9
debian_pe/dupeguru_pe.desktop
Normal file
9
debian_pe/dupeguru_pe.desktop
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Encoding=UTF-8
|
||||||
|
Name=dupeGuru Picture Edition
|
||||||
|
Comment=Find duplicate pictures in your library.
|
||||||
|
Exec=dupeguru_pe
|
||||||
|
Icon=/usr/local/share/dupeguru_pe/dgpe_logo_128.png
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Utility
|
||||||
86
debian_pe/rules
Executable file
86
debian_pe/rules
Executable file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# -*- makefile -*-
|
||||||
|
# Sample debian/rules that uses debhelper.
|
||||||
|
# This file was originally written by Joey Hess and Craig Small.
|
||||||
|
# As a special exception, when this file is copied by dh-make into a
|
||||||
|
# dh-make output file, you may use that output file without restriction.
|
||||||
|
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||||
|
|
||||||
|
# Uncomment this to turn on verbose mode.
|
||||||
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
|
configure: configure-stamp
|
||||||
|
configure-stamp:
|
||||||
|
dh_testdir
|
||||||
|
# Add here commands to configure the package.
|
||||||
|
|
||||||
|
touch configure-stamp
|
||||||
|
|
||||||
|
|
||||||
|
build: build-stamp
|
||||||
|
|
||||||
|
build-stamp: configure-stamp
|
||||||
|
dh_testdir
|
||||||
|
|
||||||
|
# Add here commands to compile the package.
|
||||||
|
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
rm -f build-stamp configure-stamp
|
||||||
|
|
||||||
|
# Add here commands to clean up after the build process.
|
||||||
|
|
||||||
|
dh_clean
|
||||||
|
|
||||||
|
install: build
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_prep
|
||||||
|
dh_installdirs
|
||||||
|
|
||||||
|
chmod +x src/start.py
|
||||||
|
cp -R src/ $(CURDIR)/debian/tmp/usr/local/share/dupeguru_pe
|
||||||
|
cp $(CURDIR)/debian/dupeguru_pe.desktop $(CURDIR)/debian/tmp/usr/share/applications
|
||||||
|
ln -s /usr/local/share/dupeguru_pe/start.py $(CURDIR)/debian/tmp/usr/local/bin/dupeguru_pe
|
||||||
|
|
||||||
|
|
||||||
|
# Build architecture-independent files here.
|
||||||
|
binary-indep: install
|
||||||
|
# We have nothing to do by default.
|
||||||
|
|
||||||
|
# Build architecture-dependent files here.
|
||||||
|
binary-arch: install
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_installchangelogs
|
||||||
|
dh_installdocs
|
||||||
|
dh_installexamples
|
||||||
|
dh_install
|
||||||
|
dh_installmenu
|
||||||
|
# dh_installdebconf
|
||||||
|
# dh_installlogrotate
|
||||||
|
# dh_installemacsen
|
||||||
|
# dh_installpam
|
||||||
|
# dh_installmime
|
||||||
|
# dh_python
|
||||||
|
# dh_installinit
|
||||||
|
# dh_installcron
|
||||||
|
# dh_installinfo
|
||||||
|
dh_installman
|
||||||
|
dh_link
|
||||||
|
dh_strip
|
||||||
|
dh_compress
|
||||||
|
dh_fixperms
|
||||||
|
# dh_perl
|
||||||
|
# dh_makeshlibs
|
||||||
|
dh_installdeb
|
||||||
|
dh_shlibdeps
|
||||||
|
dh_gencontrol
|
||||||
|
dh_md5sums
|
||||||
|
dh_builddeb
|
||||||
|
|
||||||
|
binary: binary-indep binary-arch
|
||||||
|
.PHONY: build clean binary-indep binary-arch binary install configure
|
||||||
12
debian_se/control
Normal file
12
debian_se/control
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Source: dupeguru-se
|
||||||
|
Section: devel
|
||||||
|
Priority: extra
|
||||||
|
Maintainer: Virgil Dupras <hsoft@hardcoded.net>
|
||||||
|
Build-Depends: debhelper (>= 7)
|
||||||
|
Standards-Version: 3.8.1
|
||||||
|
Homepage: http://www.hardcoded.net
|
||||||
|
|
||||||
|
Package: dupeguru-se
|
||||||
|
Architecture: any
|
||||||
|
Depends: python (>= 2.6), python-qt4 (>= 4.6), python-lxml (>= 2.1)
|
||||||
|
Description: dupeGuru
|
||||||
11
debian_se/copyright
Normal file
11
debian_se/copyright
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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.
|
||||||
3
debian_se/dirs
Normal file
3
debian_se/dirs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
usr/local/bin
|
||||||
|
usr/local/share
|
||||||
|
usr/share/applications
|
||||||
9
debian_se/dupeguru_se.desktop
Normal file
9
debian_se/dupeguru_se.desktop
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Encoding=UTF-8
|
||||||
|
Name=dupeGuru
|
||||||
|
Comment=Find duplicate files.
|
||||||
|
Exec=dupeguru_se
|
||||||
|
Icon=/usr/local/share/dupeguru_se/dgse_logo_128.png
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Utility
|
||||||
86
debian_se/rules
Executable file
86
debian_se/rules
Executable file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# -*- makefile -*-
|
||||||
|
# Sample debian/rules that uses debhelper.
|
||||||
|
# This file was originally written by Joey Hess and Craig Small.
|
||||||
|
# As a special exception, when this file is copied by dh-make into a
|
||||||
|
# dh-make output file, you may use that output file without restriction.
|
||||||
|
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||||
|
|
||||||
|
# Uncomment this to turn on verbose mode.
|
||||||
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
|
configure: configure-stamp
|
||||||
|
configure-stamp:
|
||||||
|
dh_testdir
|
||||||
|
# Add here commands to configure the package.
|
||||||
|
|
||||||
|
touch configure-stamp
|
||||||
|
|
||||||
|
|
||||||
|
build: build-stamp
|
||||||
|
|
||||||
|
build-stamp: configure-stamp
|
||||||
|
dh_testdir
|
||||||
|
|
||||||
|
# Add here commands to compile the package.
|
||||||
|
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
rm -f build-stamp configure-stamp
|
||||||
|
|
||||||
|
# Add here commands to clean up after the build process.
|
||||||
|
|
||||||
|
dh_clean
|
||||||
|
|
||||||
|
install: build
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_prep
|
||||||
|
dh_installdirs
|
||||||
|
|
||||||
|
chmod +x src/start.py
|
||||||
|
cp -R src/ $(CURDIR)/debian/tmp/usr/local/share/dupeguru_se
|
||||||
|
cp $(CURDIR)/debian/dupeguru_se.desktop $(CURDIR)/debian/tmp/usr/share/applications
|
||||||
|
ln -s /usr/local/share/dupeguru_se/start.py $(CURDIR)/debian/tmp/usr/local/bin/dupeguru_se
|
||||||
|
|
||||||
|
|
||||||
|
# Build architecture-independent files here.
|
||||||
|
binary-indep: install
|
||||||
|
# We have nothing to do by default.
|
||||||
|
|
||||||
|
# Build architecture-dependent files here.
|
||||||
|
binary-arch: install
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_installchangelogs
|
||||||
|
dh_installdocs
|
||||||
|
dh_installexamples
|
||||||
|
dh_install
|
||||||
|
dh_installmenu
|
||||||
|
# dh_installdebconf
|
||||||
|
# dh_installlogrotate
|
||||||
|
# dh_installemacsen
|
||||||
|
# dh_installpam
|
||||||
|
# dh_installmime
|
||||||
|
# dh_python
|
||||||
|
# dh_installinit
|
||||||
|
# dh_installcron
|
||||||
|
# dh_installinfo
|
||||||
|
dh_installman
|
||||||
|
dh_link
|
||||||
|
dh_strip
|
||||||
|
dh_compress
|
||||||
|
dh_fixperms
|
||||||
|
# dh_perl
|
||||||
|
# dh_makeshlibs
|
||||||
|
dh_installdeb
|
||||||
|
dh_shlibdeps
|
||||||
|
dh_gencontrol
|
||||||
|
dh_md5sums
|
||||||
|
dh_builddeb
|
||||||
|
|
||||||
|
binary: binary-indep binary-arch
|
||||||
|
.PHONY: build clean binary-indep binary-arch binary install configure
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
- date: 2010-02-13
|
||||||
|
version: 5.7.2
|
||||||
|
description: |
|
||||||
|
* Fixed a crash upon quitting when support folder is not present. (#83)
|
||||||
|
* Fixed a crash during sorting. (#85)
|
||||||
|
* Fixed selection glitches, especially while renaming. (#93)
|
||||||
- date: 2010-01-19
|
- date: 2010-01-19
|
||||||
version: 5.7.1
|
version: 5.7.1
|
||||||
description: |
|
description: |
|
||||||
|
|||||||
@@ -1,3 +1,22 @@
|
|||||||
|
- date: 2010-04-08
|
||||||
|
version: 1.8.6
|
||||||
|
description: |
|
||||||
|
* Fixed a crash when performing very big scans.
|
||||||
|
* Fixed a rare crash during results loading. (#90)
|
||||||
|
- date: 2010-03-01
|
||||||
|
version: 1.8.5
|
||||||
|
description: |
|
||||||
|
* Fixed a bug preventing some iPhoto Libraries to be read. [Mac OS X]
|
||||||
|
* Improved results loading and saving speed.
|
||||||
|
- date: 2010-02-18
|
||||||
|
version: 1.8.4
|
||||||
|
description: |
|
||||||
|
* Fixed a glitch in the details panel causing it to sometimes show the wrong pictures.
|
||||||
|
- date: 2010-02-11
|
||||||
|
version: 1.8.3
|
||||||
|
description: |
|
||||||
|
* Fixed a crash when reading certain pictures. [Mac OS X] (#94)
|
||||||
|
* Fixed selection glitches, especially while renaming. (#93)
|
||||||
- date: 2010-02-06
|
- date: 2010-02-06
|
||||||
version: 1.8.2
|
version: 1.8.2
|
||||||
description: |
|
description: |
|
||||||
@@ -79,159 +98,145 @@
|
|||||||
* Converted the Windows GUI to Qt, thus enabling multiprocessing and making the scanning process
|
* Converted the Windows GUI to Qt, thus enabling multiprocessing and making the scanning process
|
||||||
faster.
|
faster.
|
||||||
- date: 2009-03-24
|
- date: 2009-03-24
|
||||||
description: "* **Improved** scanning speed, mainly on OS X where all cores of the\
|
|
||||||
\ CPU are now used.\r\n* **Fixed** an occasional crash caused by permission issues.\r\
|
|
||||||
\n* **Fixed** a bug where the \"X discarded\" notice would show a too large number\
|
|
||||||
\ of discarded duplicates."
|
|
||||||
version: 1.6.0
|
version: 1.6.0
|
||||||
|
description: |
|
||||||
|
* **Improved** scanning speed, mainly on OS X where all cores of the CPU are now used.
|
||||||
|
* **Fixed** an occasional crash caused by permission issues.
|
||||||
|
* **Fixed** a bug where the "X discarded" notice would show a too large number of discarded duplicates.
|
||||||
- date: 2008-09-10
|
- date: 2008-09-10
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Added</b> a notice in the status bar when\
|
|
||||||
\ matches were discarded during the scan.</li>\n\t\t\t\t\t\t<li><b>Improved</b>\
|
|
||||||
\ duplicate prioritization (smartly chooses which file you will keep).</li>\n\t\
|
|
||||||
\t\t\t\t\t<li><b>Improved</b> scan progress feedback.</li>\n\t\t\t\t\t\t<li><b>Improved</b>\
|
|
||||||
\ responsiveness of the user interface for certain actions.</li>\n\t\t \
|
|
||||||
\ </ul>"
|
|
||||||
version: 1.5.0
|
version: 1.5.0
|
||||||
|
description: |
|
||||||
|
* **Added** a notice in the status bar when matches were discarded during the scan.
|
||||||
|
* **Improved** duplicate prioritization (smartly chooses which file you will keep).
|
||||||
|
* **Improved** scan progress feedback.
|
||||||
|
* **Improved** responsiveness of the user interface for certain actions.
|
||||||
- date: 2008-07-28
|
- date: 2008-07-28
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Improved</b> iPhoto compatibility on Mac\
|
|
||||||
\ OS X.</li>\n\t\t\t\t\t\t<li><b>Improved</b> the speed of results loading and\
|
|
||||||
\ saving.</li>\n\t\t\t\t\t\t<li><b>Fixed</b> a crash sometimes occurring during\
|
|
||||||
\ duplicate deletion.</li>\n\t\t </ul>"
|
|
||||||
version: 1.4.2
|
version: 1.4.2
|
||||||
|
description: |
|
||||||
|
* **Improved** iPhoto compatibility on Mac OS X.
|
||||||
|
* **Improved** the speed of results loading and saving.
|
||||||
|
* **Fixed** a crash sometimes occurring during duplicate deletion.
|
||||||
- date: 2008-04-12
|
- date: 2008-04-12
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Improved</b> iPhoto Library loading feedback\
|
|
||||||
\ on Mac OS X.</li>\n\t\t\t\t\t\t<li><b>Fixed</b> the directory selection dialog.\
|
|
||||||
\ Bundles can be selected again on Mac OS X.</li>\n\t\t\t\t\t\t<li><b>Fixed</b>\
|
|
||||||
\ \"Clear Ignore List\" crash in Windows.</li>\n\t\t </ul>"
|
|
||||||
version: 1.4.1
|
version: 1.4.1
|
||||||
|
description: |
|
||||||
|
* **Improved** iPhoto Library loading feedback on Mac OS X.
|
||||||
|
* **Fixed** the directory selection dialog. Bundles can be selected again on Mac OS X.
|
||||||
|
* **Fixed** "Clear Ignore List" crash in Windows.
|
||||||
- date: 2008-02-20
|
- date: 2008-02-20
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Added</b> iPhoto Library support on Mac OS\
|
|
||||||
\ X.</li>\n\t\t\t\t\t\t<li><b>Fixed</b> occasional crashes when scanning corrupted\
|
|
||||||
\ pictures.</li>\n\t\t </ul>"
|
|
||||||
version: 1.4.0
|
|
||||||
- date: 2008-02-20
|
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Added</b> iPhoto Library support on Mac OS\
|
|
||||||
\ X.</li>\n\t\t\t\t\t\t<li><b>Fixed</b> occasional crashes when scanning corrupted\
|
|
||||||
\ pictures.</li>\n\t\t </ul>"
|
|
||||||
version: 1.4.0
|
version: 1.4.0
|
||||||
|
description: |
|
||||||
|
* **Added** iPhoto Library support on Mac OS X.
|
||||||
|
* **Fixed** occasional crashes when scanning corrupted pictures.
|
||||||
- date: 2008-01-12
|
- date: 2008-01-12
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Improved</b> scan, delete and move speed\
|
|
||||||
\ in situations where there were a lot of duplicates.</li>\n\t\t\t\t\t\t<li><b>Fixed</b>\
|
|
||||||
\ occasional crashes when moving a lot of files at once.</li>\n\t\t\t\t\t\t<li><b>Fixed</b>\
|
|
||||||
\ an issue sometimes preventing the application from starting at all.</li>\n\t\
|
|
||||||
\t </ul>"
|
|
||||||
version: 1.3.4
|
version: 1.3.4
|
||||||
|
description: |
|
||||||
|
* **Improved** scan, delete and move speed in situations where there were a lot of duplicates.
|
||||||
|
* **Fixed** occasional crashes when moving a lot of files at once.
|
||||||
|
* **Fixed** an issue sometimes preventing the application from starting at all.
|
||||||
- date: 2007-12-03
|
- date: 2007-12-03
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Improved</b> the handling of low memory situations.</li>\n\
|
|
||||||
\t\t\t\t\t\t<li><b>Improved</b> the directory panel. The \"Remove\" button changes\
|
|
||||||
\ to \"Put Back\" when an excluded directory is selected.</li>\n\t\t\t\t\t\t<li><b>Fixed</b>\
|
|
||||||
\ the directory selection dialog. iPhoto '08 library files can now be selected.</li>\n\
|
|
||||||
\t\t </ul>"
|
|
||||||
version: 1.3.3
|
version: 1.3.3
|
||||||
|
description: |
|
||||||
|
* **Improved** the handling of low memory situations.
|
||||||
|
* **Improved** the directory panel. The "Remove" button changes to "Put Back" when an excluded directory is selected.
|
||||||
|
* **Fixed** the directory selection dialog. iPhoto '08 library files can now be selected.
|
||||||
- date: 2007-11-24
|
- date: 2007-11-24
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Added</b> the \"Remove empty folders\" option.</li>\n\
|
|
||||||
\t\t\t\t\t\t<li><b>Fixed</b> results load/save issues.</li>\n\t\t\t\t\t\t<li><b>Fixed</b>\
|
|
||||||
\ occasional status bar inaccuracies when the results are filtered.</li>\n\t\t\
|
|
||||||
\ </ul>"
|
|
||||||
version: 1.3.2
|
version: 1.3.2
|
||||||
|
description: |
|
||||||
|
* **Added** the "Remove empty folders" option.
|
||||||
|
* **Fixed** results load/save issues.
|
||||||
|
* **Fixed** occasional status bar inaccuracies when the results are filtered.
|
||||||
- date: 2007-10-21
|
- date: 2007-10-21
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Improved</b> results loading speed.</li>\n\
|
|
||||||
\t\t\t\t\t\t<li><b>Improved</b> details panel's picture loading (made it asynchronous).</li>\n\
|
|
||||||
\t\t\t\t\t\t<li><b>Fixed</b> a bug where the stats line at the bottom would sometimes\
|
|
||||||
\ go confused while having a filter active.</li>\n\t\t\t\t\t\t<li><b>Fixed</b>\
|
|
||||||
\ a bug under Windows where some duplicate markings would be lost.</li>\n\t\t\
|
|
||||||
\ </ul>"
|
|
||||||
version: 1.3.1
|
version: 1.3.1
|
||||||
|
description: |
|
||||||
|
* **Improved** results loading speed.
|
||||||
|
* **Improved** details panel's picture loading (made it asynchronous).
|
||||||
|
* **Fixed** a bug where the stats line at the bottom would sometimes go confused while having a filter active.
|
||||||
|
* **Fixed** a bug under Windows where some duplicate markings would be lost.
|
||||||
- date: 2007-09-22
|
- date: 2007-09-22
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Added</b> post scan filtering.</li>\n\t\t\
|
|
||||||
\t\t\t\t<li><b>Fixed</b> issues with the rename feature under Windows</li>\n\t\
|
|
||||||
\t\t\t\t\t<li><b>Fixed</b> some user interface annoyances under Windows</li>\n\
|
|
||||||
\t\t </ul>"
|
|
||||||
version: 1.3.0
|
version: 1.3.0
|
||||||
|
description: |
|
||||||
|
* **Added** post scan filtering.
|
||||||
|
* **Fixed** issues with the rename feature under Windows.
|
||||||
|
* **Fixed** some user interface annoyances under Windows.
|
||||||
- date: 2007-05-19
|
- date: 2007-05-19
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Improved</b> UI responsiveness (using threads)\
|
|
||||||
\ under Mac OS X.</li>\n\t\t\t\t\t\t<li><b>Improved</b> result load/save speed\
|
|
||||||
\ and memory usage.</li>\n\t\t </ul>"
|
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
|
description: |
|
||||||
|
* **Improved** UI responsiveness (using threads) under Mac OS X.
|
||||||
|
* **Improved** result load/save speed and memory usage.
|
||||||
- date: 2007-03-17
|
- date: 2007-03-17
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Changed</b> the picture decoding libraries\
|
|
||||||
\ for both Mac OS X and Windows. The Mac OS X version uses the Core Graphics library\
|
|
||||||
\ and the Windows version uses the .NET framework imaging capabilities. This results\
|
|
||||||
\ in much faster scans. As a bonus, the Mac OS X version of dupeGuru PE now supports\
|
|
||||||
\ RAW images.</li>\n\t\t </ul>"
|
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
|
description: |
|
||||||
|
* **Changed** the picture decoding libraries for both Mac OS X and Windows. The Mac OS X version
|
||||||
|
uses the Core Graphics library and the Windows version uses the .NET framework imaging
|
||||||
|
capabilities. This results in much faster scans. As a bonus, the Mac OS X version of dupeGuru
|
||||||
|
PE now supports RAW images.
|
||||||
- date: 2007-02-11
|
- date: 2007-02-11
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Added</b> Re-orderable columns. In fact,\
|
|
||||||
\ I re-added the feature which was lost in the C# conversion in 2.4.0 (Windows).</li>\n\
|
|
||||||
\t\t\t\t\t\t<li><b>Fixed</b> a bug with all the Delete/Move/Copy actions with\
|
|
||||||
\ certain kinds of files.</li>\n\t\t </ul>"
|
|
||||||
version: 1.1.6
|
version: 1.1.6
|
||||||
|
description: |
|
||||||
|
* **Added** Re-orderable columns. In fact, I re-added the feature which was lost in the C#
|
||||||
|
conversion in 1.1.0 (Windows).
|
||||||
|
* **Fixed** a bug with all the Delete/Move/Copy actions with certain kinds of files.
|
||||||
- date: 2007-01-11
|
- date: 2007-01-11
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Fixed</b> a bug with the Move action.</li>\n\
|
|
||||||
\t\t </ul>"
|
|
||||||
version: 1.1.5
|
version: 1.1.5
|
||||||
|
description: |
|
||||||
|
* **Fixed** a bug with the Move action.
|
||||||
- date: 2007-01-09
|
- date: 2007-01-09
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Fixed</b> a \"ghosting\" bug. Dupes deleted\
|
|
||||||
\ by dupeGuru would sometimes come back in subsequent scans (Windows).</li>\n\t\
|
|
||||||
\t\t\t\t\t<li><b>Fixed</b> bugs sometimes making dupeGuru crash when marking a\
|
|
||||||
\ dupe (Windows).</li>\n\t\t\t\t\t\t<li><b>Fixed</b> some minor visual glitches\
|
|
||||||
\ (Windows).</li>\n\t\t </ul>"
|
|
||||||
version: 1.1.4
|
version: 1.1.4
|
||||||
|
description: |
|
||||||
|
* **Fixed** a "ghosting" bug. Dupes deleted by dupeGuru would sometimes come back in subsequent scans (Windows).
|
||||||
|
* **Fixed** bugs sometimes making dupeGuru crash when marking a dupe (Windows).
|
||||||
|
* **Fixed** some minor visual glitches (Windows).
|
||||||
- date: 2006-12-23
|
- date: 2006-12-23
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Improved</b> the caching system. This makes\
|
|
||||||
\ duplicate scans significantly faster.</li>\n\t\t\t\t\t\t<li><b>Improved</b>\
|
|
||||||
\ the rename file dialog to exclude the extension from the original selection\
|
|
||||||
\ (so when you start typing your new filename, it doesn't overwrite it) (Windows).</li>\n\
|
|
||||||
\t\t\t\t\t\t<li><b>Changed</b> some menu key shortcuts that created conflicts\
|
|
||||||
\ (Windows).</li>\n\t\t\t\t\t\t<li><b>Fixed</b> a bug preventing files from \"\
|
|
||||||
reference\" directories to be displayed in blue in the results (Windows).</li>\n\
|
|
||||||
\t\t\t\t\t\t<li><b>Fixed</b> a bug preventing some files to be sent to the recycle\
|
|
||||||
\ bin (Windows).</li>\n\t\t\t\t\t\t<li><b>Fixed</b> a bug with the \"Remove\"\
|
|
||||||
\ button of the directories panel (Windows).</li>\n\t\t\t\t\t\t<li><b>Fixed</b>\
|
|
||||||
\ a bug in the packaging preventing certain Windows configurations to start dupeGuru\
|
|
||||||
\ at all.</li>\n\t\t </ul>"
|
|
||||||
version: 1.1.3
|
version: 1.1.3
|
||||||
|
description: |
|
||||||
|
* **Improved** the caching system. This makes duplicate scans significantly faster.
|
||||||
|
* **Improved** the rename file dialog to exclude the extension from the original selection (so
|
||||||
|
when you start typing your new filename, it doesn't overwrite it) (Windows).
|
||||||
|
* **Changed** some menu key shortcuts that created conflicts (Windows).
|
||||||
|
* **Fixed** a bug preventing files from "reference" directories to be displayed in blue in the results (Windows).
|
||||||
|
* **Fixed** a bug preventing some files to be sent to the recycle bin (Windows).
|
||||||
|
* **Fixed** a bug with the "Remove" button of the directories panel (Windows).
|
||||||
|
* **Fixed** a bug in the packaging preventing certain Windows configurations to start dupeGuru at all.
|
||||||
- date: 2006-11-18
|
- date: 2006-11-18
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Fixed</b> a bug with directory states.</li>\n\
|
|
||||||
\t\t </ul>"
|
|
||||||
version: 1.1.2
|
version: 1.1.2
|
||||||
|
description: |
|
||||||
|
* **Fixed** a bug with directory states.
|
||||||
- date: 2006-11-17
|
- date: 2006-11-17
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Fixed</b> a bug causing the ignore list not\
|
|
||||||
\ to be saved.</li>\n\t\t\t\t\t\t<li><b>Fixed</b> a bug with selection under Power\
|
|
||||||
\ Marker mode.</li>\n\t\t </ul>"
|
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
|
description: |
|
||||||
|
* **Fixed** a bug causing the ignore list not to be saved.
|
||||||
|
* **Fixed** a bug with selection under Power Marker mode.
|
||||||
- date: 2006-11-15
|
- date: 2006-11-15
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Changed</b> the Windows interface. It is\
|
|
||||||
\ now .NET based.</li>\n\t\t\t\t\t\t<li><b>Added</b> an auto-update feature to\
|
|
||||||
\ the windows version.</li>\n\t\t\t\t\t\t<li><b>Changed</b> the way power marking\
|
|
||||||
\ works. It is now a mode instead of a separate window.</li>\n\t\t\t\t\t\t<li><b>Changed</b>\
|
|
||||||
\ the \"Size (MB)\" column for a \"Size (KB)\" column. The values are now \"ceiled\"\
|
|
||||||
\ instead of rounded. Therefore, a size \"0\" is now really 0 bytes, not just\
|
|
||||||
\ a value too small to be rounded up. It is also the case for delta values.</li>\n\
|
|
||||||
\t\t\t\t\t\t<li><b>Fixed</b> a bug sometimes making delete and move operations\
|
|
||||||
\ stall.</li>\n\t\t </ul>"
|
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
|
description: |
|
||||||
|
* **Changed** the Windows interface. It is now .NET based.
|
||||||
|
* **Added** an auto-update feature to the windows version.
|
||||||
|
* **Changed** the way power marking works. It is now a mode instead of a separate window.
|
||||||
|
* **Changed** the "Size (MB)" column for a "Size (KB)" column. The values are now "ceiled"
|
||||||
|
instead of rounded. Therefore, a size "0" is now really 0 bytes, not just a value too small to
|
||||||
|
be rounded up. It is also the case for delta values.
|
||||||
|
* **Fixed** a bug sometimes making delete and move operations stall.
|
||||||
- date: 2006-10-12
|
- date: 2006-10-12
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Added</b> an auto-update feature in the Mac\
|
|
||||||
\ OS X version (with Sparkle).</li>\n\t\t \t<li><b>Fixed</b> a bug\
|
|
||||||
\ sometimes causing inaccuracies of the Match %.</li>\n\t\t </ul>"
|
|
||||||
version: 1.0.5
|
version: 1.0.5
|
||||||
|
description: |
|
||||||
|
* **Added** an auto-update feature in the Mac OS X version (with Sparkle).
|
||||||
|
* **Fixed** a bug sometimes causing inaccuracies of the Match %.
|
||||||
- date: 2006-09-21
|
- date: 2006-09-21
|
||||||
description: "<ul>\n\t\t \t<li><b>Fixed</b> a bug with the cache system.</li>\n\
|
|
||||||
\t\t </ul>"
|
|
||||||
version: 1.0.4
|
version: 1.0.4
|
||||||
|
description: |
|
||||||
|
* **Fixed** a bug with the cache system.
|
||||||
- date: 2006-09-15
|
- date: 2006-09-15
|
||||||
description: "<ul>\n\t\t\t\t\t\t<li><b>Added</b> the ability to search for scaled\
|
|
||||||
\ duplicates.</li>\n\t\t\t\t\t\t<li><b>Added</b> a cache system for faster scans.</li>\n\
|
|
||||||
\t\t \t<li><b>Improved</b> speed of the scanning engine.</li>\n\t\t\
|
|
||||||
\ </ul>"
|
|
||||||
version: 1.0.3
|
version: 1.0.3
|
||||||
|
description: |
|
||||||
|
* **Added** the ability to search for scaled duplicates.
|
||||||
|
* **Added** a cache system for faster scans.
|
||||||
|
* **Improved** speed of the scanning engine.
|
||||||
- date: 2006-09-11
|
- date: 2006-09-11
|
||||||
description: "<ul>\n\t\t \t<li><b>Improved</b> speed of the scanning\
|
|
||||||
\ engine.</li>\n\t\t\t\t\t\t<li><b>Improved</b> the display of pictures in the\
|
|
||||||
\ details panel (Windows).</li>\n\t\t </ul>"
|
|
||||||
version: 1.0.2
|
version: 1.0.2
|
||||||
|
description: |
|
||||||
|
* **Improved** speed of the scanning engine.
|
||||||
|
* **Improved** the display of pictures in the details panel (Windows).
|
||||||
- date: 2006-09-08
|
- date: 2006-09-08
|
||||||
description: "<ul>\n\t\t \t<li>Initial release.</li>\n\t\t \
|
|
||||||
\ </ul>"
|
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
description: |
|
||||||
|
* Initial release.
|
||||||
|
|||||||
85
package.py
85
package.py
@@ -10,11 +10,13 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import os.path as op
|
import os.path as op
|
||||||
|
import compileall
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from hsutil.build import build_dmg, add_to_pythonpath, print_and_do
|
from hsutil.build import (build_dmg, add_to_pythonpath, print_and_do, copy_packages,
|
||||||
|
build_debian_changelog, copy_qt_plugins)
|
||||||
|
|
||||||
def package_cocoa(edition):
|
def package_cocoa(edition):
|
||||||
app_path = {
|
app_path = {
|
||||||
@@ -24,7 +26,7 @@ def package_cocoa(edition):
|
|||||||
}[edition]
|
}[edition]
|
||||||
build_dmg(app_path, '.')
|
build_dmg(app_path, '.')
|
||||||
|
|
||||||
def package_qt(edition):
|
def package_windows(edition, dev):
|
||||||
# On Windows, PyInstaller is used to build an exe (py2exe creates a very bad looking icon)
|
# On Windows, PyInstaller is used to build an exe (py2exe creates a very bad looking icon)
|
||||||
# The release version is outdated. Use at least r672 on http://svn.pyinstaller.org/trunk
|
# The release version is outdated. Use at least r672 on http://svn.pyinstaller.org/trunk
|
||||||
if sys.platform != "win32":
|
if sys.platform != "win32":
|
||||||
@@ -36,47 +38,84 @@ def package_qt(edition):
|
|||||||
os.chdir(op.join('qt', edition))
|
os.chdir(op.join('qt', edition))
|
||||||
from app import DupeGuru
|
from app import DupeGuru
|
||||||
|
|
||||||
# Removing build and dist
|
|
||||||
if op.exists('build'):
|
|
||||||
shutil.rmtree('build')
|
|
||||||
if op.exists('dist'):
|
if op.exists('dist'):
|
||||||
shutil.rmtree('dist')
|
shutil.rmtree('dist')
|
||||||
version = DupeGuru.VERSION
|
|
||||||
versioncomma = version.replace('.', ', ') + ', 0'
|
|
||||||
verinfo = open('verinfo').read()
|
|
||||||
verinfo = verinfo.replace('$versioncomma', versioncomma).replace('$version', version)
|
|
||||||
fp = open('verinfo_tmp', 'w')
|
|
||||||
fp.write(verinfo)
|
|
||||||
fp.close()
|
|
||||||
print_and_do("python C:\\Python26\\pyinstaller\\Build.py dg{0}.spec".format(edition))
|
|
||||||
os.remove('verinfo_tmp')
|
|
||||||
|
|
||||||
print_and_do("del dist\\*90.dll") # They're in vcredist, no need to include them
|
cmd = 'cxfreeze --base-name Win32GUI --target-name "{0}.exe" --icon {1} start.py'
|
||||||
print_and_do("del dist\\POWRPROF.dll") # no need of that crap
|
target_name = {'se': 'dupeGuru', 'me': 'dupeGuru ME', 'pe': 'dupeGuru PE'}[edition]
|
||||||
print_and_do("del dist\\SHLWAPI.dll") # no need of that crap
|
icon_path = '..\\..\\images\\dg{0}_logo.ico'.format(edition)
|
||||||
print_and_do("xcopy /Y /S /I ..\\..\\help_me\\dupeguru_me_help dist\\help")
|
print_and_do(cmd.format(target_name, icon_path))
|
||||||
|
|
||||||
|
if not dev:
|
||||||
|
# Copy qt plugins
|
||||||
|
plugin_dest = op.join('dist', 'qt4_plugins')
|
||||||
|
plugin_names = ['accessible', 'codecs', 'iconengines', 'imageformats']
|
||||||
|
copy_qt_plugins(plugin_names, plugin_dest)
|
||||||
|
|
||||||
|
# Compress with UPX
|
||||||
|
libs = [name for name in os.listdir('dist') if op.splitext(name)[1] in ('.pyd', '.dll', '.exe')]
|
||||||
|
for lib in libs:
|
||||||
|
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))
|
||||||
|
|
||||||
# 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
|
||||||
shutil.copy('installer.aip', 'installer_tmp.aip')
|
shutil.copy('installer.aip', 'installer_tmp.aip')
|
||||||
print_and_do('AdvancedInstaller.com /edit installer_tmp.aip /SetVersion %s' % version)
|
print_and_do('AdvancedInstaller.com /edit installer_tmp.aip /SetVersion %s' % DupeGuru.VERSION)
|
||||||
print_and_do('AdvancedInstaller.com /build installer_tmp.aip -force')
|
print_and_do('AdvancedInstaller.com /build installer_tmp.aip -force')
|
||||||
os.remove('installer_tmp.aip')
|
os.remove('installer_tmp.aip')
|
||||||
os.chdir(op.join('..', '..'))
|
os.chdir(op.join('..', '..'))
|
||||||
|
|
||||||
|
def package_debian(edition):
|
||||||
|
add_to_pythonpath('qt')
|
||||||
|
add_to_pythonpath(op.join('qt', edition))
|
||||||
|
from app import DupeGuru
|
||||||
|
|
||||||
|
if op.exists('build'):
|
||||||
|
shutil.rmtree('build')
|
||||||
|
ed = lambda s: s.format(edition)
|
||||||
|
destpath = op.join('build', 'dupeguru-{0}-{1}'.format(edition, DupeGuru.VERSION))
|
||||||
|
srcpath = op.join(destpath, 'src')
|
||||||
|
help_src = ed('help_{0}')
|
||||||
|
os.makedirs(destpath)
|
||||||
|
shutil.copytree(ed('qt/{0}'), srcpath)
|
||||||
|
packages = ['hsutil', 'hsgui', 'core', ed('core_{0}'), 'qtlib', 'qt/base']
|
||||||
|
if edition == 'me':
|
||||||
|
packages.append('hsmedia')
|
||||||
|
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'))
|
||||||
|
yaml_path = op.join(help_src, 'changelog.yaml')
|
||||||
|
changelog_dest = op.join(destpath, 'debian', 'changelog')
|
||||||
|
project_name = ed('dupeguru-{0}')
|
||||||
|
from_version = {'se': '2.9.2', 'me': '5.7.2', 'pe': '1.8.5'}[edition]
|
||||||
|
build_debian_changelog(yaml_path, changelog_dest, project_name, from_version=from_version)
|
||||||
|
help_name = {'se': 'dupeguru_help', 'me': 'dupeguru_me_help', 'pe': 'dupeguru_pe_help'}[edition]
|
||||||
|
shutil.copytree(op.join(help_src, help_name), op.join(srcpath, 'help'))
|
||||||
|
shutil.copy(op.join('images', ed('dg{0}_logo_128.png')), srcpath)
|
||||||
|
compileall.compile_dir(srcpath)
|
||||||
|
os.chdir(destpath)
|
||||||
|
os.system("dpkg-buildpackage")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
conf = yaml.load(open('conf.yaml'))
|
conf = yaml.load(open('conf.yaml'))
|
||||||
edition = conf['edition']
|
edition = conf['edition']
|
||||||
ui = conf['ui']
|
ui = conf['ui']
|
||||||
dev = conf['dev']
|
dev = conf['dev']
|
||||||
if dev:
|
|
||||||
print "You can't package in dev mode"
|
|
||||||
return
|
|
||||||
print "Packaging dupeGuru {0} with UI {1}".format(edition.upper(), ui)
|
print "Packaging dupeGuru {0} with UI {1}".format(edition.upper(), ui)
|
||||||
if ui == 'cocoa':
|
if ui == 'cocoa':
|
||||||
package_cocoa(edition)
|
package_cocoa(edition)
|
||||||
elif ui == 'qt':
|
elif ui == 'qt':
|
||||||
package_qt(edition)
|
if sys.platform == "win32":
|
||||||
|
package_windows(edition, dev)
|
||||||
|
elif sys.platform == "linux2":
|
||||||
|
package_debian(edition)
|
||||||
|
else:
|
||||||
|
print "Qt packaging only works under Windows or Linux."
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
@@ -12,13 +12,12 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import os.path as op
|
import os.path as op
|
||||||
|
|
||||||
from PyQt4.QtCore import Qt, QTimer, QObject, QCoreApplication, QUrl, SIGNAL
|
from PyQt4.QtCore import QTimer, QObject, QCoreApplication, QUrl, SIGNAL
|
||||||
from PyQt4.QtGui import QProgressDialog, QDesktopServices, QFileDialog, QDialog, QMessageBox
|
from PyQt4.QtGui import QDesktopServices, QFileDialog, QDialog, QMessageBox
|
||||||
|
|
||||||
from hsutil import job
|
from hsutil import job
|
||||||
from hsutil.reg import RegistrationRequired
|
from hsutil.reg import RegistrationRequired
|
||||||
|
|
||||||
from core import fs
|
|
||||||
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
|
||||||
|
|
||||||
from qtlib.about_box import AboutBox
|
from qtlib.about_box import AboutBox
|
||||||
@@ -122,10 +121,6 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
url = QUrl.fromLocalFile(unicode(path))
|
url = QUrl.fromLocalFile(unicode(path))
|
||||||
QDesktopServices.openUrl(url)
|
QDesktopServices.openUrl(url)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _recycle_dupe(dupe):
|
|
||||||
platform.recycle_file(dupe.path)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _reveal_path(path):
|
def _reveal_path(path):
|
||||||
DupeGuru._open_path(path[:-1])
|
DupeGuru._open_path(path[:-1])
|
||||||
@@ -148,10 +143,6 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
if self.main_window._confirm(title, msg):
|
if self.main_window._confirm(title, msg):
|
||||||
DupeGuruBase.add_selected_to_ignore_list(self)
|
DupeGuruBase.add_selected_to_ignore_list(self)
|
||||||
|
|
||||||
def apply_filter(self, filter):
|
|
||||||
DupeGuruBase.apply_filter(self, filter)
|
|
||||||
self.emit(SIGNAL('resultsChanged()'))
|
|
||||||
|
|
||||||
@demo_method
|
@demo_method
|
||||||
def copy_or_move_marked(self, copy):
|
def copy_or_move_marked(self, copy):
|
||||||
opname = 'copy' if copy else 'move'
|
opname = 'copy' if copy else 'move'
|
||||||
@@ -165,14 +156,6 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
|
|
||||||
delete_marked = demo_method(DupeGuruBase.delete_marked)
|
delete_marked = demo_method(DupeGuruBase.delete_marked)
|
||||||
|
|
||||||
def make_selected_reference(self):
|
|
||||||
DupeGuruBase.make_selected_reference(self)
|
|
||||||
self.emit(SIGNAL('resultsChanged()'))
|
|
||||||
|
|
||||||
def remove_duplicates(self, duplicates):
|
|
||||||
DupeGuruBase.remove_duplicates(self, duplicates)
|
|
||||||
self.emit(SIGNAL('resultsChanged()'))
|
|
||||||
|
|
||||||
def remove_selected(self):
|
def remove_selected(self):
|
||||||
dupes = self.without_ref(self.selected_dupes)
|
dupes = self.without_ref(self.selected_dupes)
|
||||||
if not dupes:
|
if not dupes:
|
||||||
@@ -186,37 +169,10 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
def askForRegCode(self):
|
def askForRegCode(self):
|
||||||
self.reg.ask_for_code()
|
self.reg.ask_for_code()
|
||||||
|
|
||||||
def mark_all(self):
|
|
||||||
self.results.mark_all()
|
|
||||||
self.emit(SIGNAL('dupeMarkingChanged()'))
|
|
||||||
|
|
||||||
def mark_invert(self):
|
|
||||||
self.results.mark_invert()
|
|
||||||
self.emit(SIGNAL('dupeMarkingChanged()'))
|
|
||||||
|
|
||||||
def mark_none(self):
|
|
||||||
self.results.mark_none()
|
|
||||||
self.emit(SIGNAL('dupeMarkingChanged()'))
|
|
||||||
|
|
||||||
def openDebugLog(self):
|
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)
|
||||||
|
|
||||||
def remove_marked_duplicates(self):
|
|
||||||
marked = [d for d in self.results.dupes if self.results.is_marked(d)]
|
|
||||||
self.remove_duplicates(marked)
|
|
||||||
|
|
||||||
def rename_dupe(self, dupe, newname):
|
|
||||||
try:
|
|
||||||
dupe.rename(newname)
|
|
||||||
return True
|
|
||||||
except (IndexError, fs.FSError) as e:
|
|
||||||
logging.warning("dupeGuru Warning: %s" % unicode(e))
|
|
||||||
return False
|
|
||||||
|
|
||||||
def select_dupes(self, dupes):
|
|
||||||
self._select_dupes(dupes)
|
|
||||||
|
|
||||||
def show_about_box(self):
|
def show_about_box(self):
|
||||||
self.about_box.show()
|
self.about_box.show()
|
||||||
|
|
||||||
@@ -227,7 +183,8 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
self.directories_dialog.show()
|
self.directories_dialog.show()
|
||||||
|
|
||||||
def show_help(self):
|
def show_help(self):
|
||||||
url = QUrl.fromLocalFile(op.abspath('help/intro.htm'))
|
base_path = platform.HELP_PATH.format(self.EDITION)
|
||||||
|
url = QUrl.fromLocalFile(op.abspath(op.join(base_path, 'intro.htm')))
|
||||||
QDesktopServices.openUrl(url)
|
QDesktopServices.openUrl(url)
|
||||||
|
|
||||||
def show_preferences(self):
|
def show_preferences(self):
|
||||||
@@ -238,11 +195,6 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
self.prefs.save()
|
self.prefs.save()
|
||||||
self._update_options()
|
self._update_options()
|
||||||
|
|
||||||
def toggle_marking_for_dupes(self, dupes):
|
|
||||||
for dupe in dupes:
|
|
||||||
self.results.mark_toggle(dupe)
|
|
||||||
self.emit(SIGNAL('dupeMarkingChanged()'))
|
|
||||||
|
|
||||||
#--- Events
|
#--- Events
|
||||||
def application_will_terminate(self):
|
def application_will_terminate(self):
|
||||||
self.save()
|
self.save()
|
||||||
@@ -253,7 +205,7 @@ class DupeGuru(DupeGuruBase, QObject):
|
|||||||
self.reg.show_nag()
|
self.reg.show_nag()
|
||||||
|
|
||||||
def job_finished(self, jobid):
|
def job_finished(self, jobid):
|
||||||
self.emit(SIGNAL('resultsChanged()'))
|
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) and self.last_op_error_count > 0:
|
||||||
msg = "{0} files could not be processed.".format(self.results.mark_count)
|
msg = "{0} files could not be processed.".format(self.results.mark_count)
|
||||||
QMessageBox.warning(self.main_window, 'Warning', msg)
|
QMessageBox.warning(self.main_window, 'Warning', msg)
|
||||||
|
|||||||
9
qt/base/cxfreeze_fix.py
Normal file
9
qt/base/cxfreeze_fix.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# cxfreeze has some problems detecting all dependencies.
|
||||||
|
# This modules explicitly import those problematic modules.
|
||||||
|
|
||||||
|
import lxml._elementpath
|
||||||
|
import gzip
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
os.environ['QT_PLUGIN_PATH'] = 'qt4_plugins'
|
||||||
@@ -23,6 +23,7 @@ class DetailsDialog(QDialog):
|
|||||||
self.tableModel = DetailsModel(self.model)
|
self.tableModel = DetailsModel(self.model)
|
||||||
# tableView is defined in subclasses
|
# tableView is defined in subclasses
|
||||||
self.tableView.setModel(self.tableModel)
|
self.tableView.setModel(self.tableModel)
|
||||||
|
self.model.connect()
|
||||||
|
|
||||||
def _setupUi(self): # Virtual
|
def _setupUi(self): # Virtual
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ class DirectoriesModel(TreeModel):
|
|||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
TreeModel.__init__(self)
|
TreeModel.__init__(self)
|
||||||
self.model = DirectoryTree(self, app)
|
self.model = DirectoryTree(self, app)
|
||||||
|
self.model.connect()
|
||||||
|
|
||||||
def _createNode(self, ref, row):
|
def _createNode(self, ref, row):
|
||||||
return RefNode(self, None, ref, row)
|
return RefNode(self, None, ref, row)
|
||||||
|
|||||||
@@ -6,9 +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
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
from PyQt4.QtCore import Qt, QCoreApplication, QProcess, SIGNAL, QUrl
|
from PyQt4.QtCore import Qt, QCoreApplication, QProcess, SIGNAL, QUrl
|
||||||
from PyQt4.QtGui import (QMainWindow, QMenu, QPixmap, QIcon, QToolButton, QLabel, QHeaderView,
|
from PyQt4.QtGui import (QMainWindow, QMenu, QPixmap, QIcon, QToolButton, QLabel, QHeaderView,
|
||||||
QMessageBox, QInputDialog, QLineEdit, QItemSelectionModel, QDesktopServices)
|
QMessageBox, QInputDialog, QLineEdit, QDesktopServices)
|
||||||
|
|
||||||
from hsutil.misc import nonone
|
from hsutil.misc import nonone
|
||||||
|
|
||||||
@@ -16,7 +18,8 @@ from core.app import NoScannableFileError, AllFilesAreRefError
|
|||||||
|
|
||||||
import dg_rc
|
import dg_rc
|
||||||
from main_window_ui import Ui_MainWindow
|
from main_window_ui import Ui_MainWindow
|
||||||
from results_model import ResultsDelegate, ResultsModel
|
from results_model import ResultsModel
|
||||||
|
from stats_label import StatsLabel
|
||||||
|
|
||||||
class MainWindow(QMainWindow, Ui_MainWindow):
|
class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
@@ -24,23 +27,16 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.app = app
|
self.app = app
|
||||||
self._last_filter = None
|
self._last_filter = None
|
||||||
self._setupUi()
|
self._setupUi()
|
||||||
self.resultsDelegate = ResultsDelegate()
|
self.resultsModel = ResultsModel(self.app, self.resultsView)
|
||||||
self.resultsModel = ResultsModel(self.app)
|
self.stats = StatsLabel(app, self.statusLabel)
|
||||||
self.resultsView.setModel(self.resultsModel)
|
|
||||||
self.resultsView.setItemDelegate(self.resultsDelegate)
|
|
||||||
self._load_columns()
|
self._load_columns()
|
||||||
self._update_column_actions_status()
|
self._update_column_actions_status()
|
||||||
self.resultsView.expandAll()
|
|
||||||
self._update_status_line()
|
|
||||||
|
|
||||||
self.connect(self.app, SIGNAL('resultsChanged()'), self.resultsChanged)
|
|
||||||
self.connect(self.app, SIGNAL('dupeMarkingChanged()'), self.dupeMarkingChanged)
|
|
||||||
self.connect(self.actionQuit, SIGNAL('triggered()'), QCoreApplication.instance().quit)
|
self.connect(self.actionQuit, SIGNAL('triggered()'), QCoreApplication.instance().quit)
|
||||||
self.connect(self.resultsView.selectionModel(), SIGNAL('selectionChanged(QItemSelection,QItemSelection)'), self.selectionChanged)
|
|
||||||
self.connect(self.menuColumns, SIGNAL('triggered(QAction*)'), self.columnToggled)
|
self.connect(self.menuColumns, SIGNAL('triggered(QAction*)'), self.columnToggled)
|
||||||
self.connect(QCoreApplication.instance(), SIGNAL('aboutToQuit()'), self.application_will_terminate)
|
self.connect(QCoreApplication.instance(), SIGNAL('aboutToQuit()'), self.application_will_terminate)
|
||||||
self.connect(self.resultsModel, SIGNAL('modelReset()'), self.resultsReset)
|
|
||||||
self.connect(self.resultsView, SIGNAL('doubleClicked()'), self.resultsDoubleClicked)
|
self.connect(self.resultsView, SIGNAL('doubleClicked()'), self.resultsDoubleClicked)
|
||||||
|
self.connect(self.resultsView, SIGNAL('spacePressed()'), self.resultsSpacePressed)
|
||||||
|
|
||||||
def _setupUi(self):
|
def _setupUi(self):
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
@@ -92,6 +88,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.statusLabel = QLabel(self)
|
self.statusLabel = QLabel(self)
|
||||||
self.statusbar.addPermanentWidget(self.statusLabel, 1)
|
self.statusbar.addPermanentWidget(self.statusLabel, 1)
|
||||||
|
|
||||||
|
# Linux setup
|
||||||
|
if sys.platform == 'linux2':
|
||||||
|
self.actionCheckForUpdate.setVisible(False) # This only works on Windows
|
||||||
|
|
||||||
#--- Private
|
#--- Private
|
||||||
def _confirm(self, title, msg, default_button=QMessageBox.Yes):
|
def _confirm(self, title, msg, default_button=QMessageBox.Yes):
|
||||||
buttons = QMessageBox.Yes | QMessageBox.No
|
buttons = QMessageBox.Yes | QMessageBox.No
|
||||||
@@ -108,11 +108,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
h.setSectionHidden(index, not visible)
|
h.setSectionHidden(index, not visible)
|
||||||
h.setResizeMode(0, QHeaderView.Stretch)
|
h.setResizeMode(0, QHeaderView.Stretch)
|
||||||
|
|
||||||
def _redraw_results(self):
|
|
||||||
# HACK. this is the only way I found to update the widget without reseting everything
|
|
||||||
self.resultsView.scroll(0, 1)
|
|
||||||
self.resultsView.scroll(0, -1)
|
|
||||||
|
|
||||||
def _save_columns(self):
|
def _save_columns(self):
|
||||||
h = self.resultsView.header()
|
h = self.resultsView.header()
|
||||||
widths = []
|
widths = []
|
||||||
@@ -131,9 +126,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
colid = action.column_index
|
colid = action.column_index
|
||||||
action.setChecked(not h.isSectionHidden(colid))
|
action.setChecked(not h.isSectionHidden(colid))
|
||||||
|
|
||||||
def _update_status_line(self):
|
|
||||||
self.statusLabel.setText(self.app.stat_line)
|
|
||||||
|
|
||||||
#--- Actions
|
#--- Actions
|
||||||
def aboutTriggered(self):
|
def aboutTriggered(self):
|
||||||
self.app.show_about_box()
|
self.app.show_about_box()
|
||||||
@@ -185,8 +177,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.app.delete_marked()
|
self.app.delete_marked()
|
||||||
|
|
||||||
def deltaTriggered(self):
|
def deltaTriggered(self):
|
||||||
self.resultsModel.delta = self.actionDelta.isChecked()
|
self.resultsModel.delta_values = self.actionDelta.isChecked()
|
||||||
self._redraw_results()
|
|
||||||
|
|
||||||
def detailsTriggered(self):
|
def detailsTriggered(self):
|
||||||
self.app.show_details()
|
self.app.show_details()
|
||||||
@@ -217,8 +208,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.app.mark_none()
|
self.app.mark_none()
|
||||||
|
|
||||||
def markSelectedTriggered(self):
|
def markSelectedTriggered(self):
|
||||||
dupes = self.resultsView.selectedDupes()
|
self.app.toggle_selected_mark_state()
|
||||||
self.app.toggle_marking_for_dupes(dupes)
|
|
||||||
|
|
||||||
def moveTriggered(self):
|
def moveTriggered(self):
|
||||||
self.app.copy_or_move_marked(False)
|
self.app.copy_or_move_marked(False)
|
||||||
@@ -245,7 +235,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
title = "Remove duplicates"
|
title = "Remove duplicates"
|
||||||
msg = "You are about to remove {0} files from results. Continue?".format(count)
|
msg = "You are about to remove {0} files from results. Continue?".format(count)
|
||||||
if self._confirm(title, msg):
|
if self._confirm(title, msg):
|
||||||
self.app.remove_marked_duplicates()
|
self.app.remove_marked()
|
||||||
|
|
||||||
def removeSelectedTriggered(self):
|
def removeSelectedTriggered(self):
|
||||||
self.app.remove_selected()
|
self.app.remove_selected()
|
||||||
@@ -292,25 +282,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
def contextMenuEvent(self, event):
|
def contextMenuEvent(self, event):
|
||||||
self.actionActions.menu().exec_(event.globalPos())
|
self.actionActions.menu().exec_(event.globalPos())
|
||||||
|
|
||||||
def dupeMarkingChanged(self):
|
|
||||||
self._redraw_results()
|
|
||||||
self._update_status_line()
|
|
||||||
|
|
||||||
def resultsChanged(self):
|
|
||||||
self.resultsView.model().reset()
|
|
||||||
|
|
||||||
def resultsDoubleClicked(self):
|
def resultsDoubleClicked(self):
|
||||||
self.app.open_selected()
|
self.app.open_selected()
|
||||||
|
|
||||||
def resultsReset(self):
|
def resultsSpacePressed(self):
|
||||||
self.resultsView.expandAll()
|
self.app.toggle_selected_mark_state()
|
||||||
if self.app.selected_dupes:
|
|
||||||
[modelIndex] = self.resultsModel.indexesForDupes(self.app.selected_dupes[:1])
|
|
||||||
if modelIndex.isValid():
|
|
||||||
flags = QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows
|
|
||||||
self.resultsView.selectionModel().setCurrentIndex(modelIndex, flags)
|
|
||||||
self._update_status_line()
|
|
||||||
|
|
||||||
def selectionChanged(self, selected, deselected):
|
|
||||||
self.app.select_dupes(self.resultsView.selectedDupes())
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,5 +14,7 @@ if sys.platform == 'win32':
|
|||||||
from platform_win import *
|
from platform_win import *
|
||||||
elif sys.platform == 'darwin':
|
elif sys.platform == 'darwin':
|
||||||
from platform_osx import *
|
from platform_osx import *
|
||||||
|
elif sys.platform == 'linux2':
|
||||||
|
from platform_lnx import *
|
||||||
else:
|
else:
|
||||||
pass # unsupported platform
|
pass # unsupported platform
|
||||||
|
|||||||
11
qt/base/platform_lnx.py
Normal file
11
qt/base/platform_lnx.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Created By: Virgil Dupras
|
||||||
|
# Created On: 2010-02-13
|
||||||
|
# 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
|
||||||
|
|
||||||
|
INITIAL_FOLDER_IN_DIALOGS = u'/'
|
||||||
|
HELP_PATH = '/usr/local/share/dupeguru_{0}/help'
|
||||||
@@ -9,7 +9,5 @@
|
|||||||
|
|
||||||
# dummy unit to allow the app to run under OSX during development
|
# dummy unit to allow the app to run under OSX during development
|
||||||
|
|
||||||
INITIAL_FOLDER_IN_DIALOGS = '/'
|
INITIAL_FOLDER_IN_DIALOGS = u'/'
|
||||||
|
HELP_PATH = ''
|
||||||
def recycle_file(path):
|
|
||||||
pass
|
|
||||||
|
|||||||
@@ -7,16 +7,5 @@
|
|||||||
# 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 __future__ import unicode_literals
|
INITIAL_FOLDER_IN_DIALOGS = u'C:\\'
|
||||||
|
HELP_PATH = 'help'
|
||||||
import logging
|
|
||||||
|
|
||||||
import winshell
|
|
||||||
|
|
||||||
INITIAL_FOLDER_IN_DIALOGS = 'C:\\'
|
|
||||||
|
|
||||||
def recycle_file(path):
|
|
||||||
try:
|
|
||||||
winshell.delete_file(unicode(path), no_confirm=True, silent=True)
|
|
||||||
except winshell.x_winshell as e:
|
|
||||||
logging.warning("winshell error: %s", e)
|
|
||||||
|
|||||||
@@ -6,74 +6,63 @@
|
|||||||
# 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 PyQt4.QtCore import SIGNAL, Qt, QAbstractItemModel, QModelIndex, QRect
|
from PyQt4.QtCore import SIGNAL, Qt
|
||||||
from PyQt4.QtGui import QBrush, QStyledItemDelegate, QFont, QTreeView, QColor
|
from PyQt4.QtGui import (QBrush, QStyledItemDelegate, QFont, QTreeView, QColor, QItemSelectionModel,
|
||||||
|
QItemSelection)
|
||||||
|
|
||||||
from qtlib.tree_model import TreeNode, TreeModel
|
from qtlib.tree_model import TreeModel, RefNode
|
||||||
|
|
||||||
class ResultNode(TreeNode):
|
|
||||||
def __init__(self, model, parent, row, dupe, group):
|
|
||||||
TreeNode.__init__(self, model, parent, row)
|
|
||||||
self.dupe = dupe
|
|
||||||
self.group = group
|
|
||||||
self._normalData = None
|
|
||||||
self._deltaData = None
|
|
||||||
|
|
||||||
def _createNode(self, ref, row):
|
|
||||||
return ResultNode(self.model, self, row, ref, self.group)
|
|
||||||
|
|
||||||
def _getChildren(self):
|
|
||||||
return self.group.dupes if self.dupe is self.group.ref else []
|
|
||||||
|
|
||||||
def invalidate(self):
|
|
||||||
self._normalData = None
|
|
||||||
self._deltaData = None
|
|
||||||
TreeNode.invalidate(self)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def normalData(self):
|
|
||||||
if self._normalData is None:
|
|
||||||
self._normalData = self.model._app._get_display_info(self.dupe, self.group, delta=False)
|
|
||||||
return self._normalData
|
|
||||||
|
|
||||||
@property
|
|
||||||
def deltaData(self):
|
|
||||||
if self._deltaData is None:
|
|
||||||
self._deltaData = self.model._app._get_display_info(self.dupe, self.group, delta=True)
|
|
||||||
return self._deltaData
|
|
||||||
|
|
||||||
|
from core.gui.result_tree import ResultTree as ResultTreeModel
|
||||||
|
|
||||||
class ResultsDelegate(QStyledItemDelegate):
|
class ResultsDelegate(QStyledItemDelegate):
|
||||||
def initStyleOption(self, option, index):
|
def initStyleOption(self, option, index):
|
||||||
QStyledItemDelegate.initStyleOption(self, option, index)
|
QStyledItemDelegate.initStyleOption(self, option, index)
|
||||||
node = index.internalPointer()
|
node = index.internalPointer()
|
||||||
if node.group.ref is node.dupe:
|
ref = node.ref
|
||||||
|
if ref._group.ref is ref._dupe:
|
||||||
newfont = QFont(option.font)
|
newfont = QFont(option.font)
|
||||||
newfont.setBold(True)
|
newfont.setBold(True)
|
||||||
option.font = newfont
|
option.font = newfont
|
||||||
|
|
||||||
|
|
||||||
class ResultsModel(TreeModel):
|
class ResultsModel(TreeModel):
|
||||||
def __init__(self, app):
|
def __init__(self, app, view):
|
||||||
|
TreeModel.__init__(self)
|
||||||
|
self.view = view
|
||||||
self._app = app
|
self._app = app
|
||||||
self._results = app.results
|
|
||||||
self._data = app.data
|
self._data = app.data
|
||||||
self._delta_columns = app.DELTA_COLUMNS
|
self._delta_columns = app.DELTA_COLUMNS
|
||||||
self.delta = False
|
self.resultsDelegate = ResultsDelegate()
|
||||||
self._power_marker = False
|
self.model = ResultTreeModel(self, app)
|
||||||
TreeModel.__init__(self)
|
self.view.setItemDelegate(self.resultsDelegate)
|
||||||
|
self.view.setModel(self)
|
||||||
|
self.model.connect()
|
||||||
|
|
||||||
|
self.connect(self.view.selectionModel(), SIGNAL('selectionChanged(QItemSelection,QItemSelection)'), self.selectionChanged)
|
||||||
|
|
||||||
def _createNode(self, ref, row):
|
def _createNode(self, ref, row):
|
||||||
if self.power_marker:
|
return RefNode(self, None, ref, row)
|
||||||
# ref is a dupe
|
|
||||||
group = self._results.get_group_of_duplicate(ref)
|
|
||||||
return ResultNode(self, None, row, ref, group)
|
|
||||||
else:
|
|
||||||
# ref is a group
|
|
||||||
return ResultNode(self, None, row, ref.ref, ref)
|
|
||||||
|
|
||||||
def _getChildren(self):
|
def _getChildren(self):
|
||||||
return self._results.dupes if self.power_marker else self._results.groups
|
return list(self.model)
|
||||||
|
|
||||||
|
def _updateSelection(self):
|
||||||
|
selectedIndexes = []
|
||||||
|
for path in self.model.selected_paths:
|
||||||
|
modelIndex = self.findIndex(path)
|
||||||
|
if modelIndex.isValid():
|
||||||
|
selectedIndexes.append(modelIndex)
|
||||||
|
if selectedIndexes:
|
||||||
|
selection = QItemSelection()
|
||||||
|
for modelIndex in selectedIndexes:
|
||||||
|
selection.select(modelIndex, modelIndex)
|
||||||
|
flags = QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows
|
||||||
|
self.view.selectionModel().select(selection, flags)
|
||||||
|
flags = QItemSelectionModel.Rows
|
||||||
|
self.view.selectionModel().setCurrentIndex(selectedIndexes[0], flags)
|
||||||
|
self.view.scrollTo(selectedIndexes[0])
|
||||||
|
else:
|
||||||
|
self.view.selectionModel().clear()
|
||||||
|
|
||||||
def columnCount(self, parent):
|
def columnCount(self, parent):
|
||||||
return len(self._data.COLUMNS)
|
return len(self._data.COLUMNS)
|
||||||
@@ -82,51 +71,23 @@ class ResultsModel(TreeModel):
|
|||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return None
|
return None
|
||||||
node = index.internalPointer()
|
node = index.internalPointer()
|
||||||
|
ref = node.ref
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
data = node.deltaData if self.delta else node.normalData
|
data = ref.data_delta if self.model.delta_values else ref.data
|
||||||
return data[index.column()]
|
return data[index.column()]
|
||||||
elif role == Qt.CheckStateRole:
|
elif role == Qt.CheckStateRole:
|
||||||
if index.column() == 0 and node.dupe is not node.group.ref:
|
if index.column() == 0 and ref.markable:
|
||||||
state = Qt.Checked if self._results.is_marked(node.dupe) else Qt.Unchecked
|
return Qt.Checked if ref.marked else Qt.Unchecked
|
||||||
return state
|
|
||||||
elif role == Qt.ForegroundRole:
|
elif role == Qt.ForegroundRole:
|
||||||
if node.dupe is node.group.ref or node.dupe.is_ref:
|
if ref._dupe is ref._group.ref or ref._dupe.is_ref:
|
||||||
return QBrush(Qt.blue)
|
return QBrush(Qt.blue)
|
||||||
elif self.delta and index.column() in self._delta_columns:
|
elif self.model.delta_values and index.column() in self._delta_columns:
|
||||||
return QBrush(QColor(255, 142, 40)) # orange
|
return QBrush(QColor(255, 142, 40)) # orange
|
||||||
elif role == Qt.EditRole:
|
elif role == Qt.EditRole:
|
||||||
if index.column() == 0:
|
if index.column() == 0:
|
||||||
return node.normalData[index.column()]
|
return ref.data[index.column()]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def dupesForIndexes(self, indexes):
|
|
||||||
nodes = [index.internalPointer() for index in indexes]
|
|
||||||
return [node.dupe for node in nodes]
|
|
||||||
|
|
||||||
def indexesForDupes(self, dupes):
|
|
||||||
def index(dupe):
|
|
||||||
try:
|
|
||||||
if self.power_marker:
|
|
||||||
row = self._results.dupes.index(dupe)
|
|
||||||
node = self.subnodes[row]
|
|
||||||
assert node.dupe is dupe
|
|
||||||
return self.createIndex(row, 0, node)
|
|
||||||
else:
|
|
||||||
group = self._results.get_group_of_duplicate(dupe)
|
|
||||||
row = self._results.groups.index(group)
|
|
||||||
node = self.subnodes[row]
|
|
||||||
if dupe is group.ref:
|
|
||||||
assert node.dupe is dupe
|
|
||||||
return self.createIndex(row, 0, node)
|
|
||||||
subrow = group.dupes.index(dupe)
|
|
||||||
subnode = node.subnodes[subrow]
|
|
||||||
assert subnode.dupe is dupe
|
|
||||||
return self.createIndex(subrow, 0, subnode)
|
|
||||||
except ValueError: # the dupe is not there anymore
|
|
||||||
return QModelIndex()
|
|
||||||
|
|
||||||
return map(index, dupes)
|
|
||||||
|
|
||||||
def flags(self, index):
|
def flags(self, index):
|
||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return Qt.ItemIsEnabled
|
return Qt.ItemIsEnabled
|
||||||
@@ -144,48 +105,61 @@ class ResultsModel(TreeModel):
|
|||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return False
|
return False
|
||||||
node = index.internalPointer()
|
node = index.internalPointer()
|
||||||
|
ref = node.ref
|
||||||
if role == Qt.CheckStateRole:
|
if role == Qt.CheckStateRole:
|
||||||
if index.column() == 0:
|
if index.column() == 0:
|
||||||
self._app.toggle_marking_for_dupes([node.dupe])
|
self._app.mark_dupe(ref._dupe, value.toBool())
|
||||||
return True
|
return True
|
||||||
if role == Qt.EditRole:
|
if role == Qt.EditRole:
|
||||||
if index.column() == 0:
|
if index.column() == 0:
|
||||||
value = unicode(value.toString())
|
value = unicode(value.toString())
|
||||||
if self._app.rename_dupe(node.dupe, value):
|
return self.model.rename_selected(value)
|
||||||
node.invalidate()
|
|
||||||
return True
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def sort(self, column, order):
|
def sort(self, column, order):
|
||||||
if self.power_marker:
|
self.model.sort(column, order == Qt.AscendingOrder)
|
||||||
self._results.sort_dupes(column, order == Qt.AscendingOrder, self.delta)
|
|
||||||
else:
|
|
||||||
self._results.sort_groups(column, order == Qt.AscendingOrder)
|
|
||||||
self.reset()
|
|
||||||
|
|
||||||
def toggleMarked(self, indexes):
|
|
||||||
assert indexes
|
|
||||||
dupes = self.dupesForIndexes(indexes)
|
|
||||||
self._app.toggle_marking_for_dupes(dupes)
|
|
||||||
|
|
||||||
#--- Properties
|
#--- Properties
|
||||||
@property
|
@property
|
||||||
def power_marker(self):
|
def power_marker(self):
|
||||||
return self._power_marker
|
return self.model.power_marker
|
||||||
|
|
||||||
@power_marker.setter
|
@power_marker.setter
|
||||||
def power_marker(self, value):
|
def power_marker(self, value):
|
||||||
if value == self._power_marker:
|
self.model.power_marker = value
|
||||||
return
|
|
||||||
self._power_marker = value
|
@property
|
||||||
|
def delta_values(self):
|
||||||
|
return self.model.delta_values
|
||||||
|
|
||||||
|
@delta_values.setter
|
||||||
|
def delta_values(self, value):
|
||||||
|
self.model.delta_values = value
|
||||||
|
|
||||||
|
#--- Events
|
||||||
|
def selectionChanged(self, selected, deselected):
|
||||||
|
indexes = self.view.selectionModel().selectedRows()
|
||||||
|
nodes = [index.internalPointer() for index in indexes]
|
||||||
|
self.model.selected_nodes = [node.ref for node in nodes]
|
||||||
|
|
||||||
|
#--- model --> view
|
||||||
|
def refresh(self):
|
||||||
self.reset()
|
self.reset()
|
||||||
|
self.view.expandAll()
|
||||||
|
self._updateSelection()
|
||||||
|
|
||||||
|
def invalidate_markings(self):
|
||||||
|
# redraw view
|
||||||
|
# HACK. this is the only way I found to update the widget without reseting everything
|
||||||
|
self.view.scroll(0, 1)
|
||||||
|
self.view.scroll(0, -1)
|
||||||
|
|
||||||
|
|
||||||
class ResultsView(QTreeView):
|
class ResultsView(QTreeView):
|
||||||
#--- Override
|
#--- Override
|
||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
if event.text() == ' ':
|
if event.text() == ' ':
|
||||||
self.model().toggleMarked(self.selectionModel().selectedRows())
|
self.emit(SIGNAL('spacePressed()'))
|
||||||
return
|
return
|
||||||
QTreeView.keyPressEvent(self, event)
|
QTreeView.keyPressEvent(self, event)
|
||||||
|
|
||||||
@@ -193,11 +167,3 @@ class ResultsView(QTreeView):
|
|||||||
self.emit(SIGNAL('doubleClicked()'))
|
self.emit(SIGNAL('doubleClicked()'))
|
||||||
# We don't call the superclass' method because the default behavior is to rename the cell.
|
# We don't call the superclass' method because the default behavior is to rename the cell.
|
||||||
|
|
||||||
def setModel(self, model):
|
|
||||||
assert isinstance(model, ResultsModel)
|
|
||||||
QTreeView.setModel(self, model)
|
|
||||||
|
|
||||||
#--- Public
|
|
||||||
def selectedDupes(self):
|
|
||||||
return self.model().dupesForIndexes(self.selectionModel().selectedRows())
|
|
||||||
|
|
||||||
|
|||||||
20
qt/base/stats_label.py
Normal file
20
qt/base/stats_label.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Created By: Virgil Dupras
|
||||||
|
# Created On: 2010-02-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 core.gui.stats_label import StatsLabel as StatsLabelModel
|
||||||
|
|
||||||
|
class StatsLabel(object):
|
||||||
|
def __init__(self, app, view):
|
||||||
|
self.view = view
|
||||||
|
self.model = StatsLabelModel(self, app)
|
||||||
|
self.model.connect()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self.view.setText(self.model.display)
|
||||||
|
|
||||||
@@ -14,9 +14,10 @@ from preferences import Preferences
|
|||||||
from preferences_dialog import PreferencesDialog
|
from preferences_dialog import PreferencesDialog
|
||||||
|
|
||||||
class DupeGuru(DupeGuruBase):
|
class DupeGuru(DupeGuruBase):
|
||||||
|
EDITION = 'me'
|
||||||
LOGO_NAME = 'logo_me'
|
LOGO_NAME = 'logo_me'
|
||||||
NAME = 'dupeGuru Music Edition'
|
NAME = 'dupeGuru Music Edition'
|
||||||
VERSION = '5.7.1'
|
VERSION = '5.7.2'
|
||||||
DELTA_COLUMNS = frozenset([2, 3, 4, 5, 7, 8])
|
DELTA_COLUMNS = frozenset([2, 3, 4, 5, 7, 8])
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
a = Analysis([os.path.join(HOMEPATH,'support\\_mountzlib.py'), os.path.join(HOMEPATH,'support\\useUnicode.py'), 'start.py'],
|
|
||||||
pathex=[])
|
|
||||||
pyz = PYZ(a.pure)
|
|
||||||
exe = EXE(pyz,
|
|
||||||
a.scripts,
|
|
||||||
exclude_binaries=1,
|
|
||||||
name=os.path.join('build\\pyi.win32\\dupeGuru ME', 'dupeGuru ME.exe'),
|
|
||||||
debug=False,
|
|
||||||
strip=False,
|
|
||||||
upx=True,
|
|
||||||
console=False , icon='..\\..\\images\\dgme_logo.ico', version='verinfo_tmp')
|
|
||||||
coll = COLLECT( exe,
|
|
||||||
a.binaries,
|
|
||||||
a.zipfiles,
|
|
||||||
a.datas,
|
|
||||||
strip=False,
|
|
||||||
upx=True,
|
|
||||||
name=os.path.join('dist'))
|
|
||||||
@@ -1,30 +1,27 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<DOCUMENT type="Advanced Installer" CreateVersion="4.7.2" version="4.9.2" modules="professional" RootPath="." Language="en">
|
<DOCUMENT type="Advanced Installer" CreateVersion="4.7.2" version="7.5" modules="professional" RootPath="." Language="en">
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">
|
||||||
<ROW Property="AI_DESKTOP_SH" Value="1" Type="4"/>
|
<ROW Property="AI_FINDEXE_TITLE" Value="Select the installation package for [|ProductName]" ValueLocId="AI.Property.FindExeTitle"/>
|
||||||
<ROW Property="AI_QUICKLAUNCH_SH" Value="1" Type="4"/>
|
|
||||||
<ROW Property="AI_SHORTCUTSREG" Value="0|0|0|"/>
|
<ROW Property="AI_SHORTCUTSREG" Value="0|0|0|"/>
|
||||||
<ROW Property="AI_STARTMENU_SH" Value="1" Type="4"/>
|
|
||||||
<ROW Property="AI_STARTUP_SH" Value="1" Type="4"/>
|
|
||||||
<ROW Property="ALLUSERS" Value="2"/>
|
<ROW Property="ALLUSERS" Value="2"/>
|
||||||
<ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]." ValueLocId="*"/>
|
<ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]." ValueLocId="*"/>
|
||||||
<ROW Property="ARPCONTACT" Value="support@hardcoded.net"/>
|
<ROW Property="ARPCONTACT" Value="support@hardcoded.net"/>
|
||||||
<ROW Property="ARPHELPLINK" Value="http://www.hardcoded.net/support/"/>
|
<ROW Property="ARPHELPLINK" Value="http://www.hardcoded.net/support/"/>
|
||||||
<ROW Property="ARPURLINFOABOUT" Value="http://www.hardcoded.net/dupeguru_me/"/>
|
<ROW Property="ARPURLINFOABOUT" Value="http://www.hardcoded.net/dupeguru_me/"/>
|
||||||
<ROW Property="ARPURLUPDATEINFO" Value="http://www.hardcoded.net/dupeguru_me/"/>
|
<ROW Property="ARPURLUPDATEINFO" Value="http://www.hardcoded.net/dupeguru_me/"/>
|
||||||
<ROW Property="BannerBitmap" Value="default_banner.bmp" Type="1"/>
|
<ROW Property="BannerBitmap" MultiBuildValue="DefaultBuild:banner_image.jpg" Type="1"/>
|
||||||
<ROW Property="CTRLS" Value="2"/>
|
<ROW Property="CTRLS" Value="2"/>
|
||||||
<ROW Property="DialogBitmap" Value="default_dialog.bmp" Type="1"/>
|
<ROW Property="DialogBitmap" MultiBuildValue="DefaultBuild:dialog_image.jpg" Type="1"/>
|
||||||
<ROW Property="Manufacturer" Value="Hardcoded Software" ValueLocId="*"/>
|
<ROW Property="Manufacturer" Value="Hardcoded Software" ValueLocId="*"/>
|
||||||
<ROW Property="ProductCode" Value="1033:{A7037226-389C-4704-81C3-E2CA17D11058} "/>
|
<ROW Property="ProductCode" Value="1033:{A7037226-389C-4704-81C3-E2CA17D11058} " Type="16"/>
|
||||||
<ROW Property="ProductLanguage" Value="1033"/>
|
<ROW Property="ProductLanguage" Value="1033"/>
|
||||||
<ROW Property="ProductName" Value="dupeGuru Music Edition" ValueLocId="*"/>
|
<ROW Property="ProductName" Value="dupeGuru Music Edition" ValueLocId="*"/>
|
||||||
<ROW Property="ProductVersion" Value="5.6.0"/>
|
<ROW Property="ProductVersion" Value="5.6.0"/>
|
||||||
<ROW Property="RUNAPPLICATION" Value="1" Type="4"/>
|
<ROW Property="RUNAPPLICATION" Value="1" Type="4"/>
|
||||||
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND"/>
|
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND;AI_SETUPEXEPATH;SETUPEXEDIR"/>
|
||||||
<ROW Property="UpgradeCode" Value="{E11BFC48-7639-44BD-BB5B-A6AC934BC12D}"/>
|
<ROW Property="UpgradeCode" Value="{E11BFC48-7639-44BD-BB5B-A6AC934BC12D}"/>
|
||||||
<ROW Property="WindowsFamily9X" Value="Windows 9x/ME"/>
|
<ROW Property="WindowsFamily9X" MultiBuildValue="DefaultBuild:Windows 9x/ME" ValueLocId="-"/>
|
||||||
<ROW Property="WindowsTypeNT" Value="Windows 2000"/>
|
<ROW Property="WindowsTypeNT" MultiBuildValue="DefaultBuild:Windows 2000" ValueLocId="-"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">
|
||||||
<ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1"/>
|
<ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1"/>
|
||||||
@@ -33,121 +30,134 @@
|
|||||||
<ROW Directory="TARGETDIR" DefaultDir="SourceDir"/>
|
<ROW Directory="TARGETDIR" DefaultDir="SourceDir"/>
|
||||||
<ROW Directory="accessible_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="access~1|accessible"/>
|
<ROW Directory="accessible_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="access~1|accessible"/>
|
||||||
<ROW Directory="codecs_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="codecs"/>
|
<ROW Directory="codecs_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="codecs"/>
|
||||||
|
<ROW Directory="help_DIR" Directory_Parent="APPDIR" DefaultDir="help"/>
|
||||||
<ROW Directory="iconengines_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="iconen~1|iconengines"/>
|
<ROW Directory="iconengines_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="iconen~1|iconengines"/>
|
||||||
<ROW Directory="imageformats_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="imagef~1|imageformats"/>
|
<ROW Directory="imageformats_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="imagef~1|imageformats"/>
|
||||||
|
<ROW Directory="images_DIR" Directory_Parent="help_DIR" DefaultDir="images"/>
|
||||||
<ROW Directory="qt4_plugins_DIR" Directory_Parent="APPDIR" DefaultDir="qt4_pl~1|qt4_plugins"/>
|
<ROW Directory="qt4_plugins_DIR" Directory_Parent="APPDIR" DefaultDir="qt4_pl~1|qt4_plugins"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
|
||||||
<ROW Component="AIShRegAnswer" ComponentId="{7DB5C163-2978-436F-A47D-54F1C76F1D64}" Directory_="APPDIR" Attributes="4" KeyPath="AIShRegAnswer" FullKeyPath="HK_UM\Software\Caphyon\Advanced Installer\Installs\[ProductCode]\AIShRegAnswer"/>
|
<ROW Component="AIShRegAnswer" ComponentId="{7DB5C163-2978-436F-A47D-54F1C76F1D64}" Directory_="APPDIR" Attributes="4" KeyPath="AIShRegAnswer"/>
|
||||||
<ROW Component="MSVCP90.dll" ComponentId="{9CD64E9F-44D0-4EB9-9FB2-B2F1AB1551CE}" Directory_="APPDIR" Attributes="0" KeyPath="MSVCP90.dll" FullKeyPath="APPDIR\MSVCP90.dll"/>
|
<ROW Component="AI_ExePath" ComponentId="{AB8EF793-B4A4-4A5C-A343-8095FFE16175}" Directory_="APPDIR" Attributes="4" KeyPath="AI_ExePath"/>
|
||||||
<ROW Component="MSVCR90.dll" ComponentId="{2D77BB4F-0B6B-452A-A7D1-2DB8CDC3BC0B}" Directory_="APPDIR" Attributes="0" KeyPath="MSVCR90.dll" FullKeyPath="APPDIR\MSVCR90.dll"/>
|
<ROW Component="PyWinTypes26.dll" ComponentId="{E7DC87D7-F396-46F0-8132-D4F582709AA2}" Directory_="APPDIR" Attributes="0" KeyPath="PyWinTypes26.dll"/>
|
||||||
<ROW Component="POWRPROF.dll" ComponentId="{12B8FFB0-6FEB-49A9-8A09-5B4B26379034}" Directory_="APPDIR" Attributes="0" KeyPath="POWRPROF.dll" FullKeyPath="APPDIR\POWRPROF.dll"/>
|
<ROW Component="QtCore4.dll" ComponentId="{731F12A4-0DB0-4484-8BA1-399560578D68}" Directory_="APPDIR" Attributes="0" KeyPath="QtCore4.dll"/>
|
||||||
<ROW Component="PyWinTypes26.dll" ComponentId="{E7DC87D7-F396-46F0-8132-D4F582709AA2}" Directory_="APPDIR" Attributes="0" KeyPath="PyWinTypes26.dll" FullKeyPath="APPDIR\PyWinTypes26.dll"/>
|
<ROW Component="QtGui4.dll" ComponentId="{3D4FDAFA-EE5E-43C5-A4F5-125F7FA6A550}" Directory_="APPDIR" Attributes="0" KeyPath="QtGui4.dll"/>
|
||||||
<ROW Component="QtCore4.dll" ComponentId="{731F12A4-0DB0-4484-8BA1-399560578D68}" Directory_="APPDIR" Attributes="0" KeyPath="QtCore4.dll" FullKeyPath="APPDIR\QtCore4.dll"/>
|
<ROW Component="bz2.pyd_1" ComponentId="{E34B2912-4B50-4EEA-B1EF-B56FA625FCC7}" Directory_="APPDIR" Attributes="0" KeyPath="bz2.pyd" Type="0"/>
|
||||||
<ROW Component="QtGui4.dll" ComponentId="{3D4FDAFA-EE5E-43C5-A4F5-125F7FA6A550}" Directory_="APPDIR" Attributes="0" KeyPath="QtGui4.dll" FullKeyPath="APPDIR\QtGui4.dll"/>
|
<ROW Component="credits.htm" ComponentId="{4C0F14CD-BD35-44FE-B307-4834264AB347}" Directory_="help_DIR" Attributes="0" KeyPath="credits.htm" Type="0"/>
|
||||||
<ROW Component="SHLWAPI.dll" ComponentId="{FF064632-83EE-43F6-8AE2-7982EFF81216}" Directory_="APPDIR" Attributes="0" KeyPath="SHLWAPI.dll" FullKeyPath="APPDIR\SHLWAPI.dll"/>
|
<ROW Component="dupeGuru_ME.exe" ComponentId="{14F7B73A-FA85-4C10-AA92-10BE05FE103B}" Directory_="APPDIR" Attributes="0" KeyPath="dupeGuru_ME.exe"/>
|
||||||
<ROW Component="bz2.pyd_1" ComponentId="{E34B2912-4B50-4EEA-B1EF-B56FA625FCC7}" Directory_="APPDIR" Attributes="0" KeyPath="bz2.pyd" FullKeyPath="APPDIR"/>
|
<ROW Component="hs_title.png" ComponentId="{A292ADA8-FEC0-49B9-81A5-6C7F837290D4}" Directory_="images_DIR" Attributes="0" KeyPath="hs_title.png" Type="0"/>
|
||||||
<ROW Component="dupeGuru_ME.exe" ComponentId="{14F7B73A-FA85-4C10-AA92-10BE05FE103B}" Directory_="APPDIR" Attributes="0" KeyPath="dupeGuru_ME.exe" FullKeyPath="APPDIR\dupeGuru ME.exe"/>
|
<ROW Component="python26.dll" ComponentId="{20E0EA31-C5CF-4278-B7C6-5FCA0C691B7F}" Directory_="APPDIR" Attributes="0" KeyPath="python26.dll"/>
|
||||||
<ROW Component="iertutil.dll" ComponentId="{C4907490-FE25-4CD9-B31A-583DFF8A4359}" Directory_="APPDIR" Attributes="0" KeyPath="iertutil.dll" FullKeyPath="APPDIR\iertutil.dll"/>
|
<ROW Component="pythoncom26.dll" ComponentId="{C0489561-2362-48C1-86E8-D5F1A08DE4DE}" Directory_="APPDIR" Attributes="0" KeyPath="pythoncom26.dll"/>
|
||||||
<ROW Component="mfc90.dll" ComponentId="{B206C255-03A4-4A40-92F2-5565830FEB14}" Directory_="APPDIR" Attributes="0" KeyPath="mfc90.dll" FullKeyPath="APPDIR\mfc90.dll"/>
|
<ROW Component="qcncodecs4.dll" ComponentId="{03C97279-4453-48E0-A40D-D28E6F3E701F}" Directory_="codecs_DIR" Attributes="0" KeyPath="qcncodecs4.dll"/>
|
||||||
<ROW Component="msvcm90.dll" ComponentId="{B86025F0-23B8-45B6-B870-459DF292E17D}" Directory_="APPDIR" Attributes="0" KeyPath="msvcm90.dll" FullKeyPath="APPDIR\msvcm90.dll"/>
|
<ROW Component="qgif4.dll" ComponentId="{5D6E676F-18BC-49C8-BBD2-E6BA1F3CA043}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qgif4.dll"/>
|
||||||
<ROW Component="python26.dll" ComponentId="{20E0EA31-C5CF-4278-B7C6-5FCA0C691B7F}" Directory_="APPDIR" Attributes="0" KeyPath="python26.dll" FullKeyPath="APPDIR\python26.dll"/>
|
<ROW Component="qico4.dll" ComponentId="{C23E13E3-0E14-46E8-AA73-5D592CDBB725}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qico4.dll"/>
|
||||||
<ROW Component="pythoncom26.dll" ComponentId="{C0489561-2362-48C1-86E8-D5F1A08DE4DE}" Directory_="APPDIR" Attributes="0" KeyPath="pythoncom26.dll" FullKeyPath="APPDIR\pythoncom26.dll"/>
|
<ROW Component="qjpcodecs4.dll" ComponentId="{E6649370-16BB-449A-8668-9995B5C1CEB5}" Directory_="codecs_DIR" Attributes="0" KeyPath="qjpcodecs4.dll"/>
|
||||||
<ROW Component="qcncodecs4.dll" ComponentId="{03C97279-4453-48E0-A40D-D28E6F3E701F}" Directory_="codecs_DIR" Attributes="0" KeyPath="qcncodecs4.dll" FullKeyPath="APPDIR\qt4_plugins\codecs\qcncodecs4.dll"/>
|
<ROW Component="qjpeg4.dll" ComponentId="{1D084E38-4A03-4C3C-87F7-3C68FEB41B4C}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qjpeg4.dll"/>
|
||||||
<ROW Component="qgif4.dll" ComponentId="{5D6E676F-18BC-49C8-BBD2-E6BA1F3CA043}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qgif4.dll" FullKeyPath="APPDIR\qt4_plugins\imageformats\qgif4.dll"/>
|
<ROW Component="qkrcodecs4.dll" ComponentId="{18F32B38-7D3F-4F3C-AB80-3778634C8676}" Directory_="codecs_DIR" Attributes="0" KeyPath="qkrcodecs4.dll"/>
|
||||||
<ROW Component="qico4.dll" ComponentId="{C23E13E3-0E14-46E8-AA73-5D592CDBB725}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qico4.dll" FullKeyPath="APPDIR\qt4_plugins\imageformats\qico4.dll"/>
|
<ROW Component="qmng4.dll" ComponentId="{D7E0BF84-EB34-4E4B-81CD-93B47B31503C}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qmng4.dll"/>
|
||||||
<ROW Component="qjpcodecs4.dll" ComponentId="{E6649370-16BB-449A-8668-9995B5C1CEB5}" Directory_="codecs_DIR" Attributes="0" KeyPath="qjpcodecs4.dll" FullKeyPath="APPDIR\qt4_plugins\codecs\qjpcodecs4.dll"/>
|
<ROW Component="qsvg4.dll" ComponentId="{3920BD4C-9A56-4CE4-A321-E649652D3D8A}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qsvg4.dll"/>
|
||||||
<ROW Component="qjpeg4.dll" ComponentId="{1D084E38-4A03-4C3C-87F7-3C68FEB41B4C}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qjpeg4.dll" FullKeyPath="APPDIR\qt4_plugins\imageformats\qjpeg4.dll"/>
|
<ROW Component="qsvgicon4.dll" ComponentId="{F5D7A7C3-6320-4274-90DF-9F42C94FCDED}" Directory_="iconengines_DIR" Attributes="0" KeyPath="qsvgicon4.dll"/>
|
||||||
<ROW Component="qkrcodecs4.dll" ComponentId="{18F32B38-7D3F-4F3C-AB80-3778634C8676}" Directory_="codecs_DIR" Attributes="0" KeyPath="qkrcodecs4.dll" FullKeyPath="APPDIR\qt4_plugins\codecs\qkrcodecs4.dll"/>
|
<ROW Component="qtaccessiblecompatwidgets4.dll" ComponentId="{990608A3-AD85-439A-B46A-764DF560FA3A}" Directory_="accessible_DIR" Attributes="0" KeyPath="qtaccessiblecompatwidgets4.dll"/>
|
||||||
<ROW Component="qmng4.dll" ComponentId="{D7E0BF84-EB34-4E4B-81CD-93B47B31503C}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qmng4.dll" FullKeyPath="APPDIR\qt4_plugins\imageformats\qmng4.dll"/>
|
<ROW Component="qtaccessiblewidgets4.dll" ComponentId="{1F04BD2B-42BD-412D-B101-806B130CD1B8}" Directory_="accessible_DIR" Attributes="0" KeyPath="qtaccessiblewidgets4.dll"/>
|
||||||
<ROW Component="qsvg4.dll" ComponentId="{3920BD4C-9A56-4CE4-A321-E649652D3D8A}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qsvg4.dll" FullKeyPath="APPDIR\qt4_plugins\imageformats\qsvg4.dll"/>
|
<ROW Component="qtiff4.dll" ComponentId="{D5B4A7B8-7D9B-4A5C-9DD5-2048690EEE11}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qtiff4.dll"/>
|
||||||
<ROW Component="qsvgicon4.dll" ComponentId="{F5D7A7C3-6320-4274-90DF-9F42C94FCDED}" Directory_="iconengines_DIR" Attributes="0" KeyPath="qsvgicon4.dll" FullKeyPath="APPDIR\qt4_plugins\iconengines\qsvgicon4.dll"/>
|
<ROW Component="qtwcodecs4.dll" ComponentId="{E6C5E92F-D193-4A75-88E2-5058F069C224}" Directory_="codecs_DIR" Attributes="0" KeyPath="qtwcodecs4.dll"/>
|
||||||
<ROW Component="qt4_plugins" ComponentId="{5711E103-B078-4868-94BC-A50DC4CA2EE6}" Directory_="qt4_plugins_DIR" Attributes="0"/>
|
<ROW Component="updater.exe" ComponentId="{D1DDB6CB-B336-4112-BC40-1ABD36C3ABDA}" Directory_="APPDIR" Attributes="0" KeyPath="updater.exe"/>
|
||||||
<ROW Component="qtaccessiblecompatwidgets4.dll" ComponentId="{990608A3-AD85-439A-B46A-764DF560FA3A}" Directory_="accessible_DIR" Attributes="0" KeyPath="qtaccessiblecompatwidgets4.dll" FullKeyPath="APPDIR\qt4_plugins\accessible\qtaccessiblecompatwidgets4.dll"/>
|
|
||||||
<ROW Component="qtaccessiblewidgets4.dll" ComponentId="{1F04BD2B-42BD-412D-B101-806B130CD1B8}" Directory_="accessible_DIR" Attributes="0" KeyPath="qtaccessiblewidgets4.dll" FullKeyPath="APPDIR\qt4_plugins\accessible\qtaccessiblewidgets4.dll"/>
|
|
||||||
<ROW Component="qtiff4.dll" ComponentId="{D5B4A7B8-7D9B-4A5C-9DD5-2048690EEE11}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qtiff4.dll" FullKeyPath="APPDIR\qt4_plugins\imageformats\qtiff4.dll"/>
|
|
||||||
<ROW Component="qtwcodecs4.dll" ComponentId="{E6C5E92F-D193-4A75-88E2-5058F069C224}" Directory_="codecs_DIR" Attributes="0" KeyPath="qtwcodecs4.dll" FullKeyPath="APPDIR\qt4_plugins\codecs\qtwcodecs4.dll"/>
|
|
||||||
<ROW Component="updater.exe" ComponentId="{D1DDB6CB-B336-4112-BC40-1ABD36C3ABDA}" Directory_="APPDIR" Attributes="0" KeyPath="updater.exe" FullKeyPath="APPDIR\updater.exe"/>
|
|
||||||
<ROW Component="urlmon.dll" ComponentId="{BAD794CE-427A-4BB0-9C23-E4BBCDE988C3}" Directory_="APPDIR" Attributes="0" KeyPath="urlmon.dll" FullKeyPath="APPDIR\urlmon.dll"/>
|
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
|
||||||
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="updater.exe dupeGuru_ME.exe AIShRegAnswer bz2.pyd_1 iertutil.dll mfc90.dll MSVCP90.dll MSVCR90.dll POWRPROF.dll python26.dll pythoncom26.dll PyWinTypes26.dll qtaccessiblecompatwidgets4.dll qtaccessiblewidgets4.dll qcncodecs4.dll qjpcodecs4.dll qkrcodecs4.dll qtwcodecs4.dll qsvgicon4.dll qgif4.dll qico4.dll qjpeg4.dll qmng4.dll qsvg4.dll qtiff4.dll qt4_plugins QtCore4.dll QtGui4.dll SHLWAPI.dll urlmon.dll msvcm90.dll"/>
|
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="updater.exe dupeGuru_ME.exe AIShRegAnswer bz2.pyd_1 python26.dll pythoncom26.dll PyWinTypes26.dll qtaccessiblecompatwidgets4.dll qtaccessiblewidgets4.dll qcncodecs4.dll qjpcodecs4.dll qkrcodecs4.dll qtwcodecs4.dll qsvgicon4.dll qgif4.dll qico4.dll qjpeg4.dll qmng4.dll qsvg4.dll qtiff4.dll QtCore4.dll QtGui4.dll AI_ExePath credits.htm hs_title.png"/>
|
||||||
<ATTRIBUTE name="CurrentFeature" value="MainFeature"/>
|
<ATTRIBUTE name="CurrentFeature" value="MainFeature"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
|
||||||
<ROW File="MSVCP90.dll" Component_="MSVCP90.dll" FileName="MSVCP90.dll" Attributes="0" SourcePath="dist\MSVCP90.dll" SelfReg="false" Sequence="6"/>
|
<ROW File="PyQt4.QtCore.pyd" Component_="bz2.pyd_1" FileName="PyQt4Q~1.pyd|PyQt4.QtCore.pyd" Attributes="0" SourcePath="dist\PyQt4.QtCore.pyd" SelfReg="false" Sequence="5"/>
|
||||||
<ROW File="MSVCR90.dll" Component_="MSVCR90.dll" FileName="MSVCR90.dll" Attributes="0" SourcePath="dist\MSVCR90.dll" SelfReg="false" Sequence="7"/>
|
<ROW File="PyQt4.QtGui.pyd" Component_="bz2.pyd_1" FileName="PyQt4Q~2.pyd|PyQt4.QtGui.pyd" Attributes="0" SourcePath="dist\PyQt4.QtGui.pyd" SelfReg="false" Sequence="6"/>
|
||||||
<ROW File="Microsoft.VC90.CRT.manifest" Component_="bz2.pyd_1" FileName="Micros~1.man|Microsoft.VC90.CRT.manifest" Attributes="0" SourcePath="dist\Microsoft.VC90.CRT.manifest" SelfReg="false" Sequence="45"/>
|
<ROW File="PyWinTypes26.dll" Component_="PyWinTypes26.dll" FileName="PyWinT~1.dll|PyWinTypes26.dll" Attributes="0" SourcePath="dist\PyWinTypes26.dll" SelfReg="false" Sequence="9"/>
|
||||||
<ROW File="POWRPROF.dll" Component_="POWRPROF.dll" FileName="POWRPROF.dll" Attributes="0" SourcePath="dist\POWRPROF.dll" SelfReg="false" Sequence="8"/>
|
<ROW File="QtCore4.dll" Component_="QtCore4.dll" FileName="QtCore4.dll" Attributes="0" SourcePath="dist\QtCore4.dll" SelfReg="false" Sequence="23"/>
|
||||||
<ROW File="PyQt4.QtCore.pyd" Component_="bz2.pyd_1" FileName="PyQt4Q~1.pyd|PyQt4.QtCore.pyd" Attributes="0" SourcePath="dist\PyQt4.QtCore.pyd" SelfReg="false" Sequence="10"/>
|
<ROW File="QtGui4.dll" Component_="QtGui4.dll" FileName="QtGui4.dll" Attributes="0" SourcePath="dist\QtGui4.dll" SelfReg="false" Sequence="24"/>
|
||||||
<ROW File="PyQt4.QtGui.pyd" Component_="bz2.pyd_1" FileName="PyQt4Q~2.pyd|PyQt4.QtGui.pyd" Attributes="0" SourcePath="dist\PyQt4.QtGui.pyd" SelfReg="false" Sequence="11"/>
|
|
||||||
<ROW File="PyWinTypes26.dll" Component_="PyWinTypes26.dll" FileName="PyWinT~1.dll|PyWinTypes26.dll" Attributes="0" SourcePath="dist\PyWinTypes26.dll" SelfReg="false" Sequence="14"/>
|
|
||||||
<ROW File="QtCore4.dll" Component_="QtCore4.dll" FileName="QtCore4.dll" Attributes="0" SourcePath="dist\QtCore4.dll" SelfReg="false" Sequence="28"/>
|
|
||||||
<ROW File="QtGui4.dll" Component_="QtGui4.dll" FileName="QtGui4.dll" Attributes="0" SourcePath="dist\QtGui4.dll" SelfReg="false" Sequence="29"/>
|
|
||||||
<ROW File="SHLWAPI.dll" Component_="SHLWAPI.dll" FileName="SHLWAPI.dll" Attributes="0" SourcePath="dist\SHLWAPI.dll" SelfReg="false" Sequence="31"/>
|
|
||||||
<ROW File="bz2.pyd" Component_="bz2.pyd_1" FileName="bz2.pyd" Attributes="0" SourcePath="dist\bz2.pyd" SelfReg="false" Sequence="3"/>
|
<ROW File="bz2.pyd" Component_="bz2.pyd_1" FileName="bz2.pyd" Attributes="0" SourcePath="dist\bz2.pyd" SelfReg="false" Sequence="3"/>
|
||||||
<ROW File="ctypes.pyd" Component_="bz2.pyd_1" FileName="_ctypes.pyd" Attributes="0" SourcePath="dist\_ctypes.pyd" SelfReg="false" Sequence="39"/>
|
<ROW File="credits.htm" Component_="credits.htm" FileName="credits.htm" Attributes="0" SourcePath="dist\help\credits.htm" SelfReg="false" Sequence="36"/>
|
||||||
|
<ROW File="directories.htm" Component_="credits.htm" FileName="direct~1.htm|directories.htm" Attributes="0" SourcePath="dist\help\directories.htm" SelfReg="false" Sequence="37"/>
|
||||||
<ROW File="dupeGuru_ME.exe" Component_="dupeGuru_ME.exe" FileName="dupeGu~1.exe|dupeGuru ME.exe" Attributes="0" SourcePath="dist\dupeGuru ME.exe" SelfReg="false" Sequence="2"/>
|
<ROW File="dupeGuru_ME.exe" Component_="dupeGuru_ME.exe" FileName="dupeGu~1.exe|dupeGuru ME.exe" Attributes="0" SourcePath="dist\dupeGuru ME.exe" SelfReg="false" Sequence="2"/>
|
||||||
<ROW File="hashlib.pyd" Component_="bz2.pyd_1" FileName="_hashlib.pyd" Attributes="0" SourcePath="dist\_hashlib.pyd" SelfReg="false" Sequence="40"/>
|
<ROW File="faq.htm" Component_="credits.htm" FileName="faq.htm" Attributes="0" SourcePath="dist\help\faq.htm" SelfReg="false" Sequence="38"/>
|
||||||
<ROW File="iertutil.dll" Component_="iertutil.dll" FileName="iertutil.dll" Attributes="0" SourcePath="dist\iertutil.dll" SelfReg="false" Sequence="4"/>
|
<ROW File="hardcoded.css" Component_="credits.htm" FileName="hardco~1.css|hardcoded.css" Attributes="0" SourcePath="dist\help\hardcoded.css" SelfReg="false" Sequence="39"/>
|
||||||
<ROW File="mfc90.dll" Component_="mfc90.dll" FileName="mfc90.dll" Attributes="0" SourcePath="dist\mfc90.dll" SelfReg="false" Sequence="5"/>
|
<ROW File="hashlib.pyd" Component_="bz2.pyd_1" FileName="_hashlib.pyd" Attributes="0" SourcePath="dist\_hashlib.pyd" SelfReg="false" Sequence="32"/>
|
||||||
<ROW File="msvcm90.dll" Component_="msvcm90.dll" FileName="msvcm90.dll" Attributes="0" SourcePath="dist\msvcm90.dll" SelfReg="false" Sequence="46"/>
|
<ROW File="hs_title.png" Component_="hs_title.png" FileName="hs_title.png" Attributes="0" SourcePath="dist\help\images\hs_title.png" SelfReg="false" Sequence="40"/>
|
||||||
<ROW File="multiprocessing.pyd" Component_="bz2.pyd_1" FileName="_multi~1.pyd|_multiprocessing.pyd" Attributes="0" SourcePath="dist\_multiprocessing.pyd" SelfReg="false" Sequence="41"/>
|
<ROW File="intro.htm" Component_="credits.htm" FileName="intro.htm" Attributes="0" SourcePath="dist\help\intro.htm" SelfReg="false" Sequence="41"/>
|
||||||
<ROW File="pyexpat.pyd" Component_="bz2.pyd_1" FileName="pyexpat.pyd" Attributes="0" SourcePath="dist\pyexpat.pyd" SelfReg="false" Sequence="9"/>
|
<ROW File="power_marker.htm" Component_="credits.htm" FileName="power_~1.htm|power_marker.htm" Attributes="0" SourcePath="dist\help\power_marker.htm" SelfReg="false" Sequence="42"/>
|
||||||
<ROW File="python26.dll" Component_="python26.dll" FileName="python26.dll" Attributes="0" SourcePath="dist\python26.dll" SelfReg="false" Sequence="12"/>
|
<ROW File="preferences.htm" Component_="credits.htm" FileName="prefer~1.htm|preferences.htm" Attributes="0" SourcePath="dist\help\preferences.htm" SelfReg="false" Sequence="43"/>
|
||||||
<ROW File="pythoncom26.dll" Component_="pythoncom26.dll" FileName="python~1.dll|pythoncom26.dll" Attributes="0" SourcePath="dist\pythoncom26.dll" SelfReg="false" Sequence="13"/>
|
<ROW File="pyexpat.pyd" Component_="bz2.pyd_1" FileName="pyexpat.pyd" Attributes="0" SourcePath="dist\pyexpat.pyd" SelfReg="false" Sequence="4"/>
|
||||||
<ROW File="qcncodecs4.dll" Component_="qcncodecs4.dll" FileName="qcncod~1.dll|qcncodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qcncodecs4.dll" SelfReg="false" Sequence="17"/>
|
<ROW File="python26.dll" Component_="python26.dll" FileName="python26.dll" Attributes="0" SourcePath="dist\python26.dll" SelfReg="false" Sequence="7"/>
|
||||||
<ROW File="qgif4.dll" Component_="qgif4.dll" FileName="qgif4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qgif4.dll" SelfReg="false" Sequence="22"/>
|
<ROW File="pythoncom26.dll" Component_="pythoncom26.dll" FileName="python~1.dll|pythoncom26.dll" Attributes="0" SourcePath="dist\pythoncom26.dll" SelfReg="false" Sequence="8"/>
|
||||||
<ROW File="qico4.dll" Component_="qico4.dll" FileName="qico4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qico4.dll" SelfReg="false" Sequence="23"/>
|
<ROW File="qcncodecs4.dll" Component_="qcncodecs4.dll" FileName="qcncod~1.dll|qcncodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qcncodecs4.dll" SelfReg="false" Sequence="12"/>
|
||||||
<ROW File="qjpcodecs4.dll" Component_="qjpcodecs4.dll" FileName="qjpcod~1.dll|qjpcodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qjpcodecs4.dll" SelfReg="false" Sequence="18"/>
|
<ROW File="qgif4.dll" Component_="qgif4.dll" FileName="qgif4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qgif4.dll" SelfReg="false" Sequence="17"/>
|
||||||
<ROW File="qjpeg4.dll" Component_="qjpeg4.dll" FileName="qjpeg4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qjpeg4.dll" SelfReg="false" Sequence="24"/>
|
<ROW File="qico4.dll" Component_="qico4.dll" FileName="qico4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qico4.dll" SelfReg="false" Sequence="18"/>
|
||||||
<ROW File="qkrcodecs4.dll" Component_="qkrcodecs4.dll" FileName="qkrcod~1.dll|qkrcodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qkrcodecs4.dll" SelfReg="false" Sequence="19"/>
|
<ROW File="qjpcodecs4.dll" Component_="qjpcodecs4.dll" FileName="qjpcod~1.dll|qjpcodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qjpcodecs4.dll" SelfReg="false" Sequence="13"/>
|
||||||
<ROW File="qmng4.dll" Component_="qmng4.dll" FileName="qmng4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qmng4.dll" SelfReg="false" Sequence="25"/>
|
<ROW File="qjpeg4.dll" Component_="qjpeg4.dll" FileName="qjpeg4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qjpeg4.dll" SelfReg="false" Sequence="19"/>
|
||||||
<ROW File="qsvg4.dll" Component_="qsvg4.dll" FileName="qsvg4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qsvg4.dll" SelfReg="false" Sequence="26"/>
|
<ROW File="qkrcodecs4.dll" Component_="qkrcodecs4.dll" FileName="qkrcod~1.dll|qkrcodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qkrcodecs4.dll" SelfReg="false" Sequence="14"/>
|
||||||
<ROW File="qsvgicon4.dll" Component_="qsvgicon4.dll" FileName="qsvgic~1.dll|qsvgicon4.dll" Attributes="0" SourcePath="dist\qt4_plugins\iconengines\qsvgicon4.dll" SelfReg="false" Sequence="21"/>
|
<ROW File="qmng4.dll" Component_="qmng4.dll" FileName="qmng4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qmng4.dll" SelfReg="false" Sequence="20"/>
|
||||||
<ROW File="qtaccessiblecompatwidgets4.dll" Component_="qtaccessiblecompatwidgets4.dll" FileName="qtacce~1.dll|qtaccessiblecompatwidgets4.dll" Attributes="0" SourcePath="dist\qt4_plugins\accessible\qtaccessiblecompatwidgets4.dll" SelfReg="false" Sequence="15"/>
|
<ROW File="qsvg4.dll" Component_="qsvg4.dll" FileName="qsvg4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qsvg4.dll" SelfReg="false" Sequence="21"/>
|
||||||
<ROW File="qtaccessiblewidgets4.dll" Component_="qtaccessiblewidgets4.dll" FileName="qtacce~2.dll|qtaccessiblewidgets4.dll" Attributes="0" SourcePath="dist\qt4_plugins\accessible\qtaccessiblewidgets4.dll" SelfReg="false" Sequence="16"/>
|
<ROW File="qsvgicon4.dll" Component_="qsvgicon4.dll" FileName="qsvgic~1.dll|qsvgicon4.dll" Attributes="0" SourcePath="dist\qt4_plugins\iconengines\qsvgicon4.dll" SelfReg="false" Sequence="16"/>
|
||||||
<ROW File="qtiff4.dll" Component_="qtiff4.dll" FileName="qtiff4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qtiff4.dll" SelfReg="false" Sequence="27"/>
|
<ROW File="qtaccessiblecompatwidgets4.dll" Component_="qtaccessiblecompatwidgets4.dll" FileName="qtacce~1.dll|qtaccessiblecompatwidgets4.dll" Attributes="0" SourcePath="dist\qt4_plugins\accessible\qtaccessiblecompatwidgets4.dll" SelfReg="false" Sequence="10"/>
|
||||||
<ROW File="qtwcodecs4.dll" Component_="qtwcodecs4.dll" FileName="qtwcod~1.dll|qtwcodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qtwcodecs4.dll" SelfReg="false" Sequence="20"/>
|
<ROW File="qtaccessiblewidgets4.dll" Component_="qtaccessiblewidgets4.dll" FileName="qtacce~2.dll|qtaccessiblewidgets4.dll" Attributes="0" SourcePath="dist\qt4_plugins\accessible\qtaccessiblewidgets4.dll" SelfReg="false" Sequence="11"/>
|
||||||
<ROW File="select.pyd" Component_="bz2.pyd_1" FileName="select.pyd" Attributes="0" SourcePath="dist\select.pyd" SelfReg="false" Sequence="30"/>
|
<ROW File="qtiff4.dll" Component_="qtiff4.dll" FileName="qtiff4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qtiff4.dll" SelfReg="false" Sequence="22"/>
|
||||||
<ROW File="sip.pyd" Component_="bz2.pyd_1" FileName="sip.pyd" Attributes="0" SourcePath="dist\sip.pyd" SelfReg="false" Sequence="32"/>
|
<ROW File="qtwcodecs4.dll" Component_="qtwcodecs4.dll" FileName="qtwcod~1.dll|qtwcodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qtwcodecs4.dll" SelfReg="false" Sequence="15"/>
|
||||||
<ROW File="socket.pyd" Component_="bz2.pyd_1" FileName="_socket.pyd" Attributes="0" SourcePath="dist\_socket.pyd" SelfReg="false" Sequence="42"/>
|
<ROW File="quick_start.htm" Component_="credits.htm" FileName="quick_~1.htm|quick_start.htm" Attributes="0" SourcePath="dist\help\quick_start.htm" SelfReg="false" Sequence="44"/>
|
||||||
<ROW File="ssl.pyd" Component_="bz2.pyd_1" FileName="_ssl.pyd" Attributes="0" SourcePath="dist\_ssl.pyd" SelfReg="false" Sequence="43"/>
|
<ROW File="results.htm" Component_="credits.htm" FileName="results.htm" Attributes="0" SourcePath="dist\help\results.htm" SelfReg="false" Sequence="45"/>
|
||||||
<ROW File="unicodedata.pyd" Component_="bz2.pyd_1" FileName="unicod~1.pyd|unicodedata.pyd" Attributes="0" SourcePath="dist\unicodedata.pyd" SelfReg="false" Sequence="33"/>
|
<ROW File="select.pyd" Component_="bz2.pyd_1" FileName="select.pyd" Attributes="0" SourcePath="dist\select.pyd" SelfReg="false" Sequence="25"/>
|
||||||
<ROW File="updater.exe" Component_="updater.exe" FileName="updater.exe" Attributes="0" SourcePath="<updater.exe>" SelfReg="false" Sequence="1" DigSign="true"/>
|
<ROW File="sip.pyd" Component_="bz2.pyd_1" FileName="sip.pyd" Attributes="0" SourcePath="dist\sip.pyd" SelfReg="false" Sequence="26"/>
|
||||||
<ROW File="urlmon.dll" Component_="urlmon.dll" FileName="urlmon.dll" Attributes="0" SourcePath="dist\urlmon.dll" SelfReg="false" Sequence="34"/>
|
<ROW File="socket.pyd" Component_="bz2.pyd_1" FileName="_socket.pyd" Attributes="0" SourcePath="dist\_socket.pyd" SelfReg="false" Sequence="33"/>
|
||||||
<ROW File="win32api.pyd" Component_="bz2.pyd_1" FileName="win32api.pyd" Attributes="0" SourcePath="dist\win32api.pyd" SelfReg="false" Sequence="35"/>
|
<ROW File="ssl.pyd" Component_="bz2.pyd_1" FileName="_ssl.pyd" Attributes="0" SourcePath="dist\_ssl.pyd" SelfReg="false" Sequence="34"/>
|
||||||
<ROW File="win32com.shell.shell.pyd" Component_="bz2.pyd_1" FileName="win32c~1.pyd|win32com.shell.shell.pyd" Attributes="0" SourcePath="dist\win32com.shell.shell.pyd" SelfReg="false" Sequence="36"/>
|
<ROW File="unicodedata.pyd" Component_="bz2.pyd_1" FileName="unicod~1.pyd|unicodedata.pyd" Attributes="0" SourcePath="dist\unicodedata.pyd" SelfReg="false" Sequence="27"/>
|
||||||
<ROW File="win32sysloader.pyd" Component_="bz2.pyd_1" FileName="_win32~1.pyd|_win32sysloader.pyd" Attributes="0" SourcePath="dist\_win32sysloader.pyd" SelfReg="false" Sequence="44"/>
|
<ROW File="updater.exe" Component_="updater.exe" FileName="updater.exe" Attributes="0" SourcePath="<AI_HOME>updater.exe" SelfReg="false" Sequence="1" DigSign="true"/>
|
||||||
<ROW File="win32trace.pyd" Component_="bz2.pyd_1" FileName="win32t~1.pyd|win32trace.pyd" Attributes="0" SourcePath="dist\win32trace.pyd" SelfReg="false" Sequence="37"/>
|
<ROW File="versions.htm" Component_="credits.htm" FileName="versions.htm" Attributes="0" SourcePath="dist\help\versions.htm" SelfReg="false" Sequence="46"/>
|
||||||
<ROW File="win32ui.pyd" Component_="bz2.pyd_1" FileName="win32ui.pyd" Attributes="0" SourcePath="dist\win32ui.pyd" SelfReg="false" Sequence="38"/>
|
<ROW File="win32api.pyd" Component_="bz2.pyd_1" FileName="win32api.pyd" Attributes="0" SourcePath="dist\win32api.pyd" SelfReg="false" Sequence="28"/>
|
||||||
|
<ROW File="win32com.shell.shell.pyd" Component_="bz2.pyd_1" FileName="win32c~1.pyd|win32com.shell.shell.pyd" Attributes="0" SourcePath="dist\win32com.shell.shell.pyd" SelfReg="false" Sequence="29"/>
|
||||||
|
<ROW File="win32sysloader.pyd" Component_="bz2.pyd_1" FileName="_win32~1.pyd|_win32sysloader.pyd" Attributes="0" SourcePath="dist\_win32sysloader.pyd" SelfReg="false" Sequence="35"/>
|
||||||
|
<ROW File="win32trace.pyd" Component_="bz2.pyd_1" FileName="win32t~1.pyd|win32trace.pyd" Attributes="0" SourcePath="dist\win32trace.pyd" SelfReg="false" Sequence="30"/>
|
||||||
|
<ROW File="win32ui.pyd" Component_="bz2.pyd_1" FileName="win32ui.pyd" Attributes="0" SourcePath="dist\win32ui.pyd" SelfReg="false" Sequence="31"/>
|
||||||
|
</COMPONENT>
|
||||||
|
<COMPONENT cid="caphyon.advinst.msicomp.BuildComponent">
|
||||||
|
<ROW BuildKey="DefaultBuild" BuildName="DefaultBuild" BuildOrder="1" BuildType="0" PackageName="install\dupeguru_me_win_[|ProductVersion]" Languages="en" InstallationType="4" CabsLocation="1" PackageType="1" FilesInsideExe="true" CreateMd5="true" ExtractionFolder="[AppDataFolder][|Manufacturer]\[|ProductName]\install" ExtUI="true"/>
|
||||||
|
<ATTRIBUTE name="CurrentBuild" value="DefaultBuild"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.DictionaryComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.DictionaryComponent">
|
||||||
<ROW Path="<ui.ail>"/>
|
<ROW Path="<AI_DICTS>ui.ail"/>
|
||||||
<ROW Path="<ui_en.ail>"/>
|
<ROW Path="<AI_DICTS>ui_en.ail"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.FragmentComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.FragmentComponent">
|
||||||
<ROW Fragment="FolderDlg.aip" Path="<FolderDlg.aip>"/>
|
<ROW Fragment="CommonUI.aip" Path="<AI_FRAGS>CommonUI.aip"/>
|
||||||
<ROW Fragment="ShortcutsDlg.aip" Path="<ShortcutsDlg.aip>"/>
|
<ROW Fragment="FolderDlg.aip" Path="<AI_THEMES>classic\fragments\FolderDlg.aip"/>
|
||||||
<ROW Fragment="StaticUIStrings.aip" Path="<StaticUIStrings.aip>"/>
|
<ROW Fragment="SequenceDialogs.aip" Path="<AI_THEMES>classic\fragments\SequenceDialogs.aip"/>
|
||||||
<ROW Fragment="UI.aip" Path="<UI.aip>"/>
|
<ROW Fragment="Sequences.aip" Path="<AI_FRAGS>Sequences.aip"/>
|
||||||
|
<ROW Fragment="ShortcutsDlg.aip" Path="<AI_THEMES>classic\fragments\ShortcutsDlg.aip"/>
|
||||||
|
<ROW Fragment="StaticUIStrings.aip" Path="<AI_FRAGS>StaticUIStrings.aip"/>
|
||||||
|
<ROW Fragment="UI.aip" Path="<AI_THEMES>classic\fragments\UI.aip"/>
|
||||||
|
<ROW Fragment="Validation.aip" Path="<AI_FRAGS>Validation.aip"/>
|
||||||
|
</COMPONENT>
|
||||||
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiActionTextComponent">
|
||||||
|
<ROW Action="AI_DeleteLzma" Description="Deleting files extracted from archive" DescriptionLocId="ActionText.Description.AI_DeleteLzma" TemplateLocId="-"/>
|
||||||
|
<ROW Action="AI_DeleteRLzma" Description="Deleting files extracted from archive" DescriptionLocId="ActionText.Description.AI_DeleteLzma" TemplateLocId="-"/>
|
||||||
|
<ROW Action="AI_ExtractLzma" Description="Extracting files from archive" DescriptionLocId="ActionText.Description.AI_ExtractLzma" TemplateLocId="-"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiAppSearchComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiAppSearchComponent">
|
||||||
|
<ROW Property="AI_SETUPEXEPATH" Signature_="AI_EXE_PATH_CU" Builds="DefaultBuild"/>
|
||||||
|
<ROW Property="AI_SETUPEXEPATH" Signature_="AI_EXE_PATH_LM" Builds="DefaultBuild"/>
|
||||||
<ROW Property="AI_SHORTCUTSREG" Signature_="AI_ShRegOptionMachine"/>
|
<ROW Property="AI_SHORTCUTSREG" Signature_="AI_ShRegOptionMachine"/>
|
||||||
<ROW Property="AI_SHORTCUTSREG" Signature_="AI_ShRegOptionUser"/>
|
<ROW Property="AI_SHORTCUTSREG" Signature_="AI_ShRegOptionUser"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiBinaryComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiBinaryComponent">
|
||||||
<ROW Name="aicustact.dll" SourcePath="<aicustact.dll>"/>
|
<ROW Name="Prereq.dll" SourcePath="<AI_CUSTACTS>Prereq.dll"/>
|
||||||
<ROW Name="default_banner.bmp" SourcePath="<default-banner.bmp>"/>
|
<ROW Name="aicustact.dll" SourcePath="<AI_CUSTACTS>aicustact.dll"/>
|
||||||
<ROW Name="default_dialog.bmp" SourcePath="<default-dialog.bmp>"/>
|
<ROW Name="banner_image.jpg" SourcePath="<AI_THEMES>classic\resources\banner-image.jpg"/>
|
||||||
|
<ROW Name="dialog_image.jpg" SourcePath="<AI_THEMES>classic\resources\dialog-image.jpg"/>
|
||||||
|
<ROW Name="lzmaextractor.dll" SourcePath="<AI_CUSTACTS>lzmaextractor.dll"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiControlComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiControlComponent">
|
||||||
<ATTRIBUTE name="FixedSizeBitmaps" value="0"/>
|
<ATTRIBUTE name="FixedSizeBitmaps" value="0"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiControlConditionComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiControlConditionComponent">
|
||||||
<ROW Dialog_="ShortcutsDlg" Control_="QuickLaunchShorcutsCheckBox" Action="Hide" Condition="(Not Installed)"/>
|
<ROW Dialog_="ShortcutsDlg" Control_="QuickLaunchShorcutsCheckBox" Action="Hide" Condition="(Not Installed) AND (VersionNT<"601")"/>
|
||||||
<ROW Dialog_="ShortcutsDlg" Control_="StartupShorcutsCheckBox" Action="Hide" Condition="(Not Installed)"/>
|
<ROW Dialog_="ShortcutsDlg" Control_="StartupShorcutsCheckBox" Action="Hide" Condition="(Not Installed)"/>
|
||||||
<ATTRIBUTE name="DeletedRows" value="ShortcutsDlg#QuickLaunchShorcutsCheckBox#Show#(Not Installed)@ShortcutsDlg#StartupShorcutsCheckBox#Show#(Not Installed)"/>
|
<ATTRIBUTE name="DeletedRows" value="ShortcutsDlg#QuickLaunchShorcutsCheckBox#Show#(Not Installed) AND (VersionNT<"601")@ShortcutsDlg#StartupShorcutsCheckBox#Show#(Not Installed)@ShortcutsDlg#QuickLaunchShorcutsCheckBox#Show#(Not Installed)"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiControlEventComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiControlEventComponent">
|
||||||
<ROW Dialog_="FolderDlg" Control_="Back" Event="NewDialog" Argument="ShortcutsDlg" Condition="AI_INSTALL" Ordering="1"/>
|
<ROW Dialog_="FolderDlg" Control_="Back" Event="NewDialog" Argument="ShortcutsDlg" Condition="AI_INSTALL" Ordering="1"/>
|
||||||
@@ -161,15 +171,21 @@
|
|||||||
<ROW Dialog_="ShortcutsDlg" Control_="Back" Event="NewDialog" Argument="WelcomeDlg" Condition="AI_INSTALL" Ordering="1"/>
|
<ROW Dialog_="ShortcutsDlg" Control_="Back" Event="NewDialog" Argument="WelcomeDlg" Condition="AI_INSTALL" Ordering="1"/>
|
||||||
<ROW Dialog_="ShortcutsDlg" Control_="Next" Event="NewDialog" Argument="FolderDlg" Condition="AI_INSTALL" Ordering="1"/>
|
<ROW Dialog_="ShortcutsDlg" Control_="Next" Event="NewDialog" Argument="FolderDlg" Condition="AI_INSTALL" Ordering="1"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiCreateFolderComponent">
|
|
||||||
<ROW Directory_="qt4_plugins_DIR" Component_="qt4_plugins"/>
|
|
||||||
</COMPONENT>
|
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiCustActComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiCustActComponent">
|
||||||
|
<ROW Action="AI_AppSearchEx" Type="1" Source="Prereq.dll" Target="DoAppSearchEx"/>
|
||||||
<ROW Action="AI_DELETE_SHORTCUTS" Type="1" Source="aicustact.dll" Target="DeleteShortcuts"/>
|
<ROW Action="AI_DELETE_SHORTCUTS" Type="1" Source="aicustact.dll" Target="DeleteShortcuts"/>
|
||||||
<ROW Action="AI_DOWNGRADE" Type="19" Target="4010"/>
|
<ROW Action="AI_DOWNGRADE" Type="19" Target="4010"/>
|
||||||
|
<ROW Action="AI_DeleteCadLzma" Type="51" Source="AI_DeleteLzma" Target="[AI_SETUPEXEPATH]"/>
|
||||||
|
<ROW Action="AI_DeleteLzma" Type="1025" Source="lzmaextractor.dll" Target="DeleteLZMAFiles"/>
|
||||||
|
<ROW Action="AI_DeleteRCadLzma" Type="51" Source="AI_DeleteRLzma" Target="[AI_SETUPEXEPATH]"/>
|
||||||
|
<ROW Action="AI_DeleteRLzma" Type="1281" Source="lzmaextractor.dll" Target="DeleteLZMAFiles"/>
|
||||||
|
<ROW Action="AI_ExtractCadLzma" Type="51" Source="AI_ExtractLzma" Target="[AI_SETUPEXEPATH]"/>
|
||||||
|
<ROW Action="AI_ExtractLzma" Type="1025" Source="lzmaextractor.dll" Target="ExtractLZMAFiles"/>
|
||||||
|
<ROW Action="AI_FindExeLzma" Type="1" Source="lzmaextractor.dll" Target="FindEXE"/>
|
||||||
<ROW Action="AI_LaunchApp" Type="1" Source="aicustact.dll" Target="[#dupeGuru_ME.exe]"/>
|
<ROW Action="AI_LaunchApp" Type="1" Source="aicustact.dll" Target="[#dupeGuru_ME.exe]"/>
|
||||||
<ROW Action="AI_PREPARE_UPGRADE" Type="1" Source="aicustact.dll" Target="PrepareUpgrade"/>
|
<ROW Action="AI_PREPARE_UPGRADE" Type="65" Source="aicustact.dll" Target="PrepareUpgrade"/>
|
||||||
<ROW Action="AI_RESTORE_LOCATION" Type="1" Source="aicustact.dll" Target="RestoreLocation"/>
|
<ROW Action="AI_RESTORE_LOCATION" Type="65" Source="aicustact.dll" Target="RestoreLocation"/>
|
||||||
|
<ROW Action="AI_ResolveKnownFolders" Type="1" Source="aicustact.dll" Target="AI_ResolveKnownFolders"/>
|
||||||
<ROW Action="AI_STORE_LOCATION" Type="51" Source="ARPINSTALLLOCATION" Target="[APPDIR]"/>
|
<ROW Action="AI_STORE_LOCATION" Type="51" Source="ARPINSTALLLOCATION" Target="[APPDIR]"/>
|
||||||
<ROW Action="AI_UPDATER_UNINSTALL" Type="18" Source="updater.exe" Target="/clean silent"/>
|
<ROW Action="AI_UPDATER_UNINSTALL" Type="18" Source="updater.exe" Target="/clean silent"/>
|
||||||
<ROW Action="SET_APPDIR" Type="307" Source="APPDIR" Target="[ProgramFilesFolder][Manufacturer]\[ProductName]"/>
|
<ROW Action="SET_APPDIR" Type="307" Source="APPDIR" Target="[ProgramFilesFolder][Manufacturer]\[ProductName]"/>
|
||||||
@@ -177,7 +193,7 @@
|
|||||||
<ROW Action="SET_TARGETDIR_TO_APPDIR" Type="51" Source="TARGETDIR" Target="[APPDIR]"/>
|
<ROW Action="SET_TARGETDIR_TO_APPDIR" Type="51" Source="TARGETDIR" Target="[APPDIR]"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiIconsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiIconsComponent">
|
||||||
<ROW Name="SystemFolder_msiexec.exe" SourcePath="<uninstall.ico>" Index="0"/>
|
<ROW Name="SystemFolder_msiexec.exe" SourcePath="<AI_RES>uninstall.ico" Index="0"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiIniFileComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiIniFileComponent">
|
||||||
<ROW IniFile="AppDir" FileName="updater.ini" DirProperty="APPDIR" Section="General" Key="AppDir" Value="[APPDIR]" Action="0" Component_="updater.exe"/>
|
<ROW IniFile="AppDir" FileName="updater.ini" DirProperty="APPDIR" Section="General" Key="AppDir" Value="[APPDIR]" Action="0" Component_="updater.exe"/>
|
||||||
@@ -193,31 +209,36 @@
|
|||||||
<ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=""" Sequence="740"/>
|
<ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=""" Sequence="740"/>
|
||||||
<ROW Action="AI_STORE_LOCATION" Condition="Not Installed" Sequence="1545"/>
|
<ROW Action="AI_STORE_LOCATION" Condition="Not Installed" Sequence="1545"/>
|
||||||
<ROW Action="AI_PREPARE_UPGRADE" Condition="AI_UPGRADE="No" AND (Not Installed)" Sequence="1300"/>
|
<ROW Action="AI_PREPARE_UPGRADE" Condition="AI_UPGRADE="No" AND (Not Installed)" Sequence="1300"/>
|
||||||
<ROW Action="AI_UPDATER_UNINSTALL" Condition="($updater.exe = 2) AND (?updater.exe = 3) AND NOT (UPGRADINGPRODUCTCODE)" Sequence="1549"/>
|
<ROW Action="AI_UPDATER_UNINSTALL" Condition="($updater.exe = 2) AND (?updater.exe = 3) AND NOT (UPGRADINGPRODUCTCODE)" Sequence="1547"/>
|
||||||
<ROW Action="AI_DELETE_SHORTCUTS" Condition="NOT (REMOVE="ALL")" Sequence="1449"/>
|
<ROW Action="AI_DELETE_SHORTCUTS" Condition="NOT (REMOVE="ALL")" Sequence="1449"/>
|
||||||
|
<ROW Action="AI_AppSearchEx" Sequence="101"/>
|
||||||
|
<ROW Action="AI_DeleteCadLzma" Condition="SETUPEXEDIR="" AND Installed AND (REMOVE<>"ALL") AND (NOT PATCH)" Sequence="199" Builds="DefaultBuild"/>
|
||||||
|
<ROW Action="AI_DeleteRCadLzma" Condition="SETUPEXEDIR="" AND Installed AND (REMOVE<>"ALL") AND (NOT PATCH)" Sequence="198" Builds="DefaultBuild"/>
|
||||||
|
<ROW Action="AI_ExtractCadLzma" Condition="SETUPEXEDIR="" AND Installed AND (REMOVE<>"ALL") AND (NOT PATCH)" Sequence="197" Builds="DefaultBuild"/>
|
||||||
|
<ROW Action="AI_FindExeLzma" Condition="SETUPEXEDIR="" AND Installed AND (REMOVE<>"ALL") AND (NOT PATCH)" Sequence="196" Builds="DefaultBuild"/>
|
||||||
|
<ROW Action="AI_ExtractLzma" Condition="SETUPEXEDIR="" AND Installed AND (REMOVE<>"ALL") AND (NOT PATCH)" Sequence="1549" Builds="DefaultBuild"/>
|
||||||
|
<ROW Action="AI_DeleteRLzma" Condition="SETUPEXEDIR="" AND Installed AND (REMOVE<>"ALL") AND (NOT PATCH)" Sequence="1548" Builds="DefaultBuild"/>
|
||||||
|
<ROW Action="AI_DeleteLzma" Condition="SETUPEXEDIR="" AND Installed AND (REMOVE<>"ALL") AND (NOT PATCH)" Sequence="6599" Builds="DefaultBuild"/>
|
||||||
|
<ROW Action="AI_ResolveKnownFolders" Sequence="51"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent">
|
||||||
<ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=""" Sequence="740"/>
|
<ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=""" Sequence="740"/>
|
||||||
|
<ROW Action="AI_AppSearchEx" Sequence="101"/>
|
||||||
|
<ROW Action="AI_ResolveKnownFolders" Sequence="51"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiLaunchConditionsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiLaunchConditionsComponent">
|
||||||
<ROW Condition="Version9X OR VersionNT64 OR (VersionNT >= 500 )" Description="[ProductName] can not be installed on systems earlier than [WindowsTypeNT]"/>
|
<ROW Condition="Version9X OR VersionNT64 OR (VersionNT >= 500 )" Description="[ProductName] cannot be installed on systems earlier than [WindowsTypeNT]" DescriptionLocId="AI.LaunchCondition.NoSpecificNT" IsPredefined="true" Builds="DefaultBuild"/>
|
||||||
<ROW Condition="VersionNT" Description="[ProductName] can not be installed on [WindowsFamily9X]"/>
|
<ROW Condition="VersionNT" Description="[ProductName] cannot be installed on [WindowsFamily9X]" DescriptionLocId="AI.LaunchCondition.No9X" IsPredefined="true" Builds="DefaultBuild"/>
|
||||||
</COMPONENT>
|
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiMediaComponent">
|
|
||||||
<ATTRIBUTE name="CabsLocation" value="1"/>
|
|
||||||
<ATTRIBUTE name="Compress" value="1"/>
|
|
||||||
<ATTRIBUTE name="CreateMd5" value="true"/>
|
|
||||||
<ATTRIBUTE name="InstallationType" value="4"/>
|
|
||||||
<ATTRIBUTE name="Package" value="6"/>
|
|
||||||
<ATTRIBUTE name="PackageName" value="install\dupeguru_me_win_[|ProductVersion]"/>
|
|
||||||
<ATTRIBUTE name="UseLargeSchema" value="true"/>
|
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiRegLocatorComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiRegLocatorComponent">
|
||||||
|
<ROW Signature_="AI_EXE_PATH_CU" Root="1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Type="2"/>
|
||||||
|
<ROW Signature_="AI_EXE_PATH_LM" Root="2" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Type="2"/>
|
||||||
<ROW Signature_="AI_ShRegOptionMachine" Root="2" Key="Software\Caphyon\Advanced Installer\Installs\[ProductCode]" Name="AIShRegAnswer" Type="2"/>
|
<ROW Signature_="AI_ShRegOptionMachine" Root="2" Key="Software\Caphyon\Advanced Installer\Installs\[ProductCode]" Name="AIShRegAnswer" Type="2"/>
|
||||||
<ROW Signature_="AI_ShRegOptionUser" Root="1" Key="Software\Caphyon\Advanced Installer\Installs\[ProductCode]" Name="AIShRegAnswer" Type="2"/>
|
<ROW Signature_="AI_ShRegOptionUser" Root="1" Key="Software\Caphyon\Advanced Installer\Installs\[ProductCode]" Name="AIShRegAnswer" Type="2"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiRegsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiRegsComponent">
|
||||||
<ROW Registry="AIShRegAnswer" Root="-1" Key="Software\Caphyon\Advanced Installer\Installs\[ProductCode]" Name="AIShRegAnswer" Value="[AI_SHORTCUTSREG]" Component_="AIShRegAnswer"/>
|
<ROW Registry="AIShRegAnswer" Root="-1" Key="Software\Caphyon\Advanced Installer\Installs\[ProductCode]" Name="AIShRegAnswer" Value="[AI_SHORTCUTSREG]" Component_="AIShRegAnswer"/>
|
||||||
|
<ROW Registry="AI_ExePath" Root="-1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Value="[AI_SETUPEXEPATH]" Component_="AI_ExePath"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiShortsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiShortsComponent">
|
||||||
<ROW Shortcut="Check_for_update" Directory_="SHORTCUTDIR" Name="Checkf~2|Check for update" Component_="updater.exe" Target="[#updater.exe]" Arguments="/checknow" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
<ROW Shortcut="Check_for_update" Directory_="SHORTCUTDIR" Name="Checkf~2|Check for update" Component_="updater.exe" Target="[#updater.exe]" Arguments="/checknow" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
||||||
@@ -225,19 +246,22 @@
|
|||||||
<ROW Shortcut="dupeGuru_ME" Directory_="SHORTCUTDIR" Name="dupeGu~1|dupeGuru ME" Component_="dupeGuru_ME.exe" Target="[#dupeGuru_ME.exe]" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
<ROW Shortcut="dupeGuru_ME" Directory_="SHORTCUTDIR" Name="dupeGu~1|dupeGuru ME" Component_="dupeGuru_ME.exe" Target="[#dupeGuru_ME.exe]" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
||||||
<ROW Shortcut="dupeGuru_ME_1" Directory_="DesktopFolder" Name="dupeGu~1|dupeGuru ME" Component_="dupeGuru_ME.exe" Target="[#dupeGuru_ME.exe]" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
<ROW Shortcut="dupeGuru_ME_1" Directory_="DesktopFolder" Name="dupeGu~1|dupeGuru ME" Component_="dupeGuru_ME.exe" Target="[#dupeGuru_ME.exe]" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiThemeComponent">
|
||||||
|
<ATTRIBUTE name="UsedTheme" value="classic"/>
|
||||||
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiUpgradeComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiUpgradeComponent">
|
||||||
<ROW UpgradeCode="[|UpgradeCode]" VersionMax="[|ProductVersion]" Attributes="1025" ActionProperty="OLDPRODUCTS"/>
|
<ROW UpgradeCode="[|UpgradeCode]" VersionMax="[|ProductVersion]" Attributes="1025" ActionProperty="OLDPRODUCTS"/>
|
||||||
<ROW UpgradeCode="[|UpgradeCode]" VersionMin="[|ProductVersion]" Attributes="2" ActionProperty="AI_NEWERPRODUCTFOUND"/>
|
<ROW UpgradeCode="[|UpgradeCode]" VersionMin="[|ProductVersion]" Attributes="2" ActionProperty="AI_NEWERPRODUCTFOUND"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.PreReqComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.PreReqComponent">
|
||||||
<ROW PrereqKey="0" DisplayName="Visual C++ 2008 SP1 Redistributable" SetupFileUrl="http://download.hardcoded.net/vcredist_90sp1_x86.exe" Location="1" ExactSize="4216840" MinWin9xVer="37" MinWinNTVer="17" Operator="1" ComLine="/q" Sequence="1" MD5="5689d43c3b201dd3810fa3bba4a6476a"/>
|
<ROW PrereqKey="0" DisplayName="Visual C++ 2008 SP1 Redistributable" SetupFileUrl="http://download.hardcoded.net/vcredist_90sp1_x86.exe" Location="1" ExactSize="4216840" MinWin9xVer="37" MinWinNTVer="17" Operator="1" ComLine="/q" MD5="5689d43c3b201dd3810fa3bba4a6476a"/>
|
||||||
<ATTRIBUTE name="ExtractionFolder" value="[AppDataFolder][|Manufacturer]\[|ProductName]\install"/>
|
<ATTRIBUTE name="PrereqsOrder" value="0"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.PreReqSearchComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.PreReqSearchComponent">
|
||||||
<ROW Prereq="0" SearchType="9" SearchString="HKLM\SOFTWARE\Microsoft\DevDiv\VC\Servicing\9.0\RED\1033\SP" RefContent="M1" Order="1"/>
|
<ROW SearchKey="SP" Prereq="0" SearchType="9" SearchString="HKLM\SOFTWARE\Microsoft\DevDiv\VC\Servicing\9.0\RED\1033\SP" RefContent="M1" Order="1" Property="PreReqSearch"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.SynchronizedFolderComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.SynchronizedFolderComponent">
|
||||||
<ROW Directory_="APPDIR" SourcePath="dist" ExcludePattern="*~|#*#|%*%|._|CVS|.cvsignore|SCCS|vssver.scc|mssccprj.scc|vssver2.scc|.svn|.DS_Store|*.pdb|*.vshost.*" ExcludeFlags="6"/>
|
<ROW Directory_="APPDIR" SourcePath="dist" Feature="MainFeature" ExcludePattern="*~|#*#|%*%|._|CVS|.cvsignore|SCCS|vssver.scc|mssccprj.scc|vssver2.scc|.svn|.DS_Store|*.pdb|*.vshost.*" ExcludeFlags="6"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.UpdaterComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.UpdaterComponent">
|
||||||
<ROW Updater="updater.exe" URL="URL" SearchFreq="CheckFrequency" DownloadsFolder="DownloadsFolder" ID="ID" TargetDir="AppDir" AppName="ApplicationName" CompanyName="CompanyName" UnistallCASeq="AI_UPDATER_UNINSTALL"/>
|
<ROW Updater="updater.exe" URL="URL" SearchFreq="CheckFrequency" DownloadsFolder="DownloadsFolder" ID="ID" TargetDir="AppDir" AppName="ApplicationName" CompanyName="CompanyName" UnistallCASeq="AI_UPDATER_UNINSTALL"/>
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
VSVersionInfo(
|
|
||||||
ffi=FixedFileInfo(
|
|
||||||
filevers=($versioncomma),
|
|
||||||
prodvers=($versioncomma),
|
|
||||||
mask=0x17,
|
|
||||||
flags=0x0,
|
|
||||||
OS=0x4,
|
|
||||||
fileType=0x1,
|
|
||||||
subtype=0x0,
|
|
||||||
date=(0, 0)
|
|
||||||
),
|
|
||||||
kids=[
|
|
||||||
StringFileInfo(
|
|
||||||
[
|
|
||||||
StringTable(
|
|
||||||
'040904b0',
|
|
||||||
[StringStruct('CompanyName', 'Hardcoded Software'),
|
|
||||||
StringStruct('FileDescription', 'dupeGuru Music Edition'),
|
|
||||||
StringStruct('FileVersion', '$version'),
|
|
||||||
StringStruct('InternalName', 'dupeGuru ME.exe'),
|
|
||||||
StringStruct('LegalCopyright', '(c) Hardcoded Software. All rights reserved.'),
|
|
||||||
StringStruct('OriginalFilename', 'dupeGuru ME.exe'),
|
|
||||||
StringStruct('ProductName', 'dupeGuru Music Edition'),
|
|
||||||
StringStruct('ProductVersion', '$versioncomma')])
|
|
||||||
]),
|
|
||||||
VarFileInfo([VarStruct('Translation', [1033])])
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@@ -54,9 +54,10 @@ class File(fs.File):
|
|||||||
|
|
||||||
|
|
||||||
class DupeGuru(DupeGuruBase):
|
class DupeGuru(DupeGuruBase):
|
||||||
|
EDITION = 'pe'
|
||||||
LOGO_NAME = 'logo_pe'
|
LOGO_NAME = 'logo_pe'
|
||||||
NAME = 'dupeGuru Picture Edition'
|
NAME = 'dupeGuru Picture Edition'
|
||||||
VERSION = '1.8.2'
|
VERSION = '1.8.6'
|
||||||
DELTA_COLUMNS = frozenset([2, 5, 6])
|
DELTA_COLUMNS = frozenset([2, 5, 6])
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -85,7 +85,7 @@
|
|||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>16777215</width>
|
<width>16777215</width>
|
||||||
<height>188</height>
|
<height>190</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="alternatingRowColors">
|
<property name="alternatingRowColors">
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
a = Analysis([os.path.join(HOMEPATH,'support\\_mountzlib.py'), os.path.join(HOMEPATH,'support\\useUnicode.py'), 'start.py'],
|
|
||||||
pathex=[])
|
|
||||||
pyz = PYZ(a.pure)
|
|
||||||
exe = EXE(pyz,
|
|
||||||
a.scripts,
|
|
||||||
exclude_binaries=1,
|
|
||||||
name=os.path.join('build\\pyi.win32\\dupeGuru PE', 'dupeGuru PE.exe'),
|
|
||||||
debug=False,
|
|
||||||
strip=False,
|
|
||||||
upx=True,
|
|
||||||
console=False , icon='..\\..\\images\\dgpe_logo.ico', version='verinfo_tmp')
|
|
||||||
coll = COLLECT( exe,
|
|
||||||
a.binaries,
|
|
||||||
a.zipfiles,
|
|
||||||
a.datas,
|
|
||||||
strip=False,
|
|
||||||
upx=True,
|
|
||||||
name=os.path.join('dist'))
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<DOCUMENT type="Advanced Installer" CreateVersion="4.7.2" version="7.5" modules="professional" RootPath="." Language="en">
|
<DOCUMENT type="Advanced Installer" CreateVersion="4.7.2" version="7.5.2" modules="professional" RootPath="." Language="en">
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">
|
||||||
<ROW Property="AI_FINDEXE_TITLE" Value="Select the installation package for [|ProductName]" ValueLocId="AI.Property.FindExeTitle"/>
|
<ROW Property="AI_FINDEXE_TITLE" Value="Select the installation package for [|ProductName]" ValueLocId="AI.Property.FindExeTitle"/>
|
||||||
<ROW Property="AI_SHORTCUTSREG" Value="0|0|0|"/>
|
<ROW Property="AI_SHORTCUTSREG" Value="0|0|0|"/>
|
||||||
@@ -28,110 +28,65 @@
|
|||||||
<ROW Directory="DesktopFolder" Directory_Parent="TARGETDIR" DefaultDir="Deskto~1|DesktopFolder" IsPseudoRoot="1"/>
|
<ROW Directory="DesktopFolder" Directory_Parent="TARGETDIR" DefaultDir="Deskto~1|DesktopFolder" IsPseudoRoot="1"/>
|
||||||
<ROW Directory="SHORTCUTDIR" Directory_Parent="TARGETDIR" DefaultDir="SHORTC~1|SHORTCUTDIR" IsPseudoRoot="1"/>
|
<ROW Directory="SHORTCUTDIR" Directory_Parent="TARGETDIR" DefaultDir="SHORTC~1|SHORTCUTDIR" IsPseudoRoot="1"/>
|
||||||
<ROW Directory="TARGETDIR" DefaultDir="SourceDir"/>
|
<ROW Directory="TARGETDIR" DefaultDir="SourceDir"/>
|
||||||
<ROW Directory="accessible_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="access~1|accessible"/>
|
|
||||||
<ROW Directory="codecs_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="codecs"/>
|
|
||||||
<ROW Directory="gen_py_DIR" Directory_Parent="support_DIR" DefaultDir="gen_py"/>
|
|
||||||
<ROW Directory="help_DIR" Directory_Parent="APPDIR" DefaultDir="help"/>
|
<ROW Directory="help_DIR" Directory_Parent="APPDIR" DefaultDir="help"/>
|
||||||
<ROW Directory="iconengines_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="iconen~1|iconengines"/>
|
|
||||||
<ROW Directory="imageformats_DIR" Directory_Parent="qt4_plugins_DIR" DefaultDir="imagef~1|imageformats"/>
|
|
||||||
<ROW Directory="images_DIR" Directory_Parent="help_DIR" DefaultDir="images"/>
|
<ROW Directory="images_DIR" Directory_Parent="help_DIR" DefaultDir="images"/>
|
||||||
<ROW Directory="qt4_plugins_DIR" Directory_Parent="APPDIR" DefaultDir="qt4_pl~1|qt4_plugins"/>
|
|
||||||
<ROW Directory="support_DIR" Directory_Parent="APPDIR" DefaultDir="support"/>
|
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
|
||||||
<ROW Component="AIShRegAnswer" ComponentId="{F315B3C7-7C86-41EB-BE7D-2A6A8E3073B4}" Directory_="APPDIR" Attributes="4" KeyPath="AIShRegAnswer"/>
|
<ROW Component="AIShRegAnswer" ComponentId="{F315B3C7-7C86-41EB-BE7D-2A6A8E3073B4}" Directory_="APPDIR" Attributes="4" KeyPath="AIShRegAnswer"/>
|
||||||
<ROW Component="AI_ExePath" ComponentId="{8D009995-D5B9-4E68-A969-45A06F69ACB8}" Directory_="APPDIR" Attributes="4" KeyPath="AI_ExePath"/>
|
<ROW Component="AI_ExePath" ComponentId="{8D009995-D5B9-4E68-A969-45A06F69ACB8}" Directory_="APPDIR" Attributes="4" KeyPath="AI_ExePath"/>
|
||||||
<ROW Component="POWRPROF.dll" ComponentId="{65828A9D-101E-433C-82E5-11290FDB7054}" Directory_="APPDIR" Attributes="0" KeyPath="POWRPROF.dll"/>
|
<ROW Component="CurrentVersion" ComponentId="{1A0BFEFD-F9D9-4861-93AC-D9717B7A635E}" Directory_="APPDIR" Attributes="4" KeyPath="CurrentVersion"/>
|
||||||
<ROW Component="PyWinTypes26.dll" ComponentId="{51E80B3A-C753-48CB-B7A4-65610CC49E1F}" Directory_="APPDIR" Attributes="0" KeyPath="PyWinTypes26.dll"/>
|
|
||||||
<ROW Component="QtCore4.dll" ComponentId="{5BB6B87D-BE40-4240-B529-23A303942E18}" Directory_="APPDIR" Attributes="0" KeyPath="QtCore4.dll"/>
|
<ROW Component="QtCore4.dll" ComponentId="{5BB6B87D-BE40-4240-B529-23A303942E18}" Directory_="APPDIR" Attributes="0" KeyPath="QtCore4.dll"/>
|
||||||
<ROW Component="QtGui4.dll" ComponentId="{EF519048-F252-4FA0-9875-A6B45C7F3020}" Directory_="APPDIR" Attributes="0" KeyPath="QtGui4.dll"/>
|
<ROW Component="QtGui4.dll" ComponentId="{EF519048-F252-4FA0-9875-A6B45C7F3020}" Directory_="APPDIR" Attributes="0" KeyPath="QtGui4.dll"/>
|
||||||
<ROW Component="SHLWAPI.dll" ComponentId="{11CA10DE-F6AF-4EC7-B5B9-EE1E9D08A7B0}" Directory_="APPDIR" Attributes="0" KeyPath="SHLWAPI.dll"/>
|
|
||||||
<ROW Component="SHORTCUTDIR" ComponentId="{29E7E841-7820-418B-8542-7F8CCC9777A8}" Directory_="SHORTCUTDIR" Attributes="0"/>
|
<ROW Component="SHORTCUTDIR" ComponentId="{29E7E841-7820-418B-8542-7F8CCC9777A8}" Directory_="SHORTCUTDIR" Attributes="0"/>
|
||||||
<ROW Component="bz2.pyd" ComponentId="{F7FDAE87-233A-45B0-8976-021B8264E176}" Directory_="APPDIR" Attributes="0" KeyPath="bz2.pyd" Type="0"/>
|
<ROW Component="bz2.pyd" ComponentId="{F7FDAE87-233A-45B0-8976-021B8264E176}" Directory_="APPDIR" Attributes="0" KeyPath="bz2.pyd" Type="0"/>
|
||||||
<ROW Component="credits.htm" ComponentId="{CF738E4F-8E05-4B2D-99FD-A035FC25D710}" Directory_="help_DIR" Attributes="0" KeyPath="credits.htm" Type="0"/>
|
<ROW Component="credits.htm" ComponentId="{CF738E4F-8E05-4B2D-99FD-A035FC25D710}" Directory_="help_DIR" Attributes="0" KeyPath="credits.htm" Type="0"/>
|
||||||
<ROW Component="dupeGuru_PE.exe" ComponentId="{4A31F2AE-F42E-4B0F-BC4D-A09F312D469B}" Directory_="APPDIR" Attributes="0" KeyPath="dupeGuru_PE.exe"/>
|
<ROW Component="dupeGuru_PE.exe" ComponentId="{4A31F2AE-F42E-4B0F-BC4D-A09F312D469B}" Directory_="APPDIR" Attributes="0" KeyPath="dupeGuru_PE.exe"/>
|
||||||
<ROW Component="hs_title.png" ComponentId="{ACCD16EE-68BE-4EDA-AE6B-013621EAB3B2}" Directory_="images_DIR" Attributes="0" KeyPath="hs_title.png" Type="0"/>
|
<ROW Component="hs_title.png" ComponentId="{ACCD16EE-68BE-4EDA-AE6B-013621EAB3B2}" Directory_="images_DIR" Attributes="0" KeyPath="hs_title.png" Type="0"/>
|
||||||
<ROW Component="init_.py" ComponentId="{DBD0E45F-6773-431E-A716-5518A0B8C54E}" Directory_="gen_py_DIR" Attributes="0" KeyPath="init_.py" Type="0"/>
|
|
||||||
<ROW Component="python26.dll" ComponentId="{20529423-B717-4C53-AE3A-B82E53207A62}" Directory_="APPDIR" Attributes="0" KeyPath="python26.dll"/>
|
<ROW Component="python26.dll" ComponentId="{20529423-B717-4C53-AE3A-B82E53207A62}" Directory_="APPDIR" Attributes="0" KeyPath="python26.dll"/>
|
||||||
<ROW Component="pythoncom26.dll" ComponentId="{46CE0516-582F-44F0-86D7-7F2F5F7458C3}" Directory_="APPDIR" Attributes="0" KeyPath="pythoncom26.dll"/>
|
|
||||||
<ROW Component="qcncodecs4.dll" ComponentId="{629EB310-99C7-4304-91DB-9134E521A83F}" Directory_="codecs_DIR" Attributes="0" KeyPath="qcncodecs4.dll"/>
|
|
||||||
<ROW Component="qgif4.dll" ComponentId="{788DB84F-6216-4334-B92E-9992FD02A31A}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qgif4.dll"/>
|
|
||||||
<ROW Component="qico4.dll" ComponentId="{CED777C8-E8F6-421F-B533-91A7B5310BCF}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qico4.dll"/>
|
|
||||||
<ROW Component="qjpcodecs4.dll" ComponentId="{9A112855-BA4A-4C41-BCA0-20D564A2A7C2}" Directory_="codecs_DIR" Attributes="0" KeyPath="qjpcodecs4.dll"/>
|
|
||||||
<ROW Component="qjpeg4.dll" ComponentId="{0FC6A53E-6DDC-4833-944B-00944A45FB62}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qjpeg4.dll"/>
|
|
||||||
<ROW Component="qkrcodecs4.dll" ComponentId="{5EE53027-96D1-4ABA-A2F6-507A7D85EA44}" Directory_="codecs_DIR" Attributes="0" KeyPath="qkrcodecs4.dll"/>
|
|
||||||
<ROW Component="qmng4.dll" ComponentId="{5E3A9C7B-F545-4EF5-B083-2A29E54784BE}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qmng4.dll"/>
|
|
||||||
<ROW Component="qsvg4.dll" ComponentId="{590998F6-2A55-48DC-A83A-AABC75EF7F99}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qsvg4.dll"/>
|
|
||||||
<ROW Component="qsvgicon4.dll" ComponentId="{0440300E-1BAE-49C5-8575-AF43C2557271}" Directory_="iconengines_DIR" Attributes="0" KeyPath="qsvgicon4.dll"/>
|
|
||||||
<ROW Component="qtaccessiblecompatwidgets4.dll" ComponentId="{217EE5AA-868E-4DDA-B374-E1007D54C1CF}" Directory_="accessible_DIR" Attributes="0" KeyPath="qtaccessiblecompatwidgets4.dll"/>
|
|
||||||
<ROW Component="qtaccessiblewidgets4.dll" ComponentId="{74F17E1E-D2BC-4C85-A5B9-A093D4AFC840}" Directory_="accessible_DIR" Attributes="0" KeyPath="qtaccessiblewidgets4.dll"/>
|
|
||||||
<ROW Component="qtiff4.dll" ComponentId="{545FB567-9E3A-4E44-85A0-74446ABB8FC8}" Directory_="imageformats_DIR" Attributes="0" KeyPath="qtiff4.dll"/>
|
|
||||||
<ROW Component="qtwcodecs4.dll" ComponentId="{59FB6978-93A0-4DD6-A617-FE6460CDE4DB}" Directory_="codecs_DIR" Attributes="0" KeyPath="qtwcodecs4.dll"/>
|
|
||||||
<ROW Component="sqlite3.dll" ComponentId="{B5D4B746-A65D-4F4A-B31A-D1C3C7F59952}" Directory_="APPDIR" Attributes="0" KeyPath="sqlite3.dll"/>
|
<ROW Component="sqlite3.dll" ComponentId="{B5D4B746-A65D-4F4A-B31A-D1C3C7F59952}" Directory_="APPDIR" Attributes="0" KeyPath="sqlite3.dll"/>
|
||||||
<ROW Component="updater.exe" ComponentId="{D1DDB6CB-B336-4112-BC40-1ABD36C3ABDA}" Directory_="APPDIR" Attributes="0" KeyPath="updater.exe"/>
|
<ROW Component="updater.exe" ComponentId="{D1DDB6CB-B336-4112-BC40-1ABD36C3ABDA}" Directory_="APPDIR" Attributes="0" KeyPath="updater.exe"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
|
||||||
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="updater.exe dupeGuru_PE.exe AIShRegAnswer SHORTCUTDIR bz2.pyd POWRPROF.dll python26.dll pythoncom26.dll PyWinTypes26.dll qtaccessiblewidgets4.dll qcncodecs4.dll qjpcodecs4.dll qkrcodecs4.dll qtwcodecs4.dll qsvgicon4.dll qgif4.dll qico4.dll qjpeg4.dll qmng4.dll qsvg4.dll qtiff4.dll QtCore4.dll QtGui4.dll SHLWAPI.dll sqlite3.dll AI_ExePath credits.htm hs_title.png init_.py qtaccessiblecompatwidgets4.dll"/>
|
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="updater.exe dupeGuru_PE.exe AIShRegAnswer SHORTCUTDIR bz2.pyd python26.dll QtCore4.dll QtGui4.dll sqlite3.dll AI_ExePath credits.htm hs_title.png CurrentVersion"/>
|
||||||
<ATTRIBUTE name="CurrentFeature" value="MainFeature"/>
|
<ATTRIBUTE name="CurrentFeature" value="MainFeature"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
|
||||||
<ROW File="PIL._imaging.pyd" Component_="bz2.pyd" FileName="PIL_im~1.pyd|PIL._imaging.pyd" Attributes="0" SourcePath="dist\PIL._imaging.pyd" SelfReg="false" Sequence="4"/>
|
<ROW File="PIL._imaging.pyd" Component_="bz2.pyd" FileName="PIL_im~1.pyd|PIL._imaging.pyd" Attributes="0" SourcePath="dist\PIL._imaging.pyd" SelfReg="false" Sequence="4"/>
|
||||||
<ROW File="POWRPROF.dll" Component_="POWRPROF.dll" FileName="POWRPROF.dll" Attributes="0" SourcePath="dist\POWRPROF.dll" SelfReg="false" Sequence="5"/>
|
<ROW File="PyQt4.QtCore.pyd" Component_="bz2.pyd" FileName="PyQt4Q~1.pyd|PyQt4.QtCore.pyd" Attributes="0" SourcePath="dist\PyQt4.QtCore.pyd" SelfReg="false" Sequence="6"/>
|
||||||
<ROW File="PyQt4.QtCore.pyd" Component_="bz2.pyd" FileName="PyQt4Q~1.pyd|PyQt4.QtCore.pyd" Attributes="0" SourcePath="dist\PyQt4.QtCore.pyd" SelfReg="false" Sequence="7"/>
|
<ROW File="PyQt4.QtGui.pyd" Component_="bz2.pyd" FileName="PyQt4Q~2.pyd|PyQt4.QtGui.pyd" Attributes="0" SourcePath="dist\PyQt4.QtGui.pyd" SelfReg="false" Sequence="7"/>
|
||||||
<ROW File="PyQt4.QtGui.pyd" Component_="bz2.pyd" FileName="PyQt4Q~2.pyd|PyQt4.QtGui.pyd" Attributes="0" SourcePath="dist\PyQt4.QtGui.pyd" SelfReg="false" Sequence="8"/>
|
<ROW File="QtCore4.dll" Component_="QtCore4.dll" FileName="QtCore4.dll" Attributes="0" SourcePath="dist\QtCore4.dll" SelfReg="false" Sequence="9"/>
|
||||||
<ROW File="PyWinTypes26.dll" Component_="PyWinTypes26.dll" FileName="PyWinT~1.dll|PyWinTypes26.dll" Attributes="0" SourcePath="dist\PyWinTypes26.dll" SelfReg="false" Sequence="11"/>
|
<ROW File="QtGui4.dll" Component_="QtGui4.dll" FileName="QtGui4.dll" Attributes="0" SourcePath="dist\QtGui4.dll" SelfReg="false" Sequence="10"/>
|
||||||
<ROW File="QtCore4.dll" Component_="QtCore4.dll" FileName="QtCore4.dll" Attributes="0" SourcePath="dist\QtCore4.dll" SelfReg="false" Sequence="24"/>
|
<ROW File="block.pyd" Component_="bz2.pyd" FileName="_block.pyd" Attributes="0" SourcePath="dist\_block.pyd" SelfReg="false" Sequence="15"/>
|
||||||
<ROW File="QtGui4.dll" Component_="QtGui4.dll" FileName="QtGui4.dll" Attributes="0" SourcePath="dist\QtGui4.dll" SelfReg="false" Sequence="25"/>
|
|
||||||
<ROW File="SHLWAPI.dll" Component_="SHLWAPI.dll" FileName="SHLWAPI.dll" Attributes="0" SourcePath="dist\SHLWAPI.dll" SelfReg="false" Sequence="27"/>
|
|
||||||
<ROW File="block.pyd" Component_="bz2.pyd" FileName="_block.pyd" Attributes="0" SourcePath="dist\_block.pyd" SelfReg="false" Sequence="35"/>
|
|
||||||
<ROW File="bz2.pyd" Component_="bz2.pyd" FileName="bz2.pyd" Attributes="0" SourcePath="dist\bz2.pyd" SelfReg="false" Sequence="3"/>
|
<ROW File="bz2.pyd" Component_="bz2.pyd" FileName="bz2.pyd" Attributes="0" SourcePath="dist\bz2.pyd" SelfReg="false" Sequence="3"/>
|
||||||
<ROW File="core_pe._block.pyd" Component_="bz2.pyd" FileName="core_p~1.pyd|core_pe._block.pyd" Attributes="0" SourcePath="dist\core_pe._block.pyd" SelfReg="false" Sequence="43"/>
|
<ROW File="core_pe._block.pyd" Component_="bz2.pyd" FileName="core_p~1.pyd|core_pe._block.pyd" Attributes="0" SourcePath="dist\core_pe._block.pyd" SelfReg="false" Sequence="22"/>
|
||||||
<ROW File="core_pe._cache.pyd" Component_="bz2.pyd" FileName="core_p~2.pyd|core_pe._cache.pyd" Attributes="0" SourcePath="dist\core_pe._cache.pyd" SelfReg="false" Sequence="44"/>
|
<ROW File="core_pe._cache.pyd" Component_="bz2.pyd" FileName="core_p~2.pyd|core_pe._cache.pyd" Attributes="0" SourcePath="dist\core_pe._cache.pyd" SelfReg="false" Sequence="23"/>
|
||||||
<ROW File="credits.htm" Component_="credits.htm" FileName="credits.htm" Attributes="0" SourcePath="dist\help\credits.htm" SelfReg="false" Sequence="45"/>
|
<ROW File="credits.htm" Component_="credits.htm" FileName="credits.htm" Attributes="0" SourcePath="dist\help\credits.htm" SelfReg="false" Sequence="24"/>
|
||||||
<ROW File="ctypes.pyd" Component_="bz2.pyd" FileName="_ctypes.pyd" Attributes="0" SourcePath="dist\_ctypes.pyd" SelfReg="false" Sequence="36"/>
|
<ROW File="ctypes.pyd" Component_="bz2.pyd" FileName="_ctypes.pyd" Attributes="0" SourcePath="dist\_ctypes.pyd" SelfReg="false" Sequence="16"/>
|
||||||
<ROW File="directories.htm" Component_="credits.htm" FileName="direct~1.htm|directories.htm" Attributes="0" SourcePath="dist\help\directories.htm" SelfReg="false" Sequence="46"/>
|
<ROW File="directories.htm" Component_="credits.htm" FileName="direct~1.htm|directories.htm" Attributes="0" SourcePath="dist\help\directories.htm" SelfReg="false" Sequence="25"/>
|
||||||
<ROW File="dupeGuru_PE.exe" Component_="dupeGuru_PE.exe" FileName="dupeGu~2.exe|dupeGuru PE.exe" Attributes="0" SourcePath="dist\dupeGuru PE.exe" SelfReg="false" Sequence="2"/>
|
<ROW File="dupeGuru_PE.exe" Component_="dupeGuru_PE.exe" FileName="dupeGu~2.exe|dupeGuru PE.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="dist\dupeGuru PE.exe" SelfReg="false" Sequence="2"/>
|
||||||
<ROW File="faq.htm" Component_="credits.htm" FileName="faq.htm" Attributes="0" SourcePath="dist\help\faq.htm" SelfReg="false" Sequence="47"/>
|
<ROW File="faq.htm" Component_="credits.htm" FileName="faq.htm" Attributes="0" SourcePath="dist\help\faq.htm" SelfReg="false" Sequence="26"/>
|
||||||
<ROW File="hardcoded.css" Component_="credits.htm" FileName="hardco~1.css|hardcoded.css" Attributes="0" SourcePath="dist\help\hardcoded.css" SelfReg="false" Sequence="48"/>
|
<ROW File="hardcoded.css" Component_="credits.htm" FileName="hardco~1.css|hardcoded.css" Attributes="0" SourcePath="dist\help\hardcoded.css" SelfReg="false" Sequence="27"/>
|
||||||
<ROW File="hashlib.pyd" Component_="bz2.pyd" FileName="_hashlib.pyd" Attributes="0" SourcePath="dist\_hashlib.pyd" SelfReg="false" Sequence="37"/>
|
<ROW File="hashlib.pyd" Component_="bz2.pyd" FileName="_hashlib.pyd" Attributes="0" SourcePath="dist\_hashlib.pyd" SelfReg="false" Sequence="17"/>
|
||||||
<ROW File="hs_title.png" Component_="hs_title.png" FileName="hs_title.png" Attributes="0" SourcePath="dist\help\images\hs_title.png" SelfReg="false" Sequence="49"/>
|
<ROW File="hs_title.png" Component_="hs_title.png" FileName="hs_title.png" Attributes="0" SourcePath="dist\help\images\hs_title.png" SelfReg="false" Sequence="28"/>
|
||||||
<ROW File="init_.py" Component_="init_.py" FileName="__init__.py" Attributes="0" SourcePath="dist\support\gen_py\__init__.py" SelfReg="false" Sequence="56"/>
|
<ROW File="intro.htm" Component_="credits.htm" FileName="intro.htm" Attributes="0" SourcePath="dist\help\intro.htm" SelfReg="false" Sequence="29"/>
|
||||||
<ROW File="intro.htm" Component_="credits.htm" FileName="intro.htm" Attributes="0" SourcePath="dist\help\intro.htm" SelfReg="false" Sequence="50"/>
|
<ROW File="lxml.etree.pyd" Component_="bz2.pyd" FileName="lxmlet~1.pyd|lxml.etree.pyd" Attributes="0" SourcePath="dist\lxml.etree.pyd" SelfReg="false" Sequence="35"/>
|
||||||
<ROW File="multiprocessing.pyd" Component_="bz2.pyd" FileName="_multi~1.pyd|_multiprocessing.pyd" Attributes="0" SourcePath="dist\_multiprocessing.pyd" SelfReg="false" Sequence="38"/>
|
<ROW File="multiprocessing.pyd" Component_="bz2.pyd" FileName="_multi~1.pyd|_multiprocessing.pyd" Attributes="0" SourcePath="dist\_multiprocessing.pyd" SelfReg="false" Sequence="18"/>
|
||||||
<ROW File="power_marker.htm" Component_="credits.htm" FileName="power_~1.htm|power_marker.htm" Attributes="0" SourcePath="dist\help\power_marker.htm" SelfReg="false" Sequence="51"/>
|
<ROW File="power_marker.htm" Component_="credits.htm" FileName="power_~1.htm|power_marker.htm" Attributes="0" SourcePath="dist\help\power_marker.htm" SelfReg="false" Sequence="30"/>
|
||||||
<ROW File="preferences.htm" Component_="credits.htm" FileName="prefer~1.htm|preferences.htm" Attributes="0" SourcePath="dist\help\preferences.htm" SelfReg="false" Sequence="52"/>
|
<ROW File="preferences.htm" Component_="credits.htm" FileName="prefer~1.htm|preferences.htm" Attributes="0" SourcePath="dist\help\preferences.htm" SelfReg="false" Sequence="31"/>
|
||||||
<ROW File="pyexpat.pyd" Component_="bz2.pyd" FileName="pyexpat.pyd" Attributes="0" SourcePath="dist\pyexpat.pyd" SelfReg="false" Sequence="6"/>
|
<ROW File="pyexpat.pyd" Component_="bz2.pyd" FileName="pyexpat.pyd" Attributes="0" SourcePath="dist\pyexpat.pyd" SelfReg="false" Sequence="5"/>
|
||||||
<ROW File="python26.dll" Component_="python26.dll" FileName="python26.dll" Attributes="0" SourcePath="dist\python26.dll" SelfReg="false" Sequence="9"/>
|
<ROW File="python26.dll" Component_="python26.dll" FileName="python26.dll" Attributes="0" SourcePath="dist\python26.dll" SelfReg="false" Sequence="8"/>
|
||||||
<ROW File="pythoncom26.dll" Component_="pythoncom26.dll" FileName="python~1.dll|pythoncom26.dll" Attributes="0" SourcePath="dist\pythoncom26.dll" SelfReg="false" Sequence="10"/>
|
<ROW File="quick_start.htm" Component_="credits.htm" FileName="quick_~1.htm|quick_start.htm" Attributes="0" SourcePath="dist\help\quick_start.htm" SelfReg="false" Sequence="32"/>
|
||||||
<ROW File="qcncodecs4.dll" Component_="qcncodecs4.dll" FileName="qcncod~1.dll|qcncodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qcncodecs4.dll" SelfReg="false" Sequence="13"/>
|
<ROW File="results.htm" Component_="credits.htm" FileName="results.htm" Attributes="0" SourcePath="dist\help\results.htm" SelfReg="false" Sequence="33"/>
|
||||||
<ROW File="qgif4.dll" Component_="qgif4.dll" FileName="qgif4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qgif4.dll" SelfReg="false" Sequence="18"/>
|
<ROW File="select.pyd" Component_="bz2.pyd" FileName="select.pyd" Attributes="0" SourcePath="dist\select.pyd" SelfReg="false" Sequence="11"/>
|
||||||
<ROW File="qico4.dll" Component_="qico4.dll" FileName="qico4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qico4.dll" SelfReg="false" Sequence="19"/>
|
<ROW File="send2trash_win.pyd" Component_="bz2.pyd" FileName="_send2~1.pyd|_send2trash_win.pyd" Attributes="0" SourcePath="dist\_send2trash_win.pyd" SelfReg="false" Sequence="36"/>
|
||||||
<ROW File="qjpcodecs4.dll" Component_="qjpcodecs4.dll" FileName="qjpcod~1.dll|qjpcodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qjpcodecs4.dll" SelfReg="false" Sequence="14"/>
|
<ROW File="sip.pyd" Component_="bz2.pyd" FileName="sip.pyd" Attributes="0" SourcePath="dist\sip.pyd" SelfReg="false" Sequence="12"/>
|
||||||
<ROW File="qjpeg4.dll" Component_="qjpeg4.dll" FileName="qjpeg4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qjpeg4.dll" SelfReg="false" Sequence="20"/>
|
<ROW File="socket.pyd" Component_="bz2.pyd" FileName="_socket.pyd" Attributes="0" SourcePath="dist\_socket.pyd" SelfReg="false" Sequence="19"/>
|
||||||
<ROW File="qkrcodecs4.dll" Component_="qkrcodecs4.dll" FileName="qkrcod~1.dll|qkrcodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qkrcodecs4.dll" SelfReg="false" Sequence="15"/>
|
<ROW File="sqlite3.dll" Component_="sqlite3.dll" FileName="sqlite3.dll" Attributes="0" SourcePath="dist\sqlite3.dll" SelfReg="false" Sequence="13"/>
|
||||||
<ROW File="qmng4.dll" Component_="qmng4.dll" FileName="qmng4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qmng4.dll" SelfReg="false" Sequence="21"/>
|
<ROW File="sqlite3.pyd" Component_="bz2.pyd" FileName="_sqlite3.pyd" Attributes="0" SourcePath="dist\_sqlite3.pyd" SelfReg="false" Sequence="20"/>
|
||||||
<ROW File="qsvg4.dll" Component_="qsvg4.dll" FileName="qsvg4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qsvg4.dll" SelfReg="false" Sequence="22"/>
|
<ROW File="ssl.pyd" Component_="bz2.pyd" FileName="_ssl.pyd" Attributes="0" SourcePath="dist\_ssl.pyd" SelfReg="false" Sequence="21"/>
|
||||||
<ROW File="qsvgicon4.dll" Component_="qsvgicon4.dll" FileName="qsvgic~1.dll|qsvgicon4.dll" Attributes="0" SourcePath="dist\qt4_plugins\iconengines\qsvgicon4.dll" SelfReg="false" Sequence="17"/>
|
<ROW File="unicodedata.pyd" Component_="bz2.pyd" FileName="unicod~1.pyd|unicodedata.pyd" Attributes="0" SourcePath="dist\unicodedata.pyd" SelfReg="false" Sequence="14"/>
|
||||||
<ROW File="qtaccessiblecompatwidgets4.dll" Component_="qtaccessiblecompatwidgets4.dll" FileName="qtacce~1.dll|qtaccessiblecompatwidgets4.dll" Attributes="0" SourcePath="dist\qt4_plugins\accessible\qtaccessiblecompatwidgets4.dll" SelfReg="false" Sequence="57"/>
|
|
||||||
<ROW File="qtaccessiblewidgets4.dll" Component_="qtaccessiblewidgets4.dll" FileName="qtacce~2.dll|qtaccessiblewidgets4.dll" Attributes="0" SourcePath="dist\qt4_plugins\accessible\qtaccessiblewidgets4.dll" SelfReg="false" Sequence="12"/>
|
|
||||||
<ROW File="qtiff4.dll" Component_="qtiff4.dll" FileName="qtiff4.dll" Attributes="0" SourcePath="dist\qt4_plugins\imageformats\qtiff4.dll" SelfReg="false" Sequence="23"/>
|
|
||||||
<ROW File="qtwcodecs4.dll" Component_="qtwcodecs4.dll" FileName="qtwcod~1.dll|qtwcodecs4.dll" Attributes="0" SourcePath="dist\qt4_plugins\codecs\qtwcodecs4.dll" SelfReg="false" Sequence="16"/>
|
|
||||||
<ROW File="quick_start.htm" Component_="credits.htm" FileName="quick_~1.htm|quick_start.htm" Attributes="0" SourcePath="dist\help\quick_start.htm" SelfReg="false" Sequence="53"/>
|
|
||||||
<ROW File="results.htm" Component_="credits.htm" FileName="results.htm" Attributes="0" SourcePath="dist\help\results.htm" SelfReg="false" Sequence="54"/>
|
|
||||||
<ROW File="select.pyd" Component_="bz2.pyd" FileName="select.pyd" Attributes="0" SourcePath="dist\select.pyd" SelfReg="false" Sequence="26"/>
|
|
||||||
<ROW File="sip.pyd" Component_="bz2.pyd" FileName="sip.pyd" Attributes="0" SourcePath="dist\sip.pyd" SelfReg="false" Sequence="28"/>
|
|
||||||
<ROW File="socket.pyd" Component_="bz2.pyd" FileName="_socket.pyd" Attributes="0" SourcePath="dist\_socket.pyd" SelfReg="false" Sequence="39"/>
|
|
||||||
<ROW File="sqlite3.dll" Component_="sqlite3.dll" FileName="sqlite3.dll" Attributes="0" SourcePath="dist\sqlite3.dll" SelfReg="false" Sequence="29"/>
|
|
||||||
<ROW File="sqlite3.pyd" Component_="bz2.pyd" FileName="_sqlite3.pyd" Attributes="0" SourcePath="dist\_sqlite3.pyd" SelfReg="false" Sequence="40"/>
|
|
||||||
<ROW File="ssl.pyd" Component_="bz2.pyd" FileName="_ssl.pyd" Attributes="0" SourcePath="dist\_ssl.pyd" SelfReg="false" Sequence="41"/>
|
|
||||||
<ROW File="unicodedata.pyd" Component_="bz2.pyd" FileName="unicod~1.pyd|unicodedata.pyd" Attributes="0" SourcePath="dist\unicodedata.pyd" SelfReg="false" Sequence="30"/>
|
|
||||||
<ROW File="updater.exe" Component_="updater.exe" FileName="updater.exe" Attributes="0" SourcePath="<AI_HOME>updater.exe" SelfReg="false" Sequence="1" DigSign="true"/>
|
<ROW File="updater.exe" Component_="updater.exe" FileName="updater.exe" Attributes="0" SourcePath="<AI_HOME>updater.exe" SelfReg="false" Sequence="1" DigSign="true"/>
|
||||||
<ROW File="versions.htm" Component_="credits.htm" FileName="versions.htm" Attributes="0" SourcePath="dist\help\versions.htm" SelfReg="false" Sequence="55"/>
|
<ROW File="versions.htm" Component_="credits.htm" FileName="versions.htm" Attributes="0" SourcePath="dist\help\versions.htm" SelfReg="false" Sequence="34"/>
|
||||||
<ROW File="win32api.pyd" Component_="bz2.pyd" FileName="win32api.pyd" Attributes="0" SourcePath="dist\win32api.pyd" SelfReg="false" Sequence="31"/>
|
|
||||||
<ROW File="win32com.shell.shell.pyd" Component_="bz2.pyd" FileName="win32c~1.pyd|win32com.shell.shell.pyd" Attributes="0" SourcePath="dist\win32com.shell.shell.pyd" SelfReg="false" Sequence="32"/>
|
|
||||||
<ROW File="win32sysloader.pyd" Component_="bz2.pyd" FileName="_win32~1.pyd|_win32sysloader.pyd" Attributes="0" SourcePath="dist\_win32sysloader.pyd" SelfReg="false" Sequence="42"/>
|
|
||||||
<ROW File="win32trace.pyd" Component_="bz2.pyd" FileName="win32t~1.pyd|win32trace.pyd" Attributes="0" SourcePath="dist\win32trace.pyd" SelfReg="false" Sequence="33"/>
|
|
||||||
<ROW File="win32ui.pyd" Component_="bz2.pyd" FileName="win32ui.pyd" Attributes="0" SourcePath="dist\win32ui.pyd" SelfReg="false" Sequence="34"/>
|
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.BuildComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.BuildComponent">
|
||||||
<ROW BuildKey="DefaultBuild" BuildName="DefaultBuild" BuildOrder="1" BuildType="0" PackageName="install\dupeguru_pe_win_[|ProductVersion]" Languages="en" InstallationType="4" CabsLocation="1" PackageType="1" FilesInsideExe="true" CreateMd5="true" ExtractionFolder="[AppDataFolder][|Manufacturer]\[|ProductName]\install" ExtUI="true"/>
|
<ROW BuildKey="DefaultBuild" BuildName="DefaultBuild" BuildOrder="1" BuildType="0" PackageName="install\dupeguru_pe_win_[|ProductVersion]" Languages="en" InstallationType="4" CabsLocation="1" PackageType="1" FilesInsideExe="true" CreateMd5="true" ExtractionFolder="[AppDataFolder][|Manufacturer]\[|ProductName]\install" ExtUI="true"/>
|
||||||
@@ -261,6 +216,7 @@
|
|||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiRegsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiRegsComponent">
|
||||||
<ROW Registry="AIShRegAnswer" Root="-1" Key="Software\Caphyon\Advanced Installer\Installs\[ProductCode]" Name="AIShRegAnswer" Value="[AI_SHORTCUTSREG]" Component_="AIShRegAnswer"/>
|
<ROW Registry="AIShRegAnswer" Root="-1" Key="Software\Caphyon\Advanced Installer\Installs\[ProductCode]" Name="AIShRegAnswer" Value="[AI_SHORTCUTSREG]" Component_="AIShRegAnswer"/>
|
||||||
<ROW Registry="AI_ExePath" Root="-1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Value="[AI_SETUPEXEPATH]" Component_="AI_ExePath"/>
|
<ROW Registry="AI_ExePath" Root="-1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Value="[AI_SETUPEXEPATH]" Component_="AI_ExePath"/>
|
||||||
|
<ROW Registry="CurrentVersion" Root="-1" Key="Software\[Manufacturer]\[ProductName]" Name="CurrentVersion" Value="[ProductVersion]" Component_="CurrentVersion"/>
|
||||||
</COMPONENT>
|
</COMPONENT>
|
||||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiShortsComponent">
|
<COMPONENT cid="caphyon.advinst.msicomp.MsiShortsComponent">
|
||||||
<ROW Shortcut="Check_for_update" Directory_="SHORTCUTDIR" Name="Checkf~2|Check for update" Component_="updater.exe" Target="[#updater.exe]" Arguments="/checknow" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
<ROW Shortcut="Check_for_update" Directory_="SHORTCUTDIR" Name="Checkf~2|Check for update" Component_="updater.exe" Target="[#updater.exe]" Arguments="/checknow" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ import base.dg_rc
|
|||||||
|
|
||||||
from app import DupeGuru
|
from app import DupeGuru
|
||||||
|
|
||||||
# This is a workaround for a pyinstaller problem where compiled dupeguru can't read tiff files
|
if sys.platform == 'win32':
|
||||||
from PIL import TiffImagePlugin, TiffTags
|
import base.cxfreeze_fix
|
||||||
|
# This is a workaround for a cxfreeze problem where compiled dupeguru can't read tiff files
|
||||||
|
from PIL import TiffImagePlugin, TiffTags
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
VSVersionInfo(
|
|
||||||
ffi=FixedFileInfo(
|
|
||||||
filevers=($versioncomma),
|
|
||||||
prodvers=($versioncomma),
|
|
||||||
mask=0x17,
|
|
||||||
flags=0x0,
|
|
||||||
OS=0x4,
|
|
||||||
fileType=0x1,
|
|
||||||
subtype=0x0,
|
|
||||||
date=(0, 0)
|
|
||||||
),
|
|
||||||
kids=[
|
|
||||||
StringFileInfo(
|
|
||||||
[
|
|
||||||
StringTable(
|
|
||||||
'040904b0',
|
|
||||||
[StringStruct('CompanyName', 'Hardcoded Software'),
|
|
||||||
StringStruct('FileDescription', 'dupeGuru Picture Edition'),
|
|
||||||
StringStruct('FileVersion', '$version'),
|
|
||||||
StringStruct('InternalName', 'dupeGuru PE.exe'),
|
|
||||||
StringStruct('LegalCopyright', '(c) Hardcoded Software. All rights reserved.'),
|
|
||||||
StringStruct('OriginalFilename', 'dupeGuru PE.exe'),
|
|
||||||
StringStruct('ProductName', 'dupeGuru Picture Edition'),
|
|
||||||
StringStruct('ProductVersion', '$versioncomma')])
|
|
||||||
]),
|
|
||||||
VarFileInfo([VarStruct('Translation', [1033])])
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@@ -24,6 +24,7 @@ class Directories(DirectoriesBase):
|
|||||||
return STATE_EXCLUDED
|
return STATE_EXCLUDED
|
||||||
|
|
||||||
class DupeGuru(DupeGuruBase):
|
class DupeGuru(DupeGuruBase):
|
||||||
|
EDITION = 'se'
|
||||||
LOGO_NAME = 'logo_se'
|
LOGO_NAME = 'logo_se'
|
||||||
NAME = 'dupeGuru'
|
NAME = 'dupeGuru'
|
||||||
VERSION = '2.9.2'
|
VERSION = '2.9.2'
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
a = Analysis([os.path.join(HOMEPATH,'support\\_mountzlib.py'), os.path.join(HOMEPATH,'support\\useUnicode.py'), 'start.py'],
|
|
||||||
pathex=[])
|
|
||||||
pyz = PYZ(a.pure)
|
|
||||||
exe = EXE(pyz,
|
|
||||||
a.scripts,
|
|
||||||
exclude_binaries=1,
|
|
||||||
name=os.path.join('build\\pyi.win32\\dupeGuru', 'dupeGuru.exe'),
|
|
||||||
debug=False,
|
|
||||||
strip=False,
|
|
||||||
upx=True,
|
|
||||||
console=False,
|
|
||||||
icon='..\\..\\images\\dgse_logo.ico',
|
|
||||||
version='verinfo_tmp')
|
|
||||||
coll = COLLECT( exe,
|
|
||||||
a.binaries,
|
|
||||||
a.zipfiles,
|
|
||||||
a.datas,
|
|
||||||
strip=False,
|
|
||||||
upx=True,
|
|
||||||
name=os.path.join('dist'))
|
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>294</width>
|
<width>449</width>
|
||||||
<height>296</height>
|
<height>312</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -170,110 +170,105 @@
|
|||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>0</width>
|
<width>0</width>
|
||||||
<height>134</height>
|
<height>136</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QCheckBox" name="wordWeightingBox">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
<property name="geometry">
|
<property name="spacing">
|
||||||
<rect>
|
<number>0</number>
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>350</width>
|
|
||||||
<height>21</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="wordWeightingBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Word weighting</string>
|
<string>Word weighting</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QCheckBox" name="matchSimilarBox">
|
<widget class="QCheckBox" name="matchSimilarBox">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>22</y>
|
|
||||||
<width>350</width>
|
|
||||||
<height>21</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Match similar words</string>
|
<string>Match similar words</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QCheckBox" name="mixFileKindBox">
|
<widget class="QCheckBox" name="mixFileKindBox">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>44</y>
|
|
||||||
<width>350</width>
|
|
||||||
<height>21</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Can mix file kind</string>
|
<string>Can mix file kind</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QCheckBox" name="useRegexpBox">
|
<widget class="QCheckBox" name="useRegexpBox">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>66</y>
|
|
||||||
<width>350</width>
|
|
||||||
<height>21</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Use regular expressions when filtering</string>
|
<string>Use regular expressions when filtering</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QCheckBox" name="removeEmptyFoldersBox">
|
<widget class="QCheckBox" name="removeEmptyFoldersBox">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>88</y>
|
|
||||||
<width>350</width>
|
|
||||||
<height>21</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Remove empty folders on delete or move</string>
|
<string>Remove empty folders on delete or move</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QCheckBox" name="ignoreSmallFilesBox">
|
</item>
|
||||||
<property name="geometry">
|
<item>
|
||||||
<rect>
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<x>0</x>
|
<property name="spacing">
|
||||||
<y>110</y>
|
<number>0</number>
|
||||||
<width>171</width>
|
|
||||||
<height>21</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="ignoreSmallFilesBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Ignore files smaller than</string>
|
<string>Ignore files smaller than</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QLineEdit" name="sizeThresholdEdit">
|
<widget class="QLineEdit" name="sizeThresholdEdit">
|
||||||
<property name="geometry">
|
<property name="sizePolicy">
|
||||||
<rect>
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
<x>170</x>
|
<horstretch>0</horstretch>
|
||||||
<y>110</y>
|
<verstretch>0</verstretch>
|
||||||
<width>51</width>
|
</sizepolicy>
|
||||||
<height>22</height>
|
</property>
|
||||||
</rect>
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QLabel" name="label_6">
|
<widget class="QLabel" name="label_6">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>230</x>
|
|
||||||
<y>110</y>
|
|
||||||
<width>21</width>
|
|
||||||
<height>17</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>KB</string>
|
<string>KB</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
VSVersionInfo(
|
|
||||||
ffi=FixedFileInfo(
|
|
||||||
filevers=($versioncomma),
|
|
||||||
prodvers=($versioncomma),
|
|
||||||
mask=0x17,
|
|
||||||
flags=0x0,
|
|
||||||
OS=0x4,
|
|
||||||
fileType=0x1,
|
|
||||||
subtype=0x0,
|
|
||||||
date=(0, 0)
|
|
||||||
),
|
|
||||||
kids=[
|
|
||||||
StringFileInfo(
|
|
||||||
[
|
|
||||||
StringTable(
|
|
||||||
'040904b0',
|
|
||||||
[StringStruct('CompanyName', 'Hardcoded Software'),
|
|
||||||
StringStruct('FileDescription', 'dupeGuru'),
|
|
||||||
StringStruct('FileVersion', '$version'),
|
|
||||||
StringStruct('InternalName', 'dupeGuru.exe'),
|
|
||||||
StringStruct('LegalCopyright', '(c) Hardcoded Software. All rights reserved.'),
|
|
||||||
StringStruct('OriginalFilename', 'dupeGuru.exe'),
|
|
||||||
StringStruct('ProductName', 'dupeGuru'),
|
|
||||||
StringStruct('ProductVersion', '$versioncomma')])
|
|
||||||
]),
|
|
||||||
VarFileInfo([VarStruct('Translation', [1033])])
|
|
||||||
]
|
|
||||||
)
|
|
||||||
Reference in New Issue
Block a user