123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %
- % Browser.SL - Browser object definition
- %
- % Author: Alan Snyder
- % Hewlett-Packard/CRC
- % Date: 4 February 1983
- % Revised: 14 February 1983
- %
- % This file implements browser objects. These objects form the basis of
- % a general browser support mechanism. See Browser-Support.SL for additional
- % support functions and Buffer-Browser.SL for an example of a browser
- % using this mechanism.
- %
- % 14-Feb-83 Alan Snyder
- % Fix bug in filter application (was trying to apply a macro).
- % 11-Feb-83 Alan Snyder
- % Fix &remove-current-item to reset the display buffer's modified flag.
- % Improve comments.
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- (compiletime (load fast-vectors fast-int))
- (load gsort)
- (de create-browser (display-buffer view-buffer header-text items current-sorter)
- % Create a brower. DISPLAY-BUFFER is the buffer to use for displaying the
- % items. VIEW-BUFFER is the buffer to use for viewing an item; if NIL, the
- % item is expected to provide its own buffer. HEADER-TEXT is a vector of
- % strings to display at the top of the display buffer; it may be NIL. ITEMS
- % is a list or vector containing the set of items to display (this data
- % structure will not be modified). CURRENT-SORTER may be NIL or a function
- % ID. If non-NIL, the function will be used to sort the initial set of
- % items.
- (make-instance 'browser
- 'display-buffer display-buffer
- 'view-buffer view-buffer
- 'header-text header-text
- 'items items
- 'current-sorter current-sorter
- ))
- (defflavor browser
- (
- (display-buffer NIL) % buffer used to display items
- (view-buffer NIL) % buffer used to view items (NIL => ask item)
- (viewed-item NIL) % the item most recently viewed
- (header-text NIL) % text displayed at top of buffer
- items % vector of visible items (may have junk at end)
- first-item-linepos % line number of first item in display
- last-item-index % index of last item in ITEMS vector
- (filtered-items ()) % list of lists of items removed by filtering
- (current-sorter NIL) % sorter used if items are un-filtered
- )
- ()
- (initable-instance-variables display-buffer view-buffer header-text items
- current-sorter)
- )
- % Methods provided by items:
- %
- % (=> item display-text)
- % Return string used to display the item.
- %
- % (=> item delete)
- % Mark the item as deleted. May do nothing if deletion is not supported.
- % May change the display-text. This method need not be provided if no
- % delete commands are provided in the particular browser.
- %
- % (=> item undelete)
- % Mark the item as not deleted. May do nothing if deletion is not
- % supported. May change the display-text. This method need not be provided
- % if no delete commands are provided in the particular browser.
- %
- % (=> item deleted?)
- % Return T if the item has been marked for deletion. This method need not
- % be provided if no delete commands are provided in the particular browser.
- %
- % (=> item kill)
- % Kill the real item. (Instead of just marking the item for deletion, this
- % should actually dispose of the item, if that action is supported.) May do
- % nothing if killing is not supported. Return T if the item is actually
- % killed, NIL otherwise. This method need not be provided if no delete
- % commands are provided in the particular browser.
- %
- % (=> item view-buffer buffer)
- % Return a buffer containing the item for viewing. If the buffer argument
- % is non-NIL, then that buffer should be used for viewing. Otherwise, the
- % item must provide its own buffer.
- %
- % (=> item cleanup)
- % Throw away any unneeded stuff, such as a buffer created for viewing. This
- % method is invoked when an item is no longer being viewed, or when the item
- % is being filtered out, or when the browser is being exited.
- %
- % (=> item apply-filter filter)
- % The item should apply the filter to itself and return T if the filter
- % matches the item and NIL otherwise.
- (defmethod (browser current-item) ()
- % Return the current item, which is the item that is displayed on the
- % display-buffer's current line, or NIL, if there is no such item.
- (let ((index (- (=> display-buffer line-pos) first-item-linepos)))
- (when (and (>= index 0) (<= index last-item-index))
- (vector-fetch items index)
- )))
- (defmethod (browser current-item-index) ()
- % Return the index of the current item, which is the item that is displayed
- % on the display-buffer's current line, or NIL, if there is no such item.
- (let ((index (- (=> display-buffer line-pos) first-item-linepos)))
- (when (and (>= index 0) (<= index last-item-index))
- index
- )))
- (defmethod (browser kill-item) ()
- % Kill the current item, if any. Return T if the item is killed,
- % NIL otherwise.
- (let ((item (=> self current-item)))
- (when (=> item kill)
- (=> self &remove-current-item)
- )))
- (defmethod (browser kill-deleted-items) ()
- % Attempts to KILL all items that have been marked for deletion.
- % Returns a list of the items actually killed.
- (=> self &keep-items '&browser-item-not-killed ())
- )
- (defmethod (browser delete-item) ()
- % Mark the current item as deleted, if any. Return T if the item exists,
- % NIL otherwise.
- (let ((item (=> self current-item)))
- (when item
- (=> item delete)
- (=> self &update-current-item)
- T
- )))
- (defmethod (browser undelete-item) ()
- % Mark the current item as not deleted, if any. Return T if the item exists,
- % NIL otherwise.
- (let ((item (=> self current-item)))
- (when item
- (=> item undelete)
- (=> self &update-current-item)
- T
- )))
- (defmethod (browser view-item) ()
- % View the current item, if any, in a separate buffer.
- % Return the buffer if the item exists, NIL otherwise.
- (let ((item (=> self current-item)))
- (when item
- (when viewed-item
- (=> viewed-item cleanup))
- (setf viewed-item item)
- (=> item view-buffer view-buffer) % return the buffer
- )))
- (defmethod (browser ignore-item) ()
- % Ignore the current item, if any. Return T if the item exists.
- % Ignoring an item is like running a filter that accepts every item
- % except the current one, except that multiple successive ignores
- % coalesce into one filtered-item-set for undoing purposes.
- (let ((item (=> self &remove-current-item)))
- (when item
- (cond ((and filtered-items (eqcar (car filtered-items) 'IGNORE-COMMAND))
- % add this item to the previous list of ignored items
- (let ((filter-set (car filtered-items)))
- (setf (cdr filter-set) (cons item (cdr filter-set)))
- ))
- (t (setf filtered-items
- (cons (list 'IGNORE-COMMAND item) filtered-items))
- )))))
- (defmethod (browser filter-items) (filter)
- % Remove those items that do not match the specified filter.
- % If some items are removed, then they are added as a set to the
- % list of filtered items, so that this step can be undone, and T
- % is returned. Otherwise, no new set is created, and NIL is returned.
- (let ((filtered-list (=> self &keep-items 'ev-send
- (list 'apply-filter (list filter)))))
- (when filtered-list
- (setf filtered-list (cons filter filtered-list))
- (setf filtered-items (cons filtered-list filtered-items))
- T
- )))
- (defmethod (browser undo-filter) ()
- % Undo the effect of the most recent active filtering step.
- % Return the filter or NIL if there are no active filtering steps.
- (when filtered-items
- (let ((filter (car (car filtered-items)))
- (the-items (cdr (car filtered-items)))
- (current-item (=> self current-item))
- )
- (setf filtered-items (cdr filtered-items))
- (while the-items
- (let ((item (car the-items)))
- (setf the-items (cdr the-items))
- (setf last-item-index (+ last-item-index 1))
- (vector-store items last-item-index item)
- ))
- (=> self &sort-items)
- (=> self &update-display)
- (=> self select-item current-item)
- filter
- )))
- (defmethod (browser exit) ()
- (setf viewed-item NIL)
- (for (from i 0 last-item-index)
- (do (=> (vector-fetch items i) cleanup)))
- )
- (defmethod (browser items) ()
- % Return a list of the items.
- (for (from i 0 last-item-index)
- (collect (vector-fetch items i)))
- )
- (defmethod (browser sort) (sorter)
- (let ((current-item (=> self current-item)))
- (setf current-sorter sorter)
- (=> self &sort-items)
- (=> self &update-display)
- (=> self select-item current-item)
- ))
- (defmethod (browser send-item) (msg args)
- % Send the current item, if any, the specified message with the specified
- % arguments. Return NIL if there is no current item; otherwise, return
- % the result of sending the message to the item.
- (let ((item (=> self current-item)))
- (when item
- (prog1
- (lexpr-send item msg args)
- (=> self &update-current-item)
- ))))
- (defmethod (browser select-item) (item)
- % If ITEM is not NIL, then adjust the buffer pointer to point to
- % that item.
- (for (from i 0 last-item-index)
- (do (when (eq item (vector-fetch items i))
- (=> display-buffer goto (+ i first-item-linepos) 0)
- (exit)
- ))))
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Private methods:
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- (defmethod (browser init) (init-plist)
- (=> display-buffer put 'browser self)
- (setf items (cond ((ListP items) (List2Vector items))
- ((VectorP items) (CopyVector items))
- (t (List2Vector ()))
- ))
- (setf last-item-index (vector-upper-bound items))
- (=> self &sort-items)
- (=> self &update-display)
- )
- (defmethod (browser &update-display) ()
- % Update the display. The cursor is moved to the first item.
- (=> display-buffer reset)
- (when header-text
- (=> display-buffer insert-text header-text)
- (=> display-buffer insert-eol)
- )
- (setf first-item-linepos (=> display-buffer line-pos))
- (for (from i 0 last-item-index)
- (do (let ((item (vector-fetch items i)))
- (=> display-buffer insert-line (=> item display-text))
- )))
- (=> display-buffer set-modified? NIL)
- (=> display-buffer goto first-item-linepos 0)
- )
- (defmethod (browser &sort-items) ()
- % Sort the items according to the current sorter, if any.
- % Do not update the display buffer.
- (when current-sorter
- (let ((list ()))
- (for (from i 0 last-item-index)
- (do (setf list (cons (vector-fetch items i) list)))
- )
- (setf list (GSort list current-sorter))
- (for (from i 0 last-item-index)
- (do (vector-store items i (car list))
- (setf list (cdr list))
- ))
- )))
- (defmethod (browser &remove-current-item) ()
- % Remove the current item from ITEMS and the display.
- % Return the item or NIL if there is no current item.
- (let ((index (=> self current-item-index)))
- (when index
- (let ((item (vector-fetch items index)))
- (for (from i (+ index 1) last-item-index)
- (do (vector-store items (- i 1) (vector-fetch items i))
- ))
- (vector-store items last-item-index NIL)
- (setf last-item-index (- last-item-index 1))
- (=> display-buffer move-to-start-of-line)
- (let ((start-pos (=> display-buffer position)))
- (=> display-buffer move-to-next-line)
- (=> display-buffer extract-region T start-pos
- (=> display-buffer position))
- (=> display-buffer set-modified? NIL)
- )
- item
- ))))
- (defmethod (browser &update-current-item) ()
- % Update the display for the current item.
- (let ((index (=> self current-item-index)))
- (when index
- (let ((item (vector-fetch items index)))
- (=> display-buffer store-line (+ index first-item-linepos)
- (=> item display-text))
- (=> display-buffer set-modified? NIL)
- ))))
- (defmethod (browser &keep-items) (fcn args)
- % Apply the function FCN once for each item. The first argument to FCN
- % is the item; the remaining items are ARGS (a list).
- % Remove those items for which FCN returns NIL and return them
- % in a list of items.
- (let ((removed-items ())
- (ptr 0)
- (current-item-index (=> self current-item-index))
- (new-current-item-index 0)
- )
- (for (from i 0 last-item-index)
- (do (let ((item (vector-fetch items i))
- (this-ptr ptr)
- )
- (cond ((apply fcn (cons item args)) % keep it
- (vector-store items ptr item)
- (setf ptr (+ ptr 1))
- )
- (t % remove it
- (setf removed-items (cons item removed-items))
- (=> item cleanup)
- ))
- (when (and current-item-index (= i current-item-index))
- (setf new-current-item-index this-ptr))
- )))
- (setf last-item-index (- ptr 1))
- (=> self &update-display)
- (=> display-buffer goto (+ new-current-item-index first-item-linepos) 0)
- removed-items
- ))
- (de &browser-item-not-killed (item)
- (or (not (=> item deleted?))
- (not (=> item kill))
- ))
|