aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/SPFieldEditor.h48
-rw-r--r--Source/SPFieldEditor.m371
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj8
3 files changed, 426 insertions, 1 deletions
diff --git a/Source/SPFieldEditor.h b/Source/SPFieldEditor.h
new file mode 100644
index 00000000..8b057f80
--- /dev/null
+++ b/Source/SPFieldEditor.h
@@ -0,0 +1,48 @@
+//
+// SPFieldEditor.h
+// sequel-pro
+//
+// Created by Bibiko on 25.06.09.
+// Copyright 2009 __MyCompanyName__. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface SPFieldEditor : NSWindow {
+
+ IBOutlet id editSheetProgressBar;
+ IBOutlet id editSheet;
+ IBOutlet id editSheetSegmentControl;
+ IBOutlet id editSheetQuickLookButton;
+ IBOutlet id editImage;
+ IBOutlet id editTextView;
+ IBOutlet id hexTextView;
+ IBOutlet id editTextScrollView;
+ IBOutlet id hexTextScrollView;
+
+ id editData;
+ BOOL editSheetWillBeInitialized;
+ int quickLookCloseMarker;
+ NSStringEncoding encoding;
+
+}
+
+- (IBAction)closeEditSheet:(id)sender;
+- (IBAction)openEditSheet:(id)sender;
+- (IBAction)saveEditSheet:(id)sender;
+- (IBAction)dropImage:(id)sender;
+- (IBAction)segmentControllerChanged:(id)sender;
+- (IBAction)quickLookFormatButton:(id)sender;
+
+- (void)setEditData:(id)data;
+
+- (void)setMySQLConnectionEncoding:(NSStringEncoding)anEncoding;
+
+- (void)processPasteImageData;
+- (void)processUpdatedImageData:(NSData *)data;
+
+- (void)invokeQuickLookOfType:(NSString *)type treatAsText:(BOOL)isText;
+- (void)removeQuickLooksTempFile:(NSString*)aPath;
+
+@end
diff --git a/Source/SPFieldEditor.m b/Source/SPFieldEditor.m
new file mode 100644
index 00000000..9d0bb75e
--- /dev/null
+++ b/Source/SPFieldEditor.m
@@ -0,0 +1,371 @@
+//
+// SPFieldEditor.m
+// sequel-pro
+//
+// Created by Bibiko on 25.06.09.
+// Copyright 2009 __MyCompanyName__. All rights reserved.
+//
+
+#import "SPFieldEditor.h"
+#import "SPStringAdditions.h"
+#import "SPArrayAdditions.h"
+#import "SPTextViewAdditions.h"
+#import "SPDataAdditions.h"
+#import "QLPreviewPanel.h"
+
+
+@implementation SPFieldEditor
+
+
+- (void)setEditData:(id)data
+{
+ editData = [data retain];
+}
+
+- (void)setMySQLConnectionEncoding:(NSStringEncoding)anEncoding;
+{
+ encoding = anEncoding;
+}
+
+
+- (IBAction)closeEditSheet:(id)sender
+{
+ [NSApp stopModalWithCode:[sender tag]];
+}
+
+- (IBAction)openEditSheet:(id)sender
+{
+ NSOpenPanel *panel = [NSOpenPanel openPanel];
+
+ if ( [panel runModal] == NSOKButton ) {
+ NSString *fileName = [panel filename];
+ NSString *contents = nil;
+
+ editSheetWillBeInitialized = YES;
+
+ [editSheetProgressBar startAnimation:self];
+
+ // free old data
+ if ( editData != nil ) {
+ [editData release];
+ }
+
+ // load new data/images
+ editData = [[NSData alloc] initWithContentsOfFile:fileName];
+
+ NSImage *image = [[NSImage alloc] initWithData:editData];
+ contents = [[NSString alloc] initWithData:editData encoding:encoding];
+ if (contents == nil)
+ contents = [[NSString alloc] initWithData:editData encoding:NSASCIIStringEncoding];
+
+ // set the image preview, string contents and hex representation
+ [editImage setImage:image];
+
+
+ if(contents)
+ [editTextView setString:contents];
+ else
+ [editTextView setString:@""];
+
+ // Load hex data only if user has already displayed them
+ if(![[hexTextView string] isEqualToString:@""])
+ [hexTextView setString:[editData dataToFormattedHexString]];
+
+ // If the image cell now contains a valid image, select the image view
+ if (image) {
+ [editSheetSegmentControl setSelectedSegment:1];
+ [hexTextView setHidden:YES];
+ [hexTextScrollView setHidden:YES];
+ [editImage setHidden:NO];
+ [editTextView setHidden:YES];
+ [editTextScrollView setHidden:YES];
+
+ // Otherwise deselect the image view
+ } else {
+ [editSheetSegmentControl setSelectedSegment:0];
+ [hexTextView setHidden:YES];
+ [hexTextScrollView setHidden:YES];
+ [editImage setHidden:YES];
+ [editTextView setHidden:NO];
+ [editTextScrollView setHidden:NO];
+ }
+
+ [image release];
+ if(contents)
+ [contents release];
+ [editSheetProgressBar stopAnimation:self];
+ editSheetWillBeInitialized = NO;
+ }
+}
+
+/*
+ * Segement controller for text/image/hex buttons in editSheet
+ */
+- (IBAction)segmentControllerChanged:(id)sender
+{
+ switch([sender selectedSegment]){
+ case 0: // text
+ [editTextView setHidden:NO];
+ [editTextScrollView setHidden:NO];
+ [editImage setHidden:YES];
+ [hexTextView setHidden:YES];
+ [hexTextScrollView setHidden:YES];
+ [editSheet makeFirstResponder:editTextView];
+ break;
+ case 1: // image
+ [editTextView setHidden:YES];
+ [editTextScrollView setHidden:YES];
+ [editImage setHidden:NO];
+ [hexTextView setHidden:YES];
+ [hexTextScrollView setHidden:YES];
+ [editSheet makeFirstResponder:editImage];
+ break;
+ case 2: // hex - load on demand
+ if([editData length] && [[hexTextView string] isEqualToString:@""]) {
+ [editSheetProgressBar startAnimation:self];
+ [hexTextView setString:[editData dataToFormattedHexString]];
+ [editSheetProgressBar stopAnimation:self];
+ }
+ [editTextView setHidden:YES];
+ [editTextScrollView setHidden:YES];
+ [editImage setHidden:YES];
+ [hexTextView setHidden:NO];
+ [hexTextScrollView setHidden:NO];
+ [editSheet makeFirstResponder:hexTextView];
+ break;
+ }
+}
+
+/*
+ * Saves a file containing the content of the editSheet
+ */
+- (IBAction)saveEditSheet:(id)sender
+{
+ NSSavePanel *panel = [NSSavePanel savePanel];
+
+ if ( [panel runModal] == NSOKButton ) {
+
+ [editSheetProgressBar startAnimation:self];
+
+ NSString *fileName = [panel filename];
+
+ // Write binary field types directly to the file
+ //// || [editSheetBinaryButton state] == NSOnState
+ if ( [editData isKindOfClass:[NSData class]] ) {
+ [editData writeToFile:fileName atomically:YES];
+
+ // Write other field types' representations to the file via the current encoding
+ } else {
+ [[editData description] writeToFile:fileName
+ atomically:YES
+ encoding:encoding
+ error:NULL];
+ }
+
+ [editSheetProgressBar stopAnimation:self];
+
+ }
+}
+
+
+#pragma mark -
+#pragma mark QuickLook
+
+- (IBAction)quickLookFormatButton:(id)sender
+{
+ switch([sender tag]) {
+ case 0: [self invokeQuickLookOfType:@"pict" treatAsText:NO]; break;
+ case 1: [self invokeQuickLookOfType:@"m4a" treatAsText:NO]; break;
+ case 2: [self invokeQuickLookOfType:@"mp3" treatAsText:NO]; break;
+ case 3: [self invokeQuickLookOfType:@"wav" treatAsText:NO]; break;
+ case 4: [self invokeQuickLookOfType:@"mov" treatAsText:NO]; break;
+ case 5: [self invokeQuickLookOfType:@"pdf" treatAsText:NO]; break;
+ case 6: [self invokeQuickLookOfType:@"html" treatAsText:YES]; break;
+ case 7: [self invokeQuickLookOfType:@"doc" treatAsText:NO]; break;
+ case 8: [self invokeQuickLookOfType:@"rtf" treatAsText:YES]; break;
+ }
+}
+
+/*
+ * Opens QuickLook for current data if QuickLook is available
+ */
+- (void)invokeQuickLookOfType:(NSString *)type treatAsText:(BOOL)isText
+{
+
+ // Load private framework
+ if([[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/QuickLookUI.framework"] load]) {
+
+ [editSheetProgressBar startAnimation:self];
+
+ // Create a temporary file name to store the data as file
+ // since QuickLook only works on files.
+ NSString *tmpFileName = [NSString stringWithFormat:@"/tmp/SequelProQuickLook.%@", type];
+
+ // if data are binary
+ if ( [editData isKindOfClass:[NSData class]] || !isText) {
+ [editData writeToFile:tmpFileName atomically:YES];
+
+ // write other field types' representations to the file via the current encoding
+ } else {
+ [[editData description] writeToFile:tmpFileName
+ atomically:YES
+ encoding:encoding
+ error:NULL];
+ }
+
+ id ql = [NSClassFromString(@"QLPreviewPanel") sharedPreviewPanel];
+
+ // Init QuickLook
+ [[ql delegate] setDelegate:self];
+ [ql setURLs:[NSArray arrayWithObject:
+ [NSURL fileURLWithPath:tmpFileName]] currentIndex:0 preservingDisplayState:YES];
+ // TODO: No interaction with iChat and iPhoto due to .scriptSuite warning:
+ // for superclass of class 'MainController' in suite 'Sequel Pro': 'NSCoreSuite.NSAbstractObject' is not a valid class name.
+ [ql setShowsAddToiPhotoButton:NO];
+ [ql setShowsiChatTheaterButton:NO];
+ // Since we are inside of editSheet we have to avoid full-screen zooming
+ // otherwise QuickLook hangs
+ [ql setShowsFullscreenButton:NO];
+ [ql setEnableDragNDrop:NO];
+ // Order out QuickLook with animation effect according to self:previewPanel:frameForURL:
+ [ql makeKeyAndOrderFrontWithEffect:2]; // 1 = fade in
+
+ // quickLookCloseMarker == 1 break the modal session
+ quickLookCloseMarker = 0;
+
+ [editSheetProgressBar stopAnimation:self];
+
+ // Run QuickLook in its own modal seesion for event handling
+ NSModalSession session = [NSApp beginModalSessionForWindow:ql];
+ for (;;) {
+ // Conditions for closing QuickLook
+ if ([NSApp runModalSession:session] != NSRunContinuesResponse
+ || quickLookCloseMarker == 1
+ || ![ql isVisible])
+ break;
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
+ beforeDate:[NSDate distantFuture]];
+
+ }
+ [NSApp endModalSession:session];
+
+ // Remove temp file after closing the sheet to allow double-click event at the QuickLook preview.
+ // The afterDelay: time is a kind of dummy, because after double-clicking the model session loop
+ // will break (ql not visible) and returns the event handling back to the editSheet which by itself
+ // blocks the execution of removeQuickLooksTempFile: until the editSheet is closed.
+ [self performSelector:@selector(removeQuickLooksTempFile:) withObject:tmpFileName afterDelay:2];
+
+ // [[NSFileManager defaultManager] removeItemAtPath:tmpFileName error:NULL];
+
+ }
+
+}
+
+- (void)removeQuickLooksTempFile:(NSString*)aPath
+{
+ [[NSFileManager defaultManager] removeItemAtPath:aPath error:NULL];
+}
+
+// This is the delegate method
+// It should return the frame for the item represented by the URL
+// If an empty frame is returned then the panel will fade in/out instead
+- (NSRect)previewPanel:(NSPanel*)panel frameForURL:(NSURL*)URL
+{
+
+ // Close modal session defined in invokeQuickLookOfType:
+ // if user closes the QuickLook view
+ quickLookCloseMarker = 1;
+
+ // Return the App's middle point
+ NSRect mwf = [[NSApp mainWindow] frame];
+ return NSMakeRect(
+ mwf.origin.x+mwf.size.width/2,
+ mwf.origin.y+mwf.size.height/2,
+ 5, 5);
+
+}
+
+-(void)processPasteImageData
+{
+ editSheetWillBeInitialized = YES;
+
+ NSImage *image = nil;
+
+ image = [[[NSImage alloc] initWithPasteboard:[NSPasteboard generalPasteboard]] autorelease];
+ if (image) {
+
+ if (nil != editData) [editData release];
+
+ [editImage setImage:image];
+
+ editData = [[NSData alloc] initWithData:[image TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1]];
+
+ NSString *contents = [[NSString alloc] initWithData:editData encoding:encoding];
+ if (contents == nil)
+ contents = [[NSString alloc] initWithData:editData encoding:NSASCIIStringEncoding];
+
+ // Set the string contents and hex representation
+ if(contents)
+ [editTextView setString:contents];
+ if(![[hexTextView string] isEqualToString:@""])
+ [hexTextView setString:[editData dataToFormattedHexString]];
+
+ [contents release];
+
+ }
+
+ editSheetWillBeInitialized = NO;
+}
+/*
+ * Invoked when the imageView in the connection sheet has the contents deleted
+ * or a file dragged and dropped onto it.
+ */
+- (void)processUpdatedImageData:(NSData *)data
+{
+
+ editSheetWillBeInitialized = YES;
+
+ if (nil != editData) [editData release];
+
+ // If the image was not processed, set a blank string as the contents of the edit and hex views.
+ if ( data == nil ) {
+ editData = [[NSData alloc] init];
+ [editTextView setString:@""];
+ [hexTextView setString:@""];
+ editSheetWillBeInitialized = NO;
+ return;
+ }
+
+ // Process the provided image
+ editData = [[NSData alloc] initWithData:data];
+ NSString *contents = [[NSString alloc] initWithData:data encoding:encoding];
+ if (contents == nil)
+ contents = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
+
+ // Set the string contents and hex representation
+ if(contents)
+ [editTextView setString:contents];
+ if(![[hexTextView string] isEqualToString:@""])
+ [hexTextView setString:[editData dataToFormattedHexString]];
+
+ [contents release];
+ editSheetWillBeInitialized = NO;
+}
+
+- (IBAction)dropImage:(id)sender
+{
+
+ // If the image was deleted, set a blank string as the contents of the edit and hex views.
+ // The actual dropped image processing is handled by processUpdatedImageData:.
+ if ( [editImage image] == nil ) {
+ if (nil != editData) [editData release];
+ editData = [[NSData alloc] init];
+ [editTextView setString:@""];
+ [hexTextView setString:@""];
+ return;
+ }
+}
+
+
+
+@end
diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj
index 07f4455d..61b6d333 100644
--- a/sequel-pro.xcodeproj/project.pbxproj
+++ b/sequel-pro.xcodeproj/project.pbxproj
@@ -156,6 +156,7 @@
BC1847EA0FE6EC8400094BFB /* SPEditSheetTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC1847E90FE6EC8400094BFB /* SPEditSheetTextView.m */; };
BC2C16D40FEBEDF10003993B /* SPDataAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = BC2C16D30FEBEDF10003993B /* SPDataAdditions.m */; };
BC2C8E220FA8C2DB008468C7 /* sequel-pro-mysql-help-template.html in Resources */ = {isa = PBXBuildFile; fileRef = BC2C8E210FA8C2DB008468C7 /* sequel-pro-mysql-help-template.html */; };
+ BC99296E0FF3D001008B79AB /* SPFieldEditor.m in Sources */ = {isa = PBXBuildFile; fileRef = BC99296D0FF3D001008B79AB /* SPFieldEditor.m */; };
BCD0AD490FBBFC340066EA5C /* SPSQLTokenizer.l in Sources */ = {isa = PBXBuildFile; fileRef = BCD0AD480FBBFC340066EA5C /* SPSQLTokenizer.l */; };
/* End PBXBuildFile section */
@@ -199,7 +200,7 @@
isa = PBXContainerItemProxy;
containerPortal = B5538CD70FF279AD00219803 /* BWToolkit.xcodeproj */;
proxyType = 1;
- remoteGlobalIDString = 8D1AC9600486D14A00FE50C9 /* BWToolkit */;
+ remoteGlobalIDString = 8D1AC9600486D14A00FE50C9;
remoteInfo = BWToolkit;
};
/* End PBXContainerItemProxy section */
@@ -445,6 +446,8 @@
BC2C16D20FEBEDF10003993B /* SPDataAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPDataAdditions.h; sourceTree = "<group>"; };
BC2C16D30FEBEDF10003993B /* SPDataAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPDataAdditions.m; sourceTree = "<group>"; };
BC2C8E210FA8C2DB008468C7 /* sequel-pro-mysql-help-template.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "sequel-pro-mysql-help-template.html"; sourceTree = "<group>"; };
+ BC99296C0FF3D001008B79AB /* SPFieldEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPFieldEditor.h; sourceTree = "<group>"; };
+ BC99296D0FF3D001008B79AB /* SPFieldEditor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPFieldEditor.m; sourceTree = "<group>"; };
BCD0AD480FBBFC340066EA5C /* SPSQLTokenizer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = SPSQLTokenizer.l; sourceTree = "<group>"; };
BCD0AD4A0FBBFC480066EA5C /* SPSQLTokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPSQLTokenizer.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -738,6 +741,8 @@
5841423E0F97E11000A34B47 /* NoodleLineNumberView.m */,
BC1847E80FE6EC8400094BFB /* SPEditSheetTextView.h */,
BC1847E90FE6EC8400094BFB /* SPEditSheetTextView.m */,
+ BC99296C0FF3D001008B79AB /* SPFieldEditor.h */,
+ BC99296D0FF3D001008B79AB /* SPFieldEditor.m */,
);
name = GUI;
sourceTree = "<group>";
@@ -1248,6 +1253,7 @@
29A1B7E50FD1293A000B88E8 /* SPPrintAccessory.m in Sources */,
BC1847EA0FE6EC8400094BFB /* SPEditSheetTextView.m in Sources */,
BC2C16D40FEBEDF10003993B /* SPDataAdditions.m in Sources */,
+ BC99296E0FF3D001008B79AB /* SPFieldEditor.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};