This is FlashDocument.m in view mode; [Download] [Up]
#import "FlashDocument.h" #import "FlashApp.h" #import "Deck.h" #import "Card.h" #import "Random.h" #import <appkit/Matrix.h> #import <appkit/ScrollView.h> #import <appkit/Text.h> #import <appkit/Font.h> #import <appkit/Panel.h> #import <appkit/ButtonCell.h> #import <appkit/nextstd.h> #import <objc/hashtable.h> /* for NXCopyStringBuffer() */ #import <text/pathutil.h> #define KEY 0 // Text Views #define RES 1 #define P_HIGH 104.0 // Cell Size #define P_WIDE 274.0 #define P_MARG 7.0 @implementation FlashDocument /* * This class is used to keep track of a Flash document. * /* Private Functions */ #define ObjName(S) "Card_" #S #define SetCell(I,T,S) [[[diff cellAt:0:I] setTitle:#T] setAction:@selector(S)] #define SetDiffCell(I,N) SetCell(I,N, was ## N ## :) static Text *getText(id me, STR name) { Text* tv; tv = [[NXGetNamedObject(name, me) docView] setDelegate:me]; return tv; } static void alignText(Text *text, int align) { [[text setAlignment:align] calcLine]; } static void writeToCard(Card *card, id* tv) { int i=2; // Bottom Up NXStream *stream; while(i--) { stream=NXOpenMemory(NULL,0,NX_READWRITE); [tv[i] writeRichText:stream]; [card setFace:i stream:stream]; NXCloseMemory(stream, NX_FREEBUFFER); [card setFace:i tag:[tv[i] alignment]]; } } static void readFromCard(Card *card, id* tv) { int i=2; NXStream *stream; while(i--) { stream=[card faceStream:i]; [tv[i] readRichText:stream]; NXCloseMemory(stream, NX_SAVEBUFFER); alignText(tv[i],[card faceTag:i]); } } static Text *newText(int i, int j) // Generate a TextCell of the Printout. { Text *text; NXRect myRect; NXSetRect(&myRect, i*P_WIDE, j*P_HIGH, P_WIDE, P_HIGH ); text = [Text newFrame:&myRect]; [text setMarginLeft:P_MARG right:P_MARG top:P_MARG bottom:P_MARG]; return text; } /* Factory methods */ + new /* * Creates a new, empty, document. * Creates a deck; creates a window for that deck; */ { self = [super new]; contents = [Deck new]; [self getWindow]; [self setName:NULL andDirectory:NULL]; [self setViewMode:NO]; [self showTextOf:[self newCard]]; return self; } + newFromFile:(const char *)file /* * Opens an existing document from the specified file. */ { if (self = [super newFromFile:file]) { [self getWindow]; [self setName:file]; [self showTextOf:[contents giveCard]]; return self; } return nil; } /* Create and Destroy Methods*/ - getWindow /* * set textViews and their delegates; orders the window front; */ { rand = [Random new]; [contents setMarkerAtEnd]; window=[NXApp locateWindow:[NXApp loadNibSection:"Card.nib" owner:self]]; viewMode = YES; textView[RES]=[getText(self, ObjName(ResScroll)) setFont:[NXApp defaultFont:"ResFont"]]; textView[KEY]=[getText(self, ObjName(KeyScroll)) setFont:[NXApp defaultFont:"KeyFont"]]; [window makeKeyAndOrderFront:self]; [NXApp addDocument:[self filename]]; return self; } - newCard { cardNew = YES; cardChanged = NO; return [[Card new] setFace:KEY tag:NX_CENTERED]; } - free /* * Free all subsisting objects */ { [contents freeObjects]; return [super free]; } /* State Variables */ - view /* * Returns the TextView which is first responder; * Returns nil if firstResponder is not Text. */ { view = [window firstResponder]; if (! [view isKindOfGivenName:"Text"] ) view = nil; return view; } - setViewMode:(BOOL)newMode /* * Change between viewing and updating mode */ { BOOL tmp = viewMode; viewMode = newMode; if (viewMode) { if ( ![self checkCurrent] ) { viewMode = tmp; return nil; } [self cover:self]; [[reveal setTitle:"Reveal"] setAction:@selector(reveal:)]; [[[reveal setAltTitle:"Cover"] setType:NX_TOGGLE] setState:0]; SetDiffCell(0,Easy); SetDiffCell(1,Fair); SetDiffCell(2,Hard); } else { [self reveal:self]; [[reveal setTitle:"Next"] setAction:@selector(next:)]; [reveal setType:NX_MOMENTARYPUSH]; SetCell(0,Add,add:); SetCell(1,Modify,modify:); SetCell(2,Delete,delete:); cardNew = cardChanged = NO; // [[window makeFirstResponder:textView[KEY]] makeKeyWindow]; } return self; } - (BOOL) viewMode; /* * Returns the view Mode associated with this document. */ { return viewMode; } - switchViewMode:sender /* * Toggle between view and update mode */ { return [self setViewMode:(! viewMode)]; } /* Card Display Methods */ - showTextOf:aCard /* * set to current card before displaying */ { if (! aCard) { Notify("Deck", "End of Deck. Staring over."); aCard = [[contents setMarkerAtEnd] giveCard]; } currentCard = aCard; return [self showText]; } - showText /* * Display card. Blacken RES if in View Mode */ { if (! currentCard) currentCard = [self newCard]; if ([reveal state]) [reveal performClick:self]; readFromCard(currentCard,textView); [markCount setIntValue:[contents marker]]; return self; } /* Action methods for Card View/Update */ - reveal:sender /* * If I ask, display RES. If Button asks, toggle. */ { if ((sender == self) || ([textView[RES] backgroundGray] == NX_BLACK)) [[textView[RES] setBackgroundGray:NX_WHITE] update]; else [self cover:self]; return self; } - cover:sender /* * Blacken RES. */ { [[textView[RES] setBackgroundGray:NX_BLACK] update]; return self; } - wasEasy:sender /* * Place in Back. */ { [self showTextOf:[[contents takeCard:currentCard] giveCard]]; return self; } - wasFair:sender /* * Place in front of marker. */ { [contents insertObject:currentCard at: [rand partition:[contents marker] part:2 of :2]]; [self showTextOf:[contents giveCard]]; return self; } - wasHard:sender; /* * Place in front. */ { [contents insertObject:currentCard at: [rand partition:[contents marker] part:1 of :2]]; [self showTextOf:[contents giveCard]]; return self; } /* Update Mode */ - (BOOL)checkCurrent /* * Make sure current card isn't new or modified. * returns NO if user requests cancel. */ { if (cardChanged) { switch(NXRunAlertPanel("Update", "Card changed. Add to deck?", "YES", "NO", "Cancel")) { case NX_ALERTDEFAULT: [self add:self]; break; case NX_ALERTALTERNATE: break; default: return NO; } } if (cardNew) { [currentCard free]; [self showTextOf:[contents removeLastObject]]; cardNew = cardChanged = NO; } return YES; } - next:sender /* * Show the next card. If current one has been changed, ask. */ { if (! [self checkCurrent]) return nil; [self wasEasy:sender]; cardNew = cardChanged = NO; return self; } - add:sender /* * Add a new card to the deck. */ { if (! cardNew) { [contents takeCard:currentCard]; currentCard = [self newCard]; } return [self modify:sender]; } - modify:sender /* * Change the current Card. */ { writeToCard(currentCard,textView); [contents takeCard:currentCard]; [self showTextOf:[self newCard]]; [window setDocEdited:YES]; return self; } - delete:sender /* * Delete the current Card. */ { if (NXRunAlertPanel("Delete", "Are you sure you want to delete this card?", "YES", "NO", "Cancel") != NX_ALERTDEFAULT) return self; [window setDocEdited:YES]; [currentCard free]; [self showTextOf:[contents giveCard]]; return self; } /* Action Methods for manipulating the Deck */ - previous:sender /* * Move back one. */ { if ([self checkCurrent]) { [contents setMarkerAt:([contents marker]+1)]; [contents insertObject:currentCard at:0]; [self showTextOf:[contents removeLastObject]]; cardNew = cardChanged = NO; } return self; } - find:sender /* * Find a string. Use a panel to set parameters */ { id card; /* [self next:self]; */ [self checkCurrent]; if (card = [super find:sender]) { [contents takeCard:currentCard]; [contents cutAt:[contents indexOf:card]]; [self showTextOf:[contents giveCard]]; } return self; } - doAct:(SEL)action for:(STR)caller /* * Pass action methods on to Deck */ { if (viewMode) { [[contents takeCard:currentCard] perform:action with:self]; return [self showTextOf:[contents giveCard]]; } else { NotifyArg("Update", "Can't %s in update mode.",caller); return nil; } } - shuffle:sender /* * Shuffle the deck. */ { return [self doAct:@selector(shuffle:) for:"shuffle"]; } - sort:sender /* * Organize in some coherent fashion. Use a default sort on key. */ { [window setDocEdited:YES]; return [self doAct:@selector(sort:) for:"sort"]; } - swapFields:sender /* * Exchange Key and Response. */ { return [self doAct:@selector(flipAll:) for:"swap fields"]; } - reset:sender { [markCount setIntValue:[[contents setMarkerAtEnd] marker]]; return self; } /* Action Methods for File services */ - print:sender /* * Create a view displaying the entire deck, staggered. Then print it. */ { int row=0; NXRect myRect; View *deckView; Text *tv[2]; Deck *pdeck; Card *pcard; Window *holder; pdeck = [contents copy]; [[pdeck insertObject:currentCard at:0] setMarkerAtEnd]; NXSetRect(&myRect, 0.0, 0.0, 2*P_WIDE, ([pdeck count]+1)*P_HIGH); deckView = [[View newFrame:&myRect] setFlip:YES]; holder = [Window newContent:&myRect style:NX_PLAINSTYLE backing: NX_NONRETAINED buttonMask:0 defer:NO]; [holder setContentView:deckView]; [deckView addSubview:[newText(1,row) setText:[self filename]] ]; while (pcard = [pdeck giveCard]) { tv[0] = newText(0,row++); tv[1] = newText(1,row); readFromCard(pcard,tv); [deckView addSubview:tv[0]]; [deckView addSubview:tv[1]]; } [deckView printPSCode:sender]; [holder close]; return self; } - save:sender /* * Saves the file. If this document has never been saved to disk, * then a SavePanel is put up to ask the user what file name she * wishes to use to save the document. */ { if (! [contents count]) return self; [contents insertObject:currentCard at:0]; [super save:sender]; [contents giveCard]; return self; } - revertToSaved:sender /* * Revert the document back to what is on the disk. */ { [contents insertObject:currentCard at:0]; [super revertToSaved:sender]; [contents setMarkerAtEnd]; [self showTextOf:[contents giveCard]]; return self; } /* Text delegate methods. */ - (BOOL)textWillChange:sender /* * Assigns the current text to where the cursor is. * Doesn't allow editing in view mode. */ { view = sender; if (viewMode) { Notify("Update", "Can only edit cards in Update Mode."); return YES; } else { cardChanged = YES; return NO; } } - (BOOL)textWillEnd:sender /* * Nulls the current text as it resigns first responder. */ { view = nil; return NO; } /* * Target/Action messages to affect the current TextView in the main window. * This is the places where messages from the Text menu are handled. */ - centerText:sender { alignText([self view],NX_CENTERED); return self; } - leftJustifyText:sender { alignText([self view],NX_LEFTALIGNED); return self; } - rightJustifyText:sender { alignText([self view],NX_RIGHTALIGNED); return self; } /* Outlet Connections */ - setReveal:anObject { reveal = anObject; return self; } - setDiff:anObject { diff = anObject; return self; } - setMarkCount:anObject { markCount = anObject; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.