Package com.google.livingstories.client.ui.richtexttoolbar

Source Code of com.google.livingstories.client.ui.richtexttoolbar.RichTextToolbar

/**
* Copyright 2010 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.google.livingstories.client.ui.richtexttoolbar;

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.user.client.Window;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ImageBundle;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.ToggleButton;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.livingstories.client.ContentItemType;
import com.google.livingstories.client.BaseContentItem;
import com.google.livingstories.client.EventContentItem;
import com.google.livingstories.client.NarrativeContentItem;
import com.google.livingstories.client.lsp.SourceLink;
import com.google.livingstories.client.ui.SingleContentItemSelectionPanel;
import com.google.livingstories.client.util.RichTextUtil;

import java.util.EnumSet;
import java.util.Set;

/**
* A toolbar for use with {@link RichTextArea}. It provides a simple UI
* for all rich text formatting, dynamically displayed only for the available
* functionality.
*
* <p>A limited subset of the buttons will provide user feedback depending on
* the cursor location.  Specifically, the following toggle buttons will appear
* depressed if the cursor is over a portion of text that exhibits the
* associated style:
*
* <ul>
*   <li>BOLD_TOGGLE</li>
*   <li>ITALIC_TOGGLE</li>
*   <li>UNDERLINE_TOGGLE</li>
*   <li>SUBSCRIPT_TOGGLE</li>
*   <li>SUPERSCRIPT_TOGGLE</li>
*   <li>STRIKETHROUGH_TOGGLE</li>
* </ul>
*
*
* <h3>CSS Style Rules</h3>
* <ul class='css'>
* <li>.gwt-RichTextToolbar { primary style }</li>
* <li>.gwt-BoldToggle { on the BoldToggle control }</li>
* <li>.gwt-ItalicToggle { on the ItalicToggle control }</li>
* <li>.gwt-UnderlineToggle { on the UnderlineToggle control }</li>
* <li>.gwt-SubscriptToggle { on the SubscriptToggle control }</li>
* <li>.gwt-SuperscriptToggle { on the SuperscriptToggle control }</li>
* <li>.gwt-JustifyLeftButton { on the JustifyLeftButton control }</li>
* <li>.gwt-JustifyCenterButton { on the JustifyCenterButton control }</li>
* <li>.gwt-JustifyRightButton { on the JustifyRightButton control }</li>
* <li>.gwt-StrikethroughButton { on the StrikethroughButton control }</li>
* <li>.gwt-IndentButton { on the IndentButton control }</li>
* <li>.gwt-OutdentButton { on the OutdentButton control }</li>
* <li>.gwt-HorizontalRuleButton { on the HorizontalRuleButton control }</li>
* <li>.gwt-OrderedListButton { on the OrderedListButton control }</li>
* <li>.gwt-UnorderedListButton { on the UnorderedListButton control }</li>
* <li>.gwt-InsertImageButton { on the InsertImageButton control }</li>
* <li>.gwt-CreateLinkButton { on the CreateLinkButton control }</li>
* <li>.gwt-RemoveLinkButton { on the RemoveLinkButton control }</li>
* <li>.gwt-RemoveFormatButton { on the RemoveFormatButton control }</li>
* <li>.gwt-hasRichTextToolbar { added to associated RichTextArea }</li>
* </ul>
*/
public class RichTextToolbar extends Composite {

  /** I18n messages. */
  private static final RichTextMessages MESSAGES = GWT.create(RichTextMessages.class);

  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 Images images = (Images) GWT.create(Images.class);
  private RichTextUtil richTextUtil = GWT.create(RichTextUtil.class);

  private RichTextArea richText;
  private RichTextArea.BasicFormatter basic;
  private RichTextArea.ExtendedFormatter extended;

  // All of these controls can be null, if the creator so chooses, so always
  // null-check them before attempting to access them
  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 insertGoToContentItem;
  private PushButton insertContentItem;
  private PushButton insertSource;
  private PushButton insertLightbox;
  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, provides all
   * available controls, and divides the toolbar into two rows.
   *
   * @param richText the {@link RichTextArea} to be controlled
   */
  public RichTextToolbar(RichTextArea richText) {
    this(richText, true);
  }

  /**
   * Creates a new toolbar that drives the given rich text area, provides the
   * given controls, and divides the toolbar into two rows.  If you prefer to
   * specify which controls are disabled (and keep the rest), then use
   * {@link EnumSet#complementOf} or the combination of
   * {@link EnumSet#allOf} and {@link EnumSet#remove}.
   *
   * @param richText the {@link RichTextArea} to be controlled
   * @param controls the set of enabled controls
   */
  public RichTextToolbar(RichTextArea richText, Set<Control> controls) {
    this(richText, controls, true);
  }

  /**
   * Creates a new toolbar that drives the given rich text area, provides all
   * available controls, and optionally divides the toolbar into two rows.
   *
   * @param richText the {@link RichTextArea} to be controlled
   * @param divideToolbar whether or not to divide the toolbar
   */
  public RichTextToolbar(RichTextArea richText, boolean divideToolbar) {
    this(richText, EnumSet.allOf(Control.class), divideToolbar);
  }

  /**
   * Creates a new toolbar that drives the given rich text area, provides the
   * given controls, and optionally divides the toolbar into two rows.  If you
   * prefer to specify which controls are disabled (and keep the rest), then
   * use {@link EnumSet#complementOf} or the combination of
   * {@link EnumSet#allOf} and {@link EnumSet#remove}.
   *
   * <p>The {@code divideToolbar} argument, if true, will divide the toolbar into
   * two sections - one for buttons, and one for the lists.  If false, both
   * sections will be on the same row.  With all buttons enabled, a single-row
   * toolbar can take upwards of 800 pixels of horizontal space.
   *
   * <p>If {@code controls} is null, then all available controls are enabled.
   *
   * @param richText the {@link RichTextArea} to be controlled
   * @param controls the set of enabled controls
   * @param divideToolbar whether or not to divide the toolbar
   */
  public RichTextToolbar(RichTextArea richText, Set<Control> controls, boolean divideToolbar) {
    this.richText = richText;
    this.basic = richText.getBasicFormatter();
    this.extended = richText.getExtendedFormatter();

    boolean hasToggle = false;
    boolean hasTopPanel = false;
    boolean hasBottomPanel = false;

    HorizontalPanel topPanel = new HorizontalPanel();
    HorizontalPanel bottomPanel = null;
    VerticalPanel outer = null;

    if (divideToolbar) {
      bottomPanel = new HorizontalPanel();
      outer = new VerticalPanel();
      outer.add(topPanel);
      outer.add(bottomPanel);
    }

    if (basic != null) {
      if (controls.contains(Control.BOLD_TOGGLE)) {
        bold = createToggleButton(images.bold(), MESSAGES.bold());
        addControlToToolbar(topPanel, bold, "gwt-BoldToggle");
        hasTopPanel = true;
        hasToggle = true;
      }

      if (controls.contains(Control.ITALIC_TOGGLE)) {
        italic = createToggleButton(images.italic(), MESSAGES.italic());
        addControlToToolbar(topPanel, italic, "gwt-ItalicToggle");
        hasTopPanel = true;
        hasToggle = true;
      }

      if (controls.contains(Control.UNDERLINE_TOGGLE)) {
        underline = createToggleButton(images.underline(), MESSAGES.underline());
        addControlToToolbar(topPanel, underline, "gwt-UnderlineToggle");
        hasTopPanel = true;
        hasToggle = true;
      }

      if (controls.contains(Control.SUBSCRIPT_TOGGLE)) {
        subscript = createToggleButton(images.subscript(), MESSAGES.subscript());
        addControlToToolbar(topPanel, subscript, "gwt-SubscriptToggle");
        hasTopPanel = true;
        hasToggle = true;
      }

      if (controls.contains(Control.SUPERSCRIPT_TOGGLE)) {
        superscript = createToggleButton(images.superscript(), MESSAGES.superscript());
        addControlToToolbar(topPanel, superscript, "gwt-SuperscriptToggle");
        hasTopPanel = true;
        hasToggle = true;
      }

      if (controls.contains(Control.JUSTIFY_LEFT_BUTTON)) {
        justifyLeft = createPushButton(images.justifyLeft(), MESSAGES.justifyLeft());
        addControlToToolbar(topPanel, justifyLeft, "gwt-JustifyLeftButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.JUSTIFY_CENTER_BUTTON)) {
        justifyCenter = createPushButton(images.justifyCenter(), MESSAGES.justifyCenter());
        addControlToToolbar(topPanel, justifyCenter, "gwt-JustifyCenterButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.JUSTIFY_RIGHT_BUTTON)) {
        justifyRight = createPushButton(images.justifyRight(), MESSAGES.justifyRight());
        addControlToToolbar(topPanel, justifyRight, "gwt-JustifyRightButton");
        hasTopPanel = true;
      }
    }

    if (extended != null) {
      if (controls.contains(Control.STRIKETHROUGH_TOGGLE)) {
        strikethrough = createToggleButton(images.strikeThrough(), MESSAGES.strikeThrough());
        addControlToToolbar(topPanel, strikethrough, "gwt-StrikethroughButton");
        hasTopPanel = true;
        hasToggle = true;
      }

      if (controls.contains(Control.INDENT_BUTTON)) {
        indent = createPushButton(images.indent(), MESSAGES.indent());
        addControlToToolbar(topPanel, indent, "gwt-IndentButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.OUTDENT_BUTTON)) {
        outdent = createPushButton(images.outdent(), MESSAGES.outdent());
        addControlToToolbar(topPanel, outdent, "gwt-OutdentButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.HORIZONTAL_RULE_BUTTON)) {
        hr = createPushButton(images.hr(), MESSAGES.hr());
        addControlToToolbar(topPanel, hr, "gwt-HorizontalRuleButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.ORDERED_LIST_BUTTON)) {
        ol = createPushButton(images.ol(), MESSAGES.ol());
        addControlToToolbar(topPanel, ol, "gwt-OrderedListButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.UNORDERED_LIST_BUTTON)) {
        ul = createPushButton(images.ul(), MESSAGES.ul());
        addControlToToolbar(topPanel, ul, "gwt-UnorderedListButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.INSERT_IMAGE_BUTTON)) {
        insertImage = createPushButton(images.insertImage(), MESSAGES.insertImage());
        addControlToToolbar(topPanel, insertImage, "gwt-InsertImageButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.INSERT_GO_TO_CONTENT_ITEM_BUTTON)) {
        insertGoToContentItem =
            createPushButton(images.insertGoToContentItem(), MESSAGES.insertGoToContentItem());
        addControlToToolbar(topPanel, insertGoToContentItem, "gwt-InsertGoToContentItemButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.INSERT_CONTENT_ITEM_BUTTON)) {
        insertContentItem =
            createPushButton(images.insertContentItem(), MESSAGES.insertContentItem());
        addControlToToolbar(topPanel, insertContentItem, "gwt-InsertContentItemButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.INSERT_SOURCE_BUTTON)) {
        insertSource = createPushButton(images.insertSource(), MESSAGES.insertSource());
        addControlToToolbar(topPanel, insertSource, "gwt-InsertSourceButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.INSERT_LIGHTBOX_BUTTON)) {
        insertLightbox = createPushButton(images.insertLightbox(), MESSAGES.insertLightbox());
        addControlToToolbar(topPanel, insertLightbox, "gwt-InsertLightboxButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.CREATE_LINK_BUTTON)) {
        createLink = createPushButton(images.createLink(), MESSAGES.createLink());
        addControlToToolbar(topPanel, createLink, "gwt-CreateLinkButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.REMOVE_LINK_BUTTON)) {
        removeLink = createPushButton(images.removeLink(), MESSAGES.removeLink());
        addControlToToolbar(topPanel, removeLink, "gwt-RemoveLinkButton");
        hasTopPanel = true;
      }

      if (controls.contains(Control.REMOVE_FORMAT_BUTTON)) {
        removeFormat = createPushButton(images.removeFormat(), MESSAGES.removeFormat());
        addControlToToolbar(topPanel, removeFormat, "gwt-RemoveFormatButton");
        hasTopPanel = true;
      }
    }

    if (basic != null) {
      HorizontalPanel panelToAddTo = bottomPanel != null ? bottomPanel : topPanel;
      if (controls.contains(Control.BACK_COLORS_LIST)) {
        backColors = createColorList(MESSAGES.background());
        addControlToToolbar(panelToAddTo, backColors, "gwt-BackColorsList");
        hasBottomPanel = true;
      }

      if (controls.contains(Control.FORE_COLORS_LIST)) {
        foreColors = createColorList(MESSAGES.foreground());
        addControlToToolbar(panelToAddTo, foreColors, "gwt-ForeColorsList");
        hasBottomPanel = true;
      }

      if (controls.contains(Control.FONTS_LIST)) {
        fonts = createFontList();
        addControlToToolbar(panelToAddTo, fonts, "gwt-FontsList");
        hasBottomPanel = true;
      }

      if (controls.contains(Control.FONT_SIZES_LIST)) {
        fontSizes = createFontSizes();
        addControlToToolbar(panelToAddTo, fontSizes, "gwt-FontSizesList");
        hasBottomPanel = true;
      }

      // We only use these listeners for updating status, so don't hook them up
      // unless at least basic editing is supported, and unless we have at
      // least one toggle button.
      if (hasToggle) {
        richText.addKeyUpHandler(new ToolbarKeyUpHandler());
        richText.addClickHandler(new ToolbarClickHandler());
      }
    }

    if (divideToolbar) {
      if (hasTopPanel && hasBottomPanel) {
        initWidget(outer);
      } else if (hasBottomPanel) {
        initWidget(bottomPanel);
      } else { // hasTopPanel (or has no panel)
        initWidget(topPanel);
      }
    } else { // divideToolbar == false
      // Also covers the case where they have no controls at all
      initWidget(topPanel);
    }

    setStyleName("gwt-RichTextToolbar");
    richText.addStyleName("gwt-hasRichTextToolbar");
  }

  private ListBox createColorList(String caption) {
    ListBox lb = new ListBox();
    lb.addChangeHandler(new ToolbarChangeHandler());
    lb.setVisibleItemCount(1);

    lb.addItem(caption);
    lb.addItem(MESSAGES.white(), "white");
    lb.addItem(MESSAGES.black(), "black");
    lb.addItem(MESSAGES.red(), "red");
    lb.addItem(MESSAGES.green(), "green");
    lb.addItem(MESSAGES.yellow(), "yellow");
    lb.addItem(MESSAGES.blue(), "blue");
    return lb;
  }

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

    lb.addItem(MESSAGES.font(), "");
    lb.addItem(MESSAGES.normal(), "");
    lb.addItem(MESSAGES.timesNewRoman(), "Times New Roman");
    lb.addItem(MESSAGES.arial(), "Arial");
    lb.addItem(MESSAGES.courierNew(), "Courier New");
    lb.addItem(MESSAGES.georgia(), "Georgia");
    lb.addItem(MESSAGES.trebuchet(), "Trebuchet");
    lb.addItem(MESSAGES.verdana(), "Verdana");
    return lb;
  }

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

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

  private PushButton createPushButton(AbstractImagePrototype img, String tip) {
    PushButton pb = new PushButton(img.createImage());
    pb.addClickHandler(new ToolbarClickHandler());
    pb.setTitle(tip);
    return pb;
  }

  private ToggleButton createToggleButton(AbstractImagePrototype img, String tip) {
    ToggleButton tb = new ToggleButton(img.createImage());
    tb.addClickHandler(new ToolbarClickHandler());
    tb.setTitle(tip);
    return tb;
  }

  private void addControlToToolbar(HorizontalPanel toolbar, Widget w, String styleName) {
    w.addStyleName(styleName);
    toolbar.add(w);
  }

  /**
   * Updates the status of all the stateful buttons.
   */
  private void updateStatus() {
    if (bold != null) {
      bold.setDown(basic.isBold());
    }

    if (italic != null) {
      italic.setDown(basic.isItalic());
    }

    if (underline != null) {
      underline.setDown(basic.isUnderlined());
    }

    if (subscript != null) {
      subscript.setDown(basic.isSubscript());
    }

    if (superscript != null) {
      superscript.setDown(basic.isSuperscript());
    }

    if (strikethrough != null) {
      strikethrough.setDown(extended.isStrikethrough());
    }
  }

  /**
   * The possible controls that are supported by this toolbar implementation.
   */
  public enum Control {
    BOLD_TOGGLE,
    ITALIC_TOGGLE,
    UNDERLINE_TOGGLE,
    SUBSCRIPT_TOGGLE,
    SUPERSCRIPT_TOGGLE,
    STRIKETHROUGH_TOGGLE,
    INDENT_BUTTON,
    OUTDENT_BUTTON,
    JUSTIFY_LEFT_BUTTON,
    JUSTIFY_CENTER_BUTTON,
    JUSTIFY_RIGHT_BUTTON,
    HORIZONTAL_RULE_BUTTON,
    ORDERED_LIST_BUTTON,
    UNORDERED_LIST_BUTTON,
    INSERT_IMAGE_BUTTON,
    INSERT_GO_TO_CONTENT_ITEM_BUTTON,
    INSERT_CONTENT_ITEM_BUTTON,
    INSERT_SOURCE_BUTTON,
    INSERT_LIGHTBOX_BUTTON,
    CREATE_LINK_BUTTON,
    REMOVE_LINK_BUTTON,
    REMOVE_FORMAT_BUTTON,
    BACK_COLORS_LIST,
    FORE_COLORS_LIST,
    FONTS_LIST,
    FONT_SIZES_LIST
  }
 
  private class ToolbarClickHandler implements ClickHandler {
    public void onClick(ClickEvent event) {
      Object sender = event.getSource();
      if (sender == bold) {
        basic.toggleBold();
      } else if (sender == italic) {
        basic.toggleItalic();
      } else if (sender == underline) {
        basic.toggleUnderline();
      } else if (sender == subscript) {
        basic.toggleSubscript();
      } else if (sender == superscript) {
        basic.toggleSuperscript();
      } else if (sender == strikethrough) {
        extended.toggleStrikethrough();
      } else if (sender == indent) {
        extended.rightIndent();
      } else if (sender == outdent) {
        extended.leftIndent();
      } else if (sender == justifyLeft) {
        basic.setJustification(RichTextArea.Justification.LEFT);
      } else if (sender == justifyCenter) {
        basic.setJustification(RichTextArea.Justification.CENTER);
      } else if (sender == justifyRight) {
        basic.setJustification(RichTextArea.Justification.RIGHT);
      } else if (sender == insertImage) {
        String url = Window.prompt(MESSAGES.enterImageUrl(), "http://");
        if (url != null) {
          extended.insertImage(url);
        }
      } else if (sender == insertGoToContentItem) {
        PopupPanel popup = new PopupPanel();
        FlowPanel contentPanel = new FlowPanel();
        final SingleContentItemSelectionPanel selectionPanel =
            new SingleContentItemSelectionPanel();
        contentPanel.add(selectionPanel);
        contentPanel.add(createButtonPanel(popup, new ContentItemSelectionHandler() {
          @Override
          public void onSelect() {
            BaseContentItem contentItem = selectionPanel.getSelection();
            String headline = null;
            if (contentItem.getContentItemType() == ContentItemType.EVENT) {
              headline = ((EventContentItem) contentItem).getEventUpdate();
            } else if (contentItem.getContentItemType() == ContentItemType.NARRATIVE) {
              headline = ((NarrativeContentItem) contentItem).getHeadline();
            } else {
              Window.alert("You must link to an event or top level narrative!");
              contentItem = null;
            }
            if (contentItem != null && contentItem.displayTopLevel()) {
              richTextUtil.createJavascriptLink(richText.getElement(),
                  "goToContentItem(" + contentItem.getId() + ")",
                  "Jump to: " + headline.replace("\"", "'"));
            }
          }
        }));
        popup.add(contentPanel);
        popup.showRelativeTo(insertContentItem);
      } else if (sender == insertContentItem) {
        PopupPanel popup = new PopupPanel();
        FlowPanel contentPanel = new FlowPanel();
        final SingleContentItemSelectionPanel selectionPanel =
            new SingleContentItemSelectionPanel();
        contentPanel.add(selectionPanel);
        contentPanel.add(createButtonPanel(popup, new ContentItemSelectionHandler() {
          @Override
          public void onSelect() {
            BaseContentItem contentItem = selectionPanel.getSelection();
            if (contentItem != null) {
              richTextUtil.createJavascriptLink(richText.getElement(),
                  "showContentItemPopup(" + contentItem.getId() + ", this)");
            }
          }
        }));
        popup.add(contentPanel);
        popup.showRelativeTo(insertContentItem);
      } else if (sender == insertSource) {
        PopupPanel popup = new PopupPanel();
        FlowPanel contentPanel = new FlowPanel();
        final TextBox descriptionBox = new TextBox();
        HorizontalPanel descriptionPanel = new HorizontalPanel();
        descriptionPanel.add(new Label("Source description:"));
        descriptionPanel.add(descriptionBox);
        contentPanel.add(descriptionPanel);
        final SingleContentItemSelectionPanel selectionPanel =
            new SingleContentItemSelectionPanel();
        contentPanel.add(selectionPanel);
        contentPanel.add(createButtonPanel(popup, new ContentItemSelectionHandler() {
          @Override
          public void onSelect() {
            String description = descriptionBox.getText();
            BaseContentItem contentItem = selectionPanel.getSelection();
            if (!description.isEmpty() || contentItem != null) {
              String selectedText = richTextUtil.getSelection(richText.getElement());
              richTextUtil.insertHTML(richText.getElement(), selectedText + " " +
                  new SourceLink(description, contentItem == null ? -1
                      : contentItem.getId()).getOuterHTML());
            }
          }
        }));
        popup.add(contentPanel);
        popup.showRelativeTo(insertSource);
      } else if (sender == insertLightbox) {
        PopupPanel popup = new PopupPanel();
        FlowPanel contentPanel = new FlowPanel();
        final SingleContentItemSelectionPanel selectionPanel =
            new SingleContentItemSelectionPanel();
        contentPanel.add(selectionPanel);
        contentPanel.add(createButtonPanel(popup, new ContentItemSelectionHandler() {
          @Override
          public void onSelect() {
            BaseContentItem contentItem = selectionPanel.getSelection();
            if (contentItem != null) {
              richTextUtil.createJavascriptLink(richText.getElement(),
                  "showLightboxForContentItem('" + contentItem.getTypeString()
                  + "', " + contentItem.getId() + ")");
            }
          }
        }));
        popup.add(contentPanel);
        popup.showRelativeTo(insertLightbox);
      } else if (sender == createLink) {
        String url = Window.prompt(MESSAGES.enterLinkUrl(), "http://");
        if (url != null) {
          extended.createLink(url);
        }
      } else if (sender == removeLink) {
        extended.removeLink();
      } else if (sender == hr) {
        extended.insertHorizontalRule();
      } else if (sender == ol) {
        extended.insertOrderedList();
      } else if (sender == ul) {
        extended.insertUnorderedList();
      } else if (sender == removeFormat) {
        extended.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();
      }
    }

    private Widget createButtonPanel(final PopupPanel popup,
        final ContentItemSelectionHandler handler) {
      Button okButton = new Button("Ok");
      okButton.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
          handler.onSelect();
          popup.hide();
        }
      });
      Button cancelButton = new Button("Cancel");
      cancelButton.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
          popup.hide();
        }
      });
     
      HorizontalPanel buttons = new HorizontalPanel();
      buttons.add(okButton);
      buttons.add(cancelButton);     
      return buttons;
    }
  }
   
  private class ToolbarChangeHandler implements ChangeHandler {
    public void onChange(ChangeEvent event) {
      Object sender = event.getSource();
      if (sender == backColors) {
        basic.setBackColor(backColors.getValue(backColors.getSelectedIndex()));
        backColors.setSelectedIndex(0);
      } else if (sender == foreColors) {
        basic.setForeColor(foreColors.getValue(foreColors.getSelectedIndex()));
        foreColors.setSelectedIndex(0);
      } else if (sender == fonts) {
        basic.setFontName(fonts.getValue(fonts.getSelectedIndex()));
        fonts.setSelectedIndex(0);
      } else if (sender == fontSizes) {
        basic.setFontSize(fontSizesConstants[fontSizes.getSelectedIndex() - 1]);
        fontSizes.setSelectedIndex(0);
      }
    }
  }
 
  private class ToolbarKeyUpHandler implements KeyUpHandler {
    public void onKeyUp(KeyUpEvent event) {
      if (event.getSource() == 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 interface ContentItemSelectionHandler {
    void onSelect();
  }

  /**
   * This {@link ImageBundle} is used for all the button icons. Using an image
   * 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 ImageBundle {
    AbstractImagePrototype bold();
    AbstractImagePrototype createLink();
    AbstractImagePrototype hr();
    AbstractImagePrototype indent();
    AbstractImagePrototype insertImage();
    AbstractImagePrototype insertGoToContentItem();
    AbstractImagePrototype insertContentItem();
    AbstractImagePrototype insertSource();
    AbstractImagePrototype insertLightbox();
    AbstractImagePrototype italic();
    AbstractImagePrototype justifyCenter();
    AbstractImagePrototype justifyLeft();
    AbstractImagePrototype justifyRight();
    AbstractImagePrototype ol();
    AbstractImagePrototype outdent();
    AbstractImagePrototype removeFormat();
    AbstractImagePrototype removeLink();
    AbstractImagePrototype strikeThrough();
    AbstractImagePrototype subscript();
    AbstractImagePrototype superscript();
    AbstractImagePrototype ul();
    AbstractImagePrototype underline();
  }

}
TOP

Related Classes of com.google.livingstories.client.ui.richtexttoolbar.RichTextToolbar

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.