This is Preferences.m in view mode; [Download] [Up]
// Copyright H. Giesen, University of Koblenz-Landau 1996 #import "Preferences.h" #import "Controller.h" #import "BibliographicFile.h" #import "BibTexView.h" #import "Shelf.h" #import "MacroDB.h" #import "TabMatrix.h" #import <dbkit/dbkit.h> #import <ansi/time.h> #import <sys/types.h> #import <pwd.h> typedef struct _passwd { /* see getpwent(3) */ char *pw_name; char *pw_passwd; int pw_uid; int pw_gid; int pw_quota; char *pw_comment; char *pw_gecos; char *pw_dir; char *pw_shell; } passwd; #define ADD 4 #define REN 2 #define DEL 1 extern int errno; static unsigned char buttonTable[] = { 0, DEL, ADD, ADD, 0, DEL, ADD+REN, ADD+REN }; /**************** Es werden zwei Listen verwaltet: 1: die Liste aller Entrynames -> entryNameList 2: die Eigenschaften eines jeden Entry findet man in der configList bei mode[i] zu einem gegebenen Index i findet man in entryNameList[i] den Namen des Entry und in configList[i] alle zugehoerigen Eigenschaften Wichtig: Sonderbehandlung von STRING und PREAMBLE und COMMENT Diese "Entries" stehen am Ende der entryNameList. Eine Beschreibung der Eigenschaften in der configList fehlt dagegen, weil immer eine Sonderbehandlung erforderlich ist. Die Liste der Entrynames ist also groesser als die Liste der Eigenschaften. Die entryNameList soll beim Erstellen von PopUpMenus verwendet werden. ****************/ static id thePreference = nil; static NXAtom STRING ; static NXAtom PREAMBLE; static NXAtom COMMENT; @implementation Preferences + new { if( thePreference==nil ){ thePreference = [[super alloc] init]; } return thePreference; } + alloc { return [self notImplemented:_cmd]; } - (void)alert:(const char *)txt :(const char *)para { NXRunAlertPanel("Bibliography", txt, " OK ", // 1: default button NULL, // 0: alternate NULL, //-1: other para ); } - (int)findIndexFor:(int)inx :(unsigned char)label { int i = 0; while( toggleList[i].entryIndex ){ if( (toggleList[i].entryIndex==inx) && (toggleList[i].label==label) ){ // that's it return i; } i++; } // not found, create a new entry toggleList[i].entryIndex = inx; toggleList[i].label = label; toggleList[i].state = 0; return i; } // NO CHECK ????? - (void)insert:(NXAtom)txt at:(int)inx { if( toggleList[inx].txt0 ){ // second entry toggleList[inx].txt1 = txt; if( inx ){ if( toggleList[inx].entryIndex == toggleList[inx-1].entryIndex ) toggleList[inx].tglButtonInx = toggleList[inx-1].tglButtonInx + 1; else toggleList[inx].tglButtonInx = 0; } } else toggleList[inx].txt0 = txt; } - (toggleListType *)toggleList { return toggleList; } - (void)activatePopUpList { // connect the popUpList to the trigger Button // this can only be done if the nib-file is loaded // before loading we have no popUpButton [popUpButton setFont:[Font newFont:"Courier" size:12.0 ]]; NXAttachPopUpList( popUpButton, popUpList ); [popUpList sizeButton:popUpButton]; [[popUpList setAction:@selector(bibPopup:)] setTarget:self]; entryIndex = 0; } // show all options for entryType at index 'inx' in entryNameList - (void)showOptionsFor:(int)inx { if( [popUpList target]!=self ) [self activatePopUpList]; [[showBox window] disableDisplay]; [[showBox window] endEditingFor:nil]; // fill tableView (assuming 'inx' did change) [tableView rowsChangedFrom:0 to:[configList count]-1]; [tableView layoutChanged:self]; [[[showBox window] reenableDisplay] display]; } - (void)setButtonsFor:(char *)name { int mode, state; int inx; mode = ([tableView selectedRow]>=0) ? ADD : 0; if( (inx=[self indexOfFieldname:name])<0 ) mode |= REN; if( inx>=0 ) mode |= DEL; state = buttonTable[ mode ]; [addButton setEnabled:(state&ADD)==ADD]; [renameButton setEnabled:(state&REN)==REN]; [deleteButton setEnabled:(state&DEL)==DEL]; } - (void) readDefaults { const char *defBuffer; defBuffer = NXReadDefault("Bibliography", "FieldConversion"); if( defBuffer==NULL ) fieldConversion = 0; else fieldConversion = atoi( defBuffer ); defBuffer = NXReadDefault("Bibliography", "EntryConversion"); if( defBuffer==NULL ) entryConversion = 0; else entryConversion = atoi( defBuffer ); defBuffer = NXReadDefault("Bibliography", "Remove"); if( defBuffer==NULL ) removeTemp = YES; else removeTemp = defBuffer[0]=='Y'; } // set defaults from radio buttons - fieldFormatButton:sender { char fBuf[4]; fieldConversion = [fieldRadio selectedRow]; fBuf[0] = '0' + fieldConversion; fBuf[1] = '\0'; NXWriteDefault("Bibliography", "FieldConversion", fBuf ); return self; } - entryFormatButton:sender { char fBuf[4]; entryConversion = [entryRadio selectedRow]; fBuf[0] = '0' + entryConversion; fBuf[1] = '\0'; NXWriteDefault("Bibliography", "EntryConversion", fBuf ); return self; } /* ==== the configuration is saved in ~/Library/Bibliography/config ==== */ - init { int index; char buffer[1024]; passwd *userData; STRING = NXUniqueString( "STRING" ); PREAMBLE = NXUniqueString( "PREAMBLE" ); COMMENT = NXUniqueString( "COMMENT" ); [super init]; // create and make the temporary directory sprintf( buffer, "/tmp/BIB%08d", getpid() ); tempDir = NXCopyStringBuffer(buffer); mkdir( (const char *)tempDir, 0755 ); // create and make the library sprintf( buffer, "%s/Library", NXHomeDirectory() ); if( mkdir( (const char *)buffer, 0755 )<0 ){ if( errno!=EEXIST ){ strcat(buffer, " %s" ); [self alert:buffer :strerror(errno)]; } } sprintf( buffer, "%s/Library/Bibliography", NXHomeDirectory() ); libDir = NXCopyStringBuffer(buffer); if( mkdir( (const char *)buffer, 0755 )<0 ){ if( errno!=EEXIST ){ strcat(buffer, " %s" ); [self alert:buffer :strerror(errno)]; } } // configuration file sprintf( buffer, "%s/config", libDir ); configurationFile = NXCopyStringBuffer(buffer); // shelf file sprintf( buffer, "%s/shelf", libDir ); shelfFile = NXCopyStringBuffer(buffer); // TeX template file sprintf( buffer, "%s/texTemplate.tex", libDir ); templateFile = NXCopyStringBuffer(buffer); // read defaults from database [self readDefaults]; // set the shell userData = (passwd *)getpwuid( getuid() ); theShell = NXCopyStringBuffer(userData->pw_shell); // set the editor sprintf( buffer, "Edit" ); theEditor = NXCopyStringBuffer(buffer); // set the style sprintf( buffer, "alpha" ); theStyle = NXCopyStringBuffer(buffer); [self parse]; // fill entryNameList and configList // special entries [entryNameList addObject:(id)STRING]; [entryNameList addObject:(id)PREAMBLE]; [entryNameList addObject:(id)COMMENT]; popUpList = [[PopUpList alloc] init]; for( index=0; index<[entryNameList count]; index++ ){ const char *name = (const char *)[entryNameList objectAt:index]; if( name==STRING ) continue; if( name==PREAMBLE ) continue; if( name==COMMENT ) continue; [popUpList addItem:name]; } [[showBox window] useOptimizedDrawing:YES]; inspector = [BibTexView new]; tableViewIsLoaded = NO; if( toggleList[0].entryIndex==0 ){ NXRunAlertPanel("Bibliography", "Your configurationfile is not uptodate,\n" " (You cannot toggle Author<Ð>Editor,)\n" "Erase ~/Library/Bibliography/config\n", " OK ", // 1: default button NULL, // 0: alternate NULL //-1: other ); } if( [self canExecuteProgram:"bibtex"]==NO ){ [self alert:"you cannot execute %s" :"bibtex"]; } if( [self canExecuteProgram:"latex"]==NO ){ [self alert:"you cannot execute %s" :"latex"]; } return self; } - (void)outMode:(FILE *)stream :(const char *)name :(int)m { unsigned int tgl; fprintf( stream, "%s %c", name, (m&SHOW)? '+' : '-' ); if( m&LARGE )fprintf( stream, "L" ); fprintf( stream, "%c", "XROC"[m&3] ); if( tgl=((m>>8)&0xff) )fprintf( stream, "T%c", tgl ); } - (char *)timeStamp { time_t timeptr = time( NULL ); return( asctime( localtime( &timeptr ) ) ); } // called from a button - saveConfiguration:sender { int i, j; FILE *fileStream = NULL; configListType item; int mode; BOOL out; if( configurationFile && (fileStream = fopen( configurationFile, "w+" ) )==NULL ){ [self alert:"cannot open configuration file %s" :configurationFile]; return self; } fprintf( fileStream, "\n\n%%%%%%generated by Bibliography.app\n" ); fprintf( fileStream, "%%%%%%\t\t%s\n", [self timeStamp] ); fprintf( fileStream, "%%%%%%handle with care\n\n" ); for( i=0; i<[entryNameList count]; i++ ){ // for all entryNames if( (NXAtom)[entryNameList objectAt:i]==STRING ) continue; if( (NXAtom)[entryNameList objectAt:i]==PREAMBLE ) continue; if( (NXAtom)[entryNameList objectAt:i]==COMMENT ) continue; fprintf( fileStream, "\n%s %c\n\t%c", (char *)[entryNameList objectAt:i], LBRACE, LBRACE ); out = NO; for( j=0; j<[configList count]; j++ ){ // for required fieldNames item = *((configListType*)[configList elementAt:j]); mode = item.mode[i]; if( (mode&3)==REQUIRED ){ if( out ) fprintf( fileStream, ", " ); [self outMode:fileStream :item.fieldName :mode]; out = YES; } } fprintf( fileStream, "%c\n\t%c", RBRACE, LBRACE ); out = NO; for( j=0; j<[configList count]; j++ ){ // for optional fieldNames item = *((configListType*)[configList elementAt:j]); mode = item.mode[i]; if( (mode&3)==OPTIONAL ){ if( out ) fprintf( fileStream, ", " ); [self outMode:fileStream :item.fieldName :mode]; out = YES; } } fprintf( fileStream, "%c\n\t%c", RBRACE, LBRACE ); out = NO; for( j=0; j<[configList count]; j++ ){ // for custom fieldNames item = *((configListType*)[configList elementAt:j]); mode = item.mode[i]; if( (mode&3)==CUSTOM ){ if( out ) fprintf( fileStream, ", " ); [self outMode:fileStream :item.fieldName :mode]; out = YES; } } fprintf( fileStream, "%c\n", RBRACE ); fprintf( fileStream, "%c\n", RBRACE ); } fclose( fileStream ); NXWriteDefault("Bibliography", "FieldConversion", "2"); NXWriteDefault("Bibliography", "EntryConversion", "2"); NXWriteDefault("Bibliography", "Remove", removeTemp?"YES":"NO"); return self; } - (void)shelfSettings { int i, row; theShelf = [[NXApp delegate] theShelf]; if( theShelf==nil ) return; [shelfMatrix renewRows:0 cols:1]; for(i=0, row=0; i<[theShelf count]; i++){ const char *fn = [theShelf filenameOfIconAt:i]; id cell; [shelfMatrix addRow]; cell = [shelfMatrix cellAt:row :0]; if( fn ){ [cell setTitle:fn]; [cell setState:[theShelf getstateOfIconAt:i]]; [cell setEnabled:YES]; } else{ [cell setTitle:" <empty>"]; [cell setEnabled:NO]; } row++; } [shelfMatrix sizeToCells]; } - nextShell:sender { char *sh = getusershell(); if( access("/usr/bin/bibtex", F_OK)<0 ){ [self alert:"cannot access %s" :"bibtex"]; //return self; } if( sh==NULL ){ setusershell(); sh = getusershell(); } if( access(sh, F_OK)<0 ){ [self alert:"the shell %s does not exist" :sh]; return self; } if( access(sh, X_OK)<0 ){ [self alert:"the shell %s is not executable" :sh]; return self; } if( theShell ) free( (char *)theShell ); theShell = NXCopyStringBuffer( sh ); [defaultForm setStringValue:theShell at:2]; return self; } - shelfDidChange { [self shelfSettings]; [[showBox window] display]; return self; } - saveShelf:sender { int i, rows, cols; FILE *fileStream = NULL; if( shelfFile && (fileStream = fopen( shelfFile, "w+" ) )==NULL ){ [self alert:"cannot open shelf %s" :shelfFile]; return nil; } fprintf( fileStream, "\n\n%%%%%% shelf generated by Bibliography.app\n" ); fprintf( fileStream, "%%%%%%\t\t%s\n", [self timeStamp] ); fprintf( fileStream, "%%%%%% handle with care\n\n" ); [shelfMatrix getNumRows:&rows numCols:&cols]; for(i=0; i<rows; i++){ id cell = [shelfMatrix cellAt:i :0]; fprintf( fileStream, "\"%s\" %c \n", [cell title], "-+"[[cell state]] ); } fclose( fileStream ); return self; } // valid formats are: // 0 : no conversion // 1 : abcde // 2 : ABCDE // 3 : Abcde - (void)convert:(char *)txt mode:(int)mode { char c; BOOL first=YES; if( mode==0 ) return; while( c=*txt ){ switch( mode ){ case 0: break; // no conversion case 1: if( NXIsUpper(c) ) *txt = NXToLower(c); break; case 2: if( NXIsLower(c) ) *txt = NXToUpper(c); break; case 3: if( first ){ if( NXIsLower(c) ) *txt = NXToUpper(c); first = NO; } else if( NXIsUpper(c) ) *txt = NXToLower(c); break; default: break; } txt++; } } // a (hopefully) new field is added to configList - (void)addCustomField:(char *)name { int i; configListType item; // new fieldname for( i=0; i<MODESIZE; i++ ) item.mode[ i ] = CUSTOM | SHOW; [self convert:name mode:fieldConversion]; item.fieldName = NXUniqueString( name ); [self fieldNameList]; // it really now exists [configList addElement:&item]; // not sorted [fieldNameList addObject:(id)item.fieldName]; if( tableViewIsLoaded){ [[showBox window] disableDisplay]; [tableView addRow:(id)item.fieldName withTitle:item.fieldName]; [tableView rowsChangedFrom:rowCount to:rowCount]; [tableView setRowHeadingVisible:YES]; rowCount++; [tableView scrollRowToVisible:rowCount]; [[showBox window] reenableDisplay]; } if( prefPanel ){ [self showOptionsFor:entryIndex]; } [inspector prefsDidChange]; } // activated from 'ADD' - button - addFieldName:sender { int inx; inx = [self indexOfFieldname:[fieldNameField stringValue]]; if( inx>=0 ) return self; // name already exists if( ([fieldNameField stringValue]==NULL) || [fieldNameField stringValue][0]=='\0' ) return self; [self addCustomField:(char *)[fieldNameField stringValue]]; [addButton setEnabled:NO]; return self; } - changeFieldname:sender // geht nicht { int inx; inx = [self indexOfFieldname:[fieldNameField stringValue]]; if( inx<0 ) return self; // name does not exists fprintf( stderr, "index of %s is %d\n", [fieldNameField stringValue], inx ); fprintf( stderr, "changeEntryname \n" ); return self; } - deleteFieldname:sender { int inx; configListType *item; inx = [self indexOfFieldname:[fieldNameField stringValue]]; if( inx<0 ) return self; // name does not exists item = ((configListType*)[configList elementAt:inx]); //fprintf( stderr, "%d %s %d\n", inx, item->fieldName, (item->mode[0]&3)); if( (item->mode[0]&3) != CUSTOM ){ // do not delete ! @@@ if( BIBTEST ) fprintf( stderr, "do not delete\n" ); return self; } [[showBox window] disableDisplay]; [configList removeElementAt:inx]; [fieldNameList removeObjectAt:inx]; [tableView rowAt:inx]; //[[tableView rowAt:inx] free]; [tableView removeRowAt:inx]; [tableView rowsChangedFrom:0 to:rowCount]; rowCount--; [tableView setRowHeadingVisible:YES]; [tableView scrollRowToVisible:rowCount-1]; [[showBox window] reenableDisplay]; [tableView display]; [inspector prefsDidChange]; return self; } // sets the mode "m" for the fieldname "name" at index 'actual entryType' // if the field exists it is changed // otherwise a new field is added to configList // called from readConfigList - addField:(NXAtom)name mode:(unsigned short)m { int i; configListType *item, newItem; int inx = [entryNameList count] - 1; // index of actual (??) entryType for( i=0; i<[configList count]; i++ ){ // new fieldname ? item = ((configListType*)[configList elementAt:i]); if( (item->fieldName)==name ){ item->mode[ inx ] = m; return self; } } // new fieldname for( i=0; i<MODESIZE; i++ ) newItem.mode[ i ] = 0; newItem.fieldName = name; newItem.mode[ inx ] = m; [configList addElement:&newItem]; [inspector prefsDidChange]; return self; } - (void) nextToken { if( token=='\n' ){ lineNumber++; } token = NXGetc( configStream ); } - (void) skip { while( NXIsSpace(token) || (token=='%') ){ if( token=='%' ){ // skip to end of line while( (token!='\n') && (token!=EOF) ) [self nextToken]; } else [self nextToken]; } } - (NXAtom) getEntryName { char buf[128]; int i = 0; while( NXIsAlpha(token) ){ buf[i] = token; i++; [self nextToken]; } buf[i] = '\0'; [self convert:buf mode:entryConversion]; return NXUniqueString( (const char *)buf ); } #define isOneOfTheTen(x) (x=='"' || x=='#' || x=='%' || x=='\''\ || x==LPARA || x==RPARA || x==',' || x=='=' || x==LBRACE || x==RBRACE) - (NXAtom) getFieldName { char buf[128]; int i = 0; while( !isOneOfTheTen(token) && token!=EOF && !NXIsSpace(token) ){ buf[i] = token; i++; [self nextToken]; } buf[i] = '\0'; [self convert:buf mode:fieldConversion]; return NXUniqueString( (const char *)buf ); } // precondition: token = LBRACE - (void) readConfigList { unsigned int mode=0; int j; NXAtom fieldName; [self nextToken]; // skip LBRACE [self skip]; while( token!=EOF ){ fieldName = [self getFieldName]; // read mode while( (token!=',') && (token!=RBRACE) && (token!=EOF)){ [self skip]; mode = 0; while( (token!=',') && (token!=RBRACE) && (token!=EOF)){ switch( token ){ case '+' : mode = SHOW; break; case '-' : break; case 'R' : mode |= REQUIRED; break; case 'O' : mode |= OPTIONAL; break; case 'C' : mode |= CUSTOM; break; case 'L' : mode |= LARGE; break; case 'T' : mode |= (NXGetc( configStream ))<<8; j = [self findIndexFor:[entryNameList count]-1 :(mode>>8)]; [self insert:fieldName at:j]; break; default : break; } [self nextToken]; } [self addField:fieldName mode:mode]; //[self nextToken]; } if( token==',' ){ [self nextToken]; // skip ',' [self skip]; } else if( token==RBRACE ){ [self nextToken]; // skip RBRACE' break; } } // postcondition = first char after (matching) RBRACE } static char *titles[] = {"mode", "show", "size"}; - setUpTableView { int i; rowCount = 0; columnCount = 3; [tableView setRowHeadingVisible:YES]; [tableView setColumnHeadingVisible:YES]; [tableView setDataSource:self]; [tableView setTarget:self]; [tableView setDelegate:self]; [tableView setAction:@selector(tableViewSingleClick:)]; [tableView setDoubleAction:@selector(tableViewDoubleClick:)]; [tableView setGridVisible:YES]; [tableView setEditable:NO]; [tableView allowVectorReordering:YES]; [tableView allowVectorResizing:YES]; [tableView removeColumnAt:0]; [tableView removeColumnAt:1]; for(i=0; i<columnCount; i++ ){ [tableView addColumn:(id)i withTitle:titles[i]]; [[tableView columnAt:i] setMinSize:45]; [[tableView columnAt:i] setMaxSize:90]; } return self; } - makeTableView { int index; for( index=0; index<[configList count]; index++ ){ configListType *item; item =((configListType*)[configList elementAt:index]); [tableView addRow:(id)item->fieldName withTitle:item->fieldName]; rowCount++; } return self; } - makeTabMatrix { NXRect backgroundRect,matrixRect; TabSelectionCell *aCell; unsigned int entryFormMask = [tabCellView autosizing]; //€as set in IB /* Set tabCellView to be flipped ('cause Matrices are flipped) */ [tabCellView setFlipped:YES]; /* Get the tabCellView's dimensions */ [tabCellView getBounds:&backgroundRect]; /* Set up the matrix bounds */ matrixRect = backgroundRect; matrixRect.origin.y = NX_MAXY(&matrixRect) - 17.0; /* Prepare a matrix to go inside the tabCellView */ tabMatrix = [[Matrix allocFromZone:[self zone]] initFrame:&matrixRect mode:NX_RADIOMODE cellClass:[TabSelectionCell class] numRows:1 numCols:5]; /* Set the background gray of tabMatrix to NX_DKGRAY */ [tabMatrix setBackgroundGray:NX_DKGRAY]; /* Set the autosizing and autoscrolling attributes of the matrix */ [tabMatrix setAutosizing:entryFormMask]; //[tabMatrix setAutoscroll:YES]; [tabMatrix setAutosizeCells:YES]; /* Stick the matrix in our scrollView */ [tabCellView addSubview:tabMatrix]; [tabCellView setAutoresizeSubviews:YES]; [tabCellView setAutosizing:entryFormMask]; /* Set our target and single-click actions */ [tabMatrix setTarget:self]; [tabMatrix setAction:@selector(tabMatrixAction:)]; aCell = [tabMatrix cellAt:0 :0]; [aCell initTextCell:"entries"]; aCell = [tabMatrix cellAt:0 :1]; [aCell initTextCell:"shelf"]; aCell = [tabMatrix cellAt:0 :2]; [aCell initTextCell:"styles"]; aCell = [tabMatrix cellAt:0 :3]; [aCell initTextCell:"general"]; aCell = [tabMatrix cellAt:0 :4]; [aCell initTextCell:"citation"]; /* Size tabMatrix to its cells and display it */ [tabMatrix sizeToCells]; [tabMatrix display]; return self; } - awakeFromNib { entryView = [entryView contentView]; shelfView = [shelfView contentView]; filenameView = [filenameView contentView]; styleView = [styleView contentView]; expertView = [expertView contentView]; [shelfMatrix setTarget:self]; [shelfMatrix setAction:@selector(openOnLaunch:)]; [prefPanel setFrameUsingName:"PreferencePanel"]; [prefPanel setFrameAutosaveName:"PreferencePanel"]; [addButton setEnabled:NO]; [renameButton setEnabled:NO]; [deleteButton setEnabled:NO]; [fieldNameField setStringValue:""]; // default buttons [fieldRadio selectCellAt:fieldConversion :0]; [entryRadio selectCellAt:entryConversion :0]; [removeTempButton setState:removeTemp==YES]; // style browser [styleBrowser setDelegate:self]; [styleBrowser setAction:@selector(styleSingleClick:)]; [styleBrowser setDoubleAction:@selector(styleDoubleClick:)]; [styleBrowser setMinColumnWidth:22]; [styleBrowser setMaxVisibleColumns:2]; [styleBrowser setTitle:"TEXINPUTS" ofColumn:0]; // prepare the tabCells [self makeTabMatrix]; /* other setup code */ return self; } - tabMatrixAction:sender { [[showBox window] disableDisplay]; switch( [sender selectedCol] ){ case 0: [showBox setContentView:entryView]; break; case 1: [showBox setContentView:shelfView]; break; case 2: [showBox setContentView:styleView]; [styleBrowser loadColumnZero]; break; case 3: [showBox setContentView:filenameView]; break; case 4: [showBox setContentView:expertView]; break; default : break; } [[showBox window] reenableDisplay]; [showBox display]; return self; } - (void) loadDefault { char buf[MAXPATHLEN]; id m = [NXBundle mainBundle]; // load configuration file from the bundle if( [m getPath:buf forResource:"Configuration" ofType:""] ){ configStream = NXMapFile(buf, NX_READONLY); } else { [self alert:"cannot load default file\n%s" :"Configuration"]; [self alert: "I am helpless without configuration" "\nApplication will abort"// message : NULL ]; exit( 77 ); } } - parse { char buf[64]; lineNumber = 1; sprintf( buf, "{%%ii[%dS]}", MODESIZE ); configList = [[Storage alloc] initCount:0 elementSize:sizeof(configListType) description:buf]; configStream = NXMapFile( configurationFile, NX_READONLY); if( configStream==NULL ) [self loadDefault]; entryNameList = [[List alloc] initCount:20]; NXSeek( configStream, 0, NX_FROMSTART ); // position [self nextToken]; // first token is now defined while( token!=EOF ){ NXAtom theName; [self skip]; if( token==EOF ) break; if( !NXIsAlpha(token) ){ fprintf( stderr, "error in line %d (char '%c' = %d)\n", lineNumber, token, token ); break; } theName = [self getEntryName]; // STRING is not allowed if( ! NXOrderStrings( theName, "STRING", NO, -1, NULL ) ){ [self alert: "STRING not allowed in preferences" "\nchange (or delete) your file" " %s/Library/Bibliography/config" "\nApplication will abort"// message : NXHomeDirectory() ]; exit( 77 ); } // PREAMBLE is not allowed if( ! NXOrderStrings( theName, "PREAMBLE", NO, -1, NULL ) ){ [self alert: "PREAMBLE not allowed in preferences" "\nchange (or delete) your file" " %s/Library/Bibliography/config" "\nApplication will abort"// message : NXHomeDirectory() ]; exit( 77 ); } // COMMENT is not allowed if( ! NXOrderStrings( theName, "COMMENT", NO, -1, NULL ) ){ [self alert: "COMMENT not allowed in preferences" "\nchange (or delete) your file" " %s/Library/Bibliography/config" "\nApplication will abort"// message : NXHomeDirectory() ]; exit( 77 ); } [entryNameList addObject:(id)theName]; [self skip]; if( token!=LBRACE ){ fprintf( stderr, "syntax error in line %d (char '%c' = %d)", lineNumber, token, token ); break; } [self nextToken]; // skip LBRACE [self skip]; if( token==RBRACE ) continue; // empty entry while( token==LBRACE ){ [self readConfigList]; [self skip]; } if( token!=RBRACE ){ NXRunAlertPanel("Bibliography", "syntax error in line %d (char '%c' = %d) of file %s", " OK ", // 1: default button NULL, // 0: alternate NULL, //-1: other lineNumber, token, token, configurationFile ); if(0)fprintf( stderr, "syntax error in line %d (char '%c' = %d)", lineNumber, token, token ); break; } [self nextToken]; // skip RBRACE [self skip]; } NXCloseMemory( configStream, NX_FREEBUFFER ); return self; } // [NXApp delegate] calls this method to show the panel // comes from menu Info -> Preferences - show { if( prefPanel ){ // not first call [prefPanel makeKeyAndOrderFront:self]; return self; } // first call [NXApp loadNibSection:"preferences.nib" owner:self]; if( tableViewIsLoaded==NO ){ [[showBox window] disableDisplay]; [self setUpTableView]; [self makeTableView]; tableViewIsLoaded=YES; [[showBox window] reenableDisplay]; } [self showOptionsFor:entryIndex]; [self shelfSettings]; [prefPanel makeKeyAndOrderFront:self]; [fieldNameField setEnabled:YES]; [fieldNameField selectText:self]; [defaultForm setStringValue:tempDir at:0]; [defaultForm setStringValue:"~/Library" at:1]; // default files [defaultForm setStringValue:theShell at:2]; // favorite shell [defaultForm setStringValue:theEditor at:3]; // favorite editor [defaultForm setStringValue:theStyle at:4]; // default style return self; } - (const char *)theShell { return theShell; } - (const char *)theEditor { if( !prefPanel ){ // take the default return theEditor; } return [defaultForm stringValueAt:3]; // favorite editor } - (const char *)theStyle { return theStyle; } - (BOOL) canExecuteProgram:(const char *)prog { int i; char buffer[2048]; char thePath[1024]; List *path = [self shellArgsOf:"PATH" toBuffer:buffer size:2048]; if( path==nil ) return NO; for( i=0; i<[path count]; i++ ){ sprintf( thePath, "%s/%s", (char *)[path objectAt:i], prog ); if( access(thePath, X_OK)<0 ) continue; [path free]; return YES; } [path free]; return NO; } - bibPopup:sender // sender is Matrix { entryIndex = [sender selectedRow]; [self showOptionsFor:entryIndex]; return self; } - (int)citeMode { int mode; if( [[NXApp delegate] entryDragMethod]==1 ){ return 3; // drag entries as text } if( prefPanel ){ mode = [[[[citeStyleButton target] itemList] selectedCell] tag]; return (mode<1)? 1 : mode; } return 1; } - (const char *) citeStyle { if( prefPanel ) return [citeStyleButton title]; return "\\c{...}, \\c{...}"; } - (const char *) citeText { if( prefPanel ) return [citeTextButton title]; return "\\cite"; } - citationStyle:sender { return self; } - setCitationPopUpList:(const char *)theString { PopUpList *citeTextPopUpList = [citeTextButton target]; if( [citeTextPopUpList indexOfItem:theString]>=0 ) return self; [citeTextPopUpList insertItem:theString at:[[citeTextButton target] count]-1]; [citeTextButton setTitle:theString]; return self; } - citationText:sender { if( [[sender selectedCell] tag]==4 ){ [self perform:@selector(setCitationPopUpList:) with:(id)[customCiteText stringValue] afterDelay:0 cancelPrevious:YES]; } return self; } - setCustomcite:sender { [self setCitationPopUpList:[customCiteText stringValue]]; return self; } - removeTempButton:sender { removeTemp = [sender state]==1; NXWriteDefault("Bibliography", "Remove", removeTemp?"YES":"NO"); return self; } - (BOOL)shallRemoveTempFiles { return removeTemp; } - openOnLaunch:sender { [theShelf setState:[[sender selectedCell] state] forIconAt:[sender selectedRow]]; return self; } - (int)indexOfIdentifier:(NXAtom)ident { int i; if( (ident==NULL) || (*ident=='\0') ) return -1; [self fieldNameList]; for( i=0; i<[fieldNameList count]; i++ ){ if( (NXAtom)[fieldNameList objectAt:i]==ident) return i; // index in fieldNameList == index in configList } return -1; } // row and col are the `physical' values // they must be converted to the `logical' rows and cols - (BOOL)changeValueAt:(int)row :(int)col { int i; unsigned int bit; configListType *item; id <DBTableVectors> rowVector; id <DBTableVectors> colVector; if( row<0 ) return NO; // nothing selected if( col<0 ) return NO; // nothing selected rowVector = [tableView rowAt:row]; colVector = [tableView columnAt:col]; row = [self indexOfIdentifier:(NXAtom)[rowVector identifier]]; col = (unsigned)[colVector identifier]; item = ((configListType*)[configList elementAt:row]); switch( col ){ case 0: return NO; // req etc. cannot be changed case 1: item->mode[entryIndex] ^= SHOW; // SHOW <-> NotShow if( [validButton state] ){ bit = item->mode[entryIndex] & SHOW; for( i=0; i<MODESIZE; i++ ){ if( bit ) item->mode[i] |= SHOW; else item->mode[i] &= ~SHOW; } } break; case 2: item->mode[entryIndex] ^= LARGE; // LARGE <-> SMALL if( [validButton state] ){ bit = item->mode[entryIndex] & LARGE; for( i=0; i<MODESIZE; i++ ){ if( bit ) item->mode[i] |= LARGE; else item->mode[i] &= ~LARGE; } } break; default: break; } return YES; } - tableViewSingleClick:sender // sender is matrix { int x; int col; int row = [sender selectedRow]; NXRect aRect; View *rowHead = [tableView rowHeading]; NXEvent event; NXPoint point; if( NXGetOrPeekEvent( [NXApp context], &event, NX_MOUSEUPMASK, 0.0, 22, 1) ){ point = event.location; // convert the coordinate of point to the window [rowHead convertPoint:&point fromView:nil]; [rowHead getVisibleRect:&aRect]; // x is leftmost position of the mouseclick (window coordinates) x = (int)(aRect.origin.x + aRect.size.width) + 2; // search for the selected column col = 0; while( ((int)point.x > x) && (col<=2) ) x += (int)[[tableView columnAt:col++] size] + 2; col--; if( col<0 ) col=0; // row and col are the `physical' values if( [self changeValueAt:row :col] ){ [tableView rowsChangedFrom:row to:row]; [inspector prefsDidChange]; } } else{ [self fieldNameList]; [fieldNameField setStringValue: (const unsigned char *)[fieldNameList objectAt:row]]; [self setButtonsFor:(char *)[fieldNameField stringValue]]; } return self; } - tableViewDoubleClick:sender // sender is DBTableView { int row = [sender selectedRow]; int col = [sender selectedColumn]; NXEvent event; NXPoint point; return self; if( NXGetOrPeekEvent( [NXApp context], &event, NX_MOUSEUPMASK, 0.0, 22, 1) ){ point = event.location; fprintf( stderr, "double at (%d,%d) -> (%d,%d)\n", row, col, (int)point.x, (int)point.y ); fprintf( stderr, "selRow:%d\n", [tableView selectedRowAfter:0] ); fprintf( stderr, "selCol:%d\n", [tableView selectedColumnAfter:0] ); fprintf( stderr, "sender is a %s\n", [sender name] ); fprintf( stderr, "rowlist %d\n", [[tableView rowList] count] ); fprintf( stderr, "is of type %s\n", [[[tableView rowList] objectAt:0] name] ); if(0)fprintf( stderr, "selected cell is a %s\n", [[sender selectedCell] name] ); } else fprintf( stderr, "double at %d %d\n", row, col ); return self; } - entryNameList { return entryNameList; } - configList { return configList; } - fieldNameList { if( fieldNameList==nil ){ int i; configListType *item; fieldNameList = [[List alloc] initCount:32]; for( i=0; i<[configList count]; i++ ){ item = ((configListType*)[configList elementAt:i]); [fieldNameList addObject:(id)(item->fieldName)]; } } return fieldNameList; } - (int)indexOfFieldname:(const char *)name { int i; if( (name==NULL) || (*name=='\0') ) return -1; [self fieldNameList]; for( i=0; i<[fieldNameList count]; i++ ){ if( ! NXOrderStrings( (const unsigned char *)[fieldNameList objectAt:i], (const unsigned char *)name, NO, -1, NULL ) )return i; // index in fieldNameList == index in configList } return -1; } - (int)indexOfEntryname:(const char *)name { int i; for( i=0; i<[entryNameList count]; i++ ){ if( ! NXOrderStrings( (const unsigned char *)[entryNameList objectAt:i], (const unsigned char *)name, NO, -1, NULL ) )return i; // index in entryNameList } return -1; } - (const char *)tempDirectory { return tempDir; } - (const char *)libDirectory { return libDir; } - (const char *)templateFile { return templateFile; } - (const char *)shelfFile { return shelfFile; } // returns the new state of the menuCell // YES = enabled // NO = disabled - (BOOL)updateMenuFor:menuCell { BOOL newState=NO; // .. and the compiler keeps silent switch( [menuCell tag] ){ case CUT : case COPY : case PASTE : case SELECTALL : case ENTERSELECTION : newState = YES; break; case PRVWINDOW : newState = YES; break; // why ? default : newState = [[NXApp delegate] updateMenuFor:menuCell]; break; } return newState; } - textDidGetKeys:sender isEmpty:(BOOL)flag { [self setButtonsFor:(char *)[fieldNameField stringValue]]; return self; } - restoreEditorName { [defaultForm setStringValue:theEditor at:3]; // restore return self; } - (BOOL)textWillEnd:sender { int row; const char* edt; if( [[sender delegate] tag]!=77 ) return NO; row = [[sender delegate] selectedIndex]; edt = [[Application workspace] getFullPathForApplication: [[sender delegate] stringValueAt:row]]; if( edt==NULL ){ [self alert:"cannot find application %s" :[[sender delegate] stringValueAt:row]]; [self perform:@selector(restoreEditorName) with:(id)nil afterDelay:0 cancelPrevious:YES]; } return NO; } /*====================================================================== * DBTableView data source (pseudo-delegate) methods *======================================================================*/ - (unsigned int)rowCount { fprintf( stderr, "rowCount %d\n", rowCount ); return rowCount; } - (unsigned int)columnCount { fprintf( stderr, "columnCount\n" ); return 3; } /* DBTV sends this message when it needs to know what to display */ - getValueFor:identifier at:(unsigned int)aPosition into:aValue { /* * note that when loaded, we set the identifiers to be the locations of the * configuration objects in the configuration list */ fprintf( stderr, "getValueFor %d at %d\n", (int)identifier, aPosition ); //[aValue setIntValue:(int)identifier]; // ignore this method, we use getValueFor::into: return nil; } /* DBTV sends this message when it needs to know what to display */ - getValueFor:rowIdentifier :colIdentifier into:aValue { int row = [self indexOfIdentifier:(NXAtom)rowIdentifier]; int col = (int)colIdentifier; int m; configListType *item; if( row<0 ) return nil; // nothing selected if( col<0 ) return nil; // nothing selected item = ((configListType*)[configList elementAt:row]); m = item->mode[entryIndex]; //fprintf( stderr, "entryIndex is %d at %d %d\n", entryIndex, row, col ); switch( col ){ case 0 : switch( m & 3 ){ case REQUIRED : [aValue setStringValue:"req"]; break; case OPTIONAL : [aValue setStringValue:"opt"]; break; case CUSTOM : [aValue setStringValue:"custom"]; break; default : [aValue setStringValue:" - "]; break; } break; case 1 : if( m & SHOW ) [aValue setStringValue:"show"]; else if( m&3 )[aValue setStringValue:"hide"]; else [aValue setStringValue:" - "]; break; case 2 : if( m & LARGE ) [aValue setStringValue:"LARGE"]; else [aValue setStringValue:"SMALL"]; break; default : break; } if(0)fprintf( stderr, "getValueFor (%d %d)\n", row, col ); return nil; } /* DBTV sends this message when data in a cell has changed */ - setValueFor:identifier at:(unsigned int)aPosition from:aValue { fprintf( stderr, "setValueFor\n" ); return nil; } - setValueFor:rowIdentifier :columnIdentifier from:aValue { fprintf( stderr, "setValueFor row=%d col=%d\n", (int)rowIdentifier, (int)columnIdentifier ); return nil; } // browser delegate methods #include <sys/dir.h> /* POSIX applications #include <dirent.h> */ - (BOOL)isDirectory:(const char *)path { struct stat fBuf; int rtn = stat(path, &fBuf); if( rtn<0 ){ perror("stat error"); return NO; } return (S_IFDIR & fBuf.st_mode) != 0; } - styleDoubleClick:sender { //fprintf( stderr, "styleDoubleClick\n" ); return self; } - styleSingleClick:sender { char path[1024]; char *lastDot; int selCol = [sender selectedColumn]; if( selCol==0 ) return self; [styleBrowser getPath:path toColumn:selCol+1]; // paths starts with "//" if( access(path, F_OK)<0 ){ [self alert:"the stylefile %s does not exist" :path+1]; return self; } if( access(path, R_OK)<0 ){ [self alert:"the stylefile %s is not readable" :path+1]; return self; } if( theStyle ) free( (char *)theStyle ); lastDot = rindex( path, '.' ); if( lastDot ){ *lastDot = '\0'; } theStyle = NXCopyStringBuffer(path+1); [styleText setStringValue:theStyle]; if(0)[[Application workspace] openFile:(path+1) withApplication:[self theEditor]]; return self; } - (List *)shellArgsOf:(const char *)para toBuffer:(char *)buf size:(int)size { int i=0; char c, *str; FILE *env; List *args; sprintf( buf, "%s -c 'echo -n $%s' 2>/dev/null", [self theShell], para ); env = popen( buf, "r" ); str = fgets( buf, size-1, env ); if (str==NULL ){ return nil; } args = [[List alloc] init]; [args addObject:(id)buf]; while( YES ){ c = buf[i]; if( (c==':') || (c=='\0') ){ buf[i] = '\0'; if( c=='\0' ) break; else [args addObject:(id)&buf[i+1]]; } i++; } return args; } - (int)fillColZero:locMatrix { int i=0, row=0; id newCell; char buffer[1024]; List *args = [self shellArgsOf:"TEXINPUTS" toBuffer:buffer size:1024]; //[self canExecuteProgram:"bibtex"]; //[self canExecuteProgram:"latex"]; if (args==nil ){ //fprintf( stderr, "Erorr: no variable TEXINPUTS\n" ); args = [[List alloc] init]; [args addObject:(id)"."]; [args addObject:(id)"/usr/lib/tex/inputs"]; // default } for( i=0; i<[args count]; i++ ){ const char *para = (const char *)[args objectAt:i]; if( para[0]=='\0' ) continue; // (empty string) [locMatrix addRow]; newCell = [locMatrix cellAt:row :0]; row++; if( strcmp(para, ".")==0 ){ [newCell setStringValue:tempDir]; //[newCell setStringValue:NXHomeDirectory()]; } else{ [newCell setStringValue:para]; } [newCell setLeaf:NO]; [newCell setLoaded:YES]; } [args free]; return row; } - (int)fillMatrix:locMatrix { DIR *dirp; struct direct *dp; int length; int count = 0; id newCell; char path[1024]; char buffer[1024]; ////////return [[MacroDB new] fillMatrix:locMatrix]; [styleBrowser getPath:path toColumn:[styleBrowser selectedColumn]+1]; // path starts with "//", do not use the first character dirp = opendir( path+1 ); if( dirp==NULL ){ sprintf( buffer, "%s\n%s", path+1, strerror(errno) ); [self alert:" %s" :buffer]; return 0; } for( dp = readdir(dirp); dp != NULL; dp = readdir(dirp) ) { length = strlen( dp->d_name ); if( length<=4 ) continue; // show also directories sprintf( buffer, "%s/%s", path+1, dp->d_name ); if( NO && [self isDirectory:buffer] ){ [locMatrix addRow]; newCell = [locMatrix cellAt:count :0]; [newCell setStringValue:dp->d_name]; [newCell setLeaf:NO]; [newCell setLoaded:YES]; count++; continue; } if( dp->d_name[length-4]=='.' && dp->d_name[length-3]=='b' && dp->d_name[length-2]=='s' && dp->d_name[length-1]=='t' ){ [locMatrix addRow]; newCell = [locMatrix cellAt:count :0]; [newCell setStringValue:dp->d_name]; [newCell setLeaf:YES]; [newCell setLoaded:YES]; count++; } } closedir(dirp); return count; } - (int)browser:sender fillMatrix:locMatrix inColumn:(int)column { //id matrix = [theBrowser matrixInColumn:column-1]; //int index = [matrix selectedRow]; if( column==0 ){ return [self fillColZero:locMatrix]; } return [self fillMatrix:locMatrix]; } /***** for experts only ********/ - (int)sortAlgorithm { return 0; } - (int)cutOff { return 50; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.