This is Shelf.m in view mode; [Download] [Up]
// Copyright H. Giesen, University of Koblenz-Landau 1996 #import "Shelf.h" #import "Controller.h" #import "DragView.h" #import "BibliographicFile.h" #import "Preferences.h" #define DRAGVIEWTAG 7 #define W_SPACE 10.0 #define H_SPACE 10.0 #define L_MARGIN 5.0 @implementation Shelf - initFrame:(const NXRect *)frameRect /* %initFrame% initializes the view and registers the Pasteboard types that the shelf will accept in an image-dragging session. The shelf accepts only the NXFilenamePboardType. Returns self. */ { [self registerForDraggedTypes:&NXFilenamePboardType count:1]; MyListPboardType = NXUniqueString( "My List Pboard Type" ); [super initFrame:frameRect]; [self setFlipped:YES]; preferences = [Preferences new]; isSelected = NO; theImage = [NXImage findImageNamed:"Images/SmallBooks"]; boxList = [[List alloc] init]; return self; } - (void) setBoxPrototype:(Box *)aBox /* New boxes for the shelf are generated from %aStream% by calling the function NXReadObjectFromBuffer() using the buffer of %aStream%. See also readBoxFromStream. */ { NXTypedStream *masterTypedStr; int streamLength; int streamMaxLength; char *streamBuffer; [aBox getFrame:&boxRect]; protypeStream = NXOpenMemory( NULL, 0, NX_WRITEONLY); masterTypedStr = NXOpenTypedStream(protypeStream, NX_WRITEONLY); NXWriteRootObject( masterTypedStr, aBox ); NXCloseTypedStream( masterTypedStr ); NXGetMemoryBuffer(protypeStream, &streamBuffer, &streamLength, &streamMaxLength); NXCloseMemory(protypeStream, NX_TRUNCATEBUFFER); protypeStream = NXOpenMemory( streamBuffer, streamLength, NX_READONLY); } - (BOOL)loadShelfFromFile:(const char *)file { int newInx; int okFlag; Box *newBox; char buffer[1024]; char *first, *last, *comment; FILE *fp; fp = fopen( file, "r" ); if( fp==NULL ) return NO; if( protypeStream==NULL ) return NO; while( fgets( buffer, 512, fp ) ){ first = strchr( buffer, '"'); // first occurence of '"' if( first==NULL ) continue; last = strrchr( buffer, '"'); // last occurence of '"' if( last==NULL ) continue; *last = '\0'; // commentline ? comment = strchr( buffer, '%'); // first occurence of '%' if( comment && (comment<first) ) continue; // filename is ok newBox = [self readBoxFromStream:protypeStream]; newInx = [self insertBox:newBox]; [[newBox findViewWithTag:DRAGVIEWTAG] setFilename:first+1]; last++; //first character behind '\0', was '"' while( *last ){ int rtn; if( *last=='+' ){ // open the file shelfBox[newInx].state = 1; rtn = [NXApp openFile:first+1 ok:&okFlag]; break; } if( *last=='-' ) break; last++; } } fclose( fp ); return YES; } - setBackgroundColor:(NXColor)color { [[self superview] setBackgroundColor:color]; [[self superview] display]; return self; } - setBackgroundGray:(float)gray { [[self superview] setBackgroundGray:gray]; //[[self superview] display]; [self display]; return self; } /*********** find box or empty slot ************/ - (int)indexOfBox:(Box *)box { int j; for( j=0; j<count; j++ ){ if( shelfBox[j].theBox == box ) return j; } return -1; } - (int)indexOfBoxWithIcon:(DragView *)icon { return [boxList indexOf:icon]; } - (int)indexOfBoxForFile:(BibliographicFile *)aFile { //DragView *theView; int j; for( j=0; j<count; j++ ){ //theView = [boxList objectAt:j]; if( shelfBox[j].theFile == aFile ) return j; } return -1; } - (int)indexOfBoxNamed:(const char *)fileName { DragView *theView; int j; for( j=0; j<count; j++ ){ theView = [boxList objectAt:j]; if( [theView fileName]==NULL ) continue; if( strcmp([theView fileName], fileName)==0 ) return j; } return -1; } - (int)indexOfEmptySlot { int j; for( j=0; j<count; j++ ){ if( shelfBox[j].theBox==nil ) return j; } return -1; } /***** properties of an icon ****/ - (const char *)filenameOfIconAt:(int)inx { if( (inx<0) || (inx>=count) ) return NULL; if( shelfBox[inx].theBox==nil ) return NULL; return [[boxList objectAt:inx] fileName]; } - (int)getstateOfIconAt:(int)inx { if( (inx<0) || (inx>=count) ) return -1; return shelfBox[inx].state; } - setState:(int)state forIconAt:(int)inx { if( (inx<0) || (inx>=count) ) return nil; shelfBox[inx].state = state; return self; } /******** notification methods *******/ static const char * dragTypes[3]; - attachFile:(const char *)fName toObject:(BibliographicFile *)obj { DragView *theView; int j = [self indexOfBoxNamed:fName]; if( j<0 ) return nil; theView = [boxList objectAt:j]; [theView setFileObject:obj]; dragTypes[0] = MyListPboardType; dragTypes[1] = NXAsciiPboardType; [theView registerForDraggedTypes:dragTypes count:2]; shelfBox[j].theFile = obj; [theView display]; return self; } - attachObject:(BibliographicFile *)obj toFile:(const char *)fName { DragView *theView; int j = [self indexOfBoxForFile:obj]; if( j<0 ) return nil; theView = [boxList objectAt:j]; [theView setFileObject:obj]; [theView display]; [preferences shelfDidChange]; return self; } - detachObject:(BibliographicFile *)obj { int j = [self indexOfBoxForFile:obj]; if( j<0 ) return nil; [[boxList objectAt:j] unregister]; shelfBox[j].theFile = nil; return self; } /*********** remove box identified by ... ************/ - (void) removeBoxAt:(int)inx { DragView *theView; if( inx<0 ) return; theView = [boxList objectAt:inx]; [theView clear]; [theView unregisterDraggedTypes]; [shelfBox[inx].theBox removeFromSuperview]; [NXApp delayedFree:shelfBox[inx].theBox]; shelfBox[inx].theBox = nil; shelfBox[inx].theFile = nil; [boxList removeObjectAt:inx]; [self redrawShelf]; return; if( inx==count-1 ){ // determine last box and compact while( count && (shelfBox[count-1].theBox==nil) ) count--; [self redrawShelf]; } else [self redrawShelf]; // compact //else [self display]; // does not compact } - (void) removeBoxWithIcon:(DragView *)icon { [self removeBoxAt:[self indexOfBoxWithIcon:icon]]; [self display]; [preferences shelfDidChange]; } - (Box *) readBoxFromStream:(NXStream *)theStream { char *buffer; int len, maxlen; Box *box; NXGetMemoryBuffer(theStream, &buffer, &len, &maxlen); box = NXReadObjectFromBuffer( buffer, len); [box getFrame:&boxRect]; [box setBorderType:NX_NOBORDER]; return box; } - (void) sizeShelf:(int)cnt { NXRect r; if( scrollView==nil ){ // first call needsHorizontalScroller = YES; //1.2 select type of scroller scrollView = [[self superview] superview]; [scrollView setVertScrollerRequired:!needsHorizontalScroller]; [scrollView setHorizScrollerRequired:needsHorizontalScroller]; if( needsHorizontalScroller ) [[scrollView setVertScroller:nil] free]; else [[scrollView setHorizScroller:nil] free]; // set size (this is the first call) [[self superview] getFrame:&r]; [self sizeTo:r.W :r.H]; } [[self superview] getFrame:&r]; if( needsHorizontalScroller ){ // horizontal NXCoord width, height; iconsPerRow = cnt; width = iconsPerRow*(boxRect.W + W_SPACE); height = boxRect.H + H_SPACE; [self sizeTo:( (width<r.W)?r.W:width ) :( (height<r.H)?r.H:(boxRect.H + H_SPACE) )]; [scrollView setLineScroll:(boxRect.W + W_SPACE)]; } else{ iconsPerRow = (int)((r.W - L_MARGIN + W_SPACE)/(boxRect.W + W_SPACE)); [self sizeTo:r.W :(((cnt-1)/iconsPerRow)+1)*(boxRect.H + H_SPACE)]; [scrollView setLineScroll:(boxRect.H + H_SPACE)]; } } - (void) setCoordinates:(NXRect *)r at:(int)inx { if( inx<0 ) { r->X = W_SPACE; r->Y = H_SPACE; return; } if( needsHorizontalScroller ){ // horizontal r->X = (inx)*(r->W + W_SPACE) + L_MARGIN; r->Y = 0; } else{ r->X = (inx%iconsPerRow)*(r->W + W_SPACE) + L_MARGIN; r->Y = (inx/iconsPerRow)*(r->H + H_SPACE); } } - (void) redrawShelf { Box *box; int in, out; [self sizeShelf:count]; for( in=0, out=0; in<count; in++){ box = shelfBox[in].theBox; if( box==nil ) continue; [self setCoordinates:&boxRect at:out]; [box setFrame:&boxRect]; shelfBox[out] = shelfBox[in]; out++; } if( count==out ){ [[self superview] display]; return; } count = out; [self sizeShelf:count]; [[self superview] display]; [preferences shelfDidChange]; } - (int)insertBox:(Box *)box at:(int)inx { DragView *newView; if( (inx<0) || (inx>=MAXCOUNT) ){ fprintf( stderr, "internal error, invalid shelf index %d\n", inx ); return -1; } [self setCoordinates:&boxRect at:inx]; [box setFrame:&boxRect]; newView = [box findViewWithTag:DRAGVIEWTAG]; [boxList addObject:newView]; [newView setShelf:self]; shelfBox[inx].theBox = box; shelfBox[inx].theFile = nil; shelfBox[inx].state = 0; [self addSubview:box]; [self scrollRectToVisible:&boxRect]; [preferences shelfDidChange]; return inx; } - (int)insertBox:(Box *)box { int inx = [self indexOfEmptySlot]; if( inx>=0 ){ [self insertBox:box at:inx]; } else { if( count>=MAXCOUNT ){ fprintf( stderr, "too many icons\n" ); // <--------- return -1; } count++; [self sizeShelf:count]; inx = [self insertBox:box at:count-1]; // last entry in table } [self display]; return inx; } - (int)count { return count; } - windowDidResize:sender { [self redrawShelf]; return self; } /************ methods used while dragging ************/ - drawSelf:(const NXRect *)rects :(int)rectCount { NXRect shadowBoxRect = boxRect; NXPoint zero = {0.0, 0.0 }; if( isSelected && (theImage!=nil) ){ NXImage *tmpImage = [[NXImage alloc] initSize:&boxRect.size]; if( [tmpImage lockFocus] ){ PSsetgray( NX_LTGRAY ); PSrectfill(0.0, 0.0, boxRect.size.width, boxRect.size.height); shadowBoxRect.origin.x += 14; shadowBoxRect.origin.y +=shadowBoxRect.size.height - 16; [theImage dissolve:0.6 toPoint:&zero]; [tmpImage unlockFocus]; [tmpImage composite:NX_SOVER toPoint:&shadowBoxRect.origin]; [tmpImage free]; } else{ fprintf( stderr, "cannot lockFocus\n" ); } } return self; } /************ dragging ************/ // includesType() returns YES if %type% is included within %types%. static BOOL includesType (const NXAtom *types, NXAtom type) { if (types) while (*types){ if (*types++ == type) return YES; } return NO; } - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender { int inx; NXDragOperation rtn = [self draggingUpdated:sender]; if( rtn!=NX_DragOperationGeneric ) return rtn; inx = [self indexOfEmptySlot]; if( inx<0 ){ [self sizeShelf:count+1]; inx = count; } [self setCoordinates:&boxRect at:inx]; isSelected = YES; theImage = [sender draggedImage]; [self scrollRectToVisible:&boxRect]; [self display]; return rtn; } - (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender { Pasteboard *pboard = [sender draggingPasteboard]; char *data, *lastDot, *file, *tab; int length; if (includesType([pboard types], MyListPboardType)) { return NX_DragOperationNone; } if( ([sender draggingSourceOperationMask] & NX_DragOperationGeneric) ||([sender draggingSourceOperationMask] & NX_DragOperationCopy) ){ if( includesType([pboard types], NXFilenamePboardType) ){ [pboard readType:NXFilenamePboardType data:&data length:&length]; // is it a list of files ? file = data; while (file) { if( tab = strchr(file, '\t') ) { *tab = '\0'; } lastDot = rindex( file, '.' ); if( lastDot ){ if( strcmp( lastDot, ".bib" ) ) { // only .bib allowed return NX_DragOperationNone; } } else return NX_DragOperationNone; // no suffix -> invalid // is the file already on the shelf ? if( [self indexOfBoxNamed:file]>=0 ){ // yes return NX_DragOperationNone; } file = (tab) ? ++tab : NULL; } return NX_DragOperationGeneric; } } return NX_DragOperationNone; } - (BOOL)performDragOperation:(id <NXDraggingInfo>)sender { char *data, *file, *tab; int length; Pasteboard *pboard = [sender draggingPasteboard]; isSelected = NO; if( includesType([pboard types], NXFilenamePboardType) ){ [pboard readType:NXFilenamePboardType data:&data length:&length]; file = data; while (file) { Box *newBox; DragView *newView; BibliographicFile *fileObj; if (tab = strchr(file, '\t')) *tab = '\0'; newBox = [self readBoxFromStream:protypeStream]; newView = [newBox findViewWithTag:DRAGVIEWTAG]; [newView setFilename:file]; [self insertBox:newBox]; // ask if this file is open in this application fileObj = [[NXApp delegate] objectForFileNamed:file]; if( fileObj )[self attachFile:file toObject:fileObj]; file = (tab) ? ++tab : NULL; } return YES; } return NO; } - draggingExited:sender { isSelected = NO; [self redrawShelf]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.