Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

LinkBack 1.0.3 from <http://linkbackproject.org/files/LinkBack-103.zip>

  • Loading branch information...
commit 30285de44a0eebe15a9303111a744ad340db6869 1 parent fcc2958
@tjw tjw authored
View
BIN  Documentation/LinkBack Developer's Guide.pdf
Binary file not shown
View
1,017 Documentation/LinkBack Developer's Guide.rtf
1,017 additions, 0 deletions not shown
View
33 LinkBack Release Notes.rtf
@@ -7,16 +7,39 @@
;}
}
{\colortbl ;\red0 \green0 \blue0 ;}
-{\stylesheet {\s3 \nisusnoteplacement0 \nisusreferencestyle7 {\*\nsmpltxt Some text goes here so you can see what your style will look like.}
+{\stylesheet {\*\cs335 {\*\nsmpltxt The quick brown fox jumped over the lazy dogs.}
+\super footnote reference;}
+{\*\cs336 {\*\nsmpltxt The quick brown fox jumped over the lazy dogs.}
+\super endnote reference;}
+{\s337 \nisusnoteplacement0 \nisusreferencestyle335 {\*\nsmpltxt Some text goes here so you can see what your style will look like.}
\f3 footnote text;}
-{\s4 \nisusnoteplacement1 \nisusreferencestyle9 {\*\nsmpltxt Sample text for Foot/End Notes Style}
+{\s338 \nisusnoteplacement1 \nisusreferencestyle336 {\*\nsmpltxt Sample text for Foot/End Notes Style}
\f3 endnote text;}
}
-\deftab720 \defformat \viewkind1 \viewzk1 {\*\nisuswindow \x70 \y232 \w741 \h638 }
-\nshwinv0 \nshwpg1 \hyphauto0 \ftnnar \endnotes \aendnotes \aftnnar \fet2 \ftnbj \paperw12240 \paperh15840 \margl1440 \margr1440 \margt1440 \margb1440 \gutter0 \pgnstart1 \nocolbal \sectd \sbknone \cols1 \ltrsect \colbalsxn0 \marglsxn1440 \margrsxn1440 \margtsxn1440 \margbsxn1440 \guttersxn0 \headery720 \footery720 \pgnstarts1 \pgnrestart \pgndec \sxnstarts1 \sxnrestart \sxndec {\header \par }
-{\footer \par }
+\deftab720 \defformat \viewkind1 \viewzk1 {\*\nisuswindow \x70 \y194 \w741 \h638 }
+\nshwinv0 \nshwpg1 \hyphauto0 \ftnnar \endnotes \aendnotes \aftnnar \fet2 \ftnbj \paperw12240 \paperh15840 \margl1440 \margr1440 \margt1440 \margb1440 \gutter0 \pgnstart1 \nocolbal \sectd \sbknone \cols1 \ltrsect \colbalsxn0 \marglsxn1440 \margrsxn1440 \margtsxn1440 \margbsxn1440 \guttersxn0 \headery720 \footery720 \pgnstarts1 \pgnrestart \pgndec \sxnstarts1 \sxnrestart \sxndec {\header \pard \ql \sb0 \sa0 \sl240 \slmult1 \ilvl0 \li0 \lin0 \fi0 \ri0 \rin0 \par }
+{\footer \pard \ql \sb0 \sa0 \sl240 \slmult1 \ilvl0 \li0 \lin0 \fi0 \ri0 \rin0 \par }
{\pard \ql \sb0 \sa0 \sl240 \slmult1 \ilvl0 \li0 \lin0 \fi0 \ri0 \rin0 {\f1 \fs24 \b \cf1 LinkBack Release Notes\par
\f2 \b0 \par
+\b LINKBACK 103: \tab (March 29, 2005)\par
+\b0 \par
+\b Missing Items:\b0 \par
+The LinkBack badge mentioned in the documentation is not in the distribution yet. Sorry. This will be forthcoming. \par
+\par
+\b Documentation:\b0 First draft of the LinkBack Developer\rquote s Guide. Hey, its better than nothing. \u9786 ? Seriously though, I have not written many API docs. Any feedback or suggested edits are greatly welcomed!\par
+\par
+\b TextEdit+LinkBack:\b0 Incorporates new framework API. Pretty much this works as before though. Notice the new edit menu item introduces in 102.\par
+\b \par
+LiveSketch:\b0 Incorporates new framework API. Modified to use some new API so that it provides all the information needed to relaunch LiveSketch. Also uses matches the new developer\rquote s guide for the window title. \par
+\par
+\b Cool trick:\b0 Paste a LiveSketch graphic into the new version of TextEdit+LinkBack. Then quit LiveSketch and move the app to the trash. Now double-click the graphic in TextEdit+LinkBack. After a few seconds, a dialog will show telling you that the LiveSketch application should not be found and offering to take you to a web-site to get the application. This is great advertising for you!\par
+\par
+\b LinkBack:\b0 Now server applications can include a suggested refresh rate with their data. Client applications can use this to implement automatic updating. Currently there is no special API support for automatic updating, but this should not be hard for a client to implement.\par
+ \par
+\b LinkBack:\b0 Included change sent by Andrew Stone to fix the source application name included in LinkBack data.\par
+\par
+\b LinkBack: \b0 Added improved support for finding server applications if they are not running or if the wrong version is returned by NSWorkspace. This code uses new keys you can add to your application\rquote s Info.plist to determine which version to launch. It will search the standard directories.\par
+\par
\b LINKBACK 102:\par
\b0 \par
\b LinkBack:\b0 LinkBack has several helper methods to make it easier for you to add a menu item in clients to edit LinkBack content. Two functions and one method provide the localized string for the menu name. You should place the menu at the bottom of your edit menu with a separator before it. Make your validateMenuItem: set the menu title based on the current selection. You should set your title based on the number of LinkBack items selected:\par
View
3  LiveSketch/DocumentModel.subproj/SKTDrawDocument.m
@@ -55,7 +55,8 @@ - (NSString*)displayName
{
if (link) {
NSString* sourceName = [link sourceName] ;
- NSString* ret = [NSString stringWithFormat: @"Graphics from %@", sourceName] ;
+ NSString* sourceAppName = [link sourceApplicationName] ;
+ NSString* ret = [NSString stringWithFormat: @"Graphics from %@ (%@)", sourceName, sourceAppName] ;
return ret ;
} else return [super displayName] ;
}
View
4 LiveSketch/Sketch.pbxproj/project.pbxproj
@@ -855,8 +855,8 @@
<string>alpha.01</string>
<key>LinkBackApplicationURL</key>
<string>http://www.linkbackproject.org</string>
- <key>LinkBackVersion</key>
- <string>A</string>
+ <key>LinkBackServer</key>
+ <string>sketch</string>
<key>NSAppleScriptEnabled</key>
<string>YES</string>
<key>NSMainNibFile</key>
View
13 Source/English.lproj/Localized.strings
@@ -2,4 +2,15 @@
"_EditMultiple" = "Edit LinkBack Items" ;
"_EditNone" = "Edit LinkBack Item" ;
"_Edit" = "Edit" ;
-"_Refresh" = "Refresh" ;
+"_Refresh" = "Refresh" ;
+
+/* Strings used for the LinkBack App Not Found panel */
+"_AppNotFoundTitle" = "The creator application \"%@\" could not be found." ;
+
+"_AppNotFoundMessageWithURL" = "Make sure this application is installed in your Applications folder to use it. If you do not have this software, you can choose \"Get Application\" to download it." ;
+
+"_AppNotFoundMessageNoURL" = "Make sure this application is installed in your Applications folder to use it." ;
+
+"_OK" = "OK" ;
+
+"_GetApplication" = "Get Application" ;
View
5 Source/LinkBack.h
@@ -115,6 +115,7 @@ BOOL LinkBackDataBelongsToActiveApplication(id data) ;
NSPasteboard* pboard ;
id repobj ;
NSString* sourceName ;
+ NSString* sourceApplicationName ;
NSString* key ;
}
@@ -132,6 +133,7 @@ BOOL LinkBackDataBelongsToActiveApplication(id data) ;
// Applications can use this represented object to attach some meaning to the live link. For example, a client application may set this to the object to be modified when the edit is refreshed. This retains its value.
- (NSString*)sourceName ;
+- (NSString*)sourceApplicationName ;
- (NSString*)itemKey ; // maybe this matters only on the client side.
// ...........................................................................
@@ -156,7 +158,8 @@ BOOL LinkBackDataBelongsToActiveApplication(id data) ;
- (id)initClientWithSourceName:(NSString*)aName delegate:(id<LinkBackClientDelegate>)aDel itemKey:(NSString*)aKey ;
-- (BOOL)connectToServerWithName:(NSString*)aName inApplication:(NSString*)bundleIdentifier ;
+- (BOOL)connectToServerWithName:(NSString*)aName inApplication:(NSString*)bundleIdentifier fallbackURL:(NSURL*)url appName:(NSString*)appName ;
+
- (void)requestEdit ;
@end
View
23 Source/LinkBack.m
@@ -118,8 +118,8 @@ + (NSDictionary*)linkBackDataWithServerName:(NSString*)serverName appData:(id)ap
NSMutableDictionary* ret = [[NSMutableDictionary alloc] init] ;
NSString* bundleId = [[NSBundle mainBundle] bundleIdentifier] ;
NSString* url = [appInfo objectForKey: @"LinkBackApplicationURL"] ;
- NSString* appName = [[[NSWorkspace sharedWorkspace] activeApplication] objectForKey: @"NSApplicationName"] ;
- id version = @"A" ;
+ NSString* appName = [[NSProcessInfo processInfo] processName] ;
+ id version = @"A" ;
if (nil==serverName) [NSException raise: NSInvalidArgumentException format: @"LinkBack Data cannot be created without a server name."] ;
@@ -226,6 +226,7 @@ - (id)initServerWithClient: (LinkBack*)aLinkBack delegate: (id<LinkBackServerDel
if (self = [super init]) {
peer = [aLinkBack retain] ;
sourceName = [[peer sourceName] copy] ;
+ sourceApplicationName = [[peer sourceApplicationName] copy] ;
key = [[peer itemKey] copy] ;
isServer = YES ;
delegate = aDel ;
@@ -241,6 +242,7 @@ - (id)initClientWithSourceName:(NSString*)aName delegate:(id<LinkBackClientDeleg
isServer = NO ;
delegate = aDel ;
sourceName = [aName copy] ;
+ sourceApplicationName = [[NSProcessInfo processInfo] processName] ;
pboard = [[NSPasteboard pasteboardWithUniqueName] retain] ;
key = [aKey copy] ;
}
@@ -287,6 +289,11 @@ - (NSString*)sourceName
return sourceName ;
}
+- (NSString*)sourceApplicationName
+{
+ return sourceApplicationName ;
+}
+
- (NSString*)itemKey
{
return key ;
@@ -360,12 +367,16 @@ + (LinkBack*)editLinkBackData:(id)data sourceName:(NSString*)aName delegate:(id<
BOOL ok ;
NSString* serverName ;
NSString* serverId ;
-
+ NSString* appName ;
+ NSURL* url ;
+
// collect server contact information from data.
ok = [data isKindOfClass: [NSDictionary class]] ;
if (ok) {
serverName = [data objectForKey: LinkBackServerNameKey] ;
serverId = [data objectForKey: LinkBackServerBundleIdentifierKey];
+ appName = [data linkBackSourceApplicationName] ;
+ url = [data linkBackApplicationURL] ;
}
if (!ok || !serverName || !serverId) [NSException raise: NSInvalidArgumentException format: @"LinkBackData is not of the correct format: %@", data] ;
@@ -373,7 +384,7 @@ + (LinkBack*)editLinkBackData:(id)data sourceName:(NSString*)aName delegate:(id<
// create the live link object and try to connect to the server.
ret = [[LinkBack alloc] initClientWithSourceName: aName delegate: del itemKey: aKey] ;
- if (![ret connectToServerWithName: serverName inApplication: serverId]) {
+ if (![ret connectToServerWithName: serverName inApplication: serverId fallbackURL: url appName: appName]) {
[ret release] ;
ret = nil ;
}
@@ -397,10 +408,10 @@ + (LinkBack*)editLinkBackData:(id)data sourceName:(NSString*)aName delegate:(id<
return ret ;
}
-- (BOOL)connectToServerWithName:(NSString*)aName inApplication:(NSString*)bundleIdentifier
+- (BOOL)connectToServerWithName:(NSString*)aName inApplication:(NSString*)bundleIdentifier fallbackURL:(NSURL*)url appName:(NSString*)appName
{
// get the LinkBackServer.
- LinkBackServer* server = [LinkBackServer LinkBackServerWithName: aName inApplication: bundleIdentifier launchIfNeeded: YES] ;
+ LinkBackServer* server = [LinkBackServer LinkBackServerWithName: aName inApplication: bundleIdentifier launchIfNeeded: YES fallbackURL: url appName: appName] ;
if (!server) return NO ; // failed to get server
peer = [[server initiateLinkBackFromClient: self] retain] ;
View
3  Source/LinkBackServer.h
@@ -55,7 +55,8 @@ NSString* MakeLinkBackServerName(NSString* bundleIdentifier, NSString* name) ;
+ (LinkBackServer*)LinkBackServerWithName:(NSString*)name ;
+ (BOOL)publishServerWithName:(NSString*)name delegate:(id<LinkBackServerDelegate>)del ;
-+ (LinkBackServer*)LinkBackServerWithName:(NSString*)name inApplication:(NSString*)bundleIdentifier launchIfNeeded:(BOOL)flag ;
++ (LinkBackServer*)LinkBackServerWithName:(NSString*)name inApplication:(NSString*)bundleIdentifier launchIfNeeded:(BOOL)flag fallbackURL:(NSURL*)url appName:(NSString*)appName ;
+
// This method is used by clients to connect
- (id)initWithName:(NSString*)name delegate:(id<LinkBackServerDelegate>)aDel;
View
163 Source/LinkBackServer.m
@@ -69,37 +69,154 @@ + (BOOL)publishServerWithName:(NSString*)aName delegate:(id<LinkBackServerDelega
return ret ;
}
-+ (LinkBackServer*)LinkBackServerWithName:(NSString*)aName inApplication:(NSString*)bundleIdentifier launchIfNeeded:(BOOL)flag
+BOOL LinkBackServerIsSupported(NSString* name, id supportedServers)
{
+ BOOL ret = NO ;
+ int idx ;
+ NSString* curServer = supportedServers ;
+
+ // NOTE: supportedServers may be nil, an NSArray, or NSString.
+ if (supportedServers) {
+ if ([supportedServers isKindOfClass: [NSArray class]]) {
+ idx = [supportedServers count] ;
+ while((NO==ret) && (--idx >= 0)) {
+ curServer = [supportedServers objectAtIndex: idx] ;
+ ret = [curServer isEqualToString: name] ;
+ }
+ } else ret = [curServer isEqualToString: name] ;
+ }
+
+ return ret ;
+}
+
+NSString* FindLinkBackServer(NSString* bundleIdentifier, NSString* serverName, NSString* dir, int level)
+{
+ NSString* ret = nil ;
+
+ NSFileManager* fm = [NSFileManager defaultManager] ;
+ NSArray* contents = [fm directoryContentsAtPath: dir] ;
+ int idx ;
+
+ NSLog(@"searching for %@ in folder: %@", serverName, dir) ;
+
+ // working info
+ NSString* cpath ;
+ NSBundle* cbundle ;
+ NSString* cbundleIdentifier ;
+ id supportedServers ;
+
+ // resolve any symlinks, expand tildes.
+ dir = [dir stringByStandardizingPath] ;
+
+ // find all .app bundles in the directory and test them.
+ idx = (contents) ? [contents count] : 0 ;
+ while((nil==ret) && (--idx >= 0)) {
+ cpath = [contents objectAtIndex: idx] ;
+
+ if ([[cpath pathExtension] isEqualToString: @"app"]) {
+ cpath = [dir stringByAppendingPathComponent: cpath] ;
+ cbundle = [NSBundle bundleWithPath: cpath] ;
+ cbundleIdentifier = [cbundle bundleIdentifier] ;
+
+ if ([cbundleIdentifier isEqualToString: bundleIdentifier]) {
+ supportedServers = [[cbundle infoDictionary] objectForKey: @"LinkBackServer"] ;
+ ret= (LinkBackServerIsSupported(serverName, supportedServers)) ? cpath : nil ;
+ }
+ }
+ }
+
+ // if the app was not found, descend into non-app dirs. only descend 4 levels to avoid taking forever.
+ if ((nil==ret) && (level<4)) {
+ idx = (contents) ? [contents count] : 0 ;
+ while((nil==ret) && (--idx >= 0)) {
+ BOOL isdir ;
+
+ cpath = [contents objectAtIndex: idx] ;
+ [fm fileExistsAtPath: cpath isDirectory: &isdir] ;
+ if (isdir && (![[cpath pathExtension] isEqualToString: @"app"])) {
+ cpath = [dir stringByAppendingPathComponent: cpath] ;
+ ret = FindLinkBackServer(bundleIdentifier, serverName, cpath, level+1) ;
+ }
+ }
+ }
+
+ return ret ;
+}
+
+void LinkBackRunAppNotFoundPanel(NSString* appName, NSURL* url)
+{
+ int result ;
+
+ // strings for panel
+ NSBundle* b = [NSBundle bundleForClass: [LinkBack class]] ;
+ NSString* title ;
+ NSString* msg ;
+ NSString* ok ;
+ NSString* urlstr ;
+
+ title = NSLocalizedStringFromTableInBundle(@"_AppNotFoundTitle", @"Localized", b, @"app not found title") ;
+ ok = NSLocalizedStringFromTableInBundle(@"_OK", @"Localized", b, @"ok") ;
+
+ msg = (url) ? NSLocalizedStringFromTableInBundle(@"_AppNotFoundMessageWithURL", @"Localized", b, @"app not found msg") : NSLocalizedStringFromTableInBundle(@"_AppNotFoundMessageNoURL", @"Localized", b, @"app not found msg") ;
+
+ urlstr = (url) ? NSLocalizedStringFromTableInBundle(@"_GetApplication", @"Localized", b, @"Get application") : nil ;
+
+ title = [NSString stringWithFormat: title, appName] ;
+
+ result = NSRunCriticalAlertPanel(title, msg, ok, urlstr, nil) ;
+ if (NSAlertAlternateReturn == result) {
+ [[NSWorkspace sharedWorkspace] openURL: url] ;
+ }
+}
+
++ (LinkBackServer*)LinkBackServerWithName:(NSString*)aName inApplication:(NSString*)bundleIdentifier launchIfNeeded:(BOOL)flag fallbackURL:(NSURL*)url appName:(NSString*)appName ;
+{
+ BOOL connect = YES ;
NSString* serverName = MakeLinkBackServerName(bundleIdentifier, aName) ;
id ret = nil ;
NSTimeInterval tryMark ;
- // Let see if its already running
- BOOL appLaunched = FALSE;
- NSArray *appsArray = [[NSWorkspace sharedWorkspace] launchedApplications];
- NSEnumerator *appsArrayEnumerator = [appsArray objectEnumerator];
- NSDictionary *appDict;
- NSString *appBundleIdentifier;
- while (appDict = [appsArrayEnumerator nextObject])
- {
- appBundleIdentifier = [appDict objectForKey:@"NSApplicationBundleIdentifier"];
- if((appBundleIdentifier) && ([appBundleIdentifier isEqualToString:bundleIdentifier]))
- appLaunched = TRUE;
- }
+ // Try to connect
+ ret = [NSConnection rootProxyForConnectionWithRegisteredName: serverName host: nil] ;
- // if flag, and not launched try to launch.
- if((!appLaunched) && (flag))
- [[NSWorkspace sharedWorkspace] launchAppWithBundleIdentifier: bundleIdentifier options: (NSWorkspaceLaunchWithoutAddingToRecents | NSWorkspaceLaunchWithoutActivation) additionalEventParamDescriptor: nil launchIdentifier: nil] ;
+ // if launchIfNeeded, and the connection was not available, try to launch.
+ if((!ret) && (flag)) {
+ NSString* appPath ;
+ id linkBackServers ;
+
+ // first, try to find the app with the bundle identifier
+ appPath = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier: bundleIdentifier] ;
+ linkBackServers = [[[NSBundle bundleWithPath: appPath] infoDictionary] objectForKey: @"LinkBackServer"] ;
+ appPath = (LinkBackServerIsSupported(aName, linkBackServers)) ? appPath : nil ;
+
+ // if the found app is not supported, we will need to search for the app ourselves.
+ if (nil==appPath) appPath = FindLinkBackServer(bundleIdentifier, aName, @"/Applications",0);
+
+ if (nil==appPath) appPath = FindLinkBackServer(bundleIdentifier, aName, @"~/Applications",0);
+
+ if (nil==appPath) appPath = FindLinkBackServer(bundleIdentifier, aName, @"/Network/Applications",0);
+
+ // if app path has been found, launch the app.
+ if (appPath) {
+ [[NSWorkspace sharedWorkspace] launchApplication: appName] ;
+ } else {
+ LinkBackRunAppNotFoundPanel(appName, url) ;
+ connect = NO ;
+ }
+ }
- // now, try to connect. retry connection for a while if we did not succeed at first. This gives the app time to launch.
- tryMark = [NSDate timeIntervalSinceReferenceDate] ;
- do {
- ret = [NSConnection rootProxyForConnectionWithRegisteredName: serverName host: nil] ;
- } while ((!ret) && (([NSDate timeIntervalSinceReferenceDate]-tryMark)<10)) ;
+ // if needed, try to connect.
+ // retry connection for a while if we did not succeed at first. This gives the app time to launch.
+ if (connect && (nil==ret)) {
+ tryMark = [NSDate timeIntervalSinceReferenceDate] ;
+ do {
+ ret = [NSConnection rootProxyForConnectionWithRegisteredName: serverName host: nil] ;
+ } while ((!ret) && (([NSDate timeIntervalSinceReferenceDate]-tryMark)<10)) ;
+
+ }
- [ret setProtocolForProxy: @protocol(LinkBackServer)] ;
-
+ // setup protocol and return
+ if (ret) [ret setProtocolForProxy: @protocol(LinkBackServer)] ;
return ret ;
}
View
3  TextEdit+LinkBack/LinkBackTextView.m
@@ -23,8 +23,7 @@ - (BOOL)readSelectionFromPasteboard:(NSPasteboard*)pboard
while(type = [e nextObject]) {
if ([type isEqual: NSTIFFPboardType]) hasTIFF = YES ;
if ([type isEqual: NSPDFPboardType]) hasPDF = YES ;
-// if ([type isEqual: LinkBackPboardType]) hasLinkBack = YES ;
- hasLinkBack = YES ;
+ if ([type isEqual: LinkBackPboardType]) hasLinkBack = YES ;
}
if (hasLinkBack && (hasPDF || hasTIFF)) {
Please sign in to comment.
Something went wrong with that request. Please try again.