1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2025-03-10 05:34:36 +00:00

Converted the result tree into a result table.

--HG--
rename : cocoa/base/PyResultTree.h => cocoa/base/PyResultTable.h
rename : cocoa/base/ResultOutline.h => cocoa/base/ResultTable.h
rename : cocoa/base/ResultOutline.m => cocoa/base/ResultTable.m
rename : core/gui/result_tree.py => core/gui/result_table.py
This commit is contained in:
Virgil Dupras 2010-09-24 15:48:59 +02:00
parent 9bd093a03c
commit 0d8ed92a68
15 changed files with 566 additions and 698 deletions

View File

@ -7,18 +7,18 @@ http://www.hardcoded.net/licenses/hs_license
*/ */
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "PyOutline.h" #import "PyTable.h"
@interface PyResultTree : PyOutline @interface PyResultTable : PyTable
- (BOOL)powerMarkerMode; - (BOOL)powerMarkerMode;
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode; - (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode;
- (BOOL)deltaValuesMode; - (BOOL)deltaValuesMode;
- (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode; - (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode;
- (NSString *)valueForPath:(NSArray *)aPath column:(NSInteger)aColumn; - (NSString *)valueForRow:(NSInteger)rowIndex column:(NSInteger)aColumn;
- (BOOL)renameSelected:(NSString *)aNewName; - (BOOL)renameSelected:(NSString *)aNewName;
- (void)sortBy:(NSInteger)aIdentifier ascending:(BOOL)aAscending; - (void)sortBy:(NSInteger)aIdentifier ascending:(BOOL)aAscending;
- (void)markSelected; - (void)markSelected;
- (void)removeSelected; - (void)removeSelected;
- (NSArray *)rootChildrenCounts; - (NSInteger)selectedDupeCount;
@end @end

View File

@ -1,207 +0,0 @@
/*
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
This software is licensed under the "HS" License as described in the "LICENSE" file,
which should be included with this package. The terms are also available at
http://www.hardcoded.net/licenses/hs_license
*/
#import "ResultOutline.h"
#import "Dialogs.h"
#import "Utils.h"
#import "Consts.h"
@implementation ResultOutline
- (id)initWithPyParent:(id)aPyParent view:(HSOutlineView *)aOutlineView
{
self = [super initWithPyClassName:@"PyResultOutline" pyParent:aPyParent view:aOutlineView];
_rootChildrenCounts = nil;
[self connect];
return self;
}
- (void)dealloc
{
[self disconnect];
[_deltaColumns release];
[super dealloc];
}
- (PyResultTree *)py
{
return (PyResultTree *)py;
}
/* Public */
- (BOOL)powerMarkerMode
{
return [[self py] powerMarkerMode];
}
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode
{
[[self py] setPowerMarkerMode:aPowerMarkerMode];
}
- (BOOL)deltaValuesMode
{
return [[self py] deltaValuesMode];
}
- (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode
{
[[self py] setDeltaValuesMode:aDeltaValuesMode];
}
- (void)setDeltaColumns:(NSIndexSet *)aDeltaColumns
{
[_deltaColumns release];
_deltaColumns = [aDeltaColumns retain];
}
- (NSInteger)selectedDupeCount
{
NSArray *selected = [self selectedIndexPaths];
if ([self powerMarkerMode]) {
return [selected count];
}
else {
NSInteger r = 0;
for (NSIndexPath *path in selected) {
if ([path length] == 2) {
r++;
}
}
return r;
}
}
- (void)removeSelected
{
NSInteger selectedDupeCount = [self selectedDupeCount];
if (!selectedDupeCount)
return;
NSString *msg = [NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",selectedDupeCount];
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
return;
[[self py] removeSelected];
}
/* Datasource */
- (NSInteger)outlineView:(NSOutlineView *)aOutlineView numberOfChildrenOfItem:(id)item
{
NSIndexPath *path = item;
if ((path != nil) && ([path length] == 1)) {
if (_rootChildrenCounts == nil) {
_rootChildrenCounts = [[[self py] rootChildrenCounts] retain];
}
NSInteger index = [path indexAtPosition:0];
return n2i([_rootChildrenCounts objectAtIndex:index]);
}
return [super outlineView:aOutlineView numberOfChildrenOfItem:item];
}
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)column byItem:(id)item
{
NSIndexPath *path = item;
NSString *identifier = [column identifier];
if ([identifier isEqual:@"marked"]) {
return b2n([self boolProperty:@"marked" valueAtPath:path]);
}
NSInteger columnId = [identifier integerValue];
return [[self py] valueForPath:p2a(path) column:columnId];
}
- (void)outlineView:(NSOutlineView *)aOutlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
if ([[tableColumn identifier] isEqual:@"0"]) {
NSIndexPath *path = item;
NSString *oldName = [[self py] valueForPath:p2a(path) column:0];
NSString *newName = object;
if (![newName isEqual:oldName]) {
BOOL renamed = [[self py] renameSelected:newName];
if (!renamed) {
[Dialogs showMessage:[NSString stringWithFormat:@"The name '%@' already exists.", newName]];
}
else {
[self refreshItemAtPath:path];
}
}
}
else {
[super outlineView:aOutlineView setObjectValue:object forTableColumn:tableColumn byItem:item];
}
}
/* Delegate */
- (void)outlineView:(NSOutlineView *)aOutlineView didClickTableColumn:(NSTableColumn *)tableColumn
{
if ([[outlineView sortDescriptors] count] < 1)
return;
NSSortDescriptor *sd = [[outlineView sortDescriptors] objectAtIndex:0];
[[self py] sortBy:[[sd key] integerValue] ascending:[sd ascending]];
}
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
NSIndexPath *path = item;
BOOL isMarkable = [self boolProperty:@"markable" valueAtPath:path];
if ([[tableColumn identifier] isEqual:@"marked"]) {
[cell setEnabled:isMarkable];
}
if ([cell isKindOfClass:[NSTextFieldCell class]]) {
// Determine if the text color will be blue due to directory being reference.
NSTextFieldCell *textCell = cell;
if (isMarkable) {
[textCell setTextColor:[NSColor blackColor]];
}
else {
[textCell setTextColor:[NSColor blueColor]];
}
if (([self deltaValuesMode]) && ([self powerMarkerMode] || ([path length] > 1))) {
NSInteger i = [[tableColumn identifier] integerValue];
if ([_deltaColumns containsIndex:i]) {
[textCell setTextColor:[NSColor orangeColor]];
}
}
}
}
- (BOOL)tableViewHadDeletePressed:(NSTableView *)tableView
{
[self removeSelected];
return YES;
}
- (BOOL)tableViewHadSpacePressed:(NSTableView *)tableView
{
[[self py] markSelected];
return YES;
}
/* don't calls saveEdits and cancelEdits */
- (void)outlineViewDidEndEditing:(HSOutlineView *)outlineView
{
}
- (void)outlineViewCancelsEdition:(HSOutlineView *)outlineView
{
}
/* Python --> Cocoa */
- (void)refresh /* Override */
{
[_rootChildrenCounts release];
_rootChildrenCounts = nil;
[super refresh];
[outlineView expandItem:nil expandChildren:YES];
}
- (void)invalidateMarkings
{
for (NSMutableDictionary *props in [itemData objectEnumerator]) {
[props removeObjectForKey:@"marked"];
}
[outlineView setNeedsDisplay:YES];
}
@end

View File

@ -7,15 +7,14 @@ http://www.hardcoded.net/licenses/hs_license
*/ */
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "HSOutline.h" #import "HSTable.h"
#import "PyResultTree.h" #import "PyResultTable.h"
@interface ResultOutline : HSOutline @interface ResultTable : HSTable
{ {
NSIndexSet *_deltaColumns; NSIndexSet *_deltaColumns;
NSArray *_rootChildrenCounts;
} }
- (PyResultTree *)py; - (PyResultTable *)py;
- (BOOL)powerMarkerMode; - (BOOL)powerMarkerMode;
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode; - (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode;
- (BOOL)deltaValuesMode; - (BOOL)deltaValuesMode;

162
cocoa/base/ResultTable.m Normal file
View File

@ -0,0 +1,162 @@
/*
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 "ResultTable.h"
#import "Dialogs.h"
#import "Utils.h"
#import "Consts.h"
@implementation ResultTable
- (id)initWithPyParent:(id)aPyParent view:(NSTableView *)aTableView
{
self = [super initWithPyClassName:@"PyResultTable" pyParent:aPyParent view:aTableView];
[self connect];
return self;
}
- (void)dealloc
{
[self disconnect];
[_deltaColumns release];
[super dealloc];
}
- (PyResultTable *)py
{
return (PyResultTable *)py;
}
/* Public */
- (BOOL)powerMarkerMode
{
return [[self py] powerMarkerMode];
}
- (void)setPowerMarkerMode:(BOOL)aPowerMarkerMode
{
[[self py] setPowerMarkerMode:aPowerMarkerMode];
}
- (BOOL)deltaValuesMode
{
return [[self py] deltaValuesMode];
}
- (void)setDeltaValuesMode:(BOOL)aDeltaValuesMode
{
[[self py] setDeltaValuesMode:aDeltaValuesMode];
}
- (void)setDeltaColumns:(NSIndexSet *)aDeltaColumns
{
[_deltaColumns release];
_deltaColumns = [aDeltaColumns retain];
}
- (NSInteger)selectedDupeCount
{
return [[self py] selectedDupeCount];
}
- (void)removeSelected
{
NSInteger selectedDupeCount = [self selectedDupeCount];
if (!selectedDupeCount)
return;
NSString *msg = [NSString stringWithFormat:@"You are about to remove %d files from results. Continue?",selectedDupeCount];
if ([Dialogs askYesNo:msg] == NSAlertSecondButtonReturn) // NO
return;
[[self py] removeSelected];
}
/* Datasource */
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)column row:(NSInteger)row
{
NSString *identifier = [column identifier];
if ([identifier isEqual:@"marked"]) {
return [[self py] valueForColumn:@"marked" row:row];
}
NSInteger columnId = [identifier integerValue];
return [[self py] valueForRow:row column:columnId];
}
- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)column row:(NSInteger)row
{
NSString *identifier = [column identifier];
if ([identifier isEqual:@"marked"]) {
[[self py] setValue:object forColumn:identifier row:row];
}
else if ([identifier isEqual:@"0"]) {
NSString *oldName = [[self py] valueForRow:row column:0];
NSString *newName = object;
if (![newName isEqual:oldName]) {
BOOL renamed = [[self py] renameSelected:newName];
if (!renamed) {
[Dialogs showMessage:[NSString stringWithFormat:@"The name '%@' already exists.", newName]];
}
else {
[tableView setNeedsDisplay:YES];
}
}
}
}
/* Delegate */
- (void)tableView:(NSTableView *)aTableView didClickTableColumn:(NSTableColumn *)tableColumn
{
if ([[tableView sortDescriptors] count] < 1)
return;
NSSortDescriptor *sd = [[tableView sortDescriptors] objectAtIndex:0];
[[self py] sortBy:[[sd key] integerValue] ascending:[sd ascending]];
}
- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)column row:(NSInteger)row
{
BOOL isMarkable = n2b([[self py] valueForColumn:@"markable" row:row]);
if ([[column identifier] isEqual:@"marked"]) {
[cell setEnabled:isMarkable];
// Low-tech solution, for indentation, but it works...
NSCellImagePosition pos = isMarkable ? NSImageRight : NSImageLeft;
[cell setImagePosition:pos];
}
if ([cell isKindOfClass:[NSTextFieldCell class]]) {
// Determine if the text color will be blue due to directory being reference.
NSTextFieldCell *textCell = cell;
if (isMarkable) {
[textCell setTextColor:[NSColor blackColor]];
}
else {
[textCell setTextColor:[NSColor blueColor]];
if ([self deltaValuesMode]) {
NSInteger i = [[column identifier] integerValue];
if ([_deltaColumns containsIndex:i]) {
[textCell setTextColor:[NSColor orangeColor]];
}
}
}
}
}
- (BOOL)tableViewHadDeletePressed:(NSTableView *)tableView
{
[self removeSelected];
return YES;
}
- (BOOL)tableViewHadSpacePressed:(NSTableView *)tableView
{
[[self py] markSelected];
return YES;
}
/* Python --> Cocoa */
- (void)invalidateMarkings
{
[tableView setNeedsDisplay:YES];
}
@end

View File

@ -7,10 +7,10 @@ http://www.hardcoded.net/licenses/hs_license
*/ */
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "HSOutlineView.h"
#import "StatsLabel.h" #import "StatsLabel.h"
#import "ResultOutline.h" #import "ResultTable.h"
#import "ProblemDialog.h" #import "ProblemDialog.h"
#import "HSTableView.h"
#import "PyDupeGuru.h" #import "PyDupeGuru.h"
@interface ResultWindowBase : NSWindowController @interface ResultWindowBase : NSWindowController
@ -19,7 +19,7 @@ http://www.hardcoded.net/licenses/hs_license
IBOutlet PyDupeGuruBase *py; IBOutlet PyDupeGuruBase *py;
IBOutlet id app; IBOutlet id app;
IBOutlet NSSegmentedControl *deltaSwitch; IBOutlet NSSegmentedControl *deltaSwitch;
IBOutlet HSOutlineView *matches; IBOutlet HSTableView *matches;
IBOutlet NSSegmentedControl *pmSwitch; IBOutlet NSSegmentedControl *pmSwitch;
IBOutlet NSTextField *stats; IBOutlet NSTextField *stats;
IBOutlet NSMenu *columnsMenu; IBOutlet NSMenu *columnsMenu;
@ -27,7 +27,7 @@ http://www.hardcoded.net/licenses/hs_license
NSMutableArray *_resultColumns; NSMutableArray *_resultColumns;
NSWindowController *preferencesPanel; NSWindowController *preferencesPanel;
ResultOutline *outline; ResultTable *table;
StatsLabel *statsLabel; StatsLabel *statsLabel;
ProblemDialog *problemDialog; ProblemDialog *problemDialog;
} }

View File

@ -19,7 +19,7 @@ http://www.hardcoded.net/licenses/hs_license
{ {
[self window]; [self window];
preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"]; preferencesPanel = [[NSWindowController alloc] initWithWindowNibName:@"Preferences"];
outline = [[ResultOutline alloc] initWithPyParent:py view:matches]; table = [[ResultTable alloc] initWithPyParent:py view:matches];
statsLabel = [[StatsLabel alloc] initWithPyParent:py labelView:stats]; statsLabel = [[StatsLabel alloc] initWithPyParent:py labelView:stats];
problemDialog = [[ProblemDialog alloc] initWithPy:py]; problemDialog = [[ProblemDialog alloc] initWithPy:py];
[self initResultColumns]; [self initResultColumns];
@ -37,7 +37,7 @@ http://www.hardcoded.net/licenses/hs_license
- (void)dealloc - (void)dealloc
{ {
[outline release]; [table release];
[preferencesPanel release]; [preferencesPanel release];
[statsLabel release]; [statsLabel release];
[problemDialog release]; [problemDialog release];
@ -137,12 +137,12 @@ http://www.hardcoded.net/licenses/hs_license
- (IBAction)changeDelta:(id)sender - (IBAction)changeDelta:(id)sender
{ {
[outline setDeltaValuesMode:[deltaSwitch selectedSegment] == 1]; [table setDeltaValuesMode:[deltaSwitch selectedSegment] == 1];
} }
- (IBAction)changePowerMarker:(id)sender - (IBAction)changePowerMarker:(id)sender
{ {
[outline setPowerMarkerMode:[pmSwitch selectedSegment] == 1]; [table setPowerMarkerMode:[pmSwitch selectedSegment] == 1];
} }
- (IBAction)copyMarked:(id)sender - (IBAction)copyMarked:(id)sender
@ -191,7 +191,7 @@ http://www.hardcoded.net/licenses/hs_license
- (IBAction)ignoreSelected:(id)sender - (IBAction)ignoreSelected:(id)sender
{ {
NSInteger selectedDupeCount = [outline selectedDupeCount]; NSInteger selectedDupeCount = [table selectedDupeCount];
if (!selectedDupeCount) if (!selectedDupeCount)
return; return;
NSString *msg = [NSString stringWithFormat:@"All selected %d matches are going to be ignored in all subsequent scans. Continue?",selectedDupeCount]; NSString *msg = [NSString stringWithFormat:@"All selected %d matches are going to be ignored in all subsequent scans. Continue?",selectedDupeCount];
@ -293,7 +293,7 @@ http://www.hardcoded.net/licenses/hs_license
- (IBAction)removeSelected:(id)sender - (IBAction)removeSelected:(id)sender
{ {
[outline removeSelected]; [table removeSelected];
} }
- (IBAction)renameSelected:(id)sender - (IBAction)renameSelected:(id)sender
@ -416,8 +416,8 @@ http://www.hardcoded.net/licenses/hs_license
} }
} }
else if ([lastAction isEqualTo:jobScan]) { else if ([lastAction isEqualTo:jobScan]) {
NSInteger groupCount = [outline intProperty:@"children_count" valueAtPath:nil]; NSInteger rowCount = [[table py] numberOfRows];
if (groupCount == 0) if (rowCount == 0)
[Dialogs showMessage:@"No duplicates found."]; [Dialogs showMessage:@"No duplicates found."];
} }

View File

@ -12,7 +12,8 @@
</object> </object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<integer value="1204"/> <integer value="1209"/>
<integer value="29"/>
</object> </object>
<object class="NSArray" key="IBDocument.PluginDependencies"> <object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
@ -82,11 +83,9 @@
<string key="NSToolbarItemPaletteLabel">Power Marker</string> <string key="NSToolbarItemPaletteLabel">Power Marker</string>
<nil key="NSToolbarItemToolTip"/> <nil key="NSToolbarItemToolTip"/>
<object class="NSSegmentedControl" key="NSToolbarItemView" id="35398541"> <object class="NSSegmentedControl" key="NSToolbarItemView" id="35398541">
<reference key="NSNextResponder"/> <nil key="NSNextResponder"/>
<int key="NSvFlags">256</int> <int key="NSvFlags">256</int>
<string key="NSFrame">{{7, 14}, {67, 24}}</string> <string key="NSFrame">{{7, 14}, {67, 24}}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
<object class="NSSegmentedCell" key="NSCell" id="431579725"> <object class="NSSegmentedCell" key="NSCell" id="431579725">
<int key="NSCellFlags">67239424</int> <int key="NSCellFlags">67239424</int>
@ -177,11 +176,9 @@
<string key="NSToolbarItemPaletteLabel">Filter</string> <string key="NSToolbarItemPaletteLabel">Filter</string>
<nil key="NSToolbarItemToolTip"/> <nil key="NSToolbarItemToolTip"/>
<object class="NSSearchField" key="NSToolbarItemView" id="1013657232"> <object class="NSSearchField" key="NSToolbarItemView" id="1013657232">
<reference key="NSNextResponder"/> <nil key="NSNextResponder"/>
<int key="NSvFlags">258</int> <int key="NSvFlags">258</int>
<string key="NSFrame">{{0, 14}, {81, 22}}</string> <string key="NSFrame">{{0, 14}, {81, 22}}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
<object class="NSSearchFieldCell" key="NSCell" id="484816507"> <object class="NSSearchFieldCell" key="NSCell" id="484816507">
<int key="NSCellFlags">343014976</int> <int key="NSCellFlags">343014976</int>
@ -323,11 +320,9 @@
<string key="NSToolbarItemPaletteLabel">Action</string> <string key="NSToolbarItemPaletteLabel">Action</string>
<nil key="NSToolbarItemToolTip"/> <nil key="NSToolbarItemToolTip"/>
<object class="NSPopUpButton" key="NSToolbarItemView" id="165812138"> <object class="NSPopUpButton" key="NSToolbarItemView" id="165812138">
<reference key="NSNextResponder"/> <nil key="NSNextResponder"/>
<int key="NSvFlags">256</int> <int key="NSvFlags">256</int>
<string key="NSFrame">{{0, 14}, {58, 26}}</string> <string key="NSFrame">{{0, 14}, {58, 26}}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
<object class="NSPopUpButtonCell" key="NSCell" id="436420677"> <object class="NSPopUpButtonCell" key="NSCell" id="436420677">
<int key="NSCellFlags">-2076049856</int> <int key="NSCellFlags">-2076049856</int>
@ -530,11 +525,9 @@
<string key="NSToolbarItemPaletteLabel">Delta Values</string> <string key="NSToolbarItemPaletteLabel">Delta Values</string>
<nil key="NSToolbarItemToolTip"/> <nil key="NSToolbarItemToolTip"/>
<object class="NSSegmentedControl" key="NSToolbarItemView" id="311230297"> <object class="NSSegmentedControl" key="NSToolbarItemView" id="311230297">
<reference key="NSNextResponder"/> <nil key="NSNextResponder"/>
<int key="NSvFlags">256</int> <int key="NSvFlags">256</int>
<string key="NSFrame">{{4, 14}, {67, 24}}</string> <string key="NSFrame">{{4, 14}, {67, 24}}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
<object class="NSSegmentedCell" key="NSCell" id="211272396"> <object class="NSSegmentedCell" key="NSCell" id="211272396">
<int key="NSCellFlags">67239424</int> <int key="NSCellFlags">67239424</int>
@ -681,52 +674,76 @@
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
<string key="NSWindowContentMinSize">{340, 340}</string> <string key="NSWindowContentMinSize">{340, 340}</string>
<object class="NSView" key="NSWindowView" id="455829030"> <object class="NSView" key="NSWindowView" id="455829030">
<nil key="NSNextResponder"/> <reference key="NSNextResponder"/>
<int key="NSvFlags">256</int> <int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews"> <object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSScrollView" id="417210994"> <object class="NSTextField" id="895966510">
<reference key="NSNextResponder" ref="455829030"/>
<int key="NSvFlags">290</int>
<string key="NSFrame">{{17, 20}, {523, 17}}</string>
<reference key="NSSuperview" ref="455829030"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="839278531">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">138412032</int>
<string key="NSContents">Marked: 0 files, 0 B. Total: 0 files, 0 B.</string>
<reference key="NSSupport" ref="594927229"/>
<reference key="NSControlView" ref="895966510"/>
<object class="NSColor" key="NSBackgroundColor">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlColor</string>
<object class="NSColor" key="NSColor" id="713772391">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
</object>
</object>
<reference key="NSTextColor" ref="1058073270"/>
</object>
</object>
<object class="NSScrollView" id="516888538">
<reference key="NSNextResponder" ref="455829030"/> <reference key="NSNextResponder" ref="455829030"/>
<int key="NSvFlags">274</int> <int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews"> <object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSClipView" id="948758365"> <object class="NSClipView" id="657398517">
<reference key="NSNextResponder" ref="417210994"/> <reference key="NSNextResponder" ref="516888538"/>
<int key="NSvFlags">2304</int> <int key="NSvFlags">2304</int>
<object class="NSMutableArray" key="NSSubviews"> <object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSOutlineView" id="40047569"> <object class="NSTableView" id="982695974">
<reference key="NSNextResponder" ref="948758365"/> <reference key="NSNextResponder" ref="657398517"/>
<int key="NSvFlags">274</int> <int key="NSvFlags">256</int>
<string key="NSFrameSize">{515, 317}</string> <string key="NSFrameSize">{515, 317}</string>
<reference key="NSSuperview" ref="948758365"/> <reference key="NSSuperview" ref="657398517"/>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
<object class="NSTableHeaderView" key="NSHeaderView" id="837301452"> <object class="NSTableHeaderView" key="NSHeaderView" id="437229738">
<reference key="NSNextResponder" ref="1000298166"/> <reference key="NSNextResponder" ref="1021759594"/>
<int key="NSvFlags">256</int> <int key="NSvFlags">256</int>
<string key="NSFrameSize">{515, 17}</string> <string key="NSFrameSize">{515, 17}</string>
<reference key="NSSuperview" ref="1000298166"/> <reference key="NSSuperview" ref="1021759594"/>
<reference key="NSTableView" ref="40047569"/> <reference key="NSTableView" ref="982695974"/>
</object> </object>
<object class="_NSCornerView" key="NSCornerView" id="860570967"> <object class="_NSCornerView" key="NSCornerView" id="622871751">
<reference key="NSNextResponder" ref="417210994"/> <reference key="NSNextResponder" ref="516888538"/>
<int key="NSvFlags">-2147483392</int> <int key="NSvFlags">-2147483392</int>
<string key="NSFrame">{{-26, 0}, {16, 17}}</string> <string key="NSFrame">{{224, 0}, {16, 17}}</string>
<reference key="NSSuperview" ref="417210994"/> <reference key="NSSuperview" ref="516888538"/>
</object> </object>
<object class="NSMutableArray" key="NSTableColumns"> <object class="NSMutableArray" key="NSTableColumns">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSTableColumn" id="430098394"> <object class="NSTableColumn" id="201009225">
<string key="NSIdentifier">marked</string> <string key="NSIdentifier">marked</string>
<double key="NSWidth">47</double> <double key="NSWidth">26</double>
<double key="NSMinWidth">16</double> <double key="NSMinWidth">26</double>
<double key="NSMaxWidth">1000</double> <double key="NSMaxWidth">26</double>
<object class="NSTableHeaderCell" key="NSHeaderCell"> <object class="NSTableHeaderCell" key="NSHeaderCell">
<int key="NSCellFlags">75628096</int> <int key="NSCellFlags">75628096</int>
<int key="NSCellFlags2">2048</int> <int key="NSCellFlags2">134219776</int>
<string key="NSContents"/> <string key="NSContents"/>
<reference key="NSSupport" ref="26"/> <reference key="NSSupport" ref="26"/>
<object class="NSColor" key="NSBackgroundColor"> <object class="NSColor" key="NSBackgroundColor" id="589534335">
<int key="NSColorSpace">6</int> <int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string> <string key="NSCatalogName">System</string>
<string key="NSColorName">headerColor</string> <string key="NSColorName">headerColor</string>
@ -739,64 +756,63 @@
<reference key="NSColor" ref="951662694"/> <reference key="NSColor" ref="951662694"/>
</object> </object>
</object> </object>
<object class="NSButtonCell" key="NSDataCell" id="705360835"> <object class="NSButtonCell" key="NSDataCell" id="267036250">
<int key="NSCellFlags">67239424</int> <int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">131072</int> <int key="NSCellFlags2">131072</int>
<string key="NSContents"/> <string key="NSContents"/>
<object class="NSFont" key="NSSupport"> <reference key="NSSupport" ref="26"/>
<string key="NSName">LucidaGrande</string> <reference key="NSControlView" ref="982695974"/>
<double key="NSSize">12</double>
<int key="NSfFlags">16</int>
</object>
<reference key="NSControlView" ref="40047569"/>
<int key="NSButtonFlags">1211912703</int> <int key="NSButtonFlags">1211912703</int>
<int key="NSButtonFlags2">2</int> <int key="NSButtonFlags2">2</int>
<object class="NSCustomResource" key="NSNormalImage">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSSwitch</string>
</object>
<object class="NSButtonImageSource" key="NSAlternateImage"> <object class="NSButtonImageSource" key="NSAlternateImage">
<string key="NSImageName">NSSwitch</string> <string key="NSImageName">NSSwitch</string>
</object> </object>
<string key="NSAlternateContents"/> <string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/> <string key="NSKeyEquivalent"/>
<int key="NSPeriodicDelay">400</int> <int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">75</int> <int key="NSPeriodicInterval">25</int>
</object> </object>
<bool key="NSIsEditable">YES</bool> <bool key="NSIsEditable">YES</bool>
<reference key="NSTableView" ref="40047569"/> <reference key="NSTableView" ref="982695974"/>
</object> </object>
<object class="NSTableColumn" id="932540235"> <object class="NSTableColumn" id="146307356">
<string key="NSIdentifier">0</string> <string key="NSIdentifier">0</string>
<double key="NSWidth">195</double> <double key="NSWidth">195</double>
<double key="NSMinWidth">16</double> <double key="NSMinWidth">16</double>
<double key="NSMaxWidth">1000</double> <double key="NSMaxWidth">3.4028234663852886e+38</double>
<object class="NSTableHeaderCell" key="NSHeaderCell"> <object class="NSTableHeaderCell" key="NSHeaderCell">
<int key="NSCellFlags">75628096</int> <int key="NSCellFlags">75628096</int>
<int key="NSCellFlags2">2048</int> <int key="NSCellFlags2">2048</int>
<string key="NSContents">Name</string> <string key="NSContents">Name</string>
<reference key="NSSupport" ref="26"/> <reference key="NSSupport" ref="26"/>
<object class="NSColor" key="NSBackgroundColor"> <reference key="NSBackgroundColor" ref="589534335"/>
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes>
</object>
<reference key="NSTextColor" ref="570076428"/> <reference key="NSTextColor" ref="570076428"/>
</object> </object>
<object class="NSTextFieldCell" key="NSDataCell" id="573658629"> <object class="NSTextFieldCell" key="NSDataCell" id="810890923">
<int key="NSCellFlags">337772096</int> <int key="NSCellFlags">337772096</int>
<int key="NSCellFlags2">2048</int> <int key="NSCellFlags2">2048</int>
<reference key="NSSupport" ref="26"/> <string key="NSContents">Text Cell</string>
<reference key="NSControlView" ref="40047569"/> <object class="NSFont" key="NSSupport">
<string key="NSName">LucidaGrande</string>
<double key="NSSize">11</double>
<int key="NSfFlags">16</int>
</object>
<reference key="NSControlView" ref="982695974"/>
<object class="NSColor" key="NSBackgroundColor" id="91259834"> <object class="NSColor" key="NSBackgroundColor" id="91259834">
<int key="NSColorSpace">6</int> <int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string> <string key="NSCatalogName">System</string>
<string key="NSColorName">controlBackgroundColor</string> <string key="NSColorName">controlBackgroundColor</string>
<object class="NSColor" key="NSColor" id="713772391"> <reference key="NSColor" ref="713772391"/>
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
</object>
</object> </object>
<reference key="NSTextColor" ref="1058073270"/> <reference key="NSTextColor" ref="1058073270"/>
</object> </object>
<int key="NSResizingMask">2</int> <int key="NSResizingMask">2</int>
<bool key="NSIsResizeable">YES</bool> <bool key="NSIsResizeable">YES</bool>
<reference key="NSTableView" ref="40047569"/> <reference key="NSTableView" ref="982695974"/>
<object class="NSSortDescriptor" key="NSSortDescriptorPrototype"> <object class="NSSortDescriptor" key="NSSortDescriptorPrototype">
<string key="NSKey">0</string> <string key="NSKey">0</string>
<bool key="NSAscending">YES</bool> <bool key="NSAscending">YES</bool>
@ -821,7 +837,7 @@
<reference key="NSDelegate"/> <reference key="NSDelegate"/>
<reference key="NSDataSource"/> <reference key="NSDataSource"/>
<int key="NSGridStyleMask">2</int> <int key="NSGridStyleMask">2</int>
<int key="NSColumnAutoresizingStyle">0</int> <int key="NSColumnAutoresizingStyle">4</int>
<int key="NSDraggingSourceMaskForLocal">15</int> <int key="NSDraggingSourceMaskForLocal">15</int>
<int key="NSDraggingSourceMaskForNonLocal">0</int> <int key="NSDraggingSourceMaskForNonLocal">0</int>
<bool key="NSAllowsTypeSelect">YES</bool> <bool key="NSAllowsTypeSelect">YES</bool>
@ -829,78 +845,62 @@
</object> </object>
</object> </object>
<string key="NSFrame">{{1, 17}, {515, 317}}</string> <string key="NSFrame">{{1, 17}, {515, 317}}</string>
<reference key="NSSuperview" ref="417210994"/> <reference key="NSSuperview" ref="516888538"/>
<reference key="NSDocView" ref="40047569"/> <reference key="NSNextKeyView" ref="982695974"/>
<reference key="NSDocView" ref="982695974"/>
<reference key="NSBGColor" ref="91259834"/> <reference key="NSBGColor" ref="91259834"/>
<int key="NScvFlags">4</int> <int key="NScvFlags">4</int>
</object> </object>
<object class="NSScroller" id="167459243"> <object class="NSScroller" id="998740212">
<reference key="NSNextResponder" ref="417210994"/> <reference key="NSNextResponder" ref="516888538"/>
<int key="NSvFlags">-2147483392</int> <int key="NSvFlags">-2147483392</int>
<string key="NSFrame">{{-30, 17}, {15, 302}}</string> <string key="NSFrame">{{224, 17}, {15, 102}}</string>
<reference key="NSSuperview" ref="417210994"/> <reference key="NSSuperview" ref="516888538"/>
<reference key="NSTarget" ref="417210994"/> <reference key="NSTarget" ref="516888538"/>
<string key="NSAction">_doScroller:</string> <string key="NSAction">_doScroller:</string>
<double key="NSPercent">0.98739492893218994</double> <double key="NSCurValue">37</double>
<double key="NSPercent">0.1947367936372757</double>
</object> </object>
<object class="NSScroller" id="916628114"> <object class="NSScroller" id="752400791">
<reference key="NSNextResponder" ref="417210994"/> <reference key="NSNextResponder" ref="516888538"/>
<int key="NSvFlags">-2147483392</int> <int key="NSvFlags">-2147483392</int>
<string key="NSFrame">{{1, 319}, {515, 15}}</string> <string key="NSFrame">{{1, 119}, {223, 15}}</string>
<reference key="NSSuperview" ref="417210994"/> <reference key="NSSuperview" ref="516888538"/>
<int key="NSsFlags">1</int> <int key="NSsFlags">1</int>
<reference key="NSTarget" ref="417210994"/> <reference key="NSTarget" ref="516888538"/>
<string key="NSAction">_doScroller:</string> <string key="NSAction">_doScroller:</string>
<double key="NSPercent">0.85406301824212272</double> <double key="NSPercent">0.57142859697341919</double>
</object> </object>
<object class="NSClipView" id="1000298166"> <object class="NSClipView" id="1021759594">
<reference key="NSNextResponder" ref="417210994"/> <reference key="NSNextResponder" ref="516888538"/>
<int key="NSvFlags">2304</int> <int key="NSvFlags">2304</int>
<object class="NSMutableArray" key="NSSubviews"> <object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="837301452"/> <reference ref="437229738"/>
</object> </object>
<string key="NSFrame">{{1, 0}, {515, 17}}</string> <string key="NSFrame">{{1, 0}, {515, 17}}</string>
<reference key="NSSuperview" ref="417210994"/> <reference key="NSSuperview" ref="516888538"/>
<reference key="NSDocView" ref="837301452"/> <reference key="NSNextKeyView" ref="437229738"/>
<reference key="NSDocView" ref="437229738"/>
<reference key="NSBGColor" ref="91259834"/> <reference key="NSBGColor" ref="91259834"/>
<int key="NScvFlags">4</int> <int key="NScvFlags">4</int>
</object> </object>
<reference ref="860570967"/> <reference ref="622871751"/>
</object> </object>
<string key="NSFrame">{{20, 45}, {517, 335}}</string> <string key="NSFrame">{{20, 45}, {517, 335}}</string>
<reference key="NSSuperview" ref="455829030"/> <reference key="NSSuperview" ref="455829030"/>
<reference key="NSNextKeyView" ref="657398517"/>
<int key="NSsFlags">562</int> <int key="NSsFlags">562</int>
<reference key="NSVScroller" ref="167459243"/> <reference key="NSVScroller" ref="998740212"/>
<reference key="NSHScroller" ref="916628114"/> <reference key="NSHScroller" ref="752400791"/>
<reference key="NSContentView" ref="948758365"/> <reference key="NSContentView" ref="657398517"/>
<reference key="NSHeaderClipView" ref="1000298166"/> <reference key="NSHeaderClipView" ref="1021759594"/>
<reference key="NSCornerView" ref="860570967"/> <reference key="NSCornerView" ref="622871751"/>
<bytes key="NSScrollAmts">QSAAAEEgAABBgAAAQYAAAA</bytes> <bytes key="NSScrollAmts">QSAAAEEgAABBgAAAQYAAAA</bytes>
</object> </object>
<object class="NSTextField" id="895966510">
<reference key="NSNextResponder" ref="455829030"/>
<int key="NSvFlags">290</int>
<string key="NSFrame">{{17, 20}, {523, 17}}</string>
<reference key="NSSuperview" ref="455829030"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="839278531">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">138412032</int>
<string key="NSContents">Marked: 0 files, 0 B. Total: 0 files, 0 B.</string>
<reference key="NSSupport" ref="594927229"/>
<reference key="NSControlView" ref="895966510"/>
<object class="NSColor" key="NSBackgroundColor">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlColor</string>
<reference key="NSColor" ref="713772391"/>
</object>
<reference key="NSTextColor" ref="1058073270"/>
</object>
</object>
</object> </object>
<string key="NSFrameSize">{557, 400}</string> <string key="NSFrameSize">{557, 400}</string>
<reference key="NSSuperview"/>
</object> </object>
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
<string key="NSMinSize">{340, 418}</string> <string key="NSMinSize">{340, 418}</string>
@ -1713,14 +1713,6 @@
</object> </object>
<int key="connectionID">212</int> <int key="connectionID">212</int>
</object> </object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">initialFirstResponder</string>
<reference key="source" ref="641929189"/>
<reference key="destination" ref="40047569"/>
</object>
<int key="connectionID">279</int>
</object>
<object class="IBConnectionRecord"> <object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection"> <object class="IBOutletConnection" key="connection">
<string key="label">stats</string> <string key="label">stats</string>
@ -1833,14 +1825,6 @@
</object> </object>
<int key="connectionID">661</int> <int key="connectionID">661</int>
</object> </object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">menu</string>
<reference key="source" ref="40047569"/>
<reference key="destination" ref="591769558"/>
</object>
<int key="connectionID">663</int>
</object>
<object class="IBConnectionRecord"> <object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection"> <object class="IBActionConnection" key="connection">
<string key="label">openSelected:</string> <string key="label">openSelected:</string>
@ -2241,14 +2225,6 @@
</object> </object>
<int key="connectionID">1175</int> <int key="connectionID">1175</int>
</object> </object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">matches</string>
<reference key="source" ref="339936126"/>
<reference key="destination" ref="40047569"/>
</object>
<int key="connectionID">1176</int>
</object>
<object class="IBConnectionRecord"> <object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection"> <object class="IBActionConnection" key="connection">
<string key="label">invokeCustomCommand:</string> <string key="label">invokeCustomCommand:</string>
@ -2273,6 +2249,22 @@
</object> </object>
<int key="connectionID">1208</int> <int key="connectionID">1208</int>
</object> </object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">matches</string>
<reference key="source" ref="339936126"/>
<reference key="destination" ref="982695974"/>
</object>
<int key="connectionID">1225</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">menu</string>
<reference key="source" ref="982695974"/>
<reference key="destination" ref="591769558"/>
</object>
<int key="connectionID">1226</int>
</object>
</object> </object>
<object class="IBMutableOrderedSet" key="objectRecords"> <object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects"> <object class="NSArray" key="orderedObjects">
@ -2317,56 +2309,11 @@
<reference key="object" ref="455829030"/> <reference key="object" ref="455829030"/>
<object class="NSMutableArray" key="children"> <object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="417210994"/>
<reference ref="895966510"/> <reference ref="895966510"/>
<reference ref="516888538"/>
</object> </object>
<reference key="parent" ref="641929189"/> <reference key="parent" ref="641929189"/>
</object> </object>
<object class="IBObjectRecord">
<int key="objectID">219</int>
<reference key="object" ref="417210994"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="40047569"/>
<reference ref="167459243"/>
<reference ref="916628114"/>
<reference ref="837301452"/>
</object>
<reference key="parent" ref="455829030"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">220</int>
<reference key="object" ref="40047569"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="932540235"/>
<reference ref="430098394"/>
</object>
<reference key="parent" ref="417210994"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">222</int>
<reference key="object" ref="932540235"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="573658629"/>
</object>
<reference key="parent" ref="40047569"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">406</int>
<reference key="object" ref="430098394"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="705360835"/>
</object>
<reference key="parent" ref="40047569"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">407</int>
<reference key="object" ref="705360835"/>
<reference key="parent" ref="430098394"/>
</object>
<object class="IBObjectRecord"> <object class="IBObjectRecord">
<int key="objectID">291</int> <int key="objectID">291</int>
<reference key="object" ref="895966510"/> <reference key="object" ref="895966510"/>
@ -2870,26 +2817,6 @@
<reference key="object" ref="839278531"/> <reference key="object" ref="839278531"/>
<reference key="parent" ref="895966510"/> <reference key="parent" ref="895966510"/>
</object> </object>
<object class="IBObjectRecord">
<int key="objectID">1140</int>
<reference key="object" ref="573658629"/>
<reference key="parent" ref="932540235"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1144</int>
<reference key="object" ref="167459243"/>
<reference key="parent" ref="417210994"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1145</int>
<reference key="object" ref="916628114"/>
<reference key="parent" ref="417210994"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1146</int>
<reference key="object" ref="837301452"/>
<reference key="parent" ref="417210994"/>
</object>
<object class="IBObjectRecord"> <object class="IBObjectRecord">
<int key="objectID">1147</int> <int key="objectID">1147</int>
<reference key="object" ref="307721027"/> <reference key="object" ref="307721027"/>
@ -3171,6 +3098,71 @@
<reference key="object" ref="630362403"/> <reference key="object" ref="630362403"/>
<reference key="parent" ref="948321368"/> <reference key="parent" ref="948321368"/>
</object> </object>
<object class="IBObjectRecord">
<int key="objectID">1209</int>
<reference key="object" ref="516888538"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="998740212"/>
<reference ref="752400791"/>
<reference ref="982695974"/>
<reference ref="437229738"/>
</object>
<reference key="parent" ref="455829030"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1210</int>
<reference key="object" ref="998740212"/>
<reference key="parent" ref="516888538"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1211</int>
<reference key="object" ref="752400791"/>
<reference key="parent" ref="516888538"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1212</int>
<reference key="object" ref="982695974"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="201009225"/>
<reference ref="146307356"/>
</object>
<reference key="parent" ref="516888538"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1213</int>
<reference key="object" ref="437229738"/>
<reference key="parent" ref="516888538"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1218</int>
<reference key="object" ref="201009225"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="267036250"/>
</object>
<reference key="parent" ref="982695974"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1222</int>
<reference key="object" ref="146307356"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="810890923"/>
</object>
<reference key="parent" ref="982695974"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1223</int>
<reference key="object" ref="810890923"/>
<reference key="parent" ref="146307356"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1224</int>
<reference key="object" ref="267036250"/>
<reference key="parent" ref="201009225"/>
</object>
</object> </object>
</object> </object>
<object class="NSMutableDictionary" key="flattenedProperties"> <object class="NSMutableDictionary" key="flattenedProperties">
@ -3205,14 +3197,6 @@
<string>1137.IBPluginDependency</string> <string>1137.IBPluginDependency</string>
<string>1138.IBPluginDependency</string> <string>1138.IBPluginDependency</string>
<string>1139.IBPluginDependency</string> <string>1139.IBPluginDependency</string>
<string>1140.IBPluginDependency</string>
<string>1140.IBShouldRemoveOnLegacySave</string>
<string>1144.IBPluginDependency</string>
<string>1144.IBShouldRemoveOnLegacySave</string>
<string>1145.IBPluginDependency</string>
<string>1145.IBShouldRemoveOnLegacySave</string>
<string>1146.IBPluginDependency</string>
<string>1146.IBShouldRemoveOnLegacySave</string>
<string>1147.IBEditorWindowLastContentRect</string> <string>1147.IBEditorWindowLastContentRect</string>
<string>1147.IBPluginDependency</string> <string>1147.IBPluginDependency</string>
<string>1156.IBPluginDependency</string> <string>1156.IBPluginDependency</string>
@ -3229,6 +3213,16 @@
<string>1204.IBPluginDependency</string> <string>1204.IBPluginDependency</string>
<string>1205.IBPluginDependency</string> <string>1205.IBPluginDependency</string>
<string>1206.IBPluginDependency</string> <string>1206.IBPluginDependency</string>
<string>1209.IBPluginDependency</string>
<string>1210.IBPluginDependency</string>
<string>1211.IBPluginDependency</string>
<string>1212.CustomClassName</string>
<string>1212.IBPluginDependency</string>
<string>1213.IBPluginDependency</string>
<string>1218.IBPluginDependency</string>
<string>1222.IBPluginDependency</string>
<string>1223.IBPluginDependency</string>
<string>1224.IBPluginDependency</string>
<string>134.IBPluginDependency</string> <string>134.IBPluginDependency</string>
<string>134.ImportedFromIB2</string> <string>134.ImportedFromIB2</string>
<string>136.IBPluginDependency</string> <string>136.IBPluginDependency</string>
@ -3256,13 +3250,6 @@
<string>21.NSWindowTemplate.visibleAtLaunch</string> <string>21.NSWindowTemplate.visibleAtLaunch</string>
<string>21.windowTemplate.hasMinSize</string> <string>21.windowTemplate.hasMinSize</string>
<string>21.windowTemplate.minSize</string> <string>21.windowTemplate.minSize</string>
<string>219.IBPluginDependency</string>
<string>219.ImportedFromIB2</string>
<string>220.CustomClassName</string>
<string>220.IBPluginDependency</string>
<string>220.ImportedFromIB2</string>
<string>222.IBPluginDependency</string>
<string>222.ImportedFromIB2</string>
<string>23.IBPluginDependency</string> <string>23.IBPluginDependency</string>
<string>23.ImportedFromIB2</string> <string>23.ImportedFromIB2</string>
<string>24.IBEditorWindowLastContentRect</string> <string>24.IBEditorWindowLastContentRect</string>
@ -3277,10 +3264,6 @@
<string>398.ImportedFromIB2</string> <string>398.ImportedFromIB2</string>
<string>399.IBPluginDependency</string> <string>399.IBPluginDependency</string>
<string>399.ImportedFromIB2</string> <string>399.ImportedFromIB2</string>
<string>406.IBPluginDependency</string>
<string>406.ImportedFromIB2</string>
<string>407.IBPluginDependency</string>
<string>407.ImportedFromIB2</string>
<string>497.ImportedFromIB2</string> <string>497.ImportedFromIB2</string>
<string>5.IBPluginDependency</string> <string>5.IBPluginDependency</string>
<string>5.ImportedFromIB2</string> <string>5.ImportedFromIB2</string>
@ -3452,14 +3435,6 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>{{409, 745}, {617, 0}}</string> <string>{{409, 745}, {617, 0}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@ -3477,6 +3452,16 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>HSTableView</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/> <boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/> <boolean value="YES"/>
@ -3496,22 +3481,15 @@
<boolean value="YES"/> <boolean value="YES"/>
<boolean value="YES"/> <boolean value="YES"/>
<boolean value="YES"/> <boolean value="YES"/>
<string>{{439, 345}, {557, 400}}</string> <string>{{324, 289}, {557, 400}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>{{439, 345}, {557, 400}}</string> <string>{{324, 289}, {557, 400}}</string>
<boolean value="YES"/> <boolean value="YES"/>
<boolean value="YES"/> <boolean value="YES"/>
<boolean value="YES"/> <boolean value="YES"/>
<string>{340, 340}</string> <string>{340, 340}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/> <boolean value="YES"/>
<string>HSOutlineView</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>{{531, 625}, {193, 143}}</string> <string>{{531, 625}, {193, 143}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/> <boolean value="YES"/>
@ -3524,10 +3502,6 @@
<boolean value="YES"/> <boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/> <boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<boolean value="YES"/> <boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/> <boolean value="YES"/>
@ -3686,7 +3660,7 @@
</object> </object>
</object> </object>
<nil key="sourceID"/> <nil key="sourceID"/>
<int key="maxID">1208</int> <int key="maxID">1226</int>
</object> </object>
<object class="IBClassDescriber" key="IBDocument.Classes"> <object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions"> <object class="NSMutableArray" key="referencedPartialClassDescriptions">
@ -3863,16 +3837,23 @@
</object> </object>
</object> </object>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
<string key="className">HSOutlineView</string> <string key="className">HSTableView</string>
<string key="superclassName">NSOutlineView</string> <string key="superclassName">NSTableView</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="384069338"> <object class="IBClassDescriptionSource" key="sourceIdentifier" id="1040579274">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">../views/HSTableView.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string> <string key="majorKey">IBProjectSource</string>
<string key="minorKey">../views/HSOutlineView.h</string> <string key="minorKey">../views/HSOutlineView.h</string>
</object> </object>
</object> </object>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
<string key="className">NSObject</string> <string key="className">NSObject</string>
<reference key="sourceIdentifier" ref="384069338"/> <reference key="sourceIdentifier" ref="1040579274"/>
</object> </object>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
<string key="className">NSObject</string> <string key="className">NSObject</string>
@ -4311,7 +4292,7 @@
<string>NSMenu</string> <string>NSMenu</string>
<string>NSSegmentedControl</string> <string>NSSegmentedControl</string>
<string>NSSearchField</string> <string>NSSearchField</string>
<string>HSOutlineView</string> <string>HSTableView</string>
<string>NSSegmentedControl</string> <string>NSSegmentedControl</string>
<string>PyDupeGuruBase</string> <string>PyDupeGuruBase</string>
<string>NSTextField</string> <string>NSTextField</string>
@ -4350,7 +4331,7 @@
</object> </object>
<object class="IBToOneOutletInfo"> <object class="IBToOneOutletInfo">
<string key="name">matches</string> <string key="name">matches</string>
<string key="candidateClassName">HSOutlineView</string> <string key="candidateClassName">HSTableView</string>
</object> </object>
<object class="IBToOneOutletInfo"> <object class="IBToOneOutletInfo">
<string key="name">pmSwitch</string> <string key="name">pmSwitch</string>
@ -4576,7 +4557,7 @@
</object> </object>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
<string key="className">NSObject</string> <string key="className">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="444201337"> <object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBFrameworkSource</string> <string key="majorKey">IBFrameworkSource</string>
<string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string> <string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
</object> </object>
@ -4763,11 +4744,6 @@
<string key="minorKey">Sparkle.framework/Headers/SUUpdater.h</string> <string key="minorKey">Sparkle.framework/Headers/SUUpdater.h</string>
</object> </object>
</object> </object>
<object class="IBPartialClassDescription">
<string key="className">NSOutlineView</string>
<string key="superclassName">NSTableView</string>
<reference key="sourceIdentifier" ref="444201337"/>
</object>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
<string key="className">NSPopUpButton</string> <string key="className">NSPopUpButton</string>
<string key="superclassName">NSButton</string> <string key="superclassName">NSButton</string>
@ -5023,6 +4999,7 @@
<string>NSApplicationIcon</string> <string>NSApplicationIcon</string>
<string>NSMenuCheckmark</string> <string>NSMenuCheckmark</string>
<string>NSMenuMixedState</string> <string>NSMenuMixedState</string>
<string>NSSwitch</string>
<string>details32</string> <string>details32</string>
<string>folder32</string> <string>folder32</string>
<string>preferences32</string> <string>preferences32</string>
@ -5033,6 +5010,7 @@
<string>{128, 128}</string> <string>{128, 128}</string>
<string>{9, 8}</string> <string>{9, 8}</string>
<string>{7, 2}</string> <string>{7, 2}</string>
<string>{15, 15}</string>
<string>{48, 48}</string> <string>{48, 48}</string>
<string>{32, 32}</string> <string>{32, 32}</string>
<string>{32, 32}</string> <string>{32, 32}</string>

View File

@ -20,7 +20,7 @@ http://www.hardcoded.net/licenses/hs_license
[super awakeFromNib]; [super awakeFromNib];
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndex:2]; NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndex:2];
[deltaColumns addIndex:4]; [deltaColumns addIndex:4];
[outline setDeltaColumns:deltaColumns]; [table setDeltaColumns:deltaColumns];
} }
/* Actions */ /* Actions */

View File

@ -20,6 +20,8 @@
CE4557B40AE3BC50005A9546 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE45579A0AE3BC2B005A9546 /* Sparkle.framework */; }; CE4557B40AE3BC50005A9546 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE45579A0AE3BC2B005A9546 /* Sparkle.framework */; };
CE647E571173024A006D28BA /* ProblemDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = CE647E551173024A006D28BA /* ProblemDialog.m */; }; CE647E571173024A006D28BA /* ProblemDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = CE647E551173024A006D28BA /* ProblemDialog.m */; };
CE647E591173026F006D28BA /* ProblemDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE647E581173026F006D28BA /* ProblemDialog.xib */; }; CE647E591173026F006D28BA /* ProblemDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE647E581173026F006D28BA /* ProblemDialog.xib */; };
CE6DD4E7124CA3070089A48D /* ResultTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CE6DD4E6124CA3070089A48D /* ResultTable.m */; };
CE6DD547124CAF1F0089A48D /* HSTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE6DD546124CAF1F0089A48D /* HSTableView.m */; };
CE6E0DFE1054E9EF008D9390 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = CE6E0DFD1054E9EF008D9390 /* dsa_pub.pem */; }; CE6E0DFE1054E9EF008D9390 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = CE6E0DFD1054E9EF008D9390 /* dsa_pub.pem */; };
CE76FDC4111EE37C006618EA /* HSOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDBF111EE37C006618EA /* HSOutlineView.m */; }; CE76FDC4111EE37C006618EA /* HSOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDBF111EE37C006618EA /* HSOutlineView.m */; };
CE76FDC5111EE37C006618EA /* NSIndexPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDC1111EE37C006618EA /* NSIndexPathAdditions.m */; }; CE76FDC5111EE37C006618EA /* NSIndexPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDC1111EE37C006618EA /* NSIndexPathAdditions.m */; };
@ -29,7 +31,6 @@
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDDE111EE42F006618EA /* HSOutline.m */; }; CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDDE111EE42F006618EA /* HSOutline.m */; };
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDF6111EE561006618EA /* NSEventAdditions.m */; }; CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDF6111EE561006618EA /* NSEventAdditions.m */; };
CE8C53BC117324CE0011B41F /* HSTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CE8C53BB117324CE0011B41F /* HSTable.m */; }; CE8C53BC117324CE0011B41F /* HSTable.m in Sources */ = {isa = PBXBuildFile; fileRef = CE8C53BB117324CE0011B41F /* HSTable.m */; };
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F212113BC22D0010360B /* ResultOutline.m */; };
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F214113BC22D0010360B /* StatsLabel.m */; }; CE91F216113BC22D0010360B /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F214113BC22D0010360B /* StatsLabel.m */; };
CEAC6811109B0B7E00B43C85 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEAC6810109B0B7E00B43C85 /* Preferences.xib */; }; CEAC6811109B0B7E00B43C85 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEAC6810109B0B7E00B43C85 /* Preferences.xib */; };
CEBC6C3912144A4B007B43AE /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEBC6C3712144A4B007B43AE /* registration.xib */; }; CEBC6C3912144A4B007B43AE /* registration.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEBC6C3712144A4B007B43AE /* registration.xib */; };
@ -89,6 +90,11 @@
CE647E551173024A006D28BA /* ProblemDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProblemDialog.m; path = ../base/ProblemDialog.m; sourceTree = SOURCE_ROOT; }; CE647E551173024A006D28BA /* ProblemDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProblemDialog.m; path = ../base/ProblemDialog.m; sourceTree = SOURCE_ROOT; };
CE647E561173024A006D28BA /* PyProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyProblemDialog.h; path = ../base/PyProblemDialog.h; sourceTree = SOURCE_ROOT; }; CE647E561173024A006D28BA /* PyProblemDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyProblemDialog.h; path = ../base/PyProblemDialog.h; sourceTree = SOURCE_ROOT; };
CE647E581173026F006D28BA /* ProblemDialog.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ProblemDialog.xib; path = ../base/xib/ProblemDialog.xib; sourceTree = SOURCE_ROOT; }; CE647E581173026F006D28BA /* ProblemDialog.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ProblemDialog.xib; path = ../base/xib/ProblemDialog.xib; sourceTree = SOURCE_ROOT; };
CE6DD4E4124CA3070089A48D /* PyResultTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTable.h; path = ../base/PyResultTable.h; sourceTree = SOURCE_ROOT; };
CE6DD4E5124CA3070089A48D /* ResultTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultTable.h; path = ../base/ResultTable.h; sourceTree = SOURCE_ROOT; };
CE6DD4E6124CA3070089A48D /* ResultTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultTable.m; path = ../base/ResultTable.m; sourceTree = SOURCE_ROOT; };
CE6DD545124CAF1F0089A48D /* HSTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSTableView.h; path = ../../cocoalib/views/HSTableView.h; sourceTree = SOURCE_ROOT; };
CE6DD546124CAF1F0089A48D /* HSTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSTableView.m; path = ../../cocoalib/views/HSTableView.m; sourceTree = SOURCE_ROOT; };
CE6E0DFD1054E9EF008D9390 /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dsa_pub.pem; path = ../base/dsa_pub.pem; sourceTree = "<group>"; }; CE6E0DFD1054E9EF008D9390 /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dsa_pub.pem; path = ../base/dsa_pub.pem; sourceTree = "<group>"; };
CE6E7407111C997500C350E3 /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; sourceTree = SOURCE_ROOT; }; CE6E7407111C997500C350E3 /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; sourceTree = SOURCE_ROOT; };
CE76FDBE111EE37C006618EA /* HSOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutlineView.h; sourceTree = "<group>"; }; CE76FDBE111EE37C006618EA /* HSOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSOutlineView.h; sourceTree = "<group>"; };
@ -110,10 +116,7 @@
CE76FDF6111EE561006618EA /* NSEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSEventAdditions.m; path = ../../cocoalib/NSEventAdditions.m; sourceTree = SOURCE_ROOT; }; CE76FDF6111EE561006618EA /* NSEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSEventAdditions.m; path = ../../cocoalib/NSEventAdditions.m; sourceTree = SOURCE_ROOT; };
CE8C53B61173248F0011B41F /* PyTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyTable.h; sourceTree = "<group>"; }; CE8C53B61173248F0011B41F /* PyTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyTable.h; sourceTree = "<group>"; };
CE8C53BB117324CE0011B41F /* HSTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSTable.m; sourceTree = "<group>"; }; CE8C53BB117324CE0011B41F /* HSTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSTable.m; sourceTree = "<group>"; };
CE91F20F113BC22D0010360B /* PyResultTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTree.h; path = ../base/PyResultTree.h; sourceTree = SOURCE_ROOT; };
CE91F210113BC22D0010360B /* PyStatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyStatsLabel.h; path = ../base/PyStatsLabel.h; sourceTree = SOURCE_ROOT; }; CE91F210113BC22D0010360B /* PyStatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyStatsLabel.h; path = ../base/PyStatsLabel.h; sourceTree = SOURCE_ROOT; };
CE91F211113BC22D0010360B /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
CE91F212113BC22D0010360B /* ResultOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultOutline.m; path = ../base/ResultOutline.m; sourceTree = SOURCE_ROOT; };
CE91F213113BC22D0010360B /* StatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatsLabel.h; path = ../base/StatsLabel.h; sourceTree = SOURCE_ROOT; }; CE91F213113BC22D0010360B /* StatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatsLabel.h; path = ../base/StatsLabel.h; sourceTree = SOURCE_ROOT; };
CE91F214113BC22D0010360B /* StatsLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatsLabel.m; path = ../base/StatsLabel.m; sourceTree = SOURCE_ROOT; }; CE91F214113BC22D0010360B /* StatsLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatsLabel.m; path = ../base/StatsLabel.m; sourceTree = SOURCE_ROOT; };
CEAC6810109B0B7E00B43C85 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Preferences.xib; path = xib/Preferences.xib; sourceTree = "<group>"; }; CEAC6810109B0B7E00B43C85 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Preferences.xib; path = xib/Preferences.xib; sourceTree = "<group>"; };
@ -260,6 +263,8 @@
CE76FDBD111EE37C006618EA /* views */ = { CE76FDBD111EE37C006618EA /* views */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CE6DD545124CAF1F0089A48D /* HSTableView.h */,
CE6DD546124CAF1F0089A48D /* HSTableView.m */,
CE76FDBE111EE37C006618EA /* HSOutlineView.h */, CE76FDBE111EE37C006618EA /* HSOutlineView.h */,
CE76FDBF111EE37C006618EA /* HSOutlineView.m */, CE76FDBF111EE37C006618EA /* HSOutlineView.m */,
CE76FDC0111EE37C006618EA /* NSIndexPathAdditions.h */, CE76FDC0111EE37C006618EA /* NSIndexPathAdditions.h */,
@ -362,10 +367,10 @@
CEFC7FB00FC9518F00CD5728 /* dgbase */ = { CEFC7FB00FC9518F00CD5728 /* dgbase */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CE91F20F113BC22D0010360B /* PyResultTree.h */, CE6DD4E4124CA3070089A48D /* PyResultTable.h */,
CE6DD4E5124CA3070089A48D /* ResultTable.h */,
CE6DD4E6124CA3070089A48D /* ResultTable.m */,
CE91F210113BC22D0010360B /* PyStatsLabel.h */, CE91F210113BC22D0010360B /* PyStatsLabel.h */,
CE91F211113BC22D0010360B /* ResultOutline.h */,
CE91F212113BC22D0010360B /* ResultOutline.m */,
CE91F213113BC22D0010360B /* StatsLabel.h */, CE91F213113BC22D0010360B /* StatsLabel.h */,
CE91F214113BC22D0010360B /* StatsLabel.m */, CE91F214113BC22D0010360B /* StatsLabel.m */,
CE76FDD1111EE3A7006618EA /* DirectoryOutline.h */, CE76FDD1111EE3A7006618EA /* DirectoryOutline.h */,
@ -491,10 +496,11 @@
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */, CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */,
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */, CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */,
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */, CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */,
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */,
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */, CE91F216113BC22D0010360B /* StatsLabel.m in Sources */,
CE647E571173024A006D28BA /* ProblemDialog.m in Sources */, CE647E571173024A006D28BA /* ProblemDialog.m in Sources */,
CE8C53BC117324CE0011B41F /* HSTable.m in Sources */, CE8C53BC117324CE0011B41F /* HSTable.m in Sources */,
CE6DD4E7124CA3070089A48D /* ResultTable.m in Sources */,
CE6DD547124CAF1F0089A48D /* HSTableView.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -15,7 +15,7 @@ from .gui.details_panel import DetailsPanel
from .gui.directory_tree import DirectoryTree from .gui.directory_tree import DirectoryTree
from .gui.problem_dialog import ProblemDialog from .gui.problem_dialog import ProblemDialog
from .gui.problem_table import ProblemTable from .gui.problem_table import ProblemTable
from .gui.result_tree import ResultTree from .gui.result_table import ResultTable
from .gui.stats_label import StatsLabel from .gui.stats_label import StatsLabel
# Fix py2app's problems on relative imports # Fix py2app's problems on relative imports
@ -163,8 +163,8 @@ class PyDirectoryOutline(PyOutline):
self.py.add_directory(path) self.py.add_directory(path)
class PyResultOutline(PyOutline): class PyResultTable(PyTable):
py_class = ResultTree py_class = ResultTable
@signature('c@:') @signature('c@:')
def powerMarkerMode(self): def powerMarkerMode(self):
@ -182,9 +182,9 @@ class PyResultOutline(PyOutline):
def setDeltaValuesMode_(self, value): def setDeltaValuesMode_(self, value):
self.py.delta_values = value self.py.delta_values = value
@signature('@@:@i') @signature('@@:ii')
def valueForPath_column_(self, path, column): def valueForRow_column_(self, row_index, column):
return self.py.get_node_value(path, column) return self.py.get_row_value(row_index, column)
@signature('c@:@') @signature('c@:@')
def renameSelected_(self, newname): def renameSelected_(self, newname):
@ -200,8 +200,9 @@ class PyResultOutline(PyOutline):
def removeSelected(self): def removeSelected(self):
self.py.app.remove_selected() self.py.app.remove_selected()
def rootChildrenCounts(self): @signature('i@:')
return self.py.root_children_counts() def selectedDupeCount(self):
return self.py.selected_dupe_count
# python --> cocoa # python --> cocoa
def invalidate_markings(self): def invalidate_markings(self):

View File

@ -9,14 +9,14 @@
from operator import attrgetter from operator import attrgetter
from hsgui.tree import Tree, Node from hsgui.table import GUITable, Row
from .base import GUIObject from .base import GUIObject
class DupeNode(Node): class DupeRow(Row):
def __init__(self, app, group, dupe): def __init__(self, table, group, dupe):
Node.__init__(self, '') Row.__init__(self, table)
self._app = app self._app = table.app
self._group = group self._group = group
self._dupe = dupe self._dupe = dupe
self._data = None self._data = None
@ -34,6 +34,10 @@ class DupeNode(Node):
self._data_delta = self._app._get_display_info(self._dupe, self._group, True) self._data_delta = self._app._get_display_info(self._dupe, self._group, True)
return self._data_delta return self._data_delta
@property
def isref(self):
return self._dupe is self._group.ref
@property @property
def markable(self): def markable(self):
return self._app.results.is_markable(self._dupe) return self._app.results.is_markable(self._dupe)
@ -47,10 +51,10 @@ class DupeNode(Node):
self._app.mark_dupe(self._dupe, value) self._app.mark_dupe(self._dupe, value)
class ResultTree(GUIObject, Tree): class ResultTable(GUIObject, GUITable):
def __init__(self, view, app): def __init__(self, view, app):
GUIObject.__init__(self, view, app) GUIObject.__init__(self, view, app)
Tree.__init__(self) GUITable.__init__(self)
self._power_marker = False self._power_marker = False
self._delta_values = False self._delta_values = False
self._sort_descriptors = (0, True) self._sort_descriptors = (0, True)
@ -58,60 +62,54 @@ class ResultTree(GUIObject, Tree):
#--- Override #--- Override
def connect(self): def connect(self):
GUIObject.connect(self) GUIObject.connect(self)
self._refresh() self.refresh()
self.view.refresh() self.view.refresh()
def _select_nodes(self, nodes): def _restore_selection(self, previous_selection):
Tree._select_nodes(self, nodes) if self.app.selected_dupes:
self.app._select_dupes(list(map(attrgetter('_dupe'), nodes))) to_find = set(self.app.selected_dupes)
indexes = [i for i, r in enumerate(self) if r._dupe in to_find]
self.selected_indexes = indexes
#--- Private def _update_selection(self):
def _refresh(self): rows = self.selected_rows
self.clear() self.app._select_dupes(list(map(attrgetter('_dupe'), rows)))
def _fill(self):
if not self.power_marker: if not self.power_marker:
for group in self.app.results.groups: for group in self.app.results.groups:
group_node = DupeNode(self.app, group, group.ref) self.append(DupeRow(self, group, group.ref))
self.append(group_node)
for dupe in group.dupes: for dupe in group.dupes:
group_node.append(DupeNode(self.app, group, dupe)) self.append(DupeRow(self, group, dupe))
else: else:
for dupe in self.app.results.dupes: for dupe in self.app.results.dupes:
group = self.app.results.get_group_of_duplicate(dupe) group = self.app.results.get_group_of_duplicate(dupe)
self.append(DupeNode(self.app, group, dupe)) self.append(DupeRow(self, group, dupe))
if self.app.selected_dupes:
to_find = set(self.app.selected_dupes)
nodes = list(self.findall(lambda n: n is not self and n._dupe in to_find))
self.selected_nodes = nodes
#--- Public #--- Public
def get_node_value(self, path, column): def get_row_value(self, index, column):
try: try:
node = self.get_node(path) row = self[index]
except IndexError: except IndexError:
return '---' return '---'
if self.delta_values: if self.delta_values:
return node.data_delta[column] return row.data_delta[column]
else: else:
return node.data[column] return row.data[column]
def rename_selected(self, newname): def rename_selected(self, newname):
node = self.selected_node row = self.selected_row
node._data = None row._data = None
node._data_delta = None row._data_delta = None
return self.app.rename_selected(newname) return self.app.rename_selected(newname)
def root_children_counts(self):
# This is a speed optimization for cases where there's a lot of results so that there is
# not thousands of children_count queries when expandAll is called.
return [len(node) for node in self]
def sort(self, key, asc): def sort(self, key, asc):
if self.power_marker: if self.power_marker:
self.app.results.sort_dupes(key, asc, self.delta_values) self.app.results.sort_dupes(key, asc, self.delta_values)
else: else:
self.app.results.sort_groups(key, asc) self.app.results.sort_groups(key, asc)
self._sort_descriptors = (key, asc) self._sort_descriptors = (key, asc)
self._refresh() self.refresh()
self.view.refresh() self.view.refresh()
#--- Properties #--- Properties
@ -126,7 +124,7 @@ class ResultTree(GUIObject, Tree):
self._power_marker = value self._power_marker = value
key, asc = self._sort_descriptors key, asc = self._sort_descriptors
self.sort(key, asc) self.sort(key, asc)
self._refresh() self.refresh()
self.view.refresh() self.view.refresh()
@property @property
@ -138,22 +136,26 @@ class ResultTree(GUIObject, Tree):
if value == self._delta_values: if value == self._delta_values:
return return
self._delta_values = value self._delta_values = value
self._refresh() self.refresh()
self.view.refresh() self.view.refresh()
@property
def selected_dupe_count(self):
return sum(1 for row in self.selected_rows if not row.isref)
#--- Event Handlers #--- Event Handlers
def marking_changed(self): def marking_changed(self):
self.view.invalidate_markings() self.view.invalidate_markings()
def results_changed(self): def results_changed(self):
self._refresh() self.refresh()
self.view.refresh() self.view.refresh()
def results_changed_but_keep_selection(self): def results_changed_but_keep_selection(self):
# What we want to to here is that instead of restoring selected *dupes* after refresh, we # What we want to to here is that instead of restoring selected *dupes* after refresh, we
# restore selected *paths*. # restore selected *paths*.
paths = self.selected_paths indexes = self.selected_indexes
self._refresh() self.refresh()
self.selected_paths = paths self.select(indexes)
self.view.refresh() self.view.refresh()

View File

@ -23,7 +23,7 @@ from .. import app, fs, engine
from ..app import DupeGuru as DupeGuruBase from ..app import DupeGuru as DupeGuruBase
from ..gui.details_panel import DetailsPanel from ..gui.details_panel import DetailsPanel
from ..gui.directory_tree import DirectoryTree from ..gui.directory_tree import DirectoryTree
from ..gui.result_tree import ResultTree from ..gui.result_table import ResultTable
class DupeGuru(DupeGuruBase): class DupeGuru(DupeGuruBase):
def __init__(self): def __init__(self):
@ -166,11 +166,11 @@ class TCDupeGuruWithResults(TestCase):
self.dpanel = DetailsPanel(self.dpanel_gui, self.app) self.dpanel = DetailsPanel(self.dpanel_gui, self.app)
self.dtree_gui = CallLogger() self.dtree_gui = CallLogger()
self.dtree = DirectoryTree(self.dtree_gui, self.app) self.dtree = DirectoryTree(self.dtree_gui, self.app)
self.rtree_gui = CallLogger() self.rtable_gui = CallLogger()
self.rtree = ResultTree(self.rtree_gui, self.app) self.rtable = ResultTable(self.rtable_gui, self.app)
self.dpanel.connect() self.dpanel.connect()
self.dtree.connect() self.dtree.connect()
self.rtree.connect() self.rtable.connect()
tmppath = self.tmppath() tmppath = self.tmppath()
io.mkdir(tmppath + 'foo') io.mkdir(tmppath + 'foo')
io.mkdir(tmppath + 'bar') io.mkdir(tmppath + 'bar')
@ -217,42 +217,35 @@ class TCDupeGuruWithResults(TestCase):
def test_GetObjects(self): def test_GetObjects(self):
objects = self.objects objects = self.objects
groups = self.groups groups = self.groups
n = self.rtree.get_node([0]) r = self.rtable[0]
assert n._group is groups[0] assert r._group is groups[0]
assert n._dupe is objects[0] assert r._dupe is objects[0]
n = self.rtree.get_node([0, 0]) r = self.rtable[1]
assert n._group is groups[0] assert r._group is groups[0]
assert n._dupe is objects[1] assert r._dupe is objects[1]
n = self.rtree.get_node([1, 0]) r = self.rtable[4]
assert n._group is groups[1] assert r._group is groups[1]
assert n._dupe is objects[4] assert r._dupe is objects[4]
def test_GetObjects_after_sort(self): def test_GetObjects_after_sort(self):
objects = self.objects objects = self.objects
groups = self.groups[:] # we need an un-sorted reference groups = self.groups[:] # we need an un-sorted reference
self.rtree.sort(0, False) #0 = Filename self.rtable.sort(0, False) #0 = Filename
n = self.rtree.get_node([0, 0]) r = self.rtable[1]
assert n._group is groups[1] assert r._group is groups[1]
assert n._dupe is objects[4] assert r._dupe is objects[4]
def test_selected_result_node_paths(self):
# app.selected_dupes is correctly converted into node paths
paths = [[0, 0], [0, 1], [1]]
self.rtree.selected_paths = paths
eq_(self.rtree.selected_paths, paths)
def test_selected_result_node_paths_after_deletion(self): def test_selected_result_node_paths_after_deletion(self):
# cases where the selected dupes aren't there are correctly handled # cases where the selected dupes aren't there are correctly handled
paths = [[0, 0], [0, 1], [1]] self.rtable.select([1, 2, 3])
self.rtree.selected_paths = paths
self.app.remove_selected() self.app.remove_selected()
# The first 2 dupes have been removed. The 3rd one is a ref. it stays there, in first pos. # The first 2 dupes have been removed. The 3rd one is a ref. it stays there, in first pos.
eq_(self.rtree.selected_paths, [[0, 0]]) # no exception eq_(self.rtable.selected_indexes, [1]) # no exception
def test_selectResultNodePaths(self): def test_selectResultNodePaths(self):
app = self.app app = self.app
objects = self.objects objects = self.objects
self.rtree.selected_paths = [[0, 0], [0, 1]] self.rtable.select([1, 2])
eq_(len(app.selected_dupes), 2) eq_(len(app.selected_dupes), 2)
assert app.selected_dupes[0] is objects[1] assert app.selected_dupes[0] is objects[1]
assert app.selected_dupes[1] is objects[2] assert app.selected_dupes[1] is objects[2]
@ -260,7 +253,7 @@ class TCDupeGuruWithResults(TestCase):
def test_selectResultNodePaths_with_ref(self): def test_selectResultNodePaths_with_ref(self):
app = self.app app = self.app
objects = self.objects objects = self.objects
self.rtree.selected_paths = [[0, 0], [0, 1], [1]] self.rtable.select([1, 2, 3])
eq_(len(app.selected_dupes), 3) eq_(len(app.selected_dupes), 3)
assert app.selected_dupes[0] is objects[1] assert app.selected_dupes[0] is objects[1]
assert app.selected_dupes[1] is objects[2] assert app.selected_dupes[1] is objects[2]
@ -270,9 +263,9 @@ class TCDupeGuruWithResults(TestCase):
app = self.app app = self.app
objects = self.objects objects = self.objects
groups = self.groups[:] #To keep the old order in memory groups = self.groups[:] #To keep the old order in memory
self.rtree.sort(0, False) #0 = Filename self.rtable.sort(0, False) #0 = Filename
#Now, the group order is supposed to be reversed #Now, the group order is supposed to be reversed
self.rtree.selected_paths = [[0, 0], [1], [1, 0]] self.rtable.select([1, 2, 3])
eq_(len(app.selected_dupes), 3) eq_(len(app.selected_dupes), 3)
assert app.selected_dupes[0] is objects[4] assert app.selected_dupes[0] is objects[4]
assert app.selected_dupes[1] is groups[0].ref assert app.selected_dupes[1] is groups[0].ref
@ -282,39 +275,26 @@ class TCDupeGuruWithResults(TestCase):
# app.selected_dupes is correctly converted into paths # app.selected_dupes is correctly converted into paths
app = self.app app = self.app
objects = self.objects objects = self.objects
self.rtree.power_marker = True self.rtable.power_marker = True
self.rtree.selected_paths = [[0], [1], [2]] self.rtable.select([0, 1, 2])
self.rtree.power_marker = False self.rtable.power_marker = False
eq_(self.rtree.selected_paths, [[0, 0], [0, 1], [1, 0]]) eq_(self.rtable.selected_indexes, [1, 2, 4])
def test_selected_powermarker_node_paths_after_deletion(self): def test_selected_powermarker_node_paths_after_deletion(self):
# cases where the selected dupes aren't there are correctly handled # cases where the selected dupes aren't there are correctly handled
app = self.app app = self.app
objects = self.objects objects = self.objects
self.rtree.power_marker = True self.rtable.power_marker = True
self.rtree.selected_paths = [[0], [1], [2]] self.rtable.select([0, 1, 2])
app.remove_selected() app.remove_selected()
eq_(self.rtree.selected_paths, []) # no exception eq_(self.rtable.selected_indexes, []) # no exception
def test_selectPowerMarkerRows(self):
app = self.app
objects = self.objects
self.rtree.selected_paths = [[0, 0], [0, 1], [1, 0]]
eq_(len(app.selected_dupes), 3)
assert app.selected_dupes[0] is objects[1]
assert app.selected_dupes[1] is objects[2]
assert app.selected_dupes[2] is objects[4]
def test_selectPowerMarkerRows_empty(self):
self.rtree.selected_paths = []
eq_(len(self.app.selected_dupes), 0)
def test_selectPowerMarkerRows_after_sort(self): def test_selectPowerMarkerRows_after_sort(self):
app = self.app app = self.app
objects = self.objects objects = self.objects
self.rtree.power_marker = True self.rtable.power_marker = True
self.rtree.sort(0, False) #0 = Filename self.rtable.sort(0, False) #0 = Filename
self.rtree.selected_paths = [[0], [1], [2]] self.rtable.select([0, 1, 2])
eq_(len(app.selected_dupes), 3) eq_(len(app.selected_dupes), 3)
assert app.selected_dupes[0] is objects[4] assert app.selected_dupes[0] is objects[4]
assert app.selected_dupes[1] is objects[2] assert app.selected_dupes[1] is objects[2]
@ -325,7 +305,7 @@ class TCDupeGuruWithResults(TestCase):
objects = self.objects objects = self.objects
app.toggle_selected_mark_state() app.toggle_selected_mark_state()
eq_(app.results.mark_count, 0) eq_(app.results.mark_count, 0)
self.rtree.selected_paths = [[0, 0], [1, 0]] self.rtable.select([1, 4])
app.toggle_selected_mark_state() app.toggle_selected_mark_state()
eq_(app.results.mark_count, 2) eq_(app.results.mark_count, 2)
assert not app.results.is_marked(objects[0]) assert not app.results.is_marked(objects[0])
@ -335,10 +315,10 @@ class TCDupeGuruWithResults(TestCase):
assert app.results.is_marked(objects[4]) assert app.results.is_marked(objects[4])
def test_refreshDetailsWithSelected(self): def test_refreshDetailsWithSelected(self):
self.rtree.selected_paths = [[0, 0], [1, 0]] self.rtable.select([1, 4])
eq_(self.dpanel.row(0), ('Filename', 'bar bleh', 'foo bar')) eq_(self.dpanel.row(0), ('Filename', 'bar bleh', 'foo bar'))
self.check_gui_calls(self.dpanel_gui, ['refresh']) self.check_gui_calls(self.dpanel_gui, ['refresh'])
self.rtree.selected_paths = [] self.rtable.select([])
eq_(self.dpanel.row(0), ('Filename', '---', '---')) eq_(self.dpanel.row(0), ('Filename', '---', '---'))
self.check_gui_calls(self.dpanel_gui, ['refresh']) self.check_gui_calls(self.dpanel_gui, ['refresh'])
@ -346,7 +326,7 @@ class TCDupeGuruWithResults(TestCase):
app = self.app app = self.app
objects = self.objects objects = self.objects
groups = self.groups groups = self.groups
self.rtree.selected_paths = [[0, 0], [1, 0]] self.rtable.select([1, 4])
app.make_selected_reference() app.make_selected_reference()
assert groups[0].ref is objects[1] assert groups[0].ref is objects[1]
assert groups[1].ref is objects[4] assert groups[1].ref is objects[4]
@ -355,7 +335,7 @@ class TCDupeGuruWithResults(TestCase):
app = self.app app = self.app
objects = self.objects objects = self.objects
groups = self.groups groups = self.groups
self.rtree.selected_paths = [[0, 0], [0, 1], [1, 0]] self.rtable.select([1, 2, 4])
#Only [0, 0] and [1, 0] must go ref, not [0, 1] because it is a part of the same group #Only [0, 0] and [1, 0] must go ref, not [0, 1] because it is a part of the same group
app.make_selected_reference() app.make_selected_reference()
assert groups[0].ref is objects[1] assert groups[0].ref is objects[1]
@ -363,7 +343,7 @@ class TCDupeGuruWithResults(TestCase):
def test_removeSelected(self): def test_removeSelected(self):
app = self.app app = self.app
self.rtree.selected_paths = [[0, 0], [1, 0]] self.rtable.select([1, 4])
app.remove_selected() app.remove_selected()
eq_(len(app.results.dupes), 1) # the first path is now selected eq_(len(app.results.dupes), 1) # the first path is now selected
app.remove_selected() app.remove_selected()
@ -386,10 +366,10 @@ class TCDupeGuruWithResults(TestCase):
def test_ignore(self): def test_ignore(self):
app = self.app app = self.app
self.rtree.selected_path = [1, 0] #The dupe of the second, 2 sized group self.rtable.select([4]) #The dupe of the second, 2 sized group
app.add_selected_to_ignore_list() app.add_selected_to_ignore_list()
eq_(len(app.scanner.ignore_list), 1) eq_(len(app.scanner.ignore_list), 1)
self.rtree.selected_path = [0, 0] #first dupe of the 3 dupes group self.rtable.select([1]) #first dupe of the 3 dupes group
app.add_selected_to_ignore_list() app.add_selected_to_ignore_list()
#BOTH the ref and the other dupe should have been added #BOTH the ref and the other dupe should have been added
eq_(len(app.scanner.ignore_list), 3) eq_(len(app.scanner.ignore_list), 3)
@ -416,7 +396,7 @@ class TCDupeGuruWithResults(TestCase):
app = self.app app = self.app
app.scanner.ignore_list.Ignore = FakeIgnore app.scanner.ignore_list.Ignore = FakeIgnore
self.rtree.selected_path = [1, 0] self.rtable.select([4])
app.add_selected_to_ignore_list() app.add_selected_to_ignore_list()
@ -440,14 +420,14 @@ class TCDupeGuru_renameSelected(TestCase):
self.groups = groups self.groups = groups
self.p = p self.p = p
self.files = files self.files = files
self.rtree_gui = CallLogger() self.rtable_gui = CallLogger()
self.rtree = ResultTree(self.rtree_gui, self.app) self.rtable = ResultTable(self.rtable_gui, self.app)
self.rtree.connect() self.rtable.connect()
def test_simple(self): def test_simple(self):
app = self.app app = self.app
g = self.groups[0] g = self.groups[0]
self.rtree.selected_path = [0, 0] self.rtable.select([1])
assert app.rename_selected('renamed') assert app.rename_selected('renamed')
names = io.listdir(self.p) names = io.listdir(self.p)
assert 'renamed' in names assert 'renamed' in names
@ -457,7 +437,7 @@ class TCDupeGuru_renameSelected(TestCase):
def test_none_selected(self): def test_none_selected(self):
app = self.app app = self.app
g = self.groups[0] g = self.groups[0]
self.rtree.selected_paths = [] self.rtable.select([])
self.mock(logging, 'warning', log_calls(lambda msg: None)) self.mock(logging, 'warning', log_calls(lambda msg: None))
assert not app.rename_selected('renamed') assert not app.rename_selected('renamed')
msg = logging.warning.calls[0]['msg'] msg = logging.warning.calls[0]['msg']
@ -470,7 +450,7 @@ class TCDupeGuru_renameSelected(TestCase):
def test_name_already_exists(self): def test_name_already_exists(self):
app = self.app app = self.app
g = self.groups[0] g = self.groups[0]
self.rtree.selected_path = [0, 0] self.rtable.select([1])
self.mock(logging, 'warning', log_calls(lambda msg: None)) self.mock(logging, 'warning', log_calls(lambda msg: None))
assert not app.rename_selected('foo bar 1') assert not app.rename_selected('foo bar 1')
msg = logging.warning.calls[0]['msg'] msg = logging.warning.calls[0]['msg']

View File

@ -48,7 +48,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def _setupUi(self): def _setupUi(self):
self.setupUi(self) self.setupUi(self)
# Stuff that can't be setup in the Designer # Stuff that can't be setup in the Designer
h = self.resultsView.header() h = self.resultsView.horizontalHeader()
h.setHighlightSections(False) h.setHighlightSections(False)
h.setMovable(True) h.setMovable(True)
h.setStretchLastSection(False) h.setStretchLastSection(False)
@ -110,7 +110,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
return answer == QMessageBox.Yes return answer == QMessageBox.Yes
def _load_columns(self): def _load_columns(self):
h = self.resultsView.header() h = self.resultsView.horizontalHeader()
h.setResizeMode(QHeaderView.Interactive) h.setResizeMode(QHeaderView.Interactive)
prefs = self.app.prefs prefs = self.app.prefs
attrs = list(zip(prefs.columns_width, prefs.columns_visible)) attrs = list(zip(prefs.columns_width, prefs.columns_visible))
@ -120,7 +120,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
h.setResizeMode(0, QHeaderView.Stretch) h.setResizeMode(0, QHeaderView.Stretch)
def _update_column_actions_status(self): def _update_column_actions_status(self):
h = self.resultsView.header() h = self.resultsView.horizontalHeader()
for action in self._column_actions: for action in self._column_actions:
colid = action.column_index colid = action.column_index
action.setChecked(not h.isSectionHidden(colid)) action.setChecked(not h.isSectionHidden(colid))
@ -185,7 +185,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.app.show_directories() self.app.show_directories()
def exportTriggered(self): def exportTriggered(self):
h = self.resultsView.header() h = self.resultsView.horizontalHeader()
column_ids = [] column_ids = []
for i in range(len(self.app.data.COLUMNS)): for i in range(len(self.app.data.COLUMNS)):
if not h.isSectionHidden(i): if not h.isSectionHidden(i):
@ -278,7 +278,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
#--- Events #--- Events
def appWillSavePrefs(self): def appWillSavePrefs(self):
prefs = self.app.prefs prefs = self.app.prefs
h = self.resultsView.header() h = self.resultsView.horizontalHeader()
widths = [] widths = []
visible = [] visible = []
for i in range(len(self.app.data.COLUMNS)): for i in range(len(self.app.data.COLUMNS)):
@ -295,7 +295,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.app.prefs.reset_columns() self.app.prefs.reset_columns()
self._load_columns() self._load_columns()
else: else:
h = self.resultsView.header() h = self.resultsView.horizontalHeader()
h.setSectionHidden(colid, not h.isSectionHidden(colid)) h.setSectionHidden(colid, not h.isSectionHidden(colid))
self._update_column_actions_status() self._update_column_actions_status()

View File

@ -26,27 +26,21 @@
<property name="selectionBehavior"> <property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum> <enum>QAbstractItemView::SelectRows</enum>
</property> </property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="sortingEnabled"> <property name="sortingEnabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="expandsOnDoubleClick"> <attribute name="verticalHeaderVisible">
<bool>false</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool> <bool>false</bool>
</attribute> </attribute>
<attribute name="headerStretchLastSection"> <attribute name="verticalHeaderDefaultSectionSize">
<number>18</number>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool> <bool>false</bool>
</attribute> </attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>18</number>
</attribute>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -57,7 +51,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>630</width> <width>630</width>
<height>20</height> <height>22</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuColumns"> <widget class="QMenu" name="menuColumns">
@ -462,7 +456,7 @@
<customwidgets> <customwidgets>
<customwidget> <customwidget>
<class>ResultsView</class> <class>ResultsView</class>
<extends>QTreeView</extends> <extends>QTableView</extends>
<header>.results_model</header> <header>.results_model</header>
</customwidget> </customwidget>
</customwidgets> </customwidgets>

View File

@ -7,62 +7,20 @@
# http://www.hardcoded.net/licenses/hs_license # http://www.hardcoded.net/licenses/hs_license
from PyQt4.QtCore import SIGNAL, Qt from PyQt4.QtCore import SIGNAL, Qt
from PyQt4.QtGui import (QBrush, QStyledItemDelegate, QFont, QTreeView, QColor, QItemSelectionModel, from PyQt4.QtGui import QBrush, QFont, QTableView, QColor, QItemSelectionModel, QItemSelection
QItemSelection)
from qtlib.tree_model import TreeModel, RefNode from qtlib.table import Table
from core.gui.result_tree import ResultTree as ResultTreeModel from core.gui.result_table import ResultTable as ResultTableModel
class ResultsDelegate(QStyledItemDelegate): class ResultsModel(Table):
def initStyleOption(self, option, index):
QStyledItemDelegate.initStyleOption(self, option, index)
node = index.internalPointer()
ref = node.ref
if ref._group.ref is ref._dupe:
newfont = QFont(option.font)
newfont.setBold(True)
option.font = newfont
class ResultsModel(TreeModel):
def __init__(self, app, view): def __init__(self, app, view):
TreeModel.__init__(self) model = ResultTableModel(self, app)
self.view = view
self._app = app self._app = app
self._data = app.data self._data = app.data
self._delta_columns = app.DELTA_COLUMNS self._delta_columns = app.DELTA_COLUMNS
self.resultsDelegate = ResultsDelegate() Table.__init__(self, model, view)
self.model = ResultTreeModel(self, app)
self.view.setItemDelegate(self.resultsDelegate)
self.view.setModel(self)
self.model.connect() self.model.connect()
self.connect(self.view.selectionModel(), SIGNAL('selectionChanged(QItemSelection,QItemSelection)'), self.selectionChanged)
def _createNode(self, ref, row):
return RefNode(self, None, ref, row)
def _getChildren(self):
return list(self.model)
def _updateSelection(self):
selectedIndexes = []
for path in self.model.selected_paths:
modelIndex = self.findIndex(path)
if modelIndex.isValid():
selectedIndexes.append(modelIndex)
if selectedIndexes:
selection = QItemSelection()
for modelIndex in selectedIndexes:
selection.select(modelIndex, modelIndex)
flags = QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows
self.view.selectionModel().select(selection, flags)
flags = QItemSelectionModel.Rows
self.view.selectionModel().setCurrentIndex(selectedIndexes[0], flags)
self.view.scrollTo(selectedIndexes[0])
else:
self.view.selectionModel().clear()
def columnCount(self, parent): def columnCount(self, parent):
return len(self._data.COLUMNS) return len(self._data.COLUMNS)
@ -70,22 +28,26 @@ class ResultsModel(TreeModel):
def data(self, index, role): def data(self, index, role):
if not index.isValid(): if not index.isValid():
return None return None
node = index.internalPointer() row = self.model[index.row()]
ref = node.ref
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
data = ref.data_delta if self.model.delta_values else ref.data data = row.data_delta if self.model.delta_values else row.data
return data[index.column()] return data[index.column()]
elif role == Qt.CheckStateRole: elif role == Qt.CheckStateRole:
if index.column() == 0 and ref.markable: if index.column() == 0 and row.markable:
return Qt.Checked if ref.marked else Qt.Unchecked return Qt.Checked if row.marked else Qt.Unchecked
elif role == Qt.ForegroundRole: elif role == Qt.ForegroundRole:
if ref._dupe is ref._group.ref or ref._dupe.is_ref: if row.isref:
return QBrush(Qt.blue) return QBrush(Qt.blue)
elif self.model.delta_values and index.column() in self._delta_columns: elif self.model.delta_values and index.column() in self._delta_columns:
return QBrush(QColor(255, 142, 40)) # orange return QBrush(QColor(255, 142, 40)) # orange
elif role == Qt.FontRole:
isBold = row.isref
font = QFont(self.view.font())
font.setBold(isBold)
return font
elif role == Qt.EditRole: elif role == Qt.EditRole:
if index.column() == 0: if index.column() == 0:
return ref.data[index.column()] return row.data[index.column()]
return None return None
def flags(self, index): def flags(self, index):
@ -93,7 +55,10 @@ class ResultsModel(TreeModel):
return Qt.ItemIsEnabled return Qt.ItemIsEnabled
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if index.column() == 0: if index.column() == 0:
flags |= Qt.ItemIsUserCheckable | Qt.ItemIsEditable flags |= Qt.ItemIsEditable
row = self.model[index.row()]
if row.markable:
flags |= Qt.ItemIsUserCheckable
return flags return flags
def headerData(self, section, orientation, role): def headerData(self, section, orientation, role):
@ -104,13 +69,12 @@ class ResultsModel(TreeModel):
def setData(self, index, value, role): def setData(self, index, value, role):
if not index.isValid(): if not index.isValid():
return False return False
node = index.internalPointer() row = self.model[index.row()]
ref = node.ref
if role == Qt.CheckStateRole: if role == Qt.CheckStateRole:
if index.column() == 0: if index.column() == 0:
self._app.mark_dupe(ref._dupe, value.toBool()) self._app.mark_dupe(row._dupe, value.toBool())
return True return True
if role == Qt.EditRole: elif role == Qt.EditRole:
if index.column() == 0: if index.column() == 0:
value = str(value.toString()) value = str(value.toString())
return self.model.rename_selected(value) return self.model.rename_selected(value)
@ -136,18 +100,7 @@ class ResultsModel(TreeModel):
def delta_values(self, value): def delta_values(self, value):
self.model.delta_values = value self.model.delta_values = value
#--- Events
def selectionChanged(self, selected, deselected):
indexes = self.view.selectionModel().selectedRows()
nodes = [index.internalPointer() for index in indexes]
self.model.selected_nodes = [node.ref for node in nodes]
#--- model --> view #--- model --> view
def refresh(self):
self.reset()
self.view.expandAll()
self._updateSelection()
def invalidate_markings(self): def invalidate_markings(self):
# redraw view # redraw view
# HACK. this is the only way I found to update the widget without reseting everything # HACK. this is the only way I found to update the widget without reseting everything
@ -155,13 +108,13 @@ class ResultsModel(TreeModel):
self.view.scroll(0, -1) self.view.scroll(0, -1)
class ResultsView(QTreeView): class ResultsView(QTableView):
#--- Override #--- Override
def keyPressEvent(self, event): def keyPressEvent(self, event):
if event.text() == ' ': if event.text() == ' ':
self.emit(SIGNAL('spacePressed()')) self.emit(SIGNAL('spacePressed()'))
return return
QTreeView.keyPressEvent(self, event) QTableView.keyPressEvent(self, event)
def mouseDoubleClickEvent(self, event): def mouseDoubleClickEvent(self, event):
self.emit(SIGNAL('doubleClicked()')) self.emit(SIGNAL('doubleClicked()'))