This is IKList.m in view mode; [Download] [Up]
/* File IKList.m Release 1.2, 7 June 1994 Copyright (C) 1994 by H. Scott Roy This code is part of IconKit, a general toolbox for drag-and-drop applications. IconKit is free for noncommercial use, but costs money for a commercial license. You should have received a copy of the license agreement with this file. If not, a copy of the license and the complete source of IconKit can be obtained from the author: H. Scott Roy 2573 Stowe Ct. Northbrook, IL 60062-8103 iconkit@cs.stanford.edu For your editing convenience, this file is best viewed using an editor that automatically wraps long lines, in a fixed point font at 80 columns, with tabs every 4 spaces. */ /* ========================================================================== */ /* IKList specializes the list class in two ways. First, it incorporates reference counting to take care of automatic memory management. Second, it conforms to the IKIconObject protocol so that it can display itself and be dragged around the workspace. A typical use is to represent a multiple selection in an IKBrowser. The icon of an IKList is the hand-and-sheaf when there is more than one element in the list; otherwise it is the icon of the first element. */ #import <appkit/appkit.h> #import <apps/InterfaceBuilder.h> #import "iconkit.h" @implementation IKList /* ========================================================================== */ /* All IKLists share the same sheaf image. They also share a common buffer for writing their names. */ static char name [1000]; static NXImage * sheaf = nil; + initialize { if (self == [IKList class]) { IKInitIDpboardType(); sheaf = [NXImage findImageNamed: "Sheaf"]; } return self; } - (NXImage *) getIBImage { return sheaf; } /* ========================================================================== */ /* Here are the methods required to initialize, copy, free. Note that copying is broken in the List class, so all classes that inherit from IKList must implement "copyFromZone:" to work correctly. */ - initCount: (unsigned int) numSlots { if ((self = [super initCount: numSlots]) != nil) users = [[IKAnnouncer alloc] initOwner: self]; return self; } - copyFromZone: (NXZone *) zone { IKList * copy = [super copyFromZone: zone]; if (copy) copy->users = [[IKAnnouncer alloc] initOwner: copy]; return copy; } - free { IKdprintf("freeing list: %s\n", [self name]); [users announce: @selector(willFree:)]; [[[users usersAndListeners] empty] addObject: self]; [self makeObjectsPerform: @selector(removeUser:) with: self]; users = [users free]; return self = [super free]; } /* ========================================================================== */ /* An IKList will forward unknown messages to the first object in the list. */ - forward: (SEL) message : (marg_list) argFrame { id destination = [self objectAt: 0]; return [destination respondsTo: message] ? [destination performv: message : argFrame]: [super forward: message : argFrame]; } - (BOOL) respondsTo: (SEL) method { return [super respondsTo: method] || [[self objectAt: 0] respondsTo: method]; } /* ========================================================================== */ /* An IKList needs to create a new IKAnnouncer when being unarchived from a stream. */ - read: (NXTypedStream *) stream { [super read: stream]; users = [[IKAnnouncer alloc] initOwner: self]; return self; } /* ========================================================================== */ /* An IKList performs automatic reference counting memory management. When it has no more users it considers itself inaccessible and frees itself. Users can negate this behavior by overriding the garbageCollect method. Other than removeUser:, the IKDependency methods are all simply forwarded to the users object. */ - addUser: who { return [users addUser: who]; } - addListener: who { return [users addListener: who]; } - removeListener: who { return [users removeListener: who]; } - removeUser: who { [users removeUser: who]; return [users numUsers] == 0 && [self garbageCollect] && ![NXApp conformsTo: @protocol(IB)] ? self = [self free] : self; } - (BOOL) garbageCollect { return YES; } /* ========================================================================== */ /* The methods below find an appropriate icon and title for the list. The name buffer cannot be allocated on the stack since it would get clobbered when the code returned. */ - image { if (numElements == 0) return nil; else if (numElements == 1) return [dataPtr[0] image]; else return sheaf; } - (const char *) name { if (numElements == 0) return NULL; else if (numElements == 1) return [dataPtr[0] name]; else { sprintf(name, "%d items", numElements); return name; } } - (BOOL) isDraggable { return dataPtr ? [dataPtr[0] isDraggable]:NO; } - (BOOL) isDragAccepting { return NO; } - (BOOL) isEditable { return NO; } - setDraggable: (BOOL)flag; { return nil; } /* ========================================================================== */ /* An IKList sends out notification messages before and after its contents change. Objects that use the list can intercede to abort the operation: all users must give their approval for the operation to take place. Note that these methods do not send out a didChangeName: notification, even though it might be appropriate. The reason is that the list can't really tell whether it's name actually changed, since these methods might be invoked by a subclass that provides its own names (like IKSuitcase). */ - appendList: (List *) objects { if (![users poll: @selector(list:willAppendList:) with: objects]) return nil; [users setSendAnnouncements: NO]; [super appendList: objects]; [users setSendAnnouncements: YES]; [users announce: @selector(list:didAppendList:) with: objects]; return self; } - removeList: (List *) objects { int i; if (![users poll: @selector(list:willRemoveList:) with: objects]) return nil; [users setSendAnnouncements: NO]; for (i = 0; i < [objects count]; i++) [self removeObject: [objects objectAt: i]]; [users setSendAnnouncements: YES]; [users announce: @selector(list:didRemoveList:) with: objects]; return self; } - insertObject: object at: (unsigned int) i { if (![users poll: @selector(list:willAdd:) with: object]) return nil; [super insertObject: object at: i]; [object addUser: self]; [users announce: @selector(list:didAdd:) with: object]; return self; } - removeObjectAt: (unsigned int) i { id object = [self objectAt: i]; if (![users poll: @selector(list:willRemove:) with: object]) return nil; [super removeObjectAt: i]; [object removeUser: self]; [users announce: @selector(list:didRemove:) with: object]; return self; } /* ========================================================================== */ /* An IKList unloads any object that wants to free itself. */ - willFree: who { [self removeObject: who]; return self; } /* ========================================================================== */ /* IKLists copy and read from the pasteboard using local object id. */ + (NXAtom *) pasteTypes { return IKIDPasteTypes(); } - copyToPasteboard: (Pasteboard *) pboard { IKCopyID (pboard, self); return self; } + readFromPasteboard: (Pasteboard *) pboard; { id object = IKReadID (pboard); return [object isKindOf: [self class]] ? object : nil; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.