#include "MyDocument.h"
#include "GNUstep.h"
#include "CalendarView.h"
@implementation MyDocument
- (void) calendarViewSelectionDidChange: (NSNotification *) not
{
NSCalendarDate *date = [[not object] date];
NSArray *titles = [dataSource titlesCreatedOnDate: date];
NSEnumerator *e = [titles objectEnumerator];
id object;
NSMutableString *result = [[NSMutableString alloc] init];;
[result appendString: [NSString stringWithFormat: @"%@
\n", [date descriptionWithCalendarFormat: DateFormat]]];
while ((object = [e nextObject]))
{
[result appendString: [NSString stringWithFormat: @"%@\n\n", object]];
}
[dataSource setContent: AUTORELEASE([result copy])
withTitle: JournalTitle];
//[editButton setState: NSOffState];
[tableView reloadData];
[self selectTitle: JournalTitle];
[self updateTextView];
}
- (void) calendarView: (CalendarView *) view
willDisplayCell: (id) cell
ofDate: (NSCalendarDate *) date
{
if ([dataSource hasContentCreatedOnDate: date] == YES)
{
[cell setBordered: YES];
//[cell setBezeled: YES];
[cell setBezelStyle: NSShadowlessSquareBezelStyle];
//[cell setGradientType: NSGradientConcaveStrong];
}
}
- (BOOL) selectTitle: (NSString *) title
{
unsigned int row = [dataSource indexOfTitle: title];
if (row == -1) return NO;
#ifdef GNUSTEP
[tableView selectRow: row
byExtendingSelection: NO];
#else
[tableView selectRowIndexes: [NSIndexSet indexSetWithIndex: row]
byExtendingSelection: NO];
#endif
return YES;
}
- (IBAction)homeAction:(id)sender
{
if ([self selectTitle: HomeTitle] == NO)
{
#ifdef GNUSTEP
[tableView selectRow: 0
byExtendingSelection: NO];
#else
[tableView selectRowIndexes: [NSIndexSet indexSetWithIndex: 0]
byExtendingSelection: NO];
#endif
}
}
- (IBAction)backAction:(id)sender
{
historyIndex--;
if (historyIndex < 1) // Reach to the first
[backButton setEnabled: NO];
[forwardButton setEnabled: YES];
backOrForwardAction = YES;
[self selectTitle: [history objectAtIndex: historyIndex]];
}
- (IBAction)forwardAction:(id)sender
{
historyIndex++;
if (historyIndex >= [history count]-1)
[forwardButton setEnabled: NO];
[backButton setEnabled: YES];
backOrForwardAction = YES;
[self selectTitle: [history objectAtIndex: historyIndex]];
}
- (IBAction)addAction:(id)sender
{
NSString *title = @"New Page";
int row;
if ([dataSource indexOfTitle: title] != NSNotFound)
{
// Find avaiable title
int i;
for(i = 1;;i++)
{
title = [NSString stringWithFormat: @"New Page %d", i];
if ([dataSource indexOfTitle: title] == NSNotFound)
break;
}
}
[dataSource setContent: @"Put new content here" withTitle: title];
[tableView reloadData];
[self selectTitle: title];
row = [dataSource indexOfTitle: title];
[tableView editColumn: 0 row: row withEvent: nil select: YES];
}
- (IBAction)deleteAction:(id)sender
{
unsigned int row = [tableView selectedRow];
if (row == -1)
return;
NSString *title = [dataSource titleAtIndex: row];
if ([dataSource canRemoveContentOfTitle: title] == NO)
return;
int result = NSRunAlertPanel(@"Delete page ?",
[NSString stringWithFormat: @"\"%@\" will be deleted. Are you sure ?", title],
@"Delete", @"Don't Delete", nil, nil);
if (result != NSAlertDefaultReturn)
return;
[dataSource removeContentOfTitle: title];
[tableView reloadData];
// Remove the history associated with the delete page
int i, count = [history count];;
for (i = count-1; i > -1; i--)
{
if ([[history objectAtIndex: i] isEqualToString: title])
{
[history removeObjectAtIndex: i];
historyIndex--;
}
}
//NSLog(@"deleteAction %@ %d", history, historyIndex);
row--;
if (row < 0) row = 0;
#ifdef GNUSTEP
[tableView selectRow: row
byExtendingSelection: NO];
#else
[tableView selectRowIndexes: [NSIndexSet indexSetWithIndex: row]
byExtendingSelection: NO];
#endif
}
- (IBAction)searchAction:(id)sender
{
NSString *searchString = [[sender stringValue] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
if ((searchString == nil) ||
([searchString isEqualToString: @""]))
{
return;
}
NSEnumerator *e = [[dataSource titles] objectEnumerator];
id object, content;
NSRange range;
NSMutableString *searchResult = [[NSMutableString alloc] init];;
[searchResult appendString: [NSString stringWithFormat: @"These pages contains \"%@\"
\n", searchString]];
while ((object = [e nextObject]))
{
if ([object isEqualToString: SearchResultTitle])
continue;
if ([object isEqualToString: JournalTitle])
continue;
content = [[dataSource renderWithTitle: object] string];
range = [content rangeOfString: searchString
options: NSCaseInsensitiveSearch];
if (range.location == NSNotFound)
continue;
else
{
[searchResult appendString: [NSString stringWithFormat: @"%@\n\n", object]];
}
}
[dataSource setContent: AUTORELEASE([searchResult copy])
withTitle: SearchResultTitle];
//[editButton setState: NSOffState];
[tableView reloadData];
[self selectTitle: SearchResultTitle];
[self updateTextView];
}
- (IBAction)calendarAction:(id)sender
{
BOOL state = [sender state];
NSRect frame;
id scrollView = [[tableView superview] superview];
id view = [scrollView superview];
if (state == NSOnState)
{
// Put on CalendarView
if ([calendarView superview] != nil)
{
// Already put on, do nothing
}
else
{
//NSLog(@"%@", [[[tableView superview] superview] superview]);
frame = NSMakeRect(0,
[calendarView bounds].size.height+8,
[view bounds].size.width,
[view bounds].size.height-[calendarView frame].size.height-8);
[scrollView setFrame: frame];
frame = NSMakeRect(0, 0,
[view bounds].size.width,
[calendarView frame].size.height);
[calendarView setFrame: frame];
[view addSubview: calendarView];
RELEASE(calendarView);
[view setNeedsDisplay: YES];
}
}
else
{
// Take off CalendarView
if ([calendarView superview] == nil)
{
// Already take off, do nothing
}
else
{
RETAIN(calendarView);
[calendarView removeFromSuperview];
[scrollView setFrame: [view bounds]];
}
}
}
- (BOOL) textView: (NSTextView *) aView clickedOnLink: (id) link
atIndex: (unsigned) 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]];
backOrForwardAction = NO;
// Create new page if not existed
NSEnumerator *e = [[dataSource titles] objectEnumerator];
NSString *key;
BOOL isPageExisted = NO;
unsigned int i = 0;
while ((key = [e nextObject]))
{
if ([key caseInsensitiveCompare: string] == NSOrderedSame)
{
isPageExisted = YES;
break;
}
i++;
}
if (isPageExisted == NO)
{
//NSLog(@"Create page \"%@\"", string);
[dataSource setContent: @"Put new content here" withTitle: string];
[tableView reloadData];
[self selectTitle: string];
}
else
{
#ifdef GNUSTEP
[tableView selectRow: i
byExtendingSelection: NO];
#else
[tableView selectRowIndexes: [NSIndexSet indexSetWithIndex: i]
byExtendingSelection: NO];
#endif
}
return YES;
}
else if ([attribute hasPrefix: @"<"])
{
NSLog(@"Email to %@", attribute);
return YES;
}
else // Assume it is a file
{
// Should handle saving file first
NSString *fullpath = [NSString stringWithFormat: @"%@/%@", [self fileName], attribute];
NSLog(@"Open file \"%@\"", fullpath);
return [[NSWorkspace sharedWorkspace] openFile: fullpath];
}
}
return NO;
}
- (void) updateTextView
{
if ([editButton state] == NSOnState)
{
[textView setString: [dataSource sourceWithTitle: index]];
}
else
{
NSAttributedString *as = [dataSource renderWithTitle: index];
[[textView textStorage] setAttributedString: as];
}
}
- (void) tableViewSelectionDidChange: (NSNotification *) not
{
// Render text
int selectedRow = [[not object] selectedRow];
if (selectedRow == -1) return;
ASSIGN(index, [dataSource titleAtIndex: selectedRow]);
if (([index isEqualToString: [history lastObject]] == NO) &&
(backOrForwardAction == NO))
{
[history removeObjectsInRange: NSMakeRange(historyIndex+1, [history count]-historyIndex-1)];
[history addObject: AUTORELEASE([index copy])];
historyIndex = [history count]-1;
[forwardButton setEnabled: NO];
if ([history count] > 1)
[backButton setEnabled: YES];
else
[backButton setEnabled: NO];
}
backOrForwardAction = NO;
if ([dataSource canRemoveContentOfTitle: index] == NO)
[deleteButton setEnabled: NO];
else
[deleteButton setEnabled: YES];
if ([dataSource canEditContentOfTitle: index] == NO)
{
[editButton setState: NSOffState];
[editButton setEnabled: NO];
}
else
[editButton setEnabled: YES];
if ([editButton state] == NSOnState)
{
[textView setString: [dataSource sourceWithTitle: index]];
[textView setBackgroundColor: [NSColor yellowColor]];
[textView setEditable: YES];
}
else
{
NSAttributedString *as = [dataSource renderWithTitle: index];
[[textView textStorage] setAttributedString: as];
[textView setBackgroundColor: [NSColor whiteColor]];
[textView setEditable: NO];
}
}
- (int) numberOfRowsInTableView: (NSTableView *) aTableView
{
return [dataSource numberOfPages];
}
- (id) tableView: (NSTableView *) view
iconForTableColumn: (NSTableColumn *) column
row: (int) row;
{
NSString *t = [dataSource titleAtIndex: row];;
NSImage *image;
NSCell *cell = [column dataCellForRow: row];
#ifdef GNUSTEP
if([t isEqualToString: HomeTitle])
image = [NSImage imageNamed: @"Home12black.png"];
else if ([t isEqualToString: SearchResultTitle])
image = [NSImage imageNamed: @"Search12black.png"];
else if ([t isEqualToString: JournalTitle])
image = [NSImage imageNamed: @"Journal12black.png"];
else
image = [NSImage imageNamed: @"Page12black.png"];
#else
if (([[view window] isKeyWindow] == YES) &&
((([view selectedRow] == row) &&
([[view window] firstResponder] == view)) ||
(row == [view editedRow])))
{
if([t isEqualToString: HomeTitle])
image = [NSImage imageNamed: @"Home12white.png"];
else if ([t isEqualToString: SearchResultTitle])
image = [NSImage imageNamed: @"Search12white.png"];
else if ([t isEqualToString: JournalTitle])
image = [NSImage imageNamed: @"Journal12white.png"];
else
image = [NSImage imageNamed: @"Page12white.png"];
}
else
{
if([t isEqualToString: HomeTitle])
image = [NSImage imageNamed: @"Home12black.png"];
else if ([t isEqualToString: SearchResultTitle])
image = [NSImage imageNamed: @"Search12black.png"];
else if ([t isEqualToString: JournalTitle])
image = [NSImage imageNamed: @"Journal12black.png"];
else
image = [NSImage imageNamed: @"Page12black.png"];
}
#endif
return image;
}
- (id) tableView: (NSTableView *) aTableView
objectValueForTableColumn: (NSTableColumn *) aTableColumn
row: (int) rowIndex
{
NSString *title = [dataSource titleAtIndex: rowIndex];
if ([title isEqualToString: SearchResultTitle] == YES)
return @"Search Result";
else if ([title isEqualToString: JournalTitle] == YES)
return @"Journal";
else
return title;
}
- (void) tableView:(NSTableView *)aTableView setObjectValue:(id)anObject
forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
unsigned int titleIndex;
NSString *newTitle, *oldTitle = [[dataSource titleAtIndex: rowIndex] copy];
newTitle = [anObject stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
if ([oldTitle isEqualToString: anObject])
{
return;
}
titleIndex = [dataSource indexOfTitle: newTitle];
if (titleIndex != NSNotFound)
{
NSRunAlertPanel(@"Title Conflict",
[NSString stringWithFormat: @"Title \"%@\" already exist, please use another name", anObject],
@"OK", nil, nil, nil);
[aTableView editColumn: 0 row: rowIndex withEvent: nil select: YES];
return;
}
//NSLog(@"%@", newTitle);
isDocumentEdited = YES;
[window setDocumentEdited: YES];
[dataSource replaceTitle: oldTitle withTitle: newTitle];
// Replace all the link with new title
int result = NSAlertDefaultReturn;
if ([dataSource isLinkedByOthers: oldTitle] == YES)
{
result= NSRunInformationalAlertPanel(@"Update link ?",
@"The title of this page is changed. Do you want to update all the links to this page ?", @"Update", @"Don't Update", nil, nil);
}
if (result == NSAlertDefaultReturn)
{
// Yes to replace
//NSLog(@"update all the link");
[dataSource replaceContentOfLink: oldTitle withString: newTitle];
}
RELEASE(oldTitle);
[tableView reloadData];
}
- (BOOL) tableView: (NSTableView *) aTableView
shouldEditTableColumn: (NSTableColumn *) aTableColumn
row: (int) rowIndex
{
if (rowIndex == 0) return NO;
return YES;
}
- (BOOL) tableView:(NSTableView *)tableView
writeRows:(NSArray *)rows
toPasteboard:(NSPasteboard *)pboard
{
if ([rows count] < 0) return NO;
int row = [[rows objectAtIndex: 0] intValue];
NSString *title = [dataSource titleAtIndex: row];
[pboard declareTypes: [NSArray arrayWithObject: NSStringPboardType]
owner: nil];
return [pboard setString: [NSString stringWithFormat: @"%@", title]
forType: NSStringPboardType];
}
- (float) splitView: (NSSplitView *) sender
constrainMinCoordinate: (float) proposedMin
ofSubviewAt: (int) offset
{
if (proposedMin < 130)
return 130;
else
return proposedMin;
}
- (BOOL) splitView: (NSSplitView *) sender
canCollapseSubview: (NSView *) subview
{
return YES;
}
// Copy the backup to the file name
- (BOOL)writeToFile:(NSString *)fullDocumentPath
ofType:(NSString *)docType
originalFile:(NSString *)fullOriginalDocumentPath
saveOperation:(NSSaveOperationType)saveOperationType
{
if (fullOriginalDocumentPath == nil)
{
return [super writeToFile: fullDocumentPath
ofType: docType
originalFile: fullOriginalDocumentPath
saveOperation: saveOperationType];
}
else
{
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL succeed;
if ([fileManager fileExistsAtPath: fullDocumentPath])
{
succeed = [fileManager removeFileAtPath: fullDocumentPath
handler: nil];
if (succeed == NO) return NO;
}
succeed = [fileManager movePath: fullOriginalDocumentPath
toPath: fullDocumentPath
handler: nil];
if (succeed == NO) return NO;
// Overwrite the index.xml
NSString *path = [fullDocumentPath stringByAppendingPathComponent: IndexFile];
if ([editButton state] == NSOnState)
{
[dataSource setContent: [textView string] withTitle: index];
}
NSData *data = [dataSource dataOfIndexFile];
succeed = [data writeToFile: path atomically: YES];
if (succeed == YES)
{
isDocumentEdited = NO;
[window setDocumentEdited: NO];
}
return succeed;
}
}
// Only called when saving to new name
- (NSFileWrapper *) fileWrapperRepresentationOfType: (NSString *) aType
{
NSData *data;
NSFileWrapper *docFileWrapper, *indexFileWrapper;
NSDictionary *dict;
if ([editButton state] == NSOnState)
{
[dataSource setContent: [textView string] withTitle: index];
}
data = [dataSource dataOfIndexFile];
indexFileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: data];
dict = [NSDictionary dictionaryWithObject: indexFileWrapper
forKey: IndexFile];
docFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers: dict];
AUTORELEASE(indexFileWrapper);
AUTORELEASE(docFileWrapper);
isDocumentEdited = NO;
[window setDocumentEdited: NO];
return docFileWrapper;
}
- (BOOL)loadFileWrapperRepresentation:(NSFileWrapper *)docFileWrapper
ofType:(NSString *)aType
{
NSData *data;
NSString *string;
RETAIN(docFileWrapper);
if ([docFileWrapper isDirectory] == YES)
{
NSDictionary *dict = [docFileWrapper fileWrappers];
/// Should only have "index.xml"
NSFileWrapper *indexFileWrapper = [dict valueForKey: IndexFile];
if ((indexFileWrapper == nil) ||
([indexFileWrapper isRegularFile] == NO))
{
NSLog(@"No index.xml");
RELEASE(docFileWrapper);
return NO;
}
data = [indexFileWrapper regularFileContents];
string = [[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding];
[dataSource setDataFromContentOfFile: string];
}
RELEASE(docFileWrapper);
return YES;
}
- (IBAction)editAction:(id)sender
{
BOOL state = [editButton state];
if (state == NSOnState)
{
id source = [dataSource sourceWithTitle: index];
[textView setRichText: NO];
[textView setEditable: YES];
[textView setBackgroundColor: [NSColor yellowColor]];
// Allow drop
[textView registerForDraggedTypes: [NSArray arrayWithObjects:
NSStringPboardType, NSFilenamesPboardType, nil]];
// Put back original source
// Reset the attributed string in case it contain , , etc..
if (source)
[[textView textStorage] setAttributedString: [[NSAttributedString alloc] initWithString: source]];
}
else
{
NSAttributedString *as;
[textView setRichText: YES];
// Save source
[dataSource setContent: [textView string] withTitle: index];
// Render text
as = [dataSource renderWithTitle: index];
[[textView textStorage] setAttributedString: as];
[textView setEditable: NO];
[textView setBackgroundColor: [NSColor whiteColor]];
[textView unregisterDraggedTypes];
[tableView reloadData];
}
}
- (void)editMenuAction:(id)sender
{
[editButton performClick: sender];
}
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
// Add any code here that needs to be executed once the windowController has
// loaded the document's window.
[editButton setState: NSOffState];
[calendarButton setState: NSOnState];
[backButton setEnabled: NO];
[forwardButton setEnabled: NO];
[deleteButton setEnabled: NO];
if ([dataSource indexOfTitle: HomeTitle] == NSNotFound)
{
[dataSource setContent: @"Welcome to use MyWiki" withTitle: HomeTitle];
}
[textView setRichText: YES];
[textView setEditable: NO];
[textView setBackgroundColor: [NSColor whiteColor]];
[textView unregisterDraggedTypes];
// Reload titles
[tableView reloadData];
#ifdef GNUSTEP
[tableView selectRow: 0
byExtendingSelection: NO];
#else
[tableView selectRowIndexes: [NSIndexSet indexSetWithIndex: 0]
byExtendingSelection: NO];
#endif
#ifdef GNUSTEP
[splitView setDelegate: self];
#endif
[[NSNotificationCenter defaultCenter]
postNotificationName: NSTableViewSelectionDidChangeNotification
object: tableView];
[[aController window] makeFirstResponder: textView];
// Not sure why this is required since it is connected in IB already
window = [aController window];
}
- (BOOL) isDocumentEdited
{
return isDocumentEdited;
}
- (BOOL)textView:(NSTextView *)aTextView
shouldChangeTextInRange:(NSRange)affectedCharRange
replacementString:(NSString *)replacementString
{
[window setDocumentEdited: YES];
isDocumentEdited = YES;
return YES;
}
- (id) init
{
self = [super init];
ASSIGN(index, HomeTitle);
ASSIGN(dataSource, [[DataSource alloc] init]);
isDocumentEdited = NO;
history = [[NSMutableArray alloc] init];
[history addObject: AUTORELEASE([index copy])];
historyIndex = 0;
backOrForwardAction = NO;
return self;
}
- (void) dealloc
{
RELEASE(index);
RELEASE(dataSource);
RELEASE(history);
[super dealloc];
}
- (NSString *)windowNibName
{
return @"MyDocument";
}
@end