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
.util
.*;
29 import com
.intellij
.util
.Icons
;
30 import com
.intellij
.util
.ui
.tree
.TreeUtil
;
31 import gnu
.trove
.Equality
;
32 import org
.jetbrains
.annotations
.Nullable
;
35 import javax
.swing
.tree
.DefaultMutableTreeNode
;
36 import javax
.swing
.tree
.TreeNode
;
37 import java
.awt
.event
.KeyEvent
;
38 import java
.text
.MessageFormat
;
39 import java
.util
.ArrayList
;
40 import java
.util
.Collections
;
41 import java
.util
.List
;
43 public abstract class NamedItemsListEditor
<T
> extends MasterDetailsComponent
{
44 private final Namer
<T
> myNamer
;
45 private final Factory
<T
> myFactory
;
46 private final Cloner
<T
> myCloner
;
47 private final List
<T
> myItems
= new ArrayList
<T
>();
48 private final Equality
<T
> myComparer
;
49 private List
<T
> myResultItems
;
50 private final List
<T
> myOriginalItems
;
52 protected NamedItemsListEditor(Namer
<T
> namer
,
60 myComparer
= comparer
;
62 myOriginalItems
= items
;
63 myResultItems
= items
;
70 myResultItems
= myOriginalItems
;
73 myRoot
.removeAllChildren();
74 for (T item
: myOriginalItems
) {
75 addNewNode(myCloner
.cloneOf(item
));
81 protected void processRemovedItems() {
84 protected boolean wasObjectStored(Object editableObject
) {
88 protected String
subjDisplayName() {
93 public String
askForProfileName(String titlePattern
) {
94 String title
= MessageFormat
.format(titlePattern
, subjDisplayName());
95 return Messages
.showInputDialog("New " + subjDisplayName() + " name:", title
, Messages
.getQuestionIcon(), "", new InputValidator() {
96 public boolean checkInput(String s
) {
97 return s
.length() > 0 && findByName(s
) == null;
100 public boolean canClose(String s
) {
101 return checkInput(s
);
107 private T
findByName(String name
) {
108 for (T item
: myItems
) {
109 if (Comparing
.equal(name
, myNamer
.getName(item
))) return item
;
116 protected ArrayList
<AnAction
> createActions(boolean fromPopup
) {
117 ArrayList
<AnAction
> result
= new ArrayList
<AnAction
>();
118 result
.add(new AddAction());
120 result
.add(new MyDeleteAction(new Condition
<Object
>() {
121 @SuppressWarnings({"unchecked"})
122 public boolean value(Object o
) {
123 return canDelete((T
) ((MyNode
) o
).getConfigurable().getEditableObject());
127 result
.add(new CopyAction());
132 private void addNewNode(T item
) {
133 addNode(new MyNode(new ItemConfigurable(item
)), myRoot
);
137 protected boolean canDelete(T item
) {
141 protected abstract UnnamedConfigurable
createConfigurable(T item
);
144 protected void onItemDeleted(Object item
) {
145 myItems
.remove((T
)item
);
148 protected void setDisplayName(T item
, String name
) {
149 myNamer
.setName(item
, name
);
153 protected UnnamedConfigurable
getItemConfigurable(final T item
) {
154 final Ref
<UnnamedConfigurable
> result
= new Ref
<UnnamedConfigurable
>();
155 TreeUtil
.traverse((TreeNode
)myTree
.getModel().getRoot(), new TreeUtil
.Traverse() {
156 public boolean accept(Object node
) {
157 final NamedConfigurable configurable
= (NamedConfigurable
)((DefaultMutableTreeNode
)node
).getUserObject();
158 if (configurable
.getEditableObject() == item
) {
159 result
.set(((ItemConfigurable
)configurable
).myConfigurable
);
170 private class ItemConfigurable
extends NamedConfigurable
{
171 private final T myItem
;
172 private final UnnamedConfigurable myConfigurable
;
174 public ItemConfigurable(T item
) {
175 super(myNamer
.canRename(item
), TREE_UPDATER
);
177 myConfigurable
= createConfigurable(item
);
180 public void setDisplayName(String name
) {
181 NamedItemsListEditor
.this.setDisplayName(myItem
, name
);
184 public Object
getEditableObject() {
188 public String
getBannerSlogan() {
189 return myNamer
.getName(myItem
);
192 public JComponent
createOptionsPanel() {
193 return myConfigurable
.createComponent();
196 public String
getDisplayName() {
197 return myNamer
.getName(myItem
);
200 public Icon
getIcon() {
201 if (myConfigurable
instanceof Iconable
) {
202 return ((Iconable
)myConfigurable
).getIcon(0);
207 public String
getHelpTopic() {
211 public boolean isModified() {
212 return myConfigurable
.isModified();
215 public void apply() throws ConfigurationException
{
216 myConfigurable
.apply();
219 public void reset() {
220 myConfigurable
.reset();
223 public void disposeUIResources() {
224 myConfigurable
.disposeUIResources();
229 public boolean isModified() {
230 if (myResultItems
.size() != myItems
.size()) return true;
232 for (int i
= 0; i
< myItems
.size(); i
++) {
233 if (!myComparer
.equals(myItems
.get(i
), myResultItems
.get(i
))) return true;
236 return super.isModified();
239 public void apply() throws ConfigurationException
{
241 myResultItems
= myItems
;
244 protected List
<T
> getCurrentItems() {
245 return Collections
.unmodifiableList(myItems
);
248 public List
<T
> getItems() {
249 return myResultItems
;
252 public T
getSelectedItem() {
253 return (T
) getSelectedObject();
257 private class CopyAction
extends AnAction
{
258 public CopyAction() {
259 super("Copy", "Copy", MasterDetailsComponent
.COPY_ICON
);
260 registerCustomShortcutSet(new CustomShortcutSet(KeyStroke
.getKeyStroke(KeyEvent
.VK_D
, KeyEvent
.CTRL_MASK
)), myTree
);
263 public void actionPerformed(AnActionEvent event
) {
264 final String profileName
= askForProfileName("Copy {0}");
265 if (profileName
== null) return;
267 final T clone
= myCloner
.copyOf((T
) getSelectedObject());
268 myNamer
.setName(clone
, profileName
);
270 selectNodeInTree(clone
);
275 public void update(AnActionEvent event
) {
277 event
.getPresentation().setEnabled(getSelectedObject() != null);
281 protected void onItemCloned(T clone
) {
284 private class AddAction
extends AnAction
{
286 super("Add", "Add", Icons
.ADD_ICON
);
287 registerCustomShortcutSet(CommonShortcuts
.INSERT
, myTree
);
290 public void actionPerformed(AnActionEvent event
) {
291 final T newItem
= createItem();
292 if (newItem
!= null) {
293 onItemCreated(newItem
);
298 public void selectItem(T item
) {
299 selectNodeInTree(findByName(myNamer
.getName(item
)));
303 protected T
createItem() {
304 final String name
= askForProfileName("Create new {0}");
305 if (name
== null) return null;
306 final T newItem
= myFactory
.create();
307 myNamer
.setName(newItem
, name
);
311 protected void onItemCreated(T newItem
) {
313 selectNodeInTree(newItem
);