mirror of
https://github.com/arsenetar/dupeguru.git
synced 2025-03-10 05:34:36 +00:00
Began the transition to a HSOutline based result outline. There's still a lot of glitches, the most glaring one being the lack of support for multiple selection.
This commit is contained in:
parent
87351b5920
commit
42559f13d8
@ -36,7 +36,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
- (void)addSelectedToIgnoreList;
|
- (void)addSelectedToIgnoreList;
|
||||||
- (void)removeSelected;
|
- (void)removeSelected;
|
||||||
- (void)openSelected;
|
- (void)openSelected;
|
||||||
- (NSNumber *)renameSelected:(NSString *)aNewName;
|
|
||||||
- (void)revealSelected;
|
- (void)revealSelected;
|
||||||
- (void)makeSelectedReference;
|
- (void)makeSelectedReference;
|
||||||
- (void)applyFilter:(NSString *)filter;
|
- (void)applyFilter:(NSString *)filter;
|
||||||
|
19
cocoa/base/PyResultTree.h
Normal file
19
cocoa/base/PyResultTree.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||||
|
|
||||||
|
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||||
|
which should be included with this package. The terms are also available at
|
||||||
|
http://www.hardcoded.net/licenses/hs_license
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import "PyOutline.h"
|
||||||
|
|
||||||
|
@interface PyResultTree : PyOutline
|
||||||
|
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode;
|
||||||
|
|
||||||
|
- (NSString *)valueForPath:(NSArray *)aPath column:(NSInteger)aColumn;
|
||||||
|
- (BOOL)renameSelected:(NSString *)aNewName;
|
||||||
|
- (void)sortBy:(NSInteger)aIdentifier ascending:(BOOL)aAscending;
|
||||||
|
- (void)markSelected;
|
||||||
|
@end
|
21
cocoa/base/ResultOutline.h
Normal file
21
cocoa/base/ResultOutline.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||||
|
|
||||||
|
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||||
|
which should be included with this package. The terms are also available at
|
||||||
|
http://www.hardcoded.net/licenses/hs_license
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import "HSOutline.h"
|
||||||
|
#import "PyResultTree.h"
|
||||||
|
|
||||||
|
@interface ResultOutline : HSOutline
|
||||||
|
{
|
||||||
|
NSMutableIndexSet *_deltaColumns;
|
||||||
|
}
|
||||||
|
- (PyResultTree *)py;
|
||||||
|
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode;
|
||||||
|
|
||||||
|
- (IBAction)markSelected:(id)sender;
|
||||||
|
@end;
|
107
cocoa/base/ResultOutline.m
Normal file
107
cocoa/base/ResultOutline.m
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||||
|
|
||||||
|
This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||||
|
which should be included with this package. The terms are also available at
|
||||||
|
http://www.hardcoded.net/licenses/hs_license
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "ResultOutline.h"
|
||||||
|
#import "Dialogs.h"
|
||||||
|
#import "Utils.h"
|
||||||
|
#import "Consts.h"
|
||||||
|
|
||||||
|
@implementation ResultOutline
|
||||||
|
- (id)initWithPyParent:(id)aPyParent view:(HSOutlineView *)aOutlineView
|
||||||
|
{
|
||||||
|
self = [super initWithPyClassName:@"PyResultOutline" pyParent:aPyParent view:aOutlineView];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (PyResultTree *)py
|
||||||
|
{
|
||||||
|
return (PyResultTree *)py;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override */
|
||||||
|
- (void)refresh
|
||||||
|
{
|
||||||
|
[super refresh];
|
||||||
|
[outlineView expandItem:nil expandChildren:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public */
|
||||||
|
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode
|
||||||
|
{
|
||||||
|
[[self py] setPowerMarkerMode:aPowerMarkerMode];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)markSelected:(id)sender
|
||||||
|
{
|
||||||
|
[[self py] markSelected];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Datasource */
|
||||||
|
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)column byItem:(id)item
|
||||||
|
{
|
||||||
|
NSIndexPath *path = item;
|
||||||
|
NSString *identifier = [column identifier];
|
||||||
|
if ([identifier isEqual:@"mark"]) {
|
||||||
|
return b2n([self boolProperty:@"marked" valueAtPath:path]);
|
||||||
|
}
|
||||||
|
NSInteger columnId = [identifier integerValue];
|
||||||
|
return [[self py] valueForPath:p2a(path) column:columnId];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)outlineView:(NSOutlineView *)aOutlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
|
||||||
|
{
|
||||||
|
if (![[tableColumn identifier] isEqual:@"0"])
|
||||||
|
return; //We only want to cover renames.
|
||||||
|
NSIndexPath *path = item;
|
||||||
|
NSString *oldName = [[self py] valueForPath:p2a(path) column:0];
|
||||||
|
NSString *newName = object;
|
||||||
|
if (![newName isEqual:oldName]) {
|
||||||
|
BOOL renamed = [[self py] renameSelected:newName];
|
||||||
|
if (renamed) {
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[Dialogs showMessage:[NSString stringWithFormat:@"The name '%@' already exists.", newName]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delegate */
|
||||||
|
- (void)outlineView:(NSOutlineView *)aOutlineView didClickTableColumn:(NSTableColumn *)tableColumn
|
||||||
|
{
|
||||||
|
if ([[outlineView sortDescriptors] count] < 1)
|
||||||
|
return;
|
||||||
|
NSSortDescriptor *sd = [[outlineView sortDescriptors] objectAtIndex:0];
|
||||||
|
[[self py] sortBy:[[sd key] integerValue] ascending:[sd ascending]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||||
|
{
|
||||||
|
NSIndexPath *path = item;
|
||||||
|
BOOL isMarkable = [self boolProperty:@"markable" valueAtPath:path];
|
||||||
|
if ([[tableColumn identifier] isEqual:@"mark"]) {
|
||||||
|
[cell setEnabled:isMarkable];
|
||||||
|
}
|
||||||
|
if ([cell isKindOfClass:[NSTextFieldCell class]]) {
|
||||||
|
// Determine if the text color will be blue due to directory being reference.
|
||||||
|
NSTextFieldCell *textCell = cell;
|
||||||
|
if (isMarkable) {
|
||||||
|
[textCell setTextColor:[NSColor blackColor]];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[textCell setTextColor:[NSColor blueColor]];
|
||||||
|
}
|
||||||
|
// if ((_displayDelta) && (_powerMode || ([node level] > 1))) {
|
||||||
|
// NSInteger i = [[tableColumn identifier] integerValue];
|
||||||
|
// if ([_deltaColumns containsIndex:i]) {
|
||||||
|
// [textCell setTextColor:[NSColor orangeColor]];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
@ -7,10 +7,11 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "Outline.h"
|
#import "HSOutlineView.h"
|
||||||
|
#import "ResultOutline.h"
|
||||||
#import "PyDupeGuru.h"
|
#import "PyDupeGuru.h"
|
||||||
|
|
||||||
@interface MatchesView : OutlineView
|
@interface MatchesView : HSOutlineView
|
||||||
- (void)keyDown:(NSEvent *)theEvent;
|
- (void)keyDown:(NSEvent *)theEvent;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -31,16 +32,15 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
NSMutableArray *_resultColumns;
|
NSMutableArray *_resultColumns;
|
||||||
NSMutableIndexSet *_deltaColumns;
|
NSMutableIndexSet *_deltaColumns;
|
||||||
NSWindowController *preferencesPanel;
|
NSWindowController *preferencesPanel;
|
||||||
|
ResultOutline *outline;
|
||||||
}
|
}
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
- (void)fillColumnsMenu;
|
- (void)fillColumnsMenu;
|
||||||
- (NSTableColumn *)getColumnForIdentifier:(NSInteger)aIdentifier title:(NSString *)aTitle width:(NSInteger)aWidth refCol:(NSTableColumn *)aColumn;
|
- (NSTableColumn *)getColumnForIdentifier:(NSInteger)aIdentifier title:(NSString *)aTitle width:(NSInteger)aWidth refCol:(NSTableColumn *)aColumn;
|
||||||
- (NSArray *)getColumnsOrder;
|
- (NSArray *)getColumnsOrder;
|
||||||
- (NSDictionary *)getColumnsWidth;
|
- (NSDictionary *)getColumnsWidth;
|
||||||
- (NSArray *)getSelected:(BOOL)aDupesOnly;
|
|
||||||
- (NSArray *)getSelectedPaths:(BOOL)aDupesOnly;
|
- (NSArray *)getSelectedPaths:(BOOL)aDupesOnly;
|
||||||
- (void)initResultColumns;
|
- (void)initResultColumns;
|
||||||
- (void)updatePySelection;
|
|
||||||
- (void)performPySelection:(NSArray *)aIndexPaths;
|
- (void)performPySelection:(NSArray *)aIndexPaths;
|
||||||
- (void)refreshStats;
|
- (void)refreshStats;
|
||||||
- (void)reloadMatches;
|
- (void)reloadMatches;
|
||||||
|
@ -28,23 +28,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
else
|
else
|
||||||
[super keyDown:theEvent];
|
[super keyDown:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
|
|
||||||
{
|
|
||||||
if (![[tableColumn identifier] isEqual:@"0"])
|
|
||||||
return; //We only want to cover renames.
|
|
||||||
OVNode *node = item;
|
|
||||||
NSString *oldName = [[node buffer] objectAtIndex:0];
|
|
||||||
NSString *newName = object;
|
|
||||||
if (![newName isEqual:oldName])
|
|
||||||
{
|
|
||||||
BOOL renamed = n2b([(PyDupeGuruBase *)py renameSelected:newName]);
|
|
||||||
if (renamed)
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
else
|
|
||||||
[Dialogs showMessage:[NSString stringWithFormat:@"The name '%@' already exists.",newName]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ResultWindowBase
|
@implementation ResultWindowBase
|
||||||
@ -54,6 +37,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
_powerMode = NO;
|
_powerMode = NO;
|
||||||
[self window];
|
[self window];
|
||||||
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
|
||||||
|
outline = [[ResultOutline alloc] initWithPyParent:py view:matches];
|
||||||
[self initResultColumns];
|
[self initResultColumns];
|
||||||
[self fillColumnsMenu];
|
[self fillColumnsMenu];
|
||||||
[deltaSwitch setSelectedSegment:0];
|
[deltaSwitch setSelectedSegment:0];
|
||||||
@ -69,11 +53,11 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobInProgress:) name:JobInProgress object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobInProgress:) name:JobInProgress object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsMarkingChanged:) name:ResultsMarkingChangedNotification object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsMarkingChanged:) name:ResultsMarkingChangedNotification object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsChanged:) name:ResultsChangedNotification object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsChanged:) name:ResultsChangedNotification object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resultsUpdated:) name:ResultsUpdatedNotification object:nil];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
|
[outline release];
|
||||||
[preferencesPanel release];
|
[preferencesPanel release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
@ -130,34 +114,22 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)getSelected:(BOOL)aDupesOnly
|
- (NSArray *)getSelectedPaths:(BOOL)aDupesOnly
|
||||||
{
|
{
|
||||||
if (_powerMode)
|
if (_powerMode)
|
||||||
aDupesOnly = NO;
|
aDupesOnly = NO;
|
||||||
NSIndexSet *indexes = [matches selectedRowIndexes];
|
NSIndexSet *indexes = [matches selectedRowIndexes];
|
||||||
NSMutableArray *nodeList = [NSMutableArray array];
|
NSMutableArray *nodeList = [NSMutableArray array];
|
||||||
OVNode *node;
|
|
||||||
NSInteger i = [indexes firstIndex];
|
NSInteger i = [indexes firstIndex];
|
||||||
while (i != NSNotFound)
|
while (i != NSNotFound) {
|
||||||
{
|
NSIndexPath *path = [matches itemAtRow:i];
|
||||||
node = [matches itemAtRow:i];
|
if (!aDupesOnly || ([path length] > 1))
|
||||||
if (!aDupesOnly || ([node level] > 1))
|
[nodeList addObject:p2a(path)];
|
||||||
[nodeList addObject:node];
|
|
||||||
i = [indexes indexGreaterThanIndex:i];
|
i = [indexes indexGreaterThanIndex:i];
|
||||||
}
|
}
|
||||||
return nodeList;
|
return nodeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)getSelectedPaths:(BOOL)aDupesOnly
|
|
||||||
{
|
|
||||||
NSMutableArray *r = [NSMutableArray array];
|
|
||||||
NSArray *selected = [self getSelected:aDupesOnly];
|
|
||||||
for (OVNode *node in selected) {
|
|
||||||
[r addObject:p2a([node indexPath])];
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)initResultColumns
|
- (void)initResultColumns
|
||||||
{
|
{
|
||||||
// Virtual
|
// Virtual
|
||||||
@ -185,17 +157,17 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updatePySelection
|
// - (void)updatePySelection
|
||||||
{
|
// {
|
||||||
NSArray *selection;
|
// NSArray *selection;
|
||||||
if (_powerMode) {
|
// if (_powerMode) {
|
||||||
selection = [py selectedPowerMarkerNodePaths];
|
// selection = [py selectedPowerMarkerNodePaths];
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
selection = [py selectedResultNodePaths];
|
// selection = [py selectedResultNodePaths];
|
||||||
}
|
// }
|
||||||
[matches selectNodePaths:selection];
|
// [matches selectNodePaths:selection];
|
||||||
}
|
// }
|
||||||
|
|
||||||
- (void)performPySelection:(NSArray *)aIndexPaths
|
- (void)performPySelection:(NSArray *)aIndexPaths
|
||||||
{
|
{
|
||||||
@ -215,11 +187,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
/* Reload the matches outline and restore selection from py */
|
/* Reload the matches outline and restore selection from py */
|
||||||
- (void)reloadMatches
|
- (void)reloadMatches
|
||||||
{
|
{
|
||||||
[matches setDelegate:nil];
|
[outline refresh];
|
||||||
[matches reloadData];
|
|
||||||
[matches expandItem:nil expandChildren:YES];
|
|
||||||
[matches setDelegate:self];
|
|
||||||
[self updatePySelection];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
@ -243,13 +211,8 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
- (IBAction)changePowerMarker:(id)sender
|
- (IBAction)changePowerMarker:(id)sender
|
||||||
{
|
{
|
||||||
_powerMode = [pmSwitch selectedSegment] == 1;
|
_powerMode = [pmSwitch selectedSegment] == 1;
|
||||||
if (_powerMode)
|
[outline setPowerMarkerMode:_powerMode];
|
||||||
[matches setTag:2];
|
// [self outlineView:matches didClickTableColumn:nil];
|
||||||
else
|
|
||||||
[matches setTag:0];
|
|
||||||
[matches expandItem:nil expandChildren:YES];
|
|
||||||
[self outlineView:matches didClickTableColumn:nil];
|
|
||||||
[self updatePySelection];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)copyMarked:(id)sender
|
- (IBAction)copyMarked:(id)sender
|
||||||
@ -299,10 +262,10 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (IBAction)ignoreSelected:(id)sender
|
- (IBAction)ignoreSelected:(id)sender
|
||||||
{
|
{
|
||||||
NSArray *nodeList = [self getSelected:YES];
|
NSArray *pathList = [self getSelectedPaths:YES];
|
||||||
if (![nodeList count])
|
if (![pathList count])
|
||||||
return;
|
return;
|
||||||
NSString *msg = [NSString stringWithFormat:@"All selected %d matches are going to be ignored in all subsequent scans. Continue?",[nodeList count]];
|
NSString *msg = [NSString stringWithFormat:@"All selected %d matches are going to be ignored in all subsequent scans. Continue?",[pathList count]];
|
||||||
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
|
||||||
return;
|
return;
|
||||||
[py addSelectedToIgnoreList];
|
[py addSelectedToIgnoreList];
|
||||||
@ -336,8 +299,8 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (IBAction)markToggle:(id)sender
|
- (IBAction)markToggle:(id)sender
|
||||||
{
|
{
|
||||||
OVNode *node = [matches itemAtRow:[matches clickedRow]];
|
NSIndexPath *path = [matches itemAtRow:[matches clickedRow]];
|
||||||
[self performPySelection:[NSArray arrayWithObject:p2a([node indexPath])]];
|
[self performPySelection:[NSArray arrayWithObject:p2a(path)]];
|
||||||
[py toggleSelectedMark];
|
[py toggleSelectedMark];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsMarkingChangedNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsMarkingChangedNotification object:self];
|
||||||
}
|
}
|
||||||
@ -395,10 +358,10 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (IBAction)removeSelected:(id)sender
|
- (IBAction)removeSelected:(id)sender
|
||||||
{
|
{
|
||||||
NSArray *nodeList = [self getSelected:YES];
|
NSArray *pathList = [self getSelectedPaths:YES];
|
||||||
if (![nodeList count])
|
if (![pathList count])
|
||||||
return;
|
return;
|
||||||
if ([Dialogs askYesNo:[NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",[nodeList count]]] == NSAlertSecondButtonReturn) // NO
|
if ([Dialogs askYesNo:[NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",[pathList count]]] == NSAlertSecondButtonReturn) // NO
|
||||||
return;
|
return;
|
||||||
[self performPySelection:[self getSelectedPaths:YES]];
|
[self performPySelection:[self getSelectedPaths:YES]];
|
||||||
[py removeSelected];
|
[py removeSelected];
|
||||||
@ -430,19 +393,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (IBAction)switchSelected:(id)sender
|
- (IBAction)switchSelected:(id)sender
|
||||||
{
|
{
|
||||||
// It might look like a complicated way to get the length of the current dupe list on the py side
|
|
||||||
// but after a lot of fussing around, believe it or not, it actually is.
|
|
||||||
NSInteger matchesTag = _powerMode ? 2 : 0;
|
|
||||||
NSInteger startLen = [[py getOutlineView:matchesTag childCountsForPath:[NSArray array]] count];
|
|
||||||
[py makeSelectedReference];
|
[py makeSelectedReference];
|
||||||
[self performPySelection:[self getSelectedPaths:NO]];
|
|
||||||
// In some cases (when in a filtered view in Power Marker mode, it's possible that the demoted
|
|
||||||
// ref is not a part of the filter, making the table smaller. In those cases, we want to do a
|
|
||||||
// complete reload of the table to avoid a crash.
|
|
||||||
if ([[py getOutlineView:matchesTag childCountsForPath:[NSArray array]] count] == startLen)
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsUpdatedNotification object:self];
|
|
||||||
else
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)toggleColumn:(id)sender
|
- (IBAction)toggleColumn:(id)sender
|
||||||
@ -488,43 +439,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[self changePowerMarker:sender];
|
[self changePowerMarker:sender];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delegate */
|
|
||||||
- (void)outlineView:(NSOutlineView *)outlineView didClickTableColumn:(NSTableColumn *)tableColumn
|
|
||||||
{
|
|
||||||
if ([[outlineView sortDescriptors] count] < 1)
|
|
||||||
return;
|
|
||||||
NSSortDescriptor *sd = [[outlineView sortDescriptors] objectAtIndex:0];
|
|
||||||
if (_powerMode)
|
|
||||||
[py sortDupesBy:i2n([[sd key] intValue]) ascending:b2n([sd ascending])];
|
|
||||||
else
|
|
||||||
[py sortGroupsBy:i2n([[sd key] intValue]) ascending:b2n([sd ascending])];
|
|
||||||
[self reloadMatches];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
|
||||||
{
|
|
||||||
OVNode *node = item;
|
|
||||||
if ([[tableColumn identifier] isEqual:@"mark"]) {
|
|
||||||
[cell setEnabled: [node isMarkable]];
|
|
||||||
}
|
|
||||||
if ([cell isKindOfClass:[NSTextFieldCell class]]) {
|
|
||||||
// Determine if the text color will be blue due to directory being reference.
|
|
||||||
NSTextFieldCell *textCell = cell;
|
|
||||||
if ([node isMarkable]) {
|
|
||||||
[textCell setTextColor:[NSColor blackColor]];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
[textCell setTextColor:[NSColor blueColor]];
|
|
||||||
}
|
|
||||||
if ((_displayDelta) && (_powerMode || ([node level] > 1))) {
|
|
||||||
NSInteger i = [[tableColumn identifier] integerValue];
|
|
||||||
if ([_deltaColumns containsIndex:i]) {
|
|
||||||
[textCell setTextColor:[NSColor orangeColor]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Notifications */
|
/* Notifications */
|
||||||
- (void)windowWillClose:(NSNotification *)aNotification
|
- (void)windowWillClose:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
@ -533,7 +447,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (void)jobCompleted:(NSNotification *)aNotification
|
- (void)jobCompleted:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:ResultsChangedNotification object:self];
|
|
||||||
NSInteger r = n2i([py getOperationalErrorCount]);
|
NSInteger r = n2i([py getOperationalErrorCount]);
|
||||||
id lastAction = [[ProgressController mainProgressController] jobId];
|
id lastAction = [[ProgressController mainProgressController] jobId];
|
||||||
if ([lastAction isEqualTo:jobCopy]) {
|
if ([lastAction isEqualTo:jobCopy]) {
|
||||||
@ -558,7 +471,7 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
[Dialogs showMessage:@"All marked files were sucessfully sent to Trash."];
|
[Dialogs showMessage:@"All marked files were sucessfully sent to Trash."];
|
||||||
}
|
}
|
||||||
else if ([lastAction isEqualTo:jobScan]) {
|
else if ([lastAction isEqualTo:jobScan]) {
|
||||||
NSInteger groupCount = [[py getOutlineView:0 childCountsForPath:[NSArray array]] count];
|
NSInteger groupCount = [outline intProperty:@"children_count" valueAtPath:nil];
|
||||||
if (groupCount == 0)
|
if (groupCount == 0)
|
||||||
[Dialogs showMessage:@"No duplicates found."];
|
[Dialogs showMessage:@"No duplicates found."];
|
||||||
}
|
}
|
||||||
@ -602,16 +515,10 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
|
|
||||||
- (void)resultsMarkingChanged:(NSNotification *)aNotification
|
- (void)resultsMarkingChanged:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
[matches invalidateMarkings];
|
[self reloadMatches];
|
||||||
[self refreshStats];
|
[self refreshStats];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)resultsUpdated:(NSNotification *)aNotification
|
|
||||||
{
|
|
||||||
[matches invalidateBuffers];
|
|
||||||
[matches invalidateMarkings];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
|
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
|
||||||
{
|
{
|
||||||
return ![[ProgressController mainProgressController] isShown];
|
return ![[ProgressController mainProgressController] isShown];
|
||||||
|
@ -7,7 +7,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "../../cocoalib/Outline.h"
|
|
||||||
#import "../base/ResultWindow.h"
|
#import "../base/ResultWindow.h"
|
||||||
#import "DirectoryPanel.h"
|
#import "DirectoryPanel.h"
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */; };
|
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CC511242D00004B0AA7 /* NSTableViewAdditions.m */; };
|
||||||
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */; };
|
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */; };
|
||||||
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */; };
|
CE073F6309CAE1A3005C1D2F /* dupeguru_me_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */; };
|
||||||
|
CE0B3D6711243F83009A7A30 /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE0B3D6611243F83009A7A30 /* ResultOutline.m */; };
|
||||||
CE1425890AFB718500BD5167 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
CE1425890AFB718500BD5167 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
||||||
CE14259F0AFB719300BD5167 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
CE14259F0AFB719300BD5167 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE1425880AFB718500BD5167 /* Sparkle.framework */; };
|
||||||
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; };
|
||||||
@ -43,7 +44,6 @@
|
|||||||
CE4B59CA1119919700C06C9E /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4B59C71119919700C06C9E /* registration.xib */; };
|
CE4B59CA1119919700C06C9E /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4B59C71119919700C06C9E /* registration.xib */; };
|
||||||
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE10FC6C12E00EC695D /* Dialogs.m */; };
|
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE10FC6C12E00EC695D /* Dialogs.m */; };
|
||||||
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */; };
|
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */; };
|
||||||
CE515DF50FC6C12E00EC695D /* Outline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE50FC6C12E00EC695D /* Outline.m */; };
|
|
||||||
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE70FC6C12E00EC695D /* ProgressController.m */; };
|
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DE70FC6C12E00EC695D /* ProgressController.m */; };
|
||||||
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */; };
|
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEA0FC6C12E00EC695D /* RecentDirectories.m */; };
|
||||||
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEC0FC6C12E00EC695D /* RegistrationInterface.m */; };
|
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CE515DEC0FC6C12E00EC695D /* RegistrationInterface.m */; };
|
||||||
@ -107,6 +107,9 @@
|
|||||||
CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryOutline.m; path = ../base/DirectoryOutline.m; sourceTree = SOURCE_ROOT; };
|
CE003CCE11242D2C004B0AA7 /* DirectoryOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryOutline.m; path = ../base/DirectoryOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE003CCF11242D2C004B0AA7 /* PyDirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDirectoryOutline.h; path = ../base/PyDirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
CE003CCF11242D2C004B0AA7 /* PyDirectoryOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDirectoryOutline.h; path = ../base/PyDirectoryOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_me_help; path = ../../help_me/dupeguru_me_help; sourceTree = "<group>"; };
|
CE073F5409CAE1A3005C1D2F /* dupeguru_me_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_me_help; path = ../../help_me/dupeguru_me_help; sourceTree = "<group>"; };
|
||||||
|
CE0B3D6411243F83009A7A30 /* PyResultTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTree.h; path = ../base/PyResultTree.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0B3D6511243F83009A7A30 /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE0B3D6611243F83009A7A30 /* ResultOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultOutline.m; path = ../base/ResultOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE1425880AFB718500BD5167 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
CE1425880AFB718500BD5167 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
|
||||||
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
|
||||||
@ -124,8 +127,6 @@
|
|||||||
CE515DE10FC6C12E00EC695D /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
CE515DE10FC6C12E00EC695D /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
CE515DE20FC6C12E00EC695D /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE40FC6C12E00EC695D /* Outline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Outline.h; path = ../../cocoalib/Outline.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE515DE50FC6C12E00EC695D /* Outline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Outline.m; path = ../../cocoalib/Outline.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CE515DE60FC6C12E00EC695D /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
CE515DE60FC6C12E00EC695D /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE70FC6C12E00EC695D /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
CE515DE70FC6C12E00EC695D /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
||||||
CE515DE80FC6C12E00EC695D /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
CE515DE80FC6C12E00EC695D /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
||||||
@ -349,8 +350,6 @@
|
|||||||
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */,
|
CE515DE30FC6C12E00EC695D /* HSErrorReportWindow.m */,
|
||||||
CE003CB911242D00004B0AA7 /* NSEventAdditions.h */,
|
CE003CB911242D00004B0AA7 /* NSEventAdditions.h */,
|
||||||
CE003CBA11242D00004B0AA7 /* NSEventAdditions.m */,
|
CE003CBA11242D00004B0AA7 /* NSEventAdditions.m */,
|
||||||
CE515DE40FC6C12E00EC695D /* Outline.h */,
|
|
||||||
CE515DE50FC6C12E00EC695D /* Outline.m */,
|
|
||||||
CE515DE60FC6C12E00EC695D /* ProgressController.h */,
|
CE515DE60FC6C12E00EC695D /* ProgressController.h */,
|
||||||
CE515DE70FC6C12E00EC695D /* ProgressController.m */,
|
CE515DE70FC6C12E00EC695D /* ProgressController.m */,
|
||||||
CE515DE80FC6C12E00EC695D /* PyApp.h */,
|
CE515DE80FC6C12E00EC695D /* PyApp.h */,
|
||||||
@ -380,10 +379,13 @@
|
|||||||
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */,
|
CE6032BF0FE6784C007E33FF /* DetailsPanel.m */,
|
||||||
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
|
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
|
||||||
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
|
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
|
||||||
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
|
|
||||||
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */,
|
|
||||||
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
|
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
|
||||||
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
|
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
|
||||||
|
CE0B3D6511243F83009A7A30 /* ResultOutline.h */,
|
||||||
|
CE0B3D6611243F83009A7A30 /* ResultOutline.m */,
|
||||||
|
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
|
||||||
|
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */,
|
||||||
|
CE0B3D6411243F83009A7A30 /* PyResultTree.h */,
|
||||||
);
|
);
|
||||||
name = dgbase;
|
name = dgbase;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -473,7 +475,6 @@
|
|||||||
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */,
|
CE68EE6809ABC48000971085 /* DirectoryPanel.m in Sources */,
|
||||||
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */,
|
CE515DF30FC6C12E00EC695D /* Dialogs.m in Sources */,
|
||||||
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */,
|
CE515DF40FC6C12E00EC695D /* HSErrorReportWindow.m in Sources */,
|
||||||
CE515DF50FC6C12E00EC695D /* Outline.m in Sources */,
|
|
||||||
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */,
|
CE515DF60FC6C12E00EC695D /* ProgressController.m in Sources */,
|
||||||
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */,
|
CE515DF70FC6C12E00EC695D /* RecentDirectories.m in Sources */,
|
||||||
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */,
|
CE515DF80FC6C12E00EC695D /* RegistrationInterface.m in Sources */,
|
||||||
@ -492,6 +493,7 @@
|
|||||||
CE003CCB11242D00004B0AA7 /* NSIndexPathAdditions.m in Sources */,
|
CE003CCB11242D00004B0AA7 /* NSIndexPathAdditions.m in Sources */,
|
||||||
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */,
|
CE003CCC11242D00004B0AA7 /* NSTableViewAdditions.m in Sources */,
|
||||||
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */,
|
CE003CD011242D2C004B0AA7 /* DirectoryOutline.m in Sources */,
|
||||||
|
CE0B3D6711243F83009A7A30 /* ResultOutline.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
11
core/app.py
11
core/app.py
@ -104,6 +104,11 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
path = Path(str_path)
|
path = Path(str_path)
|
||||||
return fs.get_file(path, self.directories.fileclasses)
|
return fs.get_file(path, self.directories.fileclasses)
|
||||||
|
|
||||||
|
def _job_completed(self, jobid):
|
||||||
|
# Must be called by subclasses when they detect that an async job is completed.
|
||||||
|
if jobid in (JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_DELETE):
|
||||||
|
self.notify('results_changed')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _open_path(path):
|
def _open_path(path):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@ -233,6 +238,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
if g not in changed_groups:
|
if g not in changed_groups:
|
||||||
self.results.make_ref(dupe)
|
self.results.make_ref(dupe)
|
||||||
changed_groups.add(g)
|
changed_groups.add(g)
|
||||||
|
self.notify('results_changed')
|
||||||
|
|
||||||
def open_selected(self):
|
def open_selected(self):
|
||||||
if self.selected_dupes:
|
if self.selected_dupes:
|
||||||
@ -283,6 +289,11 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
self.results.groups = []
|
self.results.groups = []
|
||||||
self._start_job(JOB_SCAN, do)
|
self._start_job(JOB_SCAN, do)
|
||||||
|
|
||||||
|
def toggle_selected_mark_state(self):
|
||||||
|
for dupe in self.selected_dupes:
|
||||||
|
self.results.mark_toggle(dupe)
|
||||||
|
self.notify('results_changed')
|
||||||
|
|
||||||
def without_ref(self, dupes):
|
def without_ref(self, dupes):
|
||||||
return [dupe for dupe in dupes if self.results.get_group_of_duplicate(dupe).ref is not dupe]
|
return [dupe for dupe in dupes if self.results.get_group_of_duplicate(dupe).ref is not dupe]
|
||||||
|
|
||||||
|
@ -162,57 +162,3 @@ class DupeGuru(app.DupeGuru):
|
|||||||
def sort_groups(self,key,asc):
|
def sort_groups(self,key,asc):
|
||||||
self.results.sort_groups(key,asc)
|
self.results.sort_groups(key,asc)
|
||||||
|
|
||||||
def ToggleSelectedMarkState(self):
|
|
||||||
for dupe in self.selected_dupes:
|
|
||||||
self.results.mark_toggle(dupe)
|
|
||||||
|
|
||||||
#---Data
|
|
||||||
def GetOutlineViewMaxLevel(self, tag):
|
|
||||||
if tag == 0:
|
|
||||||
return 2
|
|
||||||
elif tag == 2:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
def GetOutlineViewChildCounts(self, tag, node_path):
|
|
||||||
if self.progress._job_running:
|
|
||||||
return []
|
|
||||||
if tag == 0: #Normal results
|
|
||||||
assert not node_path # no other value is possible
|
|
||||||
return [len(g.dupes) for g in self.results.groups]
|
|
||||||
else: #Power Marker
|
|
||||||
assert not node_path # no other value is possible
|
|
||||||
return [0 for d in self.results.dupes]
|
|
||||||
|
|
||||||
def GetOutlineViewValues(self, tag, node_path):
|
|
||||||
if self.progress._job_running:
|
|
||||||
return
|
|
||||||
if not node_path:
|
|
||||||
return
|
|
||||||
if tag in (0,2): #Normal results / Power Marker
|
|
||||||
if tag == 0:
|
|
||||||
g, d = self.GetObjects(node_path)
|
|
||||||
if (d is None) and (g is not None):
|
|
||||||
d = g.ref
|
|
||||||
else:
|
|
||||||
d = self.results.dupes[node_path[0]]
|
|
||||||
g = self.results.get_group_of_duplicate(d)
|
|
||||||
result = self._get_display_info(d, g, self.display_delta_values)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def GetOutlineViewMarked(self, tag, node_path):
|
|
||||||
# 0=unmarked 1=marked 2=unmarkable
|
|
||||||
if self.progress._job_running:
|
|
||||||
return
|
|
||||||
if not node_path:
|
|
||||||
return 2
|
|
||||||
if tag == 0: #Normal results
|
|
||||||
g, d = self.GetObjects(node_path)
|
|
||||||
else: #Power Marker
|
|
||||||
d = self.results.dupes[node_path[0]]
|
|
||||||
if (d is None) or (not self.results.is_markable(d)):
|
|
||||||
return 2
|
|
||||||
elif self.results.is_marked(d):
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ from hsutil.cocoa.inter import signature, PyOutline, PyGUIObject, PyRegistrable
|
|||||||
|
|
||||||
from .gui.details_panel import DetailsPanel
|
from .gui.details_panel import DetailsPanel
|
||||||
from .gui.directory_tree import DirectoryTree
|
from .gui.directory_tree import DirectoryTree
|
||||||
|
from .gui.result_tree import ResultTree
|
||||||
|
|
||||||
# Fix py2app's problems on relative imports
|
# Fix py2app's problems on relative imports
|
||||||
from core import app, app_cocoa, data, directories, engine, export, ignore, results, fs, scanner
|
from core import app, app_cocoa, data, directories, engine, export, ignore, results, fs, scanner
|
||||||
@ -55,7 +56,7 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
self.py.PurgeIgnoreList()
|
self.py.PurgeIgnoreList()
|
||||||
|
|
||||||
def toggleSelectedMark(self):
|
def toggleSelectedMark(self):
|
||||||
self.py.ToggleSelectedMarkState()
|
self.py.toggle_selected_mark_state()
|
||||||
|
|
||||||
def saveIgnoreList(self):
|
def saveIgnoreList(self):
|
||||||
self.py.save_ignore_list()
|
self.py.save_ignore_list()
|
||||||
@ -126,21 +127,6 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
def getOperationalErrorCount(self):
|
def getOperationalErrorCount(self):
|
||||||
return self.py.last_op_error_count
|
return self.py.last_op_error_count
|
||||||
|
|
||||||
#---Data
|
|
||||||
@signature('i@:i')
|
|
||||||
def getOutlineViewMaxLevel_(self, tag):
|
|
||||||
return self.py.GetOutlineViewMaxLevel(tag)
|
|
||||||
|
|
||||||
@signature('@@:i@')
|
|
||||||
def getOutlineView_childCountsForPath_(self, tag, node_path):
|
|
||||||
return self.py.GetOutlineViewChildCounts(tag, node_path)
|
|
||||||
|
|
||||||
def getOutlineView_valuesForIndexes_(self, tag, node_path):
|
|
||||||
return self.py.GetOutlineViewValues(tag, node_path)
|
|
||||||
|
|
||||||
def getOutlineView_markedAtIndexes_(self, tag, node_path):
|
|
||||||
return self.py.GetOutlineViewMarked(tag, node_path)
|
|
||||||
|
|
||||||
#---Properties
|
#---Properties
|
||||||
def setMixFileKind_(self, mix_file_kind):
|
def setMixFileKind_(self, mix_file_kind):
|
||||||
self.py.scanner.mix_file_kind = mix_file_kind
|
self.py.scanner.mix_file_kind = mix_file_kind
|
||||||
@ -164,6 +150,9 @@ class PyDupeGuruBase(PyRegistrable):
|
|||||||
def cancelJob(self):
|
def cancelJob(self):
|
||||||
self.py.progress.job_cancelled = True
|
self.py.progress.job_cancelled = True
|
||||||
|
|
||||||
|
def jobCompleted_(self, jobid):
|
||||||
|
self.py._job_completed(jobid)
|
||||||
|
|
||||||
|
|
||||||
class PyDetailsPanel(PyGUIObject):
|
class PyDetailsPanel(PyGUIObject):
|
||||||
py_class = DetailsPanel
|
py_class = DetailsPanel
|
||||||
@ -182,3 +171,25 @@ class PyDirectoryOutline(PyOutline):
|
|||||||
def addDirectory_(self, path):
|
def addDirectory_(self, path):
|
||||||
self.py.add_directory(path)
|
self.py.add_directory(path)
|
||||||
|
|
||||||
|
|
||||||
|
class PyResultOutline(PyOutline):
|
||||||
|
py_class = ResultTree
|
||||||
|
|
||||||
|
@signature('v@:c')
|
||||||
|
def setPowerMarkerMode_(self, value):
|
||||||
|
self.py.power_marker = value
|
||||||
|
|
||||||
|
@signature('@@:@i')
|
||||||
|
def valueForPath_column_(self, path, column):
|
||||||
|
return self.py.get_node_value(path, column)
|
||||||
|
|
||||||
|
@signature('c@:@')
|
||||||
|
def renameSelected_(self, newname):
|
||||||
|
return self.py.app.RenameSelected(newname)
|
||||||
|
|
||||||
|
def sortBy_ascending_(self, key, asc):
|
||||||
|
self.py.sort(key, asc)
|
||||||
|
|
||||||
|
def markSelected(self):
|
||||||
|
self.py.app.toggle_selected_mark_state()
|
||||||
|
|
||||||
|
@ -21,3 +21,6 @@ class GUIObject(Listener):
|
|||||||
def dupes_selected(self):
|
def dupes_selected(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def results_changed(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
98
core/gui/result_tree.py
Normal file
98
core/gui/result_tree.py
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Created By: Virgil Dupras
|
||||||
|
# Created On: 2010-02-11
|
||||||
|
# Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
|
||||||
|
#
|
||||||
|
# This software is licensed under the "HS" License as described in the "LICENSE" file,
|
||||||
|
# which should be included with this package. The terms are also available at
|
||||||
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
|
from hsgui.tree import Tree, Node
|
||||||
|
|
||||||
|
from .base import GUIObject
|
||||||
|
|
||||||
|
class DupeNode(Node):
|
||||||
|
def __init__(self, app, group, dupe):
|
||||||
|
Node.__init__(self, '')
|
||||||
|
self._app = app
|
||||||
|
self._group = group
|
||||||
|
self._dupe = dupe
|
||||||
|
self.data = app._get_display_info(dupe, group, False)
|
||||||
|
self.data_delta = app._get_display_info(dupe, group, True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def markable(self):
|
||||||
|
return self._app.results.is_markable(self._dupe)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def marked(self):
|
||||||
|
return self._app.results.is_marked(self._dupe)
|
||||||
|
|
||||||
|
|
||||||
|
class ResultTree(GUIObject, Tree):
|
||||||
|
def __init__(self, view, app):
|
||||||
|
GUIObject.__init__(self, view, app)
|
||||||
|
Tree.__init__(self)
|
||||||
|
self._power_marker = False
|
||||||
|
self.connect()
|
||||||
|
self._refresh()
|
||||||
|
self.view.refresh()
|
||||||
|
|
||||||
|
def _refresh(self):
|
||||||
|
self.clear()
|
||||||
|
if not self.power_marker:
|
||||||
|
for group in self.app.results.groups:
|
||||||
|
group_node = DupeNode(self.app, group, group.ref)
|
||||||
|
self.append(group_node)
|
||||||
|
for dupe in group.dupes:
|
||||||
|
group_node.append(DupeNode(self.app, group, dupe))
|
||||||
|
else:
|
||||||
|
for dupe in self.app.results.dupes:
|
||||||
|
group = self.app.results.get_group_of_duplicate(dupe)
|
||||||
|
self.append(DupeNode(self.app, group, dupe))
|
||||||
|
if self.app.selected_dupes:
|
||||||
|
to_find = self.app.selected_dupes[0]
|
||||||
|
node = self.find(lambda n: n is not self and n._dupe is to_find)
|
||||||
|
self.selected = node
|
||||||
|
|
||||||
|
def get_node_value(self, path, column):
|
||||||
|
try:
|
||||||
|
node = self.get_node(path)
|
||||||
|
except IndexError:
|
||||||
|
return '---'
|
||||||
|
if self.app.display_delta_values:
|
||||||
|
return node.data_delta[column]
|
||||||
|
else:
|
||||||
|
return node.data[column]
|
||||||
|
|
||||||
|
def sort(self, key, asc):
|
||||||
|
if self.power_marker:
|
||||||
|
self.app.sort_dupes(key, asc)
|
||||||
|
else:
|
||||||
|
self.app.sort_groups(key, asc)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def power_marker(self):
|
||||||
|
return self._power_marker
|
||||||
|
|
||||||
|
@power_marker.setter
|
||||||
|
def power_marker(self, value):
|
||||||
|
if value == self._power_marker:
|
||||||
|
return
|
||||||
|
self._power_marker = value
|
||||||
|
self._refresh()
|
||||||
|
self.view.refresh()
|
||||||
|
|
||||||
|
@Tree.selected.setter
|
||||||
|
def selected(self, node):
|
||||||
|
self._selected = node
|
||||||
|
if node is None:
|
||||||
|
self.app._select_dupes([])
|
||||||
|
else:
|
||||||
|
self.app._select_dupes([node._dupe])
|
||||||
|
|
||||||
|
#--- Event Handlers
|
||||||
|
def results_changed(self):
|
||||||
|
self._refresh()
|
||||||
|
self.view.refresh()
|
||||||
|
|
@ -243,16 +243,16 @@ class TCDupeGuru(TestCase):
|
|||||||
def test_toggleSelectedMark(self):
|
def test_toggleSelectedMark(self):
|
||||||
app = self.app
|
app = self.app
|
||||||
objects = self.objects
|
objects = self.objects
|
||||||
app.ToggleSelectedMarkState()
|
app.toggle_selected_mark_state()
|
||||||
self.assertEqual(0,app.results.mark_count)
|
eq_(app.results.mark_count, 0)
|
||||||
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
||||||
app.ToggleSelectedMarkState()
|
app.toggle_selected_mark_state()
|
||||||
self.assertEqual(2,app.results.mark_count)
|
eq_(app.results.mark_count, 2)
|
||||||
self.assert_(not app.results.is_marked(objects[0]))
|
assert not app.results.is_marked(objects[0])
|
||||||
self.assert_(app.results.is_marked(objects[1]))
|
assert app.results.is_marked(objects[1])
|
||||||
self.assert_(not app.results.is_marked(objects[2]))
|
assert not app.results.is_marked(objects[2])
|
||||||
self.assert_(not app.results.is_marked(objects[3]))
|
assert not app.results.is_marked(objects[3])
|
||||||
self.assert_(app.results.is_marked(objects[4]))
|
assert app.results.is_marked(objects[4])
|
||||||
|
|
||||||
def test_refreshDetailsWithSelected(self):
|
def test_refreshDetailsWithSelected(self):
|
||||||
self.app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
self.app.SelectPowerMarkerNodePaths(r2np([0,2]))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user