1 package org.columba.mail.gui.table; 19 20 import java.awt.Dimension ; 21 import java.awt.event.MouseAdapter ; 22 import java.awt.event.MouseEvent ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.util.List ; 26 import java.util.Observable ; 27 import java.util.Vector ; 28 import java.util.logging.Logger ; 29 30 import javax.swing.ImageIcon ; 31 import javax.swing.JLabel ; 32 import javax.swing.JPopupMenu ; 33 import javax.swing.ListSelectionModel ; 34 import javax.swing.SwingUtilities ; 35 import javax.swing.event.EventListenerList ; 36 import javax.swing.event.ListSelectionEvent ; 37 import javax.swing.event.ListSelectionListener ; 38 import javax.swing.table.DefaultTableColumnModel ; 39 import javax.swing.table.JTableHeader ; 40 import javax.swing.table.TableColumn ; 41 import javax.swing.table.TableColumnModel ; 42 import javax.swing.tree.TreePath ; 43 44 import org.columba.api.gui.frame.IFrameMediator; 45 import org.columba.core.folder.api.IFolder; 46 import org.columba.core.folder.api.IFolderCommandReference; 47 import org.columba.core.gui.base.AscendingIcon; 48 import org.columba.core.gui.base.DescendingIcon; 49 import org.columba.core.gui.menu.ExtendablePopupMenu; 50 import org.columba.core.gui.menu.MenuXMLDecoder; 51 import org.columba.core.io.DiskIO; 52 import org.columba.mail.folder.IMailFolder; 53 import org.columba.mail.folder.IMailbox; 54 import org.columba.mail.folder.event.FolderEventDelegator; 55 import org.columba.mail.folderoptions.FolderOptionsController; 56 import org.columba.mail.gui.frame.MailFrameMediator; 57 import org.columba.mail.gui.table.model.HeaderTableModel; 58 import org.columba.mail.gui.table.model.MessageNode; 59 import org.columba.mail.gui.table.model.TableModelChangedEvent; 60 import org.columba.mail.gui.table.model.TableModelChangedListener; 61 import org.columba.mail.gui.table.model.TableModelSorter; 62 import org.columba.mail.gui.table.model.TableModelThreadedView; 63 import org.columba.mail.message.IColumbaHeader; 64 import org.columba.mail.message.IHeaderList; 65 import org.columba.mail.util.MailResourceLoader; 66 import org.frapuccino.treetable.Tree; 67 68 76 public class TableController implements ListSelectionListener , TableModelChangedListener, ITableController { 77 78 79 private static final Logger LOG = Logger.getLogger("org.columba.mail.gui.table"); 80 81 84 private HeaderTableModel headerTableModel; 85 86 89 protected TableView view; 90 91 94 protected IFrameMediator frameController; 95 96 99 protected ExtendablePopupMenu menu; 100 101 104 protected TableModelSorter tableModelSorter; 105 106 109 protected TableModelThreadedView tableModelThreadedView; 110 111 114 protected int[] previouslySelectedRows; 115 116 private MessageNode[] previouslySelectedNodes; 117 118 121 private IMailbox previouslySelectedFolder; 122 123 126 private ColumnHeaderTooltips tips; 127 128 protected EventListenerList listenerList = new EventListenerList (); 129 130 136 public TableController(IFrameMediator frameController) { 137 this.frameController = frameController; 138 139 headerTableModel = new HeaderTableModel(); 141 142 tableModelThreadedView = new TableModelThreadedView(); 144 headerTableModel.registerVisitor(tableModelThreadedView); 145 146 tableModelSorter = new TableModelSorter(); 148 headerTableModel.registerVisitor(tableModelSorter); 149 150 view = new TableView(headerTableModel, tableModelSorter); 152 153 headerTableModel.setTree((Tree) view.getTree()); 155 156 getView().setTransferHandler(new TableViewTransferHandler(getFrameController())); 157 getView().setDragEnabled(true); 158 159 new TableHeaderMouseListener(getTableModelSorter()); 161 view.getColumnModel().addColumnModelListener(headerTableModel); 162 163 getView().getSelectionModel().addListSelectionListener(this); 165 166 JTableHeader header = view.getTableHeader(); 167 168 tips = new ColumnHeaderTooltips(); 169 header.addMouseMotionListener(tips); 170 171 FolderEventDelegator.getInstance().addTableListener(this); 173 174 } 175 176 183 public void initTooltips() { 184 tips.clear(); 185 186 for (int c = 0; c < view.getColumnCount(); c++) { 188 TableColumn col = view.getColumnModel().getColumn(c); 189 190 String lookup = ((String ) col.getIdentifier()).toLowerCase(); 192 193 lookup = lookup + "_tooltip"; 195 196 String s = MailResourceLoader.getString("header", "header", lookup); 198 199 tips.setToolTip(col, s); 200 } 201 } 202 203 208 public TableView getView() { 209 return view; 210 } 211 212 217 public IHeaderTableModel getHeaderTableModel() { 218 return headerTableModel; 219 } 220 221 229 public void setSelected(Object [] uids) { 230 231 MessageNode[] nodes = new MessageNode[uids.length]; 233 234 for (int i = 0; i < uids.length; i++) { 235 nodes[i] = ((HeaderTableModel) getHeaderTableModel()).getMessageNode(uids[i]); 236 } 237 238 int[] rows = new int[nodes.length]; 239 for (int i = 0; i < nodes.length; i++) { 240 TreePath path = new TreePath (nodes[i].getPath()); 241 rows[i] = view.getTree().getRowForPath(path); 242 243 } 244 view.selectRow(rows[0]); 245 246 } 247 248 249 252 public void createPopupMenu() { 253 try { 254 InputStream is = DiskIO.getResourceStream("org/columba/mail/action/table_contextmenu.xml"); 255 256 menu = new MenuXMLDecoder(getFrameController()).createPopupMenu(is); 257 } catch (IOException e) { 258 e.printStackTrace(); 259 } 260 } 261 262 267 public JPopupMenu getPopupMenu() { 268 return menu; 269 } 270 271 279 public void tableChanged(TableModelChangedEvent event) { 280 281 previouslySelectedRows = view.getSelectedRows(); 284 previouslySelectedNodes = getView().getSelectedNodes(); 285 286 IFolder folder = event.getSrcFolder(); 288 289 if (folder == null) { 290 return; 291 } 292 293 LOG.info("source folder=" + folder.getName()); 294 295 IFolderCommandReference r = (IFolderCommandReference) ((MailFrameMediator) frameController).getTableSelection(); 297 IFolder srcFolder = r.getSourceFolder(); 298 299 if (srcFolder != null) { 301 LOG.info("selected folder=" + srcFolder.getName()); 302 } 303 304 310 311 if (!folder.equals(srcFolder)) { 314 return; 315 } 316 317 switch (event.getEventType()) { 318 case -1: { 319 getHeaderTableModel().set(event.getHeaderList()); 320 321 328 break; 329 } 330 331 case TableModelChangedEvent.UPDATE: { 332 getHeaderTableModel().update(); 333 334 break; 335 } 336 337 case TableModelChangedEvent.REMOVE: { 338 getHeaderTableModel().remove(event.getUids()); 339 340 break; 341 } 342 343 case TableModelChangedEvent.MARK: { 344 getHeaderTableModel().modify(event.getUids()); 345 346 break; 347 } 348 } 349 350 if (event.getEventType() == TableModelChangedEvent.MARK) 352 return; 353 354 if (previouslySelectedRows != null) { 356 if ((previouslySelectedRows.length == 1) && (previouslySelectedNodes.length > 0)) { 358 int row = ((HeaderTableModel) getHeaderTableModel()).getRow(previouslySelectedNodes[0]); 359 360 if (row == -1) 362 row = previouslySelectedRows[0]; 363 364 view.selectRow(row); 366 367 getView().makeRowVisible(row); 369 370 } 371 } 372 373 } 374 375 380 public IFrameMediator getFrameController() { 381 return frameController; 382 } 383 384 393 public void showHeaderList(IMailbox folder, IHeaderList headerList) throws Exception { 394 395 if (previouslySelectedFolder != null) { 397 ((MailFrameMediator) getFrameController()).getFolderOptionsController().save(previouslySelectedFolder); 398 } 399 400 ((MailFrameMediator) getFrameController()).getFolderOptionsController().load(folder, FolderOptionsController.STATE_BEFORE); 402 403 getHeaderTableModel().set(headerList); 404 405 ((MailFrameMediator) getFrameController()).getFolderOptionsController().load(folder, FolderOptionsController.STATE_AFTER); 407 408 previouslySelectedFolder = folder; 410 } 411 412 415 public void clear() { 416 getHeaderTableModel().set(null); 418 419 } 420 421 422 425 public TableModelSorter getTableModelSorter() { 426 return tableModelSorter; 427 } 428 429 432 public TableModelThreadedView getTableModelThreadedView() { 433 return tableModelThreadedView; 434 } 435 436 437 438 441 public void valueChanged(ListSelectionEvent arg0) { 442 443 446 if (arg0.getValueIsAdjusting()) 449 return; 450 451 456 458 MessageNode[] nodes = getView().getSelectedNodes(); 460 461 List <String > v = new Vector <String >(); 462 463 for (int i = 0; i < nodes.length; i++) { 464 final MessageNode _node = nodes[i]; 465 if (_node != null) { 466 final Integer _selectedNode = (Integer ) _node.getUid(); 467 if (_selectedNode != null) { 468 v.add(_selectedNode.toString()); 469 } 470 } 471 } 472 473 fireMessageListSelectionChangedEvent(v); 474 475 } 476 477 480 public boolean isInterestedIn(IMailFolder folder) { 481 482 return folder == previouslySelectedFolder; 483 } 484 485 488 public IMessageNode[] getSelectedNodes() { 489 return getView().getSelectedNodes(); 490 } 491 492 495 public Object selectFirstRow() { 496 Object result = getView().selectFirstRow(); 497 498 return result; 499 } 500 501 504 public Object selectLastRow() { 505 if (getView().getColumnCount() > 0) { 506 Object result = getView().selectLastRow(); 507 return result; 508 } else { 509 return null; 510 } 511 512 } 513 514 517 public void selectRow(int row) { 518 getView().selectRow(row); 519 520 } 521 522 525 public IMessageNode getMessageNode(Object uid) { 526 return getView().getMessagNode(uid); 527 } 528 529 532 public void enableThreadedView(boolean enableThreadedMode, boolean updateModel) { 533 getTableModelThreadedView().setEnabled(enableThreadedMode); 534 getHeaderTableModel().enableThreadedView(enableThreadedMode); 535 getView().enableThreadedView(enableThreadedMode); 536 537 if (updateModel) 538 getHeaderTableModel().update(); 539 540 if (enableThreadedMode) { 541 for (int i = 0; i < getView().getRowCount(); i++) { 543 LOG.info("i=" + i + " count=" + getView().getRowCount()); 545 546 TreePath path = getView().getTree().getPathForRow(i); 547 MessageNode node = (MessageNode) path.getLastPathComponent(); 548 IColumbaHeader h = node.getHeader(); 549 boolean unseen = !h.getFlags().getSeen(); 550 if (unseen) { 551 getView().getTree().expandPath(path); 552 } 553 } 554 } 555 } 556 557 560 public void clearSelection() { 561 getView().getSelectionModel().clearSelection(); 562 } 563 564 567 public void makeSelectedRowVisible() { 568 getView().scrollRectToVisible(getView().getCellRect(getView().getSelectedRow(), 0, false)); 569 } 570 571 574 public Observable getSortingStateObservable() { 575 return getTableModelSorter().getSortingStateObservable(); 576 } 577 578 581 public void setSortingOrder(boolean order) { 582 getTableModelSorter().setSortingOrder(order); 583 } 584 585 588 public void setSortingColumn(String column) { 589 getTableModelSorter().setSortingColumn(column); 590 } 591 592 595 public String getSortingColumn() { 596 return getTableModelSorter().getSortingColumn(); 597 } 598 599 602 public boolean getSortingOrder() { 603 return getTableModelSorter().getSortingOrder(); 604 } 605 606 609 public boolean isThreadedViewEnabled() { 610 return getTableModelThreadedView().isEnabled(); 611 } 612 613 616 public int getRowCount() { 617 return getView().getRowCount(); 618 } 619 620 623 public TableColumnModel getColumnModel() { 624 return view.getColumnModel(); 625 } 626 627 630 public void resetColumnModel() { 631 TableView view = getView(); 632 633 getHeaderTableModel().clearColumns(); 635 636 view.resetRowHeight(); 638 view.setShowHorizontalLines(false); 639 640 view.getColumnModel().removeColumnModelListener(getHeaderTableModel()); 642 view.setColumnModel(new DefaultTableColumnModel ()); 643 view.getColumnModel().addColumnModelListener(getHeaderTableModel()); 644 645 view.setIntercellSpacing(new Dimension (0, 0)); 649 650 initTooltips(); 652 } 653 654 657 public TableColumn createTableColumn(String name, int size) { 658 return view.createTableColumn(name, size); 659 } 660 661 664 public void addColumn(TableColumn column) { 665 view.addColumn(column); 666 } 667 668 675 class TableHeaderMouseListener extends MouseAdapter { 676 677 private TableModelSorter sorter; 678 679 private SortingStateObservable observable; 680 681 private ImageIcon ascending = new AscendingIcon(); 682 683 private ImageIcon descending = new DescendingIcon(); 684 685 688 public TableHeaderMouseListener(TableModelSorter sorter) { 689 690 this.sorter = sorter; 691 692 this.observable = sorter.getSortingStateObservable(); 693 694 JTableHeader th = view.getTableHeader(); 695 th.addMouseListener(this); 696 } 697 698 public void mouseClicked(MouseEvent e) { 699 TableColumnModel columnModel = view.getColumnModel(); 700 int viewColumn = columnModel.getColumnIndexAtX(e.getX()); 701 int column = viewColumn; 702 703 if (column != -1) { 706 ImageIcon icon = null; 707 708 if (sorter.getSortingOrder() == true) { 709 icon = ascending; 710 } else { 711 icon = descending; 712 } 713 714 for (int i = 0; i < columnModel.getColumnCount(); i++) { 717 JLabel renderer = (JLabel ) columnModel.getColumn(i).getHeaderRenderer(); 718 719 if (i == column) { 720 renderer.setIcon(icon); 721 } else { 722 renderer.setIcon(null); 723 } 724 } 725 726 MessageNode[] nodes = view.getSelectedNodes(); 728 Object uid = null; 729 730 if ((nodes != null) && (nodes.length > 0)) 731 uid = nodes[0].getUid(); 732 733 SwingUtilities.invokeLater(new Runnable () { 735 public void run() { 736 view.getTableHeader().repaint(); 737 } 738 }); 739 740 String columnName = getHeaderTableModel().getColumnName(column); 741 742 boolean order = false; 745 746 if (sorter.getSortingColumn().equals(columnName)) { 747 order = !sorter.getSortingOrder(); 748 } 749 observable.setSortingState(columnName, order); 751 752 setSortingColumn(columnName); 753 setSortingOrder(order); 754 getHeaderTableModel().update(); 755 756 if (uid != null) 758 setSelected(new Object [] { uid }); 759 760 } 761 } 762 } 763 764 public ListSelectionModel getListSelectionModel() { 765 return view.getSelectionModel(); 766 } 767 768 771 public int[] getSelectedRows() { 772 return view.getSelectedRows(); 773 } 774 775 778 public TreePath getPathForRow(int row) { 779 return view.getTree().getPathForRow(row); 780 } 781 782 public void addMessageListSelectionListener(IMessageListSelectionListener l) { 783 listenerList.add(IMessageListSelectionListener.class, l); 784 } 785 786 public void removeMessageListSelectionListener(IMessageListSelectionListener l) { 787 listenerList.remove(IMessageListSelectionListener.class, l); 788 } 789 790 protected void fireMessageListSelectionChangedEvent(List <String > messageIds) { 791 792 IMessageListSelectionEvent e = new MessageListSelectionEvent(this, messageIds); 793 Object [] listeners = listenerList.getListenerList(); 795 796 for (int i = listeners.length - 2; i >= 0; i -= 2) { 799 if (listeners[i] == IMessageListSelectionListener.class) { 800 ((IMessageListSelectionListener) listeners[i + 1]).selectionChanged(e); 801 } 802 } 803 } 804 805 } | Popular Tags |