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