com.bcdlog.client.edition.RichTextToolbar.java Source code

Java tutorial

Introduction

Here is the source code for com.bcdlog.client.edition.RichTextToolbar.java

Source

/*
 * 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 com.bcdlog.client.edition;

import com.bcdlog.client.Client;
import com.bcdlog.client.resources.Strings;
import com.bcdlog.client.resources.images.edition.Images;
import com.bcdlog.client.ui.ClearBothDiv;
import com.bcdlog.client.ui.MessageBox;
import com.bcdlog.client.ui.PromptClickHandler;
import com.bcdlog.client.ui.Trigger;
import com.bcdlog.client.ui.TriggerPushButton;
import com.bcdlog.client.ui.WindowPanel;
import com.bcdlog.client.util.GWTUtils;
import com.bcdlog.shared.resources.FrameworkMessages;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArrayString;
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.ImageResource;
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 sample 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 FlowPanel {

    /**
     * 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(ChangeEvent event) {
            Widget sender = (Widget) event.getSource();
            if (sender == fontStyles) {
                setFontStyle(fontStyles.getValue(fontStyles.getSelectedIndex()));
                fontStyles.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(ClickEvent event) {
            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 == insertSpecialCharacter) {
                specialCharactersManager.selectCharacter(insertSpecialCharacter);
            } else if (sender == insertImage) {
                PromptClickHandler okClickHandler = new PromptClickHandler() {

                    public void onClick(ClickEvent event) {
                        formatter.insertImage(getTextBox().getValue());
                    }
                };
                MessageBox.prompt(client, strings.enterImageURL(), okClickHandler, (Trigger) sender, "http://");
            } else if (sender == createLink) {
                PromptClickHandler okClickHandler = new PromptClickHandler() {

                    public void onClick(ClickEvent event) {
                        formatter.createLink(getTextBox().getValue());
                    }
                };
                MessageBox.prompt(client, strings.enterLinkURL(), okClickHandler, (Trigger) sender,
                        getHrefFromSelection());
            } 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 == backColors) {
                showColorPicker(sender);
            } else if (sender == foreColors) {
                showColorPicker(sender);
            } else if (sender == richTextArea) {
                // 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(KeyUpEvent event) {
            Widget sender = (Widget) event.getSource();
            if (sender == richTextArea) {
                // 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 Strings strings = (Strings) GWT.create(Strings.class);
    private final EventHandler handler = new EventHandler();

    private final RichTextArea richTextArea;
    private final RichTextArea.Formatter formatter;

    private final FlowPanel outer = new FlowPanel();
    private final FlowPanel buttonsPanel = 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 insertSpecialCharacter;
    private TriggerPushButton createLink;
    private PushButton removeLink;
    private PushButton removeFormat;

    private PushButton backColors;
    private PushButton foreColors;
    private ListBox fonts;
    private ListBox fontSizes;
    private ListBox fontStyles;
    private final Client client;

    private final WindowPanel backgroundColorChooser;

    private final WindowPanel foregroundColorChooser;

    private final RichMessageArea richMessageArea;

    private final SpecialCharactersManager specialCharactersManager;

    private int scrollTop;
    private int scrollLeft;

    /**
     * Creates a new toolbar that drives the given rich text area.
     * 
     * @param richTextArea the rich text area to be controlled
     */
    public RichTextToolbar(final RichMessageArea richMessageArea, final Client client) {
        this.client = client;
        this.richMessageArea = richMessageArea;
        this.richTextArea = (RichTextArea) richMessageArea.getTextArea();
        this.formatter = richTextArea.getFormatter();

        specialCharactersManager = new SpecialCharactersManager(client, formatter);

        outer.add(buttonsPanel);
        outer.add(richTextArea);
        add(outer);

        createFullScreenButton();
        buttonsPanel.add(createHtmlEdit());
        buttonsPanel.add(bold = createToggleButton(images.bold(), strings.bold()));
        buttonsPanel.add(italic = createToggleButton(images.italic(), strings.italic()));
        buttonsPanel.add(underline = createToggleButton(images.underline(), strings.underline()));
        buttonsPanel.add(subscript = createToggleButton(images.subscript(), strings.subscript()));
        buttonsPanel.add(superscript = createToggleButton(images.superscript(), strings.superscript()));
        buttonsPanel.add(justifyLeft = createPushButton(images.justifyLeft(), strings.justifyLeft()));
        buttonsPanel.add(justifyCenter = createPushButton(images.justifyCenter(), strings.justifyCenter()));
        buttonsPanel.add(justifyRight = createPushButton(images.justifyRight(), strings.justifyRight()));
        buttonsPanel.add(strikethrough = createToggleButton(images.strikeThrough(), strings.strikeThrough()));

        buttonsPanel.add(hr = createPushButton(images.hr(), strings.hr()));
        buttonsPanel.add(ol = createPushButton(images.ol(), strings.ol()));
        buttonsPanel.add(ul = createPushButton(images.ul(), strings.ul()));

        buttonsPanel.add(outdent = createPushButton(images.outdent(), strings.outdent()));
        buttonsPanel.add(indent = createPushButton(images.indent(), strings.indent()));
        buttonsPanel.add(insertImage = createPushButton(images.insertImage(), strings.insertImage()));
        buttonsPanel.add(insertSpecialCharacter = createPushButton(images.insertSpecialCharacter(),
                client.getFrameworkMessages().insertSpecialCharacter()));
        buttonsPanel.add(createLink = createPushButton(images.createLink(), strings.createLink()));
        buttonsPanel.add(removeLink = createPushButton(images.removeLink(), strings.removeLink()));
        buttonsPanel.add(backColors = createPushButton(images.backColors(), strings.background()));
        backgroundColorChooser = new ColorChooser(client, formatter, strings.background(),
                ColorChooser.Kind.BACKGROUND);

        buttonsPanel.add(foreColors = createPushButton(images.foreColors(), strings.foreground()));
        foregroundColorChooser = new ColorChooser(client, formatter, strings.foreground(),
                ColorChooser.Kind.FOREGROUND);

        buttonsPanel.add(removeFormat = createPushButton(images.removeFormat(), strings.removeFormat()));
        buttonsPanel.add(createFullScreenButton());
        buttonsPanel.add(fontStyles = createFontStylesList());
        buttonsPanel.add(fonts = createFontList());
        buttonsPanel.add(fontSizes = createFontSizes());

        // We only use these handlers for updating status, so don't hook them up
        // unless at least basic editing is supported.
        richTextArea.addKeyUpHandler(handler);
        richTextArea.addClickHandler(handler);

        addStyleName(FrameworkMessages.FWK_PREFIX + "EditorToolbar");

        buttonsPanel.add(new ClearBothDiv());
    }

    /**
     * Add given style to selected text 
     * @param style
     */
    public void setFontStyle(String style) {
        // Remove parent header ?
        addTagAroundSelectedText(style);
    }

    /**
     * Add given tag around selected text
     * @param tag
     * @return
     */
    private void addTagAroundSelectedText(String tag) {
        formatter.insertHTML(tag + getSelectedText() + tag.replaceFirst("<", "</"));
    }

    /**
     * Get first occurence of selected text
     * @return
     */
    private String getSelectedText() {
        JsArrayString tx = GWTUtils.getSelection(richTextArea.getElement());
        return tx.get(0);
    }

    /**
     * Have url around selected text
     * <a href="http://my.url.com">selectedText</a>
     * @return
     */
    public String getHrefFromSelection() {
        return GWTUtils.getHrefFromText(richTextArea.getElement(), getSelectedText());
    }

    /**
     * Have url around selected image
     * <img src="http://my.url.com" ...
     * @return
     */
    public String getSrcFromSelection() {
        return GWTUtils.getSrcFromText(richTextArea.getElement(), getSelectedText());
    }

    private ToggleButton createFullScreenButton() {
        final ToggleButton fullScreen = new ToggleButton(new Image(images.fullScreen()));
        fullScreen.addStyleName(FrameworkMessages.FWK_PREFIX + "fullscreenBtn");
        fullScreen.addClickHandler(new ClickHandler() {
            // To restore originale size

            public void onClick(ClickEvent event) {
                if (richMessageArea.getPanel().getStyleName()
                        .contains(FrameworkMessages.FWK_PREFIX + "fullscreen")) {
                    richMessageArea.getPanel().removeStyleName(FrameworkMessages.FWK_PREFIX + "fullscreen");
                    richMessageArea.restore();
                    fullScreen.setTitle(client.getFrameworkMessages().fullSreenOn());
                } else {
                    // richMessageArea.saveSize();
                    richMessageArea.enlarge();
                    fullScreen.setTitle(client.getFrameworkMessages().fullSreenOff());
                    richMessageArea.getPanel().addStyleName(FrameworkMessages.FWK_PREFIX + "fullscreen");
                }
            }
        });
        fullScreen.setTitle(client.getFrameworkMessages().fullSreenOn());
        return fullScreen;
    }

    private Widget createHtmlEdit() {
        final ToggleButton htmlEdit = new ToggleButton(new Image(images.html()));
        htmlEdit.addClickHandler(new ClickHandler() {

            public void onClick(ClickEvent event) {
                ToggleButton editorEdit = new ToggleButton(new Image(images.html()));
                editorEdit.addClickHandler(new ClickHandler() {

                    public void onClick(ClickEvent event) {
                        richMessageArea.switchToEditor();
                        htmlEdit.setDown(false);
                        GWTUtils.setScrollTop(richTextArea.getElement(), scrollTop);
                        GWTUtils.setScrollLeft(richTextArea.getElement(), scrollLeft);
                    }
                });
                editorEdit.setDown(true);
                editorEdit.setTitle(client.getFrameworkMessages().htmlEditOff());
                scrollTop = GWTUtils.getScrollTop(richTextArea.getElement());
                scrollLeft = GWTUtils.getScrollLeft(richTextArea.getElement());
                richMessageArea.switchToHtml(editorEdit, createFullScreenButton());
            }
        });
        htmlEdit.setTitle(client.getFrameworkMessages().htmlEditOn());
        return htmlEdit;
    }

    public void showColorPicker(Widget sender) {
        if (sender == backColors) {
            backgroundColorChooser.showAtPreviousPositionOrRelative(sender);
        } else if (sender == foreColors) {
            foregroundColorChooser.showAtPreviousPositionOrRelative(sender);
        }
    }

    private ListBox createFontStylesList() {
        ListBox lb = new ListBox();
        lb.addChangeHandler(handler);
        lb.setVisibleItemCount(1);
        lb.addItem(strings.fontStyle(), "");
        lb.addItem("Paragraph", "<p>");
        lb.addItem("Address", "<address>");
        lb.addItem("Preformatted", "<pre>");
        lb.addItem("Blockquote", "<blockquote>");
        lb.addItem("Header 1", "<h1>");
        lb.addItem("Header 2", "<h2>");
        lb.addItem("Header 3", "<h3>");
        lb.addItem("Header 4", "<h4>");
        lb.addItem("Header 5", "<h5>");
        lb.addItem("Header 6", "<h6>");
        return lb;
    }

    private ListBox createFontList() {
        ListBox lb = new ListBox();
        lb.addChangeHandler(handler);
        lb.setVisibleItemCount(1);

        lb.addItem(strings.font(), "");
        lb.addItem("Arial", "Arial");
        lb.addItem("Arial Black", "Arial Black");
        lb.addItem("Comic Sans MS", "Comic Sans MS");
        lb.addItem("Courier New", "Courier New");
        lb.addItem("Georgia", "Georgia");
        lb.addItem("Impact", "Impact");
        lb.addItem("Times New Roman", "Times New Roman");
        lb.addItem("Trebuchet MS", "Trebuchet MS");
        lb.addItem("Verdana", "Verdana");
        return lb;
    }

    private ListBox createFontSizes() {
        ListBox lb = new ListBox();
        lb.addChangeHandler(handler);
        lb.setVisibleItemCount(1);

        lb.addItem(strings.size());
        lb.addItem(strings.xxsmall());
        lb.addItem(strings.xsmall());
        lb.addItem(strings.small());
        lb.addItem(strings.medium());
        lb.addItem(strings.large());
        lb.addItem(strings.xlarge());
        lb.addItem(strings.xxlarge());
        return lb;
    }

    private TriggerPushButton createPushButton(ImageResource img, String tip) {
        TriggerPushButton pb = new TriggerPushButton(new Image(img));
        pb.addClickHandler(handler);
        pb.setTitle(tip);
        return pb;
    }

    private ToggleButton createToggleButton(ImageResource img, String tip) {
        ToggleButton tb = new ToggleButton(new Image(img));
        tb.addClickHandler(handler);
        tb.setTitle(tip);
        return tb;
    }

    /**
     * Updates the status of all the stateful buttons.
     */
    private void updateStatus() {
        bold.setDown(formatter.isBold());
        italic.setDown(formatter.isItalic());
        underline.setDown(formatter.isUnderlined());
        subscript.setDown(formatter.isSubscript());
        superscript.setDown(formatter.isSuperscript());
        strikethrough.setDown(formatter.isStrikethrough());
    }
}