Package org.waveprotocol.wave.client.wavepanel.impl.toolbar

Source Code of org.waveprotocol.wave.client.wavepanel.impl.toolbar.EditToolbar$FontFamily

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.waveprotocol.wave.client.wavepanel.impl.toolbar;

import com.google.common.base.Preconditions;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.http.client.URL;

import org.waveprotocol.wave.client.editor.Editor;
import org.waveprotocol.wave.client.editor.EditorContext;
import org.waveprotocol.wave.client.editor.EditorContextAdapter;
import org.waveprotocol.wave.client.editor.content.CMutableDocument;
import org.waveprotocol.wave.client.editor.content.ContentElement;
import org.waveprotocol.wave.client.editor.content.ContentNode;
import org.waveprotocol.wave.client.editor.content.misc.StyleAnnotationHandler;
import org.waveprotocol.wave.client.editor.content.paragraph.Paragraph;
import org.waveprotocol.wave.client.editor.content.paragraph.Paragraph.LineStyle;
import org.waveprotocol.wave.client.editor.toolbar.ButtonUpdater;
import org.waveprotocol.wave.client.editor.toolbar.ParagraphApplicationController;
import org.waveprotocol.wave.client.editor.toolbar.ParagraphTraversalController;
import org.waveprotocol.wave.client.editor.toolbar.TextSelectionController;
import org.waveprotocol.wave.client.editor.util.EditorAnnotationUtil;
import org.waveprotocol.wave.client.gadget.GadgetXmlUtil;
import org.waveprotocol.wave.client.wavepanel.impl.toolbar.attachment.AttachmentPopupWidget;
import org.waveprotocol.wave.client.wavepanel.impl.toolbar.color.ColorHelper;
import org.waveprotocol.wave.client.wavepanel.impl.toolbar.gadget.GadgetInfoProviderImpl;
import org.waveprotocol.wave.client.wavepanel.impl.toolbar.gadget.GadgetSelectorWidget;
import org.waveprotocol.wave.client.wavepanel.impl.toolbar.gadget.GwtGadgetInfoParser;
import org.waveprotocol.wave.client.wavepanel.view.AttachmentPopupView;
import org.waveprotocol.wave.client.wavepanel.view.AttachmentPopupView.Listener;
import org.waveprotocol.wave.client.widget.popup.UniversalPopup;
import org.waveprotocol.wave.client.widget.toolbar.SubmenuToolbarView;
import org.waveprotocol.wave.client.widget.toolbar.ToolbarButtonViewBuilder;
import org.waveprotocol.wave.client.widget.toolbar.ToolbarView;
import org.waveprotocol.wave.client.widget.toolbar.ToplevelToolbarWidget;
import org.waveprotocol.wave.client.widget.toolbar.buttons.ToolbarClickButton;
import org.waveprotocol.wave.client.widget.toolbar.buttons.ToolbarToggleButton;
import org.waveprotocol.wave.media.model.AttachmentIdGenerator;
import org.waveprotocol.wave.media.model.AttachmentIdGeneratorImpl;
import org.waveprotocol.wave.model.document.util.FocusedRange;
import org.waveprotocol.wave.model.document.util.LineContainers;
import org.waveprotocol.wave.model.document.util.Point;
import org.waveprotocol.wave.model.document.util.XmlStringBuilder;
import org.waveprotocol.wave.model.id.IdGenerator;
import org.waveprotocol.wave.model.id.WaveId;
import org.waveprotocol.wave.model.wave.ParticipantId;
import org.waveprotocol.wave.model.waveref.WaveRef;
import org.waveprotocol.wave.util.escapers.GwtWaverefEncoder;
import org.waveprotocol.wave.client.editor.content.FocusedContentRange;
import org.waveprotocol.wave.client.doodad.attachment.ImageThumbnail;
import org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailWrapper;

/**
* Attaches actions that can be performed in a Wave's "edit mode" to a toolbar.
* <p>
* Also constructs an initial set of such actions.
*
* @author kalman@google.com (Benjamin Kalman)
*/
public class EditToolbar {

  /**
   * Handler for click buttons added with {@link EditToolbar#addClickButton}.
   */
  public interface ClickHandler {
    void onClicked(EditorContext context);
  }

  /**
   * Container for a font family.
   */
  private static final class FontFamily {
    public final String description;
    public final String style;
    public FontFamily(String description, String style) {
      this.description = description;
      this.style = style;
    }
  }

  /**
   * Container for an alignment.
   */
  private static final class Alignment {
    public final String description;
    public final String iconCss;
    public final LineStyle style;
    public Alignment(String description, String iconCss, LineStyle style) {
      this.description = description;
      this.iconCss = iconCss;
      this.style = style;
    }
  }

  private final EditorToolbarResources.Css css;
  private final ToplevelToolbarWidget toolbarUi;
  private final ParticipantId user;
  private final AttachmentIdGenerator attachmentIdGenerator;

  /** The id of the currently loaded wave. */
  private WaveId waveId;

  private final EditorContextAdapter editor = new EditorContextAdapter(null);
  private final ButtonUpdater updater = new ButtonUpdater(editor);

  private EditToolbar(EditorToolbarResources.Css css, ToplevelToolbarWidget toolbarUi,
      ParticipantId user, IdGenerator idGenerator, WaveId waveId) {
    this.css = css;
    this.toolbarUi = toolbarUi;
    this.user = user;
    this.waveId = waveId;
    attachmentIdGenerator = new AttachmentIdGeneratorImpl(idGenerator);
  }

  /**
   * Attaches editor behaviour to a toolbar, adding all the edit buttons.
   */
  public static EditToolbar create(ParticipantId user, IdGenerator idGenerator, WaveId waveId) {
    ToplevelToolbarWidget toolbarUi = new ToplevelToolbarWidget();
    EditorToolbarResources.Css css = EditorToolbarResources.Loader.res.css();
    return new EditToolbar(css, toolbarUi, user, idGenerator, waveId);
  }

  /** Constructs the initial set of actions in the toolbar. */
  public void init() {
    ToolbarView group = toolbarUi.addGroup();
    createBoldButton(group);
    createItalicButton(group);
    createUnderlineButton(group);
    createStrikethroughButton(group);

    group = toolbarUi.addGroup();
    createSuperscriptButton(group);
    createSubscriptButton(group);

    group = toolbarUi.addGroup();
    createFontSizeButton(group);
    createFontFamilyButton(group);
    createHeadingButton(group);

    group = toolbarUi.addGroup();
    createFontColorButton(group);
    createFontBackColorButton(group);

    group = toolbarUi.addGroup();
    createIndentButton(group);
    createOutdentButton(group);

    group = toolbarUi.addGroup();
    createUnorderedListButton(group);
    createOrderedListButton(group);

    group = toolbarUi.addGroup();
    createAlignButtons(group);
    createClearFormattingButton(group);

    group = toolbarUi.addGroup();
    createInsertLinkButton(group);
    createRemoveLinkButton(group);

    group = toolbarUi.addGroup();
    createInsertGadgetButton(group, user);

    group = toolbarUi.addGroup();
    createInsertAttachmentButton(group, user);
  }

  private void createBoldButton(ToolbarView toolbar) {
    ToolbarToggleButton b = toolbar.addToggleButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.bold())
        .applyTo(b, createTextSelectionController(b, "fontWeight", "bold"));
  }

  private void createItalicButton(ToolbarView toolbar) {
    ToolbarToggleButton b = toolbar.addToggleButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.italic())
        .applyTo(b, createTextSelectionController(b, "fontStyle", "italic"));
  }

  private void createUnderlineButton(ToolbarView toolbar) {
    ToolbarToggleButton b = toolbar.addToggleButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.underline())
        .applyTo(b, createTextSelectionController(b, "textDecoration", "underline"));
  }

  private void createFontBackColorButton(ToolbarView toolbar) {
    final ToolbarClickButton button = toolbar.addClickButton();
    new ToolbarButtonViewBuilder()
    .setIcon(css.backcolor())
    .applyTo(button, new ToolbarClickButton.Listener() {
      @Override  public void onClicked() {
        ColorHelper.onSetBackColor(editor, button);
      }
    });
  }

  private void createFontColorButton(ToolbarView toolbar) {
    final ToolbarClickButton button = toolbar.addClickButton();
    new ToolbarButtonViewBuilder()
    .setIcon(css.color())
    .applyTo(button, new ToolbarClickButton.Listener() {
      @Override  public void onClicked() {
        ColorHelper.onSetColor(editor, button);
      }
    });
  }

  private void createStrikethroughButton(ToolbarView toolbar) {
    ToolbarToggleButton b = toolbar.addToggleButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.strikethrough())
        .applyTo(b, createTextSelectionController(b, "textDecoration", "line-through"));
  }

  private void createSuperscriptButton(ToolbarView toolbar) {
    ToolbarToggleButton b = toolbar.addToggleButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.superscript())
        .applyTo(b, createTextSelectionController(b, "verticalAlign", "super"));
  }

  private void createSubscriptButton(ToolbarView toolbar) {
    ToolbarToggleButton b = toolbar.addToggleButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.subscript())
        .applyTo(b, createTextSelectionController(b, "verticalAlign", "sub"));
  }

  private void createFontSizeButton(ToolbarView toolbar) {
    SubmenuToolbarView submenu = toolbar.addSubmenu();
    new ToolbarButtonViewBuilder()
        .setIcon(css.fontSize())
        .applyTo(submenu, null);
    submenu.setShowDropdownArrow(false); // Icon already has dropdown arrow.
    // TODO(kalman): default text size option.
    ToolbarView group = submenu.addGroup();
    for (int size : asArray(8, 9, 10, 11, 12, 14, 16, 18, 21, 24, 28, 32, 36, 42, 48, 56, 64, 72)) {
      ToolbarToggleButton b = group.addToggleButton();
      double baseSize = 12.0;
      b.setVisualElement(createFontSizeElement(baseSize, size));
      b.setListener(createTextSelectionController(b, "fontSize", (size / baseSize) + "em"));
    }
  }

  private Element createFontSizeElement(double baseSize, double size) {
    Element e = Document.get().createSpanElement();
    e.getStyle().setFontSize(size / baseSize, Unit.EM);
    e.setInnerText(((int) size) + "");
    return e;
  }

  private void createFontFamilyButton(ToolbarView toolbar) {
    SubmenuToolbarView submenu = toolbar.addSubmenu();
    new ToolbarButtonViewBuilder()
        .setIcon(css.fontFamily())
        .applyTo(submenu, null);
    submenu.setShowDropdownArrow(false); // Icon already has dropdown arrow.
    createFontFamilyGroup(submenu.addGroup(), new FontFamily("Default", null));
    createFontFamilyGroup(submenu.addGroup(),
        new FontFamily("Sans Serif", "sans-serif"),
        new FontFamily("Serif", "serif"),
        new FontFamily("Wide", "arial black,sans-serif"),
        new FontFamily("Narrow", "arial narrow,sans-serif"),
        new FontFamily("Fixed Width", "monospace"));
    createFontFamilyGroup(submenu.addGroup(),
        new FontFamily("Arial", "arial,helvetica,sans-serif"),
        new FontFamily("Comic Sans MS", "comic sans ms,sans-serif"),
        new FontFamily("Courier New", "courier new,monospace"),
        new FontFamily("Garamond", "garamond,serif"),
        new FontFamily("Georgia", "georgia,serif"),
        new FontFamily("Tahoma", "tahoma,sans-serif"),
        new FontFamily("Times New Roman", "times new roman,serif"),
        new FontFamily("Trebuchet MS", "trebuchet ms,sans-serif"),
        new FontFamily("Verdana", "verdana,sans-serif"));
  }

  private void createFontFamilyGroup(ToolbarView toolbar, FontFamily... families) {
    for (FontFamily family : families) {
      ToolbarToggleButton b = toolbar.addToggleButton();
      b.setVisualElement(createFontFamilyElement(family));
      b.setListener(createTextSelectionController(b, "fontFamily", family.style));
    }
  }

  private Element createFontFamilyElement(FontFamily family) {
    Element e = Document.get().createSpanElement();
    e.getStyle().setProperty("fontFamily", family.style);
    e.setInnerText(family.description);
    return e;
  }

  private void createClearFormattingButton(ToolbarView toolbar) {
    new ToolbarButtonViewBuilder()
        .setIcon(css.clearFormatting())
        .applyTo(toolbar.addClickButton(), new ToolbarClickButton.Listener() {
          @Override public void onClicked() {
            EditorAnnotationUtil.clearAnnotationsOverSelection(editor, asArray(
                StyleAnnotationHandler.key("backgroundColor"),
                StyleAnnotationHandler.key("color"),
                StyleAnnotationHandler.key("fontFamily"),
                StyleAnnotationHandler.key("fontSize"),
                StyleAnnotationHandler.key("fontStyle"),
                StyleAnnotationHandler.key("fontWeight"),
                StyleAnnotationHandler.key("textDecoration"),
                StyleAnnotationHandler.key("verticalAlign")
                // NOTE: add more as required.
            ));
            createClearHeadingsListener().onClicked();
          }
        });
  }

  private void createInsertGadgetButton(ToolbarView toolbar, final ParticipantId user) {
    new ToolbarButtonViewBuilder()
        .setIcon(css.insertGadget())
        .applyTo(toolbar.addClickButton(), new ToolbarClickButton.Listener() {
          @Override public void onClicked() {
            final FocusedRange focusedRange = editor.getSelectionHelper().getSelectionRange();
            GadgetSelectorWidget selector = new GadgetSelectorWidget(new GadgetInfoProviderImpl(new GwtGadgetInfoParser()));
            selector.addFeaturedOptions();
            final UniversalPopup popup = selector.showInPopup();
            selector.setListener(new GadgetSelectorWidget.Listener() {
              @Override public void onSelect(String url) {
                insertGadget(url, focusedRange);
                popup.hide();
              }
            });
          }
        });
  }

  private void insertGadget(String url, FocusedRange focusedRange) {
    int from = -1;
    if (focusedRange != null) {
      from = focusedRange.getFocus();
    }
    if (url != null && !url.isEmpty()) {
      XmlStringBuilder xml = GadgetXmlUtil.constructXml(url, "", user.getAddress());
      CMutableDocument document = editor.getDocument();
      if (document == null) {
        return;
      }
      if (from != -1) {
        Point<ContentNode> point = document.locate(from);
        document.insertXml(point, xml);
      } else {
        LineContainers.appendLine(document, xml);
      }
    }
  }

  private void createInsertAttachmentButton(ToolbarView toolbar, final ParticipantId user) {
    WaveRef waveRef = WaveRef.of(waveId);
    Preconditions.checkState(waveRef != null);
    final String waveRefToken = URL.encode(GwtWaverefEncoder.encodeToUriQueryString(waveRef));

    new ToolbarButtonViewBuilder().setIcon(css.insertAttachment()).setTooltip("Insert attachment")
        .applyTo(toolbar.addClickButton(), new ToolbarClickButton.Listener() {
          @Override
          public void onClicked() {
            int tmpCursor = -1;
            FocusedRange focusedRange = editor.getSelectionHelper().getSelectionRange();
            if (focusedRange != null) {
              tmpCursor = focusedRange.getFocus();
            }
            final int cursorLoc = tmpCursor;
            AttachmentPopupView attachmentView = new AttachmentPopupWidget();
            attachmentView.init(new Listener() {

              @Override
              public void onShow() {
              }

              @Override
              public void onHide() {
              }

              @Override
              public void onDone(String encodedWaveRef, String attachmentId, String fullFileName) {
                // Insert a file name linking to the attachment URL.
                int lastSlashPos = fullFileName.lastIndexOf("/");
                int lastBackSlashPos = fullFileName.lastIndexOf("\\");
                String fileName = fullFileName;
                if (lastSlashPos != -1) {
                  fileName = fullFileName.substring(lastSlashPos + 1, fullFileName.length());
                } else if (lastBackSlashPos != -1) {
                  fileName = fullFileName.substring(lastBackSlashPos + 1, fullFileName.length());
                }
                /*
                 * From UploadToolbarAction in Walkaround
                 * @author hearnden@google.com (David Hearnden)
                 */
                CMutableDocument doc = editor.getDocument();
                FocusedContentRange selection = editor.getSelectionHelper().getSelectionPoints();
                Point<ContentNode> point;
                if (selection != null) {
                  point = selection.getFocus();
                } else {
                  // Focus was probably lost.  Bring it back.
                  editor.focus(false);
                  selection = editor.getSelectionHelper().getSelectionPoints();
                  if (selection != null) {
                    point = selection.getFocus();
                  } else {
                    // Still no selection.  Oh well, put it at the end.
                    point = doc.locate(doc.size() - 1);
                  }
                }
                XmlStringBuilder content = ImageThumbnail.constructXml(attachmentId, fileName);
                ImageThumbnailWrapper thumbnail = ImageThumbnailWrapper.of(doc.insertXml(point, content));
                thumbnail.setAttachmentId(attachmentId);
              }
            });

            attachmentView.setAttachmentId(attachmentIdGenerator.newAttachmentId());
            attachmentView.setWaveRef(waveRefToken);
            attachmentView.show();
          }
        });
}

  private void createInsertLinkButton(ToolbarView toolbar) {
    // TODO (Yuri Z.) use createTextSelectionController when the full
    // link doodad is incorporated
    new ToolbarButtonViewBuilder()
        .setIcon(css.insertLink())
        .applyTo(toolbar.addClickButton(), new ToolbarClickButton.Listener() {
              @Override  public void onClicked() {
                LinkerHelper.onCreateLink(editor);
              }
            });
  }

  private void createRemoveLinkButton(ToolbarView toolbar) {
    new ToolbarButtonViewBuilder()
        .setIcon(css.removeLink())
        .applyTo(toolbar.addClickButton(), new ToolbarClickButton.Listener() {
          @Override public void onClicked() {
            LinkerHelper.onClearLink(editor);
          }
        });
  }

  private ToolbarClickButton.Listener createClearHeadingsListener() {
    return new ParagraphTraversalController(editor, new ContentElement.Action() {
        @Override public void execute(ContentElement e) {
          e.getMutableDoc().setElementAttribute(e, Paragraph.SUBTYPE_ATTR, null);
        }
      });
  }

  private void createHeadingButton(ToolbarView toolbar) {
    SubmenuToolbarView submenu = toolbar.addSubmenu();
    new ToolbarButtonViewBuilder()
        .setIcon(css.heading())
        .applyTo(submenu, null);
    submenu.setShowDropdownArrow(false); // Icon already has dropdown arrow.
    ToolbarClickButton defaultButton = submenu.addClickButton();
    new ToolbarButtonViewBuilder()
        .setText("Default")
        .applyTo(defaultButton, createClearHeadingsListener());
    ToolbarView group = submenu.addGroup();
    for (int level : asArray(1, 2, 3, 4)) {
      ToolbarToggleButton b = group.addToggleButton();
      b.setVisualElement(createHeadingElement(level));
      b.setListener(createParagraphApplicationController(b, Paragraph.regularStyle("h" + level)));
    }
  }

  private Element createHeadingElement(int level) {
    Element e = Document.get().createElement("h" + level);
    e.getStyle().setMarginTop(2, Unit.PX);
    e.getStyle().setMarginBottom(2, Unit.PX);
    e.setInnerText("Heading " + level);
    return e;
  }

  private void createIndentButton(ToolbarView toolbar) {
    ToolbarClickButton b = toolbar.addClickButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.indent())
        .applyTo(b, new ParagraphTraversalController(editor, Paragraph.INDENTER));
  }

  private void createOutdentButton(ToolbarView toolbar) {
    ToolbarClickButton b = toolbar.addClickButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.outdent())
        .applyTo(b, new ParagraphTraversalController(editor, Paragraph.OUTDENTER));
  }

  private void createUnorderedListButton(ToolbarView toolbar) {
    ToolbarToggleButton b = toolbar.addToggleButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.unorderedlist())
        .applyTo(b, createParagraphApplicationController(b, Paragraph.listStyle(null)));
  }

  private void createOrderedListButton(ToolbarView toolbar) {
    ToolbarToggleButton b = toolbar.addToggleButton();
    new ToolbarButtonViewBuilder()
        .setIcon(css.orderedlist())
        .applyTo(b, createParagraphApplicationController(
            b, Paragraph.listStyle(Paragraph.LIST_STYLE_DECIMAL)));
  }

  private void createAlignButtons(ToolbarView toolbar) {
    SubmenuToolbarView submenu = toolbar.addSubmenu();
    new ToolbarButtonViewBuilder()
        .setIcon(css.alignDrop())
        .applyTo(submenu, null);
    submenu.setShowDropdownArrow(false); // Icon already has dropdown arrow.
    ToolbarView group = submenu.addGroup();
    for (Alignment alignment : asArray(
        new Alignment("Left", css.alignLeft(), Paragraph.Alignment.LEFT),
        new Alignment("Centre", css.alignCentre(), Paragraph.Alignment.CENTER),
        new Alignment("Right", css.alignRight(), Paragraph.Alignment.RIGHT))) {
      ToolbarToggleButton b = group.addToggleButton();
      new ToolbarButtonViewBuilder()
          .setText(alignment.description)
          .setIcon(alignment.iconCss)
          .applyTo(b, createParagraphApplicationController(b, alignment.style));
    }
  }

  /**
   * Adds a button to this toolbar.
   */
  public void addClickButton(String icon, final ClickHandler handler) {
    ToolbarClickButton.Listener uiHandler = new ToolbarClickButton.Listener() {
      @Override
      public void onClicked() {
        handler.onClicked(editor);
      }
    };
    new ToolbarButtonViewBuilder().setIcon(icon).applyTo(toolbarUi.addClickButton(), uiHandler);
  }

  /**
   * Starts listening to editor changes.
   *
   * @throws IllegalStateException if this toolbar is already enabled
   * @throws IllegalArgumentException if the editor is <code>null</code>
   */
  public void enable(Editor editor) {
    this.editor.checkEditor(null);
    Preconditions.checkArgument(editor != null);
    this.editor.switchEditor(editor);
    editor.addUpdateListener(updater);
    updater.updateButtonStates();
  }

  /**
   * Stops listening to editor changes.
   *
   * @throws IllegalStateException if this toolbar is not currently enabled
   * @throws IllegalArgumentException if this toolbar is currently enabled for a
   *         different editor
   */
  public void disable(Editor editor) {
    this.editor.checkEditor(editor);
    // The above won't throw if we're not currently enabled, but it makes sure
    // 'editor' is the same as the current editor, if any. So if 'editor' is
    // null, it means we aren't enabled (the wrapped editor is null too).
    Preconditions.checkState(editor != null);
    editor.removeUpdateListener(updater);
    this.editor.switchEditor(null);
  }

  /**
   * @return the {@link ToplevelToolbarWidget} backing this toolbar.
   */
  public ToplevelToolbarWidget getWidget() {
    return toolbarUi;
  }

  private ToolbarToggleButton.Listener createParagraphApplicationController(ToolbarToggleButton b,
      LineStyle style) {
    return updater.add(new ParagraphApplicationController(b, editor, style));
  }

  private ToolbarToggleButton.Listener createTextSelectionController(ToolbarToggleButton b,
      String styleName, String value) {
    return updater.add(new TextSelectionController(b, editor,
        StyleAnnotationHandler.key(styleName), value));
  }

  @SuppressWarnings("unchecked")
  private static <E> E[] asArray(E... elements) {
    return elements;
  }
}
TOP

Related Classes of org.waveprotocol.wave.client.wavepanel.impl.toolbar.EditToolbar$FontFamily

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.