This is BibTexView.m in view mode; [Download] [Up]
// Copyright H. Giesen, University of Koblenz-Landau 1996 #import "Controller.h" #import "BibTexView.h" #import "BibTeXObject.h" #import "BibliographicFile.h" #import "Preferences.h" #import "BufferClass.h" #define IN & #define KEY_FIELD_TAG 100 #define NOTE_TEXT_TAG 120 #define FORM_FIELD_TAG 123 #define BIG_LEFT NXPrintf( localStream, "%s",\ [leftBraceButton state] ?\ [leftBraceButton altTitle]: [leftBraceButton title] ) #define BIG_RIGHT NXPrintf( localStream, "%s\n\n",\ [rightBraceButton state] ?\ [rightBraceButton altTitle]: [rightBraceButton title] ) #define LEFTQUOTE if( cooked ) NXPutc(localStream, LBRACE ) #define RIGHTQUOTE if( cooked ) NXPutc(localStream, RBRACE ) #define THE_TYPE NXPrintf( localStream, "\n@%s",[popUpButton title] ) #define THE_KEY NXPrintf( localStream, " %s",\ [self stringOf:[keyField stringValue]] ) #define ASSIGN NXPrintf( localStream, "\t= " ) #define ACTUALBUFFER \ [self convert:[self listBufferFor:actualRow] toStream:localStream] #define NEXTENTRY(title) NXPrintf( localStream, ",\n\t%s\t= ", title ) #define NEWLINE NXPrintf( localStream, "\n" ) #define ADD_HASH_MARK { NXPrintf( toStream, " # "); } static id entryInspectorObject = nil; static int STRING; static int PREAMBLE; static int COMMENT; static NXStream *localStream = NULL; static char *localBuffer; static int locBufferLength, locBufferMaxLength; static id viewBuffer = nil; static id cookedBuffer = nil; @implementation BibTexView + new { if( entryInspectorObject==nil ){ entryInspectorObject = [[super alloc] init]; viewBuffer = [[BufferClass alloc] initBufferSize:80]; cookedBuffer = [[BufferClass alloc] init]; } return entryInspectorObject; } + alloc { return [self notImplemented:_cmd]; } - (void)initButtons { int i; id button; NXRect aFrame = { {0.0, 0.0}, {18.0, 18.0} }; toggleListType *toggleList = [preferences toggleList]; i = 0; while( toggleList[i].entryIndex ){ // create a button // create a new toggle button button = [[Button alloc] initFrame:&aFrame]; [button setTitle:"t"]; [button setTag:i]; [button setTarget:self]; [button setAction:@selector(toggle:)]; [button setTransparent:YES]; toggleList[i].tglButton = button; toggleList[i].isInWindow = NO; i++; } } - (void)clearToggleButtons { int i = 0; toggleListType *toggleList = [preferences toggleList]; while( toggleList[i].entryIndex ){ // remove a button from superview if( toggleList[i].isInWindow==YES ){ [toggleList[i].tglButton removeFromSuperview]; toggleList[i].isInWindow = NO; } i++; } } - findCellWithTitle:(NXAtom)txt at:(int *)inx { int rows, cols; int i, len = strlen(txt); [entryForm getNumRows:&rows numCols:&cols]; for( i=0; i<rows; i++ ){ if( NXOrderStrings([entryForm titleAt:i], txt, NO, len, NULL)==0 ){ // fprintf( stderr, "found %s in %d\n", txt, i ); *inx = i; return [entryForm cellAt:i :0]; } } //fprintf( stderr, "not found %s\n", txt ); // %%%% ??? %%%%% *inx = -1; return nil; } - setDelayedToggleButtonsFor:(int)eType { int i=0, j; id tglButton; id theCell; NXRect cellFrame; toggleListType *toggleList = [preferences toggleList]; [self clearToggleButtons]; while( toggleList[i].entryIndex ){ if( toggleList[i].entryIndex==eType ){ id fnt = [Font newFont:"Helvetica-BoldOblique" size:12.0 ]; theCell = [self findCellWithTitle:toggleList[i].txt0 at:&j]; if( theCell==nil ) theCell = [self findCellWithTitle:toggleList[i].txt1 at:&j]; if( theCell==nil ) break; if( fnt ) [theCell setTitleFont:fnt]; [entryForm getCellFrame:&cellFrame at:j :0]; tglButton = toggleList[i].tglButton; toggleList[i].formInx = j; cellFrame.W = [theCell titleWidth]; [tglButton setFrame:&cellFrame]; [entryForm addSubview:tglButton]; [tglButton display]; // <--- toggleList[i].isInWindow = YES; } i++; } return self; } - setToggleButtonsFor:(int)eType { [self perform:@selector(setDelayedToggleButtonsFor:) with:(id)eType afterDelay:0 cancelPrevious:YES]; //[self setDelayedToggleButtonsFor:eType]; return self; } static char itemTextBuffer[1024]; // variable length ?????? - (const char *)titleOf:(configListType *)item { char *pnt = itemTextBuffer; int mode = item->mode[entryType]; strcpy( itemTextBuffer, item->fieldName ); while( *pnt ) pnt++; *pnt++ = ' '; if( (3 IN mode )==REQUIRED ) *pnt++ = '·'; else *pnt++ = 0x80; *pnt = '\0'; return itemTextBuffer; } - (BOOL)fillFormAt:(int)inx for:(locType)location { // copy into a formcell // and test for linefeed int i; char c, *theString; if( location.length==0 ){ [entryForm setStringValue:NULL at:inx]; return NO; } [viewBuffer setMinSizeTo:location.length]; [theObject convertRawField:location to:[viewBuffer buffer]]; [entryForm setStringValue:[viewBuffer buffer] at:inx]; i = 0; theString = [viewBuffer buffer]; while( c=theString[i++] ){ if( c=='\n' ) return YES; } return NO; } - toggle:sender { toggleListType *toggleList = [preferences toggleList]; int tag = [sender tag]; int fieldInx; int formInx = toggleList[tag].formInx; configListType *item; locType location; if( toggleList[tag].state==0 ){ fieldInx = [preferences indexOfFieldname:toggleList[tag].txt1]; toggleList[tag].state = 1; } else{ fieldInx = [preferences indexOfFieldname:toggleList[tag].txt0]; toggleList[tag].state = 0; } item = ((configListType*)[configList elementAt:fieldInx]); [entryForm setTitle:[self titleOf:item] at:formInx]; location.start = item->start; // set by the parser location.length = item->length; [self fillFormAt:formInx for:location]; return self; } // a key is a string of characters. // all characters are allowed exept the comma // BUT: if the entryType is STRING the following 10 characters are not allowed // " # % ' ( ) , { } #define isOneOfTheTen(x) (x=='"' || x=='#' || x=='%' || x=='\''\ || x=='(' || x==')' || x==',' || x=='=' || x=='{' || x=='}') - (BOOL) key:(const char *)key isValidFrom:(int*)first to:(int*)last { unsigned char c; int i = 0; if( (entryType==PREAMBLE) || (entryType==COMMENT) ) return YES; if( key==NULL ) return NO; if( (c = key[i])=='\0' ) return NO; while( NXIsSpace(c) ) c = key[++i]; *first = i; while( c ){ //if( isOneOfTheTen(c) || (c>127) ){ // not valid if( c==',' || ( (entryType==STRING) && isOneOfTheTen(c) ) ){ // not valid *last = i; // here is the error return NO; } if( NXIsSpace(c) ) break; c = key[++i]; } *last = i; if( c=='\0' ) return YES; // skip trailing blanks while( NXIsSpace(c) ) c = key[++i]; if( c ) return NO; return YES; } - enableReplaceButton { char buttonBuffer[128], *lastDot; //if( [replaceButton isEnabled] ) return self; sprintf( buttonBuffer, "update ." ); lastDot = rindex( buttonBuffer, '.' ); [theObject copyRange:[theObject key] toBuffer:lastDot]; [replaceButton setTitle:buttonBuffer]; [replaceButton setEnabled:YES]; return self; } - enableAddButton { char buttonBuffer[128], *lastDot; if( [addButton isEnabled] ) return self; sprintf( buttonBuffer, "add to file %s", [theFile fileName] ); lastDot = rindex( buttonBuffer, '.' ); *lastDot = '\0'; [addButton setTitle:buttonBuffer]; [addButton setEnabled:YES]; return self; } - (void) updateButtons { [clearButton setEnabled:YES]; if( theFile==nil ){ // no file selected [revertButton setEnabled:NO]; [addButton setEnabled:NO]; [replaceButton setEnabled:NO]; return; } // file exists if( theObject==nil ){ // a file but no object (maybe we create a new object) [revertButton setEnabled:NO]; [replaceButton setEnabled:NO]; if( isDirty &&( (entryType==PREAMBLE)||(entryType==COMMENT) ) ){ [self enableAddButton]; return; } if( isDirty && keyIsValid && (objWithThisKey==nil) ) [self enableAddButton]; // key is unique else [addButton setEnabled:NO]; return; } // both file and object exist if( (isDirty==NO) && (objWithThisKey==theObject) ){ [revertButton setEnabled:NO]; [replaceButton setEnabled:NO]; [addButton setEnabled:NO]; return; } // both file and object exist and the text has been edited [revertButton setEnabled:YES]; if( keyIsValid ){ if( objWithThisKey==nil ){ // key is valid and unique [self enableReplaceButton]; [self enableAddButton]; return; } // key is valid but not unique if( objWithThisKey==theObject ){ // it's me [self enableReplaceButton]; [addButton setEnabled:NO]; return; } // key is valid but belongs to another entry [replaceButton setEnabled:NO]; [addButton setEnabled:NO]; return; } // key is syntactically not valid [replaceButton setEnabled:NO]; [addButton setEnabled:NO]; return; } - raw:(const char *)rawText toCooked:(char *)cookedText { return self; } - (const char *)convertText:(int)i { const char* txt = [entryForm stringValueAt:i]; if( cooked==NO ) return txt; if( (txt[0]=='"') || (txt[0]==LBRACE) ){ [cookedBuffer setText:txt]; return [cookedBuffer buffer]+1; } return txt; } - (void) clearConfigList { int i; configListType *item; // clear location entries in configList for( i=0; i<[configList count]; i++ ){ item = ((configListType*)[configList elementAt:i]); item->start = 0; item->length = 0; } } // called from controller (newButton) - newEntryFor:(BibliographicFile *)file { [self setEntry:nil inFile:file]; NXAttachPopUpList( popUpButton, popUpListNew ); [self drawTemplate:-1]; //[self clear:self]; [inspector makeKeyAndOrderFront:self]; if( [keyField isEnabled] ) [keyForm selectTextAt:0]; else [noteView setSel:0 :0]; [self clearConfigList]; return self; } - fillCharMatrix:sender { unsigned char str[8]; char **tbl = [BibTexParser NX2TeX]; //char *texString; int i; str[1] = '\0'; [[charMatrix window] disableDisplay]; for( i=0; i<128; i++ ){ id cell = [charMatrix cellAt:i/8 :i%8]; str[0] = i + 0x80; [cell setTitle:str]; //texString = tbl[ i ]; if( tbl[i][1]=='?' ) [cell setEnabled:NO]; } [[[charMatrix window] reenableDisplay] display]; [[charMatrix window]setBecomeKeyOnlyIfNeeded:YES]; return self; } - firstCall { int index; NXRect entryFrame; [NXApp loadNibSection:"EntryInspector.nib" owner:self]; if( BIBTEST==NO ) [[bufferedButton removeFromSuperview] free]; [inspector useOptimizedDrawing:YES]; [entryForm setInterline:0]; // ****** preferences = [Preferences new]; STRING = [preferences indexOfEntryname:"STRING"]; PREAMBLE = [preferences indexOfEntryname:"PREAMBLE"]; COMMENT = [preferences indexOfEntryname:"COMMENT"]; entryNameList = [preferences entryNameList]; configList = [preferences configList]; [self clearConfigList]; popUpList = [[PopUpList alloc] init]; popUpListNew = [[PopUpList alloc] init]; for( index=0; index<[entryNameList count]; index++ ){ const char *title = (const char *)[entryNameList objectAt:index]; [popUpList addItem:title]; [popUpListNew addItem:title]; } // clean the popUpList [[popUpList removeItem:"STRING"] free]; [[popUpList removeItem:"PREAMBLE"] free]; [[popUpList removeItem:"COMMENT"] free]; // size both lists to fit, setTarget [popUpList sizeToFit]; [[popUpList setAction:@selector(bibPopup:)] setTarget:self]; [popUpListNew sizeToFit]; [[popUpListNew setAction:@selector(bibPopup:)] setTarget:self]; [popUpButton setFont:[Font newFont:"Courier" size:12.0 ]]; popUpListString = [[PopUpList alloc] init]; [popUpListString addItem:"STRING"]; popUpListPreamble = [[PopUpList alloc] init]; [popUpListPreamble addItem:"PREAMBLE"]; popUpListComment = [[PopUpList alloc] init]; [popUpListComment addItem:"COMMENT"]; // we start with the "normal" list NXAttachPopUpList( popUpButton, popUpList ); [popUpList sizeButton:popUpButton]; // get the original windowFrame (without entryForm and scrollView) [entryForm getFrame:&entryFrame]; [inspector getFrame:&windowFrame]; [noteView getFrame:&minTextFrame]; // as set in IB windowFrame.Y += windowFrame.H; // northwest_corner windowFrame.H -= entryFrame.H; // without entryForm windowFrame.H -= minTextFrame.H; // without scrollView // windowFrame is now the raw frame (only height is of interest) // without entryform entryFormMask = [entryForm autosizing]; // as made in IB scrollViewMask = [scrollView autosizing]; // as made in IB scrollViewMask = [marker autosizing]; // as made in IB [noteView setDelegate:self]; [noteView setTag:120]; [noteView setFont:[Font userFontOfSize:0.0 matrix:NX_FLIPPEDMATRIX]]; theFont = [[entryForm cellAt:0 :0] titleFont]; isDirty = NO; textBufferList = [[List alloc] init]; [marker renewRows:0 cols:1]; [marker setFont:[Font newFont:"Symbol" size:12.0 ]]; [self drawTemplate:-1]; [inspector orderFront:self]; [self fillCharMatrix:self]; [self initButtons]; [fieldEditor setMonoFont:YES]; [fieldEditor setCharFilter:NXFieldFilter]; cooked = YES; return self; } - (void) clearBuffers { int i; for( i=[textBufferList count]-1; i>=0; i-- ) [[textBufferList objectAt:i] clear]; } - prefsDidChange { prefsDidChange = YES; if( [inspector isDisplayEnabled]==NO ) return self; [self drawTemplate:-1]; [self revert:self]; return self; } - (void) sizeBufferListTo:(int)index { while( [textBufferList count]<=index ) [textBufferList addObject:[[BufferClass alloc] init] ]; } - (char *) listBufferFor:(int)inx { if( [textBufferList count] <= inx ){ [self sizeBufferListTo:inx]; } return [[textBufferList objectAt:inx] buffer]; } - (char *) listBufferFor:(int)inx size:(int)size { if( [textBufferList count] <= inx ){ [self sizeBufferListTo:inx]; } [[textBufferList objectAt:inx] setMinSizeTo:size]; return [[textBufferList objectAt:inx] buffer]; } - noteSelect:sender // sender is Matrix { int row = [sender selectedRow]; char *aTextBuffer; // source buffer if( row<0 ) return self; aTextBuffer = [self listBufferFor:row]; if( noteIsDirty ){ // write the text back to the buffer char *actualTextBuffer = [self listBufferFor:actualRow size:[noteView textLength]+1]; [noteView getSubstring:actualTextBuffer start:0 length:[noteView textLength]+1]; } [noteView setSel:0 :[noteView textLength]]; [noteView replaceSel:aTextBuffer]; noteIsDirty = NO; actualRow = row; return self; } - copyLoc:(locType)loc ofObject:obj to:(int)inx { char *aTextBuffer = [self listBufferFor:inx size:loc.length]; if( entryType==COMMENT ){ [obj copyRange:loc toBuffer:aTextBuffer]; } else [obj convertRawField:loc to:aTextBuffer]; return self; } // the key-field is already filled - showString:(int)k { configListType *item; locType location; int NOTE = [preferences indexOfFieldname:"NOTE"]; // STRING has no fieldname, it's content is stored in NOTE // PREAMBLE has no fieldname, it's content is stored in NOTE // COMMENT has no fieldname, it's content is stored in NOTE item = ((configListType*)[configList elementAt:NOTE]); location.start = item->start; // set by the parser location.length = item->length; // copy the content to a buffer at index [0]; [self copyLoc:location ofObject:theObject to:0]; [noteView setSel:0 :[noteView textLength]]; [noteView replaceSel:[self listBufferFor:0]]; [[entryForm renewRows:0 cols:1] sizeToCells]; [noteMatrix renewRows:0 cols:0]; return self; } - resizeInspector:(NXRect *)fr { NXRect entryFrame, textFrame, minFrame; [entryForm getFrame:&entryFrame]; [scrollView getFrame:&textFrame]; newWindowFrame = windowFrame; newWindowFrame.H = // new minimal frame windowFrame.H + entryFrame.H + minTextFrame.H; minFrame = newWindowFrame; minFrame.W = 300.0; [inspector setMinSize:&minFrame.size]; newWindowFrame.H = // new real frame windowFrame.H + entryFrame.H + textFrame.H; // northwest_corner --> southeast_corner newWindowFrame.Y -= newWindowFrame.H; *fr = newWindowFrame; return self; } // skips leading blanks // returns a pointer to a string from the first nonblanl // character. The string ends before the first blank // behind the string. // used in printing key, digits and the title of the fields - (const char *)stringOf:(const char *)txt { int i = 0; char c; while( (c=*txt++)==' ' ); // skip leading blanks while( c && (c!=' ') ){itemTextBuffer[i++] = c; c = *txt++;} itemTextBuffer[i] = '\0'; return itemTextBuffer; } - (void) addURLat:(int)inx { NXRect cellFrame; Cell *theCell = [entryForm cellAt:inx :0]; Cell *markerCell = [marker cellAt:inx :0]; [entryForm getCellFrame:&cellFrame at:inx :0]; fprintf( stderr, "add type=%d\n", [markerCell type] ); //[markerCell setIcon:"Images/smallIcon"]; [theCell setIcon:"Images/smallIcon"]; fprintf( stderr, "add type=%d %s\n", [theCell type], [theCell icon] ); } - (void) addMarker:(BOOL)m at:(int)inx { id cell; int row, col; [marker addRow]; [marker getNumRows:&row numCols:&col]; cell = [marker cellAt:(row-1) :0]; if( m ){ [cell setStringValue:"\272"]; //[self addURLat:inx]; } else [cell setStringValue:NULL]; } - (void) setMarker:(BOOL)m at:(int)inx { id cell = [marker cellAt:inx :0]; const char *str = [cell stringValue]; if( m == (str!=NULL) ) return; if( m ){ [cell setStringValue:"\272"]; //[self addURLat:inx]; } else [cell setStringValue:NULL]; } - (void) drawTemplate:(int)aType // empty inspector { int i, count, mode, rows, cols; configListType *item; NXRect winFrame; if( aType<0 ){ entryType = [preferences indexOfEntryname:(char *)[popUpButton title]]; } else entryType = aType; [inspector disableDisplay]; [inspector endEditingFor:nil]; [keyForm setNextText:entryForm]; [keyField setEnabled:YES]; [keyForm selectTextAt:0]; [[entryForm renewRows:0 cols:1] sizeToCells]; // clear the matrix [marker renewRows:0 cols:1]; if( (entryType==STRING) || (entryType==PREAMBLE) || (entryType==COMMENT) ){ // special handling [[noteMatrix renewRows:0 cols:1] sizeToCells]; if( entryType==PREAMBLE )[keyField setEnabled:NO]; if( entryType==COMMENT )[keyField setEnabled:NO]; if( entryType==STRING ) [keyForm setNextText:noteView]; [self resizeInspector:&winFrame]; [inspector reenableDisplay]; [inspector placeWindowAndDisplay:&winFrame]; return; } [noteMatrix renewRows:0 cols:1]; // set the empty forms for( i=0, count=0; i<[configList count]; i++ ){ item = ((configListType*)[configList elementAt:i]); item->tag = -1; // clear mode = item->mode[entryType]; if( SHOW IN mode ){ if( (LARGE IN mode) ){ id cell; int row, col; [noteMatrix addRow]; [noteMatrix getNumRows:&row numCols:&col]; cell = [noteMatrix cellAt:(row-1) :0]; [cell setTitle:item->fieldName]; } else{ // normal form [entryForm addRow]; [[entryForm cellAt:count :0] setTitleFont:theFont]; item->tag = count; [entryForm setTitle:[self titleOf:item] at:count]; count++; } } } [noteMatrix sizeToCells]; [entryForm sizeToCells]; [entryForm getNumRows:&rows numCols:&cols]; [marker renewRows:rows cols:cols]; [marker sizeToCells]; for( i=0; i<rows; i++ ){ [[marker cellAt:i :0] setStringValue:NULL]; } [self resizeInspector:&winFrame]; [self setToggleButtonsFor:entryType]; [self clearBuffers]; prefsDidChange = NO; [inspector reenableDisplay]; [inspector placeWindowAndDisplay:&winFrame]; } - (void) fillTemplate { int i, j, n, mode; configListType *item; locType location, range; BOOL multiLine = NO; [self showAllFieldsFor:entryType]; [[inspector reenableDisplay] displayIfNeeded]; return; [theObject setKeyTo:keyField]; [marker renewRows:0 cols:1]; if( (entryType==STRING)||(entryType==PREAMBLE)||(entryType==COMMENT) ){ [self showString:entryType]; [[inspector reenableDisplay] displayIfNeeded]; [scrollView display]; return; } for( i=0, j=0, n=0; i<[configList count]; i++ ){ item = ((configListType*)[configList elementAt:i]); mode = item->mode[entryType]; location.start = item->start; // set by the parser location.length = item->length; [viewBuffer setMinSizeTo:location.length]; if( SHOW IN mode ){ if( (LARGE IN mode) ){ [self copyLoc:location ofObject:theObject to:n]; n++; continue; } multiLine = [self fillFormAt:j for:location]; [self addMarker:multiLine at:j]; j++; } } noteIsDirty = NO; range = [theObject range]; sprintf( [viewBuffer buffer], "line %d, charpos %d, length %d", [theObject line], range.start, range.length ); [positionField setStringValue:[viewBuffer buffer]]; [self noteSelect:noteMatrix]; [marker sizeToCells]; [[inspector reenableDisplay] displayIfNeeded]; [scrollView display]; [marker display]; } - (void) showAllFieldsFor:(int)aType { int i, j, count, mode; configListType *item; locType location; BOOL multiLine; BOOL mustEnable = NO; if( (aType==STRING)||(aType==PREAMBLE)||(aType==COMMENT) ){ [self showString:aType]; return; } if( [inspector isDisplayEnabled] ){ [inspector disableDisplay]; mustEnable = YES; } // how many fields are needed ? configList = [preferences configList]; // actual list for( i=0, count=0; i<[configList count]; i++ ){ item = ((configListType*)[configList elementAt:i]); mode = item->mode[aType]; item->tag = -1; // clear if( LARGE IN mode ) continue; if( SHOW IN mode ) count++; } [[entryForm renewRows:count cols:1] sizeToCells]; [noteMatrix renewRows:0 cols:1]; [marker renewRows:0 cols:1]; for( i=0, j=0; i<[configList count]; i++ ){ item = ((configListType*)[configList elementAt:i]); mode = item->mode[aType]; location.start = item->start; // set by the parser location.length = item->length; if( SHOW IN mode ){ if( (LARGE IN mode) ){ // copy to the noteView - textObject id cell; int row, col; [noteMatrix addRow]; [noteMatrix getNumRows:&row numCols:&col]; cell = [noteMatrix cellAt:(row-1) :0]; [cell setTitle:item->fieldName]; // copy the content to textObject[row-1]; [self copyLoc:location ofObject:theObject to:row-1]; } else{ // copy into a formcell [[entryForm cellAt:j :0] setTitleFont:theFont]; [entryForm setTitle:[self titleOf:item] at:j]; item->tag = j; multiLine = [self fillFormAt:j for:location]; [self addMarker:multiLine at:j]; j++; } } } [noteMatrix sizeToCells]; [marker sizeToCells]; noteIsDirty = NO; [self noteSelect:[noteMatrix selectCellAt:actualRow :0]]; if( mustEnable ) [inspector reenableDisplay]; } // here is a method envoked from controller and finder - setEntry:anObject inFile:(BibliographicFile *)file { locType range; if( inspector==nil ){ if( file ) [self firstCall]; // else no inspector needed else return self; } if(0)if( isDirty==YES ){ // doesn't work int rtn; //fprintf( stderr, "isdirty\n" ); rtn = NXRunAlertPanel("EntryInspector", // title "entry did change", // message " save ", // 1: default button " don't save ", // 0: alternate " " cancel " //-1: other " ); if( rtn==NX_ALERTDEFAULT ){ //[self entryChangedIsNew:isNew]; //[self makeEntry:self]; } if( rtn==NX_ALERTOTHER ) return self; } keyIsValid = (anObject==nil) ? NO : YES; objWithThisKey = anObject; if( (theObject==anObject) && (theFile==file) ){ if( isDirty==NO ) return self; isDirty=NO; // restore } theObject = anObject; theFile = file; [entryForm setAutosizing:entryFormMask]; [scrollView setAutosizing:scrollViewMask]; if( (theFile == nil) || (theObject == nil) ){ [self clear:self]; return self; } [inspector disableDisplay]; [inspector endEditingFor:nil]; [self enableAddButton]; // set the filename as title [self enableReplaceButton]; // sets key as title [self updateButtons]; // theObject and theFile are both existent [inspector setTitleAsFilename:[theFile fullPath]]; if( NO /*isDirty==YES*/ ){ //entryType = aType; } else { [theObject parseSelf]; [leftBraceButton setState:( [theObject delimiter]==RBRACE )?0:1]; [rightBraceButton setState:( [theObject delimiter]==RBRACE )?0:1]; if(0)if( (entryType==[theObject entryType]) && (prefsDidChange==NO) ){ // the new entry is the same entrytype as the former entry // we need no resizing, no new toggle buttons [self fillTemplate]; [inspector orderFront:self]; return self; } prefsDidChange=NO; entryType=[theObject entryType]; [keyField setEnabled:YES]; if( entryType==STRING ){ NXAttachPopUpList( popUpButton, popUpListString ); [keyForm setNextText:noteView]; } else if( entryType==PREAMBLE ){ NXAttachPopUpList( popUpButton, popUpListPreamble ); [keyField setEnabled:NO]; } else if( entryType==COMMENT ){ NXAttachPopUpList( popUpButton, popUpListComment ); [keyField setEnabled:NO]; } else{ NXAttachPopUpList( popUpButton, popUpList ); [keyForm setNextText:entryForm]; } isDirty = NO; isNew = NO; } [theObject setKeyTo:keyField]; range = [theObject range]; sprintf( [viewBuffer buffer], "line %d, charpos %d, length %d", [theObject line], range.start, range.length ); [positionField setStringValue:[viewBuffer buffer]]; [self showAllFieldsFor:entryType]; // and now resize the window [self resizeInspector:&newWindowFrame]; [self setToggleButtonsFor:entryType]; [popUpButton setTitle: (const char *)[entryNameList objectAt:entryType]]; [inspector reenableDisplay]; [self displayEntry:self]; return self; } - displayEntry:sender { [inspector placeWindowAndDisplay:&newWindowFrame]; [inspector orderFront:self]; return self; } // erases the form, nothing else is changed - clear:sender { int rows, cols, i; if( inspector==nil ) return self; [inspector disableDisplay]; [inspector endEditingFor:nil]; if( theFile ){ [inspector setTitleAsFilename:[theFile fullPath]]; //[self callSomethingNotImplemented]; // Make me crash!!! } else{ [inspector setTitle:"Entry Panel"]; } [entryForm getNumRows:&rows numCols:&cols]; for( i=0; i<rows; i++ ){ [entryForm setStringValue:NULL at:i]; [[marker cellAt:i :0] setStringValue:NULL]; } [keyField setStringValue:NULL]; //[noteView setText:""]; // loescht nicht isDirty = (theObject)? YES :NO; // --> revert is possible keyIsValid = NO; [self updateButtons]; [clearButton setEnabled:NO]; [self clearConfigList]; // !!!! [[inspector reenableDisplay] displayIfNeeded]; [marker display]; [noteView setText:""]; [scrollView displayIfNeeded]; return self; } - bibPopup:sender // sender is Matrix { int originalEntryType = [theObject entryType]; entryType = [sender selectedRow]; if( theObject==nil ){ [self drawTemplate:entryType]; return self; } entryType = [sender selectedRow]; if( ((originalEntryType==STRING) && (entryType!=STRING)) || ((originalEntryType!=STRING) && (entryType==STRING)) ){ NXRunAlertPanel("EntryInspector", // title "you cannot change %s to %s", // message " OK ", // 1: default button NULL, // 0: alternate " NULL, //-1: other " (const char *)[entryNameList objectAt:originalEntryType], (const char *)[entryNameList objectAt:entryType] ); [sender selectCellAt:originalEntryType :0]; return self; } [inspector endEditingFor:nil]; isDirty = isDirty || (entryType!=[theObject entryType]); [self drawTemplate:entryType]; // empty inspector [self fillTemplate]; [self updateButtons]; return self; } - (BOOL)saveDigitsFrom:(int)inx :(const char *)txt { char *digitText; int count = 0; while( NXIsSpace(*txt) ) txt++; if( *txt=='\0' ) return NO; digitText = (char *)txt; // first digit while( NXIsDigit(*txt) ){ txt++; count++; } while( NXIsSpace(*txt) ) txt++; // trailing blanks if( *txt ) return NO; NXPrintf( localStream, ",\n\t%s\t= ", [self stringOf:[entryForm titleAt:inx]] ); while( count-- ){ NXPutc( localStream, *digitText ); digitText++; } return YES; } - convert:(const char *)txt toStream:(NXStream *)toStream { unsigned char c; int i = 0; int level = 0; BOOL leftPartIsEmpty = YES; // skip over blanks c = txt[0]; while( NXIsSpace(c) ) c = txt[++i]; if( c=='\0' ) return self; // empty text while( YES ){ if( c=='\0' ) return self; if( c!='@' ){ if( leftPartIsEmpty==NO ) ADD_HASH_MARK; NXPutc(toStream, LBRACE); while( c && ( (c!='@')||(level>0) ) ){ if( c>=0x80 ){ unsigned char tc; const char *texText = [BibTexParser NX2TeX][ c-0x80 ]; while( tc = *texText++ ) NXPutc(toStream, tc); } else NXPutc(toStream, c); if( c==LBRACE ) level++; if( c==RBRACE ) level--; c = txt[++i]; } NXPutc(toStream, RBRACE); if( c=='\0' ) return self; leftPartIsEmpty = NO; } // c == '@' if( leftPartIsEmpty==NO ) ADD_HASH_MARK; c = txt[++i]; //while( NXIsAlpha(c) ) // STRING allows more characters --> theTen while( c && (c!=',') && !NXIsSpace(c) && (c!='@') ){ NXPutc(toStream, c); c = txt[++i]; leftPartIsEmpty = NO; } while( NXIsSpace(c) ) c = txt[++i]; // skip trailing blanks } return self; } - parseKey { int first, last,i=0; const char *key; char keyBuffer[64]; if( (entryType==PREAMBLE)||(entryType==COMMENT) ){ keyIsValid = YES; objWithThisKey=theObject; return self; } keyIsValid = [self key:[keyField stringValue] isValidFrom:&first to:&last]; if( keyIsValid==NO ){ objWithThisKey = nil; return self; } key = [keyField stringValue]; while( *key ){ keyBuffer[i++] = *key++; } // copy the key keyBuffer[last] = '\0'; objWithThisKey = [theFile findKey:&keyBuffer[first]]; return self; } - entryChangedIsNew:(BOOL)n { isNew = n; isDirty = NO; [self makeEntry:self]; [theFile setDirty]; [self parseKey]; [self updateButtons]; return self; } - addNewEntry:sender { return [self entryChangedIsNew:YES]; } - replaceEntry:sender { return [self entryChangedIsNew:NO]; } - (BOOL) textIsEmpty:(const char *)txt { int i = 0; unsigned char c = txt[0]; while( NXIsSpace(c) ) c = txt[++i]; return c=='\0'; } - makeEntry:sender // from add-/replace button { int rows, cols, i, pos; char *outString; NXStream *theStream; if(0)if( theObject==nil ){ // it's really new theStream = [theFile stream]; return self; } if ( localStream==NULL ){ localStream = NXOpenMemory( NULL, 0, NX_READWRITE ); } NXSeek(localStream, 0, NX_FROMSTART); [entryForm getNumRows:&rows numCols:&cols]; // update changes (if any) if( noteIsDirty ){ // write the text back to the buffer char *actualTextBuffer = [self listBufferFor:actualRow size:[noteView textLength]+1]; [noteView getSubstring:actualTextBuffer start:0 length:[noteView textLength]+1]; } // print all fields from the view if( entryType==PREAMBLE ){ // PREAMBLE has no keyfield THE_TYPE; // @PREAMBLE BIG_LEFT; //LEFTQUOTE; ACTUALBUFFER; RIGHTQUOTE; ACTUALBUFFER; BIG_RIGHT; } else if( entryType==COMMENT ){ // COMMENT has no keyfield THE_TYPE; // @COMMENT BIG_LEFT; ACTUALBUFFER; BIG_RIGHT; } else if( entryType==STRING ){ THE_TYPE; // @STRING BIG_LEFT; //THE_KEY; ASSIGN; LEFTQUOTE; ACTUALBUFFER; RIGHTQUOTE; THE_KEY; ASSIGN; ACTUALBUFFER; BIG_RIGHT; } else{ THE_TYPE; // @BOOK or so BIG_LEFT; THE_KEY; // key value for( i=0; i<[configList count]; i++ ){ locType location; configListType *item = ((configListType*)[configList elementAt:i]); int tag = item->tag; int mode = item->mode[entryType]; //fprintf( stderr, "%3d %s\n", item->tag, item->fieldName ); if( (tag>=0) && [entryForm stringValueAt:tag] && (![self textIsEmpty:[entryForm stringValueAt:tag]]) ){ outString = (char *)[self convertText:tag]; // check for digits if( [self saveDigitsFrom:tag :outString] ) continue; NEXTENTRY([self stringOf:[entryForm titleAt:tag]]); //LEFTQUOTE; [self convert:[entryForm stringValueAt:tag] toStream:localStream]; //RIGHTQUOTE; } else if( (tag<0) && !(LARGE IN mode) ) { location.start = item->start; // set by the parser location.length = item->length; if( location.length > 0 ){ NXPrintf( localStream, ",\n\t%s\t= ", item->fieldName ); [theObject copyRange:location toStream:localStream]; } } } // copy LARGE entry fields { int row, col, i; [noteMatrix getNumRows:&row numCols:&col]; for( i=0; i<row; i++ ){ id cell = [noteMatrix cellAt:i :0]; char *buffer = [self listBufferFor:i]; if( buffer && (![self textIsEmpty:buffer]) ){ NEXTENTRY([cell title]); //LEFTQUOTE; [self convert:(const char *)buffer toStream:localStream]; //RIGHTQUOTE; } } } NEWLINE; BIG_RIGHT; } NXFlush( localStream ); pos = NXTell( localStream ); // we need the buffer of this stream for NXWrite NXGetMemoryBuffer( localStream, &localBuffer, &locBufferLength, &locBufferMaxLength); // we have now a bibtex - conforming text of the entryObject // append the text if( isNew==YES ){ theObject = [theFile appendNewText:pos :localBuffer]; [theObject parseSelf]; // @@@@@ 1.1 } else{ //[theFile replace:pos :localBuffer forObject:theObject]; [theFile replaceTextOf:theObject with:localBuffer length:pos]; } [[NXApp delegate] update:theObject for:theFile isNew:isNew shiftLit:NO]; return self; } - revert:sender { isDirty=YES; [self setEntry:theObject inFile:theFile]; //isDirty=NO; [self updateButtons]; return self; } // copy selected text to findPasteBoard - enterSelection:sender { [[NXApp delegate] enterSelectionFor:[inspector firstResponder]]; return self; } - mainBrace:sender { [leftBraceButton setState:[sender state]]; [rightBraceButton setState:[sender state]]; if( theFile ){ isDirty = YES; [self updateButtons]; } return self; } - showCharPanel:sender { [[charMatrix window] orderFront:self]; return self; } - insertText:(char *)txt { id keyWindow = [NXApp keyWindow]; id delegate = [keyWindow delegate]; id editor = [keyWindow firstResponder]; NXSelPt start, end; if( ![editor respondsTo:@selector(getSel::)] ) return self; [editor getSel:&start :&end]; [editor replaceSel:txt]; if( [delegate respondsTo:@selector(textDidGetKeys:isEmpty:)] ){ [delegate textDidGetKeys:editor isEmpty:NO]; } return self; } extern fnct_convertRawString(); - insertMacro:(char *)txt isRaw:(BOOL)isRaw { id editor = [inspector firstResponder]; NXSelPt start, end; if( ![editor isKindOf:[Text class]] ){ return self; } else [editor getSel:&start :&end]; if( start.cp<0 ){ // nothing selected (noteView?) return self; //[editor getSel:&start :&end]; } if( isRaw ){ [viewBuffer setMinSizeTo:strlen(txt)+1]; fnct_convertRawString(txt, [viewBuffer buffer] ); [editor replaceSel:[viewBuffer buffer]]; } else [editor replaceSel:txt]; //[editor showCaret]; [self textDidGetKeys:editor isEmpty:NO]; return self; } - specialMatrix:sender { [self insertText:(char *)[[sender selectedCell] title]]; return self; } // * * * * * * * delegate methods - windowDidResignKey:sender { return self; } - windowWillReturnFieldEditor:sender toObject:client { return nil; // we need something like 'endEditingfor:' fprintf( stderr, "client is %s", [client name] ); if( [client class]==[Button class] ){ fprintf( stderr, " %s", [client title] ); } if( [client class]==[TextField class] ){ fprintf( stderr, " %d", [client tag] ); } fprintf( stderr, "\n" ); if( [client class]==[Form class] ){ if(0)[sender perform:@selector(endEditingFor:) with:(id)nil afterDelay:0 cancelPrevious:YES]; if(1) fprintf( stderr, "sender is %s firstResponder = %s index=%d tag=%d\n", [sender name], [[sender firstResponder] name], [client selectedIndex], [client tag] ); [sender endEditingFor:nil]; return fieldEditor; } return nil; } - windowWillResize:sender toSize:(NXSize *)frameSize { [entryForm setAutosizing: NX_WIDTHSIZABLE | NX_MINYMARGINSIZABLE]; [marker setAutosizing: NX_MINXMARGINSIZABLE | NX_MINYMARGINSIZABLE]; [scrollView setAutosizing: NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE ]; return self; } - windowDidResize:sender { NXRect newFrame; [inspector getFrame:&newFrame]; [sender endEditingFor:nil]; windowFrame.W = newFrame.W; windowFrame.X = newFrame.X; [entryForm setAutosizing:entryFormMask]; // @@@@ 1.1 [scrollView setAutosizing:scrollViewMask]; [marker setAutosizing:markerMask]; return self; } - windowDidMove:sender { NXRect newFrame; [inspector getFrame:&newFrame]; windowFrame.X = newFrame.X; windowFrame.Y = newFrame.Y + newFrame.H; // northwest_corner return self; } - textDidGetKeys:sender isEmpty:(BOOL)flag { if(0)fprintf( stderr, "sender is %s resp=%s, tag=%d\n", [sender name], [[inspector firstResponder]name], [[sender delegate] tag] ); if( [[sender delegate] tag] == KEY_FIELD_TAG ){ [self parseKey]; if( theFile ) [self updateButtons]; return self; } isDirty = YES; if( theFile ) [self updateButtons]; // set the marker if( [[sender delegate] tag]==FORM_FIELD_TAG ){ int i = 0; char c; int row = [[sender delegate] selectedRow]; const char *theString = [[sender delegate] stringValueAt:row]; if( theString==NULL ) return self; while( c=theString[i++] ){ if( c=='\n' )break; } [self setMarker:c=='\n' at:row]; } noteIsDirty = YES; return self; } - (BOOL)testSyntaxFor:(const char *)txt // returns NO, if this method has no objections { char c; int braceLevel = 0, paraLevel = 0; if( (txt==NULL) || (*txt=='\0') ) return NO; while( c=*txt++ ){ if( c==LBRACE ) braceLevel++; else if( c==RBRACE ) braceLevel--; else if( c==LPARA ) paraLevel++; else if( c==RPARA ) paraLevel--; } if( braceLevel || paraLevel ) return YES; return NO; } - (BOOL)testSyntaxForStream:(NXStream *)str // returns NO, if this method has no objections { char c; int braceLevel = 0, paraLevel = 0; NXSeek( str, 0, NX_FROMSTART ); while( (c = NXGetc( str ))!=EOF ){ if( c==LBRACE ) braceLevel++; else if( c==RBRACE ) braceLevel--; else if( c==LPARA ) paraLevel++; else if( c==RPARA ) paraLevel--; } if( braceLevel || paraLevel ){ NXBeep(); return YES; } return NO; } - (BOOL)textWillEnd:sender { //fprintf( stderr, "textWillEnd sender is %s\n", [sender name] ); //fprintf( stderr, "textWillEnd delagte is %s\n", [[sender delegate] name] ); //fprintf( stderr, "textWillEnd tag is %d\n", [[sender delegate] tag] ); if( [sender tag]==NOTE_TEXT_TAG ){ if( noteIsDirty==NO ) return NO; // test text return [self testSyntaxForStream:[noteView stream]]; } if( [[sender delegate] tag]==KEY_FIELD_TAG ){ return NO; // key is ok } if( [[sender delegate] tag]==FORM_FIELD_TAG ){ int row = [[sender delegate] selectedRow]; // sender delegate is Form --> Matrix return [self testSyntaxFor: [[sender delegate] stringValueAt:row]]; } return NO; } - XXXXtextDidEnd:sender endChar:(unsigned short)whyEnd { int i = 0; char *theString, c; if( [[sender delegate] tag]==FORM_FIELD_TAG ){ int row = [[sender delegate] selectedRow]; theString = (char *)[[sender delegate] stringValueAt:row]; if( theString==NULL ) return self; while( c=theString[i++] ){ if( c=='\n' )break; } [self setMarker:c=='\n' at:row]; } return self; } - (BOOL)shouldDelayWindowOrderingForEvent:(NXEvent *)theEvent { // This is the other portion of the new appkit functionality // which allows you to drag a partially obscure object without // making the source window become main, and without making the // source application the current app. fprintf( stderr, "shouldDelayWindow\n" ); return YES; } - (BOOL)acceptsFirstMouse { fprintf( stderr, "acceptsFirstMouse\n" ); return YES; } - (BOOL)updateMenuFor:menuCell { BOOL newState=NO; // .. and the compiler keeps silent //BOOL isEnabled = [menuCell isEnabled]; switch( [menuCell tag] ){ case CUT : newState = YES; break; case COPY : newState = YES; break; case PASTE : newState = YES; break; case SELECTALL : newState = YES; break; case ENTERSELECTION : newState = YES; break; default : newState = [[[NXApp mainWindow] delegate]updateMenuFor:menuCell]; break; } return newState; } - setBacking:sender { [inspector setBackingType: ([sender state]==1) ? NX_BUFFERED :NX_RETAINED]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.