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.
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
;
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
,
61 myComparer
= comparer
;
63 myOriginalItems
= items
;
64 myResultItems
= items
;
71 myResultItems
= myOriginalItems
;
74 myRoot
.removeAllChildren();
75 for (T item
: myOriginalItems
) {
76 addNewNode(myCloner
.cloneOf(item
));
82 protected void processRemovedItems() {
85 protected boolean wasObjectStored(Object editableObject
) {
89 protected String
subjDisplayName() {
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
);
108 private T
findByName(String name
) {
109 for (T item
: myItems
) {
110 if (Comparing
.equal(name
, myNamer
.getName(item
))) return item
;
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());
128 result
.add(new CopyAction());
133 private void addNewNode(T item
) {
134 addNode(new MyNode(new ItemConfigurable(item
)), myRoot
);
138 protected boolean canDelete(T item
) {
142 protected abstract UnnamedConfigurable
createConfigurable(T item
);
145 protected void onItemDeleted(Object item
) {
146 myItems
.remove((T
)item
);
149 protected void setDisplayName(T item
, String name
) {
150 myNamer
.setName(item
, name
);
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
);
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
);
178 myConfigurable
= createConfigurable(item
);
181 public void setDisplayName(String name
) {
182 NamedItemsListEditor
.this.setDisplayName(myItem
, name
);
185 public Object
getEditableObject() {
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);
208 public String
getHelpTopic() {
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();
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
{
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
);
271 selectNodeInTree(clone
);
276 public void update(AnActionEvent event
) {
278 event
.getPresentation().setEnabled(getSelectedObject() != null);
282 protected void onItemCloned(T clone
) {
285 private class AddAction
extends DumbAwareAction
{
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
)));
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
);
312 protected void onItemCreated(T newItem
) {
314 selectNodeInTree(newItem
);