Package org.waveprotocol.wave.client.widget.menu

Source Code of org.waveprotocol.wave.client.widget.menu.PopupMenu$PopupMenuItem

/**
* 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.widget.menu;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.StyleInjector;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.CssResource.NotStrict;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;

import org.waveprotocol.wave.client.common.webdriver.DebugClassHelper;
import org.waveprotocol.wave.client.widget.popup.AlignedPopupPositioner;
import org.waveprotocol.wave.client.widget.popup.PopupChromeFactory;
import org.waveprotocol.wave.client.widget.popup.PopupEventListener;
import org.waveprotocol.wave.client.widget.popup.PopupFactory;
import org.waveprotocol.wave.client.widget.popup.RelativePopupPositioner;
import org.waveprotocol.wave.client.widget.popup.UniversalPopup;
import org.waveprotocol.wave.model.util.Pair;

/**
*
* Desktop version for rendering a vertical sub-menu.
* I don't like it any more than you do.
*/
public class PopupMenu implements Menu {
  interface Resources extends ClientBundle {
    /** CSS class names used by DesktopSubMenu. These are used in Menu.css */
    interface Css extends CssResource {
      String item();
      String disabled();
      String divider();
    }

    @Source("Menu.css")
    @NotStrict  // TODO(user): make Strict by including/inheriting "verticalSeparator"
    Css css();
  }

  /**
   * An implementation of {@code MenuItem} for a {@code PopupMenu}.
   *
   */
  private class PopupMenuItem extends Label implements MenuItem {
    /**
     * Whether the default state of the item is enabled or not.
     */
    private final boolean defaultEnabled;

    /**
     * Whether the item is enabled or not.
     */
    private boolean enabled;

    /**
     * The command to execute when clicked.
     */
    private Command command;

    /** Should clicking this menu item hide the popup? */
    private final boolean hide;

    /**
     * Constructs a {@PopupMenuItem}
     *
     * @param text The text label for the item.
     * @param cmd The command to run when the item is clicked.
     * @param isEnabled True if this menu item is enabled.
     * @param hide True if clicking this menu item should hide the popup.
     */
    public PopupMenuItem(String text, Command cmd, boolean isEnabled, boolean hide) {
      super(text);
      setStyleName(RESOURCES.css().item());
      setEnabled(isEnabled);
      defaultEnabled = isEnabled;
      command = cmd;
      this.hide = hide;
      if (isPreClicked) {
        // If this menu is pre-clicked it doesn't require a full click to select
        // an item, just a mouseup over the item.  If the user then does click the
        // item then that will also give a mouseup so this handler will deal with
        // that case as well.
        addMouseUpHandler(new MouseUpHandler() {
          @Override
          public void onMouseUp(MouseUpEvent event) {
            onClicked();
          }
        });
      } else {
        addClickHandler(new ClickHandler() {
          public void onClick(ClickEvent e) {
            onClicked();
          }
        });
      }
      // Ensure that clicking this menu item doesn't affect the current selection.
      addMouseDownHandler(PREVENT_DEFAULT_HANDLER);
    }

    private void onClicked() {
      if (enabled) {
        if (command != null) {
          command.execute();
        }
        if (hide) {
          popup.hide();
        }
      }
    }

    @Override
    public void setEnabled(boolean enabled) {
      if (!enabled) {
        addStyleName(RESOURCES.css().disabled());
      } else {
        removeStyleName(RESOURCES.css().disabled());
      }
      this.enabled = enabled;
    }

    @Override
    public void resetEnabled() {
      setEnabled(defaultEnabled);
    }

    @Override
    public final void setDebugClassTODORename(String debugClass) {
      DebugClassHelper.addDebugClass(this, debugClass);
    }

    /** Set the command to me executed when this menu item is clicked */
    public void setCommand(Command cmd) {
      command = cmd;
    }
  }

  /**
   * Mouse down handler that prevents the event's default action thereby, the
   * way it's used here, preventing mouse downs from affecting selection.
   */
  private static final MouseDownHandler PREVENT_DEFAULT_HANDLER = new MouseDownHandler() {
    @Override
    public void onMouseDown(MouseDownEvent event) {
      event.preventDefault();
    }
  };

  /** The singleton instance of our resources. */
  private static final Resources RESOURCES = GWT.create(Resources.class);
  public static final Resources.Css CSS = RESOURCES.css();

  /**
   * Inject the CSS once.
   */
  static {
    StyleInjector.inject(RESOURCES.css().getText());
  }

  /** The popup to use for this submenu */
  private final UniversalPopup popup;

  /**
   * True if the user has already clicked a mouse button and so just releasing the
   * mouse over an item should count as a click.
   */
  private final boolean isPreClicked;

  /**
   * Create a new PopupMenu
   *
   * @param relative The reference element for the positioner.
   * @param positioner The positioner to position the menu popup.
   */
  public PopupMenu(Element relative, RelativePopupPositioner positioner,
      boolean isPreClicked) {
    popup = PopupFactory.createPopup(relative, positioner,
        PopupChromeFactory.createPopupChrome(), true);
    this.isPreClicked = isPreClicked;
  }

  /**
   * Create a new PopupMenu
   *
   * @param relative The reference element for the positioner.
   * @param positioner The positioner to position the menu popup.
   */
  public PopupMenu(Element relative, RelativePopupPositioner positioner) {
    this(relative, positioner, false);
  }

  @Override
  public void addDivider() {
    Widget divider = new Label();
    divider.setStyleName(RESOURCES.css().divider());
    popup.add(divider);
  }

  @Override
  public Pair<Menu, MenuItem> createSubMenu(String title, boolean enabled) {
    PopupMenuItem item = addItem(title, null, enabled, false);
    final PopupMenu menu = new PopupMenu(item.getElement(), AlignedPopupPositioner.BELOW_RIGHT);
    item.setCommand(new Command() {
      @Override
      public void execute() {
        menu.show();
      }
    });
    return new Pair<Menu, MenuItem>(menu, item);
  }

  @Override
  public MenuItem addItem(String label, final Command cmd, boolean enabled) {
    return addItem(label, cmd, enabled, true);
  }

  private PopupMenuItem addItem(String label, final Command cmd, boolean enabled,
                                boolean hideOnClick) {
    PopupMenuItem item = new PopupMenuItem(label, cmd, enabled, hideOnClick);
    popup.add(item);
    return item;
  }

  /**
   * Removes an item previously added to the menu.
   *
   * @param item The item to remove.
   */
  public boolean removeItem(MenuItem item) {
    if (item instanceof PopupMenuItem) {
      PopupMenuItem popup = (PopupMenuItem) item;
      return this.popup.remove(popup);
    }
    return false;
  }

  /**
   * Hide the menu.
   */
  public void hide() {
    popup.hide();
  }

  /**
   * Show the menu.
   */
  public void show() {
    popup.show();
  }

  /**
   * Set the debugClassName (for Webdriver) on the popup window.
   * @param dcName debugClassName to set.
   */
  public void setDebugClass(String dcName) {
    popup.setDebugClass(dcName);
  }

  @Override
  public void clearItems() {
    popup.clear();
  }

  /**
   * Add a PopupEventListener to this menu.
   * @param listener The listener to add.
   */
  public void addPopupEventListener(PopupEventListener listener) {
    popup.addPopupEventListener(listener);
  }
  /**
   * Remove a PopupEventListener to this menu.
   * @param listener The listener to remove.
   */
  public void removePopupEventListener(PopupEventListener listener) {
    popup.removePopupEventListener(listener);
  }

  /**
   * Indicates that clicks inside the given widget should not be considered
   * 'outside' of the popup menu, for purposes of auto-hiding.
   *
   * @param w A widget.
   */
  public void associateWidget(Widget w) {
    popup.associateWidget(w);
  }
}
TOP

Related Classes of org.waveprotocol.wave.client.widget.menu.PopupMenu$PopupMenuItem

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.