From 17349a5e426dc7acf1216a3767a22f69974cbca0 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Mon, 14 Apr 2008 21:45:08 -0400 Subject: Initial commit. --- Liaison/ApplicationController.h | 21 + Liaison/ApplicationController.m | 90 ++ Liaison/ClientManager.h | 43 + Liaison/ClientManager.m | 488 +++++++ Liaison/CopyController.h | 27 + Liaison/CopyController.m | 133 ++ Liaison/DownloadManager.h | 36 + Liaison/DownloadManager.m | 69 + Liaison/DownloadStatusView.h | 27 + Liaison/DownloadStatusView.m | 118 ++ Liaison/Downloader.h | 63 + Liaison/Downloader.m | 429 +++++++ .../CopyPanel.nib/Download_StopPressed.tiff | 0 Liaison/English.lproj/CopyPanel.nib/classes.nib | 38 + Liaison/English.lproj/CopyPanel.nib/info.nib | 22 + Liaison/English.lproj/CopyPanel.nib/objects.nib | Bin 0 -> 2593 bytes Liaison/English.lproj/InfoPlist.strings | Bin 0 -> 726 bytes Liaison/English.lproj/Liaison Help/Liaison.html | 18 + .../English.lproj/Liaison Help/images/Liaison.png | Bin 0 -> 28966 bytes .../Liaison Help/images/Liaison_small.png | Bin 0 -> 944 bytes Liaison/English.lproj/Liaison Help/pages/bugs.html | 25 + Liaison/English.lproj/Liaison Help/pages/faq.html | 80 ++ .../English.lproj/Liaison Help/pages/glossary.html | 29 + .../Liaison Help/pages/navigation.html | 20 + .../English.lproj/Liaison Help/pages/overview.html | 36 + Liaison/English.lproj/Liaison Help/pages/todo.html | 25 + .../English.lproj/Liaison Help/pages/whatsnew.html | 167 +++ Liaison/English.lproj/Liaison.scriptTerminology | 22 + .../LoadPanel.nib/JavaCompiling.plist | 8 + .../_LoadPanel_EOArchive_English.java | 143 +++ Liaison/English.lproj/LoadPanel.nib/classes.nib | 28 + Liaison/English.lproj/LoadPanel.nib/info.nib | 16 + Liaison/English.lproj/LoadPanel.nib/objects.nib | Bin 0 -> 1356 bytes Liaison/English.lproj/MainMenu.nib/classes.nib | 123 ++ Liaison/English.lproj/MainMenu.nib/info.nib | 36 + .../English.lproj/MainMenu.nib/keyedobjects.nib | Bin 0 -> 32761 bytes .../PreferencesWindow.nib/classes.nib | 50 + .../English.lproj/PreferencesWindow.nib/info.nib | 38 + .../PreferencesWindow.nib/objects.nib | Bin 0 -> 2516 bytes Liaison/English.lproj/WindowElements.strings | 37 + Liaison/FileTableDelegate.h | 106 ++ Liaison/FileTableDelegate.m | 1345 ++++++++++++++++++++ Liaison/FindController.h | 43 + Liaison/FindController.m | 154 +++ Liaison/FlippedBox.h | 6 + Liaison/FlippedBox.m | 8 + Liaison/Group.h | 52 + Liaison/Group.m | 321 +++++ Liaison/GroupTableDelegate.h | 43 + Liaison/GroupTableDelegate.m | 611 +++++++++ Liaison/ImageAndTextCell.h | 20 + Liaison/ImageAndTextCell.m | 156 +++ Liaison/Images/Add.tiff | Bin 0 -> 2898 bytes Liaison/Images/AddFiles.tiff | Bin 0 -> 4378 bytes Liaison/Images/AddGroup.tiff | Bin 0 -> 4378 bytes Liaison/Images/Download_Reload.tiff | Bin 0 -> 438 bytes Liaison/Images/Download_ReloadPressed.tiff | Bin 0 -> 446 bytes Liaison/Images/Download_Reveal.tiff | Bin 0 -> 452 bytes Liaison/Images/Download_RevealPressed.tiff | Bin 0 -> 458 bytes Liaison/Images/Download_Stop.tiff | Bin 0 -> 438 bytes Liaison/Images/Download_StopPressed.tiff | Bin 0 -> 444 bytes Liaison/Images/File Icons/Liaison.icns | Bin 0 -> 58750 bytes Liaison/Images/LeftSearchCap.tiff | Bin 0 -> 1116 bytes Liaison/Images/NormalMailbox.tiff | Bin 0 -> 1218 bytes Liaison/Images/NormalMailboxLarge.tiff | Bin 0 -> 7446 bytes Liaison/Images/RemoveFiles.tiff | Bin 0 -> 4378 bytes Liaison/Images/RemoveGroup.tiff | Bin 0 -> 4378 bytes Liaison/Images/RightSearchCap.tiff | Bin 0 -> 3728 bytes Liaison/Images/SortAscending.gif | Bin 0 -> 62 bytes Liaison/Images/SortDescending.gif | Bin 0 -> 62 bytes Liaison/Images/TrashMailbox.tiff | Bin 0 -> 1218 bytes Liaison/Images/TrashMailboxLarge.tiff | Bin 0 -> 4290 bytes Liaison/Images/delete.tiff | Bin 0 -> 4290 bytes Liaison/Images/info (italic).tiff | Bin 0 -> 17384 bytes Liaison/Images/info (plain).tiff | Bin 0 -> 3684 bytes Liaison/Images/quickpick.tiff | Bin 0 -> 1218 bytes Liaison/Images/rendezvous.tiff | Bin 0 -> 782 bytes Liaison/Images/reveal.tiff | Bin 0 -> 21332 bytes Liaison/Info.plist | 74 ++ Liaison/InspectorController.h | 24 + Liaison/InspectorController.m | 250 ++++ Liaison/LiDataTranslator.h | 27 + Liaison/LiDataTranslator.m | 120 ++ Liaison/LiScrolLView.h | 10 + Liaison/LiScrolLView.m | 34 + Liaison/LiTableView.h | 2 + Liaison/LiTableView.m | 166 +++ Liaison/Liaison.h | 30 + Liaison/Liaison.scriptSuite | 32 + Liaison/Liaison.xcodeproj/project.pbxproj | 936 ++++++++++++++ Liaison/LoadPanelController.h | 25 + Liaison/LoadPanelController.m | 74 ++ Liaison/NIBConnector.h | 30 + Liaison/NIBConnector.m | 66 + Liaison/NSException+LiDebugging.m | 23 + Liaison/NSFileHandleExtensions.h | 14 + Liaison/NSFileHandleExtensions.m | 24 + Liaison/PluginManager.h | 27 + Liaison/PluginManager.m | 116 ++ Liaison/PreferencesController.h | 22 + Liaison/PreferencesController.m | 154 +++ Liaison/RenIPC.h | 21 + Liaison/RenManager.h | 48 + Liaison/RenManager.m | 357 ++++++ Liaison/ServerManager.h | 41 + Liaison/ServerManager.m | 428 +++++++ Liaison/ViewOptionsController.h | 24 + Liaison/ViewOptionsController.m | 158 +++ Liaison/WindowController.h | 17 + Liaison/WindowController.m | 306 +++++ Liaison/WriterThread.h | 38 + Liaison/WriterThread.m | 211 +++ Liaison/WriterThreadPool.h | 17 + Liaison/WriterThreadPool.m | 95 ++ Liaison/chef.lproj/CopyPanel.nib/classes.nib | 38 + Liaison/chef.lproj/CopyPanel.nib/info.nib | 17 + Liaison/chef.lproj/CopyPanel.nib/objects.nib | Bin 0 -> 2733 bytes Liaison/chef.lproj/InfoPlist.strings | Bin 0 -> 732 bytes .../chef.lproj/LoadPanel.nib/JavaCompiling.plist | 8 + .../LoadPanel.nib/_LoadPanel_EOArchive_chef.java | 143 +++ Liaison/chef.lproj/LoadPanel.nib/classes.nib | 28 + Liaison/chef.lproj/LoadPanel.nib/info.nib | 16 + Liaison/chef.lproj/LoadPanel.nib/objects.nib | Bin 0 -> 1362 bytes Liaison/chef.lproj/MainMenu.nib/classes.nib | 120 ++ Liaison/chef.lproj/MainMenu.nib/info.nib | 38 + Liaison/chef.lproj/MainMenu.nib/objects.nib | Bin 0 -> 16364 bytes .../chef.lproj/PreferencesWindow.nib/classes.nib | 50 + Liaison/chef.lproj/PreferencesWindow.nib/info.nib | 38 + .../chef.lproj/PreferencesWindow.nib/objects.nib | Bin 0 -> 2533 bytes Liaison/chef.lproj/WindowElements.strings | 37 + Liaison/main.m | 12 + 131 files changed, 9956 insertions(+) create mode 100644 Liaison/ApplicationController.h create mode 100644 Liaison/ApplicationController.m create mode 100644 Liaison/ClientManager.h create mode 100644 Liaison/ClientManager.m create mode 100644 Liaison/CopyController.h create mode 100644 Liaison/CopyController.m create mode 100644 Liaison/DownloadManager.h create mode 100644 Liaison/DownloadManager.m create mode 100644 Liaison/DownloadStatusView.h create mode 100644 Liaison/DownloadStatusView.m create mode 100644 Liaison/Downloader.h create mode 100644 Liaison/Downloader.m create mode 100644 Liaison/English.lproj/CopyPanel.nib/Download_StopPressed.tiff create mode 100644 Liaison/English.lproj/CopyPanel.nib/classes.nib create mode 100644 Liaison/English.lproj/CopyPanel.nib/info.nib create mode 100644 Liaison/English.lproj/CopyPanel.nib/objects.nib create mode 100644 Liaison/English.lproj/InfoPlist.strings create mode 100644 Liaison/English.lproj/Liaison Help/Liaison.html create mode 100644 Liaison/English.lproj/Liaison Help/images/Liaison.png create mode 100644 Liaison/English.lproj/Liaison Help/images/Liaison_small.png create mode 100644 Liaison/English.lproj/Liaison Help/pages/bugs.html create mode 100644 Liaison/English.lproj/Liaison Help/pages/faq.html create mode 100644 Liaison/English.lproj/Liaison Help/pages/glossary.html create mode 100644 Liaison/English.lproj/Liaison Help/pages/navigation.html create mode 100644 Liaison/English.lproj/Liaison Help/pages/overview.html create mode 100644 Liaison/English.lproj/Liaison Help/pages/todo.html create mode 100644 Liaison/English.lproj/Liaison Help/pages/whatsnew.html create mode 100644 Liaison/English.lproj/Liaison.scriptTerminology create mode 100644 Liaison/English.lproj/LoadPanel.nib/JavaCompiling.plist create mode 100644 Liaison/English.lproj/LoadPanel.nib/_LoadPanel_EOArchive_English.java create mode 100644 Liaison/English.lproj/LoadPanel.nib/classes.nib create mode 100644 Liaison/English.lproj/LoadPanel.nib/info.nib create mode 100644 Liaison/English.lproj/LoadPanel.nib/objects.nib create mode 100644 Liaison/English.lproj/MainMenu.nib/classes.nib create mode 100644 Liaison/English.lproj/MainMenu.nib/info.nib create mode 100644 Liaison/English.lproj/MainMenu.nib/keyedobjects.nib create mode 100644 Liaison/English.lproj/PreferencesWindow.nib/classes.nib create mode 100644 Liaison/English.lproj/PreferencesWindow.nib/info.nib create mode 100644 Liaison/English.lproj/PreferencesWindow.nib/objects.nib create mode 100644 Liaison/English.lproj/WindowElements.strings create mode 100644 Liaison/FileTableDelegate.h create mode 100644 Liaison/FileTableDelegate.m create mode 100644 Liaison/FindController.h create mode 100644 Liaison/FindController.m create mode 100644 Liaison/FlippedBox.h create mode 100644 Liaison/FlippedBox.m create mode 100644 Liaison/Group.h create mode 100644 Liaison/Group.m create mode 100644 Liaison/GroupTableDelegate.h create mode 100644 Liaison/GroupTableDelegate.m create mode 100644 Liaison/ImageAndTextCell.h create mode 100644 Liaison/ImageAndTextCell.m create mode 100644 Liaison/Images/Add.tiff create mode 100644 Liaison/Images/AddFiles.tiff create mode 100644 Liaison/Images/AddGroup.tiff create mode 100644 Liaison/Images/Download_Reload.tiff create mode 100644 Liaison/Images/Download_ReloadPressed.tiff create mode 100644 Liaison/Images/Download_Reveal.tiff create mode 100644 Liaison/Images/Download_RevealPressed.tiff create mode 100644 Liaison/Images/Download_Stop.tiff create mode 100644 Liaison/Images/Download_StopPressed.tiff create mode 100644 Liaison/Images/File Icons/Liaison.icns create mode 100644 Liaison/Images/LeftSearchCap.tiff create mode 100644 Liaison/Images/NormalMailbox.tiff create mode 100644 Liaison/Images/NormalMailboxLarge.tiff create mode 100644 Liaison/Images/RemoveFiles.tiff create mode 100644 Liaison/Images/RemoveGroup.tiff create mode 100644 Liaison/Images/RightSearchCap.tiff create mode 100644 Liaison/Images/SortAscending.gif create mode 100644 Liaison/Images/SortDescending.gif create mode 100644 Liaison/Images/TrashMailbox.tiff create mode 100644 Liaison/Images/TrashMailboxLarge.tiff create mode 100644 Liaison/Images/delete.tiff create mode 100644 Liaison/Images/info (italic).tiff create mode 100644 Liaison/Images/info (plain).tiff create mode 100644 Liaison/Images/quickpick.tiff create mode 100644 Liaison/Images/rendezvous.tiff create mode 100644 Liaison/Images/reveal.tiff create mode 100644 Liaison/Info.plist create mode 100644 Liaison/InspectorController.h create mode 100644 Liaison/InspectorController.m create mode 100644 Liaison/LiDataTranslator.h create mode 100644 Liaison/LiDataTranslator.m create mode 100644 Liaison/LiScrolLView.h create mode 100644 Liaison/LiScrolLView.m create mode 100644 Liaison/LiTableView.h create mode 100644 Liaison/LiTableView.m create mode 100644 Liaison/Liaison.h create mode 100644 Liaison/Liaison.scriptSuite create mode 100644 Liaison/Liaison.xcodeproj/project.pbxproj create mode 100644 Liaison/LoadPanelController.h create mode 100644 Liaison/LoadPanelController.m create mode 100644 Liaison/NIBConnector.h create mode 100644 Liaison/NIBConnector.m create mode 100644 Liaison/NSException+LiDebugging.m create mode 100644 Liaison/NSFileHandleExtensions.h create mode 100644 Liaison/NSFileHandleExtensions.m create mode 100644 Liaison/PluginManager.h create mode 100644 Liaison/PluginManager.m create mode 100644 Liaison/PreferencesController.h create mode 100644 Liaison/PreferencesController.m create mode 100644 Liaison/RenIPC.h create mode 100644 Liaison/RenManager.h create mode 100644 Liaison/RenManager.m create mode 100644 Liaison/ServerManager.h create mode 100644 Liaison/ServerManager.m create mode 100644 Liaison/ViewOptionsController.h create mode 100644 Liaison/ViewOptionsController.m create mode 100644 Liaison/WindowController.h create mode 100644 Liaison/WindowController.m create mode 100644 Liaison/WriterThread.h create mode 100644 Liaison/WriterThread.m create mode 100644 Liaison/WriterThreadPool.h create mode 100644 Liaison/WriterThreadPool.m create mode 100644 Liaison/chef.lproj/CopyPanel.nib/classes.nib create mode 100644 Liaison/chef.lproj/CopyPanel.nib/info.nib create mode 100644 Liaison/chef.lproj/CopyPanel.nib/objects.nib create mode 100644 Liaison/chef.lproj/InfoPlist.strings create mode 100644 Liaison/chef.lproj/LoadPanel.nib/JavaCompiling.plist create mode 100644 Liaison/chef.lproj/LoadPanel.nib/_LoadPanel_EOArchive_chef.java create mode 100644 Liaison/chef.lproj/LoadPanel.nib/classes.nib create mode 100644 Liaison/chef.lproj/LoadPanel.nib/info.nib create mode 100644 Liaison/chef.lproj/LoadPanel.nib/objects.nib create mode 100644 Liaison/chef.lproj/MainMenu.nib/classes.nib create mode 100644 Liaison/chef.lproj/MainMenu.nib/info.nib create mode 100644 Liaison/chef.lproj/MainMenu.nib/objects.nib create mode 100644 Liaison/chef.lproj/PreferencesWindow.nib/classes.nib create mode 100644 Liaison/chef.lproj/PreferencesWindow.nib/info.nib create mode 100644 Liaison/chef.lproj/PreferencesWindow.nib/objects.nib create mode 100644 Liaison/chef.lproj/WindowElements.strings create mode 100644 Liaison/main.m (limited to 'Liaison') diff --git a/Liaison/ApplicationController.h b/Liaison/ApplicationController.h new file mode 100644 index 0000000..b89cc19 --- /dev/null +++ b/Liaison/ApplicationController.h @@ -0,0 +1,21 @@ +/* ApplicationController */ + +@protocol LiFileStoreDelegate; + +@interface ApplicationController : NSObject +{ + IBOutlet NSWindow *inspectorWindow; + IBOutlet NSWindow *mainWindow; + + LiFileStore *theFileStore; +} ++ (ApplicationController *)theApp; + +- (IBAction)openHomepage:(id)sender; + +- (IBAction)showInspectorWindow:(id)sender; +- (IBAction)showMainWindow:(id)sender; +@property (retain) NSWindow *mainWindow; +@property (retain) NSWindow *inspectorWindow; +@property (retain) LiFileStore *theFileStore; +@end \ No newline at end of file diff --git a/Liaison/ApplicationController.m b/Liaison/ApplicationController.m new file mode 100644 index 0000000..edff915 --- /dev/null +++ b/Liaison/ApplicationController.m @@ -0,0 +1,90 @@ +#import "ApplicationController.h" + +#import "FileTableDelegate.h" +#import "Group.h" +#import "GroupTableDelegate.h" +#import "NIBConnector.h" +#import "PluginManager.h" +#import "RenManager.h" +#import "WindowController.h" + +@implementation ApplicationController +// Set in awakeFromNib. +static ApplicationController *theApp = nil; + ++ (ApplicationController *)theApp; +{ + return theApp; +} + +- (void)awakeFromNib +{ + theApp = self; +} + +- (void)applicationDidFinishLaunching: (NSNotification *)aNotification +{ + RenManager *renManager; + NSArray *fileStorePlugins; + NSString *libraryPath; + id plugin; + + // Make sure the library exists. + libraryPath = [[[Preferences sharedPreferences] libraryPath] stringByDeletingLastPathComponent]; + [[NSFileManager defaultManager] createDirectoryAtPath: libraryPath + attributes: nil]; + + // Load the plugins. + fileStorePlugins = [[PluginManager defaultManager] fileStorePlugins]; + plugin = [fileStorePlugins objectAtIndex: 0]; // XXX + [plugin initFileStore]; + + renManager = [RenManager sharedManager]; + [renManager setFileStore: [plugin fileStore]]; + [renManager startup]; +} + +- (BOOL)application: (NSApplication *)anApp openFile: (NSString *)aPath +{ + [[NSWorkspace sharedWorkspace] openFile: aPath]; + [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL: [NSURL fileURLWithPath: aPath]]; + return YES; +} + +- (IBAction)openHomepage:(id)sender +{ + [[NSWorkspace sharedWorkspace] openURL: + [NSURL URLWithString: @"http://www.kublai.com/~shmit/software/Liaison/"]]; +} + + +- (IBAction)showInspectorWindow:(id)sender +{ + [inspectorWindow makeKeyAndOrderFront: self]; +} + +- (IBAction)showMainWindow:(id)sender +{ + [mainWindow makeKeyAndOrderFront: self]; +} +@synthesize theFileStore; +@synthesize inspectorWindow; +@synthesize mainWindow; +@end + +@implementation ApplicationController (AppleScript) +- (BOOL)application: (NSApplication *)anApp + delegateHandlesKey: (NSString *)aKey +{ + [LiLog logAsDebug: @"[ApplicationController application:delegateHandlesKey: %@", aKey]; + if ([aKey isEqualToString: @"orderedFileStores"]) + return YES; + return NO; +} + +- (NSArray *)orderedFileStores +{ + [LiLog logAsDebug: @"[ApplicationController orderedFileStores]"]; + return [LiFileStore allFileStores]; +} +@end \ No newline at end of file diff --git a/Liaison/ClientManager.h b/Liaison/ClientManager.h new file mode 100644 index 0000000..206c3a5 --- /dev/null +++ b/Liaison/ClientManager.h @@ -0,0 +1,43 @@ +// +// ClientManager.h +// Liaison +// +// Created by Brian Cully on Sun Feb 16 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@interface ClientManager : NSObject { + LiFileStore *theFileStore; + NSFileHandle *theFile; + NSString *theHostname; + + NSFileHandle *theCopyFile; + + NSMutableData *theBuffer; +} + +- (id)initWithFile: (NSFileHandle *)aFile + andFileStore: (LiFileStore *)aFileStore; + +- (void)startup; +- (void)shutdown; +- (void)sendHostname; +@property (retain,getter=copyFile) NSFileHandle *theCopyFile; +@property (retain,getter=buffer) NSMutableData *theBuffer; +@property (retain,getter=fileStore) LiFileStore *theFileStore; +@property (retain,getter=file) NSFileHandle *theFile; +@property (retain,getter=hostname) NSString *theHostname; +@end + +@interface ClientManager (Accessors) +- (NSMutableData *)buffer; +- (void)setBuffer: (NSMutableData *)aBuffer; +- (NSFileHandle *)copyFile; +- (void)setCopyFile: (NSFileHandle *)aFile; +- (NSFileHandle *)file; +- (void)setFile: (NSFileHandle *)aFile; +- (NSString *)hostname; +- (void)setHostname: (NSString *)aHostname; +- (LiFileStore *)fileStore; +- (void)setFileStore: (LiFileStore *)aFileStore; +@end diff --git a/Liaison/ClientManager.m b/Liaison/ClientManager.m new file mode 100644 index 0000000..2190bc4 --- /dev/null +++ b/Liaison/ClientManager.m @@ -0,0 +1,488 @@ +// +// ClientManager.m +// Liaison +// +// Created by Brian Cully on Sun Feb 16 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// +#import "ClientManager.h" + +#import "LiDataTranslator.h" +#import "RenIPC.h" + +#import +#import +#import +#import + +@interface ClientManager (Downloader) +- (void)startCopyOfFileHandle: (LiFileHandle *)aFileHandle; +@end + +@implementation ClientManager +- (BOOL)sendCommand: (NSDictionary *)aCmd +{ + NSData *cmdData; + + cmdData = [aCmd encodedData]; + if (cmdData != nil) { + [(NSFileHandleExtensions *)[self file] writeDataInBackground: cmdData]; + return YES; + } else + return NO; +} + +- (NSDictionary *)processData: (NSData *)someData +{ + NSDictionary *msg; + + [[self buffer] appendData: someData]; + msg = [NSDictionary dictionaryWithEncodedData: [self buffer]]; + if (msg != nil) + [self setBuffer: [NSMutableData data]]; + return msg; +} + +- (id)initWithFile: (NSFileHandle *)aFile + andFileStore: (LiFileStore *)aFileStore +{ + NSNotificationCenter *defaultCenter; + + self = [super init]; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(remoteClosed:) + name: FileHandleClosed + object: aFile]; + + [self setFile: aFile]; + [self setFileStore: aFileStore]; + [self setCopyFile: nil]; + [self setBuffer: [NSMutableData data]]; + + return self; +} + +- (void)dealloc +{ + NSNotificationCenter *defaultCenter; + + [LiLog logAsDebug: @"[ClientManager dealloc]"]; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self]; + + [self setFile: nil]; + [self setFileStore: nil]; + [self setCopyFile: nil]; + [self setBuffer: nil]; + + [super dealloc]; +} + +- (void)startup +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(doHandshake:) + name: NSFileHandleReadCompletionNotification + object: [self file]]; + [[self file] readInBackgroundAndNotify]; +} + +- (BOOL)filePassesFilter: (LiFileHandle *)aFileHandle + withCustomAttributes: (NSDictionary *)someAttrs +{ + NSArray *groups; + + if ([aFileHandle url] == nil || [[aFileHandle url] isFileURL] == NO) + return NO; + + groups = [someAttrs objectForKey: LiGroupsAttribute]; + if (groups != nil) { + return [groups count] > 0; + } else { + return [[aFileHandle groups] count] > 0; + } +} + +- (BOOL)filePassesFilter: (LiFileHandle *)aFileHandle +{ + return [self filePassesFilter: aFileHandle + withCustomAttributes: nil]; +} + +- (NSMutableDictionary *)filteredAttributesForAttributes: + (NSDictionary *)someAttrs +{ + NSMutableDictionary *filteredAttributes; + + [LiLog indentDebugLog]; + filteredAttributes = [NSMutableDictionary dictionaryWithDictionary: someAttrs]; + [filteredAttributes setObject: [NSNumber numberWithBool: NO] + forKey: LiIsEditableAttribute]; + [filteredAttributes removeObjectForKey: LiDirectoryAttribute]; + [filteredAttributes removeObjectForKey: LiApplicationAttribute]; + [filteredAttributes removeObjectForKey: @"LiAliasAttribute"]; + + [LiLog unindentDebugLog]; + + return filteredAttributes; +} + +- (NSMutableDictionary *)filteredAttributesForFileHandle: + (LiFileHandle *)aFileHandle +{ + return [self filteredAttributesForAttributes: [[aFileHandle fileStore] attributesForFileHandle: aFileHandle]]; +} + +- (void)sendFileList: (NSArray *)aFileList +{ + LiFileHandle *file; + NSMutableArray *filteredChanges; + + [LiLog logAsDebug: @"Filtering file list."]; + filteredChanges = [[NSMutableArray alloc] init]; + for (file in aFileList) { + if ([self filePassesFilter: file]) { + NSDictionary *fileAttrs; + + fileAttrs = [self filteredAttributesForFileHandle: file]; + [filteredChanges addObject: fileAttrs]; + } + } + [LiLog logAsDebug: @"Done filtering file list."]; + + if ([filteredChanges count] > 0) { + NSDictionary *tmpDict; + + [LiLog logAsDebug: @"Creating command dictionary."]; + tmpDict = [NSDictionary dictionaryWithObjects: + [NSArray arrayWithObjects: RenFilesAddedKey, filteredChanges, nil] + forKeys: + [NSArray arrayWithObjects: @"type", @"arg", nil]]; + [LiLog logAsDebug: @"Done creating command dictionary."]; + [self sendCommand: tmpDict]; + } +} + +- (void)sendDeleteList: (NSArray *)aFileList +{ + NSDictionary *fileInfo; + NSMutableArray *deleteList; + + deleteList = [NSMutableArray array]; + for (fileInfo in aFileList) { + LiFileHandle *file; + NSDictionary *oldAttributes; + + file = [fileInfo objectForKey: LiFileHandleAttribute]; + oldAttributes = [fileInfo objectForKey: LiFileOldAttributes]; + if ([self filePassesFilter: file + withCustomAttributes: oldAttributes]) { + [deleteList addObject: [file fileID]]; + } + } + + if ([deleteList count] > 0) { + NSDictionary *tmpDict; + + tmpDict = [NSDictionary dictionaryWithObjects: + [NSArray arrayWithObjects: RenFilesRemovedKey, deleteList, nil] + forKeys: + [NSArray arrayWithObjects: @"type", @"arg", nil]]; + [self sendCommand: tmpDict]; + } +} + +- (void)sendChangeList: (NSArray *)aFileList +{ + NSDictionary *changeDict, *fileInfo; + NSMutableArray *changeList, *addList, *deleteList; + + changeList = [NSMutableArray array]; + addList = [NSMutableArray array]; + deleteList = [NSMutableArray array]; + for (fileInfo in aFileList) { + LiFileHandle *file; + NSDictionary *oldAttributes; + + file = [fileInfo objectForKey: LiFileHandleAttribute]; + oldAttributes = [fileInfo objectForKey: LiFileOldAttributes]; + if ([self filePassesFilter: file + withCustomAttributes: oldAttributes]) { + NSDictionary *fileAttrs; + + if ([self filePassesFilter: file]) { + NSEnumerator *attrEnum; + NSMutableDictionary *filtAttrs; + NSString *attr; + + filtAttrs = [[NSMutableDictionary alloc] init]; + fileAttrs = [self filteredAttributesForAttributes: oldAttributes]; + attrEnum = [oldAttributes keyEnumerator]; + while ((attr = [attrEnum nextObject]) != nil) { + [filtAttrs setObject: [file valueForAttribute: attr] + forKey: attr]; + } + [filtAttrs setObject: [file fileID] + forKey: LiFileHandleAttribute]; + [changeList addObject: filtAttrs]; + [filtAttrs release]; + } else + [deleteList addObject: + [NSDictionary dictionaryWithObjects: + [NSArray arrayWithObjects: file, oldAttributes, nil] + forKeys: + [NSArray arrayWithObjects: LiFileHandleAttribute, LiFileOldAttributes, nil]]]; + } else if ([self filePassesFilter: file]) + [addList addObject: file]; + } + [self sendDeleteList: deleteList]; + [self sendFileList: addList]; + + if ([changeList count] > 0) { + changeDict = [NSDictionary dictionaryWithObjects: + [NSArray arrayWithObjects: RenFilesChangedKey, changeList, nil] + forKeys: + [NSArray arrayWithObjects: @"type", @"arg", nil]]; + [self sendCommand: changeDict]; + } +} + +/* + * Figure out what type of connection this is, and dispatch appropriately. + */ +- (void)doHandshake: (NSNotification *)aNotification +{ + NSData *data; + NSDictionary *clientMsg; + NSFileHandle *remoteSocket; + NSNotificationCenter *defaultCenter; + + remoteSocket = [aNotification object]; + defaultCenter = [NSNotificationCenter defaultCenter]; + + data = [[aNotification userInfo] objectForKey: + NSFileHandleNotificationDataItem]; + + clientMsg = [self processData: data]; + if (clientMsg != nil) { + NSString *clientType; + + clientType = [clientMsg objectForKey: @"type"]; + if ([clientType isEqualToString: @"browser"]) { + [defaultCenter removeObserver: self + name: NSFileHandleReadCompletionNotification + object: [self file]]; + [self sendFileList: [[self fileStore] allFileHandles]]; + + [defaultCenter addObserver: self + selector: @selector(respondToFileChanged:) + name: LiFileChangedNotification + object: [self fileStore]]; + } else if ([clientType isEqualToString: @"download"]) { + LiFileHandle *tmpFile; + id handle; + + handle = [clientMsg objectForKey: LiFileHandleAttribute]; + tmpFile = [[[LiFileHandle alloc] init] autorelease]; + [tmpFile setFileStore: [self fileStore]]; + [tmpFile setFileID: handle]; + if ([self filePassesFilter: tmpFile]) { + [defaultCenter removeObserver: self + name: NSFileHandleReadCompletionNotification + object: [self file]]; + + [self startCopyOfFileHandle: tmpFile]; + } else { + [LiLog logAsWarning: @"attempt to access non-shared file: %@.", [tmpFile url]]; + [self shutdown]; + return; + } + } + } + + [remoteSocket readInBackgroundAndNotify]; +} + +- (void)shutdown +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter postNotificationName: CLIENTMANAGERDEATHNOTIFICATION + object: self + userInfo: nil]; +} + +- (void)sendHostname +{ + NSDictionary *tmpDict; + + tmpDict = [NSDictionary dictionaryWithObjects: + [NSArray arrayWithObjects: RenHostnameKey, [self hostname], nil] + forKeys: + [NSArray arrayWithObjects: @"type", @"arg", nil]]; + [self sendCommand: tmpDict]; +} + +- (void)respondToFileChanged: (NSNotification *)aNotification +{ + NSDictionary *fileDict; + + fileDict = [aNotification userInfo]; + if ([fileDict objectForKey: LiFilesAdded] != nil) { + [self sendFileList: [fileDict objectForKey: LiFilesAdded]]; + } + if ([fileDict objectForKey: LiFilesChanged]) { + [self sendChangeList: [fileDict objectForKey: LiFilesChanged]]; + } + if ([fileDict objectForKey: LiFilesRemoved]) { + [self sendDeleteList: [fileDict objectForKey: LiFilesRemoved]]; + } +} + +- (void)remoteClosed: (NSNotification *)aNotification +{ + [self shutdown]; +} +@synthesize theFile; +@synthesize theFileStore; +@synthesize theHostname; +@synthesize theBuffer; +@synthesize theCopyFile; +@end + +@implementation ClientManager (Accessors) +- (NSMutableData *)buffer +{ + return theBuffer; +} + +- (void)setBuffer: (NSMutableData *)aBuffer +{ + [aBuffer retain]; + [theBuffer release]; + theBuffer = aBuffer; +} + +- (NSFileHandle *)copyFile +{ + return theCopyFile; +} + +- (void)setCopyFile: (NSFileHandle *)aFile +{ + [aFile retain]; + [theCopyFile release]; + theCopyFile = aFile; +} + +- (NSFileHandle *)file +{ + return theFile; +} + +- (void)setFile: (NSFileHandle *)aFile +{ + [aFile retain]; + [theFile release]; + theFile = aFile; +} + +- (NSString *)hostname +{ + return theHostname; +} + +- (void)setHostname: (NSString *)aHostname +{ + [aHostname retain]; + [theHostname release]; + theHostname = aHostname; +} + +- (LiFileStore *)fileStore +{ + return theFileStore; +} + +- (void)setFileStore: (LiFileStore *)aFileStore +{ + [aFileStore retain]; + [theFileStore release]; + theFileStore = aFileStore; +} +@end + +@implementation ClientManager (Downloader) +#define XMITBUFFLEN 1400 + +- (void)readyToWrite: (NSNotification *)aNotification +{ + NSData *fileData; + NSFileHandle *remoteSocket; + + remoteSocket = [aNotification object]; + if (remoteSocket == nil) + remoteSocket = [self file]; + + fileData = [[self copyFile] readDataOfLength: XMITBUFFLEN]; + if ([fileData length] < XMITBUFFLEN) { + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self + name: FileHandleWriteComplete + object: remoteSocket]; + [defaultCenter addObserver: self + selector: @selector(finishedCopying:) + name: FileHandleWriteComplete + object: remoteSocket]; + } + + [(NSFileHandleExtensions *)remoteSocket writeDataInBackground: fileData]; +} + +- (void)startCopyOfFileHandle: (LiFileHandle *)aFileHandle +{ + NSNotificationCenter *defaultCenter; + NSURL *fileURL; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(readyToWrite:) + name: FileHandleWriteComplete + object: [self file]]; + + fileURL = [aFileHandle url]; + if (fileURL != nil && [fileURL isFileURL]) { + [self setCopyFile: + [NSFileHandle fileHandleForReadingAtPath: [fileURL path]]]; + } + [self readyToWrite: nil]; +} + +- (void)finishedCopying: (NSNotification *)aNotification +{ + NSFileHandle *remoteSocket; + NSNotificationCenter *defaultCenter; + + remoteSocket = [aNotification object]; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self + name: FileHandleWriteComplete + object: remoteSocket]; + [defaultCenter removeObserver: self + name: NSFileHandleReadCompletionNotification + object: remoteSocket]; + + [self setCopyFile: nil]; + [self shutdown]; +} +@end \ No newline at end of file diff --git a/Liaison/CopyController.h b/Liaison/CopyController.h new file mode 100644 index 0000000..e12a6e0 --- /dev/null +++ b/Liaison/CopyController.h @@ -0,0 +1,27 @@ +/* CopyController */ + +@class DownloadStatusView; + +@interface CopyController : NSObject +{ + IBOutlet NSWindow *theWindow; + IBOutlet DownloadStatusView *theTemplate; + IBOutlet NSBox *theContentBox; + IBOutlet NSScrollView *theScrollView; + + BOOL theWindowIsShowing; + + NSMutableDictionary *theDownloads; +} + +- (void)showWindow; +- (void)hideWindow; + +- (DownloadStatusView *)statusViewForFileHandle: (LiFileHandle *)aFile; +@property (retain) NSScrollView *theScrollView; +@property (retain) DownloadStatusView *theTemplate; +@property (retain) NSBox *theContentBox; +@property (retain) NSWindow *theWindow; +@property BOOL theWindowIsShowing; +@property (retain) NSMutableDictionary *theDownloads; +@end diff --git a/Liaison/CopyController.m b/Liaison/CopyController.m new file mode 100644 index 0000000..079e65a --- /dev/null +++ b/Liaison/CopyController.m @@ -0,0 +1,133 @@ +#import "CopyController.h" + +#import "DownloadStatusView.h" + +@implementation CopyController +- (id)init +{ + self = [super init]; + + theDownloads = [[NSMutableDictionary alloc] init]; + theWindowIsShowing = NO; + + return self; +} + +- (void)dealloc +{ + [theDownloads release]; + + [super dealloc]; +} + +- (void)awakeFromNib +{ + [theContentBox setFrame: NSMakeRect(0.0, 0.0, 0.0, 0.0)]; +} + +- (BOOL)windowShouldClose:(id)sender +{ + theWindowIsShowing = NO; + + return YES; +} + +- (NSRect)windowWillUseStandardFrame: (NSWindow *)aWindow + defaultFrame: (NSRect)defaultFrame +{ + NSRect stdFrame; + NSSize smallSize, boxSize; + + defaultFrame.origin.y += 64; + defaultFrame.size.height -= 64; + + stdFrame = [NSWindow contentRectForFrameRect: [aWindow frame] + styleMask: [aWindow styleMask]]; + + boxSize = [theContentBox bounds].size; + smallSize.width = MIN(defaultFrame.size.width, boxSize.width); + smallSize.height = MIN(defaultFrame.size.height, boxSize.height); + + // XXX + stdFrame.size.height = MAX(smallSize.height, 100.0); + stdFrame.size.width = MAX(smallSize.width, 220.0); + stdFrame = [NSWindow frameRectForContentRect: stdFrame + styleMask: [aWindow styleMask]]; + + return stdFrame; +} + +- (void)showWindow +{ + if (theWindowIsShowing == NO) { + [theWindow makeKeyAndOrderFront: self]; + theWindowIsShowing = YES; + } +} + +- (void)hideWindow +{ + if (theWindowIsShowing) { + [theWindow close]; + theWindowIsShowing = NO; + } +} + +- (void)addDownloadView: (NSView *)aView +{ + NSRect viewFrame; + NSSize contentSize, viewSize, boxSize; + + viewSize = [aView bounds].size; + boxSize = [theContentBox bounds].size; + contentSize.width = MAX(viewSize.width, boxSize.width); + contentSize.height = boxSize.height + viewSize.height; + [theContentBox setFrameSize: contentSize]; + + viewFrame.size = viewSize; + viewFrame.origin = NSMakePoint(0.0, boxSize.height); + [aView setFrame: viewFrame]; + + [[theScrollView contentView] addSubview: aView]; + //viewFrame.origin.y *= -1; + [aView scrollRectToVisible: viewFrame]; +} + +- (DownloadStatusView *)newDownloadView +{ + DownloadStatusView *tmpView; + NSData *viewData; + + viewData = [NSKeyedArchiver archivedDataWithRootObject: theTemplate]; + tmpView = [NSKeyedUnarchiver unarchiveObjectWithData: viewData]; + + return tmpView; +} + +- (DownloadStatusView *)statusViewForFileHandle: (LiFileHandle *)aFile; +{ + NSString *viewKey; + DownloadStatusView *downloadView; + + viewKey = [NSString stringWithFormat: @"%@:%@", [aFile storeID], [aFile fileID]]; + + downloadView = [theDownloads objectForKey: viewKey]; + if (downloadView == nil) { + downloadView = [self newDownloadView]; + [downloadView setFileHandle: aFile]; + + [theDownloads setObject: downloadView forKey: viewKey]; + + [self addDownloadView: downloadView]; + } + + [self showWindow]; + return downloadView; +} +@synthesize theTemplate; +@synthesize theWindowIsShowing; +@synthesize theScrollView; +@synthesize theContentBox; +@synthesize theWindow; +@synthesize theDownloads; +@end diff --git a/Liaison/DownloadManager.h b/Liaison/DownloadManager.h new file mode 100644 index 0000000..42f9ee6 --- /dev/null +++ b/Liaison/DownloadManager.h @@ -0,0 +1,36 @@ +// +// DownloadManager.h +// Liaison +// +// Created by Brian Cully on Wed Jun 04 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@interface DownloadManager : NSObject +{ + NSMutableDictionary *theDownloads; +} +// The default download manager. ++ (DownloadManager *)defaultManager; + +// Tell the manager to download a file. When it's finished, it'll +// call the selector, if it's there, and if context is supplied, +// it'll be passed on to the selector as well. +// The selector should have the following signature: +// - (void)fileHandleFinishedDownloading: (LiFileHandle *)aFileHandle +// context: (void *)someContext +// errorString: (NSString *)anError +// If errorString isn't nil, then the file did not finish downloading +// properly, either by user action or by some other error. +- (void)downloadFileHandle: (LiFileHandle *)aFileHandle + fromSocket: (NSFileHandle *)aSocket + target: (id)anObject + didFinishSelector: (SEL)aSelector + withContext: (void *)someContext; +@property (retain,getter=downloads) NSMutableDictionary *theDownloads; +@end + +@interface DownloadManager (Accessors) +- (NSMutableDictionary *)downloads; +- (void)setDownloads: (NSMutableDictionary *)someDownloads; +@end \ No newline at end of file diff --git a/Liaison/DownloadManager.m b/Liaison/DownloadManager.m new file mode 100644 index 0000000..5fb1085 --- /dev/null +++ b/Liaison/DownloadManager.m @@ -0,0 +1,69 @@ +// +// DownloadManager.m +// Liaison +// +// Created by Brian Cully on Wed Jun 04 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "DownloadManager.h" +#import "Downloader.h" + +@implementation DownloadManager +DownloadManager *defaultManager = nil; + ++ (DownloadManager *)defaultManager +{ + if (defaultManager == nil) + defaultManager = [[DownloadManager alloc] init]; + return defaultManager; +} + +- (id)init +{ + self = [super init]; + + [self setDownloads: [NSMutableDictionary dictionary]]; + + return self; +} + +- (void)dealloc +{ + [self setDownloads: nil]; + + [super dealloc]; +} + +- (void)downloadFileHandle: (LiFileHandle *)aFileHandle + fromSocket: (NSFileHandle *)aSocket + target: (id)anObject + didFinishSelector: (SEL)aSelector + withContext: (void *)someContext +{ + Downloader *downloader; + + downloader = [[Downloader alloc] initWithSocket: aSocket + target: anObject + selector: aSelector + context: someContext]; + [[self downloads] setObject: downloader forKey: aFileHandle]; + [downloader downloadFileHandle: aFileHandle]; + [downloader release]; +} +@synthesize theDownloads; +@end + +@implementation DownloadManager (Accessors) +- (NSMutableDictionary *)downloads +{ + return theDownloads; +} + +- (void)setDownloads: (NSMutableDictionary *)someDownloads +{ + [someDownloads retain]; + [theDownloads release]; + theDownloads = someDownloads; +} +@end \ No newline at end of file diff --git a/Liaison/DownloadStatusView.h b/Liaison/DownloadStatusView.h new file mode 100644 index 0000000..7d7865a --- /dev/null +++ b/Liaison/DownloadStatusView.h @@ -0,0 +1,27 @@ +/* DownloadStatusView */ + +@interface DownloadStatusView : NSView +{ + IBOutlet NSTextField *theFilename; + IBOutlet NSImageView *theIcon; + IBOutlet NSProgressIndicator *theProgressBar; + IBOutlet NSButton *theButton; + + LiFileHandle *theFileHandle; +} +- (LiFileHandle *)fileHandle; +- (void)setFileHandle: (LiFileHandle *)aFileHandle; + +- (void)setIcon: (NSImage *)anIcon; +- (void)setFilename: (NSString *)aFilename; +- (void)setProgress: (double)aProgress; +- (void)setButtonImage: (NSImage *)anImage; +- (void)setButtonAltImage: (NSImage *)anImage; +- (void)setButtonTarget: (id)aTarget; +- (void)setButtonAction: (SEL)anAction; +@property (retain,getter=fileHandle) LiFileHandle *theFileHandle; +@property (retain) NSTextField *theFilename; +@property (retain) NSButton *theButton; +@property (retain) NSImageView *theIcon; +@property (retain) NSProgressIndicator *theProgressBar; +@end diff --git a/Liaison/DownloadStatusView.m b/Liaison/DownloadStatusView.m new file mode 100644 index 0000000..2844904 --- /dev/null +++ b/Liaison/DownloadStatusView.m @@ -0,0 +1,118 @@ +#import "DownloadStatusView.h" + +@implementation DownloadStatusView (NSCoding) +- (id)initWithCoder: (NSCoder *)aCoder +{ + self = [super initWithCoder: aCoder]; + + if ([aCoder allowsKeyedCoding]) { + theFilename = [aCoder decodeObjectForKey: @"filename"]; + theIcon = [aCoder decodeObjectForKey: @"icon"]; + theProgressBar = [aCoder decodeObjectForKey: @"progressBar"]; + theButton = [aCoder decodeObjectForKey: @"button"]; + } else { + theFilename = [aCoder decodeObject]; + theIcon = [aCoder decodeObject]; + theProgressBar = [aCoder decodeObject]; + theButton = [aCoder decodeObject]; + } + + [theFilename retain]; + [theIcon retain]; + [theProgressBar retain]; + [theButton retain]; + + return self; +} + +- (void)encodeWithCoder: (NSCoder *)aCoder +{ + if ([aCoder allowsKeyedCoding]) { + [aCoder encodeObject: theFilename forKey: @"filename"]; + [aCoder encodeObject: theIcon forKey: @"icon"]; + [aCoder encodeObject: theProgressBar forKey: @"progressBar"]; + [aCoder encodeObject: theButton forKey: @"button"]; + } else { + [aCoder encodeObject: theFilename]; + [aCoder encodeObject: theIcon]; + [aCoder encodeObject: theProgressBar]; + [aCoder encodeObject: theButton]; + } + [super encodeWithCoder: aCoder]; +} +@end + +@implementation DownloadStatusView (NSViewSubclass) +- (id)initWithFrame:(NSRect)frameRect +{ + self = [super initWithFrame:frameRect]; + + return self; +} + +- (void)drawRect:(NSRect)rect +{ + [super drawRect: rect]; +} +@end + +@implementation DownloadStatusView +- (void)dealloc +{ + [self setFileHandle: nil]; + + [super dealloc]; +} + +- (LiFileHandle *)fileHandle +{ + return theFileHandle; +} + +- (void)setFileHandle: (LiFileHandle *)aFileHandle +{ + [aFileHandle retain]; + [theFileHandle release]; + theFileHandle = aFileHandle; +} + +- (void)setIcon: (NSImage *)anIcon +{ + [theIcon setImage: anIcon]; +} + +- (void)setFilename: (NSString *)aFilename +{ + [theFilename setStringValue: aFilename]; +} + +- (void)setProgress: (double)aProgress +{ + [theProgressBar setDoubleValue: aProgress]; +} + +- (void)setButtonImage: (NSImage *)anImage +{ + [theButton setImage: anImage]; +} + +- (void)setButtonAltImage: (NSImage *)anImage +{ + [theButton setAlternateImage: anImage]; +} + +- (void)setButtonTarget: (id)aTarget +{ + [theButton setTarget: aTarget]; +} + +- (void)setButtonAction: (SEL)anAction +{ + [theButton setAction: anAction]; +} +@synthesize theFileHandle; +@synthesize theButton; +@synthesize theProgressBar; +@synthesize theIcon; +@synthesize theFilename; +@end diff --git a/Liaison/Downloader.h b/Liaison/Downloader.h new file mode 100644 index 0000000..efe7f97 --- /dev/null +++ b/Liaison/Downloader.h @@ -0,0 +1,63 @@ +// +// Downloader.h +// Liaison +// +// Created by Brian Cully on Fri Jun 06 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@class DownloadStatusView; + +@interface Downloader : NSObject +{ + DownloadStatusView *theStatusView; + LiFileHandle *theRemoteFileHandle; + NSDictionary *theFileAttributes; + NSFileHandle *theSocket; + NSFileHandle *theLocalFile; + NSString *theLocalFilePath; + void *theCallbackContext; + id theCallbackTarget; + SEL theCallbackSelector; + + unsigned long theBytesInLocalFile; +} +- (id)initWithSocket: (NSFileHandle *)aSocket + target: (id)aTarget + selector: (SEL)aSelector + context: (void *)someContext; + +- (void)downloadFileHandle: (LiFileHandle *)aFileHandle; +@property (retain,getter=localFilePath) NSString *theLocalFilePath; +@property (getter=callbackContext,setter=setCallbackContext:) void *theCallbackContext; +@property (retain,getter=statusView) DownloadStatusView *theStatusView; +@property (getter=callbackSelector,setter=setCallbackSelector:) SEL theCallbackSelector; +@property (retain,getter=socket) NSFileHandle *theSocket; +@property (retain,getter=callbackTarget) id theCallbackTarget; +@property (retain,getter=fileAttributes) NSDictionary *theFileAttributes; +@property (retain,getter=remoteFileHandle) LiFileHandle *theRemoteFileHandle; +@property (retain,getter=localFile) NSFileHandle *theLocalFile; +@property unsigned long theBytesInLocalFile; +@end + +@interface Downloader (Accessors) +- (LiFileHandle *)remoteFileHandle; +- (void)setRemoteFileHandle: (LiFileHandle *)aFileHandle; +- (NSFileHandle *)localFile; +- (void)setLocalFile: (NSFileHandle *)aFile; +- (NSString *)localFilePath; +- (void)setLocalFilePath: (NSString *)aPath; +- (DownloadStatusView *)statusView; +- (void)setStatusView: (DownloadStatusView *)aStatusView; + +- (NSDictionary *)fileAttributes; +- (void)setFileAttributes: (NSDictionary *)someAttributes; +- (NSFileHandle *)socket; +- (void)setSocket: (NSFileHandle *)aSocket; +- (id)callbackTarget; +- (void)setCallbackTarget: (id)aTarget; +- (SEL)callbackSelector; +- (void)setCallbackSelector: (SEL)aSelector; +- (void *)callbackContext; +- (void)setCallbackContext: (void *)someContext; +@end \ No newline at end of file diff --git a/Liaison/Downloader.m b/Liaison/Downloader.m new file mode 100644 index 0000000..d60d865 --- /dev/null +++ b/Liaison/Downloader.m @@ -0,0 +1,429 @@ +// +// Downloader.m +// Liaison +// +// Created by Brian Cully on Fri Jun 06 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "Downloader.h" + +#import "CopyController.h" +#import "DownloadStatusView.h" +#import "LiDataTranslator.h" +#import "NIBConnector.h" + +@interface Downloader (NetworkStuff) +- (void)errorMsg: (NSString *)aMsg; +- (void)beginCopy; +- (void)shutdown; +@end + +@implementation Downloader +- (id)initWithSocket: (NSFileHandle *)aSocket + target: (id)aTarget + selector: (SEL)aSelector + context: (void *)someContext +{ + self = [super init]; + + [self setSocket: aSocket]; + [self setCallbackTarget: aTarget]; + [self setCallbackSelector: aSelector]; + [self setCallbackContext: someContext]; + + return self; +} + +- (void)dealloc +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self]; + + [self setSocket: nil]; + [self setCallbackTarget: nil]; + [self setCallbackSelector: nil]; + [self setCallbackContext: nil]; + + [super dealloc]; +} + +- (void)downloadFileHandle: (LiFileHandle *)aFileHandle +{ + NSFileManager *defaultManager; + NSString *filename, *type, *path; + + filename = [aFileHandle filename]; + type = [aFileHandle type]; + if ([type length] > 0) + filename = [filename stringByAppendingPathExtension: type]; + + path = [[[Preferences sharedPreferences] downloadDirectory] + stringByAppendingPathComponent: filename]; + [self setLocalFilePath: path]; + + defaultManager = [NSFileManager defaultManager]; + if ([defaultManager createFileAtPath: path + contents: nil + attributes: nil]) { + NSFileHandle *tmpFile; + + tmpFile = [NSFileHandle fileHandleForWritingAtPath: path]; + [self setLocalFile: tmpFile]; + + [self setRemoteFileHandle: aFileHandle]; + [self setFileAttributes: + [[aFileHandle fileStore] attributesForFileHandle: aFileHandle]]; + [self beginCopy]; + } else { + NSString *errorMsg; + + errorMsg = [NSString stringWithFormat: + @"couldn't write to %@: %@", path, strerror(errno)]; + [self errorMsg: errorMsg]; + } +} +@synthesize theBytesInLocalFile; +@synthesize theLocalFilePath; +@synthesize theFileAttributes; +@synthesize theRemoteFileHandle; +@synthesize theLocalFile; +@synthesize theStatusView; +@synthesize theCallbackTarget; +@synthesize theSocket; +@end + +@implementation Downloader (Accessors) +- (LiFileHandle *)remoteFileHandle +{ + return theRemoteFileHandle; +} + +- (void)setRemoteFileHandle: (LiFileHandle *)aFileHandle +{ + [aFileHandle retain]; + [theRemoteFileHandle release]; + theRemoteFileHandle = aFileHandle; +} + +- (NSFileHandle *)localFile +{ + return theLocalFile; +} + +- (void)setLocalFile: (NSFileHandle *)aFile +{ + [aFile retain]; + [theLocalFile release]; + theLocalFile = aFile; +} + +- (NSString *)localFilePath +{ + return theLocalFilePath; +} + +- (void)setLocalFilePath: (NSString *)aPath +{ + [aPath retain]; + [theLocalFilePath release]; + theLocalFilePath = aPath; +} + +- (DownloadStatusView *)statusView +{ + return theStatusView; +} + +- (void)setStatusView: (DownloadStatusView *)aStatusView +{ + [aStatusView retain]; + [theStatusView release]; + theStatusView = aStatusView; +} + +- (NSDictionary *)fileAttributes +{ + return theFileAttributes; +} + +- (void)setFileAttributes: (NSDictionary *)someAttributes +{ + [someAttributes retain]; + [theFileAttributes release]; + theFileAttributes = someAttributes; +} + +- (NSFileHandle *)socket +{ + return theSocket; +} + +- (void)setSocket: (NSFileHandle *)aSocket +{ + [aSocket retain]; + [theSocket release]; + theSocket = aSocket; +} + +- (id)callbackTarget +{ + return theCallbackTarget; +} + +- (void)setCallbackTarget: (id)aTarget +{ + [aTarget retain]; + [theCallbackTarget release]; + theCallbackTarget = aTarget; +} + +- (SEL)callbackSelector +{ + return theCallbackSelector; +} + +- (void)setCallbackSelector: (SEL)aSelector +{ + theCallbackSelector = aSelector; +} + +- (void *)callbackContext +{ + return theCallbackContext; +} + +- (void)setCallbackContext: (void *)someContext +{ + theCallbackContext = someContext; +} +@end + +@implementation Downloader (NetworkStuff) +- (NSImage *)cancelImage +{ + NSBundle *myBundle; + NSString *tmpPath; + NSImage *tmpImage; + + myBundle = [NSBundle bundleForClass: [self class]]; + tmpPath = [myBundle pathForImageResource: @"Download_Stop.tiff"]; + tmpImage = [[NSImage alloc] initWithContentsOfFile: tmpPath]; + return [tmpImage autorelease]; +} + +- (NSImage *)cancelImagePressed +{ + NSBundle *myBundle; + NSString *tmpPath; + NSImage *tmpImage; + + myBundle = [NSBundle bundleForClass: [self class]]; + tmpPath = [myBundle pathForImageResource: @"Download_StopPressed.tiff"]; + tmpImage = [[NSImage alloc] initWithContentsOfFile: tmpPath]; + return [tmpImage autorelease]; +} + +- (NSImage *)reloadImage +{ + NSBundle *myBundle; + NSString *tmpPath; + NSImage *tmpImage; + + myBundle = [NSBundle bundleForClass: [self class]]; + tmpPath = [myBundle pathForImageResource: @"Download_Reload.tiff"]; + tmpImage = [[NSImage alloc] initWithContentsOfFile: tmpPath]; + return [tmpImage autorelease]; +} + +- (NSImage *)reloadImagePressed +{ + NSBundle *myBundle; + NSString *tmpPath; + NSImage *tmpImage; + + myBundle = [NSBundle bundleForClass: [self class]]; + tmpPath = [myBundle pathForImageResource: @"Download_ReloadPressed.tiff"]; + tmpImage = [[NSImage alloc] initWithContentsOfFile: tmpPath]; + return [tmpImage autorelease]; +} + +- (NSImage *)revealImage +{ + NSBundle *myBundle; + NSString *tmpPath; + NSImage *tmpImage; + + myBundle = [NSBundle bundleForClass: [self class]]; + tmpPath = [myBundle pathForImageResource: @"Download_Reveal.tiff"]; + tmpImage = [[NSImage alloc] initWithContentsOfFile: tmpPath]; + return [tmpImage autorelease]; +} + +- (NSImage *)revealImagePressed +{ + NSBundle *myBundle; + NSString *tmpPath; + NSImage *tmpImage; + + myBundle = [NSBundle bundleForClass: [self class]]; + tmpPath = [myBundle pathForImageResource: @"Download_RevealPressed.tiff"]; + tmpImage = [[NSImage alloc] initWithContentsOfFile: tmpPath]; + return [tmpImage autorelease]; +} + +- (void)setupStatusViewForFileHandle: (LiFileHandle *)aFileHandle +{ + DownloadStatusView *statusView; + NSImage *fileIcon; + + fileIcon = [[NSWorkspace sharedWorkspace] iconForFileType: + [aFileHandle type]]; + [fileIcon setSize: NSMakeSize(32.0, 32.0)]; + + statusView = [[[NIBConnector connector] copyController] statusViewForFileHandle: aFileHandle]; + [statusView setFilename: [aFileHandle filename]]; + [statusView setIcon: fileIcon]; + [statusView setProgress: 0.0]; + [statusView setButtonImage: [self cancelImage]]; + [statusView setButtonAltImage: [self cancelImagePressed]]; + [statusView setButtonTarget: self]; + [statusView setButtonAction: @selector(cancelCopy)]; + [self setStatusView: statusView]; +} + +- (void)errorMsg: (NSString *)aMsg +{ + id target; + + [self shutdown]; + + target = [self callbackTarget]; + if (target != nil) { + SEL callbackSelector; + + callbackSelector = [self callbackSelector]; + if (callbackSelector != nil) { + IMP callback; + void *context; + + context = [self callbackContext]; + callback = [target methodForSelector: callbackSelector]; + if (callback != nil) + callback(target, callbackSelector, + [self remoteFileHandle], context, aMsg); + } + } +} + +- (BOOL)sendCommand: (NSDictionary *)aCmd +{ + NSData *cmdData; + + cmdData = [aCmd encodedData]; + if (cmdData != nil) { + [[self socket] writeData: cmdData]; + return YES; + } else + return NO; +} + +- (void)beginCopy +{ + NSDictionary *copyCmd; + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(gotCopyData:) + name: NSFileHandleReadCompletionNotification + object: [self socket]]; + + [self setupStatusViewForFileHandle: [self remoteFileHandle]]; + + copyCmd = [NSDictionary dictionaryWithObjects: + [NSArray arrayWithObjects: @"download", + [[self remoteFileHandle] fileID], nil] + forKeys: + [NSArray arrayWithObjects: @"type", + @"LiFileHandleAttribute", nil]]; + [self sendCommand: copyCmd]; + + theBytesInLocalFile = 0; + [[self socket] readInBackgroundAndNotify]; +} + +- (void)gotCopyData: (NSNotification *)aNotification +{ + NSData *fileData; + double totalLength, progress; + + fileData = [[aNotification userInfo] objectForKey: + NSFileHandleNotificationDataItem]; + + totalLength = [[[self fileAttributes] objectForKey: LiFileSizeAttribute] doubleValue]; + theBytesInLocalFile += [fileData length]; + if ([fileData length] > 0 && theBytesInLocalFile < totalLength) { + [[self localFile] writeData: fileData]; + + if (totalLength > 0) { + progress = theBytesInLocalFile / totalLength; + [[self statusView] setProgress: progress]; + } + + [[self socket] readInBackgroundAndNotify]; + } else { + DownloadStatusView *statusView; + + [self shutdown]; + + statusView = [self statusView]; + [statusView setButtonImage: [self revealImage]]; + [statusView setButtonAltImage: [self revealImagePressed]]; + [statusView setButtonTarget: self]; + [statusView setButtonAction: @selector(revealInFinder)]; + [statusView setProgress: 1.0]; + } +} + +- (void)cancelCopy +{ + DownloadStatusView *statusView; + NSFileManager *defaultManager; + + defaultManager = [NSFileManager defaultManager]; + [defaultManager removeFileAtPath: [self localFilePath] + handler: nil]; + + [self shutdown]; + + statusView = [self statusView]; + [statusView setButtonImage: [self reloadImage]]; + [statusView setButtonAltImage: [self reloadImagePressed]]; + [statusView setButtonTarget: [self remoteFileHandle]]; + [statusView setButtonAction: @selector(open)]; + [statusView setProgress: 0.0]; +} + +- (void)shutdown +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self + name: NSFileHandleReadCompletionNotification + object: [self socket]]; + + [self setLocalFile: nil]; + [self setSocket: nil]; +} + +- (void)revealInFinder +{ + if ([self localFilePath] != nil) { + [[NSWorkspace sharedWorkspace] selectFile: [self localFilePath] inFileViewerRootedAtPath: @""]; + } +} +@end \ No newline at end of file diff --git a/Liaison/English.lproj/CopyPanel.nib/Download_StopPressed.tiff b/Liaison/English.lproj/CopyPanel.nib/Download_StopPressed.tiff new file mode 100644 index 0000000..e69de29 diff --git a/Liaison/English.lproj/CopyPanel.nib/classes.nib b/Liaison/English.lproj/CopyPanel.nib/classes.nib new file mode 100644 index 0000000..67bc2f5 --- /dev/null +++ b/Liaison/English.lproj/CopyPanel.nib/classes.nib @@ -0,0 +1,38 @@ +{ + IBClasses = ( + { + CLASS = CopyController; + LANGUAGE = ObjC; + OUTLETS = { + theContentBox = NSBox; + theScrollView = NSScrollView; + theTemplate = DownloadStatusView; + theWindow = NSWindow; + }; + SUPERCLASS = NSObject; + }, + { + CLASS = DownloadStatusView; + LANGUAGE = ObjC; + OUTLETS = { + theButton = NSButton; + theFilename = NSTextField; + theIcon = NSImageView; + theProgressBar = NSProgressIndicator; + }; + SUPERCLASS = NSView; + }, + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = FlippedBox; LANGUAGE = ObjC; SUPERCLASS = NSBox; }, + { + CLASS = NIBConnector; + LANGUAGE = ObjC; + OUTLETS = { + theCopyController = CopyController; + thePreferencesController = PreferencesController; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Liaison/English.lproj/CopyPanel.nib/info.nib b/Liaison/English.lproj/CopyPanel.nib/info.nib new file mode 100644 index 0000000..cfe2a0a --- /dev/null +++ b/Liaison/English.lproj/CopyPanel.nib/info.nib @@ -0,0 +1,22 @@ + + + + + IBDocumentLocation + 112 70 356 240 0 0 1600 1178 + IBEditorPositions + + 16 + 690 764 220 82 0 0 1600 1178 + + IBFramework Version + 326.0 + IBOpenObjects + + 16 + 28 + + IBSystem Version + 7B28 + + diff --git a/Liaison/English.lproj/CopyPanel.nib/objects.nib b/Liaison/English.lproj/CopyPanel.nib/objects.nib new file mode 100644 index 0000000..ad7bd0a Binary files /dev/null and b/Liaison/English.lproj/CopyPanel.nib/objects.nib differ diff --git a/Liaison/English.lproj/InfoPlist.strings b/Liaison/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..72d0e56 Binary files /dev/null and b/Liaison/English.lproj/InfoPlist.strings differ diff --git a/Liaison/English.lproj/Liaison Help/Liaison.html b/Liaison/English.lproj/Liaison Help/Liaison.html new file mode 100644 index 0000000..9f3f483 --- /dev/null +++ b/Liaison/English.lproj/Liaison Help/Liaison.html @@ -0,0 +1,18 @@ + + + + Liaison Help + + + + + + + + + + + + + \ No newline at end of file diff --git a/Liaison/English.lproj/Liaison Help/images/Liaison.png b/Liaison/English.lproj/Liaison Help/images/Liaison.png new file mode 100644 index 0000000..e301611 Binary files /dev/null and b/Liaison/English.lproj/Liaison Help/images/Liaison.png differ diff --git a/Liaison/English.lproj/Liaison Help/images/Liaison_small.png b/Liaison/English.lproj/Liaison Help/images/Liaison_small.png new file mode 100644 index 0000000..436d6f6 Binary files /dev/null and b/Liaison/English.lproj/Liaison Help/images/Liaison_small.png differ diff --git a/Liaison/English.lproj/Liaison Help/pages/bugs.html b/Liaison/English.lproj/Liaison Help/pages/bugs.html new file mode 100644 index 0000000..d7da2a6 --- /dev/null +++ b/Liaison/English.lproj/Liaison Help/pages/bugs.html @@ -0,0 +1,25 @@ + + + + Known Bugs + + + + +

Known Bugs

+
    +
  • Help is woefully incomplete.
  • +
  • Find panel doesn't do anything.
  • +
  • Applescript support isn't very useful.
  • +
  • The "Open" and "Show in Finder" menu items don't dim properly when the file table + isn't the first responder.
  • +
  • The view options do not update based on key window.
  • +
  • It's possible to get duplicate files if you remove a file from a path, move a new + file into the same path, and then add the new file to the library. (The old file handle + now resolves to the new file, and then you add the new file again - using alias data as + the primary key should fix this, but it's still possible - perhaps alias data isn't + being updated properly when the new file is found?)
  • +
+ + diff --git a/Liaison/English.lproj/Liaison Help/pages/faq.html b/Liaison/English.lproj/Liaison Help/pages/faq.html new file mode 100644 index 0000000..a78b649 --- /dev/null +++ b/Liaison/English.lproj/Liaison Help/pages/faq.html @@ -0,0 +1,80 @@ + + + + Frequently Asked Questions + + + + +

Frequently Asked Questions

+ +

Click on a topic to the left to find out more about it, or click on a + question below to find the answer.

+ +
How do I use groups?
+
+

You can use groups to organize files + in your library. For instance, you might want to create a group for all your + image files, for all the files in a project you're working on, or to share + files with other Liaison users.

+ + + + + + + + + + + + + + + + + + + + + + + +
To create a group:
+ 1 + + Select "New group" from the File menu. +
To add files to a group:
+ 1 + + Select the list of files in the library, and drag + them to the newly created group. +
To rename a group:
+ 1 + Double-click its entry in the group list and type in a new name.
+
+ +
How do I share my files?
+
+

You can share any file in your library by putting it in a group.

+
+ +
How do I download a shared file?
+
+

Double-click on it, or drag it from Liaison to the Finder.

+
+ +
What is meta-data and how do I edit it?
+
+

Meta-data is information about the file itself, such as when it was + created, to what groups it belongs, its icon, its filename, and other + ways of referencing a file.

+ +

To edit meta-data, you can double click on a field in the file list, + or edit it via the inspector.

+
+ +

©2003 Brian Cully + + diff --git a/Liaison/English.lproj/Liaison Help/pages/glossary.html b/Liaison/English.lproj/Liaison Help/pages/glossary.html new file mode 100644 index 0000000..4753608 --- /dev/null +++ b/Liaison/English.lproj/Liaison Help/pages/glossary.html @@ -0,0 +1,29 @@ + + + + Glossary + + + + +

Glossary

+
    +
  • +
    group
    +
    Groups are lists of files that you can create to organize your file + library or to share with other Liaison users.
    +
  • +
  • +
    LAN
    +
    LAN is an acronym which means "Local Area Network," which is a computer + network that is confined to a limited geography, such as your office, your + home, or your local McDonald's™.
    +
  • +
  • +
    library
    +
    Libraries are lists of files on a computer that Liaison knows about.
    +
  • +
+ + diff --git a/Liaison/English.lproj/Liaison Help/pages/navigation.html b/Liaison/English.lproj/Liaison Help/pages/navigation.html new file mode 100644 index 0000000..51d2505 --- /dev/null +++ b/Liaison/English.lproj/Liaison Help/pages/navigation.html @@ -0,0 +1,20 @@ + + + + Navigation + + + + +
+ + + diff --git a/Liaison/English.lproj/Liaison Help/pages/overview.html b/Liaison/English.lproj/Liaison Help/pages/overview.html new file mode 100644 index 0000000..d4fbffc --- /dev/null +++ b/Liaison/English.lproj/Liaison Help/pages/overview.html @@ -0,0 +1,36 @@ + + + + Overview + + + + +

Overview

+ +

Liaison is a file browser that lets your organize all your files. Here are some of the + things you can do with Liaison.

+ +
    +
  • +

    Add files to your library. When you add files to your + library, you can open them, + edit their meta-data, and even share them with other Liaison users.

    +
  • +
  • +

    Organize your file library. Once you add files to your library, you can organize + them into groups. You can create groups to organize + files by theme, location, content, or anything else you can imagine.

    +
  • +
  • +

    Share your file library with other people. File sharing allows you to browse your + library across multiple computers on your LAN and + download them to another computer. File sharing requires a copy of Liaison on each + computer which is used to share files.

    +
  • +
+ +

If you want to learn more about any of this, click a topic on the left.

+ + diff --git a/Liaison/English.lproj/Liaison Help/pages/todo.html b/Liaison/English.lproj/Liaison Help/pages/todo.html new file mode 100644 index 0000000..d57a0bc --- /dev/null +++ b/Liaison/English.lproj/Liaison Help/pages/todo.html @@ -0,0 +1,25 @@ + + + + To Do + + + + +

To Do

+ +
    +
  • Application Wizard for first-time users.
  • +
  • Smart groups / saved searches.
  • +
  • Better preferences system. Perhaps Omni's?
  • +
  • Group level access control for sharing.
  • +
  • Password protected libraries.
  • +
  • Directory tracking.
  • +
  • Be able to send whole directories, most especially for bundles.
  • +
  • Implement file categories and browser.
  • +
  • Need better formatters for date information in the browser.
  • +
  • Group inspector.
  • +
+ + diff --git a/Liaison/English.lproj/Liaison Help/pages/whatsnew.html b/Liaison/English.lproj/Liaison Help/pages/whatsnew.html new file mode 100644 index 0000000..64d8471 --- /dev/null +++ b/Liaison/English.lproj/Liaison Help/pages/whatsnew.html @@ -0,0 +1,167 @@ + + + + What's New + + + + +

What's new

+

Since 0.4.2:

+
    +
  • Fixed a bug with the load sheet not closing properly.
  • +
  • You can now drag whole directories onto the group list or file list to add the files + in them to Liaison.
  • +
  • Drag-and-Drop of promised files works.
  • +
  • The table view no longer scrolls to the top of the list after you remove files.
  • +
  • You can drag files from Liaison to the finder now.
  • +
  • The shared inspector now updates when you make other windows key.
  • +
  • No longer cache icon information. This slows everything down a tiny bit, but saves + a huge amount of memory.
  • +
  • The icon that signifies an unlocatable file now updates automatically.
  • +
+ +

Since 0.4.1:

+
    +
  • Added help.
  • +
  • Project split up for future open source plans.
  • +
  • A lot of old code culled.
  • +
  • You can unsort your file list by clicking on the header.
  • +
  • Editing files now works consistently with the sort and search.
  • +
  • Fixed many bugs where the file selection would change unexpectedly.
  • +
  • Fixed bugs with groups being assigned incorrectly.
  • +
  • Added contextual menus to the file and group panels.
  • +
  • Fixed dimming of menus and toolbars with two exceptions: the "Open" and + "Show in Finder" menu items don't work properly when the group list is the + first responder.
  • +
+ +

Since 0.4:

+
    +
  • Many GUI fixes and enhancements.
  • +
  • Major speed improvements for loading large amounts of files at a time.
  • +
+ +

Since 0.3.3a:

+
    +
  • The file database has been ripped to shreds and rewritten from scratch. The new one + is much more extensible and faster overall.
  • +
  • Application is now prebound for faster launch times.
  • +
  • Network code has been rewritten to take advantage of the new file database, and is + much more connection friendly now for persistant connections.
  • +
  • Loading files into your library should be substantially faster. However, you cannot + load more than about one thousand at a time.
  • +
  • File selection is saved as you navigate through groups, if possible.
  • +
  • The zoom box works properly (or mostly properly) everywhere.
  • +
  • Preliminary AppleScript support has been added. It's not very useful, but it's there.
  • +
  • You are no longer able to group remote file stores within an over-all "Rendezvous" + group.
  • +
  • Some minor fixes for Panther.
  • +
  • BUG: The "Add Files to Library" menu item doesn't get properly dimmed.
  • +
+ +

What's new since 0.3.2a:

+
    +
  • Application starts again.
  • +
+ +

Since 0.3.1a:

+
    +
  • Fix date sorts.
  • +
  • Make string searches case insensitive.
  • +
  • Add a plugin architecture for the file browser and inspector.
  • +
  • Add a Find panel stub so I can work out the interface.
  • +
  • You can set the file's icon in the inspector now - simply drag an image + file (not a .icns file!) onto the file's icon in the file inspector.
  • +
  • You can copy a file's icon by dragging it from the icon in the file + inspector to a folder. Note: files are saved as TIFF documents, with one + layer per icon size (so layer 1 is 128x128, layer 2 is 32x32, layer 3 is + 16,16) -- Thanx Cocoa!
  • +
  • If a file change can't happen, a sheet is displayed.
  • +
+ +

Since 0.3a:

+
    +
  • You can set or delete HFS file creator codes via the inspector.
  • +
  • Add columns for last modified time, creation time, and file size.
  • +
  • Column sizes and order in the file list are remembered now.
  • +
  • Added a "view options" dialog box, under the view menu. You can use + this to set which columns are displayed.
  • +
  • The delete key and the "Delete" item under the "Edit" menu work now.
  • +
  • If you have an editable group selected, adding files will also add them + to the current group. Otherwise the files are just dumped in the library.
  • +
  • Fix network code. I don't know how long it's been broken, but it works + again as well as it did the last time I checked, perhaps better.
  • +
  • Display scroll bars when the group list is longer than the view.
  • +
  • When reloading a file in the download panel, don't create a new status + view, just re-use the old one.
  • +
  • If the hostname changes you can still download files properly.
  • +
+ +

Since 0.2.1a:

+
    +
  • Use aliases instead of paths as the database key. Files can now be + renamed without being lost to Liaison. +
    + WARNING: This means + you have to delete your old library. You can accomplish this by deleting the + files in ~/Library/Liaison/. You must do this for Liaison to function + properly. Hopefully this shouldn't happen again.
  • + +
  • Initialize the local group name if there's no existing library.
  • +
  • Add a little "!" icon for files that can't be located.
  • +
  • Edits in the file table and the inspector are now written to disk.
  • +
+ +

Since 0.2a:

+
    +
  • Editing a group doesn't clear the icon anymore.
  • +
  • Only draw the vertical grid; since we have alterntating row colors, we + don't need the horizontal grid.
  • +
  • File selection is saved between searches in the toolbar and sorts (from + clicking on the table header).
  • +
  • Empty groups are removed from the remote group list.
  • +
  • Add a menu item under the help menu to go to Liaison's web site.
  • +
  • Clear selection when group is changed.
  • +
+ +

Since 0.1.3a:

+
    +
  • File list is editable now. Changes still aren't written to disk.
  • +
  • Added a preference to put remote hosts under a rendezvous group, + or as a top-level group. By default, remote stores aren't displayed + under a rendezvous group.
  • +
  • File list has striped rows.
  • +
  • File extension is now relegated soley to the "type" column. The other + way just doesn't make sense.
  • +
  • "Reveal in Finder" tool bar icon.
  • +
  • Added "Get Info" under the file menu. This duplicates the "Inspector" menu + under the window menu.
  • +
+ +

Since 0.1.2a:

+
    +
  • A few new toolbar icons.
  • +
  • HFS type/creator codes are visible on remote hosts.
  • +
  • Writer threads are cleaned up properly.
  • +
  • The hooks for the Edit menu actions are in.
  • +
  • Remote group browsing works again.
  • +
+ +

Since 0.1.1a:

+
    +
  • File copying works again.
  • +
+ +

Since 0.1a:

+
    +
  • I have an icon! (However, I do not have Photoshop skillz).
  • +
  • Host name changes now update across the network. + (Actually, this needs work. I doubt a file copy will work without + restarting.)
  • +
  • Fixed a bug with the preferences always thinking the hostname had + changed.
  • +
+ + diff --git a/Liaison/English.lproj/Liaison.scriptTerminology b/Liaison/English.lproj/Liaison.scriptTerminology new file mode 100644 index 0000000..55a5291 --- /dev/null +++ b/Liaison/English.lproj/Liaison.scriptTerminology @@ -0,0 +1,22 @@ + + + + + Classes + + NSApplication + + Description + Liaison's top level scripting object. + Name + application + PluralName + applications + + + Description + Liaison classes. + Name + Liaison suite + + diff --git a/Liaison/English.lproj/LoadPanel.nib/JavaCompiling.plist b/Liaison/English.lproj/LoadPanel.nib/JavaCompiling.plist new file mode 100644 index 0000000..23e0cb0 --- /dev/null +++ b/Liaison/English.lproj/LoadPanel.nib/JavaCompiling.plist @@ -0,0 +1,8 @@ + + + + + JavaSourceSubpath + _LoadPanel_EOArchive_English.java + + diff --git a/Liaison/English.lproj/LoadPanel.nib/_LoadPanel_EOArchive_English.java b/Liaison/English.lproj/LoadPanel.nib/_LoadPanel_EOArchive_English.java new file mode 100644 index 0000000..40b378d --- /dev/null +++ b/Liaison/English.lproj/LoadPanel.nib/_LoadPanel_EOArchive_English.java @@ -0,0 +1,143 @@ +// _LoadPanel_EOArchive_English.java +// Generated by EnterpriseObjects palette at Saturday, September 06, 2003 17:02:16 America/New_York + +import com.webobjects.eoapplication.*; +import com.webobjects.eocontrol.*; +import com.webobjects.eodistribution.client.*; +import com.webobjects.eointerface.*; +import com.webobjects.eointerface.swing.*; +import com.webobjects.foundation.*; +import java.awt.*; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.table.*; +import javax.swing.text.*; + +public class _LoadPanel_EOArchive_English extends com.webobjects.eoapplication.EOArchive { + LoadPanelController _loadPanelController0; + com.webobjects.eointerface.swing.EOFrame _eoFrame0; + com.webobjects.eointerface.swing.EOTextField _nsTextField0, _nsTextField1; + com.webobjects.eointerface.swing.EOView _nsProgressIndicator0; + javax.swing.JPanel _nsView0; + + public _LoadPanel_EOArchive_English(Object owner, NSDisposableRegistry registry) { + super(owner, registry); + } + + protected void _construct() { + Object owner = _owner(); + EOArchive._ObjectInstantiationDelegate delegate = (owner instanceof EOArchive._ObjectInstantiationDelegate) ? (EOArchive._ObjectInstantiationDelegate)owner : null; + Object replacement; + + super._construct(); + + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController.thePathField")) != null)) { + _nsTextField1 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (com.webobjects.eointerface.swing.EOTextField)replacement; + _replacedObjects.setObjectForKey(replacement, "_nsTextField1"); + } else { + _nsTextField1 = (com.webobjects.eointerface.swing.EOTextField)_registered(new com.webobjects.eointerface.swing.EOTextField(), "NSTextField1"); + } + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController.theProgressBar")) != null)) { + _nsProgressIndicator0 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (com.webobjects.eointerface.swing.EOView)replacement; + _replacedObjects.setObjectForKey(replacement, "_nsProgressIndicator0"); + } else { + _nsProgressIndicator0 = (com.webobjects.eointerface.swing.EOView)_registered(new com.webobjects.eointerface.swing.EOView(), "1"); + } + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController")) != null)) { + _loadPanelController0 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (LoadPanelController)replacement; + _replacedObjects.setObjectForKey(replacement, "_loadPanelController0"); + } else { + _loadPanelController0 = (LoadPanelController)_registered(new LoadPanelController(), "LoadPanelController"); + } + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController.theStatusField")) != null)) { + _nsTextField0 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (com.webobjects.eointerface.swing.EOTextField)replacement; + _replacedObjects.setObjectForKey(replacement, "_nsTextField0"); + } else { + _nsTextField0 = (com.webobjects.eointerface.swing.EOTextField)_registered(new com.webobjects.eointerface.swing.EOTextField(), "NSTextField2"); + } + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController.theLoadPanel")) != null)) { + _eoFrame0 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (com.webobjects.eointerface.swing.EOFrame)replacement; + _replacedObjects.setObjectForKey(replacement, "_eoFrame0"); + } else { + _eoFrame0 = (com.webobjects.eointerface.swing.EOFrame)_registered(new com.webobjects.eointerface.swing.EOFrame(), "Load Panel"); + } + + _nsView0 = (JPanel)_eoFrame0.getContentPane(); + } + + protected void _awaken() { + super._awaken(); + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_owner(), _loadPanelController0, "theLoadPanelController"); + } + } + + protected void _init() { + super._init(); + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_loadPanelController0, _eoFrame0, "theLoadPanel"); + } + + if (_replacedObjects.objectForKey("_nsTextField1") == null) { + _setFontForComponent(_nsTextField1, "Lucida Grande", 11, Font.PLAIN); + _nsTextField1.setEditable(false); + _nsTextField1.setOpaque(false); + _nsTextField1.setText("Loading files\u2026"); + _nsTextField1.setHorizontalAlignment(javax.swing.JTextField.LEFT); + _nsTextField1.setSelectable(false); + _nsTextField1.setEnabled(true); + _nsTextField1.setBorder(null); + } + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_loadPanelController0, _nsTextField1, "thePathField"); + } + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_loadPanelController0, _nsProgressIndicator0, "theProgressBar"); + } + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_loadPanelController0, _nsTextField0, "theStatusField"); + } + + if (_replacedObjects.objectForKey("_nsTextField0") == null) { + _setFontForComponent(_nsTextField0, "Lucida Grande", 11, Font.PLAIN); + _nsTextField0.setEditable(false); + _nsTextField0.setOpaque(false); + _nsTextField0.setText("Getting info for:"); + _nsTextField0.setHorizontalAlignment(javax.swing.JTextField.RIGHT); + _nsTextField0.setSelectable(false); + _nsTextField0.setEnabled(true); + _nsTextField0.setBorder(null); + } + + if (!(_nsView0.getLayout() instanceof EOViewLayout)) { _nsView0.setLayout(new EOViewLayout()); } + _nsTextField0.setSize(102, 18); + _nsTextField0.setLocation(10, 10); + ((EOViewLayout)_nsView0.getLayout()).setAutosizingMask(_nsTextField0, EOViewLayout.WidthSizable | EOViewLayout.MinYMargin); + _nsView0.add(_nsTextField0); + _nsTextField1.setSize(222, 18); + _nsTextField1.setLocation(114, 10); + ((EOViewLayout)_nsView0.getLayout()).setAutosizingMask(_nsTextField1, EOViewLayout.WidthSizable | EOViewLayout.MinYMargin); + _nsView0.add(_nsTextField1); + _nsProgressIndicator0.setSize(324, 20); + _nsProgressIndicator0.setLocation(11, 36); + ((EOViewLayout)_nsView0.getLayout()).setAutosizingMask(_nsProgressIndicator0, EOViewLayout.WidthSizable | EOViewLayout.MinYMargin); + _nsView0.add(_nsProgressIndicator0); + + if (_replacedObjects.objectForKey("_eoFrame0") == null) { + _nsView0.setSize(346, 66); + _eoFrame0.setTitle(""); + _eoFrame0.setLocation(395, 803); + _eoFrame0.setSize(346, 66); + } + } +} diff --git a/Liaison/English.lproj/LoadPanel.nib/classes.nib b/Liaison/English.lproj/LoadPanel.nib/classes.nib new file mode 100644 index 0000000..e1ab46c --- /dev/null +++ b/Liaison/English.lproj/LoadPanel.nib/classes.nib @@ -0,0 +1,28 @@ +{ + IBClasses = ( + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + CLASS = LoadPanelController; + LANGUAGE = ObjC; + OUTLETS = { + theLoadPanel = NSPanel; + thePathField = NSTextField; + theProgressBar = NSProgressIndicator; + theStatusField = NSTextField; + }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {showDownloadWindow = id; }; + CLASS = NIBConnector; + LANGUAGE = ObjC; + OUTLETS = { + theCopyController = CopyController; + theLoadPanelController = LoadPanelController; + thePreferencesController = PreferencesController; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Liaison/English.lproj/LoadPanel.nib/info.nib b/Liaison/English.lproj/LoadPanel.nib/info.nib new file mode 100644 index 0000000..7484a71 --- /dev/null +++ b/Liaison/English.lproj/LoadPanel.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBDocumentLocation + 89 245 356 240 0 0 1600 1178 + IBFramework Version + 291.0 + IBOpenObjects + + 6 + + IBSystem Version + 6L60 + + diff --git a/Liaison/English.lproj/LoadPanel.nib/objects.nib b/Liaison/English.lproj/LoadPanel.nib/objects.nib new file mode 100644 index 0000000..51e479f Binary files /dev/null and b/Liaison/English.lproj/LoadPanel.nib/objects.nib differ diff --git a/Liaison/English.lproj/MainMenu.nib/classes.nib b/Liaison/English.lproj/MainMenu.nib/classes.nib new file mode 100644 index 0000000..3fbfcb0 --- /dev/null +++ b/Liaison/English.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,123 @@ +{ + IBClasses = ( + { + ACTIONS = {openHomepage = id; showInspectorWindow = id; showMainWindow = id; }; + CLASS = ApplicationController; + LANGUAGE = ObjC; + OUTLETS = {inspectorWindow = NSWindow; mainWindow = NSWindow; }; + SUPERCLASS = NSObject; + }, + { + CLASS = CopyController; + LANGUAGE = ObjC; + OUTLETS = {theFilenameField = NSTextField; theProgressBar = NSProgressIndicator; }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {addFiles = id; open = id; }; + CLASS = FileTableDelegate; + LANGUAGE = ObjC; + OUTLETS = { + inspectorController = InspectorController; + statusLine = NSTextField; + tableView = NSTableView; + theContextMenu = NSMenu; + }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = { + addFilterRow = id; + libraryUpdated = id; + removeFilterRow = id; + showWindow = id; + }; + CLASS = FindController; + LANGUAGE = ObjC; + OUTLETS = { + theFileList = NSTableView; + theFilterBox = NSBox; + theFindView = NSView; + theFindWindow = NSWindow; + theLibraryPopUp = NSPopUpButton; + theOperatorPopUp = NSPopUpButton; + }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {deselectAll = id; openSelectedFiles = id; revealInFinder = id; }; + CLASS = FirstResponder; + LANGUAGE = ObjC; + SUPERCLASS = NSObject; + }, + {CLASS = FlippedBox; LANGUAGE = ObjC; SUPERCLASS = NSBox; }, + { + ACTIONS = {addGroup = id; }; + CLASS = GroupTableDelegate; + LANGUAGE = ObjC; + OUTLETS = { + outlineView = NSOutlineView; + statusLine = NSTextField; + theContextMenu = NSMenu; + theFileDelegate = FileTableDelegate; + theWindow = WindowController; + }; + SUPERCLASS = NSObject; + }, + { + CLASS = InspectorController; + LANGUAGE = ObjC; + OUTLETS = {theDefaultTabView = NSView; theTabView = NSTabView; theWindow = NSWindow; }; + SUPERCLASS = NSObject; + }, + {CLASS = LiScrollView; LANGUAGE = ObjC; SUPERCLASS = NSScrollView; }, + { + ACTIONS = {delete = id; }; + CLASS = LiTableView; + LANGUAGE = ObjC; + SUPERCLASS = NSTableView; + }, + { + ACTIONS = {showDownloadWindow = id; showPreferencesWindow = id; }; + CLASS = NIBConnector; + LANGUAGE = ObjC; + OUTLETS = { + theCopyController = CopyController; + theLoadPanelController = LoadPanelController; + thePreferencesController = PreferencesController; + }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {delete = id; }; + CLASS = NSOutlineView; + LANGUAGE = ObjC; + SUPERCLASS = NSTableView; + }, + { + ACTIONS = {showWindow = id; }; + CLASS = ViewOptionsController; + LANGUAGE = ObjC; + OUTLETS = { + theContentView = id; + theFileDelegate = FileTableDelegate; + theHeaderField = id; + theWindow = NSWindow; + }; + SUPERCLASS = NSObject; + }, + { + CLASS = WindowController; + LANGUAGE = ObjC; + OUTLETS = { + theFileList = NSTableView; + theGroupList = NSOutlineView; + theInspectorWindow = NSWindow; + theMainWindow = NSWindow; + theSearchField = id; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Liaison/English.lproj/MainMenu.nib/info.nib b/Liaison/English.lproj/MainMenu.nib/info.nib new file mode 100644 index 0000000..ca7b875 --- /dev/null +++ b/Liaison/English.lproj/MainMenu.nib/info.nib @@ -0,0 +1,36 @@ + + + + + IBDocumentLocation + 17 80 461 291 0 0 1024 746 + IBEditorPositions + + 29 + 5 1124 310 44 0 0 1600 1178 + 377 + 711 772 176 64 0 0 1600 1178 + 700 + 287 435 224 118 0 0 1024 746 + 773 + 974 1012 129 130 0 0 1600 1178 + 786 + 981 899 106 80 0 0 1600 1178 + + IBFramework Version + 349.0 + IBOldestOS + 3 + IBOpenObjects + + 664 + 773 + 786 + 21 + 377 + 29 + + IBSystem Version + 7B85 + + diff --git a/Liaison/English.lproj/MainMenu.nib/keyedobjects.nib b/Liaison/English.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 0000000..482a180 Binary files /dev/null and b/Liaison/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/Liaison/English.lproj/PreferencesWindow.nib/classes.nib b/Liaison/English.lproj/PreferencesWindow.nib/classes.nib new file mode 100644 index 0000000..76a7d6c --- /dev/null +++ b/Liaison/English.lproj/PreferencesWindow.nib/classes.nib @@ -0,0 +1,50 @@ +{ + IBClasses = ( + { + ACTIONS = { + addFiles = id; + addGroup = id; + removeGroup = id; + showInspectorWindow = id; + showMainWindow = id; + }; + CLASS = ApplicationController; + LANGUAGE = ObjC; + OUTLETS = { + fileDelegate = FileTableDelegate; + fileTableView = NSTableView; + groupDelegate = GroupTableDelegate; + groupOutlineView = NSOutlineView; + inspectorWindow = NSWindow; + mainWindow = NSWindow; + openMenuItem = NSMenuItem; + showInspectorWindowMenuItem = NSMenuItem; + showMainWindowMenuItem = NSMenuItem; + thePanelController = LoadPanelController; + thePreferenceController = PreferenceController; + }; + SUPERCLASS = NSObject; + }, + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + CLASS = NIBConnector; + LANGUAGE = ObjC; + OUTLETS = {thePreferencesController = PreferencesController; }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {applyChanges = id; selectDownloadDirectory = id; toggleNetworkEnabled = id; }; + CLASS = PreferencesController; + LANGUAGE = ObjC; + OUTLETS = { + theDownloadField = NSTextField; + theHostnameField = NSTextField; + theHostnameFieldDescription = NSTextField; + theNetworkEnabledButton = NSButton; + theWindow = NSWindow; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Liaison/English.lproj/PreferencesWindow.nib/info.nib b/Liaison/English.lproj/PreferencesWindow.nib/info.nib new file mode 100644 index 0000000..ba3c2a9 --- /dev/null +++ b/Liaison/English.lproj/PreferencesWindow.nib/info.nib @@ -0,0 +1,38 @@ + + + + + IBDocumentLocation + 50 54 356 240 0 0 1600 1178 + IBFramework Version + 326.0 + IBGroupedObjects + + 0 + + 39 + 40 + 49 + + 1 + + 21 + 22 + + 2 + + 34 + 35 + 36 + + + IBLastGroupID + 3 + IBOpenObjects + + 5 + + IBSystem Version + 7B28 + + diff --git a/Liaison/English.lproj/PreferencesWindow.nib/objects.nib b/Liaison/English.lproj/PreferencesWindow.nib/objects.nib new file mode 100644 index 0000000..8dbe7e0 Binary files /dev/null and b/Liaison/English.lproj/PreferencesWindow.nib/objects.nib differ diff --git a/Liaison/English.lproj/WindowElements.strings b/Liaison/English.lproj/WindowElements.strings new file mode 100644 index 0000000..dbc6eb8 --- /dev/null +++ b/Liaison/English.lproj/WindowElements.strings @@ -0,0 +1,37 @@ +/* Common strings. */ +LiFileSingular = "file"; +LiFilePlural = "files"; + +/* Default group names. */ +LiRendezvousGroupName = "Rendezvous"; +LiUntitledGroupName = "untitled"; + +/* Toolbar strings. */ +LiToolbarAddFileLabel = "Add Files"; +LiToolbarAddFilePaletteLabel = "Add Files to Library"; +LiToolbarAddFileToolTip = "Add files to your library."; +LiToolbarRemoveFileLabel = "Remove File"; +LiToolbarRemoveFilesLabel = "Remove Files"; +LiToolbarRemoveFilePaletteLabel = "Remove from Group"; +LiToolbarRemoveFileToolTip = "Remove the currently selected files."; +LiToolbarRemoveFilesFromLibraryToolTip = "Remove the currently selected %@ from your library."; +LiToolbarRemoveFilesFromGroupToolTip = "Remove the currently selected %@ from the group."; +LiToolbarSearchLabel = "Search"; +LiToolbarSearchPaletteLabel = "Search in Group"; +LiToolbarSearchToolTip = "Search in selected group."; +LiToolbarGetInfoLabel = "Get Info"; +LiToolbarGetInfoPaletteLabel = "Get Info"; +LiToolbarGetInfoToolTip = "Open the inspector window."; +LiToolbarAddGroupLabel = "Add Group"; +LiToolbarAddGroupPaletteLabel = "Add Group"; +LiToolbarAddGroupToolTip = "Create a new group."; +LiToolbarRemoveGroupLabel = "Delete Group"; +LiToolbarRemoveGroupPaletteLabel = "Delete Group"; +LiToolbarRemoveGroupToolTip = "Deletes the currently selected group."; +LiToolbarRevealLabel = "Show in Finder"; +LiToolbarRevealPaletteLabel = "Show in Finder"; +LiToolbarRevealToolTip = "Show the selected item in the Finder."; + +/* File load panel. */ +LiLoadPanelTitle = "Add to Library"; +LiLoadingDirectory = "Scanning: "; diff --git a/Liaison/FileTableDelegate.h b/Liaison/FileTableDelegate.h new file mode 100644 index 0000000..43b4f8a --- /dev/null +++ b/Liaison/FileTableDelegate.h @@ -0,0 +1,106 @@ +/* FileTableDelegate */ + +@class InspectorController; + +@interface LiFileStore (BatchPathAdditions) +- (NSArray *)addPaths: (NSArray *)aPathList toGroup: (NSString *)aGroup; +@end + +@interface FileTableDelegate : NSObject +{ + IBOutlet InspectorController *inspectorController; + IBOutlet NSTableView *tableView; + IBOutlet NSTextField *statusLine; + IBOutlet NSMenu *theContextMenu; + + NSImage *ascendingSortingImage, *descendingSortingImage; + + LiFileStore *theFileStore; + LiFilter *theFilter; + NSString *theSearchString; + NSTableColumn *theSelectedColumn; + BOOL isAscending; + + NSArray *theActiveList, *theSortedList; + NSMutableDictionary *theListPrefs; + NSMutableDictionary *theTableColumns; + NSMutableDictionary *theShownColumns; + NSMutableSet *theSavedSelection; +} +- (IBAction)addFiles: (id)sender; +- (IBAction)openSelectedFiles: (id)sender; +- (IBAction)revealInFinder: (id)sender; + +- (NSDictionary *)browserColumns; + +- (LiBrowserColumn *)columnForIdentifier: (NSString *)anIdentifier; +- (void)showColumnWithIdentifier: (NSString *)anIdentifier; +- (void)removeColumnWithIdentifier: (NSString *)anIdentifier; +- (int)numberOfFiles; +- (LiFileHandle *)fileAtIndex: (int)index; + +- (void)addAttributeFilter: (LiFilter *)aFilter; +- (void)removeAttributeFilter: (LiFilter *)aFilter; + +- (void)saveSelectionOfTableView: (NSTableView *)aTableView; +- (void)restoreSelectionToTableView: (NSTableView *)aTableView + refresh: (BOOL)inRefresh; + +- (NSSize)minSize; + +- (BOOL)validateAction: (SEL)anAction; + +- (void)redisplay; +@property (retain,getter=shownColumns) NSMutableDictionary *theShownColumns; +@property (retain,getter=searchString) NSString *theSearchString; +@property (retain) InspectorController *inspectorController; +@property (retain,getter=selectedColumn) NSTableColumn *theSelectedColumn; +@property (retain,getter=savedSelection) NSMutableSet *theSavedSelection; +@property (retain) NSMutableDictionary *theTableColumns; +@property (retain,getter=filter) LiFilter *theFilter; +@property (retain) NSTextField *statusLine; +@property (retain) NSMenu *theContextMenu; +@property BOOL isAscending; +@property (retain,getter=tableView) NSTableView *tableView; +@property (retain) NSMutableDictionary *theListPrefs; +@property (retain,getter=fileStore) LiFileStore *theFileStore; +@end + +@interface FileTableDelegate (LiTableViewDelegate) +- (void)deleteSelectedRowsInTableView: (NSTableView *)aTableView; +@end + +@interface FileTableDelegate (CommonAccessors) +- (NSString *)group; +- (void)setGroup: (NSString *)aGroupName; +@end + +@interface FileTableDelegate (Accessors) +- (LiFileStore *)fileStore; +- (void)setFileStore: (LiFileStore *)aFileStore; +- (LiFilter *)filter; +- (void)setFilter: (LiFilter *)aFilter; + +- (NSMutableDictionary *)shownColumns; +- (void)setShownColumns: (NSMutableDictionary *)someColumns; + +- (NSArray *)sortedList; +- (void)setSortedList: (NSArray *)aFileList; +- (NSArray *)activeList; +- (void)setActiveList: (NSArray *)aFileList; +- (NSArray *)fileList; +- (NSString *)searchString; +- (void)setSearchString: (NSString *)aSearchString; +- (NSTableColumn *)selectedColumn; +- (void)setSelectedColumn: (NSTableColumn *)aColumn; +- (void)setSelectedColumn: (NSTableColumn *)aColumn + withContext: (void *)someContext; +- (NSMutableSet *)savedSelection; +- (void)setSavedSelection: (NSMutableSet *)aSelection; +- (NSMutableDictionary *)listPrefs; +- (void)setListPrefs: (NSMutableDictionary *)listPrefs; +- (NSMutableDictionary *)columnPrefsForIdentifier: (NSString *)anIdentifier; +- (void)setColumnPrefs: (NSMutableDictionary *)columnPrefs + forIdentifier: (NSString *)anIdentifier; +- (NSTableView *)tableView; +@end diff --git a/Liaison/FileTableDelegate.m b/Liaison/FileTableDelegate.m new file mode 100644 index 0000000..cd8591a --- /dev/null +++ b/Liaison/FileTableDelegate.m @@ -0,0 +1,1345 @@ +#import "FileTableDelegate.h" + +#import "InspectorController.h" +#import "ImageAndTextCell.h" +#import "LoadPanelController.h" +#import "NIBConnector.h" +#import "PluginManager.h" + +#include +#include + +// XXX - should use SEL instead of NSString. +struct SortContext { + BOOL ascending; + SEL compareMethod, getMethod; +}; + +int contextSorter(id file1, id file2, void *someContext) +{ + struct SortContext *context; + id leftVal, rightVal; + + context = (struct SortContext *)someContext; + if (context->ascending) { + leftVal = [file1 performSelector: context->getMethod]; + rightVal = [file2 performSelector: context->getMethod]; + } else { + leftVal = [file2 performSelector: context->getMethod]; + rightVal = [file1 performSelector: context->getMethod]; + } + + if (rightVal == nil) { + if (leftVal == nil) + return 0; + else + return -1; + } else if (leftVal == nil) + return 1; + + return (int)[leftVal performSelector: context->compareMethod + withObject: rightVal]; +} + +static NSString * +myLocalizedString(NSString *aString) +{ + return NSLocalizedStringFromTable(aString, @"WindowElements", @""); +} + +static void +logRect(NSString *desc, NSRect aRect) +{ + [LiLog logAsDebug: @"%@, (%f, %f, %f, %f)", desc, aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height]; +} + +@interface LiFileHandle (GUIStuff) +- (void)revealInFinder; +@end + +@implementation LiFileStore (BatchPathAdditions) +- (BOOL)isValidPath: (NSString *)aPath +{ + NSString *filename; + + filename = [aPath lastPathComponent]; + if ([filename hasPrefix: @"."] || + [filename isEqualToString: @"Icon\r"]) + return NO; + + return YES; +} + +- (BOOL)addURLs: (NSArray *)aURLList toGroup: (NSString *)aGroup +{ + NSURL *fileURL; + int i, numFiles; + + if ([aURLList count] == 0) + return YES; + + numFiles = [aURLList count]; + + i = 0; + for (fileURL in aURLList) { + LiFileHandle *tmpFile; + + NS_DURING + tmpFile = [self addURL: fileURL]; + + if (aGroup != nil) { + [tmpFile addToGroup: aGroup]; + } + NS_HANDLER + [LiLog logAsWarning: @"Couldn't add file: %@ - %@", [localException name], [localException reason]]; + NS_ENDHANDLER + + i++; + } + + return YES; +} + +- (NSArray *)makeURLsFromPaths: (NSArray *)aFileList toGroup: (NSString *)aGroup +{ + LoadPanelController *loadPanelController; + NSMutableArray *myFileList; + NSString *path; + int i, fileCount; + + loadPanelController = [[NIBConnector connector] loadPanelController]; + [loadPanelController setStatus: myLocalizedString(@"LiLoadingDirectory")]; + [loadPanelController setProgress: 100.0]; + [loadPanelController setIndeterminantProgress: YES]; + [loadPanelController update]; + fileCount = [aFileList count]; + i = 0; + + myFileList = [NSMutableArray array]; + for (path in aFileList) { + if ((i % 10) == 0) { + [loadPanelController setPath: [path lastPathComponent]]; + [loadPanelController update]; + } + + if ([self isValidPath: path]) { + NSFileManager *defaultManager; + BOOL isBundle; + BOOL isDirectory; + + isDirectory = NO; + defaultManager = [NSFileManager defaultManager]; + [defaultManager fileExistsAtPath: path isDirectory: &isDirectory]; + if ([path hasSuffix: @".app"] || + [[NSWorkspace sharedWorkspace] isFilePackageAtPath: path]) + isBundle = YES; + else + isBundle = NO; + + if (isDirectory && !isBundle) { + struct dirent *dirp; + DIR *directory; + NSAutoreleasePool *rp; + NSMutableArray *dirContents; + int j; + + [LiLog logAsDebug: @"Recursing into: %@", path]; + [LiLog indentDebugLog]; + + // Let people know we're working in a subdirectory. + j = 0; + + dirContents = [[NSMutableArray alloc] init]; + directory = opendir([path UTF8String]); + while ((dirp = readdir(directory)) != NULL) { + NSString *subPath; + + subPath = [NSString stringWithUTF8String: dirp->d_name]; + if ([self isValidPath: subPath] == YES) { + NSString *fullPath; + + if ((j % 10) == 0) { + [loadPanelController update]; + } + + fullPath = [path stringByAppendingPathComponent: subPath]; + [dirContents addObject: fullPath]; + } + j++; + } + closedir(directory); + + rp = [[NSAutoreleasePool alloc] init]; + [self addURLs: [self makeURLsFromPaths: dirContents toGroup: aGroup] + toGroup: aGroup]; + [rp release]; + [dirContents release]; + + [LiLog unindentDebugLog]; + } else { + [LiLog logAsDebug: @"Adding %@ to file list", path]; + [loadPanelController setPath: [path lastPathComponent]]; + [myFileList addObject: [NSURL fileURLWithPath: path]]; + } + } + i++; + } + + return myFileList; +} + +- (NSArray *)addPaths: (NSArray *)aPathList toGroup: (NSString *)aGroup +{ + if ([aPathList count] > 0) { + LoadPanelController *loadPanelController; + NSArray *fileList; + + loadPanelController = [[NIBConnector connector] loadPanelController]; + [loadPanelController show]; + fileList = [self makeURLsFromPaths: aPathList toGroup: aGroup]; + [self addURLs: fileList toGroup: aGroup]; + [loadPanelController hide]; + [self synchronize]; + } + + return nil; +} +@end + +@implementation FileTableDelegate (LiTableViewDelegate) +- (void)tableViewDidBecomeFirstResponder: (NSTableView *)aTableView +{ + [LiLog logAsDebug: @"[FileTableDelegate becameFirstResponder]"]; + [LiLog indentDebugLog]; + if ([tableView numberOfSelectedRows] == 1) { + LiFileHandle *theRecord; + + theRecord = [self fileAtIndex: [tableView selectedRow]]; + // Auto-update a clicked file. + [theRecord update]; + [[theRecord fileStore] synchronize]; + [inspectorController setFile: theRecord]; + } + [LiLog unindentDebugLog]; +} + +- (void)deleteSelectedRowsInTableView: (NSTableView *)aTableView +{ + NSEnumerator *rowEnum; + NSString *myGroup; + NSMutableArray *selectedFiles; + NSNumber *row; + + rowEnum = [aTableView selectedRowEnumerator]; + selectedFiles = [NSMutableArray array]; + while ((row = [rowEnum nextObject]) != nil) { + LiFileHandle *record; + + record = [self fileAtIndex: [row intValue]]; + [selectedFiles addObject: record]; + } + + [aTableView deselectAll: self]; + + myGroup = [self group]; + if (myGroup == nil) { + LiFileHandle *file; + + for (file in selectedFiles) { + [[self fileStore] removeFileHandle: file]; + } + } else { + LiFileHandle *file; + + for (file in selectedFiles) { + [LiLog logAsDebug: @"Removing %@ from %@", [file filename], myGroup]; + [LiLog logAsDebug: @"old groups: %@", [[file groups] description]]; + [file removeFromGroup: myGroup]; + [LiLog logAsDebug: @"new groups: %@", [[file groups] description]]; + } + } + [[self fileStore] synchronize]; +} +@end + +@implementation FileTableDelegate (TableViewDataSource) +- (int)numberOfRowsInTableView:(NSTableView *)aTableView +{ + return [[self sortedList] count]; +} + +- (id)tableView: (NSTableView *)aTableView +objectValueForTableColumn: (NSTableColumn *)aTableColumn + row: (int)rowIndex +{ + LiFileHandle *record; + LiBrowserColumn *col; + + col = [self columnForIdentifier: [aTableColumn identifier]]; + record = [self fileAtIndex: rowIndex]; + return [col objectForRecord: record]; +} + +- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex +{ + LiFileHandle *record; + LiBrowserColumn *col; + + if (rowIndex < 0 || rowIndex >= (int)[[self sortedList] count]) + return; + + col = [self columnForIdentifier: [aTableColumn identifier]]; + record = [self fileAtIndex: rowIndex]; + [col setObject: anObject forRecord: record]; + + [[record fileStore] synchronize]; +} + +- (NSDragOperation)tableView: (NSTableView *)aTableView + validateDrop: (id )sender + proposedRow: (int)index + proposedDropOperation: (NSDragOperation)operation; +{ + NSDragOperation dragOp; + + dragOp = NSDragOperationNone; + if ([sender draggingSource] != tableView && + [[self fileStore] isEditable] == YES) { + NSPasteboard *pboard; + + pboard = [sender draggingPasteboard]; + if ([pboard availableTypeFromArray: + [NSArray arrayWithObjects: NSFilenamesPboardType, NSFilesPromisePboardType, nil]]) { + [aTableView setDropRow: -1 dropOperation: NSTableViewDropOn]; + dragOp = NSDragOperationCopy; + } + } + + return dragOp; +} + +- (BOOL)tableView: (NSTableView *)aTableView + acceptDrop: (id )aSender + row: (int)anIndex + dropOperation: (NSTableViewDropOperation)anOperation +{ + NSArray *pathList; + NSPasteboard *pboard; + + pboard = [aSender draggingPasteboard]; + + pathList = nil; + if ([pboard availableTypeFromArray: + [NSArray arrayWithObject: NSFilenamesPboardType]]) { + pathList = [pboard propertyListForType: NSFilenamesPboardType]; + } + + // Handle promised files. + if ([[pboard types] containsObject: NSFilesPromisePboardType]) { + NSEnumerator *pathEnum; + NSMutableArray *promisedPaths; + NSString *path; + NSURL *dropLocation; + + dropLocation = [NSURL fileURLWithPath: + [[Preferences sharedPreferences] downloadDirectory]]; + pathEnum = [[aSender namesOfPromisedFilesDroppedAtDestination: dropLocation] objectEnumerator]; + promisedPaths = [NSMutableArray array]; + while ((path = [pathEnum nextObject]) != nil) { + [promisedPaths addObject: [[dropLocation path] stringByAppendingPathComponent: path]]; + } + pathList = promisedPaths; + } + + if ([pathList count] > 0) { + [[self fileStore] addPaths: pathList toGroup: [self group]]; + return YES; + } + + // XXX - should select the added songs now. + + return NO; + +} + +- (BOOL)tableView: (NSTableView *)aTableView + writeRows: (NSArray *)someRows + toPasteboard: (NSPasteboard *)aPboard +{ + NSMutableArray *liaisonPboard, *filenamePboard, *promisePboard; + NSMutableArray *typeList; + NSNumber *row; + + liaisonPboard = [NSMutableArray array]; + filenamePboard = [NSMutableArray array]; + promisePboard = [NSMutableArray array]; + + for (row in someRows) { + LiFileHandle *file; + NSURL *url; + + file = [self fileAtIndex: [row intValue]]; + [liaisonPboard addObject: file]; + url = [file url]; + if ([url isFileURL] == YES) { + [filenamePboard addObject: [url path]]; + } + } + + typeList = [NSMutableArray array]; + if ([liaisonPboard count] > 0) + [typeList addObject: LiaisonPboardType]; + if ([filenamePboard count] > 0) + [typeList addObject: NSFilenamesPboardType]; + // Make an HFS promise. + + if ([typeList count] > 0) { + [aPboard declareTypes: typeList owner: self]; + + if ([liaisonPboard count] > 0) { + NSData *liaisonPboardData; + + liaisonPboardData = [NSKeyedArchiver archivedDataWithRootObject: + liaisonPboard]; + if ([aPboard setData: liaisonPboardData + forType: LiaisonPboardType] == NO) + return NO; + } + + if ([filenamePboard count] > 0) { + if ([aPboard setPropertyList: filenamePboard + forType: NSFilenamesPboardType] == NO) + return NO; + } + return YES; + } + return NO; +} +@end + +@implementation FileTableDelegate (TableViewDelegate) +- (void)tableView: (NSTableView*)aTableView +didClickTableColumn: (NSTableColumn *)aTableColumn +{ + LiBrowserColumn *col; + + col = [self columnForIdentifier: [aTableColumn identifier]]; + if ([col compareMethod]) { + struct SortContext context; + + if ([self selectedColumn] && [self selectedColumn] == aTableColumn) { + if (isAscending) + isAscending = NO; + else + aTableColumn = nil; // XXX, but it works. + } else + isAscending = YES; + + context.ascending = isAscending; + context.getMethod = [col getMethod]; + context.compareMethod = [col compareMethod]; + [self saveSelectionOfTableView: tableView]; + [self setSelectedColumn: aTableColumn withContext: &context]; + [self redisplay]; + [self restoreSelectionToTableView: tableView refresh: YES]; + } +} + +- (BOOL)tableView: (NSTableView *)theTable shouldSelectRow: (int)theRow +{ + if (theRow < 0 || (int)[[self sortedList] count] <= theRow) + return NO; + return YES; +} + +- (BOOL)tableView: (NSTableView *)aTableView +shouldEditTableColumn: (NSTableColumn *)aTableColumn + row: (int)rowIndex +{ + LiFileHandle *record; + + record = [self fileAtIndex: rowIndex]; + return [record isEditable]; +} + +- (void)tableView: (NSTableView *)aTableView + copyRow: (int)aRow +{ + [LiLog logAsDebug: @"[tableView copyRow]"]; +} + +- (void)tableViewSelectionDidChange: (NSNotification *)aNotification +{ + [LiLog logAsDebug: @"[FileTableDelegate tableViewSelectionDidChange: (notification)]"]; + [LiLog indentDebugLog]; + if ([tableView numberOfSelectedRows] == 1) { + LiFileHandle *theRecord; + + theRecord = [self fileAtIndex: [tableView selectedRow]]; + // Auto-update a clicked file. + [theRecord update]; + [[theRecord fileStore] synchronize]; + [inspectorController setFile: theRecord]; + } + [LiLog unindentDebugLog]; +} + +- (void)doDoubleClickInTable: (NSTableView *)aTable; +{ + NSEnumerator *rowEnum; + NSNumber *selectedRow; + + rowEnum = [aTable selectedRowEnumerator]; + while ((selectedRow = [rowEnum nextObject]) != nil) { + LiFileHandle *file; + + file = [self fileAtIndex: [selectedRow intValue]]; + [file open]; + } +} + +- (void)tableViewColumnDidMove: (NSNotification *)aNotification +{ + NSEnumerator *colEnum; + NSMutableArray *colOrder; + NSMutableDictionary *listPrefs; + NSTableColumn *column; + + listPrefs = [self listPrefs]; + colOrder = [NSMutableArray array]; + colEnum = [[[self tableView] tableColumns] objectEnumerator]; + while ((column = [colEnum nextObject]) != nil) { + [colOrder addObject: [column identifier]]; + } + + [listPrefs setObject: colOrder forKey: @"columnOrder"]; + [self setListPrefs: listPrefs]; +} + +- (void)tableViewColumnDidResize: (NSNotification *)aNotification +{ + NSMutableDictionary *colPrefs; + NSNumber *colSize; + NSTableColumn *column; + + column = [[aNotification userInfo] objectForKey: @"NSTableColumn"]; + if (column != nil) { + colPrefs = [self columnPrefsForIdentifier: [column identifier]]; + colSize = [NSNumber numberWithFloat: [column width]]; + [colPrefs setObject: colSize forKey: @"width"]; + [self setColumnPrefs: colPrefs forIdentifier: [column identifier]]; + } +} +@end + +@implementation FileTableDelegate +- (void)openPanelDidEnd: (NSOpenPanel *)openPanel + returnCode: (int)returnCode + contextInfo: (void *)context +{ + [openPanel close]; + if (returnCode == NSOKButton) { + [[self fileStore] addPaths: [openPanel filenames] toGroup: [self group]]; + } +} + +- (IBAction)addFiles: (id)sender +{ + NSOpenPanel *openPanel; + + if ([[self fileStore] isEditable]) { + openPanel = [NSOpenPanel openPanel]; + [openPanel setTitle: myLocalizedString(@"LiLoadPanelTitle")]; + [openPanel setAllowsMultipleSelection: YES]; + [openPanel setCanChooseDirectories: YES]; + [openPanel setCanChooseFiles: YES]; + + [openPanel beginSheetForDirectory: nil file: nil types: nil + modalForWindow: [NSApp mainWindow] modalDelegate: self + didEndSelector: @selector(openPanelDidEnd:returnCode:contextInfo:) + contextInfo: nil]; + } +} + +- (IBAction)openSelectedFiles: (id)sender +{ + NSEnumerator *selectionEnum; + NSNumber *row; + + selectionEnum = [tableView selectedRowEnumerator]; + while ((row = [selectionEnum nextObject]) != nil) { + LiFileHandle *fileHandle; + + fileHandle = [self fileAtIndex: [row intValue]]; + [fileHandle open]; + } +} + +- (IBAction)revealInFinder: (id)sender +{ + NSEnumerator *rowEnum; + NSNumber *row; + + rowEnum = [tableView selectedRowEnumerator]; + while ((row = [rowEnum nextObject]) != nil) { + LiFileHandle *tmpFile; + + tmpFile = [self fileAtIndex: [row intValue]]; + [tmpFile revealInFinder]; + } +} + +- (NSDictionary *)browserColumns +{ + NSEnumerator *pluginEnum; + NSMutableDictionary *browserColumns; + NSObject *plugin; + + browserColumns = [NSMutableDictionary dictionary]; + pluginEnum = [[[PluginManager defaultManager] browserPlugins] objectEnumerator]; + while ((plugin = [pluginEnum nextObject]) != nil) { + LiBrowserColumn *col; + NSEnumerator *colEnum; + + colEnum = [[plugin columns] objectEnumerator]; + while ((col = [colEnum nextObject]) != nil) { + NSString *identifier; + + identifier = [NSString stringWithFormat: @"%@:%@", + NSStringFromClass([plugin class]), [col identifier]]; + [browserColumns setObject: col forKey: identifier]; + } + } + + return browserColumns; +} + +- (LiBrowserColumn *)columnForIdentifier: (NSString *)anIdentifier +{ + return [theTableColumns objectForKey: anIdentifier]; +} + +- (void)showColumnWithIdentifier: (NSString *)anIdentifier +{ + LiBrowserColumn *col; + NSMutableDictionary *shownColumns; + + shownColumns = [self shownColumns]; + if (shownColumns == nil) { + shownColumns = [NSMutableDictionary dictionary]; + [self setShownColumns: shownColumns]; + } + + col = [self columnForIdentifier: anIdentifier]; + if (col && [shownColumns objectForKey: anIdentifier] == nil) { + NSDictionary *colPrefs; + NSTableColumn *tableColumn; + + colPrefs = [self columnPrefsForIdentifier: anIdentifier]; + tableColumn = [[[NSTableColumn alloc] initWithIdentifier: anIdentifier] autorelease]; + [tableColumn setEditable: [col editable]]; + [tableColumn setDataCell: [col cell]]; + [tableColumn setResizable: [col resizable]]; + if ([col resizable]) { + NSNumber *colWidth; + + colWidth = [colPrefs objectForKey: @"width"]; + if (colWidth != nil) + [col setWidth: colWidth]; + } + + if ([col showsHeader]) + [[tableColumn headerCell] setStringValue: [col name]]; + else + [[tableColumn headerCell] setStringValue: @""]; + + if ([col width]) + [tableColumn setWidth: [[col width] floatValue]]; + + [shownColumns setObject: tableColumn forKey: anIdentifier]; + + [tableView addTableColumn: tableColumn]; + } +} + +- (void)removeColumnWithIdentifier: (NSString *)anIdentifier +{ + NSTableColumn *col; + + col = [[self shownColumns] objectForKey: anIdentifier]; + if (col != nil) { + [[self shownColumns] removeObjectForKey: anIdentifier]; + [tableView removeTableColumn: col]; + } +} + +- (id)init +{ + self = [super init]; + + theTableColumns = [[NSMutableDictionary alloc] init]; + + return self; +} + +- (void)dealloc +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self]; + + [ascendingSortingImage release]; + [descendingSortingImage release]; + [self setActiveList: nil]; + [self setFileStore: nil]; + [self setFilter: nil]; + [self setSearchString: nil]; + + [theTableColumns release]; + + [super dealloc]; +} + +- (void)awakeFromNib +{ + NSArray *shownColumns; + NSDictionary *listPrefs; + NSEnumerator *columnEnum; + NSString *columnID; + + [LiLog logAsDebug: @"[FileTableDelegate awakeFromNib]"]; + [LiLog indentDebugLog]; + + ascendingSortingImage = [[NSImage imageNamed: @"SortAscending.gif"] retain]; + descendingSortingImage = [[NSImage imageNamed: @"SortDescending.gif"] retain]; + + [tableView setTarget: self]; + [tableView setDoubleAction: @selector(doDoubleClickInTable:)]; + + // XXX + theTableColumns = (NSMutableDictionary *)[self browserColumns]; + [theTableColumns retain]; + + listPrefs = [self listPrefs]; + shownColumns = [listPrefs objectForKey: @"columnOrder"]; + for (columnID in shownColumns) { + [self showColumnWithIdentifier: columnID]; + } + + if ([[[self tableView] tableColumns] count] == 0) { + columnEnum = [theTableColumns keyEnumerator]; + while ((columnID = [columnEnum nextObject]) != nil) { + [LiLog logAsDebug: @"showCol: %@", columnID]; + [self showColumnWithIdentifier: columnID]; + } + } + + /* Register for Drag-and-Drop operation. */ + [tableView registerForDraggedTypes: + [NSArray arrayWithObjects: NSFilenamesPboardType, NSFilesPromisePboardType, NSHTMLPboardType, NSTIFFPboardType, NSPICTPboardType, NSURLPboardType, NSFileContentsPboardType, nil]]; + + [statusLine setStringValue: @""]; + + [LiLog unindentDebugLog]; +} + +- (void)respondToFileChanged: (NSNotification *)aNotification +{ + LiFileHandle *file; + NSArray *addedFileList, *changedFileList, *removedFileList; + NSDictionary *fileDict; + NSEnumerator *fileEnum; + BOOL needsRedisplay; + + needsRedisplay = NO; + + addedFileList = [[aNotification userInfo] objectForKey: LiFilesAdded]; + changedFileList = [[aNotification userInfo] objectForKey: LiFilesChanged]; + removedFileList = [[aNotification userInfo] objectForKey: LiFilesRemoved]; + + fileEnum = [addedFileList objectEnumerator]; + while (needsRedisplay == NO && + (file = [fileEnum nextObject]) != nil) { + if ([file matchesFilter: [self filter]]) + needsRedisplay = YES; + } + + fileEnum = [changedFileList objectEnumerator]; + while (needsRedisplay == NO && + (fileDict = [fileEnum nextObject]) != nil) { + LiFileHandle *tmpHandle; + NSDictionary *oldAttributes; + + tmpHandle = [fileDict objectForKey: @"LiFileHandleAttribute"]; + oldAttributes = [fileDict objectForKey: LiFileOldAttributes]; + if ([[self fileStore] attributes: oldAttributes matchFilter: [self filter]] || + [tmpHandle matchesFilter: [self filter]]) + needsRedisplay = YES; + } + + fileEnum = [removedFileList objectEnumerator]; + while (needsRedisplay == NO && + (fileDict = [fileEnum nextObject]) != nil) { + if ([[self fileStore] attributes: [fileDict objectForKey: LiFileOldAttributes] + matchFilter: [self filter]]) { + needsRedisplay = YES; + } + } + + if (needsRedisplay) { + [self saveSelectionOfTableView: tableView]; + [self redisplay]; + [self restoreSelectionToTableView: tableView refresh: YES]; + } +} + +- (int)numberOfFiles +{ + return [[self sortedList] count]; +} + +- (LiFileHandle *)fileAtIndex: (int)index +{ + return [[self sortedList] objectAtIndex: index]; +} + +- (void)addAttributeFilter: (LiFilter *)aFilter +{ + [LiLog logAsDebug: @"[FileTableDelegate addAttributeFilter: %@]", [aFilter description]]; + [LiLog indentDebugLog]; + + [self setFilter: aFilter]; + +#if 0 + filters = [self attributeFilters]; + attrEnum = [someFilters keyEnumerator]; + while ((attribute = [attrEnum nextObject]) != nil) + [filters setObject: [someFilters objectForKey: attribute] + forKey: attribute]; + + [LiLog unindentDebugLog]; +#endif +} + +#if 0 +- (id)filterForAttribute: (NSString *)anAttribute +{ + [LiLog logAsDebug: @"[FileTableDelegate filterForAttribute: %@]", anAttribute]; + [[LiLog indentDebugLog] logAsDebug: @"filters: %@", [[self attributeFilters] description]]; + [LiLog unindentDebugLog]; + return [[self attributeFilters] objectForKey: anAttribute]; +} +#endif + +- (void)removeAttributeFilter: (LiFilter *)aFilter +{ + [LiLog logAsDebug: @"[FileTableDelegate removeAttributeFilter: %@]", [aFilter description]]; + [self setFilter: nil]; + +#if 0 + filters = [self attributeFilters]; + attrEnum = [someFilters keyEnumerator]; + while ((attribute = [attrEnum nextObject]) != nil) + [filters removeObjectForKey: attribute]; +#endif +} + +- (void)saveSelectionOfTableView: (NSTableView *)aTableView +{ + NSEnumerator *theEnum; + NSMutableSet *savedSelection; + NSNumber *rowNum; + + savedSelection = [self savedSelection]; + if (savedSelection == nil) { + savedSelection = [[NSMutableSet alloc] init]; + theEnum = [aTableView selectedRowEnumerator]; + while ((rowNum = [theEnum nextObject]) != nil) { + id item; + + item = [[self sortedList] objectAtIndex: [rowNum intValue]]; + [savedSelection addObject: item]; + } + [self setSavedSelection: savedSelection]; + } +} + +- (void)restoreSelectionToTableView: (NSTableView *)aTableView + refresh: (BOOL)inRefresh +{ + NSMutableSet *savedSelection; + id item; + int savedLastRow; + + [aTableView deselectAll: self]; + + savedLastRow = -1; + savedSelection = [self savedSelection]; + if (savedSelection != nil) { + for (item in savedSelection) { + int row; + + row = [[self sortedList] indexOfObject: item]; + if (row != NSNotFound) { + [aTableView selectRow: row byExtendingSelection: YES]; + savedLastRow = row; + } + } + + [self setSavedSelection: nil]; + + if (inRefresh && savedLastRow > -1) + [aTableView scrollRowToVisible: savedLastRow]; + } +} + +- (NSSize)minSize +{ + NSArray *tableColumns; + NSRect headerRect; + NSTableColumn *column; + float minHeight, minWidth, rowHeight, scrollHeight, scrollWidth; + int numRows; + + [LiLog logAsDebug: @"[FileTableDelegate minSize]"]; + [LiLog indentDebugLog]; + + headerRect = [[[self tableView] headerView] frame]; + logRect(@"headerRect", headerRect); + + rowHeight = [[self tableView] rowHeight]; + [LiLog logAsDebug: @"row height: %f", rowHeight]; + numRows = [self numberOfRowsInTableView: [self tableView]]; + [LiLog logAsDebug: @"number of rows: %d", numRows]; + + scrollWidth = 17.0; + scrollHeight = 34.0; + + tableColumns = [[self tableView] tableColumns]; + minWidth = scrollWidth; + [LiLog indentDebugLog]; + for (column in tableColumns) { + float colWidth; + + colWidth = [column width]; + [LiLog logAsDebug: @"colWidth: %f", colWidth]; + minWidth += colWidth; + } + [LiLog unindentDebugLog]; + [LiLog logAsDebug: @"minWidth: %f", minWidth]; + + minHeight = headerRect.size.height + rowHeight * numRows + scrollHeight; + [LiLog logAsDebug: @"minHeight: %f", minHeight]; + + [LiLog unindentDebugLog]; + return NSMakeSize(minWidth, minHeight); +} + + +- (BOOL)validateAction: (SEL)anAction +{ + //[LiLog logAsDebug: @"[FileTableDelegate validateAction: %@]", NSStringFromSelector(anAction)]; + if (anAction == @selector(addFiles:)) { + return [[self fileStore] isEditable]; + } else if (anAction == @selector(delete:)) { + return ([[self fileStore] isEditable] && + [tableView numberOfSelectedRows] > 0); + } else if (anAction == @selector(revealInFinder:)) { + return ([[self fileStore] isEditable] && + [tableView numberOfSelectedRows] > 0); + } else if (anAction == @selector(openSelectedFiles:)) { + return ([[self fileStore] isEditable] && + [tableView numberOfSelectedRows] > 0); + } else + return YES; +} + +- (BOOL)validateMenuItem: (NSMenuItem *)anItem +{ + return [self validateAction: [anItem action]]; +} + +- (void)redisplay +{ + NSString *filePlural; + unsigned long numRecords; + + [self setSearchString: [self searchString]]; + [self setSelectedColumn: [self selectedColumn]]; + + numRecords = [[self sortedList] count]; + if (numRecords == 1) { + filePlural = myLocalizedString(@"LiFileSingular"); + } else { + filePlural = myLocalizedString(@"LiFilePlural"); + } + [statusLine setStringValue: + [NSString stringWithFormat: @"(%d %@)", numRecords, filePlural]]; + + [tableView reloadData]; +} +@synthesize statusLine; +@synthesize theTableColumns; +@synthesize theFileStore; +@synthesize theListPrefs; +@synthesize isAscending; +@synthesize tableView; +@synthesize theContextMenu; +@synthesize theFilter; +@synthesize theSavedSelection; +@synthesize theShownColumns; +@synthesize theSelectedColumn; +@synthesize inspectorController; +@synthesize theSearchString; +@end + +@implementation FileTableDelegate (CommonAccessors) +#if 0 +- (NSString *)group +{ + return [self filterForAttribute: LiGroupsAttribute]; +} + +- (void)setGroup: (NSString *)aGroupName +{ + if (aGroupName == nil) { + if ([self group] != nil) { + NSDictionary *filter; + + filter = [NSDictionary dictionaryWithObject: [self group] + forKey: LiGroupsAttribute]; + [self removeAttributeFilters: filter]; + } + } else { + NSDictionary *filter; + + filter = [NSDictionary dictionaryWithObject: aGroupName + forKey: LiGroupsAttribute]; + [self addAttributeFilters: filter]; + } + // We're re-filtering. + [self setActiveList: nil]; + + [self redisplay]; +} +#endif + +- (NSString *)group +{ + return [[self filter] value]; +} + +- (void)setGroup: (NSString *)aGroup +{ + LiFilter *filter; + + if (aGroup != nil) + filter = [LiFilter filterWithAttribute: LiGroupsAttribute + compareSelector: @selector(isEqual:) + value: aGroup]; + else + filter = nil; + [self setFilter: filter]; +} +@end + +@implementation FileTableDelegate (Accessors) +- (LiFileStore *)fileStore +{ + return theFileStore; +} + +- (void)setFileStore: (LiFileStore *)aFileStore +{ + [LiLog logAsDebug: @"[FileTableDelegate setFileStore: %@]", aFileStore]; + + if (aFileStore != theFileStore) { + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + if (theFileStore != nil) { + [defaultCenter removeObserver: self + name: LiFileChangedNotification + object: theFileStore]; + [theFileStore release]; + } + if (aFileStore != nil) { + [defaultCenter addObserver: self + selector: @selector(respondToFileChanged:) + name: LiFileChangedNotification + object: aFileStore]; + theFileStore = [aFileStore retain]; + } + } +} + +#if 0 +- (NSMutableDictionary *)attributeFilters +{ + return theFilters; +} + +- (void)setAttributeFilters: (NSMutableDictionary *)someFilters +{ + if (someFilters != theFilters) { + [someFilters retain]; + [theFilters release]; + theFilters = someFilters; + } +} +#endif + +- (LiFilter *)filter +{ + return theFilter; +} + +- (void)setFilter: (LiFilter *)aFilter +{ + [aFilter retain]; + [theFilter retain]; + theFilter = aFilter; +} + +- (NSMutableDictionary *)shownColumns +{ + return theShownColumns; +} + +- (void)setShownColumns: (NSMutableDictionary *)someColumns +{ + [someColumns retain]; + [theShownColumns release]; + theShownColumns = someColumns; +} + +- (NSArray *)sortedList +{ + if (theSortedList == nil) + return [self activeList]; + else + return theSortedList; +} + +- (void)setSortedList: (NSArray *)aFileList +{ + [aFileList retain]; + [theSortedList release]; + theSortedList = aFileList; +} + +- (NSArray *)activeList +{ + if (theActiveList == nil) + return [self fileList]; + else + return theActiveList; +} + +- (void)setActiveList: (NSArray *)aFileList +{ + if (aFileList != theActiveList) { + [aFileList retain]; + [theActiveList release]; + theActiveList = aFileList; + + [self setSortedList: nil]; + } +} + +- (NSArray *)fileList +{ + return [[self fileStore] filesMatchingFilter: [self filter]]; +} + +- (NSString *)searchString +{ + return theSearchString; +} + +- (NSArray *)filter: (NSArray *)aFileList + byString: (NSString *)aSearchString +{ + LiFileHandle *record; + NSMutableArray *subset; + + if ([aSearchString length] == 0) + return aFileList; + + subset = [NSMutableArray array]; + for (record in aFileList) { + NSString *filename; + NSRange range; + + filename = [[record filename] lowercaseString]; + range = [filename rangeOfString: aSearchString]; + if (range.location != NSNotFound) + [subset addObject: record]; + } + + return subset; +} + +- (void)setSearchString: (NSString *)aSearchString +{ + NSArray *tmpList; + + if (aSearchString == nil) { + aSearchString = @""; + tmpList = [self fileList]; + } else if ([aSearchString rangeOfString: theSearchString options: NSCaseInsensitiveSearch].location != NSNotFound) { + // Optimized filter - only need to select off the active list. + tmpList = [self filter: [self activeList] byString: aSearchString]; + } else { + tmpList = [self filter: [self fileList] byString: aSearchString]; + } + + [aSearchString retain]; + [theSearchString release]; + theSearchString = aSearchString; + + [self setActiveList: tmpList]; +} + +- (NSTableColumn *)selectedColumn +{ + return theSelectedColumn; +} + +- (void)setSelectedColumn: (NSTableColumn *)aColumn +{ + LiBrowserColumn *col; + struct SortContext context; + + col = [self columnForIdentifier: [aColumn identifier]]; + + context.ascending = isAscending; + context.getMethod = [col getMethod]; + context.compareMethod = [col compareMethod]; + [self setSelectedColumn: aColumn withContext: &context]; +} + +- (void)setSelectedColumn: (NSTableColumn *)aColumn + withContext: (void *)someContext +{ + struct SortContext *context; + NSArray *sortedList; + + [aColumn retain]; + [theSelectedColumn release]; + theSelectedColumn = aColumn; + + context = (struct SortContext *)someContext; + + if ([tableView highlightedTableColumn] != theSelectedColumn) { + [tableView setIndicatorImage: nil + inTableColumn: [tableView highlightedTableColumn]]; + } + + [tableView setHighlightedTableColumn: theSelectedColumn]; + if (theSelectedColumn != nil) { + if (context->ascending) + [tableView setIndicatorImage: ascendingSortingImage + inTableColumn: theSelectedColumn]; + else + [tableView setIndicatorImage: descendingSortingImage + inTableColumn: theSelectedColumn]; + + sortedList = [[self activeList] sortedArrayUsingFunction: contextSorter + context: someContext]; + + [self setSortedList: sortedList]; + } else { + [self setSortedList: nil]; + } +} + +- (NSMutableSet *)savedSelection +{ + return theSavedSelection; +} + +- (void)setSavedSelection: (NSMutableSet *)aSelection +{ + [aSelection retain]; + [theSavedSelection release]; + theSavedSelection = aSelection; +} + +- (NSMutableDictionary *)listPrefs +{ + if (theListPrefs == nil) { + NSDictionary *listPrefs; + + listPrefs = [[Preferences sharedPreferences] fileListPrefs]; + if (listPrefs != nil) { + theListPrefs = [[NSMutableDictionary alloc] initWithDictionary: listPrefs]; + } else + theListPrefs = [[NSMutableDictionary alloc] init]; + } + return theListPrefs; +} + +- (void)setListPrefs: (NSMutableDictionary *)listPrefs +{ + [listPrefs retain]; + [theListPrefs release]; + theListPrefs = listPrefs; + + [[Preferences sharedPreferences] setFileListPrefs: theListPrefs]; +} + +- (NSMutableDictionary *)columnPrefsForIdentifier: (NSString *)anIdentifier +{ + NSMutableDictionary *colPrefs, *retVal; + + colPrefs = [[self listPrefs] objectForKey: @"columns"]; + if (colPrefs == nil) { + colPrefs = [NSMutableDictionary dictionary]; + [[self listPrefs] setObject: colPrefs forKey: @"columns"]; + } + + retVal = [colPrefs objectForKey: anIdentifier]; + if (retVal == nil) { + retVal = [NSMutableDictionary dictionary]; + [colPrefs setObject: retVal forKey: anIdentifier]; + } + + return retVal; +} + +- (void)setColumnPrefs: (NSMutableDictionary *)columnPrefs + forIdentifier: (NSString *)anIdentifier +{ + NSMutableDictionary *colPrefs; + + colPrefs = [[self listPrefs] objectForKey: @"columns"]; + if (colPrefs == nil) { + colPrefs = [NSMutableDictionary dictionary]; + [[self listPrefs] setObject: colPrefs forKey: @"columns"]; + } + + [colPrefs setObject: columnPrefs forKey: anIdentifier]; + + [[Preferences sharedPreferences] setFileListPrefs: theListPrefs]; +} + +- (NSTableView *)tableView +{ + return tableView; +} +@end + +@implementation LiFileHandle (GUIStuff) +- (void)revealInFinder +{ + NSURL *fileURL; + + fileURL = [self url]; + if ([fileURL isFileURL]) { + [[NSWorkspace sharedWorkspace] selectFile: + [fileURL path] inFileViewerRootedAtPath: @""]; + } +} +@end \ No newline at end of file diff --git a/Liaison/FindController.h b/Liaison/FindController.h new file mode 100644 index 0000000..5f36e08 --- /dev/null +++ b/Liaison/FindController.h @@ -0,0 +1,43 @@ +// +// FindController.h +// Liaison +// +// Created by Brian Cully on Sat Aug 23 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@interface FindController : NSObject +{ + IBOutlet NSBox *theFilterBox; + IBOutlet NSTableView *theFileList; + IBOutlet NSView *theFindView; + IBOutlet NSWindow *theFindWindow; + IBOutlet NSPopUpButton *theLibraryPopUp; + IBOutlet NSPopUpButton *theOperatorPopUp; + + LiFilter *theFilter; + + NSMutableDictionary *theTableColumns; +} +- (IBAction)showWindow: (id)sender; + +- (IBAction)libraryUpdated: (id)sender; + +- (IBAction)addFilterRow: (id)sender; +- (IBAction)removeFilterRow: (id)sender; +@property (retain) NSPopUpButton *theOperatorPopUp; +@property (retain,getter=filter) LiFilter *theFilter; +@property (retain,getter=tableColumns) NSMutableDictionary *theTableColumns; +@property (retain) NSView *theFindView; +@property (retain) NSWindow *theFindWindow; +@property (retain) NSPopUpButton *theLibraryPopUp; +@property (retain) NSBox *theFilterBox; +@property (retain) NSTableView *theFileList; +@end + +@interface FindController (Accessors) +- (LiFilter *)filter; +- (void)setFilter: (LiFilter *)aFilter; +- (NSMutableDictionary *)tableColumns; +- (void)setTableColumns: (NSMutableDictionary *)someColumns; +@end \ No newline at end of file diff --git a/Liaison/FindController.m b/Liaison/FindController.m new file mode 100644 index 0000000..8b16bbf --- /dev/null +++ b/Liaison/FindController.m @@ -0,0 +1,154 @@ +// +// FindController.m +// Liaison +// +// Created by Brian Cully on Sat Aug 23 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "FindController.h" + +#import "FileTableDelegate.h" + +@implementation FindController (WindowDelegate) +- (void)windowDidBecomeKey: (NSNotification *)aNotificatin +{ + [LiLog logAsDebug: @"[FindController windowDidBecomeKey]"]; + [[theFindWindow firstResponder] becomeFirstResponder]; +} +@end + +@implementation FindController +- (id)init +{ + self = [super init]; + if (self != nil) { + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(respondToFileStoreChanged:) + name: LiFileStoresChangedNotification + object: nil]; + } + return self; +} + +- (void)dealloc +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self]; + + [self setFilter: nil]; + [self setTableColumns: nil]; + + [super dealloc]; +} + +- (IBAction)showWindow: (id)sender +{ + FileTableDelegate *fileDelegate; + + [LiLog logAsDebug: @"[FindController showWindow: (sender)]"]; + + fileDelegate = [theFileList delegate]; + [fileDelegate setFileStore: [[LiFileStore allFileStores] objectAtIndex: 0]]; + [fileDelegate setGroup: nil]; + + [theFindWindow makeKeyAndOrderFront: self]; +} + +- (IBAction)libraryUpdated: (id)sender +{ + LiFileStore *selectedStore; + int itemTag; + + itemTag = [[theLibraryPopUp selectedItem] tag]; + selectedStore = [LiFileStore fileStoreWithID: [NSNumber numberWithInt: itemTag]]; + if (selectedStore != nil) { + FileTableDelegate *fileDelegate; + + [LiLog logAsDebug: @"Selected store: %@", [selectedStore name]]; + fileDelegate = [theFileList delegate]; + [fileDelegate setFileStore: selectedStore]; + [fileDelegate setGroup: nil]; + } +} + +- (IBAction)addFilterRow: (id)sender +{ + [LiLog logAsDebug: @"[FindController addFilterRow: (sender)]"]; +} + +- (IBAction)removeFilterRow: (id)sender +{ + [LiLog logAsDebug: @"[FindController removeFilterRow: (sender)]"]; +} +@synthesize theLibraryPopUp; +@synthesize theFilter; +@synthesize theFileList; +@synthesize theFindView; +@synthesize theTableColumns; +@synthesize theFindWindow; +@synthesize theFilterBox; +@synthesize theOperatorPopUp; +@end + +@implementation FindController (Accessors) +- (LiFilter *)filter +{ + return theFilter; +} + +- (void)setFilter: (LiFilter *)aFilter +{ + [aFilter retain]; + [theFilter release]; + aFilter = theFilter; +} + +- (NSMutableDictionary *)tableColumns +{ + return theTableColumns; +} + +- (void)setTableColumns: (NSMutableDictionary *)someColumns +{ + [someColumns retain]; + [theTableColumns release]; + theTableColumns = someColumns; +} +@end + +@implementation FindController (Private) +- (void)respondToFileStoreChanged: (NSNotification *)aNotification +{ + LiFileStore *fileStore; + NSEnumerator *fsEnum; + NSMenu *libraryMenu; + int i; + + [LiLog logAsDebug: @"[FindController respondToFileStoreChanged: (notification)]"]; + [LiLog indentDebugLog]; + + libraryMenu = [[[NSMenu alloc] initWithTitle: @"Libraries"] autorelease]; + i = 0; + fsEnum = [LiFileStore fileStoreEnumerator]; + for (i = 0; (fileStore = [fsEnum nextObject]) != nil; i++) { + NSMenuItem *fsItem; + + [LiLog logAsDebug: @"found file store: %@", [fileStore name]]; + fsItem = [[[NSMenuItem alloc] initWithTitle: [fileStore name] + action: nil + keyEquivalent: @""] autorelease]; + [fsItem setImage: [fileStore icon]]; + [fsItem setTag: [[fileStore storeID] intValue]]; + [libraryMenu insertItem: fsItem atIndex: i]; + } + [theLibraryPopUp setMenu: libraryMenu]; + + [LiLog unindentDebugLog]; +} +@end \ No newline at end of file diff --git a/Liaison/FlippedBox.h b/Liaison/FlippedBox.h new file mode 100644 index 0000000..6d6ef0f --- /dev/null +++ b/Liaison/FlippedBox.h @@ -0,0 +1,6 @@ +/* FlippedBox */ + +@interface FlippedBox : NSBox +{ +} +@end diff --git a/Liaison/FlippedBox.m b/Liaison/FlippedBox.m new file mode 100644 index 0000000..fddf3e8 --- /dev/null +++ b/Liaison/FlippedBox.m @@ -0,0 +1,8 @@ +#import "FlippedBox.h" + +@implementation FlippedBox +- (BOOL)isFlipped +{ + return YES; +} +@end diff --git a/Liaison/Group.h b/Liaison/Group.h new file mode 100644 index 0000000..2112bff --- /dev/null +++ b/Liaison/Group.h @@ -0,0 +1,52 @@ +// +// Group.h +// Liaison +// +// Created by Brian Cully on Tue Feb 04 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +typedef enum _GroupType { LEAF, BRANCH } GroupType; + +@interface Group : NSObject +{ + NSString *name; + GroupType type; + NSImage *icon; + NSMutableArray *children; + Group *parent; + + LiFileStore *theFileStore; +} ++ (Group *)groupWithName: (NSString *)aName; ++ (Group *)groupWithName: (NSString *)aName andType: (GroupType)aType; +- (Group *)initWithName: (NSString *)aName; +- (Group *)initWithName: (NSString *)aName andType: (GroupType)aType; + +- (id)initWithContentsOfFile: (NSString *)aFilename; +- (BOOL)writeToFile: (NSString *)aFilename; + +- (LiFileStore *)fileStore; +- (void)setFileStore: (LiFileStore *)aFileStore; + +- (NSString *)name; +- (GroupType)type; +- (void)setName: (NSString *)aName; +- (void)setType: (GroupType)aType; +- (NSImage *)icon; +- (void)setIcon: (NSImage *)anIcon; + +- (Group *)parent; + +- (int)numberOfChildren; +- (NSEnumerator *)childEnumerator; +- (BOOL)hasChild: (id)aChild; +- (void)addChild: (id)aChild; +- (void)removeChild: (id)aChild; +- (Group *)childNamed: (NSString *)aName; +- (void)removeChildNamed: (NSString *)aName; +- (id)childAtIndex: (int)index; +- (void)removeChildAtIndex: (int)index; +@property (retain) NSMutableArray *children; +@property (retain,getter=fileStore) LiFileStore *theFileStore; +@end diff --git a/Liaison/Group.m b/Liaison/Group.m new file mode 100644 index 0000000..f975f60 --- /dev/null +++ b/Liaison/Group.m @@ -0,0 +1,321 @@ +// +// Group.m +// Liaison +// +// Created by Brian Cully on Tue Feb 04 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// +#import "Group.h" + +@implementation Group (Copying) +- (id)copyWithZone: (NSZone *)aZone +{ + Group *tmpGroup; + + tmpGroup = [[Group alloc] initWithName: [self name] andType: [self type]]; + [tmpGroup setIcon: [self icon]]; + [tmpGroup setFileStore: [self fileStore]]; + tmpGroup->parent = parent; // XXX + tmpGroup->children = children; // XXX + + return tmpGroup; +} + +- (unsigned)hash +{ + unsigned nameHash, storeHash; + + storeHash = (unsigned)[[[self fileStore] storeID] performSelector: @selector(hash)]; + nameHash = [[self name] hash]; + return (storeHash ^ nameHash); +} + +- (BOOL)isEqual: (id)anObject +{ + if ([anObject isKindOfClass: [self class]]) { + Group *otherGroup; + id myStoreID, otherStoreID; + + myStoreID = [[self fileStore] storeID]; + otherGroup = anObject; + otherStoreID = [[otherGroup fileStore] storeID]; + + if ([myStoreID performSelector: @selector(compare:) withObject: otherStoreID] && + [[self name] isEqualToString: [otherGroup name]]) + return YES; + else + return NO; + } + + return NO; +} +@end + +@implementation Group ++ (Group *)groupWithName: (NSString *)aName +{ + return [[[self alloc] initWithName: aName] autorelease]; +} + ++ (Group *)groupWithName: (NSString *)aName andType: (GroupType)aType +{ + return [[[self alloc] initWithName: aName andType: aType] autorelease]; +} + +- (Group *)initWithName: (NSString *)aName +{ + return [self initWithName: aName andType: BRANCH]; +} + +- (Group *)initWithName: (NSString *)aName andType: (GroupType)aType; +{ + self = [super init]; + + [self setName: aName]; + [self setType: aType]; + icon = [[NSImage imageNamed: LiNormalGroupIcon] retain]; + children = [[NSMutableArray alloc] init]; + + return self; +} + +- (id)init +{ + NSException *myException; + + [self autorelease]; + + myException = [NSException exceptionWithName: @"GroupInitFailure" + reason: @"[[Group alloc] init] isn't supported." + userInfo: nil]; + [myException raise]; + return nil; +} + +- (void)dealloc +{ + [self setName: nil]; + [icon release]; + [children release]; + [self setFileStore: nil]; + + [super dealloc]; +} + +- (id)initWithContentsOfFile: (NSString *)aFilename +{ + NSArray *groupArray; + NSDictionary *groupDict; + NSString *groupname; + + groupDict = [NSDictionary dictionaryWithContentsOfFile: aFilename]; + self = [self initWithName: [groupDict objectForKey: @"name"]]; + + groupArray = [groupDict objectForKey: @"children"]; + for (groupname in groupArray) { + Group *newGroup; + + // XXX - should encode type + newGroup = [[[Group alloc] initWithName: groupname + andType: LEAF] autorelease]; + [newGroup setIcon: [NSImage imageNamed: LiNormalGroupIcon]]; + [self addChild: newGroup]; + } + return self; +} + +- (BOOL)writeToFile: (NSString *)aFilename +{ + Group *group; + NSMutableArray *groupArray; + NSMutableDictionary *groupDict; + + groupDict = [NSMutableDictionary dictionary]; + + groupArray = [NSMutableArray array]; + for (group in children) { + [groupArray addObject: [group name]]; + } + + [groupDict setObject: name forKey: @"name"]; + [groupDict setObject: groupArray forKey: @"children"]; + + return [groupDict writeToFile: aFilename atomically: NO]; +} + +- (LiFileStore *)fileStore +{ + return theFileStore; +} + +- (void)setFileStore: (LiFileStore *)aFileStore +{ + [aFileStore retain]; + [theFileStore release]; + theFileStore = aFileStore; +} + +- (id)initWithCoder: (NSCoder *)coder +{ + NSString *typeString; + + self = [super init]; + + if ([coder allowsKeyedCoding]) { + [self setName: [coder decodeObjectForKey: @"name"]]; + typeString = [coder decodeObjectForKey: @"type"]; + children = [[coder decodeObjectForKey: @"children"] retain]; + } else { + [self setName: [coder decodeObject]]; + typeString = [coder decodeObject]; + children = [[coder decodeObject] retain]; + } + + if ([typeString isEqualToString: @"LEAF"]) + [self setType: LEAF]; + else + [self setType: BRANCH]; + + icon = [[NSImage imageNamed: LiNormalGroupIcon] retain]; + + return self; +} + +- (void)encodeWithCoder: (NSCoder *)coder +{ + NSString *typeString; + + if ([self type] == LEAF) + typeString = @"LEAF"; + else + typeString = @"BRANCH"; + + if ([coder allowsKeyedCoding]) { + [coder encodeObject: [self name] forKey: @"name"]; + [coder encodeObject: typeString forKey: @"type"]; + [coder encodeObject: children forKey: @"children"]; + } else { + [coder encodeObject: [self name]]; + [coder encodeObject: typeString]; + [coder encodeObject: children]; + } +} + +- (NSString *)name +{ + return name; +} + +- (GroupType)type +{ + return type; +} + +- (void)setName: (NSString *)aName +{ + [aName retain]; + [name release]; + name = aName; +} + +- (void)setType: (GroupType)aType +{ + type = aType; +} + +- (NSImage *)icon +{ + return icon; +} + +- (void)setIcon: (NSImage *)anIcon +{ + [anIcon retain]; + [icon release]; + icon = anIcon; +} + +- (Group *)parent +{ + return parent; +} + +- (void)setParent: (Group *)aParent +{ + [aParent retain]; + [parent release]; + parent = aParent; +} + +- (int)numberOfChildren +{ + return [children count]; +} + +- (BOOL)hasChild: (id)aChild +{ + return [children containsObject: aChild]; +} + +- (NSEnumerator *)childEnumerator +{ + return [children objectEnumerator]; +} + +- (void)addChild: (id)aChild +{ + [children addObject: aChild]; + [aChild setParent: self]; +} + +- (void)removeChild: (id)aChild +{ + [aChild setParent: nil]; + [children removeObject: aChild]; +} + +- (Group *)childNamed: (NSString *)aName +{ + Group *child; + int i, numberOfChildren; + + child = nil; + numberOfChildren = [children count]; + for (i = 0; i < numberOfChildren; i++) { + child = [children objectAtIndex: i]; + if ([[child name] isEqualToString: aName]) + break; + } + if (i < numberOfChildren) + return child; + return nil; +} + +- (void)removeChildNamed: (NSString *)aName +{ + int i, numberOfChildren; + + numberOfChildren = [children count]; + for (i = 0; i < numberOfChildren; i++) { + Group *child; + + child = [children objectAtIndex: i]; + if ([[child name] isEqualToString: aName]) + break; + } + if (i < numberOfChildren) + [children removeObjectAtIndex: i]; +} + +- (id)childAtIndex: (int)index +{ + return [children objectAtIndex: index]; +} + +- (void)removeChildAtIndex: (int)index +{ + [children removeObjectAtIndex: index]; +} +@synthesize children; +@synthesize theFileStore; +@end diff --git a/Liaison/GroupTableDelegate.h b/Liaison/GroupTableDelegate.h new file mode 100644 index 0000000..d31ef42 --- /dev/null +++ b/Liaison/GroupTableDelegate.h @@ -0,0 +1,43 @@ +/* GroupTableDelegate */ + +@class Group; +@class FileTableDelegate; +@class WindowController; + +@interface GroupTableDelegate : NSObject +{ + IBOutlet NSOutlineView *outlineView; + IBOutlet NSTextField *statusLine; + IBOutlet WindowController *theWindow; + IBOutlet FileTableDelegate *theFileDelegate; + IBOutlet NSMenu *theContextMenu; + + Group *theGroup; + Group *theSelectedGroup; + + NSEvent *theMouseDownEvent; +} +- (IBAction)addGroup:(id)sender; + +- (NSSize)minSize; +- (void)respondToFileStoreChanged: (NSNotification *)aNotification; + +- (BOOL)validateAction: (SEL)anAction; + +- (void)highlightDefaultGroup; +@property (retain,getter=group) Group *theGroup; +@property (retain) NSEvent *theMouseDownEvent; +@property (retain) NSTextField *statusLine; +@property (retain) FileTableDelegate *theFileDelegate; +@property (retain) NSMenu *theContextMenu; +@property (retain,getter=selectedGroup) Group *theSelectedGroup; +@property (retain) NSOutlineView *outlineView; +@property (retain) WindowController *theWindow; +@end + +@interface GroupTableDelegate (Accessors) +- (Group *)group; +- (void)setGroup: (Group *)aGroup; +- (Group *)selectedGroup; +- (void)setSelectedGroup: (Group *)aGroup; +@end \ No newline at end of file diff --git a/Liaison/GroupTableDelegate.m b/Liaison/GroupTableDelegate.m new file mode 100644 index 0000000..e744534 --- /dev/null +++ b/Liaison/GroupTableDelegate.m @@ -0,0 +1,611 @@ +#import "GroupTableDelegate.h" + +#import "FileTableDelegate.h" +#import "Group.h" +#import "ImageAndTextCell.h" +#import "WindowController.h" + +static NSString * +myLocalizedString(NSString *aString) +{ + return NSLocalizedStringFromTable(aString, @"WindowElements", @""); +} + +@interface GroupTableDelegate (Private) +- (BOOL)groupIsLibrary: (Group *)aGroup; +@end + +@implementation GroupTableDelegate (LiTableViewDelegate) +- (void)outlineViewDidBecomeFirstResponder: (NSOutlineView *)anOutlineView +{ + [LiLog logAsDebug: @"[GroupTableDelegate becameFirstResponder]"]; +} + +- (void)deleteSelectedRowsInOutlineView: (NSOutlineView *)anOutlineView +{ + Group *removedGroup; + int selectedRow; + + selectedRow = [outlineView selectedRow] - 1; + + removedGroup = [anOutlineView itemAtRow: [anOutlineView selectedRow]]; + if ([self groupIsLibrary: removedGroup] == NO) { + LiFileHandle *file; + LiFilter *groupFilter; + NSArray *filesInGroup; + NSDictionary *removedGroupAttribute; + NSString *groupname; + + groupname = [removedGroup name]; + groupFilter = [LiFilter filterWithAttribute: LiGroupsAttribute + compareSelector: @selector(isEqual:) + value: groupname]; + + filesInGroup = [[removedGroup fileStore] filesMatchingFilter: groupFilter]; + for (file in filesInGroup) { + [file removeFromGroup: groupname]; + } + + removedGroupAttribute = [NSDictionary dictionaryWithObject: groupname + forKey: LiGroupsAttribute]; + [[[removedGroup fileStore] delegate] removeDefaultAttribute: removedGroupAttribute + fromFileStore: [removedGroup fileStore]]; + + [[removedGroup parent] removeChild: removedGroup]; + + [[removedGroup fileStore] synchronize]; + + [outlineView reloadData]; + [outlineView selectRow: selectedRow byExtendingSelection: NO]; + } +} + +- (void)mouseDownEvent: (NSEvent *)mouseEvent +{ + [LiLog logAsDebug: @"[GroupTableDelegate mouseDownEvent: %@]", mouseEvent]; + theMouseDownEvent = mouseEvent; +} +@end + +@implementation GroupTableDelegate (OutlineViewDelegate) +- (id)outlineView: (NSOutlineView *)outlineView + child: (int)index ofItem:(Group *)item +{ + if (item == nil) + item = theGroup; + + return [[item childAtIndex: index] retain]; +} + +- (BOOL)outlineView: (NSOutlineView *)outlineView + isItemExpandable: (Group *)item +{ + if (item == nil) + item = theGroup; + + return ([item type] == BRANCH); +} + +- (int)outlineView: (NSOutlineView *)outlineView +numberOfChildrenOfItem: (Group *)item +{ + if (item == nil) + item = theGroup; + + return [item numberOfChildren]; +} + +- (id)outlineView: (NSOutlineView *)outlineView +objectValueForTableColumn: (NSTableColumn *)aTableColumn + byItem: (Group *)item +{ + if (item == nil) + item = theGroup; + + if ([[aTableColumn identifier] isEqualToString: @"name"]) + return [[item name] retain]; + return @"nil"; +} + +- (void)outlineView: (NSOutlineView *)anOutlineView + setObjectValue: (id)anObject + forTableColumn: (NSTableColumn *)aTableColumn + byItem: (id)anItem +{ + NSArray *groupFiles; + NSDictionary *renamedGroupAttribute; + NSString *oldGroupName, *newGroupName; + LiFileHandle *file; + LiFilter *groupFilter; + Group *renamedGroup; + + renamedGroup = anItem; + groupFilter = [LiFilter filterWithAttribute: LiGroupsAttribute + compareSelector: @selector(isEqual:) + value: [renamedGroup name]]; + groupFiles = [[renamedGroup fileStore] filesMatchingFilter: groupFilter]; + oldGroupName = [renamedGroup name]; + newGroupName = anObject; + for (file in groupFiles) { + [file renameGroup: oldGroupName toGroup: newGroupName]; + } + [renamedGroup setName: newGroupName]; + + renamedGroupAttribute = [NSDictionary dictionaryWithObject: oldGroupName + forKey: LiGroupsAttribute]; + [[[renamedGroup fileStore] delegate] changeDefaultValueForAttribute: renamedGroupAttribute + toValue: newGroupName + inFileStore: [renamedGroup fileStore]]; + + [[renamedGroup fileStore] synchronize]; + [self setSelectedGroup: renamedGroup]; +} + +- (BOOL)outlineView: (NSOutlineView *)outlineView +shouldEditTableColumn: (NSTableColumn *)tableColumn + item: (id)anItem +{ + Group *group; + + group = anItem; + return [[group fileStore] isEditable]; +} + +- (void)outlineView: (NSOutlineView *)outlineView + willDisplayCell: (NSCell *)aCell + forTableColumn: (NSTableColumn *)aColumn + item: (id)theItem +{ + if (theItem == nil) + return; + + if ([[aColumn identifier] isEqualToString: @"name"]) { + [aCell setImage: [[theItem icon] retain]]; + //[aCell setStringValue: [theItem name]]; + } +} + +- (BOOL)outlineView: (NSOutlineView *)anOutlineView + shouldSelectItem: (id)item +{ + return YES; +} + +- (void)outlineViewSelectionDidChange: (NSNotification *)aNotification +{ + Group *group; + + [LiLog logAsDebug: @"[GroupTableDelegate outlineViewSelectionDidChange: (Notification)]"]; + [LiLog indentDebugLog]; + + group = [outlineView itemAtRow: [outlineView selectedRow]]; + [self setSelectedGroup: group]; + + [LiLog unindentDebugLog]; +} + +- (NSDragOperation)outlineView: (NSOutlineView*)olv + validateDrop: (id )info + proposedItem: (id)anItem + proposedChildIndex: (int)childIndex +{ + Group *group; + NSPasteboard *pboard; + + group = anItem; + if (group == nil) + return NSDragOperationNone; + + if (childIndex != NSOutlineViewDropOnItemIndex) + return NSDragOperationNone; + + if ([[group fileStore] isEditable] == NO) + return NSDragOperationNone; + + pboard = [info draggingPasteboard]; + if ([pboard availableTypeFromArray: + [NSArray arrayWithObjects: + LiaisonPboardType, NSFilenamesPboardType, nil]]) + return NSDragOperationCopy; + + return NO; +} + +- (BOOL)outlineView: (NSOutlineView*)olv + acceptDrop: (id )info + item: (id)anItem + childIndex: (int)childIndex +{ + Group *item; + NSPasteboard *pboard; + NSString *groupName; + + item = anItem; + if ([self groupIsLibrary: item]) + groupName = nil; + else + groupName = [item name]; + + pboard = [info draggingPasteboard]; + + if ([pboard availableTypeFromArray: + [NSArray arrayWithObject: LiaisonPboardType]]) { + NSArray *theFileList; + NSData *theFileListData; + LiFileHandle *file; + + theFileListData = [pboard dataForType: LiaisonPboardType]; + theFileList = [NSKeyedUnarchiver unarchiveObjectWithData: + theFileListData]; + for (file in theFileList) { + [file addToGroup: groupName]; + } + } else if ([pboard availableTypeFromArray: + [NSArray arrayWithObject: NSFilenamesPboardType]]) { + NSArray *pathList; + + pathList = [pboard propertyListForType: NSFilenamesPboardType]; + if ([pathList count] > 0) { + [[item fileStore] addPaths: pathList toGroup: [item name]]; + return YES; + } else + return NO; + } + + [[item fileStore] synchronize]; + + return YES; +} + +- (BOOL)outlineView: (NSOutlineView *)anOutlineView + writeItems: (NSArray *)someItems + toPasteboard: (NSPasteboard *)aPasteboard +{ + Group *item; + NSMutableArray *promisePboard; + + promisePboard = [NSMutableArray array]; + + for (item in someItems) { + [promisePboard addObject: [item name]]; + } + + if ([promisePboard count] > 0) { + NSPoint dragPosition; + NSRect imageLocation; + + dragPosition = [outlineView convertPoint: [theMouseDownEvent locationInWindow] + fromView: nil]; + imageLocation.origin = dragPosition; + imageLocation.size = NSMakeSize(32,32); + [outlineView dragPromisedFilesOfTypes: [NSArray arrayWithObject: @""] + fromRect: NSMakeRect(0.0, 0.0, 0.0, 0.0) + source: self + slideBack: YES event: theMouseDownEvent]; + return YES; + } + + // We always return NO, because we start the drag ourselves, which is lame, + // but we have to in order to support promised files. + return NO; +} + +/* We get this in response to dragging a directory to another app. */ +- (NSArray *)namesOfPromisedFilesDroppedAtDestination: (NSURL *)dropDestination +{ + NSArray *filenames; + NSFileManager *defaultManager; + NSString *dropDir, *path; + int suffix; + + defaultManager = [NSFileManager defaultManager]; + dropDir = [dropDestination path]; + for (suffix = 1; suffix <= 100; suffix++) { + NSString *myDir; + + if (suffix > 1) + myDir = [NSString stringWithFormat: @"DEBUGgroupName %d", suffix]; + else + myDir = @"DEBUGgroupName"; + + path = [dropDir stringByAppendingPathComponent: myDir]; + if ([defaultManager fileExistsAtPath: path] == NO) { + break; + } + } + + filenames = nil; + if (suffix <= 100) { + [LiLog logAsDebug: @"Create dir: %@", path]; + if ([defaultManager createDirectoryAtPath: path + attributes: nil] == YES) + filenames = [NSArray arrayWithObject: path]; + } + return filenames; +} +@end + +@implementation GroupTableDelegate +- (id)init +{ + NSNotificationCenter *defaultCenter; + + self = [super init]; + + [self setGroup: nil]; + + // We want to watch for file changes, so we can change our view. + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(respondToFileStoreChanged:) + name: LiFileStoresChangedNotification + object: nil]; + [defaultCenter addObserver: self + selector: @selector(respondToFileStoreChanged:) + name: LiFileChangedNotification + object: nil]; + + return self; +} + +- (void)dealloc +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self]; + + [self setGroup: nil]; + [super dealloc]; +} + +- (void)awakeFromNib +{ + NSTableColumn *tableColumn; + ImageAndTextCell *imageAndTextCell; + + tableColumn = [outlineView tableColumnWithIdentifier: @"name"]; + imageAndTextCell = [[[ImageAndTextCell alloc] init] autorelease]; + [imageAndTextCell setEditable: YES]; + [tableColumn setDataCell: imageAndTextCell]; + + [outlineView registerForDraggedTypes: + [NSArray arrayWithObjects: + LiaisonPboardType, NSFilenamesPboardType, nil]]; +} + +- (void)respondToFileStoreChanged: (NSNotification *)aNotification +{ + Group *myGroups, *child; + LiFileStore *fileStore; + NSEnumerator *fsEnum, *groupEnum; + NSMutableSet *oldFileStores, *newFileStores; + NSString *groupName; + BOOL needsRedisplay; + + myGroups = [self group]; + if (myGroups == nil) { + myGroups = [Group groupWithName: @"ALL" andType: BRANCH]; + [self setGroup: myGroups]; + } + needsRedisplay = NO; + + newFileStores = [NSMutableSet setWithArray: [LiFileStore allFileStores]]; + oldFileStores = [NSMutableSet set]; + groupEnum = [myGroups childEnumerator]; + while ((child = [groupEnum nextObject]) != nil) { + [oldFileStores addObject: [child fileStore]]; + } + + // Remove old file stores. + [oldFileStores minusSet: newFileStores]; + if ([oldFileStores count] > 0) + needsRedisplay = YES; + + groupEnum = [oldFileStores objectEnumerator]; + while ((groupName = [[groupEnum nextObject] name]) != nil) { + [LiLog logAsDebug: @"Removing fileStore for %@ from the group list.", groupName]; + [myGroups removeChildNamed: groupName]; + } + + fsEnum = [LiFileStore fileStoreEnumerator]; + while ((fileStore = [fsEnum nextObject]) != nil) { + Group *storeGroup; + NSArray *allStoreGroups; + NSEnumerator *groupEnum; + + allStoreGroups = [fileStore allValuesForAttribute: LiGroupsAttribute]; + storeGroup = [myGroups childNamed: [fileStore name]]; + if (storeGroup == nil) { + needsRedisplay = YES; + storeGroup = [Group groupWithName: [fileStore name] andType: BRANCH]; + + [myGroups addChild: storeGroup]; + } else { + NSMutableSet *oldGroups, *newGroups; + + newGroups = [NSMutableSet setWithArray: allStoreGroups]; + oldGroups = [NSMutableSet set]; + groupEnum = [storeGroup childEnumerator]; + while ((child = [groupEnum nextObject]) != nil) { + [oldGroups addObject: [child name]]; + } + + // Remove old groups. + [oldGroups minusSet: newGroups]; + if ([oldGroups count] > 0) + needsRedisplay = YES; + + for (groupName in oldGroups) { + [LiLog logAsDebug: @"Removing group %@ from group list.", groupName]; + [storeGroup removeChildNamed: groupName]; + } + } + + // Always set this. + [storeGroup setIcon: [fileStore icon]]; + [storeGroup setFileStore: fileStore]; + + // Add new groups. + for (groupName in allStoreGroups) { + Group *subGroup; + + if ([storeGroup childNamed: groupName] == nil) { + needsRedisplay = YES; + subGroup = [Group groupWithName: groupName andType: LEAF]; + [subGroup setFileStore: fileStore]; + [storeGroup addChild: subGroup]; + } + } + } + + if (needsRedisplay) { + [outlineView reloadData]; + } +} + +- (void)highlightDefaultGroup +{ + Group *firstGroup; + + firstGroup = [outlineView itemAtRow: 0]; + [outlineView selectRow: 0 byExtendingSelection: NO]; +} + +- (IBAction)addGroup:(id)sender +{ + Group *group; + NSString *untitledName; + unsigned long untitledPrefix; + + [LiLog logAsDebug: @"[GroupTableDelegate addGroup: sender]"]; + [LiLog indentDebugLog]; + + group = [self selectedGroup]; + if ([[group fileStore] isEditable] == NO) { + [LiLog logAsDebug: @"Group %@ isn't editable.", [[group fileStore] name]]; + } + + if ([[group fileStore] isEditable]) { + Group *newGroup; + NSDictionary *newGroupAttribute; + + if ([group type] == LEAF) + group = [group parent]; + [LiLog logAsDebug: @"adding to group: %@", [group name]]; + + untitledPrefix = 1; + untitledName = myLocalizedString(@"LiUntitledGroupName"); + while ([group childNamed: untitledName] != nil) { + untitledPrefix++; + untitledName = [NSString stringWithFormat: @"%@ %lu", + myLocalizedString(@"LiUntitledGroupName"), untitledPrefix]; + } + + newGroupAttribute = [NSDictionary dictionaryWithObject: untitledName + forKey: LiGroupsAttribute]; + [[[group fileStore] delegate] addDefaultAttribute: newGroupAttribute + toFileStore: [group fileStore]]; + + newGroup = [Group groupWithName: untitledName andType: LEAF]; + [newGroup setFileStore: [group fileStore]]; + [group addChild: newGroup]; + + [outlineView reloadData]; + [outlineView expandItem: group]; + } + + [LiLog unindentDebugLog]; +} + +- (NSSize)minSize +{ + float rowHeight; + int numRows; + + [LiLog logAsDebug: @"[GroupTableDelegate minSize]"]; + rowHeight = [outlineView rowHeight]; + numRows = [outlineView numberOfRows]; + return NSMakeSize([outlineView frame].size.width, rowHeight * numRows); +} + +- (BOOL)validateAction: (SEL)anAction +{ + //[LiLog logAsDebug: @"[GroupTableDelegate validateAction: %@]", NSStringFromSelector(anAction)]; + if (anAction == @selector(copy:)) + return [outlineView numberOfSelectedRows] > 0; + else if (anAction == @selector(delete:)) { + if ([self groupIsLibrary: [self selectedGroup]]) + return NO; + else + return [[[self selectedGroup] fileStore] isEditable]; + } else if (anAction == @selector(addGroup:)) { + return [[[self selectedGroup] fileStore] isEditable]; + } else + return YES; +} + +- (BOOL)validateMenuItem: (NSMenuItem *)anItem +{ + return [self validateAction: [anItem action]]; +} +@synthesize theGroup; +@synthesize theMouseDownEvent; +@synthesize theWindow; +@synthesize theFileDelegate; +@synthesize theSelectedGroup; +@synthesize theContextMenu; +@synthesize statusLine; +@synthesize outlineView; +@end + +@implementation GroupTableDelegate (Accessors) +- (Group *)group +{ + return theGroup; +} + +- (void)setGroup: (Group *)aGroup +{ + [aGroup retain]; + [theGroup release]; + theGroup = aGroup; + + [outlineView reloadData]; + [self highlightDefaultGroup]; +} + +- (Group *)selectedGroup +{ + return theSelectedGroup; +} + +- (void)setSelectedGroup: (Group *)aGroup +{ + [aGroup retain]; + [theSelectedGroup release]; + theSelectedGroup = aGroup; + + [theFileDelegate saveSelectionOfTableView: [theFileDelegate tableView]]; + + [theFileDelegate setFileStore: [theSelectedGroup fileStore]]; + + if ([self groupIsLibrary: theSelectedGroup]) { + [theFileDelegate setGroup: nil]; + } else { + [theFileDelegate setGroup: [theSelectedGroup name]]; + } + [theFileDelegate redisplay]; + [theFileDelegate restoreSelectionToTableView: [theFileDelegate tableView] refresh: YES]; +} +@end + +@implementation GroupTableDelegate (Private) +- (BOOL)groupIsLibrary: (Group *)aGroup +{ + if ([[self group] hasChild: aGroup]) + return YES; + else + return NO; +} +@end diff --git a/Liaison/ImageAndTextCell.h b/Liaison/ImageAndTextCell.h new file mode 100644 index 0000000..5c39369 --- /dev/null +++ b/Liaison/ImageAndTextCell.h @@ -0,0 +1,20 @@ +// +// ImageAndTextCell.h +// +// Copyright (c) 2001-2002, Apple. All rights reserved. +// + +@interface ImageAndTextCell : NSTextFieldCell +{ +@private + NSImage *image; +} + +- (void)drawWithFrame: (NSRect)cellFrame inView: (NSView *)controlView; +- (NSSize)cellSize; +@end + +@interface ImageAndTextCell (Accessors) +- (NSImage *)image; +- (void)setImage: (NSImage *)anImage; +@end \ No newline at end of file diff --git a/Liaison/ImageAndTextCell.m b/Liaison/ImageAndTextCell.m new file mode 100644 index 0000000..2a81bb6 --- /dev/null +++ b/Liaison/ImageAndTextCell.m @@ -0,0 +1,156 @@ +/* + ImageAndTextCell.m + Copyright (c) 2001-2002, Apple Computer, Inc., all rights reserved. + Author: Chuck Pisula + + Milestones: + Initially created 3/1/01 + + Subclass of NSTextFieldCell which can display text and an image simultaneously. +*/ + +/* + IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in + consideration of your agreement to the following terms, and your use, installation, + modification or redistribution of this Apple software constitutes acceptance of these + terms. If you do not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject to these + terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in + this original Apple software (the "Apple Software"), to use, reproduce, modify and + redistribute the Apple Software, with or without modifications, in source and/or binary + forms; provided that if you redistribute the Apple Software in its entirety and without + modifications, you must retain this notice and the following text and disclaimers in all + such redistributions of the Apple Software. Neither the name, trademarks, service marks + or logos of Apple Computer, Inc. may be used to endorse or promote products derived from + the Apple Software without specific prior written permission from Apple. Except as expressly + stated in this notice, no other rights or licenses, express or implied, are granted by Apple + herein, including but not limited to any patent rights that may be infringed by your + derivative works or by other works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS + USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, + REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND + WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR + OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#import "ImageAndTextCell.h" + +#define LEADINGEDGE 2 + +@implementation ImageAndTextCell + +- (void)dealloc +{ + [self setImage: nil]; + [super dealloc]; +} + +- copyWithZone: (NSZone *)zone +{ + ImageAndTextCell *cell; + + cell = (ImageAndTextCell *)[super copyWithZone: zone]; + [cell setImage: [self image]]; + return cell; +} + +- (NSRect)imageFrameForCellFrame: (NSRect)cellFrame +{ + if (image != nil) { + NSRect imageFrame; + imageFrame.size = [image size]; + imageFrame.origin = cellFrame.origin; + imageFrame.origin.x += LEADINGEDGE; + imageFrame.origin.y += + ceil((cellFrame.size.height - imageFrame.size.height) / 2); + return imageFrame; + } + else + return NSZeroRect; +} + +- (void)editWithFrame: (NSRect)aRect + inView: (NSView *)controlView + editor: (NSText *)textObj + delegate: (id)anObject + event: (NSEvent *)theEvent +{ + NSRect textFrame, imageFrame; + + NSDivideRect(aRect, &imageFrame, &textFrame, + LEADINGEDGE + [image size].width, NSMinXEdge); + [super editWithFrame: textFrame inView: controlView editor: textObj delegate: anObject event: theEvent]; +} + +- (void)selectWithFrame: (NSRect)aRect + inView: (NSView *)controlView + editor: (NSText *)textObj + delegate: (id)anObject + start: (int)selStart + length: (int)selLength +{ + NSRect textFrame, imageFrame; + + NSDivideRect (aRect, &imageFrame, &textFrame, LEADINGEDGE + [image size].width, NSMinXEdge); + [super selectWithFrame: textFrame inView: controlView editor:textObj delegate:anObject start:selStart length:selLength]; +} + +- (void)drawWithFrame: (NSRect)cellFrame inView: (NSView *)controlView +{ + if (image != nil) { + NSSize imageSize; + NSRect imageFrame; + + imageSize = [image size]; + NSDivideRect(cellFrame, &imageFrame, &cellFrame, LEADINGEDGE + imageSize.width, NSMinXEdge); + if ([self drawsBackground]) { + [[self backgroundColor] set]; + NSRectFill(imageFrame); + } + imageFrame.origin.x += LEADINGEDGE; + imageFrame.size = imageSize; + + if ([controlView isFlipped]) + imageFrame.origin.y += + ceil((cellFrame.size.height + imageFrame.size.height) / 2); + else + imageFrame.origin.y += + ceil((cellFrame.size.height - imageFrame.size.height) / 2); + + [image compositeToPoint: imageFrame.origin operation: NSCompositeSourceOver]; + } + [super drawWithFrame: cellFrame inView: controlView]; +} + +- (NSSize)cellSize +{ + NSSize cellSize; + + cellSize = [super cellSize]; + cellSize.width += (image ? [image size].width : 0) + LEADINGEDGE; + return cellSize; +} +@end + +@implementation ImageAndTextCell (Accessors) +- (NSImage *)image +{ + return image; +} + +- (void)setImage: (NSImage *)anImage +{ + [anImage retain]; + [image release]; + image = anImage; +} +@end \ No newline at end of file diff --git a/Liaison/Images/Add.tiff b/Liaison/Images/Add.tiff new file mode 100644 index 0000000..79d4e34 Binary files /dev/null and b/Liaison/Images/Add.tiff differ diff --git a/Liaison/Images/AddFiles.tiff b/Liaison/Images/AddFiles.tiff new file mode 100644 index 0000000..7fe8e48 Binary files /dev/null and b/Liaison/Images/AddFiles.tiff differ diff --git a/Liaison/Images/AddGroup.tiff b/Liaison/Images/AddGroup.tiff new file mode 100644 index 0000000..b8753d7 Binary files /dev/null and b/Liaison/Images/AddGroup.tiff differ diff --git a/Liaison/Images/Download_Reload.tiff b/Liaison/Images/Download_Reload.tiff new file mode 100644 index 0000000..f4cf9ab Binary files /dev/null and b/Liaison/Images/Download_Reload.tiff differ diff --git a/Liaison/Images/Download_ReloadPressed.tiff b/Liaison/Images/Download_ReloadPressed.tiff new file mode 100644 index 0000000..bcd6900 Binary files /dev/null and b/Liaison/Images/Download_ReloadPressed.tiff differ diff --git a/Liaison/Images/Download_Reveal.tiff b/Liaison/Images/Download_Reveal.tiff new file mode 100644 index 0000000..c090901 Binary files /dev/null and b/Liaison/Images/Download_Reveal.tiff differ diff --git a/Liaison/Images/Download_RevealPressed.tiff b/Liaison/Images/Download_RevealPressed.tiff new file mode 100644 index 0000000..13f68a5 Binary files /dev/null and b/Liaison/Images/Download_RevealPressed.tiff differ diff --git a/Liaison/Images/Download_Stop.tiff b/Liaison/Images/Download_Stop.tiff new file mode 100644 index 0000000..156869d Binary files /dev/null and b/Liaison/Images/Download_Stop.tiff differ diff --git a/Liaison/Images/Download_StopPressed.tiff b/Liaison/Images/Download_StopPressed.tiff new file mode 100644 index 0000000..c9ee4a1 Binary files /dev/null and b/Liaison/Images/Download_StopPressed.tiff differ diff --git a/Liaison/Images/File Icons/Liaison.icns b/Liaison/Images/File Icons/Liaison.icns new file mode 100644 index 0000000..d1b79dc Binary files /dev/null and b/Liaison/Images/File Icons/Liaison.icns differ diff --git a/Liaison/Images/LeftSearchCap.tiff b/Liaison/Images/LeftSearchCap.tiff new file mode 100644 index 0000000..51664e1 Binary files /dev/null and b/Liaison/Images/LeftSearchCap.tiff differ diff --git a/Liaison/Images/NormalMailbox.tiff b/Liaison/Images/NormalMailbox.tiff new file mode 100644 index 0000000..351b06b Binary files /dev/null and b/Liaison/Images/NormalMailbox.tiff differ diff --git a/Liaison/Images/NormalMailboxLarge.tiff b/Liaison/Images/NormalMailboxLarge.tiff new file mode 100644 index 0000000..5ebd76d Binary files /dev/null and b/Liaison/Images/NormalMailboxLarge.tiff differ diff --git a/Liaison/Images/RemoveFiles.tiff b/Liaison/Images/RemoveFiles.tiff new file mode 100644 index 0000000..67fbe49 Binary files /dev/null and b/Liaison/Images/RemoveFiles.tiff differ diff --git a/Liaison/Images/RemoveGroup.tiff b/Liaison/Images/RemoveGroup.tiff new file mode 100644 index 0000000..dc840ab Binary files /dev/null and b/Liaison/Images/RemoveGroup.tiff differ diff --git a/Liaison/Images/RightSearchCap.tiff b/Liaison/Images/RightSearchCap.tiff new file mode 100644 index 0000000..5672df6 Binary files /dev/null and b/Liaison/Images/RightSearchCap.tiff differ diff --git a/Liaison/Images/SortAscending.gif b/Liaison/Images/SortAscending.gif new file mode 100644 index 0000000..4c11dba Binary files /dev/null and b/Liaison/Images/SortAscending.gif differ diff --git a/Liaison/Images/SortDescending.gif b/Liaison/Images/SortDescending.gif new file mode 100644 index 0000000..c95c00d Binary files /dev/null and b/Liaison/Images/SortDescending.gif differ diff --git a/Liaison/Images/TrashMailbox.tiff b/Liaison/Images/TrashMailbox.tiff new file mode 100644 index 0000000..4e6995f Binary files /dev/null and b/Liaison/Images/TrashMailbox.tiff differ diff --git a/Liaison/Images/TrashMailboxLarge.tiff b/Liaison/Images/TrashMailboxLarge.tiff new file mode 100644 index 0000000..ea8fe02 Binary files /dev/null and b/Liaison/Images/TrashMailboxLarge.tiff differ diff --git a/Liaison/Images/delete.tiff b/Liaison/Images/delete.tiff new file mode 100644 index 0000000..ea8fe02 Binary files /dev/null and b/Liaison/Images/delete.tiff differ diff --git a/Liaison/Images/info (italic).tiff b/Liaison/Images/info (italic).tiff new file mode 100644 index 0000000..435c112 Binary files /dev/null and b/Liaison/Images/info (italic).tiff differ diff --git a/Liaison/Images/info (plain).tiff b/Liaison/Images/info (plain).tiff new file mode 100644 index 0000000..3ecf888 Binary files /dev/null and b/Liaison/Images/info (plain).tiff differ diff --git a/Liaison/Images/quickpick.tiff b/Liaison/Images/quickpick.tiff new file mode 100644 index 0000000..2cda6de Binary files /dev/null and b/Liaison/Images/quickpick.tiff differ diff --git a/Liaison/Images/rendezvous.tiff b/Liaison/Images/rendezvous.tiff new file mode 100644 index 0000000..f162ef0 Binary files /dev/null and b/Liaison/Images/rendezvous.tiff differ diff --git a/Liaison/Images/reveal.tiff b/Liaison/Images/reveal.tiff new file mode 100644 index 0000000..90c6e1b Binary files /dev/null and b/Liaison/Images/reveal.tiff differ diff --git a/Liaison/Info.plist b/Liaison/Info.plist new file mode 100644 index 0000000..3035d74 --- /dev/null +++ b/Liaison/Info.plist @@ -0,0 +1,74 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + liaisonplugin + + CFBundleTypeMIMETypes + + application/x-com.kublai.Liaison.plugin + + CFBundleTypeName + Liaison Plugin + CFBundleTypeRole + None + LSTypeIsPackage + + + + CFBundleTypeExtensions + + * + + CFBundleTypeName + Everything + CFBundleTypeRole + Viewer + + + CFBundleExecutable + Liaison + CFBundleGetInfoString + version 0.4.2 + CFBundleIconFile + Liaison.icns + CFBundleIdentifier + com.kublai.Liaison + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Liaison + CFBundlePackageType + APPL + CFBundleShortVersionString + v0.4.2 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleURLName + Liaison URL + CFBundleURLSchemes + + liaison + + + + CFBundleVersion + 0.4.2 + NSAppleScriptEnabled + YES + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/Liaison/InspectorController.h b/Liaison/InspectorController.h new file mode 100644 index 0000000..d17c05f --- /dev/null +++ b/Liaison/InspectorController.h @@ -0,0 +1,24 @@ +/* InspectorController */ + +@class LiInspectorView; + +@interface InspectorController : NSObject +{ + IBOutlet NSTabView *theTabView; + IBOutlet NSView *theDefaultTabView; + IBOutlet NSWindow *theWindow; + + NSMutableDictionary *theInspectorViews; + LiFileHandle *theFile; +} +- (LiInspectorView *)inspectorViewForIdentifier: (NSString *)anIdentifier; +- (NSRect)minWindowFrame; +- (void)resizeWindow; + +- (void)setFile: (LiFileHandle *)aFile; +@property (retain) LiFileHandle *theFile; +@property (retain) NSWindow *theWindow; +@property (retain) NSMutableDictionary *theInspectorViews; +@property (retain) NSTabView *theTabView; +@property (retain) NSView *theDefaultTabView; +@end diff --git a/Liaison/InspectorController.m b/Liaison/InspectorController.m new file mode 100644 index 0000000..453574c --- /dev/null +++ b/Liaison/InspectorController.m @@ -0,0 +1,250 @@ +#import "InspectorController.h" + +#import "PluginManager.h" + +@implementation InspectorController (WindowDelegate) +- (NSRect)windowWillUseStandardFrame: (NSWindow *)aWindow + defaultFrame: (NSRect)defaultFrame +{ + return [self minWindowFrame]; +} +@end + +@implementation InspectorController +- (id)init +{ + self = [super init]; + + theInspectorViews = [[NSMutableDictionary alloc] init]; + + return self; +} + +- (void)dealloc +{ + [theInspectorViews release]; + [super dealloc]; +} + +- (LiInspectorView *)viewForDefault +{ + LiInspectorView *view; + + view = [[[LiInspectorView alloc] init] autorelease]; + [view setIdentifier: @"nothing"]; + [view setName: @"Nada"]; + [view setImage: nil]; + [view setIsHorizontallyResizable: NO]; + [view setIsVerticallyResizable: NO]; + [view setView: theDefaultTabView]; + [view setViewSize: [[view view] frame].size]; + + return view; +} + +- (void)awakeFromNib +{ + NSEnumerator *pluginEnum; + NSObject *plugin; + + [self setFile: nil]; + + // Load our default, "nothing's there" view. + [theInspectorViews setObject: [self viewForDefault] forKey: @"DEFAULT"]; + + // Load plug-in views. + pluginEnum = [[[PluginManager defaultManager] inspectorPlugins] objectEnumerator]; + while ((plugin = [pluginEnum nextObject]) != nil) { + LiInspectorView *view; + NSEnumerator *viewEnum; + + viewEnum = [[plugin allInspectorViews] objectEnumerator]; + while ((view = [viewEnum nextObject]) != nil) { + NSString *identifier; + + identifier = [NSString stringWithFormat: @"%@:%@", + NSStringFromClass([plugin class]), [view identifier]]; + [theInspectorViews setObject: view forKey: identifier]; + } + } +} + +- (LiInspectorView *)inspectorViewForIdentifier: (NSString *)anIdentifier +{ + return [theInspectorViews objectForKey: anIdentifier]; +} + +- (void)showInspectorViewWithIdentifier: (NSString *)anIdentifier +{ + LiInspectorView *view; + + view = [self inspectorViewForIdentifier: anIdentifier]; + if (view != nil) { + NSTabViewItem *tab; + + tab = [[NSTabViewItem alloc] initWithIdentifier: anIdentifier]; + [tab autorelease]; + [tab setLabel: [view name]]; + [tab setView: [view view]]; + [theTabView addTabViewItem: tab]; + } +} + +- (void)removeInspectorViewWithIdentifier: (NSString *)anIdentifier +{ + LiInspectorView *view; + + view = [self inspectorViewForIdentifier: anIdentifier]; +} + +- (NSRect)minWindowFrame +{ + LiInspectorView *inspectorView; + NSTabViewItem *tab; + NSRect windowFrame; + NSSize viewSize; + float newHeight, newWidth; + + tab = [theTabView selectedTabViewItem]; + inspectorView = [self inspectorViewForIdentifier: [tab identifier]]; + + viewSize = [inspectorView viewSize]; + newHeight = viewSize.height + 40; + newWidth = viewSize.width; + + windowFrame = [NSWindow contentRectForFrameRect: [theWindow frame] + styleMask: [theWindow styleMask]]; + windowFrame.origin.y += windowFrame.size.height; + windowFrame.origin.y -= newHeight; + windowFrame.size.height = newHeight; + windowFrame.size.width = newWidth; + + windowFrame = [NSWindow frameRectForContentRect: windowFrame + styleMask: [theWindow styleMask]]; + + return windowFrame; +} + +- (void)resizeWindow +{ + LiInspectorView *inspectorView; + NSTabViewItem *tab; + NSRect minWindowFrame, windowFrame; + BOOL displayGrowBox = NO; + + tab = [theTabView selectedTabViewItem]; + inspectorView = [self inspectorViewForIdentifier: [tab identifier]]; + + windowFrame = [theWindow frame]; + minWindowFrame = [self minWindowFrame]; + if ([inspectorView isVerticallyResizable] && + [inspectorView isHorizontallyResizable]) { + // Resize nothing. + if (windowFrame.size.width < minWindowFrame.size.width) + windowFrame.size.width = minWindowFrame.size.width; + if (windowFrame.size.height < minWindowFrame.size.height) + windowFrame.size.height = minWindowFrame.size.height; + + displayGrowBox = YES; + } else { + if ([inspectorView isVerticallyResizable]) { + // Resize the width. + windowFrame.size.width = minWindowFrame.size.width; + if (windowFrame.size.height < minWindowFrame.size.height) + windowFrame.size.height = minWindowFrame.size.height; + + displayGrowBox = YES; + } else if ([inspectorView isHorizontallyResizable]) { + // Resize the height. + windowFrame.origin.y = minWindowFrame.origin.y; + windowFrame.size.height = minWindowFrame.size.height; + if (windowFrame.size.width < minWindowFrame.size.width) + windowFrame.size.width = minWindowFrame.size.width; + + displayGrowBox = YES; + } else + windowFrame = minWindowFrame; + } + [theWindow setFrame: windowFrame display: YES animate: YES]; + [theWindow setShowsResizeIndicator: displayGrowBox]; +} + +- (void)setFile: (LiFileHandle *)aFile +{ + NSEnumerator *pluginEnum, *tabEnum; + NSMutableArray *shownTabs; + NSString *identifier; + NSTabViewItem *tab; + NSObject *plugin; + + shownTabs = [NSMutableArray array]; + pluginEnum = [[[PluginManager defaultManager] inspectorPlugins] objectEnumerator]; + while ((plugin = [pluginEnum nextObject]) != nil) { + LiInspectorView *view; + NSEnumerator *viewEnum; + + viewEnum = [[plugin inspectorViewsForFile: aFile] objectEnumerator]; + while ((view = [viewEnum nextObject]) != nil) { + identifier = [NSString stringWithFormat: @"%@:%@", + NSStringFromClass([plugin class]), [view identifier]]; + [shownTabs addObject: identifier]; + } + + NS_DURING + [plugin setFile: aFile]; + NS_HANDLER + [LiLog logAsError: + @"Inspector plugin: %@ couldn't handle '%@': %@, %@", + NSStringFromClass([plugin class]), + [aFile filename], [localException name], + [localException reason]]; + NS_ENDHANDLER + } + + tabEnum = [[theTabView tabViewItems] objectEnumerator]; + while ((tab = [tabEnum nextObject]) != nil) { + if ([shownTabs containsObject: [tab identifier]]) + [shownTabs removeObject: [tab identifier]]; + else + [theTabView removeTabViewItem: tab]; + } + + for (identifier in shownTabs) { + [self showInspectorViewWithIdentifier: identifier]; + } + + if ([theTabView numberOfTabViewItems] == 0) { + [LiLog logAsDebug: @"No tabs in view."]; + + [self showInspectorViewWithIdentifier: @"DEFAULT"]; + } +} +@synthesize theWindow; +@synthesize theInspectorViews; +@synthesize theTabView; +@synthesize theDefaultTabView; +@synthesize theFile; +@end + +@implementation InspectorController (TabViewDelegate) +- (void)tabView: (NSTabView *)tabView didSelectTabViewItem: (NSTabViewItem *)tabViewItem +{ + LiInspectorView *inspectorView; + NSTabViewItem *tab; + NSSize minSize, maxSize; + + tab = [theTabView selectedTabViewItem]; + inspectorView = [self inspectorViewForIdentifier: [tab identifier]]; + + minSize = [self minWindowFrame].size; + maxSize = NSMakeSize(800.0, 800.0); + if ([inspectorView isHorizontallyResizable] == NO) + maxSize.width = minSize.width; + if ([inspectorView isVerticallyResizable] == NO) + maxSize.height = minSize.height; + + [theWindow setMinSize: minSize]; + [theWindow setMaxSize: maxSize]; + [self resizeWindow]; +} +@end \ No newline at end of file diff --git a/Liaison/LiDataTranslator.h b/Liaison/LiDataTranslator.h new file mode 100644 index 0000000..f988d71 --- /dev/null +++ b/Liaison/LiDataTranslator.h @@ -0,0 +1,27 @@ +// +// LiDataTranslator.h +// Liaison +// +// Created by Brian Cully on Thu Sep 25 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#define LiPlainEncoding 0x10101010 + +#import + +@interface LiDataTranslator : NSObject ++ (LiDataTranslator *)sharedTranslator; +- (NSData *)decodeData: (NSData *)someData; +- (NSData *)encodeData: (NSData *)someData; +@end + +@interface NSData (LiDataTranslator) +- (NSData *)decodedData; +- (NSData *)encodedData; +@end + +@interface NSDictionary (LiDataTranslator) ++ (NSDictionary *)dictionaryWithEncodedData: (NSData *)someData; +- (NSData *)encodedData; +@end \ No newline at end of file diff --git a/Liaison/LiDataTranslator.m b/Liaison/LiDataTranslator.m new file mode 100644 index 0000000..4481c21 --- /dev/null +++ b/Liaison/LiDataTranslator.m @@ -0,0 +1,120 @@ +// +// LiDataTranslator.m +// Liaison +// +// Created by Brian Cully on Thu Sep 25 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "LiDataTranslator.h" + +@implementation LiDataTranslator +static LiDataTranslator *sharedTranslator = nil; ++ (LiDataTranslator *)sharedTranslator +{ + if (sharedTranslator == nil) + sharedTranslator = [[self alloc] init]; + return sharedTranslator; +} + +- (NSData *)decodeData: (NSData *)someData +{ + NSData *myData; + NSRange headerRange; + unsigned long encoding, length; + unsigned dataLen; + + myData = nil; + headerRange.location = 0; + headerRange.length = sizeof(encoding) + sizeof(length); + dataLen = [someData length]; + if (dataLen > headerRange.length) { + + dataLen -= headerRange.length; + [someData getBytes: &encoding range: NSMakeRange(0, sizeof(encoding))]; + [someData getBytes: &length range: NSMakeRange(sizeof(encoding), sizeof(length))]; + encoding = ntohl(encoding); + length = ntohl(length); + + if (dataLen >= length) { + myData = [someData subdataWithRange: NSMakeRange(headerRange.length, length)]; + } + } + + return myData; +} + +- (NSData *)encodeData: (NSData *)someData +{ + NSMutableData *myData; + + myData = nil; + if (someData != nil) { + unsigned long encoding, length; + + myData = [NSMutableData data]; + encoding = htonl(LiPlainEncoding); + length = htonl([someData length]); + + [myData appendBytes: &encoding length: sizeof(encoding)]; + [myData appendBytes: &length length: sizeof(length)]; + [myData appendData: someData]; + } + return myData; +} +@end + +@implementation NSData (LiDataTranslator) +- (NSData *)decodedData +{ + return [[LiDataTranslator sharedTranslator] decodeData: self]; +} + +- (NSData *)encodedData +{ + return [[LiDataTranslator sharedTranslator] encodeData: self]; +} +@end + +@implementation NSDictionary (LiDataTranslator) ++ (NSDictionary *)dictionaryWithEncodedData: (NSData *)someData +{ + NSData *myData; + NSDictionary *msg; + + msg = nil; + myData = [someData decodedData]; + if (myData != nil) { + NSString *errorString; + + errorString = nil; + msg = [NSPropertyListSerialization propertyListFromData: myData + mutabilityOption: NSPropertyListImmutable + format: NULL + errorDescription: &errorString]; + if (errorString != nil || [msg isKindOfClass: [NSDictionary class]] == NO) { + [msg release]; + [errorString release]; + return nil; + } + } + return msg; +} + +- (NSData *)encodedData +{ + NSData *myData; + NSString *errorString; + + errorString = nil; + myData = [NSPropertyListSerialization dataFromPropertyList: self + format: NSPropertyListBinaryFormat_v1_0 + errorDescription: &errorString]; + if (errorString != nil) { + [LiLog logAsError: @"Couldn't serialize dictionary: %@.", errorString]; + [errorString release]; + return nil; + } + return [myData encodedData]; +} +@end \ No newline at end of file diff --git a/Liaison/LiScrolLView.h b/Liaison/LiScrolLView.h new file mode 100644 index 0000000..149e34b --- /dev/null +++ b/Liaison/LiScrolLView.h @@ -0,0 +1,10 @@ +// +// LiScrolLView.h +// Liaison +// +// Created by Brian Cully on Sat May 10 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@interface LiScrollView : NSScrollView +@end diff --git a/Liaison/LiScrolLView.m b/Liaison/LiScrolLView.m new file mode 100644 index 0000000..2441ed0 --- /dev/null +++ b/Liaison/LiScrolLView.m @@ -0,0 +1,34 @@ +// +// LiScrolLView.m +// Liaison +// +// Created by Brian Cully on Sat May 10 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "LiScrolLView.h" + +@implementation LiScrollView +- (void)validateScrollers; +{ + BOOL horizVisible, vertVisible; + NSSize mySize, contentSize; + + mySize = [self frame].size; + contentSize = [[self documentView] frame].size; + + vertVisible = mySize.height < contentSize.height; + horizVisible = mySize.width < contentSize.width; + + [self setHasVerticalScroller: vertVisible]; + [self setHasHorizontalScroller: horizVisible]; + + return; +} + +- (void)drawRect: (NSRect)aRect +{ + [self validateScrollers]; + [super drawRect: aRect]; +} +@end diff --git a/Liaison/LiTableView.h b/Liaison/LiTableView.h new file mode 100644 index 0000000..5b3869b --- /dev/null +++ b/Liaison/LiTableView.h @@ -0,0 +1,2 @@ +@interface LiTableView : NSTableView +@end diff --git a/Liaison/LiTableView.m b/Liaison/LiTableView.m new file mode 100644 index 0000000..9fa66f6 --- /dev/null +++ b/Liaison/LiTableView.m @@ -0,0 +1,166 @@ +#import "LiTableView.h" + +@implementation LiTableView ++ (void)load +{ + [self poseAsClass: [NSTableView class]]; +} + +- methodSignatureForSelector: (SEL)aSelector +{ + id signature; + + signature = [super methodSignatureForSelector: aSelector]; + if (signature == nil) { + NSString *selString; + + selString = NSStringFromSelector(aSelector); + + if ([selString isEqualToString: @"validateMenuItem:"]) { + signature = [[self delegate] methodSignatureForSelector: @selector(validateMenuItem:)]; + } else if ([selString isEqualToString: @"delete:"]) { + if ([self isKindOfClass: [NSOutlineView class]]) + signature = [[self dataSource] methodSignatureForSelector: @selector(deleteSelectedRowsInOutlineView:)]; + else + signature = [[self dataSource] methodSignatureForSelector: + @selector(deleteSelectedRowsInTableView:)]; + } else if ([[self delegate] respondsToSelector: aSelector]) + signature = [[self delegate] methodSignatureForSelector: aSelector]; + } + return signature; +} + +- (void)forwardInvocation: (NSInvocation *)anInvocation +{ + NSString *selString; + + selString = NSStringFromSelector([anInvocation selector]); + if ([selString isEqualToString: @"validateMenuItem:"]) { + [anInvocation setTarget: [self delegate]]; + [anInvocation invoke]; + } else if ([selString isEqualToString: @"delete:"]) { + [anInvocation setTarget: [self dataSource]]; + if ([self isKindOfClass: [NSOutlineView class]]) { + [anInvocation setSelector: @selector(deleteSelectedRowsInOutlineView:)]; + } else { + [anInvocation setSelector: @selector(deleteSelectedRowsInTableView:)]; + } + + [anInvocation setArgument: &self atIndex: 2]; + [anInvocation invoke]; + } else if ([[self delegate] respondsToSelector: [anInvocation selector]]) { + [anInvocation setTarget: [self delegate]]; + [anInvocation invoke]; + } else + [super forwardInvocation: anInvocation]; +} + +- (BOOL)respondsToSelector: (SEL)aSelector +{ + NSString *selString; + + if ([super respondsToSelector: aSelector]) + return YES; + + selString = NSStringFromSelector(aSelector); + if ([selString isEqualToString: @"validateMenuItem:"]) { + return [[self delegate] respondsToSelector: aSelector]; + } else if ([selString isEqualToString: @"delete:"]) { + if ([self isKindOfClass: [NSOutlineView class]]) { + return [[self dataSource] respondsToSelector: + @selector(deleteSelectedRowsInOutlineView:)]; + } else { + return [[self dataSource] respondsToSelector: @selector(deleteSelectedRowsInTableView:)]; + } + } + return [[self delegate] respondsToSelector: aSelector]; +} + +- (void)keyDown: (NSEvent *)theEvent +{ + NSString *keyString; + unichar keyChar; + + keyString = [theEvent charactersIgnoringModifiers]; + keyChar = [keyString characterAtIndex: 0]; + switch (keyChar) { + case 0177: // Delete Key + case NSDeleteFunctionKey: + case NSDeleteCharFunctionKey: { + SEL selector; + + if ([self isKindOfClass: [NSOutlineView class]]) { + selector = @selector(deleteSelectedRowsInOutlineView:); + } else { + selector = @selector(deleteSelectedRowsInTableView:); + } + if ([self selectedRow] >= 0 && + [[self dataSource] respondsToSelector: selector]) { + [[self dataSource] performSelector: selector + withObject: self]; + } + break; + } default: + [super keyDown: theEvent]; + } +} + +- (BOOL)becomeFirstResponder +{ + BOOL rc; + + rc = [super becomeFirstResponder]; + if (rc == YES) { + SEL selector; + + if ([self isKindOfClass: [NSOutlineView class]]) + selector = @selector(outlineViewDidBecomeFirstResponder:); + else + selector = @selector(tableViewDidBecomeFirstResponder:); + + if ([[self delegate] respondsToSelector: selector]) + [[self delegate] performSelector: selector + withObject: self]; + } + return rc; +} + +- (void)mouseDown: (NSEvent *)theEvent +{ + if ([[self delegate] respondsToSelector: @selector(mouseDownEvent:)]) + [[self delegate] performSelector: @selector(mouseDownEvent:) + withObject: theEvent]; + [super mouseDown: theEvent]; +} + +- (unsigned int)draggingSourceOperationMaskForLocal: (BOOL)isLocal +{ + if (isLocal) + return NSDragOperationPrivate; + else + return NSDragOperationCopy | NSDragOperationLink | NSDragOperationGeneric; +} + +- (void)textDidEndEditing: (NSNotification *)aNotification +{ + int keyPressed; + + keyPressed = [[[aNotification userInfo] objectForKey: @"NSTextMovement"] intValue]; + if (keyPressed == NSReturnTextMovement) { + NSMutableDictionary *newUserInfo; + NSNotification *newNotification; + + newUserInfo = [NSMutableDictionary dictionaryWithDictionary: + [aNotification userInfo]]; + [newUserInfo setObject: [NSNumber numberWithInt:0] + forKey: @"NSTextMovement"]; + newNotification = [NSNotification notificationWithName: [aNotification name] + object: [aNotification object] + userInfo: newUserInfo]; + [super textDidEndEditing: newNotification]; + + [[self window] makeFirstResponder: self]; + } else + [super textDidEndEditing: aNotification]; +} +@end \ No newline at end of file diff --git a/Liaison/Liaison.h b/Liaison/Liaison.h new file mode 100644 index 0000000..6732b7d --- /dev/null +++ b/Liaison/Liaison.h @@ -0,0 +1,30 @@ +/* + * Liaison.h + * Liaison + * + * Created by Brian Cully on Fri Feb 14 2003. + * Copyright (c) 2003 Brian Cully. All rights reserved. + * + * ----- + * + * This header file contains common #defines for ipc and other + * "configurable" resources. + */ + +// We're basically just a front end to this. +#import +// That uses this. +#import + +// Icons in the browser outline view. +#define LiLocalLibraryIcon @"local.tiff" +#define LiRendezvousGroupIcon @"rendezvous.tiff" +#define LiNormalGroupIcon @"quickpick.tiff" +#define LiNetworkGroupIcon @"Network (Small).tiff" + +// For internal drag-and-drop. +#define LiaisonPboardType @"LiaisonPboardType" + +// Load extensions and class posers. +#import "NSFileHandleExtensions.h" +#import "LiTableView.h" \ No newline at end of file diff --git a/Liaison/Liaison.scriptSuite b/Liaison/Liaison.scriptSuite new file mode 100644 index 0000000..255b1a9 --- /dev/null +++ b/Liaison/Liaison.scriptSuite @@ -0,0 +1,32 @@ + + + + + AppleEventCode + Lisn + Classes + + NSApplication + + AppleEventCode + capp + Superclass + NSCoreSuite.NSApplication + ToManyRelationships + + orderedFileStores + + AppleEventCode + LiFS + ReadOnly + YES + Type + LiBackend.LiFileStore + + + + + Name + Liaison + + diff --git a/Liaison/Liaison.xcodeproj/project.pbxproj b/Liaison/Liaison.xcodeproj/project.pbxproj new file mode 100644 index 0000000..26e71de --- /dev/null +++ b/Liaison/Liaison.xcodeproj/project.pbxproj @@ -0,0 +1,936 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 286D15B30CDD52F0006463CC /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 286D15B20CDD52F0006463CC /* Info.plist */; }; + F7D3988C0546870000BD181E /* LiBackend.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = F7D6588204F3576900000104 /* LiBackend.framework */; }; + F7D3988D0546870000BD181E /* LiPlugin.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = F7D6588304F3576900000104 /* LiPlugin.framework */; }; + F7D398900546870000BD181E /* Built In Functions.liaisonplugin in CopyFiles */ = {isa = PBXBuildFile; fileRef = F7D6588604F3579700000104 /* Built In Functions.liaisonplugin */; }; + F7D398920546870000BD181E /* FileTableDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = F790696104EF48AB00000104 /* FileTableDelegate.h */; }; + F7D398930546870000BD181E /* LiTableView.h in Headers */ = {isa = PBXBuildFile; fileRef = F790696604EF48AB00000104 /* LiTableView.h */; }; + F7D398940546870000BD181E /* Downloader.h in Headers */ = {isa = PBXBuildFile; fileRef = F790696904EF48AB00000104 /* Downloader.h */; }; + F7D398950546870000BD181E /* DownloadStatusView.h in Headers */ = {isa = PBXBuildFile; fileRef = F790696A04EF48AB00000104 /* DownloadStatusView.h */; }; + F7D398960546870000BD181E /* CopyController.h in Headers */ = {isa = PBXBuildFile; fileRef = F790696B04EF48AB00000104 /* CopyController.h */; }; + F7D398970546870000BD181E /* LoadPanelController.h in Headers */ = {isa = PBXBuildFile; fileRef = F790696D04EF48AB00000104 /* LoadPanelController.h */; }; + F7D398980546870000BD181E /* DownloadManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F790696E04EF48AB00000104 /* DownloadManager.h */; }; + F7D398990546870000BD181E /* ApplicationController.h in Headers */ = {isa = PBXBuildFile; fileRef = F790697104EF48AB00000104 /* ApplicationController.h */; }; + F7D3989A0546870000BD181E /* FlippedBox.h in Headers */ = {isa = PBXBuildFile; fileRef = F790697304EF48AB00000104 /* FlippedBox.h */; }; + F7D3989B0546870000BD181E /* LiScrolLView.h in Headers */ = {isa = PBXBuildFile; fileRef = F790697404EF48AB00000104 /* LiScrolLView.h */; }; + F7D3989C0546870000BD181E /* ImageAndTextCell.h in Headers */ = {isa = PBXBuildFile; fileRef = F790697604EF48AB00000104 /* ImageAndTextCell.h */; }; + F7D3989D0546870000BD181E /* InspectorController.h in Headers */ = {isa = PBXBuildFile; fileRef = F790697804EF48AB00000104 /* InspectorController.h */; }; + F7D3989E0546870000BD181E /* GroupTableDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = F790697904EF48AB00000104 /* GroupTableDelegate.h */; }; + F7D3989F0546870000BD181E /* ClientManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F790697C04EF48AB00000104 /* ClientManager.h */; }; + F7D398A00546870000BD181E /* Liaison.h in Headers */ = {isa = PBXBuildFile; fileRef = F790697D04EF48AB00000104 /* Liaison.h */; }; + F7D398A10546870000BD181E /* Group.h in Headers */ = {isa = PBXBuildFile; fileRef = F790698204EF48AC00000104 /* Group.h */; }; + F7D398A20546870000BD181E /* WindowController.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069B904EF4A2700000104 /* WindowController.h */; }; + F7D398A30546870000BD181E /* ServerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069BD04EF4A2700000104 /* ServerManager.h */; }; + F7D398A40546870000BD181E /* RenManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069BE04EF4A2700000104 /* RenManager.h */; }; + F7D398A50546870000BD181E /* PreferencesController.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069BF04EF4A2700000104 /* PreferencesController.h */; }; + F7D398A60546870000BD181E /* WriterThread.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069C004EF4A2700000104 /* WriterThread.h */; }; + F7D398A70546870000BD181E /* RenIPC.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069C104EF4A2700000104 /* RenIPC.h */; }; + F7D398A80546870000BD181E /* NIBConnector.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069C604EF4A2700000104 /* NIBConnector.h */; }; + F7D398A90546870000BD181E /* ViewOptionsController.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069C804EF4A2700000104 /* ViewOptionsController.h */; }; + F7D398AA0546870000BD181E /* PluginManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069CE04EF4A2700000104 /* PluginManager.h */; }; + F7D398AB0546870000BD181E /* WriterThreadPool.h in Headers */ = {isa = PBXBuildFile; fileRef = F79069CF04EF4A2700000104 /* WriterThreadPool.h */; }; + F7D398AC0546870000BD181E /* NSFileHandleExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = F75ACF7304EF59C800000104 /* NSFileHandleExtensions.h */; }; + F7D398AD0546870000BD181E /* FindController.h in Headers */ = {isa = PBXBuildFile; fileRef = F7A5B69904F841A900000104 /* FindController.h */; }; + F7D398AE0546870000BD181E /* LiDataTranslator.h in Headers */ = {isa = PBXBuildFile; fileRef = F74B98C80523F102000001C7 /* LiDataTranslator.h */; }; + F7D398B00546870000BD181E /* Liaison.scriptSuite in Resources */ = {isa = PBXBuildFile; fileRef = F79069A504EF48BA00000104 /* Liaison.scriptSuite */; }; + F7D398B10546870000BD181E /* Liaison.scriptTerminology in Resources */ = {isa = PBXBuildFile; fileRef = F79069A904EF48C800000104 /* Liaison.scriptTerminology */; }; + F7D398B20546870000BD181E /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; }; + F7D398B30546870000BD181E /* LoadPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = F79069AD04EF48C800000104 /* LoadPanel.nib */; }; + F7D398B40546870000BD181E /* CopyPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = F79069AF04EF48C800000104 /* CopyPanel.nib */; }; + F7D398B50546870000BD181E /* PreferencesWindow.nib in Resources */ = {isa = PBXBuildFile; fileRef = F79069B104EF48C800000104 /* PreferencesWindow.nib */; }; + F7D398B60546870000BD181E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + F7D398B70546870000BD181E /* WindowElements.strings in Resources */ = {isa = PBXBuildFile; fileRef = F79069A704EF48C800000104 /* WindowElements.strings */; }; + F7D398B80546870000BD181E /* Liaison Help in Resources */ = {isa = PBXBuildFile; fileRef = F73ECD6904F6BF0A00000104 /* Liaison Help */; }; + F7D398B90546870000BD181E /* Liaison.icns in Resources */ = {isa = PBXBuildFile; fileRef = F790693604EF484300000104 /* Liaison.icns */; }; + F7D398BA0546870000BD181E /* Add.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790692A04EF484300000104 /* Add.tiff */; }; + F7D398BB0546870000BD181E /* AddFiles.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790692B04EF484300000104 /* AddFiles.tiff */; }; + F7D398BC0546870000BD181E /* AddGroup.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790692C04EF484300000104 /* AddGroup.tiff */; }; + F7D398BD0546870000BD181E /* delete.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790692D04EF484300000104 /* delete.tiff */; }; + F7D398BE0546870000BD181E /* Download_Reload.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790692E04EF484300000104 /* Download_Reload.tiff */; }; + F7D398BF0546870000BD181E /* Download_ReloadPressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790692F04EF484300000104 /* Download_ReloadPressed.tiff */; }; + F7D398C00546870000BD181E /* Download_Reveal.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693004EF484300000104 /* Download_Reveal.tiff */; }; + F7D398C10546870000BD181E /* Download_RevealPressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693104EF484300000104 /* Download_RevealPressed.tiff */; }; + F7D398C20546870000BD181E /* Download_Stop.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693204EF484300000104 /* Download_Stop.tiff */; }; + F7D398C30546870000BD181E /* Download_StopPressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693304EF484300000104 /* Download_StopPressed.tiff */; }; + F7D398C40546870000BD181E /* info (italic).tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693704EF484300000104 /* info (italic).tiff */; }; + F7D398C50546870000BD181E /* info (plain).tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693804EF484300000104 /* info (plain).tiff */; }; + F7D398C60546870000BD181E /* LeftSearchCap.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693904EF484300000104 /* LeftSearchCap.tiff */; }; + F7D398C70546870000BD181E /* NormalMailbox.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693A04EF484300000104 /* NormalMailbox.tiff */; }; + F7D398C80546870000BD181E /* NormalMailboxLarge.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693B04EF484300000104 /* NormalMailboxLarge.tiff */; }; + F7D398C90546870000BD181E /* quickpick.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693C04EF484300000104 /* quickpick.tiff */; }; + F7D398CA0546870000BD181E /* RemoveFiles.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693D04EF484300000104 /* RemoveFiles.tiff */; }; + F7D398CB0546870000BD181E /* RemoveGroup.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693E04EF484300000104 /* RemoveGroup.tiff */; }; + F7D398CC0546870000BD181E /* rendezvous.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790693F04EF484300000104 /* rendezvous.tiff */; }; + F7D398CD0546870000BD181E /* reveal.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790694004EF484300000104 /* reveal.tiff */; }; + F7D398CE0546870000BD181E /* RightSearchCap.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790694104EF484300000104 /* RightSearchCap.tiff */; }; + F7D398CF0546870000BD181E /* SortAscending.gif in Resources */ = {isa = PBXBuildFile; fileRef = F790694204EF484300000104 /* SortAscending.gif */; }; + F7D398D00546870000BD181E /* SortDescending.gif in Resources */ = {isa = PBXBuildFile; fileRef = F790694304EF484300000104 /* SortDescending.gif */; }; + F7D398D10546870000BD181E /* TrashMailbox.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790694404EF484300000104 /* TrashMailbox.tiff */; }; + F7D398D20546870000BD181E /* TrashMailboxLarge.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790694504EF484300000104 /* TrashMailboxLarge.tiff */; }; + F7D398D40546870000BD181E /* LoadPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = F790696204EF48AB00000104 /* LoadPanelController.m */; }; + F7D398D50546870000BD181E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F790696304EF48AB00000104 /* main.m */; }; + F7D398D60546870000BD181E /* FlippedBox.m in Sources */ = {isa = PBXBuildFile; fileRef = F790696404EF48AB00000104 /* FlippedBox.m */; }; + F7D398D70546870000BD181E /* ApplicationController.m in Sources */ = {isa = PBXBuildFile; fileRef = F790696504EF48AB00000104 /* ApplicationController.m */; }; + F7D398D80546870000BD181E /* LiTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = F790696804EF48AB00000104 /* LiTableView.m */; }; + F7D398D90546870000BD181E /* DownloadStatusView.m in Sources */ = {isa = PBXBuildFile; fileRef = F790696C04EF48AB00000104 /* DownloadStatusView.m */; }; + F7D398DA0546870000BD181E /* ClientManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F790697004EF48AB00000104 /* ClientManager.m */; }; + F7D398DB0546870000BD181E /* ImageAndTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F790697204EF48AB00000104 /* ImageAndTextCell.m */; }; + F7D398DC0546870000BD181E /* Downloader.m in Sources */ = {isa = PBXBuildFile; fileRef = F790697504EF48AB00000104 /* Downloader.m */; }; + F7D398DD0546870000BD181E /* Group.m in Sources */ = {isa = PBXBuildFile; fileRef = F790697704EF48AB00000104 /* Group.m */; }; + F7D398DE0546870000BD181E /* InspectorController.m in Sources */ = {isa = PBXBuildFile; fileRef = F790697A04EF48AB00000104 /* InspectorController.m */; }; + F7D398DF0546870000BD181E /* FileTableDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F790697B04EF48AB00000104 /* FileTableDelegate.m */; }; + F7D398E00546870000BD181E /* LiScrolLView.m in Sources */ = {isa = PBXBuildFile; fileRef = F790697E04EF48AC00000104 /* LiScrolLView.m */; }; + F7D398E10546870000BD181E /* DownloadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F790697F04EF48AC00000104 /* DownloadManager.m */; }; + F7D398E20546870000BD181E /* CopyController.m in Sources */ = {isa = PBXBuildFile; fileRef = F790698004EF48AC00000104 /* CopyController.m */; }; + F7D398E30546870000BD181E /* GroupTableDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F790698104EF48AC00000104 /* GroupTableDelegate.m */; }; + F7D398E40546870000BD181E /* ViewOptionsController.m in Sources */ = {isa = PBXBuildFile; fileRef = F79069C504EF4A2700000104 /* ViewOptionsController.m */; }; + F7D398E50546870000BD181E /* PluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F79069C704EF4A2700000104 /* PluginManager.m */; }; + F7D398E60546870000BD181E /* WindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = F79069C904EF4A2700000104 /* WindowController.m */; }; + F7D398E70546870000BD181E /* PreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = F79069CA04EF4A2700000104 /* PreferencesController.m */; }; + F7D398E80546870000BD181E /* WriterThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = F79069CB04EF4A2700000104 /* WriterThreadPool.m */; }; + F7D398E90546870000BD181E /* WriterThread.m in Sources */ = {isa = PBXBuildFile; fileRef = F79069CC04EF4A2700000104 /* WriterThread.m */; }; + F7D398EA0546870000BD181E /* RenManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F79069CD04EF4A2700000104 /* RenManager.m */; }; + F7D398EB0546870000BD181E /* NIBConnector.m in Sources */ = {isa = PBXBuildFile; fileRef = F79069D004EF4A2700000104 /* NIBConnector.m */; }; + F7D398EC0546870000BD181E /* ServerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F79069D104EF4A2700000104 /* ServerManager.m */; }; + F7D398ED0546870000BD181E /* NSFileHandleExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = F75ACF7404EF59C800000104 /* NSFileHandleExtensions.m */; }; + F7D398EE0546870000BD181E /* FindController.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A5B69A04F841A900000104 /* FindController.m */; }; + F7D398EF0546870000BD181E /* NSException+LiDebugging.m in Sources */ = {isa = PBXBuildFile; fileRef = F7C329D30514615A00000103 /* NSException+LiDebugging.m */; }; + F7D398F00546870000BD181E /* LiDataTranslator.m in Sources */ = {isa = PBXBuildFile; fileRef = F74B98C90523F102000001C7 /* LiDataTranslator.m */; }; + F7D398F20546870000BD181E /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + F7D398F30546870000BD181E /* LiBackend.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7D6588204F3576900000104 /* LiBackend.framework */; }; + F7D398F40546870000BD181E /* LiPlugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7D6588304F3576900000104 /* LiPlugin.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + F7D3988B0546870000BD181E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + F7D3988C0546870000BD181E /* LiBackend.framework in CopyFiles */, + F7D3988D0546870000BD181E /* LiPlugin.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7D3988F0546870000BD181E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + F7D398900546870000BD181E /* Built In Functions.liaisonplugin in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 286D15B20CDD52F0006463CC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + F73ECD1304F6BEE000000104 /* English */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = folder; name = English; path = "English.lproj/Liaison Help"; sourceTree = ""; }; + F74B98C80523F102000001C7 /* LiDataTranslator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiDataTranslator.h; sourceTree = ""; }; + F74B98C90523F102000001C7 /* LiDataTranslator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LiDataTranslator.m; sourceTree = ""; }; + F75ACF7304EF59C800000104 /* NSFileHandleExtensions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NSFileHandleExtensions.h; sourceTree = ""; }; + F75ACF7404EF59C800000104 /* NSFileHandleExtensions.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NSFileHandleExtensions.m; sourceTree = ""; }; + F790692A04EF484300000104 /* Add.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Add.tiff; sourceTree = ""; }; + F790692B04EF484300000104 /* AddFiles.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = AddFiles.tiff; sourceTree = ""; }; + F790692C04EF484300000104 /* AddGroup.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = AddGroup.tiff; sourceTree = ""; }; + F790692D04EF484300000104 /* delete.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = delete.tiff; sourceTree = ""; }; + F790692E04EF484300000104 /* Download_Reload.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_Reload.tiff; sourceTree = ""; }; + F790692F04EF484300000104 /* Download_ReloadPressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_ReloadPressed.tiff; sourceTree = ""; }; + F790693004EF484300000104 /* Download_Reveal.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_Reveal.tiff; sourceTree = ""; }; + F790693104EF484300000104 /* Download_RevealPressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_RevealPressed.tiff; sourceTree = ""; }; + F790693204EF484300000104 /* Download_Stop.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_Stop.tiff; sourceTree = ""; }; + F790693304EF484300000104 /* Download_StopPressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_StopPressed.tiff; sourceTree = ""; }; + F790693604EF484300000104 /* Liaison.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Liaison.icns; sourceTree = ""; }; + F790693704EF484300000104 /* info (italic).tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "info (italic).tiff"; sourceTree = ""; }; + F790693804EF484300000104 /* info (plain).tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "info (plain).tiff"; sourceTree = ""; }; + F790693904EF484300000104 /* LeftSearchCap.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = LeftSearchCap.tiff; sourceTree = ""; }; + F790693A04EF484300000104 /* NormalMailbox.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = NormalMailbox.tiff; sourceTree = ""; }; + F790693B04EF484300000104 /* NormalMailboxLarge.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = NormalMailboxLarge.tiff; sourceTree = ""; }; + F790693C04EF484300000104 /* quickpick.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = quickpick.tiff; sourceTree = ""; }; + F790693D04EF484300000104 /* RemoveFiles.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = RemoveFiles.tiff; sourceTree = ""; }; + F790693E04EF484300000104 /* RemoveGroup.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = RemoveGroup.tiff; sourceTree = ""; }; + F790693F04EF484300000104 /* rendezvous.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = rendezvous.tiff; sourceTree = ""; }; + F790694004EF484300000104 /* reveal.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = reveal.tiff; sourceTree = ""; }; + F790694104EF484300000104 /* RightSearchCap.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = RightSearchCap.tiff; sourceTree = ""; }; + F790694204EF484300000104 /* SortAscending.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = SortAscending.gif; sourceTree = ""; }; + F790694304EF484300000104 /* SortDescending.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = SortDescending.gif; sourceTree = ""; }; + F790694404EF484300000104 /* TrashMailbox.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TrashMailbox.tiff; sourceTree = ""; }; + F790694504EF484300000104 /* TrashMailboxLarge.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TrashMailboxLarge.tiff; sourceTree = ""; }; + F790696104EF48AB00000104 /* FileTableDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FileTableDelegate.h; sourceTree = ""; }; + F790696204EF48AB00000104 /* LoadPanelController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LoadPanelController.m; sourceTree = ""; }; + F790696304EF48AB00000104 /* main.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + F790696404EF48AB00000104 /* FlippedBox.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FlippedBox.m; sourceTree = ""; }; + F790696504EF48AB00000104 /* ApplicationController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ApplicationController.m; sourceTree = ""; }; + F790696604EF48AB00000104 /* LiTableView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiTableView.h; sourceTree = ""; }; + F790696804EF48AB00000104 /* LiTableView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiTableView.m; sourceTree = ""; }; + F790696904EF48AB00000104 /* Downloader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Downloader.h; sourceTree = ""; }; + F790696A04EF48AB00000104 /* DownloadStatusView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DownloadStatusView.h; sourceTree = ""; }; + F790696B04EF48AB00000104 /* CopyController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CopyController.h; sourceTree = ""; }; + F790696C04EF48AB00000104 /* DownloadStatusView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DownloadStatusView.m; sourceTree = ""; }; + F790696D04EF48AB00000104 /* LoadPanelController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LoadPanelController.h; sourceTree = ""; }; + F790696E04EF48AB00000104 /* DownloadManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DownloadManager.h; sourceTree = ""; }; + F790697004EF48AB00000104 /* ClientManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ClientManager.m; sourceTree = ""; }; + F790697104EF48AB00000104 /* ApplicationController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ApplicationController.h; sourceTree = ""; }; + F790697204EF48AB00000104 /* ImageAndTextCell.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ImageAndTextCell.m; sourceTree = ""; }; + F790697304EF48AB00000104 /* FlippedBox.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FlippedBox.h; sourceTree = ""; }; + F790697404EF48AB00000104 /* LiScrolLView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiScrolLView.h; sourceTree = ""; }; + F790697504EF48AB00000104 /* Downloader.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Downloader.m; sourceTree = ""; }; + F790697604EF48AB00000104 /* ImageAndTextCell.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ImageAndTextCell.h; sourceTree = ""; }; + F790697704EF48AB00000104 /* Group.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Group.m; sourceTree = ""; }; + F790697804EF48AB00000104 /* InspectorController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = InspectorController.h; sourceTree = ""; }; + F790697904EF48AB00000104 /* GroupTableDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = GroupTableDelegate.h; sourceTree = ""; }; + F790697A04EF48AB00000104 /* InspectorController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = InspectorController.m; sourceTree = ""; }; + F790697B04EF48AB00000104 /* FileTableDelegate.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FileTableDelegate.m; sourceTree = ""; }; + F790697C04EF48AB00000104 /* ClientManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ClientManager.h; sourceTree = ""; }; + F790697D04EF48AB00000104 /* Liaison.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Liaison.h; sourceTree = ""; }; + F790697E04EF48AC00000104 /* LiScrolLView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiScrolLView.m; sourceTree = ""; }; + F790697F04EF48AC00000104 /* DownloadManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DownloadManager.m; sourceTree = ""; }; + F790698004EF48AC00000104 /* CopyController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = CopyController.m; sourceTree = ""; }; + F790698104EF48AC00000104 /* GroupTableDelegate.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = GroupTableDelegate.m; sourceTree = ""; }; + F790698204EF48AC00000104 /* Group.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Group.h; sourceTree = ""; }; + F79069A504EF48BA00000104 /* Liaison.scriptSuite */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Liaison.scriptSuite; sourceTree = ""; }; + F79069A804EF48C800000104 /* English */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/WindowElements.strings; sourceTree = ""; }; + F79069AA04EF48C800000104 /* English */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = English; path = English.lproj/Liaison.scriptTerminology; sourceTree = ""; }; + F79069AE04EF48C800000104 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/LoadPanel.nib; sourceTree = ""; }; + F79069B004EF48C800000104 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/CopyPanel.nib; sourceTree = ""; }; + F79069B204EF48C800000104 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/PreferencesWindow.nib; sourceTree = ""; }; + F79069B904EF4A2700000104 /* WindowController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WindowController.h; sourceTree = ""; }; + F79069BD04EF4A2700000104 /* ServerManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ServerManager.h; sourceTree = ""; }; + F79069BE04EF4A2700000104 /* RenManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenManager.h; sourceTree = ""; }; + F79069BF04EF4A2700000104 /* PreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PreferencesController.h; sourceTree = ""; }; + F79069C004EF4A2700000104 /* WriterThread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WriterThread.h; sourceTree = ""; }; + F79069C104EF4A2700000104 /* RenIPC.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenIPC.h; sourceTree = ""; }; + F79069C504EF4A2700000104 /* ViewOptionsController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ViewOptionsController.m; sourceTree = ""; }; + F79069C604EF4A2700000104 /* NIBConnector.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NIBConnector.h; sourceTree = ""; }; + F79069C704EF4A2700000104 /* PluginManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PluginManager.m; sourceTree = ""; }; + F79069C804EF4A2700000104 /* ViewOptionsController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ViewOptionsController.h; sourceTree = ""; }; + F79069C904EF4A2700000104 /* WindowController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = WindowController.m; sourceTree = ""; }; + F79069CA04EF4A2700000104 /* PreferencesController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PreferencesController.m; sourceTree = ""; }; + F79069CB04EF4A2700000104 /* WriterThreadPool.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = WriterThreadPool.m; sourceTree = ""; }; + F79069CC04EF4A2700000104 /* WriterThread.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = WriterThread.m; sourceTree = ""; }; + F79069CD04EF4A2700000104 /* RenManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = RenManager.m; sourceTree = ""; }; + F79069CE04EF4A2700000104 /* PluginManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PluginManager.h; sourceTree = ""; }; + F79069CF04EF4A2700000104 /* WriterThreadPool.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WriterThreadPool.h; sourceTree = ""; }; + F79069D004EF4A2700000104 /* NIBConnector.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NIBConnector.m; sourceTree = ""; }; + F79069D104EF4A2700000104 /* ServerManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ServerManager.m; sourceTree = ""; }; + F79069EC04EF4A8C00000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = chef; path = chef.lproj/WindowElements.strings; sourceTree = ""; }; + F79069ED04EF4A9500000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = chef; path = chef.lproj/LoadPanel.nib; sourceTree = ""; }; + F79069EE04EF4A9C00000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = chef; path = chef.lproj/CopyPanel.nib; sourceTree = ""; }; + F79069EF04EF4AA300000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = chef; path = chef.lproj/PreferencesWindow.nib; sourceTree = ""; }; + F79069F004EF4AAB00000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = chef; path = chef.lproj/MainMenu.nib; sourceTree = ""; }; + F79069F104EF4AB300000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = chef; path = chef.lproj/InfoPlist.strings; sourceTree = ""; }; + F7A5B69904F841A900000104 /* FindController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FindController.h; sourceTree = ""; }; + F7A5B69A04F841A900000104 /* FindController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FindController.m; sourceTree = ""; }; + F7C329D30514615A00000103 /* NSException+LiDebugging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSException+LiDebugging.m"; sourceTree = ""; }; + F7D398F60546870000BD181E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F7D398F70546870000BD181E /* Liaison.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Liaison.app; sourceTree = BUILT_PRODUCTS_DIR; }; + F7D6588204F3576900000104 /* LiBackend.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LiBackend.framework; path = ../Frameworks/build/Development/LiBackend.framework; sourceTree = ""; }; + F7D6588304F3576900000104 /* LiPlugin.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LiPlugin.framework; path = ../Frameworks/build/Development/LiPlugin.framework; sourceTree = ""; }; + F7D6588604F3579700000104 /* Built In Functions.liaisonplugin */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "Built In Functions.liaisonplugin"; path = "../Plugins/BuiltInFunctions/build/Development/Built In Functions.liaisonplugin"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F7D398F10546870000BD181E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F7D398F20546870000BD181E /* Cocoa.framework in Frameworks */, + F7D398F30546870000BD181E /* LiBackend.framework in Frameworks */, + F7D398F40546870000BD181E /* LiPlugin.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + F7C329D10514613300000103 /* Debugging */, + F75ACE9404EF50D500000104 /* Main Window */, + F7A5B69804F8417E00000104 /* Find Window */, + F75ACEA304EF514B00000104 /* Inspector Window */, + F75ACEA204EF513800000104 /* Prefs Window */, + F7906A0304EF4FE000000104 /* View Options Window */, + F75ACEA104EF512000000104 /* NIBConnector */, + F7906A0404EF500D00000104 /* Plugin Manager */, + F75ACEA004EF510900000104 /* Network Models */, + F75ACEAF04EF517E00000104 /* Cocoa Extensions */, + ); + name = Classes; + sourceTree = ""; + }; + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + F7D398F70546870000BD181E /* Liaison.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* Liaison */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 286D15B20CDD52F0006463CC /* Info.plist */, + F790690F04EF46F200000104 /* Plugins */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + F7D398F60546870000BD181E /* Info.plist */, + ); + name = Liaison; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + F790697D04EF48AB00000104 /* Liaison.h */, + F790696304EF48AB00000104 /* main.m */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + F79069A504EF48BA00000104 /* Liaison.scriptSuite */, + F79069A904EF48C800000104 /* Liaison.scriptTerminology */, + F79069A704EF48C800000104 /* WindowElements.strings */, + F79069AD04EF48C800000104 /* LoadPanel.nib */, + F79069AF04EF48C800000104 /* CopyPanel.nib */, + F79069B104EF48C800000104 /* PreferencesWindow.nib */, + 29B97318FDCFA39411CA2CEA /* MainMenu.nib */, + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, + F790692904EF484300000104 /* Images */, + F73ECD6904F6BF0A00000104 /* Liaison Help */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + F7D6588204F3576900000104 /* LiBackend.framework */, + F7D6588304F3576900000104 /* LiPlugin.framework */, + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; + F75ACE9404EF50D500000104 /* Main Window */ = { + isa = PBXGroup; + children = ( + F790697104EF48AB00000104 /* ApplicationController.h */, + F790696504EF48AB00000104 /* ApplicationController.m */, + F79069B904EF4A2700000104 /* WindowController.h */, + F79069C904EF4A2700000104 /* WindowController.m */, + F790696104EF48AB00000104 /* FileTableDelegate.h */, + F790697B04EF48AB00000104 /* FileTableDelegate.m */, + F790696D04EF48AB00000104 /* LoadPanelController.h */, + F790696204EF48AB00000104 /* LoadPanelController.m */, + F790698204EF48AC00000104 /* Group.h */, + F790697704EF48AB00000104 /* Group.m */, + F790697904EF48AB00000104 /* GroupTableDelegate.h */, + F790698104EF48AC00000104 /* GroupTableDelegate.m */, + ); + name = "Main Window"; + sourceTree = ""; + }; + F75ACEA004EF510900000104 /* Network Models */ = { + isa = PBXGroup; + children = ( + F79069C104EF4A2700000104 /* RenIPC.h */, + F74B98C80523F102000001C7 /* LiDataTranslator.h */, + F74B98C90523F102000001C7 /* LiDataTranslator.m */, + F79069BE04EF4A2700000104 /* RenManager.h */, + F79069CD04EF4A2700000104 /* RenManager.m */, + F790697C04EF48AB00000104 /* ClientManager.h */, + F790697004EF48AB00000104 /* ClientManager.m */, + F79069BD04EF4A2700000104 /* ServerManager.h */, + F79069D104EF4A2700000104 /* ServerManager.m */, + F790696904EF48AB00000104 /* Downloader.h */, + F790697504EF48AB00000104 /* Downloader.m */, + F790696E04EF48AB00000104 /* DownloadManager.h */, + F790697F04EF48AC00000104 /* DownloadManager.m */, + F790696B04EF48AB00000104 /* CopyController.h */, + F790698004EF48AC00000104 /* CopyController.m */, + F790696A04EF48AB00000104 /* DownloadStatusView.h */, + F790696C04EF48AB00000104 /* DownloadStatusView.m */, + ); + name = "Network Models"; + sourceTree = ""; + }; + F75ACEA104EF512000000104 /* NIBConnector */ = { + isa = PBXGroup; + children = ( + F79069C604EF4A2700000104 /* NIBConnector.h */, + F79069D004EF4A2700000104 /* NIBConnector.m */, + ); + name = NIBConnector; + sourceTree = ""; + }; + F75ACEA204EF513800000104 /* Prefs Window */ = { + isa = PBXGroup; + children = ( + F79069BF04EF4A2700000104 /* PreferencesController.h */, + F79069CA04EF4A2700000104 /* PreferencesController.m */, + ); + name = "Prefs Window"; + sourceTree = ""; + }; + F75ACEA304EF514B00000104 /* Inspector Window */ = { + isa = PBXGroup; + children = ( + F790697804EF48AB00000104 /* InspectorController.h */, + F790697A04EF48AB00000104 /* InspectorController.m */, + ); + name = "Inspector Window"; + sourceTree = ""; + }; + F75ACEAF04EF517E00000104 /* Cocoa Extensions */ = { + isa = PBXGroup; + children = ( + F75ACF7704EF5D2600000104 /* NSFileHandleExtensions */, + F75ACF7904EF5D3B00000104 /* LiTableView */, + F75ACF7B04EF5D4D00000104 /* LiScrollView */, + F75ACF7A04EF5D4500000104 /* ImageAndTextCell */, + F75ACF7804EF5D3400000104 /* FlippedBox */, + ); + name = "Cocoa Extensions"; + sourceTree = ""; + }; + F75ACF7704EF5D2600000104 /* NSFileHandleExtensions */ = { + isa = PBXGroup; + children = ( + F75ACF7304EF59C800000104 /* NSFileHandleExtensions.h */, + F75ACF7404EF59C800000104 /* NSFileHandleExtensions.m */, + F79069CF04EF4A2700000104 /* WriterThreadPool.h */, + F79069CB04EF4A2700000104 /* WriterThreadPool.m */, + F79069C004EF4A2700000104 /* WriterThread.h */, + F79069CC04EF4A2700000104 /* WriterThread.m */, + ); + name = NSFileHandleExtensions; + sourceTree = ""; + }; + F75ACF7804EF5D3400000104 /* FlippedBox */ = { + isa = PBXGroup; + children = ( + F790697304EF48AB00000104 /* FlippedBox.h */, + F790696404EF48AB00000104 /* FlippedBox.m */, + ); + name = FlippedBox; + sourceTree = ""; + }; + F75ACF7904EF5D3B00000104 /* LiTableView */ = { + isa = PBXGroup; + children = ( + F790696604EF48AB00000104 /* LiTableView.h */, + F790696804EF48AB00000104 /* LiTableView.m */, + ); + name = LiTableView; + sourceTree = ""; + }; + F75ACF7A04EF5D4500000104 /* ImageAndTextCell */ = { + isa = PBXGroup; + children = ( + F790697604EF48AB00000104 /* ImageAndTextCell.h */, + F790697204EF48AB00000104 /* ImageAndTextCell.m */, + ); + name = ImageAndTextCell; + sourceTree = ""; + }; + F75ACF7B04EF5D4D00000104 /* LiScrollView */ = { + isa = PBXGroup; + children = ( + F790697404EF48AB00000104 /* LiScrolLView.h */, + F790697E04EF48AC00000104 /* LiScrolLView.m */, + ); + name = LiScrollView; + sourceTree = ""; + }; + F790690F04EF46F200000104 /* Plugins */ = { + isa = PBXGroup; + children = ( + F7D6588604F3579700000104 /* Built In Functions.liaisonplugin */, + ); + name = Plugins; + sourceTree = ""; + }; + F790692904EF484300000104 /* Images */ = { + isa = PBXGroup; + children = ( + F790693404EF484300000104 /* File Icons */, + F790692A04EF484300000104 /* Add.tiff */, + F790692B04EF484300000104 /* AddFiles.tiff */, + F790692C04EF484300000104 /* AddGroup.tiff */, + F790692D04EF484300000104 /* delete.tiff */, + F790692E04EF484300000104 /* Download_Reload.tiff */, + F790692F04EF484300000104 /* Download_ReloadPressed.tiff */, + F790693004EF484300000104 /* Download_Reveal.tiff */, + F790693104EF484300000104 /* Download_RevealPressed.tiff */, + F790693204EF484300000104 /* Download_Stop.tiff */, + F790693304EF484300000104 /* Download_StopPressed.tiff */, + F790693704EF484300000104 /* info (italic).tiff */, + F790693804EF484300000104 /* info (plain).tiff */, + F790693904EF484300000104 /* LeftSearchCap.tiff */, + F790693A04EF484300000104 /* NormalMailbox.tiff */, + F790693B04EF484300000104 /* NormalMailboxLarge.tiff */, + F790693C04EF484300000104 /* quickpick.tiff */, + F790693D04EF484300000104 /* RemoveFiles.tiff */, + F790693E04EF484300000104 /* RemoveGroup.tiff */, + F790693F04EF484300000104 /* rendezvous.tiff */, + F790694004EF484300000104 /* reveal.tiff */, + F790694104EF484300000104 /* RightSearchCap.tiff */, + F790694204EF484300000104 /* SortAscending.gif */, + F790694304EF484300000104 /* SortDescending.gif */, + F790694404EF484300000104 /* TrashMailbox.tiff */, + F790694504EF484300000104 /* TrashMailboxLarge.tiff */, + ); + path = Images; + sourceTree = ""; + }; + F790693404EF484300000104 /* File Icons */ = { + isa = PBXGroup; + children = ( + F790693604EF484300000104 /* Liaison.icns */, + ); + path = "File Icons"; + sourceTree = ""; + }; + F7906A0304EF4FE000000104 /* View Options Window */ = { + isa = PBXGroup; + children = ( + F79069C804EF4A2700000104 /* ViewOptionsController.h */, + F79069C504EF4A2700000104 /* ViewOptionsController.m */, + ); + name = "View Options Window"; + sourceTree = ""; + }; + F7906A0404EF500D00000104 /* Plugin Manager */ = { + isa = PBXGroup; + children = ( + F79069CE04EF4A2700000104 /* PluginManager.h */, + F79069C704EF4A2700000104 /* PluginManager.m */, + ); + name = "Plugin Manager"; + sourceTree = ""; + }; + F7A5B69804F8417E00000104 /* Find Window */ = { + isa = PBXGroup; + children = ( + F7A5B69904F841A900000104 /* FindController.h */, + F7A5B69A04F841A900000104 /* FindController.m */, + ); + name = "Find Window"; + sourceTree = ""; + }; + F7C329D10514613300000103 /* Debugging */ = { + isa = PBXGroup; + children = ( + F7C329D30514615A00000103 /* NSException+LiDebugging.m */, + ); + name = Debugging; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + F7D398910546870000BD181E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + F7D398920546870000BD181E /* FileTableDelegate.h in Headers */, + F7D398930546870000BD181E /* LiTableView.h in Headers */, + F7D398940546870000BD181E /* Downloader.h in Headers */, + F7D398950546870000BD181E /* DownloadStatusView.h in Headers */, + F7D398960546870000BD181E /* CopyController.h in Headers */, + F7D398970546870000BD181E /* LoadPanelController.h in Headers */, + F7D398980546870000BD181E /* DownloadManager.h in Headers */, + F7D398990546870000BD181E /* ApplicationController.h in Headers */, + F7D3989A0546870000BD181E /* FlippedBox.h in Headers */, + F7D3989B0546870000BD181E /* LiScrolLView.h in Headers */, + F7D3989C0546870000BD181E /* ImageAndTextCell.h in Headers */, + F7D3989D0546870000BD181E /* InspectorController.h in Headers */, + F7D3989E0546870000BD181E /* GroupTableDelegate.h in Headers */, + F7D3989F0546870000BD181E /* ClientManager.h in Headers */, + F7D398A00546870000BD181E /* Liaison.h in Headers */, + F7D398A10546870000BD181E /* Group.h in Headers */, + F7D398A20546870000BD181E /* WindowController.h in Headers */, + F7D398A30546870000BD181E /* ServerManager.h in Headers */, + F7D398A40546870000BD181E /* RenManager.h in Headers */, + F7D398A50546870000BD181E /* PreferencesController.h in Headers */, + F7D398A60546870000BD181E /* WriterThread.h in Headers */, + F7D398A70546870000BD181E /* RenIPC.h in Headers */, + F7D398A80546870000BD181E /* NIBConnector.h in Headers */, + F7D398A90546870000BD181E /* ViewOptionsController.h in Headers */, + F7D398AA0546870000BD181E /* PluginManager.h in Headers */, + F7D398AB0546870000BD181E /* WriterThreadPool.h in Headers */, + F7D398AC0546870000BD181E /* NSFileHandleExtensions.h in Headers */, + F7D398AD0546870000BD181E /* FindController.h in Headers */, + F7D398AE0546870000BD181E /* LiDataTranslator.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + F7D398890546870000BD181E /* Liaison */ = { + isa = PBXNativeTarget; + buildConfigurationList = 28986794095DABC900B5DC99 /* Build configuration list for PBXNativeTarget "Liaison" */; + buildPhases = ( + F7D3988B0546870000BD181E /* CopyFiles */, + F7D3988F0546870000BD181E /* CopyFiles */, + F7D398910546870000BD181E /* Headers */, + F7D398AF0546870000BD181E /* Resources */, + F7D398D30546870000BD181E /* Sources */, + F7D398F10546870000BD181E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Liaison; + productInstallPath = "$(HOME)/Applications"; + productName = Liaison; + productReference = F7D398F70546870000BD181E /* Liaison.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 28986798095DABC900B5DC99 /* Build configuration list for PBXProject "Liaison" */; + compatibilityVersion = "Xcode 2.4"; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + chef, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* Liaison */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F7D398890546870000BD181E /* Liaison */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + F7D398AF0546870000BD181E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F7D398B00546870000BD181E /* Liaison.scriptSuite in Resources */, + F7D398B10546870000BD181E /* Liaison.scriptTerminology in Resources */, + F7D398B20546870000BD181E /* MainMenu.nib in Resources */, + F7D398B30546870000BD181E /* LoadPanel.nib in Resources */, + F7D398B40546870000BD181E /* CopyPanel.nib in Resources */, + F7D398B50546870000BD181E /* PreferencesWindow.nib in Resources */, + F7D398B60546870000BD181E /* InfoPlist.strings in Resources */, + F7D398B70546870000BD181E /* WindowElements.strings in Resources */, + F7D398B80546870000BD181E /* Liaison Help in Resources */, + F7D398B90546870000BD181E /* Liaison.icns in Resources */, + F7D398BA0546870000BD181E /* Add.tiff in Resources */, + F7D398BB0546870000BD181E /* AddFiles.tiff in Resources */, + F7D398BC0546870000BD181E /* AddGroup.tiff in Resources */, + F7D398BD0546870000BD181E /* delete.tiff in Resources */, + F7D398BE0546870000BD181E /* Download_Reload.tiff in Resources */, + F7D398BF0546870000BD181E /* Download_ReloadPressed.tiff in Resources */, + F7D398C00546870000BD181E /* Download_Reveal.tiff in Resources */, + F7D398C10546870000BD181E /* Download_RevealPressed.tiff in Resources */, + F7D398C20546870000BD181E /* Download_Stop.tiff in Resources */, + F7D398C30546870000BD181E /* Download_StopPressed.tiff in Resources */, + F7D398C40546870000BD181E /* info (italic).tiff in Resources */, + F7D398C50546870000BD181E /* info (plain).tiff in Resources */, + F7D398C60546870000BD181E /* LeftSearchCap.tiff in Resources */, + F7D398C70546870000BD181E /* NormalMailbox.tiff in Resources */, + F7D398C80546870000BD181E /* NormalMailboxLarge.tiff in Resources */, + F7D398C90546870000BD181E /* quickpick.tiff in Resources */, + F7D398CA0546870000BD181E /* RemoveFiles.tiff in Resources */, + F7D398CB0546870000BD181E /* RemoveGroup.tiff in Resources */, + F7D398CC0546870000BD181E /* rendezvous.tiff in Resources */, + F7D398CD0546870000BD181E /* reveal.tiff in Resources */, + F7D398CE0546870000BD181E /* RightSearchCap.tiff in Resources */, + F7D398CF0546870000BD181E /* SortAscending.gif in Resources */, + F7D398D00546870000BD181E /* SortDescending.gif in Resources */, + F7D398D10546870000BD181E /* TrashMailbox.tiff in Resources */, + F7D398D20546870000BD181E /* TrashMailboxLarge.tiff in Resources */, + 286D15B30CDD52F0006463CC /* Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + F7D398D30546870000BD181E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F7D398D40546870000BD181E /* LoadPanelController.m in Sources */, + F7D398D50546870000BD181E /* main.m in Sources */, + F7D398D60546870000BD181E /* FlippedBox.m in Sources */, + F7D398D70546870000BD181E /* ApplicationController.m in Sources */, + F7D398D80546870000BD181E /* LiTableView.m in Sources */, + F7D398D90546870000BD181E /* DownloadStatusView.m in Sources */, + F7D398DA0546870000BD181E /* ClientManager.m in Sources */, + F7D398DB0546870000BD181E /* ImageAndTextCell.m in Sources */, + F7D398DC0546870000BD181E /* Downloader.m in Sources */, + F7D398DD0546870000BD181E /* Group.m in Sources */, + F7D398DE0546870000BD181E /* InspectorController.m in Sources */, + F7D398DF0546870000BD181E /* FileTableDelegate.m in Sources */, + F7D398E00546870000BD181E /* LiScrolLView.m in Sources */, + F7D398E10546870000BD181E /* DownloadManager.m in Sources */, + F7D398E20546870000BD181E /* CopyController.m in Sources */, + F7D398E30546870000BD181E /* GroupTableDelegate.m in Sources */, + F7D398E40546870000BD181E /* ViewOptionsController.m in Sources */, + F7D398E50546870000BD181E /* PluginManager.m in Sources */, + F7D398E60546870000BD181E /* WindowController.m in Sources */, + F7D398E70546870000BD181E /* PreferencesController.m in Sources */, + F7D398E80546870000BD181E /* WriterThreadPool.m in Sources */, + F7D398E90546870000BD181E /* WriterThread.m in Sources */, + F7D398EA0546870000BD181E /* RenManager.m in Sources */, + F7D398EB0546870000BD181E /* NIBConnector.m in Sources */, + F7D398EC0546870000BD181E /* ServerManager.m in Sources */, + F7D398ED0546870000BD181E /* NSFileHandleExtensions.m in Sources */, + F7D398EE0546870000BD181E /* FindController.m in Sources */, + F7D398EF0546870000BD181E /* NSException+LiDebugging.m in Sources */, + F7D398F00546870000BD181E /* LiDataTranslator.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C165DFE840E0CC02AAC07 /* English */, + F79069F104EF4AB300000104 /* chef */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = { + isa = PBXVariantGroup; + children = ( + 29B97319FDCFA39411CA2CEA /* English */, + F79069F004EF4AAB00000104 /* chef */, + ); + name = MainMenu.nib; + sourceTree = ""; + }; + F73ECD6904F6BF0A00000104 /* Liaison Help */ = { + isa = PBXVariantGroup; + children = ( + F73ECD1304F6BEE000000104 /* English */, + ); + name = "Liaison Help"; + sourceTree = ""; + }; + F79069A704EF48C800000104 /* WindowElements.strings */ = { + isa = PBXVariantGroup; + children = ( + F79069A804EF48C800000104 /* English */, + F79069EC04EF4A8C00000104 /* chef */, + ); + name = WindowElements.strings; + sourceTree = ""; + }; + F79069A904EF48C800000104 /* Liaison.scriptTerminology */ = { + isa = PBXVariantGroup; + children = ( + F79069AA04EF48C800000104 /* English */, + ); + name = Liaison.scriptTerminology; + sourceTree = ""; + }; + F79069AD04EF48C800000104 /* LoadPanel.nib */ = { + isa = PBXVariantGroup; + children = ( + F79069AE04EF48C800000104 /* English */, + F79069ED04EF4A9500000104 /* chef */, + ); + name = LoadPanel.nib; + sourceTree = ""; + }; + F79069AF04EF48C800000104 /* CopyPanel.nib */ = { + isa = PBXVariantGroup; + children = ( + F79069B004EF48C800000104 /* English */, + F79069EE04EF4A9C00000104 /* chef */, + ); + name = CopyPanel.nib; + sourceTree = ""; + }; + F79069B104EF48C800000104 /* PreferencesWindow.nib */ = { + isa = PBXVariantGroup; + children = ( + F79069B204EF48C800000104 /* English */, + F79069EF04EF4AA300000104 /* chef */, + ); + name = PreferencesWindow.nib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 28986795095DABC900B5DC99 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ../Frameworks/build/Development; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREFIX_HEADER = Liaison.h; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + LIBRARY_SEARCH_PATHS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = Liaison; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost"; + WRAPPER_EXTENSION = app; + ZERO_LINK = YES; + }; + name = Development; + }; + 28986796095DABC900B5DC99 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + CC = "/usr/bin/gcc-3.3"; + COPY_PHASE_STRIP = YES; + CPLUSPLUS = "/usr/bin/g++-3.3"; + FRAMEWORK_SEARCH_PATHS = ../Frameworks/build; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_PREFIX_HEADER = Liaison.h; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + LIBRARY_SEARCH_PATHS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = Liaison; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost"; + WRAPPER_EXTENSION = app; + ZERO_LINK = NO; + }; + name = Deployment; + }; + 28986797095DABC900B5DC99 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + CC = "/usr/bin/gcc-3.3"; + CPLUSPLUS = "/usr/bin/g++-3.3"; + FRAMEWORK_SEARCH_PATHS = ../Frameworks/build; + GCC_PREFIX_HEADER = Liaison.h; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + LIBRARY_SEARCH_PATHS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = Liaison; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost"; + WRAPPER_EXTENSION = app; + }; + name = Default; + }; + 28986799095DABC900B5DC99 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Development; + }; + 2898679A095DABC900B5DC99 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Deployment; + }; + 2898679B095DABC900B5DC99 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 28986794095DABC900B5DC99 /* Build configuration list for PBXNativeTarget "Liaison" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 28986795095DABC900B5DC99 /* Development */, + 28986796095DABC900B5DC99 /* Deployment */, + 28986797095DABC900B5DC99 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 28986798095DABC900B5DC99 /* Build configuration list for PBXProject "Liaison" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 28986799095DABC900B5DC99 /* Development */, + 2898679A095DABC900B5DC99 /* Deployment */, + 2898679B095DABC900B5DC99 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/Liaison/LoadPanelController.h b/Liaison/LoadPanelController.h new file mode 100644 index 0000000..f83adf8 --- /dev/null +++ b/Liaison/LoadPanelController.h @@ -0,0 +1,25 @@ +/* LoadPanelController */ + +@interface LoadPanelController : NSObject +{ + IBOutlet NSTextField *thePathField, *theStatusField; + IBOutlet NSProgressIndicator *theProgressBar; + IBOutlet NSPanel *theLoadPanel; + + NSModalSession modalSession; + + BOOL isShowing; +} +- (void)show; +- (void)hide; + +- (void)setStatus: (NSString *)aStatusMsg; +- (void)setPath: (NSString *)aPath; +- (void)setProgress: (double)aProgress; +- (void)setIndeterminantProgress: (BOOL)isIndeterminante; +- (void)update; +@property BOOL isShowing; +@property (retain) NSPanel *theLoadPanel; +@property (retain) NSProgressIndicator *theProgressBar; +@property NSModalSession modalSession; +@end diff --git a/Liaison/LoadPanelController.m b/Liaison/LoadPanelController.m new file mode 100644 index 0000000..efed833 --- /dev/null +++ b/Liaison/LoadPanelController.m @@ -0,0 +1,74 @@ +#import "LoadPanelController.h" + +@implementation LoadPanelController +- (id)init +{ + self = [super init]; + + isShowing = NO; + + return self; +} + +- (void)sheetDidEnd: (NSWindow *)sheet + returnCode: (int)returnCode + contextInfo: (void *)contextInfo +{ + [sheet close]; +} + +- (void)show +{ + if (isShowing == NO) { + [NSApp beginSheet: theLoadPanel + modalForWindow: [NSApp mainWindow] + modalDelegate: self + didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo: nil]; + modalSession = [NSApp beginModalSessionForWindow: theLoadPanel]; + isShowing = YES; + } +} + +- (void)hide +{ + if (isShowing) { + [NSApp endModalSession: modalSession]; + [NSApp endSheet: theLoadPanel]; + isShowing = NO; + } +} + +- (void)setStatus: (NSString *)aStatusMsg +{ + [theStatusField setStringValue: aStatusMsg]; +} + +- (void)setPath: (NSString *)aPath +{ + [thePathField setStringValue: aPath]; +} + +- (void)setProgress: (double)aProgress +{ + [theProgressBar setDoubleValue: aProgress]; +} + +- (void)setIndeterminantProgress: (BOOL)isIndeterminante +{ + [theProgressBar setIndeterminate: isIndeterminante]; +} + +- (void)update +{ + if (isShowing) { + if ([theProgressBar isIndeterminate]) + [theProgressBar animate: self]; + [NSApp runModalSession: modalSession]; + } +} +@synthesize modalSession; +@synthesize isShowing; +@synthesize theProgressBar; +@synthesize theLoadPanel; +@end diff --git a/Liaison/NIBConnector.h b/Liaison/NIBConnector.h new file mode 100644 index 0000000..7af1fa8 --- /dev/null +++ b/Liaison/NIBConnector.h @@ -0,0 +1,30 @@ +// +// NIBConnector.h +// Liaison +// +// Created by Brian Cully on Mon Mar 03 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@class PreferencesController; +@class CopyController; +@class LoadPanelController; + +// Links to other NIB controllers. +@interface NIBConnector : NSObject { + IBOutlet PreferencesController *thePreferencesController; + IBOutlet CopyController *theCopyController; + IBOutlet LoadPanelController *theLoadPanelController; +} + ++ (NIBConnector *)connector; + +- (IBAction)showPreferencesWindow: (id)sender; +- (IBAction)showDownloadWindow: (id)sender; + +- (CopyController *)copyController; +- (LoadPanelController *)loadPanelController; +@property (retain) CopyController *theCopyController; +@property (retain) LoadPanelController *theLoadPanelController; +@property (retain) PreferencesController *thePreferencesController; +@end diff --git a/Liaison/NIBConnector.m b/Liaison/NIBConnector.m new file mode 100644 index 0000000..7873b78 --- /dev/null +++ b/Liaison/NIBConnector.m @@ -0,0 +1,66 @@ +// +// NIBConnector.m +// Liaison +// +// Created by Brian Cully on Mon Mar 03 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "NIBConnector.h" + +#import "CopyController.h" +#import "PreferencesController.h" + +@implementation NIBConnector +static NIBConnector *sharedInstance = nil; ++ (NIBConnector *)connector +{ + // Set in awakeFromNib + return sharedInstance; +} + +- (id) init +{ + self = [super init]; + + thePreferencesController = nil; + theCopyController = nil; + + return self; +} + +- (void)awakeFromNib +{ + if (sharedInstance == nil) + sharedInstance = self; +} + +- (void)showPreferencesWindow: (id)sender +{ + if (thePreferencesController == nil) + [NSBundle loadNibNamed: @"PreferencesWindow.nib" owner: self]; + [thePreferencesController showWindow]; +} + +- (IBAction)showDownloadWindow: (id)sender +{ + [[self copyController] showWindow]; +} + +- (CopyController *)copyController +{ + if (theCopyController == nil) + [NSBundle loadNibNamed: @"CopyPanel.nib" owner: self]; + return theCopyController; +} + +- (LoadPanelController *)loadPanelController +{ + if (theLoadPanelController == nil) + [NSBundle loadNibNamed: @"LoadPanel.nib" owner: self]; + return theLoadPanelController; +} +@synthesize theCopyController; +@synthesize thePreferencesController; +@synthesize theLoadPanelController; +@end diff --git a/Liaison/NSException+LiDebugging.m b/Liaison/NSException+LiDebugging.m new file mode 100644 index 0000000..4dc0067 --- /dev/null +++ b/Liaison/NSException+LiDebugging.m @@ -0,0 +1,23 @@ +// +// NSException+LiDebugging.m +// Liaison +// +// Created by Brian Cully on Sun Sep 14 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@interface LiException : NSException +@end + +@implementation LiException ++ (void)load +{ + [self poseAsClass: [NSException class]]; +} + +- (void)raise +{ + [LiLog logAsDebug: @"Raising exception"]; + [super raise]; +} +@end diff --git a/Liaison/NSFileHandleExtensions.h b/Liaison/NSFileHandleExtensions.h new file mode 100644 index 0000000..8267af3 --- /dev/null +++ b/Liaison/NSFileHandleExtensions.h @@ -0,0 +1,14 @@ +// +// NSFileHandleExtensions.h +// Liaison +// +// Created by Brian Cully on Sun May 25 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#define FileHandleWriteComplete @"FileHandleWriteComplete" +#define FileHandleClosed @"FileHandleClosed" + +@interface NSFileHandleExtensions : NSFileHandle +- (void)writeDataInBackground: (NSData *)someData; +@end diff --git a/Liaison/NSFileHandleExtensions.m b/Liaison/NSFileHandleExtensions.m new file mode 100644 index 0000000..fa65189 --- /dev/null +++ b/Liaison/NSFileHandleExtensions.m @@ -0,0 +1,24 @@ +// +// NSFileHandleExtensions.m +// Liaison +// +// Created by Brian Cully on Sun May 25 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "NSFileHandleExtensions.h" + +#import "WriterThreadPool.h" + +@implementation NSFileHandleExtensions +- (void)dealloc +{ + [[WriterThreadPool sharedPool] killThreadFor: self]; + [super dealloc]; +} + +- (void)writeDataInBackground: (NSData *)someData +{ + [[WriterThreadPool sharedPool] writeData: someData to: self]; +} +@end diff --git a/Liaison/PluginManager.h b/Liaison/PluginManager.h new file mode 100644 index 0000000..beb7eab --- /dev/null +++ b/Liaison/PluginManager.h @@ -0,0 +1,27 @@ +// +// PluginManager.h +// Liaison +// +// Created by Brian Cully on Thu May 15 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@interface PluginManager : NSObject +{ + NSMutableArray *theFileStorePlugins; + NSMutableArray *theBrowserPlugins; + NSMutableArray *theInspectorPlugins; +} + ++ (PluginManager *)defaultManager; +- (void)scanForPlugins; +@property (retain) NSMutableArray *theFileStorePlugins; +@property (retain) NSMutableArray *theInspectorPlugins; +@property (retain) NSMutableArray *theBrowserPlugins; +@end + +@interface PluginManager (Accessors) +- (NSArray *)fileStorePlugins; +- (NSArray *)browserPlugins; +- (NSArray *)inspectorPlugins; +@end diff --git a/Liaison/PluginManager.m b/Liaison/PluginManager.m new file mode 100644 index 0000000..319dd20 --- /dev/null +++ b/Liaison/PluginManager.m @@ -0,0 +1,116 @@ +// +// PluginManager.m +// Liaison +// +// Created by Brian Cully on Thu May 15 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "PluginManager.h" + +@implementation PluginManager +static PluginManager *defaultManager = nil; ++ (PluginManager *)defaultManager +{ + if (defaultManager == nil) + defaultManager = [[self alloc] init]; + return defaultManager; +} + +- (id)init +{ + self = [super init]; + + theFileStorePlugins = [[NSMutableArray alloc] init]; + theBrowserPlugins = [[NSMutableArray alloc] init]; + theInspectorPlugins = [[NSMutableArray alloc] init]; + + [self scanForPlugins]; + + return self; +} + +- (void)dealloc +{ + [theFileStorePlugins release]; + [theBrowserPlugins release]; + [theInspectorPlugins release]; + + [super dealloc]; +} + +- (void)activatePluginAtPath: (NSString *)aPath +{ + NSBundle *pluginBundle; + + pluginBundle = [NSBundle bundleWithPath: aPath]; + if (pluginBundle != nil) { + NSDictionary *pluginDict; + NSString *classString; + + pluginDict = [pluginBundle infoDictionary]; + classString = [pluginDict objectForKey: @"NSPrincipalClass"]; + if (classString != nil) { + Class pluginClass; + + pluginClass = NSClassFromString(classString); + if (pluginClass == nil) { + id plugin; + + pluginClass = [pluginBundle principalClass]; + plugin = [[[pluginClass alloc] init] autorelease]; + if ([pluginClass conformsToProtocol:@protocol(LiFileStorePlugin)]) { + [pluginClass setBundle: pluginBundle]; + [theFileStorePlugins addObject: plugin]; + } + if ([pluginClass conformsToProtocol:@protocol(LiBrowserPlugin)]) { + [pluginClass setBundle: pluginBundle]; + [theBrowserPlugins addObject: plugin]; + } + if ([pluginClass conformsToProtocol:@protocol(LiInspectorPlugin)]) { + [pluginClass setBundle: pluginBundle]; + [theInspectorPlugins addObject: plugin]; + } + } + } + } + return; +} + +- (void)scanForPlugins +{ + NSString *appLocation; + + appLocation = [[NSBundle mainBundle] builtInPlugInsPath]; + if (appLocation) { + NSEnumerator *pluginEnum; + NSString *pluginPath; + + pluginEnum = [[NSBundle pathsForResourcesOfType: @"liaisonplugin" + inDirectory: appLocation] objectEnumerator]; + while ((pluginPath = [pluginEnum nextObject]) != nil) { + [self activatePluginAtPath: pluginPath]; + } + } +} +@synthesize theBrowserPlugins; +@synthesize theFileStorePlugins; +@synthesize theInspectorPlugins; +@end + +@implementation PluginManager (Accessors) +- (NSArray *)fileStorePlugins +{ + return theFileStorePlugins; +} + +- (NSArray *)browserPlugins +{ + return theBrowserPlugins; +} + +- (NSArray *)inspectorPlugins +{ + return theInspectorPlugins; +} +@end diff --git a/Liaison/PreferencesController.h b/Liaison/PreferencesController.h new file mode 100644 index 0000000..f2569aa --- /dev/null +++ b/Liaison/PreferencesController.h @@ -0,0 +1,22 @@ +/* PreferencesController */ + +@interface PreferencesController : NSObject +{ + IBOutlet NSWindow *theWindow; + + IBOutlet NSTextField *theDownloadField; + IBOutlet NSTextField *theHostnameFieldDescription; + IBOutlet NSTextField *theHostnameField; + IBOutlet NSButton *theNetworkEnabledButton; +} +- (IBAction)applyChanges:(id)sender; +- (IBAction)selectDownloadDirectory:(id)sender; +- (IBAction)toggleNetworkEnabled:(id)sender; + +- (void)showWindow; +@property (retain) NSWindow *theWindow; +@property (retain) NSButton *theNetworkEnabledButton; +@property (retain) NSTextField *theHostnameFieldDescription; +@property (retain) NSTextField *theDownloadField; +@property (retain) NSTextField *theHostnameField; +@end diff --git a/Liaison/PreferencesController.m b/Liaison/PreferencesController.m new file mode 100644 index 0000000..3676505 --- /dev/null +++ b/Liaison/PreferencesController.m @@ -0,0 +1,154 @@ +#import "PreferencesController.h" + +#import "RenManager.h" + +@implementation PreferencesController (ToolbarDelegate) +- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar +{ + return [NSArray arrayWithObjects: + NSToolbarSeparatorItemIdentifier, + NSToolbarSpaceItemIdentifier, + NSToolbarFlexibleSpaceItemIdentifier, + NSToolbarCustomizeToolbarItemIdentifier, + @"Network", + nil]; +} + +- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar +{ + return [NSArray arrayWithObjects: + @"Network", + NSToolbarFlexibleSpaceItemIdentifier, + NSToolbarSeparatorItemIdentifier, + NSToolbarCustomizeToolbarItemIdentifier, nil]; +} + +- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar + itemForItemIdentifier:(NSString *)itemIdentifier + willBeInsertedIntoToolbar:(BOOL)flag +{ + NSToolbarItem *item; + + item = [[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier]; + if ([itemIdentifier isEqualToString: @"Network"]) { + [item setLabel: @"Network"]; + [item setPaletteLabel: @"Network"]; + [item setToolTip: @"Open network preferences."]; + [item setImage: [NSImage imageNamed: @"Network (Large).tiff"]]; + [item setTarget: self]; + [item setAction: @selector(revealNetworkPane:)]; + } + + return item; +} + +- (BOOL)validateToolbarItem: (NSToolbarItem *)theItem +{ + return YES; +} +@end + +@implementation PreferencesController +- (void)setupToolbar +{ + NSToolbar *toolbar; + + toolbar = [[[NSToolbar alloc] + initWithIdentifier: @"prefsToolbar"] autorelease]; + [toolbar setDelegate: self]; + [toolbar setAllowsUserCustomization: YES]; + [toolbar setAutosavesConfiguration: YES]; + [theWindow setToolbar: toolbar]; +} + +- (void)awakeFromNib +{ + // We don't need this yet, but leave the stubs. + //[self setupToolbar]; +} + +- (IBAction)applyChanges:(id)sender +{ + Preferences *prefs; + + prefs = [Preferences sharedPreferences]; + + [prefs setDownloadDirectory: [theDownloadField stringValue]]; + + if ([[prefs hostname] isEqualToString: + [theHostnameField stringValue]] == NO) { + [prefs setHostname: [theHostnameField stringValue]]; + [[RenManager sharedManager] updateHostname]; + } + + if ([theNetworkEnabledButton state] == 1 && + [prefs networkEnabled] == NO) { + [prefs setNetworkEnabled: YES]; + [[RenManager sharedManager] startSharing]; + } else if ([theNetworkEnabledButton state] == 0 && + [prefs networkEnabled] == YES) { + [prefs setNetworkEnabled: NO]; + [[RenManager sharedManager] stopSharing]; + } + + [theWindow close]; +} + +- (IBAction)toggleNetworkEnabled:(id)sender +{ + if ([sender state] == 1) { + [theHostnameFieldDescription setEnabled: YES]; + [theHostnameField setEnabled: YES]; + } else { + [theHostnameFieldDescription setEnabled: NO]; + [theHostnameField setEnabled: NO]; + } +} + +- (IBAction)selectDownloadDirectory:(id)sender +{ + NSOpenPanel *openPanel; + + openPanel = [NSOpenPanel openPanel]; + [openPanel setTitle: @"Select Download Directory"]; + [openPanel setAllowsMultipleSelection: NO]; + [openPanel setCanChooseDirectories: YES]; + [openPanel setCanChooseFiles: NO]; + + [openPanel beginSheetForDirectory: [theDownloadField stringValue] + file: nil + types: nil + modalForWindow: theWindow + modalDelegate: self + didEndSelector: @selector(openPanelDidEnd:returnCode:contextInfo:) + contextInfo: nil]; +} + +- (void)openPanelDidEnd: (NSOpenPanel *)aPanel + returnCode: (int)rc + contextInfo: (void *)someContext +{ + if (rc == NSCancelButton) + return; + + [theDownloadField setStringValue: [[aPanel filenames] objectAtIndex: 0]]; +} + +- (void)showWindow +{ + Preferences *prefs; + + prefs = [Preferences sharedPreferences]; + [theDownloadField setStringValue: [prefs downloadDirectory]]; + [theHostnameField setStringValue: [prefs hostname]]; + [theNetworkEnabledButton setState: + [prefs networkEnabled] ? 1 : 0]; + [self toggleNetworkEnabled: theNetworkEnabledButton]; + [theWindow makeKeyAndOrderFront: self]; +} +@synthesize theWindow; +@synthesize theNetworkEnabledButton; +@synthesize theHostnameFieldDescription; +@synthesize theHostnameField; +@synthesize theDownloadField; +@end diff --git a/Liaison/RenIPC.h b/Liaison/RenIPC.h new file mode 100644 index 0000000..714b130 --- /dev/null +++ b/Liaison/RenIPC.h @@ -0,0 +1,21 @@ +/* + * RenIPC.h + * Liaison + * + * Created by Brian Cully on Thu Mar 20 2003. + * Copyright (c) 2003 Brian Cully. All rights reserved. + * + */ + +// Rendezvous port name. +#define LiRendezvousPortName @"_liaison._tcp." + +// Notifications of death. +#define SERVERMANAGERDEATHNOTIFICATION @"Server Died" +#define CLIENTMANAGERDEATHNOTIFICATION @"Client Died" + +// Client/server keys. +#define RenHostnameKey @"hostname" +#define RenFilesAddedKey @"files added" +#define RenFilesChangedKey @"files changed" +#define RenFilesRemovedKey @"files removed" \ No newline at end of file diff --git a/Liaison/RenManager.h b/Liaison/RenManager.h new file mode 100644 index 0000000..e25734d --- /dev/null +++ b/Liaison/RenManager.h @@ -0,0 +1,48 @@ +// +// RenManager.h +// Liaison +// +// Created by Brian Cully on Sun Feb 16 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@interface RenManager : NSObject { + NSSocketPort *theListenPort; + NSFileHandle *theListenSocket; + NSNetService *theService; + NSNetServiceBrowser *theBrowser; + NSMutableDictionary *theServersByName; + NSMutableDictionary *theClients; + + LiFileStore *theFileStore; + + BOOL theShareIsEnabled; +} ++ (RenManager *)sharedManager; + +- (void)startup; +- (void)startSharing; +- (void)stopSharing; +- (void)updateHostname; +@property (retain,getter=listenSocket) NSFileHandle *theListenSocket; +@property (retain,getter=service) NSNetService *theService; +@property (retain) NSMutableDictionary *theServersByName; +@property (retain,getter=browser) NSNetServiceBrowser *theBrowser; +@property (retain) NSMutableDictionary *theClients; +@property BOOL theShareIsEnabled; +@property (retain,getter=fileStore) LiFileStore *theFileStore; +@property (retain,getter=listenPort) NSSocketPort *theListenPort; +@end + +@interface RenManager (Accessors) +- (NSNetServiceBrowser *)browser; +- (void)setBrowser: (NSNetServiceBrowser *)aBrowser; +- (LiFileStore *)fileStore; +- (void)setFileStore: (LiFileStore *)aFileStore; +- (NSSocketPort *)listenPort; +- (void)setListenPort: (NSSocketPort *)aPort; +- (NSFileHandle *)listenSocket; +- (void)setListenSocket: (NSFileHandle *)aSocket; +- (NSNetService *)service; +- (void)setService: (NSNetService *)aService; +@end \ No newline at end of file diff --git a/Liaison/RenManager.m b/Liaison/RenManager.m new file mode 100644 index 0000000..38323d3 --- /dev/null +++ b/Liaison/RenManager.m @@ -0,0 +1,357 @@ +// +// RenManager.m +// Liaison +// +// Created by Brian Cully on Sun Feb 16 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// +#import "RenIPC.h" +#import "RenManager.h" + +#import "ClientManager.h" +#import "ServerManager.h" + +#import +#import + +@implementation RenManager (NetServiceDelegate) +- (void)serverManagerDied: (NSNotification *)aNotification +{ + ServerManager *deadServer; + + [LiLog logAsDebug: @"server manager died."]; + deadServer = [aNotification object]; + [theServersByName removeObjectForKey: [[deadServer service] name]]; +} + +- (void)clientManagerDied: (NSNotification *)aNotification +{ + ClientManager *client; + + client = [aNotification object]; + if (client != nil) { + [LiLog logAsDebug: @"removing client for %@!", [client file]]; + [theClients removeObjectForKey: [client file]]; + [LiLog logAsDebug: @"removed client!"]; + } +} + +- (void)acceptConnection: (NSNotification *)aNotification +{ + ClientManager *client; + NSDictionary *userInfo; + NSFileHandle *socket; + NSNotificationCenter *defaultCenter; + + userInfo = [aNotification userInfo]; + socket = [userInfo objectForKey: + NSFileHandleNotificationFileHandleItem]; + + client = [[ClientManager alloc] initWithFile: socket + andFileStore: [self fileStore]]; + //[socket release]; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(clientManagerDied:) + name: CLIENTMANAGERDEATHNOTIFICATION + object: client]; + + [theClients setObject: client forKey: [client file]]; + [client startup]; + [client release]; + + [[self listenSocket] acceptConnectionInBackgroundAndNotify]; +} + +- (void)netServiceWillPublish:(NSNetService *)sender +{ + theShareIsEnabled = YES; + [self setService: sender]; +} + +- (void)netServiceDidStop: (NSNetService *)sender +{ + theShareIsEnabled = NO; + [self setService: nil]; +} + +- (void)netServiceBrowser: (NSNetServiceBrowser *)aNetServiceBrowser + didFindService: (NSNetService *)aNetService + moreComing: (BOOL)moreComing +{ + [aNetService setDelegate: self]; + [aNetService resolve]; +} + +- (void)netServiceBrowserDidStopSearch: (NSNetServiceBrowser *)browser +{ + [LiLog logAsDebug: @"stopping search."]; +} + +- (void)netServiceWillResolve: (NSNetService *)aNetService +{ +} + +- (void)netServiceDidResolveAddress: (NSNetService *)aNetService +{ + ServerManager *server; + + if ([theServersByName objectForKey: [aNetService name]] == nil) { + server = [[ServerManager alloc] initWithNetService: aNetService]; + if (server != nil) { + [theServersByName setObject: server forKey: [aNetService name]]; + [server startup]; + } + } +} + +// XXX - should set group name to IP address and proceed. +- (void)netService: (NSNetService *)aNetService + didNotResolve: (NSDictionary *)someErrors +{ + [LiLog logAsDebug: @"XXX: Couldn't resolve address for %@.", [aNetService name]]; +} + +- (void)netServiceBrowser: (NSNetServiceBrowser *)aNetServiceBrowser + didRemoveService: (NSNetService *)aNetService + moreComing: (BOOL)moreComing +{ + ServerManager *removedServer; + + [LiLog logAsDebug: @"removing service: %@", [aNetService name]]; + removedServer = [theServersByName objectForKey: [aNetService name]]; + [LiLog logAsDebug: @"\tremoved file store: %@", [[removedServer fileStore] storeID]]; + [removedServer shutdown]; +} +@end + +@implementation RenManager +static RenManager *sharedManager = nil; + ++ (RenManager *)sharedManager +{ + if (sharedManager == nil) + sharedManager = [[RenManager alloc] init]; + return sharedManager; +} + +- (id)init +{ + NSNotificationCenter *defaultCenter; + + self = [super init]; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(serverManagerDied:) + name: SERVERMANAGERDEATHNOTIFICATION + object: nil]; + + [self setFileStore: nil]; + + theServersByName = [[NSMutableDictionary alloc] init]; + theClients = [[NSMutableDictionary alloc] init]; + + [self setListenSocket: nil]; + [self setListenPort: nil]; + [self setService: nil]; + [self setBrowser: nil]; + + theShareIsEnabled = NO; + + return self; +} + +- (void)dealloc +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self]; + + [self setFileStore: nil]; + + [theServersByName release]; + [theClients release]; + + [self setListenSocket: nil]; + [self setListenPort: nil]; + [self setService: nil]; + [self setBrowser: nil]; + + [super dealloc]; +} + +- (void)startup +{ + NSNetServiceBrowser *browser; + + if ([[Preferences sharedPreferences] networkEnabled]) + [self startSharing]; + + browser = [[NSNetServiceBrowser alloc] init]; + [browser autorelease]; + [browser setDelegate: self]; + [browser searchForServicesOfType: LiRendezvousPortName + inDomain: @""]; + [self setBrowser: browser]; +} + +- (void)startSharing +{ + NSFileHandle *listenSocket; + NSNetService *service; + NSNotificationCenter *defaultCenter; + NSSocketPort *listenPort; + NSString *hostname; + struct sockaddr *addr; + int port; + + if (theShareIsEnabled) + return; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(acceptConnection:) + name: NSFileHandleConnectionAcceptedNotification + object: nil]; + + listenPort = [[NSSocketPort alloc] init]; + [listenPort autorelease]; + listen([listenPort socket], 10); + [self setListenPort: listenPort]; + + listenSocket = [[NSFileHandle alloc] initWithFileDescriptor: [listenPort socket] + closeOnDealloc: YES]; + [listenSocket autorelease]; + [listenSocket acceptConnectionInBackgroundAndNotify]; + [self setListenSocket: listenSocket]; + + hostname = [[Preferences sharedPreferences] hostname]; + addr = (struct sockaddr *)[[listenPort address] bytes]; + if (addr->sa_family == AF_INET6) + port = ((struct sockaddr_in6 *)addr)->sin6_port; + else + port = ((struct sockaddr_in *)addr)->sin_port; + + service = [[NSNetService alloc] initWithDomain: @"" + type: LiRendezvousPortName + name: hostname + port: port]; + [service autorelease]; + [service setDelegate: self]; + [service publish]; +} + +- (void)stopSharing +{ + if (theShareIsEnabled) { + NSNotificationCenter *defaultCenter; + NSEnumerator *clientEnum; + id clientKey; + + [[self service] stop]; + [self setListenSocket: nil]; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self + name: NSFileHandleConnectionAcceptedNotification + object: nil]; + + clientEnum = [theClients keyEnumerator]; + while ((clientKey = [clientEnum nextObject]) != nil) { + ClientManager *client; + + [LiLog logAsDebug: @"shutting down client"]; + client = [theClients objectForKey: clientKey]; + [client shutdown]; + } + [LiLog logAsDebug: @"sharing stopped."]; + } +} + +- (void)updateHostname +{ + if (theShareIsEnabled) { + ClientManager *client; + NSEnumerator *clientEnum; + + clientEnum = [theClients objectEnumerator]; + while ((client = [clientEnum nextObject]) != nil) { + [client setHostname: [[Preferences sharedPreferences] hostname]]; + [client sendHostname]; + } + } +} +@synthesize theBrowser; +@synthesize theServersByName; +@synthesize theService; +@synthesize theListenSocket; +@synthesize theFileStore; +@synthesize theShareIsEnabled; +@synthesize theClients; +@synthesize theListenPort; +@end + +@implementation RenManager (Accessors) +- (NSNetServiceBrowser *)browser +{ + return theBrowser; +} + +- (void)setBrowser: (NSNetServiceBrowser *)aBrowser +{ + [aBrowser retain]; + [theBrowser release]; + theBrowser = aBrowser; +} + +- (NSSocketPort *)listenPort +{ + return theListenPort; +} + +- (void)setListenPort: (NSSocketPort *)aPort +{ + [aPort retain]; + [theListenPort release]; + theListenPort = aPort; +} + +- (NSFileHandle *)listenSocket +{ + return theListenSocket; +} + +- (void)setListenSocket: (NSFileHandle *)aSocket +{ + [aSocket retain]; + [theListenSocket release]; + theListenSocket = aSocket; +} + +- (NSNetService *)service +{ + return theService; +} + +- (void)setService: (NSNetService *)aService +{ + [aService retain]; + [theService release]; + theService = aService; +} + +- (LiFileStore *)fileStore +{ + return theFileStore; +} + +- (void)setFileStore: (LiFileStore *)aFileStore +{ + [aFileStore retain]; + [theFileStore release]; + theFileStore = aFileStore; +} +@end \ No newline at end of file diff --git a/Liaison/ServerManager.h b/Liaison/ServerManager.h new file mode 100644 index 0000000..1c4da97 --- /dev/null +++ b/Liaison/ServerManager.h @@ -0,0 +1,41 @@ +// +// ServerManager.h +// Liaison +// +// Created by Brian Cully on Sun Feb 16 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@class DownloadStatusView; + +@interface ServerManager : NSObject +{ + NSFileHandle *theFile; + NSNetService *theService; + NSMutableData *theBuffer; + + LiFileStore *theFileStore; +} +- (id)initWithNetService: (NSNetService *)aService; + +- (void)startup; +- (void)shutdown; +@property (retain,getter=service) NSNetService *theService; +@property (retain,getter=buffer) NSMutableData *theBuffer; +@property (retain,getter=fileStore) LiFileStore *theFileStore; +@property (retain,getter=file) NSFileHandle *theFile; +@end + +@interface ServerManager (Accessors) +- (NSFileHandle *)file; +- (void)setFile: (NSFileHandle *)aFile; +- (NSNetService *)service; +- (void)setService: (NSNetService *)aService; +- (NSMutableData *)buffer; +- (void)setBuffer: (NSMutableData *)aBuffer; +- (LiFileStore *)fileStore; +- (void)setFileStore: (LiFileStore *)aFileStore; +@end + +@interface ServerManager (LiFileStore) +@end \ No newline at end of file diff --git a/Liaison/ServerManager.m b/Liaison/ServerManager.m new file mode 100644 index 0000000..903c3d5 --- /dev/null +++ b/Liaison/ServerManager.m @@ -0,0 +1,428 @@ +// +// ServerManager.m +// Liaison +// +// Created by Brian Cully on Sun Feb 16 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// +#import "RenIPC.h" +#import "ServerManager.h" + +#import "CopyController.h" +#import "DownloadStatusView.h" +#import "DownloadManager.h" +#import "LiDataTranslator.h" +#import "NIBConnector.h" + +#import +#import +#import + +@interface ServerManager (NetworkStuff) +- (BOOL)sendCommand: (NSDictionary *)aCmd; +@end + +@interface NSNetService (FileHandleExtensions) +- (NSFileHandle *)fileHandle; +@end + +@implementation ServerManager ++ (NSImage *)fileStoreIcon +{ + NSImage *image; + NSString *iconPath; + + image = [NSImage imageNamed: @"LiBuiltInFunctions RenStoreIcon"]; + if (image == nil) { + iconPath = [[NSBundle bundleForClass: [self class]] pathForResource: @"rendezvous" ofType: @"tiff"]; + image = [[NSImage alloc] initWithContentsOfFile: iconPath]; + [image setName: @"LiBuiltInFunctions RenStoreIcon"]; + } + + return image; +} + +- (id)initWithNetService: (NSNetService *)aService +{ + NSBundle *myBundle; + + self = [super init]; + + [self setService: aService]; + [self setFile: [[self service] fileHandle]]; + if ([self file] == nil) { + [self autorelease]; + return nil; + } + [self setFileStore: [LiFileStore fileStoreWithName: [aService name]]]; + [[self fileStore] setEditable: NO]; + [[self fileStore] setIcon: [[self class] fileStoreIcon]]; + [[self fileStore] setDelegate: self]; + [[self fileStore] addIndexForAttribute: LiGroupsAttribute]; + + theBuffer = [[NSMutableData alloc] init]; + + myBundle = [NSBundle bundleForClass: [self class]]; + + return self; +} + +- (void)dealloc +{ + NSNotificationCenter *defaultCenter; + + [LiLog logAsDebug: @"[ServerManager dealloc]"]; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self]; + + [self setService: nil]; + [self setFile: nil]; + [self setFileStore: nil]; + [self setBuffer: nil]; + + [super dealloc]; +} + +- (void)startup +{ + NSDictionary *handshake; + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(browserRead:) + name: NSFileHandleReadCompletionNotification + object: [self file]]; + + handshake = [NSDictionary dictionaryWithObject: @"browser" + forKey: @"type"]; + [self sendCommand: handshake]; + + [[self file] readInBackgroundAndNotify]; +} + +- (void)shutdown +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self + name: NSFileHandleReadCompletionNotification + object: [self file]]; + + [LiFileStore removeStoreWithID: [[self fileStore] storeID]]; + [self setFile: nil]; + [self setFileStore: nil]; + + [defaultCenter postNotificationName: SERVERMANAGERDEATHNOTIFICATION + object: self + userInfo: nil]; +} +@synthesize theBuffer; +@synthesize theFileStore; +@synthesize theFile; +@synthesize theService; +@end + +@implementation ServerManager (Accessors) +- (NSFileHandle *)file +{ + return theFile; +} + +- (void)setFile: (NSFileHandle *)aFile +{ + [aFile retain]; + [theFile release]; + theFile = aFile; +} + +- (NSNetService *)service +{ + return theService; +} + +- (void)setService: (NSNetService *)aService +{ + [aService retain]; + [theService release]; + theService = aService; +} + +- (NSMutableData *)buffer +{ + return theBuffer; +} + +- (void)setBuffer: (NSMutableData *)aBuffer +{ + [aBuffer retain]; + [theBuffer release]; + theBuffer = aBuffer; +} + +- (LiFileStore *)fileStore +{ + return theFileStore; +} + +- (void)setFileStore: (LiFileStore *)aFileStore +{ + [aFileStore retain]; + [theFileStore release]; + theFileStore = aFileStore; +} +@end + +@implementation ServerManager (LiFileStore) +- (BOOL)synchronizeFileStore +{ + return YES; +} + +- (void)synchronizeFileHandle: (LiFileHandle *)aFileHandle + withNewAttributes: (NSMutableDictionary *)someAttributes +{ +} + +- (BOOL)shouldUpdateFileHandle: (LiFileHandle *)aFileHandle +{ + return NO; +} + +- (void)updateFileHandle: (LiFileHandle *)aFileHandle +{ + return; +} + +- (void)openFileHandle: (LiFileHandle *)aFileHandle +{ + NSFileHandle *copySocket; + + [LiLog logAsDebug: @"[ServerManager openFileHandle: %@]", aFileHandle]; + [LiLog indentDebugLog]; + + [LiLog logAsDebug: @"filename: %@", [aFileHandle filename]]; + copySocket = [[self service] fileHandle]; + [[DownloadManager defaultManager] downloadFileHandle: aFileHandle + fromSocket: copySocket + target: self + didFinishSelector: @selector(fileHandleFinishedDownloading:context:errorString:) + withContext: nil]; + [LiLog unindentDebugLog]; +} + +- (void)fileHandleFinishedDownloading: (LiFileHandle *)aFileHandle + context: (void *)someContext + errorString: (NSString *)anError +{ + [LiLog logAsDebug: @"[ServerManager fileHandleFinishedDownloading]"]; + [LiLog indentDebugLog]; + if (anError != nil) { + [LiLog logAsError: @"Couldn't download %@: %@", + [aFileHandle filename], anError]; + } else { + [LiLog logAsDebug: @"File downloaded successfully."]; + } + [LiLog unindentDebugLog]; +} + +- (LiFileHandle *)addURL: (NSURL *)anURL + toFileStore: (LiFileStore *)aFileStore +{ + return nil; +} + +- (NSURL *)urlForFileHandle: (LiFileHandle *)aFileHandle +{ + NSURL *url; + NSString *urlStr; + + urlStr = [NSString stringWithFormat: @"liaison://%@/%@", [[aFileHandle fileStore] name], [aFileHandle fileID]]; + url = [NSURL URLWithString: urlStr]; + return url; +} + +- (NSArray *)defaultValuesForAttribute: (NSString *)anAttribute +{ + return nil; +} + +- (BOOL)addDefaultAttribute: (NSDictionary *)anAttribute toFileStore: (LiFileStore *)aFileStore +{ + return NO; +} + +- (BOOL)changeDefaultValueForAttribute: (NSDictionary *)anAttribute toValue: (id)aValue inFileStore: (LiFileStore *)aFileStore +{ + return NO; +} + +- (BOOL)removeDefaultAttribute: (NSDictionary *)anAttribute fromFileStore: (LiFileStore *)aFileStore +{ + return NO; +} +@end + +@implementation ServerManager (NetworkStuff) +- (BOOL)sendCommand: (NSDictionary *)aCmd +{ + NSData *cmdData; + NSString *errorString; + + errorString = nil; + cmdData = [aCmd encodedData]; + if (cmdData != nil) { + [[self file] writeData: cmdData]; + return YES; + } else + return NO; +} + +- (void)processAddList: (NSArray *)changeList +{ + NSDictionary *fileInfo; + + for (fileInfo in changeList) { + LiFileHandle *file; + + file = [[self fileStore] addFileWithAttributes: fileInfo]; + } + + [[self fileStore] synchronize]; +} + +- (void)processChangeList: (NSArray *)aFileList +{ + NSDictionary *changeDict; + + for (changeDict in aFileList) { + id fileID; + + fileID = [changeDict objectForKey: LiFileHandleAttribute]; + if (fileID != nil) { + LiFileHandle *tmpHandle; + NSEnumerator *attrEnum; + NSString *attribute; + + tmpHandle = [[LiFileHandle alloc] init]; + [tmpHandle setFileStore: [self fileStore]]; + [tmpHandle setFileID: fileID]; + + attrEnum = [changeDict keyEnumerator]; + while ((attribute = [attrEnum nextObject]) != nil) { + if ([attribute compare: LiFileHandleAttribute] != 0) { + [tmpHandle setValue: [changeDict objectForKey: attribute] + forAttribute: attribute]; + } + } + + [tmpHandle release]; + } + } + + [[self fileStore] synchronize]; +} + +- (void)processDeleteList: (NSArray *)aFileList +{ + id fileID; + + for (fileID in aFileList) { + LiFileHandle *tmpFile; + + tmpFile = [[LiFileHandle alloc] init]; + [tmpFile setFileStore: [self fileStore]]; + [tmpFile setFileID: fileID]; + + [[self fileStore] removeFileHandle: tmpFile]; + [tmpFile release]; + } + + [[self fileStore] synchronize]; +} + +- (void)processServerMessage: (NSDictionary *)aMsg +{ + NSString *msgType; + id arg; + + msgType = [aMsg objectForKey: @"type"]; + arg = [aMsg objectForKey: @"arg"]; + if ([msgType isEqualToString: RenHostnameKey]) { + [[self fileStore] setName: arg]; + } else if ([msgType isEqualToString: RenFilesAddedKey]) { + [self processAddList: arg]; + } else if ([msgType isEqualToString: RenFilesChangedKey]) { + [self processChangeList: arg]; + } else if ([msgType isEqualToString: RenFilesRemovedKey]) { + [self processDeleteList: arg]; + } else { + [LiLog logAsError: @"Unknown server message type: '%@'.", msgType]; + } +} + +- (void)processData: (NSData *)someData +{ + NSDictionary *msg; + + [[self buffer] appendData: someData]; + msg = [NSDictionary dictionaryWithEncodedData: [self buffer]]; + if (msg != nil) { + [self setBuffer: [NSMutableData data]]; + [self processServerMessage: msg]; + } +} + +- (void)browserRead: (NSNotification *)aNotification +{ + NSData *data; + NSFileHandle *remoteSocket; + + remoteSocket = [aNotification object]; + data = [[aNotification userInfo] objectForKey: + NSFileHandleNotificationDataItem]; + if ([data length] > 0) + [self processData: data]; + else { + [LiLog logAsDebug: @"browserRead shutdown"]; + [self shutdown]; + } + + [[aNotification object] readInBackgroundAndNotify]; +} +@end + +@implementation NSNetService (FileHandleExtensions) +- (NSFileHandle *)fileHandle +{ + NSArray *serverAddresses; + NSData *data; + NSFileHandle *remoteSocket; + struct sockaddr_in *remoteAddr; + int remotePort, rc; + + serverAddresses = [self addresses]; + if ([serverAddresses count] <= 0) + return nil; + + data = [serverAddresses objectAtIndex: 0]; + remoteAddr = (struct sockaddr_in *)[data bytes]; + + remotePort = socket(AF_INET, SOCK_STREAM, 0); + remoteSocket = [[NSFileHandle alloc] initWithFileDescriptor: remotePort + closeOnDealloc: YES]; + [remoteSocket autorelease]; + + rc = connect(remotePort, + (struct sockaddr *)remoteAddr, + sizeof(*remoteAddr)); + if (rc == -1) { + [LiLog logAsWarning: @"couldn't connect to %@: %s.", [self name], strerror(errno)]; + return nil; + } + + return remoteSocket; +} +@end \ No newline at end of file diff --git a/Liaison/ViewOptionsController.h b/Liaison/ViewOptionsController.h new file mode 100644 index 0000000..87fee6d --- /dev/null +++ b/Liaison/ViewOptionsController.h @@ -0,0 +1,24 @@ +/* ViewOptionsController */ + +@class FileTableDelegate; + +@interface ViewOptionsController : NSObject +{ + NSMatrix *layoutMatrix; + + IBOutlet FileTableDelegate *theFileDelegate; + IBOutlet id theHeaderField; + IBOutlet id theContentView; + IBOutlet NSWindow *theWindow; + + NSMutableArray *theShownColumns; +} + +- (IBAction)showWindow: (id)sender; +@property (retain) id theHeaderField; +@property (retain) FileTableDelegate *theFileDelegate; +@property (retain) NSWindow *theWindow; +@property (retain) NSMatrix *layoutMatrix; +@property (retain) id theContentView; +@property (retain) NSMutableArray *theShownColumns; +@end diff --git a/Liaison/ViewOptionsController.m b/Liaison/ViewOptionsController.m new file mode 100644 index 0000000..21f4c47 --- /dev/null +++ b/Liaison/ViewOptionsController.m @@ -0,0 +1,158 @@ +#import "ViewOptionsController.h" + +#import "FileTableDelegate.h" + +@implementation ViewOptionsController +- (id)init +{ + self = [super init]; + + theShownColumns = [[NSMutableArray alloc] init]; + + return self; +} + +- (void)dealloc +{ + [theShownColumns release]; + [super dealloc]; +} + +- (void)toggledButton: (id)sender +{ + NSButtonCell *senderCell; + NSMutableArray *colOrder; + NSMutableDictionary *listPrefs; + NSString *colID; + + senderCell = [sender selectedCell]; + listPrefs = [theFileDelegate listPrefs]; + colOrder = [listPrefs objectForKey: @"columnOrder"]; + colID = [theShownColumns objectAtIndex: [senderCell tag]]; + if (colID != nil) { + if ([senderCell state] == 1) { + [theFileDelegate showColumnWithIdentifier: colID]; + [colOrder addObject: colID]; + } else { + [theFileDelegate removeColumnWithIdentifier: colID]; + [colOrder removeObject: colID]; + } + } + + [theFileDelegate setListPrefs: listPrefs]; +} + +- (void)sizeWindowToFit +{ + NSRect contentRect, headerRect, windowFrame, oldWindowFrame; + + oldWindowFrame = [NSWindow contentRectForFrameRect: [theWindow frame] + styleMask: [theWindow styleMask]]; + + [layoutMatrix sizeToCells]; + contentRect = [theContentView frame]; + contentRect.size = [layoutMatrix bounds].size; + headerRect = [theHeaderField frame]; + + windowFrame.origin = oldWindowFrame.origin; + windowFrame.size.width = MAX(2*contentRect.origin.x + contentRect.size.width, + headerRect.origin.x + headerRect.size.width + 20); + windowFrame.size.height = headerRect.size.height + contentRect.size.height; + windowFrame = [NSWindow frameRectForContentRect: windowFrame + styleMask: [theWindow styleMask]]; + [theWindow setFrame: windowFrame display: YES animate: NO]; + + [theHeaderField setFrameOrigin: + NSMakePoint(headerRect.origin.x, contentRect.size.height)]; + [theContentView setFrame: contentRect]; +} + +- (IBAction)showWindow: (id)sender +{ + NSDictionary *browserColumns; + NSEnumerator *columnEnum; + NSMutableArray *optionCol; + NSString *identifier; + NSRect tmpRect; + unsigned int numRows; + int cellTag; + + layoutMatrix = [[NSMatrix alloc] initWithFrame: NSMakeRect(0.0, 0.0, 0.0, 0.0)]; + [layoutMatrix autorelease]; + [layoutMatrix setMode: NSTrackModeMatrix]; + [layoutMatrix setCellSize: NSMakeSize(100.0, 20.0)]; + [layoutMatrix setDrawsBackground: YES]; + + cellTag = 0; + browserColumns = [theFileDelegate browserColumns]; + numRows = ceil(sqrt([browserColumns count])); + optionCol = [NSMutableArray array]; + columnEnum = [browserColumns keyEnumerator]; + while ((identifier = [columnEnum nextObject]) != nil) { + LiBrowserColumn *col; + + col = [theFileDelegate columnForIdentifier: identifier]; + if (col != nil) { + NSButtonCell *checkBox; + NSTableColumn *tableCol; + BOOL checked; + + tableCol = [[theFileDelegate tableView] tableColumnWithIdentifier: identifier]; + if (tableCol == nil) + checked = 0; + else + checked = 1; + + checkBox = [[[NSButtonCell alloc] init] autorelease]; + [checkBox setButtonType: NSSwitchButton]; + [checkBox setTitle: [col name]]; + [checkBox setTag: cellTag]; + [checkBox setTarget: self]; + [checkBox setAction: @selector(toggledButton:)]; + [checkBox setState: checked]; + + [theShownColumns addObject: identifier]; + + [optionCol addObject: checkBox]; + if ([optionCol count] == numRows) { + if ([layoutMatrix numberOfColumns] == 0) { + unsigned int j; + + [layoutMatrix addColumn]; + for (j = [layoutMatrix numberOfRows]; j < numRows; j++) { + [layoutMatrix addRowWithCells: + [NSArray arrayWithObject: [optionCol objectAtIndex: j]]]; + } + [layoutMatrix putCell: [optionCol objectAtIndex: 0] + atRow: 0 column: 0]; + } else { + [layoutMatrix addColumnWithCells: optionCol]; + } + [optionCol removeAllObjects]; + } + } + + cellTag++; + } + + if ([optionCol count] > 0) { + while ([optionCol count] < numRows) + [optionCol addObject: [[[NSCell alloc] init] autorelease]]; + + [layoutMatrix addColumnWithCells: optionCol]; + } + + tmpRect = [layoutMatrix bounds]; + [theContentView setFrameSize: tmpRect.size]; + [theContentView addSubview: layoutMatrix]; + [self sizeWindowToFit]; + + [theWindow makeKeyAndOrderFront: self]; +} +@synthesize theShownColumns; +@synthesize theFileDelegate; +@synthesize theWindow; +@synthesize theContentView; +@synthesize theHeaderField; +@synthesize layoutMatrix; +@end diff --git a/Liaison/WindowController.h b/Liaison/WindowController.h new file mode 100644 index 0000000..38778c0 --- /dev/null +++ b/Liaison/WindowController.h @@ -0,0 +1,17 @@ +/* WindowController */ + +@interface WindowController : NSObject +{ + IBOutlet NSTableView *theFileList; + IBOutlet NSOutlineView *theGroupList; + IBOutlet NSWindow *theInspectorWindow; + IBOutlet NSWindow *theMainWindow; + + IBOutlet id theSearchField; +} +@property (retain) id theSearchField; +@property (retain) NSTableView *theFileList; +@property (retain) NSWindow *theMainWindow; +@property (retain) NSWindow *theInspectorWindow; +@property (retain) NSOutlineView *theGroupList; +@end \ No newline at end of file diff --git a/Liaison/WindowController.m b/Liaison/WindowController.m new file mode 100644 index 0000000..5ecd5d9 --- /dev/null +++ b/Liaison/WindowController.m @@ -0,0 +1,306 @@ +#import "WindowController.h" + +#import "ApplicationController.h" +#import "FileTableDelegate.h" +#import "GroupTableDelegate.h" + +static NSString * +myLocalizedString(NSString *aString) +{ + return NSLocalizedStringFromTable(aString, @"WindowElements", @""); +} + +static void +logRect(NSString *desc, NSRect aRect) +{ + [LiLog logAsDebug: @"%@, (%f, %f, %f, %f)", desc, aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height]; +} + +@implementation WindowController (WindowDelegate) +- (NSRect)windowWillUseStandardFrame: (NSWindow *)aWindow + defaultFrame: (NSRect)defaultFrame +{ + FileTableDelegate *fileDelegate; + GroupTableDelegate *groupDelegate; + NSRect curGroupFrame, curFileFrame, windowFrame; + NSSize minGroupSize, minFileSize; + float newWidth, newHeight, splitterWidth, headerHeight; + + [LiLog logAsDebug: @"[WindowController minSize]"]; + [LiLog indentDebugLog]; + + groupDelegate = [theGroupList delegate]; + fileDelegate = [theFileList delegate]; + + windowFrame = [aWindow frame]; + logRect(@"Unadjusted window frame", windowFrame); + + windowFrame = [NSWindow contentRectForFrameRect: [aWindow frame] + styleMask: [aWindow styleMask]]; + logRect(@"Old window frame", windowFrame); + + curFileFrame = [[theFileList superview] frame]; + logRect(@"curFileFrame", curFileFrame); + curGroupFrame = [[theGroupList superview] frame]; + logRect(@"curGroupFrame", curGroupFrame); + + splitterWidth = windowFrame.size.width - (curFileFrame.size.width + curGroupFrame.size.width); + [LiLog logAsDebug: @"splitter width: %f", splitterWidth]; + headerHeight = windowFrame.size.height - MAX(curFileFrame.size.height, curGroupFrame.size.height); + [LiLog logAsDebug: @"header height: %f, wf.height: %f, MAX(file,group).height: %f", headerHeight, windowFrame.size.height, MAX(curFileFrame.size.height, curGroupFrame.size.height)]; + + minGroupSize = [groupDelegate minSize]; + [LiLog logAsDebug: @"minGroupSize: %f, %f", minGroupSize.width, minGroupSize.height]; + minFileSize = [fileDelegate minSize]; + [LiLog logAsDebug: @"minFileSize: %f, %f", minFileSize.width, minFileSize.height]; + + newWidth = minGroupSize.width + minFileSize.width + splitterWidth; + newHeight = MAX(minGroupSize.height, minFileSize.height) + headerHeight + 6.0; + + [LiLog logAsDebug: @"newWidth, newHeight: %f, %f", newWidth, newHeight]; + + windowFrame.origin.y += windowFrame.size.height; + windowFrame.origin.y -= newHeight; + windowFrame.size = NSMakeSize(newWidth, newHeight); + windowFrame = [NSWindow frameRectForContentRect: windowFrame + styleMask: [aWindow styleMask]]; + + if ((windowFrame.origin.x + windowFrame.size.width) > + (defaultFrame.origin.x + defaultFrame.size.width)) { + [LiLog logAsDebug: @"Need to adjust width"]; + if (windowFrame.size.width > defaultFrame.size.width) { + windowFrame.origin.x = defaultFrame.origin.x; + windowFrame.size.width = defaultFrame.size.width; + } else { + windowFrame.origin.x = defaultFrame.size.width - windowFrame.size.width; + } + } + if ((windowFrame.origin.y + windowFrame.size.height) > + (defaultFrame.origin.y + defaultFrame.size.height)) { + [LiLog logAsDebug: @"Need to adjust height"]; + if (windowFrame.size.height > defaultFrame.size.height) { + windowFrame.origin.y = defaultFrame.origin.y; + windowFrame.size.height = defaultFrame.size.height; + } else { + windowFrame.origin.y = defaultFrame.size.height - windowFrame.size.height; + } + } + logRect(@"New window frame", windowFrame); + + [LiLog unindentDebugLog]; + + return windowFrame; +} + +- (void)windowDidBecomeKey: (NSNotification *)aNotificatin +{ + [LiLog logAsDebug: @"[WindowController windowDidBecomeKey]"]; + [[theMainWindow firstResponder] becomeFirstResponder]; +} + +- (void)controlTextDidChange:(NSNotification *)aNotification +{ + FileTableDelegate *fileDelegate; + + fileDelegate = [theFileList dataSource]; + [fileDelegate saveSelectionOfTableView: theFileList]; + [fileDelegate setSearchString: + [[[[aNotification object] stringValue] lowercaseString] retain]]; + [fileDelegate redisplay]; + [fileDelegate restoreSelectionToTableView: theFileList refresh: YES]; +} +@end + +@implementation WindowController +- (id)init +{ + self = [super init]; + + return self; +} + +- (void)dealloc +{ + [super dealloc]; +} + +- (void)setupToolbar +{ + NSToolbar *toolbar; + + toolbar = [[[NSToolbar alloc] + initWithIdentifier: @"mainToolbar"] autorelease]; + [toolbar setDelegate: self]; + [toolbar setAllowsUserCustomization: YES]; + [toolbar setAutosavesConfiguration: YES]; + [theMainWindow setToolbar: toolbar]; +} + +- (void)awakeFromNib +{ + [self setupToolbar]; +} +@synthesize theInspectorWindow; +@synthesize theGroupList; +@synthesize theFileList; +@synthesize theSearchField; +@synthesize theMainWindow; +@end + +@implementation WindowController (ToolbarDelegateCategory) +- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar +{ + return [NSArray arrayWithObjects: + NSToolbarSeparatorItemIdentifier, + NSToolbarSpaceItemIdentifier, + NSToolbarFlexibleSpaceItemIdentifier, + NSToolbarCustomizeToolbarItemIdentifier, + @"AddFilesItem", + @"RemoveFilesItem", + @"SearchItem", + @"InfoItem", + @"AddGroupItem", + @"RemoveGroupItem", + @"RevealInFinderItem", + nil]; +} + +- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar +{ + return [NSArray arrayWithObjects: + @"AddGroupItem", + @"RemoveGroupItem", + NSToolbarSeparatorItemIdentifier, + @"AddFilesItem", + @"RemoveFilesItem", + @"InfoItem", + @"RevealInFinderItem", + NSToolbarFlexibleSpaceItemIdentifier, + @"SearchItem", + NSToolbarSeparatorItemIdentifier, + NSToolbarCustomizeToolbarItemIdentifier, + nil]; +} + +- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar + itemForItemIdentifier:(NSString *)itemIdentifier + willBeInsertedIntoToolbar:(BOOL)flag +{ + NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier: + itemIdentifier]; + + if ([itemIdentifier isEqualToString: @"AddFilesItem"]) { + [item setLabel: myLocalizedString(@"LiToolbarAddFileLabel")]; + [item setPaletteLabel: myLocalizedString(@"LiToolbarAddFilePaletteLabel")]; + [item setToolTip: myLocalizedString(@"LiToolbarAddFileToolTip")]; + + [item setImage: [NSImage imageNamed: @"AddFiles.tiff"]]; + [item setTarget: self]; + [item setAction: @selector(addToLibrary:)]; + } else if ([itemIdentifier isEqualToString: @"RemoveFilesItem"]) { + [item setLabel: myLocalizedString(@"LiToolbarRemoveFileLabel")]; + [item setPaletteLabel: myLocalizedString(@"LiToolbarRemoveFilePaletteLabel")]; + [item setToolTip: myLocalizedString(@"LiToolbarRemoveFileToolTip")]; + + [item setImage: [NSImage imageNamed: @"RemoveFiles.tiff"]]; + [item setTarget: self]; + [item setAction: @selector(removeFiles:)]; + } else if ([itemIdentifier isEqualToString: @"SearchItem"]) { + NSRect frame; + + frame = [theSearchField frame]; + [item setLabel: myLocalizedString(@"LiToolbarSearchLabel")]; + [item setPaletteLabel: myLocalizedString(@"LiToolbarSearchPaletteLabel")]; + [item setToolTip: myLocalizedString(@"LiToolbarSearchToolTip")]; + + [item setView: theSearchField]; + [item setMinSize: frame.size]; + [item setMaxSize: frame.size]; + } else if ([itemIdentifier isEqualToString: @"InfoItem"]) { + [item setLabel: myLocalizedString(@"LiToolbarGetInfoLabel")]; + [item setPaletteLabel: myLocalizedString(@"LiToolbarGetInfoPaletteLabel")]; + [item setToolTip: myLocalizedString(@"LiToolbarGetInfoToolTip")]; + + [item setImage: [NSImage imageNamed: @"info (italic).tiff"]]; + [item setTarget: self]; + [item setAction: @selector(openInspector:)]; + } else if ([itemIdentifier isEqualToString: @"AddGroupItem"]) { + [item setLabel: myLocalizedString(@"LiToolbarAddGroupLabel")]; + [item setPaletteLabel: myLocalizedString(@"LiToolbarAddGroupPaletteLabel")]; + [item setToolTip: myLocalizedString(@"LiToolbarAddGroupToolTip")]; + + [item setImage: [NSImage imageNamed: @"AddGroup.tiff"]]; + [item setTarget: self]; + [item setAction: @selector(addGroup:)]; + } else if ([itemIdentifier isEqualToString: @"RemoveGroupItem"]) { + [item setLabel: myLocalizedString(@"LiToolbarRemoveGroupLabel")]; + [item setPaletteLabel: myLocalizedString(@"LiToolbarRemoveGroupPaletteLabel")]; + [item setToolTip: myLocalizedString(@"LiToolbarRemoveGroupToolTip")]; + + [item setImage: [NSImage imageNamed: @"RemoveGroup.tiff"]]; + [item setTarget: self]; + [item setAction: @selector(removeGroup:)]; + } else if ([itemIdentifier isEqualToString: @"RevealInFinderItem"]) { + [item setLabel: myLocalizedString(@"LiToolbarRevealLabel")]; + [item setPaletteLabel: myLocalizedString(@"LiToolbarRevealPaletteLabel")]; + [item setToolTip: myLocalizedString(@"LiToolbarRevealToolTip")]; + + [item setImage: [NSImage imageNamed: @"reveal.tiff"]]; + [item setTarget: self]; + [item setAction: @selector(revealInFinder:)]; + } + return [item autorelease]; +} + +- (BOOL)validateToolbarItem: (NSToolbarItem *)theItem +{ + GroupTableDelegate *groupDelegate; + FileTableDelegate *fileDelegate; + + groupDelegate = [theGroupList delegate]; + fileDelegate = [theFileList delegate]; + if ([theItem action] == @selector(addToLibrary:)) { + return [fileDelegate validateAction: @selector(addFiles:)]; + } else if ([theItem action] == @selector(revealInFinder:)) { + return [fileDelegate validateAction: @selector(revealInFinder:)]; + } else if ([theItem action] == @selector(removeFiles:)) { + return [fileDelegate validateAction: @selector(delete:)]; + } else if ([theItem action] == @selector(addGroup:)) { + return [groupDelegate validateAction: @selector(addGroup:)]; + } else if ([theItem action] == @selector(removeGroup:)) { + return [groupDelegate validateAction: @selector(delete:)]; + } + + return YES; +} + +- (IBAction)addGroup:(id)sender +{ + [[theGroupList delegate] addGroup: self]; +} + +- (IBAction)removeGroup:(id)sender +{ + [theGroupList performSelector: @selector(delete:) withObject: sender]; +} + +- (IBAction)addToLibrary:(id)sender +{ + [[theFileList delegate] addFiles: self]; +} + +- (IBAction)removeFiles:(id)sender +{ + [theFileList performSelector: @selector(delete:) withObject: sender]; +} + +- (IBAction)openInspector:(id)sender +{ + [[ApplicationController theApp] showInspectorWindow: self]; +} + +- (IBAction)revealInFinder:(id)sender +{ + [[theFileList delegate] revealInFinder: self]; +} +@end \ No newline at end of file diff --git a/Liaison/WriterThread.h b/Liaison/WriterThread.h new file mode 100644 index 0000000..6dc8ece --- /dev/null +++ b/Liaison/WriterThread.h @@ -0,0 +1,38 @@ +// +// WriterThread.h +// Liaison +// +// Created by Brian Cully on Wed Feb 26 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#define WriterThreadDied @"LiWriterThreadDied" + +@interface WriterThread : NSObject { + NSMutableArray *theDataQueue; + NSConditionLock *theQueueLock; + + NSFileHandle *theFile; + + volatile BOOL theConnectionIsOpen; + volatile BOOL theKillFlag; +} +- (id)initWithFileHandle: (NSFileHandle *)aFileHandle; +- (void)die; + +- (void)writeData: (NSData *)someData; +@property (retain,getter=queueLock) NSConditionLock *theQueueLock; +@property (retain,getter=dataQueue) NSMutableArray *theDataQueue; +@property volatile BOOL theConnectionIsOpen; +@property volatile BOOL theKillFlag; +@property (assign,getter=file,setter=setFile:) NSFileHandle *theFile; +@end + +@interface WriterThread (Accessors) +- (NSMutableArray *)dataQueue; +- (void)setDataQueue: (NSMutableArray *)aQueue; +- (NSConditionLock *)queueLock; +- (void)setQueueLock: (NSConditionLock *)aLock; +- (NSFileHandle *)file; +- (void)setFile: (NSFileHandle *)aFile; +@end diff --git a/Liaison/WriterThread.m b/Liaison/WriterThread.m new file mode 100644 index 0000000..f34f8c9 --- /dev/null +++ b/Liaison/WriterThread.m @@ -0,0 +1,211 @@ +// +// WriterThread.m +// Liaison +// +// Created by Brian Cully on Wed Feb 26 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "NSFileHandleExtensions.h" +#import "WriterThread.h" + +#import +#import +#import +#import + +#define NO_DATA 0 +#define HAS_DATA 1 + +@implementation WriterThread +- (id)initWithFileHandle: (NSFileHandle *)aFileHandle +{ + self = [super init]; + + theKillFlag = NO; + [self setDataQueue: [NSMutableArray array]]; + [self setQueueLock: + [[[NSConditionLock alloc] initWithCondition: NO_DATA] autorelease]]; + [self setFile: aFileHandle]; + + [NSThread detachNewThreadSelector: @selector(startThreadWithObject:) + toTarget: self + withObject: nil]; + + return self; +} + +- (void)dealloc +{ + [self setFile: nil]; + [self setDataQueue: nil]; + [self setQueueLock: nil]; + [super dealloc]; +} + +- (BOOL)writeBufferedData: (NSData *)someData +{ + if (theConnectionIsOpen) { + int fileDescriptor; + ssize_t dataLen, wroteLen; + void *data; + + fileDescriptor = [[self file] fileDescriptor]; + data = (void *)[someData bytes]; + dataLen = [someData length]; + wroteLen = 0; + while (wroteLen < dataLen) { + ssize_t rc; + + rc = write(fileDescriptor, + data+wroteLen, + dataLen-wroteLen); + if (rc >= 0) { + wroteLen += rc; + } else { + if (errno == EINTR || errno == EAGAIN) + continue; + theConnectionIsOpen = NO; + break; + } + } + } + + return theConnectionIsOpen; +} + +- (void)sendNextData +{ + NSData *dataToSend; + NSNotificationCenter *defaultCenter; + + [[self queueLock] lockWhenCondition: HAS_DATA]; + if (theKillFlag || theConnectionIsOpen == NO) { + return; + } + if ([[self dataQueue] count] <= 0) { + [[self queueLock] unlockWithCondition: NO_DATA]; + [LiLog unindentDebugLog]; + return; + } + + dataToSend = [[[[self dataQueue] objectAtIndex: 0] retain] autorelease]; + [[self dataQueue] removeObjectAtIndex: 0]; + if ([[self dataQueue] count] > 0) + [[self queueLock] unlockWithCondition: HAS_DATA]; + else + [[self queueLock] unlockWithCondition: NO_DATA]; + + defaultCenter = [NSNotificationCenter defaultCenter]; + if ([self writeBufferedData: dataToSend] == NO) { + NSNotification *notification; + + notification = [NSNotification notificationWithName: FileHandleClosed + object: [self file]]; + [defaultCenter performSelectorOnMainThread: @selector(postNotification:) + withObject: notification + waitUntilDone: YES]; + } else { + NSNotification *notification; + + notification = [NSNotification notificationWithName: FileHandleWriteComplete + object: [self file]]; + [defaultCenter performSelectorOnMainThread: @selector(postNotification:) + withObject: notification + waitUntilDone: NO]; + } +} + +- (void)startThreadWithObject: (id)anObject +{ + NSAutoreleasePool *rp; + NSDictionary *userInfo; + NSNotification *notification; + NSNotificationCenter *defaultCenter; + NSNumber *fd; + + rp = [[NSAutoreleasePool alloc] init]; + + fd = [NSNumber numberWithInt: [[self file] fileDescriptor]]; + theConnectionIsOpen = YES; + while (theKillFlag == NO) { + NSAutoreleasePool *srp; + + srp = [[NSAutoreleasePool alloc] init]; + [self sendNextData]; + [srp release]; + } + + userInfo = [NSDictionary dictionaryWithObject: fd + forKey: @"FileDescriptorKey"]; + defaultCenter = [NSNotificationCenter defaultCenter]; + notification = [NSNotification notificationWithName: WriterThreadDied + object: self + userInfo: userInfo]; + [defaultCenter performSelectorOnMainThread: @selector(postNotification:) + withObject: notification + waitUntilDone: YES]; + [rp release]; +} + +- (void)die +{ + [[self queueLock] lock]; + theKillFlag = YES; + [[self queueLock] unlockWithCondition: HAS_DATA]; +} + +- (void)writeData: (NSData *)someData +{ + if (someData == nil) + return; + + [[self queueLock] lock]; + NS_DURING + [[self dataQueue] addObject: someData]; + NS_HANDLER + [LiLog logAsDebug: @"Got exception '%@' trying to add to data queue: %@.", [localException name], [localException reason]]; + NS_ENDHANDLER + [[self queueLock] unlockWithCondition: HAS_DATA]; +} +@synthesize theQueueLock; +@synthesize theConnectionIsOpen; +@synthesize theKillFlag; +@synthesize theDataQueue; +@end + +@implementation WriterThread (Accessors) +- (NSMutableArray *)dataQueue +{ + return theDataQueue; +} + +- (void)setDataQueue: (NSMutableArray *)aQueue +{ + [aQueue retain]; + [theDataQueue release]; + theDataQueue = aQueue; +} + +- (NSConditionLock *)queueLock +{ + return theQueueLock; +} + +- (void)setQueueLock: (NSConditionLock *)aLock +{ + [aLock retain]; + [theQueueLock release]; + theQueueLock = aLock; +} + +- (NSFileHandle *)file +{ + return theFile; +} + +- (void)setFile: (NSFileHandle *)aFile +{ + theFile = aFile; +} +@end \ No newline at end of file diff --git a/Liaison/WriterThreadPool.h b/Liaison/WriterThreadPool.h new file mode 100644 index 0000000..20825a5 --- /dev/null +++ b/Liaison/WriterThreadPool.h @@ -0,0 +1,17 @@ +// +// WriterThreadPool.h +// Liaison +// +// Created by Brian Cully on Wed Feb 26 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +@interface WriterThreadPool : NSObject { + NSMutableDictionary *theWriterThreads; +} ++ (WriterThreadPool *)sharedPool; + +- (void)writeData: (NSData *)someData to: (NSFileHandle *)aFileHandle; +- (void)killThreadFor: (NSFileHandle *)aFileHandle; +@property (retain) NSMutableDictionary *theWriterThreads; +@end diff --git a/Liaison/WriterThreadPool.m b/Liaison/WriterThreadPool.m new file mode 100644 index 0000000..6aefc44 --- /dev/null +++ b/Liaison/WriterThreadPool.m @@ -0,0 +1,95 @@ +// +// WriterThreadPool.m +// Liaison +// +// Created by Brian Cully on Wed Feb 26 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// + +#import "WriterThreadPool.h" + +#import "WriterThread.h" + +#import + +@implementation WriterThreadPool +static WriterThreadPool *sharedPool = nil; + ++ (WriterThreadPool *)sharedPool +{ + if (sharedPool == nil) + sharedPool = [[WriterThreadPool alloc] init]; + return sharedPool; +} + +void ign_handler() +{ + return; +} + +- (id)init +{ + NSNotificationCenter *defaultCenter; + struct sigaction ign_action; + + self = [super init]; + + ign_action.sa_handler = ign_handler; + sigemptyset(&ign_action.sa_mask); + ign_action.sa_flags = SA_RESTART; + sigaction(SIGPIPE, &ign_action, NULL); + + theWriterThreads = [[NSMutableDictionary alloc] init]; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver: self + selector: @selector(writerThreadDied:) + name: WriterThreadDied + object: nil]; + + return self; +} + +- (void)dealloc +{ + [theWriterThreads release]; + [super dealloc]; +} + +- (void)writeData: (NSData *)someData to: (NSFileHandle *)aFileHandle +{ + NSNumber *fd; + WriterThread *writer; + + fd = [NSNumber numberWithInt: [aFileHandle fileDescriptor]]; + writer = [theWriterThreads objectForKey: fd]; + if (writer == nil) { + writer = [[WriterThread alloc] initWithFileHandle: aFileHandle]; + [theWriterThreads setObject: writer forKey: fd]; + [writer release]; + } + [writer writeData: someData]; +} + +- (void)killThreadFor: (NSFileHandle *)aFileHandle +{ + NSNumber *fd; + WriterThread *writer; + + fd = [NSNumber numberWithInt: [aFileHandle fileDescriptor]]; + writer = [theWriterThreads objectForKey: fd]; + [writer die]; +} + +- (void)writerThreadDied: (NSNotification *)aNotification +{ + NSNumber *fd; + WriterThread *writer; + + writer = [aNotification object]; + + fd = [[aNotification userInfo] objectForKey: @"FileDescriptorKey"]; + [theWriterThreads removeObjectForKey: fd]; +} +@synthesize theWriterThreads; +@end diff --git a/Liaison/chef.lproj/CopyPanel.nib/classes.nib b/Liaison/chef.lproj/CopyPanel.nib/classes.nib new file mode 100644 index 0000000..67bc2f5 --- /dev/null +++ b/Liaison/chef.lproj/CopyPanel.nib/classes.nib @@ -0,0 +1,38 @@ +{ + IBClasses = ( + { + CLASS = CopyController; + LANGUAGE = ObjC; + OUTLETS = { + theContentBox = NSBox; + theScrollView = NSScrollView; + theTemplate = DownloadStatusView; + theWindow = NSWindow; + }; + SUPERCLASS = NSObject; + }, + { + CLASS = DownloadStatusView; + LANGUAGE = ObjC; + OUTLETS = { + theButton = NSButton; + theFilename = NSTextField; + theIcon = NSImageView; + theProgressBar = NSProgressIndicator; + }; + SUPERCLASS = NSView; + }, + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = FlippedBox; LANGUAGE = ObjC; SUPERCLASS = NSBox; }, + { + CLASS = NIBConnector; + LANGUAGE = ObjC; + OUTLETS = { + theCopyController = CopyController; + thePreferencesController = PreferencesController; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Liaison/chef.lproj/CopyPanel.nib/info.nib b/Liaison/chef.lproj/CopyPanel.nib/info.nib new file mode 100644 index 0000000..cf2ac52 --- /dev/null +++ b/Liaison/chef.lproj/CopyPanel.nib/info.nib @@ -0,0 +1,17 @@ + + + + + IBDocumentLocation + 60 38 356 240 0 0 1024 746 + IBEditorPositions + + 16 + 373 456 220 82 0 0 1024 746 + + IBFramework Version + 291.0 + IBSystem Version + 6L60 + + diff --git a/Liaison/chef.lproj/CopyPanel.nib/objects.nib b/Liaison/chef.lproj/CopyPanel.nib/objects.nib new file mode 100644 index 0000000..5ea039a Binary files /dev/null and b/Liaison/chef.lproj/CopyPanel.nib/objects.nib differ diff --git a/Liaison/chef.lproj/InfoPlist.strings b/Liaison/chef.lproj/InfoPlist.strings new file mode 100644 index 0000000..150b632 Binary files /dev/null and b/Liaison/chef.lproj/InfoPlist.strings differ diff --git a/Liaison/chef.lproj/LoadPanel.nib/JavaCompiling.plist b/Liaison/chef.lproj/LoadPanel.nib/JavaCompiling.plist new file mode 100644 index 0000000..9153786 --- /dev/null +++ b/Liaison/chef.lproj/LoadPanel.nib/JavaCompiling.plist @@ -0,0 +1,8 @@ + + + + + JavaSourceSubpath + _LoadPanel_EOArchive_chef.java + + diff --git a/Liaison/chef.lproj/LoadPanel.nib/_LoadPanel_EOArchive_chef.java b/Liaison/chef.lproj/LoadPanel.nib/_LoadPanel_EOArchive_chef.java new file mode 100644 index 0000000..cd2b01f --- /dev/null +++ b/Liaison/chef.lproj/LoadPanel.nib/_LoadPanel_EOArchive_chef.java @@ -0,0 +1,143 @@ +// _LoadPanel_EOArchive_chef.java +// Generated by EnterpriseObjects palette at Saturday, September 06, 2003 17:02:27 America/New_York + +import com.webobjects.eoapplication.*; +import com.webobjects.eocontrol.*; +import com.webobjects.eodistribution.client.*; +import com.webobjects.eointerface.*; +import com.webobjects.eointerface.swing.*; +import com.webobjects.foundation.*; +import java.awt.*; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.table.*; +import javax.swing.text.*; + +public class _LoadPanel_EOArchive_chef extends com.webobjects.eoapplication.EOArchive { + LoadPanelController _loadPanelController0; + com.webobjects.eointerface.swing.EOFrame _eoFrame0; + com.webobjects.eointerface.swing.EOTextField _nsTextField0, _nsTextField1; + com.webobjects.eointerface.swing.EOView _nsProgressIndicator0; + javax.swing.JPanel _nsView0; + + public _LoadPanel_EOArchive_chef(Object owner, NSDisposableRegistry registry) { + super(owner, registry); + } + + protected void _construct() { + Object owner = _owner(); + EOArchive._ObjectInstantiationDelegate delegate = (owner instanceof EOArchive._ObjectInstantiationDelegate) ? (EOArchive._ObjectInstantiationDelegate)owner : null; + Object replacement; + + super._construct(); + + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController.thePathField")) != null)) { + _nsTextField1 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (com.webobjects.eointerface.swing.EOTextField)replacement; + _replacedObjects.setObjectForKey(replacement, "_nsTextField1"); + } else { + _nsTextField1 = (com.webobjects.eointerface.swing.EOTextField)_registered(new com.webobjects.eointerface.swing.EOTextField(), "NSTextField1"); + } + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController.theProgressBar")) != null)) { + _nsProgressIndicator0 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (com.webobjects.eointerface.swing.EOView)replacement; + _replacedObjects.setObjectForKey(replacement, "_nsProgressIndicator0"); + } else { + _nsProgressIndicator0 = (com.webobjects.eointerface.swing.EOView)_registered(new com.webobjects.eointerface.swing.EOView(), "1"); + } + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController")) != null)) { + _loadPanelController0 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (LoadPanelController)replacement; + _replacedObjects.setObjectForKey(replacement, "_loadPanelController0"); + } else { + _loadPanelController0 = (LoadPanelController)_registered(new LoadPanelController(), "LoadPanelController"); + } + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController.theStatusField")) != null)) { + _nsTextField0 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (com.webobjects.eointerface.swing.EOTextField)replacement; + _replacedObjects.setObjectForKey(replacement, "_nsTextField0"); + } else { + _nsTextField0 = (com.webobjects.eointerface.swing.EOTextField)_registered(new com.webobjects.eointerface.swing.EOTextField(), "NSTextField2"); + } + + if ((delegate != null) && ((replacement = delegate.objectForOutletPath(this, "theLoadPanelController.theLoadPanel")) != null)) { + _eoFrame0 = (replacement == EOArchive._ObjectInstantiationDelegate.NullObject) ? null : (com.webobjects.eointerface.swing.EOFrame)replacement; + _replacedObjects.setObjectForKey(replacement, "_eoFrame0"); + } else { + _eoFrame0 = (com.webobjects.eointerface.swing.EOFrame)_registered(new com.webobjects.eointerface.swing.EOFrame(), "Load Panel"); + } + + _nsView0 = (JPanel)_eoFrame0.getContentPane(); + } + + protected void _awaken() { + super._awaken(); + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_owner(), _loadPanelController0, "theLoadPanelController"); + } + } + + protected void _init() { + super._init(); + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_loadPanelController0, _eoFrame0, "theLoadPanel"); + } + + if (_replacedObjects.objectForKey("_nsTextField1") == null) { + _setFontForComponent(_nsTextField1, "Lucida Grande", 11, Font.PLAIN); + _nsTextField1.setEditable(false); + _nsTextField1.setOpaque(false); + _nsTextField1.setText("Luedeeng feeles\u2026"); + _nsTextField1.setHorizontalAlignment(javax.swing.JTextField.LEFT); + _nsTextField1.setSelectable(false); + _nsTextField1.setEnabled(true); + _nsTextField1.setBorder(null); + } + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_loadPanelController0, _nsTextField1, "thePathField"); + } + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_loadPanelController0, _nsProgressIndicator0, "theProgressBar"); + } + + if (_replacedObjects.objectForKey("_loadPanelController0") == null) { + _connect(_loadPanelController0, _nsTextField0, "theStatusField"); + } + + if (_replacedObjects.objectForKey("_nsTextField0") == null) { + _setFontForComponent(_nsTextField0, "Lucida Grande", 11, Font.PLAIN); + _nsTextField0.setEditable(false); + _nsTextField0.setOpaque(false); + _nsTextField0.setText("Getteeng inffu fur:"); + _nsTextField0.setHorizontalAlignment(javax.swing.JTextField.RIGHT); + _nsTextField0.setSelectable(false); + _nsTextField0.setEnabled(true); + _nsTextField0.setBorder(null); + } + + if (!(_nsView0.getLayout() instanceof EOViewLayout)) { _nsView0.setLayout(new EOViewLayout()); } + _nsTextField0.setSize(113, 18); + _nsTextField0.setLocation(10, 10); + ((EOViewLayout)_nsView0.getLayout()).setAutosizingMask(_nsTextField0, EOViewLayout.WidthSizable | EOViewLayout.MinYMargin); + _nsView0.add(_nsTextField0); + _nsTextField1.setSize(211, 18); + _nsTextField1.setLocation(125, 10); + ((EOViewLayout)_nsView0.getLayout()).setAutosizingMask(_nsTextField1, EOViewLayout.WidthSizable | EOViewLayout.MinYMargin); + _nsView0.add(_nsTextField1); + _nsProgressIndicator0.setSize(324, 20); + _nsProgressIndicator0.setLocation(11, 36); + ((EOViewLayout)_nsView0.getLayout()).setAutosizingMask(_nsProgressIndicator0, EOViewLayout.WidthSizable | EOViewLayout.MinYMargin); + _nsView0.add(_nsProgressIndicator0); + + if (_replacedObjects.objectForKey("_eoFrame0") == null) { + _nsView0.setSize(346, 66); + _eoFrame0.setTitle(""); + _eoFrame0.setLocation(401, 733); + _eoFrame0.setSize(346, 66); + } + } +} diff --git a/Liaison/chef.lproj/LoadPanel.nib/classes.nib b/Liaison/chef.lproj/LoadPanel.nib/classes.nib new file mode 100644 index 0000000..e1ab46c --- /dev/null +++ b/Liaison/chef.lproj/LoadPanel.nib/classes.nib @@ -0,0 +1,28 @@ +{ + IBClasses = ( + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + CLASS = LoadPanelController; + LANGUAGE = ObjC; + OUTLETS = { + theLoadPanel = NSPanel; + thePathField = NSTextField; + theProgressBar = NSProgressIndicator; + theStatusField = NSTextField; + }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {showDownloadWindow = id; }; + CLASS = NIBConnector; + LANGUAGE = ObjC; + OUTLETS = { + theCopyController = CopyController; + theLoadPanelController = LoadPanelController; + thePreferencesController = PreferencesController; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Liaison/chef.lproj/LoadPanel.nib/info.nib b/Liaison/chef.lproj/LoadPanel.nib/info.nib new file mode 100644 index 0000000..7484a71 --- /dev/null +++ b/Liaison/chef.lproj/LoadPanel.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBDocumentLocation + 89 245 356 240 0 0 1600 1178 + IBFramework Version + 291.0 + IBOpenObjects + + 6 + + IBSystem Version + 6L60 + + diff --git a/Liaison/chef.lproj/LoadPanel.nib/objects.nib b/Liaison/chef.lproj/LoadPanel.nib/objects.nib new file mode 100644 index 0000000..6126624 Binary files /dev/null and b/Liaison/chef.lproj/LoadPanel.nib/objects.nib differ diff --git a/Liaison/chef.lproj/MainMenu.nib/classes.nib b/Liaison/chef.lproj/MainMenu.nib/classes.nib new file mode 100644 index 0000000..209ba77 --- /dev/null +++ b/Liaison/chef.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,120 @@ +{ + IBClasses = ( + { + ACTIONS = { + openHomepage = id; + showInspectorWindow = id; + showMainWindow = id; + showPreferenceWindow = id; + }; + CLASS = ApplicationController; + LANGUAGE = ObjC; + OUTLETS = { + fileDelegate = FileTableDelegate; + fileTableView = NSTableView; + groupDelegate = GroupTableDelegate; + groupOutlineView = NSOutlineView; + inspectorWindow = NSWindow; + mainWindow = NSWindow; + openMenuItem = NSMenuItem; + showInspectorWindowMenuItem = NSMenuItem; + showMainWindowMenuItem = NSMenuItem; + }; + SUPERCLASS = NSObject; + }, + { + CLASS = CopyController; + LANGUAGE = ObjC; + OUTLETS = {theFilenameField = NSTextField; theProgressBar = NSProgressIndicator; }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {addFiles = id; }; + CLASS = FileTableDelegate; + LANGUAGE = ObjC; + OUTLETS = { + inspectorController = InspectorController; + statusLine = NSTextField; + tableView = NSTableView; + }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {deselectAll = id; }; + CLASS = FirstResponder; + LANGUAGE = ObjC; + SUPERCLASS = NSObject; + }, + {CLASS = FlippedBox; LANGUAGE = ObjC; SUPERCLASS = NSBox; }, + { + ACTIONS = {addGroup = id; }; + CLASS = GroupTableDelegate; + LANGUAGE = ObjC; + OUTLETS = { + outlineView = NSOutlineView; + statusLine = NSTextField; + theFileDelegate = FileTableDelegate; + theWindow = WindowController; + }; + SUPERCLASS = NSObject; + }, + { + CLASS = InspectorController; + LANGUAGE = ObjC; + OUTLETS = {theDefaultTabView = NSView; theTabView = NSTabView; theWindow = NSWindow; }; + SUPERCLASS = NSObject; + }, + {CLASS = LiScrollView; LANGUAGE = ObjC; SUPERCLASS = NSScrollView; }, + { + ACTIONS = {delete = id; }; + CLASS = LiTableView; + LANGUAGE = ObjC; + SUPERCLASS = NSTableView; + }, + { + ACTIONS = {showDownloadWindow = id; }; + CLASS = NIBConnector; + LANGUAGE = ObjC; + OUTLETS = { + theCopyController = CopyController; + theLoadPanelController = LoadPanelController; + thePreferencesController = PreferencesController; + }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {showWindow = id; }; + CLASS = ViewOptionsController; + LANGUAGE = ObjC; + OUTLETS = { + theContentView = id; + theFileDelegate = FileTableDelegate; + theHeaderField = id; + theWindow = NSWindow; + }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = { + addGroup = id; + addToLibrary = id; + openFile = id; + openInspector = id; + removeFiles = id; + removeGroup = id; + revealInFinder = id; + }; + CLASS = WindowController; + LANGUAGE = ObjC; + OUTLETS = { + theFileList = NSTableView; + theGroupList = NSOutlineView; + theInspectorWindow = NSWindow; + theMainWindow = NSWindow; + theSearchField = id; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Liaison/chef.lproj/MainMenu.nib/info.nib b/Liaison/chef.lproj/MainMenu.nib/info.nib new file mode 100644 index 0000000..bb7213f --- /dev/null +++ b/Liaison/chef.lproj/MainMenu.nib/info.nib @@ -0,0 +1,38 @@ + + + + + IBDocumentLocation + 23 72 461 291 0 0 1024 746 + IBEditorPositions + + 29 + 3 696 310 44 0 0 1024 746 + 377 + 423 486 177 62 0 0 1024 746 + 700 + 287 435 224 118 0 0 1024 746 + + IBFramework Version + 291.0 + IBGroupedObjects + + 1 + + 666 + 671 + 672 + + + IBLastGroupID + 2 + IBOpenObjects + + 21 + 301 + 208 + + IBSystem Version + 6L60 + + diff --git a/Liaison/chef.lproj/MainMenu.nib/objects.nib b/Liaison/chef.lproj/MainMenu.nib/objects.nib new file mode 100644 index 0000000..5fb322e Binary files /dev/null and b/Liaison/chef.lproj/MainMenu.nib/objects.nib differ diff --git a/Liaison/chef.lproj/PreferencesWindow.nib/classes.nib b/Liaison/chef.lproj/PreferencesWindow.nib/classes.nib new file mode 100644 index 0000000..76a7d6c --- /dev/null +++ b/Liaison/chef.lproj/PreferencesWindow.nib/classes.nib @@ -0,0 +1,50 @@ +{ + IBClasses = ( + { + ACTIONS = { + addFiles = id; + addGroup = id; + removeGroup = id; + showInspectorWindow = id; + showMainWindow = id; + }; + CLASS = ApplicationController; + LANGUAGE = ObjC; + OUTLETS = { + fileDelegate = FileTableDelegate; + fileTableView = NSTableView; + groupDelegate = GroupTableDelegate; + groupOutlineView = NSOutlineView; + inspectorWindow = NSWindow; + mainWindow = NSWindow; + openMenuItem = NSMenuItem; + showInspectorWindowMenuItem = NSMenuItem; + showMainWindowMenuItem = NSMenuItem; + thePanelController = LoadPanelController; + thePreferenceController = PreferenceController; + }; + SUPERCLASS = NSObject; + }, + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + CLASS = NIBConnector; + LANGUAGE = ObjC; + OUTLETS = {thePreferencesController = PreferencesController; }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {applyChanges = id; selectDownloadDirectory = id; toggleNetworkEnabled = id; }; + CLASS = PreferencesController; + LANGUAGE = ObjC; + OUTLETS = { + theDownloadField = NSTextField; + theHostnameField = NSTextField; + theHostnameFieldDescription = NSTextField; + theNetworkEnabledButton = NSButton; + theWindow = NSWindow; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Liaison/chef.lproj/PreferencesWindow.nib/info.nib b/Liaison/chef.lproj/PreferencesWindow.nib/info.nib new file mode 100644 index 0000000..ba3c2a9 --- /dev/null +++ b/Liaison/chef.lproj/PreferencesWindow.nib/info.nib @@ -0,0 +1,38 @@ + + + + + IBDocumentLocation + 50 54 356 240 0 0 1600 1178 + IBFramework Version + 326.0 + IBGroupedObjects + + 0 + + 39 + 40 + 49 + + 1 + + 21 + 22 + + 2 + + 34 + 35 + 36 + + + IBLastGroupID + 3 + IBOpenObjects + + 5 + + IBSystem Version + 7B28 + + diff --git a/Liaison/chef.lproj/PreferencesWindow.nib/objects.nib b/Liaison/chef.lproj/PreferencesWindow.nib/objects.nib new file mode 100644 index 0000000..764eedf Binary files /dev/null and b/Liaison/chef.lproj/PreferencesWindow.nib/objects.nib differ diff --git a/Liaison/chef.lproj/WindowElements.strings b/Liaison/chef.lproj/WindowElements.strings new file mode 100644 index 0000000..9753251 --- /dev/null +++ b/Liaison/chef.lproj/WindowElements.strings @@ -0,0 +1,37 @@ +/* Common strings */ +LiFileSingular = "feele-a"; +LiFilePlural = "feeles"; + +/* Default group names. */ +LiRendezvousGroupName = "Rendezfuoos"; +LiUntitledGroupName = "unteetled"; + +/* Toolbar strings. */ +LiToolbarAddFileLabel = "Edd Feeles"; +LiToolbarAddFilePaletteLabel = "Edd Feeles tu Leebrery"; +LiToolbarAddFileToolTip = "Edd feeles tu yuoor leebrery."; +LiToolbarRemoveFileLabel = "Remufe-a Feele-a"; +LiToolbarRemoveFilesLabel = "Remufe-a Feeles"; +LiToolbarRemoveFilePaletteLabel = "Remufe-a frum Gruoop"; +LiToolbarRemoveFileToolTip = "Remufe-a zee coorrently selected feeles."; +LiToolbarRemoveFilesFromLibraryToolTip = "Remufe-a zee coorrently selected %@ frum yuoor leebrery."; +LiToolbarRemoveFilesFromGroupToolTip = "Remufe-a zee coorrently selected %@ frum zee gruoop."; +LiToolbarSearchLabel = "Seerch"; +LiToolbarSearchPaletteLabel = "Seerch in Gruoop"; +LiToolbarSearchToolTip = "Seerch in selected gruoop."; +LiToolbarGetInfoLabel = "Get Inffu"; +LiToolbarGetInfoPaletteLabel = "Get Inffu"; +LiToolbarGetInfoToolTip = "Oopee zee inspectur veendoo."; +LiToolbarAddGroupLabel = "Edd Gruoop"; +LiToolbarAddGroupPaletteLabel = "Edd Gruoop"; +LiToolbarAddGroupToolTip = "Creete-a a noo gruoop."; +LiToolbarRemoveGroupLabel = "Delete-a Gruoop"; +LiToolbarRemoveGroupPaletteLabel = "Delete-a Gruoop"; +LiToolbarRemoveGroupToolTip = "Deletes zee coorrently selected gruoop."; +LiToolbarRevealLabel = "Shoo in Finder"; +LiToolbarRevealPaletteLabel = "Shoo in Finder"; +LiToolbarRevealToolTip = "Shoo zee selected item in zee Finder."; + +/* File load panel. */ +LiLoadPanelTitle = "Edd tu Leebrery"; +LiLoadingDirectory = "Scunneeng: "; \ No newline at end of file diff --git a/Liaison/main.m b/Liaison/main.m new file mode 100644 index 0000000..88c49d7 --- /dev/null +++ b/Liaison/main.m @@ -0,0 +1,12 @@ +// +// main.m +// Liaison +// +// Created by Brian Cully on Sun Feb 02 2003. +// Copyright (c) 2003 Brian Cully. All rights reserved. +// +int main(int argc, const char *argv[]) +{ + [NSFileHandleExtensions poseAsClass: [NSFileHandle class]]; + return NSApplicationMain(argc, argv); +} -- cgit v1.2.3