mirror of
https://github.com/arsenetar/dupeguru.git
synced 2025-03-10 05:34:36 +00:00
cocoa: merge se/me/pe into one single app
That merge has already been done in core and qt, we're following. I broke picture scan details panel image loading. Will fix later.
This commit is contained in:
parent
b780816e3c
commit
8c1078aa71
36
build.py
36
build.py
@ -90,31 +90,27 @@ def build_xibless(dest='cocoa/autogen'):
|
|||||||
('prioritize_dialog.py', 'PrioritizeDialog_UI'),
|
('prioritize_dialog.py', 'PrioritizeDialog_UI'),
|
||||||
('result_window.py', 'ResultWindow_UI'),
|
('result_window.py', 'ResultWindow_UI'),
|
||||||
('main_menu.py', 'MainMenu_UI'),
|
('main_menu.py', 'MainMenu_UI'),
|
||||||
('preferences_panel.py', 'PreferencesPanel_UI'),
|
('details_panel.py', 'DetailsPanel_UI'),
|
||||||
|
('details_panel_picture.py', 'DetailsPanelPicture_UI'),
|
||||||
]
|
]
|
||||||
for srcname, dstname in FNPAIRS:
|
for srcname, dstname in FNPAIRS:
|
||||||
xibless.generate(
|
xibless.generate(
|
||||||
op.join('cocoa', 'base', 'ui', srcname), op.join(dest, dstname),
|
op.join('cocoa', 'ui', srcname), op.join(dest, dstname),
|
||||||
localizationTable='Localizable'
|
localizationTable='Localizable'
|
||||||
)
|
)
|
||||||
# XXX This is broken
|
for appmode in ('standard', 'music', 'picture'):
|
||||||
assert False
|
xibless.generate(
|
||||||
# if edition == 'pe':
|
op.join('cocoa', 'ui', 'preferences_panel.py'),
|
||||||
# xibless.generate(
|
op.join(dest, 'PreferencesPanel%s_UI' % appmode.capitalize()),
|
||||||
# 'cocoa/pe/ui/details_panel.py', op.join(dest, 'DetailsPanel_UI'),
|
localizationTable='Localizable',
|
||||||
# localizationTable='Localizable'
|
args={'appmode': appmode},
|
||||||
# )
|
)
|
||||||
# else:
|
|
||||||
# xibless.generate(
|
|
||||||
# 'cocoa/base/ui/details_panel.py', op.join(dest, 'DetailsPanel_UI'),
|
|
||||||
# localizationTable='Localizable'
|
|
||||||
# )
|
|
||||||
|
|
||||||
def build_cocoa(dev):
|
def build_cocoa(dev):
|
||||||
print("Creating OS X app structure")
|
print("Creating OS X app structure")
|
||||||
app = cocoa_app()
|
app = cocoa_app()
|
||||||
app_version = get_module_version('core')
|
app_version = get_module_version('core')
|
||||||
cocoa_project_path = 'cocoa/se'
|
cocoa_project_path = 'cocoa'
|
||||||
filereplace(op.join(cocoa_project_path, 'InfoTemplate.plist'), op.join('build', 'Info.plist'), version=app_version)
|
filereplace(op.join(cocoa_project_path, 'InfoTemplate.plist'), op.join('build', 'Info.plist'), version=app_version)
|
||||||
app.create(op.join('build', 'Info.plist'))
|
app.create(op.join('build', 'Info.plist'))
|
||||||
print("Building localizations")
|
print("Building localizations")
|
||||||
@ -156,8 +152,8 @@ def build_cocoa(dev):
|
|||||||
app.copy_executable('cocoa/build/dupeGuru')
|
app.copy_executable('cocoa/build/dupeGuru')
|
||||||
build_help()
|
build_help()
|
||||||
print("Copying resources and frameworks")
|
print("Copying resources and frameworks")
|
||||||
image_path = 'cocoa/se/dupeguru.icns'
|
image_path = 'cocoa/dupeguru.icns'
|
||||||
resources = [image_path, 'cocoa/base/dsa_pub.pem', 'build/dg_cocoa.py', 'build/help']
|
resources = [image_path, 'cocoa/dsa_pub.pem', 'build/dg_cocoa.py', 'build/help']
|
||||||
app.copy_resources(*resources, use_symlinks=dev)
|
app.copy_resources(*resources, use_symlinks=dev)
|
||||||
app.copy_frameworks('build/Python', 'cocoalib/Sparkle.framework')
|
app.copy_frameworks('build/Python', 'cocoalib/Sparkle.framework')
|
||||||
print("Creating the run.py file")
|
print("Creating the run.py file")
|
||||||
@ -197,7 +193,7 @@ def build_localizations(ui):
|
|||||||
loc.compile_all_po('locale')
|
loc.compile_all_po('locale')
|
||||||
if ui == 'cocoa':
|
if ui == 'cocoa':
|
||||||
app = cocoa_app()
|
app = cocoa_app()
|
||||||
loc.build_cocoa_localizations(app, en_stringsfile=op.join('cocoa', 'base', 'en.lproj', 'Localizable.strings'))
|
loc.build_cocoa_localizations(app, en_stringsfile=op.join('cocoa', 'en.lproj', 'Localizable.strings'))
|
||||||
locale_dest = op.join(app.resources, 'locale')
|
locale_dest = op.join(app.resources, 'locale')
|
||||||
elif ui == 'qt':
|
elif ui == 'qt':
|
||||||
build_qt_localizations()
|
build_qt_localizations()
|
||||||
@ -212,7 +208,7 @@ def build_updatepot():
|
|||||||
build_cocoalib_xibless('cocoalib/autogen')
|
build_cocoalib_xibless('cocoalib/autogen')
|
||||||
loc.generate_cocoa_strings_from_code('cocoalib', 'cocoalib/en.lproj')
|
loc.generate_cocoa_strings_from_code('cocoalib', 'cocoalib/en.lproj')
|
||||||
build_xibless('se', op.join('cocoa', 'autogen', 'se'))
|
build_xibless('se', op.join('cocoa', 'autogen', 'se'))
|
||||||
loc.generate_cocoa_strings_from_code('cocoa', 'cocoa/base/en.lproj')
|
loc.generate_cocoa_strings_from_code('cocoa', 'cocoa/en.lproj')
|
||||||
print("Building .pot files from source files")
|
print("Building .pot files from source files")
|
||||||
print("Building core.pot")
|
print("Building core.pot")
|
||||||
loc.generate_pot(['core'], op.join('locale', 'core.pot'), ['tr'])
|
loc.generate_pot(['core'], op.join('locale', 'core.pot'), ['tr'])
|
||||||
@ -232,7 +228,7 @@ def build_updatepot():
|
|||||||
loc.strings2pot(op.join('cocoalib', 'en.lproj', 'cocoalib.strings'), cocoalib_pot)
|
loc.strings2pot(op.join('cocoalib', 'en.lproj', 'cocoalib.strings'), cocoalib_pot)
|
||||||
print("Enhancing ui.pot with Cocoa's strings files")
|
print("Enhancing ui.pot with Cocoa's strings files")
|
||||||
loc.strings2pot(
|
loc.strings2pot(
|
||||||
op.join('cocoa', 'base', 'en.lproj', 'Localizable.strings'),
|
op.join('cocoa', 'en.lproj', 'Localizable.strings'),
|
||||||
op.join('locale', 'ui.pot')
|
op.join('locale', 'ui.pot')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,11 +14,13 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
#import "DetailsPanel.h"
|
#import "DetailsPanel.h"
|
||||||
#import "DirectoryPanel.h"
|
#import "DirectoryPanel.h"
|
||||||
#import "IgnoreListDialog.h"
|
#import "IgnoreListDialog.h"
|
||||||
|
#import "ProblemDialog.h"
|
||||||
|
#import "DeletionOptions.h"
|
||||||
#import "HSAboutBox.h"
|
#import "HSAboutBox.h"
|
||||||
#import "HSRecentFiles.h"
|
#import "HSRecentFiles.h"
|
||||||
#import "HSProgressWindow.h"
|
#import "HSProgressWindow.h"
|
||||||
|
|
||||||
@interface AppDelegateBase : NSObject <NSFileManagerDelegate>
|
@interface AppDelegate : NSObject <NSFileManagerDelegate>
|
||||||
{
|
{
|
||||||
NSMenu *recentResultsMenu;
|
NSMenu *recentResultsMenu;
|
||||||
NSMenu *columnsMenu;
|
NSMenu *columnsMenu;
|
||||||
@ -29,6 +31,8 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
DirectoryPanel *_directoryPanel;
|
DirectoryPanel *_directoryPanel;
|
||||||
DetailsPanel *_detailsPanel;
|
DetailsPanel *_detailsPanel;
|
||||||
IgnoreListDialog *_ignoreListDialog;
|
IgnoreListDialog *_ignoreListDialog;
|
||||||
|
ProblemDialog *_problemDialog;
|
||||||
|
DeletionOptions *_deletionOptions;
|
||||||
HSProgressWindow *_progressWindow;
|
HSProgressWindow *_progressWindow;
|
||||||
NSWindowController *_preferencesPanel;
|
NSWindowController *_preferencesPanel;
|
||||||
HSAboutBox *_aboutBox;
|
HSAboutBox *_aboutBox;
|
||||||
@ -43,9 +47,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
+ (NSDictionary *)defaultPreferences;
|
+ (NSDictionary *)defaultPreferences;
|
||||||
- (PyDupeGuru *)model;
|
- (PyDupeGuru *)model;
|
||||||
- (DetailsPanel *)createDetailsPanel;
|
- (DetailsPanel *)createDetailsPanel;
|
||||||
- (NSString *)homepageURL;
|
|
||||||
- (void)setScanOptions;
|
- (void)setScanOptions;
|
||||||
- (void)initResultColumns:(ResultTable *)aTable;
|
|
||||||
|
|
||||||
/* Public */
|
/* Public */
|
||||||
- (void)finalizeInit;
|
- (void)finalizeInit;
|
||||||
@ -53,6 +55,8 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
- (DirectoryPanel *)directoryPanel;
|
- (DirectoryPanel *)directoryPanel;
|
||||||
- (DetailsPanel *)detailsPanel;
|
- (DetailsPanel *)detailsPanel;
|
||||||
- (HSRecentFiles *)recentResults;
|
- (HSRecentFiles *)recentResults;
|
||||||
|
- (NSInteger)getAppMode;
|
||||||
|
- (void)setAppMode:(NSInteger)appMode;
|
||||||
|
|
||||||
/* Delegate */
|
/* Delegate */
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
|
||||||
@ -62,6 +66,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
- (void)recentFileClicked:(NSString *)path;
|
- (void)recentFileClicked:(NSString *)path;
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
|
- (void)clearPictureCache;
|
||||||
- (void)loadResults;
|
- (void)loadResults;
|
||||||
- (void)openWebsite;
|
- (void)openWebsite;
|
||||||
- (void)openHelp;
|
- (void)openHelp;
|
@ -6,16 +6,19 @@ which should be included with this package. The terms are also available at
|
|||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "AppDelegateBase.h"
|
#import "AppDelegate.h"
|
||||||
#import "ProgressController.h"
|
#import "ProgressController.h"
|
||||||
#import "HSPyUtil.h"
|
#import "HSPyUtil.h"
|
||||||
#import "Consts.h"
|
#import "Consts.h"
|
||||||
#import "Dialogs.h"
|
#import "Dialogs.h"
|
||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
#import "ValueTransformers.h"
|
#import "ValueTransformers.h"
|
||||||
#import "PreferencesPanel_UI.h"
|
#import "DetailsPanelPicture.h"
|
||||||
|
#import "PreferencesPanelStandard_UI.h"
|
||||||
|
#import "PreferencesPanelMusic_UI.h"
|
||||||
|
#import "PreferencesPanelPicture_UI.h"
|
||||||
|
|
||||||
@implementation AppDelegateBase
|
@implementation AppDelegate
|
||||||
|
|
||||||
@synthesize recentResultsMenu;
|
@synthesize recentResultsMenu;
|
||||||
@synthesize columnsMenu;
|
@synthesize columnsMenu;
|
||||||
@ -24,6 +27,21 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
+ (NSDictionary *)defaultPreferences
|
+ (NSDictionary *)defaultPreferences
|
||||||
{
|
{
|
||||||
NSMutableDictionary *d = [NSMutableDictionary dictionary];
|
NSMutableDictionary *d = [NSMutableDictionary dictionary];
|
||||||
|
[d setObject:i2n(1) forKey:@"scanTypeStandard"];
|
||||||
|
[d setObject:i2n(3) forKey:@"scanTypeMusic"];
|
||||||
|
[d setObject:i2n(0) forKey:@"scanTypePicture"];
|
||||||
|
[d setObject:i2n(95) forKey:@"minMatchPercentage"];
|
||||||
|
[d setObject:i2n(30) forKey:@"smallFileThreshold"];
|
||||||
|
[d setObject:b2n(YES) forKey:@"wordWeighting"];
|
||||||
|
[d setObject:b2n(NO) forKey:@"matchSimilarWords"];
|
||||||
|
[d setObject:b2n(YES) forKey:@"ignoreSmallFiles"];
|
||||||
|
[d setObject:b2n(NO) forKey:@"scanTagTrack"];
|
||||||
|
[d setObject:b2n(YES) forKey:@"scanTagArtist"];
|
||||||
|
[d setObject:b2n(YES) forKey:@"scanTagAlbum"];
|
||||||
|
[d setObject:b2n(YES) forKey:@"scanTagTitle"];
|
||||||
|
[d setObject:b2n(NO) forKey:@"scanTagGenre"];
|
||||||
|
[d setObject:b2n(NO) forKey:@"scanTagYear"];
|
||||||
|
[d setObject:b2n(NO) forKey:@"matchScaled"];
|
||||||
[d setObject:i2n(1) forKey:@"recreatePathType"];
|
[d setObject:i2n(1) forKey:@"recreatePathType"];
|
||||||
[d setObject:i2n(11) forKey:TableFontSize];
|
[d setObject:i2n(11) forKey:TableFontSize];
|
||||||
[d setObject:b2n(YES) forKey:@"mixFileKind"];
|
[d setObject:b2n(YES) forKey:@"mixFileKind"];
|
||||||
@ -53,6 +71,20 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
model = [[PyDupeGuru alloc] init];
|
model = [[PyDupeGuru alloc] init];
|
||||||
[model bindCallback:createCallback(@"DupeGuruView", self)];
|
[model bindCallback:createCallback(@"DupeGuruView", self)];
|
||||||
[self setUpdater:[SUUpdater sharedUpdater]];
|
[self setUpdater:[SUUpdater sharedUpdater]];
|
||||||
|
NSMutableIndexSet *contentsIndexes = [NSMutableIndexSet indexSet];
|
||||||
|
[contentsIndexes addIndex:1];
|
||||||
|
[contentsIndexes addIndex:2];
|
||||||
|
VTIsIntIn *vt = [[[VTIsIntIn alloc] initWithValues:contentsIndexes reverse:YES] autorelease];
|
||||||
|
[NSValueTransformer setValueTransformer:vt forName:@"vtScanTypeIsNotContent"];
|
||||||
|
NSMutableIndexSet *i = [NSMutableIndexSet indexSetWithIndex:0];
|
||||||
|
VTIsIntIn *vtScanTypeIsFuzzy = [[[VTIsIntIn alloc] initWithValues:i reverse:NO] autorelease];
|
||||||
|
[NSValueTransformer setValueTransformer:vtScanTypeIsFuzzy forName:@"vtScanTypeIsFuzzy"];
|
||||||
|
i = [NSMutableIndexSet indexSetWithIndex:4];
|
||||||
|
[i addIndex:5];
|
||||||
|
VTIsIntIn *vtScanTypeIsNotContent = [[[VTIsIntIn alloc] initWithValues:i reverse:YES] autorelease];
|
||||||
|
[NSValueTransformer setValueTransformer:vtScanTypeIsNotContent forName:@"vtScanTypeMusicIsNotContent"];
|
||||||
|
VTIsIntIn *vtScanTypeIsTag = [[[VTIsIntIn alloc] initWithValues:[NSIndexSet indexSetWithIndex:3] reverse:NO] autorelease];
|
||||||
|
[NSValueTransformer setValueTransformer:vtScanTypeIsTag forName:@"vtScanTypeIsTag"];
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,14 +101,17 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
}
|
}
|
||||||
_recentResults = [[HSRecentFiles alloc] initWithName:@"recentResults" menu:recentResultsMenu];
|
_recentResults = [[HSRecentFiles alloc] initWithName:@"recentResults" menu:recentResultsMenu];
|
||||||
[_recentResults setDelegate:self];
|
[_recentResults setDelegate:self];
|
||||||
_resultWindow = [[ResultWindow alloc] initWithParentApp:self];
|
|
||||||
_directoryPanel = [[DirectoryPanel alloc] initWithParentApp:self];
|
_directoryPanel = [[DirectoryPanel alloc] initWithParentApp:self];
|
||||||
_detailsPanel = [self createDetailsPanel];
|
|
||||||
_ignoreListDialog = [[IgnoreListDialog alloc] initWithPyRef:[model ignoreListDialog]];
|
_ignoreListDialog = [[IgnoreListDialog alloc] initWithPyRef:[model ignoreListDialog]];
|
||||||
|
_problemDialog = [[ProblemDialog alloc] initWithPyRef:[model problemDialog]];
|
||||||
|
_deletionOptions = [[DeletionOptions alloc] initWithPyRef:[model deletionOptions]];
|
||||||
_progressWindow = [[HSProgressWindow alloc] initWithPyRef:[[self model] progressWindow] view:nil];
|
_progressWindow = [[HSProgressWindow alloc] initWithPyRef:[[self model] progressWindow] view:nil];
|
||||||
[_progressWindow setParentWindow:[_directoryPanel window]];
|
[_progressWindow setParentWindow:[_directoryPanel window]];
|
||||||
_aboutBox = nil; // Lazily loaded
|
// Lazily loaded
|
||||||
_preferencesPanel = nil; // Lazily loaded
|
_aboutBox = nil;
|
||||||
|
_preferencesPanel = nil;
|
||||||
|
_resultWindow = nil;
|
||||||
|
_detailsPanel = nil;
|
||||||
[[[self directoryPanel] window] makeKeyAndOrderFront:self];
|
[[[self directoryPanel] window] makeKeyAndOrderFront:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,20 +124,45 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
|
|
||||||
- (DetailsPanel *)createDetailsPanel
|
- (DetailsPanel *)createDetailsPanel
|
||||||
{
|
{
|
||||||
return [[DetailsPanel alloc] initWithPyRef:[model detailsPanel]];
|
NSInteger appMode = [self getAppMode];
|
||||||
}
|
if (appMode == AppModePicture) {
|
||||||
|
return [[DetailsPanelPicture alloc] initWithPyRef:[model detailsPanel]];
|
||||||
- (NSString *)homepageURL
|
}
|
||||||
{
|
else {
|
||||||
return @""; // must be overriden by all editions
|
return [[DetailsPanel alloc] initWithPyRef:[model detailsPanel]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setScanOptions
|
- (void)setScanOptions
|
||||||
{
|
{
|
||||||
}
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSString *scanTypeOptionName;
|
||||||
- (void)initResultColumns:(ResultTable *)aTable
|
NSInteger appMode = [self getAppMode];
|
||||||
{
|
if (appMode == AppModePicture) {
|
||||||
|
scanTypeOptionName = @"scanTypePicture";
|
||||||
|
}
|
||||||
|
else if (appMode == AppModeMusic) {
|
||||||
|
scanTypeOptionName = @"scanTypeMusic";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scanTypeOptionName = @"scanTypeStandard";
|
||||||
|
}
|
||||||
|
[model setScanType:n2i([ud objectForKey:scanTypeOptionName])];
|
||||||
|
[model setMinMatchPercentage:n2i([ud objectForKey:@"minMatchPercentage"])];
|
||||||
|
[model setWordWeighting:n2b([ud objectForKey:@"wordWeighting"])];
|
||||||
|
[model setMixFileKind:n2b([ud objectForKey:@"mixFileKind"])];
|
||||||
|
[model setIgnoreHardlinkMatches:n2b([ud objectForKey:@"ignoreHardlinkMatches"])];
|
||||||
|
[model setMatchSimilarWords:n2b([ud objectForKey:@"matchSimilarWords"])];
|
||||||
|
int smallFileThreshold = [ud integerForKey:@"smallFileThreshold"]; // In KB
|
||||||
|
int sizeThreshold = [ud boolForKey:@"ignoreSmallFiles"] ? smallFileThreshold * 1024 : 0; // The py side wants bytes
|
||||||
|
[model setSizeThreshold:sizeThreshold];
|
||||||
|
[model enable:n2b([ud objectForKey:@"scanTagTrack"]) scanForTag:@"track"];
|
||||||
|
[model enable:n2b([ud objectForKey:@"scanTagArtist"]) scanForTag:@"artist"];
|
||||||
|
[model enable:n2b([ud objectForKey:@"scanTagAlbum"]) scanForTag:@"album"];
|
||||||
|
[model enable:n2b([ud objectForKey:@"scanTagTitle"]) scanForTag:@"title"];
|
||||||
|
[model enable:n2b([ud objectForKey:@"scanTagGenre"]) scanForTag:@"genre"];
|
||||||
|
[model enable:n2b([ud objectForKey:@"scanTagYear"]) scanForTag:@"year"];
|
||||||
|
[model setMatchScaled:n2b([ud objectForKey:@"matchScaled"])];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Public */
|
/* Public */
|
||||||
@ -126,7 +186,29 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
return _recentResults;
|
return _recentResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSInteger)getAppMode
|
||||||
|
{
|
||||||
|
return [model getAppMode];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAppMode:(NSInteger)appMode
|
||||||
|
{
|
||||||
|
[model setAppMode:appMode];
|
||||||
|
if (_preferencesPanel != nil) {
|
||||||
|
[_preferencesPanel release];
|
||||||
|
_preferencesPanel = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
|
- (void)clearPictureCache
|
||||||
|
{
|
||||||
|
NSString *msg = NSLocalizedString(@"Do you really want to remove all your cached picture analysis?", @"");
|
||||||
|
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
||||||
|
return;
|
||||||
|
[model clearPictureCache];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)loadResults
|
- (void)loadResults
|
||||||
{
|
{
|
||||||
NSOpenPanel *op = [NSOpenPanel openPanel];
|
NSOpenPanel *op = [NSOpenPanel openPanel];
|
||||||
@ -145,7 +227,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
|
|
||||||
- (void)openWebsite
|
- (void)openWebsite
|
||||||
{
|
{
|
||||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[self homepageURL]]];
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.hardcoded.net/dupeguru/"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)openHelp
|
- (void)openHelp
|
||||||
@ -172,7 +254,18 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
- (void)showPreferencesPanel
|
- (void)showPreferencesPanel
|
||||||
{
|
{
|
||||||
if (_preferencesPanel == nil) {
|
if (_preferencesPanel == nil) {
|
||||||
_preferencesPanel = [[NSWindowController alloc] initWithWindow:createPreferencesPanel_UI(nil)];
|
NSWindow *window;
|
||||||
|
NSInteger appMode = [model getAppMode];
|
||||||
|
if (appMode == AppModePicture) {
|
||||||
|
window = createPreferencesPanelPicture_UI(nil);
|
||||||
|
}
|
||||||
|
else if (appMode == AppModeMusic) {
|
||||||
|
window = createPreferencesPanelMusic_UI(nil);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window = createPreferencesPanelStandard_UI(nil);
|
||||||
|
}
|
||||||
|
_preferencesPanel = [[NSWindowController alloc] initWithWindow:window];
|
||||||
}
|
}
|
||||||
[_preferencesPanel showWindow:nil];
|
[_preferencesPanel showWindow:nil];
|
||||||
}
|
}
|
||||||
@ -252,6 +345,17 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
return [Dialogs askYesNo:prompt] == NSAlertFirstButtonReturn;
|
return [Dialogs askYesNo:prompt] == NSAlertFirstButtonReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)createResultsWindow
|
||||||
|
{
|
||||||
|
if (_resultWindow != nil) {
|
||||||
|
[_resultWindow release];
|
||||||
|
}
|
||||||
|
if (_detailsPanel != nil) {
|
||||||
|
[_detailsPanel release];
|
||||||
|
}
|
||||||
|
_resultWindow = [[ResultWindow alloc] initWithParentApp:self];
|
||||||
|
_detailsPanel = [self createDetailsPanel];
|
||||||
|
}
|
||||||
- (void)showResultsWindow
|
- (void)showResultsWindow
|
||||||
{
|
{
|
||||||
[[[self resultWindow] window] makeKeyAndOrderFront:nil];
|
[[[self resultWindow] window] makeKeyAndOrderFront:nil];
|
||||||
@ -259,7 +363,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
|
|
||||||
- (void)showProblemDialog
|
- (void)showProblemDialog
|
||||||
{
|
{
|
||||||
[[self resultWindow] showProblemDialog];
|
[_problemDialog showWindow:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)selectDestFolderWithPrompt:(NSString *)prompt
|
- (NSString *)selectDestFolderWithPrompt:(NSString *)prompt
|
@ -17,3 +17,8 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
#define jobDelete @"job_delete"
|
#define jobDelete @"job_delete"
|
||||||
|
|
||||||
#define DGPrioritizeIndexPasteboardType @"DGPrioritizeIndexPasteboardType"
|
#define DGPrioritizeIndexPasteboardType @"DGPrioritizeIndexPasteboardType"
|
||||||
|
#define ImageLoadedNotification @"ImageLoadedNotification"
|
||||||
|
|
||||||
|
#define AppModeStandard 0
|
||||||
|
#define AppModeMusic 1
|
||||||
|
#define AppModePicture 2
|
@ -10,7 +10,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
#import <Python.h>
|
#import <Python.h>
|
||||||
#import "PyDetailsPanel.h"
|
#import "PyDetailsPanel.h"
|
||||||
|
|
||||||
@interface DetailsPanelBase : NSWindowController <NSTableViewDataSource>
|
@interface DetailsPanel : NSWindowController <NSTableViewDataSource>
|
||||||
{
|
{
|
||||||
NSTableView *detailsTable;
|
NSTableView *detailsTable;
|
||||||
|
|
@ -6,10 +6,11 @@ which should be included with this package. The terms are also available at
|
|||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "DetailsPanelBase.h"
|
#import "DetailsPanel.h"
|
||||||
#import "HSPyUtil.h"
|
#import "HSPyUtil.h"
|
||||||
|
#import "DetailsPanel_UI.h"
|
||||||
|
|
||||||
@implementation DetailsPanelBase
|
@implementation DetailsPanel
|
||||||
|
|
||||||
@synthesize detailsTable;
|
@synthesize detailsTable;
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
|
|
||||||
- (NSWindow *)createWindow
|
- (NSWindow *)createWindow
|
||||||
{
|
{
|
||||||
return nil; // Virtual
|
return createDetailsPanel_UI(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)refreshDetails
|
- (void)refreshDetails
|
@ -7,10 +7,10 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "DetailsPanelBase.h"
|
#import "DetailsPanel.h"
|
||||||
#import "PyDupeGuru.h"
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
@interface DetailsPanel : DetailsPanelBase
|
@interface DetailsPanelPicture : DetailsPanel
|
||||||
{
|
{
|
||||||
NSImageView *dupeImage;
|
NSImageView *dupeImage;
|
||||||
NSProgressIndicator *dupeProgressIndicator;
|
NSProgressIndicator *dupeProgressIndicator;
|
@ -10,11 +10,11 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
#import "NSNotificationAdditions.h"
|
#import "NSNotificationAdditions.h"
|
||||||
#import "NSImageAdditions.h"
|
#import "NSImageAdditions.h"
|
||||||
#import "PyDupeGuru.h"
|
#import "PyDupeGuru.h"
|
||||||
#import "DetailsPanel.h"
|
#import "DetailsPanelPicture.h"
|
||||||
#import "Consts.h"
|
#import "Consts.h"
|
||||||
#import "DetailsPanel_UI.h"
|
#import "DetailsPanelPicture_UI.h"
|
||||||
|
|
||||||
@implementation DetailsPanel
|
@implementation DetailsPanelPicture
|
||||||
|
|
||||||
@synthesize dupeImage;
|
@synthesize dupeImage;
|
||||||
@synthesize dupeProgressIndicator;
|
@synthesize dupeProgressIndicator;
|
||||||
@ -32,7 +32,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
|
|
||||||
- (NSWindow *)createWindow
|
- (NSWindow *)createWindow
|
||||||
{
|
{
|
||||||
return createDetailsPanel_UI(self);
|
return createDetailsPanelPicture_UI(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)loadImageAsync:(NSString *)imagePath
|
- (void)loadImageAsync:(NSString *)imagePath
|
@ -12,15 +12,16 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
#import "DirectoryOutline.h"
|
#import "DirectoryOutline.h"
|
||||||
#import "PyDupeGuru.h"
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
@class AppDelegateBase;
|
@class AppDelegate;
|
||||||
|
|
||||||
@interface DirectoryPanel : NSWindowController <NSOpenSavePanelDelegate>
|
@interface DirectoryPanel : NSWindowController <NSOpenSavePanelDelegate>
|
||||||
{
|
{
|
||||||
AppDelegateBase *_app;
|
AppDelegate *_app;
|
||||||
PyDupeGuru *model;
|
PyDupeGuru *model;
|
||||||
HSRecentFiles *_recentDirectories;
|
HSRecentFiles *_recentDirectories;
|
||||||
DirectoryOutline *outline;
|
DirectoryOutline *outline;
|
||||||
BOOL _alwaysShowPopUp;
|
BOOL _alwaysShowPopUp;
|
||||||
|
NSSegmentedControl *appModeSelector;
|
||||||
NSPopUpButton *scanTypePopup;
|
NSPopUpButton *scanTypePopup;
|
||||||
NSPopUpButton *addButtonPopUp;
|
NSPopUpButton *addButtonPopUp;
|
||||||
NSPopUpButton *loadRecentButtonPopUp;
|
NSPopUpButton *loadRecentButtonPopUp;
|
||||||
@ -29,6 +30,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
NSButton *loadResultsButton;
|
NSButton *loadResultsButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property (readwrite, retain) NSSegmentedControl *appModeSelector;
|
||||||
@property (readwrite, retain) NSPopUpButton *scanTypePopup;
|
@property (readwrite, retain) NSPopUpButton *scanTypePopup;
|
||||||
@property (readwrite, retain) NSPopUpButton *addButtonPopUp;
|
@property (readwrite, retain) NSPopUpButton *addButtonPopUp;
|
||||||
@property (readwrite, retain) NSPopUpButton *loadRecentButtonPopUp;
|
@property (readwrite, retain) NSPopUpButton *loadRecentButtonPopUp;
|
||||||
@ -36,9 +38,10 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
@property (readwrite, retain) NSButton *removeButton;
|
@property (readwrite, retain) NSButton *removeButton;
|
||||||
@property (readwrite, retain) NSButton *loadResultsButton;
|
@property (readwrite, retain) NSButton *loadResultsButton;
|
||||||
|
|
||||||
- (id)initWithParentApp:(AppDelegateBase *)aParentApp;
|
- (id)initWithParentApp:(AppDelegate *)aParentApp;
|
||||||
|
|
||||||
- (void)fillPopUpMenu; // Virtual
|
- (void)fillPopUpMenu;
|
||||||
|
- (void)fillScanTypeMenu;
|
||||||
- (void)adjustUIToLocalization;
|
- (void)adjustUIToLocalization;
|
||||||
|
|
||||||
- (void)askForDirectory;
|
- (void)askForDirectory;
|
@ -11,9 +11,11 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
#import "Dialogs.h"
|
#import "Dialogs.h"
|
||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
|
#import "Consts.h"
|
||||||
|
|
||||||
@implementation DirectoryPanel
|
@implementation DirectoryPanel
|
||||||
|
|
||||||
|
@synthesize appModeSelector;
|
||||||
@synthesize scanTypePopup;
|
@synthesize scanTypePopup;
|
||||||
@synthesize addButtonPopUp;
|
@synthesize addButtonPopUp;
|
||||||
@synthesize loadRecentButtonPopUp;
|
@synthesize loadRecentButtonPopUp;
|
||||||
@ -21,15 +23,15 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
@synthesize removeButton;
|
@synthesize removeButton;
|
||||||
@synthesize loadResultsButton;
|
@synthesize loadResultsButton;
|
||||||
|
|
||||||
- (id)initWithParentApp:(AppDelegateBase *)aParentApp
|
- (id)initWithParentApp:(AppDelegate *)aParentApp
|
||||||
{
|
{
|
||||||
self = [super initWithWindow:nil];
|
self = [super initWithWindow:nil];
|
||||||
[self setWindow:createDirectoryPanel_UI(self)];
|
[self setWindow:createDirectoryPanel_UI(self)];
|
||||||
_app = aParentApp;
|
_app = aParentApp;
|
||||||
model = [_app model];
|
model = [_app model];
|
||||||
[[self window] setTitle:[model appName]];
|
[[self window] setTitle:[model appName]];
|
||||||
[[self scanTypePopup] addItemsWithTitles:[[aParentApp model] getScanOptions]];
|
self.appModeSelector.selectedSegment = 0;
|
||||||
[[self scanTypePopup] bind:@"selectedIndex" toObject:[NSUserDefaultsController sharedUserDefaultsController] withKeyPath:@"values.scanType" options:nil];
|
[self fillScanTypeMenu];
|
||||||
_alwaysShowPopUp = NO;
|
_alwaysShowPopUp = NO;
|
||||||
[self fillPopUpMenu];
|
[self fillPopUpMenu];
|
||||||
_recentDirectories = [[HSRecentFiles alloc] initWithName:@"recentDirectories" menu:[addButtonPopUp menu]];
|
_recentDirectories = [[HSRecentFiles alloc] initWithName:@"recentDirectories" menu:[addButtonPopUp menu]];
|
||||||
@ -62,6 +64,25 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
[m addItem:[NSMenuItem separatorItem]];
|
[m addItem:[NSMenuItem separatorItem]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)fillScanTypeMenu
|
||||||
|
{
|
||||||
|
[[self scanTypePopup] unbind:@"selectedIndex"];
|
||||||
|
[[self scanTypePopup] removeAllItems];
|
||||||
|
[[self scanTypePopup] addItemsWithTitles:[[_app model] getScanOptions]];
|
||||||
|
NSString *keypath;
|
||||||
|
NSInteger appMode = [_app getAppMode];
|
||||||
|
if (appMode == AppModePicture) {
|
||||||
|
keypath = @"values.scanTypePicture";
|
||||||
|
}
|
||||||
|
else if (appMode == AppModeMusic) {
|
||||||
|
keypath = @"values.scanTypeMusic";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
keypath = @"values.scanTypeStandard";
|
||||||
|
}
|
||||||
|
[[self scanTypePopup] bind:@"selectedIndex" toObject:[NSUserDefaultsController sharedUserDefaultsController] withKeyPath:keypath options:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)adjustUIToLocalization
|
- (void)adjustUIToLocalization
|
||||||
{
|
{
|
||||||
NSString *lang = [[NSBundle preferredLocalizationsFromArray:[[NSBundle mainBundle] localizations]] objectAtIndex:0];
|
NSString *lang = [[NSBundle preferredLocalizationsFromArray:[[NSBundle mainBundle] localizations]] objectAtIndex:0];
|
||||||
@ -100,6 +121,23 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)changeAppMode:(id)sender
|
||||||
|
{
|
||||||
|
NSInteger appMode;
|
||||||
|
NSUInteger selectedSegment = self.appModeSelector.selectedSegment;
|
||||||
|
if (selectedSegment == 2) {
|
||||||
|
appMode = AppModePicture;
|
||||||
|
}
|
||||||
|
else if (selectedSegment == 1) {
|
||||||
|
appMode = AppModeMusic;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appMode = AppModeStandard;
|
||||||
|
}
|
||||||
|
[_app setAppMode:appMode];
|
||||||
|
[self fillScanTypeMenu];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)popupAddDirectoryMenu:(id)sender
|
- (void)popupAddDirectoryMenu:(id)sender
|
||||||
{
|
{
|
||||||
if ((!_alwaysShowPopUp) && ([[_recentDirectories filepaths] count] == 0)) {
|
if ((!_alwaysShowPopUp) && ([[_recentDirectories filepaths] count] == 0)) {
|
@ -10,12 +10,10 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
#import <Quartz/Quartz.h>
|
#import <Quartz/Quartz.h>
|
||||||
#import "StatsLabel.h"
|
#import "StatsLabel.h"
|
||||||
#import "ResultTable.h"
|
#import "ResultTable.h"
|
||||||
#import "ProblemDialog.h"
|
|
||||||
#import "DeletionOptions.h"
|
|
||||||
#import "HSTableView.h"
|
#import "HSTableView.h"
|
||||||
#import "PyDupeGuru.h"
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
@class AppDelegateBase;
|
@class AppDelegate;
|
||||||
|
|
||||||
@interface ResultWindow : NSWindowController
|
@interface ResultWindow : NSWindowController
|
||||||
{
|
{
|
||||||
@ -26,12 +24,10 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
NSTextField *stats;
|
NSTextField *stats;
|
||||||
NSSearchField *filterField;
|
NSSearchField *filterField;
|
||||||
|
|
||||||
AppDelegateBase *app;
|
AppDelegate *app;
|
||||||
PyDupeGuru *model;
|
PyDupeGuru *model;
|
||||||
ResultTable *table;
|
ResultTable *table;
|
||||||
StatsLabel *statsLabel;
|
StatsLabel *statsLabel;
|
||||||
ProblemDialog *problemDialog;
|
|
||||||
DeletionOptions *deletionOptions;
|
|
||||||
QLPreviewPanel* previewPanel;
|
QLPreviewPanel* previewPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,13 +37,13 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
@property (readwrite, retain) NSTextField *stats;
|
@property (readwrite, retain) NSTextField *stats;
|
||||||
@property (readwrite, retain) NSSearchField *filterField;
|
@property (readwrite, retain) NSSearchField *filterField;
|
||||||
|
|
||||||
- (id)initWithParentApp:(AppDelegateBase *)app;
|
- (id)initWithParentApp:(AppDelegate *)app;
|
||||||
|
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
- (void)fillColumnsMenu;
|
- (void)fillColumnsMenu;
|
||||||
- (void)updateOptionSegments;
|
- (void)updateOptionSegments;
|
||||||
- (void)showProblemDialog;
|
|
||||||
- (void)adjustUIToLocalization;
|
- (void)adjustUIToLocalization;
|
||||||
|
- (void)initResultColumns:(ResultTable *)aTable;
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
- (void)changeOptions;
|
- (void)changeOptions;
|
@ -23,7 +23,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
@synthesize stats;
|
@synthesize stats;
|
||||||
@synthesize filterField;
|
@synthesize filterField;
|
||||||
|
|
||||||
- (id)initWithParentApp:(AppDelegateBase *)aApp;
|
- (id)initWithParentApp:(AppDelegate *)aApp;
|
||||||
{
|
{
|
||||||
self = [super initWithWindow:nil];
|
self = [super initWithWindow:nil];
|
||||||
app = aApp;
|
app = aApp;
|
||||||
@ -34,9 +34,7 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
[[self window] setContentBorderThickness:28 forEdge:NSMinYEdge];
|
[[self window] setContentBorderThickness:28 forEdge:NSMinYEdge];
|
||||||
table = [[ResultTable alloc] initWithPyRef:[model resultTable] view:matches];
|
table = [[ResultTable alloc] initWithPyRef:[model resultTable] view:matches];
|
||||||
statsLabel = [[StatsLabel alloc] initWithPyRef:[model statsLabel] view:stats];
|
statsLabel = [[StatsLabel alloc] initWithPyRef:[model statsLabel] view:stats];
|
||||||
problemDialog = [[ProblemDialog alloc] initWithPyRef:[model problemDialog]];
|
[self initResultColumns:table];
|
||||||
deletionOptions = [[DeletionOptions alloc] initWithPyRef:[model deletionOptions]];
|
|
||||||
[aApp initResultColumns:table];
|
|
||||||
[[table columns] setColumnsAsReadOnly];
|
[[table columns] setColumnsAsReadOnly];
|
||||||
[self fillColumnsMenu];
|
[self fillColumnsMenu];
|
||||||
[matches setTarget:self];
|
[matches setTarget:self];
|
||||||
@ -49,7 +47,6 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
{
|
{
|
||||||
[table release];
|
[table release];
|
||||||
[statsLabel release];
|
[statsLabel release];
|
||||||
[problemDialog release];
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,11 +77,6 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
[optionsSwitch setSelected:[table deltaValuesMode] forSegment:2];
|
[optionsSwitch setSelected:[table deltaValuesMode] forSegment:2];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showProblemDialog
|
|
||||||
{
|
|
||||||
[problemDialog showWindow:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)adjustUIToLocalization
|
- (void)adjustUIToLocalization
|
||||||
{
|
{
|
||||||
NSString *lang = [[NSBundle preferredLocalizationsFromArray:[[NSBundle mainBundle] localizations]] objectAtIndex:0];
|
NSString *lang = [[NSBundle preferredLocalizationsFromArray:[[NSBundle mainBundle] localizations]] objectAtIndex:0];
|
||||||
@ -109,6 +101,87 @@ http://www.gnu.org/licenses/gpl-3.0.html
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)initResultColumns:(ResultTable *)aTable
|
||||||
|
{
|
||||||
|
NSInteger appMode = [app getAppMode];
|
||||||
|
if (appMode == AppModePicture) {
|
||||||
|
HSColumnDef defs[] = {
|
||||||
|
{@"marked", 26, 26, 26, YES, [NSButtonCell class]},
|
||||||
|
{@"name", 162, 16, 0, YES, nil},
|
||||||
|
{@"folder_path", 142, 16, 0, YES, nil},
|
||||||
|
{@"size", 63, 16, 0, YES, nil},
|
||||||
|
{@"extension", 40, 16, 0, YES, nil},
|
||||||
|
{@"dimensions", 73, 16, 0, YES, nil},
|
||||||
|
{@"exif_timestamp", 120, 16, 0, YES, nil},
|
||||||
|
{@"mtime", 120, 16, 0, YES, nil},
|
||||||
|
{@"percentage", 58, 16, 0, YES, nil},
|
||||||
|
{@"dupe_count", 80, 16, 0, YES, nil},
|
||||||
|
nil
|
||||||
|
};
|
||||||
|
[[aTable columns] initializeColumns:defs];
|
||||||
|
NSTableColumn *c = [[aTable view] tableColumnWithIdentifier:@"marked"];
|
||||||
|
[[c dataCell] setButtonType:NSSwitchButton];
|
||||||
|
[[c dataCell] setControlSize:NSSmallControlSize];
|
||||||
|
c = [[aTable view] tableColumnWithIdentifier:@"size"];
|
||||||
|
[[c dataCell] setAlignment:NSRightTextAlignment];
|
||||||
|
}
|
||||||
|
else if (appMode == AppModeMusic) {
|
||||||
|
HSColumnDef defs[] = {
|
||||||
|
{@"marked", 26, 26, 26, YES, [NSButtonCell class]},
|
||||||
|
{@"name", 235, 16, 0, YES, nil},
|
||||||
|
{@"folder_path", 120, 16, 0, YES, nil},
|
||||||
|
{@"size", 63, 16, 0, YES, nil},
|
||||||
|
{@"duration", 50, 16, 0, YES, nil},
|
||||||
|
{@"bitrate", 50, 16, 0, YES, nil},
|
||||||
|
{@"samplerate", 60, 16, 0, YES, nil},
|
||||||
|
{@"extension", 40, 16, 0, YES, nil},
|
||||||
|
{@"mtime", 120, 16, 0, YES, nil},
|
||||||
|
{@"title", 120, 16, 0, YES, nil},
|
||||||
|
{@"artist", 120, 16, 0, YES, nil},
|
||||||
|
{@"album", 120, 16, 0, YES, nil},
|
||||||
|
{@"genre", 80, 16, 0, YES, nil},
|
||||||
|
{@"year", 40, 16, 0, YES, nil},
|
||||||
|
{@"track", 40, 16, 0, YES, nil},
|
||||||
|
{@"comment", 120, 16, 0, YES, nil},
|
||||||
|
{@"percentage", 57, 16, 0, YES, nil},
|
||||||
|
{@"words", 120, 16, 0, YES, nil},
|
||||||
|
{@"dupe_count", 80, 16, 0, YES, nil},
|
||||||
|
nil
|
||||||
|
};
|
||||||
|
[[aTable columns] initializeColumns:defs];
|
||||||
|
NSTableColumn *c = [[aTable view] tableColumnWithIdentifier:@"marked"];
|
||||||
|
[[c dataCell] setButtonType:NSSwitchButton];
|
||||||
|
[[c dataCell] setControlSize:NSSmallControlSize];
|
||||||
|
c = [[aTable view] tableColumnWithIdentifier:@"size"];
|
||||||
|
[[c dataCell] setAlignment:NSRightTextAlignment];
|
||||||
|
c = [[aTable view] tableColumnWithIdentifier:@"duration"];
|
||||||
|
[[c dataCell] setAlignment:NSRightTextAlignment];
|
||||||
|
c = [[aTable view] tableColumnWithIdentifier:@"bitrate"];
|
||||||
|
[[c dataCell] setAlignment:NSRightTextAlignment];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
HSColumnDef defs[] = {
|
||||||
|
{@"marked", 26, 26, 26, YES, [NSButtonCell class]},
|
||||||
|
{@"name", 195, 16, 0, YES, nil},
|
||||||
|
{@"folder_path", 183, 16, 0, YES, nil},
|
||||||
|
{@"size", 63, 16, 0, YES, nil},
|
||||||
|
{@"extension", 40, 16, 0, YES, nil},
|
||||||
|
{@"mtime", 120, 16, 0, YES, nil},
|
||||||
|
{@"percentage", 60, 16, 0, YES, nil},
|
||||||
|
{@"words", 120, 16, 0, YES, nil},
|
||||||
|
{@"dupe_count", 80, 16, 0, YES, nil},
|
||||||
|
nil
|
||||||
|
};
|
||||||
|
[[aTable columns] initializeColumns:defs];
|
||||||
|
NSTableColumn *c = [[aTable view] tableColumnWithIdentifier:@"marked"];
|
||||||
|
[[c dataCell] setButtonType:NSSwitchButton];
|
||||||
|
[[c dataCell] setControlSize:NSSmallControlSize];
|
||||||
|
c = [[aTable view] tableColumnWithIdentifier:@"size"];
|
||||||
|
[[c dataCell] setAlignment:NSRightTextAlignment];
|
||||||
|
}
|
||||||
|
[[aTable columns] restoreColumns];
|
||||||
|
}
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
- (void)changeOptions
|
- (void)changeOptions
|
||||||
{
|
{
|
@ -6,6 +6,7 @@ from cocoa.inter import PyBaseApp, BaseAppView
|
|||||||
|
|
||||||
class DupeGuruView(BaseAppView):
|
class DupeGuruView(BaseAppView):
|
||||||
def askYesNoWithPrompt_(self, prompt: str) -> bool: pass
|
def askYesNoWithPrompt_(self, prompt: str) -> bool: pass
|
||||||
|
def createResultsWindow(self): pass
|
||||||
def showResultsWindow(self): pass
|
def showResultsWindow(self): pass
|
||||||
def showProblemDialog(self): pass
|
def showProblemDialog(self): pass
|
||||||
def selectDestFolderWithPrompt_(self, prompt: str) -> str: pass
|
def selectDestFolderWithPrompt_(self, prompt: str) -> str: pass
|
||||||
@ -123,6 +124,9 @@ class PyDupeGuruBase(PyBaseApp):
|
|||||||
def showIgnoreList(self):
|
def showIgnoreList(self):
|
||||||
self.model.ignore_list_dialog.show()
|
self.model.ignore_list_dialog.show()
|
||||||
|
|
||||||
|
def clearPictureCache(self):
|
||||||
|
self.model.clear_picture_cache()
|
||||||
|
|
||||||
#---Information
|
#---Information
|
||||||
def getScanOptions(self) -> list:
|
def getScanOptions(self) -> list:
|
||||||
return [o.label for o in self.model.SCANNER_CLASS.get_scan_options()]
|
return [o.label for o in self.model.SCANNER_CLASS.get_scan_options()]
|
||||||
@ -130,7 +134,50 @@ class PyDupeGuruBase(PyBaseApp):
|
|||||||
def resultsAreModified(self) -> bool:
|
def resultsAreModified(self) -> bool:
|
||||||
return self.model.results.is_modified
|
return self.model.results.is_modified
|
||||||
|
|
||||||
|
def getSelectedDupePath(self) -> str:
|
||||||
|
return str(self.model.selected_dupe_path())
|
||||||
|
|
||||||
|
def getSelectedDupeRefPath(self) -> str:
|
||||||
|
return str(self.model.selected_dupe_ref_path())
|
||||||
|
|
||||||
#---Properties
|
#---Properties
|
||||||
|
def getAppMode(self) -> int:
|
||||||
|
return self.model.app_mode
|
||||||
|
|
||||||
|
def setAppMode_(self, app_mode: int):
|
||||||
|
self.model.app_mode = app_mode
|
||||||
|
|
||||||
|
def setScanType_(self, scan_type_index: int):
|
||||||
|
scan_options = self.model.SCANNER_CLASS.get_scan_options()
|
||||||
|
try:
|
||||||
|
so = scan_options[scan_type_index]
|
||||||
|
self.model.options['scan_type'] = so.scan_type
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def setMinMatchPercentage_(self, percentage: int):
|
||||||
|
self.model.options['min_match_percentage'] = int(percentage)
|
||||||
|
|
||||||
|
def setWordWeighting_(self, words_are_weighted: bool):
|
||||||
|
self.model.options['word_weighting'] = words_are_weighted
|
||||||
|
|
||||||
|
def setMatchSimilarWords_(self, match_similar_words: bool):
|
||||||
|
self.model.options['match_similar_words'] = match_similar_words
|
||||||
|
|
||||||
|
def setSizeThreshold_(self, size_threshold: int):
|
||||||
|
self.model.options['size_threshold'] = size_threshold
|
||||||
|
|
||||||
|
def enable_scanForTag_(self, enable: bool, scan_tag: str):
|
||||||
|
if 'scanned_tags' not in self.model.options:
|
||||||
|
self.model.options['scanned_tags'] = set()
|
||||||
|
if enable:
|
||||||
|
self.model.options['scanned_tags'].add(scan_tag)
|
||||||
|
else:
|
||||||
|
self.model.options['scanned_tags'].discard(scan_tag)
|
||||||
|
|
||||||
|
def setMatchScaled_(self, match_scaled: bool):
|
||||||
|
self.model.options['match_scaled'] = match_scaled
|
||||||
|
|
||||||
def setMixFileKind_(self, mix_file_kind: bool):
|
def setMixFileKind_(self, mix_file_kind: bool):
|
||||||
self.model.options['mix_file_kind'] = mix_file_kind
|
self.model.options['mix_file_kind'] = mix_file_kind
|
||||||
|
|
||||||
@ -151,6 +198,10 @@ class PyDupeGuruBase(PyBaseApp):
|
|||||||
def ask_yes_no(self, prompt):
|
def ask_yes_no(self, prompt):
|
||||||
return self.callback.askYesNoWithPrompt_(prompt)
|
return self.callback.askYesNoWithPrompt_(prompt)
|
||||||
|
|
||||||
|
@dontwrap
|
||||||
|
def create_results_window(self):
|
||||||
|
self.callback.createResultsWindow()
|
||||||
|
|
||||||
@dontwrap
|
@dontwrap
|
||||||
def show_results_window(self):
|
def show_results_window(self):
|
||||||
self.callback.showResultsWindow()
|
self.callback.showResultsWindow()
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
# Copyright 2016 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
#
|
|
||||||
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
# which should be included with this package. The terms are also available at
|
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
|
|
||||||
from hscommon.trans import trget
|
|
||||||
|
|
||||||
from core.scanner import ScanType
|
|
||||||
from core_me.app import DupeGuru as DupeGuruME
|
|
||||||
from .app import PyDupeGuruBase
|
|
||||||
|
|
||||||
tr = trget('ui')
|
|
||||||
|
|
||||||
class PyDupeGuru(PyDupeGuruBase):
|
|
||||||
def __init__(self):
|
|
||||||
self._init(DupeGuruME)
|
|
||||||
|
|
||||||
#---Properties
|
|
||||||
def setMinMatchPercentage_(self, percentage: int):
|
|
||||||
self.model.options['min_match_percentage'] = percentage
|
|
||||||
|
|
||||||
def setScanType_(self, scan_type: int):
|
|
||||||
try:
|
|
||||||
self.model.options['scan_type'] = [
|
|
||||||
ScanType.Filename,
|
|
||||||
ScanType.Fields,
|
|
||||||
ScanType.FieldsNoOrder,
|
|
||||||
ScanType.Tag,
|
|
||||||
ScanType.Contents,
|
|
||||||
ScanType.ContentsAudio,
|
|
||||||
][scan_type]
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def setWordWeighting_(self, words_are_weighted: bool):
|
|
||||||
self.model.options['word_weighting'] = words_are_weighted
|
|
||||||
|
|
||||||
def setMatchSimilarWords_(self, match_similar_words: bool):
|
|
||||||
self.model.options['match_similar_words'] = match_similar_words
|
|
||||||
|
|
||||||
def enable_scanForTag_(self, enable: bool, scan_tag: str):
|
|
||||||
if 'scanned_tags' not in self.model.options:
|
|
||||||
self.model.options['scanned_tags'] = set()
|
|
||||||
if enable:
|
|
||||||
self.model.options['scanned_tags'].add(scan_tag)
|
|
||||||
else:
|
|
||||||
self.model.options['scanned_tags'].discard(scan_tag)
|
|
@ -1,90 +0,0 @@
|
|||||||
# Copyright 2016 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
#
|
|
||||||
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
# which should be included with this package. The terms are also available at
|
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
|
|
||||||
from cocoa import proxy
|
|
||||||
|
|
||||||
from core.scanner import ScanType
|
|
||||||
from core_pe import _block_osx
|
|
||||||
from core_pe.photo import Photo as PhotoBase
|
|
||||||
from core_pe.app import DupeGuru as DupeGuruBase
|
|
||||||
from .app import PyDupeGuruBase
|
|
||||||
|
|
||||||
|
|
||||||
class Photo(PhotoBase):
|
|
||||||
HANDLED_EXTS = PhotoBase.HANDLED_EXTS.copy()
|
|
||||||
HANDLED_EXTS.update({'psd', 'nef', 'cr2', 'orf'})
|
|
||||||
|
|
||||||
def _plat_get_dimensions(self):
|
|
||||||
return _block_osx.get_image_size(str(self.path))
|
|
||||||
|
|
||||||
def _plat_get_blocks(self, block_count_per_side, orientation):
|
|
||||||
try:
|
|
||||||
blocks = _block_osx.getblocks(str(self.path), block_count_per_side, orientation)
|
|
||||||
except Exception as e:
|
|
||||||
raise IOError('The reading of "%s" failed with "%s"' % (str(self.path), str(e)))
|
|
||||||
if not blocks:
|
|
||||||
raise IOError('The picture %s could not be read' % str(self.path))
|
|
||||||
return blocks
|
|
||||||
|
|
||||||
def _get_exif_timestamp(self):
|
|
||||||
exifdata = proxy.readExifData_(str(self.path))
|
|
||||||
if exifdata:
|
|
||||||
try:
|
|
||||||
return exifdata['{Exif}']['DateTimeOriginal']
|
|
||||||
except KeyError:
|
|
||||||
return ''
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
class DupeGuruPE(DupeGuruBase):
|
|
||||||
def __init__(self, view):
|
|
||||||
DupeGuruBase.__init__(self, view)
|
|
||||||
self.fileclasses = [Photo]
|
|
||||||
|
|
||||||
def selected_dupe_path(self):
|
|
||||||
if not self.selected_dupes:
|
|
||||||
return None
|
|
||||||
return self.selected_dupes[0].path
|
|
||||||
|
|
||||||
def selected_dupe_ref_path(self):
|
|
||||||
if not self.selected_dupes:
|
|
||||||
return None
|
|
||||||
ref = self.results.get_group_of_duplicate(self.selected_dupes[0]).ref
|
|
||||||
if ref is self.selected_dupes[0]: # we don't want the same pic to be displayed on both sides
|
|
||||||
return None
|
|
||||||
return ref.path
|
|
||||||
|
|
||||||
|
|
||||||
class PyDupeGuru(PyDupeGuruBase):
|
|
||||||
def __init__(self):
|
|
||||||
self._init(DupeGuruPE)
|
|
||||||
|
|
||||||
def clearPictureCache(self):
|
|
||||||
self.model.clear_picture_cache()
|
|
||||||
|
|
||||||
#---Information
|
|
||||||
def getSelectedDupePath(self) -> str:
|
|
||||||
return str(self.model.selected_dupe_path())
|
|
||||||
|
|
||||||
def getSelectedDupeRefPath(self) -> str:
|
|
||||||
return str(self.model.selected_dupe_ref_path())
|
|
||||||
|
|
||||||
#---Properties
|
|
||||||
def setScanType_(self, scan_type: int):
|
|
||||||
try:
|
|
||||||
self.model.options['scan_type'] = [
|
|
||||||
ScanType.FuzzyBlock,
|
|
||||||
ScanType.ExifTimestamp,
|
|
||||||
][scan_type]
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def setMatchScaled_(self, match_scaled: bool):
|
|
||||||
self.model.options['match_scaled'] = match_scaled
|
|
||||||
|
|
||||||
def setMinMatchPercentage_(self, percentage: int):
|
|
||||||
self.model.options['threshold'] = percentage
|
|
@ -12,10 +12,12 @@ import os.path as op
|
|||||||
from hscommon.path import Path, pathify
|
from hscommon.path import Path, pathify
|
||||||
from cocoa import proxy
|
from cocoa import proxy
|
||||||
|
|
||||||
from core.scanner import ScanType
|
|
||||||
from core.directories import Directories as DirectoriesBase, DirectoryState
|
from core.directories import Directories as DirectoriesBase, DirectoryState
|
||||||
from core_se.app import DupeGuru as DupeGuruBase
|
import core.pe.photo
|
||||||
from core_se import fs
|
from core.pe import _block_osx
|
||||||
|
from core.pe.photo import Photo as PhotoBase
|
||||||
|
from core.app import DupeGuru as DupeGuruBase, AppMode
|
||||||
|
from core.se import fs
|
||||||
from .app import PyDupeGuruBase
|
from .app import PyDupeGuruBase
|
||||||
|
|
||||||
def is_bundle(str_path):
|
def is_bundle(str_path):
|
||||||
@ -31,13 +33,37 @@ class Bundle(fs.Folder):
|
|||||||
return not path.islink() and path.isdir() and is_bundle(str(path))
|
return not path.islink() and path.isdir() and is_bundle(str(path))
|
||||||
|
|
||||||
|
|
||||||
|
class Photo(PhotoBase):
|
||||||
|
HANDLED_EXTS = PhotoBase.HANDLED_EXTS.copy()
|
||||||
|
HANDLED_EXTS.update({'psd', 'nef', 'cr2', 'orf'})
|
||||||
|
|
||||||
|
def _plat_get_dimensions(self):
|
||||||
|
return _block_osx.get_image_size(str(self.path))
|
||||||
|
|
||||||
|
def _plat_get_blocks(self, block_count_per_side, orientation):
|
||||||
|
try:
|
||||||
|
blocks = _block_osx.getblocks(str(self.path), block_count_per_side, orientation)
|
||||||
|
except Exception as e:
|
||||||
|
raise IOError('The reading of "%s" failed with "%s"' % (str(self.path), str(e)))
|
||||||
|
if not blocks:
|
||||||
|
raise IOError('The picture %s could not be read' % str(self.path))
|
||||||
|
return blocks
|
||||||
|
|
||||||
|
def _get_exif_timestamp(self):
|
||||||
|
exifdata = proxy.readExifData_(str(self.path))
|
||||||
|
if exifdata:
|
||||||
|
try:
|
||||||
|
return exifdata['{Exif}']['DateTimeOriginal']
|
||||||
|
except KeyError:
|
||||||
|
return ''
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
class Directories(DirectoriesBase):
|
class Directories(DirectoriesBase):
|
||||||
ROOT_PATH_TO_EXCLUDE = list(map(Path, ['/Library', '/Volumes', '/System', '/bin', '/sbin', '/opt', '/private', '/dev']))
|
ROOT_PATH_TO_EXCLUDE = list(map(Path, ['/Library', '/Volumes', '/System', '/bin', '/sbin', '/opt', '/private', '/dev']))
|
||||||
HOME_PATH_TO_EXCLUDE = [Path('Library')]
|
HOME_PATH_TO_EXCLUDE = [Path('Library')]
|
||||||
def __init__(self):
|
|
||||||
DirectoriesBase.__init__(self)
|
|
||||||
self.folderclass = fs.Folder
|
|
||||||
|
|
||||||
def _default_state_for_path(self, path):
|
def _default_state_for_path(self, path):
|
||||||
result = DirectoriesBase._default_state_for_path(self, path)
|
result = DirectoriesBase._default_state_for_path(self, path)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
@ -58,8 +84,7 @@ class Directories(DirectoriesBase):
|
|||||||
yield from_folder
|
yield from_folder
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
for folder in DirectoriesBase._get_folders(self, from_folder, j):
|
yield from DirectoriesBase._get_folders(self, from_folder, j)
|
||||||
yield folder
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_subfolders(path):
|
def get_subfolders(path):
|
||||||
@ -69,37 +94,31 @@ class Directories(DirectoriesBase):
|
|||||||
|
|
||||||
class DupeGuru(DupeGuruBase):
|
class DupeGuru(DupeGuruBase):
|
||||||
def __init__(self, view):
|
def __init__(self, view):
|
||||||
# appdata = op.join(appdata, 'dupeGuru')
|
|
||||||
# print(repr(appdata))
|
|
||||||
DupeGuruBase.__init__(self, view)
|
DupeGuruBase.__init__(self, view)
|
||||||
self.fileclasses = [Bundle, fs.File]
|
|
||||||
self.directories = Directories()
|
self.directories = Directories()
|
||||||
|
|
||||||
|
def selected_dupe_path(self):
|
||||||
|
if not self.selected_dupes:
|
||||||
|
return None
|
||||||
|
return self.selected_dupes[0].path
|
||||||
|
|
||||||
|
def selected_dupe_ref_path(self):
|
||||||
|
if not self.selected_dupes:
|
||||||
|
return None
|
||||||
|
ref = self.results.get_group_of_duplicate(self.selected_dupes[0]).ref
|
||||||
|
if ref is self.selected_dupes[0]: # we don't want the same pic to be displayed on both sides
|
||||||
|
return None
|
||||||
|
return ref.path
|
||||||
|
|
||||||
|
def _get_fileclasses(self):
|
||||||
|
result = DupeGuruBase._get_fileclasses(self)
|
||||||
|
if self.app_mode == AppMode.Standard:
|
||||||
|
result = [Bundle] + result
|
||||||
|
return result
|
||||||
|
|
||||||
class PyDupeGuru(PyDupeGuruBase):
|
class PyDupeGuru(PyDupeGuruBase):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
core.pe.photo.PLAT_SPECIFIC_PHOTO_CLASS = Photo
|
||||||
self._init(DupeGuru)
|
self._init(DupeGuru)
|
||||||
|
|
||||||
#---Properties
|
|
||||||
def setMinMatchPercentage_(self, percentage: int):
|
|
||||||
self.model.options['min_match_percentage'] = int(percentage)
|
|
||||||
|
|
||||||
def setScanType_(self, scan_type: int):
|
|
||||||
try:
|
|
||||||
self.model.options['scan_type'] = [
|
|
||||||
ScanType.Filename,
|
|
||||||
ScanType.Contents,
|
|
||||||
ScanType.Folders,
|
|
||||||
][scan_type]
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def setWordWeighting_(self, words_are_weighted: bool):
|
|
||||||
self.model.options['word_weighting'] = words_are_weighted
|
|
||||||
|
|
||||||
def setMatchSimilarWords_(self, match_similar_words: bool):
|
|
||||||
self.model.options['match_similar_words'] = match_similar_words
|
|
||||||
|
|
||||||
def setSizeThreshold_(self, size_threshold: int):
|
|
||||||
self.model.options['size_threshold'] = size_threshold
|
|
||||||
|
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import "AppDelegateBase.h"
|
|
||||||
#import "ResultWindow.h"
|
|
||||||
#import "PyDupeGuru.h"
|
|
||||||
|
|
||||||
@interface AppDelegate : AppDelegateBase {}
|
|
||||||
@end
|
|
@ -1,106 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2016 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "AppDelegate.h"
|
|
||||||
#import "ProgressController.h"
|
|
||||||
#import "Utils.h"
|
|
||||||
#import "ValueTransformers.h"
|
|
||||||
#import "Dialogs.h"
|
|
||||||
#import "DetailsPanel.h"
|
|
||||||
#import "ResultWindow.h"
|
|
||||||
#import "Consts.h"
|
|
||||||
|
|
||||||
@implementation AppDelegate
|
|
||||||
+ (NSDictionary *)defaultPreferences
|
|
||||||
{
|
|
||||||
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:[super defaultPreferences]];
|
|
||||||
[d setObject:i2n(3) forKey:@"scanType"];
|
|
||||||
[d setObject:i2n(80) forKey:@"minMatchPercentage"];
|
|
||||||
[d setObject:b2n(NO) forKey:@"wordWeighting"];
|
|
||||||
[d setObject:b2n(NO) forKey:@"matchSimilarWords"];
|
|
||||||
[d setObject:b2n(NO) forKey:@"scanTagTrack"];
|
|
||||||
[d setObject:b2n(YES) forKey:@"scanTagArtist"];
|
|
||||||
[d setObject:b2n(YES) forKey:@"scanTagAlbum"];
|
|
||||||
[d setObject:b2n(YES) forKey:@"scanTagTitle"];
|
|
||||||
[d setObject:b2n(NO) forKey:@"scanTagGenre"];
|
|
||||||
[d setObject:b2n(NO) forKey:@"scanTagYear"];
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
NSMutableIndexSet *i = [NSMutableIndexSet indexSetWithIndex:4];
|
|
||||||
[i addIndex:5];
|
|
||||||
VTIsIntIn *vtScanTypeIsNotContent = [[[VTIsIntIn alloc] initWithValues:i reverse:YES] autorelease];
|
|
||||||
[NSValueTransformer setValueTransformer:vtScanTypeIsNotContent forName:@"vtScanTypeIsNotContent"];
|
|
||||||
VTIsIntIn *vtScanTypeIsTag = [[[VTIsIntIn alloc] initWithValues:[NSIndexSet indexSetWithIndex:3] reverse:NO] autorelease];
|
|
||||||
[NSValueTransformer setValueTransformer:vtScanTypeIsTag forName:@"vtScanTypeIsTag"];
|
|
||||||
_directoryPanel = nil;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)homepageURL
|
|
||||||
{
|
|
||||||
return @"https://www.hardcoded.net/dupeguru_me/";
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setScanOptions
|
|
||||||
{
|
|
||||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
|
||||||
[model setScanType:n2i([ud objectForKey:@"scanType"])];
|
|
||||||
[model enable:n2b([ud objectForKey:@"scanTagTrack"]) scanForTag:@"track"];
|
|
||||||
[model enable:n2b([ud objectForKey:@"scanTagArtist"]) scanForTag:@"artist"];
|
|
||||||
[model enable:n2b([ud objectForKey:@"scanTagAlbum"]) scanForTag:@"album"];
|
|
||||||
[model enable:n2b([ud objectForKey:@"scanTagTitle"]) scanForTag:@"title"];
|
|
||||||
[model enable:n2b([ud objectForKey:@"scanTagGenre"]) scanForTag:@"genre"];
|
|
||||||
[model enable:n2b([ud objectForKey:@"scanTagYear"]) scanForTag:@"year"];
|
|
||||||
[model setMinMatchPercentage:n2i([ud objectForKey:@"minMatchPercentage"])];
|
|
||||||
[model setWordWeighting:n2b([ud objectForKey:@"wordWeighting"])];
|
|
||||||
[model setMixFileKind:n2b([ud objectForKey:@"mixFileKind"])];
|
|
||||||
[model setIgnoreHardlinkMatches:n2b([ud objectForKey:@"ignoreHardlinkMatches"])];
|
|
||||||
[model setMatchSimilarWords:n2b([ud objectForKey:@"matchSimilarWords"])];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)initResultColumns:(ResultTable *)aTable
|
|
||||||
{
|
|
||||||
HSColumnDef defs[] = {
|
|
||||||
{@"marked", 26, 26, 26, YES, [NSButtonCell class]},
|
|
||||||
{@"name", 235, 16, 0, YES, nil},
|
|
||||||
{@"folder_path", 120, 16, 0, YES, nil},
|
|
||||||
{@"size", 63, 16, 0, YES, nil},
|
|
||||||
{@"duration", 50, 16, 0, YES, nil},
|
|
||||||
{@"bitrate", 50, 16, 0, YES, nil},
|
|
||||||
{@"samplerate", 60, 16, 0, YES, nil},
|
|
||||||
{@"extension", 40, 16, 0, YES, nil},
|
|
||||||
{@"mtime", 120, 16, 0, YES, nil},
|
|
||||||
{@"title", 120, 16, 0, YES, nil},
|
|
||||||
{@"artist", 120, 16, 0, YES, nil},
|
|
||||||
{@"album", 120, 16, 0, YES, nil},
|
|
||||||
{@"genre", 80, 16, 0, YES, nil},
|
|
||||||
{@"year", 40, 16, 0, YES, nil},
|
|
||||||
{@"track", 40, 16, 0, YES, nil},
|
|
||||||
{@"comment", 120, 16, 0, YES, nil},
|
|
||||||
{@"percentage", 57, 16, 0, YES, nil},
|
|
||||||
{@"words", 120, 16, 0, YES, nil},
|
|
||||||
{@"dupe_count", 80, 16, 0, YES, nil},
|
|
||||||
nil
|
|
||||||
};
|
|
||||||
[[aTable columns] initializeColumns:defs];
|
|
||||||
NSTableColumn *c = [[aTable view] tableColumnWithIdentifier:@"marked"];
|
|
||||||
[[c dataCell] setButtonType:NSSwitchButton];
|
|
||||||
[[c dataCell] setControlSize:NSSmallControlSize];
|
|
||||||
c = [[aTable view] tableColumnWithIdentifier:@"size"];
|
|
||||||
[[c dataCell] setAlignment:NSRightTextAlignment];
|
|
||||||
c = [[aTable view] tableColumnWithIdentifier:@"duration"];
|
|
||||||
[[c dataCell] setAlignment:NSRightTextAlignment];
|
|
||||||
c = [[aTable view] tableColumnWithIdentifier:@"bitrate"];
|
|
||||||
[[c dataCell] setAlignment:NSRightTextAlignment];
|
|
||||||
[[aTable columns] restoreColumns];
|
|
||||||
}
|
|
||||||
@end
|
|
@ -1,13 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import "DetailsPanelBase.h"
|
|
||||||
|
|
||||||
@interface DetailsPanel : DetailsPanelBase
|
|
||||||
@end
|
|
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "DetailsPanel.h"
|
|
||||||
#import "DetailsPanel_UI.h"
|
|
||||||
|
|
||||||
@implementation DetailsPanel
|
|
||||||
- (NSWindow *)createWindow
|
|
||||||
{
|
|
||||||
return createDetailsPanel_UI(self);
|
|
||||||
}
|
|
||||||
@end
|
|
@ -1,40 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>English</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>dupeGuru</string>
|
|
||||||
<key>CFBundleHelpBookFolder</key>
|
|
||||||
<string>dupeguru_me_help</string>
|
|
||||||
<key>CFBundleHelpBookName</key>
|
|
||||||
<string>dupeGuru ME Help</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>dupeguru</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>com.hardcoded-software.dupeguru-me</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>dupeGuru ME</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>hsft</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>{version}</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>{version}</string>
|
|
||||||
<key>NSMainNibFile</key>
|
|
||||||
<string>MainMenu</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string>NSApplication</string>
|
|
||||||
<key>NSHumanReadableCopyright</key>
|
|
||||||
<string>© Hardcoded Software, 2016</string>
|
|
||||||
<key>SUFeedURL</key>
|
|
||||||
<string>https://www.hardcoded.net/updates/dupeguru_me.appcast</string>
|
|
||||||
<key>SUPublicDSAKeyFile</key>
|
|
||||||
<string>dsa_pub.pem</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@ -1,17 +0,0 @@
|
|||||||
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
#
|
|
||||||
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
# which should be included with this package. The terms are also available at
|
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
|
|
||||||
from hscommon.trans import install_gettext_trans_under_cocoa
|
|
||||||
install_gettext_trans_under_cocoa()
|
|
||||||
|
|
||||||
from cocoa.inter import PySelectableList, PyColumns, PyTable
|
|
||||||
|
|
||||||
from inter.all import *
|
|
||||||
from inter.app_me import PyDupeGuru
|
|
||||||
|
|
||||||
# When built under virtualenv, the dependency collector misses this module, so we have to force it
|
|
||||||
# to see the module.
|
|
||||||
import distutils.sysconfig
|
|
Binary file not shown.
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import "AppDelegateBase.h"
|
|
||||||
|
|
||||||
@interface AppDelegate : AppDelegateBase {}
|
|
||||||
- (void)clearPictureCache;
|
|
||||||
@end
|
|
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "AppDelegate.h"
|
|
||||||
#import "ProgressController.h"
|
|
||||||
#import "Utils.h"
|
|
||||||
#import "Dialogs.h"
|
|
||||||
#import "ValueTransformers.h"
|
|
||||||
#import "Consts.h"
|
|
||||||
#import "DetailsPanel.h"
|
|
||||||
#import "ResultWindow.h"
|
|
||||||
|
|
||||||
@implementation AppDelegate
|
|
||||||
+ (NSDictionary *)defaultPreferences
|
|
||||||
{
|
|
||||||
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:[super defaultPreferences]];
|
|
||||||
[d setObject:i2n(0) forKey:@"scanType"];
|
|
||||||
[d setObject:i2n(95) forKey:@"minMatchPercentage"];
|
|
||||||
[d setObject:b2n(NO) forKey:@"matchScaled"];
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
NSMutableIndexSet *i = [NSMutableIndexSet indexSetWithIndex:0];
|
|
||||||
VTIsIntIn *vtScanTypeIsFuzzy = [[[VTIsIntIn alloc] initWithValues:i reverse:NO] autorelease];
|
|
||||||
[NSValueTransformer setValueTransformer:vtScanTypeIsFuzzy forName:@"vtScanTypeIsFuzzy"];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)homepageURL
|
|
||||||
{
|
|
||||||
return @"https://www.hardcoded.net/dupeguru_pe/";
|
|
||||||
}
|
|
||||||
|
|
||||||
- (DetailsPanel *)createDetailsPanel
|
|
||||||
{
|
|
||||||
return [[DetailsPanel alloc] initWithApp:model];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setScanOptions
|
|
||||||
{
|
|
||||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
|
||||||
[model setScanType:n2i([ud objectForKey:@"scanType"])];
|
|
||||||
[model setMinMatchPercentage:n2i([ud objectForKey:@"minMatchPercentage"])];
|
|
||||||
[model setMixFileKind:n2b([ud objectForKey:@"mixFileKind"])];
|
|
||||||
[model setIgnoreHardlinkMatches:n2b([ud objectForKey:@"ignoreHardlinkMatches"])];
|
|
||||||
[model setMatchScaled:n2b([ud objectForKey:@"matchScaled"])];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)initResultColumns:(ResultTable *)aTable
|
|
||||||
{
|
|
||||||
HSColumnDef defs[] = {
|
|
||||||
{@"marked", 26, 26, 26, YES, [NSButtonCell class]},
|
|
||||||
{@"name", 162, 16, 0, YES, nil},
|
|
||||||
{@"folder_path", 142, 16, 0, YES, nil},
|
|
||||||
{@"size", 63, 16, 0, YES, nil},
|
|
||||||
{@"extension", 40, 16, 0, YES, nil},
|
|
||||||
{@"dimensions", 73, 16, 0, YES, nil},
|
|
||||||
{@"exif_timestamp", 120, 16, 0, YES, nil},
|
|
||||||
{@"mtime", 120, 16, 0, YES, nil},
|
|
||||||
{@"percentage", 58, 16, 0, YES, nil},
|
|
||||||
{@"dupe_count", 80, 16, 0, YES, nil},
|
|
||||||
nil
|
|
||||||
};
|
|
||||||
[[aTable columns] initializeColumns:defs];
|
|
||||||
NSTableColumn *c = [[aTable view] tableColumnWithIdentifier:@"marked"];
|
|
||||||
[[c dataCell] setButtonType:NSSwitchButton];
|
|
||||||
[[c dataCell] setControlSize:NSSmallControlSize];
|
|
||||||
c = [[aTable view] tableColumnWithIdentifier:@"size"];
|
|
||||||
[[c dataCell] setAlignment:NSRightTextAlignment];
|
|
||||||
[[aTable columns] restoreColumns];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)clearPictureCache
|
|
||||||
{
|
|
||||||
NSString *msg = NSLocalizedString(@"Do you really want to remove all your cached picture analysis?", @"");
|
|
||||||
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
|
||||||
return;
|
|
||||||
[model clearPictureCache];
|
|
||||||
}
|
|
||||||
@end
|
|
@ -1,11 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "../base/Consts.h"
|
|
||||||
|
|
||||||
#define ImageLoadedNotification @"ImageLoadedNotification"
|
|
@ -1,40 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>English</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>dupeGuru</string>
|
|
||||||
<key>CFBundleHelpBookFolder</key>
|
|
||||||
<string>dupeguru_pe_help</string>
|
|
||||||
<key>CFBundleHelpBookName</key>
|
|
||||||
<string>dupeGuru PE Help</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>dupeguru</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>com.hardcoded-software.dupeguru-pe</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>dupeGuru PE</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>hsft</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>{version}</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>{version}</string>
|
|
||||||
<key>NSMainNibFile</key>
|
|
||||||
<string>MainMenu</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string>NSApplication</string>
|
|
||||||
<key>NSHumanReadableCopyright</key>
|
|
||||||
<string>© Hardcoded Software, 2016</string>
|
|
||||||
<key>SUFeedURL</key>
|
|
||||||
<string>https://www.hardcoded.net/updates/dupeguru_pe.appcast</string>
|
|
||||||
<key>SUPublicDSAKeyFile</key>
|
|
||||||
<string>dsa_pub.pem</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@ -1,17 +0,0 @@
|
|||||||
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
#
|
|
||||||
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
# which should be included with this package. The terms are also available at
|
|
||||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
|
|
||||||
from hscommon.trans import install_gettext_trans_under_cocoa
|
|
||||||
install_gettext_trans_under_cocoa()
|
|
||||||
|
|
||||||
from cocoa.inter import PySelectableList, PyColumns, PyTable
|
|
||||||
|
|
||||||
from inter.all import *
|
|
||||||
from inter.app_pe import PyDupeGuru
|
|
||||||
|
|
||||||
# When built under virtualenv, the dependency collector misses this module, so we have to force it
|
|
||||||
# to see the module.
|
|
||||||
import distutils.sysconfig
|
|
Binary file not shown.
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import "AppDelegateBase.h"
|
|
||||||
#import "PyDupeGuru.h"
|
|
||||||
|
|
||||||
@interface AppDelegate : AppDelegateBase {}
|
|
||||||
@end
|
|
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "AppDelegate.h"
|
|
||||||
#import "ProgressController.h"
|
|
||||||
#import "Utils.h"
|
|
||||||
#import "ValueTransformers.h"
|
|
||||||
#import "DetailsPanel.h"
|
|
||||||
#import "DirectoryPanel.h"
|
|
||||||
#import "ResultWindow.h"
|
|
||||||
#import "Consts.h"
|
|
||||||
|
|
||||||
@implementation AppDelegate
|
|
||||||
+ (NSDictionary *)defaultPreferences
|
|
||||||
{
|
|
||||||
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:[super defaultPreferences]];
|
|
||||||
[d setObject:i2n(1) forKey:@"scanType"];
|
|
||||||
[d setObject:i2n(80) forKey:@"minMatchPercentage"];
|
|
||||||
[d setObject:i2n(30) forKey:@"smallFileThreshold"];
|
|
||||||
[d setObject:b2n(YES) forKey:@"wordWeighting"];
|
|
||||||
[d setObject:b2n(NO) forKey:@"matchSimilarWords"];
|
|
||||||
[d setObject:b2n(YES) forKey:@"ignoreSmallFiles"];
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
NSMutableIndexSet *contentsIndexes = [NSMutableIndexSet indexSet];
|
|
||||||
[contentsIndexes addIndex:1];
|
|
||||||
[contentsIndexes addIndex:2];
|
|
||||||
VTIsIntIn *vt = [[[VTIsIntIn alloc] initWithValues:contentsIndexes reverse:YES] autorelease];
|
|
||||||
[NSValueTransformer setValueTransformer:vt forName:@"vtScanTypeIsNotContent"];
|
|
||||||
_directoryPanel = nil;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)homepageURL
|
|
||||||
{
|
|
||||||
return @"http://www.hardcoded.net/dupeguru/";
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setScanOptions
|
|
||||||
{
|
|
||||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
|
||||||
[model setScanType:n2i([ud objectForKey:@"scanType"])];
|
|
||||||
[model setMinMatchPercentage:n2i([ud objectForKey:@"minMatchPercentage"])];
|
|
||||||
[model setWordWeighting:n2b([ud objectForKey:@"wordWeighting"])];
|
|
||||||
[model setMixFileKind:n2b([ud objectForKey:@"mixFileKind"])];
|
|
||||||
[model setIgnoreHardlinkMatches:n2b([ud objectForKey:@"ignoreHardlinkMatches"])];
|
|
||||||
[model setMatchSimilarWords:n2b([ud objectForKey:@"matchSimilarWords"])];
|
|
||||||
int smallFileThreshold = [ud integerForKey:@"smallFileThreshold"]; // In KB
|
|
||||||
int sizeThreshold = [ud boolForKey:@"ignoreSmallFiles"] ? smallFileThreshold * 1024 : 0; // The py side wants bytes
|
|
||||||
[model setSizeThreshold:sizeThreshold];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)initResultColumns:(ResultTable *)aTable
|
|
||||||
{
|
|
||||||
HSColumnDef defs[] = {
|
|
||||||
{@"marked", 26, 26, 26, YES, [NSButtonCell class]},
|
|
||||||
{@"name", 195, 16, 0, YES, nil},
|
|
||||||
{@"folder_path", 183, 16, 0, YES, nil},
|
|
||||||
{@"size", 63, 16, 0, YES, nil},
|
|
||||||
{@"extension", 40, 16, 0, YES, nil},
|
|
||||||
{@"mtime", 120, 16, 0, YES, nil},
|
|
||||||
{@"percentage", 60, 16, 0, YES, nil},
|
|
||||||
{@"words", 120, 16, 0, YES, nil},
|
|
||||||
{@"dupe_count", 80, 16, 0, YES, nil},
|
|
||||||
nil
|
|
||||||
};
|
|
||||||
[[aTable columns] initializeColumns:defs];
|
|
||||||
NSTableColumn *c = [[aTable view] tableColumnWithIdentifier:@"marked"];
|
|
||||||
[[c dataCell] setButtonType:NSSwitchButton];
|
|
||||||
[[c dataCell] setControlSize:NSSmallControlSize];
|
|
||||||
c = [[aTable view] tableColumnWithIdentifier:@"size"];
|
|
||||||
[[c dataCell] setAlignment:NSRightTextAlignment];
|
|
||||||
[[aTable columns] restoreColumns];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
@ -1,13 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import "DetailsPanelBase.h"
|
|
||||||
|
|
||||||
@interface DetailsPanel : DetailsPanelBase
|
|
||||||
@end
|
|
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
||||||
|
|
||||||
This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
||||||
which should be included with this package. The terms are also available at
|
|
||||||
http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "DetailsPanel.h"
|
|
||||||
#import "DetailsPanel_UI.h"
|
|
||||||
|
|
||||||
@implementation DetailsPanel
|
|
||||||
- (NSWindow *)createWindow
|
|
||||||
{
|
|
||||||
return createDetailsPanel_UI(self);
|
|
||||||
}
|
|
||||||
@end
|
|
@ -1,5 +1,5 @@
|
|||||||
ownerclass = 'DetailsPanel'
|
ownerclass = 'DetailsPanelPicture'
|
||||||
ownerimport = 'DetailsPanel.h'
|
ownerimport = 'DetailsPanelPicture.h'
|
||||||
|
|
||||||
result = Panel(593, 398, "Details of Selected File")
|
result = Panel(593, 398, "Details of Selected File")
|
||||||
table = TableView(result)
|
table = TableView(result)
|
@ -5,6 +5,8 @@ result = Window(425, 300, "dupeGuru")
|
|||||||
promptLabel = Label(result, "Select folders to scan and press \"Scan\".")
|
promptLabel = Label(result, "Select folders to scan and press \"Scan\".")
|
||||||
directoryOutline = OutlineView(result)
|
directoryOutline = OutlineView(result)
|
||||||
directoryOutline.OBJC_CLASS = 'HSOutlineView'
|
directoryOutline.OBJC_CLASS = 'HSOutlineView'
|
||||||
|
appModeSelector = SegmentedControl(result)
|
||||||
|
appModeLabel = Label(result, "Application Mode:")
|
||||||
scanTypePopup = Popup(result)
|
scanTypePopup = Popup(result)
|
||||||
scanTypeLabel = Label(result, "Scan Type:")
|
scanTypeLabel = Label(result, "Scan Type:")
|
||||||
addButton = Button(result, "")
|
addButton = Button(result, "")
|
||||||
@ -15,6 +17,7 @@ addPopup = Popup(None)
|
|||||||
loadRecentPopup = Popup(None)
|
loadRecentPopup = Popup(None)
|
||||||
|
|
||||||
owner.outlineView = directoryOutline
|
owner.outlineView = directoryOutline
|
||||||
|
owner.appModeSelector = appModeSelector
|
||||||
owner.scanTypePopup = scanTypePopup
|
owner.scanTypePopup = scanTypePopup
|
||||||
owner.removeButton = removeButton
|
owner.removeButton = removeButton
|
||||||
owner.loadResultsButton = loadResultsButton
|
owner.loadResultsButton = loadResultsButton
|
||||||
@ -23,7 +26,9 @@ owner.loadRecentButtonPopUp = loadRecentPopup
|
|||||||
|
|
||||||
result.autosaveName = 'DirectoryPanel'
|
result.autosaveName = 'DirectoryPanel'
|
||||||
result.canMinimize = False
|
result.canMinimize = False
|
||||||
result.minSize = Size(370, 270)
|
result.minSize = Size(400, 270)
|
||||||
|
for label in ["Standard", "Music", "Picture"]:
|
||||||
|
appModeSelector.addSegment(label, 80)
|
||||||
addButton.bezelStyle = removeButton.bezelStyle = const.NSTexturedRoundedBezelStyle
|
addButton.bezelStyle = removeButton.bezelStyle = const.NSTexturedRoundedBezelStyle
|
||||||
addButton.image = 'NSAddTemplate'
|
addButton.image = 'NSAddTemplate'
|
||||||
removeButton.image = 'NSRemoveTemplate'
|
removeButton.image = 'NSRemoveTemplate'
|
||||||
@ -31,6 +36,7 @@ for button in (addButton, removeButton):
|
|||||||
button.style = const.NSTexturedRoundedBezelStyle
|
button.style = const.NSTexturedRoundedBezelStyle
|
||||||
button.imagePosition = const.NSImageOnly
|
button.imagePosition = const.NSImageOnly
|
||||||
scanButton.keyEquivalent = '\\r'
|
scanButton.keyEquivalent = '\\r'
|
||||||
|
appModeSelector.action = Action(owner, 'changeAppMode:')
|
||||||
addButton.action = Action(owner, 'popupAddDirectoryMenu:')
|
addButton.action = Action(owner, 'popupAddDirectoryMenu:')
|
||||||
removeButton.action = Action(owner, 'removeSelectedDirectory')
|
removeButton.action = Action(owner, 'removeSelectedDirectory')
|
||||||
loadResultsButton.action = Action(owner, 'popupLoadRecentMenu:')
|
loadResultsButton.action = Action(owner, 'popupLoadRecentMenu:')
|
||||||
@ -49,8 +55,10 @@ directoryOutline.allowsColumnReordering = False
|
|||||||
directoryOutline.allowsColumnSelection = False
|
directoryOutline.allowsColumnSelection = False
|
||||||
directoryOutline.allowsMultipleSelection = True
|
directoryOutline.allowsMultipleSelection = True
|
||||||
|
|
||||||
scanTypeLabel.width = 90
|
appModeLabel.width = scanTypeLabel.width = 110
|
||||||
scanTypeLayout = HLayout([scanTypeLabel, scanTypePopup], filler=scanTypePopup)
|
scanTypePopup.width = 248
|
||||||
|
appModeLayout = HLayout([appModeLabel, appModeSelector])
|
||||||
|
scanTypeLayout = HLayout([scanTypeLabel, scanTypePopup])
|
||||||
|
|
||||||
for button in (addButton, removeButton):
|
for button in (addButton, removeButton):
|
||||||
button.width = 28
|
button.width = 28
|
||||||
@ -58,15 +66,11 @@ for button in (loadResultsButton, scanButton):
|
|||||||
button.width = 118
|
button.width = 118
|
||||||
|
|
||||||
buttonLayout = HLayout([addButton, removeButton, None, loadResultsButton, scanButton])
|
buttonLayout = HLayout([addButton, removeButton, None, loadResultsButton, scanButton])
|
||||||
bottomLayout = VLayout([None, scanTypeLayout, buttonLayout])
|
mainLayout = VLayout([appModeLayout, scanTypeLayout, promptLabel, directoryOutline, buttonLayout], filler=directoryOutline)
|
||||||
promptLabel.packToCorner(Pack.UpperLeft)
|
mainLayout.packToCorner(Pack.UpperLeft)
|
||||||
promptLabel.fill(Pack.Right)
|
mainLayout.fill(Pack.LowerRight)
|
||||||
directoryOutline.packRelativeTo(promptLabel, Pack.Below)
|
directoryOutline.packRelativeTo(promptLabel, Pack.Below)
|
||||||
bottomLayout.packRelativeTo(directoryOutline, Pack.Below, margin=8)
|
|
||||||
directoryOutline.fill(Pack.LowerRight)
|
|
||||||
bottomLayout.fill(Pack.Right)
|
|
||||||
|
|
||||||
promptLabel.setAnchor(Pack.UpperLeft, growX=True)
|
promptLabel.setAnchor(Pack.UpperLeft, growX=True)
|
||||||
directoryOutline.setAnchor(Pack.UpperLeft, growX=True, growY=True)
|
directoryOutline.setAnchor(Pack.UpperLeft, growX=True, growY=True)
|
||||||
scanTypeLayout.setAnchor(Pack.Below)
|
|
||||||
buttonLayout.setAnchor(Pack.Below)
|
buttonLayout.setAnchor(Pack.Below)
|
@ -1,6 +1,5 @@
|
|||||||
ownerclass = 'AppDelegateBase'
|
ownerclass = 'AppDelegate'
|
||||||
ownerimport = 'AppDelegateBase.h'
|
ownerimport = 'AppDelegate.h'
|
||||||
edition = args.get('edition', 'se')
|
|
||||||
|
|
||||||
result = Menu("")
|
result = Menu("")
|
||||||
appMenu = result.addMenu("dupeGuru")
|
appMenu = result.addMenu("dupeGuru")
|
||||||
@ -30,8 +29,7 @@ owner.recentResultsMenu = fileMenu.addMenu("Load Recent Results")
|
|||||||
fileMenu.addItem("Save Results...", Action(None, 'saveResults'), 'cmd+s')
|
fileMenu.addItem("Save Results...", Action(None, 'saveResults'), 'cmd+s')
|
||||||
fileMenu.addItem("Export Results to XHTML", Action(owner.model, 'exportToXHTML'), 'cmd+shift+e')
|
fileMenu.addItem("Export Results to XHTML", Action(owner.model, 'exportToXHTML'), 'cmd+shift+e')
|
||||||
fileMenu.addItem("Export Results to CSV", Action(owner.model, 'exportToCSV'))
|
fileMenu.addItem("Export Results to CSV", Action(owner.model, 'exportToCSV'))
|
||||||
if edition == 'pe':
|
fileMenu.addItem("Clear Picture Cache", Action(owner, 'clearPictureCache'), 'cmd+shift+p')
|
||||||
fileMenu.addItem("Clear Picture Cache", Action(owner, 'clearPictureCache'), 'cmd+shift+p')
|
|
||||||
|
|
||||||
editMenu.addItem("Mark All", Action(None, 'markAll'), 'cmd+a')
|
editMenu.addItem("Mark All", Action(None, 'markAll'), 'cmd+a')
|
||||||
editMenu.addItem("Mark None", Action(None, 'markNone'), 'cmd+shift+a')
|
editMenu.addItem("Mark None", Action(None, 'markNone'), 'cmd+shift+a')
|
@ -1,16 +1,11 @@
|
|||||||
edition = args.get('edition', 'se')
|
appmode = args.get('appmode', 'standard')
|
||||||
dialogTitles = {
|
|
||||||
'se': "dupeGuru Preferences",
|
|
||||||
'me': "dupeGuru ME Preferences",
|
|
||||||
'pe': "dupeGuru PE Preferences",
|
|
||||||
}
|
|
||||||
dialogHeights = {
|
dialogHeights = {
|
||||||
'se': 325,
|
'standard': 325,
|
||||||
'me': 345,
|
'music': 345,
|
||||||
'pe': 255,
|
'picture': 255,
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Window(410, dialogHeights[edition], dialogTitles[edition])
|
result = Window(410, dialogHeights[appmode], "dupeGuru Preferences")
|
||||||
tabView = TabView(result)
|
tabView = TabView(result)
|
||||||
basicTab = tabView.addTab("Basic")
|
basicTab = tabView.addTab("Basic")
|
||||||
advancedTab = tabView.addTab("Advanced")
|
advancedTab = tabView.addTab("Advanced")
|
||||||
@ -21,19 +16,19 @@ fewerResultsLabel = Label(basicTab.view, "Fewer results")
|
|||||||
thresholdValueLabel = Label(basicTab.view, "")
|
thresholdValueLabel = Label(basicTab.view, "")
|
||||||
fontSizeCombo = Combobox(basicTab.view, ["11", "12", "13", "14", "18", "24"])
|
fontSizeCombo = Combobox(basicTab.view, ["11", "12", "13", "14", "18", "24"])
|
||||||
fontSizeLabel = Label(basicTab.view, "Font Size:")
|
fontSizeLabel = Label(basicTab.view, "Font Size:")
|
||||||
if edition in ('se', 'me'):
|
if appmode in ('standard', 'music'):
|
||||||
wordWeightingBox = Checkbox(basicTab.view, "Word weighting")
|
wordWeightingBox = Checkbox(basicTab.view, "Word weighting")
|
||||||
matchSimilarWordsBox = Checkbox(basicTab.view, "Match similar words")
|
matchSimilarWordsBox = Checkbox(basicTab.view, "Match similar words")
|
||||||
elif edition == 'pe':
|
elif appmode == 'picture':
|
||||||
matchDifferentDimensionsBox = Checkbox(basicTab.view, "Match pictures of different dimensions")
|
matchDifferentDimensionsBox = Checkbox(basicTab.view, "Match pictures of different dimensions")
|
||||||
mixKindBox = Checkbox(basicTab.view, "Can mix file kind")
|
mixKindBox = Checkbox(basicTab.view, "Can mix file kind")
|
||||||
removeEmptyFoldersBox = Checkbox(basicTab.view, "Remove empty folders on delete or move")
|
removeEmptyFoldersBox = Checkbox(basicTab.view, "Remove empty folders on delete or move")
|
||||||
checkForUpdatesBox = Checkbox(basicTab.view, "Automatically check for updates")
|
checkForUpdatesBox = Checkbox(basicTab.view, "Automatically check for updates")
|
||||||
if edition == 'se':
|
if appmode == 'standard':
|
||||||
ignoreSmallFilesBox = Checkbox(basicTab.view, "Ignore files smaller than:")
|
ignoreSmallFilesBox = Checkbox(basicTab.view, "Ignore files smaller than:")
|
||||||
smallFilesThresholdText = TextField(basicTab.view, "")
|
smallFilesThresholdText = TextField(basicTab.view, "")
|
||||||
smallFilesThresholdSuffixLabel = Label(basicTab.view, "KB")
|
smallFilesThresholdSuffixLabel = Label(basicTab.view, "KB")
|
||||||
elif edition == 'me':
|
elif appmode == 'music':
|
||||||
tagsToScanLabel = Label(basicTab.view, "Tags to scan:")
|
tagsToScanLabel = Label(basicTab.view, "Tags to scan:")
|
||||||
trackBox = Checkbox(basicTab.view, "Track")
|
trackBox = Checkbox(basicTab.view, "Track")
|
||||||
artistBox = Checkbox(basicTab.view, "Artist")
|
artistBox = Checkbox(basicTab.view, "Artist")
|
||||||
@ -63,27 +58,29 @@ ignoreHardlinksBox.bind('value', defaults, 'values.ignoreHardlinkMatches')
|
|||||||
debugModeCheckbox.bind('value', defaults, 'values.DebugMode')
|
debugModeCheckbox.bind('value', defaults, 'values.DebugMode')
|
||||||
customCommandText.bind('value', defaults, 'values.CustomCommand')
|
customCommandText.bind('value', defaults, 'values.CustomCommand')
|
||||||
copyMovePopup.bind('selectedIndex', defaults, 'values.recreatePathType')
|
copyMovePopup.bind('selectedIndex', defaults, 'values.recreatePathType')
|
||||||
if edition in ('se', 'me'):
|
if appmode in ('standard', 'music'):
|
||||||
wordWeightingBox.bind('value', defaults, 'values.wordWeighting')
|
wordWeightingBox.bind('value', defaults, 'values.wordWeighting')
|
||||||
matchSimilarWordsBox.bind('value', defaults, 'values.matchSimilarWords')
|
matchSimilarWordsBox.bind('value', defaults, 'values.matchSimilarWords')
|
||||||
disableWhenContentScan = [thresholdSlider, wordWeightingBox, matchSimilarWordsBox]
|
disableWhenContentScan = [thresholdSlider, wordWeightingBox, matchSimilarWordsBox]
|
||||||
for control in disableWhenContentScan:
|
for control in disableWhenContentScan:
|
||||||
control.bind('enabled', defaults, 'values.scanType', valueTransformer='vtScanTypeIsNotContent')
|
vtname = 'vtScanTypeMusicIsNotContent' if appmode == 'music' else 'vtScanTypeIsNotContent'
|
||||||
if edition == 'se':
|
prefname = 'values.scanTypeMusic' if appmode == 'music' else 'values.scanTypeStandard'
|
||||||
|
control.bind('enabled', defaults, prefname, valueTransformer=vtname)
|
||||||
|
if appmode == 'standard':
|
||||||
ignoreSmallFilesBox.bind('value', defaults, 'values.ignoreSmallFiles')
|
ignoreSmallFilesBox.bind('value', defaults, 'values.ignoreSmallFiles')
|
||||||
smallFilesThresholdText.bind('value', defaults, 'values.smallFileThreshold')
|
smallFilesThresholdText.bind('value', defaults, 'values.smallFileThreshold')
|
||||||
elif edition == 'me':
|
elif appmode == 'music':
|
||||||
for box in tagBoxes:
|
for box in tagBoxes:
|
||||||
box.bind('enabled', defaults, 'values.scanType', valueTransformer='vtScanTypeIsTag')
|
box.bind('enabled', defaults, 'values.scanTypeMusic', valueTransformer='vtScanTypeIsTag')
|
||||||
trackBox.bind('value', defaults, 'values.scanTagTrack')
|
trackBox.bind('value', defaults, 'values.scanTagTrack')
|
||||||
artistBox.bind('value', defaults, 'values.scanTagArtist')
|
artistBox.bind('value', defaults, 'values.scanTagArtist')
|
||||||
albumBox.bind('value', defaults, 'values.scanTagAlbum')
|
albumBox.bind('value', defaults, 'values.scanTagAlbum')
|
||||||
titleBox.bind('value', defaults, 'values.scanTagTitle')
|
titleBox.bind('value', defaults, 'values.scanTagTitle')
|
||||||
genreBox.bind('value', defaults, 'values.scanTagGenre')
|
genreBox.bind('value', defaults, 'values.scanTagGenre')
|
||||||
yearBox.bind('value', defaults, 'values.scanTagYear')
|
yearBox.bind('value', defaults, 'values.scanTagYear')
|
||||||
elif edition == 'pe':
|
elif appmode == 'picture':
|
||||||
matchDifferentDimensionsBox.bind('value', defaults, 'values.matchScaled')
|
matchDifferentDimensionsBox.bind('value', defaults, 'values.matchScaled')
|
||||||
thresholdSlider.bind('enabled', defaults, 'values.scanType', valueTransformer='vtScanTypeIsFuzzy')
|
thresholdSlider.bind('enabled', defaults, 'values.scanTypePicture', valueTransformer='vtScanTypeIsFuzzy')
|
||||||
|
|
||||||
result.canResize = False
|
result.canResize = False
|
||||||
result.canMinimize = False
|
result.canMinimize = False
|
||||||
@ -93,13 +90,13 @@ allLabels = [thresholdValueLabel, moreResultsLabel, fewerResultsLabel,
|
|||||||
thresholdLabel, fontSizeLabel, customCommandLabel, copyMoveLabel]
|
thresholdLabel, fontSizeLabel, customCommandLabel, copyMoveLabel]
|
||||||
allCheckboxes = [mixKindBox, removeEmptyFoldersBox, checkForUpdatesBox, regexpCheckbox,
|
allCheckboxes = [mixKindBox, removeEmptyFoldersBox, checkForUpdatesBox, regexpCheckbox,
|
||||||
ignoreHardlinksBox, debugModeCheckbox]
|
ignoreHardlinksBox, debugModeCheckbox]
|
||||||
if edition == 'se':
|
if appmode == 'standard':
|
||||||
allLabels += [smallFilesThresholdSuffixLabel]
|
allLabels += [smallFilesThresholdSuffixLabel]
|
||||||
allCheckboxes += [ignoreSmallFilesBox, wordWeightingBox, matchSimilarWordsBox]
|
allCheckboxes += [ignoreSmallFilesBox, wordWeightingBox, matchSimilarWordsBox]
|
||||||
elif edition == 'me':
|
elif appmode == 'music':
|
||||||
allLabels += [tagsToScanLabel]
|
allLabels += [tagsToScanLabel]
|
||||||
allCheckboxes += tagBoxes + [wordWeightingBox, matchSimilarWordsBox]
|
allCheckboxes += tagBoxes + [wordWeightingBox, matchSimilarWordsBox]
|
||||||
elif edition == 'pe':
|
elif appmode == 'picture':
|
||||||
allCheckboxes += [matchDifferentDimensionsBox]
|
allCheckboxes += [matchDifferentDimensionsBox]
|
||||||
for label in allLabels:
|
for label in allLabels:
|
||||||
label.controlSize = ControlSize.Small
|
label.controlSize = ControlSize.Small
|
||||||
@ -112,10 +109,10 @@ thresholdLabel.width = fontSizeLabel.width = 94
|
|||||||
fontSizeCombo.width = 66
|
fontSizeCombo.width = 66
|
||||||
thresholdValueLabel.width = 25
|
thresholdValueLabel.width = 25
|
||||||
resetToDefaultsButton.width = 136
|
resetToDefaultsButton.width = 136
|
||||||
if edition == 'se':
|
if appmode == 'standard':
|
||||||
smallFilesThresholdText.width = 60
|
smallFilesThresholdText.width = 60
|
||||||
smallFilesThresholdSuffixLabel.width = 40
|
smallFilesThresholdSuffixLabel.width = 40
|
||||||
elif edition == 'me':
|
elif appmode == 'music':
|
||||||
for box in tagBoxes:
|
for box in tagBoxes:
|
||||||
box.width = 70
|
box.width = 70
|
||||||
|
|
||||||
@ -135,7 +132,7 @@ fewerResultsLabel.packRelativeTo(thresholdSlider, Pack.Below, align=Pack.Right,
|
|||||||
fontSizeCombo.packRelativeTo(moreResultsLabel, Pack.Below)
|
fontSizeCombo.packRelativeTo(moreResultsLabel, Pack.Below)
|
||||||
fontSizeLabel.packRelativeTo(fontSizeCombo, Pack.Left)
|
fontSizeLabel.packRelativeTo(fontSizeCombo, Pack.Left)
|
||||||
|
|
||||||
if edition == 'me':
|
if appmode == 'music':
|
||||||
tagsToScanLabel.packRelativeTo(fontSizeCombo, Pack.Below)
|
tagsToScanLabel.packRelativeTo(fontSizeCombo, Pack.Below)
|
||||||
tagsToScanLabel.fill(Pack.Left)
|
tagsToScanLabel.fill(Pack.Left)
|
||||||
tagsToScanLabel.fill(Pack.Right)
|
tagsToScanLabel.fill(Pack.Right)
|
||||||
@ -150,13 +147,13 @@ if edition == 'me':
|
|||||||
else:
|
else:
|
||||||
viewToPackCheckboxesUnder = fontSizeCombo
|
viewToPackCheckboxesUnder = fontSizeCombo
|
||||||
|
|
||||||
if edition == 'se':
|
if appmode == 'standard':
|
||||||
checkboxesToLayout = [wordWeightingBox, matchSimilarWordsBox, mixKindBox, removeEmptyFoldersBox,
|
checkboxesToLayout = [wordWeightingBox, matchSimilarWordsBox, mixKindBox, removeEmptyFoldersBox,
|
||||||
ignoreSmallFilesBox]
|
ignoreSmallFilesBox]
|
||||||
elif edition == 'me':
|
elif appmode == 'music':
|
||||||
checkboxesToLayout = [wordWeightingBox, matchSimilarWordsBox, mixKindBox, removeEmptyFoldersBox,
|
checkboxesToLayout = [wordWeightingBox, matchSimilarWordsBox, mixKindBox, removeEmptyFoldersBox,
|
||||||
checkForUpdatesBox]
|
checkForUpdatesBox]
|
||||||
elif edition == 'pe':
|
elif appmode == 'picture':
|
||||||
checkboxesToLayout = [matchDifferentDimensionsBox, mixKindBox, removeEmptyFoldersBox,
|
checkboxesToLayout = [matchDifferentDimensionsBox, mixKindBox, removeEmptyFoldersBox,
|
||||||
checkForUpdatesBox]
|
checkForUpdatesBox]
|
||||||
checkboxLayout = VLayout(checkboxesToLayout)
|
checkboxLayout = VLayout(checkboxesToLayout)
|
||||||
@ -164,7 +161,7 @@ checkboxLayout.packRelativeTo(viewToPackCheckboxesUnder, Pack.Below)
|
|||||||
checkboxLayout.fill(Pack.Left)
|
checkboxLayout.fill(Pack.Left)
|
||||||
checkboxLayout.fill(Pack.Right)
|
checkboxLayout.fill(Pack.Right)
|
||||||
|
|
||||||
if edition == 'se':
|
if appmode == 'standard':
|
||||||
smallFilesThresholdText.packRelativeTo(ignoreSmallFilesBox, Pack.Below, margin=4)
|
smallFilesThresholdText.packRelativeTo(ignoreSmallFilesBox, Pack.Below, margin=4)
|
||||||
checkForUpdatesBox.packRelativeTo(smallFilesThresholdText, Pack.Below, margin=4)
|
checkForUpdatesBox.packRelativeTo(smallFilesThresholdText, Pack.Below, margin=4)
|
||||||
checkForUpdatesBox.fill(Pack.Right)
|
checkForUpdatesBox.fill(Pack.Right)
|
@ -9,13 +9,8 @@ out = 'build'
|
|||||||
|
|
||||||
def options(opt):
|
def options(opt):
|
||||||
opt.load('compiler_c python')
|
opt.load('compiler_c python')
|
||||||
opt.add_option('--edition', default='se', help="dupeGuru edition to build (se, me pe)")
|
|
||||||
|
|
||||||
def configure(conf):
|
def configure(conf):
|
||||||
if conf.options.edition not in ('se', 'me', 'pe'):
|
|
||||||
conf.options.edition = 'se'
|
|
||||||
print("Building dupeGuru {}".format(conf.options.edition.upper()))
|
|
||||||
conf.env.DGEDITION = conf.options.edition
|
|
||||||
# We use clang to compile our app
|
# We use clang to compile our app
|
||||||
conf.env.CC = 'clang'
|
conf.env.CC = 'clang'
|
||||||
# WAF has a "pyembed" feature allowing us to automatically find Python and compile by linking
|
# WAF has a "pyembed" feature allowing us to automatically find Python and compile by linking
|
||||||
@ -31,7 +26,7 @@ def configure(conf):
|
|||||||
os.symlink('../build/Python', versioned_dylib_path)
|
os.symlink('../build/Python', versioned_dylib_path)
|
||||||
# The rest is standard WAF code that you can find the the python and macapp demos.
|
# The rest is standard WAF code that you can find the the python and macapp demos.
|
||||||
conf.load('compiler_c python')
|
conf.load('compiler_c python')
|
||||||
conf.check_python_version((3,3,0))
|
conf.check_python_version((3,4,0))
|
||||||
conf.check_python_headers()
|
conf.check_python_headers()
|
||||||
conf.env.FRAMEWORK_COCOA = 'Cocoa'
|
conf.env.FRAMEWORK_COCOA = 'Cocoa'
|
||||||
conf.env.ARCH_COCOA = ['x86_64']
|
conf.env.ARCH_COCOA = ['x86_64']
|
||||||
@ -53,8 +48,8 @@ def build(ctx):
|
|||||||
'controllers/HSOutline', 'controllers/HSPopUpList', 'controllers/HSSelectableList',
|
'controllers/HSOutline', 'controllers/HSPopUpList', 'controllers/HSSelectableList',
|
||||||
'controllers/HSTextField', 'controllers/HSProgressWindow']
|
'controllers/HSTextField', 'controllers/HSProgressWindow']
|
||||||
cocoalib_src = [cocoalib_node.find_node(usename + '.m') for usename in cocoalib_uses] + cocoalib_node.ant_glob('autogen/*.m')
|
cocoalib_src = [cocoalib_node.find_node(usename + '.m') for usename in cocoalib_uses] + cocoalib_node.ant_glob('autogen/*.m')
|
||||||
project_folders = ['autogen', 'base', ctx.env.DGEDITION]
|
project_folders = [ctx.srcnode, ctx.srcnode.find_dir('autogen')]
|
||||||
project_src = sum([ctx.srcnode.ant_glob('%s/*.m' % folder) for folder in project_folders], [])
|
project_src = ctx.srcnode.ant_glob('autogen/*.m') + ctx.srcnode.ant_glob('*.m')
|
||||||
|
|
||||||
# Compile
|
# Compile
|
||||||
ctx.program(
|
ctx.program(
|
||||||
|
17
core/app.py
17
core/app.py
@ -323,6 +323,14 @@ class DupeGuru(Broadcaster):
|
|||||||
self.notify('dupes_selected')
|
self.notify('dupes_selected')
|
||||||
|
|
||||||
#--- Protected
|
#--- Protected
|
||||||
|
def _get_fileclasses(self):
|
||||||
|
if self.app_mode == AppMode.Picture:
|
||||||
|
return [pe.photo.PLAT_SPECIFIC_PHOTO_CLASS]
|
||||||
|
elif self.app_mode == AppMode.Music:
|
||||||
|
return [me.fs.MusicFile]
|
||||||
|
else:
|
||||||
|
return [se.fs.File]
|
||||||
|
|
||||||
def _prioritization_categories(self):
|
def _prioritization_categories(self):
|
||||||
if self.app_mode == AppMode.Picture:
|
if self.app_mode == AppMode.Picture:
|
||||||
return pe.prioritize.all_categories()
|
return pe.prioritize.all_categories()
|
||||||
@ -743,7 +751,7 @@ class DupeGuru(Broadcaster):
|
|||||||
def do(j):
|
def do(j):
|
||||||
j.set_progress(0, tr("Collecting files to scan"))
|
j.set_progress(0, tr("Collecting files to scan"))
|
||||||
if scanner.scan_type == ScanType.Folders:
|
if scanner.scan_type == ScanType.Folders:
|
||||||
files = list(self.directories.get_folders(folderclass=se.fs.folder, j=j))
|
files = list(self.directories.get_folders(folderclass=se.fs.Folder, j=j))
|
||||||
else:
|
else:
|
||||||
files = list(self.directories.get_files(fileclasses=self.fileclasses, j=j))
|
files = list(self.directories.get_files(fileclasses=self.fileclasses, j=j))
|
||||||
if self.options['ignore_hardlink_matches']:
|
if self.options['ignore_hardlink_matches']:
|
||||||
@ -794,12 +802,7 @@ class DupeGuru(Broadcaster):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def fileclasses(self):
|
def fileclasses(self):
|
||||||
if self.app_mode == AppMode.Picture:
|
return self._get_fileclasses()
|
||||||
return [pe.photo.PLAT_SPECIFIC_PHOTO_CLASS]
|
|
||||||
elif self.app_mode == AppMode.Music:
|
|
||||||
return [me.fs.MusicFile]
|
|
||||||
else:
|
|
||||||
return [se.fs.File]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SCANNER_CLASS(self):
|
def SCANNER_CLASS(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user