001 /*
002 * LAPIS lightweight structured text processing system
003 *
004 * Copyright (C) 1998-2002 Carnegie Mellon University,
005 * Copyright (C) 2003 Massachusetts Institute of Technology.
006 * All rights reserved.
007 *
008 * This library is free software; you can redistribute it
009 * and/or modify it under the terms of the GNU General
010 * Public License as published by the Free Software
011 * Foundation, version 2.
012 *
013 * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/
014 */
015
016
017 package lapisx.swing;
018
019 import javax.swing.*;
020 import javax.swing.event.*;
021 import lapisx.util.History;
022 import java.util.NoSuchElementException;
023
024 /**
025 * An adapter for lapisx.util.History that allows a history to
026 * be used as the model for a JComboBox.
027 * <P>
028 * Example of use:
029 * <PRE>
030 * // make a history with room for 10 elements
031 * HistoryComboBoxModel history = new HistoryComboBoxModel (10);
032 * // make a combo box that displays the history in its drop-down list
033 * JComboBox combobox = new JComboBox (history);
034 * </PRE>
035 */
036 public class HistoryComboBoxModel extends History implements ComboBoxModel {
037 /**
038 * Listeners on this object.
039 */
040 protected EventListenerList listenerList = new EventListenerList ();
041
042 /**
043 * Make a HistoryComboBoxModel.
044 * @param max Maximum length of history
045 */
046 public HistoryComboBoxModel (int max) {
047 super (max);
048 }
049
050 /**
051 * Make a duplicate of another History.
052 * @param h History to copy
053 */
054 public HistoryComboBoxModel (History h) {
055 super (h);
056 }
057
058 ///////////
059 /////////// ComboBoxModel interface
060 ///////////
061
062 public void addListDataListener(ListDataListener l) {
063 listenerList.add(ListDataListener.class, l);
064 }
065
066 public void removeListDataListener(ListDataListener l) {
067 listenerList.remove(ListDataListener.class, l);
068 }
069
070 public int getSize () {
071 return size ();
072 }
073
074 public Object getElementAt (int index) {
075 if (index < 0 || index > getSize ())
076 throw new ArrayIndexOutOfBoundsException (index + " out of bounds");
077
078 return history[linearToCircular (index)];
079 }
080
081 public Object getSelectedItem () {
082 return get ();
083 }
084
085 public void setSelectedItem (Object obj) {
086 try {
087 jumpTo (obj);
088 } catch (NoSuchElementException e) {
089 }
090 }
091
092 ///////////
093 /////////// Implementation
094 ///////////
095
096 protected void fireRemoved (int i, int j) {
097 fire (ListDataEvent.INTERVAL_REMOVED, i, j);
098 }
099
100 protected void fireAdded (int i, int j) {
101 fire (ListDataEvent.INTERVAL_ADDED, i, j);
102 }
103
104 protected void fireChanged (int i, int j) {
105 fire (ListDataEvent.CONTENTS_CHANGED, i, j);
106 }
107
108 protected void fire (int eventType, int start, int end) {
109 Object[] listeners = listenerList.getListenerList();
110 ListDataEvent event =
111 new ListDataEvent(this, eventType,
112 circularToLinear (start),
113 circularToLinear (end));
114
115 for (int i = listeners.length - 2; i >= 0; i -= 2)
116 if (listeners[i] == ListDataListener.class)
117 switch (eventType) {
118 case ListDataEvent.CONTENTS_CHANGED:
119 ((ListDataListener)listeners[i+1]).contentsChanged (event);
120 break;
121 case ListDataEvent.INTERVAL_ADDED:
122 ((ListDataListener)listeners[i+1]).intervalAdded (event);
123 break;
124 case ListDataEvent.INTERVAL_REMOVED:
125 ((ListDataListener)listeners[i+1]).intervalRemoved (event);
126 break;
127 }
128 }
129
130 /**
131 * Maps end-1 to 0, end-2 to 1, ..., start to L-1.
132 */
133 private int circularToLinear (int i) {
134 return (end-1 - i + history.length) % history.length;
135 }
136
137 /**
138 * Maps 0 to end-1, 1 to end-2, ..., L-1 to start.
139 */
140 private int linearToCircular (int i) {
141 return (end-1 - i + history.length) % history.length;
142 }
143
144 }
145