Package org.eclipse.egit.ui

Source Code of org.eclipse.egit.ui.UIUtils$IPreviousValueProposalHandler

/*******************************************************************************
* Copyright (c) 2010, 2013 SAP AG and others.
* 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:
*    Mathias Kinzler (SAP AG) - initial implementation
*******************************************************************************/
package org.eclipse.egit.ui;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.RepositorySaveableFilter;
import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.components.RefContentProposal;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.bindings.Trigger;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Resource;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ContributionItemFactory;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.services.IServiceLocator;

/**
* Some utilities for UI code
*/
public class UIUtils {
  /**
   * these activate the content assist; alphanumeric, space plus some expected
   * special chars
   */
  private static final char[] VALUE_HELP_ACTIVATIONCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123457890*@ <>".toCharArray(); //$NON-NLS-1$

  /**
   * A keystroke for a "submit" action, see {@link #isSubmitKeyEvent(KeyEvent)}
   */
  public static final KeyStroke SUBMIT_KEY_STROKE = KeyStroke.getInstance(SWT.MOD1, SWT.CR);

  /**
   * Handles a "previously used values" content assist.
   * <p>
   * Adding this to a text field will enable "content assist" by keeping track
   * of the previously used valued for this field. The previously used values
   * will be shown in the order they were last used (most recently used ones
   * coming first in the list) and the number of entries is limited.
   * <p>
   * A "bulb" decorator will indicate that content assist is available for the
   * field, and a tool tip is provided giving more information.
   * <p>
   * Content assist is activated by either typing in the field or by using a
   * dedicated key stroke which is indicated in the tool tip. The list will be
   * filtered with the content already in the text field with '*' being usable
   * as wild card.
   * <p>
   * Note that the application must issue a call to {@link #updateProposals()}
   * in order to add a new value to the "previously used values" list.
   * <p>
   * The list will be persisted in the plug-in dialog settings.
   *
   * @noextend not to be extended by clients
   * @noimplement not to be implemented by clients, use
   *              {@link UIUtils#addPreviousValuesContentProposalToText(Text, String)}
   *              to create instances of this
   */
  public interface IPreviousValueProposalHandler {
    /**
     * Updates the proposal list from the value in the text field.
     * <p>
     * The value will be truncated to the first 2000 characters in order to
     * limit data size.
     * <p>
     * Note that this must be called in the UI thread, since it accesses the
     * text field.
     * <p>
     * If the value is already in the list, it will become the first entry,
     * otherwise it will be added at the beginning. Note that empty Strings
     * will not be stored. The length of the list is limited, and the
     * "oldest" entries will be removed once the limit is exceeded.
     * <p>
     * This call should only be issued if the value in the text field is
     * "valid" in terms of the application.
     */
    public void updateProposals();
  }

  /**
   * Used for
   * {@link UIUtils#addRefContentProposalToText(Text, Repository, IRefListProvider)}
   */
  public interface IRefListProvider {
    /**
     * @return the List of {@link Ref}s to propose
     */
    public List<Ref> getRefList();
  }

  /**
   * @param id
   *            see {@link FontRegistry#get(String)}
   * @return the font
   */
  public static Font getFont(final String id) {
    return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme()
        .getFontRegistry().get(id);
  }

  /**
   * @param id
   *            see {@link FontRegistry#getBold(String)}
   * @return the font
   */
  public static Font getBoldFont(final String id) {
    return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme()
        .getFontRegistry().getBold(id);
  }

  /**
   * @param id
   *            see {@link FontRegistry#getItalic(String)}
   * @return the font
   */
  public static Font getItalicFont(final String id) {
    return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme()
        .getFontRegistry().getItalic(id);
  }

  /**
   * @return the indent of controls that depend on the previous control (e.g.
   *         a checkbox that is only enabled when the checkbox above it is
   *         checked)
   */
  public static int getControlIndent() {
    // Eclipse 4.3: Use LayoutConstants.getIndent once we depend on 4.3
    return 20;
  }

  /**
   * @param parent
   * @param style
   * @return a text field which is read-only but can be selected
   */
  public static Text createSelectableLabel(Composite parent, int style) {
    // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=71765
    Text text = new Text(parent, style | SWT.READ_ONLY);
    text.setBackground(text.getDisplay().getSystemColor(
        SWT.COLOR_WIDGET_BACKGROUND));
    return text;
  }

  /**
   * Adds little bulb decoration to given control. Bulb will appear in top
   * left corner of control after giving focus for this control.
   *
   * After clicking on bulb image text from <code>tooltip</code> will appear.
   *
   * @param control
   *            instance of {@link Control} object with should be decorated
   * @param tooltip
   *            text value which should appear after clicking on bulb image.
   */
  public static void addBulbDecorator(final Control control,
      final String tooltip) {
    ControlDecoration dec = new ControlDecoration(control, SWT.TOP
        | SWT.LEFT);

    dec.setImage(FieldDecorationRegistry.getDefault().getFieldDecoration(
        FieldDecorationRegistry.DEC_CONTENT_PROPOSAL).getImage());

    dec.setShowOnlyOnFocus(true);
    dec.setShowHover(true);

    dec.setDescriptionText(tooltip);
  }

  /**
   * Adds a "previously used values" content proposal handler to a text field.
   * <p>
   * The list will be limited to 10 values.
   *
   * @param textField
   *            the text field
   * @param preferenceKey
   *            the key under which to store the "previously used values" in
   *            the dialog settings
   * @return the handler the proposal handler
   */
  public static IPreviousValueProposalHandler addPreviousValuesContentProposalToText(
      final Text textField, final String preferenceKey) {
    KeyStroke stroke = UIUtils
        .getKeystrokeOfBestActiveBindingFor(IWorkbenchCommandConstants.EDIT_CONTENT_ASSIST);
    if (stroke == null)
      addBulbDecorator(textField,
          UIText.UIUtils_StartTypingForPreviousValuesMessage);
    else
      addBulbDecorator(
          textField,
          NLS.bind(UIText.UIUtils_PressShortcutMessage,
              stroke.format()));

    IContentProposalProvider cp = new IContentProposalProvider() {

      public IContentProposal[] getProposals(String contents, int position) {

        List<IContentProposal> resultList = new ArrayList<IContentProposal>();

        // make the simplest possible pattern check: allow "*"
        // for multiple characters
        String patternString = contents;
        // ignore spaces in the beginning
        while (patternString.length() > 0
            && patternString.charAt(0) == ' ') {
          patternString = patternString.substring(1);
        }

        // we quote the string as it may contain spaces
        // and other stuff colliding with the Pattern
        patternString = Pattern.quote(patternString);

        patternString = patternString.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$

        // make sure we add a (logical) * at the end
        if (!patternString.endsWith(".*")) { //$NON-NLS-1$
          patternString = patternString + ".*"; //$NON-NLS-1$
        }

        // let's compile a case-insensitive pattern (assumes ASCII only)
        Pattern pattern;
        try {
          pattern = Pattern.compile(patternString,
              Pattern.CASE_INSENSITIVE);
        } catch (PatternSyntaxException e) {
          pattern = null;
        }

        String[] proposals = org.eclipse.egit.ui.Activator.getDefault()
            .getDialogSettings().getArray(preferenceKey);

        if (proposals != null)
          for (final String uriString : proposals) {

            if (pattern != null
                && !pattern.matcher(uriString).matches())
              continue;

            IContentProposal propsal = new IContentProposal() {

              public String getLabel() {
                return null;
              }

              public String getDescription() {
                return null;
              }

              public int getCursorPosition() {
                return 0;
              }

              public String getContent() {
                return uriString;
              }
            };
            resultList.add(propsal);
          }

        return resultList.toArray(new IContentProposal[resultList
            .size()]);
      }
    };

    ContentProposalAdapter adapter = new ContentProposalAdapter(textField,
        new TextContentAdapter(), cp, stroke,
        VALUE_HELP_ACTIVATIONCHARS);
    // set the acceptance style to always replace the complete content
    adapter
        .setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);

    return new IPreviousValueProposalHandler() {
      public void updateProposals() {
        String value = textField.getText();
        // don't store empty values
        if (value.length() > 0) {
          // we don't want to save too much in the preferences
          if (value.length() > 2000) {
            value = value.substring(0, 1999);
          }
          // now we need to mix the value into the list
          IDialogSettings settings = org.eclipse.egit.ui.Activator
              .getDefault().getDialogSettings();
          String[] existingValues = settings.getArray(preferenceKey);
          if (existingValues == null) {
            existingValues = new String[] { value };
            settings.put(preferenceKey, existingValues);
          } else {

            List<String> values = new ArrayList<String>(
                existingValues.length + 1);

            for (String existingValue : existingValues)
              values.add(existingValue);
            // if it is already the first value, we don't need to do
            // anything
            if (values.indexOf(value) == 0)
              return;

            values.remove(value);
            // we insert at the top
            values.add(0, value);
            // make sure to not store more than the maximum number
            // of values
            while (values.size() > 10)
              values.remove(values.size() - 1);

            settings.put(preferenceKey, values
                .toArray(new String[values.size()]));
          }
        }
      }
    };
  }

  /**
   * Adds a content proposal for {@link Ref}s (branches, tags...) to a text
   * field
   *
   * @param textField
   *            the text field
   * @param repository
   *            the repository
   * @param refListProvider
   *            provides the {@link Ref}s to show in the proposal
   */
  public static final void addRefContentProposalToText(final Text textField,
      final Repository repository, final IRefListProvider refListProvider) {
    KeyStroke stroke = UIUtils
        .getKeystrokeOfBestActiveBindingFor(IWorkbenchCommandConstants.EDIT_CONTENT_ASSIST);
    if (stroke == null)
      addBulbDecorator(textField,
          UIText.UIUtils_StartTypingForPreviousValuesMessage);
    else
      addBulbDecorator(
          textField,
          NLS.bind(UIText.UIUtils_PressShortcutMessage,
              stroke.format()));

    IContentProposalProvider cp = new IContentProposalProvider() {
      public IContentProposal[] getProposals(String contents, int position) {
        List<IContentProposal> resultList = new ArrayList<IContentProposal>();

        // make the simplest possible pattern check: allow "*"
        // for multiple characters
        String patternString = contents;
        // ignore spaces in the beginning
        while (patternString.length() > 0
            && patternString.charAt(0) == ' ') {
          patternString = patternString.substring(1);
        }

        // we quote the string as it may contain spaces
        // and other stuff colliding with the Pattern
        patternString = Pattern.quote(patternString);

        patternString = patternString.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$

        // make sure we add a (logical) * at the end
        if (!patternString.endsWith(".*")) { //$NON-NLS-1$
          patternString = patternString + ".*"; //$NON-NLS-1$
        }

        // let's compile a case-insensitive pattern (assumes ASCII only)
        Pattern pattern;
        try {
          pattern = Pattern.compile(patternString,
              Pattern.CASE_INSENSITIVE);
        } catch (PatternSyntaxException e) {
          pattern = null;
        }

        List<Ref> proposals = refListProvider.getRefList();

        if (proposals != null)
          for (final Ref ref : proposals) {
            final String shortenedName = Repository
                .shortenRefName(ref.getName());
            if (pattern != null
                && !pattern.matcher(ref.getName()).matches()
                && !pattern.matcher(shortenedName).matches())
              continue;

            IContentProposal propsal = new RefContentProposal(
                repository, ref);
            resultList.add(propsal);
          }

        return resultList.toArray(new IContentProposal[resultList
            .size()]);
      }
    };

    ContentProposalAdapter adapter = new ContentProposalAdapter(textField,
        new TextContentAdapter(), cp, stroke,
        UIUtils.VALUE_HELP_ACTIVATIONCHARS);
    // set the acceptance style to always replace the complete content
    adapter
        .setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
  }

  /**
   * Set enabled state of the control and all its children
   * @param control
   * @param enable
   */
  public static void setEnabledRecursively(final Control control,
      final boolean enable) {
    control.setEnabled(enable);
    if (control instanceof Composite)
      for (final Control child : ((Composite) control).getChildren())
        setEnabledRecursively(child, enable);
  }

  /**
   * Dispose of the resource when the widget is disposed
   *
   * @param widget
   * @param resource
   */
  public static void hookDisposal(Widget widget, final Resource resource) {
    if (widget == null || resource == null)
      return;

    widget.addDisposeListener(new DisposeListener() {

      public void widgetDisposed(DisposeEvent e) {
        resource.dispose();
      }
    });
  }

  /**
   * Dispose of the resource manager when the widget is disposed
   *
   * @param widget
   * @param resources
   */
  public static void hookDisposal(Widget widget,
      final ResourceManager resources) {
    if (widget == null || resources == null)
      return;

    widget.addDisposeListener(new DisposeListener() {

      public void widgetDisposed(DisposeEvent e) {
        resources.dispose();
      }
    });
  }

  /**
   * Get editor image for path
   *
   * @param path
   * @return image descriptor
   */
  public static ImageDescriptor getEditorImage(final String path) {
    if (path != null && path.length() > 0) {
      final String name = new Path(path).lastSegment();
      if (name != null)
        return PlatformUI.getWorkbench().getEditorRegistry()
            .getImageDescriptor(name);
    }
    return PlatformUI.getWorkbench().getSharedImages()
        .getImageDescriptor(ISharedImages.IMG_OBJ_FILE);
  }

  /**
   * Get size of image descriptor as point.
   *
   * @param descriptor
   * @return size
   */
  public static Point getSize(ImageDescriptor descriptor) {
    ImageData data = descriptor.getImageData();
    if (data == null)
      return new Point(0, 0);
    return new Point(data.width, data.height);
  }

  /**
   * Add expand all and collapse all toolbar items to the given toolbar bound
   * to the given tree viewer
   *
   * @param toolbar
   * @param viewer
   * @return given toolbar
   */
  public static ToolBar addExpansionItems(final ToolBar toolbar,
      final AbstractTreeViewer viewer) {
    ToolItem collapseItem = new ToolItem(toolbar, SWT.PUSH);
    Image collapseImage = UIIcons.COLLAPSEALL.createImage();
    UIUtils.hookDisposal(collapseItem, collapseImage);
    collapseItem.setImage(collapseImage);
    collapseItem.setToolTipText(UIText.UIUtils_CollapseAll);
    collapseItem.addSelectionListener(new SelectionAdapter() {

      public void widgetSelected(SelectionEvent e) {
        viewer.collapseAll();
      }

    });

    ToolItem expandItem = new ToolItem(toolbar, SWT.PUSH);
    Image expandImage = UIIcons.EXPAND_ALL.createImage();
    UIUtils.hookDisposal(expandItem, expandImage);
    expandItem.setImage(expandImage);
    expandItem.setToolTipText(UIText.UIUtils_ExpandAll);
    expandItem.addSelectionListener(new SelectionAdapter() {

      public void widgetSelected(SelectionEvent e) {
        viewer.expandAll();
      }

    });
    return toolbar;
  }

  /**
   * Get dialog bound settings for given class using standard section name
   *
   * @param clazz
   * @return dialog setting
   */
  public static IDialogSettings getDialogBoundSettings(final Class<?> clazz) {
    return getDialogSettings(clazz.getName() + ".dialogBounds"); //$NON-NLS-1$
  }

  /**
   * Get dialog settings for given section name
   *
   * @param sectionName
   * @return dialog settings
   */
  public static IDialogSettings getDialogSettings(final String sectionName) {
    IDialogSettings settings = Activator.getDefault().getDialogSettings();
    IDialogSettings section = settings.getSection(sectionName);
    if (section == null)
      section = settings.addNewSection(sectionName);
    return section;
  }

  /**
   * @return The default repository directory as configured in the
   *         preferences, with variables substituted. An empty string if there
   *         was an error during substitution.
   */
  public static String getDefaultRepositoryDir() {
    String dir = Activator.getDefault().getPreferenceStore()
        .getString(UIPreferences.DEFAULT_REPO_DIR);
    IStringVariableManager manager = VariablesPlugin.getDefault()
        .getStringVariableManager();
    try {
      return manager.performStringSubstitution(dir);
    } catch (CoreException e) {
      return ""; //$NON-NLS-1$
    }
  }

  /**
   * Is viewer in a usable state?
   *
   * @param viewer
   * @return true if usable, false if null or underlying control is null or
   *         disposed
   */
  public static boolean isUsable(final Viewer viewer) {
    return viewer != null && isUsable(viewer.getControl());
  }

  /**
   * Is control usable?
   *
   * @param control
   * @return true if usable, false if null or disposed
   */
  public static boolean isUsable(final Control control) {
    return control != null && !control.isDisposed();
  }

  /**
   * Run command with specified id
   *
   * @param service
   * @param id
   */
  public static void executeCommand(IHandlerService service, String id) {
    executeCommand(service, id, null);
  }

  /**
   * Run command with specified id
   *
   * @param service
   * @param id
   * @param event
   */
  public static void executeCommand(IHandlerService service, String id,
      Event event) {
    try {
      service.executeCommand(id, event);
    } catch (ExecutionException e) {
      Activator.handleError(e.getMessage(), e, false);
    } catch (NotDefinedException e) {
      Activator.handleError(e.getMessage(), e, false);
    } catch (NotEnabledException e) {
      Activator.handleError(e.getMessage(), e, false);
    } catch (NotHandledException e) {
      Activator.handleError(e.getMessage(), e, false);
    }
  }

  /**
   * Determine if the key event represents a "submit" action
   * (&lt;modifier&gt;+Enter).
   *
   * @param event
   * @return true, if it means submit, false otherwise
   */
  public static boolean isSubmitKeyEvent(KeyEvent event) {
    return (event.stateMask & SWT.MODIFIER_MASK) != 0
        && event.keyCode == SUBMIT_KEY_STROKE.getNaturalKey();
  }

  /**
   * Prompt for saving all dirty editors for resources in the working
   * directory of the specified repository.
   *
   * @param repository
   * @return true, if the user opted to continue, false otherwise
   * @see IWorkbench#saveAllEditors(boolean)
   */
  public static boolean saveAllEditors(Repository repository) {
    return saveAllEditors(repository, null);
  }

  /**
   * Prompt for saving all dirty editors for resources in the working
   * directory of the specified repository.
   *
   * If at least one file was saved, a dialog is displayed, asking the user if
   * she wants to cancel the operation. Cancelling allows the user to do
   * something with the newly saved files, before possibly restarting the
   * operation.
   *
   * @param repository
   * @param cancelConfirmationQuestion
   *            A string asking the user if she wants to cancel the operation.
   *            May be null to not open a dialog, but rather always continue.
   * @return true, if the user opted to continue, false otherwise
   * @see IWorkbench#saveAllEditors(boolean)
   */
  public static boolean saveAllEditors(Repository repository,
      String cancelConfirmationQuestion) {
    IWorkbench workbench = PlatformUI.getWorkbench();
    IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
    RepositorySaveableFilter filter = new RepositorySaveableFilter(
        repository);
    boolean success = workbench.saveAll(window, window, filter, true);
    if (success && cancelConfirmationQuestion != null && filter.isAnythingSaved()){
      // allow the user to cancel the operation to first do something with
      // the newly saved files
      String[] buttons = new String[] { IDialogConstants.YES_LABEL,
          IDialogConstants.NO_LABEL };
      MessageDialog dialog = new MessageDialog(window.getShell(),
          UIText.CancelAfterSaveDialog_Title, null,
          cancelConfirmationQuestion,
          MessageDialog.QUESTION, buttons, 0) {
        protected int getShellStyle() {
          return (SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL
              | SWT.SHEET | getDefaultOrientation());
        }
      };
      int choice = dialog.open();
      if (choice != 1) // user clicked "yes" or closed dialog -> cancel
        return false;
    }
    return success;
  }

  /**
   * @param workbenchWindow the workbench window to use for creating the show in menu.
   * @return the show in menu
   */
  public static MenuManager createShowInMenu(IWorkbenchWindow workbenchWindow) {
    MenuManager showInSubMenu = new MenuManager(getShowInMenuLabel());
    showInSubMenu.add(ContributionItemFactory.VIEWS_SHOW_IN.create(workbenchWindow));
    return showInSubMenu;
  }

  /**
   * Use hyperlink detectors to find a text viewer's hyperlinks and return the
   * style ranges to render them.
   *
   * @param textViewer
   * @param hyperlinkDetectors
   * @return the style ranges to render the detected hyperlinks
   */
  public static StyleRange[] getHyperlinkDetectorStyleRanges(
      ITextViewer textViewer, IHyperlinkDetector[] hyperlinkDetectors) {
    HashSet<StyleRange> styleRangeList = new HashSet<StyleRange>();
    if (hyperlinkDetectors != null && hyperlinkDetectors.length > 0) {
      IDocument doc = textViewer.getDocument();
      for (int line = 0; line < doc.getNumberOfLines(); line++) {
        try {
          IRegion region = doc.getLineInformation(line);
          for (IHyperlinkDetector hyperLinkDetector : hyperlinkDetectors) {
            IHyperlink[] hyperlinks = hyperLinkDetector
                .detectHyperlinks(textViewer, region, true);
            if (hyperlinks != null) {
              for (IHyperlink hyperlink : hyperlinks) {
                StyleRange hyperlinkStyleRange = new StyleRange(
                    hyperlink.getHyperlinkRegion()
                        .getOffset(), hyperlink
                        .getHyperlinkRegion()
                        .getLength(), Display
                        .getDefault().getSystemColor(
                            SWT.COLOR_BLUE),
                    Display.getDefault().getSystemColor(
                        SWT.COLOR_WHITE));
                hyperlinkStyleRange.underline = true;
                styleRangeList.add(hyperlinkStyleRange);
              }
            }
          }
        } catch (BadLocationException e) {
          Activator.logError(e.getMessage(), e);
          break;
        }
      }
    }
    StyleRange[] styleRangeArray = new StyleRange[styleRangeList.size()];
    styleRangeList.toArray(styleRangeArray);
    return styleRangeArray;
  }

  private static String getShowInMenuLabel() {
    IBindingService bindingService = (IBindingService) PlatformUI
        .getWorkbench().getAdapter(IBindingService.class);
    if (bindingService != null) {
      String keyBinding = bindingService
          .getBestActiveBindingFormattedFor(IWorkbenchCommandConstants.NAVIGATE_SHOW_IN_QUICK_MENU);
      if (keyBinding != null)
        return UIText.UIUtils_ShowInMenuLabel + '\t' + keyBinding;
    }

    return UIText.UIUtils_ShowInMenuLabel;
  }

  /**
   * Look up best active binding's keystroke for the given command
   *
   * @param commandId
   *            The identifier of the command for which the best active
   *            binding's keystroke should be retrieved; must not be null.
   * @return {@code KeyStroke} for the best active binding for the specified
   *         commandId or {@code null} if no binding is defined or if the
   *         binding service returns a {@code TriggerSequence} containing more
   *         than one {@code Trigger}.
   */
  public static KeyStroke getKeystrokeOfBestActiveBindingFor(String commandId) {
    IBindingService bindingService = (IBindingService) PlatformUI
        .getWorkbench().getAdapter(IBindingService.class);
    TriggerSequence ts = bindingService.getBestActiveBindingFor(commandId);
    if (ts == null)
      return null;

    Trigger[] triggers = ts.getTriggers();
    if (triggers.length == 1 && triggers[0] instanceof KeyStroke)
      return (KeyStroke) triggers[0];
    else
      return null;
  }

  /**
   * Copy from {@link org.eclipse.jface.dialogs.DialogPage} with changes to
   * accommodate the lack of a Dialog context.
   *
   * @param button
   *            the button to set the <code>GridData</code>
   */
  public static void setButtonLayoutData(Button button) {
    GC gc = new GC(button);
    gc.setFont(JFaceResources.getDialogFont());
    FontMetrics fontMetrics = gc.getFontMetrics();
    gc.dispose();

    GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
    int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics,
        IDialogConstants.BUTTON_WIDTH);
    Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
    data.widthHint = Math.max(widthHint, minSize.x);
    button.setLayoutData(data);
  }

  /**
   * Locates the current part and selection and fires
   * {@link ISelectionListener#selectionChanged(IWorkbenchPart, ISelection)}
   * on the passed listener.
   *
   * @param serviceLocator
   * @param selectionListener
   */
  public static void notifySelectionChangedWithCurrentSelection(
      ISelectionListener selectionListener, IServiceLocator serviceLocator) {
    IHandlerService handlerService = CommonUtils.getService(serviceLocator, IHandlerService.class);
    IEvaluationContext state = handlerService.getCurrentState();
    // This seems to be the most reliable way to get the active part, it
    // also returns a part when it is called while creating a view that is
    // being shown.Getting the active part through the active workbench
    // window returned null in that case.
    Object partObject = state.getVariable(ISources.ACTIVE_PART_NAME);
    Object selectionObject = state
        .getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
    if (partObject instanceof IWorkbenchPart
        && selectionObject instanceof ISelection) {
      IWorkbenchPart part = (IWorkbenchPart) partObject;
      ISelection selection = (ISelection) selectionObject;
      if (!selection.isEmpty())
        selectionListener.selectionChanged(part, selection);
    }
  }
}
TOP

Related Classes of org.eclipse.egit.ui.UIUtils$IPreviousValueProposalHandler

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.