| /******************************************************************************* |
| * Copyright (c) 2004, 2009 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.keys; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.SortedMap; |
| import java.util.TreeMap; |
| import org.eclipse.core.commands.Command; |
| import org.eclipse.core.commands.ParameterizedCommand; |
| import org.eclipse.core.commands.common.CommandException; |
| import org.eclipse.core.commands.common.NotDefinedException; |
| import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher; |
| import org.eclipse.jface.bindings.Binding; |
| import org.eclipse.jface.bindings.TriggerSequence; |
| import org.eclipse.jface.bindings.keys.KeySequence; |
| import org.eclipse.jface.bindings.keys.KeyStroke; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.PopupDialog; |
| import org.eclipse.jface.preference.PreferenceDialog; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Table; |
| import org.eclipse.swt.widgets.TableColumn; |
| import org.eclipse.swt.widgets.TableItem; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.IWorkbenchCommandConstants; |
| import org.eclipse.ui.activities.IActivityManager; |
| import org.eclipse.ui.commands.ICommandService; |
| import org.eclipse.ui.contexts.IContextService; |
| import org.eclipse.ui.dialogs.PreferencesUtil; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.keys.IBindingService; |
| |
| /** |
| * <p> |
| * A dialog displaying a list of key bindings. The dialog will execute a command |
| * if it is selected. |
| * </p> |
| * <p> |
| * The methods on this class are not thread-safe and must be run from the UI |
| * thread. |
| * </p> |
| * |
| * @since 3.1 |
| */ |
| final class KeyAssistDialog extends PopupDialog { |
| |
| /** |
| * The data key for the binding stored on an SWT widget. The key is a |
| * fully-qualified name, but in reverse order. This is so that the equals |
| * method will detect misses faster. |
| */ |
| private static final String BINDING_KEY = "Binding.bindings.jface.eclipse.org"; //$NON-NLS-1$ |
| |
| /** |
| * The value of <code>previousWidth</code> to set if there is no |
| * remembered width. |
| */ |
| private static final int NO_REMEMBERED_WIDTH = -1; |
| |
| /** |
| * The activity manager for the associated workbench. |
| */ |
| private final IActivityManager activityManager; |
| |
| /** |
| * The binding service for the associated workbench. |
| */ |
| private final IBindingService bindingService; |
| |
| /** |
| * The binding that was selected when the key assist dialog last closed. |
| * This is only remembered until <code>clearRememberedState()</code> is |
| * called. |
| */ |
| private Binding binding = null; |
| |
| /** |
| * The ordered list of command identifiers corresponding to the table. |
| */ |
| private final List bindings = new ArrayList(); |
| |
| /** |
| * The command service for the associated workbench. |
| */ |
| private final ICommandService commandService; |
| |
| /** |
| * The table containing of the possible completions. This value is |
| * <code>null</code> until the dialog is created. |
| */ |
| private Table completionsTable = null; |
| |
| /** |
| * Whether this dialog is currently holding some remembered state. |
| */ |
| private boolean hasRememberedState = false; |
| |
| /** |
| * The key binding state for the associated workbench. |
| */ |
| private final KeyBindingState keyBindingState; |
| |
| /** |
| * The width of the shell when it was previously open. This is only |
| * remembered until <code>clearRememberedState()</code> is called. |
| */ |
| private int previousWidth = NO_REMEMBERED_WIDTH; |
| |
| /** |
| * The key binding listener for the associated workbench. |
| */ |
| private final KeyBindingDispatcher workbenchKeyboard; |
| |
| /** |
| * A sorted map of conflicts to be used when the dialog pops up. |
| * |
| * @since 3.3 |
| */ |
| private SortedMap conflictMatches; |
| |
| /** |
| * Constructs a new instance of <code>KeyAssistDialog</code>. When the |
| * dialog is first constructed, it contains no widgets. The dialog is first |
| * created with no parent. If a parent is required, call |
| * <code>setParentShell()</code>. Also, between uses, it might be |
| * necessary to call <code>setParentShell()</code> as well. |
| * |
| * @param workbench |
| * The workbench in which this dialog is created; must not be |
| * <code>null</code>. |
| * @param associatedKeyboard |
| * The key binding listener for the workbench; must not be |
| * <code>null</code>. |
| * @param associatedState |
| * The key binding state associated with the workbench; must not |
| * be <code>null</code>. |
| */ |
| KeyAssistDialog(final IWorkbench workbench, |
| final KeyBindingDispatcher associatedKeyboard, |
| final KeyBindingState associatedState) { |
| super((Shell) null, PopupDialog.INFOPOPUP_SHELLSTYLE, true, false, |
| false, false, null, null); |
| |
| this.activityManager = workbench.getActivitySupport() |
| .getActivityManager(); |
| this.bindingService = (IBindingService) workbench |
| .getService(IBindingService.class); |
| this.commandService = (ICommandService) workbench |
| .getService(ICommandService.class); |
| this.keyBindingState = associatedState; |
| this.workbenchKeyboard = associatedKeyboard; |
| |
| this.setInfoText(getKeySequenceString()); |
| } |
| |
| /** |
| * Clears out the remembered state of the key assist dialog. This includes |
| * its width, as well as the selected binding. |
| */ |
| final void clearRememberedState() { |
| previousWidth = NO_REMEMBERED_WIDTH; |
| binding = null; |
| hasRememberedState = false; |
| } |
| |
| /** |
| * Closes this shell, but first remembers some state of the dialog. This way |
| * it will have a response if asked to open the dialog again or if asked to |
| * open the keys preference page. This does not remember the internal state. |
| * |
| * @return Whether the shell was already closed. |
| */ |
| public final boolean close() { |
| return close(false); |
| } |
| |
| /** |
| * Closes this shell, but first remembers some state of the dialog. This way |
| * it will have a response if asked to open the dialog again or if asked to |
| * open the keys preference page. |
| * |
| * @param rememberState |
| * Whether the internal state should be remembered. |
| * @return Whether the shell was already closed. |
| */ |
| public final boolean close(final boolean rememberState) { |
| return close(rememberState, true); |
| } |
| |
| /** |
| * Closes this shell, but first remembers some state of the dialog. This way |
| * it will have a response if asked to open the dialog again or if asked to |
| * open the keys preference page. |
| * |
| * @param rememberState |
| * Whether the internal state should be remembered. |
| * @param resetState |
| * Whether the state should be reset. |
| * @return Whether the shell was already closed. |
| */ |
| private final boolean close(final boolean rememberState, |
| final boolean resetState) { |
| final Shell shell = getShell(); |
| if (rememberState) { |
| // Remember the previous width. |
| final int widthToRemember; |
| if ((shell != null) && (!shell.isDisposed())) { |
| widthToRemember = getShell().getSize().x; |
| } else { |
| widthToRemember = NO_REMEMBERED_WIDTH; |
| } |
| |
| // Remember the selected command name and key sequence. |
| final Binding bindingToRemember; |
| if ((completionsTable != null) && (!completionsTable.isDisposed())) { |
| final int selectedIndex = completionsTable.getSelectionIndex(); |
| if (selectedIndex != -1) { |
| final TableItem selectedItem = completionsTable |
| .getItem(selectedIndex); |
| bindingToRemember = (Binding) selectedItem |
| .getData(BINDING_KEY); |
| } else { |
| bindingToRemember = null; |
| } |
| } else { |
| bindingToRemember = null; |
| } |
| |
| rememberState(widthToRemember, bindingToRemember); |
| completionsTable = null; |
| } |
| |
| if (resetState) { |
| keyBindingState.reset(); |
| } |
| return super.close(); |
| } |
| |
| /** |
| * Sets the position for the dialog based on the position of the workbench |
| * window. The dialog is flush with the bottom right corner of the workbench |
| * window. However, the dialog will not appear outside of the display's |
| * client area. |
| * |
| * @param size |
| * The final size of the dialog; must not be <code>null</code>. |
| */ |
| private final void configureLocation(final Point size) { |
| final Shell shell = getShell(); |
| |
| final Shell workbenchWindowShell = keyBindingState |
| .getAssociatedWindow().getShell(); |
| final int xCoord; |
| final int yCoord; |
| if (workbenchWindowShell != null) { |
| /* |
| * Position the shell at the bottom right corner of the workbench |
| * window |
| */ |
| final Rectangle workbenchWindowBounds = workbenchWindowShell |
| .getBounds(); |
| xCoord = workbenchWindowBounds.x + workbenchWindowBounds.width |
| - size.x - 10; |
| yCoord = workbenchWindowBounds.y + workbenchWindowBounds.height |
| - size.y - 10; |
| |
| } else { |
| xCoord = 0; |
| yCoord = 0; |
| |
| } |
| final Rectangle bounds = new Rectangle(xCoord, yCoord, size.x, size.y); |
| shell.setBounds(getConstrainedShellBounds(bounds)); |
| } |
| |
| /** |
| * Sets the size for the dialog based on its previous size. The width of the |
| * dialog is its previous width, if it exists. Otherwise, it is simply the |
| * packed width of the dialog. The maximum width is 40% of the workbench |
| * window's width. The dialog's height is the packed height of the dialog to |
| * a maximum of half the height of the workbench window. |
| * |
| * @return The size of the dialog |
| */ |
| private final Point configureSize() { |
| final Shell shell = getShell(); |
| |
| // Get the packed size of the shell. |
| shell.pack(); |
| final Point size = shell.getSize(); |
| |
| // Use the previous width if appropriate. |
| if ((previousWidth != NO_REMEMBERED_WIDTH) && (previousWidth > size.x)) { |
| size.x = previousWidth; |
| } |
| |
| // Enforce maximum sizing. |
| final Shell workbenchWindowShell = keyBindingState |
| .getAssociatedWindow().getShell(); |
| if (workbenchWindowShell != null) { |
| final Point workbenchWindowSize = workbenchWindowShell.getSize(); |
| final int maxWidth = workbenchWindowSize.x * 2 / 5; |
| final int maxHeight = workbenchWindowSize.y / 2; |
| if (size.x > maxWidth) { |
| size.x = maxWidth; |
| } |
| if (size.y > maxHeight) { |
| size.y = maxHeight; |
| } |
| } |
| |
| // Set the size for the shell. |
| shell.setSize(size); |
| return size; |
| } |
| |
| /** |
| * Returns a string representing the key sequence used to open this dialog. |
| * |
| * @return the string describing the key sequence, or <code>null</code> if |
| * it cannot be determined. |
| */ |
| private String getKeySequenceString() { |
| final Command command = commandService |
| .getCommand(IWorkbenchCommandConstants.WINDOW_SHOW_KEY_ASSIST); |
| final TriggerSequence[] keyBindings = bindingService |
| .getActiveBindingsFor(new ParameterizedCommand(command, null)); |
| final int keyBindingsCount = keyBindings.length; |
| final KeySequence currentState = keyBindingState.getCurrentSequence(); |
| final int prefixSize = currentState.getKeyStrokes().length; |
| |
| // Try to find the first possible matching key binding. |
| KeySequence keySequence = null; |
| for (int i = 0; i < keyBindingsCount; i++) { |
| keySequence = (KeySequence) keyBindings[i]; |
| |
| // Now just double-check to make sure the key is still possible. |
| if (prefixSize > 0) { |
| if (keySequence.startsWith(currentState, false)) { |
| /* |
| * Okay, so we have a partial match. Replace the key binding |
| * with the required suffix completion. |
| */ |
| final KeyStroke[] oldKeyStrokes = keySequence |
| .getKeyStrokes(); |
| final int newSize = oldKeyStrokes.length - prefixSize; |
| final KeyStroke[] newKeyStrokes = new KeyStroke[newSize]; |
| System.arraycopy(oldKeyStrokes, prefixSize, newKeyStrokes, |
| 0, newSize); |
| keySequence = KeySequence.getInstance(newKeyStrokes); |
| break; |
| } |
| |
| /* |
| * The prefix doesn't match, so null out the key binding and try |
| * again. |
| */ |
| keySequence = null; |
| continue; |
| |
| } |
| |
| // There is no prefix, so just grab the first. |
| break; |
| } |
| if (keySequence == null) { |
| return null; // couldn't find a suitable key binding |
| } |
| |
| return NLS.bind(KeyAssistMessages.openPreferencePage, keySequence |
| .format()); |
| } |
| |
| /** |
| * Creates the content area for the key assistant. This creates a table and |
| * places it inside the composite. The composite will contain a list of all |
| * the key bindings. |
| * |
| * @param parent |
| * The parent composite to contain the dialog area; must not be |
| * <code>null</code>. |
| */ |
| protected final Control createDialogArea(final Composite parent) { |
| // First, register the shell type with the context support |
| registerShellType(); |
| |
| // Create a composite for the dialog area. |
| final Composite composite = new Composite(parent, SWT.NONE); |
| final GridLayout compositeLayout = new GridLayout(); |
| compositeLayout.marginHeight = 0; |
| compositeLayout.marginWidth = 0; |
| composite.setLayout(compositeLayout); |
| composite.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| composite.setBackground(parent.getBackground()); |
| |
| // Layout the partial matches. |
| final SortedMap partialMatches; |
| if (conflictMatches != null) { |
| partialMatches = conflictMatches; |
| conflictMatches = null; |
| } else { |
| partialMatches = getPartialMatches(); |
| } |
| |
| if (partialMatches.isEmpty()) { |
| createEmptyDialogArea(composite); |
| } else { |
| createTableDialogArea(composite, partialMatches); |
| } |
| return composite; |
| } |
| |
| /** |
| * Creates an empty dialog area with a simple message saying there were no |
| * matches. This is used if no partial matches could be found. This should |
| * not really ever happen, but might be possible if the commands are |
| * changing while waiting for this dialog to open. |
| * |
| * @param parent |
| * The parent composite for the dialog area; must not be |
| * <code>null</code>. |
| */ |
| private final void createEmptyDialogArea(final Composite parent) { |
| final Label noMatchesLabel = new Label(parent, SWT.NULL); |
| noMatchesLabel.setText(KeyAssistMessages.NoMatches_Message); |
| noMatchesLabel.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| noMatchesLabel.setBackground(parent.getBackground()); |
| } |
| |
| /** |
| * Creates a dialog area with a table of the partial matches for the current |
| * key binding state. The table will be either the minimum width, or |
| * <code>previousWidth</code> if it is not |
| * <code>NO_REMEMBERED_WIDTH</code>. |
| * |
| * @param parent |
| * The parent composite for the dialog area; must not be |
| * <code>null</code>. |
| * @param partialMatches |
| * The lexicographically sorted map of partial matches for the |
| * current state; must not be <code>null</code> or empty. |
| */ |
| private final void createTableDialogArea(final Composite parent, |
| final SortedMap partialMatches) { |
| // Layout the table. |
| completionsTable = new Table(parent, SWT.FULL_SELECTION | SWT.SINGLE); |
| final GridData gridData = new GridData(GridData.FILL_BOTH); |
| completionsTable.setLayoutData(gridData); |
| completionsTable.setBackground(parent.getBackground()); |
| completionsTable.setLinesVisible(true); |
| |
| // Initialize the columns and rows. |
| bindings.clear(); |
| final TableColumn columnCommandName = new TableColumn(completionsTable, |
| SWT.LEFT, 0); |
| final TableColumn columnKeySequence = new TableColumn(completionsTable, |
| SWT.LEFT, 1); |
| final Iterator itemsItr = partialMatches.entrySet().iterator(); |
| while (itemsItr.hasNext()) { |
| final Map.Entry entry = (Map.Entry) itemsItr.next(); |
| final String sequence = (String) entry.getValue(); |
| final Binding binding = (Binding) entry.getKey(); |
| final ParameterizedCommand command = binding |
| .getParameterizedCommand(); |
| try { |
| final String[] text = { command.getName(), sequence }; |
| final TableItem item = new TableItem(completionsTable, SWT.NULL); |
| item.setText(text); |
| item.setData(BINDING_KEY, binding); |
| bindings.add(binding); |
| } catch (NotDefinedException e) { |
| // Not much to do, but this shouldn't really happen. |
| } |
| } |
| |
| Dialog.applyDialogFont(parent); |
| columnKeySequence.pack(); |
| if (previousWidth != NO_REMEMBERED_WIDTH) { |
| columnKeySequence.setWidth(previousWidth); |
| } |
| columnCommandName.pack(); |
| if (completionsTable.getItems().length > 0) { |
| completionsTable.setSelection(0); |
| } |
| |
| /* |
| * If you double-click on the table, it should execute the selected |
| * command. |
| */ |
| completionsTable.addListener(SWT.DefaultSelection, new Listener() { |
| public final void handleEvent(final Event event) { |
| executeKeyBinding(event); |
| } |
| }); |
| } |
| |
| /** |
| * Edits the remembered selection in the preference dialog. |
| */ |
| private final void editKeyBinding() { |
| // Create a preference dialog on the keys preference page. |
| final String keysPageId = "org.eclipse.ui.preferencePages.Keys"; //$NON-NLS-1$ |
| final PreferenceDialog dialog = PreferencesUtil |
| .createPreferenceDialogOn(getShell(), keysPageId, null, binding); |
| |
| /* |
| * Forget the remembered state (so we don't get stuck editing |
| * preferences). |
| */ |
| clearRememberedState(); |
| |
| // Open the dialog (blocking). |
| dialog.open(); |
| } |
| |
| /** |
| * Handles the default selection event on the table of possible completions. |
| * This attempts to execute the given command. |
| */ |
| private final void executeKeyBinding(final Event trigger) { |
| // Try to execute the corresponding command. |
| final int selectionIndex = completionsTable.getSelectionIndex(); |
| if (selectionIndex >= 0) { |
| final Binding binding = (Binding) bindings.get(selectionIndex); |
| try { |
| // workbenchKeyboard.updateShellKludge(null); |
| workbenchKeyboard.executeCommand(binding.getParameterizedCommand(), trigger); |
| } catch (final CommandException e) { |
| WorkbenchPlugin.log(binding.getParameterizedCommand().toString(), e); |
| } |
| } |
| } |
| |
| /** |
| * Gets the list of key bindings that are partial matches to the current key |
| * binding state. |
| * |
| * @return A sorted map of key sequences (KeySequence) to command identifier |
| * (String) representing the list of enabled commands that could |
| * possibly complete the current key sequence. |
| */ |
| private final SortedMap getPartialMatches() { |
| // Put all partial matches into the matches into the map. |
| final Map partialMatches = bindingService |
| .getPartialMatches(keyBindingState.getCurrentSequence()); |
| |
| // Create a sorted map that sorts based on lexicographical order. |
| final SortedMap sortedMatches = new TreeMap(new Comparator() { |
| public final int compare(final Object a, final Object b) { |
| final Binding bindingA = (Binding) a; |
| final Binding bindingB = (Binding) b; |
| final ParameterizedCommand commandA = bindingA |
| .getParameterizedCommand(); |
| final ParameterizedCommand commandB = bindingB |
| .getParameterizedCommand(); |
| try { |
| return commandA.getName().compareTo(commandB.getName()); |
| } catch (final NotDefinedException e) { |
| // should not happen |
| return 0; |
| } |
| } |
| }); |
| |
| /* |
| * Remove those partial matches for which either the command is not |
| * identified or the activity manager believes the command is not |
| * enabled. |
| */ |
| final Iterator partialMatchItr = partialMatches.entrySet().iterator(); |
| while (partialMatchItr.hasNext()) { |
| final Map.Entry entry = (Map.Entry) partialMatchItr.next(); |
| final Binding binding = (Binding) entry.getValue(); |
| final Command command = binding.getParameterizedCommand() |
| .getCommand(); |
| if (command.isDefined() |
| && activityManager.getIdentifier(command.getId()) |
| .isEnabled()) { |
| TriggerSequence bestActiveBindingFor = bindingService.getBestActiveBindingFor(binding.getParameterizedCommand()); |
| sortedMatches.put(binding, bestActiveBindingFor==null?null:bestActiveBindingFor.format()); |
| } |
| } |
| |
| return sortedMatches; |
| |
| } |
| |
| /** |
| * Returns whether the dialog is currently holding some remembered state. |
| * |
| * @return <code>true</code> if the dialog has remembered state; |
| * <code>false</code> otherwise. |
| */ |
| private final boolean hasRememberedState() { |
| return hasRememberedState; |
| } |
| |
| /** |
| * Opens this dialog. This method can be called multiple times on the same |
| * dialog. This only opens the dialog if there is no remembered state; if |
| * there is remembered state, then it tries to open the preference page |
| * instead. |
| * |
| * @return The return code from this dialog. |
| */ |
| public final int open() { |
| // If there is remember state, open the preference page. |
| if (hasRememberedState()) { |
| editKeyBinding(); |
| clearRememberedState(); |
| return Window.OK; |
| } |
| |
| // If the dialog is already open, dispose the shell and recreate it. |
| final Shell shell = getShell(); |
| if (shell != null) { |
| close(false, false); |
| } |
| create(); |
| |
| // Configure the size and location. |
| final Point size = configureSize(); |
| configureLocation(size); |
| |
| // Call the super method. |
| return super.open(); |
| } |
| |
| /** |
| * Opens this dialog with the list of bindings for the user to select from. |
| * |
| * @return The return code from this dialog. |
| * @since 3.3 |
| */ |
| public final int open(Collection bindings) { |
| conflictMatches = new TreeMap(new Comparator() { |
| public final int compare(final Object a, final Object b) { |
| final Binding bindingA = (Binding) a; |
| final Binding bindingB = (Binding) b; |
| final ParameterizedCommand commandA = bindingA |
| .getParameterizedCommand(); |
| final ParameterizedCommand commandB = bindingB |
| .getParameterizedCommand(); |
| try { |
| return commandA.getName().compareTo(commandB.getName()); |
| } catch (final NotDefinedException e) { |
| // should not happen |
| return 0; |
| } |
| } |
| }); |
| Iterator i = bindings.iterator(); |
| while (i.hasNext()) { |
| Binding b = (Binding) i.next(); |
| TriggerSequence bestActiveBindingFor = bindingService.getBestActiveBindingFor(b.getParameterizedCommand()); |
| conflictMatches.put(b, bestActiveBindingFor==null?null:bestActiveBindingFor.format()); |
| } |
| |
| // If the dialog is already open, dispose the shell and recreate it. |
| final Shell shell = getShell(); |
| if (shell != null) { |
| close(false, false); |
| } |
| create(); |
| |
| // Configure the size and location. |
| final Point size = configureSize(); |
| configureLocation(size); |
| |
| // Call the super method. |
| return super.open(); |
| } |
| |
| /** |
| * Registers the shell as the same type as its parent with the context |
| * support. This ensures that it does not modify the current state of the |
| * application. |
| */ |
| private final void registerShellType() { |
| final Shell shell = getShell(); |
| final IContextService contextService = (IContextService) keyBindingState |
| .getAssociatedWindow().getWorkbench().getService( |
| IContextService.class); |
| contextService.registerShell(shell, contextService |
| .getShellType((Shell) shell.getParent())); |
| } |
| |
| /** |
| * Remembers the current state of this dialog. |
| * |
| * @param previousWidth |
| * The previous width of the dialog. |
| * @param binding |
| * The binding to remember, may be <code>null</code> if none. |
| */ |
| private final void rememberState(final int previousWidth, |
| final Binding binding) { |
| this.previousWidth = previousWidth; |
| this.binding = binding; |
| hasRememberedState = true; |
| } |
| |
| /** |
| * Exposing this within the keys package. |
| * |
| * @param newParentShell |
| * The new parent shell; this value may be <code>null</code> if |
| * there is to be no parent. |
| */ |
| protected final void setParentShell(final Shell newParentShell) { |
| super.setParentShell(newParentShell); |
| } |
| } |