summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2008-04-14 21:45:08 -0400
committerBrian Cully <github.20.shmit@spamgourmet.com>2008-04-14 21:45:08 -0400
commit17349a5e426dc7acf1216a3767a22f69974cbca0 (patch)
tree20029d02f07ab6257cccec36d34fb312f796e1d1
downloadliaison-17349a5e426dc7acf1216a3767a22f69974cbca0.tar.gz
liaison-17349a5e426dc7acf1216a3767a22f69974cbca0.zip
Initial commit.
-rw-r--r--.gitignore2
-rw-r--r--Frameworks/LiBackend/English.lproj/LiBackend.scriptTerminology79
-rw-r--r--Frameworks/LiBackend/Info.plist26
-rw-r--r--Frameworks/LiBackend/LiBackend.h17
-rw-r--r--Frameworks/LiBackend/LiBackend.scriptSuite101
-rw-r--r--Frameworks/LiBackend/LiFileHandle.h103
-rw-r--r--Frameworks/LiBackend/LiFileHandle.m476
-rw-r--r--Frameworks/LiBackend/LiFileStore.h168
-rw-r--r--Frameworks/LiBackend/LiFileStore.m1040
-rw-r--r--Frameworks/LiBackend/LiFilter.h38
-rw-r--r--Frameworks/LiBackend/LiFilter.m108
-rw-r--r--Frameworks/LiBackend/LiLog.h21
-rw-r--r--Frameworks/LiBackend/LiLog.m104
-rw-r--r--Frameworks/LiBackend/LiPreferences.h31
-rw-r--r--Frameworks/LiBackend/LiPreferences.m209
-rw-r--r--Frameworks/LiBackend/LiStoreValidator.h11
-rw-r--r--Frameworks/LiBackend/LiStoreValidator.m13
-rw-r--r--Frameworks/LiFrameworks.xcodeproj/project.pbxproj612
-rw-r--r--Frameworks/LiPlugin/Info.plist28
-rw-r--r--Frameworks/LiPlugin/LiBrowserColumn.h59
-rw-r--r--Frameworks/LiPlugin/LiBrowserColumn.m150
-rw-r--r--Frameworks/LiPlugin/LiFilterDescription.h40
-rw-r--r--Frameworks/LiPlugin/LiFilterDescription.m113
-rw-r--r--Frameworks/LiPlugin/LiInspectorView.h40
-rw-r--r--Frameworks/LiPlugin/LiInspectorView.m96
-rw-r--r--Frameworks/LiPlugin/LiPlugin.h41
-rw-r--r--Liaison/ApplicationController.h21
-rw-r--r--Liaison/ApplicationController.m90
-rw-r--r--Liaison/ClientManager.h43
-rw-r--r--Liaison/ClientManager.m488
-rw-r--r--Liaison/CopyController.h27
-rw-r--r--Liaison/CopyController.m133
-rw-r--r--Liaison/DownloadManager.h36
-rw-r--r--Liaison/DownloadManager.m69
-rw-r--r--Liaison/DownloadStatusView.h27
-rw-r--r--Liaison/DownloadStatusView.m118
-rw-r--r--Liaison/Downloader.h63
-rw-r--r--Liaison/Downloader.m429
-rw-r--r--Liaison/English.lproj/CopyPanel.nib/Download_StopPressed.tiff0
-rw-r--r--Liaison/English.lproj/CopyPanel.nib/classes.nib38
-rw-r--r--Liaison/English.lproj/CopyPanel.nib/info.nib22
-rw-r--r--Liaison/English.lproj/CopyPanel.nib/objects.nibbin0 -> 2593 bytes
-rw-r--r--Liaison/English.lproj/InfoPlist.stringsbin0 -> 726 bytes
-rw-r--r--Liaison/English.lproj/Liaison Help/Liaison.html18
-rw-r--r--Liaison/English.lproj/Liaison Help/images/Liaison.pngbin0 -> 28966 bytes
-rw-r--r--Liaison/English.lproj/Liaison Help/images/Liaison_small.pngbin0 -> 944 bytes
-rw-r--r--Liaison/English.lproj/Liaison Help/pages/bugs.html25
-rw-r--r--Liaison/English.lproj/Liaison Help/pages/faq.html80
-rw-r--r--Liaison/English.lproj/Liaison Help/pages/glossary.html29
-rw-r--r--Liaison/English.lproj/Liaison Help/pages/navigation.html20
-rw-r--r--Liaison/English.lproj/Liaison Help/pages/overview.html36
-rw-r--r--Liaison/English.lproj/Liaison Help/pages/todo.html25
-rw-r--r--Liaison/English.lproj/Liaison Help/pages/whatsnew.html167
-rw-r--r--Liaison/English.lproj/Liaison.scriptTerminology22
-rw-r--r--Liaison/English.lproj/LoadPanel.nib/JavaCompiling.plist8
-rw-r--r--Liaison/English.lproj/LoadPanel.nib/_LoadPanel_EOArchive_English.java143
-rw-r--r--Liaison/English.lproj/LoadPanel.nib/classes.nib28
-rw-r--r--Liaison/English.lproj/LoadPanel.nib/info.nib16
-rw-r--r--Liaison/English.lproj/LoadPanel.nib/objects.nibbin0 -> 1356 bytes
-rw-r--r--Liaison/English.lproj/MainMenu.nib/classes.nib123
-rw-r--r--Liaison/English.lproj/MainMenu.nib/info.nib36
-rw-r--r--Liaison/English.lproj/MainMenu.nib/keyedobjects.nibbin0 -> 32761 bytes
-rw-r--r--Liaison/English.lproj/PreferencesWindow.nib/classes.nib50
-rw-r--r--Liaison/English.lproj/PreferencesWindow.nib/info.nib38
-rw-r--r--Liaison/English.lproj/PreferencesWindow.nib/objects.nibbin0 -> 2516 bytes
-rw-r--r--Liaison/English.lproj/WindowElements.strings37
-rw-r--r--Liaison/FileTableDelegate.h106
-rw-r--r--Liaison/FileTableDelegate.m1345
-rw-r--r--Liaison/FindController.h43
-rw-r--r--Liaison/FindController.m154
-rw-r--r--Liaison/FlippedBox.h6
-rw-r--r--Liaison/FlippedBox.m8
-rw-r--r--Liaison/Group.h52
-rw-r--r--Liaison/Group.m321
-rw-r--r--Liaison/GroupTableDelegate.h43
-rw-r--r--Liaison/GroupTableDelegate.m611
-rw-r--r--Liaison/ImageAndTextCell.h20
-rw-r--r--Liaison/ImageAndTextCell.m156
-rw-r--r--Liaison/Images/Add.tiffbin0 -> 2898 bytes
-rw-r--r--Liaison/Images/AddFiles.tiffbin0 -> 4378 bytes
-rw-r--r--Liaison/Images/AddGroup.tiffbin0 -> 4378 bytes
-rw-r--r--Liaison/Images/Download_Reload.tiffbin0 -> 438 bytes
-rw-r--r--Liaison/Images/Download_ReloadPressed.tiffbin0 -> 446 bytes
-rw-r--r--Liaison/Images/Download_Reveal.tiffbin0 -> 452 bytes
-rw-r--r--Liaison/Images/Download_RevealPressed.tiffbin0 -> 458 bytes
-rw-r--r--Liaison/Images/Download_Stop.tiffbin0 -> 438 bytes
-rw-r--r--Liaison/Images/Download_StopPressed.tiffbin0 -> 444 bytes
-rw-r--r--Liaison/Images/File Icons/Liaison.icnsbin0 -> 58750 bytes
-rw-r--r--Liaison/Images/LeftSearchCap.tiffbin0 -> 1116 bytes
-rw-r--r--Liaison/Images/NormalMailbox.tiffbin0 -> 1218 bytes
-rw-r--r--Liaison/Images/NormalMailboxLarge.tiffbin0 -> 7446 bytes
-rw-r--r--Liaison/Images/RemoveFiles.tiffbin0 -> 4378 bytes
-rw-r--r--Liaison/Images/RemoveGroup.tiffbin0 -> 4378 bytes
-rw-r--r--Liaison/Images/RightSearchCap.tiffbin0 -> 3728 bytes
-rw-r--r--Liaison/Images/SortAscending.gifbin0 -> 62 bytes
-rw-r--r--Liaison/Images/SortDescending.gifbin0 -> 62 bytes
-rw-r--r--Liaison/Images/TrashMailbox.tiffbin0 -> 1218 bytes
-rw-r--r--Liaison/Images/TrashMailboxLarge.tiffbin0 -> 4290 bytes
-rw-r--r--Liaison/Images/delete.tiffbin0 -> 4290 bytes
-rw-r--r--Liaison/Images/info (italic).tiffbin0 -> 17384 bytes
-rw-r--r--Liaison/Images/info (plain).tiffbin0 -> 3684 bytes
-rw-r--r--Liaison/Images/quickpick.tiffbin0 -> 1218 bytes
-rw-r--r--Liaison/Images/rendezvous.tiffbin0 -> 782 bytes
-rw-r--r--Liaison/Images/reveal.tiffbin0 -> 21332 bytes
-rw-r--r--Liaison/Info.plist74
-rw-r--r--Liaison/InspectorController.h24
-rw-r--r--Liaison/InspectorController.m250
-rw-r--r--Liaison/LiDataTranslator.h27
-rw-r--r--Liaison/LiDataTranslator.m120
-rw-r--r--Liaison/LiScrolLView.h10
-rw-r--r--Liaison/LiScrolLView.m34
-rw-r--r--Liaison/LiTableView.h2
-rw-r--r--Liaison/LiTableView.m166
-rw-r--r--Liaison/Liaison.h30
-rw-r--r--Liaison/Liaison.scriptSuite32
-rw-r--r--Liaison/Liaison.xcodeproj/project.pbxproj936
-rw-r--r--Liaison/LoadPanelController.h25
-rw-r--r--Liaison/LoadPanelController.m74
-rw-r--r--Liaison/NIBConnector.h30
-rw-r--r--Liaison/NIBConnector.m66
-rw-r--r--Liaison/NSException+LiDebugging.m23
-rw-r--r--Liaison/NSFileHandleExtensions.h14
-rw-r--r--Liaison/NSFileHandleExtensions.m24
-rw-r--r--Liaison/PluginManager.h27
-rw-r--r--Liaison/PluginManager.m116
-rw-r--r--Liaison/PreferencesController.h22
-rw-r--r--Liaison/PreferencesController.m154
-rw-r--r--Liaison/RenIPC.h21
-rw-r--r--Liaison/RenManager.h48
-rw-r--r--Liaison/RenManager.m357
-rw-r--r--Liaison/ServerManager.h41
-rw-r--r--Liaison/ServerManager.m428
-rw-r--r--Liaison/ViewOptionsController.h24
-rw-r--r--Liaison/ViewOptionsController.m158
-rw-r--r--Liaison/WindowController.h17
-rw-r--r--Liaison/WindowController.m306
-rw-r--r--Liaison/WriterThread.h38
-rw-r--r--Liaison/WriterThread.m211
-rw-r--r--Liaison/WriterThreadPool.h17
-rw-r--r--Liaison/WriterThreadPool.m95
-rw-r--r--Liaison/chef.lproj/CopyPanel.nib/classes.nib38
-rw-r--r--Liaison/chef.lproj/CopyPanel.nib/info.nib17
-rw-r--r--Liaison/chef.lproj/CopyPanel.nib/objects.nibbin0 -> 2733 bytes
-rw-r--r--Liaison/chef.lproj/InfoPlist.stringsbin0 -> 732 bytes
-rw-r--r--Liaison/chef.lproj/LoadPanel.nib/JavaCompiling.plist8
-rw-r--r--Liaison/chef.lproj/LoadPanel.nib/_LoadPanel_EOArchive_chef.java143
-rw-r--r--Liaison/chef.lproj/LoadPanel.nib/classes.nib28
-rw-r--r--Liaison/chef.lproj/LoadPanel.nib/info.nib16
-rw-r--r--Liaison/chef.lproj/LoadPanel.nib/objects.nibbin0 -> 1362 bytes
-rw-r--r--Liaison/chef.lproj/MainMenu.nib/classes.nib120
-rw-r--r--Liaison/chef.lproj/MainMenu.nib/info.nib38
-rw-r--r--Liaison/chef.lproj/MainMenu.nib/objects.nibbin0 -> 16364 bytes
-rw-r--r--Liaison/chef.lproj/PreferencesWindow.nib/classes.nib50
-rw-r--r--Liaison/chef.lproj/PreferencesWindow.nib/info.nib38
-rw-r--r--Liaison/chef.lproj/PreferencesWindow.nib/objects.nibbin0 -> 2533 bytes
-rw-r--r--Liaison/chef.lproj/WindowElements.strings37
-rw-r--r--Liaison/main.m12
-rw-r--r--Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.h72
-rw-r--r--Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.m316
-rw-r--r--Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.rtf162
-rw-r--r--Plugins/BuiltInFunctions/BDAlias/BDAlias/License.rtf21
-rw-r--r--Plugins/BuiltInFunctions/BuiltInFunctions.h12
-rw-r--r--Plugins/BuiltInFunctions/BuiltInFunctions.xcodeproj/project.pbxproj514
-rw-r--r--Plugins/BuiltInFunctions/English.lproj/BuiltInFunctions.strings26
-rw-r--r--Plugins/BuiltInFunctions/English.lproj/ErrorMessages.strings10
-rw-r--r--Plugins/BuiltInFunctions/English.lproj/InfoPlist.stringsbin0 -> 598 bytes
-rw-r--r--Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/classes.nib38
-rw-r--r--Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/info.nib61
-rw-r--r--Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/keyedobjects.nibbin0 -> 9192 bytes
-rw-r--r--Plugins/BuiltInFunctions/FileSizeFormatter.h10
-rw-r--r--Plugins/BuiltInFunctions/FileSizeFormatter.m47
-rw-r--r--Plugins/BuiltInFunctions/HFSCodeFormatter.h4
-rw-r--r--Plugins/BuiltInFunctions/HFSCodeFormatter.m46
-rw-r--r--Plugins/BuiltInFunctions/IconFamily/IconFamily/IconFamily.h184
-rw-r--r--Plugins/BuiltInFunctions/IconFamily/IconFamily/IconFamily.m1426
-rw-r--r--Plugins/BuiltInFunctions/IconFamily/IconFamily/NSString+CarbonFSSpecCreation.h20
-rw-r--r--Plugins/BuiltInFunctions/IconFamily/IconFamily/NSString+CarbonFSSpecCreation.m66
-rw-r--r--Plugins/BuiltInFunctions/Images/LocalAccountLarge.tiffbin0 -> 2392 bytes
-rw-r--r--Plugins/BuiltInFunctions/Images/Network (Large).tiffbin0 -> 2688 bytes
-rw-r--r--Plugins/BuiltInFunctions/Images/Network (Small).tiffbin0 -> 984 bytes
-rw-r--r--Plugins/BuiltInFunctions/Images/NotThere.icnsbin0 -> 39627 bytes
-rw-r--r--Plugins/BuiltInFunctions/Images/local.tiffbin0 -> 870 bytes
-rw-r--r--Plugins/BuiltInFunctions/Info.plist24
-rw-r--r--Plugins/BuiltInFunctions/InspectorViewController.h52
-rw-r--r--Plugins/BuiltInFunctions/InspectorViewController.m193
-rw-r--r--Plugins/BuiltInFunctions/LiBuiltInFunctions.h41
-rw-r--r--Plugins/BuiltInFunctions/LiBuiltInFunctions.m1027
-rw-r--r--Plugins/BuiltInFunctions/LiImageView.h6
-rw-r--r--Plugins/BuiltInFunctions/LiImageView.m59
-rw-r--r--Plugins/BuiltInFunctions/NaturalDateFormatter.h11
-rw-r--r--Plugins/BuiltInFunctions/NaturalDateFormatter.m58
-rw-r--r--Plugins/BuiltInFunctions/chef.lproj/BuiltInFunctions.strings26
-rw-r--r--Plugins/BuiltInFunctions/chef.lproj/ErrorMessages.strings10
-rw-r--r--Plugins/BuiltInFunctions/chef.lproj/InfoPlist.stringsbin0 -> 606 bytes
-rw-r--r--Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/classes.nib38
-rw-r--r--Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/info.nib32
-rw-r--r--Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/objects.nibbin0 -> 3419 bytes
197 files changed, 18294 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..538c8c5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+*~
diff --git a/Frameworks/LiBackend/English.lproj/LiBackend.scriptTerminology b/Frameworks/LiBackend/English.lproj/LiBackend.scriptTerminology
new file mode 100644
index 0000000..5e586f9
--- /dev/null
+++ b/Frameworks/LiBackend/English.lproj/LiBackend.scriptTerminology
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Classes</key>
+ <dict>
+ <key>LiFileHandle</key>
+ <dict>
+ <key>Attributes</key>
+ <dict>
+ <key>dictionary</key>
+ <dict>
+ <key>Description</key>
+ <string>The complete attribute dictionary.</string>
+ <key>Name</key>
+ <string>dictionary</string>
+ </dict>
+ <key>fileHandle</key>
+ <dict>
+ <key>Description</key>
+ <string>The unique file identifier which locates a file in a library.</string>
+ <key>Name</key>
+ <string>id</string>
+ </dict>
+ <key>filename</key>
+ <dict>
+ <key>Description</key>
+ <string>The filename of the file, without type extension.</string>
+ <key>Name</key>
+ <string>name</string>
+ </dict>
+ <key>urlString</key>
+ <dict>
+ <key>Description</key>
+ <string>A URL which locates this file.</string>
+ <key>Name</key>
+ <string>address</string>
+ </dict>
+ </dict>
+ <key>Description</key>
+ <string>A file.</string>
+ <key>Name</key>
+ <string>file</string>
+ <key>PluralName</key>
+ <string>files</string>
+ </dict>
+ <key>LiFileStore</key>
+ <dict>
+ <key>Attributes</key>
+ <dict>
+ <key>name</key>
+ <dict>
+ <key>Description</key>
+ <string>The name of the library.</string>
+ <key>Name</key>
+ <string>name</string>
+ </dict>
+ <key>storeID</key>
+ <dict>
+ <key>Description</key>
+ <string>The unique store identifier.</string>
+ <key>Name</key>
+ <string>id</string>
+ </dict>
+ </dict>
+ <key>Description</key>
+ <string>A file library.</string>
+ <key>Name</key>
+ <string>library</string>
+ <key>PluralName</key>
+ <string>libraries</string>
+ </dict>
+ </dict>
+ <key>Description</key>
+ <string>Liaison's low-level scripting interface.</string>
+ <key>Name</key>
+ <string>LiBackend suite</string>
+</dict>
+</plist>
diff --git a/Frameworks/LiBackend/Info.plist b/Frameworks/LiBackend/Info.plist
new file mode 100644
index 0000000..f3c92de
--- /dev/null
+++ b/Frameworks/LiBackend/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>LiBackend</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.kublai.Liaison.LiBackend</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>0.4d</string>
+ <key>NSAppleScriptEnabled</key>
+ <string>YES</string>
+ <key>NSPrincipalClass</key>
+ <string></string>
+</dict>
+</plist>
diff --git a/Frameworks/LiBackend/LiBackend.h b/Frameworks/LiBackend/LiBackend.h
new file mode 100644
index 0000000..3c6465a
--- /dev/null
+++ b/Frameworks/LiBackend/LiBackend.h
@@ -0,0 +1,17 @@
+/*
+ * LiBackend.h
+ * Liaison
+ *
+ * Created by Brian Cully on Fri May 30 2003.
+ * Copyright (c) 2003 Brian Cully. All rights reserved.
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+
+#import <LiBackend/LiFileStore.h>
+#import <LiBackend/LiFileHandle.h>
+#import <LiBackend/LiFilter.h>
+#import <LiBackend/LiStoreValidator.h>
+#import <LiBackend/LiPreferences.h>
+#import <LiBackend/LiLog.h> \ No newline at end of file
diff --git a/Frameworks/LiBackend/LiBackend.scriptSuite b/Frameworks/LiBackend/LiBackend.scriptSuite
new file mode 100644
index 0000000..01e0daa
--- /dev/null
+++ b/Frameworks/LiBackend/LiBackend.scriptSuite
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>AppleEventCode</key>
+ <string>LiBE</string>
+ <key>Classes</key>
+ <dict>
+ <key>LiFileHandle</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>LiFH</string>
+ <key>Attributes</key>
+ <dict>
+ <key>dictionary</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>prec</string>
+ <key>ReadOnly</key>
+ <string>YES</string>
+ <key>Type</key>
+ <string>NSDictionary</string>
+ </dict>
+ <key>fileHandle</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>ID </string>
+ <key>ReadOnly</key>
+ <string>YES</string>
+ <key>Type</key>
+ <string>NSNumber&lt;UnsignedLong&gt;</string>
+ </dict>
+ <key>filename</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>pnam</string>
+ <key>ReadOnly</key>
+ <string>NO</string>
+ <key>Type</key>
+ <string>NSString</string>
+ </dict>
+ <key>urlString</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>curl</string>
+ <key>ReadOnly</key>
+ <string>YES</string>
+ <key>Type</key>
+ <string>NSString</string>
+ </dict>
+ </dict>
+ <key>Superclass</key>
+ <string>NSCoreSuite.AbstractObject</string>
+ <key>SupportedCommands</key>
+ <dict/>
+ </dict>
+ <key>LiFileStore</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>LiFS</string>
+ <key>Attributes</key>
+ <dict>
+ <key>name</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>pnam</string>
+ <key>ReadOnly</key>
+ <string>NO</string>
+ <key>Type</key>
+ <string>NSString</string>
+ </dict>
+ <key>storeID</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>ID </string>
+ <key>ReadOnly</key>
+ <string>YES</string>
+ <key>Type</key>
+ <string>NSNumber&lt;UnsignedLong&gt;</string>
+ </dict>
+ </dict>
+ <key>Superclass</key>
+ <string>NSCoreSuite.AbstractObject</string>
+ <key>ToManyRelationships</key>
+ <dict>
+ <key>allFileHandles</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>LiFH</string>
+ <key>ReadOnly</key>
+ <string>NO</string>
+ <key>Type</key>
+ <string>LiFileHandle</string>
+ </dict>
+ </dict>
+ </dict>
+ </dict>
+ <key>Name</key>
+ <string>LiBackend</string>
+</dict>
+</plist>
diff --git a/Frameworks/LiBackend/LiFileHandle.h b/Frameworks/LiBackend/LiFileHandle.h
new file mode 100644
index 0000000..5e5dcb3
--- /dev/null
+++ b/Frameworks/LiBackend/LiFileHandle.h
@@ -0,0 +1,103 @@
+//
+// LiFileHandle.h
+// Liaison
+//
+// Created by Brian Cully on Sat May 24 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface LiFileHandle : NSObject <NSCoding>
+{
+ id theStoreID;
+ id theFileID;
+}
++ (LiFileHandle *)fileHandleWithID: (id)aFileID
+ storeID: (id)aStoreID;
+
+// For the file validator methods.
+- (BOOL)shouldUpdate;
+
+- (id)valueForAttribute: (NSString *)anAttribute;
+- (void)setValue: (id)aValue forAttribute: (NSString *)anAttribute;
+- (NSArray *)valuesForAttributes: (NSArray *)someAttributes;
+- (void)setValues: (NSArray *)someValues forAttributes: (NSArray *)someAttributes;
+@property (retain,getter=fileID) id theFileID;
+@property (retain,getter=storeID) id theStoreID;
+@end
+
+@interface LiFileHandle (Accessors)
+- (id)storeID;
+- (void)setStoreID: (id)aStoreID;
+- (id)fileID;
+- (void)setFileID: (id)aFileID;
+@end
+
+// These are common access methods - actually nothing more than convenience
+// methods that are nothing more than wrappers to valueForAttribute: and
+// setValue:forAttribute:
+// It is recommended that plugins use the same method for attribute access.
+@interface LiFileHandle (CommonAccessors)
+- (LiFileStore *)fileStore;
+- (void)setFileStore: (LiFileStore *)aFileStore;
+- (BOOL)isEditable;
+- (void)setIsEditable: (BOOL)editable;
+- (NSString *)filename;
+- (void)setFilename: (NSString *)aFilename;
+- (NSString *)type;
+- (void)setType: (NSString *)aType;
+- (NSNumber *)hfsCreator;
+- (void)setHFSCreator: (NSNumber *)aTypeCode;
+- (NSNumber *)hfsType;
+- (void)setHFSType: (NSNumber *)aTypeCode;
+- (NSString *)application;
+- (void)setApplication: (NSString *)pathToApp;
+- (NSDate *)lastModifiedTime;
+- (void)setLastModifiedTime: (NSDate *)aTime;
+- (NSDate *)creationTime;
+- (void)setCreationTime: (NSDate *)aTime;
+- (NSNumber *)fileSize;
+
+- (NSMutableArray *)groups;
+- (void)addToGroup: (NSString *)aGroup;
+- (BOOL)isMemberOfGroup: (NSString *)aGroup;
+- (void)removeFromGroup: (NSString *)aGroup;
+- (void)renameGroup: (NSString *)oldName toGroup: (NSString *)newName;
+- (BOOL)matchesFilter: (LiFilter *)aFilter;
+@end
+
+@interface LiFileHandle (CommonUtilities)
+- (NSString *)description;
+- (NSDictionary *)dictionary;
+- (void)update;
+- (void)open;
+- (NSURL *)url;
+@end
+
+@interface LiFileHandle (Scripting)
+- (NSScriptObjectSpecifier *)objectSpecifier;
+
+- (NSString *)urlString;
+@end
+
+@interface LiFileStore (LiFileHandleMethods)
+// Add a file to the library with the results of
+// [LiFileStore fileSystemAttributesForPath:].
+- (LiFileHandle *)addFileWithAttributes: (NSDictionary *)someAttributes;
+
+// To get a file's attributes.
+- (NSDictionary *)attributesForFileHandle: (LiFileHandle *)aFileHandle;
+
+// Set the attributes to be updated in the dictionary.
+- (void)updateFileHandle: (LiFileHandle *)aFileHandle
+ withAttributes: (NSDictionary *)someAttributes;
+
+// Remove file from the library.
+- (void)removeFileHandle: (LiFileHandle *)aFileHandle;
+
+// Returns all the LiFileHandles in the store.
+- (NSArray *)allFileHandles;
+
+// Returns a list of LiFileHandle objects for attributes
+// that match the dictionary.
+- (NSArray *)filesMatchingFilter: (LiFilter *)aFilter;
+@end \ No newline at end of file
diff --git a/Frameworks/LiBackend/LiFileHandle.m b/Frameworks/LiBackend/LiFileHandle.m
new file mode 100644
index 0000000..4f057c1
--- /dev/null
+++ b/Frameworks/LiBackend/LiFileHandle.m
@@ -0,0 +1,476 @@
+//
+// LiFileHandle.m
+// Liaison
+//
+// Created by Brian Cully on Sat May 24 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "LiFileHandle.h"
+
+@implementation LiFileHandle (Copying)
+- (id)copyWithZone: (NSZone *)aZone
+{
+ LiFileHandle *tmpHandle;
+
+ tmpHandle = [[LiFileHandle allocWithZone: aZone] init];
+ [tmpHandle setStoreID: [self storeID]];
+ [tmpHandle setFileID: [self fileID]];
+
+ return tmpHandle;
+}
+
+- (unsigned)hash
+{
+ unsigned long storeID, fileID;
+
+ storeID = [[self storeID] unsignedLongValue];
+ fileID = [[self fileID] unsignedLongValue];
+
+ // Fold the store ID down to 4 bits.
+ storeID = (storeID & 0xf) ^ (storeID >> 4 & 0xf) ^
+ (storeID >> 8 & 0xf) ^ (storeID >> 12 & 0xf) ^
+ (storeID >> 16 & 0xf) ^ (storeID >> 20 & 0xf) ^
+ (storeID >> 24 & 0xf) ^ (storeID >> 28 & 0xf);
+
+ // Fold the handle to 12 bits.
+ fileID = (fileID & 0xfff) ^ (fileID >> 12 & 0xfff) ^
+ (fileID >> 24 & 0xfff);
+
+ return (storeID << 12) | fileID;
+}
+
+- (BOOL)isEqual: (id)anObject
+{
+ if ([anObject isKindOfClass: [self class]]) {
+ IMP compareMethod;
+ id myID;
+
+ myID = [self fileID];
+ compareMethod = [myID methodForSelector: @selector(compare:)];
+ if (compareMethod != nil &&
+ compareMethod(myID, @selector(compare:), [anObject fileID]) == 0) {
+ myID = [self storeID];
+ compareMethod = [myID methodForSelector: @selector(compare:)];
+ if (compareMethod != nil &&
+ compareMethod(myID, @selector(compare:), [anObject storeID]) == 0)
+ return YES;
+ }
+ }
+
+ return NO;
+}
+@end
+
+@implementation LiFileHandle
++ (LiFileHandle *)fileHandleWithID: (id)aFileID
+ storeID: (id)aStoreID
+{
+ LiFileHandle *tmpHandle;
+
+ tmpHandle = [[[LiFileHandle alloc] init] autorelease];
+ [tmpHandle setFileID: aFileID];
+ [tmpHandle setStoreID: aStoreID];
+
+ return tmpHandle;
+}
+
+- (id)init
+{
+ return [super init];
+}
+
+- (void)dealloc
+{
+ [self setStoreID: nil];
+ [self setFileID: nil];
+
+ [super dealloc];
+}
+
+- (id)initWithCoder: (NSCoder *)aCoder
+{
+ id storeID, fileID;
+
+ self = [self init];
+
+ if ([aCoder allowsKeyedCoding]) {
+ storeID = [aCoder decodeObjectForKey: @"LiStoreID"];
+ fileID = [aCoder decodeObjectForKey: @"LiFileID"];
+ } else {
+ storeID = [aCoder decodeObject];
+ fileID = [aCoder decodeObject];
+ }
+ [self setStoreID: storeID];
+ [self setFileID: fileID];
+
+ return self;
+}
+
+- (void)encodeWithCoder: (NSCoder *)aCoder
+{
+ if ([aCoder allowsKeyedCoding]) {
+ [aCoder encodeObject: [self storeID]
+ forKey: @"LiStoreID"];
+ [aCoder encodeObject: [self fileID]
+ forKey: @"LiFileID"];
+ } else {
+ [aCoder encodeObject: [self storeID]];
+ [aCoder encodeObject: [self fileID]];
+ }
+}
+
+- (BOOL)shouldUpdate
+{
+ return NO;
+}
+
+- (id)valueForAttribute: (NSString *)anAttribute
+{
+ NSDictionary *attrDict;
+
+ attrDict = [self dictionary];
+ return [attrDict objectForKey: anAttribute];
+}
+
+- (void)setValue: (id)aValue forAttribute: (NSString *)anAttribute
+{
+ if (aValue != nil)
+ [self setValues: [NSArray arrayWithObject: aValue]
+ forAttributes: [NSArray arrayWithObject: anAttribute]];
+}
+
+- (NSArray *)valuesForAttributes: (NSArray *)someAttributes
+{
+ NSDictionary *attributes;
+ NSMutableArray *someValues;
+ NSString *attribute;
+
+ attributes = [self dictionary];
+ someValues = [NSMutableArray array];
+ for (attribute in someAttributes) {
+ [someValues addObject: [attributes objectForKey: attribute]];
+ }
+
+ return someValues;
+}
+
+- (void)setValues: (NSArray *)someValues forAttributes: (NSArray *)someAttributes
+{
+ NSDictionary *newAttributes;
+
+ newAttributes = [NSDictionary dictionaryWithObjects: someValues
+ forKeys: someAttributes];
+ [[self fileStore] updateFileHandle: self withAttributes: newAttributes];
+}
+@synthesize theStoreID;
+@synthesize theFileID;
+@end
+
+@implementation LiFileHandle (Accessors)
+- (id)storeID
+{
+ return theStoreID;
+}
+
+- (void)setStoreID: (id)aStoreID
+{
+ [aStoreID retain];
+ [theStoreID release];
+ theStoreID = aStoreID;
+}
+
+- (id)fileID
+{
+ return theFileID;
+}
+
+- (void)setFileID: (id)aFileID
+{
+ [aFileID retain];
+ [theFileID release];
+ theFileID = aFileID;
+}
+@end
+
+@implementation LiFileHandle (CommonAccessors)
+- (LiFileStore *)fileStore
+{
+ return [LiFileStore fileStoreWithID: [self storeID]];
+}
+
+- (void)setFileStore: (LiFileStore *)aFileStore
+{
+ [self setStoreID: [aFileStore storeID]];
+}
+
+- (BOOL)isEditable
+{
+ return [[self valueForAttribute: LiIsEditableAttribute] boolValue];
+}
+
+- (void)setIsEditable: (BOOL)editable
+{
+ [self setValue: [NSNumber numberWithBool: editable]
+ forAttribute: LiIsEditableAttribute];
+}
+
+- (NSString *)filename
+{
+ return [self valueForAttribute: LiFilenameAttribute];
+}
+
+- (void)setFilename: (NSString *)aFilename
+{
+ [self setValue: aFilename forAttribute: LiFilenameAttribute];
+}
+
+- (NSString *)type
+{
+ return [self valueForAttribute: LiTypeAttribute];
+}
+
+- (void)setType: (NSString *)aType
+{
+ [self setValue: aType forAttribute: LiTypeAttribute];
+}
+
+- (NSNumber *)hfsCreator
+{
+ return [self valueForAttribute: LiHFSCreatorAttribute];
+}
+
+- (void)setHFSCreator: (NSNumber *)aTypeCode
+{
+ [self setValue: aTypeCode forAttribute: LiHFSCreatorAttribute];
+}
+
+- (NSNumber *)hfsType
+{
+ return [self valueForAttribute: LiHFSTypeAttribute];
+}
+
+- (void)setHFSType: (NSNumber *)aTypeCode
+{
+ [self setValue: aTypeCode forAttribute: LiHFSTypeAttribute];
+}
+
+- (NSString *)application
+{
+ return [self valueForAttribute: LiApplicationAttribute];
+}
+
+- (void)setApplication: (NSString *)pathToApp
+{
+ [self setValue: pathToApp forAttribute: LiApplicationAttribute];
+}
+
+- (NSDate *)lastModifiedTime
+{
+ return [self valueForAttribute: LiLastModifiedDateAttribute];
+}
+
+- (void)setLastModifiedTime: (NSDate *)aTime
+{
+ [self setValue: aTime forAttribute: LiLastModifiedDateAttribute];
+}
+
+- (NSDate *)creationTime
+{
+ return [self valueForAttribute: LiCreationDateAttribute];
+}
+
+- (void)setCreationTime: (NSDate *)aTime
+{
+ [self setValue: aTime forAttribute: LiCreationDateAttribute];
+}
+
+- (NSNumber *)fileSize
+{
+ return [self valueForAttribute: LiFileSizeAttribute];
+}
+
+- (NSMutableArray *)groups
+{
+ return [self valueForAttribute: LiGroupsAttribute];
+}
+
+- (void)addToGroup: (NSString *)aGroup
+{
+ NSMutableArray *myGroups, *newGroups;
+
+ myGroups = [self groups];
+ if (myGroups != nil) {
+ if ([myGroups containsObject: aGroup]) {
+ return;
+ }
+ newGroups = [NSMutableArray arrayWithArray: myGroups];
+ } else
+ newGroups = [NSMutableArray array];
+ [newGroups addObject: aGroup];
+ [self setValue: newGroups forAttribute: LiGroupsAttribute];
+}
+
+- (BOOL)isMemberOfGroup: (NSString *)aGroup
+{
+ return [[self groups] containsObject: aGroup];
+}
+
+- (void)removeFromGroup: (NSString *)aGroup
+{
+ NSMutableArray *myGroups, *newGroups;
+
+ myGroups = [self groups];
+ if (myGroups != nil) {
+ newGroups = [NSMutableArray arrayWithArray: myGroups];
+ [newGroups removeObject: aGroup];
+ [self setValue: newGroups forAttribute: LiGroupsAttribute];
+ }
+}
+
+- (void)renameGroup: (NSString *)oldName toGroup: (NSString *)newName
+{
+ NSMutableArray *myGroups, *newGroups;
+
+ myGroups = [self groups];
+ if (myGroups != nil) {
+ newGroups = [NSMutableArray arrayWithArray: myGroups];
+ [newGroups removeObject: oldName];
+ [newGroups addObject: newName];
+ [self setValue: newGroups forAttribute: LiGroupsAttribute];
+ }
+}
+
+- (BOOL)matchesFilter: (LiFilter *)aFilter
+{
+ return [[self fileStore] attributes: [self dictionary] matchFilter: aFilter];
+}
+@end
+
+@implementation LiFileHandle (CommonUtilities)
+- (NSString *)description
+{
+ return [[self dictionary] description];
+}
+
+- (NSDictionary *)dictionary
+{
+ return [[self fileStore] attributesForFileID: [self fileID]];
+}
+
+- (void)update
+{
+ [[[self fileStore] delegate] updateFileHandle: self];
+}
+
+- (void)open
+{
+ [[[self fileStore] delegate] openFileHandle: self];
+}
+
+- (NSURL *)url
+{
+ return [[[self fileStore] delegate] urlForFileHandle: self];
+}
+@end
+
+@implementation LiFileHandle (Scripting)
+- (NSScriptObjectSpecifier *)objectSpecifier
+{
+ NSScriptClassDescription *containerDescription;
+ NSScriptObjectSpecifier *containerRef;
+ unsigned index;
+
+ [LiLog logAsDebug: @"[LiFileHandle objectSpecifier]"];
+
+ index = [[[self fileStore] allFileHandles] indexOfObject: self];
+ if (index != NSNotFound) {
+ [LiLog logAsDebug: @"index: %@", [NSNumber numberWithUnsignedInt: index]];
+ containerRef = [LiFileStore objectSpecifier];
+ containerDescription = (NSScriptClassDescription *)[NSScriptClassDescription classDescriptionForClass:[LiFileStore class]];
+
+ return [[[NSIndexSpecifier alloc] initWithContainerClassDescription:containerDescription containerSpecifier:containerRef key:@"allFileHandles" index:index] autorelease];
+ } else
+ return nil;
+}
+
+- (NSString *)urlString
+{
+ return [[self url] absoluteString];
+}
+@end
+
+@implementation LiFileStore (LiFileHandleMethods)
+- (LiFileHandle *)addFileWithAttributes: (NSDictionary *)someAttributes
+{
+ LiFileHandle *tmpHandle;
+ id fileID;
+
+ tmpHandle = nil;
+ fileID = [self fileIDWithAttributes: someAttributes];
+ if (fileID != nil)
+ tmpHandle = [LiFileHandle fileHandleWithID: fileID storeID: [self storeID]];
+ return tmpHandle;
+}
+
+- (NSDictionary *)attributesForFileHandle: (LiFileHandle *)aFileHandle
+{
+ return [self attributesForFileID: [aFileHandle fileID]];
+}
+
+- (void)updateFileHandle: (LiFileHandle *)aFileHandle
+ withAttributes: (NSDictionary *)someAttributes
+{
+ [self updateFileID: [aFileHandle fileID] withAttributes: someAttributes];
+}
+
+- (void)removeFileHandle: (LiFileHandle *)aFileHandle
+{
+ [self removeFileID: [aFileHandle fileID]];
+}
+
+- (NSArray *)allFileHandles
+{
+ NSEnumerator *idEnum;
+ NSMutableArray *fileHandles;
+ id fileID;
+
+ fileHandles = [NSMutableArray array];
+ idEnum = [[self allFileIDs] objectEnumerator];
+ while ((fileID = [idEnum nextObject]) != nil) {
+ LiFileHandle *tmpHandle;
+
+ tmpHandle = [[LiFileHandle alloc] init];
+ [tmpHandle setStoreID: [self storeID]];
+ [tmpHandle setFileID: fileID];
+ [fileHandles addObject: tmpHandle];
+ [tmpHandle release];
+ }
+
+ return fileHandles;
+}
+
+- (NSArray *)filesMatchingFilter: (LiFilter *)aFilter
+{
+ NSArray *fileIDs;
+ NSMutableArray *fileHandles;
+
+ fileHandles = nil;
+ fileIDs = [self fileIDsMatchingFilter: aFilter];
+ if ([fileIDs count] > 0) {
+ id fileID;
+
+ fileHandles = [NSMutableArray array];
+ for (fileID in fileIDs) {
+ LiFileHandle *tmpHandle;
+
+ tmpHandle = [[LiFileHandle alloc] init];
+ [tmpHandle setStoreID: [self storeID]];
+ [tmpHandle setFileID: fileID];
+ [fileHandles addObject: tmpHandle];
+ [tmpHandle release];
+ }
+ }
+ return fileHandles;
+}
+@end \ No newline at end of file
diff --git a/Frameworks/LiBackend/LiFileStore.h b/Frameworks/LiBackend/LiFileStore.h
new file mode 100644
index 0000000..cba804c
--- /dev/null
+++ b/Frameworks/LiBackend/LiFileStore.h
@@ -0,0 +1,168 @@
+//
+// LiFileStore.h
+// Liaison
+//
+// Created by Brian Cully on Sat May 24 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+// Notification names.
+//
+// When the file store list changes.
+#define LiFileStoresChangedNotification @"LiFileStoresChangedNotification"
+// When a file gets changed.
+#define LiFileChangedNotification @"LiFileChangedNotification"
+
+// Keys in the userInfo for LiFileStoresChangedNotification
+#define LiFileStoreAdded @"LiFileStoreAdded"
+#define LiFileStoreRemoved @"LiFileStoreRemoved"
+
+// Keys in the userInfo for LiFileChangedNotification.
+#define LiFilesAdded @"LiFilesAdded"
+#define LiFilesChanged @"LiFilesChanged"
+#define LiFilesRemoved @"LiFilesRemoved"
+
+// For LiFilesChanged and LiFilesRemoved.
+#define LiFileOldAttributes @"LiFilesOldAttributes"
+
+// The keys we supply for every file.
+#define LiFileHandleAttribute @"LiFileHandleAttribute"
+#define LiDirectoryAttribute @"LiDirectoryAttribute"
+#define LiFilenameAttribute @"LiFilenameAttribute"
+#define LiTypeAttribute @"LiTypeAttribute"
+#define LiLastModifiedDateAttribute @"LiLastModifiedDateAttribute"
+#define LiCreationDateAttribute @"LiCreationDateAttribute"
+#define LiFileSizeAttribute @"LiFileSizeAttribute"
+#define LiGroupsAttribute @"LiGroupsAttribute"
+#define LiHFSCreatorAttribute @"LiHFSCreatorAttribute"
+#define LiHFSTypeAttribute @"LiHFSTypeAttribute"
+#define LiApplicationAttribute @"LiApplicationAttribute"
+#define LiIsEditableAttribute @"LiIsEditableAttribute"
+
+@class LiFileHandle;
+@class LiFileStore;
+@class LiFilter;
+
+@protocol LiFileStoreDelegate <NSObject>
+// Sync the file store database to permanent storage.
+- (BOOL)synchronizeFileStore;
+
+ // Sync the file handle to disk.
+- (void)synchronizeFileHandle: (LiFileHandle *)aFileHandle
+ withNewAttributes: (NSMutableDictionary *)someAttributes;
+
+ // Update a file handle from permanent storage.
+- (BOOL)shouldUpdateFileHandle: (LiFileHandle *)aFileHandle;
+- (void)updateFileHandle: (LiFileHandle *)aFileHandle;
+
+// Open a file handle. Since a file must be on local storage to
+// open it, if the file doesn't exist there, delegates must first
+// create the file before opening it.
+- (void)openFileHandle: (LiFileHandle *)aFileHandle;
+
+// Attempt to add a file, specified by a URL, to the library.
+// Returns a non-nil LiFileHandle that matches the newly added file
+// on success, nil on failure.
+- (LiFileHandle *)addURL: (NSURL *)anURL
+ toFileStore: (LiFileStore *)aFileStore;
+
+// Return a standard URL for a file. This can be anything you want,
+// but it should always point to the file in some way.
+- (NSURL *)urlForFileHandle: (LiFileHandle *)aFileHandle;
+
+// Used to fill in default values for a particular attribute.
+// For instance, you can return a set of groups for LiGroupsAttribute.
+- (NSArray *)defaultValuesForAttribute: (NSString *)anAttribute;
+
+// For messing with the default attributes for a plugin.
+- (BOOL)addDefaultAttribute: (NSDictionary *)anAttribute toFileStore: (LiFileStore *)aFileStore;
+- (BOOL)changeDefaultValueForAttribute: (NSDictionary *)anAttribute toValue: (id)aValue inFileStore: (LiFileStore *)aFileStore;
+- (BOOL)removeDefaultAttribute: (NSDictionary *)anAttribute fromFileStore: (LiFileStore *)aFileStore;
+@end
+
+@interface LiFileStore : NSObject <NSCopying, NSCoding>
+{
+ id theStoreID;
+ id <LiFileStoreDelegate>theDelegate;
+
+ BOOL theStoreIsEditable;
+
+ NSImage *theIcon;
+ NSString *theName;
+
+ NSMutableDictionary *theFiles;
+ NSMutableDictionary *theIndexes;
+
+ NSMutableSet *theAddedFiles, *theChangedFiles, *theRemovedFiles;
+
+ unsigned long nextHandle;
+}
+// Look up stores via ID.
++ (NSArray *)allFileStores;
++ (NSEnumerator *)fileStoreEnumerator;
++ (LiFileStore *)fileStoreWithID: (id)aStoreID;
++ (void)removeStoreWithID: (id)aStoreID;
+
+// Create an auto-released file store.
++ (LiFileStore *)fileStoreWithName: (NSString *)aName;
+- (LiFileStore *)initWithName: (NSString *)aName;
+
+// Use the following methods to control how to manage store indexes.
+- (void)addIndexForAttribute: (NSString *)anAttribute;
+- (NSMutableDictionary *)indexForAttribute: (NSString *)anAttribute;
+- (void)removeIndexForAttribute: (NSString *)anAttribute;
+
+- (id)fileIDWithAttributes: (NSDictionary *)someAttributes;
+- (void)updateFileID: (id)aFileID
+ withAttributes: (NSDictionary *)someAttributes;
+- (void)removeFileID: (id)aFileID;
+
+- (NSDictionary *)attributesForFileID: (id)aFileID;
+
+- (NSArray *)allFileIDs;
+
+- (NSArray *)fileIDsMatchingFilter: (LiFilter *)aFilter;
+
+// Test attribute dictionaries against a filter.
+- (BOOL)attributes: (NSDictionary *)someAttributes
+ matchFilter: (LiFilter *)aFilter;
+
+// Return all the values in the library for an attribute.
+- (NSArray *)allValuesForAttribute: (NSString *)anAttribute;
+@property unsigned long nextHandle;
+@property (retain,getter=name) NSString *theName;
+@property (retain,getter=icon) NSImage *theIcon;
+@property (retain) NSMutableDictionary *theIndexes;
+@property (retain,getter=storeID) id theStoreID;
+@property (retain,getter=delegate) id <LiFileStoreDelegate>theDelegate;
+@property (getter=isEditable,setter=setEditable:) BOOL theStoreIsEditable;
+@property (retain) NSMutableDictionary *theFiles;
+@end
+
+@interface LiFileStore (CommonAccessors)
+- (void)synchronize;
+- (LiFileHandle *)addURL: (NSURL *)anURL;
+@end
+
+@interface LiFileStore (Accessors)
+- (id)storeID;
+- (void)setStoreID: (id)anID;
+- (id <LiFileStoreDelegate>)delegate;
+- (void)setDelegate: (id <LiFileStoreDelegate>)aDelegate;
+- (BOOL)isEditable;
+- (void)setEditable: (BOOL)editable;
+- (NSString *)name;
+- (void)setName: (NSString *)aName;
+- (NSImage *)icon;
+- (void)setIcon: (NSImage *)anIcon;
+- (NSMutableSet *)addedFiles;
+- (void)setAddedFiles: (NSMutableSet *)aSet;
+- (NSMutableSet *)changedFiles;
+- (void)setChangedFiles: (NSMutableSet *)aSet;
+- (NSMutableSet *)removedFiles;
+- (void)setRemovedFiles: (NSMutableSet *)aSet;
+@end
+
+@interface LiFileStore (Scripting)
+- (NSScriptObjectSpecifier *)objectSpecifier;
+@end \ No newline at end of file
diff --git a/Frameworks/LiBackend/LiFileStore.m b/Frameworks/LiBackend/LiFileStore.m
new file mode 100644
index 0000000..25c801f
--- /dev/null
+++ b/Frameworks/LiBackend/LiFileStore.m
@@ -0,0 +1,1040 @@
+//
+// LiFileStore.m
+// Liaison
+//
+// Created by Brian Cully on Sat May 24 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "LiFileStore.h"
+
+@interface LiFileStore (Private)
+- (unsigned)sendNotifications;
+- (void)sendAddNotificationForFileHandle: (LiFileHandle *)aFileHandle;
+- (void)sendUpdateNotificationForFileHandle: (LiFileHandle *)aFileHandle
+ oldAttributes: (NSDictionary *)oldAttrs;
+- (void)sendRemoveNotificationForFileHandle: (LiFileHandle *)aFileHandle
+ oldAttributes: (NSDictionary *)oldAttrs;
+@end
+
+@implementation LiFileStore
+static NSMutableDictionary *theFileStores = nil;
+static unsigned int theNextID = 0;
++ (NSMutableDictionary *)fileStores
+{
+ if (theFileStores == nil)
+ theFileStores = [[NSMutableDictionary alloc] init];
+ return theFileStores;
+}
+
++ (NSArray *)allFileStores
+{
+ return [[self fileStores] allValues];
+}
+
++ (NSEnumerator *)fileStoreEnumerator
+{
+ return [[self fileStores] objectEnumerator];
+}
+
++ (LiFileStore *)fileStoreWithID: (id)aStoreID
+{
+ return [[self fileStores] objectForKey: aStoreID];
+}
+
++ (void)addStore: (LiFileStore *)aFileStore
+{
+ NSDictionary *userInfo;
+ NSNotificationCenter *defaultCenter;
+
+ while (([self fileStoreWithID:
+ [NSNumber numberWithUnsignedInt: theNextID]]) != nil)
+ theNextID++;
+
+ [[self fileStores] setObject: aFileStore forKey:
+ [NSNumber numberWithUnsignedInt: theNextID]];
+ [aFileStore setStoreID: [NSNumber numberWithUnsignedInt: theNextID]];
+ theNextID++;
+
+ userInfo = [NSDictionary dictionaryWithObject: [aFileStore storeID]
+ forKey: LiFileStoreAdded];
+ defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter postNotificationName: LiFileStoresChangedNotification
+ object: nil
+ userInfo: userInfo];
+}
+
++ (void)removeStoreWithID: (id)aStoreID
+{
+ NSDictionary *userInfo;
+ NSNotificationCenter *defaultCenter;
+
+ [[self fileStores] removeObjectForKey: aStoreID];
+
+ userInfo = [NSDictionary dictionaryWithObject: aStoreID
+ forKey: LiFileStoreRemoved];
+ defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter postNotificationName: LiFileStoresChangedNotification
+ object: nil
+ userInfo: userInfo];
+}
+
++ (LiFileStore *)fileStoreWithName: (NSString *)aName
+{
+ return [[[self alloc] initWithName: aName] autorelease];
+}
+
++ (NSImage *)defaultIcon
+{
+ return nil;
+}
+
+- (LiFileStore *)initWithName: (NSString *)aName
+{
+ self = [super init];
+
+ [self setName: aName];
+ [self setIcon: [[self class] defaultIcon]];
+ nextHandle = 1;
+ theFiles = [[NSMutableDictionary alloc] init];
+
+ [LiFileStore addStore: self];
+
+ return self;
+}
+
+- (id)init
+{
+ NSException *myException;
+
+ [self autorelease];
+
+ myException = [NSException exceptionWithName: @"LiFileStoreInitFailure"
+ reason: @"[[LiFileStore alloc] init] isn't supported."
+ userInfo: nil];
+ [myException raise];
+ return nil;
+}
+
+- (void)dealloc
+{
+ [LiFileStore removeStoreWithID: [self storeID]];
+ [theFiles release];
+ [theIndexes release];
+
+ [super dealloc];
+}
+
+- (id)copyWithZone: (NSZone *)aZone
+{
+ LiFileStore *tmpStore;
+
+ [LiLog logAsDebug: @"[LiFileStore copyWithZone: %@]", aZone];
+
+ tmpStore = [[LiFileStore allocWithZone: aZone] initWithName: [self name]];
+ [tmpStore setEditable: [self isEditable]];
+ [tmpStore setIcon: [self icon]];
+
+ // XXX
+ tmpStore->theFiles = theFiles;
+ tmpStore->theIndexes = theIndexes;
+ tmpStore->nextHandle = nextHandle;
+
+ return tmpStore;
+}
+
+- (id)initWithCoder: (NSCoder *)aCoder
+{
+ [LiLog logAsDebug: @"[LiFileStore initWithCoder: aCoder]"];
+
+ self = [self init];
+ if (self != nil) {
+ NSData *iconData;
+ NSDictionary *fileDB, *indexes;
+ NSNumber *isEditable, *myNextHandle;
+ NSString *name;
+
+ if ([aCoder allowsKeyedCoding]) {
+ name = [aCoder decodeObjectForKey: @"LiFSName"];
+ iconData = [aCoder decodeObjectForKey: @"LiFSIconData"];
+ isEditable = [aCoder decodeObjectForKey: @"LiFSIsEditable"];
+ myNextHandle = [aCoder decodeObjectForKey: @"LiFSNextHandle"];
+ fileDB = [aCoder decodeObjectForKey: @"LiFSFileDictionary"];
+ indexes = [aCoder decodeObjectForKey: @"LiFSIndexes"];
+ } else {
+ name = [aCoder decodeObject];
+ iconData = [aCoder decodeObject];
+ isEditable = [aCoder decodeObject];
+ myNextHandle = [aCoder decodeObject];
+ fileDB = [aCoder decodeObject];
+ indexes = [aCoder decodeObject];
+ }
+ [self setName: name];
+ [self setIcon: [[[NSImage alloc] initWithData: iconData] autorelease]];
+ [self setEditable: [isEditable boolValue]];
+ nextHandle = [myNextHandle unsignedLongValue];
+ theFiles = [[NSMutableDictionary alloc] initWithDictionary: fileDB];
+ theIndexes = [[NSMutableDictionary alloc] initWithDictionary: indexes];
+ }
+
+ return self;
+}
+
+- (void)encodeWithCoder: (NSCoder *)aCoder
+{
+ [LiLog logAsDebug: @"[LiFileStore encodeWithCoder: aCoder]"];
+ if ([aCoder allowsKeyedCoding]) {
+ [aCoder encodeObject: [self name]
+ forKey: @"LiFSName"];
+ [aCoder encodeObject: [[self icon] TIFFRepresentation]
+ forKey: @"LiFSIconData"];
+ [aCoder encodeObject: [NSNumber numberWithBool: [self isEditable]]
+ forKey: @"LiFSIsEditable"];
+ [aCoder encodeObject: [NSNumber numberWithUnsignedLong: nextHandle]
+ forKey: @"LiFSNextHandle"];
+ [aCoder encodeObject: theFiles
+ forKey: @"LiFSFileDictionary"];
+ [aCoder encodeObject: theIndexes
+ forKey: @"LiFSIndexes"];
+ } else {
+ [aCoder encodeObject: [self name]];
+ [aCoder encodeObject: [[self icon] TIFFRepresentation]];
+ [aCoder encodeObject: [NSNumber numberWithBool: [self isEditable]]];
+ [aCoder encodeObject: [NSNumber numberWithUnsignedLong: nextHandle]];
+ [aCoder encodeObject: theFiles];
+ [aCoder encodeObject: theIndexes];
+ }
+}
+
+- (void)addIndexForAttribute: (NSString *)anAttribute
+{
+ NSEnumerator *fileEnum;
+ NSMutableDictionary *newIndex;
+ id fileHandle;
+
+ if ([self indexForAttribute: anAttribute] == nil) {
+ NSMutableArray *filesInValue;
+
+ [LiLog logAsDebug: @"Indexing %@.", anAttribute];
+
+ filesInValue = [NSMutableArray array];
+ newIndex = [NSMutableDictionary dictionary];
+ fileEnum = [theFiles keyEnumerator];
+ while ((fileHandle = [fileEnum nextObject]) != nil) {
+ id value;
+
+ value = [[theFiles objectForKey: fileHandle] objectForKey: anAttribute];
+ if (value != nil) {
+ if ([value isKindOfClass: [NSArray class]]) {
+ NSEnumerator *valEnum;
+ id subValue;
+
+ valEnum = [value objectEnumerator];
+ while ((subValue = [valEnum nextObject]) != nil) {
+ filesInValue = [newIndex objectForKey: subValue];
+ if (filesInValue == nil) {
+ filesInValue = [NSMutableArray array];
+ [newIndex setObject: filesInValue forKey: subValue];
+ }
+ [filesInValue addObject: fileHandle];
+ }
+ } else {
+ filesInValue = [newIndex objectForKey: value];
+ if (filesInValue == nil) {
+ filesInValue = [NSMutableArray array];
+ [newIndex setObject: filesInValue forKey: value];
+ }
+ [filesInValue addObject: fileHandle];
+ }
+ }
+ }
+
+ if (theIndexes == nil)
+ theIndexes = [[NSMutableDictionary alloc] init];
+ [theIndexes setObject: newIndex forKey: anAttribute];
+
+ [LiLog logAsDebug: @"Done indexing %@.", anAttribute];
+ }
+}
+
+- (NSMutableDictionary *)indexForAttribute: (NSString *)anAttribute
+{
+ return [theIndexes objectForKey: anAttribute];
+}
+
+- (void)removeIndexForAttribute: (NSString *)anAttribute
+{
+ if ([theIndexes objectForKey: anAttribute] != nil)
+ [theIndexes removeObjectForKey: anAttribute];
+}
+
+- (id)fileIDWithAttributes: (NSDictionary *)someAttributes
+{
+ NSEnumerator *attrEnum;
+ NSString *attribute;
+ NSMutableDictionary *fileAttributes;
+ NSNumber *handle;
+
+ handle = [someAttributes objectForKey: LiFileHandleAttribute];
+ if (handle == nil) {
+ handle = [NSNumber numberWithUnsignedLong: nextHandle];
+ nextHandle++;
+ } else if ([theFiles objectForKey: handle] != nil) {
+ return handle;
+ } else
+ if (nextHandle <= [handle unsignedLongValue])
+ nextHandle = [handle unsignedLongValue]+1;
+
+ // First, create the file.
+ fileAttributes = [NSMutableDictionary dictionaryWithDictionary: someAttributes];
+ [fileAttributes setObject: handle forKey: LiFileHandleAttribute];
+ [theFiles setObject: fileAttributes forKey: handle];
+
+ // Then update indexes.
+ attrEnum = [someAttributes keyEnumerator];
+ while ((attribute = [attrEnum nextObject]) != nil) {
+ NSMutableDictionary *index;
+
+ index = [self indexForAttribute: attribute];
+ if (index != nil) {
+ id myValue;
+
+ myValue = [someAttributes objectForKey: attribute];
+ if (myValue != nil) {
+ NSMutableArray *fileArray;
+
+ if ([myValue isKindOfClass: [NSArray class]]) {
+ NSEnumerator *valEnum;
+ id subValue;
+
+ valEnum = [myValue objectEnumerator];
+ while ((subValue = [valEnum nextObject]) != nil) {
+ fileArray = [index objectForKey: subValue];
+ if (fileArray == nil) {
+ fileArray = [NSMutableArray array];
+ [index setObject: fileArray forKey: subValue];
+ }
+ [fileArray addObject: handle];
+ }
+ } else {
+ fileArray = [index objectForKey: myValue];
+ if (fileArray == nil) {
+ fileArray = [NSMutableArray array];
+ [index setObject: fileArray forKey: myValue];
+ }
+ [fileArray addObject: handle];
+ }
+ }
+ }
+ }
+
+ if (handle != nil)
+ [self sendAddNotificationForFileHandle: [LiFileHandle fileHandleWithID: handle storeID: [self storeID]]];
+ return handle;
+}
+
+- (void)updateFileID: (id)aFileID
+ withAttributes: (NSDictionary *)someAttributes
+{
+ NSString *attribute;
+ NSEnumerator *attrEnum;
+ NSMutableDictionary *oldAttributes, *newAttributes, *tmpAttributes;
+
+ // Call the delegate's sync method with the new attributes.
+ // Allow the delegate to filter out attributes it can't modify
+ // or modify attributes if it has to.
+ // It should return a dict of what was modified.
+ newAttributes = [NSMutableDictionary dictionaryWithDictionary:
+ someAttributes];
+ [[self delegate] synchronizeFileHandle: [LiFileHandle fileHandleWithID: aFileID
+ storeID: [self storeID]]
+ withNewAttributes: newAttributes];
+
+ oldAttributes = [theFiles objectForKey: aFileID];
+ tmpAttributes = [NSMutableDictionary dictionary];
+ attrEnum = [newAttributes keyEnumerator];
+ while ((attribute = [attrEnum nextObject]) != nil) {
+ NSMutableDictionary *index;
+ id oldValue, newValue;
+
+ oldValue = [oldAttributes objectForKey: attribute];
+ newValue = [newAttributes objectForKey: attribute];
+
+ // For notification.
+ if (oldValue != nil)
+ [tmpAttributes setObject: oldValue forKey: attribute];
+
+ index = [self indexForAttribute: attribute];
+ if (index != nil) {
+ NSMutableArray *fileArray;
+
+ // Remove old values from index.
+ if (oldValue != nil) {
+ if ([oldValue isKindOfClass: [NSArray class]]) {
+ NSEnumerator *valEnum;
+ id subValue;
+
+ valEnum = [oldValue objectEnumerator];
+ while ((subValue = [valEnum nextObject]) != nil) {
+ fileArray = [index objectForKey: subValue];
+ [fileArray removeObject: aFileID];
+ if ([fileArray count] == 0) {
+ [index removeObjectForKey: subValue];
+ }
+ }
+ } else {
+ fileArray = [index objectForKey: oldValue];
+ [fileArray removeObject: aFileID];
+ if ([fileArray count] == 0) {
+ [index removeObjectForKey: oldValue];
+ }
+ }
+ }
+
+ // Add new values to index.
+ if ([newValue isKindOfClass: [NSArray class]]) {
+ NSEnumerator *valEnum;
+ id subValue;
+
+ valEnum = [newValue objectEnumerator];
+ while ((subValue = [valEnum nextObject]) != nil) {
+ fileArray = [index objectForKey: subValue];
+ if (fileArray == nil) {
+ fileArray = [NSMutableArray array];
+ [index setObject: fileArray forKey: subValue];
+ }
+ [fileArray addObject: aFileID];
+ }
+ } else {
+ fileArray = [index objectForKey: newValue];
+ if (fileArray == nil) {
+ fileArray = [NSMutableArray array];
+ [index setObject: fileArray forKey: newValue];
+ }
+ [fileArray addObject: aFileID];
+ }
+ }
+
+ if (newValue == nil) {
+ [oldAttributes removeObjectForKey: attribute];
+ } else
+ [oldAttributes setObject: newValue forKey: attribute];
+ }
+
+ // Send notification of update if there's something to say.
+ if ([newAttributes count] > 0) {
+ [self sendUpdateNotificationForFileHandle: [LiFileHandle fileHandleWithID: aFileID storeID: [self storeID]]
+ oldAttributes: tmpAttributes];
+ }
+}
+
+- (void)removeFileID: (id)aFileID
+{
+ NSDictionary *fileAttrs;
+
+ fileAttrs = [theFiles objectForKey: aFileID];
+ if (fileAttrs != nil) {
+ NSEnumerator *attrEnum;
+ NSString *attribute;
+
+ attrEnum = [fileAttrs keyEnumerator];
+ while ((attribute = [attrEnum nextObject]) != nil) {
+ NSMutableDictionary *index;
+ id myValue;
+
+ myValue = [fileAttrs objectForKey: attribute];
+ index = [self indexForAttribute: attribute];
+ if (index != nil) {
+ NSMutableArray *fileArray;
+
+ if ([myValue isKindOfClass: [NSArray class]]) {
+ NSEnumerator *valEnum;
+ id subValue;
+
+ valEnum = [myValue objectEnumerator];
+ while ((subValue = [valEnum nextObject]) != nil) {
+ fileArray = [index objectForKey: subValue];
+ [fileArray removeObject: aFileID];
+ if ([fileArray count] == 0)
+ [index removeObjectForKey: subValue];
+ }
+ } else {
+ fileArray = [index objectForKey: myValue];
+ [fileArray removeObject: aFileID];
+ if ([fileArray count] == 0)
+ [index removeObjectForKey: myValue];
+ }
+ }
+ }
+
+ [fileAttrs retain];
+ [theFiles removeObjectForKey: aFileID];
+
+ // Send notification of removal.
+ if ([fileAttrs count] > 0) {
+ [self sendRemoveNotificationForFileHandle: [LiFileHandle fileHandleWithID: aFileID storeID: [self storeID]]
+ oldAttributes: fileAttrs];
+ }
+ [fileAttrs release];
+ }
+}
+
+- (NSDictionary *)attributesForFileID: (id)aFileID
+{
+ return [theFiles objectForKey: aFileID];
+}
+
+- (NSArray *)allFileIDs
+{
+ return [theFiles allKeys];
+}
+
+- (NSDictionary *)fileIDsMatchingFilter: (LiFilter *)aFilter
+ inList: (NSDictionary *)someFiles
+{
+ if (aFilter != nil) {
+ NSDictionary *index;
+ NSMutableDictionary *matchingFiles;
+
+ matchingFiles = nil;
+ index = [self indexForAttribute: [aFilter attribute]];
+ if (index != nil && [someFiles count] > [index count]) {
+ NSEnumerator *valEnum;
+ id value;
+
+ valEnum = [index keyEnumerator];
+ while ((value = [valEnum nextObject]) != nil) {
+ if ([value performSelector: [aFilter compareSelector]
+ withObject: [aFilter value]]) {
+ NSEnumerator *idEnum;
+ id fileID;
+
+ if (matchingFiles == nil)
+ matchingFiles = [NSMutableDictionary dictionary];
+
+ idEnum = [[index objectForKey: value] objectEnumerator];
+ while ((fileID = [idEnum nextObject]) != nil) {
+ [matchingFiles setObject: [self attributesForFileID: fileID]
+ forKey: fileID];
+ }
+ }
+ }
+ } else { // Non-indexed
+ NSEnumerator *idEnum;
+ id fileID;
+
+ // Go through all the files in the list.
+ idEnum = [someFiles keyEnumerator];
+ while ((fileID = [idEnum nextObject]) != nil) {
+ if ([self attributes: [someFiles objectForKey: fileID]
+ matchFilter: aFilter]) {
+ if (matchingFiles == nil)
+ matchingFiles = [NSMutableDictionary dictionary];
+ [matchingFiles setObject: [self attributesForFileID: fileID]
+ forKey: fileID];
+ }
+ }
+ }
+ return matchingFiles;
+ } else
+ return someFiles;
+}
+
+- (NSArray *)fileIDsMatchingFilter: (LiFilter *)aFilter
+{
+ NSArray *matchingFiles;
+ if (aFilter != nil) {
+ matchingFiles = [[self fileIDsMatchingFilter: aFilter inList: theFiles] allKeys];
+ } else
+ matchingFiles = [self allFileIDs];
+
+ return matchingFiles;
+}
+
+- (BOOL)attributes: (NSDictionary *)someAttributes
+ matchFilter: (LiFilter *)aFilter
+{
+ if (aFilter == nil)
+ return YES;
+ else if (someAttributes != nil) {
+ id myValue;
+
+ myValue = [someAttributes objectForKey: [aFilter attribute]];
+ if ([myValue respondsToSelector: @selector(objectEnumerator)]) {
+ NSEnumerator *valueEnum;
+ id subValue;
+
+ valueEnum = [myValue performSelector: @selector(objectEnumerator)];
+ while ((subValue = [valueEnum nextObject]) != nil) {
+ if ([subValue respondsToSelector: [aFilter compareSelector]]) {
+ if ([subValue performSelector: [aFilter compareSelector]
+ withObject: [aFilter value]]) {
+ return YES;
+ }
+ }
+ }
+ return NO;
+ } else { // Non-enumerable
+ BOOL match;
+
+ match = NO;
+ if ([myValue respondsToSelector: [aFilter compareSelector]])
+ if ([myValue performSelector: [aFilter compareSelector]
+ withObject: [aFilter value]])
+ match = YES;
+ return match;
+ }
+ } else
+ return NO;
+}
+
+#if 0
+- (BOOL)attributes: (NSDictionary *)someAttributes
+ match: (NSDictionary *)matchAttributes
+{
+ BOOL matches;
+
+ matches = YES;
+ if (someAttributes != nil && [someAttributes count] > 0) {
+ NSEnumerator *attrEnum;
+ NSString *attribute;
+
+ attrEnum = [someAttributes keyEnumerator];
+ while ((attribute = [attrEnum nextObject]) != nil) {
+ id myValue, matchValue;
+
+ matchValue = [someAttributes objectForKey: attribute];
+ myValue = [someAttributes objectForKey: attribute];
+ if (matchValue != myValue) {
+ if ([myValue isKindOfClass: [NSArray class]]) {
+ NSEnumerator *valEnum;
+ id subValue;
+
+ valEnum = [myValue objectEnumerator];
+ while ((subValue = [valEnum nextObject]) != nil) {
+ if (subValue != matchValue) {
+ if ([subValue respondsToSelector:
+ @selector(compare:)]) {
+ if ([subValue performSelector: @selector(compare:)
+ withObject: matchValue] != 0)
+ matches = NO;
+ } else
+ matches = NO;
+ }
+ }
+ } else if ([myValue respondsToSelector:
+ @selector(compare:)]) {
+ if ([myValue performSelector: @selector(compare:)
+ withObject: matchValue] != 0)
+ matches = NO;
+ } else
+ matches = NO;
+ }
+ }
+ }
+
+ return matches;
+}
+
+- (NSMutableSet *)filesInSet: (NSMutableSet *)fileSet
+ matchingAttributes: (NSMutableDictionary *)someAttributes
+{
+ NSEnumerator *attributeEnum;
+ NSString *attribute, *bestAttribute;
+ id attributeValue;
+ long bestCount;
+
+ if (someAttributes == nil || [someAttributes count] == 0)
+ return fileSet;
+
+ // Find the smallest sets of potential matchers. This allows us to look
+ // up as few files as possible.
+ bestAttribute = nil;
+ bestCount = -1;
+ attributeEnum = [someAttributes keyEnumerator];
+ while ((attribute = [attributeEnum nextObject]) != nil) {
+ if (bestAttribute == nil)
+ bestAttribute = attribute;
+ else {
+ NSDictionary *index;
+
+ index = [self indexForAttribute: attribute];
+ if (index != nil) {
+ unsigned long indexCount;
+
+ indexCount = [index count];
+ if (bestCount == -1) {
+ bestAttribute = attribute;
+ bestCount = indexCount;
+ } else if (bestCount > 1 && bestCount > (long)indexCount) {
+ bestAttribute = attribute;
+ bestCount = indexCount;
+ }
+ }
+ }
+ }
+ attribute = bestAttribute;
+ attributeValue = [someAttributes objectForKey: bestAttribute];
+
+ if (fileSet == nil) {
+ NSDictionary *index;
+
+ index = [self indexForAttribute: attribute];
+ if (index != nil) {
+ fileSet = [NSMutableSet setWithArray: [index objectForKey: attributeValue]];
+ } else {
+ NSEnumerator *handleEnum;
+ id handle;
+
+ // Go through every file in the library one by one. Shitty!
+ fileSet = [NSMutableSet set];
+ handleEnum = [theFiles keyEnumerator];
+ while ((handle = [handleEnum nextObject]) != nil) {
+ NSDictionary *handleAttrs;
+ id myValue;
+
+ handleAttrs = [theFiles objectForKey: handle];
+ myValue = [handleAttrs objectForKey: attribute];
+ if (myValue != attributeValue) {
+ if ([myValue isKindOfClass: [NSArray class]]) {
+ NSEnumerator *valueEnum;
+ id subValue;
+
+ valueEnum = [myValue objectEnumerator];
+ while ((subValue = [valueEnum nextObject]) != nil) {
+ if (subValue == attributeValue)
+ [fileSet addObject: handle];
+ else if ([subValue respondsToSelector: @selector(compare:)]) {
+ if ([subValue performSelector: @selector(compare:)
+ withObject: attributeValue] == 0) {
+ [fileSet addObject: handle];
+ break;
+ }
+ }
+ }
+ } else if ([myValue respondsToSelector: @selector(compare:)])
+ if ([myValue performSelector: @selector(compare:)
+ withObject: attributeValue] == 0)
+ [fileSet addObject: handle];
+ } else
+ [fileSet addObject: handle];
+ }
+ }
+ } else {
+ NSDictionary *index;
+
+ index = [self indexForAttribute: attribute];
+ if (index != nil) {
+ [fileSet intersectSet: [NSMutableSet setWithArray: [index objectForKey: attributeValue]]];
+ } else {
+ NSEnumerator *handleEnum;
+ id handle;
+
+ // Go through every file in the set.
+ handleEnum = [fileSet objectEnumerator];
+ while ((handle = [handleEnum nextObject]) != nil) {
+ NSDictionary *handleAttrs;
+ id myValue;
+
+ handleAttrs = [theFiles objectForKey: handle];
+ myValue = [handleAttrs objectForKey: attribute];
+ if (myValue == attributeValue) {
+ [fileSet removeObject: handle];
+ } else if ([myValue respondsToSelector: @selector(compare:)]) {
+ if ([myValue performSelector: @selector(compare:)
+ withObject: attributeValue] == 0)
+ [fileSet removeObject: handle];
+ }
+ }
+ }
+ }
+
+ [someAttributes removeObjectForKey: bestAttribute];
+ return [self filesInSet: fileSet matchingAttributes: someAttributes];
+}
+
+- (NSArray *)filesMatchingAttributes: (NSDictionary *)someAttributes
+{
+ if (someAttributes != nil && [someAttributes count] > 0) {
+ NSEnumerator *handleEnum;
+ NSMutableArray *matchingFiles;
+ id handle;
+
+ matchingFiles = [NSMutableArray array];
+ handleEnum = [[self filesInSet: nil
+ matchingAttributes: [NSMutableDictionary dictionaryWithDictionary: someAttributes]] objectEnumerator];
+ while ((handle = [handleEnum nextObject]) != nil) {
+ LiFileHandle *fileHandle;
+
+ fileHandle = [[LiFileHandle alloc] init];
+ [fileHandle setFileStore: self];
+ [fileHandle setFileHandle: handle];
+
+ [matchingFiles addObject: fileHandle];
+ [fileHandle release];
+ }
+ return matchingFiles;
+ } else
+ return [self allFileHandles];
+}
+#endif
+
+- (NSArray *)allValuesForAttribute: (NSString *)anAttribute
+{
+ NSArray *valueArray;
+ NSMutableDictionary *index;
+ NSMutableSet *values;
+
+ values = [NSMutableSet setWithArray: [[self delegate] defaultValuesForAttribute: anAttribute]];
+ index = [self indexForAttribute: anAttribute];
+ if (index != nil) {
+ // Use the index to find the possible values.
+ [values addObjectsFromArray: [index allKeys]];
+ } else {
+ NSDictionary *fileAttrs;
+ NSEnumerator *fileEnum;
+
+ // No index. Crappy. Go through every file in the library.
+ fileEnum = [theFiles objectEnumerator];
+ while ((fileAttrs = [fileEnum nextObject]) != nil) {
+ id value;
+
+ value = [fileAttrs objectForKey: anAttribute];
+ if (value != nil && [values member: anAttribute] != nil) {
+ [values addObject: anAttribute];
+ }
+ }
+ }
+
+ valueArray = [values allObjects];
+ return valueArray;
+}
+@synthesize theIcon;
+@synthesize theDelegate;
+@synthesize theFiles;
+@synthesize nextHandle;
+@synthesize theStoreID;
+@synthesize theName;
+@synthesize theIndexes;
+@end
+
+@implementation LiFileStore (CommonAccessors)
+- (void)synchronize
+{
+ if ([self sendNotifications] > 0) {
+ [[self delegate] synchronizeFileStore];
+ }
+}
+
+- (LiFileHandle *)addURL: (NSURL *)anURL
+{
+ return [[self delegate] addURL: anURL toFileStore: self];
+}
+@end
+
+@implementation LiFileStore (Accessors)
+- (id)storeID
+{
+ return theStoreID;
+}
+
+- (void)setStoreID: (id)anID
+{
+ [anID retain];
+ [theStoreID release];
+ theStoreID = anID;
+}
+
+- (id <LiFileStoreDelegate>)delegate
+{
+ return theDelegate;
+}
+
+- (void)setDelegate: (id <LiFileStoreDelegate>)aDelegate
+{
+ [aDelegate retain];
+ [theDelegate release];
+ theDelegate = aDelegate;
+}
+
+- (BOOL)isEditable
+{
+ return theStoreIsEditable;
+}
+
+- (void)setEditable: (BOOL)editable
+{
+ theStoreIsEditable = editable;
+}
+
+- (NSString *)name
+{
+ return theName;
+}
+
+- (void)setName: (NSString *)aName
+{
+ NSNotificationCenter *defaultCenter;
+
+ [aName retain];
+ [theName release];
+ theName = aName;
+
+ defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter postNotificationName: LiFileStoresChangedNotification
+ object: nil
+ userInfo: nil];
+}
+
+- (NSImage *)icon
+{
+ return theIcon;
+}
+
+- (void)setIcon: (NSImage *)anIcon
+{
+ NSNotificationCenter *defaultCenter;
+
+ [anIcon retain];
+ [theIcon release];
+ theIcon = anIcon;
+
+ defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter postNotificationName: LiFileStoresChangedNotification
+ object: nil
+ userInfo: nil];
+}
+
+- (NSMutableSet *)addedFiles
+{
+ if (theAddedFiles == nil)
+ [self setAddedFiles: [NSMutableSet set]];
+ return theAddedFiles;
+}
+
+- (void)setAddedFiles: (NSMutableSet *)aSet
+{
+ [aSet retain];
+ [theAddedFiles release];
+ theAddedFiles = aSet;
+}
+
+- (NSMutableSet *)changedFiles
+{
+ if (theChangedFiles == nil)
+ [self setChangedFiles: [NSMutableSet set]];
+ return theChangedFiles;
+}
+
+- (void)setChangedFiles: (NSMutableSet *)aSet
+{
+ [aSet retain];
+ [theChangedFiles release];
+ theChangedFiles = aSet;
+}
+
+- (NSMutableSet *)removedFiles
+{
+ if (theRemovedFiles == nil)
+ [self setRemovedFiles: [NSMutableSet set]];
+ return theRemovedFiles;
+}
+
+- (void)setRemovedFiles: (NSMutableSet *)aSet
+{
+ [aSet retain];
+ [theRemovedFiles release];
+ theRemovedFiles = aSet;
+}
+@end
+
+@implementation LiFileStore (Scripting)
+- (NSScriptObjectSpecifier *)objectSpecifier
+{
+ NSScriptClassDescription *containerDescription;
+ NSScriptObjectSpecifier *containerRef;
+ unsigned index;
+
+ index = [[LiFileStore allFileStores] indexOfObjectIdenticalTo: self];
+ if (index != NSNotFound) {
+ containerRef = [NSApp objectSpecifier];
+ containerDescription = (NSScriptClassDescription *)[NSScriptClassDescription classDescriptionForClass:[NSApp class]];
+
+ return [[[NSIndexSpecifier alloc] initWithContainerClassDescription:containerDescription containerSpecifier:containerRef key:@"orderedFileStores" index:index] autorelease];
+ } else
+ return nil;
+}
+@end
+
+@implementation LiFileStore (Private)
+// XXX
+// Should coalesce like events into a single event before sending it
+// and take the array code out of the individual file updates.
+- (void)sendNotificationName: (NSString *)aNotificationName
+ userInfo: (NSDictionary *)userInfo
+{
+ NSNotificationCenter *defaultCenter;
+
+ defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter postNotificationName: aNotificationName
+ object: self
+ userInfo: userInfo];
+}
+
+- (unsigned)sendNotifications
+{
+ NSMutableDictionary *userInfo;
+ unsigned changeCount;
+
+ userInfo = [NSMutableDictionary dictionary];
+ if ([[self addedFiles] count] > 0) {
+ [userInfo setObject: [[self addedFiles] allObjects]
+ forKey: LiFilesAdded];
+ [self setAddedFiles: nil];
+ }
+ if ([[self changedFiles] count] > 0) {
+ [userInfo setObject: [[self changedFiles] allObjects]
+ forKey: LiFilesChanged];
+ [self setChangedFiles: nil];
+ }
+ if ([[self removedFiles] count] > 0) {
+ [userInfo setObject: [[self removedFiles] allObjects]
+ forKey: LiFilesRemoved];
+ [self setRemovedFiles: nil];
+ }
+
+ changeCount = [userInfo count];
+ if (changeCount > 0) {
+ [self sendNotificationName: LiFileChangedNotification
+ userInfo: userInfo];
+ }
+ return changeCount;
+}
+
+- (void)sendAddNotificationForFileHandle: (LiFileHandle *)aFileHandle
+{
+ [[self addedFiles] addObject: aFileHandle];
+}
+
+- (void)sendUpdateNotificationForFileHandle: (LiFileHandle *)aFileHandle
+ oldAttributes: (NSDictionary *)oldAttrs
+{
+ if ([oldAttrs count] > 0) {
+ [[self changedFiles] addObject:
+ [NSDictionary dictionaryWithObjects:
+ [NSArray arrayWithObjects: aFileHandle, oldAttrs, nil]
+ forKeys:
+ [NSArray arrayWithObjects: LiFileHandleAttribute, LiFileOldAttributes, nil]]];
+ }
+}
+
+- (void)sendRemoveNotificationForFileHandle: (LiFileHandle *)aFileHandle
+ oldAttributes: (NSDictionary *)oldAttrs
+{
+ [[self removedFiles] addObject:
+ [NSDictionary dictionaryWithObjects:
+ [NSArray arrayWithObjects: aFileHandle, oldAttrs, nil]
+ forKeys:
+ [NSArray arrayWithObjects: LiFileHandleAttribute, LiFileOldAttributes, nil]]];
+}
+@end \ No newline at end of file
diff --git a/Frameworks/LiBackend/LiFilter.h b/Frameworks/LiBackend/LiFilter.h
new file mode 100644
index 0000000..3a81280
--- /dev/null
+++ b/Frameworks/LiBackend/LiFilter.h
@@ -0,0 +1,38 @@
+//
+// LiFilter.h
+// LiFrameworks
+//
+// Created by Brian Cully on Sat Aug 23 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface LiFilter : NSObject
+{
+ NSString *theAttribute;
+ NSString *theCompareSelector;
+ id theValue;
+}
++ (LiFilter *)filterWithAttribute: (NSString *)anAttribute
+ compareSelector: (SEL)aSelector
+ value: (id)aValue;
+
+- (id)initWithAttribute: (NSString *)anAttribute
+ compareSelector: (SEL)aSelector
+ value: (id)aValue;
+@property (retain,getter=attribute) NSString *theAttribute;
+@property (retain,getter=value) id theValue;
+@property (retain) NSString *theCompareSelector;
+@end
+
+@interface LiFilter (Accessors)
+- (NSString *)attribute;
+- (void)setAttribute: (NSString *)anAttribute;
+- (SEL)compareSelector;
+- (void)setCompareSelector: (SEL)aSelector;
+- (id)value;
+- (void)setValue: (id)aValue;
+@end
+
+@interface LiFilter (CommonAccessors)
+- (NSString *)description;
+@end \ No newline at end of file
diff --git a/Frameworks/LiBackend/LiFilter.m b/Frameworks/LiBackend/LiFilter.m
new file mode 100644
index 0000000..74e2f4a
--- /dev/null
+++ b/Frameworks/LiBackend/LiFilter.m
@@ -0,0 +1,108 @@
+//
+// LiFilter.m
+// LiFrameworks
+//
+// Created by Brian Cully on Sat Aug 23 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "LiFilter.h"
+
+@implementation LiFilter
++ (LiFilter *)filterWithAttribute: (NSString *)anAttribute
+ compareSelector: (SEL)aSelector
+ value: (id)aValue
+{
+ LiFilter *tmpFilter;
+
+ tmpFilter = [[self alloc] initWithAttribute: anAttribute
+ compareSelector: aSelector
+ value: aValue];
+ return [tmpFilter autorelease];
+}
+
+- (id)init
+{
+ NSException *exception;
+
+ exception = [NSException exceptionWithName: @"LiNoInitException"
+ reason: @"[LiFilter init] not supported"
+ userInfo: nil];
+ [exception raise];
+
+ return nil;
+}
+
+- (void)dealloc
+{
+ [self setAttribute: nil];
+ [self setCompareSelector: nil];
+ [self setValue: nil];
+
+ [super dealloc];
+}
+
+- (id)initWithAttribute: (NSString *)anAttribute
+ compareSelector: (SEL)aSelector
+ value: (id)aValue
+{
+ self = [super init];
+
+ [self setAttribute: anAttribute];
+ [self setCompareSelector: aSelector];
+ [self setValue: aValue];
+
+ return self;
+}
+@synthesize theCompareSelector;
+@synthesize theAttribute;
+@synthesize theValue;
+@end
+
+@implementation LiFilter (Accessors)
+- (NSString *)attribute
+{
+ return theAttribute;
+}
+
+- (void)setAttribute: (NSString *)anAttribute
+{
+ [anAttribute retain];
+ [theAttribute release];
+ theAttribute = anAttribute;
+}
+
+- (SEL)compareSelector
+{
+ return NSSelectorFromString(theCompareSelector);
+}
+
+- (void)setCompareSelector: (SEL)aSelector
+{
+ [theCompareSelector release];
+ theCompareSelector = [NSStringFromSelector(aSelector) retain];
+}
+
+- (id)value
+{
+ return theValue;
+}
+
+- (void)setValue: (id)aValue
+{
+ [aValue retain];
+ [theValue release];
+ theValue = aValue;
+}
+@end
+
+@implementation LiFilter (CommonAccessors)
+- (NSString *)description
+{
+ NSString *desc;
+
+ desc = [NSString stringWithFormat: @"{\n\tattribute: %@\n\tselector: %@\n\tvalue: %@\n}",
+ theAttribute, theCompareSelector, [theValue description]];
+ return desc;
+}
+@end \ No newline at end of file
diff --git a/Frameworks/LiBackend/LiLog.h b/Frameworks/LiBackend/LiLog.h
new file mode 100644
index 0000000..24043f0
--- /dev/null
+++ b/Frameworks/LiBackend/LiLog.h
@@ -0,0 +1,21 @@
+//
+// LiLog.h
+// Liaison
+//
+// Created by Brian Cully on Tue May 20 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface LiLog : NSObject
++ (void)alertWithHeader: (NSString *)aHeader
+ contents: (NSString *)someContents;
+
++ (void)logAsDebug: (NSString *)format, ...;
++ (void)logAsInfo: (NSString *)format, ...;
++ (void)logAsWarning: (NSString *)format, ...;
++ (void)logAsError: (NSString *)format, ...;
+
++ (id)indentDebugLog;
++ (id)unindentDebugLog;
++ (NSString *)debugIndentString;
+@end
diff --git a/Frameworks/LiBackend/LiLog.m b/Frameworks/LiBackend/LiLog.m
new file mode 100644
index 0000000..5dcb861
--- /dev/null
+++ b/Frameworks/LiBackend/LiLog.m
@@ -0,0 +1,104 @@
+//
+// LiLog.m
+// Liaison
+//
+// Created by Brian Cully on Tue May 20 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "LiLog.h"
+
+@implementation LiLog
+static int debugIndentLevel = 0;
+
++ (void)alertDidEnd: (NSWindow *)sheet
+ returnCode: (int)returnCode
+ contextInfo: (void *)contextInfo
+{
+ [sheet close];
+
+ return;
+}
+
++ (void)alertWithHeader: (NSString *)aHeader
+ contents: (NSString *)someContents
+ forWindow: (NSWindow *)aWindow
+{
+ if (aWindow != nil)
+ NSBeginAlertSheet(aHeader, @"Okay", nil, nil, aWindow, self,
+ @selector(alertDidEnd:returnCode:contextInfo:),
+ @selector(alertDidEnd:returnCode:contextInfo:),
+ nil, someContents);
+ else
+ NSRunAlertPanel(aHeader, someContents, @"Okay", nil, nil);
+}
+
++ (void)alertWithHeader: (NSString *)aHeader
+ contents: (NSString *)someContents
+{
+ [self alertWithHeader: aHeader contents: someContents forWindow: [NSApp keyWindow]];
+}
+
++ (void)logAsDebug: (NSString *)format, ...
+{
+#define DEBUG 1
+#if DEBUG
+ va_list args;
+
+ va_start(args, format);
+ NSLogv([[@"DEBUG: " stringByAppendingString: [self debugIndentString]] stringByAppendingString: format], args);
+ va_end(args);
+#endif
+}
+
++ (void)logAsInfo: (NSString *)format, ...
+{
+ va_list args;
+
+ va_start(args, format);
+ NSLogv([@"INFO: " stringByAppendingString: format], args);
+ va_end(args);
+}
+
++ (void)logAsWarning: (NSString *)format, ...
+{
+ va_list args;
+
+ va_start(args, format);
+ NSLogv([@"WARNING: " stringByAppendingString: format], args);
+ va_end(args);
+}
+
++ (void)logAsError: (NSString *)format, ...
+{
+ va_list args;
+
+ va_start(args, format);
+ NSLogv([@"ERROR: " stringByAppendingString: format], args);
+ va_end(args);
+}
+
++ (id)indentDebugLog
+{
+ debugIndentLevel++;
+ return self;
+}
+
++ (id)unindentDebugLog
+{
+ if (debugIndentLevel > 0)
+ debugIndentLevel--;
+ return self;
+}
+
++ (NSString *)debugIndentString
+{
+ NSMutableString *indentString;
+ int i;
+
+ indentString = [NSMutableString string];
+ for (i = 0; i < debugIndentLevel; i++)
+ [indentString appendString: @"\t"];
+ return indentString;
+}
+@end
diff --git a/Frameworks/LiBackend/LiPreferences.h b/Frameworks/LiBackend/LiPreferences.h
new file mode 100644
index 0000000..390b67f
--- /dev/null
+++ b/Frameworks/LiBackend/LiPreferences.h
@@ -0,0 +1,31 @@
+//
+// Preferences.h
+// Liaison
+//
+// Created by Brian Cully on Fri Feb 21 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface Preferences : NSObject
+{
+ NSUserDefaults *theDefaults;
+}
+
++ (Preferences *)sharedPreferences;
+
+- (NSString *)downloadDirectory;
+- (void)setDownloadDirectory: (NSString *)aPath;
+- (NSString *)groupPath;
+- (void)setGroupPath: (NSString *)aPath;
+- (NSString *)libraryPath;
+- (void)setLibraryPath: (NSString *)aPath;
+- (NSString *)hostname;
+- (void)setHostname: (NSString *)aHostname;
+- (BOOL)networkEnabled;
+- (void)setNetworkEnabled: (BOOL)isEnabled;
+- (BOOL)useRendezvousGroup;
+- (void)setUseRendezvousGroup: (BOOL)useGroup;
+- (NSDictionary *)fileListPrefs;
+- (void)setFileListPrefs: (NSDictionary *)listPrefs;
+@property (retain) NSUserDefaults *theDefaults;
+@end
diff --git a/Frameworks/LiBackend/LiPreferences.m b/Frameworks/LiBackend/LiPreferences.m
new file mode 100644
index 0000000..0f59581
--- /dev/null
+++ b/Frameworks/LiBackend/LiPreferences.m
@@ -0,0 +1,209 @@
+//
+// Preferences.m
+// Liaison
+//
+// Created by Brian Cully on Fri Feb 21 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "LiPreferences.h"
+
+// Default download directory.
+#define DOWNLOADSPATH @"/Desktop"
+
+// Default library datastore paths.
+#define LIBRARYPATH @"/Library/Liaison/Liaison Library.xml"
+#define GROUPPATH @"/Library/Liaison/Liaison Groups.xml"
+
+// Default hostname.
+#define HOSTNAME @"Unknown"
+
+// User default keys.
+#define DOWNLOADKEY @"downloadsDirectory"
+#define GROUPPATHKEY @"groupPath"
+#define HOSTNAMEKEY @"rendezvousHostname"
+#define LIBRARYPATHKEY @"libraryPath"
+#define NETWORKENABLEDKEY @"networkEnabled"
+#define USERENDEZVOUSGROUPKEY @"useRendezvousGroup"
+#define FILELISTPREFSKEY @"fileListPrefs"
+
+@implementation Preferences
+static Preferences *sharedInstance = nil;
+
++ (Preferences *)sharedPreferences
+{
+ if (sharedInstance == nil)
+ sharedInstance = [[Preferences alloc] init];
+ return sharedInstance;
+}
+
+- (id)init
+{
+ self = [super init];
+ if (self) {
+ theDefaults = [NSUserDefaults standardUserDefaults];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [theDefaults synchronize];
+ [super dealloc];
+}
+
+- (NSString *)defaultDownloadDirectory
+{
+ return [NSHomeDirectory() stringByAppendingPathComponent:
+ DOWNLOADSPATH];
+}
+
+- (NSString *)downloadDirectory
+{
+ NSString *downloadDirectory;
+
+ downloadDirectory = [theDefaults objectForKey: DOWNLOADKEY];
+ if (downloadDirectory == nil)
+ downloadDirectory = [self defaultDownloadDirectory];
+ return downloadDirectory;
+}
+
+- (void)setDownloadDirectory: (NSString *)aPath
+{
+ [theDefaults setObject: aPath forKey: DOWNLOADKEY];
+}
+
+- (NSString *)defaultGroupPath
+{
+ return [NSHomeDirectory() stringByAppendingPathComponent: GROUPPATH];
+}
+
+- (NSString *)groupPath
+{
+ NSString *groupPath;
+
+ groupPath = [theDefaults objectForKey: GROUPPATHKEY];
+ if (groupPath == nil)
+ groupPath = [self defaultGroupPath];
+ return groupPath;
+}
+
+- (void)setGroupPath: (NSString *)aPath
+{
+ [theDefaults setObject: aPath forKey: GROUPPATHKEY];
+}
+
+- (NSString *)defaultLibraryPath
+{
+ return [NSHomeDirectory() stringByAppendingPathComponent: LIBRARYPATH];
+}
+
+- (NSString *)libraryPath
+{
+ NSString *libraryPath;
+
+ libraryPath = [theDefaults objectForKey: LIBRARYPATHKEY];
+ if (libraryPath == nil)
+ libraryPath = [self defaultLibraryPath];
+ return libraryPath;
+}
+
+- (void)setLibraryPath: (NSString *)aPath
+{
+ [theDefaults setObject: aPath forKey: LIBRARYPATHKEY];
+}
+
+- (NSString *)defaultHostname
+{
+ NSArray *hostnames;
+ NSString *hostname;
+
+ hostnames = [[NSHost currentHost] names];
+ for (hostname in hostnames) {
+ NSRange localRange;
+
+ localRange = [hostname rangeOfString: @".local."];
+ if (localRange.location != NSNotFound) {
+ hostname = [hostname substringToIndex: localRange.location];
+ break;
+ }
+ }
+ if (hostname == nil)
+ hostname = [hostnames objectAtIndex: 0];
+
+ return hostname;
+}
+
+- (NSString *)hostname
+{
+ NSString *hostname;
+
+ hostname = [theDefaults objectForKey: HOSTNAMEKEY];
+ if (hostname == nil)
+ hostname = [self defaultHostname];
+ return hostname;
+}
+
+- (void)setHostname: (NSString *)aHostname
+{
+ [theDefaults setObject: aHostname forKey: HOSTNAMEKEY];
+}
+
+- (BOOL)defaultNetworkEnabled
+{
+ return YES;
+}
+
+- (BOOL)networkEnabled
+{
+ NSNumber *networkEnabled;
+
+ networkEnabled = [theDefaults objectForKey: NETWORKENABLEDKEY];
+ if (networkEnabled == nil)
+ return [self defaultNetworkEnabled];
+ if ([networkEnabled intValue] == 1)
+ return YES;
+ else
+ return NO;
+}
+- (void)setNetworkEnabled: (BOOL)isEnabled
+{
+ if (isEnabled)
+ [theDefaults setObject: [NSNumber numberWithInt: 1]
+ forKey: NETWORKENABLEDKEY];
+ else
+ [theDefaults setObject: [NSNumber numberWithInt: 0]
+ forKey: NETWORKENABLEDKEY];
+}
+
+- (BOOL)defaultUseRendezvousGroup
+{
+ return NO;
+}
+
+- (BOOL)useRendezvousGroup
+{
+ NSNumber *useRendezvousGroup;
+
+ useRendezvousGroup = [theDefaults objectForKey: USERENDEZVOUSGROUPKEY];
+ if (useRendezvousGroup == nil)
+ return [self defaultUseRendezvousGroup];
+
+ return [useRendezvousGroup boolValue];
+}
+- (void)setUseRendezvousGroup: (BOOL)useGroup
+{
+ [theDefaults setObject: [NSNumber numberWithBool: useGroup]
+ forKey: USERENDEZVOUSGROUPKEY];
+}
+
+- (NSDictionary *)fileListPrefs
+{
+ return [theDefaults objectForKey: FILELISTPREFSKEY];
+}
+- (void)setFileListPrefs: (NSDictionary *)listPrefs
+{
+ [theDefaults setObject: listPrefs forKey: FILELISTPREFSKEY];
+}
+@synthesize theDefaults;
+@end
diff --git a/Frameworks/LiBackend/LiStoreValidator.h b/Frameworks/LiBackend/LiStoreValidator.h
new file mode 100644
index 0000000..da5094e
--- /dev/null
+++ b/Frameworks/LiBackend/LiStoreValidator.h
@@ -0,0 +1,11 @@
+//
+// LiStoreValidator.h
+// Liaison
+//
+// Created by Brian Cully on Sun May 25 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface LiStoreValidator : NSObject
+- (void)addFileToUpdateQueue: (LiFileHandle *)aFileHandle;
+@end
diff --git a/Frameworks/LiBackend/LiStoreValidator.m b/Frameworks/LiBackend/LiStoreValidator.m
new file mode 100644
index 0000000..3997cd5
--- /dev/null
+++ b/Frameworks/LiBackend/LiStoreValidator.m
@@ -0,0 +1,13 @@
+//
+// LiStoreValidator.m
+// Liaison
+//
+// Created by Brian Cully on Sun May 25 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@implementation LiStoreValidator
+- (void)addFileToUpdateQueue: (LiFileHandle *)aFileHandle
+{
+}
+@end
diff --git a/Frameworks/LiFrameworks.xcodeproj/project.pbxproj b/Frameworks/LiFrameworks.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..de7c025
--- /dev/null
+++ b/Frameworks/LiFrameworks.xcodeproj/project.pbxproj
@@ -0,0 +1,612 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F7D39781054685A000BD181E /* LiLog.h in Headers */ = {isa = PBXBuildFile; fileRef = F7585F8004EF2F8C00000104 /* LiLog.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D39782054685A000BD181E /* LiPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = F7585F8104EF2F8C00000104 /* LiPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D39783054685A000BD181E /* LiStoreValidator.h in Headers */ = {isa = PBXBuildFile; fileRef = F7585F8204EF2F8C00000104 /* LiStoreValidator.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D39784054685A000BD181E /* LiBackend.h in Headers */ = {isa = PBXBuildFile; fileRef = F7585F8904EF2F9D00000104 /* LiBackend.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D39785054685A000BD181E /* LiFileStore.h in Headers */ = {isa = PBXBuildFile; fileRef = F7585F8C04EF2F9D00000104 /* LiFileStore.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D39786054685A000BD181E /* LiFileHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = F7585F8D04EF2F9D00000104 /* LiFileHandle.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D39787054685A000BD181E /* LiFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = F7A5B69104F7206C00000104 /* LiFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D3978A054685A000BD181E /* LiBackend.scriptSuite in Resources */ = {isa = PBXBuildFile; fileRef = F7585F9304EF2FAD00000104 /* LiBackend.scriptSuite */; };
+ F7D3978B054685A000BD181E /* LiBackend.scriptTerminology in Resources */ = {isa = PBXBuildFile; fileRef = F7585F9704EF2FD800000104 /* LiBackend.scriptTerminology */; };
+ F7D3978D054685A000BD181E /* LiStoreValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = F7585F7D04EF2F8C00000104 /* LiStoreValidator.m */; };
+ F7D3978E054685A000BD181E /* LiLog.m in Sources */ = {isa = PBXBuildFile; fileRef = F7585F7E04EF2F8C00000104 /* LiLog.m */; };
+ F7D3978F054685A000BD181E /* LiPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = F7585F7F04EF2F8C00000104 /* LiPreferences.m */; };
+ F7D39790054685A000BD181E /* LiFileHandle.m in Sources */ = {isa = PBXBuildFile; fileRef = F7585F8A04EF2F9D00000104 /* LiFileHandle.m */; };
+ F7D39791054685A000BD181E /* LiFileStore.m in Sources */ = {isa = PBXBuildFile; fileRef = F7585F8B04EF2F9D00000104 /* LiFileStore.m */; };
+ F7D39792054685A000BD181E /* LiFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A5B69204F7206C00000104 /* LiFilter.m */; };
+ F7D39794054685A000BD181E /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; };
+ F7D3979E054685AE00BD181E /* LiBrowserColumn.h in Headers */ = {isa = PBXBuildFile; fileRef = F7D5A4D004EF396F00000104 /* LiBrowserColumn.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D3979F054685AE00BD181E /* LiInspectorView.h in Headers */ = {isa = PBXBuildFile; fileRef = F7D5A4D204EF396F00000104 /* LiInspectorView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D397A0054685AE00BD181E /* LiPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = F7D5A4D404EF396F00000104 /* LiPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D397A1054685AE00BD181E /* LiFilterDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = F7A5B68D04F71E7900000104 /* LiFilterDescription.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ F7D397A4054685AE00BD181E /* LiBrowserColumn.m in Sources */ = {isa = PBXBuildFile; fileRef = F7D5A4D104EF396F00000104 /* LiBrowserColumn.m */; };
+ F7D397A5054685AE00BD181E /* LiInspectorView.m in Sources */ = {isa = PBXBuildFile; fileRef = F7D5A4D304EF396F00000104 /* LiInspectorView.m */; };
+ F7D397A6054685AE00BD181E /* LiFilterDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A5B68E04F71E7900000104 /* LiFilterDescription.m */; };
+ F7D397A8054685AE00BD181E /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ F7D397680546855800BD181E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F7D3977F054685A000BD181E;
+ remoteInfo = LiBackend;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ 0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
+ 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ F7585F7D04EF2F8C00000104 /* LiStoreValidator.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiStoreValidator.m; sourceTree = "<group>"; };
+ F7585F7E04EF2F8C00000104 /* LiLog.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiLog.m; sourceTree = "<group>"; };
+ F7585F7F04EF2F8C00000104 /* LiPreferences.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiPreferences.m; sourceTree = "<group>"; };
+ F7585F8004EF2F8C00000104 /* LiLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiLog.h; sourceTree = "<group>"; };
+ F7585F8104EF2F8C00000104 /* LiPreferences.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiPreferences.h; sourceTree = "<group>"; };
+ F7585F8204EF2F8C00000104 /* LiStoreValidator.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiStoreValidator.h; sourceTree = "<group>"; };
+ F7585F8904EF2F9D00000104 /* LiBackend.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiBackend.h; sourceTree = "<group>"; };
+ F7585F8A04EF2F9D00000104 /* LiFileHandle.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiFileHandle.m; sourceTree = "<group>"; };
+ F7585F8B04EF2F9D00000104 /* LiFileStore.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiFileStore.m; sourceTree = "<group>"; };
+ F7585F8C04EF2F9D00000104 /* LiFileStore.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiFileStore.h; sourceTree = "<group>"; };
+ F7585F8D04EF2F9D00000104 /* LiFileHandle.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiFileHandle.h; sourceTree = "<group>"; };
+ F7585F9304EF2FAD00000104 /* LiBackend.scriptSuite */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = LiBackend.scriptSuite; sourceTree = "<group>"; };
+ F7585F9504EF2FC500000104 /* LiBackend.scriptTerminology */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = LiBackend.scriptTerminology; path = LiBackend/English.lproj/LiBackend.scriptTerminology; sourceTree = "<group>"; };
+ F7A5B68D04F71E7900000104 /* LiFilterDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiFilterDescription.h; sourceTree = "<group>"; };
+ F7A5B68E04F71E7900000104 /* LiFilterDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LiFilterDescription.m; path = LiPlugin/LiFilterDescription.m; sourceTree = SOURCE_ROOT; };
+ F7A5B69104F7206C00000104 /* LiFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiFilter.h; sourceTree = "<group>"; };
+ F7A5B69204F7206C00000104 /* LiFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LiFilter.m; sourceTree = "<group>"; };
+ F7B4D378054B51FC006D06CC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+ F7B4D37A054B521D006D06CC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+ F7D39798054685A000BD181E /* LiBackend.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LiBackend.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ F7D397AC054685AE00BD181E /* LiPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LiPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ F7D5A4D004EF396F00000104 /* LiBrowserColumn.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiBrowserColumn.h; sourceTree = "<group>"; };
+ F7D5A4D104EF396F00000104 /* LiBrowserColumn.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiBrowserColumn.m; sourceTree = "<group>"; };
+ F7D5A4D204EF396F00000104 /* LiInspectorView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiInspectorView.h; sourceTree = "<group>"; };
+ F7D5A4D304EF396F00000104 /* LiInspectorView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiInspectorView.m; sourceTree = "<group>"; };
+ F7D5A4D404EF396F00000104 /* LiPlugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiPlugin.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F7D39793054685A000BD181E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D39794054685A000BD181E /* Cocoa.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F7D397A7054685AE00BD181E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D397A8054685AE00BD181E /* Cocoa.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DFFF38A50411DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F7D39798054685A000BD181E /* LiBackend.framework */,
+ F7D397AC054685AE00BD181E /* LiPlugin.framework */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* LiBackend */ = {
+ isa = PBXGroup;
+ children = (
+ F7D5A4A904EF396B00000104 /* LiPlugin */,
+ 08FB77AEFE84172EC02AAC07 /* LiBackend */,
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
+ 034768DFFF38A50411DB9C8B /* Products */,
+ );
+ name = LiBackend;
+ sourceTree = "<group>";
+ };
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */,
+ 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 08FB77AEFE84172EC02AAC07 /* LiBackend */ = {
+ isa = PBXGroup;
+ children = (
+ F7585F8904EF2F9D00000104 /* LiBackend.h */,
+ F7585F8D04EF2F9D00000104 /* LiFileHandle.h */,
+ F7585F8A04EF2F9D00000104 /* LiFileHandle.m */,
+ F7585F8C04EF2F9D00000104 /* LiFileStore.h */,
+ F7585F8B04EF2F9D00000104 /* LiFileStore.m */,
+ F7A5B69104F7206C00000104 /* LiFilter.h */,
+ F7A5B69204F7206C00000104 /* LiFilter.m */,
+ F7585F8004EF2F8C00000104 /* LiLog.h */,
+ F7585F7E04EF2F8C00000104 /* LiLog.m */,
+ F7585F8104EF2F8C00000104 /* LiPreferences.h */,
+ F7585F7F04EF2F8C00000104 /* LiPreferences.m */,
+ F7585F8204EF2F8C00000104 /* LiStoreValidator.h */,
+ F7585F7D04EF2F8C00000104 /* LiStoreValidator.m */,
+ F7BD554A04F3506D00000104 /* Resources */,
+ );
+ path = LiBackend;
+ sourceTree = "<group>";
+ };
+ 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */,
+ );
+ name = "Linked Frameworks";
+ sourceTree = "<group>";
+ };
+ 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 0867D69BFE84028FC02AAC07 /* Foundation.framework */,
+ 0867D6A5FE840307C02AAC07 /* AppKit.framework */,
+ );
+ name = "Other Frameworks";
+ sourceTree = "<group>";
+ };
+ F7BD554904F3506000000104 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ F7B4D37A054B521D006D06CC /* Info.plist */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ F7BD554A04F3506D00000104 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ F7B4D378054B51FC006D06CC /* Info.plist */,
+ F7585F9304EF2FAD00000104 /* LiBackend.scriptSuite */,
+ F7585F9704EF2FD800000104 /* LiBackend.scriptTerminology */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ F7D5A4A904EF396B00000104 /* LiPlugin */ = {
+ isa = PBXGroup;
+ children = (
+ F7D5A4D404EF396F00000104 /* LiPlugin.h */,
+ F7D5A4D004EF396F00000104 /* LiBrowserColumn.h */,
+ F7D5A4D104EF396F00000104 /* LiBrowserColumn.m */,
+ F7D5A4D204EF396F00000104 /* LiInspectorView.h */,
+ F7D5A4D304EF396F00000104 /* LiInspectorView.m */,
+ F7A5B68D04F71E7900000104 /* LiFilterDescription.h */,
+ F7A5B68E04F71E7900000104 /* LiFilterDescription.m */,
+ F7BD554904F3506000000104 /* Resources */,
+ );
+ path = LiPlugin;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ F7D39780054685A000BD181E /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D39781054685A000BD181E /* LiLog.h in Headers */,
+ F7D39782054685A000BD181E /* LiPreferences.h in Headers */,
+ F7D39783054685A000BD181E /* LiStoreValidator.h in Headers */,
+ F7D39784054685A000BD181E /* LiBackend.h in Headers */,
+ F7D39785054685A000BD181E /* LiFileStore.h in Headers */,
+ F7D39786054685A000BD181E /* LiFileHandle.h in Headers */,
+ F7D39787054685A000BD181E /* LiFilter.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F7D3979D054685AE00BD181E /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D3979E054685AE00BD181E /* LiBrowserColumn.h in Headers */,
+ F7D3979F054685AE00BD181E /* LiInspectorView.h in Headers */,
+ F7D397A0054685AE00BD181E /* LiPlugin.h in Headers */,
+ F7D397A1054685AE00BD181E /* LiFilterDescription.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ F7D3977F054685A000BD181E /* LiBackend */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2898673C095DAB1500B5DC99 /* Build configuration list for PBXNativeTarget "LiBackend" */;
+ buildPhases = (
+ F7D39780054685A000BD181E /* Headers */,
+ F7D39788054685A000BD181E /* Resources */,
+ F7D3978C054685A000BD181E /* Sources */,
+ F7D39793054685A000BD181E /* Frameworks */,
+ F7D39795054685A000BD181E /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = LiBackend;
+ productInstallPath = "@executable_path/../Frameworks";
+ productName = LiBackend;
+ productReference = F7D39798054685A000BD181E /* LiBackend.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ F7D3979B054685AE00BD181E /* LiPlugin */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 28986740095DAB1500B5DC99 /* Build configuration list for PBXNativeTarget "LiPlugin" */;
+ buildPhases = (
+ F7D3979D054685AE00BD181E /* Headers */,
+ F7D397A2054685AE00BD181E /* Resources */,
+ F7D397A3054685AE00BD181E /* Sources */,
+ F7D397A7054685AE00BD181E /* Frameworks */,
+ F7D397A9054685AE00BD181E /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ F7D3979C054685AE00BD181E /* PBXTargetDependency */,
+ );
+ name = LiPlugin;
+ productInstallPath = "@executable_path/../Frameworks";
+ productName = LiPlugin;
+ productReference = F7D397AC054685AE00BD181E /* LiPlugin.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 28986744095DAB1500B5DC99 /* Build configuration list for PBXProject "LiFrameworks" */;
+ compatibilityVersion = "Xcode 2.4";
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ chef,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* LiBackend */;
+ productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F7D3979B054685AE00BD181E /* LiPlugin */,
+ F7D3977F054685A000BD181E /* LiBackend */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ F7D39788054685A000BD181E /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D3978A054685A000BD181E /* LiBackend.scriptSuite in Resources */,
+ F7D3978B054685A000BD181E /* LiBackend.scriptTerminology in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F7D397A2054685AE00BD181E /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ F7D39795054685A000BD181E /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F7D397A9054685AE00BD181E /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F7D3978C054685A000BD181E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D3978D054685A000BD181E /* LiStoreValidator.m in Sources */,
+ F7D3978E054685A000BD181E /* LiLog.m in Sources */,
+ F7D3978F054685A000BD181E /* LiPreferences.m in Sources */,
+ F7D39790054685A000BD181E /* LiFileHandle.m in Sources */,
+ F7D39791054685A000BD181E /* LiFileStore.m in Sources */,
+ F7D39792054685A000BD181E /* LiFilter.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F7D397A3054685AE00BD181E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D397A4054685AE00BD181E /* LiBrowserColumn.m in Sources */,
+ F7D397A5054685AE00BD181E /* LiInspectorView.m in Sources */,
+ F7D397A6054685AE00BD181E /* LiFilterDescription.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F7D3979C054685AE00BD181E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F7D3977F054685A000BD181E /* LiBackend */;
+ targetProxy = F7D397680546855800BD181E /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ F7585F9704EF2FD800000104 /* LiBackend.scriptTerminology */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F7585F9504EF2FC500000104 /* LiBackend.scriptTerminology */,
+ );
+ name = LiBackend.scriptTerminology;
+ sourceTree = SOURCE_ROOT;
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 2898673D095DAB1500B5DC99 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_ENABLE_SSE3_EXTENSIONS = YES;
+ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = LiBackend/LiBackend.h;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = "";
+ INFOPLIST_FILE = LiBackend/Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = "";
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0x10000000,
+ );
+ PRODUCT_NAME = LiBackend;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = framework;
+ ZERO_LINK = YES;
+ };
+ name = Development;
+ };
+ 2898673E095DAB1500B5DC99 /* Deployment */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CC = "/usr/bin/gcc-3.3";
+ COPY_PHASE_STRIP = YES;
+ CPLUSPLUS = "/usr/bin/g++-3.3";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_PREFIX_HEADER = LiBackend/LiBackend.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 = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = "";
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0x10000000,
+ );
+ PRODUCT_NAME = LiBackend;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = framework;
+ ZERO_LINK = NO;
+ };
+ name = Deployment;
+ };
+ 2898673F095DAB1500B5DC99 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CC = "/usr/bin/gcc-3.3";
+ CPLUSPLUS = "/usr/bin/g++-3.3";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_PREFIX_HEADER = LiBackend/LiBackend.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 = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = "";
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0x10000000,
+ );
+ PRODUCT_NAME = LiBackend;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = framework;
+ };
+ name = Default;
+ };
+ 28986741095DAB1500B5DC99 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = LiPlugin/LiPlugin.h;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = LiPlugin/Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0x17000000,
+ );
+ PRODUCT_NAME = LiPlugin;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = framework;
+ ZERO_LINK = YES;
+ };
+ name = Development;
+ };
+ 28986742095DAB1500B5DC99 /* Deployment */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CC = "/usr/bin/gcc-3.3";
+ COPY_PHASE_STRIP = YES;
+ CPLUSPLUS = "/usr/bin/g++-3.3";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_PREFIX_HEADER = LiPlugin/LiPlugin.h;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0x17000000,
+ );
+ OTHER_LIBTOOL_FLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRINCIPAL_CLASS = "";
+ PRODUCT_NAME = LiPlugin;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = framework;
+ ZERO_LINK = NO;
+ };
+ name = Deployment;
+ };
+ 28986743095DAB1500B5DC99 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CC = "/usr/bin/gcc-3.3";
+ CPLUSPLUS = "/usr/bin/g++-3.3";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_PREFIX_HEADER = LiPlugin/LiPlugin.h;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0x17000000,
+ );
+ OTHER_LIBTOOL_FLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRINCIPAL_CLASS = "";
+ PRODUCT_NAME = LiPlugin;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = framework;
+ };
+ name = Default;
+ };
+ 28986745095DAB1500B5DC99 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Development;
+ };
+ 28986746095DAB1500B5DC99 /* Deployment */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Deployment;
+ };
+ 28986747095DAB1500B5DC99 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Default;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 2898673C095DAB1500B5DC99 /* Build configuration list for PBXNativeTarget "LiBackend" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2898673D095DAB1500B5DC99 /* Development */,
+ 2898673E095DAB1500B5DC99 /* Deployment */,
+ 2898673F095DAB1500B5DC99 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 28986740095DAB1500B5DC99 /* Build configuration list for PBXNativeTarget "LiPlugin" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 28986741095DAB1500B5DC99 /* Development */,
+ 28986742095DAB1500B5DC99 /* Deployment */,
+ 28986743095DAB1500B5DC99 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 28986744095DAB1500B5DC99 /* Build configuration list for PBXProject "LiFrameworks" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 28986745095DAB1500B5DC99 /* Development */,
+ 28986746095DAB1500B5DC99 /* Deployment */,
+ 28986747095DAB1500B5DC99 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/Frameworks/LiPlugin/Info.plist b/Frameworks/LiPlugin/Info.plist
new file mode 100644
index 0000000..6510d5d
--- /dev/null
+++ b/Frameworks/LiPlugin/Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>LiPlugin</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.kublai.Liaison.LiPlugin</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string></string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string></string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>0.4d</string>
+</dict>
+</plist>
diff --git a/Frameworks/LiPlugin/LiBrowserColumn.h b/Frameworks/LiPlugin/LiBrowserColumn.h
new file mode 100644
index 0000000..629e1c3
--- /dev/null
+++ b/Frameworks/LiPlugin/LiBrowserColumn.h
@@ -0,0 +1,59 @@
+//
+// LiBrowserColumn.h
+// Liaison
+//
+// Created by Brian Cully on Thu May 15 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface LiBrowserColumn : NSObject
+{
+ id theIdentifier;
+
+ NSString *theColumnName;
+ NSCell *theCell;
+ NSNumber *theWidth;
+ SEL theGetMethod;
+ SEL theSetMethod;
+ SEL theCompareMethod;
+ BOOL theColumnIsEditable;
+ BOOL theColumnIsResizable;
+ BOOL theColumnShowsHeader;
+}
+
+- (id)objectForRecord: (id)aRecord;
+- (void)setObject: (id)anObject forRecord: (id)aRecord;
+@property (getter=resizable,setter=setResizable:) BOOL theColumnIsResizable;
+@property (getter=setMethod,setter=setSetMethod:) SEL theSetMethod;
+@property (retain,getter=name) NSString *theColumnName;
+@property (getter=compareMethod,setter=setCompareMethod:) SEL theCompareMethod;
+@property (getter=showsHeader,setter=setShowsHeader:) BOOL theColumnShowsHeader;
+@property (retain,getter=identifier) id theIdentifier;
+@property (retain,getter=width) NSNumber *theWidth;
+@property (getter=editable,setter=setEditable:) BOOL theColumnIsEditable;
+@property (getter=getMethod,setter=setGetMethod:) SEL theGetMethod;
+@property (retain,getter=cell) NSCell *theCell;
+@end
+
+@interface LiBrowserColumn (Accessors)
+- (id)identifier;
+- (void)setIdentifier: (id)anIdentifier;
+- (NSString *)name;
+- (void)setName: (NSString *)aName;
+- (BOOL)editable;
+- (void)setEditable: (BOOL)editable;
+- (BOOL)resizable;
+- (void)setResizable: (BOOL)resizable;
+- (BOOL)showsHeader;
+- (void)setShowsHeader: (BOOL)showHeader;
+- (NSCell *)cell;
+- (void)setCell: (NSCell *)aCell;
+- (SEL)getMethod;
+- (void)setGetMethod: (SEL)aSelector;
+- (SEL)setMethod;
+- (void)setSetMethod: (SEL)aSelector;
+- (SEL)compareMethod;
+- (void)setCompareMethod: (SEL)aSelector;
+- (NSNumber *)width;
+- (void)setWidth: (NSNumber *)aWidth;
+@end
diff --git a/Frameworks/LiPlugin/LiBrowserColumn.m b/Frameworks/LiPlugin/LiBrowserColumn.m
new file mode 100644
index 0000000..471d0ee
--- /dev/null
+++ b/Frameworks/LiPlugin/LiBrowserColumn.m
@@ -0,0 +1,150 @@
+//
+// LiBrowserColumn.m
+// Liaison
+//
+// Created by Brian Cully on Thu May 15 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "LiBrowserColumn.h"
+
+@implementation LiBrowserColumn
+- (id)init
+{
+ self = [super init];
+
+ [self setResizable: YES];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [self setName: nil];
+ [super dealloc];
+}
+
+- (id)objectForRecord: (id)aRecord
+{
+ return [aRecord performSelector: [self getMethod]];
+}
+
+- (void)setObject: (id)anObject forRecord: (id)aRecord
+{
+ [aRecord performSelector: [self setMethod] withObject: anObject];
+}
+@synthesize theCell;
+@synthesize theIdentifier;
+@synthesize theWidth;
+@synthesize theColumnName;
+@end
+
+@implementation LiBrowserColumn (Accessors)
+- (id)identifier
+{
+ return theIdentifier;
+}
+
+- (void)setIdentifier: (id)anIdentifier
+{
+ [anIdentifier retain];
+ [theIdentifier release];
+ theIdentifier = anIdentifier;
+}
+
+- (NSString *)name
+{
+ return theColumnName;
+}
+
+- (void)setName: (NSString *)aName
+{
+ [aName retain];
+ [theColumnName release];
+ theColumnName = aName;
+}
+
+- (BOOL)editable
+{
+ return theColumnIsEditable;
+}
+
+- (void)setEditable: (BOOL)editable
+{
+ theColumnIsEditable = editable;
+}
+
+- (BOOL)resizable
+{
+ return theColumnIsResizable;
+}
+
+- (void)setResizable: (BOOL)resizable
+{
+ theColumnIsResizable = resizable;
+}
+
+- (BOOL)showsHeader
+{
+ return theColumnShowsHeader;
+}
+
+- (void)setShowsHeader: (BOOL)showHeader
+{
+ theColumnShowsHeader = showHeader;
+}
+
+- (NSCell *)cell
+{
+ return theCell;
+}
+
+- (void)setCell: (NSCell *)aCell
+{
+ [aCell retain];
+ [theCell release];
+ theCell = aCell;
+}
+
+- (SEL)getMethod
+{
+ return theGetMethod;
+}
+
+- (void)setGetMethod: (SEL)aSelector
+{
+ theGetMethod = aSelector;
+}
+
+- (SEL)setMethod
+{
+ return theSetMethod;
+}
+
+- (void)setSetMethod: (SEL)aSelector
+{
+ theSetMethod = aSelector;
+}
+
+- (SEL)compareMethod
+{
+ return theCompareMethod;
+}
+
+- (void)setCompareMethod: (SEL)aSelector
+{
+ theCompareMethod = aSelector;
+}
+
+- (NSNumber *)width
+{
+ return theWidth;
+}
+
+- (void)setWidth: (NSNumber *)aWidth
+{
+ [aWidth retain];
+ [theWidth release];
+ theWidth = aWidth;
+}
+@end
diff --git a/Frameworks/LiPlugin/LiFilterDescription.h b/Frameworks/LiPlugin/LiFilterDescription.h
new file mode 100644
index 0000000..a26736e
--- /dev/null
+++ b/Frameworks/LiPlugin/LiFilterDescription.h
@@ -0,0 +1,40 @@
+//
+// LiFilterDescription.h
+// LiFrameworks
+//
+// Created by Brian Cully on Sat Aug 23 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface LiFilterDescription : NSObject
+{
+ NSCell *theValueEditorCell;
+ NSDictionary *theCompareOperators;
+ NSString *theName;
+ SEL theMethod;
+}
++ (id)descriptionForMethod: (SEL)aMethod
+ name: (NSString *)aName
+ compareOperators: (NSDictionary *)someOperators
+ valueEditorCell: (NSCell *)aCell;
+
+- (id)initWithMethod: (SEL)aMethod
+ name: (NSString *)aName
+ compareOperators: (NSDictionary *)someOperators
+ valueEditorCell: (NSCell *)aCell;
+@property (getter=method,setter=setMethod:) SEL theMethod;
+@property (retain,getter=name) NSString *theName;
+@property (retain,getter=valueEditorCell) NSCell *theValueEditorCell;
+@property (retain,getter=compareOperators) NSDictionary *theCompareOperators;
+@end
+
+@interface LiFilterDescription (Accessors)
+- (SEL)method;
+- (void)setMethod: (SEL)aMethod;
+- (NSString *)name;
+- (void)setName: (NSString *)aName;
+- (NSDictionary *)compareOperators;
+- (void)setCompareOperators: (NSDictionary *)someOperators;
+- (NSCell *)valueEditorCell;
+- (void)setValueEditorCell: (NSCell *)aCell;
+@end
diff --git a/Frameworks/LiPlugin/LiFilterDescription.m b/Frameworks/LiPlugin/LiFilterDescription.m
new file mode 100644
index 0000000..d5d38da
--- /dev/null
+++ b/Frameworks/LiPlugin/LiFilterDescription.m
@@ -0,0 +1,113 @@
+//
+// LiFilterDescription.m
+// LiFrameworks
+//
+// Created by Brian Cully on Sat Aug 23 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "LiFilterDescription.h"
+
+@implementation LiFilterDescription
++ (id)descriptionForMethod: (SEL)aMethod
+ name: (NSString *)aName
+ compareOperators: (NSDictionary *)someOperators
+ valueEditorCell: (NSCell *)aCell
+{
+ id tmpDesc;
+
+ tmpDesc = [[self alloc] initWithMethod: aMethod
+ name: aName
+ compareOperators: someOperators
+ valueEditorCell: aCell];
+ return [tmpDesc autorelease];
+}
+
+- (id)init
+{
+ NSException *exception;
+
+ exception = [NSException exceptionWithName: @"LiNoInitException"
+ reason: @"[LiFilterDescription init] not supported"
+ userInfo: nil];
+ [exception raise];
+
+ return nil;
+}
+
+- (void)dealloc
+{
+ [self setMethod: nil];
+ [self setName: nil];
+ [self setCompareOperators: nil];
+ [self setValueEditorCell: nil];
+
+ [super dealloc];
+}
+
+- (id)initWithMethod: (SEL)aMethod
+ name: (NSString *)aName
+ compareOperators: (NSDictionary *)someOperators
+ valueEditorCell: (NSCell *)aCell
+{
+ self = [super init];
+
+ [self setMethod: aMethod];
+ [self setName: aName];
+ [self setCompareOperators: someOperators];
+ [self setValueEditorCell: aCell];
+
+ return self;
+}
+@synthesize theName;
+@synthesize theValueEditorCell;
+@synthesize theCompareOperators;
+@end
+
+@implementation LiFilterDescription (Accessors)
+- (SEL)method
+{
+ return theMethod;
+}
+
+- (void)setMethod: (SEL)aMethod
+{
+ theMethod = aMethod;
+}
+
+- (NSString *)name
+{
+ return theName;
+}
+
+- (void)setName: (NSString *)aName
+{
+ [aName retain];
+ [theName release];
+ aName = theName;
+}
+
+- (NSDictionary *)compareOperators
+{
+ return theCompareOperators;
+}
+
+- (void)setCompareOperators: (NSDictionary *)someOperators
+{
+ [someOperators retain];
+ [theCompareOperators release];
+ theCompareOperators = someOperators;
+}
+
+- (NSCell *)valueEditorCell
+{
+ return theValueEditorCell;
+}
+
+- (void)setValueEditorCell: (NSCell *)aCell
+{
+ [aCell retain];
+ [theValueEditorCell release];
+ theValueEditorCell = aCell;
+}
+@end \ No newline at end of file
diff --git a/Frameworks/LiPlugin/LiInspectorView.h b/Frameworks/LiPlugin/LiInspectorView.h
new file mode 100644
index 0000000..f6cbd69
--- /dev/null
+++ b/Frameworks/LiPlugin/LiInspectorView.h
@@ -0,0 +1,40 @@
+//
+// LiInspectorView.h
+// Liaison
+//
+// Created by Brian Cully on Wed May 21 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface LiInspectorView : NSObject
+{
+ id theIdentifier;
+
+ NSString *theName;
+ NSImage *theImage;
+ NSView *theView;
+ BOOL theViewIsHorizontallyResizable, theViewisVerticallyResizable;
+ NSSize theViewSize;
+}
+@property (retain,getter=image) NSImage *theImage;
+@property (retain,getter=view) NSView *theView;
+@property (retain,getter=identifier) id theIdentifier;
+@property (retain,getter=name) NSString *theName;
+@end
+
+@interface LiInspectorView (Accessors)
+- (id)identifier;
+- (void)setIdentifier: (id)anIdentifier;
+- (NSString *)name;
+- (void)setName: (NSString *)aName;
+- (NSImage *)image;
+- (void)setImage: (NSImage *)anImage;
+- (NSView *)view;
+- (void)setView: (NSView *)aView;
+- (BOOL)isHorizontallyResizable;
+- (void)setIsHorizontallyResizable: (BOOL)resizable;
+- (BOOL)isVerticallyResizable;
+- (void)setIsVerticallyResizable: (BOOL)resizable;
+- (NSSize)viewSize;
+- (void)setViewSize: (NSSize)aSize;
+@end
diff --git a/Frameworks/LiPlugin/LiInspectorView.m b/Frameworks/LiPlugin/LiInspectorView.m
new file mode 100644
index 0000000..c5279cd
--- /dev/null
+++ b/Frameworks/LiPlugin/LiInspectorView.m
@@ -0,0 +1,96 @@
+//
+// LiInspectorView.m
+// Liaison
+//
+// Created by Brian Cully on Wed May 21 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "LiInspectorView.h"
+
+@implementation LiInspectorView
+@synthesize theImage;
+@synthesize theView;
+@synthesize theIdentifier;
+@synthesize theName;
+@end
+
+@implementation LiInspectorView (Accessors)
+- (id)identifier
+{
+ return theIdentifier;
+}
+
+- (void)setIdentifier: (id)anIdentifier
+{
+ [anIdentifier retain];
+ [theIdentifier release];
+ theIdentifier = anIdentifier;
+}
+
+- (NSString *)name
+{
+ return theName;
+}
+
+- (void)setName: (NSString *)aName
+{
+ [aName retain];
+ [theName release];
+ theName = aName;
+}
+
+- (NSImage *)image
+{
+ return theImage;
+}
+
+- (void)setImage: (NSImage *)anImage
+{
+ [anImage retain];
+ [theImage release];
+ theImage = anImage;
+}
+
+- (NSView *)view
+{
+ return theView;
+}
+
+- (void)setView: (NSView *)aView
+{
+ [aView retain];
+ [theView release];
+ theView = aView;
+}
+
+- (BOOL)isHorizontallyResizable
+{
+ return theViewIsHorizontallyResizable;
+}
+
+- (void)setIsHorizontallyResizable: (BOOL)resizable
+{
+ theViewIsHorizontallyResizable = resizable;
+}
+
+- (BOOL)isVerticallyResizable
+{
+ return theViewisVerticallyResizable;
+}
+
+- (void)setIsVerticallyResizable: (BOOL)resizable
+{
+ theViewisVerticallyResizable = resizable;
+}
+
+- (NSSize)viewSize
+{
+ return theViewSize;
+}
+
+- (void)setViewSize: (NSSize)aSize
+{
+ theViewSize = aSize;
+}
+@end
diff --git a/Frameworks/LiPlugin/LiPlugin.h b/Frameworks/LiPlugin/LiPlugin.h
new file mode 100644
index 0000000..28d236f
--- /dev/null
+++ b/Frameworks/LiPlugin/LiPlugin.h
@@ -0,0 +1,41 @@
+/*
+ * LiPlugin.h
+ * Liaison
+ *
+ * Created by Brian Cully on Tue May 13 2003.
+ * Copyright (c) 2003 Brian Cully. All rights reserved.
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+
+#import <LiPlugin/LiBrowserColumn.h>
+#import <LiPlugin/LiInspectorView.h>
+#import <LiPlugin/LiFilterDescription.h>
+
+#import <LiBackend/LiBackend.h>
+
+@protocol LiFileStorePlugin
++ (NSBundle *)bundle;
++ (void)setBundle: (NSBundle *)aBundle;
+
+- (void)initFileStore;
+- (LiFileStore *)fileStore;
+@end
+
+@protocol LiBrowserPlugin
++ (NSBundle *)bundle;
++ (void)setBundle: (NSBundle *)aBundle;
+
+- (NSArray *)columns;
+- (NSDictionary *)filterDescriptions;
+@end
+
+@protocol LiInspectorPlugin
++ (NSBundle *)bundle;
++ (void)setBundle: (NSBundle *)aBundle;
+
+- (NSArray *)allInspectorViews;
+- (NSArray *)inspectorViewsForFile: (LiFileHandle *)aFile;
+- (void)setFile: (LiFileHandle *)aFile;
+@end \ No newline at end of file
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 <LiFileStorePlugin>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 <netinet/in.h>
+#import <string.h>
+#import <sys/socket.h>
+#import <unistd.h>
+
+@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
--- /dev/null
+++ b/Liaison/English.lproj/CopyPanel.nib/Download_StopPressed.tiff
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>112 70 356 240 0 0 1600 1178 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>16</key>
+ <string>690 764 220 82 0 0 1600 1178 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>326.0</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>16</integer>
+ <integer>28</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>7B28</string>
+</dict>
+</plist>
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
--- /dev/null
+++ b/Liaison/English.lproj/CopyPanel.nib/objects.nib
Binary files differ
diff --git a/Liaison/English.lproj/InfoPlist.strings b/Liaison/English.lproj/InfoPlist.strings
new file mode 100644
index 0000000..72d0e56
--- /dev/null
+++ b/Liaison/English.lproj/InfoPlist.strings
Binary files 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html lang="en">
+<head>
+ <title>Liaison Help</title>
+ <meta name="generator" content="BBEdit 6.5">
+ <meta name="AppleTitle" content="Liaison Help">
+ <meta name="AppleIcon" content="Liaison%20Help/images/Liaison_small.png">
+ <meta name="AppleFont" content="Lucida Grande,Helvetica">
+ <meta name="Description" content="Help for Liaison 0.4">
+ <meta name="keywords" content="laison">
+</head>
+
+<frameset cols="170,*" framespacing="0" border="0" frameborder="0" framespacing="0">
+ <frame name="navigationFrame" marginheight="0" marginwidth="0" scrolling="AUTO" src="pages/navigation.html">
+ <frame name="contentsFrame" marginheight="0" marginwidth="0" scrolling="AUTO" src="pages/overview.html">
+</frameset>
+</html> \ 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
--- /dev/null
+++ b/Liaison/English.lproj/Liaison Help/images/Liaison.png
Binary files 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
--- /dev/null
+++ b/Liaison/English.lproj/Liaison Help/images/Liaison_small.png
Binary files 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html lang="en">
+<head>
+ <title>Known Bugs</title>
+ <meta name="generator" content="BBEdit 6.5">
+</head>
+
+<body>
+<h1>Known Bugs</h1>
+<ul>
+ <li>Help is woefully incomplete.</li>
+ <li>Find panel doesn't do anything.</li>
+ <li>Applescript support isn't very useful.</li>
+ <li>The "Open" and "Show in Finder" menu items don't dim properly when the file table
+ isn't the first responder.</li>
+ <li>The view options do not update based on key window.</li>
+ <li>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?)</li>
+</ul>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html lang="en">
+<head>
+ <title>Frequently Asked Questions</title>
+ <meta name="generator" content="BBEdit 6.5">
+</head>
+
+<body>
+ <h1>Frequently Asked Questions</h1>
+
+ <p>Click on a topic to the left to find out more about it, or click on a
+ question below to find the answer.</p>
+
+ <dt><strong>How do I use groups?</strong></dt>
+ <dd>
+ <p>You can use <a href="glossary.html#group">groups</a> 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.</p>
+
+ <table border="0" cellpadding="5" cellspacing="0" width="100%" bgcolor="#fff8dc">
+ <tr>
+ <td colspan=2><strong>To create a group:</strong></td>
+ </tr>
+ <tr>
+ <td>
+ <strong>1</strong>
+ </td>
+ <td>
+ Select "New group" from the File menu.
+ </td>
+ </tr>
+ <tr>
+ <td colspan=2><strong>To add files to a group:</strong></td>
+ </tr>
+ <tr>
+ <td>
+ <strong>1</strong>
+ </td>
+ <td>
+ Select the list of files in the library, and drag
+ them to the newly created group.
+ </td>
+ </tr>
+ <tr>
+ <td colspan=2><strong>To rename a group:</strong></td>
+ </tr>
+ <tr>
+ <td>
+ <strong>1</strong>
+ </td>
+ <td>Double-click its entry in the group list and type in a new name.</td>
+ </tr>
+ </table>
+ </dd>
+
+ <dt><strong>How do I share my files?</strong></dt>
+ <dd>
+ <p>You can share any file in your library by putting it in a group.</p>
+ </dd>
+
+ <dt><strong>How do I download a shared file?</strong></dt>
+ <dd>
+ <p>Double-click on it, or drag it from Liaison to the Finder.</p>
+ </dd>
+
+ <dt><strong>What is meta-data and how do I edit it?</strong></dt>
+ <dd>
+ <p>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.</p>
+
+ <p>To edit meta-data, you can double click on a field in the file list,
+ or edit it via the inspector.</p>
+ </dd>
+
+ <p><font size="-2">&copy;2003 Brian Cully</font>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html lang="en">
+<head>
+ <title>Glossary</title>
+ <meta name="generator" content="BBEdit 6.5">
+</head>
+
+<body>
+ <h1>Glossary</h1>
+ <ul>
+ <li>
+ <dt><a id="group">group</a></dt>
+ <dd>Groups are lists of files that you can create to organize your file
+ library or to share with other Liaison users.</dd>
+ </li>
+ <li>
+ <dt><a id="LAN">LAN</a></dt>
+ <dd>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&trade;.</dd>
+ </li>
+ <li>
+ <dt><a id="library">library</a></dt>
+ <dd>Libraries are lists of files on a computer that Liaison knows about.</dd>
+ </li>
+ </ul>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html lang="en">
+<head>
+ <title>Navigation</title>
+ <meta name="generator" content="BBEdit 6.5">
+</head>
+
+<body>
+ <center><img src="../images/Liaison.png" alt="" width="128" height="128"></center>
+ <ul>
+ <li><a href="overview.html" target="contentsFrame">Overview</a></li>
+ <li><a href="faq.html" target="contentsFrame">Frequently Asked Questions</a></li>
+ <li><a href="whatsnew.html" target="contentsFrame">What's new</a></li>
+ <li><a href="bugs.html" target="contentsFrame">Known Bugs</a></li>
+ <li><a href="todo.html" target="contentsFrame">To Do</a></li>
+ <li><a href="http://www.kublai.com/~shmit/software/Liaison/" target="new">Website</a></li>
+ </ul>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html lang="en">
+<head>
+ <title>Overview</title>
+ <meta name="generator" content="BBEdit 6.5">
+</head>
+
+<body>
+ <h1>Overview</h1>
+
+ <p>Liaison is a file browser that lets your organize all your files. Here are some of the
+ things you can do with Liaison.</p>
+
+ <ul>
+ <li>
+ <p>Add files to your library. When you add files to your
+ <a href="glossary.html#library">library</a>, you can open them,
+ edit their meta-data, and even share them with other Liaison users.</p>
+ </li>
+ <li>
+ <p>Organize your file library. Once you add files to your library, you can organize
+ them into <a href="glossary.html#group">groups</a>. You can create groups to organize
+ files by theme, location, content, or anything else you can imagine.</p>
+ </li>
+ <li>
+ <p>Share your file library with other people. File sharing allows you to browse your
+ library across multiple computers on your <a href="glossary.html#LAN">LAN</a> and
+ download them to another computer. File sharing requires a copy of Liaison on each
+ computer which is used to share files.</p>
+ </li>
+ </ul>
+
+ <p>If you want to learn more about any of this, click a topic on the left.</p>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html lang="en">
+<head>
+ <title>To Do</title>
+ <meta name="generator" content="BBEdit 6.5">
+</head>
+
+<body>
+<h1>To Do</h1>
+
+<ul>
+ <li>Application Wizard for first-time users.</li>
+ <li>Smart groups / saved searches.</li>
+ <li>Better preferences system. Perhaps Omni's?</li>
+ <li>Group level access control for sharing.</li>
+ <li>Password protected libraries.</li>
+ <li>Directory tracking.</li>
+ <li>Be able to send whole directories, most especially for bundles.</li>
+ <li>Implement file categories and browser.</li>
+ <li>Need better formatters for date information in the browser.</li>
+ <li>Group inspector.</li>
+</ul>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html lang="en">
+<head>
+ <title>What's New</title>
+ <meta name="generator" content="BBEdit 6.5">
+</head>
+
+<body>
+<h1>What's new</h1>
+<h3>Since 0.4.2:</h3>
+<ul>
+ <li>Fixed a bug with the load sheet not closing properly.</li>
+ <li>You can now drag whole directories onto the group list or file list to add the files
+ in them to Liaison.</li>
+ <li>Drag-and-Drop of promised files works.</li>
+ <li>The table view no longer scrolls to the top of the list after you remove files.</li>
+ <li>You can drag files from Liaison to the finder now.</li>
+ <li>The shared inspector now updates when you make other windows key.</li>
+ <li>No longer cache icon information. This slows everything down a tiny bit, but saves
+ a huge amount of memory.</li>
+ <li>The icon that signifies an unlocatable file now updates automatically.</li>
+</ul>
+
+<h3>Since 0.4.1:</h3>
+<ul>
+ <li>Added help.</li>
+ <li>Project split up for future open source plans.</li>
+ <li>A lot of old code culled.</li>
+ <li>You can unsort your file list by clicking on the header.</li>
+ <li>Editing files now works consistently with the sort and search.</li>
+ <li>Fixed many bugs where the file selection would change unexpectedly.</li>
+ <li>Fixed bugs with groups being assigned incorrectly.</li>
+ <li>Added contextual menus to the file and group panels.</li>
+ <li>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.</li>
+</ul>
+
+<h3>Since 0.4:</h3>
+<ul>
+ <li>Many GUI fixes and enhancements.</li>
+ <li>Major speed improvements for loading large amounts of files at a time.</li>
+</ul>
+
+<h3>Since 0.3.3a:</h3>
+<ul>
+ <li>The file database has been ripped to shreds and rewritten from scratch. The new one
+ is much more extensible and faster overall.</li>
+ <li>Application is now prebound for faster launch times.</li>
+ <li>Network code has been rewritten to take advantage of the new file database, and is
+ much more connection friendly now for persistant connections.</li>
+ <li>Loading files into your library should be substantially faster. However, you cannot
+ load more than about one thousand at a time.</li>
+ <li>File selection is saved as you navigate through groups, if possible.</li>
+ <li>The zoom box works properly (or mostly properly) everywhere.</li>
+ <li>Preliminary AppleScript support has been added. It's not very useful, but it's there.</li>
+ <li>You are no longer able to group remote file stores within an over-all "Rendezvous"
+ group.</li>
+ <li>Some minor fixes for Panther.</li>
+ <li>BUG: The "Add Files to Library" menu item doesn't get properly dimmed.</li>
+</ul>
+
+<h3>What's new since 0.3.2a:</h3>
+<ul>
+ <li>Application starts again.</li>
+</ul>
+
+<h3>Since 0.3.1a:</h3>
+<ul>
+ <li>Fix date sorts.</li>
+ <li>Make string searches case insensitive.</li>
+ <li>Add a plugin architecture for the file browser and inspector.</li>
+ <li>Add a Find panel stub so I can work out the interface.</li>
+ <li>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.</li>
+ <li>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!</li>
+ <li>If a file change can't happen, a sheet is displayed.</li>
+</ul>
+
+<h3>Since 0.3a:</h3>
+<ul>
+ <li>You can set or delete HFS file creator codes via the inspector.</li>
+ <li>Add columns for last modified time, creation time, and file size.</li>
+ <li>Column sizes and order in the file list are remembered now.</li>
+ <li>Added a "view options" dialog box, under the view menu. You can use
+ this to set which columns are displayed.</li>
+ <li>The delete key and the "Delete" item under the "Edit" menu work now.</li>
+ <li>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.</li>
+ <li>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.</li>
+ <li>Display scroll bars when the group list is longer than the view.</li>
+ <li>When reloading a file in the download panel, don't create a new status
+ view, just re-use the old one.</li>
+ <li>If the hostname changes you can still download files properly.</li>
+</ul>
+
+<h3>Since 0.2.1a:</h3>
+<ul>
+ <li>Use aliases instead of paths as the database key. Files can now be
+ renamed without being lost to Liaison.
+ <div class="warning">
+ <strong>WARNING:</strong> 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.</li>
+ </div>
+ <li>Initialize the local group name if there's no existing library.</li>
+ <li>Add a little "!" icon for files that can't be located.</li>
+ <li>Edits in the file table and the inspector are now written to disk.</li>
+</ul>
+
+<h3>Since 0.2a:</h3>
+<ul>
+ <li>Editing a group doesn't clear the icon anymore.</li>
+ <li>Only draw the vertical grid; since we have alterntating row colors, we
+ don't need the horizontal grid.</li>
+ <li>File selection is saved between searches in the toolbar and sorts (from
+ clicking on the table header).</li>
+ <li>Empty groups are removed from the remote group list.</li>
+ <li>Add a menu item under the help menu to go to Liaison's web site.</li>
+ <li>Clear selection when group is changed.</li>
+</ul>
+
+<h3>Since 0.1.3a:</h3>
+<ul>
+ <li>File list is editable now. Changes still aren't written to disk.</li>
+ <li>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.</li>
+ <li>File list has striped rows.</li>
+ <li>File extension is now relegated soley to the "type" column. The other
+ way just doesn't make sense.</li>
+ <li>"Reveal in Finder" tool bar icon.</li>
+ <li>Added "Get Info" under the file menu. This duplicates the "Inspector" menu
+ under the window menu.</li>
+</ul>
+
+<h3>Since 0.1.2a:</h3>
+<ul>
+ <li>A few new toolbar icons.</li>
+ <li>HFS type/creator codes are visible on remote hosts.</li>
+ <li>Writer threads are cleaned up properly.</li>
+ <li>The hooks for the Edit menu actions are in.</li>
+ <li>Remote group browsing works again.</li>
+</ul>
+
+<h3>Since 0.1.1a:</h3>
+<ul>
+ <li>File copying works again.</li>
+</ul>
+
+<h3>Since 0.1a:</h3>
+<ul>
+ <li>I have an icon! (However, I do not have Photoshop skillz).</li>
+ <li>Host name changes now update across the network.
+ (Actually, this needs work. I doubt a file copy will work without
+ restarting.)</li>
+ <li>Fixed a bug with the preferences always thinking the hostname had
+ changed.</li>
+</ul>
+</body>
+</html>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Classes</key>
+ <dict>
+ <key>NSApplication</key>
+ <dict>
+ <key>Description</key>
+ <string>Liaison's top level scripting object.</string>
+ <key>Name</key>
+ <string>application</string>
+ <key>PluralName</key>
+ <string>applications</string>
+ </dict>
+ </dict>
+ <key>Description</key>
+ <string>Liaison classes.</string>
+ <key>Name</key>
+ <string>Liaison suite</string>
+</dict>
+</plist>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>JavaSourceSubpath</key>
+ <string>_LoadPanel_EOArchive_English.java</string>
+</dict>
+</plist>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>89 245 356 240 0 0 1600 1178 </string>
+ <key>IBFramework Version</key>
+ <string>291.0</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>6</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>6L60</string>
+</dict>
+</plist>
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
--- /dev/null
+++ b/Liaison/English.lproj/LoadPanel.nib/objects.nib
Binary files 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>17 80 461 291 0 0 1024 746 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>29</key>
+ <string>5 1124 310 44 0 0 1600 1178 </string>
+ <key>377</key>
+ <string>711 772 176 64 0 0 1600 1178 </string>
+ <key>700</key>
+ <string>287 435 224 118 0 0 1024 746 </string>
+ <key>773</key>
+ <string>974 1012 129 130 0 0 1600 1178 </string>
+ <key>786</key>
+ <string>981 899 106 80 0 0 1600 1178 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>349.0</string>
+ <key>IBOldestOS</key>
+ <integer>3</integer>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>664</integer>
+ <integer>773</integer>
+ <integer>786</integer>
+ <integer>21</integer>
+ <integer>377</integer>
+ <integer>29</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>7B85</string>
+</dict>
+</plist>
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
--- /dev/null
+++ b/Liaison/English.lproj/MainMenu.nib/keyedobjects.nib
Binary files 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>50 54 356 240 0 0 1600 1178 </string>
+ <key>IBFramework Version</key>
+ <string>326.0</string>
+ <key>IBGroupedObjects</key>
+ <dict>
+ <key>0</key>
+ <array>
+ <string>39</string>
+ <string>40</string>
+ <string>49</string>
+ </array>
+ <key>1</key>
+ <array>
+ <string>21</string>
+ <string>22</string>
+ </array>
+ <key>2</key>
+ <array>
+ <string>34</string>
+ <string>35</string>
+ <string>36</string>
+ </array>
+ </dict>
+ <key>IBLastGroupID</key>
+ <string>3</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>5</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>7B28</string>
+</dict>
+</plist>
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
--- /dev/null
+++ b/Liaison/English.lproj/PreferencesWindow.nib/objects.nib
Binary files 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 <dirent.h>
+#include <sys/types.h>
+
+// 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 <NSDraggingInfo>)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 <NSDraggingInfo>)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 <LiBrowserPlugin> *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 <NSCoding>
+{
+ 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 <NSDraggingInfo>)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 <NSDraggingInfo>)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
--- /dev/null
+++ b/Liaison/Images/Add.tiff
Binary files differ
diff --git a/Liaison/Images/AddFiles.tiff b/Liaison/Images/AddFiles.tiff
new file mode 100644
index 0000000..7fe8e48
--- /dev/null
+++ b/Liaison/Images/AddFiles.tiff
Binary files differ
diff --git a/Liaison/Images/AddGroup.tiff b/Liaison/Images/AddGroup.tiff
new file mode 100644
index 0000000..b8753d7
--- /dev/null
+++ b/Liaison/Images/AddGroup.tiff
Binary files differ
diff --git a/Liaison/Images/Download_Reload.tiff b/Liaison/Images/Download_Reload.tiff
new file mode 100644
index 0000000..f4cf9ab
--- /dev/null
+++ b/Liaison/Images/Download_Reload.tiff
Binary files differ
diff --git a/Liaison/Images/Download_ReloadPressed.tiff b/Liaison/Images/Download_ReloadPressed.tiff
new file mode 100644
index 0000000..bcd6900
--- /dev/null
+++ b/Liaison/Images/Download_ReloadPressed.tiff
Binary files differ
diff --git a/Liaison/Images/Download_Reveal.tiff b/Liaison/Images/Download_Reveal.tiff
new file mode 100644
index 0000000..c090901
--- /dev/null
+++ b/Liaison/Images/Download_Reveal.tiff
Binary files differ
diff --git a/Liaison/Images/Download_RevealPressed.tiff b/Liaison/Images/Download_RevealPressed.tiff
new file mode 100644
index 0000000..13f68a5
--- /dev/null
+++ b/Liaison/Images/Download_RevealPressed.tiff
Binary files differ
diff --git a/Liaison/Images/Download_Stop.tiff b/Liaison/Images/Download_Stop.tiff
new file mode 100644
index 0000000..156869d
--- /dev/null
+++ b/Liaison/Images/Download_Stop.tiff
Binary files differ
diff --git a/Liaison/Images/Download_StopPressed.tiff b/Liaison/Images/Download_StopPressed.tiff
new file mode 100644
index 0000000..c9ee4a1
--- /dev/null
+++ b/Liaison/Images/Download_StopPressed.tiff
Binary files differ
diff --git a/Liaison/Images/File Icons/Liaison.icns b/Liaison/Images/File Icons/Liaison.icns
new file mode 100644
index 0000000..d1b79dc
--- /dev/null
+++ b/Liaison/Images/File Icons/Liaison.icns
Binary files differ
diff --git a/Liaison/Images/LeftSearchCap.tiff b/Liaison/Images/LeftSearchCap.tiff
new file mode 100644
index 0000000..51664e1
--- /dev/null
+++ b/Liaison/Images/LeftSearchCap.tiff
Binary files differ
diff --git a/Liaison/Images/NormalMailbox.tiff b/Liaison/Images/NormalMailbox.tiff
new file mode 100644
index 0000000..351b06b
--- /dev/null
+++ b/Liaison/Images/NormalMailbox.tiff
Binary files differ
diff --git a/Liaison/Images/NormalMailboxLarge.tiff b/Liaison/Images/NormalMailboxLarge.tiff
new file mode 100644
index 0000000..5ebd76d
--- /dev/null
+++ b/Liaison/Images/NormalMailboxLarge.tiff
Binary files differ
diff --git a/Liaison/Images/RemoveFiles.tiff b/Liaison/Images/RemoveFiles.tiff
new file mode 100644
index 0000000..67fbe49
--- /dev/null
+++ b/Liaison/Images/RemoveFiles.tiff
Binary files differ
diff --git a/Liaison/Images/RemoveGroup.tiff b/Liaison/Images/RemoveGroup.tiff
new file mode 100644
index 0000000..dc840ab
--- /dev/null
+++ b/Liaison/Images/RemoveGroup.tiff
Binary files differ
diff --git a/Liaison/Images/RightSearchCap.tiff b/Liaison/Images/RightSearchCap.tiff
new file mode 100644
index 0000000..5672df6
--- /dev/null
+++ b/Liaison/Images/RightSearchCap.tiff
Binary files differ
diff --git a/Liaison/Images/SortAscending.gif b/Liaison/Images/SortAscending.gif
new file mode 100644
index 0000000..4c11dba
--- /dev/null
+++ b/Liaison/Images/SortAscending.gif
Binary files differ
diff --git a/Liaison/Images/SortDescending.gif b/Liaison/Images/SortDescending.gif
new file mode 100644
index 0000000..c95c00d
--- /dev/null
+++ b/Liaison/Images/SortDescending.gif
Binary files differ
diff --git a/Liaison/Images/TrashMailbox.tiff b/Liaison/Images/TrashMailbox.tiff
new file mode 100644
index 0000000..4e6995f
--- /dev/null
+++ b/Liaison/Images/TrashMailbox.tiff
Binary files differ
diff --git a/Liaison/Images/TrashMailboxLarge.tiff b/Liaison/Images/TrashMailboxLarge.tiff
new file mode 100644
index 0000000..ea8fe02
--- /dev/null
+++ b/Liaison/Images/TrashMailboxLarge.tiff
Binary files differ
diff --git a/Liaison/Images/delete.tiff b/Liaison/Images/delete.tiff
new file mode 100644
index 0000000..ea8fe02
--- /dev/null
+++ b/Liaison/Images/delete.tiff
Binary files differ
diff --git a/Liaison/Images/info (italic).tiff b/Liaison/Images/info (italic).tiff
new file mode 100644
index 0000000..435c112
--- /dev/null
+++ b/Liaison/Images/info (italic).tiff
Binary files differ
diff --git a/Liaison/Images/info (plain).tiff b/Liaison/Images/info (plain).tiff
new file mode 100644
index 0000000..3ecf888
--- /dev/null
+++ b/Liaison/Images/info (plain).tiff
Binary files differ
diff --git a/Liaison/Images/quickpick.tiff b/Liaison/Images/quickpick.tiff
new file mode 100644
index 0000000..2cda6de
--- /dev/null
+++ b/Liaison/Images/quickpick.tiff
Binary files differ
diff --git a/Liaison/Images/rendezvous.tiff b/Liaison/Images/rendezvous.tiff
new file mode 100644
index 0000000..f162ef0
--- /dev/null
+++ b/Liaison/Images/rendezvous.tiff
Binary files differ
diff --git a/Liaison/Images/reveal.tiff b/Liaison/Images/reveal.tiff
new file mode 100644
index 0000000..90c6e1b
--- /dev/null
+++ b/Liaison/Images/reveal.tiff
Binary files 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>liaisonplugin</string>
+ </array>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>application/x-com.kublai.Liaison.plugin</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Liaison Plugin</string>
+ <key>CFBundleTypeRole</key>
+ <string>None</string>
+ <key>LSTypeIsPackage</key>
+ <true/>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>*</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Everything</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ </dict>
+ </array>
+ <key>CFBundleExecutable</key>
+ <string>Liaison</string>
+ <key>CFBundleGetInfoString</key>
+ <string>version 0.4.2</string>
+ <key>CFBundleIconFile</key>
+ <string>Liaison.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.kublai.Liaison</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>Liaison</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>v0.4.2</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>Liaison URL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>liaison</string>
+ </array>
+ </dict>
+ </array>
+ <key>CFBundleVersion</key>
+ <string>0.4.2</string>
+ <key>NSAppleScriptEnabled</key>
+ <string>YES</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
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 <LiInspectorPlugin> *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 <LiInspectorPlugin> *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 <Foundation/Foundation.h>
+
+@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 <LiPlugin/LiPlugin.h>
+// That uses this.
+#import <Cocoa/Cocoa.h>
+
+// 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>AppleEventCode</key>
+ <string>Lisn</string>
+ <key>Classes</key>
+ <dict>
+ <key>NSApplication</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>capp</string>
+ <key>Superclass</key>
+ <string>NSCoreSuite.NSApplication</string>
+ <key>ToManyRelationships</key>
+ <dict>
+ <key>orderedFileStores</key>
+ <dict>
+ <key>AppleEventCode</key>
+ <string>LiFS</string>
+ <key>ReadOnly</key>
+ <string>YES</string>
+ <key>Type</key>
+ <string>LiBackend.LiFileStore</string>
+ </dict>
+ </dict>
+ </dict>
+ </dict>
+ <key>Name</key>
+ <string>Liaison</string>
+</dict>
+</plist>
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 = "<group>"; };
+ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ 286D15B20CDD52F0006463CC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
+ 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
+ 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ F73ECD1304F6BEE000000104 /* English */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = folder; name = English; path = "English.lproj/Liaison Help"; sourceTree = "<group>"; };
+ F74B98C80523F102000001C7 /* LiDataTranslator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiDataTranslator.h; sourceTree = "<group>"; };
+ F74B98C90523F102000001C7 /* LiDataTranslator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LiDataTranslator.m; sourceTree = "<group>"; };
+ F75ACF7304EF59C800000104 /* NSFileHandleExtensions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NSFileHandleExtensions.h; sourceTree = "<group>"; };
+ F75ACF7404EF59C800000104 /* NSFileHandleExtensions.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NSFileHandleExtensions.m; sourceTree = "<group>"; };
+ F790692A04EF484300000104 /* Add.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Add.tiff; sourceTree = "<group>"; };
+ F790692B04EF484300000104 /* AddFiles.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = AddFiles.tiff; sourceTree = "<group>"; };
+ F790692C04EF484300000104 /* AddGroup.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = AddGroup.tiff; sourceTree = "<group>"; };
+ F790692D04EF484300000104 /* delete.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = delete.tiff; sourceTree = "<group>"; };
+ F790692E04EF484300000104 /* Download_Reload.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_Reload.tiff; sourceTree = "<group>"; };
+ F790692F04EF484300000104 /* Download_ReloadPressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_ReloadPressed.tiff; sourceTree = "<group>"; };
+ F790693004EF484300000104 /* Download_Reveal.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_Reveal.tiff; sourceTree = "<group>"; };
+ F790693104EF484300000104 /* Download_RevealPressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_RevealPressed.tiff; sourceTree = "<group>"; };
+ F790693204EF484300000104 /* Download_Stop.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_Stop.tiff; sourceTree = "<group>"; };
+ F790693304EF484300000104 /* Download_StopPressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Download_StopPressed.tiff; sourceTree = "<group>"; };
+ F790693604EF484300000104 /* Liaison.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Liaison.icns; sourceTree = "<group>"; };
+ F790693704EF484300000104 /* info (italic).tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "info (italic).tiff"; sourceTree = "<group>"; };
+ F790693804EF484300000104 /* info (plain).tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "info (plain).tiff"; sourceTree = "<group>"; };
+ F790693904EF484300000104 /* LeftSearchCap.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = LeftSearchCap.tiff; sourceTree = "<group>"; };
+ F790693A04EF484300000104 /* NormalMailbox.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = NormalMailbox.tiff; sourceTree = "<group>"; };
+ F790693B04EF484300000104 /* NormalMailboxLarge.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = NormalMailboxLarge.tiff; sourceTree = "<group>"; };
+ F790693C04EF484300000104 /* quickpick.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = quickpick.tiff; sourceTree = "<group>"; };
+ F790693D04EF484300000104 /* RemoveFiles.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = RemoveFiles.tiff; sourceTree = "<group>"; };
+ F790693E04EF484300000104 /* RemoveGroup.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = RemoveGroup.tiff; sourceTree = "<group>"; };
+ F790693F04EF484300000104 /* rendezvous.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = rendezvous.tiff; sourceTree = "<group>"; };
+ F790694004EF484300000104 /* reveal.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = reveal.tiff; sourceTree = "<group>"; };
+ F790694104EF484300000104 /* RightSearchCap.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = RightSearchCap.tiff; sourceTree = "<group>"; };
+ F790694204EF484300000104 /* SortAscending.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = SortAscending.gif; sourceTree = "<group>"; };
+ F790694304EF484300000104 /* SortDescending.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = SortDescending.gif; sourceTree = "<group>"; };
+ F790694404EF484300000104 /* TrashMailbox.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TrashMailbox.tiff; sourceTree = "<group>"; };
+ F790694504EF484300000104 /* TrashMailboxLarge.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TrashMailboxLarge.tiff; sourceTree = "<group>"; };
+ F790696104EF48AB00000104 /* FileTableDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FileTableDelegate.h; sourceTree = "<group>"; };
+ F790696204EF48AB00000104 /* LoadPanelController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LoadPanelController.m; sourceTree = "<group>"; };
+ F790696304EF48AB00000104 /* main.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ F790696404EF48AB00000104 /* FlippedBox.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FlippedBox.m; sourceTree = "<group>"; };
+ F790696504EF48AB00000104 /* ApplicationController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ApplicationController.m; sourceTree = "<group>"; };
+ F790696604EF48AB00000104 /* LiTableView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiTableView.h; sourceTree = "<group>"; };
+ F790696804EF48AB00000104 /* LiTableView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiTableView.m; sourceTree = "<group>"; };
+ F790696904EF48AB00000104 /* Downloader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Downloader.h; sourceTree = "<group>"; };
+ F790696A04EF48AB00000104 /* DownloadStatusView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DownloadStatusView.h; sourceTree = "<group>"; };
+ F790696B04EF48AB00000104 /* CopyController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CopyController.h; sourceTree = "<group>"; };
+ F790696C04EF48AB00000104 /* DownloadStatusView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DownloadStatusView.m; sourceTree = "<group>"; };
+ F790696D04EF48AB00000104 /* LoadPanelController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LoadPanelController.h; sourceTree = "<group>"; };
+ F790696E04EF48AB00000104 /* DownloadManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DownloadManager.h; sourceTree = "<group>"; };
+ F790697004EF48AB00000104 /* ClientManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ClientManager.m; sourceTree = "<group>"; };
+ F790697104EF48AB00000104 /* ApplicationController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ApplicationController.h; sourceTree = "<group>"; };
+ F790697204EF48AB00000104 /* ImageAndTextCell.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ImageAndTextCell.m; sourceTree = "<group>"; };
+ F790697304EF48AB00000104 /* FlippedBox.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FlippedBox.h; sourceTree = "<group>"; };
+ F790697404EF48AB00000104 /* LiScrolLView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiScrolLView.h; sourceTree = "<group>"; };
+ F790697504EF48AB00000104 /* Downloader.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Downloader.m; sourceTree = "<group>"; };
+ F790697604EF48AB00000104 /* ImageAndTextCell.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ImageAndTextCell.h; sourceTree = "<group>"; };
+ F790697704EF48AB00000104 /* Group.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Group.m; sourceTree = "<group>"; };
+ F790697804EF48AB00000104 /* InspectorController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = InspectorController.h; sourceTree = "<group>"; };
+ F790697904EF48AB00000104 /* GroupTableDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = GroupTableDelegate.h; sourceTree = "<group>"; };
+ F790697A04EF48AB00000104 /* InspectorController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = InspectorController.m; sourceTree = "<group>"; };
+ F790697B04EF48AB00000104 /* FileTableDelegate.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FileTableDelegate.m; sourceTree = "<group>"; };
+ F790697C04EF48AB00000104 /* ClientManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ClientManager.h; sourceTree = "<group>"; };
+ F790697D04EF48AB00000104 /* Liaison.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Liaison.h; sourceTree = "<group>"; };
+ F790697E04EF48AC00000104 /* LiScrolLView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiScrolLView.m; sourceTree = "<group>"; };
+ F790697F04EF48AC00000104 /* DownloadManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DownloadManager.m; sourceTree = "<group>"; };
+ F790698004EF48AC00000104 /* CopyController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = CopyController.m; sourceTree = "<group>"; };
+ F790698104EF48AC00000104 /* GroupTableDelegate.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = GroupTableDelegate.m; sourceTree = "<group>"; };
+ F790698204EF48AC00000104 /* Group.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Group.h; sourceTree = "<group>"; };
+ F79069A504EF48BA00000104 /* Liaison.scriptSuite */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Liaison.scriptSuite; sourceTree = "<group>"; };
+ F79069A804EF48C800000104 /* English */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/WindowElements.strings; sourceTree = "<group>"; };
+ F79069AA04EF48C800000104 /* English */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = English; path = English.lproj/Liaison.scriptTerminology; sourceTree = "<group>"; };
+ F79069AE04EF48C800000104 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/LoadPanel.nib; sourceTree = "<group>"; };
+ F79069B004EF48C800000104 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/CopyPanel.nib; sourceTree = "<group>"; };
+ F79069B204EF48C800000104 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/PreferencesWindow.nib; sourceTree = "<group>"; };
+ F79069B904EF4A2700000104 /* WindowController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WindowController.h; sourceTree = "<group>"; };
+ F79069BD04EF4A2700000104 /* ServerManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ServerManager.h; sourceTree = "<group>"; };
+ F79069BE04EF4A2700000104 /* RenManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenManager.h; sourceTree = "<group>"; };
+ F79069BF04EF4A2700000104 /* PreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PreferencesController.h; sourceTree = "<group>"; };
+ F79069C004EF4A2700000104 /* WriterThread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WriterThread.h; sourceTree = "<group>"; };
+ F79069C104EF4A2700000104 /* RenIPC.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenIPC.h; sourceTree = "<group>"; };
+ F79069C504EF4A2700000104 /* ViewOptionsController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ViewOptionsController.m; sourceTree = "<group>"; };
+ F79069C604EF4A2700000104 /* NIBConnector.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NIBConnector.h; sourceTree = "<group>"; };
+ F79069C704EF4A2700000104 /* PluginManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PluginManager.m; sourceTree = "<group>"; };
+ F79069C804EF4A2700000104 /* ViewOptionsController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ViewOptionsController.h; sourceTree = "<group>"; };
+ F79069C904EF4A2700000104 /* WindowController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = WindowController.m; sourceTree = "<group>"; };
+ F79069CA04EF4A2700000104 /* PreferencesController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PreferencesController.m; sourceTree = "<group>"; };
+ F79069CB04EF4A2700000104 /* WriterThreadPool.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = WriterThreadPool.m; sourceTree = "<group>"; };
+ F79069CC04EF4A2700000104 /* WriterThread.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = WriterThread.m; sourceTree = "<group>"; };
+ F79069CD04EF4A2700000104 /* RenManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = RenManager.m; sourceTree = "<group>"; };
+ F79069CE04EF4A2700000104 /* PluginManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PluginManager.h; sourceTree = "<group>"; };
+ F79069CF04EF4A2700000104 /* WriterThreadPool.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WriterThreadPool.h; sourceTree = "<group>"; };
+ F79069D004EF4A2700000104 /* NIBConnector.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NIBConnector.m; sourceTree = "<group>"; };
+ F79069D104EF4A2700000104 /* ServerManager.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ServerManager.m; sourceTree = "<group>"; };
+ F79069EC04EF4A8C00000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = chef; path = chef.lproj/WindowElements.strings; sourceTree = "<group>"; };
+ F79069ED04EF4A9500000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = chef; path = chef.lproj/LoadPanel.nib; sourceTree = "<group>"; };
+ F79069EE04EF4A9C00000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = chef; path = chef.lproj/CopyPanel.nib; sourceTree = "<group>"; };
+ F79069EF04EF4AA300000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = chef; path = chef.lproj/PreferencesWindow.nib; sourceTree = "<group>"; };
+ F79069F004EF4AAB00000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = chef; path = chef.lproj/MainMenu.nib; sourceTree = "<group>"; };
+ F79069F104EF4AB300000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = chef; path = chef.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ F7A5B69904F841A900000104 /* FindController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FindController.h; sourceTree = "<group>"; };
+ F7A5B69A04F841A900000104 /* FindController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FindController.m; sourceTree = "<group>"; };
+ F7C329D30514615A00000103 /* NSException+LiDebugging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSException+LiDebugging.m"; sourceTree = "<group>"; };
+ F7D398F60546870000BD181E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 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 = "<group>"; };
+ F7D6588304F3576900000104 /* LiPlugin.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LiPlugin.framework; path = ../Frameworks/build/Development/LiPlugin.framework; sourceTree = "<group>"; };
+ F7D6588604F3579700000104 /* Built In Functions.liaisonplugin */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "Built In Functions.liaisonplugin"; path = "../Plugins/BuiltInFunctions/build/Development/Built In Functions.liaisonplugin"; sourceTree = "<group>"; };
+/* 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 = "<group>";
+ };
+ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
+ );
+ name = "Linked Frameworks";
+ sourceTree = "<group>";
+ };
+ 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 29B97325FDCFA39411CA2CEA /* Foundation.framework */,
+ 29B97324FDCFA39411CA2CEA /* AppKit.framework */,
+ );
+ name = "Other Frameworks";
+ sourceTree = "<group>";
+ };
+ 19C28FACFE9D520D11CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F7D398F70546870000BD181E /* Liaison.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 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 = "<group>";
+ };
+ 29B97315FDCFA39411CA2CEA /* Other Sources */ = {
+ isa = PBXGroup;
+ children = (
+ F790697D04EF48AB00000104 /* Liaison.h */,
+ F790696304EF48AB00000104 /* main.m */,
+ );
+ name = "Other Sources";
+ sourceTree = "<group>";
+ };
+ 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 = "<group>";
+ };
+ 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ F7D6588204F3576900000104 /* LiBackend.framework */,
+ F7D6588304F3576900000104 /* LiPlugin.framework */,
+ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
+ 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 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 = "<group>";
+ };
+ 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 = "<group>";
+ };
+ F75ACEA104EF512000000104 /* NIBConnector */ = {
+ isa = PBXGroup;
+ children = (
+ F79069C604EF4A2700000104 /* NIBConnector.h */,
+ F79069D004EF4A2700000104 /* NIBConnector.m */,
+ );
+ name = NIBConnector;
+ sourceTree = "<group>";
+ };
+ F75ACEA204EF513800000104 /* Prefs Window */ = {
+ isa = PBXGroup;
+ children = (
+ F79069BF04EF4A2700000104 /* PreferencesController.h */,
+ F79069CA04EF4A2700000104 /* PreferencesController.m */,
+ );
+ name = "Prefs Window";
+ sourceTree = "<group>";
+ };
+ F75ACEA304EF514B00000104 /* Inspector Window */ = {
+ isa = PBXGroup;
+ children = (
+ F790697804EF48AB00000104 /* InspectorController.h */,
+ F790697A04EF48AB00000104 /* InspectorController.m */,
+ );
+ name = "Inspector Window";
+ sourceTree = "<group>";
+ };
+ F75ACEAF04EF517E00000104 /* Cocoa Extensions */ = {
+ isa = PBXGroup;
+ children = (
+ F75ACF7704EF5D2600000104 /* NSFileHandleExtensions */,
+ F75ACF7904EF5D3B00000104 /* LiTableView */,
+ F75ACF7B04EF5D4D00000104 /* LiScrollView */,
+ F75ACF7A04EF5D4500000104 /* ImageAndTextCell */,
+ F75ACF7804EF5D3400000104 /* FlippedBox */,
+ );
+ name = "Cocoa Extensions";
+ sourceTree = "<group>";
+ };
+ 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 = "<group>";
+ };
+ F75ACF7804EF5D3400000104 /* FlippedBox */ = {
+ isa = PBXGroup;
+ children = (
+ F790697304EF48AB00000104 /* FlippedBox.h */,
+ F790696404EF48AB00000104 /* FlippedBox.m */,
+ );
+ name = FlippedBox;
+ sourceTree = "<group>";
+ };
+ F75ACF7904EF5D3B00000104 /* LiTableView */ = {
+ isa = PBXGroup;
+ children = (
+ F790696604EF48AB00000104 /* LiTableView.h */,
+ F790696804EF48AB00000104 /* LiTableView.m */,
+ );
+ name = LiTableView;
+ sourceTree = "<group>";
+ };
+ F75ACF7A04EF5D4500000104 /* ImageAndTextCell */ = {
+ isa = PBXGroup;
+ children = (
+ F790697604EF48AB00000104 /* ImageAndTextCell.h */,
+ F790697204EF48AB00000104 /* ImageAndTextCell.m */,
+ );
+ name = ImageAndTextCell;
+ sourceTree = "<group>";
+ };
+ F75ACF7B04EF5D4D00000104 /* LiScrollView */ = {
+ isa = PBXGroup;
+ children = (
+ F790697404EF48AB00000104 /* LiScrolLView.h */,
+ F790697E04EF48AC00000104 /* LiScrolLView.m */,
+ );
+ name = LiScrollView;
+ sourceTree = "<group>";
+ };
+ F790690F04EF46F200000104 /* Plugins */ = {
+ isa = PBXGroup;
+ children = (
+ F7D6588604F3579700000104 /* Built In Functions.liaisonplugin */,
+ );
+ name = Plugins;
+ sourceTree = "<group>";
+ };
+ 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 = "<group>";
+ };
+ F790693404EF484300000104 /* File Icons */ = {
+ isa = PBXGroup;
+ children = (
+ F790693604EF484300000104 /* Liaison.icns */,
+ );
+ path = "File Icons";
+ sourceTree = "<group>";
+ };
+ F7906A0304EF4FE000000104 /* View Options Window */ = {
+ isa = PBXGroup;
+ children = (
+ F79069C804EF4A2700000104 /* ViewOptionsController.h */,
+ F79069C504EF4A2700000104 /* ViewOptionsController.m */,
+ );
+ name = "View Options Window";
+ sourceTree = "<group>";
+ };
+ F7906A0404EF500D00000104 /* Plugin Manager */ = {
+ isa = PBXGroup;
+ children = (
+ F79069CE04EF4A2700000104 /* PluginManager.h */,
+ F79069C704EF4A2700000104 /* PluginManager.m */,
+ );
+ name = "Plugin Manager";
+ sourceTree = "<group>";
+ };
+ F7A5B69804F8417E00000104 /* Find Window */ = {
+ isa = PBXGroup;
+ children = (
+ F7A5B69904F841A900000104 /* FindController.h */,
+ F7A5B69A04F841A900000104 /* FindController.m */,
+ );
+ name = "Find Window";
+ sourceTree = "<group>";
+ };
+ F7C329D10514613300000103 /* Debugging */ = {
+ isa = PBXGroup;
+ children = (
+ F7C329D30514615A00000103 /* NSException+LiDebugging.m */,
+ );
+ name = Debugging;
+ sourceTree = "<group>";
+ };
+/* 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 = "<group>";
+ };
+ 29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 29B97319FDCFA39411CA2CEA /* English */,
+ F79069F004EF4AAB00000104 /* chef */,
+ );
+ name = MainMenu.nib;
+ sourceTree = "<group>";
+ };
+ F73ECD6904F6BF0A00000104 /* Liaison Help */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F73ECD1304F6BEE000000104 /* English */,
+ );
+ name = "Liaison Help";
+ sourceTree = "<group>";
+ };
+ F79069A704EF48C800000104 /* WindowElements.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F79069A804EF48C800000104 /* English */,
+ F79069EC04EF4A8C00000104 /* chef */,
+ );
+ name = WindowElements.strings;
+ sourceTree = "<group>";
+ };
+ F79069A904EF48C800000104 /* Liaison.scriptTerminology */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F79069AA04EF48C800000104 /* English */,
+ );
+ name = Liaison.scriptTerminology;
+ sourceTree = "<group>";
+ };
+ F79069AD04EF48C800000104 /* LoadPanel.nib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F79069AE04EF48C800000104 /* English */,
+ F79069ED04EF4A9500000104 /* chef */,
+ );
+ name = LoadPanel.nib;
+ sourceTree = "<group>";
+ };
+ F79069AF04EF48C800000104 /* CopyPanel.nib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F79069B004EF48C800000104 /* English */,
+ F79069EE04EF4A9C00000104 /* chef */,
+ );
+ name = CopyPanel.nib;
+ sourceTree = "<group>";
+ };
+ F79069B104EF48C800000104 /* PreferencesWindow.nib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F79069B204EF48C800000104 /* English */,
+ F79069EF04EF4AA300000104 /* chef */,
+ );
+ name = PreferencesWindow.nib;
+ sourceTree = "<group>";
+ };
+/* 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 <netinet/in.h>
+#import <sys/socket.h>
+
+@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) <LiFileStoreDelegate>
+@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 <netinet/in.h>
+#import <sys/socket.h>
+#import <unistd.h>
+
+@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 <errno.h>
+#import <sys/types.h>
+#import <sys/uio.h>
+#import <unistd.h>
+
+#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 <signal.h>
+
+@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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>60 38 356 240 0 0 1024 746 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>16</key>
+ <string>373 456 220 82 0 0 1024 746 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>291.0</string>
+ <key>IBSystem Version</key>
+ <string>6L60</string>
+</dict>
+</plist>
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
--- /dev/null
+++ b/Liaison/chef.lproj/CopyPanel.nib/objects.nib
Binary files differ
diff --git a/Liaison/chef.lproj/InfoPlist.strings b/Liaison/chef.lproj/InfoPlist.strings
new file mode 100644
index 0000000..150b632
--- /dev/null
+++ b/Liaison/chef.lproj/InfoPlist.strings
Binary files 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>JavaSourceSubpath</key>
+ <string>_LoadPanel_EOArchive_chef.java</string>
+</dict>
+</plist>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>89 245 356 240 0 0 1600 1178 </string>
+ <key>IBFramework Version</key>
+ <string>291.0</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>6</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>6L60</string>
+</dict>
+</plist>
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
--- /dev/null
+++ b/Liaison/chef.lproj/LoadPanel.nib/objects.nib
Binary files 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>23 72 461 291 0 0 1024 746 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>29</key>
+ <string>3 696 310 44 0 0 1024 746 </string>
+ <key>377</key>
+ <string>423 486 177 62 0 0 1024 746 </string>
+ <key>700</key>
+ <string>287 435 224 118 0 0 1024 746 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>291.0</string>
+ <key>IBGroupedObjects</key>
+ <dict>
+ <key>1</key>
+ <array>
+ <string>666</string>
+ <string>671</string>
+ <string>672</string>
+ </array>
+ </dict>
+ <key>IBLastGroupID</key>
+ <string>2</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>21</integer>
+ <integer>301</integer>
+ <integer>208</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>6L60</string>
+</dict>
+</plist>
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
--- /dev/null
+++ b/Liaison/chef.lproj/MainMenu.nib/objects.nib
Binary files 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>50 54 356 240 0 0 1600 1178 </string>
+ <key>IBFramework Version</key>
+ <string>326.0</string>
+ <key>IBGroupedObjects</key>
+ <dict>
+ <key>0</key>
+ <array>
+ <string>39</string>
+ <string>40</string>
+ <string>49</string>
+ </array>
+ <key>1</key>
+ <array>
+ <string>21</string>
+ <string>22</string>
+ </array>
+ <key>2</key>
+ <array>
+ <string>34</string>
+ <string>35</string>
+ <string>36</string>
+ </array>
+ </dict>
+ <key>IBLastGroupID</key>
+ <string>3</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>5</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>7B28</string>
+</dict>
+</plist>
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
--- /dev/null
+++ b/Liaison/chef.lproj/PreferencesWindow.nib/objects.nib
Binary files 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);
+}
diff --git a/Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.h b/Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.h
new file mode 100644
index 0000000..7d923df
--- /dev/null
+++ b/Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.h
@@ -0,0 +1,72 @@
+/*
+ Copyright (c) 2001-2002, bDistributed.com, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, are permitted provided that the following
+ conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ * Neither the name of bDistributed.com, Inc. nor the names of
+ its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ OF SUCH DAMAGE.
+*/
+
+#import <Foundation/Foundation.h>
+#import <CoreServices/CoreServices.h>
+
+@interface BDAlias : NSObject
+{
+ AliasHandle _alias;
+}
+
+- (id)initWithAliasHandle:(AliasHandle)alias; // designated initializer
+- (id)initWithData:(NSData *)data;
+- (id)initWithPath:(NSString *)fullPath;
+- (id)initWithPath:(NSString *)path relativeToPath:(NSString *)relPath;
+- (id)initWithFSRef:(FSRef *)ref;
+- (id)initWithFSRef:(FSRef *)ref relativeToFSRef:(FSRef *)relRef;
+
+- (void)dealloc;
+
+- (AliasHandle)alias;
+- (void)setAlias:(AliasHandle)newAlias;
+
+- (NSData *)aliasData;
+- (void)setAliasData:(NSData *)newAliasData;
+
+- (NSString *)fullPath;
+- (NSString *)fullPathRelativeToPath:(NSString *)relPath;
+
++ (BDAlias *)aliasWithAliasHandle:(AliasHandle)alias;
++ (BDAlias *)aliasWithData:(NSData *)data;
++ (BDAlias *)aliasWithPath:(NSString *)fullPath;
++ (BDAlias *)aliasWithPath:(NSString *)path relativeToPath:(NSString *)relPath;
++ (BDAlias *)aliasWithFSRef:(FSRef *)ref;
++ (BDAlias *)aliasWithFSRef:(FSRef *)ref relativeToFSRef:(FSRef *)relRef;
+
+@property (getter=alias) AliasHandle _alias;
+@end
diff --git a/Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.m b/Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.m
new file mode 100644
index 0000000..2cf7d1d
--- /dev/null
+++ b/Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.m
@@ -0,0 +1,316 @@
+/*
+ Copyright (c) 2001-2002, bDistributed.com, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, are permitted provided that the following
+ conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ * Neither the name of bDistributed.com, Inc. nor the names of
+ its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ OF SUCH DAMAGE.
+*/
+
+#include <assert.h>
+
+#import "BDAlias.h"
+
+
+static Handle DataToHandle(CFDataRef inData);
+static CFDataRef HandleToData(Handle inHandle);
+
+static OSStatus PathToFSRef(CFStringRef inPath, FSRef *outRef);
+static CFStringRef FSRefToPathCopy(const FSRef *inRef);
+
+
+static Handle DataToHandle(CFDataRef inData)
+{
+ CFIndex len;
+ Handle handle = NULL;
+
+ if (inData == NULL) {
+ return NULL;
+ }
+
+ len = CFDataGetLength(inData);
+
+ handle = NewHandle(len);
+
+ if ((handle != NULL) && (len > 0)) {
+ HLock(handle);
+ BlockMoveData(CFDataGetBytePtr(inData), *handle, len);
+ HUnlock(handle);
+ }
+
+ return handle;
+}
+
+static CFDataRef HandleToData(Handle inHandle)
+{
+ CFDataRef data = NULL;
+ CFIndex len;
+ SInt8 handleState;
+
+ if (inHandle == NULL) {
+ return NULL;
+ }
+
+ len = GetHandleSize(inHandle);
+
+ handleState = HGetState(inHandle);
+
+ HLock(inHandle);
+
+ data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *) *inHandle, len);
+
+ HSetState(inHandle, handleState);
+
+ return data;
+}
+
+static OSStatus PathToFSRef(CFStringRef inPath, FSRef *outRef)
+{
+ CFURLRef tempURL = NULL;
+ Boolean gotRef = false;
+
+ tempURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, inPath,
+ kCFURLPOSIXPathStyle, false);
+
+ if (tempURL == NULL) {
+ return fnfErr;
+ }
+
+ gotRef = CFURLGetFSRef(tempURL, outRef);
+
+ CFRelease(tempURL);
+
+ if (gotRef == false) {
+ return fnfErr;
+ }
+
+ return noErr;
+}
+
+static CFStringRef FSRefToPathCopy(const FSRef *inRef)
+{
+ CFURLRef tempURL = NULL;
+ CFStringRef result = NULL;
+
+ if (inRef != NULL) {
+ tempURL = CFURLCreateFromFSRef(kCFAllocatorDefault, inRef);
+
+ if (tempURL == NULL) {
+ return NULL;
+ }
+
+ result = CFURLCopyFileSystemPath(tempURL, kCFURLPOSIXPathStyle);
+
+ CFRelease(tempURL);
+ }
+
+ return result;
+}
+
+
+@implementation BDAlias
+
+- (id)initWithAliasHandle:(AliasHandle)alias
+{
+ id ret = [super init];
+
+ if (ret != nil) {
+ _alias = alias;
+ }
+
+ return ret;
+}
+
+- (id)initWithData:(NSData *)data
+{
+ return [self initWithAliasHandle:(AliasHandle)DataToHandle((CFDataRef) data)];
+}
+
+- (id)initWithPath:(NSString *)fullPath
+{
+ OSStatus anErr = noErr;
+ FSRef ref;
+
+ anErr = PathToFSRef((CFStringRef) fullPath, &ref);
+
+ if (anErr != noErr) {
+ return nil;
+ }
+
+ return [self initWithFSRef:&ref];;
+}
+
+- (id)initWithPath:(NSString *)path relativeToPath:(NSString *)relPath
+{
+ OSStatus anErr = noErr;
+ FSRef ref, relRef;
+
+ anErr = PathToFSRef((CFStringRef) [relPath stringByAppendingPathComponent:path],
+ &ref);
+
+ if (anErr != noErr) {
+ return nil;
+ }
+
+ anErr = PathToFSRef((CFStringRef) relPath, &relRef);
+
+ if (anErr != noErr) {
+ return nil;
+ }
+
+ return [self initWithFSRef:&ref relativeToFSRef:&relRef];
+}
+
+- (id)initWithFSRef:(FSRef *)ref
+{
+ return [self initWithFSRef:ref relativeToFSRef:NULL];
+}
+
+- (id)initWithFSRef:(FSRef *)ref relativeToFSRef:(FSRef *)relRef
+{
+ OSStatus anErr = noErr;
+ AliasHandle alias = NULL;
+
+ anErr = FSNewAlias(relRef, ref, &alias);
+
+ if (anErr != noErr) {
+ return nil;
+ }
+
+ return [self initWithAliasHandle:alias];
+}
+
+- (void)dealloc
+{
+ if (_alias != NULL) {
+ DisposeHandle((Handle) _alias);
+ _alias = NULL;
+ }
+
+ [super dealloc];
+}
+
+- (AliasHandle)alias
+{
+ return _alias;
+}
+
+- (void)setAlias:(AliasHandle)newAlias
+{
+ if (_alias != NULL) {
+ DisposeHandle((Handle) _alias);
+ }
+
+ _alias = newAlias;
+}
+
+- (NSData *)aliasData
+{
+ NSData *result;
+
+ result = (NSData *)HandleToData((Handle) _alias);
+
+ return [result autorelease];
+}
+
+- (void)setAliasData:(NSData *)newAliasData
+{
+ [self setAlias:(AliasHandle) DataToHandle((CFDataRef) newAliasData)];
+}
+
+- (NSString *)fullPath
+{
+ return [self fullPathRelativeToPath:nil];
+}
+
+- (NSString *)fullPathRelativeToPath:(NSString *)relPath
+{
+ OSStatus anErr = noErr;
+ FSRef relPathRef;
+ FSRef tempRef;
+ NSString *result = nil;
+ Boolean wasChanged;
+
+ if (_alias != NULL) {
+ if (relPath != nil) {
+ anErr = PathToFSRef((CFStringRef)relPath, &relPathRef);
+
+ if (anErr != noErr) {
+ return NULL;
+ }
+
+ anErr = FSResolveAlias(&relPathRef, _alias, &tempRef, &wasChanged);
+ } else {
+ anErr = FSResolveAlias(NULL, _alias, &tempRef, &wasChanged);
+ }
+
+ if (anErr != noErr) {
+ return NULL;
+ }
+
+ result = (NSString *)FSRefToPathCopy(&tempRef);
+ }
+
+ return [result autorelease];
+}
+
++ (BDAlias *)aliasWithAliasHandle:(AliasHandle)alias
+{
+ return [[[BDAlias alloc] initWithAliasHandle:alias] autorelease];
+}
+
++ (BDAlias *)aliasWithData:(NSData *)data
+{
+ return [[[BDAlias alloc] initWithData:data] autorelease];
+}
+
++ (BDAlias *)aliasWithPath:(NSString *)fullPath
+{
+ return [[[BDAlias alloc] initWithPath:fullPath] autorelease];
+}
+
++ (BDAlias *)aliasWithPath:(NSString *)path relativeToPath:(NSString *)relPath
+{
+ return [[[BDAlias alloc] initWithPath:path relativeToPath:relPath] autorelease];
+}
+
++ (BDAlias *)aliasWithFSRef:(FSRef *)ref
+{
+ return [[[BDAlias alloc] initWithFSRef:ref] autorelease];
+}
+
++ (BDAlias *)aliasWithFSRef:(FSRef *)ref relativeToFSRef:(FSRef *)relRef
+{
+ return [[[BDAlias alloc] initWithFSRef:ref relativeToFSRef:relRef] autorelease];
+}
+
+@synthesize _alias;
+@end
diff --git a/Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.rtf b/Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.rtf
new file mode 100644
index 0000000..a32ca81
--- /dev/null
+++ b/Plugins/BuiltInFunctions/BDAlias/BDAlias/BDAlias.rtf
@@ -0,0 +1,162 @@
+{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;\f1\fswiss\fcharset77 Helvetica-Bold;}
+{\colortbl;\red255\green255\blue255;\red255\green0\blue0;}
+\margl1440\margr1440\vieww9000\viewh9000\viewkind0
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs24 \cf0
+\f1\b\fs28 \cf2 b\cf0 Distributed.com, Inc.
+\f0\b0\fs24 \
+
+\fs20 2549 W. Golf Rd. #348\
+ Hoffman Estates, IL 60194\
+ Phone: (847) 372-3955\
+ Fax: (847) 589-3738\
+ Web: bdistributed.com\
+ Email: info@bdistributed.com\
+
+\fs24 \
+Below is a quick reference for the BDAlias class.\
+\
+
+\f1\b Instance Methods
+\f0\b0 \
+initWithAliasHandle:\
+initWithData:\
+initWithPath:\
+initWithPath:relativeToPath:\
+initWithFSRef:\
+initWithFSRef:relativeToFSRef:\
+dealloc\
+alias\
+setAlias:\
+aliasData\
+setAliasData:\
+fullPath\
+fullPathRelativeToPath:\
+\
+
+\f1\b Class Methods
+\f0\b0 \
+aliasWithAliasHandle:\
+aliasWithData:\
+aliasWithPath:\
+aliasWithPath:relativeToPath:\
+aliasWithFSRef:\
+aliasWithFSRef:relativeToFSRef:\
+\
+
+\f1\b - (id)initWithAliasHandle:(AliasHandle)alias
+\f0\b0 \
+Initializes an alias object with the contents of a Carbon alias handle. This is the designated initializer.\
+\
+
+\f1\b - (id)initWithData:(NSData *)data
+\f0\b0 \
+Initializes an alias object with the contents of a data object.\
+\
+
+\f1\b - (id)initWithPath:(NSString *)fullPath
+\f0\b0 \
+Initializes an alias object to point to the object at the given path in the filesystem.\
+\
+
+\f1\b - (id)initWithPath:(NSString *)path relativeToPath:(NSString *)relPath
+\f0\b0 \
+Initializes an alias object to point to the object at the given path in the filesystem, relative to the given relative path.\
+\
+
+\f1\b - (id)initWithFSRef:(FSRef *)ref
+\f0\b0 \
+Initializes an alias object to point to the object represented by the given Carbon FSRef.\
+\
+
+\f1\b - (id)initWithFSRef:(FSRef *)ref relativeToFSRef:(FSRef *)relRef
+\f0\b0 \
+Initializes an alias object to point to the object represented by the given Carbon FSRef, relative to the given relative Carbon FSRef.\
+\
+
+\f1\b - (void)dealloc
+\f0\b0 \
+Releases resources held by an instance.\
+\
+
+\f1\b - (AliasHandle)alias
+\f0\b0 \
+Returns the internal Carbon alias handle used by an instance.\
+\
+
+\f1\b - (void)setAlias:(AliasHandle)newAlias
+\f0\b0 \
+Sets the internal Carbon alias handle used by an instance, releasing the previous alias handle (if any).\
+\
+
+\f1\b - (NSData *)aliasData
+\f0\b0 \
+Returns an autoreleased data object containing a copy of the alias data in this object.\
+\
+
+\f1\b - (void)setAliasData:(NSData *)newAliasData
+\f0\b0 \
+Sets the alias to use the alias record stored in the given data object. Discards any previous data.\
+\
+
+\f1\b - (NSString *)fullPath
+\f0\b0 \
+Returns an autoreleased string containing the full path of the object pointed to by an alias.\
+\
+
+\f1\b - (NSString *)fullPathRelativeToPath:(NSString *)relPath
+\f0\b0 \
+Returns an autoreleased string containing the full path of the object pointed to by an alias, resolved relative to the other given full path.\
+\
+
+\f1\b + (BDAlias *)aliasWithAliasHandle:(AliasHandle)alias\
+
+\f0\b0 Creates an autoreleased alias object with the contents of the given Carbon alias handle.\
+\
+
+\f1\b + (BDAlias *)aliasWithData:(NSData *)data\
+
+\f0\b0 Creates an autoreleased alias object with the contents of the given NSData object.\
+\
+
+\f1\b + (BDAlias *)aliasWithPath:(NSString *)fullPath\
+
+\f0\b0 Creates an autoreleased alias object pointing to the object at the given full path.\
+\
+
+\f1\b + (BDAlias *)aliasWithPath:(NSString *)path relativeToPath:(NSString *)relPath\
+
+\f0\b0 Creates an autoreleased alias object pointing to the object at the given path, relative to the given relative path.\
+\
+
+\f1\b + (BDAlias *)aliasWithFSRef:(FSRef *)ref\
+
+\f0\b0 Creates an autoreleased alias object pointing to the object at the given Carbon FSRef.\
+\
+
+\f1\b + (BDAlias *)aliasWithFSRef:(FSREf *)ref relativeToFSRef:(FSRef *)relRef\
+
+\f0\b0 Creates an autoreleased alias object pointing to the object at the given Carbon FSRef, relative to the given relative Carbon FSRef.\
+\
+
+\f1\b License Agreement\
+
+\f0\b0 By using or downloading this software, you agree to be bound by the following license. If you do not agree to be bound by the license, please destroy all copies of this software.\
+\
+Copyright \'a9 2001-2002, bDistributed.com, Inc.\
+All rights reserved.\
+\
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\
+\
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li580\fi-580\ql\qnatural
+\cf0 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\
+\
+* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\
+\
+* Neither the name of bDistributed.com, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. \
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+\cf0 \
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \
+} \ No newline at end of file
diff --git a/Plugins/BuiltInFunctions/BDAlias/BDAlias/License.rtf b/Plugins/BuiltInFunctions/BDAlias/BDAlias/License.rtf
new file mode 100644
index 0000000..3bbbb7b
--- /dev/null
+++ b/Plugins/BuiltInFunctions/BDAlias/BDAlias/License.rtf
@@ -0,0 +1,21 @@
+{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\froman\fcharset77 TimesNewRomanPSMT;}
+{\colortbl;\red255\green255\blue255;}
+\vieww9000\viewh9000\viewkind0
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs24 \cf0 Copyright \'a9 2001-2002, bDistributed.com, Inc.\
+All rights reserved.\
+\
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\
+\
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li580\fi-580\ql\qnatural
+\cf0 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\
+\
+* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\
+\
+* Neither the name of bDistributed.com, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. \
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+\cf0 \
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \
+} \ No newline at end of file
diff --git a/Plugins/BuiltInFunctions/BuiltInFunctions.h b/Plugins/BuiltInFunctions/BuiltInFunctions.h
new file mode 100644
index 0000000..ad4208e
--- /dev/null
+++ b/Plugins/BuiltInFunctions/BuiltInFunctions.h
@@ -0,0 +1,12 @@
+/*
+ * BuiltInFunctions.h
+ * BuiltInFunctions
+ *
+ * Created by Brian Cully on Sun Aug 17 2003.
+ * Copyright (c) 2003 Brian Cully. All rights reserved.
+ *
+ */
+
+#import <LiPlugin/LiPlugin.h>
+#import <Carbon/Carbon.h>
+#import <Cocoa/Cocoa.h> \ No newline at end of file
diff --git a/Plugins/BuiltInFunctions/BuiltInFunctions.xcodeproj/project.pbxproj b/Plugins/BuiltInFunctions/BuiltInFunctions.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..2c7562f
--- /dev/null
+++ b/Plugins/BuiltInFunctions/BuiltInFunctions.xcodeproj/project.pbxproj
@@ -0,0 +1,514 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F7D397E40546864600BD181E /* BDAlias.h in Headers */ = {isa = PBXBuildFile; fileRef = F790687704EF3DE200000104 /* BDAlias.h */; };
+ F7D397E50546864600BD181E /* IconFamily.h in Headers */ = {isa = PBXBuildFile; fileRef = F790688104EF3DEB00000104 /* IconFamily.h */; };
+ F7D397E60546864600BD181E /* NSString+CarbonFSSpecCreation.h in Headers */ = {isa = PBXBuildFile; fileRef = F790688304EF3DEB00000104 /* NSString+CarbonFSSpecCreation.h */; };
+ F7D397E70546864600BD181E /* LiImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = F790689404EF3E3900000104 /* LiImageView.h */; };
+ F7D397E80546864600BD181E /* FileSizeFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = F790689804EF3E3900000104 /* FileSizeFormatter.h */; };
+ F7D397E90546864600BD181E /* HFSCodeFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = F790689904EF3E3900000104 /* HFSCodeFormatter.h */; };
+ F7D397EA0546864600BD181E /* InspectorViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = F790689B04EF3E3900000104 /* InspectorViewController.h */; };
+ F7D397EB0546864600BD181E /* LiBuiltInFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = F790689C04EF3E3900000104 /* LiBuiltInFunctions.h */; };
+ F7D397EC0546864600BD181E /* BuiltInFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = F75ACF1C04EF584E00000104 /* BuiltInFunctions.h */; };
+ F7D397ED0546864600BD181E /* NaturalDateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = F71CA8EF0502854900000104 /* NaturalDateFormatter.h */; };
+ F7D397EF0546864600BD181E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
+ F7D397F00546864600BD181E /* BDAlias.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F790687904EF3DE200000104 /* BDAlias.rtf */; };
+ F7D397F10546864600BD181E /* License.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F790687A04EF3DE200000104 /* License.rtf */; };
+ F7D397F20546864600BD181E /* local.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790688A04EF3E0D00000104 /* local.tiff */; };
+ F7D397F30546864600BD181E /* LocalAccountLarge.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790688B04EF3E0D00000104 /* LocalAccountLarge.tiff */; };
+ F7D397F40546864600BD181E /* Network (Large).tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790688C04EF3E0D00000104 /* Network (Large).tiff */; };
+ F7D397F50546864600BD181E /* Network (Small).tiff in Resources */ = {isa = PBXBuildFile; fileRef = F790688D04EF3E0D00000104 /* Network (Small).tiff */; };
+ F7D397F60546864600BD181E /* NotThere.icns in Resources */ = {isa = PBXBuildFile; fileRef = F790688E04EF3E0D00000104 /* NotThere.icns */; };
+ F7D397F70546864600BD181E /* InspectorViews.nib in Resources */ = {isa = PBXBuildFile; fileRef = F79068AC04EF3EED00000104 /* InspectorViews.nib */; };
+ F7D397F80546864600BD181E /* BuiltInFunctions.strings in Resources */ = {isa = PBXBuildFile; fileRef = F79068AE04EF3EED00000104 /* BuiltInFunctions.strings */; };
+ F7D397F90546864600BD181E /* ErrorMessages.strings in Resources */ = {isa = PBXBuildFile; fileRef = F79068B004EF3EED00000104 /* ErrorMessages.strings */; };
+ F7D397FB0546864600BD181E /* BDAlias.m in Sources */ = {isa = PBXBuildFile; fileRef = F790687804EF3DE200000104 /* BDAlias.m */; };
+ F7D397FC0546864600BD181E /* IconFamily.m in Sources */ = {isa = PBXBuildFile; fileRef = F790688204EF3DEB00000104 /* IconFamily.m */; };
+ F7D397FD0546864600BD181E /* NSString+CarbonFSSpecCreation.m in Sources */ = {isa = PBXBuildFile; fileRef = F790688404EF3DEC00000104 /* NSString+CarbonFSSpecCreation.m */; };
+ F7D397FE0546864600BD181E /* FileSizeFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = F790689504EF3E3900000104 /* FileSizeFormatter.m */; };
+ F7D397FF0546864600BD181E /* InspectorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F790689604EF3E3900000104 /* InspectorViewController.m */; };
+ F7D398000546864600BD181E /* LiBuiltInFunctions.m in Sources */ = {isa = PBXBuildFile; fileRef = F790689704EF3E3900000104 /* LiBuiltInFunctions.m */; };
+ F7D398010546864600BD181E /* HFSCodeFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = F790689A04EF3E3900000104 /* HFSCodeFormatter.m */; };
+ F7D398020546864600BD181E /* LiImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = F790689D04EF3E3900000104 /* LiImageView.m */; };
+ F7D398030546864600BD181E /* NaturalDateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = F71CA8F00502854900000104 /* NaturalDateFormatter.m */; };
+ F7D398050546864600BD181E /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; };
+ F7D398060546864600BD181E /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F79068CA04EF42F700000104 /* Carbon.framework */; };
+ F7D398070546864600BD181E /* LiBackend.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7D6587904F356ED00000104 /* LiBackend.framework */; };
+ F7D398080546864600BD181E /* LiPlugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7D6587A04F356ED00000104 /* LiPlugin.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
+ 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ F71CA8EF0502854900000104 /* NaturalDateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NaturalDateFormatter.h; sourceTree = "<group>"; };
+ F71CA8F00502854900000104 /* NaturalDateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NaturalDateFormatter.m; sourceTree = "<group>"; };
+ F75ACF1C04EF584E00000104 /* BuiltInFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BuiltInFunctions.h; sourceTree = "<group>"; };
+ F790687704EF3DE200000104 /* BDAlias.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BDAlias.h; sourceTree = "<group>"; };
+ F790687804EF3DE200000104 /* BDAlias.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BDAlias.m; sourceTree = "<group>"; };
+ F790687904EF3DE200000104 /* BDAlias.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = BDAlias.rtf; sourceTree = "<group>"; };
+ F790687A04EF3DE200000104 /* License.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = License.rtf; sourceTree = "<group>"; };
+ F790688104EF3DEB00000104 /* IconFamily.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = IconFamily.h; sourceTree = "<group>"; };
+ F790688204EF3DEB00000104 /* IconFamily.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = IconFamily.m; sourceTree = "<group>"; };
+ F790688304EF3DEB00000104 /* NSString+CarbonFSSpecCreation.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "NSString+CarbonFSSpecCreation.h"; sourceTree = "<group>"; };
+ F790688404EF3DEC00000104 /* NSString+CarbonFSSpecCreation.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = "NSString+CarbonFSSpecCreation.m"; sourceTree = "<group>"; };
+ F790688A04EF3E0D00000104 /* local.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = local.tiff; sourceTree = "<group>"; };
+ F790688B04EF3E0D00000104 /* LocalAccountLarge.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = LocalAccountLarge.tiff; sourceTree = "<group>"; };
+ F790688C04EF3E0D00000104 /* Network (Large).tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "Network (Large).tiff"; sourceTree = "<group>"; };
+ F790688D04EF3E0D00000104 /* Network (Small).tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "Network (Small).tiff"; sourceTree = "<group>"; };
+ F790688E04EF3E0D00000104 /* NotThere.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = NotThere.icns; sourceTree = "<group>"; };
+ F790689404EF3E3900000104 /* LiImageView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiImageView.h; sourceTree = "<group>"; };
+ F790689504EF3E3900000104 /* FileSizeFormatter.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FileSizeFormatter.m; sourceTree = "<group>"; };
+ F790689604EF3E3900000104 /* InspectorViewController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = InspectorViewController.m; sourceTree = "<group>"; };
+ F790689704EF3E3900000104 /* LiBuiltInFunctions.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiBuiltInFunctions.m; sourceTree = "<group>"; };
+ F790689804EF3E3900000104 /* FileSizeFormatter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FileSizeFormatter.h; sourceTree = "<group>"; };
+ F790689904EF3E3900000104 /* HFSCodeFormatter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HFSCodeFormatter.h; sourceTree = "<group>"; };
+ F790689A04EF3E3900000104 /* HFSCodeFormatter.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = HFSCodeFormatter.m; sourceTree = "<group>"; };
+ F790689B04EF3E3900000104 /* InspectorViewController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = InspectorViewController.h; sourceTree = "<group>"; };
+ F790689C04EF3E3900000104 /* LiBuiltInFunctions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LiBuiltInFunctions.h; sourceTree = "<group>"; };
+ F790689D04EF3E3900000104 /* LiImageView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = LiImageView.m; sourceTree = "<group>"; };
+ F79068AD04EF3EED00000104 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/InspectorViews.nib; sourceTree = "<group>"; };
+ F79068AF04EF3EED00000104 /* English */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/BuiltInFunctions.strings; sourceTree = "<group>"; };
+ F79068B104EF3EED00000104 /* English */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/ErrorMessages.strings; sourceTree = "<group>"; };
+ F79068B504EF3F0D00000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = chef; path = chef.lproj/InspectorViews.nib; sourceTree = "<group>"; };
+ F79068B604EF3F1700000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = chef; path = chef.lproj/BuiltInFunctions.strings; sourceTree = "<group>"; };
+ F79068B704EF3F2600000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = chef; path = chef.lproj/ErrorMessages.strings; sourceTree = "<group>"; };
+ F79068B804EF3F5800000104 /* chef */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = chef; path = chef.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ F79068CA04EF42F700000104 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
+ F7D3980B0546864600BD181E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ F7D3980C0546864600BD181E /* Built In Functions.liaisonplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Built In Functions.liaisonplugin"; sourceTree = BUILT_PRODUCTS_DIR; };
+ F7D6587904F356ED00000104 /* LiBackend.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LiBackend.framework; path = ../../Frameworks/build/Development/LiBackend.framework; sourceTree = "<group>"; };
+ F7D6587A04F356ED00000104 /* LiPlugin.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LiPlugin.framework; path = ../../Frameworks/build/Development/LiPlugin.framework; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F7D398040546864600BD181E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D398050546864600BD181E /* Cocoa.framework in Frameworks */,
+ F7D398060546864600BD181E /* Carbon.framework in Frameworks */,
+ F7D398070546864600BD181E /* LiBackend.framework in Frameworks */,
+ F7D398080546864600BD181E /* LiPlugin.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 089C166AFE841209C02AAC07 /* Built In Functions */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB77AFFE84173DC02AAC07 /* Classes */,
+ 089C167CFE841241C02AAC07 /* Resources */,
+ 089C1671FE841209C02AAC07 /* Frameworks and Libraries */,
+ 19C28FB8FE9D52D311CA2CBB /* Products */,
+ );
+ name = "Built In Functions";
+ sourceTree = "<group>";
+ };
+ 089C1671FE841209C02AAC07 /* Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ F7D6587904F356ED00000104 /* LiBackend.framework */,
+ F7D6587A04F356ED00000104 /* LiPlugin.framework */,
+ F79068CA04EF42F700000104 /* Carbon.framework */,
+ 1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */,
+ 1058C7AEFEA557BF11CA2CBB /* Other Frameworks */,
+ );
+ name = "Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 089C167CFE841241C02AAC07 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ F7D3980B0546864600BD181E /* Info.plist */,
+ F79068AC04EF3EED00000104 /* InspectorViews.nib */,
+ F79068AE04EF3EED00000104 /* BuiltInFunctions.strings */,
+ F79068B004EF3EED00000104 /* ErrorMessages.strings */,
+ 089C167DFE841241C02AAC07 /* InfoPlist.strings */,
+ F790688904EF3E0D00000104 /* Images */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 08FB77AFFE84173DC02AAC07 /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ F75ACF1C04EF584E00000104 /* BuiltInFunctions.h */,
+ F790689C04EF3E3900000104 /* LiBuiltInFunctions.h */,
+ F790689704EF3E3900000104 /* LiBuiltInFunctions.m */,
+ F790689B04EF3E3900000104 /* InspectorViewController.h */,
+ F790689604EF3E3900000104 /* InspectorViewController.m */,
+ F790689404EF3E3900000104 /* LiImageView.h */,
+ F790689D04EF3E3900000104 /* LiImageView.m */,
+ F790689904EF3E3900000104 /* HFSCodeFormatter.h */,
+ F790689A04EF3E3900000104 /* HFSCodeFormatter.m */,
+ F790689804EF3E3900000104 /* FileSizeFormatter.h */,
+ F790689504EF3E3900000104 /* FileSizeFormatter.m */,
+ F71CA8EF0502854900000104 /* NaturalDateFormatter.h */,
+ F71CA8F00502854900000104 /* NaturalDateFormatter.m */,
+ F790688004EF3DEB00000104 /* IconFamily */,
+ F790687604EF3DE200000104 /* BDAlias */,
+ );
+ name = Classes;
+ sourceTree = "<group>";
+ };
+ 1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */,
+ );
+ name = "Linked Frameworks";
+ sourceTree = "<group>";
+ };
+ 1058C7AEFEA557BF11CA2CBB /* Other Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 089C1672FE841209C02AAC07 /* Foundation.framework */,
+ 089C167FFE841241C02AAC07 /* AppKit.framework */,
+ );
+ name = "Other Frameworks";
+ sourceTree = "<group>";
+ };
+ 19C28FB8FE9D52D311CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F7D3980C0546864600BD181E /* Built In Functions.liaisonplugin */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ F790687604EF3DE200000104 /* BDAlias */ = {
+ isa = PBXGroup;
+ children = (
+ F790687704EF3DE200000104 /* BDAlias.h */,
+ F790687804EF3DE200000104 /* BDAlias.m */,
+ F790687904EF3DE200000104 /* BDAlias.rtf */,
+ F790687A04EF3DE200000104 /* License.rtf */,
+ );
+ name = BDAlias;
+ path = BDAlias/BDAlias;
+ sourceTree = "<group>";
+ };
+ F790688004EF3DEB00000104 /* IconFamily */ = {
+ isa = PBXGroup;
+ children = (
+ F790688104EF3DEB00000104 /* IconFamily.h */,
+ F790688204EF3DEB00000104 /* IconFamily.m */,
+ F790688304EF3DEB00000104 /* NSString+CarbonFSSpecCreation.h */,
+ F790688404EF3DEC00000104 /* NSString+CarbonFSSpecCreation.m */,
+ );
+ name = IconFamily;
+ path = IconFamily/IconFamily;
+ sourceTree = "<group>";
+ };
+ F790688904EF3E0D00000104 /* Images */ = {
+ isa = PBXGroup;
+ children = (
+ F790688A04EF3E0D00000104 /* local.tiff */,
+ F790688B04EF3E0D00000104 /* LocalAccountLarge.tiff */,
+ F790688C04EF3E0D00000104 /* Network (Large).tiff */,
+ F790688D04EF3E0D00000104 /* Network (Small).tiff */,
+ F790688E04EF3E0D00000104 /* NotThere.icns */,
+ );
+ path = Images;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ F7D397E30546864600BD181E /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D397E40546864600BD181E /* BDAlias.h in Headers */,
+ F7D397E50546864600BD181E /* IconFamily.h in Headers */,
+ F7D397E60546864600BD181E /* NSString+CarbonFSSpecCreation.h in Headers */,
+ F7D397E70546864600BD181E /* LiImageView.h in Headers */,
+ F7D397E80546864600BD181E /* FileSizeFormatter.h in Headers */,
+ F7D397E90546864600BD181E /* HFSCodeFormatter.h in Headers */,
+ F7D397EA0546864600BD181E /* InspectorViewController.h in Headers */,
+ F7D397EB0546864600BD181E /* LiBuiltInFunctions.h in Headers */,
+ F7D397EC0546864600BD181E /* BuiltInFunctions.h in Headers */,
+ F7D397ED0546864600BD181E /* NaturalDateFormatter.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ F7D397E20546864600BD181E /* Built In Functions */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 28986764095DAB7900B5DC99 /* Build configuration list for PBXNativeTarget "Built In Functions" */;
+ buildPhases = (
+ F7D397E30546864600BD181E /* Headers */,
+ F7D397EE0546864600BD181E /* Resources */,
+ F7D397FA0546864600BD181E /* Sources */,
+ F7D398040546864600BD181E /* Frameworks */,
+ F7D398090546864600BD181E /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "Built In Functions";
+ productInstallPath = "@executable_path/../Plugins";
+ productName = "Built In Functions";
+ productReference = F7D3980C0546864600BD181E /* Built In Functions.liaisonplugin */;
+ productType = "com.apple.product-type.bundle";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 089C1669FE841209C02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 28986768095DAB7900B5DC99 /* Build configuration list for PBXProject "BuiltInFunctions" */;
+ compatibilityVersion = "Xcode 2.4";
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ chef,
+ );
+ mainGroup = 089C166AFE841209C02AAC07 /* Built In Functions */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F7D397E20546864600BD181E /* Built In Functions */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ F7D397EE0546864600BD181E /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D397EF0546864600BD181E /* InfoPlist.strings in Resources */,
+ F7D397F00546864600BD181E /* BDAlias.rtf in Resources */,
+ F7D397F10546864600BD181E /* License.rtf in Resources */,
+ F7D397F20546864600BD181E /* local.tiff in Resources */,
+ F7D397F30546864600BD181E /* LocalAccountLarge.tiff in Resources */,
+ F7D397F40546864600BD181E /* Network (Large).tiff in Resources */,
+ F7D397F50546864600BD181E /* Network (Small).tiff in Resources */,
+ F7D397F60546864600BD181E /* NotThere.icns in Resources */,
+ F7D397F70546864600BD181E /* InspectorViews.nib in Resources */,
+ F7D397F80546864600BD181E /* BuiltInFunctions.strings in Resources */,
+ F7D397F90546864600BD181E /* ErrorMessages.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ F7D398090546864600BD181E /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F7D397FA0546864600BD181E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F7D397FB0546864600BD181E /* BDAlias.m in Sources */,
+ F7D397FC0546864600BD181E /* IconFamily.m in Sources */,
+ F7D397FD0546864600BD181E /* NSString+CarbonFSSpecCreation.m in Sources */,
+ F7D397FE0546864600BD181E /* FileSizeFormatter.m in Sources */,
+ F7D397FF0546864600BD181E /* InspectorViewController.m in Sources */,
+ F7D398000546864600BD181E /* LiBuiltInFunctions.m in Sources */,
+ F7D398010546864600BD181E /* HFSCodeFormatter.m in Sources */,
+ F7D398020546864600BD181E /* LiImageView.m in Sources */,
+ F7D398030546864600BD181E /* NaturalDateFormatter.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 089C167DFE841241C02AAC07 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 089C167EFE841241C02AAC07 /* English */,
+ F79068B804EF3F5800000104 /* chef */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+ F79068AC04EF3EED00000104 /* InspectorViews.nib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F79068AD04EF3EED00000104 /* English */,
+ F79068B504EF3F0D00000104 /* chef */,
+ );
+ name = InspectorViews.nib;
+ sourceTree = "<group>";
+ };
+ F79068AE04EF3EED00000104 /* BuiltInFunctions.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F79068AF04EF3EED00000104 /* English */,
+ F79068B604EF3F1700000104 /* chef */,
+ );
+ name = BuiltInFunctions.strings;
+ sourceTree = "<group>";
+ };
+ F79068B004EF3EED00000104 /* ErrorMessages.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F79068B104EF3EED00000104 /* English */,
+ F79068B704EF3F2600000104 /* chef */,
+ );
+ name = ErrorMessages.strings;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 28986765095DAB7900B5DC99 /* 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_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = BuiltInFunctions.h;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = "";
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@executable_path/../Plugins";
+ LIBRARY_SEARCH_PATHS = "";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0x20000000,
+ );
+ PRODUCT_NAME = "Built In Functions";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = liaisonplugin;
+ ZERO_LINK = YES;
+ };
+ name = Development;
+ };
+ 28986766095DAB7900B5DC99 /* 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 = BuiltInFunctions.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 = "@executable_path/../Plugins";
+ LIBRARY_SEARCH_PATHS = "";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0x20000000,
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "Built In Functions";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = liaisonplugin;
+ ZERO_LINK = NO;
+ };
+ name = Deployment;
+ };
+ 28986767095DAB7900B5DC99 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CC = "/usr/bin/gcc-3.3";
+ CPLUSPLUS = "/usr/bin/g++-3.3";
+ FRAMEWORK_SEARCH_PATHS = ../../Frameworks/build;
+ GCC_PREFIX_HEADER = BuiltInFunctions.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 = "@executable_path/../Plugins";
+ LIBRARY_SEARCH_PATHS = "";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0x20000000,
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "Built In Functions";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = liaisonplugin;
+ };
+ name = Default;
+ };
+ 28986769095DAB7900B5DC99 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Development;
+ };
+ 2898676A095DAB7900B5DC99 /* Deployment */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Deployment;
+ };
+ 2898676B095DAB7900B5DC99 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Default;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 28986764095DAB7900B5DC99 /* Build configuration list for PBXNativeTarget "Built In Functions" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 28986765095DAB7900B5DC99 /* Development */,
+ 28986766095DAB7900B5DC99 /* Deployment */,
+ 28986767095DAB7900B5DC99 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 28986768095DAB7900B5DC99 /* Build configuration list for PBXProject "BuiltInFunctions" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 28986769095DAB7900B5DC99 /* Development */,
+ 2898676A095DAB7900B5DC99 /* Deployment */,
+ 2898676B095DAB7900B5DC99 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 089C1669FE841209C02AAC07 /* Project object */;
+}
diff --git a/Plugins/BuiltInFunctions/English.lproj/BuiltInFunctions.strings b/Plugins/BuiltInFunctions/English.lproj/BuiltInFunctions.strings
new file mode 100644
index 0000000..5d0a940
--- /dev/null
+++ b/Plugins/BuiltInFunctions/English.lproj/BuiltInFunctions.strings
@@ -0,0 +1,26 @@
+/* Headers for columns. */
+IconHeader = "Icon";
+FilenameHeader = "Filename";
+TypeHeader = "Type";
+LastModifiedTimeHeader = "Last Modified";
+CreatedTimeHeader = "Created";
+FileSizeHeader = "Size";
+
+/* Error messages. */
+UnableToResolveAlias = "unable to resolve alias";
+
+/* Default library name. */
+LiLibraryName = "My Library";
+
+/* Names for filters. */
+LiFilenameAttribute = "filename";
+LiTypeAttribute = "type";
+
+/* Names for operators. */
+LiEqualsOperator = "is";
+LiContainsOperator = "contains";
+
+/* For the natural language formatter. */
+Today = "Today";
+Yesterday = "Yesterday";
+Tomorrow = "Tomorrow"; \ No newline at end of file
diff --git a/Plugins/BuiltInFunctions/English.lproj/ErrorMessages.strings b/Plugins/BuiltInFunctions/English.lproj/ErrorMessages.strings
new file mode 100644
index 0000000..edc17d9
--- /dev/null
+++ b/Plugins/BuiltInFunctions/English.lproj/ErrorMessages.strings
@@ -0,0 +1,10 @@
+/* Errors for file rename operations. */
+LiGenericRenameErrorHeader = "The file couldn't be renamed.";
+LiGenericRenameErrorContents = "Try shaking a dead chicken (or chicken substitute) at the screen.";
+
+LiBadFilenameErrorHeader = "The file couldn't be renamed because it contained an illegal character.";
+LiBadFilenameErrorContents = "You can try to rename the file without the slash \"/\" or colon \":\" characters.";
+LiReadOnlyFileSytemErrorHeader = "The file couldn't be modified because the filesystem is read-only.";
+LiReadOnlyFileSytemErrorContents = "You need to talk to your system administrator to fix this.";
+LiPermissionDeniedErrorHeader = "The file couldn't be modified because you lack permission to change the file.";
+LiPermissionDeniedErrorContents = "You can modify your folder permissions in the Finder.";
diff --git a/Plugins/BuiltInFunctions/English.lproj/InfoPlist.strings b/Plugins/BuiltInFunctions/English.lproj/InfoPlist.strings
new file mode 100644
index 0000000..dd02662
--- /dev/null
+++ b/Plugins/BuiltInFunctions/English.lproj/InfoPlist.strings
Binary files differ
diff --git a/Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/classes.nib b/Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/classes.nib
new file mode 100644
index 0000000..5cbffd3
--- /dev/null
+++ b/Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/classes.nib
@@ -0,0 +1,38 @@
+{
+ IBClasses = (
+ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
+ {CLASS = HFSCodeFormatter; LANGUAGE = ObjC; SUPERCLASS = NSFormatter; },
+ {
+ ACTIONS = {
+ setApplication = id;
+ setFilename = id;
+ setHFSCreatorField = id;
+ setHFSTypeField = id;
+ setIcon = id;
+ setType = id;
+ };
+ CLASS = InspectorViewController;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ hfsCreatorField = NSTextField;
+ hfsTypeField = NSTextField;
+ iconView = NSImageView;
+ pathField = NSTextField;
+ theApplicationButton = NSPopUpButton;
+ theFileTabView = NSView;
+ theFilenameField = NSTextField;
+ theHFSTabView = NSView;
+ theTypeField = NSTextField;
+ };
+ SUPERCLASS = NSObject;
+ },
+ {
+ CLASS = LiBuiltInFunctions;
+ LANGUAGE = ObjC;
+ OUTLETS = {theController = InspectorViewController; };
+ SUPERCLASS = NSObject;
+ },
+ {CLASS = LiImageView; LANGUAGE = ObjC; SUPERCLASS = NSImageView; }
+ );
+ IBVersion = 1;
+} \ No newline at end of file
diff --git a/Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/info.nib b/Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/info.nib
new file mode 100644
index 0000000..a3a74f1
--- /dev/null
+++ b/Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/info.nib
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>69 167 356 240 0 0 1600 1178 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>48</key>
+ <string>682 743 235 123 0 0 1600 1178 </string>
+ <key>5</key>
+ <string>604 657 392 277 0 0 1600 1178 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>349.0</string>
+ <key>IBGroupedObjects</key>
+ <dict>
+ <key>1</key>
+ <array>
+ <string>28</string>
+ <string>27</string>
+ </array>
+ <key>2</key>
+ <array>
+ <string>36</string>
+ <string>37</string>
+ </array>
+ <key>3</key>
+ <array>
+ <string>30</string>
+ <string>31</string>
+ </array>
+ <key>4</key>
+ <array>
+ <string>41</string>
+ <string>33</string>
+ </array>
+ <key>5</key>
+ <array>
+ <string>75</string>
+ <string>77</string>
+ </array>
+ <key>6</key>
+ <array>
+ <string>76</string>
+ <string>78</string>
+ </array>
+ </dict>
+ <key>IBLastGroupID</key>
+ <string>8</string>
+ <key>IBOldestOS</key>
+ <integer>3</integer>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>48</integer>
+ <integer>5</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>7B85</string>
+</dict>
+</plist>
diff --git a/Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/keyedobjects.nib b/Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/keyedobjects.nib
new file mode 100644
index 0000000..2e6ed0c
--- /dev/null
+++ b/Plugins/BuiltInFunctions/English.lproj/InspectorViews.nib/keyedobjects.nib
Binary files differ
diff --git a/Plugins/BuiltInFunctions/FileSizeFormatter.h b/Plugins/BuiltInFunctions/FileSizeFormatter.h
new file mode 100644
index 0000000..25f08ae
--- /dev/null
+++ b/Plugins/BuiltInFunctions/FileSizeFormatter.h
@@ -0,0 +1,10 @@
+//
+// FileSizeFormatter.h
+// Liaison
+//
+// Created by Brian Cully on Fri May 09 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface FileSizeFormatter : NSNumberFormatter
+@end
diff --git a/Plugins/BuiltInFunctions/FileSizeFormatter.m b/Plugins/BuiltInFunctions/FileSizeFormatter.m
new file mode 100644
index 0000000..c6971e6
--- /dev/null
+++ b/Plugins/BuiltInFunctions/FileSizeFormatter.m
@@ -0,0 +1,47 @@
+//
+// FileSizeFormatter.m
+// Liaison
+//
+// Created by Brian Cully on Fri May 09 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "FileSizeFormatter.h"
+
+@implementation FileSizeFormatter
+- (NSString *)stringForObjectValue: (id)anObject
+{
+ if ([anObject isKindOfClass: [NSNumber class]]) {
+ NSString *suffix;
+ int shownSize;
+ unsigned long size;
+
+ size = [anObject unsignedLongValue];
+ if (size > 1024 * 1024 * 1024) {
+ shownSize = size / 1024 / 1024 / 1024;
+ suffix = @" G";
+ } else if (size > 1024 * 1024) {
+ shownSize = size / 1024 / 1024;
+ suffix = @" M";
+ } else if (size > 1024) {
+ shownSize = size / 1024;
+ suffix = @" K";
+ } else {
+ shownSize = size;
+ suffix = @" B";
+ }
+
+ return [NSString stringWithFormat: @"%ld%@", shownSize, suffix];
+ }
+
+ return [super stringForObjectValue: anObject];
+}
+
+- (BOOL)getObjectValue: (id *)anObject
+ forString: (NSString *)string
+ errorDescription: (NSString **)error
+{
+ *anObject = string;
+ return YES;
+}
+@end
diff --git a/Plugins/BuiltInFunctions/HFSCodeFormatter.h b/Plugins/BuiltInFunctions/HFSCodeFormatter.h
new file mode 100644
index 0000000..1cd59fb
--- /dev/null
+++ b/Plugins/BuiltInFunctions/HFSCodeFormatter.h
@@ -0,0 +1,4 @@
+/* HFSCodeFormatter */
+
+@interface HFSCodeFormatter : NSFormatter
+@end
diff --git a/Plugins/BuiltInFunctions/HFSCodeFormatter.m b/Plugins/BuiltInFunctions/HFSCodeFormatter.m
new file mode 100644
index 0000000..4c3d0c1
--- /dev/null
+++ b/Plugins/BuiltInFunctions/HFSCodeFormatter.m
@@ -0,0 +1,46 @@
+#import "HFSCodeFormatter.h"
+
+@implementation HFSCodeFormatter
+- (NSString *)stringForObjectValue: (id)anObject
+{
+ unsigned long longValue;
+ char a, b, c, d;
+
+ if ([anObject isKindOfClass: [NSNumber class]])
+ longValue = [anObject unsignedLongValue];
+ else
+ longValue = 0;
+
+ a = (longValue >> 24) & 0xff;
+ b = (longValue >> 16) & 0xff;
+ c = (longValue >> 8) & 0xff;
+ d = longValue & 0xff;
+
+ return [NSString stringWithFormat: @"%c%c%c%c", a, b, c, d];
+}
+
+- (BOOL)getObjectValue: (id *)anObject
+ forString: (NSString *)string
+ errorDescription: (NSString **)error
+{
+ unsigned long objectValue;
+ unsigned int i, bitNo;
+
+ bitNo = 24;
+ objectValue = 0;
+ for (i = 0; i < [string length] && i < 4; i++) {
+ objectValue += ([string characterAtIndex: i] & 0xff) << bitNo;
+ bitNo -= 8;
+ }
+ *anObject = [NSNumber numberWithUnsignedLong: objectValue];
+
+ return YES;
+}
+
+- (BOOL)isPartialStringValid: (NSString *)partialString
+ newEditingString: (NSString **)newString
+ errorDescription: (NSString **)error
+{
+ return [partialString length] <= 4;
+}
+@end
diff --git a/Plugins/BuiltInFunctions/IconFamily/IconFamily/IconFamily.h b/Plugins/BuiltInFunctions/IconFamily/IconFamily/IconFamily.h
new file mode 100644
index 0000000..443ee13
--- /dev/null
+++ b/Plugins/BuiltInFunctions/IconFamily/IconFamily/IconFamily.h
@@ -0,0 +1,184 @@
+// IconFamily.h
+// IconFamily class interface
+// by Troy Stephens, Thomas Schnitzer, David Remahl, Nathan Day and Ben Haller
+// version 0.5
+//
+// Project Home Page:
+// http://homepage.mac.com/troy_stephens/software/objects/IconFamily/
+//
+// Problems, shortcomings, and uncertainties that I'm aware of are flagged
+// with "NOTE:". Please address bug reports, bug fixes, suggestions, etc.
+// to me at troy_stephens@mac.com
+//
+// This code is provided as-is, with no warranty, in the hope that it will be
+// useful. However, it appears to work fine on Mac OS X 10.1.4. :-)
+
+#import <Cocoa/Cocoa.h>
+#import <Carbon/Carbon.h>
+
+// This class is a Cocoa/Objective-C wrapper for the Mac OS X Carbon API's
+// "icon family" data type. Its main purpose is to enable Cocoa applications
+// to easily create custom file icons from NSImage instances, and thus take
+// advantage of Mac OS X's new 128x128 RGBA "thumbnail" icon format to provide
+// richly detailed thumbnail previews of the files' contents.
+//
+// Using IconFamily, this becomes as simple as:
+//
+// id iconFamily = [IconFamily iconFamilyWithThumbnailsOfImage:anImage];
+// [iconFamily setAsCustomIconForFile:anExistingFile];
+//
+// You can also write an icon family to an .icns file using the -writeToFile:
+// method.
+
+@interface IconFamily : NSObject
+{
+ IconFamilyHandle hIconFamily;
+}
+
+// Convenience methods. These use the corresponding -init methods to return
+// an autoreleased IconFamily instance.
+//
+// NOTE: +iconFamily relies on -init, which is currently broken (see -init).
+
++ (IconFamily*) iconFamily;
++ (IconFamily*) iconFamilyWithContentsOfFile:(NSString*)path;
++ (IconFamily*) iconFamilyWithIconOfFile:(NSString*)path;
++ (IconFamily*) iconFamilyWithIconFamilyHandle:(IconFamilyHandle)hNewIconFamily;
++ (IconFamily*) iconFamilyWithSystemIcon:(int)fourByteCode;
++ (IconFamily*) iconFamilyWithThumbnailsOfImage:(NSImage*)image;
++ (IconFamily*) iconFamilyWithThumbnailsOfImage:(NSImage*)image usingImageInterpolation:(NSImageInterpolation)imageInterpolation;
+
+// Initializes as a new, empty IconFamily. This is IconFamily's designated
+// initializer method.
+//
+// NOTE: This method is broken until we figure out how to create a valid new
+// IconFamilyHandle! In the meantime, use -initWithContentsOfFile: to
+// load an existing .icns file that you can use as a starting point, and
+// use -setIconFamilyElement:fromBitmapImageRep: to replace its
+// elements. This is what the "MakeThumbnail" demo app does.
+
+- init;
+
+// Initializes an IconFamily by loading the contents of an .icns file.
+
+- initWithContentsOfFile:(NSString*)path;
+
+// Initializes an IconFamily from an existing Carbon IconFamilyHandle.
+
+- initWithIconFamilyHandle:(IconFamilyHandle)hNewIconFamily;
+
+// Initializes an IconFamily by loading the Finder icon that's assigned to a
+// file.
+
+- initWithIconOfFile:(NSString*)path;
+
+// Initializes an IconFamily by referencing a standard system icon.
+
+- initWithSystemIcon:(int)fourByteCode;
+
+// Initializes an IconFamily by creating its elements from a resampled
+// NSImage. The second form of this method allows you to specify the degree
+// of antialiasing to be used in resampling the image, by passing in one of
+// the NSImageInterpolation... constants that are defined in
+// NSGraphicsContext.h. The first form of this initializer simply calls the
+// second form with imageInterpolation set to NSImageInterpolationHigh, which
+// produces highly smoothed thumbnails.
+
+- initWithThumbnailsOfImage:(NSImage*)image;
+- initWithThumbnailsOfImage:(NSImage*)image usingImageInterpolation:(NSImageInterpolation)imageInterpolation;
+
+// Writes the icon family to an .icns file.
+
+- (BOOL) writeToFile:(NSString*)path;
+
+// Sets the image data for one of the icon family's elements from an
+// NSBitmapImageRep. The "elementType" parameter must be one of the icon
+// family element types listed below, and the format of the "bitmapImageRep"
+// must match the corresponding requirements specified below. Regardless of
+// the elementType, the bitmapImageRep must also be non-planar and have 8 bits
+// per sample.
+//
+// elementType dimensions format
+// ------------------- ---------- ---------------------------------------
+// kThumbnail32BitData 128 x 128 32-bit RGBA, 32-bit RGB, or 24-bit RGB
+// kThumbnail8BitMask 128 x 128 32-bit RGBA or 8-bit intensity
+// kLarge32BitData 32 x 32 32-bit RGBA, 32-bit RGB, or 24-bit RGB
+// kLarge8BitMask 32 x 32 32-bit RGBA or 8-bit intensity
+// kLarge1BitMask 32 x 32 32-bit RGBA, 8-bit intensity, or 1-bit
+// kSmall32BitData 16 x 16 32-bit RGBA, 32-bit RGB, or 24-bit RGB
+// kSmall8BitMask 16 x 16 32-bit RGBA or 8-bit intensity
+// kSmall1BitMask 16 x 16 32-bit RGBA, 8-bit intensity, or 1-bit
+//
+// When an RGBA image is supplied to set a "Mask" element, the mask data is
+// taken from the image's alpha channel.
+//
+// NOTE: Setting an IconFamily's kLarge1BitMask seems to damage the IconFamily
+// for some as yet unknown reason. (If you then assign the icon family
+// as a file's custom icon using -setAsCustomIconForFile:, the custom
+// icon doesn't appear for the file in the Finder.) However, both
+// custom icon display and mouse-click hit-testing in the Finder seem to
+// work fine when we only set the other four elements (thus keeping the
+// existing kLarge1BitMask from the valid icon family from which we
+// initialized the IconFamily via -initWithContentsOfFile:, since
+// IconFamily's -init method is currently broken...), so it seems safe
+// to just leave the kLarge1BitMask alone.
+
+- (BOOL) setIconFamilyElement:(OSType)elementType
+ fromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep;
+
+// Gets the image data for one of the icon family's elements as a new, 32-bit
+// RGBA NSBitmapImageRep. The specified elementType should be one of
+// kThumbnail32BitData, kLarge32BitData, or kSmall32BitData.
+//
+// The returned NSBitmapImageRep will have the corresponding 8-bit mask data
+// in its alpha channel, or a fully opaque alpha channel if the icon family
+// has no 8-bit mask data for the specified alpha channel.
+//
+// Returns nil if the requested element cannot be retrieved (e.g. if the
+// icon family has no such 32BitData element).
+
+- (NSBitmapImageRep*) bitmapImageRepWithAlphaForIconFamilyElement:(OSType)elementType;
+
+// Creates and returns an NSImage that contains the icon family's various
+// elements as its NSImageReps.
+
+- (NSImage*) imageWithAllReps;
+
+// NOTE: Planned method -- not yet implemented.
+//
+// Gets the image data for one of the icon family's elements as a new
+// NSBitmapImageRep. The specified elementType should be one of
+// kThumbnail32BitData, kThumbnail32BitMask, kLarge32BitData, kLarge8BitMask,
+// kLarge1BitMask, kSmall32BitData, kSmall8BitMask, or kSmall1BitMask.
+
+// - (NSBitmapImageRep*) bitmapImageRepForIconFamilyElement:(OSType)elementType;
+
+// Writes the icon family to the resource fork of the specified file as its
+// kCustomIconResource, and sets the necessary Finder bits so the icon will
+// be displayed for the file in Finder views.
+
+- (BOOL) setAsCustomIconForFile:(NSString*)path;
+- (BOOL) setAsCustomIconForFile:(NSString*)path withCompatibility:(BOOL)compat;
+
+// Same as the -setAsCustomIconForFile:... methods, but for folders (directories).
+
+- (BOOL) setAsCustomIconForDirectory:(NSString*)path;
+- (BOOL) setAsCustomIconForDirectory:(NSString*)path withCompatibility:(BOOL)compat;
+
+// Removes the custom icon (if any) from the specified file's resource fork,
+// and clears the necessary Finder bits for the file. (Note that this is a
+// class method, so you don't need an instance of IconFamily to invoke it.)
+
++ (BOOL) removeCustomIconFromFile:(NSString*)path;
+
+@property IconFamilyHandle hIconFamily;
+@end
+
+// Methods for interfacing with the Carbon Scrap Manager (analogous to and
+// interoperable with the Cocoa Pasteboard).
+@interface IconFamily (ScrapAdditions)
++ (BOOL) canInitWithScrap;
++ (IconFamily*) iconFamilyWithScrap;
+- initWithScrap;
+- (BOOL) putOnScrap;
+@end
diff --git a/Plugins/BuiltInFunctions/IconFamily/IconFamily/IconFamily.m b/Plugins/BuiltInFunctions/IconFamily/IconFamily/IconFamily.m
new file mode 100644
index 0000000..2ce64f4
--- /dev/null
+++ b/Plugins/BuiltInFunctions/IconFamily/IconFamily/IconFamily.m
@@ -0,0 +1,1426 @@
+// IconFamily.m
+// IconFamily class implementation
+// by Troy Stephens, Thomas Schnitzer, David Remahl, Nathan Day and Ben Haller
+// version 0.5
+//
+// Project Home Page:
+// http://homepage.mac.com/troy_stephens/software/objects/IconFamily/
+//
+// Problems, shortcomings, and uncertainties that I'm aware of are flagged
+// with "NOTE:". Please address bug reports, bug fixes, suggestions, etc.
+// to me at troy_stephens@mac.com
+//
+// This code is provided as-is, with no warranty, in the hope that it will be
+// useful. However, it appears to work fine on Mac OS X 10.1.5 and 10.2. :-)
+
+#import "IconFamily.h"
+#import "NSString+CarbonFSSpecCreation.h"
+
+#define unknownOSType 0x3f3f3f3f
+
+@interface IconFamily (Internals)
+
++ (NSImage*) resampleImage:(NSImage*)image toIconWidth:(int)width usingImageInterpolation:(NSImageInterpolation)imageInterpolation;
+
++ (Handle) get32BitDataFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize;
+
++ (Handle) get8BitDataFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize;
+
++ (Handle) get8BitMaskFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize;
+
++ (Handle) get1BitMaskFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize;
+
+- (BOOL) addResourceType:(OSType)type asResID:(int)resID;
+
+@end
+
+@implementation IconFamily
+
++ (IconFamily*) iconFamily
+{
+ return [[[IconFamily alloc] init] autorelease];
+}
+
++ (IconFamily*) iconFamilyWithContentsOfFile:(NSString*)path
+{
+ return [[[IconFamily alloc] initWithContentsOfFile:path] autorelease];
+}
+
++ (IconFamily*) iconFamilyWithIconOfFile:(NSString*)path
+{
+ return [[[IconFamily alloc] initWithIconOfFile:path] autorelease];
+}
+
++ (IconFamily*) iconFamilyWithIconFamilyHandle:(IconFamilyHandle)hNewIconFamily
+{
+ return [[[IconFamily alloc] initWithIconFamilyHandle:hNewIconFamily] autorelease];
+}
+
++ (IconFamily*) iconFamilyWithSystemIcon:(int)fourByteCode
+{
+ return [[[IconFamily alloc] initWithSystemIcon:fourByteCode] autorelease];
+}
+
++ (IconFamily*) iconFamilyWithThumbnailsOfImage:(NSImage*)image
+{
+ return [[[IconFamily alloc] initWithThumbnailsOfImage:image] autorelease];
+}
+
++ (IconFamily*) iconFamilyWithThumbnailsOfImage:(NSImage*)image usingImageInterpolation:(NSImageInterpolation)imageInterpolation
+{
+ return [[[IconFamily alloc] initWithThumbnailsOfImage:image usingImageInterpolation:imageInterpolation] autorelease];
+}
+
+// This is IconFamily's designated initializer. It creates a new IconFamily that initially has no elements.
+//
+// The proper way to do this is to simply allocate a zero-sized handle (not to be confused with an empty handle) and assign it to hIconFamily. This technique works on Mac OS X 10.2 as well as on 10.0.x and 10.1.x. Our previous technique of allocating an IconFamily struct with a resourceSize of 0 no longer works as of Mac OS X 10.2.
+- init
+{
+ self = [super init];
+ if (self) {
+ hIconFamily = (IconFamilyHandle) NewHandle( 0 );
+ if (hIconFamily == NULL) {
+ [self autorelease];
+ return nil;
+ }
+ }
+ return self;
+}
+
+- initWithContentsOfFile:(NSString*)path
+{
+ FSSpec fsSpec;
+ OSErr result;
+
+ self = [self init];
+ if (self) {
+ if (hIconFamily) {
+ DisposeHandle( (Handle)hIconFamily );
+ hIconFamily = NULL;
+ }
+ if (![path getFSSpec:&fsSpec createFileIfNecessary:NO]) {
+ [self autorelease];
+ return nil;
+ }
+ result = ReadIconFile( &fsSpec, &hIconFamily );
+ if (result != noErr) {
+ [self autorelease];
+ return nil;
+ }
+ }
+ return self;
+}
+
+- initWithIconFamilyHandle:(IconFamilyHandle)hNewIconFamily
+{
+ self = [self init];
+ if (self) {
+ if (hIconFamily) {
+ DisposeHandle( (Handle)hIconFamily );
+ hIconFamily = NULL;
+ }
+ // NOTE: Do we have to somehow "retain" the handle
+ // (increment its reference count)?
+ hIconFamily = hNewIconFamily;
+ }
+ return self;
+}
+
+- initWithIconOfFile:(NSString*)path
+{
+ IconRef iconRef;
+ OSErr result;
+ SInt16 label;
+ FSSpec fileSpec;
+
+ self = [self init];
+ if (self)
+ {
+ if (hIconFamily)
+ {
+ DisposeHandle( (Handle)hIconFamily );
+ hIconFamily = NULL;
+ }
+
+ if( ![path getFSSpec:&fileSpec createFileIfNecessary:NO] )
+ {
+ [self autorelease];
+ return nil;
+ }
+
+ result = GetIconRefFromFile(
+ &fileSpec,
+ &iconRef,
+ &label );
+
+ if (result != noErr)
+ {
+ [self autorelease];
+ return nil;
+ }
+
+ result = IconRefToIconFamily(
+ iconRef,
+ kSelectorAllAvailableData,
+ &hIconFamily );
+
+ if (result != noErr || !hIconFamily)
+ {
+ [self autorelease];
+ return nil;
+ }
+
+ ReleaseIconRef( iconRef );
+ }
+ return self;
+}
+
+- initWithSystemIcon:(int)fourByteCode
+{
+ IconRef iconRef;
+ OSErr result;
+
+ self = [self init];
+ if (self)
+ {
+ if (hIconFamily)
+ {
+ DisposeHandle( (Handle)hIconFamily );
+ hIconFamily = NULL;
+ }
+
+ result = GetIconRef(kOnSystemDisk, kSystemIconsCreator, fourByteCode, &iconRef);
+
+ if (result != noErr)
+ {
+ [self autorelease];
+ return nil;
+ }
+
+ result = IconRefToIconFamily(
+ iconRef,
+ kSelectorAllAvailableData,
+ &hIconFamily );
+
+ if (result != noErr || !hIconFamily)
+ {
+ [self autorelease];
+ return nil;
+ }
+
+ ReleaseIconRef( iconRef );
+ }
+ return self;
+}
+
+- initWithThumbnailsOfImage:(NSImage*)image
+{
+ // The default is to use a high degree of antialiasing, producing a smooth image.
+ return [self initWithThumbnailsOfImage:image usingImageInterpolation:NSImageInterpolationHigh];
+}
+
+- initWithThumbnailsOfImage:(NSImage*)image usingImageInterpolation:(NSImageInterpolation)imageInterpolation
+{
+ NSImage* iconImage128x128;
+ NSImage* iconImage32x32;
+ NSImage* iconImage16x16;
+ NSBitmapImageRep* iconBitmap128x128;
+ NSBitmapImageRep* iconBitmap32x32;
+ NSBitmapImageRep* iconBitmap16x16;
+ NSImage* bitmappedIconImage128x128;
+
+ // Start with a new, empty IconFamily.
+ self = [self init];
+ if (self == nil)
+ return nil;
+
+ // Resample the given image to create a 128x128 pixel, 32-bit RGBA
+ // version, and use that as our "thumbnail" (128x128) icon and mask.
+ //
+ // Our +resampleImage:toIconWidth:... method, in its present form,
+ // returns an NSImage that contains an NSCacheImageRep, rather than
+ // an NSBitmapImageRep. We convert to an NSBitmapImageRep, so that
+ // our methods can scan the image data, using initWithFocusedViewRect:.
+ iconImage128x128 = [IconFamily resampleImage:image toIconWidth:128 usingImageInterpolation:imageInterpolation];
+ [iconImage128x128 lockFocus];
+ iconBitmap128x128 = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, 128, 128)];
+ [iconImage128x128 unlockFocus];
+ if (iconBitmap128x128) {
+ [self setIconFamilyElement:kThumbnail32BitData fromBitmapImageRep:iconBitmap128x128];
+ [self setIconFamilyElement:kThumbnail8BitMask fromBitmapImageRep:iconBitmap128x128];
+ }
+
+ // Create an NSImage with the iconBitmap128x128 NSBitmapImageRep, that we
+ // can resample to create the smaller icon family elements. (This is
+ // most likely more efficient than resampling from the original image again,
+ // particularly if it is large. It produces a slightly different result, but
+ // the difference is minor and should not be objectionable...)
+ bitmappedIconImage128x128 = [[NSImage alloc] initWithSize:NSMakeSize(128,128)];
+ [bitmappedIconImage128x128 addRepresentation:iconBitmap128x128];
+
+ // Resample the 128x128 image to create a 32x32 pixel, 32-bit RGBA version,
+ // and use that as our "large" (32x32) icon and 8-bit mask.
+ iconImage32x32 = [IconFamily resampleImage:bitmappedIconImage128x128 toIconWidth:32 usingImageInterpolation:imageInterpolation];
+ [iconImage32x32 lockFocus];
+ iconBitmap32x32 = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, 32, 32)];
+ [iconImage32x32 unlockFocus];
+ if (iconBitmap32x32) {
+ [self setIconFamilyElement:kLarge32BitData fromBitmapImageRep:iconBitmap32x32];
+ [self setIconFamilyElement:kLarge8BitData fromBitmapImageRep:iconBitmap32x32];
+ [self setIconFamilyElement:kLarge8BitMask fromBitmapImageRep:iconBitmap32x32];
+ [self setIconFamilyElement:kLarge1BitMask fromBitmapImageRep:iconBitmap32x32];
+ }
+
+ // Resample the 128x128 image to create a 16x16 pixel, 32-bit RGBA version,
+ // and use that as our "small" (16x16) icon and 8-bit mask.
+ iconImage16x16 = [IconFamily resampleImage:bitmappedIconImage128x128 toIconWidth:16 usingImageInterpolation:imageInterpolation];
+ [iconImage16x16 lockFocus];
+ iconBitmap16x16 = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, 16, 16)];
+ [iconImage16x16 unlockFocus];
+ if (iconBitmap16x16) {
+ [self setIconFamilyElement:kSmall32BitData fromBitmapImageRep:iconBitmap16x16];
+ [self setIconFamilyElement:kSmall8BitData fromBitmapImageRep:iconBitmap16x16];
+ [self setIconFamilyElement:kSmall8BitMask fromBitmapImageRep:iconBitmap16x16];
+ [self setIconFamilyElement:kSmall1BitMask fromBitmapImageRep:iconBitmap16x16];
+ }
+
+ // Release all of the images that we created and no longer need.
+ [bitmappedIconImage128x128 release];
+ [iconBitmap128x128 release];
+ [iconBitmap32x32 release];
+ [iconBitmap16x16 release];
+
+ // Return the new icon family!
+ return self;
+}
+
+- (void) dealloc
+{
+ DisposeHandle( (Handle)hIconFamily );
+ [super dealloc];
+}
+
+- (NSBitmapImageRep*) bitmapImageRepWithAlphaForIconFamilyElement:(OSType)elementType;
+{
+ NSBitmapImageRep* bitmapImageRep;
+ int pixelsWide;
+ Handle hRawBitmapData;
+ Handle hRawMaskData;
+ OSType maskElementType;
+ OSErr result;
+ unsigned long* pRawBitmapData;
+ unsigned long* pRawBitmapDataEnd;
+ unsigned char* pRawMaskData;
+ unsigned char* pBitmapImageRepBitmapData;
+
+ // Make sure elementType is a valid type that we know how to handle, and
+ // figure out the dimensions and bit depth of the bitmap for that type.
+ switch (elementType) {
+ // 'it32' 128x128 32-bit RGB image
+ case kThumbnail32BitData:
+ maskElementType = kThumbnail8BitMask;
+ pixelsWide = 128;
+ break;
+
+ // 'il32' 32x32 32-bit RGB image
+ case kLarge32BitData:
+ maskElementType = kLarge8BitMask;
+ pixelsWide = 32;
+ break;
+
+ // 'is32' 16x16 32-bit RGB image
+ case kSmall32BitData:
+ maskElementType = kSmall8BitMask;
+ pixelsWide = 16;
+ break;
+
+ default:
+ return nil;
+ }
+
+ // Get the raw, uncompressed bitmap data for the requested element.
+ hRawBitmapData = NewHandle( pixelsWide * pixelsWide * 4 );
+ result = GetIconFamilyData( hIconFamily, elementType, hRawBitmapData );
+ if (result != noErr) {
+ DisposeHandle( hRawBitmapData );
+ return nil;
+ }
+
+ // Get the corresponding raw, uncompressed 8-bit mask data.
+ hRawMaskData = NewHandle( pixelsWide * pixelsWide );
+ result = GetIconFamilyData( hIconFamily, maskElementType, hRawMaskData );
+ if (result != noErr) {
+ DisposeHandle( hRawMaskData );
+ hRawMaskData = NULL;
+ }
+
+ // The retrieved raw bitmap data is stored at 32 bits per pixel: 3 bytes
+ // for the RGB color of each pixel, plus an extra unused byte. We can
+ // therefore fold the mask data into the color data in-place (though
+ // getting the proper byte ordering requires some bit-shifting).
+ HLock( hRawBitmapData );
+ pRawBitmapData = (unsigned long*) *hRawBitmapData;
+ pRawBitmapDataEnd = pRawBitmapData + pixelsWide * pixelsWide;
+ if (hRawMaskData) {
+ HLock( hRawMaskData );
+ pRawMaskData = *hRawMaskData;
+ while (pRawBitmapData < pRawBitmapDataEnd) {
+ //*pRawBitmapData++ = (*pRawBitmapData << 8) | *pRawMaskData++;
+ pRawBitmapData++;
+ *pRawBitmapData = (*pRawBitmapData << 8) | *pRawMaskData++;
+ }
+ HUnlock( hRawMaskData );
+ } else {
+ while (pRawBitmapData < pRawBitmapDataEnd) {
+ //*pRawBitmapData++ = (*pRawBitmapData << 8) | 0xff;
+ pRawBitmapData++;
+ *pRawBitmapData = (*pRawBitmapData << 8) | 0xff;
+ }
+ }
+
+ // Create a new NSBitmapImageRep with the given bitmap data. Note that
+ // when creating the NSBitmapImageRep we pass in NULL for the "planes"
+ // parameter. This causes the new NSBitmapImageRep to allocate its own
+ // buffer for the bitmap data (which it will own and release when the
+ // NSBitmapImageRep is released), rather than referencing the bitmap
+ // data we pass in (which will soon disappear when we call
+ // DisposeHandle() below!). (See the NSBitmapImageRep documentation for
+ // the -initWithBitmapDataPlanes:... method, where this is explained.)
+ //
+ // Once we have the new NSBitmapImageRep, we get a pointer to its
+ // bitmapData and copy our bitmap data in.
+ bitmapImageRep = [[[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:NULL
+ pixelsWide:pixelsWide
+ pixelsHigh:pixelsWide
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace // NOTE: is this right?
+ bytesPerRow:0
+ bitsPerPixel:0] autorelease];
+ pBitmapImageRepBitmapData = [bitmapImageRep bitmapData];
+ if (pBitmapImageRepBitmapData) {
+ memcpy( pBitmapImageRepBitmapData, *hRawBitmapData,
+ pixelsWide * pixelsWide * 4 );
+ }
+ HUnlock( hRawBitmapData );
+
+ // Free the retrieved raw data.
+ DisposeHandle( hRawBitmapData );
+ if (hRawMaskData)
+ DisposeHandle( hRawMaskData );
+
+ // Return nil if the NSBitmapImageRep didn't give us a buffer to copy into.
+ if (pBitmapImageRepBitmapData == NULL)
+ return nil;
+
+ // Return the new NSBitmapImageRep.
+ return bitmapImageRep;
+}
+
+- (NSImage*) imageWithAllReps
+{
+ NSImage* image = NULL;
+ image = [[[NSImage alloc] initWithData:[NSData dataWithBytes:*hIconFamily length:GetHandleSize((Handle)hIconFamily)]] autorelease];
+
+ return image;
+
+ //investigate optimisations (dataWithBytesNoCopy:length: for example...)
+}
+
+- (BOOL) setIconFamilyElement:(OSType)elementType fromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep
+{
+ Handle hRawData = NULL;
+ OSErr result;
+
+ switch (elementType) {
+ // 'it32' 128x128 32-bit RGB image
+ case kThumbnail32BitData:
+ hRawData = [IconFamily get32BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:128];
+ break;
+
+ // 't8mk' 128x128 8-bit alpha mask
+ case kThumbnail8BitMask:
+ hRawData = [IconFamily get8BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:128];
+ break;
+
+ // 'il32' 32x32 32-bit RGB image
+ case kLarge32BitData:
+ hRawData = [IconFamily get32BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:32];
+ break;
+
+ // 'l8mk' 32x32 8-bit alpha mask
+ case kLarge8BitMask:
+ hRawData = [IconFamily get8BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:32];
+ break;
+
+ // 'ICN#' 32x32 1-bit alpha mask
+ case kLarge1BitMask:
+ hRawData = [IconFamily get1BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:32];
+ break;
+
+ // 'icl8' 32x32 8-bit indexed image data
+ case kLarge8BitData:
+ hRawData = [IconFamily get8BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:32];
+ break;
+
+ // 'is32' 16x16 32-bit RGB image
+ case kSmall32BitData:
+ hRawData = [IconFamily get32BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:16];
+ break;
+
+ // 's8mk' 16x16 8-bit alpha mask
+ case kSmall8BitMask:
+ hRawData = [IconFamily get8BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:16];
+ break;
+
+ // 'ics#' 16x16 1-bit alpha mask
+ case kSmall1BitMask:
+ hRawData = [IconFamily get1BitMaskFromBitmapImageRep:bitmapImageRep requiredPixelSize:16];
+ break;
+
+ // 'ics8' 16x16 8-bit indexed image data
+ case kSmall8BitData:
+ hRawData = [IconFamily get8BitDataFromBitmapImageRep:bitmapImageRep requiredPixelSize:16];
+ break;
+
+ default:
+ return NO;
+ }
+
+ // NSLog(@"setIconFamilyElement:%@ fromBitmapImageRep:%@ generated handle %p of size %d", NSFileTypeForHFSTypeCode(elementType), bitmapImageRep, hRawData, GetHandleSize(hRawData));
+
+ if (hRawData == NULL)
+ {
+ NSLog(@"Null data returned to setIconFamilyElement:fromBitmapImageRep:");
+ return NO;
+ }
+
+ result = SetIconFamilyData( hIconFamily, elementType, hRawData );
+ DisposeHandle( hRawData );
+
+ if (result != noErr)
+ {
+ NSLog(@"SetIconFamilyData() returned error %d", result);
+ return NO;
+ }
+
+ return YES;
+}
+
+- (BOOL) setAsCustomIconForFile:(NSString*)path
+{
+ return( [self setAsCustomIconForFile:path withCompatibility:NO] );
+}
+
+- (BOOL) setAsCustomIconForFile:(NSString*)path withCompatibility:(BOOL)compat
+{
+ FSSpec targetFileFSSpec;
+ FSRef targetFileFSRef;
+ FSRef parentDirectoryFSRef;
+ SInt16 file;
+ OSErr result;
+ FInfo finderInfo;
+ Handle hExistingCustomIcon;
+ Handle hIconFamilyCopy;
+ NSDictionary *fileAttributes;
+ OSType existingType = unknownOSType, existingCreator = unknownOSType;
+
+ // Get an FSRef and an FSSpec for the target file, and an FSRef for its parent directory that we can use in the FNNotify() call below.
+ if (![path getFSRef:&targetFileFSRef createFileIfNecessary:NO])
+ return NO;
+ result = FSGetCatalogInfo( &targetFileFSRef, kFSCatInfoNone, NULL, NULL, &targetFileFSSpec, &parentDirectoryFSRef );
+ if (result != noErr)
+ return NO;
+
+ // Get the file's type and creator codes.
+ fileAttributes = [[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:NO];
+ if (fileAttributes)
+ {
+ existingType = [fileAttributes fileHFSTypeCode];
+ existingCreator = [fileAttributes fileHFSCreatorCode];
+ }
+
+ // Make sure the file has a resource fork that we can open. (Although
+ // this sounds like it would clobber an existing resource fork, the Carbon
+ // Resource Manager docs for this function say that's not the case. If
+ // the file already has a resource fork, we receive a result code of
+ // dupFNErr, which is not really an error per se, but just a notification
+ // to us that creating a new resource fork for the file was not necessary.)
+ FSpCreateResFile( &targetFileFSSpec, existingCreator, existingType, smRoman );
+ result = ResError();
+ if (!(result == noErr || result == dupFNErr))
+ return NO;
+
+ // Open the file's resource fork.
+ file = FSpOpenResFile( &targetFileFSSpec, fsRdWrPerm );
+ if (file == -1)
+ return NO;
+
+ // Make a copy of the icon family data to pass to AddResource().
+ // (AddResource() takes ownership of the handle we pass in; after the
+ // CloseResFile() call its master pointer will be set to 0xffffffff.
+ // We want to keep the icon family data, so we make a copy.)
+ // HandToHand() returns the handle of the copy in hIconFamily.
+ hIconFamilyCopy = (Handle) hIconFamily;
+ result = HandToHand( &hIconFamilyCopy );
+ if (result != noErr) {
+ CloseResFile( file );
+ return NO;
+ }
+
+ // Remove the file's existing kCustomIconResource of type kIconFamilyType
+ // (if any).
+ hExistingCustomIcon = GetResource( kIconFamilyType, kCustomIconResource );
+ if( hExistingCustomIcon )
+ RemoveResource( hExistingCustomIcon );
+
+ // Now add our icon family as the file's new custom icon.
+ AddResource( (Handle)hIconFamilyCopy, kIconFamilyType,
+ kCustomIconResource, "\p");
+ if (ResError() != noErr) {
+ CloseResFile( file );
+ return NO;
+ }
+
+ if( compat )
+ {
+ [self addResourceType:kLarge8BitData asResID:kCustomIconResource];
+ [self addResourceType:kLarge1BitMask asResID:kCustomIconResource];
+ [self addResourceType:kSmall8BitData asResID:kCustomIconResource];
+ [self addResourceType:kSmall1BitMask asResID:kCustomIconResource];
+ }
+
+ // Close the file's resource fork, flushing the resource map and new icon
+ // data out to disk.
+ CloseResFile( file );
+ if (ResError() != noErr)
+ return NO;
+
+ // Now we need to set the file's Finder info so the Finder will know that
+ // it has a custom icon. Start by getting the file's current finder info:
+ result = FSpGetFInfo( &targetFileFSSpec, &finderInfo );
+ if (result != noErr)
+ return NO;
+
+ // Set the kHasCustomIcon flag, and clear the kHasBeenInited flag.
+ //
+ // From Apple's "CustomIcon" code sample:
+ // "set bit 10 (has custom icon) and unset the inited flag
+ // kHasBeenInited is 0x0100 so the mask will be 0xFEFF:"
+ // finderInfo.fdFlags = 0xFEFF & (finderInfo.fdFlags | kHasCustomIcon ) ;
+ finderInfo.fdFlags = (finderInfo.fdFlags | kHasCustomIcon ) & ~kHasBeenInited;
+
+ // Now write the Finder info back.
+ result = FSpSetFInfo( &targetFileFSSpec, &finderInfo );
+ if (result != noErr)
+ return NO;
+
+ // Notify the system that the directory containing the file has changed, to give Finder the chance to find out about the file's new custom icon.
+ result = FNNotify( &parentDirectoryFSRef, kFNDirectoryModifiedMessage, kNilOptions );
+ if (result != noErr)
+ return NO;
+
+ return YES;
+}
+
++ (BOOL) removeCustomIconFromFile:(NSString*)path
+{
+ FSSpec targetFileFSSpec;
+ FSRef targetFileFSRef;
+ FSRef parentDirectoryFSRef;
+ SInt16 file;
+ OSErr result;
+ FInfo finderInfo;
+ Handle hExistingCustomIcon;
+
+ // Get an FSRef and an FSSpec for the target file, and an FSRef for its parent directory that we can use in the FNNotify() call below.
+ if (![path getFSRef:&targetFileFSRef createFileIfNecessary:NO])
+ return NO;
+ result = FSGetCatalogInfo( &targetFileFSRef, kFSCatInfoNone, NULL, NULL, &targetFileFSSpec, &parentDirectoryFSRef );
+ if (result != noErr)
+ return NO;
+
+ // Open the file's resource fork, if it has one.
+ file = FSpOpenResFile( &targetFileFSSpec, fsRdWrPerm );
+ if (file == -1)
+ return NO;
+
+ // Remove the file's existing kCustomIconResource of type kIconFamilyType
+ // (if any).
+ hExistingCustomIcon = GetResource( kIconFamilyType, kCustomIconResource );
+ if( hExistingCustomIcon )
+ RemoveResource( hExistingCustomIcon );
+
+ // Close the file's resource fork, flushing the resource map out to disk.
+ CloseResFile( file );
+ if (ResError() != noErr)
+ return NO;
+
+ // Now we need to set the file's Finder info so the Finder will know that
+ // it has no custom icon. Start by getting the file's current finder info:
+ result = FSpGetFInfo( &targetFileFSSpec, &finderInfo );
+ if (result != noErr)
+ return NO;
+
+ // Clear the kHasCustomIcon flag and the kHasBeenInited flag.
+ finderInfo.fdFlags = finderInfo.fdFlags & ~(kHasCustomIcon | kHasBeenInited);
+
+ // Now write the Finder info back.
+ result = FSpSetFInfo( &targetFileFSSpec, &finderInfo );
+ if (result != noErr)
+ return NO;
+
+ // Notify the system that the directory containing the file has changed, to give Finder the chance to find out about the file's new custom icon.
+ result = FNNotify( &parentDirectoryFSRef, kFNDirectoryModifiedMessage, kNilOptions );
+ if (result != noErr)
+ return NO;
+
+ return YES;
+}
+
+- (BOOL) setAsCustomIconForDirectory:(NSString*)path
+{
+ return [self setAsCustomIconForDirectory:path withCompatibility:NO];
+}
+
+- (BOOL) setAsCustomIconForDirectory:(NSString*)path withCompatibility:(BOOL)compat
+{
+ NSFileManager *fm = [NSFileManager defaultManager];
+ BOOL isDir;
+ BOOL exists;
+ NSString *iconrPath = [path stringByAppendingPathComponent:@"Icon\r"];
+ FSSpec targetFileFSSpec, targetFolderFSSpec;
+ FSRef targetFolderFSRef;
+ SInt16 file;
+ OSErr result;
+ FInfo finderInfo;
+ FSCatalogInfo catInfo;
+ Handle hExistingCustomIcon;
+ Handle hIconFamilyCopy;
+
+ exists = [fm fileExistsAtPath:path isDirectory:&isDir];
+
+ if( !isDir || !exists )
+ return NO;
+
+ if( [fm fileExistsAtPath:iconrPath] )
+ {
+ if( ![fm removeFileAtPath:iconrPath handler:nil] )
+ return NO;
+ }
+
+ if (![iconrPath getFSSpec:&targetFileFSSpec createFileIfNecessary:YES])
+ return NO;
+
+ if( ![path getFSSpec:&targetFolderFSSpec createFileIfNecessary:YES] )
+ return NO;
+
+ if( ![path getFSRef:&targetFolderFSRef createFileIfNecessary:NO] )
+ return NO;
+
+ // Make sure the file has a resource fork that we can open. (Although
+ // this sounds like it would clobber an existing resource fork, the Carbon
+ // Resource Manager docs for this function say that's not the case.)
+ FSpCreateResFile( &targetFileFSSpec, unknownOSType, unknownOSType, smRoman );
+ if (ResError() != noErr)
+ return NO;
+
+ // Open the file's resource fork.
+ file = FSpOpenResFile( &targetFileFSSpec, fsRdWrPerm );
+ if (file == -1)
+ return NO;
+
+ // Make a copy of the icon family data to pass to AddResource().
+ // (AddResource() takes ownership of the handle we pass in; after the
+ // CloseResFile() call its master pointer will be set to 0xffffffff.
+ // We want to keep the icon family data, so we make a copy.)
+ // HandToHand() returns the handle of the copy in hIconFamily.
+ hIconFamilyCopy = (Handle) hIconFamily;
+ result = HandToHand( &hIconFamilyCopy );
+ if (result != noErr) {
+ CloseResFile( file );
+ return NO;
+ }
+
+ // Remove the file's existing kCustomIconResource of type kIconFamilyType
+ // (if any).
+ hExistingCustomIcon = GetResource( kIconFamilyType, kCustomIconResource );
+ if( hExistingCustomIcon )
+ RemoveResource( hExistingCustomIcon );
+
+ // Now add our icon family as the file's new custom icon.
+ AddResource( (Handle)hIconFamilyCopy, kIconFamilyType,
+ kCustomIconResource, "\p");
+
+ if (ResError() != noErr) {
+ CloseResFile( file );
+ return NO;
+ }
+
+ if( compat )
+ {
+ [self addResourceType:kLarge8BitData asResID:kCustomIconResource];
+ [self addResourceType:kLarge1BitMask asResID:kCustomIconResource];
+ [self addResourceType:kSmall8BitData asResID:kCustomIconResource];
+ [self addResourceType:kSmall1BitMask asResID:kCustomIconResource];
+ }
+
+ // Close the file's resource fork, flushing the resource map and new icon
+ // data out to disk.
+ CloseResFile( file );
+ if (ResError() != noErr)
+ return NO;
+
+ // Make folder icon file invisible
+ result = FSpGetFInfo( &targetFileFSSpec, &finderInfo );
+ if (result != noErr)
+ return NO;
+ finderInfo.fdFlags = (finderInfo.fdFlags | kIsInvisible ) & ~kHasBeenInited;
+ // And write info back
+ result = FSpSetFInfo( &targetFileFSSpec, &finderInfo );
+ if (result != noErr)
+ return NO;
+
+ result = FSGetCatalogInfo( &targetFolderFSRef,
+ kFSCatInfoFinderInfo,
+ &catInfo, nil, nil, nil);
+ if( result != noErr )
+ return NO;
+
+ ((DInfo*)catInfo.finderInfo)->frFlags = ( ((DInfo*)catInfo.finderInfo)->frFlags | kHasCustomIcon ) & ~kHasBeenInited;
+
+ FSSetCatalogInfo( &targetFolderFSRef,
+ kFSCatInfoFinderInfo,
+ &catInfo);
+ if( result != noErr )
+ return NO;
+
+ // Notify the system that the target directory has changed, to give Finder the chance to find out about its new custom icon.
+ result = FNNotify( &targetFolderFSRef, kFNDirectoryModifiedMessage, kNilOptions );
+ if (result != noErr)
+ return NO;
+
+ return YES;
+}
+
+/*- (BOOL) writeToFile:(NSString*)path
+{
+ FSSpec fsSpec;
+ OSErr result;
+
+ if (![path getFSSpec:&fsSpec createFileIfNecessary:YES])
+ return NO;
+ result = WriteIconFile( hIconFamily, &fsSpec );
+ if (result != noErr)
+ return NO;
+
+ return YES;
+} This method has a problem with files not representable as an FSSpec.*/
+
+- (BOOL) writeToFile:(NSString*)path
+{
+ NSData* iconData = NULL;
+
+ HLock((Handle)hIconFamily);
+
+ iconData = [NSData dataWithBytes:*hIconFamily length:GetHandleSize((Handle)hIconFamily)];
+ [iconData writeToFile:path atomically:NO];
+
+ HUnlock((Handle)hIconFamily);
+
+ return YES;
+}
+
+@synthesize hIconFamily;
+@end
+
+@implementation IconFamily (Internals)
+
++ (NSImage*) resampleImage:(NSImage*)image toIconWidth:(int)iconWidth usingImageInterpolation:(NSImageInterpolation)imageInterpolation
+{
+ NSGraphicsContext* graphicsContext;
+ BOOL wasAntialiasing;
+ NSImageInterpolation previousImageInterpolation;
+ NSImage* newImage;
+// NSBitmapImageRep* newBitmapImageRep;
+// unsigned char* bitmapData;
+// NSImageRep* originalImageRep;
+ NSImage* workingImage;
+ NSImageRep* workingImageRep;
+ NSSize size, pixelSize, newSize;
+ NSRect iconRect;
+ NSRect targetRect;
+
+ // Create a working copy of the image and scale its size down to fit in
+ // the square area of the icon.
+ //
+ // It seems like there should be a more memory-efficient alternative to
+ // first duplicating the entire original image, but I don't know what it
+ // is. We need to change some properties ("size" and "scalesWhenResized")
+ // of the original image, but we shouldn't change the original, so a copy
+ // is necessary.
+ workingImage = [image copyWithZone:[image zone]];
+ [workingImage setScalesWhenResized:YES];
+ size = [workingImage size];
+ workingImageRep = [workingImage bestRepresentationForDevice:nil];
+ if ([workingImageRep isKindOfClass:[NSBitmapImageRep class]]) {
+ pixelSize.width = [workingImageRep pixelsWide];
+ pixelSize.height = [workingImageRep pixelsHigh];
+ if (!NSEqualSizes( size, pixelSize )) {
+ [workingImage setSize:pixelSize];
+ [workingImageRep setSize:pixelSize];
+ size = pixelSize;
+ }
+ }
+ if (size.width >= size.height) {
+ newSize.width = iconWidth;
+ newSize.height = floor( (float) iconWidth * size.height / size.width + 0.5 );
+ } else {
+ newSize.height = iconWidth;
+ newSize.width = floor( (float) iconWidth * size.width / size.height + 0.5 );
+ }
+ [workingImage setSize:newSize];
+
+#if 1 // This is the way that works. It gives the newImage an NSCachedImageRep.
+
+ // Create a new image the size of the icon, and clear it to transparent.
+ newImage = [[NSImage alloc] initWithSize:NSMakeSize(iconWidth,iconWidth)];
+ [newImage lockFocus];
+ iconRect.origin.x = iconRect.origin.y = 0;
+ iconRect.size.width = iconRect.size.height = iconWidth;
+ [[NSColor clearColor] set];
+ NSRectFill( iconRect );
+
+ // Set current graphics context to use antialiasing and high-quality
+ // image scaling.
+ graphicsContext = [NSGraphicsContext currentContext];
+ wasAntialiasing = [graphicsContext shouldAntialias];
+ previousImageInterpolation = [graphicsContext imageInterpolation];
+ [graphicsContext setShouldAntialias:YES];
+ [graphicsContext setImageInterpolation:imageInterpolation];
+
+ // Composite the working image into the icon bitmap, centered.
+ targetRect.origin.x = ((float)iconWidth - newSize.width ) / 2.0;
+ targetRect.origin.y = ((float)iconWidth - newSize.height) / 2.0;
+ targetRect.size.width = newSize.width;
+ targetRect.size.height = newSize.height;
+ [workingImageRep drawInRect:targetRect];
+
+ // Restore previous graphics context settings.
+ [graphicsContext setShouldAntialias:wasAntialiasing];
+ [graphicsContext setImageInterpolation:previousImageInterpolation];
+
+ [newImage unlockFocus];
+
+ [workingImage release];
+
+#else // This was an attempt at explicitly giving the NSImage an NSBitmapImageRep
+ // and drawing to that NSBitmapImageRep. It doesn't work. (See comments
+ // in -initWithThumbnailsOfImage:)
+
+// // Create a new 32-bit RGBA bitmap that is width x width pixels.
+ originalImageRep = [image bestRepresentationForDevice:nil];
+ newImage = [[NSImage alloc] initWithSize:NSMakeSize(iconWidth,iconWidth)];
+ [newImage setDataRetained:YES];
+// [newImage setCachedSeparately:YES];
+ newBitmapImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
+ pixelsWide:iconWidth
+ pixelsHigh:iconWidth
+// bitsPerSample:8
+// samplesPerPixel:4
+ bitsPerSample:[originalImageRep bitsPerSample]
+ samplesPerPixel:[(NSBitmapImageRep*)originalImageRep samplesPerPixel]
+ hasAlpha:[originalImageRep hasAlpha]
+ isPlanar:NO
+ colorSpaceName:[originalImageRep colorSpaceName]
+ bytesPerRow:0
+ bitsPerPixel:0];
+ [newImage addRepresentation:newBitmapImageRep];
+ [newImage setScalesWhenResized:YES];
+ [newBitmapImageRep release];
+// bitmapData = [newBitmapImageRep bitmapData];
+// if (bitmapData)
+// memset( bitmapData, 128, iconWidth * iconWidth * 4 );
+ // Copy the original image into the new bitmap, rescaling it to fit.
+// [newImage lockFocus];
+ [newImage lockFocusOnRepresentation:newBitmapImageRep];
+// [image compositeToPoint:NSZeroPoint operation:NSCompositeSourceOver];
+// iconRect.origin.x = iconRect.origin.y = 0;
+// iconRect.size.width = iconRect.size.height = iconWidth;
+// [[NSColor clearColor] set];
+// NSRectFill( iconRect );
+ [workingImage compositeToPoint:NSZeroPoint operation:NSCompositeSourceOver];
+ [newImage unlockFocus];
+
+ [workingImage release];
+#endif
+
+ // Return the new image!
+ return [newImage autorelease];
+}
+
++ (Handle) get32BitDataFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize
+{
+ Handle hRawData;
+ unsigned char* pRawData;
+ Size rawDataSize;
+ unsigned char* pSrc;
+ unsigned char* pDest;
+ int x, y;
+ unsigned char alphaByte;
+ float oneOverAlpha;
+
+ // Get information about the bitmapImageRep.
+ int pixelsWide = [bitmapImageRep pixelsWide];
+ int pixelsHigh = [bitmapImageRep pixelsHigh];
+ int bitsPerSample = [bitmapImageRep bitsPerSample];
+ int samplesPerPixel = [bitmapImageRep samplesPerPixel];
+ int bitsPerPixel = [bitmapImageRep bitsPerPixel];
+// BOOL hasAlpha = [bitmapImageRep hasAlpha];
+ BOOL isPlanar = [bitmapImageRep isPlanar];
+// int numberOfPlanes = [bitmapImageRep numberOfPlanes];
+ int bytesPerRow = [bitmapImageRep bytesPerRow];
+// int bytesPerPlane = [bitmapImageRep bytesPerPlane];
+ unsigned char* bitmapData = [bitmapImageRep bitmapData];
+
+ // Make sure bitmap has the required dimensions.
+ if (pixelsWide != requiredPixelSize || pixelsHigh != requiredPixelSize)
+ return NULL;
+
+ // So far, this code only handles non-planar 32-bit RGBA and 24-bit RGB source bitmaps.
+ // This could be made more flexible with some additional programming to accommodate other possible
+ // formats...
+ if (isPlanar)
+ {
+ NSLog(@"get32BitDataFromBitmapImageRep:requiredPixelSize: returning NULL due to isPlanar == YES");
+ return NULL;
+ }
+ if (bitsPerSample != 8)
+ {
+ NSLog(@"get32BitDataFromBitmapImageRep:requiredPixelSize: returning NULL due to bitsPerSample == %d", bitsPerSample);
+ return NULL;
+ }
+
+ if (((samplesPerPixel == 3) && (bitsPerPixel == 24)) || ((samplesPerPixel == 4) && (bitsPerPixel == 32)))
+ {
+ rawDataSize = pixelsWide * pixelsHigh * 4;
+ hRawData = NewHandle( rawDataSize );
+ if (hRawData == NULL)
+ return NULL;
+ pRawData = *hRawData;
+
+ pSrc = bitmapData;
+ pDest = pRawData;
+
+ if (bitsPerPixel == 32) {
+ for (y = 0; y < pixelsHigh; y++) {
+ pSrc = bitmapData + y * bytesPerRow;
+ for (x = 0; x < pixelsWide; x++) {
+ // Each pixel is 3 bytes of RGB data, followed by 1 byte of
+ // alpha. The RGB values are premultiplied by the alpha (so
+ // that Quartz can save time when compositing the bitmap to a
+ // destination), and we undo this premultiplication (with some
+ // lossiness unfortunately) when retrieving the bitmap data.
+ *pDest++ = alphaByte = *(pSrc+3);
+ if (alphaByte) {
+ oneOverAlpha = 255.0f / (float)alphaByte;
+ *pDest++ = *(pSrc+0) * oneOverAlpha;
+ *pDest++ = *(pSrc+1) * oneOverAlpha;
+ *pDest++ = *(pSrc+2) * oneOverAlpha;
+ } else {
+ *pDest++ = 0;
+ *pDest++ = 0;
+ *pDest++ = 0;
+ }
+ pSrc+=4;
+ }
+ }
+ } else if (bitsPerPixel == 24) {
+ for (y = 0; y < pixelsHigh; y++) {
+ pSrc = bitmapData + y * bytesPerRow;
+ for (x = 0; x < pixelsWide; x++) {
+ *pDest++ = 0;
+ *pDest++ = *pSrc++;
+ *pDest++ = *pSrc++;
+ *pDest++ = *pSrc++;
+ }
+ }
+ }
+ }
+ else
+ {
+ NSLog(@"get32BitDataFromBitmapImageRep:requiredPixelSize: returning NULL due to samplesPerPixel == %d, bitsPerPixel == %", samplesPerPixel, bitsPerPixel);
+ return NULL;
+ }
+
+ return hRawData;
+}
+
++ (Handle) get8BitDataFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize
+{
+ Handle hRawData;
+ unsigned char* pRawData;
+ Size rawDataSize;
+ unsigned char* pSrc;
+ unsigned char* pDest;
+ int x, y;
+
+ // Get information about the bitmapImageRep.
+ int pixelsWide = [bitmapImageRep pixelsWide];
+ int pixelsHigh = [bitmapImageRep pixelsHigh];
+ int bitsPerSample = [bitmapImageRep bitsPerSample];
+ int samplesPerPixel = [bitmapImageRep samplesPerPixel];
+ int bitsPerPixel = [bitmapImageRep bitsPerPixel];
+ BOOL isPlanar = [bitmapImageRep isPlanar];
+ int bytesPerRow = [bitmapImageRep bytesPerRow];
+ unsigned char* bitmapData = [bitmapImageRep bitmapData];
+
+ // Make sure bitmap has the required dimensions.
+ if (pixelsWide != requiredPixelSize || pixelsHigh != requiredPixelSize)
+ return NULL;
+
+ // So far, this code only handles non-planar 32-bit RGBA and 24-bit RGB source bitmaps.
+ // This could be made more flexible with some additional programming...
+ if (isPlanar)
+ {
+ NSLog(@"get8BitDataFromBitmapImageRep:requiredPixelSize: returning NULL due to isPlanar == YES");
+ return NULL;
+ }
+ if (bitsPerSample != 8)
+ {
+ NSLog(@"get8BitDataFromBitmapImageRep:requiredPixelSize: returning NULL due to bitsPerSample == %d", bitsPerSample);
+ return NULL;
+ }
+
+ if (((samplesPerPixel == 3) && (bitsPerPixel == 24)) || ((samplesPerPixel == 4) && (bitsPerPixel == 32)))
+ {
+ CGDirectPaletteRef cgPal;
+ CGDeviceColor cgCol;
+
+ rawDataSize = pixelsWide * pixelsHigh;
+ hRawData = NewHandle( rawDataSize );
+ if (hRawData == NULL)
+ return NULL;
+ pRawData = *hRawData;
+
+ cgPal = CGPaletteCreateDefaultColorPalette();
+
+ pSrc = bitmapData;
+ pDest = pRawData;
+ if (bitsPerPixel == 32) {
+ for (y = 0; y < pixelsHigh; y++) {
+ pSrc = bitmapData + y * bytesPerRow;
+ for (x = 0; x < pixelsWide; x++) {
+ cgCol.red = ((float)*(pSrc)) / 255;
+ cgCol.green = ((float)*(pSrc+1)) / 255;
+ cgCol.blue = ((float)*(pSrc+2)) / 255;
+
+ *pDest++ = CGPaletteGetIndexForColor(cgPal, cgCol);
+
+ pSrc+=4;
+ }
+ }
+ } else if (bitsPerPixel == 24) {
+ for (y = 0; y < pixelsHigh; y++) {
+ pSrc = bitmapData + y * bytesPerRow;
+ for (x = 0; x < pixelsWide; x++) {
+ cgCol.red = ((float)*(pSrc)) / 255;
+ cgCol.green = ((float)*(pSrc+1)) / 255;
+ cgCol.blue = ((float)*(pSrc+2)) / 255;
+
+ *pDest++ = CGPaletteGetIndexForColor(cgPal, cgCol);
+
+ pSrc+=3;
+ }
+ }
+ }
+
+ CGPaletteRelease(cgPal);
+ }
+ else
+ {
+ NSLog(@"get8BitDataFromBitmapImageRep:requiredPixelSize: returning NULL due to samplesPerPixel == %d, bitsPerPixel == %", samplesPerPixel, bitsPerPixel);
+ return NULL;
+ }
+
+ return hRawData;
+}
+
++ (Handle) get8BitMaskFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize
+{
+ Handle hRawData;
+ unsigned char* pRawData;
+ Size rawDataSize;
+ unsigned char* pSrc;
+ unsigned char* pDest;
+ int x, y;
+
+ // Get information about the bitmapImageRep.
+ int pixelsWide = [bitmapImageRep pixelsWide];
+ int pixelsHigh = [bitmapImageRep pixelsHigh];
+ int bitsPerSample = [bitmapImageRep bitsPerSample];
+ int samplesPerPixel = [bitmapImageRep samplesPerPixel];
+ int bitsPerPixel = [bitmapImageRep bitsPerPixel];
+// BOOL hasAlpha = [bitmapImageRep hasAlpha];
+ BOOL isPlanar = [bitmapImageRep isPlanar];
+// int numberOfPlanes = [bitmapImageRep numberOfPlanes];
+ int bytesPerRow = [bitmapImageRep bytesPerRow];
+// int bytesPerPlane = [bitmapImageRep bytesPerPlane];
+ unsigned char* bitmapData = [bitmapImageRep bitmapData];
+
+ // Make sure bitmap has the required dimensions.
+ if (pixelsWide != requiredPixelSize || pixelsHigh != requiredPixelSize)
+ return NULL;
+
+ // So far, this code only handles non-planar 32-bit RGBA, 24-bit RGB and 8-bit grayscale source bitmaps.
+ // This could be made more flexible with some additional programming...
+ if (isPlanar)
+ {
+ NSLog(@"get8BitMaskFromBitmapImageRep:requiredPixelSize: returning NULL due to isPlanar == YES");
+ return NULL;
+ }
+ if (bitsPerSample != 8)
+ {
+ NSLog(@"get8BitMaskFromBitmapImageRep:requiredPixelSize: returning NULL due to bitsPerSample == %d", bitsPerSample);
+ return NULL;
+ }
+
+ if (((samplesPerPixel == 1) && (bitsPerPixel == 8)) || ((samplesPerPixel == 3) && (bitsPerPixel == 24)) || ((samplesPerPixel == 4) && (bitsPerPixel == 32)))
+ {
+ rawDataSize = pixelsWide * pixelsHigh;
+ hRawData = NewHandle( rawDataSize );
+ if (hRawData == NULL)
+ return NULL;
+ pRawData = *hRawData;
+
+ pSrc = bitmapData;
+ pDest = pRawData;
+
+ if (bitsPerPixel == 32) {
+ for (y = 0; y < pixelsHigh; y++) {
+ pSrc = bitmapData + y * bytesPerRow;
+ for (x = 0; x < pixelsWide; x++) {
+ pSrc += 3;
+ *pDest++ = *pSrc++;
+ }
+ }
+ }
+ else if (bitsPerPixel == 24) {
+ memset( pDest, 255, rawDataSize );
+ }
+ else if (bitsPerPixel == 8) {
+ for (y = 0; y < pixelsHigh; y++) {
+ memcpy( pDest, pSrc, pixelsWide );
+ pSrc += bytesPerRow;
+ pDest += pixelsWide;
+ }
+ }
+ }
+ else
+ {
+ NSLog(@"get8BitMaskFromBitmapImageRep:requiredPixelSize: returning NULL due to samplesPerPixel == %d, bitsPerPixel == %", samplesPerPixel, bitsPerPixel);
+ return NULL;
+ }
+
+ return hRawData;
+}
+
+// NOTE: This method hasn't been fully tested yet.
++ (Handle) get1BitMaskFromBitmapImageRep:(NSBitmapImageRep*)bitmapImageRep requiredPixelSize:(int)requiredPixelSize
+{
+ Handle hRawData;
+ unsigned char* pRawData;
+ Size rawDataSize;
+ unsigned char* pSrc;
+ unsigned char* pDest;
+ int x, y;
+ unsigned char maskByte;
+
+ // Get information about the bitmapImageRep.
+ int pixelsWide = [bitmapImageRep pixelsWide];
+ int pixelsHigh = [bitmapImageRep pixelsHigh];
+ int bitsPerSample = [bitmapImageRep bitsPerSample];
+ int samplesPerPixel = [bitmapImageRep samplesPerPixel];
+ int bitsPerPixel = [bitmapImageRep bitsPerPixel];
+// BOOL hasAlpha = [bitmapImageRep hasAlpha];
+ BOOL isPlanar = [bitmapImageRep isPlanar];
+// int numberOfPlanes = [bitmapImageRep numberOfPlanes];
+ int bytesPerRow = [bitmapImageRep bytesPerRow];
+// int bytesPerPlane = [bitmapImageRep bytesPerPlane];
+ unsigned char* bitmapData = [bitmapImageRep bitmapData];
+
+ // Make sure bitmap has the required dimensions.
+ if (pixelsWide != requiredPixelSize || pixelsHigh != requiredPixelSize)
+ return NULL;
+
+ // So far, this code only handles non-planar 32-bit RGBA, 24-bit RGB, 8-bit grayscale, and 1-bit source bitmaps.
+ // This could be made more flexible with some additional programming...
+ if (isPlanar)
+ {
+ NSLog(@"get1BitMaskFromBitmapImageRep:requiredPixelSize: returning NULL due to isPlanar == YES");
+ return NULL;
+ }
+
+ if (((bitsPerPixel == 1) && (samplesPerPixel == 1) && (bitsPerSample == 1)) || ((bitsPerPixel == 8) && (samplesPerPixel == 1) && (bitsPerSample == 8)) ||
+ ((bitsPerPixel == 24) && (samplesPerPixel == 3) && (bitsPerSample == 8)) || ((bitsPerPixel == 32) && (samplesPerPixel == 4) && (bitsPerSample == 8)))
+ {
+ rawDataSize = (pixelsWide * pixelsHigh)/4;
+ hRawData = NewHandle( rawDataSize );
+ if (hRawData == NULL)
+ return NULL;
+ pRawData = *hRawData;
+
+ pSrc = bitmapData;
+ pDest = pRawData;
+
+ if (bitsPerPixel == 32) {
+ for (y = 0; y < pixelsHigh; y++) {
+ pSrc = bitmapData + y * bytesPerRow;
+ for (x = 0; x < pixelsWide; x += 8) {
+ maskByte = 0;
+ maskByte |= (*(unsigned*)pSrc & 0xff) ? 0x80 : 0; pSrc += 4;
+ maskByte |= (*(unsigned*)pSrc & 0xff) ? 0x40 : 0; pSrc += 4;
+ maskByte |= (*(unsigned*)pSrc & 0xff) ? 0x20 : 0; pSrc += 4;
+ maskByte |= (*(unsigned*)pSrc & 0xff) ? 0x10 : 0; pSrc += 4;
+ maskByte |= (*(unsigned*)pSrc & 0xff) ? 0x08 : 0; pSrc += 4;
+ maskByte |= (*(unsigned*)pSrc & 0xff) ? 0x04 : 0; pSrc += 4;
+ maskByte |= (*(unsigned*)pSrc & 0xff) ? 0x02 : 0; pSrc += 4;
+ maskByte |= (*(unsigned*)pSrc & 0xff) ? 0x01 : 0; pSrc += 4;
+ *pDest++ = maskByte;
+ }
+ }
+ }
+ else if (bitsPerPixel == 24) {
+ memset( pDest, 255, rawDataSize );
+ }
+ else if (bitsPerPixel == 8) {
+ for (y = 0; y < pixelsHigh; y++) {
+ pSrc = bitmapData + y * bytesPerRow;
+ for (x = 0; x < pixelsWide; x += 8) {
+ maskByte = 0;
+ maskByte |= *pSrc++ ? 0x80 : 0;
+ maskByte |= *pSrc++ ? 0x40 : 0;
+ maskByte |= *pSrc++ ? 0x20 : 0;
+ maskByte |= *pSrc++ ? 0x10 : 0;
+ maskByte |= *pSrc++ ? 0x08 : 0;
+ maskByte |= *pSrc++ ? 0x04 : 0;
+ maskByte |= *pSrc++ ? 0x02 : 0;
+ maskByte |= *pSrc++ ? 0x01 : 0;
+ *pDest++ = maskByte;
+ }
+ }
+ }
+ else if (bitsPerPixel == 1) {
+ for (y = 0; y < pixelsHigh; y++) {
+ memcpy( pDest, pSrc, pixelsWide / 8 );
+ pDest += pixelsWide / 8;
+ pSrc += bytesPerRow;
+ }
+ }
+
+ memcpy( pRawData+(pixelsWide*pixelsHigh)/8, pRawData, (pixelsWide*pixelsHigh)/8 );
+ }
+ else
+ {
+ NSLog(@"get1BitMaskFromBitmapImageRep:requiredPixelSize: returning NULL due to bitsPerPixel == %d, samplesPerPixel== %d, bitsPerSample == %d", bitsPerPixel, samplesPerPixel, bitsPerSample);
+ return NULL;
+ }
+
+ return hRawData;
+}
+
+- (BOOL) addResourceType:(OSType)type asResID:(int)resID
+{
+ Handle hIconRes = NewHandle(0);
+ OSErr err;
+
+ err = GetIconFamilyData( hIconFamily, type, hIconRes );
+
+ if( !GetHandleSize(hIconRes) || err != noErr )
+ return NO;
+
+ AddResource( hIconRes, type, resID, "\p" );
+
+ return YES;
+}
+
+@end
+
+// Methods for interfacing with the Carbon Scrap Manager (analogous to and
+// interoperable with the Cocoa Pasteboard).
+
+@implementation IconFamily (ScrapAdditions)
+
++ (BOOL) canInitWithScrap
+{
+ ScrapRef scrap = NULL;
+ ScrapFlavorInfo* scrapInfos = NULL;
+ UInt32 numInfos = 0;
+ unsigned int i = 0;
+ BOOL canInit = NO;
+
+ GetCurrentScrap(&scrap);
+
+ GetScrapFlavorCount(scrap,&numInfos);
+ scrapInfos = malloc( sizeof(ScrapFlavorInfo)*numInfos );
+
+ GetScrapFlavorInfoList(scrap, &numInfos, scrapInfos);
+
+ for( i=0; i<numInfos; i++ )
+ {
+ if( scrapInfos[i].flavorType == 'icns' )
+ canInit = YES;
+ }
+
+ free( scrapInfos );
+
+ return canInit;
+}
+
++ (IconFamily*) iconFamilyWithScrap
+{
+ return [[[IconFamily alloc] initWithScrap] autorelease];
+}
+
+- initWithScrap
+{
+ Handle storageMem = NULL;
+ Size amountMem = 0;
+ ScrapRef scrap;
+
+ self = [super init];
+
+ if( self )
+ {
+ GetCurrentScrap(&scrap);
+
+ GetScrapFlavorSize( scrap, 'icns', &amountMem );
+
+ storageMem = NewHandle(amountMem);
+
+ GetScrapFlavorData( scrap, 'icns', &amountMem, *storageMem );
+
+ hIconFamily = (IconFamilyHandle)storageMem;
+ }
+ return self;
+}
+
+- (BOOL) putOnScrap
+{
+ ScrapRef scrap = NULL;
+
+ ClearCurrentScrap();
+ GetCurrentScrap(&scrap);
+
+ HLock((Handle)hIconFamily);
+ PutScrapFlavor( scrap, 'icns', kScrapFlavorMaskNone, GetHandleSize((Handle)hIconFamily), *hIconFamily);
+ HUnlock((Handle)hIconFamily);
+ return YES;
+}
+
+@end
+
+
diff --git a/Plugins/BuiltInFunctions/IconFamily/IconFamily/NSString+CarbonFSSpecCreation.h b/Plugins/BuiltInFunctions/IconFamily/IconFamily/NSString+CarbonFSSpecCreation.h
new file mode 100644
index 0000000..13cd3b9
--- /dev/null
+++ b/Plugins/BuiltInFunctions/IconFamily/IconFamily/NSString+CarbonFSSpecCreation.h
@@ -0,0 +1,20 @@
+#import <Foundation/Foundation.h>
+#import <Carbon/Carbon.h>
+
+@interface NSString (CarbonFSSpecCreation)
+
+// Fills in the given FSRef struct so it specifies the file whose path is in this string.
+// If the file doesn't exist, and "createFile" is YES, this method will attempt to create
+// an empty file with the specified path. (The caller should insure that the directory
+// the file is to be placed in already exists.)
+
+- (BOOL) getFSRef:(FSRef*)fsRef createFileIfNecessary:(BOOL)createFile;
+
+// Fills in the given FSSpec struct so it specifies the file whose path is in this string.
+// If the file doesn't exist, and "createFile" is YES, this method will attempt to create
+// an empty file with the specified path. (The caller should insure that the directory
+// the file is to be placed in already exists.)
+
+- (BOOL) getFSSpec:(FSSpec*)fsSpec createFileIfNecessary:(BOOL)createFile;
+
+@end
diff --git a/Plugins/BuiltInFunctions/IconFamily/IconFamily/NSString+CarbonFSSpecCreation.m b/Plugins/BuiltInFunctions/IconFamily/IconFamily/NSString+CarbonFSSpecCreation.m
new file mode 100644
index 0000000..711df94
--- /dev/null
+++ b/Plugins/BuiltInFunctions/IconFamily/IconFamily/NSString+CarbonFSSpecCreation.m
@@ -0,0 +1,66 @@
+#import "NSString+CarbonFSSpecCreation.h"
+
+@implementation NSString (CarbonFSSpecCreation)
+
+- (BOOL) getFSRef:(FSRef*)fsRef createFileIfNecessary:(BOOL)createFile
+{
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+ CFURLRef urlRef;
+ Boolean gotFSRef;
+
+ // Check whether the file exists already. If not, create an empty file if requested.
+ if (![fileManager fileExistsAtPath:self]) {
+ if (createFile) {
+ if (![@"" writeToFile:self atomically:YES]) {
+ return NO;
+ }
+ } else {
+ return NO;
+ }
+ }
+
+ // Create a CFURL with the specified POSIX path.
+ urlRef = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,
+ (CFStringRef) self,
+ kCFURLPOSIXPathStyle,
+ FALSE /* isDirectory */ );
+ if (urlRef == NULL) {
+// printf( "** Couldn't make a CFURLRef for the file.\n" );
+ return NO;
+ }
+
+ // Try to create an FSRef from the URL. (If the specified file doesn't exist, this
+ // function will return false, but if we've reached this code we've already insured
+ // that the file exists.)
+ gotFSRef = CFURLGetFSRef( urlRef, fsRef );
+ CFRelease( urlRef );
+
+ if (!gotFSRef) {
+// printf( "** Couldn't get an FSRef for the file.\n" );
+ return NO;
+ }
+
+ return YES;
+}
+
+- (BOOL) getFSSpec:(FSSpec*)fsSpec createFileIfNecessary:(BOOL)createFile
+{
+ FSRef fsRef;
+
+ if (![self getFSRef:&fsRef createFileIfNecessary:createFile])
+ return NO;
+
+ if (FSGetCatalogInfo( &fsRef,
+ kFSCatInfoNone,
+ NULL,
+ NULL,
+ fsSpec,
+ NULL ) != noErr) {
+ // printf( "** Couldn't get an FSSpec for the file.\n" );
+ return NO;
+ }
+
+ return YES;
+}
+
+@end
diff --git a/Plugins/BuiltInFunctions/Images/LocalAccountLarge.tiff b/Plugins/BuiltInFunctions/Images/LocalAccountLarge.tiff
new file mode 100644
index 0000000..823d17a
--- /dev/null
+++ b/Plugins/BuiltInFunctions/Images/LocalAccountLarge.tiff
Binary files differ
diff --git a/Plugins/BuiltInFunctions/Images/Network (Large).tiff b/Plugins/BuiltInFunctions/Images/Network (Large).tiff
new file mode 100644
index 0000000..2fe42dc
--- /dev/null
+++ b/Plugins/BuiltInFunctions/Images/Network (Large).tiff
Binary files differ
diff --git a/Plugins/BuiltInFunctions/Images/Network (Small).tiff b/Plugins/BuiltInFunctions/Images/Network (Small).tiff
new file mode 100644
index 0000000..09601e4
--- /dev/null
+++ b/Plugins/BuiltInFunctions/Images/Network (Small).tiff
Binary files differ
diff --git a/Plugins/BuiltInFunctions/Images/NotThere.icns b/Plugins/BuiltInFunctions/Images/NotThere.icns
new file mode 100644
index 0000000..77869e3
--- /dev/null
+++ b/Plugins/BuiltInFunctions/Images/NotThere.icns
Binary files differ
diff --git a/Plugins/BuiltInFunctions/Images/local.tiff b/Plugins/BuiltInFunctions/Images/local.tiff
new file mode 100644
index 0000000..6f3ecd6
--- /dev/null
+++ b/Plugins/BuiltInFunctions/Images/local.tiff
Binary files differ
diff --git a/Plugins/BuiltInFunctions/Info.plist b/Plugins/BuiltInFunctions/Info.plist
new file mode 100644
index 0000000..d8e9aef
--- /dev/null
+++ b/Plugins/BuiltInFunctions/Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>Built In Functions</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.kublai.Liaison.BuiltInFunctions</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>0.4</string>
+ <key>NSPrincipalClass</key>
+ <string>LiBuiltInFunctions</string>
+</dict>
+</plist>
diff --git a/Plugins/BuiltInFunctions/InspectorViewController.h b/Plugins/BuiltInFunctions/InspectorViewController.h
new file mode 100644
index 0000000..bba68ef
--- /dev/null
+++ b/Plugins/BuiltInFunctions/InspectorViewController.h
@@ -0,0 +1,52 @@
+//
+// InspectorViewController.h
+// Liaison
+//
+// Created by Brian Cully on Wed May 21 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface LiFileHandle (LiLocationStuff)
+- (NSString *)location;
+@end
+
+@interface InspectorViewController : NSObject
+{
+ IBOutlet NSView *theFileTabView;
+ IBOutlet NSView *theHFSTabView;
+
+ IBOutlet NSTextField *theFilenameField;
+ IBOutlet NSTextField *theTypeField;
+ IBOutlet NSPopUpButton *theApplicationButton;
+
+ IBOutlet NSImageView *iconView;
+ IBOutlet NSTextField *pathField;
+ IBOutlet NSTextField *hfsTypeField;
+ IBOutlet NSTextField *hfsCreatorField;
+
+ LiFileHandle *theFile;
+}
+- (IBAction)setIcon:(id)sender;
+- (IBAction)setFilename:(id)sender;
+- (IBAction)setType:(id)sender;
+- (IBAction)setApplication:(id)sender;
+- (IBAction)setHFSTypeField:(id)sender;
+- (IBAction)setHFSCreatorField:(id)sender;
+@property (retain) NSPopUpButton *theApplicationButton;
+@property (retain) NSImageView *iconView;
+@property (retain) NSTextField *hfsCreatorField;
+@property (retain,getter=hfsView) NSView *theHFSTabView;
+@property (retain) NSTextField *theTypeField;
+@property (retain,getter=fileView) NSView *theFileTabView;
+@property (retain,getter=file) LiFileHandle *theFile;
+@property (retain) NSTextField *pathField;
+@property (retain) NSTextField *theFilenameField;
+@property (retain) NSTextField *hfsTypeField;
+@end
+
+@interface InspectorViewController (Accessors)
+- (NSView *)fileView;
+- (NSView *)hfsView;
+- (LiFileHandle *)file;
+- (void)setFile: (LiFileHandle *)aFile;
+@end
diff --git a/Plugins/BuiltInFunctions/InspectorViewController.m b/Plugins/BuiltInFunctions/InspectorViewController.m
new file mode 100644
index 0000000..54d0d4e
--- /dev/null
+++ b/Plugins/BuiltInFunctions/InspectorViewController.m
@@ -0,0 +1,193 @@
+//
+// InspectorViewController.m
+// Liaison
+//
+// Created by Brian Cully on Wed May 21 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "InspectorViewController.h"
+
+#import "BDAlias.h"
+#import "LiBuiltInFunctions.h"
+
+static NSString *
+myLocalizedString(NSString *aString)
+{
+ return NSLocalizedStringFromTableInBundle(aString, @"BuiltInFunctions",
+ [LiBuiltInFunctions bundle], @"");
+}
+
+@implementation LiFileHandle (LiLocationStuff)
+- (NSString *)location
+{
+ NSData *aliasData;
+ NSString *location;
+
+ aliasData = [self valueForAttribute: LiAliasDataAttribute];
+ if (aliasData != nil) {
+ BDAlias *alias;
+
+ alias = [[BDAlias alloc] initWithData: aliasData];
+ if (alias != nil)
+ location = [alias fullPath];
+ else
+ location = myLocalizedString(@"UnableToResolveAlias");
+ } else {
+ location = [[self url] absoluteString];
+ }
+
+ return location;
+}
+@end
+
+@implementation InspectorViewController
+- (IBAction)setIcon:(id)sender
+{
+ [[sender cell] setHighlighted: NO];
+}
+
+- (IBAction)setFilename:(id)sender
+{
+ NSString *filename;
+
+ filename = [theFilenameField stringValue];
+ if ([filename compare: [[self file] filename]]) {
+ [[self file] setFilename: filename];
+ }
+}
+
+- (IBAction)setType:(id)sender
+{
+ NSString *type;
+
+ type = [theTypeField stringValue];
+ if ([type compare: [[self file] type]]) {
+ [[self file] setType: type];
+ }
+}
+
+- (IBAction)setApplication:(id)sender
+{
+ [LiLog logAsDebug: @"[InspectorViewController setApplication:]"];
+}
+
+- (IBAction)setHFSTypeField:(id)sender
+{
+ NSNumber *hfsType;
+
+ hfsType = [hfsTypeField objectValue];
+ if ([hfsType compare: [[self file] hfsType]]) {
+ [[self file] setHFSType: hfsType];
+ }
+}
+
+- (IBAction)setHFSCreatorField:(id)sender
+{
+ NSNumber *hfsCreator;
+
+ hfsCreator = [hfsCreatorField objectValue];
+ if ([hfsCreator compare: [[self file] hfsCreator]]) {
+ [[self file] setHFSCreator: hfsCreator];
+ }
+}
+@synthesize hfsTypeField;
+@synthesize theFileTabView;
+@synthesize theTypeField;
+@synthesize theHFSTabView;
+@synthesize hfsCreatorField;
+@synthesize iconView;
+@synthesize theApplicationButton;
+@synthesize theFilenameField;
+@synthesize pathField;
+@synthesize theFile;
+@end
+
+@implementation InspectorViewController (Accessors)
+- (NSView *)fileView
+{
+ return theFileTabView;
+}
+
+- (NSView *)hfsView
+{
+ return theHFSTabView;
+}
+
+- (LiFileHandle *)file
+{
+ return theFile;
+}
+
+- (void)initHFSFields
+{
+ [hfsCreatorField setObjectValue: [[self file] hfsCreator]];
+ [hfsTypeField setObjectValue: [[self file] hfsType]];
+}
+
+- (void)setFile: (LiFileHandle *)aFile
+{
+ NSImage *icon;
+ NSMutableArray *applications;
+ NSString *filename, *type, *location;
+ NSSize iconSize;
+
+ [aFile retain];
+ [theFile release];
+ theFile = aFile;
+
+ icon = [theFile icon];
+ iconSize = [iconView bounds].size;
+ iconSize.width -= 16.0;
+ iconSize.height -= 16.0;
+ [icon setSize: iconSize];
+ [iconView setImage: icon];
+
+ if ([theFile isEditable]) {
+ [theFilenameField setEnabled: YES];
+ [theTypeField setEnabled: YES];
+ [theApplicationButton setEnabled: YES];
+ [iconView setEditable: YES];
+ [hfsCreatorField setEditable: YES];
+ [hfsTypeField setEditable: YES];
+ } else {
+ [theFilenameField setEnabled: NO];
+ [theTypeField setEnabled: NO];
+ [theApplicationButton setEnabled: NO];
+ [iconView setEditable: NO];
+ [hfsCreatorField setEditable: NO];
+ [hfsTypeField setEditable: NO];
+ }
+
+ filename = [theFile filename];
+ if (filename != nil)
+ [theFilenameField setStringValue: filename];
+ else
+ [theFilenameField setStringValue: @""];
+
+ type = [theFile type];
+ if (type != nil)
+ [theTypeField setStringValue: type];
+ else
+ [theTypeField setStringValue: @""];
+
+ location = [aFile location];
+ if (location != nil)
+ [pathField setStringValue: location];
+ else
+ [pathField setStringValue: @"Couldn't locate file."];
+
+
+ applications = [NSMutableArray array];
+ if ([theFile application] != nil)
+ [applications addObject: [[theFile application] lastPathComponent]];
+
+ [theApplicationButton removeAllItems];
+ if ([applications count] > 0)
+ [theApplicationButton addItemsWithTitles: applications];
+ else
+ [theApplicationButton addItemWithTitle: @"None"];
+
+ [self initHFSFields];
+}
+@end
diff --git a/Plugins/BuiltInFunctions/LiBuiltInFunctions.h b/Plugins/BuiltInFunctions/LiBuiltInFunctions.h
new file mode 100644
index 0000000..b3bc479
--- /dev/null
+++ b/Plugins/BuiltInFunctions/LiBuiltInFunctions.h
@@ -0,0 +1,41 @@
+//
+// LiBuiltInFunctions.h
+// Liaison
+//
+// Created by Brian Cully on Tue May 13 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "BDAlias.h"
+
+#define LiAliasDataAttribute @"LiAliasAttribute"
+
+@class InspectorViewController;
+
+@interface LiBuiltInFunctions : NSObject
+<LiBrowserPlugin, LiInspectorPlugin, LiFileStorePlugin, LiFileStoreDelegate>
+{
+ IBOutlet InspectorViewController *theController;
+ LiFileStore *theFileStore;
+
+ NSMutableDictionary *theDefaultAttributes;
+}
+@property (retain) InspectorViewController *theController;
+@property (retain,getter=fileStore) LiFileStore *theFileStore;
+@property (retain,getter=defaultAttributes) NSMutableDictionary *theDefaultAttributes;
+@end
+
+@interface LiBuiltInFunctions (Accessors)
+- (void)setFileStore: (LiFileStore *)aFileStore;
+- (InspectorViewController *)viewController;
+- (NSMutableDictionary *)defaultAttributes;
+- (void)setDefaultAttributes: (NSMutableDictionary *)someAttributes;
+@end
+
+@interface LiFileHandle (LiBuiltInFunctions)
+- (NSImage *)icon;
+- (NSString *)path;
+- (NSString *)directory;
+- (BDAlias *)alias;
+- (void)setAlias: (BDAlias *)anAlias;
+@end \ No newline at end of file
diff --git a/Plugins/BuiltInFunctions/LiBuiltInFunctions.m b/Plugins/BuiltInFunctions/LiBuiltInFunctions.m
new file mode 100644
index 0000000..a7c3fed
--- /dev/null
+++ b/Plugins/BuiltInFunctions/LiBuiltInFunctions.m
@@ -0,0 +1,1027 @@
+//
+// LiBuiltInFunctions.m
+// Liaison
+//
+// Created by Brian Cully on Tue May 13 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "LiBuiltInFunctions.h"
+
+#import "FileSizeFormatter.h"
+#import "InspectorViewController.h"
+#import "NaturalDateFormatter.h"
+
+#import "IconFamily.h"
+
+static NSString *
+myLocalizedString(NSString *aString)
+{
+ return NSLocalizedStringFromTableInBundle(aString, @"BuiltInFunctions",
+ [LiBuiltInFunctions bundle], @"");
+}
+
+static NSString *
+myLocalizedErrorString(NSString *aString)
+{
+ return NSLocalizedStringFromTableInBundle(aString, @"ErrorMessages",
+ [LiBuiltInFunctions bundle], @"");
+}
+
+@implementation LiBuiltInFunctions
+static NSBundle *theBundle = nil;
+
++ (NSBundle *)bundle
+{
+ return theBundle;
+}
+
++ (void)setBundle: (NSBundle *)aBundle
+{
+ [aBundle retain];
+ [theBundle release];
+ theBundle = aBundle;
+}
+
+- (void)convertGroupDict: (NSDictionary *)someGroups
+{
+ NSArray *groupNames;
+ NSMutableDictionary *defaultGroups;
+ NSMutableSet *myGroups;
+ NSString *libraryName;
+
+ libraryName = [someGroups objectForKey: @"name"];
+ groupNames = [someGroups objectForKey: @"children"];
+
+ myGroups = [NSMutableSet setWithArray: groupNames];
+
+ if (libraryName != nil)
+ [[self fileStore] setName: libraryName];
+
+ defaultGroups = [NSMutableDictionary dictionaryWithObject: myGroups forKey: LiGroupsAttribute];
+ [self setDefaultAttributes: defaultGroups];
+}
+
+- (void)loadDefaultAttrs
+{
+ NSDictionary *defaultAttrDict;
+
+ defaultAttrDict = [NSDictionary dictionaryWithContentsOfFile: [[Preferences sharedPreferences] groupPath]];
+ if (defaultAttrDict != nil) {
+ NSNumber *versionNumber;
+
+ versionNumber = [defaultAttrDict objectForKey: @"LiDBVersion"];
+ if ([versionNumber intValue] == 1) {
+ NSDictionary *flattenedDefaults;
+ NSEnumerator *defaultEnum;
+ NSMutableDictionary *myDefaults;
+ NSString *attr;
+
+ [LiLog logAsDebug: @"Load my version group dict"];
+ myDefaults = [NSMutableDictionary dictionary];
+ flattenedDefaults = [defaultAttrDict objectForKey: @"LiDefaultAttributes"];
+ defaultEnum = [flattenedDefaults keyEnumerator];
+ while ((attr = [defaultEnum nextObject]) != nil) {
+ NSMutableSet *values;
+
+ values = [NSMutableSet setWithArray: [flattenedDefaults objectForKey: attr]];
+ [myDefaults setObject: values forKey: attr];
+ }
+ [self setDefaultAttributes: myDefaults];
+ } else {
+ [self convertGroupDict: defaultAttrDict];
+ }
+ }
+}
+
+- (BOOL)synchronizeDefaultAttrs
+{
+ NSDictionary *defaultDict;
+ NSEnumerator *defaultEnum;
+ NSMutableDictionary *flattenedDefaults;
+ NSString *attr;
+
+ flattenedDefaults = [NSMutableDictionary dictionary];
+ defaultEnum = [[self defaultAttributes] keyEnumerator];
+ while ((attr = [defaultEnum nextObject]) != nil) {
+ NSArray *values;
+
+ values = [[[self defaultAttributes] objectForKey: attr] allObjects];
+ [flattenedDefaults setObject: values forKey: attr];
+ }
+
+ defaultDict = [NSDictionary dictionaryWithObjects:
+ [NSArray arrayWithObjects: [NSNumber numberWithInt: 1], flattenedDefaults, nil]
+ forKeys:
+ [NSArray arrayWithObjects: @"LiDBVersion", @"LiDefaultAttributes", nil]];
+
+ return [defaultDict writeToFile: [[Preferences sharedPreferences] groupPath] atomically: YES];
+}
+
+- (id)init
+{
+ NSImage *image;
+ NSString *iconPath;
+
+ self = [super init];
+
+ [self loadDefaultAttrs];
+
+ // Register often-used images.
+ iconPath = [[NSBundle bundleForClass: [self class]] pathForResource: @"NotThere" ofType: @"icns"];
+ image = [[NSImage alloc] initWithContentsOfFile: iconPath];
+ [image setName: @"LiBuiltInFunctions NotThereImage"];
+
+ iconPath = [[NSBundle bundleForClass: [self class]] pathForResource: @"local" ofType: @"tiff"];
+ image = [[NSImage alloc] initWithContentsOfFile: iconPath];
+ [image setName: @"LiBuiltInFunctions FileStoreIcon"];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ NSImage *image;
+
+ [self setDefaultAttributes: nil];
+
+ // XXX - should this be done this way?
+ image = [NSImage imageNamed: @"LiBuiltInFunctions NotThereImage"];
+ [image setName: nil];
+ [image release];
+ image = [NSImage imageNamed: @"LiBuiltInFunctions FileStoreIcon"];
+ [image setName: nil];
+ [image release];
+
+ [super dealloc];
+}
+
+- (LiBrowserColumn *)columnForIcon
+{
+ LiBrowserColumn *col;
+
+ col = [[[LiBrowserColumn alloc] init] autorelease];
+ [col setIdentifier: @"icon"];
+ [col setName: myLocalizedString(@"IconHeader")];
+ [col setCell: [[[NSImageCell alloc] init] autorelease]];
+ [col setWidth: [NSNumber numberWithFloat: 16.0]];
+ [col setEditable: NO];
+ [col setResizable: NO];
+ [col setShowsHeader: NO];
+ [col setGetMethod: @selector(icon)];
+
+ return col;
+}
+
+- (LiBrowserColumn *)columnForFilename
+{
+ LiBrowserColumn *col;
+ NSCell *cell;
+
+ col = [[[LiBrowserColumn alloc] init] autorelease];
+ [col setIdentifier: @"filename"];
+ [col setName: myLocalizedString(@"FilenameHeader")];
+ cell = [[[NSTextFieldCell alloc] init] autorelease];
+ [cell setEditable: YES];
+ [col setCell: cell];
+ [col setEditable: YES];
+ [col setShowsHeader: YES];
+ [col setGetMethod: @selector(filename)];
+ [col setSetMethod: @selector(setFilename:)];
+ [col setCompareMethod: @selector(caseInsensitiveCompare:)];
+
+ return col;
+}
+
+- (LiFilterDescription *)descriptionForFilename
+{
+ LiFilterDescription *description;
+ NSCell *cell;
+ NSDictionary *compareOps;
+
+ compareOps = [NSDictionary dictionaryWithObjects:
+ [NSArray arrayWithObjects: @"isEqualToString:",
+ @"containsString:", nil]
+ forKeys:
+ [NSArray arrayWithObjects: myLocalizedString(@"LiEqualsOperator"),
+ myLocalizedString(@"LiContainsOperator"), nil]];
+ cell = [[[NSTextFieldCell alloc] init] autorelease];
+ [cell setEditable: YES];
+ description = [LiFilterDescription descriptionForMethod: @selector(filename)
+ name: myLocalizedString(LiFilenameAttribute)
+ compareOperators: compareOps
+ valueEditorCell: cell];
+
+ return description;
+}
+
+- (LiBrowserColumn *)columnForType
+{
+ LiBrowserColumn *col;
+ NSCell *cell;
+
+ col = [[[LiBrowserColumn alloc] init] autorelease];
+ [col setIdentifier: @"type"];
+ [col setName: myLocalizedString(@"TypeHeader")];
+ cell = [[[NSTextFieldCell alloc] init] autorelease];
+ [cell setEditable: YES];
+ [col setCell: cell];
+ [col setEditable: YES];
+ [col setShowsHeader: YES];
+ [col setGetMethod: @selector(type)];
+ [col setSetMethod: @selector(setType:)];
+ [col setCompareMethod: @selector(caseInsensitiveCompare:)];
+
+ return col;
+}
+
+- (LiBrowserColumn *)columnForLastModified
+{
+ LiBrowserColumn *col;
+ NSCell *cell;
+
+ col = [[[LiBrowserColumn alloc] init] autorelease];
+ [col setIdentifier: @"lastModified"];
+ [col setName: myLocalizedString(@"LastModifiedTimeHeader")];
+ cell = [[[NSTextFieldCell alloc] init] autorelease];
+ [cell setFormatter: [[[NaturalDateFormatter alloc] initWithNaturalLanguage: YES] autorelease]];
+ [cell setEditable: YES];
+ [cell setAlignment: NSRightTextAlignment];
+ [col setCell: cell];
+ [col setEditable: YES];
+ [col setShowsHeader: YES];
+ [col setGetMethod: @selector(lastModifiedTime)];
+ [col setSetMethod: @selector(setLastModifiedTime:)];
+ [col setCompareMethod: @selector(compare:)];
+
+ return col;
+}
+
+- (LiBrowserColumn *)columnForCreation
+{
+ LiBrowserColumn *col;
+ NSCell *cell;
+
+ col = [[[LiBrowserColumn alloc] init] autorelease];
+ [col setIdentifier: @"creation"];
+ [col setName: myLocalizedString(@"CreatedTimeHeader")];
+ cell = [[[NSTextFieldCell alloc] init] autorelease];
+ [cell setFormatter: [[[NaturalDateFormatter alloc] initWithNaturalLanguage: YES] autorelease]];
+ [cell setEditable: YES];
+ [cell setAlignment: NSRightTextAlignment];
+ [col setCell: cell];
+ [col setEditable: YES];
+ [col setShowsHeader: YES];
+ [col setGetMethod: @selector(creationTime)];
+ [col setSetMethod: @selector(setCreationTime:)];
+ [col setCompareMethod: @selector(compare:)];
+
+ return col;
+}
+
+- (LiBrowserColumn *)columnForSize
+{
+ LiBrowserColumn *col;
+ FileSizeFormatter *cellFormatter;
+ NSCell *cell;
+
+ col = [[[LiBrowserColumn alloc] init] autorelease];
+ [col setIdentifier: @"size"];
+ [col setName: myLocalizedString(@"FileSizeHeader")];
+ cell = [[[NSTextFieldCell alloc] init] autorelease];
+ cellFormatter = [[[FileSizeFormatter alloc] init] autorelease];
+ [cellFormatter setAllowsFloats: NO];
+ [cell setFormatter: cellFormatter];
+ [cell setAlignment: NSRightTextAlignment];
+ [col setCell: cell];
+ [col setEditable: NO];
+ [col setShowsHeader: YES];
+ [col setGetMethod: @selector(fileSize)];
+ [col setCompareMethod: @selector(compare:)];
+
+ return col;
+}
+
+- (NSArray *)columns
+{
+ NSArray *columns;
+
+ columns = [NSArray arrayWithObjects:
+ [self columnForIcon], [self columnForFilename], [self columnForType],
+ [self columnForLastModified], [self columnForCreation],
+ [self columnForSize], nil];
+
+ return columns;
+}
+
+- (NSDictionary *)filterDescriptions
+{
+ NSDictionary *descriptions;
+
+ descriptions = [NSDictionary dictionaryWithObjects:
+ [NSArray arrayWithObjects: [self descriptionForFilename], nil]
+ forKeys:
+ [NSArray arrayWithObjects: LiFilenameAttribute, nil]];
+
+ return descriptions;
+}
+
+- (LiInspectorView *)viewForFile
+{
+ LiInspectorView *view;
+
+ view = [[[LiInspectorView alloc] init] autorelease];
+ [view setIdentifier: @"file"];
+ [view setName: @"File"];
+ [view setImage: nil];
+ [view setView: [[self viewController] fileView]];
+ [view setIsVerticallyResizable: NO];
+ [view setIsHorizontallyResizable: YES];
+ [view setViewSize: [[view view] frame].size];
+
+ return view;
+}
+
+- (LiInspectorView *)viewForHFS
+{
+ LiInspectorView *view;
+
+ view = [[[LiInspectorView alloc] init] autorelease];
+ [view setIdentifier: @"hfs"];
+ [view setName: @"HFS"];
+ [view setImage: nil];
+ [view setIsVerticallyResizable: NO];
+ [view setIsHorizontallyResizable: NO];
+ [view setView: [[self viewController] hfsView]];
+ [view setViewSize: [[view view] frame].size];
+
+ return view;
+}
+
+- (NSArray *)allInspectorViews
+{
+ return [NSArray arrayWithObjects: [self viewForFile], [self viewForHFS], nil];
+}
+
+- (NSArray *)inspectorViewsForFile: (LiFileHandle *)aFile
+{
+ if (aFile != nil) {
+ NSMutableArray *viewArray;
+
+ viewArray = [NSMutableArray arrayWithObject: [self viewForFile]];
+ [viewArray addObject: [self viewForHFS]];
+ return viewArray;
+ }
+ return nil;
+}
+
+- (void)setFile: (LiFileHandle *)aFile
+{
+ if (aFile != nil) {
+ [[self viewController] setFile: aFile];
+ }
+}
+
+//
+// File store delegate stuff.
+//
+- (void)openFileHandle: (LiFileHandle *)aFileHandle
+{
+ NSString *path;
+
+ path = [aFileHandle path];
+ if (path != nil) {
+ [[NSWorkspace sharedWorkspace] openFile: [aFileHandle path]];
+ [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL: [NSURL fileURLWithPath: [aFileHandle path]]];
+ } else {
+ [LiLog alertWithHeader: @"Couldn't locate file" contents: @"This message sucks and will be changed so you can locate the file again."];
+ }
+}
+
+- (void)copyFile: (LiFileHandle *)aFileHandle
+{
+ [LiLog logAsDebug: @"should copy %@", [aFileHandle filename]];
+}
+
+- (NSDictionary *)fileSystemAttributesForPath: (NSString *)aPath
+{
+ NSMutableDictionary *tmpAttributes;
+
+ tmpAttributes = nil;
+ if (aPath != nil) {
+ BDAlias *alias;
+ NSString *filename, *filetype, *dir;
+
+ // Set the attributes that are valid for every file with a path.
+ tmpAttributes = [NSMutableDictionary dictionary];
+ filename = [[aPath lastPathComponent] stringByDeletingPathExtension];
+ filetype = [aPath pathExtension];
+ dir = [aPath stringByDeletingLastPathComponent];
+ [tmpAttributes setObject: filename forKey: LiFilenameAttribute];
+ [tmpAttributes setObject: filetype forKey: LiTypeAttribute];
+ [tmpAttributes setObject: dir forKey: LiDirectoryAttribute];
+
+ // Test if the file is resolvable by getting its alias.
+ alias = [BDAlias aliasWithPath: aPath];
+ if (alias != nil) {
+ NSDate *modifiedTime, *createdTime;
+ NSDictionary *fileAttrs;
+ NSFileWrapper *file;
+ NSNumber *fileSize, *hfsCreator, *hfsType;
+ NSString *application;
+
+ [tmpAttributes setObject: [alias aliasData]
+ forKey: LiAliasDataAttribute];
+
+ file = [[NSFileWrapper alloc] initWithPath: aPath];
+ fileAttrs = [[NSFileManager defaultManager] fileAttributesAtPath: aPath traverseLink: YES];
+
+ // Load attributes from disk.
+ modifiedTime = [fileAttrs objectForKey: NSFileModificationDate];
+ createdTime = [fileAttrs objectForKey: NSFileCreationDate];
+ fileSize = [fileAttrs objectForKey: NSFileSize];
+ hfsCreator = [fileAttrs objectForKey: NSFileHFSCreatorCode];
+ hfsType = [fileAttrs objectForKey: NSFileHFSTypeCode];
+ [[NSWorkspace sharedWorkspace] getInfoForFile: aPath
+ application: &application
+ type: &filetype];
+ if (modifiedTime != nil)
+ [tmpAttributes setObject: modifiedTime
+ forKey: LiLastModifiedDateAttribute];
+ if (createdTime != nil)
+ [tmpAttributes setObject: createdTime
+ forKey: LiCreationDateAttribute];
+ if (fileSize != nil)
+ [tmpAttributes setObject: fileSize
+ forKey: LiFileSizeAttribute];
+ if (application != nil)
+ [tmpAttributes setObject: application
+ forKey: LiApplicationAttribute];
+ if (hfsCreator != nil)
+ [tmpAttributes setObject: hfsCreator
+ forKey: LiHFSCreatorAttribute];
+ if (hfsType != nil)
+ [tmpAttributes setObject: hfsType
+ forKey: LiHFSTypeAttribute];
+ [tmpAttributes setObject: [NSNumber numberWithBool: YES]
+ forKey: LiIsEditableAttribute];
+
+ [file release];
+ } else {
+ [tmpAttributes setObject: [NSNumber numberWithBool: NO]
+ forKey: LiIsEditableAttribute];
+ }
+ }
+
+ return tmpAttributes;
+}
+
+- (NSDictionary *)fileSystemAttributesForAliasData: (NSData *)aliasData
+{
+ BDAlias *alias;
+
+ alias = [BDAlias aliasWithData: aliasData];
+ return [self fileSystemAttributesForPath: [alias fullPath]];
+}
+
+- (void)convertFirstVersionDict: (NSDictionary *)fileDict
+ fileStore: (LiFileStore *)aFileStore
+{
+ NSDictionary *filesInDict, *attrDict;
+ NSEnumerator *fileEnum;
+
+ filesInDict = [fileDict objectForKey: @"files"];
+ fileEnum = [filesInDict objectEnumerator];
+ while ((attrDict = [fileEnum nextObject]) != nil) {
+ NSData *fileAlias;
+ NSDictionary *fileAttrs;
+ NSEnumerator *groupEnum;
+ NSMutableArray *fileGroups;
+ NSMutableDictionary *myFileAttrs;
+ NSNumber *fileHandle;
+ NSString *groupname;
+
+ fileHandle = [attrDict objectForKey: @"filehandle"];
+ fileAlias = [attrDict objectForKey: @"alias"];
+
+ fileAttrs = [self fileSystemAttributesForAliasData:
+ fileAlias];
+ if (fileAttrs == nil) {
+ [LiLog logAsWarning: @"Couldn't load attributes for %@: abandoning.",
+ [attrDict objectForKey: @"path"]];
+ }
+ myFileAttrs = [NSMutableDictionary dictionaryWithDictionary: fileAttrs];
+ [myFileAttrs setObject: fileHandle forKey: LiFileHandleAttribute];
+
+ fileGroups = [NSMutableArray array];
+ groupEnum = [[attrDict objectForKey: @"groups"] objectEnumerator];
+ while ((groupname = [groupEnum nextObject]) != nil) {
+ if ([groupname isEqualToString: @"/"] == NO)
+ [fileGroups addObject: groupname];
+ }
+ [myFileAttrs setObject: fileGroups forKey: LiGroupsAttribute];
+
+ [aFileStore addFileWithAttributes: myFileAttrs];
+ }
+}
+
+- (BOOL)loadFileStore: (LiFileStore *)aFileStore
+{
+ NSDictionary *fileStoreDict;
+
+ // Make sure we have the right indexes.
+ [aFileStore addIndexForAttribute: LiGroupsAttribute];
+ [aFileStore addIndexForAttribute: LiAliasDataAttribute];
+
+ fileStoreDict = [NSDictionary dictionaryWithContentsOfFile: [[Preferences sharedPreferences] libraryPath]];
+ if (fileStoreDict != nil) {
+ NSNumber *versionNumber;
+
+ versionNumber = [fileStoreDict objectForKey: @"LiDBVersion"];
+ if ([versionNumber intValue] == 1) {
+ NSArray *allFiles;
+ NSDictionary *fileDict;
+
+ allFiles = [fileStoreDict objectForKey: @"LiFileStore"];
+ for (fileDict in allFiles) {
+ BDAlias *alias;
+ NSMutableDictionary *baseAttrs;
+
+ baseAttrs = [[NSMutableDictionary alloc] initWithDictionary: fileDict];
+
+ alias = [[BDAlias alloc] initWithData: [fileDict objectForKey: LiAliasDataAttribute]];
+ if ([alias fullPath] == nil) {
+ NSString *path, *filename, *directory;
+
+ directory = [fileDict objectForKey: LiDirectoryAttribute];
+ filename = [[fileDict objectForKey: LiFilenameAttribute] stringByAppendingPathExtension: [fileDict objectForKey: LiTypeAttribute]];
+ path = [directory stringByAppendingPathComponent: filename];
+
+ [LiLog logAsDebug: @"Couldn't locate file: %@ - (dir: %@, path: %@)", filename, directory, path];
+
+ alias = [[BDAlias alloc] initWithPath: path];
+ if ([alias fullPath] != nil) {
+ [baseAttrs setObject: [[alias fullPath] stringByDeletingLastPathComponent] forKey: LiDirectoryAttribute];
+ [baseAttrs setObject: [alias aliasData] forKey: LiAliasDataAttribute];
+ }
+ }
+
+ if ([alias aliasData] == nil) {
+ [baseAttrs setObject: [NSNumber numberWithBool: NO] forKey: LiIsEditableAttribute];
+ } else {
+ [baseAttrs setObject: [NSNumber numberWithBool: YES] forKey: LiIsEditableAttribute];
+ }
+
+ [aFileStore addFileWithAttributes: baseAttrs];
+
+ [baseAttrs release];
+ [alias release];
+ }
+ } else {
+ [self convertFirstVersionDict: fileStoreDict
+ fileStore: aFileStore];
+ }
+ }
+
+ [aFileStore synchronize];
+ return YES;
+}
+
+- (BOOL)synchronizeFileStore
+{
+ LiFileHandle *fileHandle;
+ NSArray *allFileHandles;
+ NSMutableArray *allFiles;
+ NSDictionary *fileDict;
+ NSString *path;
+
+ [LiLog logAsDebug: @"[LiBuiltInFunctions synchronizeFileStore]"];
+ [LiLog indentDebugLog];
+
+ path = [[Preferences sharedPreferences] libraryPath];
+
+ allFiles = [NSMutableArray array];
+ allFileHandles = [[self fileStore] allFileHandles];
+ for (fileHandle in allFileHandles) {
+ NSMutableDictionary *filteredAttrs;
+
+ filteredAttrs = [NSMutableDictionary dictionaryWithDictionary:
+ [fileHandle dictionary]];
+ [allFiles addObject: filteredAttrs];
+ }
+
+ fileDict = [NSDictionary dictionaryWithObjects:
+ [NSArray arrayWithObjects:
+ [NSNumber numberWithInt: 1], allFiles, nil]
+ forKeys:
+ [NSArray arrayWithObjects:
+ @"LiDBVersion", @"LiFileStore", nil]];
+ [LiLog logAsDebug: @"writing to: %@", path];
+ [fileDict writeToFile: path atomically: YES];
+ [LiLog logAsDebug: @"done!"];
+
+ [LiLog unindentDebugLog];
+ return YES;
+}
+
+- (void)synchronizeFileHandle: (LiFileHandle *)aFileHandle
+ withNewAttributes: (NSMutableDictionary *)someAttributes
+{
+ NSDictionary *fileAttrDict;
+ NSEnumerator *attrEnum;
+ NSMutableDictionary *fileAttrs;
+ NSSet *pathSet;
+ NSString *attr;
+ BOOL pathDone;
+
+ [LiLog logAsDebug: @"[LiBuiltInFunctions synchronizeFileHandle: (fh) withNewAttributes: %@]", someAttributes];
+ [LiLog indentDebugLog];
+
+ pathDone = NO;
+ pathSet = [NSSet setWithArray:
+ [NSArray arrayWithObjects:
+ LiDirectoryAttribute, LiFilenameAttribute, LiTypeAttribute, nil]];
+ fileAttrDict = [NSDictionary dictionaryWithObjects:
+ [NSArray arrayWithObjects:
+ NSFileModificationDate, NSFileCreationDate,
+ NSFileHFSCreatorCode, NSFileHFSTypeCode,
+ nil]
+ forKeys:
+ [NSArray arrayWithObjects:
+ LiLastModifiedDateAttribute, LiCreationDateAttribute,
+ LiHFSCreatorAttribute, LiHFSTypeAttribute,
+ nil]];
+
+ fileAttrs = [NSMutableDictionary dictionary];
+ attrEnum = [someAttributes keyEnumerator];
+ while ((attr = [attrEnum nextObject]) != nil) {
+ if (pathDone == NO && [pathSet containsObject: attr]) {
+ NSString *filename, *type;
+ NSString *path, *oldPath;
+
+ filename = [someAttributes objectForKey: LiFilenameAttribute];
+ if (filename == nil)
+ filename = [aFileHandle filename];
+
+ type = [someAttributes objectForKey: LiTypeAttribute];
+ if (type == nil)
+ type = [aFileHandle type];
+
+ path = [someAttributes objectForKey: LiDirectoryAttribute];
+ if (path == nil)
+ path = [aFileHandle directory];
+
+ if (type && [type length] > 0) {
+ filename = [filename stringByAppendingPathExtension: type];
+ }
+ path = [path stringByAppendingPathComponent: filename];
+
+ oldPath = [[aFileHandle alias] fullPath];
+ if ([oldPath isEqualToString: path] == NO) {
+ int rc;
+
+ rc = 0;
+ rc = rename([oldPath UTF8String], [path UTF8String]);
+ if (rc == -1) {
+ NSString *header, *contents;
+
+ switch (errno) {
+ case ENOENT:
+ header = myLocalizedErrorString(@"LiBadFilenameErrorHeader");
+ contents = myLocalizedErrorString(@"LiBadFilenameErrorContents");
+ break;
+
+ case EROFS:
+ header = myLocalizedErrorString(@"LiReadOnlyFileSytemErrorHeader");
+ contents = myLocalizedErrorString(@"LiReadOnlyFileSytemErrorContents");
+ break;
+
+ case EPERM:
+ case EACCES:
+ header = myLocalizedErrorString(@"LiPermissionDeniedErrorHeader");
+ contents = myLocalizedErrorString(@"LiPermissionDeniedErrorContents");
+ break;
+
+ default:
+ header = myLocalizedErrorString(@"LiGenericRenameErrorHeader");
+ contents = myLocalizedErrorString(@"LiGenericRenameErrorContents");
+ }
+ [LiLog alertWithHeader: header contents: contents];
+ }
+ }
+
+ pathDone = YES;
+ } else if ([fileAttrDict objectForKey: attr] != nil) {
+ [fileAttrs setObject: [someAttributes objectForKey: attr]
+ forKey: attr];
+ }
+ }
+
+ if ([fileAttrs count] > 0) {
+ NSFileManager *defaultManager;
+
+ defaultManager = [NSFileManager defaultManager];
+ [defaultManager changeFileAttributes: fileAttrs
+ atPath: [[aFileHandle alias] fullPath]];
+ }
+
+ // XXX - should flag to see if the icon needs updating and
+ // do it here, since we can't scan for that change.
+
+ [LiLog unindentDebugLog];
+}
+
+- (BOOL)shouldUpdateFileHandle: (LiFileHandle *)aFileHandle
+{
+ NSDate *handleDate, *fileDate;
+ NSFileWrapper *file;
+ NSString *newPath;
+
+ newPath = [[aFileHandle alias] fullPath];
+ if ([newPath compare: [aFileHandle path]] != 0)
+ return YES;
+
+ file = [[[NSFileWrapper alloc] initWithPath: newPath] autorelease];
+ fileDate = [[file fileAttributes] objectForKey:
+ NSFileModificationDate];
+ handleDate = [aFileHandle lastModifiedTime];
+
+ if ([fileDate compare: handleDate] == 0)
+ return NO;
+ else
+ return YES;
+}
+
+- (void)updateFileHandle: (LiFileHandle *)aFileHandle
+{
+ NSMutableDictionary *fileAttrs;
+
+ [LiLog logAsDebug: @"[LiBuiltInFunctions updateFileHandle: %@]", [aFileHandle description]];
+ fileAttrs = [NSMutableDictionary dictionaryWithDictionary:
+ [self fileSystemAttributesForAliasData:
+ [aFileHandle valueForAttribute: LiAliasDataAttribute]]];
+ [LiLog logAsDebug: @"fileAttrs: %@", [fileAttrs description]];
+
+ // Attempt path resolution if alias resolution fails.
+ if ([fileAttrs count] == 0) {
+ NSString *filePath, *filename;
+
+ filename = [[aFileHandle filename] stringByAppendingPathExtension: [aFileHandle type]];
+ filePath = [[aFileHandle directory] stringByAppendingPathComponent: filename];
+ [LiLog logAsDebug: @"Attempting to resolve path %@ to alias", filePath];
+ fileAttrs = [NSMutableDictionary dictionaryWithDictionary:
+ [self fileSystemAttributesForPath: filePath]];
+ [LiLog logAsDebug: @"\tresolved to: %@", fileAttrs];
+ }
+
+ if (fileAttrs != nil) {
+ NSDictionary *myAttrs;
+ NSEnumerator *keyEnum;
+ NSString *key;
+
+ myAttrs = [[aFileHandle fileStore] attributesForFileHandle:
+ aFileHandle];
+ keyEnum = [fileAttrs keyEnumerator];
+ while ((key = [keyEnum nextObject]) != nil) {
+ id myValue;
+
+ myValue = [myAttrs objectForKey: key];
+ if (myValue != nil) {
+ id value;
+
+ value = [fileAttrs objectForKey: key];
+ if (myValue == value) {
+ [fileAttrs removeObjectForKey: key];
+ } else {
+ if ([myValue respondsToSelector: @selector(compare:)]) {
+ if ([myValue performSelector: @selector(compare:) withObject: value] == 0) {
+ [fileAttrs removeObjectForKey: key];
+ }
+ } else {
+ // XXX
+ // Disabled because the icon keeps changing
+ // on every check.
+ [fileAttrs removeObjectForKey: key];
+ }
+ }
+ }
+ }
+
+ if ([fileAttrs count] > 0) {
+ [LiLog logAsDebug: @"fileAttrs: %@", [fileAttrs description]];
+ [[aFileHandle fileStore] updateFileHandle: aFileHandle
+ withAttributes: fileAttrs];
+ }
+ }
+}
+
+- (LiFileHandle *)addURL: (NSURL *)anURL
+ toFileStore: (LiFileStore *)aFileStore
+{
+ if ([anURL isFileURL] == YES) {
+ BDAlias *alias;
+ NSArray *existingFiles;
+ NSDictionary *fileAttrs;
+
+ // Attempt resolution of the file handle to determine uniqueness.
+ // If it's not there, it's automatically unique.
+ alias = [BDAlias aliasWithPath: [anURL path]];
+ if (alias != nil) {
+ LiFilter *filter;
+
+ filter = [LiFilter filterWithAttribute: LiAliasDataAttribute
+ compareSelector: @selector(isEqual:)
+ value: [alias aliasData]];
+
+ existingFiles = [[self fileStore] filesMatchingFilter: filter];
+ if ([existingFiles count] > 0) {
+ return [existingFiles objectAtIndex: 0];
+ }
+ }
+
+ fileAttrs = [self fileSystemAttributesForPath: [anURL path]];
+ return [[self fileStore] addFileWithAttributes: fileAttrs];
+ }
+ return nil;
+}
+
+- (NSURL *)urlForFileHandle: (LiFileHandle *)aFileHandle
+{
+ NSString *path;
+ NSURL *url;
+
+ url = nil;
+ path = [aFileHandle path];
+ if (path != nil)
+ url = [NSURL fileURLWithPath: path];
+ return url;
+}
+
+- (NSArray *)defaultValuesForAttribute: (NSString *)anAttribute
+{
+ NSMutableSet *values;
+
+ values = [[self defaultAttributes] objectForKey: anAttribute];
+ return [values allObjects];
+}
+
+- (BOOL)addDefaultAttribute: (NSDictionary *)anAttribute toFileStore: (LiFileStore *)aFileStore
+{
+ NSEnumerator *attrEnum;
+ NSMutableDictionary *defaultAttrs;
+ NSMutableSet *values;
+ NSString *attr;
+
+ [LiLog logAsDebug: @"[LiBuiltInFunctions addDefaultAttribute: %@ toFileStore: %@]", anAttribute, aFileStore];
+ [LiLog indentDebugLog];
+ defaultAttrs = [self defaultAttributes];
+ attrEnum = [anAttribute keyEnumerator];
+ while ((attr = [attrEnum nextObject]) != nil) {
+ values = [defaultAttrs objectForKey: attr];
+ if (values == nil) {
+ values = [NSMutableSet set];
+ [defaultAttrs setObject: values forKey: attr];
+ }
+ [values addObject: [anAttribute objectForKey: attr]];
+ }
+
+ [LiLog unindentDebugLog];
+
+ return [self synchronizeDefaultAttrs];
+}
+
+- (BOOL)changeDefaultValueForAttribute: (NSDictionary *)anAttribute toValue: (id)aValue inFileStore: (LiFileStore *)aFileStore
+{
+ NSEnumerator *attrEnum;
+ NSMutableDictionary *defaultAttrs;
+ NSMutableSet *values;
+ NSString *attr;
+
+ defaultAttrs = [self defaultAttributes];
+ attrEnum = [anAttribute keyEnumerator];
+ while ((attr = [attrEnum nextObject]) != nil) {
+ values = [defaultAttrs objectForKey: attr];
+ if (values == nil) {
+ return NO;
+ }
+ [values removeObject: [anAttribute objectForKey: attr]];
+ [values addObject: aValue];
+ }
+
+ return [self synchronizeDefaultAttrs];
+}
+
+- (BOOL)removeDefaultAttribute: (NSDictionary *)anAttribute fromFileStore: (LiFileStore *)aFileStore
+{
+ NSEnumerator *attrEnum;
+ NSMutableDictionary *defaultAttrs;
+ NSMutableSet *values;
+ NSString *attr;
+
+ defaultAttrs = [self defaultAttributes];
+ attrEnum = [anAttribute keyEnumerator];
+ while ((attr = [attrEnum nextObject]) != nil) {
+ values = [defaultAttrs objectForKey: attr];
+ [values removeObject: [anAttribute objectForKey: attr]];
+ }
+
+ return [self synchronizeDefaultAttrs];
+}
+
+- (void)initFileStore
+{
+ LiFileStore *tmpStore;
+
+ tmpStore = [LiFileStore fileStoreWithName: myLocalizedString(@"LiLibraryName")];
+ [tmpStore setEditable: YES];
+ [tmpStore setIcon: [NSImage imageNamed: @"LiBuiltInFunctions FileStoreIcon"]];
+ [tmpStore setDelegate: self];
+ [self setFileStore: tmpStore];
+ [self loadFileStore: [self fileStore]];
+}
+
+- (LiFileStore *)fileStore
+{
+ return theFileStore;
+}
+@synthesize theController;
+@synthesize theDefaultAttributes;
+@synthesize theFileStore;
+@end
+
+@implementation LiBuiltInFunctions (Accessors)
+- (void)setFileStore: (LiFileStore *)aFileStore
+{
+ [aFileStore retain];
+ [theFileStore release];
+ theFileStore = aFileStore;
+
+ [theFileStore setDelegate: self];
+}
+
+- (InspectorViewController *)viewController
+{
+ if (theController == nil) {
+ if ([NSBundle loadNibNamed: @"InspectorViews.nib" owner: self] == NO) {
+ [LiLog logAsError: @"Couldn't open inspector view nib file."];
+ return nil;
+ }
+ }
+ return theController;
+}
+
+- (NSMutableDictionary *)defaultAttributes
+{
+ return theDefaultAttributes;
+}
+
+- (void)setDefaultAttributes: (NSMutableDictionary *)someAttributes
+{
+ [someAttributes retain];
+ [theDefaultAttributes release];
+ theDefaultAttributes = someAttributes;
+}
+@end
+
+@implementation LiFileHandle (LiBuiltInFunctions)
+- (NSImage *)icon
+{
+ NSImage *icon;
+ NSURL *myURL;
+
+ myURL = [self url];
+ if ([myURL isFileURL] == YES)
+ icon = [[NSWorkspace sharedWorkspace] iconForFile: [self path]];
+ else if (myURL == nil)
+ icon = [NSImage imageNamed: @"LiBuiltInFunctions NotThereImage"];
+ else
+ icon = [[NSWorkspace sharedWorkspace] iconForFileType: [self type]];
+ return icon;
+}
+
+- (BDAlias *)alias
+{
+ BDAlias *tmpAlias;
+
+ tmpAlias = [BDAlias aliasWithData:
+ [self valueForAttribute: LiAliasDataAttribute]];
+
+ return tmpAlias;
+}
+
+- (void)setAlias: (BDAlias *)anAlias
+{
+ [self setValue: [anAlias aliasData]
+ forAttribute: LiAliasDataAttribute];
+}
+
+- (NSString *)path
+{
+ return [[self alias] fullPath];
+}
+
+- (NSString *)directory
+{
+ return [self valueForAttribute: LiDirectoryAttribute];
+}
+@end \ No newline at end of file
diff --git a/Plugins/BuiltInFunctions/LiImageView.h b/Plugins/BuiltInFunctions/LiImageView.h
new file mode 100644
index 0000000..6a14bea
--- /dev/null
+++ b/Plugins/BuiltInFunctions/LiImageView.h
@@ -0,0 +1,6 @@
+/* LiImageView */
+
+@interface LiImageView : NSImageView
+{
+}
+@end
diff --git a/Plugins/BuiltInFunctions/LiImageView.m b/Plugins/BuiltInFunctions/LiImageView.m
new file mode 100644
index 0000000..57bc46f
--- /dev/null
+++ b/Plugins/BuiltInFunctions/LiImageView.m
@@ -0,0 +1,59 @@
+#import "LiImageView.h"
+
+@implementation LiImageView
+- (NSArray *)namesOfPromisedFilesDroppedAtDestination: (NSURL *)dropDestination
+{
+ NSFileManager *defaultManager;
+ NSString *imageDir, *path, *filename;
+ int suffix;
+
+ [LiLog logAsDebug: @"[LiImageView names..Desitination: %@]", dropDestination];
+
+ imageDir = [dropDestination path];
+ defaultManager = [NSFileManager defaultManager];
+ for (suffix = 0; suffix < 100; suffix++) {
+ filename = [NSString stringWithFormat: @"LiaisonIcon%02d.tiff", suffix];
+ path = [imageDir stringByAppendingPathComponent: filename];
+ if ([defaultManager fileExistsAtPath: path] == NO) {
+ [LiLog logAsDebug: @"\tsaving to path: %@", path];
+ break;
+ }
+ }
+
+ if (suffix < 100) {
+ if ([defaultManager createFileAtPath: path
+ contents: [[self image] TIFFRepresentation]
+ attributes: nil] == NO) {
+ return nil;
+ }
+ } else
+ return nil;
+
+ return [NSArray arrayWithObject: filename];
+}
+
+- (void)mouseDown: (NSEvent *)theEvent
+{
+ NSPoint dragPosition;
+ NSRect imageLocation;
+
+ [[NSApp keyWindow] makeFirstResponder: self];
+
+ dragPosition = [self convertPoint: [theEvent locationInWindow]
+ fromView: nil];
+ dragPosition.x -= 16;
+ dragPosition.y -= 16;
+ imageLocation.origin = dragPosition;
+ imageLocation.size = NSMakeSize(32,32);
+ [self dragPromisedFilesOfTypes: [NSArray arrayWithObject: @"tiff"]
+ fromRect: imageLocation source: self
+ slideBack: YES event: theEvent];
+}
+
+- (void)mouseDragged: (NSEvent *)anEvent
+{
+ [LiLog logAsDebug: @"[LiImageView mouseDragged]"];
+
+ [super mouseDragged: anEvent];
+}
+@end
diff --git a/Plugins/BuiltInFunctions/NaturalDateFormatter.h b/Plugins/BuiltInFunctions/NaturalDateFormatter.h
new file mode 100644
index 0000000..76ac5ac
--- /dev/null
+++ b/Plugins/BuiltInFunctions/NaturalDateFormatter.h
@@ -0,0 +1,11 @@
+//
+// NaturalDateFormatter.h
+// BuiltInFunctions
+//
+// Created by Brian Cully on Sun Aug 31 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+@interface NaturalDateFormatter : NSDateFormatter
+- (id)initWithNaturalLanguage: (BOOL)flag;
+@end
diff --git a/Plugins/BuiltInFunctions/NaturalDateFormatter.m b/Plugins/BuiltInFunctions/NaturalDateFormatter.m
new file mode 100644
index 0000000..da83ee6
--- /dev/null
+++ b/Plugins/BuiltInFunctions/NaturalDateFormatter.m
@@ -0,0 +1,58 @@
+//
+// NaturalDateFormatter.m
+// BuiltInFunctions
+//
+// Created by Brian Cully on Sun Aug 31 2003.
+// Copyright (c) 2003 Brian Cully. All rights reserved.
+//
+
+#import "NaturalDateFormatter.h"
+
+#import "LiBuiltInFunctions.h"
+
+static NSString *
+myLocalizedString(NSString *aString)
+{
+ return NSLocalizedStringFromTableInBundle(aString, @"BuiltInFunctions",
+ [LiBuiltInFunctions bundle], @"");
+}
+
+@implementation NaturalDateFormatter
+- (id)initWithNaturalLanguage: (BOOL)flag
+{
+ NSString *format;
+
+ format = [[NSUserDefaults standardUserDefaults] objectForKey: NSShortDateFormatString];
+
+ self = [super initWithDateFormat: format allowNaturalLanguage: flag];
+ return self;
+}
+
+- (NSString *)stringForObjectValue: (id)anObject
+{
+ NSString *stringValue;
+
+ if ([anObject isKindOfClass: [NSDate class]]) {
+ NSCalendarDate *testDate;
+ int todayNum, myNum;
+
+ testDate = [NSCalendarDate dateWithTimeIntervalSinceReferenceDate:
+ [(NSDate *)anObject timeIntervalSinceReferenceDate]];
+ myNum = [[NSCalendarDate calendarDate] dayOfCommonEra];
+ todayNum = [testDate dayOfCommonEra];
+ if (myNum == todayNum)
+ stringValue = myLocalizedString(@"Today");
+ else if (todayNum == (myNum - 1))
+ stringValue = myLocalizedString(@"Yesterday");
+ else if (todayNum == (myNum + 1))
+ stringValue = myLocalizedString(@"Tomorrow");
+ else {
+ stringValue = [testDate descriptionWithCalendarFormat:
+ [self dateFormat]];
+ }
+ } else
+ stringValue = [super stringForObjectValue: anObject];
+
+ return stringValue;
+}
+@end
diff --git a/Plugins/BuiltInFunctions/chef.lproj/BuiltInFunctions.strings b/Plugins/BuiltInFunctions/chef.lproj/BuiltInFunctions.strings
new file mode 100644
index 0000000..4881c4c
--- /dev/null
+++ b/Plugins/BuiltInFunctions/chef.lproj/BuiltInFunctions.strings
@@ -0,0 +1,26 @@
+/* Headers for columns. */
+IconHeader = "Icun";
+FilenameHeader = "Feeleneme-a";
+TypeHeader = "Type-a";
+LastModifiedTimeHeader = "Lest Mudeeffied";
+CreatedTimeHeader = "Creeted";
+FileSizeHeader = "Seeze-a";
+
+/* Error messages. */
+UnableToResolveAlias = "uneble-a tu resulfe-a eleees";
+
+/* Default library name. */
+LiLibraryName = "My Leebrery";
+
+/* Names for filters. */
+LiFilenameAttribute = "feeleneme-a";
+LiTypeAttribute = "type-a";
+
+/* Names for operators. */
+LiEqualsOperator = "is";
+LiContainsOperator = "cunteeens";
+
+/* For the natural language formatter. */
+Today = "Tudey";
+Yesterday = "Yesterdey";
+Tomorrow = "Tumurroo"; \ No newline at end of file
diff --git a/Plugins/BuiltInFunctions/chef.lproj/ErrorMessages.strings b/Plugins/BuiltInFunctions/chef.lproj/ErrorMessages.strings
new file mode 100644
index 0000000..94dd413
--- /dev/null
+++ b/Plugins/BuiltInFunctions/chef.lproj/ErrorMessages.strings
@@ -0,0 +1,10 @@
+/* Errors for file rename operations. */
+LiGenericRenameErrorHeader = "Zee feele-a cuooldn't be-a renemed.";
+LiGenericRenameErrorContents = "Try shekeeng a deed cheeckee (oor cheeckee soobsteetoote-a) et zee screee.";
+
+LiBadFilenameErrorHeader = "Zee feele-a cuooldn't be-a renemed becoose-a it cunteeened un illegel cherecter.";
+LiBadFilenameErrorContents = "Yuoo cun try tu reneme-a zee feele-a veethuoot zee slesh \"/\" oor culun \":\" cherecters.";
+LiReadOnlyFileSytemErrorHeader = "Zee feele-a cuooldn't be-a mudeeffied becoose-a zee feelesystem is reed-oonly.";
+LiReadOnlyFileSytemErrorContents = "Yuoo need tu telk tu yuoor system edmeenistretur tu feex thees.";
+LiPermissionDeniedErrorHeader = "Zee feele-a cuooldn't be-a mudeeffied becoose-a yuoo leck permeessiun tu chunge-a zee feele-a.";
+LiPermissionDeniedErrorContents = "Yuoo cun mudeeffy yuoor fulder permeessiuns in zee Feender.";
diff --git a/Plugins/BuiltInFunctions/chef.lproj/InfoPlist.strings b/Plugins/BuiltInFunctions/chef.lproj/InfoPlist.strings
new file mode 100644
index 0000000..9ac3304
--- /dev/null
+++ b/Plugins/BuiltInFunctions/chef.lproj/InfoPlist.strings
Binary files differ
diff --git a/Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/classes.nib b/Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/classes.nib
new file mode 100644
index 0000000..5cbffd3
--- /dev/null
+++ b/Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/classes.nib
@@ -0,0 +1,38 @@
+{
+ IBClasses = (
+ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
+ {CLASS = HFSCodeFormatter; LANGUAGE = ObjC; SUPERCLASS = NSFormatter; },
+ {
+ ACTIONS = {
+ setApplication = id;
+ setFilename = id;
+ setHFSCreatorField = id;
+ setHFSTypeField = id;
+ setIcon = id;
+ setType = id;
+ };
+ CLASS = InspectorViewController;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ hfsCreatorField = NSTextField;
+ hfsTypeField = NSTextField;
+ iconView = NSImageView;
+ pathField = NSTextField;
+ theApplicationButton = NSPopUpButton;
+ theFileTabView = NSView;
+ theFilenameField = NSTextField;
+ theHFSTabView = NSView;
+ theTypeField = NSTextField;
+ };
+ SUPERCLASS = NSObject;
+ },
+ {
+ CLASS = LiBuiltInFunctions;
+ LANGUAGE = ObjC;
+ OUTLETS = {theController = InspectorViewController; };
+ SUPERCLASS = NSObject;
+ },
+ {CLASS = LiImageView; LANGUAGE = ObjC; SUPERCLASS = NSImageView; }
+ );
+ IBVersion = 1;
+} \ No newline at end of file
diff --git a/Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/info.nib b/Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/info.nib
new file mode 100644
index 0000000..d875328
--- /dev/null
+++ b/Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/info.nib
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>37 90 356 240 0 0 1024 746 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>48</key>
+ <string>394 455 235 123 0 0 1024 746 </string>
+ <key>5</key>
+ <string>345 428 334 178 0 0 1024 746 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>291.0</string>
+ <key>IBGroupedObjects</key>
+ <dict>
+ <key>0</key>
+ <array>
+ <string>27</string>
+ <string>28</string>
+ <string>30</string>
+ <string>31</string>
+ <string>33</string>
+ </array>
+ </dict>
+ <key>IBLastGroupID</key>
+ <string>1</string>
+ <key>IBSystem Version</key>
+ <string>6L60</string>
+</dict>
+</plist>
diff --git a/Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/objects.nib b/Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/objects.nib
new file mode 100644
index 0000000..688b472
--- /dev/null
+++ b/Plugins/BuiltInFunctions/chef.lproj/InspectorViews.nib/objects.nib
Binary files differ