001: /*
002: * Stingray Software Objective Blend
003: * Copyright (C) 1996 Stingray Software, Inc.
004: * All Rights Reserved
005: *
006: * This source code is only intended as a supplement to
007: * the Stingray Objective Blend product. See the Objective
008: * Blend html help documentation for detailed information regarding
009: * using OB classes.
010: *
011: * Author : Kerry Smith
012: * Description : SortableListBox.java - list box
013: *
014: * CHANGELOG:
015: * 7/09/96 LFW Created
016: * 5/12/97 JDK1.1
017: *
018: */
019:
020: /**
021: * The SortableListBox class is a subclass of the standard ListBox class
022: * which provides additional APIs for performing column sorting.
023: * The SortableListBox class also contains logic to implement a special
024: * "rove" mode where the selection of the listbox items is bound to the
025: * mouse motion rather than depending on mouse clicks, or on keyboard
026: * selection and focus. The "rove" mode is typically used in conjunction
027: * with combobox-type controls.
028: * @see ob.listbox.ListBox
029: */package ob.listbox;
030:
031: import java.util.*;
032: import com.sun.portal.log.common.PortalLogger;
033: import java.awt.*;
034:
035: public class SortableListBox extends ob.listbox.ListBox {
036: protected int m_nColumnSorted = 0;
037: boolean m_bSort = true;
038: boolean m_bHitHeader = true;
039: int m_nOldOver = -1;
040: boolean m_bRoveModeEnabled = false;
041: Vector m_arrSortIntegers = new Vector();
042:
043: /**
044: * Constructor for SortableListBox
045: * @param bMultipleSelections true if multiple selections are enabled, otherwise false
046: */
047: public SortableListBox(boolean bMultipleSelections) {
048: super (bMultipleSelections);
049: }
050:
051: /**
052: * sets whether rove mode is enabled or not. "Rove" mode describes a mode
053: * of selection where the selection of listbox items is tied to the motion
054: * of the mouse in addition to mouse clicks and keyboard selection. The
055: * "rove" mode is typically used in conjunction with combobox-type controls.
056: * @param bRove true if rove is enabled, otherwise false
057: */
058: public void setRoveMode(boolean bRove) {
059: m_bRoveModeEnabled = bRove;
060: }
061:
062: /**
063: * returns whether the SortableListBox is in rove mode or not.
064: * @return true if rove mode, otherwise false
065: */
066: public boolean isRoveMode() {
067: return m_bRoveModeEnabled;
068: }
069:
070: /**
071: * sorts a column based on its value. You can specify whether you want
072: * to sort by String type or by integer type. If sorting by integer type,
073: * the String type stored in the column is automatically converted to an
074: * int type when calculating the sort.
075: * @param nCol which column to sort
076: * @param bIntSort true if you wish to sort by integer type, otherwise false and
077: * searching will be done by String type.
078: */
079: public void setColumnIntegerSort(int nCol, boolean bIntSort) {
080: if (bIntSort) {
081: m_arrSortIntegers.addElement(new Integer(nCol));
082: return;
083: }
084: if (m_arrSortIntegers.contains(new Integer(nCol)))
085: m_arrSortIntegers.removeElement(new Integer(nCol));
086: }
087:
088: /**
089: * creates a new Item in the ListBox with the text you pass in.
090: * @param item the text you wish to use for the ListBox value as type String
091: */
092: public synchronized void addItem(String item) {
093:
094: addItem(item, -1, true);
095: }
096:
097: /**
098: * creates a new Item in the ListBox with the text and the image reference you
099: * pass in.
100: * @param item the text you wish to use for the ListBox value, as type String
101: * @param iImage the image reference value which refers to the ListBox image list. You need
102: * to keep track of which integers correspond to which Images that are stored.
103: */
104: public synchronized void addItem(String item, int iImage) {
105: addItem(item, iImage, true);
106: }
107:
108: /**
109: * creates a new item (row) in the ListBox with the text and image reference you pass in,
110: * and can also automatically sort the column after you've inserted the item.
111: * The sorting is done for the default column (column 0) based on the text you pass
112: * in to be associated with the ListItem.
113: * @param item the text you wish to use for the item value, as type String
114: * @param iImage the image reference value which refers to the ListBox image list. You need
115: * to keep track of which integers correspond to which Images that are stored.
116: * @param bSort true if you wish to sort, otherwise false.
117: */
118: public synchronized void addItem(String item, int iImage,
119: boolean bSort) {
120: super .addItem(item, iImage, false);
121: if (bSort == true)
122: sort();
123: }
124:
125: /**
126: * creates a new item (row) in the ListBox with the Object you pass in,
127: * @param item the Object you wish to associate with the ListItem (row) you create
128: * @param iImage the image reference value which refers to the ListBox image list. You need
129: * to keep track of which integers correspond to which Images that are stored.
130: * @param bSort true if you wish to sort, otherwise false.
131: */
132:
133: public synchronized void addItem(Object o) {
134: addItem(o, -1, true);
135: }
136:
137: /**
138: * creates a new item (row) in the ListBox with the Object you pass in,
139: * @param item the Object you wish to associate with the ListItem (row) you create
140: * @param iImage the image reference value which refers to the ListBox image list. You need
141: * to keep track of which integers correspond to which Images that are stored.
142: */
143: public synchronized void addItem(Object o, int iImage) {
144: addItem(o, iImage, true);
145: }
146:
147: /**
148: * creates a new item (row) in the ListBox with the text and image reference you pass in,
149: * and can also automatically sort the column after you've inserted the item.
150: * The sorting is done for the default column (column 0) based on the text you pass
151: * in to be associated with the ListItem.
152: * @param item the Object you wish to associate with the ListItem (row) you create
153: * @param iImage the image reference value which refers to the ListBox image list. You need
154: * to keep track of which integers correspond to which Images that are stored.
155: * @param bSort true if you wish to sort, otherwise false.
156: */
157: public synchronized void addItem(Object o, int iImage, boolean bSort) {
158: super .addItem(o, iImage, false);
159: if (bSort == true)
160: sort();
161: }
162:
163: /**
164: * creates a new item (row) in the ListBox with the text and image reference you pass in,
165: * and can also automatically sort the column after you've inserted the item.
166: * The sorting is done for the default column (column 0) based on the text you pass
167: * in to be associated with the ListItem.
168: * @param item
169: * @param iImage the image reference value which refers to the ListBox image list. You need
170: * to keep track of which integers correspond to which Images that are stored.
171: * @param bSort true if you wish to sort, otherwise false.
172: */
173: public synchronized void addItem(ListItem item, int iImage) {
174: addItem(item, iImage, true);
175: }
176:
177: /**
178: * creates a new item (row) in the ListBox based on the ListItem reference you pass in.
179: * The ListItem is added to the end of all the other rows.
180: * @param item the ListItem you wish to insert
181: * @see ob.listbox.ListItem
182: */
183: public synchronized void addItem(ListItem item) {
184: addItem(item, -1, true);
185: }
186:
187: /**
188: * creates a new item (row) in the ListBox with the ListItem and image reference you pass in,
189: * and can also automatically sort the column after you've inserted the item.
190: * The sorting is done for the default column (column 0) based on the text you pass
191: * in to be associated with the ListItem.
192: * @param item the new item (row) to insert, as type ListItem
193: * @param iImage the image reference value which refers to the ListBox image list. You need
194: * to keep track of which integers correspond to which Images that are stored.
195: * @param bSort true if you wish to sort, otherwise false.
196: * @see ob.listbox.ListItem
197: */
198: public synchronized void addItem(ListItem item, int iImage,
199: boolean bSort) {
200: super .addItem(item, iImage, false);
201: if (bSort == true)
202: sort();
203: }
204:
205: /**
206: * creates a new item (row) in the ListBox with the text you pass in,
207: * and uses the Font you pass in to display the item
208: * @param item
209: * @param font the font you want to use with the ListItem
210: * @see ob.listbox.ListItem
211: */
212: public synchronized void addItem(String item, Font font) {
213: addItem(item, font, -1, true);
214: }
215:
216: /**
217: * creates a new item (row) in the ListBox with the text and image reference you pass in,
218: * and can also include a font to render the text within the ListItem.
219: * @param item text to use with the ListItem as type String
220: * @param font the font you want to use with the ListItem
221: * @param iImage the image reference value which refers to the ListBox image list. You need
222: * to keep track of which integers correspond to which Images that are stored.
223: * @see ob.listbox.ListItem
224: */
225: public synchronized void addItem(String item, Font font, int iImage) {
226: addItem(item, font, iImage, true);
227: }
228:
229: /**
230: * creates a new item (row) in the ListBox with the text and image reference you pass in,
231: * and can also automatically sort the column after you've inserted the item.
232: * The sorting is done for the default column (column 0) based on the text you pass
233: * in to be associated with the ListItem.
234: * @param item the text you wish to associate with the default column of the row
235: * @param font the font you wish to use as a default for the row
236: * @param iImage the image reference value which refers to the ListBox image list. You need
237: * to keep track of which integers correspond to which Images that are stored.
238: * @param bSort true if you wish to sort, otherwise false.
239: */
240: public synchronized void addItem(String item, Font font,
241: int iImage, boolean bSort) {
242: super .addItem(item, font, iImage);
243: if (bSort == true)
244: sort();
245: }
246:
247: /**
248: * sets whether sorting is possible or not
249: * @param b true if sorting is allowed, otherwise false
250: */
251: public void setSort(boolean b) {
252: m_bSort = b;
253: }
254:
255: /**
256: * default sort method sorts column 0
257: */
258: public void sort() {
259:
260: sort(0);
261:
262: // default sorting on first column
263: }
264:
265: /**
266: * sorts based on the column you pass in
267: * @param nCol which column you want to sort on
268: */
269: public void sort(int nCol) {
270:
271: if (!m_bSort || m_bMouseDrag)
272: return;
273: m_nColumnSorted = nCol;
274: Vector presortList = new Vector();
275: for (int i = 0; i < selected.length; i++)
276: presortList.addElement(m_arrItems.elementAt(selected[i]));
277: if (m_arrSortIntegers.contains(new Integer(nCol)))
278: quicksortInteger(0, m_arrItems.size() - 1, nCol);
279: else
280: quicksort(0, m_arrItems.size() - 1, nCol);
281: selected = new int[0];
282:
283: for (int j = 0; j < presortList.size(); j++)
284: select(getIndex((ListItem) presortList.elementAt(j)), false);
285:
286: update();
287: }
288:
289: /**
290: * quicksort routine for sorting
291: */
292: public void quicksort(int low, int high, int nCol) {
293: int pivot;
294: if (high > low) {
295: pivot = partition(low, high, nCol);
296: quicksort(low, pivot, nCol);
297: quicksort(pivot + 1, high, nCol);
298: }
299: }
300:
301: /**
302: * quicksort routine for Integer types
303: */
304: public void quicksortInteger(int low, int high, int nCol) {
305: int pivot;
306: if (high > low) {
307: pivot = partitionIntegers(low, high, nCol);
308: quicksortInteger(low, pivot, nCol);
309: quicksortInteger(pivot + 1, high, nCol);
310: }
311: }
312:
313: protected int partition(int low, int high, int nCol) {
314: String compStr;
315: if (nCol == 0)
316: compStr = ((ListItem) m_arrItems.elementAt(low)).getText();
317: else
318: compStr = ((ListSubItem) ((ListItem) m_arrItems
319: .elementAt(low)).getSubItem(nCol)).getText();
320:
321: int i = low - 1;
322: int j = high + 1;
323: while (true) {
324: if (nCol == 0) {
325: while ((((ListItem) m_arrItems.elementAt(--j))
326: .getText().toUpperCase()).compareTo(compStr
327: .toUpperCase()) > 0
328: && j < m_arrItems.size())
329: ;
330: while ((((ListItem) m_arrItems.elementAt(++i))
331: .getText().toUpperCase()).compareTo(compStr
332: .toUpperCase()) < 0
333: && i > 0)
334: ;
335: } else {
336: while ((((ListSubItem) ((ListItem) m_arrItems
337: .elementAt(--j)).getSubItem(nCol)).getText()
338: .toUpperCase())
339: .compareTo(compStr.toUpperCase()) > 0
340: && j < m_arrItems.size())
341: ;
342: while ((((ListSubItem) ((ListItem) m_arrItems
343: .elementAt(++i)).getSubItem(nCol)).getText()
344: .toUpperCase())
345: .compareTo(compStr.toUpperCase()) < 0
346: && i > 0)
347: ;
348:
349: //while ((((ListSubItem)(((ListItem)m_arrItems.elementAt(--j)).getSubItem(nCol)).getText().toUpperCase())).compareTo(compStr.toUpperCase()) > 0 && j<m_arrItems.size());
350: //while ((((ListSubItem)(((ListItem)m_arrItems.elementAt(++i)).getSubItem(nCol)).getText().toUpperCase())).compareTo(compStr.toUpperCase()) < 0 && i>0);
351: }
352: if (i < j)
353: swap(i, j);
354: else
355: return j;
356: }
357: }
358:
359: protected int partitionIntegers(int low, int high, int nCol) {
360: int compStr;
361: if (nCol == 0)
362: compStr = Integer.parseInt(((ListItem) m_arrItems
363: .elementAt(low)).getText());
364: else
365: compStr = Integer
366: .parseInt(((ListSubItem) ((ListItem) m_arrItems
367: .elementAt(low)).getSubItem(nCol))
368: .getText());
369:
370: int i = low - 1;
371: int j = high + 1;
372: while (true) {
373: if (nCol == 0) {
374: while (Integer.parseInt((((ListItem) m_arrItems
375: .elementAt(--j)).getText())) > compStr
376: && j < m_arrItems.size())
377: ;
378: while (Integer.parseInt((((ListItem) m_arrItems
379: .elementAt(++i)).getText())) < compStr
380: && i > 0)
381: ;
382: } else {
383: while (Integer
384: .parseInt((((ListSubItem) ((ListItem) m_arrItems
385: .elementAt(--j)).getSubItem(nCol))
386: .getText())) > compStr
387: && j < m_arrItems.size())
388: ;
389: while (Integer
390: .parseInt((((ListSubItem) ((ListItem) m_arrItems
391: .elementAt(++i)).getSubItem(nCol))
392: .getText())) < compStr
393: && i > 0)
394: ;
395:
396: //while ((((ListSubItem)(((ListItem)m_arrItems.elementAt(--j)).getSubItem(nCol)).getText().toUpperCase())).compareTo(compStr.toUpperCase()) > 0 && j<m_arrItems.size());
397: //while ((((ListSubItem)(((ListItem)m_arrItems.elementAt(++i)).getSubItem(nCol)).getText().toUpperCase())).compareTo(compStr.toUpperCase()) < 0 && i>0);
398: }
399: if (i < j)
400: swap(i, j);
401: else
402: return j;
403: }
404: }
405:
406: protected void onHitColumnHeader(int nCol) {
407: if (m_bHitHeader) {
408: if (nCol == m_nColumnSorted)
409: reverse();
410:
411: else
412: sort(nCol);
413: }
414: }
415:
416: public void moveItems(Object[] items, int targetIndex) {
417: super .moveItems(items, targetIndex);
418: m_nColumnSorted = -1;
419: }
420:
421: /** reverses the desired column.
422: * NOTE: does not reverse sort -- list must already be
423: * sorted if reverse sort is desired.
424: */
425: public void reverse() {
426: if (m_bMouseDrag)
427: return;
428: for (int k = 0; k < selected.length; k++) {
429: int temp = selected[k];
430: int newIndex = m_arrItems.size() - temp - 1;
431: selected[k] = newIndex;
432: }
433:
434: int j = m_arrItems.size() - 1;
435: for (int i = 0; i < j; i++, j--)
436: swap(i, j);
437: update();
438: m_nColumnSorted = -1;
439: }
440:
441: // COMMENT OUT IF ROVE MODE NOT NEEDED
442: protected void onMoveOverItem(int x, int y) {
443: if (!m_bRoveModeEnabled)
444: return;
445: m_bHitHeader = false;
446: int overItem = getSelected(x, y);
447: if (overItem > -1) {
448: ListItem pItem = (ListItem) m_arrItems.elementAt(overItem);
449: Graphics g = getGraphics();
450: if (g == null)
451: return;
452: g.setXORMode(getBackground());
453: g.setColor(SystemColor.textHighlight);
454:
455: if (overItem != m_nOldOver) {
456: if (!isSelected(overItem))
457: g.fillRect(pItem.getTextBounds().x + 3, pItem
458: .getTextBounds().y
459: - getBounds().y + 1,
460: getInsideRect().width - 5, pItem
461: .getTextBounds().height - 1);
462: if (m_nOldOver != -1 && !isSelected(m_nOldOver)) {
463: ListItem tempItem = (ListItem) m_arrItems
464: .elementAt(m_nOldOver);
465: g.fillRect(tempItem.getTextBounds().x + 3, tempItem
466: .getTextBounds().y
467: - getBounds().y + 1,
468: getInsideRect().width - 5, tempItem
469: .getTextBounds().height - 1);
470: }
471: }
472: m_nOldOver = overItem;
473: //System.out.println("we're over item " + getSelected(x,y));
474: }
475: m_bHitHeader = true;
476: }
477:
478: // END COMMENT OUT IF ROVE MODE NOT NEEDED
479:
480: //COMMENT OUT IF ROVE MODE NOT NEEDED
481: public void draw(Graphics g) {
482: super .draw(g);
483: m_nOldOver = -1;
484: }
485:
486: // END COMMENT OUT IF ROVE MODE NOT NEEDED
487:
488: /*public int partition(int low, int high) {
489: String compStr;
490: int i, j;
491:
492: compStr = ((ListItem)m_arrItems.elementAt(high)).getText();
493: i = low - 1;
494: j = high;
495:
496: for (;;) {
497: while ((((ListItem)m_arrItems.elementAt(++i)).getText().toUpperCase()).compareTo(compStr.toUpperCase()) < 0 && i<m_arrItems.size());
498: while ((((ListItem)m_arrItems.elementAt(--j)).getText().toUpperCase()).compareTo(compStr.toUpperCase()) > 0 && j>0);
499: if (i >= j) break;
500: swap(i, high);
501: }
502: swap(i, high);
503: return i;
504: }*/
505:
506: public void swap(int a, int b) {
507: ListItem temp = ((ListItem) m_arrItems.elementAt(a));
508: m_arrItems
509: .setElementAt(((ListItem) m_arrItems.elementAt(b)), a);
510: m_arrItems.setElementAt(temp, b);
511: }
512:
513: }
|