Search code examples
cocoa

Create Cocoa Document App without xib files


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?


Solution

  • 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;
    }
    
    

    enter image description here