Created gui.details_panel and moved all details panel related logic in there (cocoa only, for now).

This commit is contained in:
Virgil Dupras 2010-02-05 20:10:54 +01:00
parent cd9b7f2f11
commit 7ffefe6259
22 changed files with 273 additions and 182 deletions

View File

@ -8,18 +8,18 @@ http://www.hardcoded.net/licenses/hs_license
#import <Cocoa/Cocoa.h>
#import "PyApp.h"
#import "Table.h"
#import "PyDetailsPanel.h"
@interface DetailsPanel : NSWindowController
{
IBOutlet TableView *detailsTable;
IBOutlet NSTableView *detailsTable;
PyDetailsPanel *py;
}
- (id)initWithPy:(PyApp *)aPy;
- (void)refresh;
- (void)toggleVisibility;
/* Notifications */
- (void)duplicateSelectionChanged:(NSNotification *)aNotification;
/* Python --> Cocoa */
- (void)refresh;
@end

View File

@ -7,38 +7,56 @@ http://www.hardcoded.net/licenses/hs_license
*/
#import "DetailsPanel.h"
#import "Consts.h"
#import "Utils.h"
@implementation DetailsPanel
- (id)initWithPy:(PyApp *)aPy
{
self = [super initWithWindowNibName:@"DetailsPanel"];
[self window]; //So the detailsTable is initialized.
[detailsTable setPy:aPy];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(duplicateSelectionChanged:) name:DuplicateSelectionChangedNotification object:nil];
Class pyClass = [Utils classNamed:@"PyDetailsPanel"];
py = [[pyClass alloc] initWithCocoa:self pyParent:aPy];
return self;
}
- (void)refresh
- (void)dealloc
{
[py release];
[super dealloc];
}
- (void)refreshDetails
{
[detailsTable reloadData];
}
- (void)toggleVisibility
{
if ([[self window] isVisible])
if ([[self window] isVisible]) {
[[self window] close];
else
{
[self refresh]; // selection might have changed since last time
}
else {
[self refreshDetails]; // selection might have changed since last time
[[self window] orderFront:nil];
}
}
/* Notifications */
- (void)duplicateSelectionChanged:(NSNotification *)aNotification
/* NSTableView Delegate */
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
if ([[self window] isVisible])
[self refresh];
return [py numberOfRows];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)column row:(NSInteger)row
{
return [py valueForColumn:[column identifier] row:row];
}
/* Python --> Cocoa */
- (void)refresh
{
if ([[self window] isVisible]) {
[self refreshDetails];
}
}
@end

View File

@ -0,0 +1,15 @@
/*
Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
This software is licensed under the "HS" License as described in the "LICENSE" file,
which should be included with this package. The terms are also available at
http://www.hardcoded.net/licenses/hs_license
*/
#import <Cocoa/Cocoa.h>
@interface PyDetailsPanel : NSObject
- (id)initWithCocoa:(id)cocoa pyParent:(id)pyParent;
- (NSInteger)numberOfRows;
- (id)valueForColumn:(NSString *)column row:(NSInteger)row;
@end

View File

@ -2,17 +2,17 @@
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
<data>
<int key="IBDocument.SystemTarget">1050</int>
<string key="IBDocument.SystemVersion">10B504</string>
<string key="IBDocument.SystemVersion">10C540</string>
<string key="IBDocument.InterfaceBuilderVersion">740</string>
<string key="IBDocument.AppKitVersion">1038.2</string>
<string key="IBDocument.HIToolboxVersion">437.00</string>
<string key="IBDocument.AppKitVersion">1038.25</string>
<string key="IBDocument.HIToolboxVersion">458.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="NS.object.0">740</string>
</object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
<integer value="5"/>
<integer value="6"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@ -297,13 +297,21 @@
</object>
<int key="connectionID">12</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">dataSource</string>
<reference key="source" ref="251969872"/>
<reference key="destination" ref="449947658"/>
</object>
<int key="connectionID">21</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">detailsTable</string>
<reference key="source" ref="449947658"/>
<reference key="destination" ref="251969872"/>
</object>
<int key="connectionID">13</int>
<int key="connectionID">22</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
@ -438,15 +446,22 @@
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>-3.IBPluginDependency</string>
<string>10.IBPluginDependency</string>
<string>10.ImportedFromIB2</string>
<string>11.IBPluginDependency</string>
<string>11.ImportedFromIB2</string>
<string>15.IBPluginDependency</string>
<string>15.IBShouldRemoveOnLegacySave</string>
<string>16.IBPluginDependency</string>
<string>16.IBShouldRemoveOnLegacySave</string>
<string>17.IBPluginDependency</string>
<string>17.IBShouldRemoveOnLegacySave</string>
<string>18.IBPluginDependency</string>
<string>18.IBShouldRemoveOnLegacySave</string>
<string>19.IBPluginDependency</string>
<string>19.IBShouldRemoveOnLegacySave</string>
<string>20.IBPluginDependency</string>
<string>20.IBShouldRemoveOnLegacySave</string>
<string>5.IBEditorWindowLastContentRect</string>
<string>5.IBPluginDependency</string>
@ -458,7 +473,6 @@
<string>6.ImportedFromIB2</string>
<string>7.IBPluginDependency</string>
<string>7.ImportedFromIB2</string>
<string>8.CustomClassName</string>
<string>8.IBPluginDependency</string>
<string>8.ImportedFromIB2</string>
<string>9.IBPluginDependency</string>
@ -467,14 +481,21 @@
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<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>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>{{109, 656}, {451, 161}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@ -486,7 +507,6 @@
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>TableView</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@ -509,19 +529,11 @@
</object>
</object>
<nil key="sourceID"/>
<int key="maxID">20</int>
<int key="maxID">22</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBPartialClassDescription">
<string key="className">DetailsPanel</string>
<string key="superclassName">NSWindowController</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">DetailsPanel.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">DetailsPanel</string>
<string key="superclassName">NSWindowController</string>
@ -530,60 +542,21 @@
<string key="NS.object.0">NSTableView</string>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">../base/DetailsPanel.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">DetailsPanel</string>
<string key="superclassName">NSWindowController</string>
<object class="NSMutableDictionary" key="outlets">
<string key="NS.key.0">detailsTable</string>
<string key="NS.object.0">TableView</string>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">dgbase/DetailsPanel.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">FirstResponder</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">PyApp</string>
<string key="superclassName">PyRegistrable</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">cocoalib/PyApp.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">PyRegistrable</string>
<string key="className">FirstResponder</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">cocoalib/PyRegistrable.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">TableView</string>
<string key="superclassName">NSTableView</string>
<object class="NSMutableDictionary" key="outlets">
<string key="NS.key.0">py</string>
<string key="NS.object.0">PyApp</string>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">cocoalib/Table.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">TableView</string>
<string key="superclassName">NSTableView</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>

View File

@ -6,7 +6,7 @@
from hsutil.cocoa import signature
from core.app_cocoa_inter import PyDupeGuruBase
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
from core_me.app_cocoa import DupeGuruME
from core.scanner import (SCAN_TYPE_FILENAME, SCAN_TYPE_FIELDS, SCAN_TYPE_FIELDS_NO_ORDER,
SCAN_TYPE_TAG, SCAN_TYPE_CONTENT, SCAN_TYPE_CONTENT_AUDIO)

View File

@ -130,6 +130,7 @@
CE900AD6109B2A9B00754048 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MainMenu.xib; path = ../../base/xib/MainMenu.xib; sourceTree = "<group>"; };
CECA899A09DB132E00A3D774 /* DetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = DetailsPanel.h; sourceTree = "<group>"; };
CECA899B09DB132E00A3D774 /* DetailsPanel.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = DetailsPanel.m; sourceTree = "<group>"; };
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; sourceTree = SOURCE_ROOT; };
CEEB135109C837A2004D2330 /* dupeguru.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = dupeguru.icns; sourceTree = "<group>"; };
CEFC294509C89E3D00D9F998 /* folder32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = folder32.png; path = ../../images/folder32.png; sourceTree = SOURCE_ROOT; };
CEFC295309C89FF200D9F998 /* details32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = details32.png; path = ../../images/details32.png; sourceTree = SOURCE_ROOT; };
@ -310,6 +311,7 @@
CE515E180FC6C19300EC695D /* DirectoryPanel.h */,
CE515E190FC6C19300EC695D /* DirectoryPanel.m */,
CE515E1A0FC6C19300EC695D /* PyDupeGuru.h */,
CED0A591111C9FD10020AD7D /* PyDetailsPanel.h */,
CE515E1B0FC6C19300EC695D /* ResultWindow.h */,
CE515E1C0FC6C19300EC695D /* ResultWindow.m */,
);

View File

@ -7,10 +7,12 @@ http://www.hardcoded.net/licenses/hs_license
*/
#import <Cocoa/Cocoa.h>
#import "Utils.h"
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[Utils setPluginName:@"dg_cocoa"];
NSString *pluginPath = [[NSBundle mainBundle]
pathForResource:@"dg_cocoa"
ofType:@"plugin"];

View File

@ -16,7 +16,7 @@ http://www.hardcoded.net/licenses/hs_license
IBOutlet NSImageView *refImage;
IBOutlet NSProgressIndicator *refProgressIndicator;
PyApp *py;
PyApp *pyApp;
BOOL _needsRefresh;
NSString *_dupePath;
NSString *_refPath;

View File

@ -17,7 +17,7 @@ http://www.hardcoded.net/licenses/hs_license
- (id)initWithPy:(PyApp *)aPy
{
self = [super initWithPy:aPy];
py = aPy;
pyApp = aPy;
_needsRefresh = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(imageLoaded:) name:ImageLoadedNotification object:self];
return self;
@ -36,18 +36,18 @@ http://www.hardcoded.net/licenses/hs_license
[pool release];
}
- (void)refresh
- (void)refreshDetails
{
if (!_needsRefresh)
return;
[detailsTable reloadData];
NSString *refPath = [(PyDupeGuru *)py getSelectedDupeRefPath];
NSString *refPath = [(PyDupeGuru *)pyApp getSelectedDupeRefPath];
if (_refPath != nil)
[_refPath autorelease];
_refPath = [refPath retain];
[NSThread detachNewThreadSelector:@selector(loadImageAsync:) toTarget:self withObject:refPath];
NSString *dupePath = [(PyDupeGuru *)py getSelectedDupePath];
NSString *dupePath = [(PyDupeGuru *)pyApp getSelectedDupePath];
if (_dupePath != nil)
[_dupePath autorelease];
_dupePath = [dupePath retain];
@ -59,12 +59,6 @@ http://www.hardcoded.net/licenses/hs_license
}
/* Notifications */
- (void)duplicateSelectionChanged:(NSNotification *)aNotification
{
_needsRefresh = YES;
[super duplicateSelectionChanged:aNotification];
}
- (void)imageLoaded:(NSNotification *)aNotification
{
NSString *imagePath = [[aNotification userInfo] valueForKey:@"imagePath"];
@ -80,4 +74,11 @@ http://www.hardcoded.net/licenses/hs_license
[dupeProgressIndicator stopAnimation:nil];
}
}
/* Python --> Cocoa */
- (void)refresh
{
_needsRefresh = YES;
[super refresh];
}
@end

View File

@ -4,7 +4,7 @@
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/hs_license
from core.app_cocoa_inter import PyDupeGuruBase
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
from core_pe import app_cocoa as app_pe_cocoa
# Fix py2app imports which chokes on relative imports

View File

@ -77,6 +77,7 @@
CE031753109B345200517EE6 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MainMenu.xib; path = ../../base/xib/MainMenu.xib; sourceTree = "<group>"; };
CE073F5409CAE1A3005C1D2F /* dupeguru_pe_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_pe_help; path = ../../help_pe/dupeguru_pe_help; sourceTree = SOURCE_ROOT; };
CE15C8A70ADEB8B50061D4A5 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyDetailsPanel.h; path = ../base/PyDetailsPanel.h; sourceTree = SOURCE_ROOT; };
CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; };
CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
CE381C9A09914ADF003581CE /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = ResultWindow.m; sourceTree = SOURCE_ROOT; };
@ -303,6 +304,7 @@
CE80DB850FC1951C0086DCA6 /* DirectoryPanel.h */,
CE80DB860FC1951C0086DCA6 /* DirectoryPanel.m */,
CE80DB870FC1951C0086DCA6 /* PyDupeGuru.h */,
CE18126F111C9D5100E49FCE /* PyDetailsPanel.h */,
CE80DB880FC1951C0086DCA6 /* ResultWindow.h */,
CE80DB890FC1951C0086DCA6 /* ResultWindow.m */,
);

View File

@ -7,10 +7,12 @@ http://www.hardcoded.net/licenses/hs_license
*/
#import <Cocoa/Cocoa.h>
#import "Utils.h"
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[Utils setPluginName:@"dg_cocoa"];
NSString *pluginPath = [[NSBundle mainBundle]
pathForResource:@"dg_cocoa"
ofType:@"plugin"];

View File

@ -2,17 +2,17 @@
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
<data>
<int key="IBDocument.SystemTarget">1050</int>
<string key="IBDocument.SystemVersion">10B504</string>
<string key="IBDocument.SystemVersion">10C540</string>
<string key="IBDocument.InterfaceBuilderVersion">740</string>
<string key="IBDocument.AppKitVersion">1038.2</string>
<string key="IBDocument.HIToolboxVersion">437.00</string>
<string key="IBDocument.AppKitVersion">1038.25</string>
<string key="IBDocument.HIToolboxVersion">458.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="NS.object.0">740</string>
</object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
<integer value="18"/>
<integer value="7"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@ -487,6 +487,14 @@
</object>
<int key="connectionID">31</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">dataSource</string>
<reference key="source" ref="1061505056"/>
<reference key="destination" ref="449950342"/>
</object>
<int key="connectionID">43</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@ -768,7 +776,6 @@
<string>6.ImportedFromIB2</string>
<string>7.IBPluginDependency</string>
<string>7.ImportedFromIB2</string>
<string>8.CustomClassName</string>
<string>8.IBPluginDependency</string>
<string>8.ImportedFromIB2</string>
<string>9.IBPluginDependency</string>
@ -825,7 +832,6 @@
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>TableView</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@ -848,11 +854,23 @@
</object>
</object>
<nil key="sourceID"/>
<int key="maxID">42</int>
<int key="maxID">43</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBPartialClassDescription">
<string key="className">DetailsPanel</string>
<string key="superclassName">NSWindowController</string>
<object class="NSMutableDictionary" key="outlets">
<string key="NS.key.0">detailsTable</string>
<string key="NS.object.0">NSTableView</string>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">../base/DetailsPanel.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">DetailsPanelPE</string>
<string key="superclassName">DetailsPanel</string>
@ -890,18 +908,6 @@
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">DetailsPanel</string>
<string key="superclassName">NSWindowController</string>
<object class="NSMutableDictionary" key="outlets">
<string key="NS.key.0">detailsTable</string>
<string key="NS.object.0">TableView</string>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">dgbase/DetailsPanel.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">FirstResponder</string>
<string key="superclassName">NSObject</string>
@ -910,34 +916,6 @@
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">PyApp</string>
<string key="superclassName">PyRegistrable</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">cocoalib/PyApp.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">TableView</string>
<string key="superclassName">NSTableView</string>
<object class="NSMutableDictionary" key="outlets">
<string key="NS.key.0">py</string>
<string key="NS.object.0">PyApp</string>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">cocoalib/Table.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">TableView</string>
<string key="superclassName">NSTableView</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
</object>
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
<bool key="EncodedWithXMLCoder">YES</bool>

View File

@ -7,7 +7,7 @@
from hsutil.cocoa import signature
from core import scanner
from core.app_cocoa_inter import PyDupeGuruBase
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
from core_se.app_cocoa import DupeGuru
# Fix py2app imports with chokes on relative imports

View File

@ -76,6 +76,7 @@
CE3A46F9109B212E002ABFD5 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MainMenu.xib; path = ../base/xib/MainMenu.xib; sourceTree = "<group>"; };
CE45579A0AE3BC2B005A9546 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = /Library/Frameworks/Sparkle.framework; sourceTree = "<absolute>"; };
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; };
CEAC6810109B0B7E00B43C85 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Preferences.xib; path = xib/Preferences.xib; sourceTree = "<group>"; };
CEDD92D60FDD01640031C7B7 /* BRSingleLineFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BRSingleLineFormatter.h; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.h; sourceTree = SOURCE_ROOT; };
CEDD92D70FDD01640031C7B7 /* BRSingleLineFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BRSingleLineFormatter.m; path = ../../cocoalib/brsinglelineformatter/BRSingleLineFormatter.m; sourceTree = SOURCE_ROOT; };
@ -289,6 +290,7 @@
CEFC7FB40FC951A700CD5728 /* DirectoryPanel.h */,
CEFC7FB50FC951A700CD5728 /* DirectoryPanel.m */,
CEFC7FB60FC951A700CD5728 /* PyDupeGuru.h */,
CE6E7407111C997500C350E3 /* PyDetailsPanel.h */,
CEFC7FB70FC951A700CD5728 /* ResultWindow.h */,
CEFC7FB80FC951A700CD5728 /* ResultWindow.m */,
);

View File

@ -7,10 +7,12 @@ http://www.hardcoded.net/licenses/hs_license
*/
#import <Cocoa/Cocoa.h>
#import "Utils.h"
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[Utils setPluginName:@"dg_cocoa"];
NSString *pluginPath = [[NSBundle mainBundle]
pathForResource:@"dg_cocoa"
ofType:@"plugin"];

View File

@ -15,6 +15,7 @@ from hsutil.cocoa.objcmin import (NSNotificationCenter, NSUserDefaults,
NSSearchPathForDirectoriesInDomains, NSApplicationSupportDirectory, NSUserDomainMask,
NSWorkspace, NSWorkspaceRecycleOperation)
from hsutil.misc import stripnone
from hsutil.notify import Broadcaster
from hsutil.reg import RegistrationRequired
from . import app, fs
@ -36,8 +37,9 @@ def demo_method(method):
return wrapper
class DupeGuru(app.DupeGuru):
class DupeGuru(app.DupeGuru, Broadcaster):
def __init__(self, data_module, appdata_subdir, appid):
Broadcaster.__init__(self)
LOGGING_LEVEL = logging.DEBUG if NSUserDefaults.standardUserDefaults().boolForKey_('debug') else logging.WARNING
logging.basicConfig(level=LOGGING_LEVEL, format='%(levelname)s %(message)s')
logging.debug('started in debug mode')
@ -48,7 +50,7 @@ class DupeGuru(app.DupeGuru):
self.progress = cocoa.ThreadedJobPerformer()
self.display_delta_values = False
self.selected_dupes = []
self.RefreshDetailsTable(None,None)
self.RefreshDetailsWithSelected()
#--- Override
@staticmethod
@ -91,14 +93,6 @@ class DupeGuru(app.DupeGuru):
curr_path = self.directories.get_subfolders(curr_path)[current_index]
return self.get_folder_path(node_path[1:], curr_path)
def RefreshDetailsTable(self,dupe,group):
l1 = self._get_display_info(dupe, group, False)
# we don't want the two sides of the table to display the stats for the same file
ref = group.ref if group is not None and group.ref is not dupe else None
l2 = self._get_display_info(ref, group, False)
names = [c['display'] for c in self.data.COLUMNS]
self.details_table = zip(names,l1,l2)
#---Public
def AddSelectedToIgnoreList(self):
for dupe in self.selected_dupes:
@ -120,13 +114,7 @@ class DupeGuru(app.DupeGuru):
self.scanner.ignore_list.Filter(lambda f,s:op.exists(f) and op.exists(s))
def RefreshDetailsWithSelected(self):
if self.selected_dupes:
self.RefreshDetailsTable(
self.selected_dupes[0],
self.results.get_group_of_duplicate(self.selected_dupes[0])
)
else:
self.RefreshDetailsTable(None,None)
self.notify('details_table_changed')
def RemoveDirectory(self,index):
try:
@ -153,7 +141,8 @@ class DupeGuru(app.DupeGuru):
NSWorkspace.sharedWorkspace().selectFile_inFileViewerRootedAtPath_(path,'')
def start_scanning(self):
self.RefreshDetailsTable(None, None)
self.selected_dupes = []
self.RefreshDetailsWithSelected()
try:
app.DupeGuru.start_scanning(self)
return 0
@ -291,15 +280,3 @@ class DupeGuru(app.DupeGuru):
else:
return 0
def GetTableViewCount(self, tag):
if self.progress._job_running:
return 0
return len(self.details_table)
def GetTableViewMarkedIndexes(self,tag):
return []
def GetTableViewValues(self,tag,row):
return self.details_table[row]

View File

@ -14,6 +14,8 @@ from hsutil.cocoa.objcmin import NSObject
from hsutil.cocoa import signature
from hsutil.reg import InvalidCodeError
from .gui.details_panel import DetailsPanel
# Fix py2app's problems on relative imports
from core import app, app_cocoa, data, directories, engine, export, ignore, results, fs, scanner
from hsutil import conflict
@ -200,3 +202,23 @@ class PyDupeGuruBase(PyApp):
def setRegisteredCode_andEmail_(self, code, email):
self.app.set_registration(code, email)
class PyDetailsPanel(NSObject):
def initWithCocoa_pyParent_(self, cocoa, pyparent):
super(PyDetailsPanel, self).init()
self.cocoa = cocoa
self.py = DetailsPanel(self, pyparent.app)
return self
@signature('i@:')
def numberOfRows(self):
return self.py.row_count()
@signature('@@:@i')
def valueForColumn_row_(self, column, row):
return self.py.row(row)[int(column)]
# python --> cocoa
def refresh(self):
self.cocoa.refresh()

0
core/gui/__init__.py Normal file
View File

47
core/gui/details_panel.py Normal file
View File

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Created By: Virgil Dupras
# Created On: 2010-02-05
# Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
#
# This software is licensed under the "HS" License as described in the "LICENSE" file,
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/hs_license
from hsutil.notify import Listener
class DetailsPanel(Listener):
def __init__(self, view, app):
Listener.__init__(self, app)
self.app = app
self.view = view
self._table = []
self._refresh()
self.connect()
#--- Private
def _refresh(self):
if self.app.selected_dupes:
dupe = self.app.selected_dupes[0]
group = self.app.results.get_group_of_duplicate(dupe)
else:
dupe = None
group = None
l1 = self.app._get_display_info(dupe, group, False)
# we don't want the two sides of the table to display the stats for the same file
ref = group.ref if group is not None and group.ref is not dupe else None
l2 = self.app._get_display_info(ref, group, False)
names = [c['display'] for c in self.app.data.COLUMNS]
self._table = zip(names, l1, l2)
#--- Public
def row_count(self):
return len(self._table)
def row(self, row_index):
return self._table[row_index]
#--- Event Handlers
def details_table_changed(self):
self._refresh()
self.view.refresh()

View File

@ -26,6 +26,7 @@ try:
except ImportError:
from nose.plugins.skip import SkipTest
raise SkipTest("These tests can only be run on OS X")
from ..gui.details_panel import DetailsPanel
class DupeGuru(DupeGuruBase):
def __init__(self):
@ -38,9 +39,28 @@ def r2np(rows):
#Transforms a list of rows [1,2,3] into a list of node paths [[1],[2],[3]]
return [[i] for i in rows]
class CallLogger(object):
"""This is a dummy object that logs all calls made to it.
It is used to simulate the GUI layer.
"""
def __init__(self):
self.calls = []
def __getattr__(self, func_name):
def func(*args, **kw):
self.calls.append(func_name)
return func
def clear_calls(self):
del self.calls[:]
class TCDupeGuru(TestCase):
def setUp(self):
self.app = DupeGuru()
self.dpanel_gui = CallLogger()
self.dpanel = DetailsPanel(self.dpanel_gui, self.app)
self.objects,self.matches,self.groups = GetTestGroups()
self.app.results.groups = self.groups
tmppath = self.tmppath()
@ -48,6 +68,44 @@ class TCDupeGuru(TestCase):
io.mkdir(tmppath + 'bar')
self.app.directories.add_path(tmppath)
def check_gui_calls(self, gui, expected, verify_order=False):
"""Checks that the expected calls have been made to 'gui', then clears the log.
`expected` is an iterable of strings representing method names.
If `verify_order` is True, the order of the calls matters.
"""
if verify_order:
eq_(gui.calls, expected)
else:
eq_(set(gui.calls), set(expected))
gui.clear_calls()
def check_gui_calls_partial(self, gui, expected=None, not_expected=None):
"""Checks that the expected calls have been made to 'gui', then clears the log.
`expected` is an iterable of strings representing method names. Order doesn't matter.
Moreover, if calls have been made that are not in expected, no failure occur.
`not_expected` can be used for a more explicit check (rather than calling `check_gui_calls`
with an empty `expected`) to assert that calls have *not* been made.
"""
calls = set(gui.calls)
if expected is not None:
expected = set(expected)
not_called = expected - calls
assert not not_called, u"These calls haven't been made: {0}".format(not_called)
if not_expected is not None:
not_expected = set(not_expected)
called = not_expected & calls
assert not called, u"These calls shouldn't have been made: {0}".format(called)
gui.clear_calls()
def clear_gui_calls(self):
for attr in dir(self):
if attr.endswith('_gui'):
gui = getattr(self, attr)
if hasattr(gui, 'calls'): # We might have test methods ending with '_gui'
gui.clear_calls()
def test_GetObjects(self):
app = self.app
objects = self.objects
@ -194,24 +252,14 @@ class TCDupeGuru(TestCase):
self.assert_(app.results.is_marked(objects[4]))
def test_refreshDetailsWithSelected(self):
def mock_refresh(dupe,group):
self.called = True
if self.app.selected_dupes:
self.assert_(dupe is self.app.selected_dupes[0])
self.assert_(group is self.app.results.get_group_of_duplicate(dupe))
else:
self.assert_(dupe is None)
self.assert_(group is None)
self.app.RefreshDetailsTable = mock_refresh
self.called = False
self.app.SelectPowerMarkerNodePaths(r2np([0,2]))
self.app.RefreshDetailsWithSelected()
self.assert_(self.called)
self.called = False
eq_(self.dpanel.row(0), ('Filename', 'bar bleh', 'foo bar'))
self.check_gui_calls(self.dpanel_gui, ['refresh'])
self.app.SelectPowerMarkerNodePaths([])
self.app.RefreshDetailsWithSelected()
self.assert_(self.called)
eq_(self.dpanel.row(0), ('Filename', '---', '---'))
self.check_gui_calls(self.dpanel_gui, ['refresh'])
def test_makeSelectedReference(self):
app = self.app

View File

@ -31,7 +31,7 @@ def GetDisplayInfo(dupe, group, delta):
dupe.name,
format_path(dupe.path),
format_size(size, 0, 1, False),
dupe.extension,
dupe.extension if hasattr(dupe, 'extension') else '---',
]
def GetDupeSortKey(dupe, get_group, key, delta):