aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPActivityTextFieldCell.h49
-rw-r--r--Source/SPActivityTextFieldCell.m357
-rw-r--r--Source/SPAppController.h8
-rw-r--r--Source/SPAppController.m31
-rw-r--r--Source/SPConstants.h1
-rw-r--r--Source/SPConstants.m1
-rw-r--r--Source/SPCopyTable.m9
-rw-r--r--Source/SPDatabaseDocument.h8
-rw-r--r--Source/SPDatabaseDocument.m20
-rw-r--r--Source/SPStringAdditions.h2
-rw-r--r--Source/SPStringAdditions.m21
-rw-r--r--Source/SPTableInfo.h1
-rw-r--r--Source/SPTableInfo.m89
-rw-r--r--Source/SPTableTextFieldCell.m5
-rw-r--r--Source/SPTextViewAdditions.m9
15 files changed, 552 insertions, 59 deletions
diff --git a/Source/SPActivityTextFieldCell.h b/Source/SPActivityTextFieldCell.h
new file mode 100644
index 00000000..4f027710
--- /dev/null
+++ b/Source/SPActivityTextFieldCell.h
@@ -0,0 +1,49 @@
+//
+// $Id: SPActivityTextFieldCell.h 2781 2010-10-19 23:37:15Z stuart02 $
+//
+// SPActivityTextFieldCell.h
+// sequel-pro
+//
+// Created by Hans-Jörg Bibiko on Dec 01, 2010
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "ImageAndTextCell.h"
+
+@interface SPActivityTextFieldCell : ImageAndTextCell
+
+{
+ NSString *activityName;
+ NSString *activityInfo;
+ NSDictionary *contextInfo;
+
+ NSButtonCell *cancelButton;
+
+ NSInteger drawState;
+
+ NSColor *mainStringColor;
+ NSColor *subStringColor;
+}
+
+@property(readwrite,retain) NSString *activityName;
+@property(readwrite,retain) NSString *activityInfo;
+@property(readwrite,retain) NSDictionary *contextInfo;
+
+- (void)invertFontColors;
+- (void)restoreFontColors;
+
+@end
diff --git a/Source/SPActivityTextFieldCell.m b/Source/SPActivityTextFieldCell.m
new file mode 100644
index 00000000..856fde52
--- /dev/null
+++ b/Source/SPActivityTextFieldCell.m
@@ -0,0 +1,357 @@
+//
+// $Id: SPActivityTextFieldCell.m 2691 2010-09-25 12:21:03Z stuart02 $
+//
+// SPActivityTextFieldCell.m
+// sequel-pro
+//
+// Created by Hans-Jörg Bibiko on Dec 01, 2010
+// Copyright (c) 2008 Stuart Connolly. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPActivityTextFieldCell.h"
+
+#define FAVORITE_NAME_FONT_SIZE 12.0
+
+@interface SPActivityTextFieldCell (PrivateAPI)
+
+- (NSAttributedString *)constructSubStringAttributedString;
+- (NSAttributedString *)attributedStringForFavoriteName;
+- (NSDictionary *)mainStringAttributedStringAttributes;
+- (NSDictionary *)subStringAttributedStringAttributes;
+
+@end
+
+@implementation SPActivityTextFieldCell
+
+/**
+ * Provide a method to derive the link rect from a cell rect.
+ */
+static inline NSRect SPTextLinkRectFromCellRect(NSRect inRect)
+{
+ return NSMakeRect(inRect.origin.x + inRect.size.width - 30, inRect.origin.y - 1, 15, inRect.size.height);
+}
+
+
+@synthesize activityName;
+@synthesize activityInfo;
+@synthesize contextInfo;
+
+/**
+ * Init.
+ */
+- (id)init
+{
+ if ((self = [super init])) {
+ mainStringColor = [NSColor blackColor];
+ subStringColor = [NSColor grayColor];
+ activityName = nil;
+ activityInfo = nil;
+ cancelButton = nil;
+ contextInfo = nil;
+ drawState = SPLinkDrawStateNormal;
+
+ cancelButton = [[NSButtonCell alloc] init];
+ [cancelButton setButtonType:NSMomentaryChangeButton];
+ [cancelButton setImagePosition:NSImageRight];
+ [cancelButton setTitle:@""];
+ [cancelButton setBordered:NO];
+ [cancelButton setShowsBorderOnlyWhileMouseInside:YES];
+ [cancelButton setImage:[NSImage imageNamed:@"link-arrow"]];
+ [cancelButton setAlternateImage:[NSImage imageNamed:@"link-arrow-clicked"]];
+ }
+
+ return self;
+}
+
+/**
+ * Encodes using a given receiver.
+ */
+- (void) encodeWithCoder:(NSCoder *)coder
+{
+ [super encodeWithCoder:coder];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+ SPActivityTextFieldCell *cell = (SPActivityTextFieldCell *)[super copyWithZone:zone];
+
+ cell->activityName = nil;
+ if (activityName) cell->activityName = [activityName copyWithZone:zone];
+
+ cell->activityInfo = nil;
+ if (activityInfo) cell->activityInfo = [activityInfo copyWithZone:zone];
+
+ cell->contextInfo = nil;
+ if (contextInfo) cell->contextInfo = [contextInfo copyWithZone:zone];
+
+ cell->cancelButton = nil;
+ if (cancelButton) cell->cancelButton = [cancelButton copyWithZone:zone];
+
+ return cell;
+}
+
+
+/**
+ * Draws the actual cell.
+ */
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
+{
+
+ [cancelButton setEnabled:(contextInfo != nil)];
+
+ (([self isHighlighted]) && (![[self highlightColorWithFrame:cellFrame inView:controlView] isEqualTo:[NSColor secondarySelectedControlColor]])) ? [self invertFontColors] : [self restoreFontColors];
+
+ // Construct and get the sub text attributed string
+ NSAttributedString *mainString = [self attributedStringForFavoriteName];
+ NSAttributedString *subString = [self constructSubStringAttributedString];
+
+ NSRect subFrame = NSMakeRect(0.0, 0.0, [subString size].width, [subString size].height);
+
+ // Total height of both strings with a 2 pixel separation space
+ CGFloat totalHeight = [mainString size].height + [subString size].height + 1.0;
+
+ cellFrame.origin.y += (cellFrame.size.height - totalHeight) / 2.0;
+ cellFrame.origin.x += 10.0; // Indent main string from image
+
+ // Position the sub text's frame rect
+ subFrame.origin.y = [mainString size].height + cellFrame.origin.y + 1.0;
+ subFrame.origin.x = cellFrame.origin.x;
+
+ cellFrame.size.height = totalHeight;
+
+ NSInteger i;
+ CGFloat maxWidth = cellFrame.size.width - 30;
+ CGFloat mainStringWidth = [mainString size].width;
+ CGFloat subStringWidth = [subString size].width;
+
+ // Set a right-padding
+ maxWidth -= 10;
+
+ if (maxWidth < mainStringWidth) {
+ for (i = 0; i <= [mainString length]; i++) {
+ if ([[mainString attributedSubstringFromRange:NSMakeRange(0, i)] size].width >= maxWidth && i >= 3) {
+ mainString = [[[NSMutableAttributedString alloc] initWithString:[[[mainString attributedSubstringFromRange:NSMakeRange(0, i - 3)] string] stringByAppendingString:@"..."] attributes:[self mainStringAttributedStringAttributes]] autorelease];
+ }
+ }
+ }
+
+ if (maxWidth < subStringWidth) {
+ for (i = 0; i <= [subString length]; i++) {
+ if ([[subString attributedSubstringFromRange:NSMakeRange(0, i)] size].width >= maxWidth && i >= 3) {
+ subString = [[[NSMutableAttributedString alloc] initWithString:[[[subString attributedSubstringFromRange:NSMakeRange(0, i - 3)] string] stringByAppendingString:@"..."] attributes:[self subStringAttributedStringAttributes]] autorelease];
+ }
+ }
+ }
+
+ [mainString drawInRect:NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width-30, cellFrame.size.height)];
+ [subString drawInRect:subFrame];
+
+ NSRect linkRect = SPTextLinkRectFromCellRect(cellFrame);
+
+ // Get the new link state
+ NSInteger newDrawState = ([self isHighlighted])?
+ ((([(NSTableView *)[self controlView] editedColumn] != -1
+ || [[[self controlView] window] firstResponder] == [self controlView])
+ && [[[self controlView] window] isKeyWindow])?SPLinkDrawStateHighlight:SPLinkDrawStateBackgroundHighlight):
+ SPLinkDrawStateNormal;
+
+ // Update the link arrow style if the state has changed
+ if (drawState != newDrawState) {
+ drawState = newDrawState;
+ switch (drawState) {
+ case SPLinkDrawStateNormal:
+ [cancelButton setImage:[NSImage imageNamed:@"link-arrow"]];
+ [cancelButton setAlternateImage:[NSImage imageNamed:@"link-arrow-clicked"]];
+ break;
+ case SPLinkDrawStateHighlight:
+ [cancelButton setImage:[NSImage imageNamed:@"link-arrow-highlighted"]];
+ [cancelButton setAlternateImage:[NSImage imageNamed:@"link-arrow-highlighted-clicked"]];
+ break;
+ case SPLinkDrawStateBackgroundHighlight:
+ [cancelButton setImage:[NSImage imageNamed:@"link-arrow-clicked"]];
+ [cancelButton setAlternateImage:[NSImage imageNamed:@"link-arrow"]];
+ break;
+ }
+ }
+
+ [cancelButton drawWithFrame:linkRect inView:controlView];
+}
+
+- (NSRect)expansionFrameWithFrame:(NSRect)cellFrame inView:(NSView *)view
+{
+ return NSZeroRect;
+}
+
+/**
+ * Allow hit tracking for cancel functionality
+ */
+- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView
+{
+ return NSCellHitContentArea | NSCellHitTrackableArea;
+}
+
+/**
+ * Allow mouse tracking within the button cell, to support expected click
+ * behaviour in the button cell.
+ */
+- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp
+{
+
+ NSPoint p = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
+ NSRect linkRect = SPTextLinkRectFromCellRect(cellFrame);
+ linkRect.origin.x += 15;
+
+ // Fast path for if not in button rect - just pass to super
+ if (!NSMouseInRect(p, linkRect, [controlView isFlipped]))
+ return [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
+
+ // Ignore events other than mouse down.
+ if ([theEvent type] != NSLeftMouseDown) return YES;
+
+ // Continue tracking the mouse while it's down, updating the state as it enters and leaves the cell,
+ // until it is released; if still within the cell, follow the link.
+ BOOL mouseInButton = YES;
+ while (1) {
+ if (mouseInButton) {
+
+ // Highlight the button
+ [cancelButton highlight:YES withFrame:linkRect inView:controlView];
+
+ // Continue to track until mouse completes a click or exits the cell while still down
+ BOOL mouseClicked = [cancelButton trackMouse:theEvent inRect:linkRect ofView:controlView untilMouseUp:NO];
+ if (mouseClicked) {
+
+ // Remove highlight, and follow the link
+ [cancelButton highlight:NO withFrame:linkRect inView:controlView];
+
+ // Cancel activity
+ if([contextInfo objectForKey:@"type"] && [[contextInfo objectForKey:@"type"] isEqualToString:@"bashcommand"]) {
+ NSInteger pid = [[contextInfo objectForKey:@"pid"] intValue];
+ if(pid > 0) {
+ NSTask *killTask = [[NSTask alloc] init];
+ [killTask setLaunchPath:@"/bin/sh"];
+ [killTask setArguments:[NSArray arrayWithObjects:@"-c", [NSString stringWithFormat:@"kill -9 -%ld", pid], nil]];
+ [killTask launch];
+ [killTask waitUntilExit];
+ [killTask release];
+ }
+ }
+ return YES;
+ }
+
+ // Mouse has exited the cell. Remove highlight.
+ mouseInButton = NO;
+ [cancelButton highlight:NO withFrame:linkRect inView:controlView];
+ }
+
+ // Keep tracking the mouse outside the button, until the mouse button is released or it reenters the button
+ theEvent = [[controlView window] nextEventMatchingMask: NSLeftMouseUpMask | NSLeftMouseDraggedMask];
+ p = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
+ mouseInButton = NSMouseInRect(p, linkRect, [controlView isFlipped]);
+
+ // If the event is a mouse release, break the loop.
+ if ([theEvent type] == NSLeftMouseUp) break;
+ }
+
+ return YES;
+}
+
+- (NSSize)cellSize
+{
+ NSSize cellSize = [super cellSize];
+ NSAttributedString *mainString = [self attributedStringForFavoriteName];
+ NSAttributedString *subString = [self constructSubStringAttributedString];
+
+ // 15 := indention 10 from image to string plus 5 px padding
+ CGFloat theWidth = MAX([mainString size].width, [subString size].width) + (([self image] != nil) ? [[self image] size].width : 0) + 15;
+
+ CGFloat totalHeight = [mainString size].height + [subString size].height + 1.0;
+
+ cellSize.width = theWidth;
+ cellSize.height = totalHeight + 13.0;
+ return cellSize;
+}
+
+/**
+ * Inverts the displayed font colors when the cell is selected.
+ */
+- (void)invertFontColors
+{
+ mainStringColor = [NSColor whiteColor];
+ subStringColor = [NSColor whiteColor];
+}
+
+/**
+ * Restores the displayed font colors once the cell is no longer selected.
+ */
+- (void)restoreFontColors
+{
+ mainStringColor = [NSColor blackColor];
+ subStringColor = [NSColor grayColor];
+}
+
+/**
+ * Dealloc.
+ */
+- (void)dealloc
+{
+ if(activityName) [activityName release], activityName = nil;
+ if(activityInfo) [activityInfo release], activityInfo = nil;
+ if(contextInfo) [contextInfo release], contextInfo = nil;
+ if(cancelButton) [cancelButton release];
+
+ [super dealloc];
+}
+
+@end
+
+@implementation SPActivityTextFieldCell (PrivateAPI)
+
+/**
+ * Constructs the attributed string to be used as the cell's substring.
+ */
+- (NSAttributedString *)constructSubStringAttributedString
+{
+ return [[[NSAttributedString alloc] initWithString:activityInfo attributes:[self subStringAttributedStringAttributes]] autorelease];
+}
+
+/**
+ * Constructs the attributed string for the cell's favorite name.
+ */
+- (NSAttributedString *)attributedStringForFavoriteName
+{
+ return [[[NSAttributedString alloc] initWithString:activityName attributes:[self mainStringAttributedStringAttributes]] autorelease];
+}
+
+/**
+ * Returns the attributes of the cell's main string.
+ */
+- (NSDictionary *)mainStringAttributedStringAttributes
+{
+ return [NSDictionary dictionaryWithObjectsAndKeys:mainStringColor, NSForegroundColorAttributeName, [NSFont systemFontOfSize:FAVORITE_NAME_FONT_SIZE], NSFontAttributeName, nil];
+}
+
+/**
+ * Returns the attributes of the cell's sub string.
+ */
+- (NSDictionary *)subStringAttributedStringAttributes
+{
+ return [NSDictionary dictionaryWithObjectsAndKeys:subStringColor, NSForegroundColorAttributeName, [NSFont systemFontOfSize:[NSFont smallSystemFontSize]], NSFontAttributeName, nil];
+}
+
+@end
diff --git a/Source/SPAppController.h b/Source/SPAppController.h
index d96af12f..2fb4aef2 100644
--- a/Source/SPAppController.h
+++ b/Source/SPAppController.h
@@ -50,7 +50,7 @@
NSMutableDictionary *bundleKeyEquivalents;
NSMutableDictionary *installedBundleUUIDs;
- NSMutableArray *runningBASHprocesses;
+ NSMutableArray *runningActivitiesArray;
}
@@ -97,9 +97,9 @@
- (NSArray *)bundleCategoriesForScope:(NSString*)scope;
- (NSArray *)bundleItemsForScope:(NSString*)scope;
- (NSDictionary *)bundleKeyEquivalentsForScope:(NSString*)scope;
-- (void)registerBASHCommand:(NSDictionary*)commandDict;
-- (void)unRegisterBASHCommand:(NSInteger)pid;
-- (NSArray*)runningBASHProcesses;
+- (void)registerActivity:(NSDictionary*)commandDict;
+- (void)removeRegisteredActivity:(NSInteger)pid;
+- (NSArray*)runningActivities;
- (void)handleEventWithURL:(NSURL*)url;
diff --git a/Source/SPAppController.m b/Source/SPAppController.m
index ad456b89..67d0427f 100644
--- a/Source/SPAppController.m
+++ b/Source/SPAppController.m
@@ -57,7 +57,7 @@
bundleUsedScopes = [[NSMutableArray alloc] initWithCapacity:1];
bundleKeyEquivalents = [[NSMutableDictionary alloc] initWithCapacity:1];
installedBundleUUIDs = [[NSMutableDictionary alloc] initWithCapacity:1];
- runningBASHprocesses = [[NSMutableArray alloc] init];
+ runningActivitiesArray = [[NSMutableArray alloc] init];
[NSApp setDelegate:self];
}
@@ -781,7 +781,14 @@
return;
}
- NSString *output = [cmd runBashCommandWithEnvironment:env atCurrentDirectoryPath:nil callerDocument:self withName:([cmdData objectForKey:SPBundleFileNameKey])?[cmdData objectForKey:SPBundleFileNameKey]:@"" error:&err];
+ NSString *output = [cmd runBashCommandWithEnvironment:env
+ atCurrentDirectoryPath:nil
+ callerInstance:self
+ contextInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+ ([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name",
+ NSLocalizedString(@"General", @"general menu item label"), @"scope",
+ nil]
+ error:&err];
[[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil];
@@ -832,24 +839,24 @@
}
-- (void)registerBASHCommand:(NSDictionary*)commandDict
+- (void)registerActivity:(NSDictionary*)commandDict
{
- [runningBASHprocesses addObject:commandDict];
+ [runningActivitiesArray addObject:commandDict];
}
-- (void)unRegisterBASHCommand:(NSInteger)pid
+- (void)removeRegisteredActivity:(NSInteger)pid
{
- for(id cmd in runningBASHprocesses) {
+ for(id cmd in runningActivitiesArray) {
if([[cmd objectForKey:@"pid"] integerValue] == pid) {
- [runningBASHprocesses removeObject:cmd];
+ [runningActivitiesArray removeObject:cmd];
break;
}
}
}
-- (NSArray*)runningBASHProcesses
+- (NSArray*)runningActivities
{
- return (NSArray*)runningBASHprocesses;
+ return (NSArray*)runningActivitiesArray;
}
#pragma mark -
@@ -1538,7 +1545,7 @@
for (NSWindow *aWindow in [NSApp orderedWindows]) {
if([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) {
for(SPDatabaseDocument *doc in [[aWindow windowController] documents]) {
- for(NSDictionary* cmd in [doc runningBASHProcesses]) {
+ for(NSDictionary* cmd in [doc runningActivities]) {
NSInteger pid = [[cmd objectForKey:@"pid"] intValue];
NSTask *killTask = [[NSTask alloc] init];
[killTask setLaunchPath:@"/bin/sh"];
@@ -1550,7 +1557,7 @@
}
}
}
- for(NSDictionary* cmd in [self runningBASHProcesses]) {
+ for(NSDictionary* cmd in [self runningActivities]) {
NSInteger pid = [[cmd objectForKey:@"pid"] intValue];
NSTask *killTask = [[NSTask alloc] init];
[killTask setLaunchPath:@"/bin/sh"];
@@ -1577,7 +1584,7 @@
if(bundleCategories) [bundleCategories release];
if(bundleKeyEquivalents) [bundleKeyEquivalents release];
if(installedBundleUUIDs) [installedBundleUUIDs release];
- if (runningBASHprocesses) [runningBASHprocesses release];
+ if (runningActivitiesArray) [runningActivitiesArray release];
[prefsController release], prefsController = nil;
diff --git a/Source/SPConstants.h b/Source/SPConstants.h
index fce149f0..5327fd45 100644
--- a/Source/SPConstants.h
+++ b/Source/SPConstants.h
@@ -358,6 +358,7 @@ extern NSString *SPNoBOMforSQLdumpFile;
extern NSString *SPContentFilters;
extern NSString *SPDocumentTaskEndNotification;
extern NSString *SPDocumentTaskStartNotification;
+extern NSString *SPActivitiesUpdateNotification;
extern NSString *SPFieldEditorSheetFont;
extern NSString *SPLastSQLFileEncoding;
extern NSString *SPPrintBackground;
diff --git a/Source/SPConstants.m b/Source/SPConstants.m
index 2ab44912..495a7580 100644
--- a/Source/SPConstants.m
+++ b/Source/SPConstants.m
@@ -170,6 +170,7 @@ NSString *SPNoBOMforSQLdumpFile = @"NoBOMforSQLdumpFile";
NSString *SPContentFilters = @"ContentFilters";
NSString *SPDocumentTaskEndNotification = @"DocumentTaskEnded";
NSString *SPDocumentTaskStartNotification = @"DocumentTaskStarted";
+NSString *SPActivitiesUpdateNotification = @"ActivitiesUpdateNotification";
NSString *SPFieldEditorSheetFont = @"FieldEditorSheetFont";
NSString *SPLastSQLFileEncoding = @"lastSqlFileEncoding";
NSString *SPPrintBackground = @"PrintBackground";
diff --git a/Source/SPCopyTable.m b/Source/SPCopyTable.m
index 94e0eb45..86fb9d85 100644
--- a/Source/SPCopyTable.m
+++ b/Source/SPCopyTable.m
@@ -923,7 +923,14 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003;
return;
}
- NSString *output = [cmd runBashCommandWithEnvironment:env atCurrentDirectoryPath:nil callerDocument:[[NSApp delegate] frontDocument] withName:([cmdData objectForKey:SPBundleFileNameKey])?[cmdData objectForKey:SPBundleFileNameKey]:@"" error:&err];
+ NSString *output = [cmd runBashCommandWithEnvironment:env
+ atCurrentDirectoryPath:nil
+ callerInstance:[[NSApp delegate] frontDocument]
+ contextInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+ ([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name",
+ NSLocalizedString(@"Data Table", @"data table menu item label"), @"scope",
+ nil]
+ error:&err];
[[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil];
diff --git a/Source/SPDatabaseDocument.h b/Source/SPDatabaseDocument.h
index 16330b39..57131de8 100644
--- a/Source/SPDatabaseDocument.h
+++ b/Source/SPDatabaseDocument.h
@@ -189,7 +189,7 @@
NSMutableDictionary *spfPreferences;
NSMutableDictionary *spfDocData;
- NSMutableArray *runningBASHprocesses;
+ NSMutableArray *runningActivitiesArray;
NSString *keyChainID;
@@ -357,9 +357,9 @@
// Scripting
- (void)handleSchemeCommand:(NSDictionary*)commandDict;
-- (void)registerBASHCommand:(NSDictionary*)commandDict;
-- (void)unRegisterBASHCommand:(NSInteger)pid;
-- (NSArray*)runningBASHProcesses;
+- (void)registerActivity:(NSDictionary*)commandDict;
+- (void)removeRegisteredActivity:(NSInteger)pid;
+- (NSArray*)runningActivities;
- (NSDictionary*)shellVariables;
// State saving and setting
diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m
index b71ef8f8..309679fe 100644
--- a/Source/SPDatabaseDocument.m
+++ b/Source/SPDatabaseDocument.m
@@ -116,7 +116,7 @@
spfSession = nil;
spfPreferences = [[NSMutableDictionary alloc] init];
spfDocData = [[NSMutableDictionary alloc] init];
- runningBASHprocesses = [[NSMutableArray alloc] init];
+ runningActivitiesArray = [[NSMutableArray alloc] init];
titleAccessoryView = nil;
taskProgressWindow = nil;
@@ -3675,7 +3675,7 @@
}
// Terminate all running BASH commands
- for(NSDictionary* cmd in [self runningBASHProcesses]) {
+ for(NSDictionary* cmd in [self runningActivities]) {
NSInteger pid = [[cmd objectForKey:@"pid"] intValue];
NSTask *killTask = [[NSTask alloc] init];
[killTask setLaunchPath:@"/bin/sh"];
@@ -4757,24 +4757,24 @@
NSLog(@"received: %@", commandDict);
}
-- (void)registerBASHCommand:(NSDictionary*)commandDict
+- (void)registerActivity:(NSDictionary*)commandDict
{
- [runningBASHprocesses addObject:commandDict];
+ [runningActivitiesArray addObject:commandDict];
}
-- (void)unRegisterBASHCommand:(NSInteger)pid
+- (void)removeRegisteredActivity:(NSInteger)pid
{
- for(id cmd in runningBASHprocesses) {
+ for(id cmd in runningActivitiesArray) {
if([[cmd objectForKey:@"pid"] integerValue] == pid) {
- [runningBASHprocesses removeObject:cmd];
+ [runningActivitiesArray removeObject:cmd];
break;
}
}
}
-- (NSArray*)runningBASHProcesses
+- (NSArray*)runningActivities
{
- return (NSArray*)runningBASHprocesses;
+ return (NSArray*)runningActivitiesArray;
}
- (NSDictionary*)shellVariables
@@ -5077,7 +5077,7 @@
if (taskProgressWindow) [taskProgressWindow release];
if (serverSupport) [serverSupport release];
if (processID) [processID release];
- if (runningBASHprocesses) [runningBASHprocesses release];
+ if (runningActivitiesArray) [runningActivitiesArray release];
[super dealloc];
}
diff --git a/Source/SPStringAdditions.h b/Source/SPStringAdditions.h
index b0e085aa..042e69f0 100644
--- a/Source/SPStringAdditions.h
+++ b/Source/SPStringAdditions.h
@@ -77,7 +77,7 @@ static inline id NSMutableAttributedStringAttributeAtIndex (NSMutableAttributedS
- (CGFloat)levenshteinDistanceWithWord:(NSString *)stringB;
-- (NSString *)runBashCommandWithEnvironment:(NSDictionary*)shellEnvironment atCurrentDirectoryPath:(NSString*)path callerDocument:(id)caller withName:(NSString*)name error:(NSError**)theError;
+- (NSString *)runBashCommandWithEnvironment:(NSDictionary*)shellEnvironment atCurrentDirectoryPath:(NSString*)path callerInstance:(id)caller contextInfo:(NSDictionary*)contextInfo error:(NSError**)theError;
- (NSString *)runBashCommandWithEnvironment:(NSDictionary*)shellEnvironment atCurrentDirectoryPath:(NSString*)path error:(NSError**)theError;
@end
diff --git a/Source/SPStringAdditions.m b/Source/SPStringAdditions.m
index 658baadb..27b8fcd0 100644
--- a/Source/SPStringAdditions.m
+++ b/Source/SPStringAdditions.m
@@ -451,7 +451,7 @@
* @param theError If not nil and the bash command failed it contains the returned error message as NSLocalizedDescriptionKey
*
*/
-- (NSString *)runBashCommandWithEnvironment:(NSDictionary*)shellEnvironment atCurrentDirectoryPath:(NSString*)path callerDocument:(id)caller withName:(NSString*)name error:(NSError**)theError
+- (NSString *)runBashCommandWithEnvironment:(NSDictionary*)shellEnvironment atCurrentDirectoryPath:(NSString*)path callerInstance:(id)caller contextInfo:(NSDictionary*)contextInfo error:(NSError**)theError
{
BOOL userTerminated = NO;
@@ -549,14 +549,16 @@
NSFileHandle *stderr_file = [stderr_pipe fileHandleForReading];
[bashTask launch];
NSInteger pid = -1;
- if(caller != nil && [caller respondsToSelector:@selector(registerBASHCommand:)]) {
+ if(caller != nil && [caller respondsToSelector:@selector(registerActivity:)]) {
// register command
pid = [bashTask processIdentifier];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInteger:pid], @"pid",
- name, @"name",
+ (contextInfo)?:[NSDictionary dictionary], @"contextInfo",
+ @"bashcommand", @"type",
[[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]], @"starttime",
nil];
- [caller registerBASHCommand:dict];
+ [caller registerActivity:dict];
+ [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:SPActivitiesUpdateNotification object:nil];
}
// Listen to ⌘. to terminate
@@ -584,15 +586,12 @@
[bashTask waitUntilExit];
// unregister BASH command if it was registered
- if(pid >= 0) [caller unRegisterBASHCommand:pid];
-
- if(userTerminated) {
- if(bashTask) [bashTask release];
- NSBeep();
- NSLog(@"“%@” was terminated by user.", ([self length] > 50) ? [self substringToIndex:50] : self);
- return @"";
+ if(pid >= 0) {
+ [caller removeRegisteredActivity:pid];
+ [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:SPActivitiesUpdateNotification object:nil];
}
+ // Remove script file if used
if(redirectForScript)
[[NSFileManager defaultManager] removeItemAtPath:scriptFilePath error:nil];
diff --git a/Source/SPTableInfo.h b/Source/SPTableInfo.h
index bae3da4e..8663ac6a 100644
--- a/Source/SPTableInfo.h
+++ b/Source/SPTableInfo.h
@@ -38,6 +38,7 @@
NSMutableArray *info;
NSMutableArray *activities;
+ BOOL _activitiesWillBeUpdated;
}
- (void)tableChanged:(NSNotification *)notification;
diff --git a/Source/SPTableInfo.m b/Source/SPTableInfo.m
index ba24040a..3dc64b01 100644
--- a/Source/SPTableInfo.m
+++ b/Source/SPTableInfo.m
@@ -27,6 +27,8 @@
#import "SPDatabaseDocument.h"
#import "SPTablesList.h"
#import "SPTableData.h"
+#import "SPActivityTextFieldCell.h"
+#import "SPTableTextFieldCell.h"
@interface SPTableInfo (PrivateAPI)
@@ -41,6 +43,7 @@
if ((self = [super init])) {
info = [[NSMutableArray alloc] init];
activities = [[NSMutableArray alloc] init];
+ _activitiesWillBeUpdated = NO;
}
return self;
@@ -48,19 +51,26 @@
- (void)awakeFromNib
{
+
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(tableChanged:)
name:SPTableChangedNotification
object:tableDocumentInstance];
- [tableInfoScrollView setAlphaValue:1.0f];
- [activitiesScrollView setAlphaValue:0.0f];
+ // Register activities update notifications for add/remove BASH commands etc.
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(updateActivities)
+ name:SPActivitiesUpdateNotification
+ object:nil];
- // [self performSelector:@selector(updateActivities) withObject:nil afterDelay:1.0f];
+ [tableInfoScrollView setHidden:NO];
+ [activitiesScrollView setHidden:YES];
+ // Add activities header
[activities addObject:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"ACTIVITIES", @"header for activities pane"), @"name", nil]];
[activitiesTable reloadData];
+ // Add Information header
[info addObject:NSLocalizedString(@"TABLE INFORMATION", @"header for table info pane")];
[infoTable reloadData];
}
@@ -80,11 +90,14 @@
NSMutableArray *acts = [NSMutableArray array];
[acts removeAllObjects];
[acts addObject:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"ACTIVITIES", @"header for activities pane"), @"name", nil]];
- [acts addObjectsFromArray:[tableDocumentInstance runningBASHProcesses]];
- [acts addObjectsFromArray:[[NSApp delegate] runningBASHProcesses]];
+ [acts addObjectsFromArray:[tableDocumentInstance runningActivities]];
+ [acts addObjectsFromArray:[[NSApp delegate] runningActivities]];
+ _activitiesWillBeUpdated = YES;
[activities setArray:acts];
+ _activitiesWillBeUpdated = NO;
[activitiesTable reloadData];
- // [self performSelector:@selector(updateActivities) withObject:nil afterDelay:1.0f];
+ [infoTable deselectAll:nil];
+ [activitiesTable deselectAll:nil];
}
/**
@@ -285,10 +298,33 @@
if(aTableView == infoTable) {
return [info objectAtIndex:rowIndex];
} else {
- if(rowIndex > -1 && rowIndex < [activities count])
- return [NSArrayObjectAtIndex(activities,rowIndex) objectForKey:@"name"];
- else
+ if(rowIndex == 0)
+ {
+ SPTableTextFieldCell *c = [[[SPTableTextFieldCell alloc] initTextCell:NSLocalizedString(@"ACTIVITIES", @"header for activities pane")] autorelease];
+ [aTableColumn setDataCell:c];
+ return NSLocalizedString(@"ACTIVITIES", @"header for activities pane");
+ }
+ else if(!_activitiesWillBeUpdated && rowIndex > 0 && rowIndex < [activities count]) {
+ NSDictionary *dict = NSArrayObjectAtIndex(activities,rowIndex);
+ SPActivityTextFieldCell *c = [[[SPActivityTextFieldCell alloc] init] autorelease];
+ [c setActivityName:[[dict objectForKey:@"contextInfo"] objectForKey:@"name"]];
+ if([dict objectForKey:@"type"] && [[dict objectForKey:@"type"] isEqualToString:@"bashcommand"]) {
+ [c setContextInfo:[NSDictionary dictionaryWithObjectsAndKeys:[dict objectForKey:@"type"], @"type", [dict objectForKey:@"pid"], @"pid", nil]];
+ [c setActivityInfo:[NSString stringWithFormat:@"[%@] %@: %@", [[dict objectForKey:@"contextInfo"] objectForKey:@"scope"], NSLocalizedString(@"started", @"started"), [dict objectForKey:@"starttime"]]];
+ }
+ else {
+ [c setActivityInfo:@"..."];
+ }
+ [aTableColumn setDataCell:c];
+ return [dict objectForKey:@"name"];
+ } else {
+ SPActivityTextFieldCell *c = [[[SPActivityTextFieldCell alloc] init] autorelease];
+ [c setActivityName:@"..."];
+ [c setActivityInfo:@""];
+ [aTableColumn setDataCell:c];
return @"...";
+ }
+ return @"";
}
}
@@ -300,28 +336,51 @@
- (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex
{
if(rowIndex == 0) return YES;
+ if(aTableView == infoTable) {
+ return NO;
+ } else {
+ return YES;
+ }
return NO;
}
- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
if(rowIndex > 0) return NO;
- if([tableInfoScrollView alphaValue] == 1.0f) {
- [tableInfoScrollView setAlphaValue:0.0f];
- [activitiesScrollView setAlphaValue:1.0f];
+
+ if(![tableInfoScrollView isHidden]) {
+ [tableInfoScrollView setHidden:YES];
+ [activitiesScrollView setHidden:NO];
+ [[NSApp mainWindow] makeFirstResponder:activitiesTable];
} else {
- [tableInfoScrollView setAlphaValue:1.0f];
- [activitiesScrollView setAlphaValue:0.0f];
+ [activitiesScrollView setHidden:YES];
+ [tableInfoScrollView setHidden:NO];
+ [[NSApp mainWindow] makeFirstResponder:infoTable];
}
+
[infoTable deselectAll:nil];
[activitiesTable deselectAll:nil];
[self updateActivities];
return NO;
}
+- (NSString *)tableView:(NSTableView *)aTableView toolTipForCell:(NSCell *)aCell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex mouseLocation:(NSPoint)mouseLocation
+{
+ if(aTableView == activitiesTable) {
+ if(rowIndex == 0) return @"";
+ if(mouseLocation.x > rect->origin.x + rect->size.width - 30)
+ return NSLocalizedString(@"Cancel", @"cancel");
+ NSDictionary *dict = NSArrayObjectAtIndex(activities,rowIndex);
+ if([[dict objectForKey:@"contextInfo"] objectForKey:@"name"])
+ return [[dict objectForKey:@"contextInfo"] objectForKey:@"name"];
+ return @"";
+ }
+ return nil;
+}
+
- (BOOL)tableView:(NSTableView *)aTableView isGroupRow:(NSInteger)row
{
- // This makes the top row (TABLE INFORMATION) have the diff styling
+ // This makes the top row (TABLE INFORMATION/ACTIVITIES) have the diff styling
return (row == 0);
}
diff --git a/Source/SPTableTextFieldCell.m b/Source/SPTableTextFieldCell.m
index bcfa0138..33508517 100644
--- a/Source/SPTableTextFieldCell.m
+++ b/Source/SPTableTextFieldCell.m
@@ -56,6 +56,11 @@
}
+- (NSRect)expansionFrameWithFrame:(NSRect)cellFrame inView:(NSView *)view
+{
+ return NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, [self cellSize].width, [self cellSize].height);
+}
+
- (NSSize)cellSize
{
NSSize cellSize = [super cellSize];
diff --git a/Source/SPTextViewAdditions.m b/Source/SPTextViewAdditions.m
index e613dac1..70548bf3 100644
--- a/Source/SPTextViewAdditions.m
+++ b/Source/SPTextViewAdditions.m
@@ -603,7 +603,14 @@
return;
}
- NSString *output = [cmd runBashCommandWithEnvironment:env atCurrentDirectoryPath:nil callerDocument:[[NSApp delegate] frontDocument] withName:([cmdData objectForKey:SPBundleFileNameKey])?[cmdData objectForKey:SPBundleFileNameKey]:@"" error:&err];
+ NSString *output = [cmd runBashCommandWithEnvironment:env
+ atCurrentDirectoryPath:nil
+ callerInstance:[[NSApp delegate] frontDocument]
+ contextInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+ ([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name",
+ NSLocalizedString(@"Input Field", @"input field menu item label"), @"scope",
+ nil]
+ error:&err];
[[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil];