001: // The contents of this file are subject to the Mozilla Public License Version
002: // 1.1
003: // (the "License"); you may not use this file except in compliance with the
004: // License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
005: //
006: // Software distributed under the License is distributed on an "AS IS" basis,
007: // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
008: // for the specific language governing rights and
009: // limitations under the License.
010: //
011: // The Original Code is "The Columba Project"
012: //
013: // The Initial Developers of the Original Code are Frederik Dietz and Timo
014: // Stich.
015: // Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
016: //
017: // All Rights Reserved.
018: package org.columba.mail.gui.table;
019:
020: import java.awt.Dimension;
021: import java.awt.event.MouseAdapter;
022: import java.awt.event.MouseEvent;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.util.List;
026: import java.util.Observable;
027: import java.util.Vector;
028: import java.util.logging.Logger;
029:
030: import javax.swing.ImageIcon;
031: import javax.swing.JLabel;
032: import javax.swing.JPopupMenu;
033: import javax.swing.ListSelectionModel;
034: import javax.swing.SwingUtilities;
035: import javax.swing.event.EventListenerList;
036: import javax.swing.event.ListSelectionEvent;
037: import javax.swing.event.ListSelectionListener;
038: import javax.swing.table.DefaultTableColumnModel;
039: import javax.swing.table.JTableHeader;
040: import javax.swing.table.TableColumn;
041: import javax.swing.table.TableColumnModel;
042: import javax.swing.tree.TreePath;
043:
044: import org.columba.api.gui.frame.IFrameMediator;
045: import org.columba.core.folder.api.IFolder;
046: import org.columba.core.folder.api.IFolderCommandReference;
047: import org.columba.core.gui.base.AscendingIcon;
048: import org.columba.core.gui.base.DescendingIcon;
049: import org.columba.core.gui.menu.ExtendablePopupMenu;
050: import org.columba.core.gui.menu.MenuXMLDecoder;
051: import org.columba.core.io.DiskIO;
052: import org.columba.mail.folder.IMailFolder;
053: import org.columba.mail.folder.IMailbox;
054: import org.columba.mail.folder.event.FolderEventDelegator;
055: import org.columba.mail.folderoptions.FolderOptionsController;
056: import org.columba.mail.gui.frame.MailFrameMediator;
057: import org.columba.mail.gui.table.model.HeaderTableModel;
058: import org.columba.mail.gui.table.model.MessageNode;
059: import org.columba.mail.gui.table.model.TableModelChangedEvent;
060: import org.columba.mail.gui.table.model.TableModelChangedListener;
061: import org.columba.mail.gui.table.model.TableModelSorter;
062: import org.columba.mail.gui.table.model.TableModelThreadedView;
063: import org.columba.mail.message.IColumbaHeader;
064: import org.columba.mail.message.IHeaderList;
065: import org.columba.mail.util.MailResourceLoader;
066: import org.frapuccino.treetable.Tree;
067:
068: /**
069: * Shows the message list. By default, this is the read/unread state if a message, Subject:, Date:, From: and Size headerfields.
070: * <p>
071: * Folder-specific configuration options are handled by <code>FolderOptionsController</code> and can be configured by the user
072: * in the AbstractMessageFolder Options Dialog.
073: *
074: * @author fdietz
075: */
076: public class TableController implements ListSelectionListener,
077: TableModelChangedListener, ITableController {
078:
079: /** JDK 1.4+ logging framework logger, used for logging. */
080: private static final Logger LOG = Logger
081: .getLogger("org.columba.mail.gui.table");
082:
083: /**
084: * table model
085: */
086: private HeaderTableModel headerTableModel;
087:
088: /**
089: * table view
090: */
091: protected TableView view;
092:
093: /**
094: * reference to mail framemediator
095: */
096: protected IFrameMediator frameController;
097:
098: /**
099: * table view context menu
100: */
101: protected ExtendablePopupMenu menu;
102:
103: /**
104: * sorting model
105: */
106: protected TableModelSorter tableModelSorter;
107:
108: /**
109: * threaded-view model
110: */
111: protected TableModelThreadedView tableModelThreadedView;
112:
113: /**
114: * previously selected rows
115: */
116: protected int[] previouslySelectedRows;
117:
118: private MessageNode[] previouslySelectedNodes;
119:
120: /**
121: * previously selected folder
122: */
123: private IMailbox previouslySelectedFolder;
124:
125: /**
126: * tooltip mouse handler
127: */
128: private ColumnHeaderTooltips tips;
129:
130: protected EventListenerList listenerList = new EventListenerList();
131:
132: /**
133: * Constructor
134: *
135: * @param mailFrameController
136: * mail framemediator
137: */
138: public TableController(IFrameMediator frameController) {
139: this .frameController = frameController;
140:
141: // init table model
142: headerTableModel = new HeaderTableModel();
143:
144: // init threaded-view model
145: tableModelThreadedView = new TableModelThreadedView();
146: headerTableModel.registerVisitor(tableModelThreadedView);
147:
148: // init sorting model
149: tableModelSorter = new TableModelSorter();
150: headerTableModel.registerVisitor(tableModelSorter);
151:
152: // init view
153: view = new TableView(headerTableModel, tableModelSorter);
154:
155: // pass tree to model, used by the threaded-view
156: headerTableModel.setTree((Tree) view.getTree());
157:
158: getView().setTransferHandler(
159: new TableViewTransferHandler(getFrameController()));
160: getView().setDragEnabled(true);
161:
162: // MouseListener sorts table when clicking on a column header
163: new TableHeaderMouseListener(getTableModelSorter());
164: view.getColumnModel().addColumnModelListener(headerTableModel);
165:
166: // we need this for the focus manager
167: getView().getSelectionModel().addListSelectionListener(this );
168:
169: JTableHeader header = view.getTableHeader();
170:
171: tips = new ColumnHeaderTooltips();
172: header.addMouseMotionListener(tips);
173:
174: // register interest on folder events
175: FolderEventDelegator.getInstance().addTableListener(this );
176:
177: }
178:
179: /**
180: * Assigns a tooltip for each column
181: * <p>
182: * Tooltips for columns can be found in org.columba.mail.i18n.header.header.properties.
183: *
184: * @see org.columba.mail.folderoptions.ColumnOptionsPlugin
185: */
186: public void initTooltips() {
187: tips.clear();
188:
189: // Assign a tooltip for each of the columns
190: for (int c = 0; c < view.getColumnCount(); c++) {
191: TableColumn col = view.getColumnModel().getColumn(c);
192:
193: // column IDs are all lower case
194: String lookup = ((String) col.getIdentifier())
195: .toLowerCase();
196:
197: // append "_tooltip"
198: lookup = lookup + "_tooltip";
199:
200: // get translation
201: String s = MailResourceLoader.getString("header", "header",
202: lookup);
203:
204: tips.setToolTip(col, s);
205: }
206: }
207:
208: /**
209: * Get view of table controller
210: *
211: * @return table view
212: */
213: public TableView getView() {
214: return view;
215: }
216:
217: /**
218: * Get table model
219: *
220: * @return table model
221: */
222: public IHeaderTableModel getHeaderTableModel() {
223: return headerTableModel;
224: }
225:
226: /**
227: * Select messages with UIDs.
228: * <p>
229: * Message UIDs are converted to {@link MessageNode}objects.
230: *
231: * @param uids
232: * array of message UIDs
233: */
234: public void setSelected(Object[] uids) {
235:
236: // select nodes
237: MessageNode[] nodes = new MessageNode[uids.length];
238:
239: for (int i = 0; i < uids.length; i++) {
240: nodes[i] = ((HeaderTableModel) getHeaderTableModel())
241: .getMessageNode(uids[i]);
242: }
243:
244: int[] rows = new int[nodes.length];
245: for (int i = 0; i < nodes.length; i++) {
246: TreePath path = new TreePath(nodes[i].getPath());
247: rows[i] = view.getTree().getRowForPath(path);
248:
249: }
250: view.selectRow(rows[0]);
251:
252: }
253:
254: /** ************************ actions ******************************* */
255: /**
256: * create the PopupMenu
257: */
258: public void createPopupMenu() {
259: try {
260: InputStream is = DiskIO
261: .getResourceStream("org/columba/mail/action/table_contextmenu.xml");
262:
263: menu = new MenuXMLDecoder(getFrameController())
264: .createPopupMenu(is);
265: } catch (IOException e) {
266: e.printStackTrace();
267: }
268: }
269:
270: /**
271: * Get popup menu
272: *
273: * @return popup menu
274: */
275: public JPopupMenu getPopupMenu() {
276: return menu;
277: }
278:
279: /**
280: * Method is called if folder data changed.
281: * <p>
282: * It is responsible for updating the correct underlying model.
283: *
284: * @param event
285: * update event
286: */
287: public void tableChanged(TableModelChangedEvent event) {
288:
289: // selected rows before updating the model
290: // -> used later to restore the selection
291: previouslySelectedRows = view.getSelectedRows();
292: previouslySelectedNodes = getView().getSelectedNodes();
293:
294: // folder in which the update occurs
295: IFolder folder = event.getSrcFolder();
296:
297: if (folder == null) {
298: return;
299: }
300:
301: LOG.info("source folder=" + folder.getName());
302:
303: // get current selection
304: IFolderCommandReference r = (IFolderCommandReference) ((MailFrameMediator) frameController)
305: .getTableSelection();
306: IFolder srcFolder = r.getSourceFolder();
307:
308: // its always possible that no folder is currenlty selected
309: if (srcFolder != null) {
310: LOG.info("selected folder=" + srcFolder.getName());
311: }
312:
313: // update infopanel (gray panel below the toolbar)
314: // showing total/unread/recent messages count
315: /*
316: * if (getFrameController() instanceof MailFrameMediator) { if (srcFolder != null) { ((ThreePaneMailFrameController)
317: * getFrameController()) .getFolderInfoPanel().setFolder((IMailFolder) srcFolder); } }
318: */
319:
320: // only update table if, this folder is the same
321: // as the currently selected
322: if (!folder.equals(srcFolder)) {
323: return;
324: }
325:
326: switch (event.getEventType()) {
327: case -1: {
328: getHeaderTableModel().set(event.getHeaderList());
329:
330: // FIXME threaded-view auto collapse
331: /*
332: * if (getTableModelThreadedView().isEnabled()) { // expand all unread message nodes for (int i = 0; i <
333: * getView().getRowCount(); i++) { System.out.println("i=" + i + " count=" + getView().getRowCount()); TreePath path =
334: * getView().getTree().getPathForRow(i); MessageNode node = (MessageNode) path .getLastPathComponent(); IColumbaHeader h =
335: * node.getHeader(); boolean unseen = !h.getFlags().getSeen(); if (unseen) { getView().getTree().expandPath(path); } } }
336: */
337: break;
338: }
339:
340: case TableModelChangedEvent.UPDATE: {
341: getHeaderTableModel().update();
342:
343: break;
344: }
345:
346: case TableModelChangedEvent.REMOVE: {
347: getHeaderTableModel().remove(event.getUids());
348:
349: break;
350: }
351:
352: case TableModelChangedEvent.MARK: {
353: getHeaderTableModel().modify(event.getUids());
354:
355: break;
356: }
357: }
358:
359: // when marking messages, don't touch selection
360: if (event.getEventType() == TableModelChangedEvent.MARK)
361: return;
362:
363: // re-select previous selection
364: if (previouslySelectedRows != null) {
365: // only re-select if only a single row was formerly selected
366: if ((previouslySelectedRows.length == 1)
367: && (previouslySelectedNodes.length > 0)) {
368: int row = ((HeaderTableModel) getHeaderTableModel())
369: .getRow(previouslySelectedNodes[0]);
370:
371: // if message was removed from JTable
372: if (row == -1)
373: row = previouslySelectedRows[0];
374:
375: // select row
376: view.selectRow(row);
377:
378: // scrolling to the selected row
379: getView().makeRowVisible(row);
380:
381: }
382: }
383:
384: }
385:
386: /**
387: * Returns the mailFrameController.
388: *
389: * @return MailFrameController
390: */
391: public IFrameMediator getFrameController() {
392: return frameController;
393: }
394:
395: /**
396: * Show the headerlist of currently selected folder.
397: * <p>
398: * Additionally, implements folderoptions plugin entrypoint.
399: *
400: * @see org.columba.mail.folder.folderoptions
401: * @see org.columba.mail.gui.frame.ViewHeaderListInterface#showHeaderList(org.columba.mail.folder.Folder,
402: * org.columba.mail.message.HeaderList)
403: */
404: public void showHeaderList(IMailbox folder, IHeaderList headerList)
405: throws Exception {
406:
407: // save previously selected folder options
408: if (previouslySelectedFolder != null) {
409: ((MailFrameMediator) getFrameController())
410: .getFolderOptionsController().save(
411: previouslySelectedFolder);
412: }
413:
414: // load options of newly selected folder
415: ((MailFrameMediator) getFrameController())
416: .getFolderOptionsController().load(folder,
417: FolderOptionsController.STATE_BEFORE);
418:
419: getHeaderTableModel().set(headerList);
420:
421: // load options of newly selected folder
422: ((MailFrameMediator) getFrameController())
423: .getFolderOptionsController().load(folder,
424: FolderOptionsController.STATE_AFTER);
425:
426: // remember previously selected folder
427: previouslySelectedFolder = folder;
428: }
429:
430: /**
431: * Show empty messagelist with no elements.
432: */
433: public void clear() {
434: // clear model
435: getHeaderTableModel().set(null);
436:
437: }
438:
439: /** *********** implement getter/setter methods ******************** */
440: /**
441: * return the table model sorter
442: */
443: public TableModelSorter getTableModelSorter() {
444: return tableModelSorter;
445: }
446:
447: /**
448: * return the threaded view model
449: */
450: public TableModelThreadedView getTableModelThreadedView() {
451: return tableModelThreadedView;
452: }
453:
454: /** ************************* ListSelectionListener interface ************* */
455:
456: /**
457: * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
458: */
459: public void valueChanged(ListSelectionEvent arg0) {
460:
461: // enable/disable cut/copy/paste/selectall actions
462: // FocusManager.getInstance().updateActions();
463:
464: // if user is currently changing selection, don't do anything
465: // -> wait until the final selection is available
466: if (arg0.getValueIsAdjusting())
467: return;
468:
469: /*
470: * // @author fdietz // bug #983931, message jumps while downloading new messages if (getView().getSelectedNodes().length ==
471: * 0) { // skip if no message selected if (getView().getRowCount() > 0) // if folder contains messages // -> skip to fix
472: * above bug return; }
473: */
474: //System.out.println("selection changed="+getView().getSelectedRow());
475: // selected nodes
476: MessageNode[] nodes = getView().getSelectedNodes();
477:
478: List<String> v = new Vector<String>();
479:
480: for (int i = 0; i < nodes.length; i++) {
481: final MessageNode _node = nodes[i];
482: if (_node != null) {
483: final Integer _selectedNode = (Integer) _node.getUid();
484: if (_selectedNode != null) {
485: v.add(_selectedNode.toString());
486: }
487: }
488: }
489:
490: fireMessageListSelectionChangedEvent(v);
491:
492: }
493:
494: /**
495: * @see org.columba.mail.gui.table.model.TableModelChangedListener#isInterestedIn(IFolder)
496: */
497: public boolean isInterestedIn(IMailFolder folder) {
498:
499: return folder == previouslySelectedFolder;
500: }
501:
502: /**
503: * @see org.columba.mail.gui.table.ITableController#getSelectedNodes()
504: */
505: public IMessageNode[] getSelectedNodes() {
506: return getView().getSelectedNodes();
507: }
508:
509: /**
510: * @see org.columba.mail.gui.table.ITableController#selectFirstRow()
511: */
512: public Object selectFirstRow() {
513: Object result = getView().selectFirstRow();
514:
515: return result;
516: }
517:
518: /**
519: * @see org.columba.mail.gui.table.ITableController#selectLastRow()
520: */
521: public Object selectLastRow() {
522: if (getView().getColumnCount() > 0) {
523: Object result = getView().selectLastRow();
524: return result;
525: } else {
526: return null;
527: }
528:
529: }
530:
531: /**
532: * @see org.columba.mail.gui.table.ITableController#selectRow(int)
533: */
534: public void selectRow(int row) {
535: getView().selectRow(row);
536:
537: }
538:
539: /**
540: * @see org.columba.mail.gui.table.ITableController#getMessagNode(java.lang.Object)
541: */
542: public IMessageNode getMessageNode(Object uid) {
543: return getView().getMessagNode(uid);
544: }
545:
546: /**
547: * @see org.columba.mail.gui.table.ITableController#enableThreadedView(boolean)
548: */
549: public void enableThreadedView(boolean enableThreadedMode,
550: boolean updateModel) {
551: getTableModelThreadedView().setEnabled(enableThreadedMode);
552: getHeaderTableModel().enableThreadedView(enableThreadedMode);
553: getView().enableThreadedView(enableThreadedMode);
554:
555: if (updateModel)
556: getHeaderTableModel().update();
557:
558: if (enableThreadedMode) {
559: // expand all unread message nodes
560: for (int i = 0; i < getView().getRowCount(); i++) {
561: LOG.info("i=" + i + " count=" //$NON-NLS-1$ //$NON-NLS-2$
562: + getView().getRowCount());
563:
564: TreePath path = getView().getTree().getPathForRow(i);
565: MessageNode node = (MessageNode) path
566: .getLastPathComponent();
567: IColumbaHeader h = node.getHeader();
568: boolean unseen = !h.getFlags().getSeen();
569: if (unseen) {
570: getView().getTree().expandPath(path);
571: }
572: }
573: }
574: }
575:
576: /**
577: * @see org.columba.mail.gui.table.ITableController#clearSelection()
578: */
579: public void clearSelection() {
580: getView().getSelectionModel().clearSelection();
581: }
582:
583: /**
584: * @see org.columba.mail.gui.table.ITableController#makeSelectedRow
585: */
586: public void makeSelectedRowVisible() {
587: getView().scrollRectToVisible(
588: getView().getCellRect(getView().getSelectedRow(), 0,
589: false));
590: }
591:
592: /**
593: * @see org.columba.mail.gui.table.ITableController#getSortingStateObservable()
594: */
595: public Observable getSortingStateObservable() {
596: return getTableModelSorter().getSortingStateObservable();
597: }
598:
599: /**
600: * @see org.columba.mail.gui.table.ITableController#setSortingOrder(boolean)
601: */
602: public void setSortingOrder(boolean order) {
603: getTableModelSorter().setSortingOrder(order);
604: }
605:
606: /**
607: * @see org.columba.mail.gui.table.ITableController#setSortingColumn(java.lang.String)
608: */
609: public void setSortingColumn(String column) {
610: getTableModelSorter().setSortingColumn(column);
611: }
612:
613: /**
614: * @see org.columba.mail.gui.table.ITableController#getSortingColumn()
615: */
616: public String getSortingColumn() {
617: return getTableModelSorter().getSortingColumn();
618: }
619:
620: /**
621: * @see org.columba.mail.gui.table.ITableController#getSortingOrder()
622: */
623: public boolean getSortingOrder() {
624: return getTableModelSorter().getSortingOrder();
625: }
626:
627: /**
628: * @see org.columba.mail.gui.table.ITableController#isThreadedViewEnabled()
629: */
630: public boolean isThreadedViewEnabled() {
631: return getTableModelThreadedView().isEnabled();
632: }
633:
634: /**
635: * @see org.columba.mail.gui.table.ITableController#getRowCount()
636: */
637: public int getRowCount() {
638: return getView().getRowCount();
639: }
640:
641: /**
642: * @see org.columba.mail.gui.table.ITableController#getColumnModel()
643: */
644: public TableColumnModel getColumnModel() {
645: return view.getColumnModel();
646: }
647:
648: /**
649: * @see org.columba.mail.gui.table.ITableController#resetColumnModel()
650: */
651: public void resetColumnModel() {
652: TableView view = getView();
653:
654: // remove all columns from table model
655: getHeaderTableModel().clearColumns();
656:
657: // reset row height
658: view.resetRowHeight();
659: view.setShowHorizontalLines(false);
660:
661: // remove all columns for column model
662: view.getColumnModel().removeColumnModelListener(
663: getHeaderTableModel());
664: view.setColumnModel(new DefaultTableColumnModel());
665: view.getColumnModel().addColumnModelListener(
666: getHeaderTableModel());
667:
668: // for some weird reason the table loses its inter-cell spacing
669: // property, when changing the underlying column model
670: // -> setting this to (0,0) again
671: view.setIntercellSpacing(new Dimension(0, 0));
672:
673: // if new columns were added, we have to initialize the tooltips
674: initTooltips();
675: }
676:
677: /**
678: * @see org.columba.mail.gui.table.ITableController#createColumn(java.lang.String, int)
679: */
680: public TableColumn createTableColumn(String name, int size) {
681: return view.createTableColumn(name, size);
682: }
683:
684: /**
685: * @see org.columba.mail.gui.table.ITableController#addColumn(javax.swing.table.TableColumn)
686: */
687: public void addColumn(TableColumn column) {
688: view.addColumn(column);
689: }
690:
691: /**
692: * Mouse listener for selecting columns with the left mouse to change the sorting order.
693: * <p>
694: * Also responsible for changing the icon in the renderer
695: *
696: * @author fdietz
697: */
698: class TableHeaderMouseListener extends MouseAdapter {
699:
700: private TableModelSorter sorter;
701:
702: private SortingStateObservable observable;
703:
704: private ImageIcon ascending = new AscendingIcon();
705:
706: private ImageIcon descending = new DescendingIcon();
707:
708: /**
709: *
710: */
711: public TableHeaderMouseListener(TableModelSorter sorter) {
712:
713: this .sorter = sorter;
714:
715: this .observable = sorter.getSortingStateObservable();
716:
717: JTableHeader th = view.getTableHeader();
718: th.addMouseListener(this );
719: }
720:
721: public void mouseClicked(MouseEvent e) {
722: TableColumnModel columnModel = view.getColumnModel();
723: int viewColumn = columnModel.getColumnIndexAtX(e.getX());
724: int column = viewColumn;
725:
726: // int column = view.convertColumnIndexToModel(viewColumn);
727: // int column2 = view.convertColumnIndexToView(viewColumn);
728: if (column != -1) {
729: ImageIcon icon = null;
730:
731: if (sorter.getSortingOrder() == true) {
732: icon = ascending;
733: } else {
734: icon = descending;
735: }
736:
737: // disable every icon
738: // -> set appropriate icon for selected column
739: for (int i = 0; i < columnModel.getColumnCount(); i++) {
740: JLabel renderer = (JLabel) columnModel.getColumn(i)
741: .getHeaderRenderer();
742:
743: if (i == column) {
744: renderer.setIcon(icon);
745: } else {
746: renderer.setIcon(null);
747: }
748: }
749:
750: // remember selected node
751: MessageNode[] nodes = view.getSelectedNodes();
752: Object uid = null;
753:
754: if ((nodes != null) && (nodes.length > 0))
755: uid = nodes[0].getUid();
756:
757: // repaint table header
758: SwingUtilities.invokeLater(new Runnable() {
759: public void run() {
760: view.getTableHeader().repaint();
761: }
762: });
763:
764: String columnName = getHeaderTableModel()
765: .getColumnName(column);
766:
767: // notify the model to sort the table
768: // sorter.sort(column);
769: boolean order = false;
770:
771: if (sorter.getSortingColumn().equals(columnName)) {
772: order = !sorter.getSortingOrder();
773: }
774: // notify observers (sorting state submenu)
775: observable.setSortingState(columnName, order);
776:
777: setSortingColumn(columnName);
778: setSortingOrder(order);
779: getHeaderTableModel().update();
780:
781: // make selected row visible again
782: if (uid != null)
783: setSelected(new Object[] { uid });
784:
785: }
786: }
787: }
788:
789: public ListSelectionModel getListSelectionModel() {
790: return view.getSelectionModel();
791: }
792:
793: /**
794: * @see org.columba.mail.gui.table.ITableController#getSelectedRows()
795: */
796: public int[] getSelectedRows() {
797: return view.getSelectedRows();
798: }
799:
800: /**
801: * @see org.columba.mail.gui.table.ITableController#getPathForRow(int)
802: */
803: public TreePath getPathForRow(int row) {
804: return view.getTree().getPathForRow(row);
805: }
806:
807: public void addMessageListSelectionListener(
808: IMessageListSelectionListener l) {
809: listenerList.add(IMessageListSelectionListener.class, l);
810: }
811:
812: public void removeMessageListSelectionListener(
813: IMessageListSelectionListener l) {
814: listenerList.remove(IMessageListSelectionListener.class, l);
815: }
816:
817: protected void fireMessageListSelectionChangedEvent(
818: List<String> messageIds) {
819:
820: IMessageListSelectionEvent e = new MessageListSelectionEvent(
821: this , messageIds);
822: // Guaranteed to return a non-null array
823: Object[] listeners = listenerList.getListenerList();
824:
825: // Process the listeners last to first, notifying
826: // those that are interested in this event
827: for (int i = listeners.length - 2; i >= 0; i -= 2) {
828: if (listeners[i] == IMessageListSelectionListener.class) {
829: ((IMessageListSelectionListener) listeners[i + 1])
830: .selectionChanged(e);
831: }
832: }
833: }
834:
835: }
|