/* ** MyLibrary.m ** ** Copyright (c) 2004 ** ** Author: Yen-Ju Chen ** ** 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 */ #include "MyLibrary.h" #include "GNUstep.h" #include "Constants.h" #include "GeneralContainer+Additions.h" #include "Sources.h" #include "LibrarySource.h" #include "FolderSource.h" #include "SmartFolderSource.h" #include "SmartFolderEditor.h" #include "SearchSource.h" #include "AttributesSource.h" #include "AttributesViewer.h" #include "IconTableView.h" #include "ItemTableView.h" #include "NoteTextView.h" #include "CriterionView.h" #include "Criterion.h" #include "ImportFilePanel.h" #include "SummaryViewer.h" #include "ContentIndexer.h" #include "LibraryLocationPanel.h" #include "TimeStamp.h" #define MakeTimeStamp \ [[TimeStamp timeStampWithIdentifier: LibraryEditedTimeStamp] setTime: [NSDate date]] @implementation MyLibrary - (SourceType) _typeOfSelectedSource { return [sources typeOfSourceAtIndex: [sourceTableView selectedRow]]; } - (void) _removeItemWithUniqueNumber: (unsigned int) uid { MakeTimeStamp; unsigned int index; index = [librarySource indexOfUniqueNumber: uid]; if (index != NSNotFound) { [librarySource removeObjectAtIndex: index]; } index = [sources indexOfUniqueNumber: uid]; if (index != NSNotFound) { [sources removeObjectAtIndex: index]; } /* replace title in sources */ unsigned int i, icount = [sources count]; unsigned int j; SourceType type; id container; for(i = 0; i < icount; i++) { type = [sources typeOfSourceAtIndex: i]; switch (type) { case SourceFolderType: { container = [sources containerAtIndex: i]; j = [container indexOfUniqueNumber: uid]; [container removeObjectAtIndex: j]; continue; } } } } /* This methods will change the order of sources * because it is automatically sorted by name. * Only for replace item title, not other sources. */ - (void) _replaceTitle: (NSString *) new forItemWithUniqueNumber: (unsigned int) uid { unsigned int index; MakeTimeStamp; index = [librarySource indexOfUniqueNumber: uid]; NSString *old = [librarySource titleAtIndex: index]; if (index != NSNotFound) { [librarySource setTitle: new atIndex: index]; } index = [sources indexOfUniqueNumber: uid]; if (index != NSNotFound) { [sources setTitle: new atIndex: index]; } /* replace title in sources */ unsigned int i, icount = [sources count]; unsigned int j; SourceType type; id container; for(i = 0; i < icount; i++) { type = [sources typeOfSourceAtIndex: i]; switch (type) { case SourceFolderType: { //NSLog(@"replace title in Folder %@", old); container = [sources containerAtIndex: i]; j = [container indexOfUniqueNumber: uid]; [container setTitle: new atIndex: j]; continue; } } } /* replace all links */ [librarySource replaceContentOfLink: old withString: new]; } - (void) _selectItemWithUniqueNumber: (unsigned int) uid { unsigned int index = [librarySource indexOfUniqueNumber: uid]; if (index == NSNotFound) return; [itemTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: index] byExtendingSelection: NO]; } - (void) _displaySelectedNote { if ([itemTableView numberOfSelectedRows] != 1) { [noteTextView setString: @""]; return; } unsigned int index = [itemTableView selectedRow]; SourceType type = [self _typeOfSelectedSource]; if ((type == SourceFolderType) || (type == SourceSmartFolderType) || (type == SourceSearchType)) { id container = [sources containerAtIndex: [sourceTableView selectedRow]]; index = [librarySource indexOfUniqueNumber: [container uniqueNumberAtIndex: index]]; } if ([noteTextView isNoteTextViewEditable] == YES) { NSString *note = [librarySource noteAtIndex: index]; if (note) [noteTextView setString: note]; else [noteTextView setString: @""]; } else { NSAttributedString *as; NS_DURING as = [librarySource renderedNoteAtIndex: index]; NS_HANDLER // Should handle exception as = nil; NS_ENDHANDLER if (as) [[noteTextView textStorage] setAttributedString: as]; else { /* Try summary */ as = [librarySource summaryAtIndex: index maximalAttributes: -1 style: SummaryBriefStyle]; if (as) [[noteTextView textStorage] setAttributedString: as]; else [noteTextView setString: @""]; } } } - (void) _saveSelectedNote { if ([itemTableView numberOfSelectedRows] != 1) return; if ([noteTextView isNoteTextViewEditable] == NO) return; unsigned int index = [itemTableView selectedRow]; SourceType type = [self _typeOfSelectedSource]; if ((type == SourceFolderType) || (type == SourceSmartFolderType) || (type == SourceSearchType)) { id container = [sources containerAtIndex: [sourceTableView selectedRow]]; index = [librarySource indexOfUniqueNumber: [container uniqueNumberAtIndex: index]]; } //NSLog(@"_saveSelectedNote **%@**", [noteTextView string]); MakeTimeStamp; [librarySource setNote: [noteTextView string] atIndex: index]; } - (void) _updateAvailableSelectionsForSource { unsigned int i, count = [sources count]; SourceType sourceType; NSString *title; NSMutableArray *selections = [[NSMutableArray alloc] init]; /* go through all sources */ for(i = 0; i < count; i++) { sourceType = [sources typeOfSourceAtIndex: i]; switch(sourceType) { case SourceSmartFolderType: case SourceFolderType: title = [sources titleAtIndex: i]; [selections addObject: title]; break; case SourceLibraryType: case SourceSearchType: /* Ignore these type */ break; } } [searchCriterion setAvailableSelections: selections forSubject: sSource]; RELEASE(selections); [searchView reloadSelections]; } - (void) _updateAllAvailableSubjectsInSearchCriterion { addAvailableSubjectsIntoCriterion (searchCriterion); [self _updateAvailableSelectionsForSource]; [searchView reloadSubjects]; } - (BOOL) _loadLibraryAtPath: (NSString *) path { if ([[LibrarySource sharedSource] loadSourceAtPath: [path stringByAppendingPathComponent: LibraryPlist]] == NO) { return NO; } if ([[AttributesSource sharedSource] loadSourceAtPath: [path stringByAppendingPathComponent: AttributesPlist]] == NO) { return NO; } if ([[Sources sharedSources] loadSourceAtPath: [path stringByAppendingPathComponent: SourcePlist]] == NO) { return NO; } MakeTimeStamp; /* Refresh table view */ [sourceTableView reloadData]; [itemTableView reloadData]; [sourceTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO]; [itemTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO]; /* back and forward stack */ [stack removeAllObjects]; [stack addObject: [NSNumber numberWithUnsignedInt: [librarySource uniqueNumberAtIndex: 0]]]; stack_index = [stack count]-1; /* display note */ [self _displaySelectedNote]; /* update all attributes */ [self _updateAllAvailableSubjectsInSearchCriterion]; NSString *em = [NSString stringWithUTF8String: "\xe2\x80\x94"]; NSString *title = [NSString stringWithFormat: @"%@ %@ %@", [path lastPathComponent], em, [path stringByDeletingLastPathComponent]]; [mainWindow setTitle: title]; return YES; } - (BOOL) _unloadLibrary { /* Save library */ if ([[AttributesSource sharedSource] unloadSourceAtPath: nil] == NO) { return NO; } if ([[LibrarySource sharedSource] unloadSourceAtPath: nil] == NO) { return NO; } if ([[Sources sharedSources] unloadSourceAtPath: nil] == NO) { return NO; } return YES; } /* Summary view */ - (void) styleDidChangeInSummaryViewer: (id) sender { [self summaryViewerAction: self]; } /* Criterion View */ - (void) criterionDidChangeInView: (CriterionView *) view { //NSLog(@"Criterion did change %@", view); unsigned int index, count, total; MakeTimeStamp; if (searchSource == nil) { ASSIGN(searchSource, AUTORELEASE([[SearchSource alloc] init])); /* add into sources */ [sources newSource: sSearch ofType: SourceSearchType]; /* Create folder container */ index = [sources indexOfTitle: sSearch]; [sources setContainer: searchSource atIndex: index]; [sourceTableView reloadData]; } else { index = [sources indexOfTitle: sSearch]; } [searchSource setCriterion: searchCriterion]; [searchSource refreshAll]; count = [searchSource count]; total = [librarySource count]; if ((count > 0) && (count < total)) { [sourceTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: index] byExtendingSelection: NO]; } [itemTableView reloadData]; [searchToolbarItem setLabel: [NSString stringWithFormat: @"%d of %d", count, total]]; } - (void) criterionViewProposeResizing: (CriterionView *) view toSize: (NSSize) proposedSize { [searchToolbarItem setMinSize: proposedSize]; [searchToolbarItem setMaxSize: proposedSize]; } /* Toolbar */ - (void) toolbarWillAddItem: (NSNotification *) not { if ([[not userInfo] objectForKey: @"item"] == searchToolbarItem) { NSSize size = [searchToolbarItem minSize]; [searchToolbarItem setMinSize: NSMakeSize(500, size.height)]; [searchToolbarItem setMaxSize: NSMakeSize(2048, size.height)]; //[(CriterionView *)[searchToolbarItem view] reloadData]; } } - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) bar { return [NSArray arrayWithObjects: SearchToolbarItemIdentifier, nil]; } - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) bar { return [NSArray arrayWithObjects: SearchToolbarItemIdentifier, nil]; } - (NSToolbarItem *) toolbar: (NSToolbar *) bar itemForItemIdentifier: (NSString *) itemIdentifier willBeInsertedIntoToolbar: (BOOL) flag { float optimal_height; //NSLog(@"%@, item %@, inserted %d", bar, itemIdentifier, flag); if ([itemIdentifier isEqualToString: SearchToolbarItemIdentifier]) { searchToolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier: SearchToolbarItemIdentifier]; searchView = [[CriterionView alloc] initWithFrame: NSMakeRect(0, 0, 400, 64)]; [searchView setBordered: NO]; [searchView setSmallControlSize: YES]; #ifdef GNUSTEP [searchView setMaxCriterions: 1]; #else [searchView setMaxCriterions: 10]; #endif [searchView setDelegate: self]; [searchView setDataSource: searchCriterion]; [searchView reloadData]; optimal_height = [searchView optimalHeight]; //NSLog(@"optimal height %f", optimal_height); [searchView setFrame: NSMakeRect(0, 0, 400, optimal_height)]; [searchToolbarItem setMinSize: NSMakeSize(400, optimal_height)]; [searchToolbarItem setMaxSize: NSMakeSize(800, optimal_height)]; [searchToolbarItem setLabel: sSearch]; [searchToolbarItem setPaletteLabel: sSearch]; [searchToolbarItem setView: searchView]; RELEASE(searchView); return AUTORELEASE(searchToolbarItem); } return nil; } /* text view delegate */ - (BOOL) textView: (NSTextView *) textView clickedOnLink: (id) link atIndex: (unsigned int) charIndex { NSRange range; NSString *string; id attribute =[[textView textStorage] attribute: NSLinkAttributeName atIndex: charIndex effectiveRange: &range]; if (attribute == nil) { NSLog(@"Error: no link"); return NO; } else if ([attribute isKindOfClass: [NSURL class]]) { string = [[[textView string] substringWithRange: range] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; return [[NSWorkspace sharedWorkspace] openURL: attribute]; } else if ([attribute isKindOfClass: [NSString class]]) { if ([attribute isEqualToString: @"Link"]) { string = [[[textView string] substringWithRange: range] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; // Create new page if not existed unsigned int index = [librarySource indexOfTitle: string]; if (index == NSNotFound) { /* Create new note */ //NSLog(@"Create page \"%@\"", string); index = [librarySource newItemWithTitle: string]; [itemTableView reloadData]; } unsigned int uid = [librarySource uniqueNumberAtIndex: index]; [self _selectItemWithUniqueNumber: uid]; return YES; } else if ([attribute hasPrefix: @"<"]) { NSLog(@"Email to %@", attribute); return YES; } else /* Unknown link */ return NO; } return NO; } /* table view delegate */ - (int) numberOfRowsInTableView: (NSTableView *) tableView { if (tableView == sourceTableView) { return [sources count]; } else /* itemTableView */ { unsigned int index = [sourceTableView selectedRow]; SourceType type = [sources typeOfSourceAtIndex: index]; switch (type) { case SourceLibraryType: case SourceNoteType: { return [librarySource count]; } case SourceFolderType: case SourceSmartFolderType: case SourceSearchType: { return [[sources containerAtIndex: index] count]; } default: return 0; } } } - (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) column row: (int) row { if (tableView == sourceTableView) { return [sources titleAtIndex: row]; } else /* itemTableView */ { unsigned int index = [sourceTableView selectedRow]; SourceType type = [sources typeOfSourceAtIndex: index]; switch (type) { case SourceLibraryType: case SourceNoteType: { if ([[column identifier] isEqualToString: ItemIdentifier]) { return [librarySource titleAtIndex: row]; } else if ([[column identifier] isEqualToString: TypeIdentifier]) { return [librarySource typeStringOfItemAtIndex: row]; } } case SourceFolderType: case SourceSmartFolderType: case SourceSearchType: { id container = [sources containerAtIndex: index]; unsigned int uid = [container uniqueNumberAtIndex: row]; if ([[column identifier] isEqualToString: ItemIdentifier]) { return [container titleAtIndex: row]; } else if ([[column identifier] isEqualToString: TypeIdentifier]) { unsigned int index = [librarySource indexOfUniqueNumber: uid]; return [librarySource typeStringOfItemAtIndex: index]; } } } } return @""; } - (void) tableView: (NSTableView *) tableView setObjectValue: (id) object forTableColumn: (NSTableColumn *) column row: (int) rowIndex { if (tableView == itemTableView) { if ([[column identifier] isEqualToString: TypeIdentifier]) return; unsigned int itemIndex, sourceIndex; unsigned int uid; id container; SourceType type = [self _typeOfSelectedSource]; if ((type == SourceFolderType) || (type == SourceSmartFolderType) || (type == SourceSearchType)) { container = [sources containerAtIndex: [sourceTableView selectedRow]]; } else { container = librarySource; } uid = [container uniqueNumberAtIndex: rowIndex]; NSString *originalTitle = [container titleAtIndex: rowIndex]; if ([originalTitle isEqualToString: object]) return; itemIndex = [librarySource indexOfUniqueNumber: uid]; sourceIndex = [sources indexOfTitle: originalTitle]; /* Check duplication */ if (([librarySource isDuplicatedTitle: object skipIndex: itemIndex]) || ([sources isDuplicatedTitle: object skipIndex: sourceIndex])) { int columnIndex = [itemTableView columnWithIdentifier: [column identifier]]; NSRunAlertPanel(sTitleError, sDuplicatedTitle, sOK, nil, nil, nil); [itemTableView editColumn: columnIndex row: rowIndex withEvent: nil select: YES]; return; } /* Change title */ [self _replaceTitle: object forItemWithUniqueNumber: uid]; if ((type == SourceSmartFolderType) || (type == SourceSearchType)) { if (container) [container refreshAll]; } [sourceTableView reloadData]; [itemTableView reloadData]; } else if (tableView == sourceTableView) { NSString *originalTitle = [sources titleAtIndex: rowIndex]; if ([originalTitle isEqualToString: object]) return; /* Check duplication */ unsigned int uid = [sources uniqueNumberAtIndex: rowIndex]; unsigned int itemIndex; if (uid != NSNotFound) { itemIndex = [librarySource indexOfUniqueNumber: uid]; } else { /* Not an item. Should not exist in library */ itemIndex = NSNotFound; } //NSLog(@"New Title \"%@\", %d %d", object, rowIndex, itemIndex); if (([sources isDuplicatedTitle: object skipIndex: rowIndex]) || ([librarySource isDuplicatedTitle: object skipIndex: itemIndex])) { NSRunAlertPanel(sTitleError, sDuplicatedTitle, sOK, nil, nil, nil); [sourceTableView editColumn: 0 row: rowIndex withEvent: nil select: YES]; return; } /* Change title */ if (uid != NSNotFound) { [self _replaceTitle: object forItemWithUniqueNumber: uid]; } else { MakeTimeStamp; [sources setTitle: object atIndex: rowIndex]; } /* _replaceTitle change the order of sources. * Need to know the new index */ unsigned int index = [sources indexOfTitle: object]; SourceType sourceType = [sources typeOfSourceAtIndex: index]; switch(sourceType) { case SourceFolderType: case SourceSmartFolderType: /* update resource, too */ [sources setResourcePath: [object stringByAppendingPathExtension: @"plist"] atIndex: index]; /* for criterion */ [self _updateAvailableSelectionsForSource]; break; case SourceSearchType: /* Becomre SmartFolder */ [searchSource becomeSmartFolder: YES]; [sources setType: SourceSmartFolderType atIndex: index]; [sources setResourcePath: [object stringByAppendingPathExtension: @"plist"] atIndex: index]; DESTROY(searchSource); break; } [sourceTableView reloadData]; [itemTableView reloadData]; } } - (id) tableView: (NSTableView *) tableView iconForTableColumn: (NSTableColumn *) column row: (int) row size: (NSSize) size { if ([tableView tag] == SourceTableViewTag) { int iconSize = 12;; SourceType type = [sources typeOfSourceAtIndex: row]; if (size.height >= 14) iconSize = 14;; switch (type) { case SourceLibraryType: return [NSImage imageNamed: [NSString stringWithFormat: @"Home%d.png", iconSize]]; case SourceNoteType: return [NSImage imageNamed: [NSString stringWithFormat: @"Page%d.png", iconSize]]; case SourceFolderType: return [NSImage imageNamed: [NSString stringWithFormat: @"Folder%d.png", iconSize]]; case SourceSmartFolderType: return [NSImage imageNamed: [NSString stringWithFormat: @"SmartFolder%d.png", iconSize]]; case SourceSearchType: return [NSImage imageNamed: [NSString stringWithFormat: @"Search%d.png", iconSize]]; default: return nil; } } #ifndef GNUSTEP else if ([tableView tag] == ItemTableViewTag) { SourceType sourceType = [self _typeOfSelectedSource]; id container; unsigned int index = row; if ((sourceType == SourceFolderType) || (sourceType == SourceSmartFolderType) || (sourceType == SourceSearchType)) { container = [sources containerAtIndex: [sourceTableView selectedRow]]; index = [librarySource indexOfUniqueNumber: [container uniqueNumberAtIndex: row]]; } ItemType type = [librarySource typeOfItemAtIndex: index]; switch (type) { case ItemFileType: { NSString *path = [libraryPath stringByAppendingPathComponent: [librarySource pathOfItemAtIndex: index]]; NSImage *img = [[NSWorkspace sharedWorkspace] iconForFile: path]; return img; } } } #endif return nil; } - (void) tableViewSelectionDidChange: (NSNotification *) not { if ([not object] == itemTableView) { if ([itemTableView numberOfSelectedRows] != 1) { [noteTextView setNoteTextViewEditable: NO]; [noteTextView setString: @""]; return; } //NSLog(@"selection did change %d", [itemTableView selectedRow]); SourceType type = [self _typeOfSelectedSource]; if ([mainWindow firstResponder] == itemTableView) { if (type == SourceNoteType) { /* Move selection in source table into library */ [sourceTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO]; } } unsigned int index = [itemTableView selectedRow];; [itemTableView scrollRowToVisible: index]; if ((type == SourceFolderType) || (type == SourceSmartFolderType) || (type == SourceSearchType)) { id container = [sources containerAtIndex: [sourceTableView selectedRow]]; index = [librarySource indexOfUniqueNumber: [container uniqueNumberAtIndex: index]]; } [self _displaySelectedNote]; if (stackAction == NO) { /* handle back & forward stack */ /* clean record after stack_index */ if ( (stack_index != ([stack count]-1)) && (stack_index != NSNotFound)) { NSRange range = NSMakeRange(stack_index+1, [stack count]-stack_index-1); [stack removeObjectsInRange: range]; } /* add new record */ [stack addObject: [NSNumber numberWithUnsignedInt: [librarySource uniqueNumberAtIndex: index]]]; stack_index = [stack count]-1; } } else if ([not object] == sourceTableView) { unsigned int selectedItemRow = [itemTableView selectedRow]; SourceType type = [self _typeOfSelectedSource]; switch(type) { case SourceNoteType: { [itemTableView reloadData]; unsigned int uid = [sources uniqueNumberAtIndex: [sourceTableView selectedRow]]; [self _selectItemWithUniqueNumber: uid]; break; } case SourceLibraryType: { [itemTableView reloadData]; if (selectedItemRow < [librarySource count]) { [itemTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: selectedItemRow] byExtendingSelection: NO]; } else { [itemTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO]; } break; } case SourceFolderType: case SourceSmartFolderType: case SourceSearchType: { /* Select first item */ id container = [sources containerAtIndex: [sourceTableView selectedRow]]; if (container == nil) { NSLog(@"Internal Error: container cannot be found"); } if (type == SourceSmartFolderType) [container refreshAll]; [itemTableView reloadData]; if ([container count] > -1) { [itemTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO]; } break; } } [self _displaySelectedNote]; } } - (BOOL) selectionShouldChangeInTableView: (NSTableView *) tableView { if (tableView == itemTableView) { //NSLog(@"should change selection %d", [tableView selectedRow]); /* If the note change, refresh Smart Folder */ if ([itemTableView numberOfSelectedRows] != 1) return YES; if ([noteTextView isNoteTextViewEditable] == NO) return YES; SourceType type = [self _typeOfSelectedSource]; if ((type == SourceSmartFolderType) || (type == SourceSearchType)) { unsigned int index = [itemTableView selectedRow]; id container = [sources containerAtIndex: [sourceTableView selectedRow]]; index = [librarySource indexOfUniqueNumber: [container uniqueNumberAtIndex: index]]; NSString *oldNote = [librarySource noteAtIndex: index]; [self _saveSelectedNote]; NSString *newNote = [librarySource noteAtIndex: index]; if ([oldNote isEqualToString: newNote] == NO) { [container refreshAll]; [itemTableView reloadData]; } } else { [self _saveSelectedNote]; } } return YES; } - (void) tableView: (NSTableView *) tableView didDoubleClickIconAtRow: (int) row { if (tableView == itemTableView) { unsigned int index = row; id container; SourceType sourceType = [self _typeOfSelectedSource]; if ((sourceType == SourceFolderType) || (sourceType == SourceSmartFolderType) || (sourceType == SourceSearchType)) { container = [sources containerAtIndex: [sourceTableView selectedRow]]; index = [librarySource indexOfUniqueNumber: [container uniqueNumberAtIndex: row]]; } ItemType type = [librarySource typeOfItemAtIndex: index]; if (type == ItemFileType) { NSString *path = [librarySource fullPathOfItemAtIndex: index]; if ([[NSWorkspace sharedWorkspace] openFile: path] == NO) { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sCannotOpenFile_, path], sOK, nil, nil, nil); } } } } - (BOOL) tableView: (NSTableView *) view shouldEditTableColumn: (NSTableColumn *) column row: (int) row { if (view == sourceTableView) { SourceType type = [sources typeOfSourceAtIndex: row]; switch (type) { case SourceLibraryType: case SourceErrorType: case SourceUnknownType: return NO; case SourceFolderType: case SourceSmartFolderType: case SourceNoteType: case SourceSearchType: return YES; } } return YES; } - (void) tableView: (NSTableView *) tableView mouseDownInHeaderOfTableColumn: (NSTableColumn *) column { id container; if (tableView == itemTableView) { SourceType type = [self _typeOfSelectedSource]; switch (type) { case SourceLibraryType: case SourceNoteType: container = librarySource; break; case SourceFolderType: case SourceSmartFolderType: case SourceSearchType: container = [sources containerAtIndex: [sourceTableView selectedRow]]; break; } if ([[column identifier] isEqualToString: ItemIdentifier]) { if (titleSortingOrder == NSOrderedDescending) { [container sortTitle: NSOrderedAscending]; titleSortingOrder = NSOrderedAscending; } else { [container sortTitle: NSOrderedDescending]; titleSortingOrder = NSOrderedDescending; } } else if ([[column identifier] isEqualToString: TypeIdentifier]) { if (typeSortingOrder == NSOrderedDescending) { [container sortType: NSOrderedAscending]; typeSortingOrder = NSOrderedAscending; } else { [container sortType: NSOrderedDescending]; typeSortingOrder = NSOrderedDescending; } } [itemTableView reloadData]; [self _displaySelectedNote]; } } /* Table view drag and drop */ - (NSDragOperation) tableView: (NSTableView *) tableView validateDrop: (id ) info proposedRow: (int) row proposedDropOperation: (NSTableViewDropOperation) operation { NSDragOperation sourceMask = [info draggingSourceOperationMask]; if (nil == [info draggingSource]) // From other application { if ([tableView tag] == SourceTableViewTag) { /* Only allow to library */ SourceType type = [sources typeOfSourceAtIndex: row]; switch(type) { case SourceLibraryType: [sourceTableView setDropRow: row dropOperation: NSTableViewDropOn]; break; case SourceNoteType: case SourceSearchType: case SourceSmartFolderType: [sourceTableView setDropRow: row dropOperation: NSTableViewDropAbove]; break; case SourceFolderType: break; default: [sourceTableView setDropRow: row dropOperation: NSTableViewDropAbove]; } if (sourceMask & NSDragOperationCopy) return NSDragOperationCopy; #ifdef GNUSTEP // FIXME, weird, but work for GWorkspace else if (sourceMask & NSDragOperationPrivate) return NSDragOperationPrivate; #endif else return NSDragOperationNone; } else { /* go to library source */ [sourceTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO]; [itemTableView setDropRow: [librarySource count] dropOperation: NSTableViewDropAbove]; if (sourceMask & NSDragOperationCopy) return NSDragOperationCopy; #ifdef GNUSTEP // FIXME, weird, but work for GWorkspace else if (sourceMask & NSDragOperationPrivate) return NSDragOperationPrivate; #endif else return NSDragOperationNone; } } else if (itemTableView == [info draggingSource]) // From ItemTableView { if ([tableView tag] == ItemTableViewTag) return NSDragOperationNone; if (sourceMask & NSDragOperationCopy) { if (operation == NSTableViewDropOn) { /* Check whether source accept drop */ SourceType type = [sources typeOfSourceAtIndex: row]; switch(type) { case SourceFolderType: return NSDragOperationCopy; default: return NSDragOperationNone; } } else /* NSTableViewDropAbove */ { return NSDragOperationCopy; } } else return NSDragOperationNone; } else if (sourceTableView == [info draggingSource]) // From SourceTableView { /* only allow from note to folder */ if ([tableView tag] == ItemTableViewTag) return NSDragOperationNone; if (sourceMask & NSDragOperationCopy) { if (operation == NSTableViewDropOn) { /* Check whether source accept drop */ SourceType type = [sources typeOfSourceAtIndex: row]; switch(type) { case SourceFolderType: return NSDragOperationCopy; default: return NSDragOperationNone; } } else /* NSTableViewDropAbove */ { return NSDragOperationNone; } } else return NSDragOperationNone; } else { return NSDragOperationNone; } } - (BOOL) tableView: (NSTableView *) tableView acceptDrop: (id ) info row: (int) row dropOperation: (NSTableViewDropOperation) operation { NSPasteboard *pboard = [info draggingPasteboard]; NSDragOperation sourceMask = [info draggingSourceOperationMask]; MakeTimeStamp; if (nil == [info draggingSource]) // From other application { NSArray *paths = [pboard propertyListForType: NSFilenamesPboardType]; #ifdef GNUSTEP // FIXME, weird, but work for GWorkspace if ((sourceMask & NSDragOperationCopy) || (sourceMask & NSDragOperationPrivate)) #else if (sourceMask & NSDragOperationCopy) #endif { /* Put files into library */ int i, count = [paths count]; unsigned int index, uid; NSString *path, *ratio, *file, *title; ImportFilePanel *panel = [ImportFilePanel sharedPanel]; [panel setProgress: 0]; float *progress; SourceType type; NSModalSession session = [NSApp beginModalSessionForWindow: [panel panel]]; for (i = 0; i < count; i++) { [NSApp runModalSession: session]; file = [paths objectAtIndex: i]; [panel setRatio: [NSString stringWithFormat: @"(%d out of %d)", (i+1), count]]; [panel setFilename: file]; [panel setProgress: ((float)(i+1)/count)]; [[panel panel] display]; index = [librarySource newItemWithFile: file]; if (index == NSNotFound) { [NSApp endModalSession: session]; NSRunAlertPanel(sFileError, [NSString stringWithFormat: sLibraryCorrupted_, [paths objectAtIndex: i]], sOK, nil, nil, nil); session = [NSApp beginModalSessionForWindow: [panel panel]]; continue; } if ([tableView tag] == SourceTableViewTag) { /* Only allow to library */ title = [librarySource titleAtIndex: index]; uid = [librarySource uniqueNumberAtIndex: index]; if (operation == NSTableViewDropAbove) { /* make a copy in sources */ if (row == [sources count]) { [sources newSource: title ofType: SourceNoteType]; } else { [sources newSource: title ofType: SourceNoteType atIndex: row]; } unsigned int sourceIndex = [sources indexOfTitle: title]; [sources setUniqueNumber: uid atIndex: sourceIndex]; } else { type = [sources typeOfSourceAtIndex: row]; switch(type) { case SourceFolderType: { /* Makd a copy in folder */ id container = [sources containerAtIndex: row]; index = [container newTitle: title]; [container setUniqueNumber: uid atIndex: index]; break; } default: break; } } } } [NSApp endModalSession: session]; [[panel panel] performClose: self]; [sources sort]; [sourceTableView reloadData]; [itemTableView reloadData]; if (index != NSNotFound) { [itemTableView scrollRowToVisible: index]; [itemTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: index] byExtendingSelection: NO]; } return YES; } else return NO; } else if (itemTableView == [info draggingSource]) // From self { /* from itemTableView to sourceTableView */ if ([tableView tag] == ItemTableViewTag) return NO; /* use multipleItemsPboardType to test multiple items */ NSArray *numbers = [pboard propertyListForType: MultipleItemsPboardType]; unsigned int index; #if 0 if (titles == nil) { NSString *title = [pboard stringForType: NSStringPboardType]; titles = [NSArray arrayWithObject: title]; } #endif if (sourceMask & NSDragOperationCopy) { if (operation == NSTableViewDropAbove) { NSNumber *number; NSString *title; unsigned int itemIndex, uid; NSEnumerator *e = [numbers objectEnumerator]; while ((number = [e nextObject])) { /* Check whether item is exist */ uid = [number unsignedIntValue]; itemIndex = [librarySource indexOfUniqueNumber: uid]; title = [librarySource titleAtIndex: itemIndex]; if ([sources isDuplicatedTitle: title] == YES) continue; if (row == [sources count]) { [sources newSource: title ofType: SourceNoteType]; } else { [sources newSource: title ofType: SourceNoteType atIndex: row]; } index = [sources indexOfTitle: title]; [sources setUniqueNumber: uid atIndex: index]; } } else { SourceType type = [sources typeOfSourceAtIndex: row]; id container; if (type == SourceFolderType) { NSNumber *number; NSString *title; unsigned int itemIndex, uid; NSEnumerator *e = [numbers objectEnumerator]; container = [sources containerAtIndex: row]; while ((number = [e nextObject])) { uid = [number unsignedIntValue]; itemIndex = [librarySource indexOfUniqueNumber: uid]; title = [librarySource titleAtIndex: itemIndex]; if ([container isDuplicatedTitle: title] == NO) { index = [container newTitle: title]; [container setUniqueNumber: uid atIndex: index]; } } } else return NO; } } [sources sort]; [sourceTableView reloadData]; return YES; } else if (sourceTableView == [info draggingSource]) { /* from note to folder in sourceTableView */ /* single selection */ if ([tableView tag] == ItemTableViewTag) return NO; //NSString *title = [pboard stringForType: NSStringPboardType]; NSNumber *number = [[pboard propertyListForType: MultipleItemsPboardType] objectAtIndex: 0]; unsigned int uid = [number unsignedIntValue]; unsigned int itemIndex = [librarySource indexOfUniqueNumber: uid]; unsigned int index; NSString *title = [librarySource titleAtIndex: itemIndex]; if (sourceMask & NSDragOperationCopy) { if (operation == NSTableViewDropOn) { SourceType type = [sources typeOfSourceAtIndex: row]; id container = [sources containerAtIndex: row]; if (type == SourceFolderType) { if ([container isDuplicatedTitle: title] == NO) { index = [container newTitle: title]; [container setUniqueNumber: uid atIndex: index]; [sources sort]; [sourceTableView reloadData]; [itemTableView reloadData]; return YES; } } } } return NO; } else { return NO; } } - (BOOL) tableView: (NSTableView *) tableView writeRows: (NSArray *) rows toPasteboard: (NSPasteboard *) pboard { unsigned int index; if (tableView == itemTableView) { switch ([rows count]) { case 0: return NO; case 1: { /* Single selection */ index = [[rows objectAtIndex: 0] intValue]; id container; SourceType sourceType = [self _typeOfSelectedSource]; ItemType type; NSString *title; NSString *path; NSString *fullPath; unsigned int itemIndex; unsigned int uid; if ((sourceType == SourceFolderType) || (sourceType == SourceSmartFolderType) || (sourceType == SourceSearchType)) { container = [sources containerAtIndex: [sourceTableView selectedRow]]; } else { container = librarySource; } title = [container titleAtIndex: index]; uid = [container uniqueNumberAtIndex: index]; itemIndex = [librarySource indexOfUniqueNumber: uid]; type = [librarySource typeOfItemAtIndex: itemIndex]; if (type == ItemFileType) { path = [librarySource pathOfItemAtIndex: itemIndex]; fullPath = [librarySource fullPathOfItemAtIndex: itemIndex]; [pboard declareTypes: [NSArray arrayWithObjects: NSStringPboardType, NSFilenamesPboardType, MultipleItemsPboardType, nil] owner: nil]; if ([pboard setPropertyList: [NSArray arrayWithObject: fullPath] forType: NSFilenamesPboardType] == NO) return NO; } else { [pboard declareTypes: [NSArray arrayWithObjects: NSStringPboardType, MultipleItemsPboardType, nil] owner: nil]; } if ([pboard setString: title forType: NSStringPboardType] == NO) return NO; if ([pboard setPropertyList: [NSArray arrayWithObject: [NSNumber numberWithUnsignedInt: uid]] forType: MultipleItemsPboardType] == NO) return YES; return YES; } default: { /* Multiple selection */ unsigned int index; ItemType type; id object; NSEnumerator *e = [rows objectEnumerator]; NSMutableString *titles = [[NSMutableString alloc] init]; NSMutableArray *paths = [[NSMutableArray alloc] init]; //NSMutableArray *itemTitles = [[NSMutableArray alloc] init]; NSMutableArray *itemNumbers = [[NSMutableArray alloc] init]; NSString *title, *path, *fullPath; SourceType sourceType = [self _typeOfSelectedSource]; id container; unsigned int uid, itemIndex; while ((object = [e nextObject])) { index = [object intValue]; if ((sourceType == SourceFolderType) || (sourceType == SourceSmartFolderType) || (sourceType == SourceSearchType)) { container = [sources containerAtIndex: [sourceTableView selectedRow]]; } else { container = librarySource; } title = [container titleAtIndex: index]; uid = [container uniqueNumberAtIndex: index]; itemIndex = [librarySource indexOfUniqueNumber: uid]; type = [librarySource typeOfItemAtIndex: itemIndex]; [titles appendFormat: @"\"%@\",", title]; //[itemTitles addObject: title]; [itemNumbers addObject: [NSNumber numberWithUnsignedInt: uid]]; if (type == ItemFileType) { path = [librarySource pathOfItemAtIndex: itemIndex]; fullPath = [librarySource fullPathOfItemAtIndex: itemIndex]; [paths addObject: fullPath]; } } if ([paths count]) { [pboard declareTypes: [NSArray arrayWithObjects: NSStringPboardType, NSFilenamesPboardType, MultipleItemsPboardType, nil] owner: nil]; if ([pboard setPropertyList: AUTORELEASE(paths) forType: NSFilenamesPboardType] == NO) { /* Clean up */ RELEASE(titles); //RELEASE(itemTitles); RELEASE(itemNumbers); return NO; } } else { [pboard declareTypes: [NSArray arrayWithObjects: NSStringPboardType, MultipleItemsPboardType, nil] owner: nil]; } if ([pboard setString: AUTORELEASE(titles) forType: NSStringPboardType] == NO) { //RELEASE(itemTitles); RELEASE(itemNumbers); return NO; } if ([pboard setPropertyList: itemNumbers /*itemTitles */ forType: MultipleItemsPboardType] == NO) { return NO; } return YES; } } } else if (tableView == sourceTableView) { /* Single selection */ index = [[rows objectAtIndex: 0] intValue]; SourceType type; NSString *title; unsigned int uid; title = [sources titleAtIndex: index]; uid = [sources uniqueNumberAtIndex: index]; type = [sources typeOfSourceAtIndex: index]; if ((type == SourceLibraryType) || (type == SourceFolderType) || (type == SourceSmartFolderType) || (type == SourceSearchType)) { return NO; } [pboard declareTypes: [NSArray arrayWithObjects: NSStringPboardType, MultipleItemsPboardType, nil] owner: nil]; if ([pboard setString: title forType: NSStringPboardType] == NO) return NO; if ([pboard setPropertyList: [NSArray arrayWithObject: [NSNumber numberWithUnsignedInt: uid]] forType: MultipleItemsPboardType] == NO) return NO; return YES; } } /* Split limit */ - (float) splitView: (NSSplitView *) sender constrainMinCoordinate: (float) proposedMin ofSubviewAt: (int) offset { if ((sender == sourceSplitView) && (proposedMin < 200.0)) return 100.0; return proposedMin; } /* application delegate */ - (BOOL) validateMenuItem: (NSMenuItem *) item { SourceType type = [self _typeOfSelectedSource]; NSString *title = [item title]; if (([title isEqualToString: sIndexingMenu]) && (type != SourceLibraryType)) return NO; if (([title isEqualToString: sEditSmartFolderMenu]) && (type != SourceSmartFolderType)) return NO; if (([title isEqualToString: sRemoveMenu]) && (type == SourceSmartFolderType) && ([mainWindow firstResponder] != sourceTableView)) return NO; return YES; } - (void) awakeFromNib { ASSIGN(sources, [Sources sharedSources]); ASSIGN(librarySource, [LibrarySource sharedSource]); ASSIGN(attributesSource, [AttributesSource sharedSource]); [sourceTableView setTag: SourceTableViewTag]; [itemTableView setTag: ItemTableViewTag]; [noteTextView setTag: NoteTextViewTag]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; BOOL editable = [defaults boolForKey: NoteTextViewEditable]; [noteTextView setNoteTextViewEditable: editable]; #ifdef GNUSTEP [noteTextView registerForDraggedTypes: [NSArray arrayWithObjects: NSStringPboardType, nil]]; #endif [sourceTableView registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, NSStringPboardType, MultipleItemsPboardType, nil]]; [itemTableView registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; titleSortingOrder = NSOrderedDescending; typeSortingOrder = NSOrderedDescending; /* set up toolbar */ toolbar = [(NSToolbar *)[NSToolbar alloc] initWithIdentifier: SearchToolbarIdentifier]; [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel]; [toolbar setAllowsUserCustomization: NO]; [toolbar setDelegate: self]; [mainWindow setToolbar: toolbar]; BOOL isVisible = [defaults boolForKey: SearchBarIsVisible]; [toolbar setVisible: isVisible]; } - (void) applicationWillFinishLaunching: (NSNotification *) not { /* if not terminate normally, don't save library */ terminateNormally = YES; /* Check library location */ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *path = [defaults stringForKey: LibraryLocationPath]; stack_index = NSNotFound; /* set up library path */ ASSIGN(libraryPath, MyLibraryPath(path)); /* make sure library directory is properly set up */ BOOL isDir; if ([fm fileExistsAtPath: libraryPath isDirectory: &isDir]) { if (isDir == NO) { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sLibraryCannotBeCreated_, libraryPath], sQuit, nil, nil, nil); terminateNormally = NO; [NSApp terminate: self]; } } else { int result = NSRunAlertPanel(sCreateLibrary, [NSString stringWithFormat: sLibraryWillBeCreated_, libraryPath], sOK, sCancelAndQuit, nil, nil); if (result != NSAlertDefaultReturn) { terminateNormally = NO; [NSApp terminate: self]; } if ([fm createDirectoryAtPath: libraryPath attributes: nil] == NO) { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sLibraryCannotBeCreated_, libraryPath], sQuit, nil, nil, nil); terminateNormally = NO; [NSApp terminate: self]; } } } - (void) applicationDidFinishLaunching: (NSNotification *) not { if ([self _loadLibraryAtPath: libraryPath] == NO) { terminateNormally = NO; [NSApp terminate: self]; } } - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) sender { if (terminateNormally == YES) { [self _saveSelectedNote]; if ([self _unloadLibrary] == NO) { return NSTerminateCancel; } } /* syn user defaults */ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject: MyLibraryPath(nil) forKey: LibraryLocationPath]; [defaults synchronize]; return NSTerminateNow; } - (void) applicationWillTerminate: (NSNotification *) not { } /* menu actions */ - (void) mainLibraryAction: (id) sender { [mainWindow makeKeyAndOrderFront: sender]; } - (void) attributesViewerAction: (id) sender { id container = nil; SourceType type = [self _typeOfSelectedSource]; unsigned int index = [itemTableView selectedRow]; if (index == NSNotFound) return; /* Only select one item */ [itemTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: index] byExtendingSelection: NO]; if ((type == SourceFolderType) || (type == SourceSmartFolderType) || (type == SourceSearchType)) { container = [sources containerAtIndex: [sourceTableView selectedRow]]; index = [librarySource indexOfUniqueNumber: [container uniqueNumberAtIndex: index]]; } NSString *path = [librarySource pathOfItemAtIndex: index]; if (path == nil) return; AttributesViewer *viewer = [AttributesViewer sharedViewer]; #if 0 [viewer setTitleOfViewer: [librarySource titleAtIndex: index]]; [viewer setTitleOfAttributes: path]; #endif [viewer setUniqueNumber: [librarySource uniqueNumberAtIndex: index]]; [viewer makeViewerKeyAndOrderFront: sender]; MakeTimeStamp; /* refresh source */ if (container) { [container refreshAll]; [itemTableView reloadData]; } /* Update all attributes */ [self _updateAllAvailableSubjectsInSearchCriterion]; } - (void) newFolderAction: (id) sender { unsigned int acc = 0; NSString *title = @"New Folder"; NSString *proposedTitle = @"New Folder"; while(1) { acc++; if (([sources isDuplicatedTitle: proposedTitle] == YES) || ([librarySource isDuplicatedTitle: proposedTitle] == YES)) proposedTitle = [title stringByAppendingFormat: @" %d", acc]; else break; } MakeTimeStamp; [sources newSource: proposedTitle ofType: SourceFolderType]; /* Create folder container */ unsigned int index = [sources indexOfTitle: proposedTitle]; FolderSource *folder = [[FolderSource alloc] init]; [sources setContainer: AUTORELEASE(folder) atIndex: index]; [sources setResourcePath: [proposedTitle stringByAppendingPathExtension: @"plist"] atIndex: index]; [sourceTableView reloadData]; [sourceTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: index] byExtendingSelection: NO]; [sourceTableView editColumn: 0 row: index withEvent: nil select: YES]; [self _updateAvailableSelectionsForSource]; } - (void) newSmartFolderAction: (id) sender { unsigned int acc = 0; NSString *title = @"New Smart Folder"; NSString *proposedTitle = @"New SmartFolder"; while(1) { acc++; if (([sources isDuplicatedTitle: proposedTitle] == YES) || ([librarySource isDuplicatedTitle: proposedTitle] == YES)) proposedTitle = [title stringByAppendingFormat: @" %d", acc]; else break; } MakeTimeStamp; [sources newSource: proposedTitle ofType: SourceSmartFolderType]; /* Create folder container */ unsigned int index = [sources indexOfTitle: proposedTitle]; SmartFolderSource *folder = [[SmartFolderSource alloc] init]; [sources setContainer: AUTORELEASE(folder) atIndex: index]; [sources setResourcePath: [proposedTitle stringByAppendingPathExtension: @"plist"] atIndex: index]; [sourceTableView reloadData]; /* Automatically edit smart folder */ [sourceTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: index] byExtendingSelection: NO]; [self editSmartFolderAction: self]; [sourceTableView editColumn: 0 row: index withEvent: nil select: YES]; [self _updateAvailableSelectionsForSource]; } - (void) editSmartFolderAction: (id) sender { unsigned int index = [sourceTableView selectedRow]; SourceType type = [sources typeOfSourceAtIndex: index]; if (type != SourceSmartFolderType) return; MakeTimeStamp; NSString *title = [sources titleAtIndex: index]; SmartFolderSource *source = [sources containerAtIndex: index]; SmartFolderEditor *editor = [SmartFolderEditor sharedEditor]; [editor setTitle: title]; [editor setCriterion: [source criterion]]; [editor makeEditorKeyAndOrderFront: self]; /* Update smart folder */ //NSLog(@"Update smart folder"); [source refreshAll]; [itemTableView reloadData]; } - (void) newNoteAction: (id) sender { MakeTimeStamp; unsigned int index = [librarySource newItem]; [sourceTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO]; [itemTableView reloadData]; if (index != NSNotFound) { [itemTableView scrollRowToVisible: index]; [itemTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: index] byExtendingSelection: NO]; } } - (void) editNoteAction: (id) sender { if ([itemTableView numberOfSelectedRows] != 1) return; // Multiple selection or null selection NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; if ([noteTextView isNoteTextViewEditable] == YES) { /* Save note first */ [self _saveSelectedNote]; [noteTextView setNoteTextViewEditable: NO]; [defaults setBool: NO forKey: NoteTextViewEditable]; } else { [noteTextView setNoteTextViewEditable: YES]; [defaults setBool: YES forKey: NoteTextViewEditable]; } [self _displaySelectedNote]; } - (void) removeItemAction: (id) sender { //NSLog(@"firstResponder %@", [mainWindow firstResponder]); MakeTimeStamp; if ([mainWindow firstResponder] == itemTableView) { SourceType type = [self _typeOfSelectedSource]; switch(type) { case SourceLibraryType: case SourceNoteType: { BOOL result = NSRunAlertPanel(sWarning, sSelectedItemRemoveFromHD, sOK, sCancel, nil, nil); if (result != NSAlertDefaultReturn) { return; } } } NSIndexSet *selectedRowIndexes = [itemTableView selectedRowIndexes]; unsigned int maxCount = [selectedRowIndexes count]; unsigned int *buffer = malloc(sizeof(unsigned int) * maxCount); unsigned int index; int i; id container; #ifdef GNUSTEP container = [sources containerAtIndex: [sourceTableView selectedRow]]; if (container == nil) { container = librarySource; } NSRange r = NSMakeRange(0, [container count]); unsigned int result = [selectedRowIndexes getIndexes: buffer maxCount: maxCount inIndexRange: &r]; #else unsigned int result = [selectedRowIndexes getIndexes: buffer maxCount: maxCount inIndexRange: NULL]; #endif unsigned int sourceIndex, attrIndex; unsigned int uid; NSString *title, *path, *fullPath; for(i = maxCount-1; i > -1; i--) { index = *(buffer+i); // NSLog(@"index %d", index); switch (type) { case SourceLibraryType: case SourceNoteType: title = [librarySource titleAtIndex: index]; uid = [librarySource uniqueNumberAtIndex: index]; path = [librarySource pathOfItemAtIndex: index]; fullPath = [librarySource fullPathOfItemAtIndex: index]; attrIndex = [attributesSource indexOfUniqueNumber: uid]; [attributesSource removeObjectAtIndex: attrIndex]; [self _removeItemWithUniqueNumber: uid]; /* Try to remove empty directory if possible */ unsigned int j, jcount = 3; for(j = 0; j < jcount; j++) { fullPath = [fullPath stringByDeletingLastPathComponent]; if ([[fm directoryContentsAtPath: fullPath] count] == 0) { [fm removeFileAtPath: fullPath handler: nil]; } else { break; } } break; case SourceFolderType: container = [sources containerAtIndex: [sourceTableView selectedRow]]; [container removeObjectAtIndex: index]; break; default: return; } } free(buffer); [itemTableView reloadData]; [itemTableView deselectAll: self]; [sourceTableView reloadData]; [self _updateAllAvailableSubjectsInSearchCriterion]; } else if ([mainWindow firstResponder] == sourceTableView) { int selectedRow = [sourceTableView selectedRow]; SourceType type = [sources typeOfSourceAtIndex: selectedRow]; switch (type) { case SourceNoteType: { [sources removeObjectAtIndex: selectedRow]; break; } case SourceFolderType: case SourceSmartFolderType: { int result = NSRunAlertPanel(sWarning, [NSString stringWithFormat: sRemoveFolder_, [sources titleAtIndex: selectedRow]], sOK, sCancel, nil, nil); if (result == NSAlertDefaultReturn) { /* remove plist files */ NSString *path = [sources resourceFullPathAtIndex: selectedRow]; NSLog(@"delete path %@", path); [fm removeFileAtPath: path handler: nil]; /* remove backup */ path = [path stringByAppendingString: @"~"]; [fm removeFileAtPath: path handler: nil]; [sources removeObjectAtIndex: selectedRow]; [self _updateAvailableSelectionsForSource]; } break; } } [sourceTableView reloadData]; } } - (void) importFileAction: (id) sender { int result; unsigned int index; NSOpenPanel *panel = [NSOpenPanel openPanel]; [panel setCanChooseDirectories: YES]; [panel setAllowsMultipleSelection:YES]; result = [panel runModalForDirectory: nil file: nil types: nil]; if (result == NSOKButton) { MakeTimeStamp; NSArray *files = [panel filenames]; NSString *filename; unsigned int i, count = [files count]; ImportFilePanel *panel = [ImportFilePanel sharedPanel]; [panel setProgress: 0]; NSString *ratio; float *progress; NSModalSession session = [NSApp beginModalSessionForWindow: [panel panel]]; for (i = 0; i < count; i++) { [NSApp runModalSession: session]; filename = [files objectAtIndex: i]; [panel setRatio: [NSString stringWithFormat: @"(%d out of %d)", (i+1), count]]; [panel setFilename: filename]; [panel setProgress: ((float)(i+1)/count)]; [[panel panel] display]; index = [librarySource newItemWithFile: filename]; } //NSLog(@"end session"); [NSApp endModalSession: session]; [[panel panel] performClose: self]; } //NSLog(@"OK"); [itemTableView reloadData]; if (index != NSNotFound) { [itemTableView scrollRowToVisible: index]; [itemTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: index] byExtendingSelection: NO]; } } - (void) backAction: (id) sender { // NSLog(@"stack_index %d", stack_index); // NSLog(@"%@", stack); /* set itemTableView as first responder */ [mainWindow makeFirstResponder: itemTableView]; if (stack_index == 0) return; stack_index--; stackAction = YES; unsigned int uid = [[stack objectAtIndex: stack_index] unsignedIntValue]; [self _selectItemWithUniqueNumber: uid]; stackAction = NO; } - (void) forwardAction: (id) sender { // NSLog(@"stack_index %d", stack_index); // NSLog(@"%@", stack); /* set itemTableView as first responder */ [mainWindow makeFirstResponder: itemTableView]; if ((stack_index+1) >= [stack count]) return; stack_index++; stackAction = YES; unsigned int uid = [[stack objectAtIndex: stack_index] unsignedIntValue]; [self _selectItemWithUniqueNumber: uid]; stackAction = NO; } - (void) showFileAction: (id) sender { unsigned int index = [itemTableView selectedRow]; SourceType sourceType = [self _typeOfSelectedSource]; id container; if ((sourceType == SourceFolderType) || (sourceType == SourceSmartFolderType) || (sourceType == SourceSearchType)) { container = [sources containerAtIndex: [sourceTableView selectedRow]]; index = [librarySource indexOfUniqueNumber: [container uniqueNumberAtIndex: index]]; } ItemType type = [librarySource typeOfItemAtIndex: index]; if (type == ItemFileType) { NSString *path = [librarySource fullPathOfItemAtIndex: index]; [[NSWorkspace sharedWorkspace] selectFile: path inFileViewerRootedAtPath: @""]; } } - (void) searchBarAction: (id) sender { [mainWindow toggleToolbarShown: sender]; BOOL isVisible = [toolbar isVisible]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setBool: isVisible forKey: SearchBarIsVisible]; } - (void) summaryViewerAction: (id) sender { SummaryViewer *viewer = [SummaryViewer sharedViewer]; [viewer setDelegate: self]; unsigned int index = [sourceTableView selectedRow]; NSString *title = [sources titleAtIndex: index]; [viewer setTitle: title]; NSIndexSet *selectedRowIndexes = [itemTableView selectedRowIndexes]; /* Save note */ if (([selectedRowIndexes count] == 1) && ([noteTextView isNoteTextViewEditable] == YES)) { [self _saveSelectedNote]; } id container; SummaryStyle summaryStyle = [viewer summaryStyle]; int maxAttr; switch(summaryStyle) { case SummaryBriefStyle: maxAttr = 10; break; case SummaryRegularStyle: maxAttr = 20; break; case SummaryCompleteStyle: maxAttr = -1; break; } NSMutableAttributedString *as = [[NSMutableAttributedString alloc] init]; NSAttributedString *a; NSAttributedString *space = [[NSAttributedString alloc] initWithString: @"\n\n"]; AUTORELEASE(space); SourceType type = [self _typeOfSelectedSource]; switch(type) { case SourceFolderType: case SourceSmartFolderType: case SourceSearchType: container = [sources containerAtIndex: [sourceTableView selectedRow]]; break; case SourceLibraryType: container = librarySource; break; default: return; } /* display summary of selected notes */ unsigned int maxCount = [selectedRowIndexes count]; unsigned int *buffer = malloc(sizeof(unsigned int) * maxCount); unsigned int i, uid; NSColor *color; NSRange range; #ifdef GNUSTEP NSRange r = NSMakeRange(0, [container count]); [selectedRowIndexes getIndexes: buffer maxCount: maxCount inIndexRange: &r]; #else [selectedRowIndexes getIndexes: buffer maxCount: maxCount inIndexRange: NULL]; #endif for(i = 0; i < maxCount; i++) { index = *(buffer+i); uid = [container uniqueNumberAtIndex: index]; index = [librarySource indexOfUniqueNumber: uid]; range.location = [as length]; a = [librarySource summaryAtIndex: index maximalAttributes: maxAttr style: summaryStyle]; [as appendAttributedString: a]; [as appendAttributedString: space]; range.length = [as length] - range.location; if ((i % 2) == 0) { color = [NSColor whiteColor]; } else { color = [NSColor colorWithCalibratedRed: 1 green: 1 blue: 0.6 alpha: 1]; } [as addAttribute: NSBackgroundColorAttributeName value: color range: range]; } [viewer setSummary: as]; AUTORELEASE(as); [viewer makeViewerKeyAndOrderFront: self]; } - (void) indexingAction: (id) sender { ContentIndexer *indexer = [ContentIndexer sharedIndexer]; SourceType type = [self _typeOfSelectedSource]; NSString *path; switch(type) { case SourceLibraryType: path = [libraryPath stringByAppendingPathComponent: ContentIndexDirectory]; break; default: return; } [indexer setIndexLocation: path]; [indexer makeIndexerKeyAndOrderFront: sender]; MakeTimeStamp; } - (void) libraryLocationAction: (id) sender { int result; NSString *original, *path; LibraryLocationPanel *locationPanel = [LibraryLocationPanel sharedPanel]; result = [locationPanel makePanelKeyAndOrderFront: sender]; if (result == NSCancelButton) return; path = [locationPanel libraryLocationPath]; if ([path isEqualToString: MyLibraryPath(nil)]) return; path = [path stringByStandardizingPath]; /* make sure library directory is properly set up */ BOOL isDir; if ([fm fileExistsAtPath: path isDirectory: &isDir]) { if (isDir == NO) { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sNotValidLibrary_, path], sOK, nil, nil, nil); return; } } else { int result = NSRunAlertPanel(sCreateLibrary, [NSString stringWithFormat: sLibraryWillBeCreated_, path], sOK, sCancel, nil, nil); if (result != NSAlertDefaultReturn) { return; } if ([fm createDirectoryAtPath: path attributes: nil] == NO) { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sLibraryCannotBeCreated_, path], sOK, nil, nil, nil); return; } } original = [MyLibraryPath(nil) copy]; AUTORELEASE(original); //NSLog(@"original %@", original); /* Unload current one */ [self _unloadLibrary]; //NSLog(@"library unloaded"); /* Try to load new one */ MyLibraryPath(path); if ([self _loadLibraryAtPath: path] == NO) { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sLibraryCannotBeLoaded_, path], sOK, nil, nil, nil); MyLibraryPath(original); if ([self _loadLibraryAtPath: original] == NO) { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sLibraryCannotBeLoaded_, original], sQuit, nil, nil, nil); terminateNormally = NO; [NSApp terminate: self]; } } } /* Window methods */ - (NSString *) windowNibName { return @"MyDocument"; } /* Basic methods */ - (id) init { self = [super init]; searchCriterion = [[Criterion alloc] init]; /* Try to get all subject */ [searchCriterion addAvailableSubject: sTitle forType: CriterionStringType]; if ([searchCriterion count] < 1) { /* Add first criterion */ [searchCriterion addCriterionWithSubject: sTitle verb: CriterionContainsVerb object: @""]; } stack = [[NSMutableArray alloc] init]; searchSource = nil; ASSIGN(fm, [NSFileManager defaultManager]); return self; } - (void) dealloc { RELEASE(stack); RELEASE(sources); RELEASE(librarySource); RELEASE(searchSource); RELEASE(attributesSource); RELEASE(toolbar); RELEASE(searchCriterion); RELEASE(fm); [super dealloc]; } @end