Package org.eclipse.sapphire.ui.swt.gef.contextbuttons

Source Code of org.eclipse.sapphire.ui.swt.gef.contextbuttons.ContextButton$PopupMenuLabelProvider

/******************************************************************************
* Copyright (c) 2014 SAP and Oracle
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    SAP - initial implementation
*    Shenxue Zhou - adaptation for Sapphire and ongoing maintenance
******************************************************************************/

package org.eclipse.sapphire.ui.swt.gef.contextbuttons;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.ActionEvent;
import org.eclipse.draw2d.ActionListener;
import org.eclipse.draw2d.Clickable;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseMotionListener;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.sapphire.ImageData;
import org.eclipse.sapphire.modeling.CapitalizationType;
import org.eclipse.sapphire.modeling.localization.LabelTransformer;
import org.eclipse.sapphire.ui.DefaultActionImage;
import org.eclipse.sapphire.ui.SapphireAction;
import org.eclipse.sapphire.ui.SapphireActionHandler;
import org.eclipse.sapphire.ui.forms.swt.SwtUtil;
import org.eclipse.sapphire.ui.swt.gef.SapphireDiagramEditor;
import org.eclipse.sapphire.ui.swt.gef.figures.FigureUtil;
import org.eclipse.sapphire.ui.swt.gef.parts.DiagramConnectionEditPart;
import org.eclipse.sapphire.ui.swt.gef.parts.DiagramNodeEditPart;
import org.eclipse.sapphire.ui.swt.gef.parts.SapphireDiagramEditorPageEditPart;
import org.eclipse.sapphire.ui.swt.gef.parts.ShapeEditPart;
import org.eclipse.sapphire.ui.swt.gef.presentation.DiagramPresentation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.widgets.Display;

/**
* A context button, which is used for example in the context button pad. It
* does not extend button, but is an implementation from scratch, because it has
* a quite specific look and behavior.
*
* @author SAP
* @author <a href="mailto:shenxue.zhou@oracle.com">Shenxue Zhou</a>
*/

public class ContextButton extends Clickable implements MouseMotionListener, ActionListener {
  private double getCurrentTransparency = 0;

  /**
   * The {@link PositionedContextButton} contains the visual information for
   * the context button (colors, position, size, opacity, ...). It is set in
   * the constructor.
   */
  private PositionedContextButton positionedContextButton;

  private SapphireAction sapphireAction;

  /**
   * The {@link ContextButtonPad} is used to access the environment (editor,
   * ...). It is set in the constructor.
   */
  private ContextButtonPad contextButtonPad;

  /**
   * The current opacity of the context button. It is changed for example on
   * mouse-events.
   */
  private double opacity;

  /**
   * The tooltip of the context button. It never changes, but it is sometimes
   * shortly disabled (e.g. on button-pressed).
   */
  private Tooltip tooltip;
 
  // ============================ inner classes =============================

  /**
   * The label provider for the popup-menu, which appears when the
   * context-button is clicked.
   */
  private class PopupMenuLabelProvider extends LabelProvider {
    @Override
    public String getText(Object element) {
      SapphireActionHandler handler  = (SapphireActionHandler) element;
      return getLabel(handler);
    }

    @Override
    public Image getImage(Object element) {
      SapphireActionHandler handler  = (SapphireActionHandler) element;
      return getActionHandlerImage(handler);
    }
  };

  // ============================ constructors ==============================

  /**
   * Creates a new ContextButton.
   *
   * @param positionedContextButton
   *            The {@link PositionedContextButton} contains the visual
   *            information for the context button (colors, position, size,
   *            opacity, ...).
   * @param contextButtonPad
   *            The {@link ContextButtonPad} is used to access the environment
   *            (editor, ...).
   */
  public ContextButton(PositionedContextButton positionedContextButton, ContextButtonPad contextButtonPad) {
    this.positionedContextButton = positionedContextButton;
    this.contextButtonPad = contextButtonPad;
    this.sapphireAction = positionedContextButton.getSapphireAction();

    setBorder(null); // get rid of default border
    setCurrentTransparency(contextButtonPad.getCurrentTransparency());
    setOpacity(getPositionedContextButton().getDefaultOpacity());

    String label = getLabel(getSapphireAction());
    if (label != null && label.length() > 0) {
      if (tooltip == null) {
        tooltip = new Tooltip();
      }     
      tooltip.setHeader(label);
    }
    String description = getToolTip(getSapphireAction());
    if (description != null && description.length() > 0 && !description.equalsIgnoreCase(label)) {
      if (tooltip == null) {
        tooltip = new Tooltip();
      }
      tooltip.setDescription(description);
    }
    setToolTip(tooltip);

    addMouseMotionListener(this);
    addActionListener(this);

    // disable the context button, if it is not executable.
    // Note, that this has to be done dependent on the context button functionality
    // (drag&drop, click with popup, single click)
    if (getSapphireAction().getActiveHandlers().size() > 1) {
      setEnabled(getExecutableMenuEntries().size() > 0);
    } else {
      setEnabled(getSapphireAction().isEnabled());
    }
  }

  // ========================= getter and setter ============================

  /**
   * Returns the {@link PositionedContextButton} which contains the visual
   * information for the context button (colors, position, size, opacity, ...)
   *
   * @return The {@link PositionedContextButton} which contains the visual
   *         information for the context button (colors, position, size,
   *         opacity, ...)
   */
  public final PositionedContextButton getPositionedContextButton() {
    return positionedContextButton;
  }

  public final SapphireAction getSapphireAction() {
    return sapphireAction;
  }

  /**
   * Returns the {@link ContextButtonPad} which is used to access the
   * environment (editor, ...).
   *
   * @return The {@link ContextButtonPad} which is used to access the
   *         environment (editor, ...).
   */
  public final ContextButtonPad getContextButtonPad() {
    return contextButtonPad;
  }

  /**
   * Returns the zoom-level for which the context-button shall be painted.
   *
   * @return The zoom-level for which the context-button shall be painted.
   */
  public final double getZoomLevel() {
    return getContextButtonPad().getZoomLevel();
  }

  /**
   * Returns the {@link DiagramEditorInternal} for which the context button is
   * displayed.
   *
   * @return The {@link DiagramEditorInternal} for which the context button is
   *         displayed.
   */
  public final SapphireDiagramEditor getEditor() {
    return getContextButtonPad().getEditor();
  }

  /**
   * Sets the opacity of this figure.
   *
   * @param opacity
   *            The opacity to set.
   */
  private void setOpacity(double opacity) {
    this.opacity = opacity;
  }

  /**
   * Returns the opacity adjusted by the current transparency. Concretely this
   * means "opacity * transparency".
   *
   * @return The opacity adjusted by the current transparency.
   */
  private double getAdjustedOpacity() {
    if (getCurrentTransparency() != 0) {
      return opacity * getCurrentTransparency();
    }

    return opacity;
  }

  // ============================== painting ================================

  /**
   * Paints the context button (lines, filling, image, ...).
   */
  @Override
  protected void paintFigure(Graphics graphics) {
    int lw = ((int) (getPositionedContextButton().getLineWidth() * getZoomLevel()));
    graphics.setLineWidth(lw);
    graphics.setAntialias(SWT.ON);
    graphics.setAlpha((int) (getAdjustedOpacity() * 255));

    Path pathOuterLine = createPath(1);
    Path pathMiddleLine = createPath(2);
    Path pathFill = createPath(3);

    graphics.setBackgroundColor(getAdjustedColor(getPositionedContextButton().getFillColor()));
    graphics.fillPath(pathFill);
    graphics.setForegroundColor(getAdjustedColor(getPositionedContextButton().getMiddleLineColor()));
    graphics.drawPath(pathMiddleLine);
    graphics.setForegroundColor(getAdjustedColor(getPositionedContextButton().getOuterLineColor()));
    graphics.drawPath(pathOuterLine);

    pathOuterLine.dispose();
    pathMiddleLine.dispose();
    pathFill.dispose();
    pathOuterLine = null;
    pathMiddleLine = null;
    pathFill = null;

    // change opacity for image (never transparent)
    double imageOpacity = 1;
    graphics.setAlpha((int) (imageOpacity * 255));

    // create image
    Image originalImage = getActionImage(getSapphireAction());
    if (originalImage == null) {
      return;
    }
   
    Image image;
    if (!isEnabled()) {
      image = new Image(originalImage.getDevice(), originalImage, SWT.IMAGE_DISABLE);
    } else {
      image = new Image(originalImage.getDevice(), originalImage, SWT.IMAGE_COPY);
    }

    // draw image
    org.eclipse.swt.graphics.Rectangle rect = image.getBounds();
    Rectangle newRect = new Rectangle(0, 0, rect.width, rect.height);
    newRect.scale(getZoomLevel());
    newRect.x = getBounds().x + ((getBounds().width - newRect.width) / 2);
    newRect.y = getBounds().y + ((getBounds().height - newRect.height) / 2);
    graphics.drawImage(image, rect.x, rect.y, rect.width, rect.height, newRect.x, newRect.y, newRect.width, newRect.height);
    image.dispose();

    // paint indicators
    List<SapphireActionHandler> menuEntries = getSapphireAction().getActiveHandlers();
    boolean isSubmenuButton = menuEntries != null && menuEntries.size() > 1;
    if (isSubmenuButton) {
      paintSubmenuIndicator(graphics, newRect);
    }

  }

  /**
   * Paints a sub-menu indicator on the context button (opens sub-menu on
   * click).
   */
  private void paintSubmenuIndicator(Graphics graphics, Rectangle newRect) {
    int x = newRect.x;
    int y = newRect.y;
    int w = newRect.width;
    int h = newRect.height;
    PointList pl = new PointList();
    pl.addPoint(x + w, y + h * 3 / 4);
    pl.addPoint(x + w, y + h);
    pl.addPoint(x + w * 3 / 4, y + h);

    preparePaintIndicator(graphics);
    graphics.drawPolygon(pl);
    graphics.fillPolygon(pl);
  }


  /**
   * Prepares the given graphics for painting an indicator (sets colors,
   * line-width, ...).
   */
  private void preparePaintIndicator(Graphics graphics) {
    graphics.setLineWidth(1);
    org.eclipse.sapphire.Color outerLineColor = getPositionedContextButton().getOuterLineColor();
    Color adjustedColor = getAdjustedColor(outerLineColor);
    graphics.setForegroundColor(adjustedColor);
    graphics.setBackgroundColor(adjustedColor);
  }

  /**
   * Returns the adjusted SWT color for the given IColorConstant. Note, that
   * this method also adjusts the color, in case that this figure is disabled.
   *
   * @param color
   *            The IColorConstant for which to return the SWT color.
   * @return The adjusted SWT color for the given IColorConstant.
   */
  private Color getAdjustedColor(org.eclipse.sapphire.Color color) {
    SapphireDiagramEditor editor = getContextButtonPad().getEditor();
    if (!isEnabled()) {
      int disabledAdjustment = 80;
      int r = Math.min(255, color.red() + disabledAdjustment);
      int g = Math.min(255, color.green() + disabledAdjustment);
      int b = Math.min(255, color.blue() + disabledAdjustment);
      color = new org.eclipse.sapphire.Color(r, g, b);
    }
    Color swtColor = editor.getResourceCache().getColor(color);
    return swtColor;
  }

  /**
   * Creates and returns the path, which defines the outer lines and filling
   * area of the context button.
   *
   * @param shrinkLines
   *            The number of lines, by which the path shall be shrinked. This
   *            allows to use this method to create the outer line, middle
   *            line and inner line of the context button.
   * @return The path, which defines the outer lines and filling area of the
   *         context button.
   */
  protected Path createPath(int shrinkLines) {
    double zoom = getZoomLevel();
    int lw = (int) (getPositionedContextButton().getLineWidth() * zoom);
    Rectangle r = FigureUtil.getAdjustedRectangle(getBounds(), 1.0, shrinkLines * lw);

    // adjust corner for the inner path (formula found by experimenting)
    double zoomedCorner = (getPositionedContextButton().getCornerRadius() * zoom);
    int corner = (int) Math.max(1, zoomedCorner - (((shrinkLines - 1) * lw) + zoomedCorner / 64));

    Path path = new Path(null);
    path.moveTo(r.x, r.y);
    path.addArc(r.x, r.y, corner, corner, 90, 90);
    path.addArc(r.x, r.y + r.height - corner, corner, corner, 180, 90);
    path.addArc(r.x + r.width - corner, r.y + r.height - corner, corner, corner, 270, 90);
    path.addArc(r.x + r.width - corner, r.y, corner, corner, 0, 90);
    path.close();

    return path;
  }

  // ============================== eventing ================================

  /**
   * Changes the opacity of the context button.
   */
  @Override
  public void handleMouseEntered(MouseEvent event) {
    setOpacity(getPositionedContextButton().getMouseOverOpacity());
    repaint();
    super.handleMouseEntered(event);

  }

  /**
   * Changes the opacity of the context button.
   */
  @Override
  public void handleMouseExited(MouseEvent event) {
    setOpacity(getPositionedContextButton().getDefaultOpacity());
    repaint();
    super.handleMouseExited(event);
  }

  /**
   * Changes the opacity of the context button.
   * <p>
   * Additionally it disables the tooltip. Especially in the middle of the
   * drag & drop procedure no tooltip shall appear.
   */
  @Override
  public void handleMousePressed(MouseEvent event) {
    // disable tooltip
    // This does not hide an already showing tooltip (which would be
    // preferred), but at least it prevents showing a tooltip after
    // mouse-pressed. This is especially important when dragging starts
    // after mouse-pressed.
    setToolTip(null);

    setOpacity(getPositionedContextButton().getMouseDownOpacity());
    repaint();
    super.handleMousePressed(event);
  }

  /**
   * Changes the opacity of the context button.
   * <p>
   * Additionally it enables the tooltip again.
   */
  @Override
  public void handleMouseReleased(MouseEvent event) {
    // enable tooltip, which was disabled on mouse-pressed
    setToolTip(tooltip);

    // still entered the button, so go back to mouse-over
    setOpacity(getPositionedContextButton().getMouseOverOpacity());
    repaint();
    super.handleMouseReleased(event);
  }

  /**
   * Creates a connection with the connection-tool when dragging the context
   * button.
   */
  public void mouseDragged(MouseEvent me) {
  }

  public void mouseEntered(MouseEvent me) {
  }

  public void mouseExited(MouseEvent me) {
  }

  public void mouseHover(MouseEvent me) {
  }

  public void mouseMoved(MouseEvent me) {
  }

  /**
   * Performs the command of the context button or opens a context-menu with a
   * selection of multiple commands to perform.
   */
  public void actionPerformed(ActionEvent event) {
    if (getSapphireAction().getActiveHandlers().size() > 1) {
      List<SapphireActionHandler> menuEntries = getExecutableMenuEntries();
      if (menuEntries.size() == 0) {
        return;
      }

      ILabelProvider labelProvider = new PopupMenuLabelProvider();
      PopupMenu popupMenu = new PopupMenu(menuEntries, labelProvider);

      boolean b = popupMenu.show(Display.getCurrent().getActiveShell());
      if (b) {
        SapphireActionHandler handler = (SapphireActionHandler)popupMenu.getResult();
        executeActionHandler(handler);
      }
    } else if (getSapphireAction().isEnabled()) {
      // has no ContextButtonMenuEntries -> execute ContextButton
      executeActionHandler(getSapphireAction().getFirstActiveHandler());
     
    }

    getEditor().getContextButtonManager().refresh();   
  }

  /**
   * Returns all action handlers, which are executable.
   *
   * @return All action handlers, which are executable.
   */
  private List<SapphireActionHandler> getExecutableMenuEntries() {
    // has ContextButtonMenuEntries -> create popup
    List<SapphireActionHandler> activeHandlers = getSapphireAction().getActiveHandlers();
    List<SapphireActionHandler> menuEntries = new ArrayList<SapphireActionHandler>();
    for (SapphireActionHandler handler : activeHandlers) {
      if (handler.isEnabled()) {
        menuEntries.add(handler);
      }
    }
    return menuEntries;
  }
 
  private Image getActionHandlerImage(SapphireActionHandler handler)
  {
      ImageData imageData = handler.getImage(16);
             
    if (imageData != null)
    {
      ImageDescriptor imageDescriptor = SwtUtil.toImageDescriptor(imageData);
      return imageDescriptor.createImage();
    }
    return DefaultActionImage.getDefaultActionImage();
  }

  private Image getActionImage(SapphireAction action)
  {   
    ImageData imageData = null;
    List<SapphireActionHandler> handlers = action.getActiveHandlers();
    if (handlers.size() == 1)
    {   
      imageData = action.getFirstActiveHandler().getImage(16);
    }
   
      if (imageData == null)
        imageData = action.getImage(16);
     
    if (imageData == null)
    {
      return DefaultActionImage.getDefaultActionImage();
    }
    else
    {
          ImageDescriptor imageDescriptor = SwtUtil.toImageDescriptor(imageData);
      return imageDescriptor.createImage();
    }   
  }
 
  private String getLabel(SapphireAction action)
  {
    String label = action.getLabel();
      label = LabelTransformer.transform( label, CapitalizationType.TITLE_STYLE, false );
      return label;   
  }
 
  private String getLabel(SapphireActionHandler handler)
  {
    String label = handler.getLabel();
      label = LabelTransformer.transform( label, CapitalizationType.TITLE_STYLE, false );
      return label;   
  }
 
  private String getToolTip(SapphireAction action)
  {
    String tooltip = null;
    List<SapphireActionHandler> handlers = action.getActiveHandlers();
    if (handlers.size() == 1)
    {
      tooltip = handlers.get(0).getToolTip();
    }
    if (tooltip == null)
    {
      tooltip = action.getToolTip();
    }
    if (tooltip != null)
    {
      tooltip = LabelTransformer.transform( tooltip, CapitalizationType.FIRST_WORD_ONLY, false );
    }
      return tooltip;   
  }
 
  private void executeActionHandler(SapphireActionHandler handler)
  {
    List<GraphicalEditPart> editParts = this.contextButtonPad.getEditParts();
    for (GraphicalEditPart editPart : editParts)
    {
      DiagramPresentation presentation;
      if( editPart instanceof SapphireDiagramEditorPageEditPart )
      {
        presentation = ((SapphireDiagramEditorPageEditPart)editPart).getPresentation();
      }
      else if( editPart instanceof DiagramNodeEditPart )
      {
        presentation = ((DiagramNodeEditPart)editPart).getPresentation();
      }
      else if (editPart instanceof ShapeEditPart)
      {
        presentation = ((ShapeEditPart)editPart).getShapePresentation();
      }
      else if( editPart instanceof DiagramConnectionEditPart )
      {
        presentation = ((DiagramConnectionEditPart)editPart).getPresentation();
      }
      else
      {
          throw new IllegalStateException();
      }
     
          handler.execute(presentation);
    }
  }

  public double getCurrentTransparency() {
    return getCurrentTransparency;
  }

  public void setCurrentTransparency(double getCurrentTransparency) {
    this.getCurrentTransparency = getCurrentTransparency;
  }
}
TOP

Related Classes of org.eclipse.sapphire.ui.swt.gef.contextbuttons.ContextButton$PopupMenuLabelProvider

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.