/** * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.bonitasoft.forms.client.view.widget; import org.bonitasoft.forms.client.i18n.RichTextLabels; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.PushButton; import com.google.gwt.user.client.ui.RichTextArea; import com.google.gwt.user.client.ui.ToggleButton; import com.google.gwt.user.client.ui.Widget; /** * A toolbar for use with {@link RichTextArea}. It provides a simple UI for all * rich text formatting, dynamically displayed only for the available * functionality. */ public class RichTextToolbar extends Composite { /** * This {@link ClientBundle} is used for all the button icons. Using a * bundle allows all of these images to be packed into a single image, which * saves a lot of HTTP requests, drastically improving startup time. */ public interface Images extends ClientBundle { ImageResource bold(); ImageResource createLink(); ImageResource hr(); ImageResource indent(); ImageResource insertImage(); ImageResource italic(); ImageResource justifyCenter(); ImageResource justifyLeft(); ImageResource justifyRight(); ImageResource ol(); ImageResource outdent(); ImageResource removeFormat(); ImageResource removeLink(); ImageResource strikeThrough(); ImageResource subscript(); ImageResource superscript(); ImageResource ul(); ImageResource underline(); } /** * We use an inner EventHandler class to avoid exposing event methods on the * RichTextToolbar itself. */ private class EventHandler implements ClickHandler, ChangeHandler, KeyUpHandler { public void onChange(final ChangeEvent event) { final Widget sender = (Widget) event.getSource(); if (sender == backColors) { formatter.setBackColor(backColors.getValue(backColors.getSelectedIndex())); backColors.setSelectedIndex(0); } else if (sender == foreColors) { formatter.setForeColor(foreColors.getValue(foreColors.getSelectedIndex())); foreColors.setSelectedIndex(0); } else if (sender == fonts) { formatter.setFontName(fonts.getValue(fonts.getSelectedIndex())); fonts.setSelectedIndex(0); } else if (sender == fontSizes) { formatter.setFontSize(fontSizesConstants[fontSizes.getSelectedIndex() - 1]); fontSizes.setSelectedIndex(0); } } public void onClick(final ClickEvent event) { final Widget sender = (Widget) event.getSource(); if (sender == bold) { formatter.toggleBold(); } else if (sender == italic) { formatter.toggleItalic(); } else if (sender == underline) { formatter.toggleUnderline(); } else if (sender == subscript) { formatter.toggleSubscript(); } else if (sender == superscript) { formatter.toggleSuperscript(); } else if (sender == strikethrough) { formatter.toggleStrikethrough(); } else if (sender == indent) { formatter.rightIndent(); } else if (sender == outdent) { formatter.leftIndent(); } else if (sender == justifyLeft) { formatter.setJustification(RichTextArea.Justification.LEFT); } else if (sender == justifyCenter) { formatter.setJustification(RichTextArea.Justification.CENTER); } else if (sender == justifyRight) { formatter.setJustification(RichTextArea.Justification.RIGHT); } else if (sender == insertImage) { final String url = Window.prompt("Enter an image URL:", "http://"); if (url != null) { formatter.insertImage(url); } } else if (sender == createLink) { final String url = Window.prompt("Enter a link URL:", "http://"); if (url != null) { formatter.createLink(url); } } else if (sender == removeLink) { formatter.removeLink(); } else if (sender == hr) { formatter.insertHorizontalRule(); } else if (sender == ol) { formatter.insertOrderedList(); } else if (sender == ul) { formatter.insertUnorderedList(); } else if (sender == removeFormat) { formatter.removeFormat(); } else if (sender == richText) { // We use the RichTextArea's onKeyUp event to update the toolbar // status. // This will catch any cases where the user moves the cursur // using the // keyboard, or uses one of the browser's built-in keyboard // shortcuts. updateStatus(); } } public void onKeyUp(final KeyUpEvent event) { final Widget sender = (Widget) event.getSource(); if (sender == richText) { // We use the RichTextArea's onKeyUp event to update the toolbar // status. // This will catch any cases where the user moves the cursur // using the // keyboard, or uses one of the browser's built-in keyboard // shortcuts. updateStatus(); } } } private static final RichTextArea.FontSize[] fontSizesConstants = new RichTextArea.FontSize[] { RichTextArea.FontSize.XX_SMALL, RichTextArea.FontSize.X_SMALL, RichTextArea.FontSize.SMALL, RichTextArea.FontSize.MEDIUM, RichTextArea.FontSize.LARGE, RichTextArea.FontSize.X_LARGE, RichTextArea.FontSize.XX_LARGE }; private final Images images = (Images) GWT.create(Images.class); private final RichTextLabels richTextLabels = (RichTextLabels) GWT.create(RichTextLabels.class); private final EventHandler handler = new EventHandler(); private final RichTextArea richText; private final RichTextArea.Formatter formatter; private final FlowPanel flowPanel = new FlowPanel(); private ToggleButton bold; private ToggleButton italic; private ToggleButton underline; private ToggleButton subscript; private ToggleButton superscript; private ToggleButton strikethrough; private PushButton indent; private PushButton outdent; private PushButton justifyLeft; private PushButton justifyCenter; private PushButton justifyRight; private PushButton hr; private PushButton ol; private PushButton ul; private PushButton insertImage; private PushButton createLink; private PushButton removeLink; private PushButton removeFormat; private ListBox backColors; private ListBox foreColors; private ListBox fonts; private ListBox fontSizes; /** * Creates a new toolbar that drives the given rich text area. * * @param richText * the rich text area to be controlled */ public RichTextToolbar(final RichTextArea richText) { this.richText = richText; this.formatter = richText.getFormatter(); initWidget(flowPanel); setStyleName("gwt-RichTextToolbar"); if (formatter != null) { flowPanel.add(bold = createToggleButton(images.bold(), richTextLabels.bold())); flowPanel.add(italic = createToggleButton(images.italic(), richTextLabels.italic())); flowPanel.add(underline = createToggleButton(images.underline(), richTextLabels.underline())); flowPanel.add(subscript = createToggleButton(images.subscript(), richTextLabels.subscript())); flowPanel.add(superscript = createToggleButton(images.superscript(), richTextLabels.superscript())); flowPanel.add(justifyLeft = createPushButton(images.justifyLeft(), richTextLabels.justifyLeft())); flowPanel.add(justifyCenter = createPushButton(images.justifyCenter(), richTextLabels.justifyCenter())); flowPanel.add(justifyRight = createPushButton(images.justifyRight(), richTextLabels.justifyRight())); flowPanel.add(strikethrough = createToggleButton(images.strikeThrough(), richTextLabels.strikeThrough())); flowPanel.add(indent = createPushButton(images.indent(), richTextLabels.indent())); flowPanel.add(outdent = createPushButton(images.outdent(), richTextLabels.outdent())); flowPanel.add(hr = createPushButton(images.hr(), richTextLabels.hr())); flowPanel.add(ol = createPushButton(images.ol(), richTextLabels.ol())); flowPanel.add(ul = createPushButton(images.ul(), richTextLabels.ul())); flowPanel.add(insertImage = createPushButton(images.insertImage(), richTextLabels.insertImage())); flowPanel.add(createLink = createPushButton(images.createLink(), richTextLabels.createLink())); flowPanel.add(removeLink = createPushButton(images.removeLink(), richTextLabels.removeLink())); flowPanel.add(removeFormat = createPushButton(images.removeFormat(), richTextLabels.removeFormat())); flowPanel.add(backColors = createColorList("Background")); flowPanel.add(foreColors = createColorList("Foreground")); flowPanel.add(fonts = createFontList()); flowPanel.add(fontSizes = createFontSizes()); final FlowPanel toolbarBottom = new FlowPanel(); toolbarBottom.setStyleName("bonita_clear_float"); flowPanel.add(toolbarBottom); // We only use these handlers for updating status, so don't hook // them up unless at least basic editing is supported. richText.addKeyUpHandler(handler); richText.addClickHandler(handler); } } private ListBox createColorList(final String caption) { final ListBox lb = new ListBox(); lb.addStyleName("bonita_toolbarElement"); lb.addStyleName("bonita_toolbarList"); lb.addChangeHandler(handler); lb.setVisibleItemCount(1); lb.addItem(caption); lb.addItem(richTextLabels.white(), "white"); lb.addItem(richTextLabels.black(), "black"); lb.addItem(richTextLabels.red(), "red"); lb.addItem(richTextLabels.green(), "green"); lb.addItem(richTextLabels.yellow(), "yellow"); lb.addItem(richTextLabels.blue(), "blue"); return lb; } private ListBox createFontList() { final ListBox lb = new ListBox(); lb.addStyleName("bonita_toolbarElement"); lb.addStyleName("bonita_toolbarList"); lb.addChangeHandler(handler); lb.setVisibleItemCount(1); lb.addItem(richTextLabels.font(), ""); lb.addItem(richTextLabels.normal(), ""); lb.addItem("Times New Roman", "Times New Roman"); lb.addItem("Arial", "Arial"); lb.addItem("Courier New", "Courier New"); lb.addItem("Georgia", "Georgia"); lb.addItem("Trebuchet", "Trebuchet"); lb.addItem("Verdana", "Verdana"); return lb; } private ListBox createFontSizes() { final ListBox lb = new ListBox(); lb.addStyleName("bonita_toolbarElement"); lb.addStyleName("bonita_toolbarList"); lb.addChangeHandler(handler); lb.setVisibleItemCount(1); lb.addItem(richTextLabels.size()); lb.addItem(richTextLabels.xxsmall()); lb.addItem(richTextLabels.xsmall()); lb.addItem(richTextLabels.small()); lb.addItem(richTextLabels.medium()); lb.addItem(richTextLabels.large()); lb.addItem(richTextLabels.xlarge()); lb.addItem(richTextLabels.xxlarge()); return lb; } private PushButton createPushButton(final ImageResource img, final String tip) { final PushButton pb = new PushButton(new Image(img)); pb.addStyleName("bonita_toolbarElement"); pb.addClickHandler(handler); pb.setTitle(tip); return pb; } private ToggleButton createToggleButton(final ImageResource img, final String tip) { final ToggleButton tb = new ToggleButton(new Image(img)); tb.addStyleName("bonita_toolbarElement"); tb.addClickHandler(handler); tb.setTitle(tip); return tb; } /** * Updates the status of all the stateful buttons. */ private void updateStatus() { if (formatter != null) { bold.setDown(formatter.isBold()); italic.setDown(formatter.isItalic()); underline.setDown(formatter.isUnderlined()); subscript.setDown(formatter.isSubscript()); superscript.setDown(formatter.isSuperscript()); } if (formatter != null) { strikethrough.setDown(formatter.isStrikethrough()); } } }