blob: 585882aaf6586a8a96de1ba55a96ef3376d77bc4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Tom Hochstein (Freescale) - Bug 393703: NotHandledException selecting inactive command under 'Previous Choices' in Quick access
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 428050, 472654
* Brian de Alwis - Fix size computation to account for trim
* Markus Kuppe <bugs.eclipse.org@lemmster.de> - Bug 449485: [QuickAccess] "Widget is disposed" exception in errorlog during shutdown due to quickaccess.SearchField.storeDialog
* Elena Laskavaia <elaskavaia.cdt@gmail.com> - Bug 433746: [QuickAccess] SWTException on closing quick access shell
* Patrik Suzzi <psuzzi@gmail.com> - Bug 488926, 491278, 491291, 491312, 491293, 436788, 513436
******************************************************************************/
package org.eclipse.ui.internal.quickaccess;
import static org.eclipse.swt.events.MenuListener.menuHiddenAdapter;
import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;
import java.util.Arrays;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.e4.core.commands.ECommandService;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.di.extensions.Preference;
import org.eclipse.e4.ui.bindings.internal.BindingTableManager;
import org.eclipse.e4.ui.bindings.internal.ContextSet;
import org.eclipse.jface.bindings.Binding;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandImageService;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.internal.IPreferenceConstants;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.util.PrefUtil;
import org.eclipse.ui.keys.IBindingService;
public class SearchField {
private static final String QUICK_ACCESS_COMMAND_ID = "org.eclipse.ui.window.quickAccess"; //$NON-NLS-1$
private ToolItem quickAccessButton;
private Display display;
private ParameterizedCommand quickAccessCommand;
private TriggerSequence triggerSequence = null;
private Listener previousFocusListener = e -> {
if (e.widget instanceof Control && e.widget != quickAccessButton) {
previousFocusControl = (Control) e.widget;
}
};
private Control previousFocusControl;
@PostConstruct
void createControls(final Composite parent) {
this.quickAccessCommand = eCommandService.createCommand(QUICK_ACCESS_COMMAND_ID, null);
display = parent.getDisplay();
display.addFilter(SWT.FocusIn, previousFocusListener);
final Composite comp = new Composite(parent, SWT.NONE);
comp.setSize(SWT.DEFAULT, 32);
GridLayoutFactory.swtDefaults().margins(3, 3).applyTo(comp);
updateQuickAccessTriggerSequence();
quickAccessButton = createQuickAccessToolbar(comp);
updateQuickAccessText();
quickAccessButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
// release mouse button = click = CTRL+3 -> activate QuickAccess
activate(previousFocusControl);
}));
}
@Inject
@Optional
protected void keybindingPreferencesChanged(
@SuppressWarnings("restriction") @Preference(nodePath = "org.eclipse.ui.workbench", value = "org.eclipse.ui.commands") String preferenceValue) {
if (preferenceValue != null) {
updateQuickAccessText();
}
}
@Inject
private BindingTableManager manager;
@Inject
private ECommandService eCommandService;
@Inject
private IContextService contextService;
@Inject
private IBindingService bindingService;
@Inject
private ICommandImageService commandImageService;
/**
* Compute the best binding for the command and sets the trigger
*
*/
protected void updateQuickAccessTriggerSequence() {
triggerSequence = bindingService.getBestActiveBindingFor(QUICK_ACCESS_COMMAND_ID);
// FIXME Bug 491701 - [KeyBinding] get best active binding is not working
if (triggerSequence == null) {
ContextSet contextSet = manager.createContextSet(Arrays.asList(contextService.getDefinedContexts()));
Binding binding = manager.getBestSequenceFor(contextSet, quickAccessCommand);
triggerSequence = (binding == null) ? null : binding.getTriggerSequence();
}
}
private ToolItem createQuickAccessToolbar(Composite parent) {
Composite comp = new Composite(parent, SWT.NONE);
RowLayout layout = new RowLayout(SWT.HORIZONTAL);
layout.marginLeft = layout.marginRight = 8;
layout.marginBottom = 0;
layout.marginTop = 0;
comp.setLayout(layout);
ToolBar toolbar = new ToolBar(comp, SWT.FLAT | SWT.WRAP | SWT.RIGHT);
ToolItem quickAccessToolItem = new ToolItem(toolbar, SWT.PUSH);
if (PrefUtil.getAPIPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.SHOW_TEXT_ON_QUICK_ACCESS)) {
changeShowText(true, quickAccessToolItem);
}
ImageDescriptor imageDescriptor = commandImageService.getImageDescriptor(quickAccessCommand.getId());
if (imageDescriptor != null) {
Image image = imageDescriptor.createImage();
quickAccessToolItem.setImage(image);
quickAccessToolItem.addDisposeListener(e -> image.dispose());
}
toolbar.addMenuDetectListener(event -> {
openMenuFor(toolbar, quickAccessToolItem);
});
return quickAccessToolItem;
}
private void openMenuFor(ToolBar toolBar, ToolItem quickAccessToolItem) {
Menu menu = new Menu(toolBar);
new MenuItem(menu, SWT.SEPARATOR);
addShowTextItem(menu, quickAccessToolItem);
Rectangle bounds = toolBar.getBounds();
Point point = toolBar.toDisplay(bounds.x, bounds.y + bounds.height);
menu.setLocation(point.x, point.y);
menu.setVisible(true);
menu.addMenuListener(menuHiddenAdapter(e -> toolBar.getDisplay().asyncExec(menu::dispose)));
}
private void addShowTextItem(Menu menu, ToolItem quickAccessToolItem) {
MenuItem showtextMenuItem = new MenuItem(menu, SWT.CHECK);
showtextMenuItem.setText(WorkbenchMessages.PerspectiveBar_showText);
IPreferenceStore apiPreferenceStore = PrefUtil.getAPIPreferenceStore();
showtextMenuItem.addSelectionListener(widgetSelectedAdapter(e -> {
boolean preference = showtextMenuItem.getSelection();
if (preference != apiPreferenceStore
.getDefaultBoolean(IWorkbenchPreferenceConstants.SHOW_TEXT_ON_QUICK_ACCESS)) {
PrefUtil.getInternalPreferenceStore().setValue(IPreferenceConstants.OVERRIDE_PRESENTATION, true);
}
apiPreferenceStore.setValue(IWorkbenchPreferenceConstants.SHOW_TEXT_ON_QUICK_ACCESS, preference);
changeShowText(preference, quickAccessToolItem);
}));
showtextMenuItem
.setSelection(apiPreferenceStore.getBoolean(IWorkbenchPreferenceConstants.SHOW_TEXT_ON_QUICK_ACCESS));
}
private void changeShowText(boolean showText, ToolItem quickAccessToolItem) {
if (showText) {
try {
quickAccessToolItem.setText(quickAccessCommand.getName());
} catch (NotDefinedException e) {
e.printStackTrace();
}
} else {
quickAccessToolItem.setText(""); //$NON-NLS-1$
}
quickAccessButton.getParent().requestLayout();
}
private void updateQuickAccessText() {
if (quickAccessButton == null || quickAccessButton.isDisposed()) {
return;
}
updateQuickAccessTriggerSequence();
if (triggerSequence != null) {
quickAccessButton.setToolTipText(
NLS.bind(QuickAccessMessages.QuickAccess_TooltipDescription, triggerSequence.format()));
} else {
quickAccessButton.setToolTipText(QuickAccessMessages.QuickAccess_TooltipDescription_Empty);
}
quickAccessButton.getParent().requestLayout();
}
public void activate(final Control previousFocusControl) {
final QuickAccessDialog quickAccessDialog = new QuickAccessDialog(
PlatformUI.getWorkbench().getActiveWorkbenchWindow(), null);
quickAccessDialog.getShell().addDisposeListener(e -> {
if (previousFocusControl != null && !previousFocusControl.isDisposed()) {
previousFocusControl.setFocus();
} else {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window != null) {
window.getShell().setFocus();
}
}
});
quickAccessDialog.open();
}
@PreDestroy
void dispose() {
if (display != null && !display.isDisposed()) {
display.removeFilter(SWT.FocusIn, previousFocusListener);
}
}
}