From 07c3b8cfcb526636daaa2798698d01a3bcd05a3c Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 9 Jan 2014 14:59:38 +0100 Subject: [PATCH] extract CheckBoxListModelEditor, consolidate copy action button placement (file watchers vs external tools) --- .../com/intellij/tools/BaseToolsPanel.java | 4 +- .../src/com/intellij/ui/CheckBoxList.java | 27 ++- .../com/intellij/ui/ListToolbarDecorator.java | 11 +- .../util/ui/CheckBoxListModelEditor.java | 181 ++++++++++++++++++ .../ContainedInBranchesConfigDialog.java | 21 +- .../git4idea/history/wholeTree/GitLogUI.java | 12 +- .../ide/browsers/BrowserSettings.java | 20 +- 7 files changed, 234 insertions(+), 42 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/util/ui/CheckBoxListModelEditor.java diff --git a/platform/lang-impl/src/com/intellij/tools/BaseToolsPanel.java b/platform/lang-impl/src/com/intellij/tools/BaseToolsPanel.java index a0c933edb818..9a9f1bcc17ef 100644 --- a/platform/lang-impl/src/com/intellij/tools/BaseToolsPanel.java +++ b/platform/lang-impl/src/com/intellij/tools/BaseToolsPanel.java @@ -76,7 +76,6 @@ public abstract class BaseToolsPanel extends JPanel { private boolean myIsModified = false; protected BaseToolsPanel() { - myTree = new CheckboxTree( new CheckboxTree.CheckboxTreeCellRenderer() { @Override @@ -181,8 +180,7 @@ public abstract class BaseToolsPanel extends JPanel { myTree.requestFocus(); } } - }).setButtonComparator("Add", "Copy", "Edit", "Remove", "Up", "Down") - .createPanel(), BorderLayout.CENTER); + }).createPanel(), BorderLayout.CENTER); myAddButton = ToolbarDecorator.findAddButton(this); myEditButton = ToolbarDecorator.findEditButton(this); diff --git a/platform/platform-api/src/com/intellij/ui/CheckBoxList.java b/platform/platform-api/src/com/intellij/ui/CheckBoxList.java index 6dcd482bbe6b..5dfc570456dd 100644 --- a/platform/platform-api/src/com/intellij/ui/CheckBoxList.java +++ b/platform/platform-api/src/com/intellij/ui/CheckBoxList.java @@ -4,6 +4,7 @@ import com.intellij.ui.components.JBList; import com.intellij.util.Function; import com.intellij.util.containers.BidirectionalMap; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -23,7 +24,7 @@ import java.util.Map; public class CheckBoxList extends JBList { private static final int DEFAULT_CHECK_BOX_WIDTH = 20; private CheckBoxListListener checkBoxListListener; - private final BidirectionalMap myItemMap = new BidirectionalMap(); + private final BidirectionalMap myItemMap = new BidirectionalMap(); public CheckBoxList(final CheckBoxListListener checkBoxListListener) { this(new DefaultListModel(), checkBoxListListener); @@ -39,6 +40,7 @@ public class CheckBoxList extends JBList { public CheckBoxList(final DefaultListModel dataModel) { super(); + //noinspection unchecked setModel(dataModel); setCellRenderer(new CellRenderer()); setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -87,7 +89,8 @@ public class CheckBoxList extends JBList { public void setStringItems(final Map items) { clear(); for (Map.Entry entry : items.entrySet()) { - addItem(entry.getKey(), entry.getKey(), entry.getValue()); + //noinspection unchecked + addItem((T)entry.getKey(), entry.getKey(), entry.getValue()); } } @@ -99,19 +102,26 @@ public class CheckBoxList extends JBList { } } - private void addItem(Object item, String text, boolean selected) { + public void addItem(T item, String text, boolean selected) { JCheckBox checkBox = new JCheckBox(text, selected); myItemMap.put(item, checkBox); + //noinspection unchecked ((DefaultListModel) getModel()).addElement(checkBox); } - public Object getItemAt(int index) { + public void updateItem(@NotNull T oldItem, @NotNull T newItem) { + JCheckBox checkBox = myItemMap.remove(oldItem); + myItemMap.put(newItem, checkBox); + } + + @Nullable + public T getItemAt(int index) { JCheckBox checkBox = (JCheckBox)getModel().getElementAt(index); - List value = myItemMap.getKeysByValue(checkBox); + List value = myItemMap.getKeysByValue(checkBox); return value == null || value.isEmpty() ? null : value.get(0); } - private void clear() { + public void clear() { ((DefaultListModel) getModel()).clear(); myItemMap.clear(); } @@ -120,12 +130,12 @@ public class CheckBoxList extends JBList { return ((JCheckBox)getModel().getElementAt(index)).isSelected(); } - public boolean isItemSelected(Object item) { + public boolean isItemSelected(T item) { JCheckBox checkBox = myItemMap.get(item); return checkBox != null && checkBox.isSelected(); } - public void setItemSelected(Object item, boolean selected) { + public void setItemSelected(T item, boolean selected) { JCheckBox checkBox = myItemMap.get(item); if (checkBox != null) { checkBox.setSelected(selected); @@ -140,6 +150,7 @@ public class CheckBoxList extends JBList { // fire change notification in case if we've already initialized model final ListModel model = getModel(); if (model instanceof DefaultListModel) { + //noinspection unchecked ((DefaultListModel)model).setElementAt(getModel().getElementAt(index), index); } diff --git a/platform/platform-api/src/com/intellij/ui/ListToolbarDecorator.java b/platform/platform-api/src/com/intellij/ui/ListToolbarDecorator.java index 92fc31636dee..bfae84fcc02c 100644 --- a/platform/platform-api/src/com/intellij/ui/ListToolbarDecorator.java +++ b/platform/platform-api/src/com/intellij/ui/ListToolbarDecorator.java @@ -83,31 +83,34 @@ class ListToolbarDecorator extends ToolbarDecorator { protected void updateButtons() { final CommonActionsPanel p = getActionsPanel(); if (p != null) { + boolean someElementSelected; if (myList.isEnabled()) { final int index = myList.getSelectedIndex(); - if (0 <= index && index < myList.getModel().getSize()) { + someElementSelected = 0 <= index && index < myList.getModel().getSize(); + if (someElementSelected) { final boolean downEnable = myList.getMaxSelectionIndex() < myList.getModel().getSize() - 1; final boolean upEnable = myList.getMinSelectionIndex() > 0; final boolean editEnabled = myList.getSelectedIndices().length == 1; p.setEnabled(CommonActionsPanel.Buttons.EDIT, editEnabled); - p.setEnabled(CommonActionsPanel.Buttons.REMOVE, true); p.setEnabled(CommonActionsPanel.Buttons.UP, upEnable); p.setEnabled(CommonActionsPanel.Buttons.DOWN, downEnable); } else { p.setEnabled(CommonActionsPanel.Buttons.EDIT, false); - p.setEnabled(CommonActionsPanel.Buttons.REMOVE, false); p.setEnabled(CommonActionsPanel.Buttons.UP, false); p.setEnabled(CommonActionsPanel.Buttons.DOWN, false); } p.setEnabled(CommonActionsPanel.Buttons.ADD, true); } else { + someElementSelected = false; p.setEnabled(CommonActionsPanel.Buttons.ADD, false); - p.setEnabled(CommonActionsPanel.Buttons.REMOVE, false); p.setEnabled(CommonActionsPanel.Buttons.UP, false); p.setEnabled(CommonActionsPanel.Buttons.DOWN, false); } + + p.setEnabled(CommonActionsPanel.Buttons.REMOVE, someElementSelected); + updateExtraElementActions(someElementSelected); } } diff --git a/platform/platform-impl/src/com/intellij/util/ui/CheckBoxListModelEditor.java b/platform/platform-impl/src/com/intellij/util/ui/CheckBoxListModelEditor.java new file mode 100644 index 000000000000..a1a2b647b343 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/ui/CheckBoxListModelEditor.java @@ -0,0 +1,181 @@ +/* + * 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.util.ui; + +import com.intellij.ide.IdeBundle; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.util.Pair; +import com.intellij.ui.AnActionButton; +import com.intellij.ui.AnActionButtonRunnable; +import com.intellij.ui.CheckBoxList; +import com.intellij.ui.ToolbarDecorator; +import com.intellij.util.Consumer; +import com.intellij.util.EditSourceOnDoubleClickHandler; +import com.intellij.util.Function; +import com.intellij.util.PlatformIcons; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +public class CheckBoxListModelEditor { + private final CheckBoxList list; + private final ToolbarDecorator toolbarDecorator; + private final Function toNameConverter; + + public CheckBoxListModelEditor(@NotNull Function toNameConverter, @NotNull String emptyText) { + this.toNameConverter = toNameConverter; + list = new CheckBoxList(); + list.setEmptyText(emptyText); + // toolbar decorator is responsible for border + list.setBorder(null); + toolbarDecorator = ToolbarDecorator.createDecorator(list); + } + + @NotNull + public CheckBoxListModelEditor editAction(final @NotNull Function consumer) { + final Runnable action = new Runnable() { + @Override + public void run() { + T item = getSelectedItem(); + if (item != null) { + T newItem = consumer.fun(item); + if (newItem != null) { + list.updateItem(item, newItem); + } + list.repaint(); + list.requestFocus(); + } + } + }; + toolbarDecorator.setEditAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + action.run(); + } + }); + EditSourceOnDoubleClickHandler.install(list, action); + return this; + } + + @NotNull + public CheckBoxListModelEditor copyAction(final @NotNull Consumer consumer) { + toolbarDecorator.addExtraAction(new ToolbarDecorator.ElementActionButton(IdeBundle.message("button.copy"), PlatformIcons.COPY_ICON) { + @Override + public void actionPerformed(AnActionEvent e) { + int[] indices = list.getSelectedIndices(); + if (indices == null || indices.length == 0) { + return; + } + + for (int index : indices) { + T item = list.getItemAt(index); + if (item != null) { + consumer.consume(item); + } + } + } + }); + return this; + } + + public ToolbarDecorator getToolbar() { + return toolbarDecorator; + } + + @NotNull + public JComponent createComponent() { + return toolbarDecorator.createPanel(); + } + + @NotNull + public DefaultListModel getModel() { + return ((DefaultListModel)list.getModel()); + } + + public void selectItemByName(@NotNull String name) { + for (int i = 0; i < list.getItemsCount(); i++) { + T item = list.getItemAt(i); + if (item != null && name.equalsIgnoreCase(toNameConverter.fun(item))) { + list.setSelectedIndex(i); + } + } + } + + @Nullable + private T getSelectedItem() { + int index = list.getSelectedIndex(); + return index == -1 ? null : list.getItemAt(index); + } + + public CheckBoxList getList() { + return list; + } + + public void reset(@NotNull List> items) { + list.clear(); + for (Pair item : items) { + list.addItem(item.first, toNameConverter.fun(item.first), item.second); + } + } + + public boolean isModified(@NotNull List> oldItems) { + if (oldItems.size() != list.getItemsCount()) { + return true; + } + + for (int i = 0; i < list.getItemsCount(); i++) { + T item = list.getItemAt(i); + if (item == null) { + return true; + } + + Pair oldItem = oldItems.get(i); + if (oldItem.second != list.isItemSelected(i) || !oldItem.first.equals(item)) { + return true; + } + } + return false; + } + + @NotNull + public List getItems() { + int count = list.getItemsCount(); + List result = new ArrayList(count); + for (int i = 0; i < count; i++) { + T item = list.getItemAt(i); + if (item != null) { + result.add(item); + } + } + return result; + } + + @NotNull + public List> apply() { + int count = list.getItemsCount(); + List> result = new ArrayList>(count); + for (int i = 0; i < count; i++) { + T item = list.getItemAt(i); + if (item != null) { + result.add(Pair.create(item, list.isItemSelected(i))); + } + } + return result; + } +} \ No newline at end of file diff --git a/plugins/git4idea/src/git4idea/history/wholeTree/ContainedInBranchesConfigDialog.java b/plugins/git4idea/src/git4idea/history/wholeTree/ContainedInBranchesConfigDialog.java index 2afeca80c063..a9a2dfa2ba9d 100644 --- a/plugins/git4idea/src/git4idea/history/wholeTree/ContainedInBranchesConfigDialog.java +++ b/plugins/git4idea/src/git4idea/history/wholeTree/ContainedInBranchesConfigDialog.java @@ -37,12 +37,11 @@ import java.util.*; */ public class ContainedInBranchesConfigDialog extends DialogWrapper { private JPanel myPanel; - private CheckBoxList myLocalBranches; - private CheckBoxList myRemoteBranches; + private CheckBoxList myLocalBranches; + private CheckBoxList myRemoteBranches; private final Project myProject; private boolean myChanged; private JRadioButton myHighlight; - private JRadioButton myFilter; public ContainedInBranchesConfigDialog(final Project project, final Collection localBranches, Collection remoteBranches, final String currentLocal, final String currentRemote) { @@ -74,15 +73,15 @@ public class ContainedInBranchesConfigDialog extends DialogWrapper { final ButtonGroup bg = new ButtonGroup(); myHighlight = new JRadioButton("Highlight them"); - myFilter = new JRadioButton("Filter others out"); + JRadioButton filter = new JRadioButton("Filter others out"); bg.add(myHighlight); - bg.add(myFilter); + bg.add(filter); gb.gridwidth = 1; gb.gridx = 0; ++ gb.gridy; myPanel.add(myHighlight, gb); ++ gb.gridy; - myPanel.add(myFilter, gb); + myPanel.add(filter, gb); gb.insets.top = 10; gb.gridwidth = 1; @@ -108,7 +107,7 @@ public class ContainedInBranchesConfigDialog extends DialogWrapper { setItems(remoteBranches, gitLogSettings.getRemoteBranchesCopy(), myRemoteBranches); myHighlight.setSelected(gitLogSettings.isHighlight()); - myFilter.setSelected(! gitLogSettings.isHighlight()); + filter.setSelected(!gitLogSettings.isHighlight()); new ListSpeedSearch(myLocalBranches); new ListSpeedSearch(myRemoteBranches); @@ -134,7 +133,7 @@ public class ContainedInBranchesConfigDialog extends DialogWrapper { return myChanged; } - private static void setItems(Collection localBranches, Set localBranchesCopy, final CheckBoxList list) { + private static void setItems(Collection localBranches, Set localBranchesCopy, final CheckBoxList list) { // order final Map localBranchesState = new TreeMap(); for (String localBranch : localBranches) { @@ -163,9 +162,9 @@ public class ContainedInBranchesConfigDialog extends DialogWrapper { final GitLogSettings gitLogSettings = GitLogSettings.getInstance(myProject); final ArrayList local = gatherSelected((DefaultListModel)myLocalBranches.getModel()); final ArrayList remote = gatherSelected((DefaultListModel)myRemoteBranches.getModel()); - boolean hightlightChanged = gitLogSettings.isHighlight() != myHighlight.isSelected(); + boolean highlightChanged = gitLogSettings.isHighlight() != myHighlight.isSelected(); gitLogSettings.setHighlight(myHighlight.isSelected()); - if (gitLogSettings.setIfChanged(local, remote) || hightlightChanged) { + if (gitLogSettings.setIfChanged(local, remote) || highlightChanged) { myChanged = true; } super.doOKAction(); @@ -183,7 +182,7 @@ public class ContainedInBranchesConfigDialog extends DialogWrapper { return selected; } - private static class MyCheckBoxList extends CheckBoxList { + private static class MyCheckBoxList extends CheckBoxList { private final String myBold; private final static Border FOCUSED_BORDER = UIManager.getBorder("List.focusCellHighlightBorder"); private final EmptyBorder myEmptyBorder; diff --git a/plugins/git4idea/src/git4idea/history/wholeTree/GitLogUI.java b/plugins/git4idea/src/git4idea/history/wholeTree/GitLogUI.java index 02b2445d21c3..17414e76893e 100644 --- a/plugins/git4idea/src/git4idea/history/wholeTree/GitLogUI.java +++ b/plugins/git4idea/src/git4idea/history/wholeTree/GitLogUI.java @@ -117,7 +117,7 @@ public class GitLogUI implements Disposable { private boolean myStarted; private String myPreviousFilter; private final CommentSearchContext myCommentSearchContext; - private List myUsersSearchContext; + private final List myUsersSearchContext; private String mySelectedBranch; private BranchSelectorAction myBranchSelectorAction; private final DescriptionRenderer myDescriptionRenderer; @@ -159,7 +159,7 @@ public class GitLogUI implements Disposable { private JScrollPane myTableScrollPane; private GitLogUI.MyTextFieldAction myTextFieldAction; private DatesFilterI myDatesFilter; - private GitLogSettings mySettings; + private final GitLogSettings mySettings; public GitLogUI(Project project, final Mediator mediator) { myProject = project; @@ -481,7 +481,7 @@ public class GitLogUI implements Disposable { }); myBranchesLoaderImpl = new Consumer() { - private Processor myRecheck; + private final Processor myRecheck; { myRecheck = new Processor() { @@ -1043,7 +1043,7 @@ public class GitLogUI implements Disposable { private class DataProviderPanel extends JPanel implements TypeSafeDataProvider { - private GitCommitDetailsProvider myCommitDetailsProvider; + private final GitCommitDetailsProvider myCommitDetailsProvider; private DataProviderPanel(LayoutManager layout) { super(layout); @@ -1989,7 +1989,7 @@ public class GitLogUI implements Disposable { private final DumbAwareAction myMultiColorAction; private final DumbAwareAction myCalmAction; private final Icon myIcon; - private JLabel myLabel; + private final JLabel myLabel; private final GitLogUI.MySelectRootsForTreeAction myRootsForTreeAction; private final DumbAwareAction myDateOrder; private final DumbAwareAction myTopoOrder; @@ -2102,7 +2102,7 @@ public class GitLogUI implements Disposable { @Override public void actionPerformed(AnActionEvent e) { - final CheckBoxList checkBoxList = new CheckBoxList(); + final CheckBoxList checkBoxList = new CheckBoxList(); final List order = myTableModel.getOrder(); final Set activeRoots = myTableModel.getActiveRoots(); diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowserSettings.java b/xml/impl/src/com/intellij/ide/browsers/BrowserSettings.java index 2059f70ecc17..f6db37f4869e 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowserSettings.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowserSettings.java @@ -25,7 +25,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; public class BrowserSettings implements SearchableConfigurable, Configurable.NoScroll { - private BrowserSettingsPanel mySettingsPanel; + private BrowserSettingsPanel myPanel; @Override @NotNull @@ -52,33 +52,33 @@ public class BrowserSettings implements SearchableConfigurable, Configurable.NoS @Override public JComponent createComponent() { - if (mySettingsPanel == null) { - mySettingsPanel = new BrowserSettingsPanel(); + if (myPanel == null) { + myPanel = new BrowserSettingsPanel(); } - return mySettingsPanel.getComponent(); + return myPanel.getComponent(); } @Override public boolean isModified() { - return mySettingsPanel != null && mySettingsPanel.isModified(); + return myPanel != null && myPanel.isModified(); } @Override public void apply() throws ConfigurationException { - if (mySettingsPanel != null) { - mySettingsPanel.apply(); + if (myPanel != null) { + myPanel.apply(); } } @Override public void reset() { - if (mySettingsPanel != null) { - mySettingsPanel.reset(); + if (myPanel != null) { + myPanel.reset(); } } @Override public void disposeUIResources() { - mySettingsPanel = null; + myPanel = null; } }