/projects/columba-1.0/src/mail/core/org/columba/mail/gui/frame/ThreePaneMailFrameController.java
Java | 579 lines | 340 code | 119 blank | 120 comment | 38 complexity | c8ced38abd1f48e6849d9f314b4e5765 MD5 | raw file
1// The contents of this file are subject to the Mozilla Public License Version
2// 1.1
3//(the "License"); you may not use this file except in compliance with the
4//License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
5//
6//Software distributed under the License is distributed on an "AS IS" basis,
7//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
8//for the specific language governing rights and
9//limitations under the License.
10//
11//The Original Code is "The Columba Project"
12//
13//The Initial Developers of the Original Code are Frederik Dietz and Timo
14// Stich.
15//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
16//
17//All Rights Reserved.
18package org.columba.mail.gui.frame;
19
20import java.awt.BorderLayout;
21import java.awt.Color;
22import java.awt.Point;
23import java.awt.event.KeyEvent;
24import java.awt.event.MouseAdapter;
25import java.awt.event.MouseEvent;
26import java.io.File;
27import java.io.FileInputStream;
28import java.io.IOException;
29import java.io.InputStream;
30
31import javax.swing.JComponent;
32import javax.swing.JPanel;
33import javax.swing.JScrollPane;
34import javax.swing.JSplitPane;
35import javax.swing.JTable;
36import javax.swing.JViewport;
37import javax.swing.KeyStroke;
38import javax.swing.SwingUtilities;
39import javax.swing.tree.TreePath;
40
41import org.columba.api.gui.frame.IContentPane;
42import org.columba.api.selection.ISelectionListener;
43import org.columba.api.selection.SelectionChangedEvent;
44import org.columba.core.config.ViewItem;
45import org.columba.core.gui.base.UIFSplitPane;
46import org.columba.core.io.DiskIO;
47import org.columba.mail.command.IMailFolderCommandReference;
48import org.columba.mail.config.MailConfig;
49import org.columba.mail.folder.IMailFolder;
50import org.columba.mail.folder.IMailbox;
51import org.columba.mail.gui.composer.HeaderController;
52import org.columba.mail.gui.infopanel.FolderInfoPanel;
53import org.columba.mail.gui.message.action.ViewMessageAction;
54import org.columba.mail.gui.table.FilterToolbar;
55import org.columba.mail.gui.table.ITableController;
56import org.columba.mail.gui.table.TableController;
57import org.columba.mail.gui.table.action.DeleteAction;
58import org.columba.mail.gui.table.action.OpenMessageWithComposerAction;
59import org.columba.mail.gui.table.action.OpenMessageWithMessageFrameAction;
60import org.columba.mail.gui.table.action.ViewHeaderListAction;
61import org.columba.mail.gui.table.model.HeaderTableModel;
62import org.columba.mail.gui.table.model.MessageNode;
63import org.columba.mail.gui.table.selection.TableSelectionChangedEvent;
64import org.columba.mail.gui.table.selection.TableSelectionHandler;
65import org.columba.mail.gui.tree.FolderTreeModel;
66import org.columba.mail.gui.tree.ITreeController;
67import org.columba.mail.gui.tree.TreeController;
68import org.columba.mail.gui.tree.action.MoveDownAction;
69import org.columba.mail.gui.tree.action.MoveUpAction;
70import org.columba.mail.gui.tree.action.RenameFolderAction;
71import org.columba.mail.gui.tree.selection.TreeSelectionChangedEvent;
72import org.columba.mail.gui.tree.selection.TreeSelectionHandler;
73import org.columba.mail.util.MailResourceLoader;
74
75/**
76 * @author fdietz
77 *
78 */
79public class ThreePaneMailFrameController extends AbstractMailFrameController
80 implements TreeViewOwner, TableViewOwner, IContentPane,
81 ISelectionListener {
82
83 public TreeController treeController;
84
85 public TableController tableController;
86
87 public HeaderController headerController;
88
89 public FilterToolbar filterToolbar;
90
91 public JSplitPane mainSplitPane;
92
93 public JSplitPane rightSplitPane;
94
95 private JPanel tablePanel;
96
97 private JPanel messagePanel;
98
99 public FolderInfoPanel folderInfoPanel;
100
101 /**
102 * true, if the messagelist table selection event was triggered by a popup
103 * event. False, otherwise.
104 */
105 public boolean isTablePopupEvent;
106
107 /**
108 * true, if the tree selection event was triggered by a popup event. False,
109 * otherwise.
110 */
111 public boolean isTreePopupEvent;
112
113 /**
114 * @param container
115 */
116 public ThreePaneMailFrameController(ViewItem viewItem) {
117 super(viewItem);
118
119 treeController = new TreeController(this, FolderTreeModel.getInstance());
120 tableController = new TableController(this);
121
122 // create selection handlers
123 TableSelectionHandler tableHandler = new TableSelectionHandler(
124 tableController);
125 getSelectionManager().addSelectionHandler(tableHandler);
126 tableHandler.addSelectionListener(this);
127
128 TreeSelectionHandler treeHandler = new TreeSelectionHandler(
129 treeController.getView());
130 getSelectionManager().addSelectionHandler(treeHandler);
131
132 // double-click mouse listener
133 tableController.getView().addMouseListener(new TableMouseListener());
134
135 treeController.getView().addMouseListener(new TreeMouseListener());
136
137 folderInfoPanel = new FolderInfoPanel(this);
138
139 // table registers interest in tree selection events
140 treeHandler.addSelectionListener(tableHandler);
141
142 // also register interest in tree seleciton events
143 // for updating the title
144 treeHandler.addSelectionListener(this);
145
146 filterToolbar = new FilterToolbar(tableController);
147
148 RenameFolderAction renameFolderAction = new RenameFolderAction(this);
149
150 // Register F2 hotkey for renaming folder when the message panel has
151 // focus
152 tableController.getView().getActionMap().put("F2", renameFolderAction);
153 tableController.getView().getInputMap().put(
154 KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "F2");
155
156 // Register F2 hotkey for renaming folder when the folder tree itself
157 // has focus
158 treeController.getView().getActionMap().put("F2", renameFolderAction);
159 treeController.getView().getInputMap().put(
160 KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "F2");
161
162 // Register Alt-Up hotkey for moving up folder when folder tree or
163 // table have focus
164 MoveUpAction moveUpAction = new MoveUpAction(this);
165 tableController.getView().getActionMap().put("ALT_UP", moveUpAction);
166 tableController.getView().getInputMap().put(
167 KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.ALT_MASK),
168 "ALT_UP");
169
170 treeController.getView().getActionMap().put("ALT_UP", moveUpAction);
171 treeController.getView().getInputMap().put(
172 KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.ALT_MASK),
173 "ALT_UP");
174
175 // Register Alt-Down hotkey for moving up folder when folder tree or
176 // table have focus
177 MoveDownAction moveDownAction = new MoveDownAction(this);
178 tableController.getView().getActionMap()
179 .put("ALT_DOWN", moveDownAction);
180 tableController.getView().getInputMap().put(
181 KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.ALT_MASK),
182 "ALT_DOWN");
183
184 treeController.getView().getActionMap().put("ALT_DOWN", moveDownAction);
185 treeController.getView().getInputMap().put(
186 KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.ALT_MASK),
187 "ALT_DOWN");
188
189 DeleteAction deleteAction = new DeleteAction(this);
190 tableController.getView().getActionMap().put("DEL", deleteAction);
191 tableController.getView().getInputMap().put(
192 KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "DEL");
193
194 }
195
196 public void enableMessagePreview(boolean enable) {
197 getViewItem().setBoolean("header_enabled", enable);
198
199 if (enable) {
200 rightSplitPane = new UIFSplitPane();
201 rightSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
202 rightSplitPane.add(tablePanel, JSplitPane.LEFT);
203 rightSplitPane.add(messagePanel, JSplitPane.RIGHT);
204
205 mainSplitPane.add(rightSplitPane, JSplitPane.RIGHT);
206 } else {
207 rightSplitPane = null;
208
209 mainSplitPane.add(tablePanel, JSplitPane.RIGHT);
210 }
211
212 mainSplitPane.setDividerLocation(viewItem.getIntegerWithDefault(
213 "splitpanes", "main", 100));
214
215 if (enable)
216 rightSplitPane.setDividerLocation(viewItem.getIntegerWithDefault(
217 "splitpanes", "header", 100));
218
219 getContainer().getFrame().validate();
220 }
221
222 /**
223 * @return Returns the filterToolbar.
224 */
225 public FilterToolbar getFilterToolbar() {
226 return filterToolbar;
227 }
228
229 /**
230 * @see org.columba.mail.gui.frame.TreeViewOwner#getTreeController()
231 */
232 public ITreeController getTreeController() {
233 return treeController;
234 }
235
236 /**
237 * @see org.columba.mail.gui.frame.TableViewOwner#getTableController()
238 */
239 public ITableController getTableController() {
240 return tableController;
241 }
242
243 /**
244 * @see org.columba.api.gui.frame.IContentPane#getComponent()
245 */
246 public JComponent getComponent() {
247 JPanel panel = new JPanel();
248
249 mainSplitPane = new UIFSplitPane();
250 mainSplitPane.setBorder(null);
251
252 panel.setLayout(new BorderLayout());
253
254 panel.add(mainSplitPane, BorderLayout.CENTER);
255
256 mainSplitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
257
258 JScrollPane treeScrollPane = new JScrollPane(treeController.getView());
259
260 // treeScrollPane.setBorder(BorderFactory.createEmptyBorder(1, 1, 1,
261 // 1));
262 mainSplitPane.add(treeScrollPane, JSplitPane.LEFT);
263
264 messagePanel = new JPanel();
265 messagePanel.setLayout(new BorderLayout());
266 messagePanel.add(messageController, BorderLayout.CENTER);
267
268 tablePanel = new JPanel();
269 tablePanel.setLayout(new BorderLayout());
270
271 ViewItem viewItem = getViewItem();
272
273 tablePanel.add(filterToolbar, BorderLayout.NORTH);
274
275 JScrollPane tableScrollPane = new JScrollPane(tableController.getView());
276 tableScrollPane
277 .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
278
279 tableScrollPane.getViewport().setScrollMode(
280 JViewport.BACKINGSTORE_SCROLL_MODE);
281
282 tableScrollPane.getViewport().setBackground(Color.white);
283 tablePanel.add(tableScrollPane, BorderLayout.CENTER);
284
285 if (viewItem
286 .getBooleanWithDefault("splitpanes", "header_enabled", true)) {
287
288 rightSplitPane = new UIFSplitPane();
289 rightSplitPane.setBorder(null);
290 rightSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
291 rightSplitPane.add(tablePanel, JSplitPane.LEFT);
292 rightSplitPane.add(messagePanel, JSplitPane.RIGHT);
293
294 mainSplitPane.add(rightSplitPane, JSplitPane.RIGHT);
295 } else {
296 mainSplitPane.add(tablePanel, JSplitPane.RIGHT);
297 }
298
299 getContainer().setInfoPanel(folderInfoPanel);
300
301 int count = MailConfig.getInstance().getAccountList().count();
302
303 if (count == 0) {
304 // pack();
305 rightSplitPane.setDividerLocation(150);
306 } else {
307 mainSplitPane.setDividerLocation(viewItem.getIntegerWithDefault(
308 "splitpanes", "main", 100));
309
310 if (viewItem.getBooleanWithDefault("splitpanes", "header_enabled",
311 true))
312 rightSplitPane.setDividerLocation(viewItem
313 .getIntegerWithDefault("splitpanes", "header", 100));
314 }
315
316 try {
317 InputStream is = DiskIO
318 .getResourceStream("org/columba/mail/action/menu.xml");
319 getContainer().extendMenu(this, is);
320
321 File configDirectory = MailConfig.getInstance()
322 .getConfigDirectory();
323 InputStream is2 = new FileInputStream(new File(configDirectory, "main_toolbar.xml"));
324 getContainer().extendToolbar(this, is2);
325
326 } catch (IOException e) {
327 e.printStackTrace();
328 }
329
330 tableController.createPopupMenu();
331 treeController.createPopupMenu();
332 messageController.createPopupMenu();
333
334 // TODO: fixme
335 // JFrame frame = (JFrame) getContainer().getFrame();
336 // ColumbaMenu menu = (ColumbaMenu) frame.getJMenuBar();
337 // menu.addMenuItem("my_reply_action_id", new ReplyAction(this),
338 // ColumbaMenu.MENU_VIEW, ColumbaMenu.PLACEHOLDER_BOTTOM);
339
340 return panel;
341 }
342
343 public void showFilterToolbar() {
344 tablePanel.add(filterToolbar, BorderLayout.NORTH);
345 tablePanel.validate();
346
347 }
348
349 public void hideFilterToolbar() {
350 tablePanel.remove(filterToolbar);
351 tablePanel.validate();
352
353 }
354
355 public void savePositions(ViewItem viewItem) {
356 super.savePositions(viewItem);
357
358 // splitpanes
359 viewItem.setInteger("splitpanes", "main", mainSplitPane
360 .getDividerLocation());
361
362 if (rightSplitPane != null)
363 viewItem.setInteger("splitpanes", "header", rightSplitPane
364 .getDividerLocation());
365 viewItem.setBoolean("splitpanes", "header_enabled",
366 rightSplitPane != null);
367
368 IMailFolderCommandReference r = getTreeSelection();
369
370 if (r != null) {
371 IMailFolder folder = (IMailFolder) r.getSourceFolder();
372
373 // folder-based configuration
374
375 if (folder instanceof IMailbox)
376 getFolderOptionsController().save((IMailbox) folder);
377 }
378 }
379
380 /**
381 * @return Returns the folderInfoPanel.
382 */
383 public FolderInfoPanel getFolderInfoPanel() {
384 return folderInfoPanel;
385 }
386
387 /**
388 * @see org.columba.api.gui.frame.IFrameMediator#getString(java.lang.String,
389 * java.lang.String, java.lang.String)
390 */
391 public String getString(String sPath, String sName, String sID) {
392 return MailResourceLoader.getString(sPath, sName, sID);
393 }
394
395 /**
396 * @see org.columba.api.gui.frame.IFrameMediator#getContentPane()
397 */
398 public IContentPane getContentPane() {
399 return this;
400 }
401
402 /**
403 * @see org.columba.api.selection.ISelectionListener#selectionChanged(org.columba.api.selection.SelectionChangedEvent)
404 */
405 public void selectionChanged(SelectionChangedEvent e) {
406
407 if (e instanceof TreeSelectionChangedEvent) {
408 // tree selection event
409 TreeSelectionChangedEvent event = (TreeSelectionChangedEvent) e;
410
411 IMailFolder[] selectedFolders = event.getSelected();
412
413 if (isTreePopupEvent == false) {
414 // view headerlist in message list viewer
415 new ViewHeaderListAction(this).actionPerformed(null);
416
417 getFolderInfoPanel().selectionChanged(e);
418
419 // update frame title
420 if (selectedFolders.length == 1 && selectedFolders[0] != null) {
421 getContainer().getFrame().setTitle(
422 selectedFolders[0].getName());
423 } else {
424 getContainer().getFrame().setTitle("");
425 }
426 }
427
428 isTreePopupEvent = false;
429
430 } else if (e instanceof TableSelectionChangedEvent) {
431 // messagelist table selection event
432 TableSelectionChangedEvent event = (TableSelectionChangedEvent) e;
433
434 if (isTablePopupEvent == false)
435 // show message content
436 new ViewMessageAction(this).actionPerformed(null);
437
438 isTablePopupEvent = false;
439 } else
440 throw new IllegalArgumentException(
441 "unknown selection changed event");
442 }
443
444 /**
445 * Double-click mouse listener for message list table component.
446 * <p>
447 * If message is marked as draft, the composer will be opened to edit the
448 * message. Otherwise, the message will be viewed in the message frame.
449 *
450 * @author Frederik Dietz
451 */
452 class TableMouseListener extends MouseAdapter {
453
454 /**
455 * @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent)
456 */
457 public void mousePressed(MouseEvent event) {
458 if (event.isPopupTrigger()) {
459 processPopup(event);
460 }
461 }
462
463 /**
464 * @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent)
465 */
466 public void mouseReleased(MouseEvent event) {
467 if (event.isPopupTrigger()) {
468 processPopup(event);
469 }
470 }
471
472 /**
473 * @see java.awt.event.MouseAdapter#mouseClicked(java.awt.event.MouseEvent)
474 */
475 public void mouseClicked(MouseEvent event) {
476 // if mouse button was pressed twice times
477 if (event.getClickCount() == 2) {
478 // get selected row
479 int selectedRow = tableController.getView().getSelectedRow();
480
481 // get message node at selected row
482 MessageNode node = (MessageNode) ((HeaderTableModel) tableController
483 .getHeaderTableModel())
484 .getMessageNodeAtRow(selectedRow);
485
486 // is the message marked as draft ?
487 boolean markedAsDraft = node.getHeader().getFlags().getDraft();
488
489 if (markedAsDraft) {
490 // edit message in composer
491 new OpenMessageWithComposerAction(
492 ThreePaneMailFrameController.this)
493 .actionPerformed(null);
494 } else {
495 // open message in new message-frame
496 new OpenMessageWithMessageFrameAction(
497 ThreePaneMailFrameController.this)
498 .actionPerformed(null);
499 }
500 }
501 }
502
503 protected void processPopup(final MouseEvent event) {
504
505 isTablePopupEvent = true;
506
507 JTable table = tableController.getView();
508
509 int selectedRows = table.getSelectedRowCount();
510
511 if (selectedRows <= 1) {
512 // select node
513 int row = table
514 .rowAtPoint(new Point(event.getX(), event.getY()));
515 table.setRowSelectionInterval(row, row);
516 }
517
518 SwingUtilities.invokeLater(new Runnable() {
519
520 public void run() {
521 tableController.getPopupMenu().show(event.getComponent(),
522 event.getX(), event.getY());
523 isTablePopupEvent = false;
524 }
525 });
526 }
527 }
528
529 class TreeMouseListener extends MouseAdapter {
530
531 /**
532 * @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent)
533 */
534 public void mousePressed(MouseEvent event) {
535 if (event.isPopupTrigger()) {
536 processPopup(event);
537 }
538 }
539
540 /**
541 * @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent)
542 */
543 public void mouseReleased(MouseEvent event) {
544 if (event.isPopupTrigger()) {
545 processPopup(event);
546 }
547 }
548
549 /**
550 * @see java.awt.event.MouseAdapter#mouseClicked(java.awt.event.MouseEvent)
551 */
552 public void mouseClicked(MouseEvent event) {
553 // if mouse button was pressed twice times
554 if (event.getClickCount() == 2) {
555 // get selected row
556
557 }
558 }
559
560 protected void processPopup(final MouseEvent event) {
561
562 isTreePopupEvent = true;
563
564 Point point = event.getPoint();
565 TreePath path = treeController.getView().getClosestPathForLocation(
566 point.x, point.y);
567 treeController.getView().setSelectionPath(path);
568
569 SwingUtilities.invokeLater(new Runnable() {
570
571 public void run() {
572 treeController.getPopupMenu().show(event.getComponent(),
573 event.getX(), event.getY());
574 isTreePopupEvent = false;
575 }
576 });
577 }
578 }
579}