aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPContentFilterManager.m324
-rw-r--r--Source/SPTableContent.m13
2 files changed, 200 insertions, 137 deletions
diff --git a/Source/SPContentFilterManager.m b/Source/SPContentFilterManager.m
index 767065d5..a3f95fa2 100644
--- a/Source/SPContentFilterManager.m
+++ b/Source/SPContentFilterManager.m
@@ -33,11 +33,10 @@
#define SP_MULTIPLE_SELECTION_PLACEHOLDER_STRING NSLocalizedString(@"[multiple selection]", @"[multiple selection]")
#define SP_NO_SELECTION_PLACEHOLDER_STRING NSLocalizedString(@"[no selection]", @"[no selection]")
+#define SP_NAME_REQUIRED_PLACEHOLDER_STRING NSLocalizedString(@"[name required]", @"[name required]")
@interface SPContentFilterManager (PrivateAPI)
-- (void)_initWithNoSelection;
-
@end
@implementation SPContentFilterManager
@@ -79,18 +78,8 @@
*/
- (void)awakeFromNib
{
- [contentFilterTextView setAllowsDocumentBackgroundColorChange:YES];
-
- NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary];
-
- [bindingOptions setObject:NSUnarchiveFromDataTransformerName forKey:@"NSValueTransformerName"];
-
- [contentFilterTextView bind:@"backgroundColor"
- toObject:[NSUserDefaultsController sharedUserDefaultsController]
- withKeyPath:@"values.CustomQueryEditorBackgroundColor"
- options:bindingOptions];
-
+ // Add global group row to contentFilters
[contentFilters addObject:[NSDictionary dictionaryWithObjectsAndKeys:
@"Global", @"MenuLabel",
@"", @"headerOfFileURL",
@@ -130,7 +119,12 @@
break;
[[self window] makeFirstResponder:contentFilterTableView];
- [self _initWithNoSelection];
+
+ // Init GUI elements
+ [contentFilterTableView selectRowIndexes:[NSIndexSet indexSet] byExtendingSelection:NO];
+ [[contentFilterNameTextField cell] setPlaceholderString:SP_NO_SELECTION_PLACEHOLDER_STRING];
+ [contentFilterNameTextField setStringValue:@""];
+ [contentFilterTextView setString:@""];
// Register drag types
[contentFilterTableView registerForDraggedTypes:[NSArray arrayWithObject:SPContentFilterPasteboardDragType]];
@@ -153,7 +147,8 @@
/**
* Returns the content filters array for fileURL.
- * fileURL == nil → global content filters
+ *
+ * @param fileURL == The SPDatabaseDocument file URL; if fileURL == nil return the global content filters
*/
- (NSMutableArray *)contentFilterForFileURL:(NSURL *)fileURL
{
@@ -293,13 +288,16 @@
}
/**
- * Insert placeholder - the placeholder string is stored as tooltip
+ * Insert placeholder - the to be inserted placeholder string is stored in sender's tooltip
*/
- (IBAction)insertPlaceholder:(id)sender
{
[contentFilterTextView insertText:[[[sender selectedItem] toolTip] substringToIndex:[[[sender selectedItem] toolTip] rangeOfString:@" – "].location]];
}
+/**
+ * Show save panel sheet for exporting content filters to disk
+ */
- (IBAction)exportContentFilter:(id)sender
{
NSSavePanel *panel = [NSSavePanel savePanel];
@@ -314,6 +312,9 @@
[panel beginSheetForDirectory:nil file:nil modalForWindow:[self window] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:@"exportFilter"];
}
+/**
+ * Show open panel sheet for importing content filters by adding them to current ones
+ */
- (IBAction)importContentFilterByAdding:(id)sender
{
NSOpenPanel *panel = [NSOpenPanel openPanel];
@@ -332,6 +333,9 @@
contextInfo:NULL];
}
+/**
+ * Show open panel sheet for importing content filters by replacing the current ones. Not yet implemented
+ */
- (IBAction)importFavoritesByReplacing:(id)sender
{
@@ -343,13 +347,6 @@
- (IBAction)closeContentFilterManagerSheet:(id)sender
{
- // First check for ESC if pressed while inline editing
- if(![sender tag] && isTableCellEditing) {
- [contentFilterTableView abortEditing];
- isTableCellEditing = NO;
- return;
- }
-
[NSApp endSheet:[self window] returnCode:0];
[[self window] orderOut:self];
@@ -381,6 +378,15 @@
}
+/**
+ * It triggers an update of contentFilterTextView and
+ * resultingClauseContentLabel by inserting @"" into contentFilterTextView
+ */
+- (IBAction)suppressLeadingFiledPlaceholderWasChanged:(id)sender
+{
+ [contentFilterTextView insertText:@""];
+}
+
#pragma mark -
#pragma mark SplitView delegate methods
@@ -401,7 +407,21 @@
}
#pragma mark -
-#pragma mark TableView datasource methods
+#pragma mark TableView delegate methods
+
+/**
+ * Update contentFilterNameTextField if selection of contentFilterTableView was changed.
+ */
+- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
+{
+ if([contentFilterTableView selectedRow] > -1) {
+ NSString *newName = [[contentFilters objectAtIndex:[contentFilterTableView selectedRow]] objectForKey:@"MenuLabel"];
+ if(newName)
+ [contentFilterNameTextField setStringValue:newName];
+ else
+ [contentFilterNameTextField setStringValue:@""];
+ }
+}
/**
* Returns the number of all content filters.
@@ -494,7 +514,7 @@
}
/**
- * Sorting by clicking at a column header inside groups
+ * Sorting by clicking at a column header inside groups. Not yet implemented
*/
- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn
{
@@ -503,111 +523,12 @@
}
/**
- * contentFilters holds the data if a table row is a group header or not
+ * If current row's contentFilters object has a key "headerOfFileURL" then row is grouped ie it's an header
*/
- (BOOL)tableView:(NSTableView *)aTableView isGroupRow:(NSInteger)rowIndex
{
return ([[contentFilters objectAtIndex:rowIndex] objectForKey:@"headerOfFileURL"]) ? YES : NO;
}
-/**
- * Detect if inline editing was done - then ESC to close the sheet will be activate
- */
-- (void)controlTextDidEndEditing:(NSNotification *)aNotification
-{
- isTableCellEditing = NO;
-}
-
-/**
- * Changes in the name text field will be saved in data source directly
- * to update the table view accordingly
- */
-- (void)controlTextDidChange:(NSNotification *)notification
-{
-
- // Do nothing if no filter is selected
- if([contentFilterTableView numberOfSelectedRows] < 1) return;
-
- id object = [notification object];
-
- if(object == contentFilterNameTextField) {
- [[contentFilters objectAtIndex:[contentFilterTableView selectedRow]] setObject:[contentFilterNameTextField stringValue] forKey:@"MenuLabel"];
- [contentFilterTableView reloadData];
- }
-
-}
-
-- (IBAction)suppressLeadingFiledPlaceholderWasChanged:(id)sender
-{
- [contentFilterTextView insertText:@""];
-}
-
-/**
- * Parse clause and update labels accordingly
- */
-- (void)textViewDidChangeSelection:(NSNotification *)notification
-{
- // Do nothing if no filter is selected
- if([contentFilterTableView numberOfSelectedRows] < 1) return;
-
- id object = [notification object];
-
- if(object == contentFilterTextView) {
- [insertPlaceholderButton setEnabled:([[contentFilterTextView string] length])];
- [resultingClauseLabel setHidden:(![[contentFilterTextView string] length])];
- [resultingClauseContentLabel setHidden:(![[contentFilterTextView string] length])];
- [numberOfArgsLabel setHidden:(![[contentFilterTextView string] length])];
-
- NSUInteger numOfArgs = [[[contentFilterTextView string] componentsMatchedByRegex:@"(?<!\\\\)(\\$\\{.*?\\})"] count];
- [numberOfArgsLabel setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Number of arguments: %lu", @"Number of arguments: %lu"), (unsigned long)numOfArgs]];
-
- [contentFilterConjunctionTextField setHidden:(numOfArgs < 2)];
- [contentFilterConjunctionLabel setHidden:(numOfArgs < 2)];
-
- if(numOfArgs > 2) {
- [resultingClauseLabel setStringValue:NSLocalizedString(@"Error", @"error")];
- [resultingClauseContentLabel setStringValue:NSLocalizedString(@"Maximum number of arguments is 2!", @"Maximum number of arguments is 2!")];
- } else {
- [resultingClauseLabel setStringValue:@"SELECT * FROM <table> WHERE"];
- NSMutableString *c = [[NSMutableString alloc] init];
- [c setString:[contentFilterTextView string]];
- [c replaceOccurrencesOfRegex:@"(?<!\\\\)\\$BINARY" withString:@"[BINARY]"];
- [c flushCachedRegexData];
- [c replaceOccurrencesOfRegex:@"(?<!\\\\)(\\$\\{.*?\\})" withString:@"[arg]"];
- [c flushCachedRegexData];
- [c replaceOccurrencesOfRegex:@"(?<!\\\\)\\$CURRENT_FIELD" withString:@"<field>"];
- [c flushCachedRegexData];
- [resultingClauseContentLabel setStringValue:[NSString stringWithFormat:@"%@%@", ([suppressLeadingFiledPlaceholderCheckbox state] == NSOnState) ? @"" : @"<field> ", c]];
- [c release];
- }
-
- }
-}
-#pragma mark -
-#pragma mark Menu validation
-
-/**
- * Menu item validation.
- */
-- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
-{
-
- // Disable all if only GLOBAL is in the table
- if([contentFilters count] < 2) return NO;
-
- SEL action = [menuItem action];
-
- if ( (action == @selector(duplicateContentFilter:)))
- {
- return ([contentFilterTableView numberOfSelectedRows] == 1);
- }
- else if ( (action == @selector(removeContentFilter:)) ||
- ( action == @selector(exportFavorites:)))
- {
- return ([contentFilterTableView numberOfSelectedRows] > 0);
- }
-
- return YES;
-}
#pragma mark -
#pragma mark TableView drag & drop delegate methods
@@ -659,7 +580,6 @@
/**
* Return whether or not to accept the drop of the supplied rows.
*/
-
- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation
{
@@ -715,10 +635,152 @@
}
#pragma mark -
+#pragma mark Various Control delegate methods
+
+/**
+ * Detect if inline editing was done
+ */
+- (void)controlTextDidEndEditing:(NSNotification *)aNotification
+{
+ isTableCellEditing = NO;
+}
+
+/**
+ * Trap the escape overriding default behaviour and ending editing,
+ * only within the current row.
+ */
+- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
+{
+ // Trap the escape key
+ if ( [[control window] methodForSelector:command] == [[control window] methodForSelector:@selector(cancelOperation:)] )
+ {
+
+ // Abort editing
+ [control abortEditing];
+ isTableCellEditing = NO;
+ // Reset name input text field
+ if([contentFilterTableView selectedRow] > -1)
+ [contentFilterNameTextField setStringValue:
+ [[contentFilters objectAtIndex:[contentFilterTableView selectedRow]] objectForKey:@"MenuLabel"]];
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Changes in the name text field will be saved in data source directly
+ * to update the table view accordingly. If filter name is changed via inline editing
+ * in the tableView update name text field accordingly and check for empty names
+ */
+- (void)controlTextDidChange:(NSNotification *)notification
+{
+
+ // Do nothing if no filter is selected
+ if([contentFilterTableView numberOfSelectedRows] < 1) return;
+
+ id object = [notification object];
+
+ if(object == contentFilterNameTextField) {
+ if([[contentFilterNameTextField stringValue] length]) {
+ [[contentFilters objectAtIndex:[contentFilterTableView selectedRow]] setObject:[contentFilterNameTextField stringValue] forKey:@"MenuLabel"];
+ [contentFilterTableView reloadData];
+ } else {
+ NSBeep();
+ [[contentFilters objectAtIndex:[contentFilterTableView selectedRow]] setObject:SP_NAME_REQUIRED_PLACEHOLDER_STRING forKey:@"MenuLabel"];
+ [contentFilterNameTextField setStringValue:SP_NAME_REQUIRED_PLACEHOLDER_STRING];
+ [contentFilterNameTextField selectText:nil];
+ }
+ }
+ else if (object == contentFilterTableView) {
+ NSTextView *editor = [[notification userInfo] objectForKey:@"NSFieldEditor"];
+ NSString *newName = [[editor textStorage] string];
+ if([newName length]) {
+ [contentFilterNameTextField setStringValue:newName];
+ } else {
+ NSBeep();
+ [editor insertText:SP_NAME_REQUIRED_PLACEHOLDER_STRING];
+ [editor setSelectedRange:NSMakeRange(0,[SP_NAME_REQUIRED_PLACEHOLDER_STRING length])];
+ [contentFilterNameTextField setStringValue:SP_NAME_REQUIRED_PLACEHOLDER_STRING];
+ }
+ }
+
+}
+
+/**
+ * Parse clause and update labels accordingly
+ */
+- (void)textViewDidChangeSelection:(NSNotification *)notification
+{
+ // Do nothing if no filter is selected
+ if([contentFilterTableView numberOfSelectedRows] < 1) return;
+
+ id object = [notification object];
+
+ if(object == contentFilterTextView) {
+ [insertPlaceholderButton setEnabled:([[contentFilterTextView string] length])];
+ [resultingClauseLabel setHidden:(![[contentFilterTextView string] length])];
+ [resultingClauseContentLabel setHidden:(![[contentFilterTextView string] length])];
+ [numberOfArgsLabel setHidden:(![[contentFilterTextView string] length])];
+
+ NSUInteger numOfArgs = [[[contentFilterTextView string] componentsMatchedByRegex:@"(?<!\\\\)(\\$\\{.*?\\})"] count];
+ [numberOfArgsLabel setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Number of arguments: %lu", @"Number of arguments: %lu"), (unsigned long)numOfArgs]];
+
+ [contentFilterConjunctionTextField setHidden:(numOfArgs < 2)];
+ [contentFilterConjunctionLabel setHidden:(numOfArgs < 2)];
+
+ if(numOfArgs > 2) {
+ [resultingClauseLabel setStringValue:NSLocalizedString(@"Error", @"error")];
+ [resultingClauseContentLabel setStringValue:NSLocalizedString(@"Maximum number of arguments is 2!", @"Maximum number of arguments is 2!")];
+ } else {
+ [resultingClauseLabel setStringValue:@"SELECT * FROM <table> WHERE"];
+ NSMutableString *c = [[NSMutableString alloc] init];
+ [c setString:[contentFilterTextView string]];
+ [c replaceOccurrencesOfRegex:@"(?<!\\\\)\\$BINARY" withString:@"[BINARY]"];
+ [c flushCachedRegexData];
+ [c replaceOccurrencesOfRegex:@"(?<!\\\\)(\\$\\{.*?\\})" withString:@"[arg]"];
+ [c flushCachedRegexData];
+ [c replaceOccurrencesOfRegex:@"(?<!\\\\)\\$CURRENT_FIELD" withString:@"<field>"];
+ [c flushCachedRegexData];
+ [resultingClauseContentLabel setStringValue:[NSString stringWithFormat:@"%@%@", ([suppressLeadingFiledPlaceholderCheckbox state] == NSOnState) ? @"" : @"<field> ", c]];
+ [c release];
+ }
+
+ }
+}
+#pragma mark -
+#pragma mark Menu validation
+
+/**
+ * Menu item validation.
+ */
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
+{
+
+ // Disable all if only GLOBAL is in the table
+ if([contentFilters count] < 2) return NO;
+
+ SEL action = [menuItem action];
+
+ if ( (action == @selector(duplicateContentFilter:)))
+ {
+ return ([contentFilterTableView numberOfSelectedRows] == 1);
+ }
+ else if ( (action == @selector(removeContentFilter:)) ||
+ ( action == @selector(exportFavorites:)))
+ {
+ return ([contentFilterTableView numberOfSelectedRows] > 0);
+ }
+
+ return YES;
+}
+
+#pragma mark -
#pragma mark Other
/**
- * Sheet did end method
+ * Sheet did end method for removing content filters
*/
- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo
{
@@ -873,12 +935,4 @@
}
}
-- (void)_initWithNoSelection
-{
- [contentFilterTableView selectRowIndexes:[NSIndexSet indexSet] byExtendingSelection:NO];
- [[contentFilterNameTextField cell] setPlaceholderString:SP_NO_SELECTION_PLACEHOLDER_STRING];
- [contentFilterNameTextField setStringValue:@""];
- [contentFilterTextView setString:@""];
-}
-
@end
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m
index 122822a3..e79b2c36 100644
--- a/Source/SPTableContent.m
+++ b/Source/SPTableContent.m
@@ -698,8 +698,17 @@
// Notify listenters that the query has finished
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
- // Trigger a full reload if required
- if (fullTableReloadRequired) [self reloadTable:self];
+ if ([mySQLConnection queryErrored] && ![mySQLConnection queryCancelled]) {
+ if(filterString)
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
+ [NSString stringWithFormat:NSLocalizedString(@"The table data couldn't be loaded presumably due to used filter clause. \n\nMySQL said: %@", @"message of panel when loading of table failed and presumably due to used filter argument"), [mySQLConnection getLastErrorMessage]]);
+ else
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
+ [NSString stringWithFormat:NSLocalizedString(@"The table data couldn't be loaded.\n\nMySQL said: %@", @"message of panel when loading of table failed"), [mySQLConnection getLastErrorMessage]]);
+ } else {
+ // Trigger a full reload if required
+ if (fullTableReloadRequired) [self reloadTable:self];
+ }
}
/**