001: //The contents of this file are subject to the Mozilla Public License Version 1.1
002: //(the "License"); you may not use this file except in compliance with the
003: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
004: //
005: //Software distributed under the License is distributed on an "AS IS" basis,
006: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
007: //for the specific language governing rights and
008: //limitations under the License.
009: //
010: //The Original Code is "The Columba Project"
011: //
012: //The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
013: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
014: //
015: //All Rights Reserved.
016:
017: package org.columba.mail.gui.composer.html;
018:
019: import java.awt.Component;
020: import java.awt.event.ActionEvent;
021: import java.awt.event.ActionListener;
022: import java.util.logging.Logger;
023:
024: import javax.swing.BorderFactory;
025: import javax.swing.Box;
026: import javax.swing.DefaultListCellRenderer;
027: import javax.swing.JComboBox;
028: import javax.swing.JList;
029: import javax.swing.JToolBar;
030: import javax.swing.UIManager;
031: import javax.swing.text.html.HTML;
032:
033: import org.columba.api.gui.frame.IFrameMediator;
034: import org.columba.api.plugin.IExtension;
035: import org.columba.api.plugin.IExtensionHandler;
036: import org.columba.api.plugin.IExtensionHandlerKeys;
037: import org.columba.api.plugin.PluginException;
038: import org.columba.api.plugin.PluginHandlerNotFoundException;
039: import org.columba.core.gui.action.AbstractColumbaAction;
040: import org.columba.core.gui.action.AbstractSelectableAction;
041: import org.columba.core.gui.base.LabelWithMnemonic;
042: import org.columba.core.gui.base.RoundedBorder;
043: import org.columba.core.gui.toolbar.ToggleToolbarButton;
044: import org.columba.core.logging.Logging;
045: import org.columba.core.plugin.PluginManager;
046: import org.columba.mail.gui.composer.ComposerController;
047: import org.columba.mail.gui.composer.ComposerModelChangedEvent;
048: import org.columba.mail.gui.composer.IComposerModelChangedListener;
049: import org.columba.mail.gui.composer.html.action.FontSizeMenu;
050: import org.columba.mail.gui.composer.html.action.ParagraphMenu;
051: import org.columba.mail.util.MailResourceLoader;
052: import org.frapuccino.htmleditor.api.IFormatChangedListener;
053: import org.frapuccino.htmleditor.event.FormatChangedEvent;
054: import org.frapuccino.htmleditor.event.FormatInfo;
055:
056: /**
057: * JPanel with useful HTML related actions.
058: *
059: * @author fdietz
060: */
061: public class HtmlToolbar extends JToolBar implements ActionListener,
062: IFormatChangedListener, IComposerModelChangedListener {
063:
064: /** JDK 1.4+ logging framework logger, used for logging. */
065: private static final Logger LOG = Logger
066: .getLogger("org.columba.mail.gui.composer.html");
067:
068: private ComposerController controller;
069:
070: private JComboBox paragraphComboBox;
071:
072: private JComboBox sizeComboBox;
073:
074: /**
075: * Flag indicating whether we are programatically changing the paragraph
076: * combobox, and therefore shall do nothing in actionPerformed.
077: */
078: private boolean ignoreFormatAction = false;
079:
080: private IExtensionHandler handler = null;
081:
082: /**
083: *
084: */
085: public HtmlToolbar(ComposerController controller) {
086: super ();
087: this .controller = controller;
088:
089: setBorder(BorderFactory.createCompoundBorder(new RoundedBorder(
090: UIManager.getColor("controlShadow")), BorderFactory
091: .createEmptyBorder(4, 4, 4, 4)));
092:
093: setRollover(true);
094:
095: setFloatable(false);
096:
097: try {
098: handler = PluginManager.getInstance().getExtensionHandler(
099: IExtensionHandlerKeys.ORG_COLUMBA_CORE_ACTION);
100: } catch (PluginHandlerNotFoundException e) {
101: e.printStackTrace();
102: }
103:
104: try {
105: initComponents();
106: } catch (Exception e) {
107: e.printStackTrace();
108: }
109:
110: ((HtmlEditorController2) controller.getHtmlEditorController())
111: .addFormatChangedListener(this );
112:
113: // register for text selection changes
114: // controller.getEditorController().addObserver(this);
115:
116: // register for changes to the editor
117: // controller.addContainerListenerForEditor(this);
118:
119: // register for changes to editor type (text / html)
120: controller.getModel().addModelChangedListener(this );
121:
122: // XmlElement optionsElement = MailConfig.getInstance().get(
123: // "composer_options").getElement("/options");
124: // XmlElement htmlElement = optionsElement.getElement("html");
125: //
126: // if (htmlElement == null) {
127: // htmlElement = optionsElement.addSubElement("html");
128: // }
129: //
130: // htmlElement.addObserver(this);
131: }
132:
133: protected void initComponents() throws Exception {
134: // CellConstraints cc = new CellConstraints();
135:
136: // we generate most buttons using the actions already instanciated
137:
138: paragraphComboBox = new JComboBox(ParagraphMenu.STYLE_TAGS);
139: paragraphComboBox.setRenderer(new ParagraphTagRenderer());
140: paragraphComboBox.setActionCommand("PARA");
141: paragraphComboBox.addActionListener(this );
142: paragraphComboBox.setFocusable(false);
143:
144: LabelWithMnemonic sizeLabel = new LabelWithMnemonic(
145: MailResourceLoader.getString("dialog", "composer",
146: "size"));
147: sizeComboBox = new JComboBox(FontSizeMenu.SIZES);
148: sizeComboBox.setActionCommand("SIZE");
149: sizeComboBox.addActionListener(this );
150: sizeComboBox.setSelectedIndex(2);
151: sizeComboBox.setFocusable(false);
152:
153: // set initial enabled state of combo boxes
154: // XmlElement optionsElement = MailConfig.getInstance().get(
155: // "composer_options").getElement("/options");
156: // XmlElement htmlElement = optionsElement.getElement("html");
157: // String s = htmlElement.getAttribute("enable", "false");
158: // boolean enableHtml = Boolean.valueOf(s).booleanValue();
159:
160: // paragraphComboBox.setEnabled(enableHtml);
161:
162: // TODO (@author javaprog):sizeComboBox can be enabled as
163: // paragraphComboBox when implemented
164: sizeComboBox.setEnabled(false);
165:
166: ToggleToolbarButton boldFormatButton = new ToggleToolbarButton(
167: (AbstractSelectableAction) getAction(
168: "BoldFormatAction", getFrameController()));
169: ToggleToolbarButton italicFormatButton = new ToggleToolbarButton(
170: (AbstractSelectableAction) getAction(
171: "ItalicFormatAction", getFrameController()));
172: ToggleToolbarButton underlineFormatButton = new ToggleToolbarButton(
173: (AbstractSelectableAction) getAction(
174: "UnderlineFormatAction", getFrameController()));
175: ToggleToolbarButton strikeoutFormatButton = new ToggleToolbarButton(
176: (AbstractSelectableAction) getAction(
177: "StrikeoutFormatAction", getFrameController()));
178: ToggleToolbarButton leftJustifyButton = new ToggleToolbarButton(
179: (AbstractSelectableAction) getAction(
180: "LeftJustifyAction", getFrameController()));
181: ToggleToolbarButton centerJustifyButton = new ToggleToolbarButton(
182: (AbstractSelectableAction) getAction(
183: "CenterJustifyAction", getFrameController()));
184: ToggleToolbarButton rightJustifyButton = new ToggleToolbarButton(
185: (AbstractSelectableAction) getAction(
186: "RightJustifyAction", getFrameController()));
187:
188: // builder.add(paraLabel, cc.xy(1, 7));
189:
190: add(paragraphComboBox);
191: addSeparator();
192: add(sizeLabel);
193: add(sizeComboBox);
194: addSeparator();
195:
196: add(boldFormatButton);
197: add(italicFormatButton);
198: add(underlineFormatButton);
199: add(strikeoutFormatButton);
200: addSeparator();
201: add(leftJustifyButton);
202: add(centerJustifyButton);
203: add(rightJustifyButton);
204:
205: add(Box.createHorizontalGlue());
206: // FormLayout layout = new FormLayout(
207: // "default, 3dlu, default, 3dlu, default, 3dlu, "
208: // + "default, 3dlu, default, 3dlu, default, 3dlu, "
209: // + "default, 6dlu, default, 3dlu, default, 3dlu, "
210: // + "default, 3dlu", "fill:default");
211: // PanelBuilder b = new PanelBuilder(this, layout);
212: //
213: // CellConstraints c = new CellConstraints();
214: //
215: // b.add(paragraphComboBox, cc.xy(1, 1));
216: // b.add(sizeLabel, cc.xy(3, 1));
217: // b.add(sizeComboBox, cc.xy(5, 1));
218: // b.add(boldFormatButton, cc.xy(7, 1));
219: // b.add(italicFormatButton, cc.xy(9, 1));
220: // b.add(underlineFormatButton, cc.xy(11, 1));
221: // b.add(strikeoutFormatButton, cc.xy(13, 1));
222: // b.add(leftJustifyButton, cc.xy(15, 1));
223: // b.add(centerJustifyButton, cc.xy(17, 1));
224: // b.add(rightJustifyButton, cc.xy(19, 1));
225:
226: // builder.add(panel, cc.xy(1, 7));
227: }
228:
229: /**
230: * @return
231: */
232: public ComposerController getFrameController() {
233: return controller;
234: }
235:
236: /**
237: * Method is called when text selection has changed.
238: * <p>
239: * Set state of togglebutton / -menu to pressed / not pressed when
240: * selections change.
241: *
242: * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
243: */
244: // public void update(Observable arg0, Object arg1) {
245: // if (arg0 instanceof HtmlEditorController2) {
246: // // Handling of paragraph combo box
247: // // select the item in the combo box corresponding to present format
248: // FormatInfo info = (FormatInfo) arg1;
249: //
250: // if (info.isHeading1()) {
251: // selectInParagraphComboBox(HTML.Tag.H1);
252: // } else if (info.isHeading2()) {
253: // selectInParagraphComboBox(HTML.Tag.H2);
254: // } else if (info.isHeading3()) {
255: // selectInParagraphComboBox(HTML.Tag.H3);
256: // } else if (info.isPreformattet()) {
257: // selectInParagraphComboBox(HTML.Tag.PRE);
258: // } else if (info.isAddress()) {
259: // selectInParagraphComboBox(HTML.Tag.ADDRESS);
260: // } else {
261: // // select the "Normal" entry as default
262: // selectInParagraphComboBox(HTML.Tag.P);
263: // }
264: //
265: // // Font size combo box
266: // // TODO (@author fdietz): Add handling for font size combo box
267: // } else if (arg0 instanceof XmlElement) {
268: // // possibly change btw. html and text
269: // XmlElement e = (XmlElement) arg0;
270: //
271: // if (e.getName().equals("html")) {
272: // // paragraphComboBox should only be enabled in html mode
273: // paragraphComboBox.setEnabled(Boolean.valueOf(
274: // e.getAttribute("enable", "false")).booleanValue());
275: //
276: // // TODO (@author fdietz): Add handling for font size combo box
277: // }
278: // }
279: // }
280: /**
281: * Private utility to select an item in the paragraph combo box, given the
282: * corresponding html tag. If such a sub menu does not exist - nothing
283: * happens
284: */
285: private void selectInParagraphComboBox(HTML.Tag tag) {
286: // need to change selection
287: // Set ignore flag
288: ignoreFormatAction = true;
289:
290: paragraphComboBox.setSelectedItem(tag);
291:
292: // clear ignore flag
293: ignoreFormatAction = false;
294: }
295:
296: /*
297: * (non-Javadoc)
298: *
299: * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
300: */
301: public void actionPerformed(ActionEvent arg0) {
302: String action = arg0.getActionCommand();
303:
304: if (action.equals("PARA")) {
305: // selection in the paragraph combo box
306: if (!ignoreFormatAction) {
307: // only do something if ignore flag is not set
308: HtmlEditorController2 ctrl = (HtmlEditorController2) getFrameController()
309: .getCurrentEditor();
310:
311: // set paragraph formatting according to the selection
312: int selectedIndex = paragraphComboBox
313: .getSelectedIndex();
314: HTML.Tag tag = ParagraphMenu.STYLE_TAGS[selectedIndex];
315:
316: LOG.fine("Setting paragraph format to: "
317: + tag.toString());
318:
319: ctrl.setParagraphFormat(tag);
320: }
321: } else if (action.equals("SIZE")) {
322: // int selectedIndex = sizeComboBox.getSelectedIndex();
323:
324: // TODO (@author fdietz):: implement action for font size combo box!
325: }
326: }
327:
328: // /**
329: // * This event could mean that a the editor controller has changed.
330: // Therefore
331: // * this object is re-registered as observer to keep getting information
332: // * about format changes.
333: // *
334: // * @see
335: // java.awt.event.ContainerListener#componentAdded(java.awt.event.ContainerEvent)
336: // */
337: // public void componentAdded(ContainerEvent e) {
338: // LOG.info("Re-registering as observer on editor controller");
339: // controller.getEditorController().addObserver(this);
340: // }
341: //
342: // public void componentRemoved(ContainerEvent e) {
343: // }
344:
345: /**
346: * Cell renderer responsible for displaying localized strings in the combo
347: * box.
348: */
349: protected static class ParagraphTagRenderer extends
350: DefaultListCellRenderer {
351: public Component getListCellRendererComponent(JList list,
352: Object value, int index, boolean selected,
353: boolean hasFocus) {
354: return super .getListCellRendererComponent(list,
355: MailResourceLoader
356: .getString("menu", "composer",
357: "menu_format_paragraph_"
358: + value.toString()), index,
359: selected, hasFocus);
360: }
361: }
362:
363: private AbstractColumbaAction getAction(String id,
364: IFrameMediator controller) {
365: if (id == null)
366: throw new IllegalArgumentException("id == null");
367: if (controller == null)
368: throw new IllegalArgumentException("controller == null");
369:
370: IExtension extension = handler.getExtension(id);
371:
372: AbstractColumbaAction a = null;
373:
374: try {
375: if (extension != null)
376: a = (AbstractColumbaAction) extension
377: .instanciateExtension(new Object[] { controller });
378: } catch (PluginException e) {
379: LOG.severe(e.getMessage());
380: if (Logging.DEBUG)
381: e.printStackTrace();
382:
383: }
384:
385: return a;
386:
387: }
388:
389: // Handling of paragraph combo box
390: // select the item in the combo box corresponding to present format
391: public void formatChanged(FormatChangedEvent event) {
392:
393: FormatInfo info = event.getInfo();
394:
395: if (info.isHeading1()) {
396: selectInParagraphComboBox(HTML.Tag.H1);
397: } else if (info.isHeading2()) {
398: selectInParagraphComboBox(HTML.Tag.H2);
399: } else if (info.isHeading3()) {
400: selectInParagraphComboBox(HTML.Tag.H3);
401: } else if (info.isPreformattet()) {
402: selectInParagraphComboBox(HTML.Tag.PRE);
403: } else if (info.isAddress()) {
404: selectInParagraphComboBox(HTML.Tag.ADDRESS);
405: } else {
406: // select the "Normal" entry as default
407: selectInParagraphComboBox(HTML.Tag.P);
408: }
409: }
410:
411: // enable controls if we are not in html edit mode
412: public void htmlModeChanged(ComposerModelChangedEvent event) {
413: paragraphComboBox.setEnabled(event.isHtmlEnabled());
414: sizeComboBox.setEnabled(event.isHtmlEnabled());
415: }
416:
417: public void modelChanged(ComposerModelChangedEvent event) {
418: }
419: }
|