mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
644 lines
18 KiB
Java
644 lines
18 KiB
Java
/* ###
|
|
* IP: GHIDRA
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package docking;
|
|
|
|
import static org.junit.Assert.*;
|
|
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.KeyEvent;
|
|
import java.util.Set;
|
|
|
|
import javax.swing.*;
|
|
|
|
import org.junit.*;
|
|
|
|
import docking.action.*;
|
|
import docking.actions.KeyEntryDialog;
|
|
import docking.actions.ToolActions;
|
|
import docking.tool.util.DockingToolConstants;
|
|
import ghidra.framework.options.ToolOptions;
|
|
import ghidra.framework.plugintool.PluginTool;
|
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
|
import ghidra.test.TestEnv;
|
|
import ghidra.util.*;
|
|
import resources.Icons;
|
|
import resources.ResourceManager;
|
|
|
|
public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|
|
|
// note: this has to happen after the test framework is initialized, so it cannot be static
|
|
private final Icon ICON = ResourceManager.loadImage("images/refresh.png");
|
|
private static final String PROVIDER_NAME = "Test Action Provider";
|
|
private static final KeyStroke CONTROL_T =
|
|
KeyStroke.getKeyStroke(KeyEvent.VK_T, DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
|
|
|
private TestEnv env;
|
|
private PluginTool tool;
|
|
private TestActionsComponentProvider provider;
|
|
private SpyErrorLogger spyLogger = new SpyErrorLogger();
|
|
|
|
@Before
|
|
public void setUp() throws Exception {
|
|
env = new TestEnv();
|
|
tool = env.showTool();
|
|
|
|
//tool = env.launchDefaultTool();
|
|
provider = new TestActionsComponentProvider(tool);
|
|
|
|
Msg.setErrorLogger(spyLogger);
|
|
}
|
|
|
|
@After
|
|
public void tearDown() {
|
|
env.dispose();
|
|
}
|
|
|
|
@Test
|
|
public void testIcon_WithIcon_BeforeAddedToTool() {
|
|
|
|
setIcon(ICON);
|
|
|
|
showProvider();
|
|
|
|
assertWindowMenuActionHasIcon(ICON);
|
|
}
|
|
|
|
@Test
|
|
public void testIcon_WithIcon_AfterAddedToTool() {
|
|
|
|
setIcon(null);
|
|
|
|
showProvider();
|
|
assertWindowMenuActionHasIcon(Icons.EMPTY_ICON);
|
|
|
|
setIcon(ICON);
|
|
assertWindowMenuActionHasIcon(ICON);
|
|
}
|
|
|
|
@Test
|
|
public void testIcon_WithoutIcon() {
|
|
showProvider();
|
|
assertWindowMenuActionHasIcon(Icons.EMPTY_ICON);
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_DirectlyOnProvider() {
|
|
//
|
|
// This is how clients set key bindings on providers, as desired, when constructing them
|
|
//
|
|
|
|
KeyStroke defaultKs = CONTROL_T;
|
|
setDefaultKeyBinding(defaultKs);
|
|
|
|
showProvider();
|
|
|
|
assertProviderKeyStroke(defaultKs);
|
|
assertOptionsKeyStroke(defaultKs);
|
|
assertMenuItemHasKeyStroke(defaultKs);
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_DirectlyOnProvider_TransientProvider() {
|
|
//
|
|
// Transient providers cannot have key bindings
|
|
//
|
|
switchToTransientProvider();
|
|
|
|
setErrorsExpected(true);
|
|
setDefaultKeyBinding(CONTROL_T);
|
|
setErrorsExpected(false);
|
|
|
|
showProvider();
|
|
|
|
spyLogger.assertLogMessage("Transient", "cannot", "key", "binding");
|
|
}
|
|
|
|
@Test
|
|
public void testSetTransientAfterSettingKeyBinding() {
|
|
|
|
setDefaultKeyBinding(CONTROL_T);
|
|
|
|
setErrorsExpected(true);
|
|
switchToTransientProvider();
|
|
setErrorsExpected(false);
|
|
|
|
showProvider();
|
|
|
|
spyLogger.assertLogMessage("Transient", "not", "key", "binding");
|
|
}
|
|
|
|
@Test(expected = IllegalStateException.class)
|
|
public void testSetTransientAfterAddedProviderToTheTool() {
|
|
|
|
showProvider();
|
|
switchToTransientProvider(); // exception
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_ViaDialog_FromWindowMenu() {
|
|
|
|
showProvider();
|
|
|
|
KeyStroke newKs = CONTROL_T;
|
|
setKeyBindingViaF4Dialog_FromWindowsMenu(newKs);
|
|
|
|
assertProviderKeyStroke(newKs);
|
|
assertOptionsKeyStroke(newKs);
|
|
assertMenuItemHasKeyStroke(newKs);
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_ViaDialog_FromWindowMenu_ThenFireKeyEventToShowProvider() {
|
|
|
|
showProvider();
|
|
|
|
KeyStroke newKs = CONTROL_T;
|
|
setKeyBindingViaF4Dialog_FromWindowsMenu(newKs);
|
|
|
|
hideProvider();
|
|
triggerKey(tool.getToolFrame(), CONTROL_T);
|
|
assertProviderIsActive();
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_ViaDialog_FromWindowMenu_ToAlreadyBoundAction() {
|
|
|
|
//
|
|
// Test the conflicting key binding use case
|
|
//
|
|
|
|
HasDefaultKeyBindingComponentProvider otherProvider =
|
|
new HasDefaultKeyBindingComponentProvider(tool);
|
|
otherProvider.setVisible(true);
|
|
|
|
showProvider();
|
|
|
|
KeyStroke newKs = CONTROL_T;
|
|
applyBindingToDialog_FromWindowsMenu(newKs);
|
|
|
|
assertCollisionsWithKeyStroke();
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_ViaOptions_WithoutToolbarAction() {
|
|
|
|
showProvider();
|
|
|
|
KeyStroke newKs = CONTROL_T;
|
|
setOptionsKeyStroke(newKs);
|
|
|
|
assertProviderKeyStroke(newKs);
|
|
assertOptionsKeyStroke(newKs);
|
|
assertMenuItemHasKeyStroke(newKs);
|
|
assertNoToolbarAction();
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_ViaOptions_WithToolbarAction() {
|
|
|
|
setToolbarIcon(ICON);
|
|
showProvider();
|
|
|
|
KeyStroke newKs = CONTROL_T;
|
|
setOptionsKeyStroke(newKs);
|
|
|
|
assertProviderKeyStroke(newKs);
|
|
assertOptionsKeyStroke(newKs);
|
|
assertMenuItemHasKeyStroke(newKs);
|
|
assertToolbarAction();
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_ViaDialog_FromToolBar() {
|
|
|
|
setToolbarIcon(ICON);
|
|
showProvider();
|
|
|
|
KeyStroke newKs = CONTROL_T;
|
|
setKeyBindingViaF4Dialog_FromToolToolbar(newKs);
|
|
|
|
assertProviderKeyStroke(newKs);
|
|
assertOptionsKeyStroke(newKs);
|
|
assertMenuItemHasKeyStroke(newKs);
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_TransientProvider_CannotBeSetFromWindowMenu() {
|
|
|
|
switchToTransientProvider();
|
|
showProvider();
|
|
|
|
assertCannotShowKeyBindingDialog_FromWindowsMenu();
|
|
}
|
|
|
|
@Test
|
|
public void testSetKeyBinding_TransientProvider_CannotBeSetFromToolbar() {
|
|
|
|
switchToTransientProvider();
|
|
|
|
setErrorsExpected(true);
|
|
setToolbarIcon(ICON);
|
|
setErrorsExpected(false);
|
|
|
|
spyLogger.assertLogMessage("Transient", "not", "toolbar");
|
|
}
|
|
|
|
@Test
|
|
public void testDefaultKeyBindingAppearsInWindowMenu() {
|
|
|
|
setDefaultKeyBinding(CONTROL_T);
|
|
showProvider();
|
|
assertWindowMenuActionHasKeyBinding(CONTROL_T);
|
|
}
|
|
|
|
@Test
|
|
public void testAddToToolbar_WithoutIcon() {
|
|
|
|
runSwing(() -> provider.addToToolbar());
|
|
|
|
try {
|
|
setErrorsExpected(true);
|
|
runSwingWithExceptions(this::showProvider, true);
|
|
setErrorsExpected(false);
|
|
fail();
|
|
}
|
|
catch (Throwable t) {
|
|
// good
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testSetIcon_NullIconWithToolbarAction() {
|
|
|
|
setIcon(ICON);
|
|
runSwing(() -> provider.addToToolbar());
|
|
showProvider();
|
|
|
|
try {
|
|
setErrorsExpected(true);
|
|
runSwingWithExceptions(() -> provider.setIcon(null), true);
|
|
setErrorsExpected(false);
|
|
fail("Expected an exception passing a null icon when specifying a toolbar action");
|
|
}
|
|
catch (Throwable t) {
|
|
// expected
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testSetIcon_WithToolbarAction() {
|
|
setToolbarIcon(ICON);
|
|
showProvider();
|
|
|
|
assertWindowMenuActionHasIcon(ICON);
|
|
assertToolbarActionHasIcon(ICON);
|
|
}
|
|
|
|
@Test
|
|
public void testSetIcon_WithToolbarAction_AfterActionHasBeenAddedToToolbar() {
|
|
|
|
//
|
|
// We currently do not prevent providers from changing their icons. Make sure we respond
|
|
// to changes correctly.
|
|
//
|
|
|
|
setToolbarIcon(ICON);
|
|
showProvider();
|
|
|
|
Icon newIcon = Icons.COLLAPSE_ALL_ICON;
|
|
setIcon(newIcon);
|
|
|
|
assertWindowMenuActionHasIcon(newIcon);
|
|
assertToolbarActionHasIcon(newIcon);
|
|
}
|
|
|
|
@Test
|
|
public void testSetCloseButtonKeyBinding() {
|
|
|
|
showProvider();
|
|
|
|
KeyStroke controlEsc =
|
|
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
|
setKeyBindingViaF4Dialog_FromCloseButton(controlEsc);
|
|
|
|
// Note: there may be a test focus issue here. If this test fails sporadically due to
|
|
// how the action context is generated (it depends on focus). It is only useful to fail
|
|
// here in development mode.
|
|
triggerKey(tool.getToolFrame(), controlEsc);
|
|
assertProviderIsHidden_InNonBatchMode();
|
|
}
|
|
|
|
@Test
|
|
public void testEveryCloseButtonsActionContext() {
|
|
|
|
// grab the tool that has all the provider's loaded
|
|
env.closeTool(tool);
|
|
tool = env.launchDefaultTool();
|
|
|
|
DockingWindowManager dwm = tool.getWindowManager();
|
|
PlaceholderManager pm = dwm.getPlaceholderManager();
|
|
Set<ComponentProvider> allProviders = pm.getActiveProviders();
|
|
for (ComponentProvider cp : allProviders) {
|
|
ActionContext context = cp.getActionContext(null);
|
|
if (context == null) {
|
|
continue; // a null context is allowed
|
|
}
|
|
|
|
// this is a rule we need for context to work as intended for some actions (like the
|
|
// close button)
|
|
assertSame("Component provider did not make itself the context's provider",
|
|
context.getComponentProvider(), cp);
|
|
}
|
|
}
|
|
|
|
//==================================================================================================
|
|
// Private Methods
|
|
//==================================================================================================
|
|
|
|
private void switchToTransientProvider() {
|
|
provider.setTransient();
|
|
}
|
|
|
|
private void showProvider() {
|
|
provider.addToTool();
|
|
tool.showComponentProvider(provider, true);
|
|
waitForSwing();
|
|
}
|
|
|
|
private void hideProvider() {
|
|
tool.showComponentProvider(provider, false);
|
|
waitForSwing();
|
|
}
|
|
|
|
private void setDefaultKeyBinding(KeyStroke defaultKs) {
|
|
runSwing(() -> provider.setKeyBinding(new KeyBindingData(defaultKs)));
|
|
}
|
|
|
|
private void setIcon(Icon icon) {
|
|
runSwing(() -> provider.setIcon(icon));
|
|
}
|
|
|
|
private void setToolbarIcon(Icon icon) {
|
|
runSwing(() -> {
|
|
provider.setIcon(icon);
|
|
provider.addToToolbar();
|
|
});
|
|
}
|
|
|
|
private DockingActionIf getShowProviderAction() {
|
|
|
|
DockingActionIf showProviderAction =
|
|
getAction(tool, provider.getOwner(), provider.getName());
|
|
assertNotNull("Could not find action to show ", showProviderAction);
|
|
return showProviderAction;
|
|
}
|
|
|
|
private DockingActionIf getWindowMenuShowProviderAction() {
|
|
waitForSwing();
|
|
DockingActionIf action = waitFor(() -> {
|
|
Set<DockingActionIf> actions = getActionsByName(tool, PROVIDER_NAME);
|
|
|
|
//@formatter:off
|
|
return actions
|
|
.stream()
|
|
.filter(a -> a.getOwner().equals(DockingWindowManager.DOCKING_WINDOWS_OWNER))
|
|
.findFirst()
|
|
.orElseGet(() -> null)
|
|
;
|
|
//@formatter:on
|
|
});
|
|
|
|
assertNotNull("Window menu action not installed for provider", action);
|
|
assertTrue(action.getClass().getSimpleName().contains("ShowComponentAction"));
|
|
return action;
|
|
}
|
|
|
|
private DockingActionIf getToolbarShowProviderAction() {
|
|
|
|
DockingWindowManager dwm = tool.getWindowManager();
|
|
ActionToGuiMapper guiActions =
|
|
(ActionToGuiMapper) getInstanceField("actionToGuiMapper", dwm);
|
|
GlobalMenuAndToolBarManager toolbarManager =
|
|
(GlobalMenuAndToolBarManager) getInstanceField("menuAndToolBarManager", guiActions);
|
|
DockingActionIf action = provider.getShowProviderAction();
|
|
DockingActionIf toolbarAction = toolbarManager.getToolbarAction(action.getName());
|
|
return toolbarAction;
|
|
}
|
|
|
|
private void setOptionsKeyStroke(KeyStroke newKs) {
|
|
ToolOptions keyOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
|
|
|
// shared option name/format: "Provider Name (Shared)" - the shared action's owner is the Tool
|
|
runSwing(() -> keyOptions.setKeyStroke(provider.getName() + " (Shared)", newKs));
|
|
waitForSwing();
|
|
}
|
|
|
|
private void assertProviderIsActive() {
|
|
|
|
assertTrue("Component provider is not showing", runSwing(() -> tool.isVisible(provider)));
|
|
|
|
// note: we can't call 'isActive()' due to focus issues in parallel testing
|
|
//assertTrue("The test provider is not showing and focused",
|
|
// runSwing(() -> tool.isActive(provider)));
|
|
}
|
|
|
|
private void assertProviderIsHidden_InNonBatchMode() {
|
|
|
|
boolean isVisible = runSwing(() -> tool.isVisible(provider));
|
|
if (!SystemUtilities.isInTestingBatchMode()) {
|
|
assertFalse("The test provider is showing, but should be hidden", isVisible);
|
|
return;
|
|
}
|
|
|
|
if (isVisible) {
|
|
Msg.error(this,
|
|
"Provider should not be visible after pressing the 'close provider' key bindings");
|
|
}
|
|
}
|
|
|
|
private void assertNoToolbarAction() {
|
|
assertNull("No toolbar action found for provider", getToolbarShowProviderAction());
|
|
}
|
|
|
|
private void assertToolbarAction() {
|
|
assertNotNull("No toolbar action found for provider", getToolbarShowProviderAction());
|
|
}
|
|
|
|
private void assertProviderKeyStroke(KeyStroke expectedKs) {
|
|
|
|
DockingActionIf action = getShowProviderAction();
|
|
KeyStroke actionKs = action.getKeyBinding();
|
|
assertEquals(expectedKs, actionKs);
|
|
}
|
|
|
|
private void assertOptionsKeyStroke(KeyStroke expectedKs) {
|
|
|
|
ToolOptions options = getKeyBindingOptions();
|
|
|
|
// Option name: the action name with the 'Shared' owner
|
|
String fullName = provider.getName() + " (Shared)";
|
|
KeyStroke optionsKs = runSwing(() -> options.getKeyStroke(fullName, null));
|
|
assertEquals("Key stroke in options does not match expected key stroke", expectedKs,
|
|
optionsKs);
|
|
}
|
|
|
|
private void assertWindowMenuActionHasIcon(Icon expected) {
|
|
DockingActionIf action = getWindowMenuShowProviderAction();
|
|
assertEquals("Windows menu icons for provider does not match the value set on the provider",
|
|
expected, action.getMenuBarData().getMenuIcon());
|
|
}
|
|
|
|
private void assertToolbarActionHasIcon(Icon expected) {
|
|
DockingActionIf action = getToolbarShowProviderAction();
|
|
assertNotNull("No toolbar action found; it should be there", action);
|
|
ToolBarData tbData = action.getToolBarData();
|
|
assertEquals(expected, tbData.getIcon());
|
|
}
|
|
|
|
private void assertWindowMenuActionHasKeyBinding(KeyStroke ks) {
|
|
DockingActionIf action = getWindowMenuShowProviderAction();
|
|
assertEquals(
|
|
"Windows menu key bindings for provider does not match the value set on the provider",
|
|
ks, action.getKeyBinding());
|
|
}
|
|
|
|
private void assertCannotShowKeyBindingDialog_FromWindowsMenu() {
|
|
// simulate the user mousing over the 'Window' menu's action
|
|
DockingActionIf windowMenuAction = getWindowMenuShowProviderAction();
|
|
DockingWindowManager.setMouseOverAction(windowMenuAction);
|
|
|
|
performLaunchKeyStrokeDialogAction();
|
|
DialogComponentProvider warningDialog = waitForDialogComponent("Unable to Set Keybinding");
|
|
close(warningDialog);
|
|
}
|
|
|
|
private void setKeyBindingViaF4Dialog_FromWindowsMenu(KeyStroke ks) {
|
|
|
|
// simulate the user mousing over the 'Window' menu's action
|
|
DockingActionIf windowMenuAction = getWindowMenuShowProviderAction();
|
|
DockingWindowManager.setMouseOverAction(windowMenuAction);
|
|
|
|
performLaunchKeyStrokeDialogAction();
|
|
KeyEntryDialog dialog = waitForDialogComponent(KeyEntryDialog.class);
|
|
|
|
runSwing(() -> dialog.setKeyStroke(ks));
|
|
|
|
pressButtonByText(dialog, "OK");
|
|
|
|
assertFalse("Invalid key stroke: " + ks, runSwing(() -> dialog.isVisible()));
|
|
}
|
|
|
|
private void setKeyBindingViaF4Dialog_FromCloseButton(KeyStroke ks) {
|
|
|
|
// simulate the user mousing over the toolbar button
|
|
DockingActionIf closeAction = getAction(tool, provider.getOwner(), "Close Window");
|
|
assertNotNull("Provider action not installed in toolbar", closeAction);
|
|
DockingWindowManager.setMouseOverAction(closeAction);
|
|
|
|
performLaunchKeyStrokeDialogAction();
|
|
KeyEntryDialog dialog = waitForDialogComponent(KeyEntryDialog.class);
|
|
|
|
runSwing(() -> dialog.setKeyStroke(ks));
|
|
|
|
pressButtonByText(dialog, "OK");
|
|
|
|
assertFalse("Invalid key stroke: " + ks, runSwing(() -> dialog.isVisible()));
|
|
}
|
|
|
|
private void applyBindingToDialog_FromWindowsMenu(KeyStroke ks) {
|
|
DockingActionIf windowMenuAction = getWindowMenuShowProviderAction();
|
|
DockingWindowManager.setMouseOverAction(windowMenuAction);
|
|
|
|
performLaunchKeyStrokeDialogAction();
|
|
KeyEntryDialog dialog = waitForDialogComponent(KeyEntryDialog.class);
|
|
|
|
runSwing(() -> dialog.setKeyStroke(ks));
|
|
}
|
|
|
|
private void assertCollisionsWithKeyStroke() {
|
|
KeyEntryDialog dialog = waitForDialogComponent(KeyEntryDialog.class);
|
|
|
|
JTextPane collisionPane = (JTextPane) getInstanceField("collisionPane", dialog);
|
|
String collisionText = runSwing(() -> collisionPane.getText());
|
|
assertTrue(collisionText.contains("Actions mapped to"));
|
|
}
|
|
|
|
private void assertMenuItemHasKeyStroke(KeyStroke expected) {
|
|
|
|
DockingActionIf action = getWindowMenuShowProviderAction();
|
|
assertEquals(
|
|
"Windows menu key binding for provider does not match the value of the provider",
|
|
expected, action.getKeyBinding());
|
|
}
|
|
|
|
private void setKeyBindingViaF4Dialog_FromToolToolbar(KeyStroke ks) {
|
|
|
|
// simulate the user mousing over the toolbar button
|
|
DockingActionIf toolbarAction = getToolbarShowProviderAction();
|
|
assertNotNull("Provider action not installed in toolbar", toolbarAction);
|
|
DockingWindowManager.setMouseOverAction(toolbarAction);
|
|
|
|
performLaunchKeyStrokeDialogAction();
|
|
KeyEntryDialog dialog = waitForDialogComponent(KeyEntryDialog.class);
|
|
|
|
runSwing(() -> dialog.setKeyStroke(ks));
|
|
|
|
pressButtonByText(dialog, "OK");
|
|
|
|
assertFalse("Invalid key stroke: " + ks, runSwing(() -> dialog.isVisible()));
|
|
}
|
|
|
|
private void performLaunchKeyStrokeDialogAction() {
|
|
ToolActions toolActions = (ToolActions) ((AbstractDockingTool) tool).getToolActions();
|
|
Action action = toolActions.getAction(KeyStroke.getKeyStroke("F4"));
|
|
assertNotNull(action);
|
|
runSwing(() -> action.actionPerformed(new ActionEvent(this, 0, "")), false);
|
|
}
|
|
|
|
private ToolOptions getKeyBindingOptions() {
|
|
return tool.getOptions(DockingToolConstants.KEY_BINDINGS);
|
|
}
|
|
|
|
private class TestActionsComponentProvider extends ComponentProvider {
|
|
|
|
private JComponent component = new JTextField("Hey!");
|
|
|
|
TestActionsComponentProvider(Tool tool) {
|
|
super(tool, PROVIDER_NAME, "Fooberry Plugin");
|
|
}
|
|
|
|
@Override
|
|
public JComponent getComponent() {
|
|
return component;
|
|
}
|
|
}
|
|
|
|
private class HasDefaultKeyBindingComponentProvider extends ComponentProvider {
|
|
private JComponent component = new JTextField("Hey!");
|
|
|
|
HasDefaultKeyBindingComponentProvider(Tool tool) {
|
|
super(tool, HasDefaultKeyBindingComponentProvider.class.getSimpleName(),
|
|
"Fooberry Plugin");
|
|
|
|
setKeyBinding(new KeyBindingData(CONTROL_T));
|
|
}
|
|
|
|
@Override
|
|
public JComponent getComponent() {
|
|
return component;
|
|
}
|
|
}
|
|
}
|