I want to create document app, but I want to write it with code-only, without any magical xib files.
There're guides out there for ordinary apps, but no guides for document app. I tried to understand the difference with Xcode projects but it's not really clear.
So what should I do to convert ordinary app without xib to document app?
This is not easy to do. The following source code subclasses NSDocument and may be run in XCode by copy/pasting into the main.m file and deleting the pre-existing AppDelegate files. The info.plist must also be edited to look exactly like the attachment; otherwise it won't run. Good luck.
#import <Cocoa/Cocoa.h>
@interface Document : NSDocument <NSTextViewDelegate> {
NSTextView *txtView;
NSWindow *window;
}
@end
@implementation Document
-(id) init {
if (self = [super init]) {
[self buildWindow];
}
return self;
}
// ---- Required for remainder of save menu to show up ---- //
+(BOOL) autosavesInPlace {
return NO;
}
-(NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
return [[txtView string] dataUsingEncoding:NSUTF8StringEncoding];
}
-(BOOL) readFromURL:(NSURL *) absoluteURL ofType:(NSString *)typeName error:(NSError **)outError {
//NSString *codeString = [[NSString alloc] initWithContentsOfURL:absoluteURL encoding:NSUTF8StringEncoding error:outError];
NSString *codeString = [[NSString alloc] initWithContentsOfURL:absoluteURL encoding:NSASCIIStringEncoding error:outError];
[txtView setString:codeString];
return YES;
}
-(void) textDidChange:(NSNotification *)notification {
[self updateChangeCount:NSChangeDone];
}
-(void) buildWindow {
#define _wndW 700
#define _wndH 650
window = [[NSWindow alloc] initWithContentRect: NSMakeRect(0, 0, _wndW, _wndH)styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:NO];
[window center];
[window setTitle: @"NSDocument window"];
[window makeKeyAndOrderFront: nil];
[window setIdentifier:@"DocumentWindow"];
NSWindowController *windowController = [[NSWindowController alloc]initWithWindow:window];
[self addWindowController: windowController];
// ****** NSTextView with Scroll ****** //
NSScrollView *scrlView = [[NSScrollView alloc] initWithFrame:NSMakeRect( 20, 60, _wndW - 40, _wndH - 80 )];
[[window contentView] addSubview:scrlView];
[scrlView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
[scrlView setHasVerticalScroller: YES];
txtView = [[NSTextView alloc] initWithFrame:NSMakeRect( 0, 0, _wndW - 40, _wndH - 80 )];
[scrlView setDocumentView: txtView];
[txtView insertText:@"Enter text - Right click for menu." replacementRange:NSMakeRange(0,0)];
[txtView setAllowsUndo: YES];
[txtView setDelegate:self];
// ***** Quit btn ***** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 60, 10, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular];
[quitBtn setTitle: @"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:@selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
@end
@interface AppDelegate : NSObject <NSApplicationDelegate>
@end
@implementation AppDelegate
-(Document *)frontDocument {
NSArray *windows = [NSApp orderedWindows];
for ( NSWindow *w in windows ) {
if([[w identifier] isEqualToString:@"DocumentWindow"]) return [[w windowController] document];
}
return nil;
}
-(void)saveAction:(id)sender {
[[self frontDocument] saveDocument:sender];
}
-(void) buildMenu {
// ******** Menu and menubar ********//
NSMenu *menubar = [NSMenu new];
NSMenuItem *menuBarItem = [NSMenuItem new];
[menubar addItem:menuBarItem];
[NSApp setMainMenu:menubar];
NSMenu *appMenu = [NSMenu new];
[menuBarItem setSubmenu:appMenu];
// ***** About/Quit ******//
NSString *appName = [[NSProcessInfo processInfo] processName];
NSString *aboutTitle = [@"About " stringByAppendingString:appName];
[appMenu addItemWithTitle: aboutTitle action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
[appMenu addItem:[NSMenuItem separatorItem]];
[appMenu addItemWithTitle: @"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
// ******** File Menu ********//
NSMenuItem *fileMenuItem = [menubar addItemWithTitle:@"" action:nil keyEquivalent:@""];
NSMenu *fileMenu = [[NSMenu alloc] initWithTitle:@"File"];
[menubar setSubmenu:fileMenu forItem:fileMenuItem];
[fileMenu addItemWithTitle: @"New" action: @selector(newDocument:) keyEquivalent:@"n"];
[fileMenu addItemWithTitle: @"Open..." action: @selector(openDocument:) keyEquivalent:@"o"];
[fileMenu addItem: [NSMenuItem separatorItem]];
[fileMenu addItemWithTitle: @"Close" action: @selector(performClose:) keyEquivalent:@"w"];
[fileMenu addItemWithTitle: @"Save..." action: @selector(saveAction:) keyEquivalent:@"s"];
[fileMenu addItemWithTitle: @"SaveAs..." action: @selector(saveDocumentAs:) keyEquivalent:@"S"];
// ******** Edit Menu ********//
NSMenuItem *editMenuItem = [menubar addItemWithTitle:@"" action:nil keyEquivalent:@""];
NSMenu *editMenu = [[NSMenu alloc] initWithTitle:@"Edit"];
[menubar setSubmenu:editMenu forItem:editMenuItem];
[editMenu addItemWithTitle: @"Undo" action:@selector(undo:) keyEquivalent:@"z"];
[editMenu addItemWithTitle: @"Redo" action:@selector(redo:) keyEquivalent:@"Z"];
[editMenu addItem:[NSMenuItem separatorItem]];
[editMenu addItemWithTitle: @"Cut" action:@selector(cut:) keyEquivalent:@"x"];
[editMenu addItemWithTitle: @"Copy" action:@selector(copy:) keyEquivalent:@"c"];
[editMenu addItemWithTitle: @"Paste" action:@selector(paste:) keyEquivalent:@"v"];
[editMenu addItemWithTitle: @"Delete" action:@selector(delete:) keyEquivalent:@""];
[editMenu addItemWithTitle: @"Select All" action:@selector(selectAll:) keyEquivalent:@"a"];
}
-(void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
}
@end
int main() {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}