KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > mail > gui > composer > ComposerController


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.
18

19 package org.columba.mail.gui.composer;
20
21 import java.awt.BorderLayout JavaDoc;
22 import java.awt.Color JavaDoc;
23 import java.awt.Component JavaDoc;
24 import java.awt.Container JavaDoc;
25 import java.awt.FocusTraversalPolicy JavaDoc;
26 import java.awt.event.ItemEvent JavaDoc;
27 import java.awt.event.ItemListener JavaDoc;
28 import java.awt.event.MouseEvent JavaDoc;
29 import java.awt.event.MouseListener JavaDoc;
30 import java.io.File JavaDoc;
31 import java.io.FileInputStream JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.nio.charset.Charset JavaDoc;
35 import java.nio.charset.UnsupportedCharsetException JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.Observable JavaDoc;
38 import java.util.Observer JavaDoc;
39 import java.util.logging.Logger JavaDoc;
40
41 import javax.swing.BorderFactory JavaDoc;
42 import javax.swing.JComponent JavaDoc;
43 import javax.swing.JEditorPane JavaDoc;
44 import javax.swing.JOptionPane JavaDoc;
45 import javax.swing.JPanel JavaDoc;
46 import javax.swing.JScrollPane JavaDoc;
47 import javax.swing.JSplitPane JavaDoc;
48 import javax.swing.SwingUtilities JavaDoc;
49 import javax.swing.UIManager JavaDoc;
50 import javax.swing.border.Border JavaDoc;
51 import javax.swing.border.LineBorder JavaDoc;
52 import javax.swing.event.DocumentEvent JavaDoc;
53 import javax.swing.event.DocumentListener JavaDoc;
54 import javax.swing.event.EventListenerList JavaDoc;
55 import javax.swing.text.BadLocationException JavaDoc;
56 import javax.swing.text.Document JavaDoc;
57
58 import org.columba.api.gui.frame.IContainer;
59 import org.columba.core.charset.CharsetEvent;
60 import org.columba.core.charset.CharsetListener;
61 import org.columba.core.charset.CharsetOwnerInterface;
62 import org.columba.core.config.ViewItem;
63 import org.columba.core.gui.base.LabelWithMnemonic;
64 import org.columba.core.gui.frame.DefaultFrameController;
65 import org.columba.core.gui.frame.FrameManager;
66 import org.columba.core.io.DiskIO;
67 import org.columba.core.xml.XmlElement;
68 import org.columba.mail.config.AccountItem;
69 import org.columba.mail.config.MailConfig;
70 import org.columba.mail.gui.composer.action.SaveAsDraftAction;
71 import org.columba.mail.gui.composer.html.HtmlEditorController2;
72 import org.columba.mail.gui.composer.html.HtmlToolbar;
73 import org.columba.mail.gui.composer.text.TextEditorController;
74 import org.columba.mail.gui.message.viewer.MessageBorder;
75 import org.columba.mail.parser.text.HtmlParser;
76 import org.columba.mail.util.MailResourceLoader;
77 import org.frapuccino.swing.MultipleTransferHandler;
78
79 import com.jgoodies.forms.debug.FormDebugPanel;
80 import com.jgoodies.forms.factories.FormFactory;
81 import com.jgoodies.forms.layout.CellConstraints;
82 import com.jgoodies.forms.layout.ColumnSpec;
83 import com.jgoodies.forms.layout.FormLayout;
84 import com.jgoodies.forms.layout.FormSpec;
85 import com.jgoodies.forms.layout.RowSpec;
86 import com.jgoodies.forms.layout.Sizes;
87
88 /**
89  *
90  * controller for message composer dialog
91  *
92  * @author fdietz
93  */

94 public class ComposerController extends DefaultFrameController implements
95         CharsetOwnerInterface, ItemListener JavaDoc, Observer JavaDoc {
96
97     /** JDK 1.4+ logging framework logger, used for logging. */
98     private static final Logger JavaDoc LOG = Logger
99             .getLogger("org.columba.mail.gui.composer");
100
101     private AttachmentController attachmentController;
102
103     private SubjectController subjectController;
104
105     private PriorityController priorityController;
106
107     private AccountController accountController;
108
109     private AbstractEditorController currentEditorController;
110
111     private HeaderController headerController;
112
113     private ComposerSpellCheck composerSpellCheck;
114
115     private ComposerModel composerModel;
116
117     private Charset JavaDoc charset;
118
119     private EventListenerList JavaDoc listenerList = new EventListenerList JavaDoc();
120
121     /** Buffer for listeners used by addContainerListenerForEditor and createView */
122     private List JavaDoc containerListenerBuffer;
123
124     private JSplitPane JavaDoc attachmentSplitPane;
125
126     /** Editor viewer resides in this panel */
127     private TextEditorPanel editorScrollPane;
128
129     private LabelWithMnemonic subjectLabel;
130
131     private LabelWithMnemonic smtpLabel;
132
133     private LabelWithMnemonic priorityLabel;
134
135     private JPanel JavaDoc centerPanel = new FormDebugPanel();
136
137     private JPanel JavaDoc topPanel;
138
139     private HtmlToolbar htmlToolbar;
140
141     private boolean promptOnDialogClosing = true;
142
143     private SignatureView signatureView;
144
145     private boolean attachmentPanelShown;
146
147     private JPanel JavaDoc editorPanel = new JPanel JavaDoc();
148
149     JPanel JavaDoc toolbarPanel = new JPanel JavaDoc();
150
151     private TextEditorController textEditor;
152
153     private HtmlEditorController2 htmlEditor;
154
155     public ComposerController() {
156         this(new ComposerModel(), FrameManager.getInstance()
157                 .createCustomViewItem("Composer"));
158
159     }
160
161     public ComposerController(ComposerModel model, ViewItem viewItem) {
162         super(viewItem);
163
164         // init model (defaults to empty plain text message)
165
composerModel = model;
166
167         // init controllers for different parts of the composer
168
attachmentController = new AttachmentController(this);
169         headerController = new HeaderController(this);
170         subjectController = new SubjectController(this);
171
172         // listen to changes in the Subject to update the title bar
173
// of the message composer window
174
getSubjectController().getView().getDocument().addDocumentListener(
175                 new MyDocumentListener());
176
177         priorityController = new PriorityController(this);
178         accountController = new AccountController(this);
179         accountController.getView().addItemListener(this);
180         composerSpellCheck = new ComposerSpellCheck();
181
182         signatureView = new SignatureView(this);
183
184         // set default html or text based on stored option
185
// ... can be overridden by setting the composer model
186
XmlElement optionsElement = MailConfig.getInstance().get(
187                 "composer_options").getElement("/options");
188
189         // composer can either edit in html or plain text mode
190
// listen for configuration changes
191
initHtmlConfiguration(optionsElement);
192
193         htmlEditor = new HtmlEditorController2(this);
194
195         textEditor = new TextEditorController(this);
196
197         // init controller for the editor depending on message type
198
if (getModel().isHtml())
199             currentEditorController = htmlEditor;
200         else
201             currentEditorController = textEditor;
202
203         initComponents();
204
205         // add JPanel with useful HTML related actions.
206
htmlToolbar = new HtmlToolbar(this);
207
208         layoutComponents();
209
210         showAttachmentPanel();
211
212         // Hack to ensure charset is set correctly at start-up
213
XmlElement charsetElement = optionsElement.getElement("charset");
214
215         if (charsetElement != null) {
216             String JavaDoc charset = charsetElement.getAttribute("name");
217
218             if (charset != null) {
219                 try {
220                     setCharset(Charset.forName(charset));
221                 } catch (UnsupportedCharsetException JavaDoc ex) {
222                     // ignore this
223
}
224             }
225         }
226
227         // Setup DnD for the text and attachment list control.
228
ComposerAttachmentTransferHandler dndTransferHandler = new ComposerAttachmentTransferHandler(
229                 attachmentController);
230         attachmentController.getView().setDragEnabled(true);
231         attachmentController.getView().setTransferHandler(dndTransferHandler);
232
233         JEditorPane JavaDoc editorComponent = (JEditorPane JavaDoc) getCurrentEditor()
234                 .getComponent();
235         MultipleTransferHandler compositeHandler = new MultipleTransferHandler();
236         compositeHandler.addTransferHandler(editorComponent
237                 .getTransferHandler());
238         compositeHandler.addTransferHandler(dndTransferHandler);
239         editorComponent.setDragEnabled(true);
240         editorComponent.setTransferHandler(compositeHandler);
241     }
242
243     private void initHtmlConfiguration(XmlElement optionsElement) {
244
245         XmlElement htmlElement = optionsElement.getElement("html");
246
247         // create default element if not available
248
if (htmlElement == null) {
249             htmlElement = optionsElement.addSubElement("html");
250         }
251
252         String JavaDoc enableHtml = htmlElement.getAttribute("enable", "false");
253
254         // register for configuration changes for the html(enabled/disabled)
255
// state
256
htmlElement.addObserver(this);
257
258         // set model based on configuration
259
if (enableHtml.equals("true")) {
260             getModel().setHtml(true);
261         } else {
262             getModel().setHtml(false);
263         }
264     }
265
266     /**
267      * Show attachment panel
268      * <p>
269      * Asks the ComposerModel if message contains attachments. If so, show the
270      * attachment panel. Otherwise, hide the attachment panel.
271      */

272     public void showAttachmentPanel() {
273         if (attachmentPanelShown == getAttachmentController().getView().count() > 0)
274             return;
275
276         // remove all components from container
277
centerPanel.removeAll();
278
279         // re-add all top components like recipient editor/subject editor
280
centerPanel.add(topPanel, BorderLayout.NORTH);
281
282         // if message contains attachments
283
if (getAttachmentController().getView().count() > 0) {
284             // create scrollapen
285
JScrollPane JavaDoc attachmentScrollPane = new JScrollPane JavaDoc(
286                     getAttachmentController().getView());
287             attachmentScrollPane
288                     .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
289             attachmentScrollPane.setBorder(BorderFactory.createEmptyBorder(1,
290                     1, 1, 1));
291             // create splitpane containing the bodytext editor and the
292
// attachment panel
293
attachmentSplitPane = new JSplitPane JavaDoc(JSplitPane.VERTICAL_SPLIT,
294                     editorScrollPane, attachmentScrollPane);
295             attachmentSplitPane.setDividerLocation(0.80);
296             attachmentSplitPane.setBorder(null);
297
298             // add splitpane to the center
299
centerPanel.add(attachmentSplitPane, BorderLayout.CENTER);
300
301             // ViewItem viewItem = getViewItem();
302

303             // default value is 200 pixel
304
// int pos =
305
// viewItem.getIntegerWithDefault("splitpanes","attachment", 200);
306
attachmentSplitPane.setDividerLocation(200);
307
308             attachmentPanelShown = true;
309         } else {
310             // no attachments
311
// -> only show bodytext editor
312
centerPanel.add(editorPanel, BorderLayout.CENTER);
313
314             attachmentPanelShown = false;
315         }
316
317         // re-paint composer-view
318
SwingUtilities.invokeLater(new Runnable JavaDoc() {
319             public void run() {
320                 fireLayoutChanged();
321             }
322         });
323
324     }
325
326     /**
327      * @return Returns the attachmentSplitPane.
328      */

329     public JSplitPane JavaDoc getAttachmentSplitPane() {
330         return attachmentSplitPane;
331     }
332
333     /**
334      * init components
335      */

336     protected void initComponents() {
337         subjectLabel = new LabelWithMnemonic(MailResourceLoader.getString(
338                 "dialog", "composer", "subject"));
339         smtpLabel = new LabelWithMnemonic(MailResourceLoader.getString(
340                 "dialog", "composer", "identity"));
341         priorityLabel = new LabelWithMnemonic(MailResourceLoader.getString(
342                 "dialog", "composer", "priority"));
343
344         editorScrollPane = new TextEditorPanel();
345     }
346
347     /**
348      * Layout components
349      */

350     public void layoutComponents() {
351         centerPanel.removeAll();
352
353         editorPanel.setLayout(new BorderLayout JavaDoc());
354
355         toolbarPanel.setLayout(new BorderLayout JavaDoc());
356         toolbarPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 4, 0));
357         toolbarPanel.add(htmlToolbar);
358         toolbarPanel.setBackground(UIManager.getColor("TextArea.background"));
359
360         topPanel = new JPanel JavaDoc();
361         topPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
362
363         FormLayout layout = new FormLayout(new ColumnSpec[] {
364                 new ColumnSpec("center:max(pref;50dlu)"),
365                 FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
366                 FormFactory.GROWING_BUTTON_COLSPEC,
367                 FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
368                 FormFactory.DEFAULT_COLSPEC,
369                 FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
370                 FormFactory.GROWING_BUTTON_COLSPEC }, new RowSpec[] {
371                 new RowSpec(RowSpec.FILL, Sizes.DEFAULT, FormSpec.NO_GROW),
372                 FormFactory.LINE_GAP_ROWSPEC,
373                 new RowSpec(RowSpec.FILL, Sizes.DEFAULT, FormSpec.NO_GROW),
374                 FormFactory.LINE_GAP_ROWSPEC,
375                 new RowSpec(RowSpec.FILL, Sizes.DEFAULT, FormSpec.NO_GROW),
376                 FormFactory.LINE_GAP_ROWSPEC,
377                 new RowSpec(RowSpec.FILL, Sizes.DEFAULT, FormSpec.NO_GROW),
378                 FormFactory.LINE_GAP_ROWSPEC,
379                 new RowSpec(RowSpec.FILL, Sizes.DEFAULT, FormSpec.NO_GROW) });
380         layout.setRowGroups(new int[][] { { 1, 3, 5, 7, 9 } });
381         layout.setColumnGroups(new int[][] { { 1 } });
382
383         topPanel.setLayout(layout);
384
385         CellConstraints c = new CellConstraints();
386
387         topPanel.add(smtpLabel, c.xy(1, 1, CellConstraints.CENTER,
388                 CellConstraints.DEFAULT));
389
390         topPanel.add(getAccountController().getView(), c.xy(3, 1));
391         topPanel.add(priorityLabel, c.xy(5, 1));
392         topPanel.add(getPriorityController().getView(), c.xy(7, 1));
393
394         getHeaderController().getView().layoutComponents(topPanel);
395
396         topPanel.add(subjectLabel, c.xy(1, 9, CellConstraints.CENTER,
397                 CellConstraints.DEFAULT));
398
399         topPanel.add(getSubjectController().getView(), c.xywh(3, 9, 5, 1));
400
401         if (composerModel.isHtml())
402             editorPanel.add(toolbarPanel, BorderLayout.NORTH);
403
404         editorScrollPane.getContentPane().add(
405                 getCurrentEditor().getViewUIComponent(), BorderLayout.CENTER);
406
407         editorPanel.add(editorScrollPane, BorderLayout.CENTER);
408
409         Border JavaDoc outterBorder = BorderFactory.createCompoundBorder(BorderFactory
410                 .createEmptyBorder(5, 5, 5, 5), new MessageBorder(
411                 Color.LIGHT_GRAY, 1, true));
412         Border JavaDoc innerBorder = BorderFactory.createCompoundBorder(outterBorder,
413                 new LineBorder JavaDoc(Color.WHITE, 5, true));
414         editorPanel.setBorder(innerBorder);
415
416         AccountItem item = (AccountItem) getAccountController().getView()
417                 .getSelectedItem();
418         if (item.getIdentity().getSignature() != null)
419             editorScrollPane.getContentPane().add(signatureView,
420                     BorderLayout.SOUTH);
421
422         editorScrollPane.addMouseListener(new MouseListener JavaDoc() {
423
424             public void mouseClicked(MouseEvent JavaDoc e) {
425                 currentEditorController.getComponent().requestFocus();
426             }
427
428             public void mouseEntered(MouseEvent JavaDoc e) {
429             }
430
431             public void mouseExited(MouseEvent JavaDoc e) {
432             }
433
434             public void mousePressed(MouseEvent JavaDoc e) {
435             }
436
437             public void mouseReleased(MouseEvent JavaDoc e) {
438             }
439
440         });
441
442         centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
443         centerPanel.setLayout(new BorderLayout JavaDoc());
444
445         centerPanel.add(topPanel, BorderLayout.NORTH);
446
447         // no attachments
448
// -> only show bodytext editor
449
centerPanel.add(editorPanel, BorderLayout.CENTER);
450
451         attachmentPanelShown = false;
452     }
453
454     /**
455      * Returns a reference to the panel, that holds the editor view. This is
456      * used by the ComposerController when adding a listener to that panel.
457      *
458      * @return editor panel reference
459      */

460     public JPanel JavaDoc getEditorPanel() {
461         return editorScrollPane.getContentPane();
462     }
463
464     /**
465      * Used to update the panel, that holds the editor viewer. This is necessary
466      * e.g. if the ComposerModel is changed to hold another message type (text /
467      * html), which the previous editor can not handle. If so a new editor
468      * controller is created, and thereby a new view.
469      */

470     public void layoutEditorContainer() {
471
472         // update panel
473
editorScrollPane.getContentPane().removeAll();
474         editorScrollPane.getContentPane().add(
475                 getCurrentEditor().getViewUIComponent(), BorderLayout.CENTER);
476
477         AccountItem item = (AccountItem) getAccountController().getView()
478                 .getSelectedItem();
479         if (item.getIdentity().getSignature() != null)
480             editorScrollPane.getContentPane().add(signatureView,
481                     BorderLayout.SOUTH);
482
483         editorScrollPane.getContentPane().validate();
484     }
485
486     public boolean isAccountInfoPanelVisible() {
487         // TODO (@author fdietz): fix account info panel check
488

489         /*
490          * return isToolbarEnabled(ACCOUNTINFOPANEL);
491          */

492
493         return true;
494     }
495
496     /**
497      * Check if data was entered correctly.
498      * <p>
499      * This includes currently a test for an empty subject and a valid recipient
500      * (to/cc/bcc) list.
501      *
502      * @return true, if data was entered correctly
503      */

504     public boolean checkState() {
505         // update ComposerModel based on user-changes in ComposerView
506
updateComponents(false);
507
508         if (!subjectController.checkState()) {
509             return false;
510         }
511
512         return !headerController.checkState();
513     }
514
515     public void updateComponents(boolean b) {
516         subjectController.updateComponents(b);
517         currentEditorController.updateComponents(b);
518         priorityController.updateComponents(b);
519         accountController.updateComponents(b);
520         attachmentController.updateComponents(b);
521         headerController.updateComponents(b);
522
523         // show attachment panel if necessary
524
if (b)
525             showAttachmentPanel();
526     }
527
528     /**
529      * @return AccountController
530      */

531     public AccountController getAccountController() {
532         return accountController;
533     }
534
535     /**
536      * @return AttachmentController
537      */

538     public AttachmentController getAttachmentController() {
539         return attachmentController;
540     }
541
542     /**
543      * @return ComposerSpellCheck
544      */

545     public ComposerSpellCheck getComposerSpellCheck() {
546         return composerSpellCheck;
547     }
548
549     /**
550      * @return TextEditorController
551      */

552     public AbstractEditorController getCurrentEditor() {
553         /*
554          * *20030906, karlpeder* Method signature changed to return an
555          * AbstractEditorController
556          */

557         return currentEditorController;
558     }
559
560     public TextEditorController getTextEditorController() {
561         return textEditor;
562     }
563
564     public HtmlEditorController2 getHtmlEditorController() {
565         return htmlEditor;
566     }
567
568     /**
569      * @return HeaderViewer
570      */

571     public HeaderController getHeaderController() {
572         return headerController;
573     }
574
575     /**
576      * @return PriorityController
577      */

578     public PriorityController getPriorityController() {
579         return priorityController;
580     }
581
582     /**
583      * @return SubjectController
584      */

585     public SubjectController getSubjectController() {
586         return subjectController;
587     }
588
589     /**
590      * @see org.columba.core.gui.FrameController#reset()
591      */

592     protected void init() {
593
594     }
595
596     /**
597      * Returns the composer model
598      *
599      * @return Composer model
600      */

601     public ComposerModel getModel() {
602         // if (composerModel == null) // *20030907, karlpeder* initialized in
603
// init
604
// composerModel = new ComposerModel();
605
return composerModel;
606     }
607
608     /**
609      * Sets the composer model. If the message type of the new model (html /
610      * text) is different from the message type of the existing, the editor
611      * controller is changed and the view is changed accordingly. <br>
612      * Finally the components are updated according to the new model.
613      *
614      * @param model
615      * New composer model
616      */

617     public void setComposerModel(ComposerModel model) {
618         boolean wasHtml = composerModel.isHtml();
619         composerModel = model;
620
621 // if (wasHtml != composerModel.isHtml()) {
622
// setHtmlState(composerModel.isHtml());
623
// }
624

625         // Update all component according to the new model
626
updateComponents(true);
627
628
629
630     }
631
632     public Charset JavaDoc getCharset() {
633         return charset;
634     }
635
636     public void setCharset(Charset JavaDoc charset) {
637         this.charset = charset;
638
639         ((ComposerModel) getModel()).setCharset(charset);
640         fireCharsetChanged(new CharsetEvent(this, charset));
641     }
642
643     public void addCharsetListener(CharsetListener l) {
644         listenerList.add(CharsetListener.class, l);
645     }
646
647     public void removeCharsetListener(CharsetListener l) {
648         listenerList.remove(CharsetListener.class, l);
649     }
650
651     protected void fireCharsetChanged(CharsetEvent e) {
652         // Guaranteed to return a non-null array
653
Object JavaDoc[] listeners = listenerList.getListenerList();
654
655         // Process the listeners last to first, notifying
656
// those that are interested in this event
657
for (int i = listeners.length - 2; i >= 0; i -= 2) {
658             if (listeners[i] == CharsetListener.class) {
659                 ((CharsetListener) listeners[i + 1]).charsetChanged(e);
660             }
661         }
662     }
663
664     public void setHtmlState(boolean enableHtml) {
665
666         composerModel.setHtml(enableHtml);
667
668         // sync model with the current (old) view
669
updateComponents(false);
670
671         // convert body text to comply with new editor format
672
String JavaDoc oldBody = composerModel.getBodyText();
673         String JavaDoc newBody = null;
674
675         if (enableHtml) {
676             LOG.fine("Converting body text to html");
677             Charset JavaDoc charset = getCharset();
678             if (charset == null)
679                 charset = Charset.defaultCharset();
680             newBody = HtmlParser.textToHtml(oldBody, "", null, charset
681                     .toString());
682         } else {
683             LOG.fine("Converting body text to text");
684             newBody = HtmlParser.htmlToText(oldBody);
685         }
686
687         composerModel.setBodyText(newBody);
688
689         // switch editor and resync view with model
690
if (enableHtml)
691             currentEditorController = htmlEditor;
692         else
693             currentEditorController = textEditor;
694
695         // sync view with new update to date model
696
updateComponents(true);
697
698         // change ui container
699
layoutEditorContainer();
700
701         // enable/disable html toolbar
702
if (enableHtml) {
703             editorPanel.add(toolbarPanel, BorderLayout.NORTH);
704         } else {
705             editorPanel.remove(toolbarPanel);
706         }
707
708         editorPanel.validate();
709     }
710
711     /**
712      * @param container
713      * @see org.columba.core.gui.frame.DefaultFrameController#close(org.columba.api.gui.frame.IContainer)
714      */

715     public void close(IContainer container) {
716
717         // don't prompt user if composer should be closed
718
if (isPromptOnDialogClosing() == false)
719             return;
720
721         // only prompt user, if composer contains some text
722
if (currentEditorController.getViewText().length() == 0) {
723             fireVisibilityChanged(false);
724
725             // close Columba, if composer is only visible frame
726
FrameManager.getInstance().close(null);
727
728             return;
729         }
730
731         Object JavaDoc[] options = { "Close", "Cancel", "Save" };
732         int n = JOptionPane.showOptionDialog(container.getFrame(),
733                 "Message wasn't sent. Would you like to save your changes?",
734                 "Warning: Message was modified",
735                 JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
736                 null, options, options[2]); // default button title
737

738         if (n == 2) {
739             saveConfiguration();
740
741             // save changes
742
new SaveAsDraftAction(ComposerController.this)
743                     .actionPerformed(null);
744
745             // close composer
746
fireVisibilityChanged(false);
747
748             // close Columba, if composer is only visible frame
749
FrameManager.getInstance().close(null);
750         } else if (n == 1) {
751             // cancel question dialog and don't close composer
752
} else {
753             saveConfiguration();
754
755             // close composer
756
fireVisibilityChanged(false);
757
758             // close Columba, if composer is only visible frame
759
FrameManager.getInstance().close(null);
760         }
761
762     }
763
764     private void saveConfiguration() {
765
766         // save charset
767
XmlElement optionsElement = MailConfig.getInstance().get(
768                 "composer_options").getElement("/options");
769         XmlElement charsetElement = optionsElement.getElement("charset");
770
771         if (getCharset() == null) {
772             optionsElement.removeElement(charsetElement);
773         } else {
774             if (charsetElement == null) {
775                 charsetElement = new XmlElement("charset");
776                 optionsElement.addElement(charsetElement);
777             }
778
779             charsetElement.addAttribute("name", getCharset().name());
780         }
781
782         // save html state
783
XmlElement htmlElement = optionsElement.getElement("html");
784         htmlElement.addAttribute("enable", Boolean
785                 .toString(getModel().isHtml()));
786     }
787
788     public class ComposerFocusTraversalPolicy extends FocusTraversalPolicy JavaDoc {
789
790         public Component JavaDoc getComponentAfter(Container JavaDoc focusCycleRoot,
791                 Component JavaDoc aComponent) {
792             if (aComponent.equals(accountController.getView()))
793                 return priorityController.getView();
794             else if (aComponent.equals(priorityController.getView()))
795                 return headerController.getView().getToComboBox();
796             else if (aComponent.equals(headerController.getView()
797                     .getToComboBox()))
798                 return headerController.getView().getCcComboBox();
799             else if (aComponent.equals(headerController.getView()
800                     .getCcComboBox()))
801                 return headerController.getView().getBccComboBox();
802             else if (aComponent.equals(headerController.getView()
803                     .getBccComboBox()))
804                 return subjectController.getView();
805             else if (aComponent.equals(subjectController.getView()))
806                 return currentEditorController.getComponent();
807
808             return headerController.getView().getToComboBox();
809         }
810
811         public Component JavaDoc getComponentBefore(Container JavaDoc focusCycleRoot,
812                 Component JavaDoc aComponent) {
813             if (aComponent.equals(currentEditorController.getComponent()))
814                 return subjectController.getView();
815             else if (aComponent.equals(subjectController.getView()))
816                 return headerController.getView().getBccComboBox();
817             else if (aComponent.equals(headerController.getView()
818                     .getBccComboBox()))
819                 return headerController.getView().getCcComboBox();
820             else if (aComponent.equals(headerController.getView()
821                     .getCcComboBox()))
822                 return headerController.getView().getToComboBox();
823             else if (aComponent.equals(headerController.getView()
824                     .getToComboBox()))
825                 return priorityController.getView();
826             else if (aComponent.equals(priorityController.getView()))
827                 return accountController.getView();
828
829             return currentEditorController.getComponent();
830         }
831
832         public Component JavaDoc getDefaultComponent(Container JavaDoc focusCycleRoot) {
833             return headerController.getView().getToComboBox();
834         }
835
836         public Component JavaDoc getLastComponent(Container JavaDoc focusCycleRoot) {
837             return currentEditorController.getComponent();
838         }
839
840         public Component JavaDoc getFirstComponent(Container JavaDoc focusCycleRoot) {
841             return accountController.getView();
842         }
843     }
844
845     /**
846      * @return panel
847      * @see org.columba.api.gui.frame.IContentPane#getComponent()
848      */

849     public JComponent JavaDoc getComponent() {
850         JPanel JavaDoc panel = new JPanel JavaDoc();
851         panel.setLayout(new BorderLayout JavaDoc());
852
853         panel.add(centerPanel, BorderLayout.CENTER);
854
855         return panel;
856     }
857
858     /**
859      * @see org.columba.api.gui.frame.IFrameMediator#getString(java.lang.String,
860      * java.lang.String, java.lang.String)
861      */

862     public String JavaDoc getString(String JavaDoc sPath, String JavaDoc sName, String JavaDoc sID) {
863         return MailResourceLoader.getString(sPath, sName, sID);
864     }
865
866     class MyDocumentListener implements DocumentListener JavaDoc {
867
868         public void changedUpdate(DocumentEvent JavaDoc arg0) {
869             handleEvent(arg0);
870         }
871
872         public void insertUpdate(DocumentEvent JavaDoc arg0) {
873             handleEvent(arg0);
874         }
875
876         public void removeUpdate(DocumentEvent JavaDoc arg0) {
877             handleEvent(arg0);
878         }
879
880         private void handleEvent(DocumentEvent JavaDoc arg0) {
881             Document JavaDoc doc = arg0.getDocument();
882             try {
883                 String JavaDoc subject = doc.getText(0, doc.getLength());
884
885                 fireTitleChanged(subject);
886             } catch (BadLocationException JavaDoc e) {
887             }
888         }
889
890     }
891
892     /**
893      * @return Returns the promptOnDialogClosing.
894      */

895     public boolean isPromptOnDialogClosing() {
896         return promptOnDialogClosing;
897     }
898
899     /**
900      * @param promptOnDialogClosing
901      * The promptOnDialogClosing to set.
902      */

903     public void setPromptOnDialogClosing(boolean promptOnDialogClosing) {
904         this.promptOnDialogClosing = promptOnDialogClosing;
905     }
906
907     public void itemStateChanged(ItemEvent JavaDoc e) {
908         if (e.getStateChange() == ItemEvent.SELECTED) {
909
910             AccountItem item = (AccountItem) getAccountController().getView()
911                     .getSelectedItem();
912             if (item.getIdentity().getSignature() != null) {
913                 // show signature viewer
914
editorScrollPane.getContentPane().add(signatureView,
915                         BorderLayout.SOUTH);
916                 editorScrollPane.revalidate();
917             } else {
918                 // hide signature viewer
919
editorScrollPane.getContentPane().remove(signatureView);
920                 editorScrollPane.revalidate();
921             }
922         }
923
924     }
925
926     public JPanel JavaDoc getContentPane() {
927         return (JPanel JavaDoc) getComponent();
928     }
929
930     /**
931      * container callbacks
932      *
933      * @param container
934      */

935
936     public void extendMenu(IContainer container) {
937         try {
938             InputStream JavaDoc is = DiskIO
939                     .getResourceStream("org/columba/mail/action/composer_menu.xml");
940             container.extendMenu(this, is);
941
942         } catch (IOException JavaDoc e) {
943             LOG.severe(e.getMessage());
944         }
945     }
946
947     public void extendToolBar(IContainer container) {
948         try {
949             File JavaDoc configDirectory = MailConfig.getInstance()
950                     .getConfigDirectory();
951             InputStream JavaDoc is2 = new FileInputStream JavaDoc(new File JavaDoc(configDirectory,
952                     "composer_toolbar.xml"));
953             container.extendToolbar(this, is2);
954         } catch (IOException JavaDoc e) {
955             e.printStackTrace();
956         }
957     }
958
959     public void initFrame(IContainer container) {
960         container.getFrame().setFocusTraversalPolicy(
961                 new ComposerFocusTraversalPolicy());
962
963         // make sure that JFrame is not closed automatically
964
// -> we want to prompt the user to save his work
965
container.setCloseOperation(false);
966     }
967
968     /**
969      * Method is called when composer configuration changed
970      *
971      * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
972      */

973     public void update(Observable JavaDoc observable, Object JavaDoc obj) {
974 // if (observable instanceof XmlElement) {
975
// // possibly change btw. html and text
976
// XmlElement e = (XmlElement) obj;
977
//
978
// if (e.getName().equals("html")) {
979
// String enableHtml = e.getAttribute("enable", "false");
980
//
981
// // This action should only be enabled in html mode
982
// getModel().setHtml(Boolean.valueOf(enableHtml).booleanValue());
983
// }
984
// }
985
}
986 }
Popular Tags