blob: 80e3d1eec7fb7e1720f5beff67ce0bcbcf1cf0ca [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* 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 com.intellij.ui;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.ui.border.CustomLineBorder;
import com.intellij.ui.table.TableView;
import com.intellij.util.SmartList;
import com.intellij.util.ui.EditableModel;
import com.intellij.util.ui.ElementProducer;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* @author Konstantin Bulenkov
*
* @see #createDecorator(javax.swing.JList)
* @see #createDecorator(javax.swing.JTable)
* @see #createDecorator(javax.swing.JTree)
*/
@SuppressWarnings("UnusedDeclaration")
public abstract class ToolbarDecorator implements CommonActionsPanel.ListenerFactory {
protected Border myPanelBorder;
protected Border myToolbarBorder;
protected boolean myAddActionEnabled;
protected boolean myEditActionEnabled;
protected boolean myRemoveActionEnabled;
protected boolean myUpActionEnabled;
protected boolean myDownActionEnabled;
protected Border myActionsPanelBorder;
private final List<AnActionButton> myExtraActions = new SmartList<AnActionButton>();
private ActionToolbarPosition myToolbarPosition;
protected AnActionButtonRunnable myAddAction;
protected AnActionButtonRunnable myEditAction;
protected AnActionButtonRunnable myRemoveAction;
protected AnActionButtonRunnable myUpAction;
protected AnActionButtonRunnable myDownAction;
private String myAddName;
private String myEditName;
private String myRemoveName;
private String myMoveUpName;
private String myMoveDownName;
private AnActionButtonUpdater myAddActionUpdater = null;
private AnActionButtonUpdater myRemoveActionUpdater = null;
private AnActionButtonUpdater myEditActionUpdater = null;
private AnActionButtonUpdater myMoveUpActionUpdater = null;
private AnActionButtonUpdater myMoveDownActionUpdater = null;
private Dimension myPreferredSize;
private CommonActionsPanel myActionsPanel;
private Comparator<AnActionButton> myButtonComparator;
private boolean myAsUsualTopToolbar = false;
private Icon myAddIcon;
private boolean myForcedDnD = false;
protected abstract JComponent getComponent();
protected abstract void updateButtons();
protected void updateExtraElementActions(boolean someElementSelected) {
for (AnActionButton action : myExtraActions) {
if (action instanceof ElementActionButton) {
action.setEnabled(someElementSelected);
}
}
}
public final CommonActionsPanel getActionsPanel() {
return myActionsPanel;
}
public ToolbarDecorator initPosition() {
setToolbarPosition(SystemInfo.isMac ? ActionToolbarPosition.BOTTOM : ActionToolbarPosition.RIGHT);
return this;
}
public ToolbarDecorator setAsUsualTopToolbar() {
myAsUsualTopToolbar = true;
setToolbarPosition(ActionToolbarPosition.TOP);
return this;
}
public static ToolbarDecorator createDecorator(@NotNull JTable table) {
return new TableToolbarDecorator(table, null).initPosition();
}
public static ToolbarDecorator createDecorator(@NotNull JTree tree) {
return createDecorator(tree, null);
}
private static ToolbarDecorator createDecorator(@NotNull JTree tree, @Nullable ElementProducer<?> producer) {
return new TreeToolbarDecorator(tree, producer).initPosition();
}
public static ToolbarDecorator createDecorator(@NotNull JList list) {
return new ListToolbarDecorator(list, null).initPosition();
}
public static ToolbarDecorator createDecorator(@NotNull JList list, EditableModel editableModel) {
return new ListToolbarDecorator(list, editableModel).initPosition();
}
public static <T> ToolbarDecorator createDecorator(@NotNull TableView<T> table, @Nullable ElementProducer<T> producer) {
return new TableToolbarDecorator(table, producer).initPosition();
}
public ToolbarDecorator disableAddAction() {
myAddActionEnabled = false;
return this;
}
public ToolbarDecorator disableRemoveAction() {
myRemoveActionEnabled = false;
return this;
}
public ToolbarDecorator disableUpAction() {
myUpActionEnabled = false;
return this;
}
public ToolbarDecorator disableUpDownActions() {
myUpActionEnabled = false;
myDownActionEnabled = false;
return this;
}
public ToolbarDecorator disableDownAction() {
myDownActionEnabled = false;
return this;
}
public ToolbarDecorator setPanelBorder(Border border) {
myPanelBorder = border;
return this;
}
public ToolbarDecorator setToolbarBorder(Border border) {
myActionsPanelBorder = border;
return this;
}
public ToolbarDecorator setButtonComparator(Comparator<AnActionButton> buttonComparator) {
myButtonComparator = buttonComparator;
return this;
}
public ToolbarDecorator setButtonComparator(String...actionNames) {
final List<String> names = Arrays.asList(actionNames);
myButtonComparator = new Comparator<AnActionButton>() {
@Override
public int compare(AnActionButton o1, AnActionButton o2) {
final String t1 = o1.getTemplatePresentation().getText();
final String t2 = o2.getTemplatePresentation().getText();
if (t1 == null || t2 == null) return 0;
final int ind1 = names.indexOf(t1);
final int ind2 = names.indexOf(t2);
if (ind1 == -1 && ind2 >= 0) return 1;
if (ind2 == -1 && ind1 >= 0) return -1;
return ind1 - ind2;
}
};
return this;
}
public ToolbarDecorator setLineBorder(int top, int left, int bottom, int right) {
return setToolbarBorder(new CustomLineBorder(top, left, bottom, right));
}
public ToolbarDecorator addExtraAction(AnActionButton action) {
myExtraActions.add(action);
return this;
}
public ToolbarDecorator setToolbarPosition(ActionToolbarPosition position) {
myToolbarPosition = position;
myActionsPanelBorder = new CustomLineBorder(myToolbarPosition == ActionToolbarPosition.BOTTOM ? 1 : 0,
myToolbarPosition == ActionToolbarPosition.RIGHT ? 1 : 0,
myToolbarPosition == ActionToolbarPosition.TOP ? 1 : 0,
myToolbarPosition == ActionToolbarPosition.LEFT ? 1 : 0);
return this;
}
public ToolbarDecorator setAddAction(AnActionButtonRunnable action) {
myAddActionEnabled = action != null;
myAddAction = action;
return this;
}
public ToolbarDecorator setEditAction(AnActionButtonRunnable action) {
myEditActionEnabled = action != null;
myEditAction = action;
return this;
}
public ToolbarDecorator setRemoveAction(AnActionButtonRunnable action) {
myRemoveActionEnabled = action != null;
myRemoveAction = action;
return this;
}
public ToolbarDecorator setMoveUpAction(AnActionButtonRunnable action) {
myUpActionEnabled = action != null;
myUpAction = action;
return this;
}
public ToolbarDecorator setMoveDownAction(AnActionButtonRunnable action) {
myDownActionEnabled = action != null;
myDownAction = action;
return this;
}
public ToolbarDecorator setAddActionName(String name) {
myAddName = name;
return this;
}
public ToolbarDecorator setEditActionName(String name) {
myEditName = name;
return this;
}
public ToolbarDecorator setRemoveActionName(String name) {
myRemoveName = name;
return this;
}
public ToolbarDecorator setMoveUpActionName(String name) {
myMoveUpName = name;
return this;
}
public ToolbarDecorator setMoveDownActionName(String name) {
myMoveDownName = name;
return this;
}
public ToolbarDecorator setAddActionUpdater(AnActionButtonUpdater updater) {
myAddActionUpdater = updater;
return this;
}
public ToolbarDecorator setRemoveActionUpdater(AnActionButtonUpdater updater) {
myRemoveActionUpdater = updater;
return this;
}
public ToolbarDecorator setEditActionUpdater(AnActionButtonUpdater updater) {
myEditActionUpdater = updater;
return this;
}
public ToolbarDecorator setMoveUpActionUpdater(AnActionButtonUpdater updater) {
myMoveUpActionUpdater = updater;
return this;
}
public ToolbarDecorator setMoveDownActionUpdater(AnActionButtonUpdater updater) {
myMoveDownActionUpdater = updater;
return this;
}
public ToolbarDecorator setForcedDnD() {
myForcedDnD = true;
return this;
}
public ToolbarDecorator setActionGroup(@NotNull ActionGroup actionGroup) {
AnAction[] actions = actionGroup.getChildren(null);
for (AnAction action : actions) {
if (!(action instanceof Separator)) {
addExtraAction(AnActionButton.fromAction(action));
}
}
return this;
}
public ToolbarDecorator setPreferredSize(Dimension size) {
myPreferredSize = size;
return this;
}
public ToolbarDecorator setVisibleRowCount(int rowCount) {
return this;//do nothing by default
}
public ToolbarDecorator setAddIcon(Icon addIcon) {
myAddIcon = addIcon;
return this;
}
/**
* @return panel that contains wrapped component (with added scrollpane) and toolbar panel.
*/
public JPanel createPanel() {
final CommonActionsPanel.Buttons[] buttons = getButtons();
final JComponent contextComponent = getComponent();
myActionsPanel = new CommonActionsPanel(this, contextComponent,
myToolbarPosition,
myExtraActions.toArray(new AnActionButton[myExtraActions.size()]),
myButtonComparator,
myAddName, myRemoveName, myMoveUpName, myMoveDownName, myEditName,
myAddIcon, buttons);
final JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(contextComponent, true);
if (myPreferredSize != null) {
scrollPane.setPreferredSize(myPreferredSize);
}
final JPanel panel = new JPanel(new BorderLayout()) {
@Override
public void addNotify() {
super.addNotify();
updateButtons();
}
};
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(myActionsPanel, getPlacement());
installUpdaters();
updateButtons();
installDnD();
panel.putClientProperty(ActionToolbar.ACTION_TOOLBAR_PROPERTY_KEY, myActionsPanel.getComponent(0));
Border mainBorder = myPanelBorder != null ? myPanelBorder : IdeBorderFactory.createBorder(SideBorder.ALL);
if (myAsUsualTopToolbar) {
scrollPane.setBorder(mainBorder);
} else {
myActionsPanel.setBorder(myActionsPanelBorder);
panel.setBorder(mainBorder);
}
return panel;
}
private void installUpdaters() {
if (myAddActionEnabled && myAddAction != null && myAddActionUpdater != null) {
myActionsPanel.getAnActionButton(CommonActionsPanel.Buttons.ADD).addCustomUpdater(myAddActionUpdater);
}
if (myEditActionEnabled && myEditAction != null && myEditActionUpdater != null) {
myActionsPanel.getAnActionButton(CommonActionsPanel.Buttons.EDIT).addCustomUpdater(myEditActionUpdater);
}
if (myRemoveActionEnabled && myRemoveAction != null && myRemoveActionUpdater != null) {
myActionsPanel.getAnActionButton(CommonActionsPanel.Buttons.REMOVE).addCustomUpdater(myRemoveActionUpdater);
}
if (myUpActionEnabled && myUpAction != null && myMoveUpActionUpdater != null) {
myActionsPanel.getAnActionButton(CommonActionsPanel.Buttons.UP).addCustomUpdater(myMoveUpActionUpdater);
}
if (myDownActionEnabled && myDownAction != null && myMoveDownActionUpdater != null) {
myActionsPanel.getAnActionButton(CommonActionsPanel.Buttons.DOWN).addCustomUpdater(myMoveDownActionUpdater);
}
}
protected void installDnD() {
if ((myForcedDnD || (myUpAction != null && myUpActionEnabled
&& myDownAction != null && myDownActionEnabled))
&& !ApplicationManager.getApplication().isHeadlessEnvironment()
&& isModelEditable()) {
installDnDSupport();
}
}
protected abstract void installDnDSupport();
protected abstract boolean isModelEditable();
private Object getPlacement() {
switch (myToolbarPosition) {
case TOP: return BorderLayout.NORTH;
case LEFT: return BorderLayout.WEST;
case BOTTOM: return BorderLayout.SOUTH;
case RIGHT: return BorderLayout.EAST;
}
return BorderLayout.SOUTH;
}
private CommonActionsPanel.Buttons[] getButtons() {
final ArrayList<CommonActionsPanel.Buttons> buttons = new ArrayList<CommonActionsPanel.Buttons>();
final HashMap<CommonActionsPanel.Buttons, Pair<Boolean, AnActionButtonRunnable>> map =
new HashMap<CommonActionsPanel.Buttons, Pair<Boolean, AnActionButtonRunnable>>();
map.put(CommonActionsPanel.Buttons.ADD, Pair.create(myAddActionEnabled, myAddAction));
map.put(CommonActionsPanel.Buttons.REMOVE, Pair.create(myRemoveActionEnabled, myRemoveAction));
map.put(CommonActionsPanel.Buttons.EDIT, Pair.create(myEditActionEnabled, myEditAction));
map.put(CommonActionsPanel.Buttons.UP, Pair.create(myUpActionEnabled, myUpAction));
map.put(CommonActionsPanel.Buttons.DOWN, Pair.create(myDownActionEnabled, myDownAction));
for (CommonActionsPanel.Buttons button : CommonActionsPanel.Buttons.values()) {
final Pair<Boolean, AnActionButtonRunnable> action = map.get(button);
if (action != null && action.first != null && action.first && action.second != null) {
buttons.add(button);
}
}
return buttons.toArray(new CommonActionsPanel.Buttons[buttons.size()]);
}
@Override
public CommonActionsPanel.Listener createListener(final CommonActionsPanel panel) {
return new CommonActionsPanel.Listener() {
@Override
public void doAdd() {
if (myAddAction != null) {
myAddAction.run(panel.getAnActionButton(CommonActionsPanel.Buttons.ADD));
}
}
@Override
public void doEdit() {
if (myEditAction != null) {
myEditAction.run(panel.getAnActionButton(CommonActionsPanel.Buttons.EDIT));
}
}
@Override
public void doRemove() {
if (myRemoveAction != null) {
myRemoveAction.run(panel.getAnActionButton(CommonActionsPanel.Buttons.REMOVE));
}
}
@Override
public void doUp() {
if (myUpAction != null) {
myUpAction.run(panel.getAnActionButton(CommonActionsPanel.Buttons.UP));
}
}
@Override
public void doDown() {
if (myDownAction != null) {
myDownAction.run(panel.getAnActionButton(CommonActionsPanel.Buttons.DOWN));
}
}
};
}
public static AnActionButton findAddButton(@NotNull JComponent container) {
return findButton(container, CommonActionsPanel.Buttons.ADD);
}
public static AnActionButton findEditButton(@NotNull JComponent container) {
return findButton(container, CommonActionsPanel.Buttons.EDIT);
}
public static AnActionButton findRemoveButton(@NotNull JComponent container) {
return findButton(container, CommonActionsPanel.Buttons.REMOVE);
}
public static AnActionButton findUpButton(@NotNull JComponent container) {
return findButton(container, CommonActionsPanel.Buttons.UP);
}
public static AnActionButton findDownButton(@NotNull JComponent container) {
return findButton(container, CommonActionsPanel.Buttons.DOWN);
}
private static AnActionButton findButton(JComponent comp, CommonActionsPanel.Buttons type) {
final CommonActionsPanel panel = UIUtil.findComponentOfType(comp, CommonActionsPanel.class);
if (panel != null) {
return panel.getAnActionButton(type);
}
//noinspection ConstantConditions
return null;
}
/**
* Marker interface, button will be disabled if no selected element
*/
public abstract static class ElementActionButton extends AnActionButton {
public ElementActionButton(String text, String description, @Nullable Icon icon) {
super(text, description, icon);
}
public ElementActionButton(String text, Icon icon) {
super(text, icon);
}
public ElementActionButton() {
}
public ElementActionButton(String text) {
super(text);
}
}
}