/*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.bindings.keys.AbstractKeyFormatter#getKeyDelimiter()
   */
  protected String getKeyDelimiter() {
    // We must do the look up every time, as our locale might change.
    if (Util.isMac()) {
      return Util.translateString(
          RESOURCE_BUNDLE, CARBON_KEY_DELIMITER_KEY, Util.ZERO_LENGTH_STRING);
    }

    return Util.translateString(RESOURCE_BUNDLE, KEY_DELIMITER_KEY, KeyStroke.KEY_DELIMITER);
  }
  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.bindings.keys.AbstractKeyFormatter#getKeyStrokeDelimiter()
   */
  protected String getKeyStrokeDelimiter() {
    // We must do the look up every time, as our locale might change.
    if (Util.isWindows()) {
      return Util.translateString(
          RESOURCE_BUNDLE, WIN32_KEY_STROKE_DELIMITER_KEY, KeySequence.KEY_STROKE_DELIMITER);
    }

    return Util.translateString(
        RESOURCE_BUNDLE, KEY_STROKE_DELIMITER_KEY, KeySequence.KEY_STROKE_DELIMITER);
  }
예제 #3
0
  static {
    final IKeyLookup lookup = KeyLookupFactory.getDefault();
    ALT = new ModifierKey(lookup.getAlt());
    COMMAND = new ModifierKey(lookup.getCommand());
    CTRL = new ModifierKey(lookup.getCtrl());
    SHIFT = new ModifierKey(lookup.getShift());

    modifierKeysByName.put(ModifierKey.ALT.toString(), ModifierKey.ALT);
    modifierKeysByName.put(ModifierKey.COMMAND.toString(), ModifierKey.COMMAND);
    modifierKeysByName.put(ModifierKey.CTRL.toString(), ModifierKey.CTRL);
    modifierKeysByName.put(ModifierKey.SHIFT.toString(), ModifierKey.SHIFT);
    modifierKeysByName.put(M1_NAME, Util.isMac() ? ModifierKey.COMMAND : ModifierKey.CTRL);
    modifierKeysByName.put(M2_NAME, ModifierKey.SHIFT);
    modifierKeysByName.put(M3_NAME, ModifierKey.ALT);
    modifierKeysByName.put(M4_NAME, Util.isMac() ? ModifierKey.CTRL : ModifierKey.COMMAND);
  }
  /** Creates and returns the Window menu. */
  private MenuManager createWindowMenu() {
    MenuManager menu = new MenuManager(Messages.WindowMenuName, IWorkbenchActionConstants.M_WINDOW);

    addPerspectiveActions(menu);
    Separator sep = new Separator(IWorkbenchActionConstants.MB_ADDITIONS);
    sep.setVisible(!Util.isMac());
    menu.add(sep);

    // See the comment for quit in createFileMenu
    ActionContributionItem openPreferencesItem = new ActionContributionItem(openPreferencesAction);
    openPreferencesItem.setVisible(!Util.isMac());
    menu.add(openPreferencesItem);

    menu.add(ContributionItemFactory.OPEN_WINDOWS.create(getWindow()));
    return menu;
  }
예제 #5
0
 /**
  * Workaround a bug in 64 bit GTK linux that causes the active editor to steal paste insertions
  * from the omnibox and Glance find UI (dartbug.com/13693).
  */
 public static void addGTKPasteHack(final ISourceViewer viewer) {
   if (Util.isLinux()) {
     viewer
         .getTextWidget()
         .addVerifyListener(
             new VerifyListener() {
               @Override
               public void verifyText(VerifyEvent e) {
                 Control focusControl = Display.getDefault().getFocusControl();
                 // If the focus control is not our text we have no business handling insertions.
                 // Redirect to the rightful target
                 if (focusControl != viewer.getTextWidget()) {
                   if (focusControl instanceof Text) {
                     ((Text) focusControl).setText(e.text);
                     e.doit = false;
                   }
                   if (focusControl instanceof Combo) {
                     ((Combo) focusControl).setText(e.text);
                     e.doit = false;
                   }
                 }
               }
             });
   }
 }
  /** Creates and returns the File menu. */
  private MenuManager createFileMenu() {
    MenuManager menu = new MenuManager(Messages.FileMenuName, IWorkbenchActionConstants.M_FILE);
    menu.add(new GroupMarker(IWorkbenchActionConstants.FILE_START));

    ActionContributionItem newExecutableItem = new ActionContributionItem(newExecutableAction);
    menu.add(newExecutableItem);

    ActionContributionItem attachExecutableItem =
        new ActionContributionItem(attachExecutableAction);
    menu.add(attachExecutableItem);

    ActionContributionItem corefileItem = new ActionContributionItem(corefileAction);
    menu.add(corefileItem);

    menu.add(new Separator());

    // If we're on OS X we shouldn't show this command in the File menu. It
    // should be invisible to the user. However, we should not remove it -
    // the carbon UI code will do a search through our menu structure
    // looking for it when Cmd-Q is invoked (or Quit is chosen from the
    // application menu.
    ActionContributionItem quitItem = new ActionContributionItem(quitAction);
    quitItem.setVisible(!Util.isMac());
    menu.add(quitItem);
    menu.add(new GroupMarker(IWorkbenchActionConstants.FILE_END));
    return menu;
  }
  /** Creates and returns the Help menu. */
  private MenuManager createHelpMenu() {
    MenuManager menu = new MenuManager(Messages.HelpMenuName, IWorkbenchActionConstants.M_HELP);
    menu.add(new GroupMarker("group.intro.ext")); // $NON-NLS-1$
    menu.add(new GroupMarker("group.main")); // $NON-NLS-1$
    menu.add(helpContentsAction);
    menu.add(helpSearchAction);
    menu.add(dynamicHelpAction);
    menu.add(new GroupMarker("group.assist")); // $NON-NLS-1$
    // HELP_START should really be the first item, but it was after
    // quickStartAction and tipsAndTricksAction in 2.1.
    menu.add(new GroupMarker(IWorkbenchActionConstants.HELP_START));
    menu.add(new GroupMarker("group.main.ext")); // $NON-NLS-1$
    menu.add(new GroupMarker("group.tutorials")); // $NON-NLS-1$
    menu.add(new GroupMarker("group.tools")); // $NON-NLS-1$
    menu.add(new GroupMarker("group.updates")); // $NON-NLS-1$
    menu.add(new GroupMarker(IWorkbenchActionConstants.HELP_END));
    menu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
    // about should always be at the bottom
    menu.add(new Separator("group.about")); // $NON-NLS-1$

    ActionContributionItem aboutItem = new ActionContributionItem(aboutAction);
    aboutItem.setVisible(!Util.isMac());
    menu.add(aboutItem);
    menu.add(new GroupMarker("group.about.ext")); // $NON-NLS-1$
    return menu;
  }
  protected void fillMenuBar(IMenuManager menuBar) {
    MenuManager fileMenu = new MenuManager("&File", IWorkbenchActionConstants.M_FILE);
    MenuManager helpMenu = new MenuManager("&Help", IWorkbenchActionConstants.M_HELP);

    menuBar.add(fileMenu);
    // Add a group marker indicating where action set menus will appear.
    menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
    menuBar.add(helpMenu);
    helpMenu.add(helpContentsAction);

    // File Menu
    /* fileMenu.add(prefAction);
    fileMenu.add(new Separator());
    fileMenu.add(exitAction); */

    // Ajout sous la forme de ActionContributionItem pour pouvoir rendre les actions ensuite
    // invisibles, car elle sont dŽjˆ prŽsentes dans le menu Pomme du mac.
    ActionContributionItem preferencesActionItem = new ActionContributionItem(prefAction);
    fileMenu.add(preferencesActionItem);
    ActionContributionItem exitActionItem = new ActionContributionItem(exitAction);
    fileMenu.add(exitActionItem);

    if (Util.isMac()) {
      preferencesActionItem.setVisible(false);
      exitActionItem.setVisible(false);
    }
  }
예제 #9
0
  protected Control createControl(Composite parent, int style) {
    if (Util.isMac()) {
      return new Scale(parent, style);
    }

    int canvasStyle = SWT.NO_REDRAW_RESIZE | SWT.V_SCROLL | SWT.H_SCROLL | SWT.DOUBLE_BUFFERED;
    FigureCanvas fc = new SliderFigureCanvas(canvasStyle, parent);
    return fc;
  }
예제 #10
0
 public final void setText(final String text) {
   final State state = command.getCommand().getState(INamedHandleStateIds.NAME);
   if (state instanceof TextState) {
     final String currentValue = (String) state.getValue();
     if (!Util.equals(text, currentValue)) {
       state.setValue(text);
     }
   }
 }
  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.bindings.keys.AbstractKeyFormatter#sortModifierKeys(int)
   */
  protected int[] sortModifierKeys(final int modifierKeys) {
    final IKeyLookup lookup = KeyLookupFactory.getDefault();
    final int[] sortedKeys = new int[4];
    int index = 0;

    if (Util.isWindows()) {
      if ((modifierKeys & lookup.getCtrl()) != 0) {
        sortedKeys[index++] = lookup.getCtrl();
      }
      if ((modifierKeys & lookup.getAlt()) != 0) {
        sortedKeys[index++] = lookup.getAlt();
      }
      if ((modifierKeys & lookup.getShift()) != 0) {
        sortedKeys[index++] = lookup.getShift();
      }

    } else if (Util.isGtk() || Util.isMotif()) {
      if ((modifierKeys & lookup.getShift()) != 0) {
        sortedKeys[index++] = lookup.getShift();
      }
      if ((modifierKeys & lookup.getCtrl()) != 0) {
        sortedKeys[index++] = lookup.getCtrl();
      }
      if ((modifierKeys & lookup.getAlt()) != 0) {
        sortedKeys[index++] = lookup.getAlt();
      }

    } else if (Util.isMac()) {
      if ((modifierKeys & lookup.getShift()) != 0) {
        sortedKeys[index++] = lookup.getShift();
      }
      if ((modifierKeys & lookup.getCtrl()) != 0) {
        sortedKeys[index++] = lookup.getCtrl();
      }
      if ((modifierKeys & lookup.getAlt()) != 0) {
        sortedKeys[index++] = lookup.getAlt();
      }
      if ((modifierKeys & lookup.getCommand()) != 0) {
        sortedKeys[index++] = lookup.getCommand();
      }
    }

    return sortedKeys;
  }
  /**
   * Formats an individual key into a human readable format. This uses an internationalization
   * resource bundle to look up the key. This does the platform-specific formatting for Carbon.
   *
   * @param key The key to format.
   * @return The key formatted as a string; should not be <code>null</code>.
   */
  public final String format(final int key) {
    final IKeyLookup lookup = KeyLookupFactory.getDefault();
    final String name = lookup.formalNameLookup(key);

    // TODO consider platform-specific resource bundles
    if (Util.isMac()) {
      String formattedName = (String) CARBON_KEY_LOOK_UP.get(name);
      if (formattedName != null) {
        return formattedName;
      }
    }

    return super.format(key);
  }
/**
 * An {@link IControlContentAdapter} for SWT Combo controls. This is a convenience class for easily
 * creating a {@link ContentProposalAdapter} for combo fields.
 *
 * @since 3.2
 */
public class ComboContentAdapter implements IControlContentAdapter, IControlContentAdapter2 {

  /*
   * Set to <code>true</code> if we should compute the text
   * vertical bounds rather than just use the field size.
   * Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=164748
   * The corresponding SWT bug is
   * https://bugs.eclipse.org/bugs/show_bug.cgi?id=44072
   */
  private static final boolean COMPUTE_TEXT_USING_CLIENTAREA = !Util.isCarbon();

  @Override
  public String getControlContents(Control control) {
    return ((Combo) control).getText();
  }

  @Override
  public void setControlContents(Control control, String text, int cursorPosition) {
    ((Combo) control).setText(text);
    ((Combo) control).setSelection(new Point(cursorPosition, cursorPosition));
  }

  @Override
  public void insertControlContents(Control control, String text, int cursorPosition) {
    Combo combo = (Combo) control;
    String contents = combo.getText();
    Point selection = combo.getSelection();
    StringBuffer sb = new StringBuffer();
    sb.append(contents.substring(0, selection.x));
    sb.append(text);
    if (selection.y < contents.length()) {
      sb.append(contents.substring(selection.y, contents.length()));
    }
    combo.setText(sb.toString());
    selection.x = selection.x + cursorPosition;
    selection.y = selection.x;
    combo.setSelection(selection);
  }

  @Override
  public int getCursorPosition(Control control) {
    return ((Combo) control).getSelection().x;
  }

  @Override
  public Rectangle getInsertionBounds(Control control) {
    // This doesn't take horizontal scrolling into affect.
    // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=204599
    Combo combo = (Combo) control;
    int position = combo.getSelection().y;
    String contents = combo.getText();
    GC gc = new GC(combo);
    gc.setFont(combo.getFont());
    Point extent = gc.textExtent(contents.substring(0, Math.min(position, contents.length())));
    gc.dispose();
    if (COMPUTE_TEXT_USING_CLIENTAREA) {
      return new Rectangle(
          combo.getClientArea().x + extent.x,
          combo.getClientArea().y,
          1,
          combo.getClientArea().height);
    }
    return new Rectangle(extent.x, 0, 1, combo.getSize().y);
  }

  @Override
  public void setCursorPosition(Control control, int index) {
    ((Combo) control).setSelection(new Point(index, index));
  }

  /**
   * @see
   *     org.eclipse.jface.fieldassist.IControlContentAdapter2#getSelection(org.eclipse.swt.widgets.Control)
   * @since 3.4
   */
  @Override
  public Point getSelection(Control control) {
    return ((Combo) control).getSelection();
  }

  /**
   * @see
   *     org.eclipse.jface.fieldassist.IControlContentAdapter2#setSelection(org.eclipse.swt.widgets.Control,
   *     org.eclipse.swt.graphics.Point)
   * @since 3.4
   */
  @Override
  public void setSelection(Control control, Point range) {
    ((Combo) control).setSelection(range);
  }
}
/*
 * The Class JDReportOutlineView.
 */
public class JDReportOutlineView extends ContentOutlinePage implements IAdaptable {

  /** The editor. */
  protected IGraphicalEditor editor;

  /** The page book. */
  private PageBook pageBook;

  /** The outline. */
  private Control outline;

  /** The overview. */
  private Canvas overview;

  /** The show overview action. */
  private IAction showOutlineAction, showOverviewAction;

  /** The Constant ID_OUTLINE. */
  public static final String ID_ACTION_OUTLINE = "showOutlineAction";

  /** The Constant ID_OVERVIEW. */
  public static final String ID_ACTION_OVERVIEW = "showOverviewAction";

  /** The thumbnail. */
  private JSSScrollableThumbnail thumbnail;

  /** The dispose listener. */
  private DisposeListener disposeListener;

  private Point mousePosition = new Point(-1, -1);

  /**
   * On linux the click event on the arrow to expand a tree node is not catched if the tree element
   * hasen't the focus. So we need a trick to have here the same behavior of the others operative
   * systems
   */
  private boolean enableFocusFix = Util.isLinux();

  /**
   * Instantiates a new jD report outline view.
   *
   * @param editor the editor
   * @param viewer the viewer
   */
  public JDReportOutlineView(IGraphicalEditor editor, EditPartViewer viewer) {
    super(viewer);
    this.editor = editor;
  }

  public IGraphicalEditor getEditor() {
    return editor;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.part.Page#init(org.eclipse.ui.part.IPageSite)
   */
  @Override
  public void init(IPageSite pageSite) {
    super.init(pageSite);
    ActionRegistry registry = editor.getActionRegistry();
    IActionBars bars = pageSite.getActionBars();
    for (Iterator<IAction> it = registry.getActions(); it.hasNext(); ) {
      IAction ia = it.next();
      bars.setGlobalActionHandler(ia.getId(), ia);
    }

    bars.updateActionBars();
  }

  protected void initActions(ActionRegistry registry, IActionBars bars) {}

  protected ContextMenuProvider getMenuContentProvider() {
    return new AppContextMenuProvider(getViewer(), editor.getActionRegistry());
  }

  /**
   * Check if the outline page was closed. When the outline page is closed the control inside the
   * viewer is disposed and removed (so this method will always catch the getViewer().getControl()
   * == null when the outline was closed).
   *
   * @return true if the outline was closed and its control disposed. False otherwise
   */
  public boolean isDisposed() {
    return (getViewer() == null
        || getViewer().getControl() == null
        || getViewer().getControl().isDisposed());
  }

  /** Configure outline viewer. */
  protected void configureOutlineViewer() {
    final EditPartViewer viewer = getViewer();
    viewer.setEditDomain(editor.getEditDomain());
    viewer.setEditPartFactory(getEditPartFactory());
    ContextMenuProvider provider = getMenuContentProvider();
    viewer.setContextMenu(provider);

    viewer.addDropTargetListener(new JSSTemplateTransferDropTargetListener(viewer));
    viewer.addDragSourceListener(
        new TemplateTransferDragSourceListener(viewer) {
          @Override
          protected Object getTemplate() {
            List<Object> models = new ArrayList<Object>();
            Object obj = super.getTemplate();
            if (obj == null) {
              List<?> selection = getViewer().getSelectedEditParts();
              for (Object it : selection) {
                if (it instanceof EditPart) {
                  Object model = ((EditPart) it).getModel();
                  if (model instanceof IDragable) {
                    models.add(model);
                  }
                  if (model instanceof MBand) {
                    BandTypeEnum bandType = ((MBand) model).getBandType();
                    if (BandTypeEnum.DETAIL.equals(bandType)
                        || BandTypeEnum.GROUP_FOOTER.equals(bandType)
                        || BandTypeEnum.GROUP_HEADER.equals(bandType)) {
                      models.add(model);
                    }
                  }
                }
              }
            }
            return models;
          }
        });
    // Add images drop listeners
    viewer.addDropTargetListener(
        new ImageResourceDropTargetListener(viewer, ResourceTransfer.getInstance()));
    viewer.addDropTargetListener(
        new ImageResourceDropTargetListener(viewer, FileTransfer.getInstance()));
    viewer.addDropTargetListener(
        new ImageResourceDropTargetListener(viewer, ImageURLTransfer.getInstance()));

    IPageSite site = getSite();
    site.registerContextMenu(provider.getId(), provider, site.getSelectionProvider());

    IToolBarManager tbm = site.getActionBars().getToolBarManager();
    registerToolbarAction(tbm);

    showPage(ID_ACTION_OUTLINE);
  }

  /**
   * Create on the table manger the toolbar actions for the outline. The actions are created only if
   * the toolbar manager dosen't contains them already. Actually the added action are the one the
   * show the standard outline and the one to show the thumbnail of the report.
   *
   * @param tbm the toolbar manager for the outline.
   */
  public void registerToolbarAction(IToolBarManager tbm) {
    IContributionItem items[] = tbm.getItems();
    HashSet<String> existingItems = new HashSet<String>();
    for (IContributionItem item : items) {
      existingItems.add(item.getId());
    }

    showOutlineAction =
        new Action() {
          @Override
          public void run() {
            showPage(ID_ACTION_OUTLINE);
          }
        };
    showOutlineAction.setId(ID_ACTION_OUTLINE);
    showOutlineAction.setImageDescriptor(
        JaspersoftStudioPlugin.getInstance()
            .getImageDescriptor("icons/outline.gif")); // $NON-NLS-1$
    showOutlineAction.setToolTipText(Messages.JDReportOutlineView_show_outline_tool_tip);
    if (!existingItems.contains(ID_ACTION_OUTLINE)) {
      ActionContributionItem showOutlineItem = new ActionContributionItem(showOutlineAction);
      showOutlineItem.setVisible(true);
      tbm.add(showOutlineItem);
    }

    showOverviewAction =
        new Action() {
          @Override
          public void run() {
            showPage(ID_ACTION_OVERVIEW);
          }
        };
    showOverviewAction.setId(ID_ACTION_OVERVIEW);
    showOverviewAction.setImageDescriptor(
        JaspersoftStudioPlugin.getInstance()
            .getImageDescriptor("icons/overview.gif")); // $NON-NLS-1$
    showOverviewAction.setToolTipText(Messages.JDReportOutlineView_show_overview_tool_tip);
    if (!existingItems.contains(ID_ACTION_OVERVIEW)) {
      ActionContributionItem showOverviewItem = new ActionContributionItem(showOverviewAction);
      showOverviewItem.setVisible(true);
      tbm.add(showOverviewItem);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.ui.parts.ContentOutlinePage#createControl(org.eclipse.swt.widgets.Composite)
   */
  @Override
  public void createControl(Composite parent) {
    pageBook = new PageBook(parent, SWT.NONE);

    outline = getViewer().createControl(pageBook);

    PlatformUI.getWorkbench()
        .getHelpSystem()
        .setHelp(outline, "com.jaspersoft.studio.doc.view_outline");

    overview = new Canvas(pageBook, SWT.NONE);
    pageBook.showPage(outline);
    configureOutlineViewer();
    hookOutlineViewer();
    setContents(editor.getModel());
    if (outline instanceof Tree) {
      final Tree tree = (Tree) outline;

      tree.addFocusListener(
          new FocusListener() {

            @Override
            public void focusLost(FocusEvent e) {
              mousePosition.setLocation(-1, -1);
            }

            @Override
            public void focusGained(FocusEvent e) {
              if (enableFocusFix && mousePosition.x != -1) {
                EditPart part = getViewer().findObjectAt(mousePosition);
                if (part != null && part.getModel() instanceof MRoot) {
                  EditPart translatedPart =
                      getViewer().findObjectAt(new Point(mousePosition.x + 10, mousePosition.y));
                  if (translatedPart != null && translatedPart.getModel() != part.getModel()) {
                    TreeItem item = (TreeItem) ((TreeEditPart) translatedPart).getWidget();
                    item.setExpanded(!item.getExpanded());
                    tree.deselectAll();
                    tree.select(item);
                    tree.layout(true);
                  }
                }
              }
            }
          });

      tree.addMouseListener(
          new MouseListener() {

            public void mouseUp(MouseEvent e) {}

            public void mouseDown(MouseEvent e) {}

            public void mouseDoubleClick(MouseEvent e) {
              if (e.getSource() instanceof Tree) {
                Tree t = (Tree) e.getSource();
                TreeItem[] ti = t.getSelection();
                if (ti != null && ti.length > 0) {
                  Object obj = ti[0].getData();
                  if (obj instanceof TreeEditPart && editor instanceof AbstractVisualEditor) {

                    EditPart part =
                        (EditPart)
                            ((AbstractVisualEditor) editor)
                                .getGraphicalViewer()
                                .getEditPartRegistry()
                                .get(((TreeEditPart) obj).getModel());
                    if (part != null) {
                      SelectionRequest request = new SelectionRequest();
                      request.setType(RequestConstants.REQ_OPEN);
                      part.performRequest(request);
                    } else {
                      TreeEditPart atep = (TreeEditPart) obj;
                      if (atep.getModel() instanceof ANode) {
                        EditableFigureEditPart.openEditor(
                            ((ANode) atep.getModel()).getValue(),
                            (IEditorPart) editor,
                            (ANode) atep.getModel());
                      }
                    }
                  }
                }
              }
            }
          });

      // This listener display the tooltip text for the abbreviated nodes names
      tree.addMouseMoveListener(
          new MouseMoveListener() {

            public void mouseMove(MouseEvent e) {
              mousePosition.setLocation(e.x, e.y);
              EditPart part = getViewer().findObjectAt(new Point(e.x, e.y));
              Tree t = (Tree) e.getSource();
              if (part != null && part.getModel() != null && !(part.getModel() instanceof MRoot)) {
                Object model = part.getModel();
                String toolTipText = Misc.nvl(((ANode) model).getToolTip());
                String displayText = Misc.nvl(((ANode) model).getDisplayText());
                String text = "";
                if (!toolTipText.isEmpty() && !toolTipText.equals(displayText))
                  text = toolTipText + "\n";
                text += displayText;
                t.setToolTipText(text);
                return;
              }
              t.setToolTipText(null);
            }
          });
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.part.Page#dispose()
   */
  @Override
  public void dispose() {
    unhookOutlineViewer();
    if (thumbnail != null) thumbnail = null;
    super.dispose();
  }

  private EditorContributor editorContributor;

  private EditPartFactory editPartFactory;

  public EditPartFactory getEditPartFactory() {
    if (editPartFactory == null) editPartFactory = new OutlineTreeEditPartFactory();
    return editPartFactory;
  }

  public void setEditPartFactory(EditPartFactory editPartFactory) {
    this.editPartFactory = editPartFactory;
    getViewer().setEditPartFactory(getEditPartFactory());
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
   */
  public Object getAdapter(@SuppressWarnings("rawtypes") Class type) {
    if (type == ZoomManager.class)
      return editor.getGraphicalViewer().getProperty(ZoomManager.class.toString());
    if (type == EditorContributor.class) {
      if (editorContributor == null)
        editorContributor = new EditorContributor(editor.getEditDomain());
      return editorContributor;
    }
    return null;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.ui.parts.ContentOutlinePage#getControl()
   */
  @Override
  public Control getControl() {
    return pageBook;
  }

  /** Hook outline viewer. */
  protected void hookOutlineViewer() {
    editor.getSelectionSynchronizer().addViewer(getViewer());
  }

  /** Initialize overview. */
  protected void initializeOverview() {
    LightweightSystem lws = new J2DLightweightSystem(overview);

    RootEditPart rep = editor.getGraphicalViewer().getRootEditPart();
    if (rep instanceof MainDesignerRootEditPart) {
      ScalableFreeformRootEditPart root = (ScalableFreeformRootEditPart) rep;
      thumbnail =
          new JSSScrollableThumbnail(
              (Viewport) root.getFigure(), (MRoot) getViewer().getContents().getModel());
      thumbnail.setSource(root.getLayer(LayerConstants.PRINTABLE_LAYERS));
      lws.setContents(thumbnail);
      disposeListener =
          new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
              if (thumbnail != null) {
                thumbnail.deactivate();
                thumbnail = null;
              }
            }
          };
      editor.getEditor().addDisposeListener(disposeListener);
    }
    lws.setControl(overview);
  }

  /**
   * Sets the contents.
   *
   * @param contents the new contents
   */
  public void setContents(Object contents) {
    if (getViewer().getEditPartFactory() != null) {
      getViewer().setContents(contents);
    }
    if (outline instanceof Tree) {
      Tree tree = (Tree) outline;
      if (!tree.isDisposed() && tree.getItems() != null && tree.getItems().length > 0)
        tree.getItem(0).setExpanded(true);
    }
  }

  /**
   * Show page.
   *
   * @param id the id
   */
  protected void showPage(String id) {
    if (ID_ACTION_OUTLINE.equals(id)) {
      showOutlineAction.setChecked(true);
      showOverviewAction.setChecked(false);
      pageBook.showPage(outline);
      if (thumbnail != null) thumbnail.setVisible(false);
    } else if (ID_ACTION_OVERVIEW.equals(id)) {
      if (thumbnail == null) initializeOverview();
      showOutlineAction.setChecked(false);
      showOverviewAction.setChecked(true);
      pageBook.showPage(overview);
      thumbnail.setVisible(true);
    }
  }

  /** Unhook outline viewer. */
  protected void unhookOutlineViewer() {
    editor.getSelectionSynchronizer().removeViewer(getViewer());
    FigureCanvas editor2 = editor.getEditor();
    if (disposeListener != null && editor2 != null && !editor2.isDisposed())
      editor2.removeDisposeListener(disposeListener);
  }

  public void setTreeSelection(ISelection s) {
    if (s != null && s instanceof StructuredSelection && outline instanceof Tree) {
      StructuredSelection sel = (StructuredSelection) s;
      List<?> sobj = sel.toList();
      List<TreeItem> toSelect = new ArrayList<TreeItem>();
      Tree tree = (Tree) outline;
      tree.getItemCount();
      checkItems(tree.getItems(), toSelect, sobj);
      if (!toSelect.isEmpty()) tree.setSelection(toSelect.toArray(new TreeItem[toSelect.size()]));
    } else setSelection(s);
  }

  public void checkItems(TreeItem[] items, List<TreeItem> toSelect, List<?> sobj) {
    if (items == null) return;
    for (TreeItem ti : items) {
      for (Object obj : sobj) {
        if (obj != null && ti.getData() != null) {
          if (obj == ti.getData()) toSelect.add(ti);
          else if (obj instanceof EditPart && ti.getData() instanceof EditPart) {
            if (((EditPart) obj).getModel() == ((EditPart) ti.getData()).getModel())
              toSelect.add(ti);
          }
        }
      }
      checkItems(ti.getItems(), toSelect, sobj);
    }
  }
}
예제 #15
0
 private boolean isCopyMove() {
   if (Util.isMac()) return getStatus().isStatus(GEF.ST_ALT_PRESSED);
   return getStatus().isStatus(GEF.ST_CONTROL_PRESSED);
 }
예제 #16
0
파일: MButton.java 프로젝트: koson/xmind3
public class MButton extends Viewer {

  /** Style bit: Create control with default behaviours, i.e. showing text, showing image. */
  public static final int NORMAL = 0;

  /** Style bit: Don't show text. */
  public static final int NO_TEXT = 1;

  /** Style bit: Don't show image. */
  public static final int NO_IMAGE = 1 << 1;

  /** Style bit: Don't show spinner arrows. */
  public static final int NO_ARROWS = 1 << 2;

  private static final boolean DRAWS_FOCUS = Util.isMac();

  protected static final int MARGIN = DRAWS_FOCUS ? 4 : 1;
  protected static final int CORNER_SIZE = 5;
  protected static final int BORDER = (CORNER_SIZE + 1) / 2;
  protected static final int FOCUS_CORNER_SIZE = CORNER_SIZE - 2;
  protected static final int FOCUS_BORDER = (FOCUS_CORNER_SIZE + 1) / 2;
  protected static final int IMAGE_TEXT_SPACING = 3;
  protected static final int CONTENT_ARROW_SPACING = 4;
  protected static final int ARROW_WIDTH = 7;
  protected static final int ARROW_HEIGHT = 4;
  protected static final int ARROWS_SPACING = 2;
  protected static final String ELLIPSIS = "..."; // $NON-NLS-1$

  private Composite control;

  private int style;

  private String text = null;

  private Image image = null;

  private Color textForeground = null;

  private Color textBackground = null;

  private boolean hovered = false;

  private boolean pressed = false;

  private boolean forceFocus = false;

  private Point textSize = null;

  private Point imageSize = null;

  private List<IOpenListener> openListeners = null;

  /*
   * Caches:
   */
  private Point cachedTextSize = null;
  private Point cachedImageSize = null;
  private String appliedText = null;
  private Rectangle bounds = null;
  private Rectangle contentArea = null;
  private Point arrowLoc = null;
  private Rectangle imgArea = null;
  private Rectangle textArea = null;

  /**
   * Constructs a new instance of this class given its parent and a style value describing its
   * behavior and appearance.
   *
   * @param parent a composite control which will be the parent of the new instance (cannot be null)
   * @param style the style of control to construct
   * @see #NORMAL
   * @see #NO_TEXT
   * @see #NO_IMAGE
   * @see #NO_ARROWS
   */
  public MButton(Composite parent, int style) {
    this.style =
        checkStyle(style, NORMAL, NORMAL, NO_TEXT, NO_IMAGE)
            | checkStyle(style, SWT.NONE, NO_ARROWS);
    this.control =
        new Canvas(parent, SWT.DOUBLE_BUFFERED) {
          public Point computeSize(int wHint, int hHint, boolean changed) {
            checkWidget();
            if (changed) clearCaches();
            Point imageSize = getImageSize();
            Point textSize = getTextSize();
            boolean hasArrows = hasArrows();

            int width;
            if (wHint != SWT.DEFAULT) {
              width = Math.max(wHint, MARGIN * 2);
            } else {
              width = MARGIN * 2 + imageSize.x + textSize.x + BORDER * 2;
              if (hasArrows) {
                width += ARROW_WIDTH + CONTENT_ARROW_SPACING;
              }
              if (imageSize.x != 0 && textSize.x != 0) {
                width += IMAGE_TEXT_SPACING;
              }
              //                    if (hasArrows && (imageSize.x != 0 || textSize.x != 0)) {
              //                        width += CONTENT_ARROW_SPACING;
              //                    }
            }

            int minHeight = MARGIN * 2 + Math.max(imageSize.y, textSize.y) + BORDER * 2;
            if (hasArrows) {
              minHeight = Math.max(minHeight, ARROW_HEIGHT * 2 + ARROWS_SPACING);
            }
            int height = minHeight;
            Rectangle trim = computeTrim(0, 0, width, height);
            return new Point(trim.width, trim.height);
          }
        };
    hookControl(control);
  }

  protected void hookControl(Control control) {
    Listener listener =
        new Listener() {
          public void handleEvent(Event event) {
            switch (event.type) {
              case SWT.Paint:
                paint(event.gc, event.display);
                break;
              case SWT.Resize:
                clearCaches();
                break;
              case SWT.MouseDown:
                if (event.button == 1) handleMousePress();
                break;
              case SWT.MouseUp:
                if (event.button == 1) handleMouseRelease();
                break;
              case SWT.MouseEnter:
                handleMouseEnter();
                break;
              case SWT.MouseExit:
                handleMouseExit();
                break;
              case SWT.KeyDown:
                handleKeyPress(event);
                break;
              case SWT.FocusIn:
                handleFocusIn();
                break;
              case SWT.FocusOut:
                handleFocusOut();
            }
          }
        };
    control.addListener(SWT.Paint, listener);
    control.addListener(SWT.Resize, listener);
    control.addListener(SWT.MouseDown, listener);
    control.addListener(SWT.MouseUp, listener);
    control.addListener(SWT.MouseEnter, listener);
    control.addListener(SWT.MouseExit, listener);
    control.addListener(SWT.KeyDown, listener);
    control.addListener(SWT.FocusIn, listener);
    control.addListener(SWT.FocusOut, listener);
  }

  protected void handleMousePress() {
    if (!getControl().isEnabled()) return;
    setHovered(true);
    setPressed(true);
    getControl().setFocus();
    fireOpen();
  }

  protected void handleMouseRelease() {
    if (!getControl().isEnabled()) return;
    setPressed(false);
  }

  protected void handleMouseEnter() {
    if (!getControl().isEnabled()) return;
    setHovered(true);
  }

  protected void handleMouseExit() {
    if (!getControl().isEnabled()) return;
    setHovered(false);
  }

  protected void handleFocusIn() {
    if (!getControl().isEnabled()) return;
    refreshControl();
  }

  protected void handleFocusOut() {
    if (!getControl().isEnabled()) return;
    setPressed(false);
    refreshControl();
  }

  protected void handleKeyPress(Event e) {
    if (!getControl().isEnabled()) return;

    int keyCode = e.keyCode;
    int stateMask = e.stateMask;
    if (SWTUtils.matchKeyCode(keyCode, SWT.TAB)) {
      if (SWTUtils.matchState(stateMask, SWT.SHIFT)) {
        getControl().traverse(SWT.TRAVERSE_TAB_PREVIOUS);
      } else if (SWTUtils.matchState(stateMask, 0)) {
        getControl().traverse(SWT.TRAVERSE_TAB_NEXT);
      }
    } else if (SWTUtils.matchKey(stateMask, keyCode, 0, SWT.CR)) {
      fireOpen();
    }
  }

  public void addOpenListener(IOpenListener listener) {
    if (openListeners == null) openListeners = new ArrayList<IOpenListener>();
    openListeners.add(listener);
  }

  public void removeOpenListener(IOpenListener listener) {
    if (openListeners == null) return;
    openListeners.remove(listener);
  }

  protected void fireOpen(final OpenEvent event) {
    if (openListeners == null) return;
    for (final Object l : openListeners.toArray()) {
      SafeRunner.run(
          new SafeRunnable() {
            public void run() throws Exception {
              ((IOpenListener) l).open(event);
            }
          });
    }
  }

  protected void fireOpen() {
    fireOpen(new OpenEvent(this, getSelection()));
  }

  public Control getControl() {
    return control;
  }

  protected int getStyle() {
    return style;
  }

  public String getText() {
    return text;
  }

  public Image getImage() {
    return image;
  }

  public boolean hasText() {
    return text != null && (style & NO_TEXT) == 0;
  }

  public boolean hasImage() {
    return image != null && (style & NO_IMAGE) == 0;
  }

  protected boolean hasArrows() {
    return (style & NO_ARROWS) == 0;
  }

  public Color getTextForeground() {
    return textForeground;
  }

  public Color getTextBackground() {
    return textBackground;
  }

  public void setTextForeground(Color c) {
    if (c == this.textForeground || (c != null && c.equals(this.textForeground))) return;
    this.textForeground = c;
    refreshControl();
  }

  public void setTextBackground(Color c) {
    if (c == this.textBackground || (c != null && c.equals(this.textBackground))) return;
    this.textBackground = c;
    refreshControl();
  }

  public boolean isHovered() {
    return hovered;
  }

  public boolean isPressed() {
    return pressed;
  }

  public boolean isForceFocus() {
    return forceFocus;
  }

  public void setHovered(boolean hovered) {
    if (hovered == this.hovered) return;
    this.hovered = hovered;
    refreshControl();
  }

  public void setPressed(boolean pressed) {
    if (pressed == this.pressed) return;
    this.pressed = pressed;
    refreshControl();
  }

  public void setForceFocus(boolean focused) {
    if (focused == this.forceFocus) return;
    this.forceFocus = focused;
    refreshControl();
  }

  public void setText(String text) {
    if (text == this.text || (text != null && text.equals(this.text))) return;
    this.text = text;
    cachedTextSize = null;
    clearCaches();
    refreshControl();
  }

  public void setImage(Image image) {
    if (image == this.image) return;
    this.image = image;
    cachedImageSize = null;
    clearCaches();
    refreshControl();
  }

  public Point getTextSize() {
    if (textSize != null) return textSize;
    if (cachedTextSize == null) {
      cachedTextSize = calcTextSize();
    }
    return cachedTextSize;
  }

  public Point getImageSize() {
    if (imageSize != null) return imageSize;
    if (cachedImageSize == null) {
      cachedImageSize = calcImageSize();
    }
    return cachedImageSize;
  }

  public void setTextSize(Point size) {
    if (size == this.textSize || (size != null && size.equals(this.textSize))) return;
    this.textSize = size;
    cachedTextSize = null;
    refreshControl();
  }

  public void setImageSize(Point size) {
    if (size == this.imageSize || (size != null && size.equals(this.imageSize))) return;
    this.imageSize = size;
    cachedImageSize = null;
    refreshControl();
  }

  protected Point calcTextSize() {
    String string = getText();
    if (!hasText()) {
      if ((style & NO_TEXT) != 0) return new Point(0, 0);
      string = "X"; // $NON-NLS-1$
    }
    Point size;
    GC gc = new GC(getControl().getDisplay());
    try {
      gc.setFont(getControl().getFont());
      size = gc.stringExtent(string);
    } finally {
      gc.dispose();
    }
    if (size.x == 0 && hasText()) size.x = 5;
    return size;
  }

  protected Point calcImageSize() {
    Point size = new Point(0, 0);
    if (hasImage()) {
      Rectangle bounds = image.getBounds();
      size.x = Math.max(size.x, bounds.width);
      size.y = Math.max(size.y, bounds.height);
    }
    return size;
  }

  public void setEnabled(boolean enabled) {
    getControl().setEnabled(enabled);
    refreshControl();
  }

  public boolean isEnabled() {
    return getControl().isEnabled();
  }

  public String getAppliedText() {
    if (appliedText == null) {
      buildCaches();
    }
    return appliedText;
  }

  protected void clearCaches() {
    appliedText = null;
    bounds = null;
    contentArea = null;
    arrowLoc = null;
    imgArea = null;
    textArea = null;
  }

  protected void buildCaches() {
    bounds = control.getClientArea();
    bounds.x += MARGIN;
    bounds.y += MARGIN;
    bounds.width -= MARGIN * 2;
    bounds.height -= MARGIN * 2;
    int x1 = bounds.x + BORDER;
    int y1 = bounds.y + BORDER;
    int w1 = bounds.width - BORDER * 2;
    int h1 = bounds.height - BORDER * 2;
    boolean hasArrows = hasArrows();

    if (hasArrows) {
      arrowLoc =
          new Point(
              x1 + w1 + BORDER / 2 - ARROW_WIDTH,
              y1 + (h1 - ARROW_HEIGHT * 2 - ARROWS_SPACING) / 2 - 1);
    }
    contentArea =
        new Rectangle(x1, y1, w1 - (hasArrows ? ARROW_WIDTH + CONTENT_ARROW_SPACING : 0), h1);

    boolean hasImage = hasImage();
    boolean hasText = hasText();
    if (hasImage) {
      if (hasText) {
        Point imgSize = getImageSize();
        imgArea = new Rectangle(x1, y1, imgSize.x, h1);
      } else {
        imgArea = contentArea;
      }
    }

    if (hasText) {
      if (hasImage) {
        int w = imgArea.width + IMAGE_TEXT_SPACING;
        textArea = new Rectangle(imgArea.x + w, y1, contentArea.width - w, h1);
      } else {
        textArea = contentArea;
      }
      int maxTextWidth = textArea.width;
      Point textSize = getTextSize();
      if (textSize.x > maxTextWidth) {
        GC gc = new GC(getControl().getDisplay());
        try {
          gc.setFont(getControl().getFont());
          appliedText =
              getSubString(gc, text, maxTextWidth - gc.stringExtent(ELLIPSIS).x) + ELLIPSIS;
        } finally {
          gc.dispose();
        }
      } else {
        appliedText = text;
      }
    }
  }

  protected void paint(GC gc, Display display) {
    if (bounds == null) buildCaches();

    gc.setAntialias(SWT.ON);
    gc.setTextAntialias(SWT.ON);

    int x, y, w, h;
    boolean focused = getControl().isFocusControl() || isForceFocus();
    boolean hasBackgroundAndBorder = pressed || hovered || focused;
    if (hasBackgroundAndBorder) {
      // draw control background
      gc.setBackground(getBorderBackground(display));
      gc.fillRoundRectangle(
          bounds.x, bounds.y, bounds.width, bounds.height, CORNER_SIZE, CORNER_SIZE);
    }

    if (focused) {
      // draw focused content background
      x = contentArea.x - FOCUS_BORDER;
      y = contentArea.y - FOCUS_BORDER;
      w = contentArea.width + FOCUS_BORDER * 2;
      h = contentArea.height + FOCUS_BORDER * 2;
      gc.setBackground(getRealTextBackground(display));
      gc.fillRoundRectangle(x, y, w, h, FOCUS_CORNER_SIZE, FOCUS_CORNER_SIZE);
    }

    boolean hasImage = hasImage();
    boolean hasText = hasText();
    if (hasImage) {
      Rectangle clipping = gc.getClipping();
      if (clipping == null || clipping.intersects(imgArea)) {
        // draw image
        Point imgSize = getImageSize();
        x = imgArea.x + (imgArea.width - imgSize.x) / 2;
        y = imgArea.y + (imgArea.height - imgSize.y) / 2;
        gc.setClipping(imgArea);
        gc.drawImage(image, x, y);
        gc.setClipping(clipping);
      }
    }
    if (hasText) {
      Rectangle clipping = gc.getClipping();
      if (clipping == null || clipping.intersects(textArea)) {
        // draw text
        String text = getAppliedText();
        gc.setFont(getControl().getFont());
        Point ext = gc.stringExtent(text);
        //                    if (hasImage) {
        x = textArea.x;
        //                    } else {
        //                        x = textArea.x + (textArea.width - ext.x) / 2;
        //                    }
        y = textArea.y + (textArea.height - ext.y) / 2;
        gc.setClipping(textArea);
        gc.setForeground(getRealTextForeground(display));
        gc.drawString(text, x, y, true);
        gc.setClipping(clipping);
      }
    }

    // draw arrows
    if (hasArrows() && arrowLoc != null) {
      gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
      x = arrowLoc.x + ARROW_WIDTH / 2;
      y = arrowLoc.y;
      int x1 = arrowLoc.x - 1;
      int y1 = arrowLoc.y + ARROW_HEIGHT + 1;
      int x2 = arrowLoc.x + ARROW_WIDTH;
      gc.fillPolygon(new int[] {x, y, x1, y1, x2, y1});

      y += ARROW_HEIGHT * 2 + ARROWS_SPACING + 1;
      x1 = arrowLoc.x;
      y1 += ARROWS_SPACING;
      gc.fillPolygon(new int[] {x, y, x2, y1, x1 - 1, y1});
    }

    // draw border
    if (focused) {
      x = bounds.x;
      y = bounds.y;
      w = bounds.width;
      h = bounds.height;
      if (DRAWS_FOCUS) {
        gc.drawFocus(x - MARGIN + 1, y - MARGIN + 1, w + MARGIN * 2 - 2, h + MARGIN * 2 - 2);
      } else {
        gc.setForeground(getBorderForeground(display, focused));
        gc.drawRoundRectangle(x, y, w, h, CORNER_SIZE, CORNER_SIZE);
      }
    }
  }

  private Color getRealTextForeground(Display display) {
    if (!getControl().isEnabled()) return display.getSystemColor(SWT.COLOR_GRAY);
    if (textForeground != null) return textForeground;
    return display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
  }

  private Color getRealTextBackground(Display display) {
    if (textBackground != null) return textBackground;
    return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
  }

  private Color getBorderBackground(Display display) {
    if (pressed) return display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
    return display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);
  }

  private Color getBorderForeground(Display display, boolean focused) {
    if (focused) return display.getSystemColor(SWT.COLOR_WIDGET_BORDER);
    return display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
  }

  protected static int checkStyle(int style, int defaultValue, int... bits) {
    for (int bit : bits) {
      int s = style & bit;
      if (s != 0) return s;
    }
    return defaultValue;
  }

  protected static String getSubString(GC gc, String string, int maxWidth) {
    Point ext = gc.stringExtent(string);
    if (ext.x <= maxWidth || string.length() == 0) return string;
    return getSubString(gc, string.substring(0, string.length() - 1), maxWidth);
  }

  public Object getInput() {
    return null;
  }

  public ISelection getSelection() {
    return new StructuredSelection(this);
  }

  public void refresh() {}

  public void refreshControl() {
    getControl().redraw();
  }

  public void setInput(Object input) {}

  public void setSelection(ISelection selection, boolean reveal) {}
}
예제 #17
0
/*
 * The lightweight popup used to show content proposals for a text field. If
 * additional information exists for a proposal, then selecting that
 * proposal will result in the information being displayed in a secondary
 * popup.
 */
public class ContentProposalPopup extends PopupDialog {

  /*
   * Set to <code>true</code> to use a Table with SWT.VIRTUAL. This is a
   * workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=98585#c40
   * The corresponding SWT bug is
   * https://bugs.eclipse.org/bugs/show_bug.cgi?id=90321
   */
  private static final boolean USE_VIRTUAL = !Util.isMotif();

  /*
   * Empty string.
   */
  private static final String EMPTY = ""; // $NON-NLS-1$

  /*
   * The delay before showing a secondary popup.
   */
  private static final int POPUP_DELAY = 750;

  /*
   * The character height hint for the popup. May be overridden by using
   * setInitialPopupSize.
   */
  private static final int POPUP_CHAR_HEIGHT = 10;

  /*
   * The minimum pixel width for the popup. May be overridden by using
   * setInitialPopupSize.
   */
  private static final int POPUP_MINIMUM_WIDTH = 300;

  /*
   * The pixel offset of the popup from the bottom corner of the control.
   */
  private static final int POPUP_OFFSET = 3;

  /*
   * The listener we install on the popup and related controls to determine
   * when to close the popup. Some events (move, resize, close, deactivate)
   * trigger closure as soon as they are received, simply because one of the
   * registered listeners received them. Other events depend on additional
   * circumstances.
   */
  private final class PopupCloserListener implements Listener {
    private boolean scrollbarClicked = false;

    public void handleEvent(final Event e) {

      // If focus is leaving an important widget or the field's
      // shell is deactivating
      if (e.type == SWT.FocusOut) {
        scrollbarClicked = false;
        /*
         * Ignore this event if it's only happening because focus is
         * moving between the popup shells, their controls, or a
         * scrollbar. Do this in an async since the focus is not
         * actually switched when this event is received.
         */
        e.display.asyncExec(
            new Runnable() {
              public void run() {
                if (isValid()) {
                  if (scrollbarClicked || hasFocus()) {
                    return;
                  }
                  // Workaround a problem on X and Mac, whereby at
                  // this point, the focus control is not known.
                  // This can happen, for example, when resizing
                  // the popup shell on the Mac.
                  // Check the active shell.
                  Shell activeShell = e.display.getActiveShell();
                  if (activeShell == getShell()
                      || (infoPopup != null && infoPopup.getShell() == activeShell)) {
                    return;
                  }
                  /*
                   * System.out.println(e);
                   * System.out.println(e.display.getFocusControl());
                   * System.out.println(e.display.getActiveShell());
                   */
                  close();
                }
              }
            });
        return;
      }

      // Scroll bar has been clicked. Remember this for focus event
      // processing.
      if (e.type == SWT.Selection) {
        scrollbarClicked = true;
        return;
      }
      // For all other events, merely getting them dictates closure.
      close();
    }

    // Install the listeners for events that need to be monitored for
    // popup closure.
    void installListeners() {
      // Listeners on this popup's table and scroll bar
      proposalTable.addListener(SWT.FocusOut, this);
      ScrollBar scrollbar = proposalTable.getVerticalBar();
      if (scrollbar != null) {
        scrollbar.addListener(SWT.Selection, this);
      }

      // Listeners on this popup's shell
      getShell().addListener(SWT.Deactivate, this);
      getShell().addListener(SWT.Close, this);

      // Listeners on the target control
      control.addListener(SWT.MouseDoubleClick, this);
      control.addListener(SWT.MouseDown, this);
      control.addListener(SWT.Dispose, this);
      control.addListener(SWT.FocusOut, this);
      // Listeners on the target control's shell
      Shell controlShell = control.getShell();
      controlShell.addListener(SWT.Move, this);
      controlShell.addListener(SWT.Resize, this);
    }

    // Remove installed listeners
    void removeListeners() {
      if (isValid()) {
        proposalTable.removeListener(SWT.FocusOut, this);
        ScrollBar scrollbar = proposalTable.getVerticalBar();
        if (scrollbar != null) {
          scrollbar.removeListener(SWT.Selection, this);
        }

        getShell().removeListener(SWT.Deactivate, this);
        getShell().removeListener(SWT.Close, this);
      }

      if (control != null && !control.isDisposed()) {

        control.removeListener(SWT.MouseDoubleClick, this);
        control.removeListener(SWT.MouseDown, this);
        control.removeListener(SWT.Dispose, this);
        control.removeListener(SWT.FocusOut, this);

        Shell controlShell = control.getShell();
        controlShell.removeListener(SWT.Move, this);
        controlShell.removeListener(SWT.Resize, this);
      }
    }
  }

  /*
   * The listener we will install on the target control.
   */
  private final class TargetControlListener implements Listener {
    // Key events from the control
    public void handleEvent(Event e) {
      if (!isValid()) {
        return;
      }

      char key = e.character;

      // Traverse events are handled depending on whether the
      // event has a character.
      if (e.type == SWT.Traverse) {
        // If the traverse event contains a legitimate character,
        // then we must set doit false so that the widget will
        // receive the key event. We return immediately so that
        // the character is handled only in the key event.
        // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=132101
        if (key != 0) {
          e.doit = false;
          return;
        }
        // Traversal does not contain a character. Set doit true
        // to indicate TRAVERSE_NONE will occur and that no key
        // event will be triggered. We will check for navigation
        // keys below.
        e.detail = SWT.TRAVERSE_NONE;
        e.doit = true;
      } else {
        // Default is to only propagate when configured that way.
        // Some keys will always set doit to false anyway.
        e.doit = adapter.getPropagateKeys();
      }

      // No character. Check for navigation keys.

      if (key == 0) {
        int newSelection = proposalTable.getSelectionIndex();
        int visibleRows = (proposalTable.getSize().y / proposalTable.getItemHeight()) - 1;
        switch (e.keyCode) {
          case SWT.ARROW_UP:
            newSelection -= 1;
            if (newSelection < 0) {
              newSelection = proposalTable.getItemCount() - 1;
            }
            // Not typical - usually we get this as a Traverse and
            // therefore it never propagates. Added for consistency.
            if (e.type == SWT.KeyDown) {
              // don't propagate to control
              e.doit = false;
            }
            break;

          case SWT.ARROW_DOWN:
            newSelection += 1;
            if (newSelection > proposalTable.getItemCount() - 1) {
              newSelection = 0;
            }
            // Not typical - usually we get this as a Traverse and
            // therefore it never propagates. Added for consistency.
            if (e.type == SWT.KeyDown) {
              // don't propagate to control
              e.doit = false;
            }
            break;

          case SWT.PAGE_DOWN:
            newSelection += visibleRows;
            if (newSelection >= proposalTable.getItemCount()) {
              newSelection = proposalTable.getItemCount() - 1;
            }
            if (e.type == SWT.KeyDown) {
              // don't propagate to control
              e.doit = false;
            }
            break;

          case SWT.PAGE_UP:
            newSelection -= visibleRows;
            if (newSelection < 0) {
              newSelection = 0;
            }
            if (e.type == SWT.KeyDown) {
              // don't propagate to control
              e.doit = false;
            }
            break;

          case SWT.HOME:
            newSelection = 0;
            if (e.type == SWT.KeyDown) {
              // don't propagate to control
              e.doit = false;
            }
            break;

          case SWT.END:
            newSelection = proposalTable.getItemCount() - 1;
            if (e.type == SWT.KeyDown) {
              // don't propagate to control
              e.doit = false;
            }
            break;

            // If received as a Traverse, these should propagate
            // to the control as keydown. If received as a keydown,
            // proposals should be recomputed since the cursor
            // position has changed.
          case SWT.ARROW_LEFT:
          case SWT.ARROW_RIGHT:
            if (e.type == SWT.Traverse) {
              e.doit = false;
            } else {
              e.doit = true;
              String contents = adapter.getControlContentAdapter().getControlContents(control);
              // If there are no contents, changes in cursor
              // position have no effect. Note also that we do
              // not affect the filter text on ARROW_LEFT as
              // we would with BS.
              if (contents.length() > 0) {
                asyncRecomputeProposals();
              }
            }
            break;

            // Any unknown keycodes will cause the popup to close.
            // Modifier keys are explicitly checked and ignored because
            // they are not complete yet (no character).
          default:
            if (e.keyCode != SWT.CAPS_LOCK
                && e.keyCode != SWT.NUM_LOCK
                && e.keyCode != SWT.MOD1
                && e.keyCode != SWT.MOD2
                && e.keyCode != SWT.MOD3
                && e.keyCode != SWT.MOD4) {
              close();
            }
            return;
        }

        // If any of these navigation events caused a new selection,
        // then handle that now and return.
        if (newSelection >= 0) {
          selectProposal(newSelection);
        }
        return;
      }

      // key != 0
      // Check for special keys involved in cancelling, accepting, or
      // filtering the proposals.
      switch (key) {
        case SWT.ESC:
          e.doit = false;
          close();
          break;

        case SWT.LF:
        case SWT.CR:
          e.doit = false;
          Object p = getSelectedProposal();
          if (p != null) {
            acceptCurrentProposal();
          } else {
            close();
          }
          break;

        case SWT.TAB:
          e.doit = false;
          getShell().setFocus();
          return;

        case SWT.BS:
          // There is no filtering provided by us, but some
          // clients provide their own filtering based on content.
          // Recompute the proposals if the cursor position
          // will change (is not at 0).
          int pos = adapter.getControlContentAdapter().getCursorPosition(control);
          // We rely on the fact that the contents and pos do not yet
          // reflect the result of the BS. If the contents were
          // already empty, then BS should not cause
          // a recompute.
          if (pos > 0) {
            asyncRecomputeProposals();
          }
          break;

        default:
          // If the key is a defined unicode character, and not one of
          // the special cases processed above, update the filter text
          // and filter the proposals.
          if (Character.isDefined(key)) {
            // Recompute proposals after processing this event.
            asyncRecomputeProposals();
          }
          break;
      }
    }
  }

  /*
   * Internal class used to implement the secondary popup.
   */
  private class InfoPopupDialog extends PopupDialog {

    /*
     * The text control that displays the text.
     */
    private Text text;

    /*
     * The String shown in the popup.
     */
    private String contents = EMPTY;

    /*
     * Construct an info-popup with the specified parent.
     */
    InfoPopupDialog(Shell parent) {
      super(parent, PopupDialog.HOVER_SHELLSTYLE, false, false, false, false, false, null, null);
    }

    /*
     * Create a text control for showing the info about a proposal.
     */
    protected Control createDialogArea(Composite parent) {
      text = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.WRAP | SWT.NO_FOCUS);

      // Use the compact margins employed by PopupDialog.
      GridData gd = new GridData(GridData.BEGINNING | GridData.FILL_BOTH);
      gd.horizontalIndent = PopupDialog.POPUP_HORIZONTALSPACING;
      gd.verticalIndent = PopupDialog.POPUP_VERTICALSPACING;
      text.setLayoutData(gd);
      text.setText(contents);

      // since SWT.NO_FOCUS is only a hint...
      text.addFocusListener(
          new FocusAdapter() {
            public void focusGained(FocusEvent event) {
              ContentProposalPopup.this.close();
            }
          });
      return text;
    }

    /*
     * Adjust the bounds so that we appear adjacent to our parent shell
     */
    protected void adjustBounds() {
      Rectangle parentBounds = getParentShell().getBounds();
      Rectangle proposedBounds;
      // Try placing the info popup to the right
      Rectangle rightProposedBounds =
          new Rectangle(
              parentBounds.x + parentBounds.width + PopupDialog.POPUP_HORIZONTALSPACING,
              parentBounds.y + PopupDialog.POPUP_VERTICALSPACING,
              parentBounds.width,
              parentBounds.height);
      rightProposedBounds = getConstrainedShellBounds(rightProposedBounds);
      // If it won't fit on the right, try the left
      if (rightProposedBounds.intersects(parentBounds)) {
        Rectangle leftProposedBounds =
            new Rectangle(
                parentBounds.x - parentBounds.width - POPUP_HORIZONTALSPACING - 1,
                parentBounds.y,
                parentBounds.width,
                parentBounds.height);
        leftProposedBounds = getConstrainedShellBounds(leftProposedBounds);
        // If it won't fit on the left, choose the proposed bounds
        // that fits the best
        if (leftProposedBounds.intersects(parentBounds)) {
          if (rightProposedBounds.x - parentBounds.x >= parentBounds.x - leftProposedBounds.x) {
            rightProposedBounds.x =
                parentBounds.x + parentBounds.width + PopupDialog.POPUP_HORIZONTALSPACING;
            proposedBounds = rightProposedBounds;
          } else {
            leftProposedBounds.width =
                parentBounds.x - POPUP_HORIZONTALSPACING - leftProposedBounds.x;
            proposedBounds = leftProposedBounds;
          }
        } else {
          // use the proposed bounds on the left
          proposedBounds = leftProposedBounds;
        }
      } else {
        // use the proposed bounds on the right
        proposedBounds = rightProposedBounds;
      }
      getShell().setBounds(proposedBounds);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.jface.dialogs.PopupDialog#getForeground()
     */
    protected Color getForeground() {
      return control.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.jface.dialogs.PopupDialog#getBackground()
     */
    protected Color getBackground() {
      return control.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
    }

    /*
     * Set the text contents of the popup.
     */
    void setContents(String newContents) {
      if (newContents == null) {
        newContents = EMPTY;
      }
      this.contents = newContents;
      if (text != null && !text.isDisposed()) {
        text.setText(contents);
      }
    }

    /*
     * Return whether the popup has focus.
     */
    boolean hasFocus() {
      if (text == null || text.isDisposed()) {
        return false;
      }
      return text.getShell().isFocusControl() || text.isFocusControl();
    }
  }

  /*
   * The listener installed on the target control.
   */
  private Listener targetControlListener;

  /*
   * The listener installed in order to close the popup.
   */
  private PopupCloserListener popupCloser;

  /*
   * The table used to show the list of proposals.
   */
  private Table proposalTable;

  /*
   * The text used to display info under the table
   */
  private Text footer;

  /*
   * The proposals to be shown (cached to avoid repeated requests).
   */
  private ContentProposalList proposalList;

  /*
   * Secondary popup used to show detailed information about the selected
   * proposal..
   */
  private InfoPopupDialog infoPopup;

  /*
   * Flag indicating whether there is a pending secondary popup update.
   */
  private boolean pendingDescriptionUpdate = false;

  /*
   * The desired size in pixels of the proposal popup.
   */
  private Point popupSize;

  /*
   * The control for which content proposals are provided.
   */
  private Control control;

  /*
   * A label provider used to display proposals in the popup, and to extract
   * Strings from non-String proposals.
   */
  private ILabelProvider labelProvider;

  private ContentProposalAdapter adapter;

  /**
   * Constructs a new instance of this popup, specifying the control for which this popup is showing
   * content, and how the proposals should be obtained and displayed.
   *
   * @param infoText Text to be shown in a lower info area, or <code>null</code> if there is no info
   *     area.
   */
  ContentProposalPopup(
      ContentProposalAdapter adapter,
      String infoText,
      ContentProposalList proposalList,
      int maxDisplay) {
    // IMPORTANT: Use of SWT.ON_TOP is critical here for ensuring
    // that the target control retains focus on Mac and Linux. Without
    // it, the focus will disappear, keystrokes will not go to the
    // popup, and the popup closer will wrongly close the popup.
    // On platforms where SWT.ON_TOP overrides SWT.RESIZE, we will live with this.
    // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=126138
    super(
        adapter.getControl().getShell(),
        SWT.RESIZE | SWT.ON_TOP,
        false,
        false,
        false,
        false,
        false,
        null,
        infoText);
    this.adapter = adapter;
    this.control = adapter.getControl();
    this.labelProvider = adapter.getLabelProvider();
    this.proposalList = proposalList;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.dialogs.PopupDialog#getForeground()
   */
  protected Color getForeground() {
    return JFaceResources.getColorRegistry().get(JFacePreferences.CONTENT_ASSIST_FOREGROUND_COLOR);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.dialogs.PopupDialog#getBackground()
   */
  protected Color getBackground() {
    return JFaceResources.getColorRegistry().get(JFacePreferences.CONTENT_ASSIST_BACKGROUND_COLOR);
  }

  /*
   * Creates the content area for the proposal popup. This creates a table and
   * places it inside the composite. The table will contain a list of all the
   * proposals.
   *
   * @param parent The parent composite to contain the dialog area; must not
   * be <code>null</code>.
   */
  protected final Control createDialogArea(final Composite parent) {
    Composite wrapper = (Composite) super.createDialogArea(parent);
    wrapper.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    wrapper.setLayout(new GridLayout());

    // Use virtual where appropriate (see flag definition).
    if (USE_VIRTUAL) {
      proposalTable = new Table(wrapper, SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL);
      Listener listener =
          new Listener() {
            public void handleEvent(Event event) {
              handleSetData(event);
            }
          };
      proposalTable.addListener(SWT.SetData, listener);
    } else {
      proposalTable = new Table(parent, SWT.H_SCROLL | SWT.V_SCROLL);
    }

    footer = new Text(wrapper, SWT.READ_ONLY | SWT.WRAP);
    GridData textGridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
    textGridData.widthHint = 100;
    footer.setLayoutData(textGridData);

    // set the proposals to force population of the table.
    setProposals(proposalList);

    proposalTable.setHeaderVisible(false);
    proposalTable.addSelectionListener(
        new SelectionListener() {
          public void widgetSelected(SelectionEvent e) {
            // If a proposal has been selected, show it in the secondary
            // popup. Otherwise close the popup.
            if (e.item == null) {
              if (infoPopup != null) {
                infoPopup.close();
              }
            } else {
              showProposalDescription();
            }
          }

          // Default selection was made. Accept the current proposal.
          public void widgetDefaultSelected(SelectionEvent e) {
            acceptCurrentProposal();
          }
        });
    return proposalTable;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.dialogs.PopupDialog.adjustBounds()
   */
  protected void adjustBounds() {
    // Get our control's location in display coordinates.
    Point location = control.getDisplay().map(control.getParent(), null, control.getLocation());
    int initialX = location.x + POPUP_OFFSET;
    int initialY = location.y + control.getSize().y + POPUP_OFFSET;
    // If we are inserting content, use the cursor position to
    // position the control.
    if (adapter.getProposalAcceptanceStyle() == ContentProposalAdapter.PROPOSAL_INSERT) {
      Rectangle insertionBounds = adapter.getControlContentAdapter().getInsertionBounds(control);
      initialX = initialX + insertionBounds.x;
      initialY = location.y + insertionBounds.y + insertionBounds.height;
    }

    // If there is no specified size, force it by setting
    // up a layout on the table.
    if (popupSize == null) {
      GridData data = new GridData(GridData.FILL_BOTH);
      data.heightHint = proposalTable.getItemHeight() * POPUP_CHAR_HEIGHT;
      data.widthHint = Math.max(control.getSize().x, POPUP_MINIMUM_WIDTH);
      proposalTable.setLayoutData(data);
      getShell().pack();
      popupSize = getShell().getSize();
    }

    // Constrain to the display
    Rectangle constrainedBounds =
        getConstrainedShellBounds(new Rectangle(initialX, initialY, popupSize.x, popupSize.y));

    // If there has been an adjustment causing the popup to overlap
    // with the control, then put the popup above the control.
    if (constrainedBounds.y < initialY)
      getShell().setBounds(initialX, location.y - popupSize.y, popupSize.x, popupSize.y);
    else getShell().setBounds(initialX, initialY, popupSize.x, popupSize.y);

    // Now set up a listener to monitor any changes in size.
    getShell()
        .addListener(
            SWT.Resize,
            new Listener() {
              public void handleEvent(Event e) {
                popupSize = getShell().getSize();
                if (infoPopup != null) {
                  infoPopup.adjustBounds();
                }
              }
            });
  }

  /*
   * Handle the set data event. Set the item data of the requested item to the
   * corresponding proposal in the proposal cache.
   */
  private void handleSetData(Event event) {
    TableItem item = (TableItem) event.item;
    int index = proposalTable.indexOf(item);

    int proposalIndex = 0;
    for (String provider : proposalList.getProviderList()) {
      if (index == proposalIndex) {
        int count = proposalList.getCount(provider);
        String text = provider + " (" + count + " matching items)";
        item.setText(text);
        // Data == null => not selectable
        item.setData(null);

        Display display = Display.getCurrent();
        Color color = display.getSystemColor(SWT.COLOR_GRAY);
        FontData fontData = item.getFont().getFontData()[0];
        Font font =
            new Font(
                display,
                new FontData(fontData.getName(), fontData.getHeight(), SWT.ITALIC | SWT.BOLD));
        item.setBackground(color);
        item.setFont(font);

        return;
      }
      proposalIndex++;
      for (IContentProposal proposal : proposalList.getProposals(provider)) {
        if (index == proposalIndex) {
          item.setText("  " + getString(proposal));
          item.setImage(getImage(proposal));
          item.setData(proposal);
          return;
        }
        proposalIndex++;
      }
    }
  }

  /*
   * Caches the specified proposals and repopulates the table if it has been
   * created.
   */
  private void setProposals(ContentProposalList newProposalList) {
    if (newProposalList == null || newProposalList.length() == 0) {
      newProposalList = getEmptyProposalArray();
    }
    this.proposalList = newProposalList;
    if (!isValid()) return;

    // If there is a table
    if (isValid()) {
      if (USE_VIRTUAL) {
        // Set and clear the virtual table. Data will be
        // provided in the SWT.SetData event handler.
        proposalTable.setItemCount(getTableLength());
        proposalTable.clearAll();
      } else {
        // Populate the table manually
        proposalTable.setRedraw(false);

        int itemCount = newProposalList.length() + newProposalList.getProviderList().size();
        proposalTable.setItemCount(itemCount);
        TableItem[] items = proposalTable.getItems();

        int index = 0;
        for (String provider : newProposalList.getProviderList()) {
          TableItem item = items[index];
          int count = newProposalList.getCount(provider);
          String text = provider + " (" + count + " matching items)";
          item.setText(text);
          // Data == null => not selectable
          item.setData(null);

          Display display = Display.getCurrent();
          Color color = display.getSystemColor(SWT.COLOR_GRAY);
          FontData fontData = item.getFont().getFontData()[0];
          Font font =
              new Font(
                  display,
                  new FontData(fontData.getName(), fontData.getHeight(), SWT.ITALIC | SWT.BOLD));
          item.setBackground(color);
          item.setFont(font);

          index++;
          for (IContentProposal proposal : newProposalList.getProposals(provider)) {
            item.setText("  " + getString(proposal));
            item.setImage(getImage(proposal));
            item.setData(proposal);
            index++;
          }
        }

        proposalTable.setRedraw(true);
      }
      // Default to the first selection if there is content.
      if (newProposalList.length() > 0) {
        int index = 0;
        boolean selected = false;
        for (String provider : newProposalList.getProviderList()) {
          index++;
          if (!selected && newProposalList.getCount(provider) > 0) {
            selectProposal(index);
            selected = true;
          }
        }
      } else {
        // No selection, close the secondary popup if it was open
        if (infoPopup != null) {
          infoPopup.close();
        }
      }
    }
    footer.setText("");
  }

  private int getTableLength() {
    if (proposalList == null) return 0;
    return proposalList.length() + proposalList.getProviderList().size();
  }

  /*
   * Get the string for the specified proposal. Always return a String of some
   * kind.
   */
  private String getString(IContentProposal proposal) {
    if (proposal == null) {
      return EMPTY;
    }
    if (labelProvider == null) {
      return proposal.getLabel() == null ? proposal.getContent() : proposal.getLabel();
    }
    return labelProvider.getText(proposal);
  }

  /*
   * Get the image for the specified proposal. If there is no image available,
   * return null.
   */
  private Image getImage(IContentProposal proposal) {
    if (proposal == null || labelProvider == null) {
      return null;
    }
    return labelProvider.getImage(proposal);
  }

  /*
   * Return an empty array. Used so that something always shows in the
   * proposal popup, even if no proposal provider was specified.
   */
  private ContentProposalList getEmptyProposalArray() {
    return new ContentProposalList();
  }

  /*
   * Answer true if the popup is valid, which means the table has been created
   * and not disposed.
   */
  private boolean isValid() {
    return proposalTable != null && !proposalTable.isDisposed();
  }

  /*
   * Return whether the receiver has focus. Since 3.4, this includes a check
   * for whether the info popup has focus.
   */
  public boolean hasFocus() {
    if (!isValid()) {
      return false;
    }
    if (getShell().isFocusControl() || proposalTable.isFocusControl()) {
      return true;
    }
    if (infoPopup != null && infoPopup.hasFocus()) {
      return true;
    }
    return false;
  }

  /*
   * Return the current selected proposal.
   */
  private IContentProposal getSelectedProposal() {
    if (isValid()) {
      int index = proposalTable.getSelectionIndex();
      if (proposalList == null || index < 0 || index >= getTableLength()) {
        return null;
      }
      int proposalIndex = 0;
      for (String provider : proposalList.getProviderList()) {
        if (index == proposalIndex) {
          return null;
        }
        proposalIndex++;
        for (IContentProposal proposal : proposalList.getProposals(provider)) {
          if (index == proposalIndex) {
            return proposal;
          }
          proposalIndex++;
        }
      }
    }
    return null;
  }

  /*
   * Select the proposal at the given index.
   */
  private void selectProposal(int index) {
    Assert.isTrue(index >= 0, "Proposal index should never be negative"); // $NON-NLS-1$
    if (!isValid() || proposalList == null || index >= getTableLength()) {
      return;
    }
    proposalTable.setSelection(index);
    proposalTable.showSelection();

    showProposalDescription();
  }

  /**
   * Opens this ContentProposalPopup. This method is extended in order to add the control listener
   * when the popup is opened and to invoke the secondary popup if applicable.
   *
   * @return the return code
   * @see org.eclipse.jface.window.Window#open()
   */
  public int open() {
    int value = super.open();
    if (popupCloser == null) {
      popupCloser = new PopupCloserListener();
    }
    popupCloser.installListeners();
    IContentProposal p = getSelectedProposal();
    if (p != null) {
      showProposalDescription();
    }
    return value;
  }

  /**
   * Closes this popup. This method is extended to remove the control listener.
   *
   * @return <code>true</code> if the window is (or was already) closed, and <code>false</code> if
   *     it is still open
   */
  public boolean close() {
    popupCloser.removeListeners();
    if (infoPopup != null) {
      infoPopup.close();
    }
    boolean ret = super.close();
    adapter.notifyPopupClosed();
    return ret;
  }

  /*
   * Show the currently selected proposal's description in a secondary popup.
   */
  private void showProposalDescription() {
    // If we do not already have a pending update, then
    // create a thread now that will show the proposal description
    if (!pendingDescriptionUpdate) {
      // Create a thread that will sleep for the specified delay
      // before creating the popup. We do not use Jobs since this
      // code must be able to run independently of the Eclipse
      // runtime.
      Runnable runnable =
          new Runnable() {
            public void run() {
              pendingDescriptionUpdate = true;
              try {
                Thread.sleep(POPUP_DELAY);
              } catch (InterruptedException e) {
              }
              if (!isValid()) {
                return;
              }
              getShell()
                  .getDisplay()
                  .syncExec(
                      new Runnable() {
                        public void run() {
                          // Query the current selection since we have
                          // been delayed
                          IContentProposal p = getSelectedProposal();
                          if (p != null) {
                            String description = p.getDescription();
                            if (description != null) {
                              if (infoPopup == null) {
                                infoPopup = new InfoPopupDialog(getShell());
                                infoPopup.open();
                                infoPopup
                                    .getShell()
                                    .addDisposeListener(
                                        new DisposeListener() {
                                          public void widgetDisposed(DisposeEvent event) {
                                            infoPopup = null;
                                          }
                                        });
                              }
                              infoPopup.setContents(p.getDescription());
                            } else if (infoPopup != null) {
                              infoPopup.close();
                            }
                            pendingDescriptionUpdate = false;
                          }
                        }
                      });
            }
          };
      Thread t = new Thread(runnable);
      t.start();
    }
  }

  /*
   * Accept the current proposal.
   */
  private void acceptCurrentProposal() {
    // Close before accepting the proposal. This is important
    // so that the cursor position can be properly restored at
    // acceptance, which does not work without focus on some controls.
    // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=127108
    IContentProposal proposal = getSelectedProposal();
    close();
    if (proposal != null) {
      adapter.proposalAccepted(proposal);
    }
  }

  /*
   * Request the proposals from the proposal provider, and recompute any
   * caches. Repopulate the popup if it is open.
   */
  private void recomputeProposals(ContentProposalList newProposalList) {
    if (newProposalList == null) newProposalList = getEmptyProposalArray();
    // If the non-filtered proposal list is empty, we should close the popup.
    // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=147377
    if (newProposalList.length() == 0) {
      this.proposalList = newProposalList;
      close();
    } else {
      // Keep the popup open, but filter by any provided filter text
      setProposals(newProposalList);
    }
  }

  /*
   * In an async block, request the proposals. This is used when clients are
   * in the middle of processing an event that affects the widget content. By
   * using an async, we ensure that the widget content is up to date with the
   * event.
   */
  private void asyncRecomputeProposals() {
    footer.setText("Searching...");
    if (isValid()) {
      control
          .getDisplay()
          .asyncExec(
              new Runnable() {
                public void run() {
                  adapter.recordCursorPosition();
                  adapter.getProposals(
                      new IContentProposalSearchHandler() {
                        @Override
                        public void handleResult(ContentProposalList proposalList) {
                          recomputeProposals(proposalList);
                        }
                      });
                }
              });
    } else {
      adapter.getProposals(
          new IContentProposalSearchHandler() {
            @Override
            public void handleResult(ContentProposalList proposalList) {
              recomputeProposals(proposalList);
            }
          });
    }
  }

  Listener getTargetControlListener() {
    if (targetControlListener == null) {
      targetControlListener = new TargetControlListener();
    }
    return targetControlListener;
  }

  public Point getPopupSize() {
    return popupSize;
  }

  public void setPopupSize(Point size) {
    popupSize = size;
  }
}
예제 #18
0
  public final void setActionDefinitionId(final String id) {
    // Get the old values.
    final boolean oldChecked = isChecked();
    final String oldDescription = getDescription();
    final boolean oldEnabled = isEnabled();
    final boolean oldHandled = isHandled();
    final ImageDescriptor oldDefaultImage = getImageDescriptor();
    final ImageDescriptor oldDisabledImage = getDisabledImageDescriptor();
    final ImageDescriptor oldHoverImage = getHoverImageDescriptor();
    final String oldText = getText();

    // Update the command.
    final Command oldBaseCommand = command.getCommand();
    oldBaseCommand.removeCommandListener(commandListener);
    final ICommandService commandService =
        (ICommandService) serviceLocator.getService(ICommandService.class);
    final Command newBaseCommand = commandService.getCommand(id);
    command = new ParameterizedCommand(newBaseCommand, null);
    newBaseCommand.addCommandListener(commandListener);

    // Get the new values.
    final boolean newChecked = isChecked();
    final String newDescription = getDescription();
    final boolean newEnabled = isEnabled();
    final boolean newHandled = isHandled();
    final ImageDescriptor newDefaultImage = getImageDescriptor();
    final ImageDescriptor newDisabledImage = getDisabledImageDescriptor();
    final ImageDescriptor newHoverImage = getHoverImageDescriptor();
    final String newText = getText();

    // Fire property change events, as necessary.
    if (newChecked != oldChecked) {
      if (oldChecked) {
        firePropertyChange(IAction.CHECKED, Boolean.TRUE, Boolean.FALSE);
      } else {
        firePropertyChange(IAction.CHECKED, Boolean.FALSE, Boolean.TRUE);
      }
    }

    if (!Util.equals(oldDescription, newDescription)) {
      firePropertyChange(IAction.DESCRIPTION, oldDescription, newDescription);
      firePropertyChange(IAction.TOOL_TIP_TEXT, oldDescription, newDescription);
    }

    if (newEnabled != oldEnabled) {
      if (oldEnabled) {
        firePropertyChange(IAction.ENABLED, Boolean.TRUE, Boolean.FALSE);
      } else {
        firePropertyChange(IAction.ENABLED, Boolean.FALSE, Boolean.TRUE);
      }
    }

    if (newHandled != oldHandled) {
      if (oldHandled) {
        firePropertyChange(IAction.HANDLED, Boolean.TRUE, Boolean.FALSE);
      } else {
        firePropertyChange(IAction.HANDLED, Boolean.FALSE, Boolean.TRUE);
      }
    }

    if (!Util.equals(oldDefaultImage, newDefaultImage)) {
      firePropertyChange(IAction.IMAGE, oldDefaultImage, newDefaultImage);
    }

    if (!Util.equals(oldDisabledImage, newDisabledImage)) {
      firePropertyChange(IAction.IMAGE, oldDisabledImage, newDisabledImage);
    }

    if (!Util.equals(oldHoverImage, newHoverImage)) {
      firePropertyChange(IAction.IMAGE, oldHoverImage, newHoverImage);
    }

    if (!Util.equals(oldText, newText)) {
      firePropertyChange(IAction.TEXT, oldText, newText);
    }
  }
  /**
   * Returns the change that will be executed when the proposal is applied. This method calls {@link
   * #createChange()} to compute the change.
   *
   * @return the change for this proposal, can be <code>null</code> in rare cases if creation of the
   *     change failed
   * @throws CoreException when the change could not be created
   */
  public final Change getChange() throws CoreException {
    if (Util.isGtk()) {
      // workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=293995 :
      // [Widgets] Deadlock while UI thread displaying/computing a change proposal and non-UI thread
      // creating image

      // Solution is to create the change outside a 'synchronized' block.
      // Synchronization is achieved by polling fChange, using "fChange == COMPUTING_CHANGE" as
      // barrier.
      // Timeout of 10s for safety reasons (should not be reached).
      long end = System.currentTimeMillis() + 10000;
      do {
        boolean computing;
        synchronized (this) {
          computing = fChange == COMPUTING_CHANGE;
        }
        if (computing) {
          try {
            Display display = Display.getCurrent();
            if (display != null) {
              while (!display.isDisposed() && display.readAndDispatch()) {
                // empty the display loop
              }
              display.sleep();
            } else {
              Thread.sleep(100);
            }
          } catch (InterruptedException e) {
            // continue
          }
        } else {
          synchronized (this) {
            if (fChange == COMPUTING_CHANGE) {
              continue;
            } else if (fChange != null) {
              return fChange;
            } else {
              fChange = COMPUTING_CHANGE;
            }
          }
          Change change = createChange();
          synchronized (this) {
            fChange = change;
          }
          return change;
        }
      } while (System.currentTimeMillis() < end);

      synchronized (this) {
        if (fChange == COMPUTING_CHANGE) {
          return null; // failed
        }
      }

    } else {
      synchronized (this) {
        if (fChange == null) {
          fChange = createChange();
        }
      }
    }
    return fChange;
  }
 static {
   UNIT = Util.isMac() ? "px" : "pt"; // $NON-NLS-1$//$NON-NLS-2$
 }
  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.internal.progress.AnimationItem#createAnimationItem(org.eclipse.swt.widgets.Composite)
   */
  @Override
  protected Control createAnimationItem(Composite parent) {

    if (okImage == null) {
      Display display = parent.getDisplay();
      noneImage =
          WorkbenchImages.getWorkbenchImageDescriptor("progress/progress_none.png")
              .createImage(display); // $NON-NLS-1$
      okImage =
          WorkbenchImages.getWorkbenchImageDescriptor("progress/progress_ok.png")
              .createImage(display); // $NON-NLS-1$
      errorImage =
          WorkbenchImages.getWorkbenchImageDescriptor("progress/progress_error.png")
              .createImage(display); // $NON-NLS-1$
    }

    top = new Composite(parent, SWT.NULL);
    top.addDisposeListener(
        new DisposeListener() {
          @Override
          public void widgetDisposed(DisposeEvent e) {
            FinishedJobs.getInstance().removeListener(ProgressAnimationItem.this);
            noneImage.dispose();
            okImage.dispose();
            errorImage.dispose();
          }
        });

    boolean isCarbon = Util.isMac();

    GridLayout gl = new GridLayout();
    if (isHorizontal()) gl.numColumns = isCarbon ? 3 : 2;
    gl.marginHeight = 0;
    gl.marginWidth = 0;
    if (isHorizontal()) {
      gl.horizontalSpacing = 2;
    } else {
      gl.verticalSpacing = 2;
    }
    top.setLayout(gl);

    bar = new ProgressBar(top, flags | SWT.INDETERMINATE);
    bar.setVisible(false);
    bar.addMouseListener(mouseListener);

    GridData gd;
    int hh = 12;
    if (isHorizontal()) {
      gd = new GridData(SWT.BEGINNING, SWT.CENTER, true, false);
      gd.heightHint = hh;
    } else {
      gd = new GridData(SWT.CENTER, SWT.BEGINNING, false, true);
      gd.widthHint = hh;
    }

    bar.setLayoutData(gd);

    toolbar = new ToolBar(top, SWT.FLAT);
    toolbar.setVisible(false);

    toolButton = new ToolItem(toolbar, SWT.NONE);
    toolButton.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            doAction();
          }
        });

    if (isCarbon) {
      new Label(top, SWT.NONE).setLayoutData(new GridData(4, 4));
    }

    refresh();

    return top;
  }
 /** Selection changed... */
 protected void handleSelectionChanged() {
   final Object newValue = doGetValue();
   if (Util.equals(myCurrentValue, newValue)) return;
   fireValueChange(Diffs.createValueDiff(myCurrentValue, myCurrentValue = newValue));
 }