item list editor: Add and Copy actions are dumb aware (part of WI-1002)
[fedora-idea.git] / platform / platform-api / src / com / intellij / openapi / ui / NamedItemsListEditor.java
blob19d51954a0873ebc0f3dfcd0b0e6291b567cfb83
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * @author max
20 package com.intellij.openapi.ui;
22 import com.intellij.openapi.actionSystem.AnAction;
23 import com.intellij.openapi.actionSystem.AnActionEvent;
24 import com.intellij.openapi.actionSystem.CommonShortcuts;
25 import com.intellij.openapi.actionSystem.CustomShortcutSet;
26 import com.intellij.openapi.options.ConfigurationException;
27 import com.intellij.openapi.options.UnnamedConfigurable;
28 import com.intellij.openapi.project.DumbAwareAction;
29 import com.intellij.openapi.util.*;
30 import com.intellij.util.Icons;
31 import com.intellij.util.ui.tree.TreeUtil;
32 import gnu.trove.Equality;
33 import org.jetbrains.annotations.Nullable;
35 import javax.swing.*;
36 import javax.swing.tree.DefaultMutableTreeNode;
37 import javax.swing.tree.TreeNode;
38 import java.awt.event.KeyEvent;
39 import java.text.MessageFormat;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.List;
44 public abstract class NamedItemsListEditor<T> extends MasterDetailsComponent {
45 private final Namer<T> myNamer;
46 private final Factory<T> myFactory;
47 private final Cloner<T> myCloner;
48 private final List<T> myItems = new ArrayList<T>();
49 private final Equality<T> myComparer;
50 private List<T> myResultItems;
51 private final List<T> myOriginalItems;
53 protected NamedItemsListEditor(Namer<T> namer,
54 Factory<T> factory,
55 Cloner<T> cloner,
56 Equality<T> comparer,
57 List<T> items) {
58 myNamer = namer;
59 myFactory = factory;
60 myCloner = cloner;
61 myComparer = comparer;
63 myOriginalItems = items;
64 myResultItems = items;
65 reset();
67 initTree();
70 public void reset() {
71 myResultItems = myOriginalItems;
72 myItems.clear();
74 myRoot.removeAllChildren();
75 for (T item : myOriginalItems) {
76 addNewNode(myCloner.cloneOf(item));
79 super.reset();
82 protected void processRemovedItems() {
85 protected boolean wasObjectStored(Object editableObject) {
86 return true;
89 protected String subjDisplayName() {
90 return "item";
93 @Nullable
94 public String askForProfileName(String titlePattern) {
95 String title = MessageFormat.format(titlePattern, subjDisplayName());
96 return Messages.showInputDialog("New " + subjDisplayName() + " name:", title, Messages.getQuestionIcon(), "", new InputValidator() {
97 public boolean checkInput(String s) {
98 return s.length() > 0 && findByName(s) == null;
101 public boolean canClose(String s) {
102 return checkInput(s);
107 @Nullable
108 private T findByName(String name) {
109 for (T item : myItems) {
110 if (Comparing.equal(name, myNamer.getName(item))) return item;
113 return null;
116 @Nullable
117 protected ArrayList<AnAction> createActions(boolean fromPopup) {
118 ArrayList<AnAction> result = new ArrayList<AnAction>();
119 result.add(new AddAction());
121 result.add(new MyDeleteAction(new Condition<Object>() {
122 @SuppressWarnings({"unchecked"})
123 public boolean value(Object o) {
124 return canDelete((T) ((MyNode) o).getConfigurable().getEditableObject());
126 }));
128 result.add(new CopyAction());
130 return result;
133 private void addNewNode(T item) {
134 addNode(new MyNode(new ItemConfigurable(item)), myRoot);
135 myItems.add(item);
138 protected boolean canDelete(T item) {
139 return true;
142 protected abstract UnnamedConfigurable createConfigurable(T item);
144 @Override
145 protected void onItemDeleted(Object item) {
146 myItems.remove((T)item);
149 protected void setDisplayName(T item, String name) {
150 myNamer.setName(item, name);
153 @Nullable
154 protected UnnamedConfigurable getItemConfigurable(final T item) {
155 final Ref<UnnamedConfigurable> result = new Ref<UnnamedConfigurable>();
156 TreeUtil.traverse((TreeNode)myTree.getModel().getRoot(), new TreeUtil.Traverse() {
157 public boolean accept(Object node) {
158 final NamedConfigurable configurable = (NamedConfigurable)((DefaultMutableTreeNode)node).getUserObject();
159 if (configurable.getEditableObject() == item) {
160 result.set(((ItemConfigurable)configurable).myConfigurable);
161 return false;
163 else {
164 return true;
168 return result.get();
171 private class ItemConfigurable extends NamedConfigurable {
172 private final T myItem;
173 private final UnnamedConfigurable myConfigurable;
175 public ItemConfigurable(T item) {
176 super(myNamer.canRename(item), TREE_UPDATER);
177 myItem = item;
178 myConfigurable = createConfigurable(item);
181 public void setDisplayName(String name) {
182 NamedItemsListEditor.this.setDisplayName(myItem, name);
185 public Object getEditableObject() {
186 return myItem;
189 public String getBannerSlogan() {
190 return myNamer.getName(myItem);
193 public JComponent createOptionsPanel() {
194 return myConfigurable.createComponent();
197 public String getDisplayName() {
198 return myNamer.getName(myItem);
201 public Icon getIcon() {
202 if (myConfigurable instanceof Iconable) {
203 return ((Iconable)myConfigurable).getIcon(0);
205 return null;
208 public String getHelpTopic() {
209 return null;
212 public boolean isModified() {
213 return myConfigurable.isModified();
216 public void apply() throws ConfigurationException {
217 myConfigurable.apply();
220 public void reset() {
221 myConfigurable.reset();
224 public void disposeUIResources() {
225 myConfigurable.disposeUIResources();
229 @Override
230 public boolean isModified() {
231 if (myResultItems.size() != myItems.size()) return true;
233 for (int i = 0; i < myItems.size(); i++) {
234 if (!myComparer.equals(myItems.get(i), myResultItems.get(i))) return true;
237 return super.isModified();
240 public void apply() throws ConfigurationException {
241 super.apply();
242 myResultItems = myItems;
245 protected List<T> getCurrentItems() {
246 return Collections.unmodifiableList(myItems);
249 public List<T> getItems() {
250 return myResultItems;
253 public T getSelectedItem() {
254 return (T) getSelectedObject();
258 private class CopyAction extends DumbAwareAction {
259 public CopyAction() {
260 super("Copy", "Copy", MasterDetailsComponent.COPY_ICON);
261 registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.CTRL_MASK)), myTree);
264 public void actionPerformed(AnActionEvent event) {
265 final String profileName = askForProfileName("Copy {0}");
266 if (profileName == null) return;
268 final T clone = myCloner.copyOf((T) getSelectedObject());
269 myNamer.setName(clone, profileName);
270 addNewNode(clone);
271 selectNodeInTree(clone);
272 onItemCloned(clone);
276 public void update(AnActionEvent event) {
277 super.update(event);
278 event.getPresentation().setEnabled(getSelectedObject() != null);
282 protected void onItemCloned(T clone) {
285 private class AddAction extends DumbAwareAction {
286 public AddAction() {
287 super("Add", "Add", Icons.ADD_ICON);
288 registerCustomShortcutSet(CommonShortcuts.INSERT, myTree);
291 public void actionPerformed(AnActionEvent event) {
292 final T newItem = createItem();
293 if (newItem != null) {
294 onItemCreated(newItem);
299 public void selectItem(T item) {
300 selectNodeInTree(findByName(myNamer.getName(item)));
303 @Nullable
304 protected T createItem() {
305 final String name = askForProfileName("Create new {0}");
306 if (name == null) return null;
307 final T newItem = myFactory.create();
308 myNamer.setName(newItem, name);
309 return newItem;
312 protected void onItemCreated(T newItem) {
313 addNewNode(newItem);
314 selectNodeInTree(newItem);