1 /*
2 * Copyright (c) 2003-2008 by Cosylab d. d.
3 *
4 * This file is part of CosyBeans-Common.
5 *
6 * CosyBeans-Common is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CosyBeans-Common is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CosyBeans-Common. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package com.cosylab.gui.components.customizer;
21
22 import java.awt.Color;
23 import java.beans.Customizer;
24 import java.beans.PropertyChangeEvent;
25 import java.beans.PropertyChangeListener;
26 import java.lang.reflect.InvocationTargetException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.Iterator;
31
32 import javax.swing.JComponent;
33 import javax.swing.JSplitPane;
34 import javax.swing.border.LineBorder;
35 import javax.swing.table.TableModel;
36
37 import com.cosylab.gui.components.introspection.BeanPropertiesTableModel;
38 import com.cosylab.gui.components.introspection.DefaultPropertiesTable;
39 import com.cosylab.util.Debug;
40 import com.cosylab.util.ObjectList;
41
42 /**
43 * A bridge between java.bean.Customizer and Cosy style Customizers.
44 *
45 * @author Alen Vrecko
46 *
47 */
48 public class CustomizerEditor extends JSplitPane implements Customizer, Editor {
49
50 private static final long serialVersionUID = 1L;
51
52 private DefaultPropertiesTable defaultPropertiesTable = null;
53
54 private HashMap<String, ArrayList> customEditors = null;
55
56 private HashMap defaultPropertiesTableModels = null;
57
58 private Object displayer = null;
59
60 private ObjectList activeEditors = null;
61
62 /**
63 * Cunstructs an empty editor.
64 */
65 public CustomizerEditor() {
66
67 defaultPropertiesTableModels = new HashMap();
68 customEditors = new HashMap<String, ArrayList>();
69 activeEditors = new ObjectList(Editor.class);
70 defaultPropertiesTable = new DefaultPropertiesTable();
71 defaultPropertiesTable.setBorder(new LineBorder(Color.BLACK));
72
73 defaultPropertiesTable
74 .addPropertyChangeListener(new PropertyChangeListener() {
75
76 public void propertyChange(PropertyChangeEvent evt) {
77 firePropertyChange(evt.getPropertyName(), null, evt
78 .getNewValue());
79 applyTableProperties();
80
81 }
82 });
83 }
84
85 /**
86 * <p>
87 * Should return names of properties of a dispalyer to be edited within the
88 * sepcified aspect through generic proeprty tables. This empty
89 * implementation however returns null.
90 * </p>
91 *
92 * <p>
93 * Subclasses should override this method to return arrays of
94 * <code>String</code> names of properties to be edited via property
95 * tables in the specified aspect.
96 * </p>
97 *
98 * <p>
99 * The Strings returned should specify names of qualified <i>JavaBean</i>
100 * properties with conventional getter and setter methods.
101 * </p>
102 *
103 * <p>
104 * If a custom editor has been specified for the aspect the result of theis
105 * method is ignored as the custom editor is used for editing the aspect
106 * instead of generic property table.
107 * </p>
108 *
109 * @param aspect
110 * the aspect of the displayer to be edited with generic proeprty
111 * table
112 *
113 * @return array of names of properties to be edited with the proeprty table
114 * in the specified aspect
115 */
116 public String[] getDefaultProperties(String aspect) {
117 Debug.out(aspect);
118
119 return null;
120 }
121
122 /**
123 * Returns the editor component for the selected aspect and displayer. If a
124 * custom editor exists for the selected aspect, it is returned. Otherwise a
125 * property table is returned containing the selected proeprties of the
126 * aspect as returned by <code>#getDefaultProperties(String)</code>
127 * method.
128 *
129 * @param displayer
130 * the component for which the editor should be returned
131 * @param aspect
132 * the specific editing aspect for which the editor should be
133 * returned
134 *
135 * @return the editor component for the selected aspect and displayer.
136 *
137 * @throws IllegalArgumentException
138 * if no custom editor is found for the aspect and
139 * getDefaultProperties(String) returns null for the aspect.
140 *
141 * @see com.cosylab.gui.components.customizer.Editor#getEditorComponent(Object,
142 * String)
143 */
144 public JComponent getEditorComponent(Object displayer, String aspect)
145 throws IllegalArgumentException {
146 Editor ed;
147 Iterator it = activeEditors.iterator();
148
149 while (it.hasNext()) {
150 if ((ed = (Editor) it.next()).canEdit(displayer, aspect)) {
151 return ed.getEditorComponent(displayer, aspect);
152 }
153 }
154
155 ArrayList l = (ArrayList) customEditors.get(aspect);
156
157 if (l != null) {
158 it = l.iterator();
159
160 while (it.hasNext()) {
161 if ((ed = (Editor) it.next()).canEdit(displayer, aspect)) {
162 activeEditors.add(ed);
163
164 return ed.getEditorComponent(displayer, aspect);
165 }
166 }
167 }
168
169 initializeDefaultPropertiesTable(displayer, aspect);
170
171 return defaultPropertiesTable;
172 }
173
174 /**
175 * Overrides the current editor for the specified aspect with the editor
176 * specified. This method can be used to replace generic property tables as
177 * editors for the aspect specified.
178 *
179 * @param aspect
180 * for which to use the editor specified
181 * @param editor
182 * the editor to replace the current editor of the aspect
183 * specified
184 */
185 public void addCustomEditor(String aspect, Editor editor) {
186 ArrayList<Editor> l = (ArrayList<Editor>) customEditors.get(aspect);
187
188 if (l == null) {
189 l = new ArrayList<Editor>();
190 customEditors.put(aspect, l);
191 }
192
193 l.add(editor);
194 }
195
196 /**
197 * Applies all the changes done to the custom editors as well as the
198 * property tables.
199 *
200 * @see com.cosylab.gui.components.customizer.Editor#applySettings()
201 */
202 public void applySettings() {
203 applyTableProperties();
204
205 Editor[] eds = getActiveEditors();
206
207 for (int i = 0; i < eds.length; i++) {
208 eds[i].applySettings();
209 }
210 }
211
212 /**
213 * Inspecting the <code>ASPECTS</code> and all the custom editors, this
214 * method determines, wether the specified aspect of the dispalyer can be
215 * edited by this editor.
216 *
217 * @param displayer
218 * Object to be edited (is ignored and can be <code>null</code>)
219 * @param aspect
220 * String name of aspect to be edited.
221 *
222 * @return <code>true</code> if the specifed aspect of the displayer can
223 * be edited, <code>false</code> otherwise.
224 *
225 * @see com.cosylab.gui.components.customizer.Editor#canEdit(Object, String)
226 */
227 public boolean canEdit(Object displayer, String aspect) {
228 ArrayList l = (ArrayList) customEditors.get(aspect);
229
230 if (l != null) {
231 Iterator it = l.iterator();
232
233 while (it.hasNext()) {
234 if (((Editor) it.next()).canEdit(displayer, aspect)) {
235 return true;
236 }
237 }
238 }
239
240 return (Arrays.binarySearch(ASPECTS, aspect) >= 0 && getDefaultProperties(aspect) != null);
241 }
242
243 /**
244 * Reverts all the changes done to the custom editors as well as the
245 * property tables.
246 *
247 * @see com.cosylab.gui.components.customizer.Editor#revertSettings()
248 */
249 public void revertSettings() {
250 Editor[] eds = getActiveEditors();
251
252 for (int i = 0; i < eds.length; i++) {
253 eds[i].revertSettings();
254 }
255 }
256
257 /**
258 * Stops editing with all custom editors as well as property tables.
259 *
260 * @see com.cosylab.gui.components.customizer.Editor#stopEditing()
261 */
262 public void stopEditing() {
263 defaultPropertiesTableModels.clear();
264
265 Editor[] eds = getActiveEditors();
266
267 for (int i = 0; i < eds.length; i++) {
268 eds[i].stopEditing();
269 }
270
271 activeEditors.clear();
272 }
273
274 /*
275 * Applies the changes done to the property tables.
276 */
277 protected void applyTableProperties() {
278 if (displayer == null) {
279 return;
280 }
281
282 Object[] modelList = defaultPropertiesTableModels.values().toArray();
283
284 for (int i = 0; i < modelList.length; i++) {
285 BeanPropertiesTableModel model = (BeanPropertiesTableModel) modelList[i];
286
287 try {
288 model.applyProperties();
289 } catch (Exception e) {
290 e.printStackTrace();
291 }
292 }
293 }
294
295 /*
296 * Initializes the proeprty table for the selected displayer and aspect.
297 */
298 protected void initializeDefaultPropertiesTable(Object displayer,
299 String aspect) throws IllegalArgumentException {
300 this.displayer = displayer;
301
302 if (defaultPropertiesTableModels.containsKey(aspect)) {
303 defaultPropertiesTable
304 .setModel((TableModel) defaultPropertiesTableModels
305 .get(aspect));
306 } else {
307 String[] names = getDefaultProperties(aspect);
308
309 BeanPropertiesTableModel model = new BeanPropertiesTableModel(
310 displayer, names);
311 defaultPropertiesTableModels.put(aspect, model);
312 defaultPropertiesTable.setModel(model);
313 }
314 }
315
316 /*
317 * Returns all the custom editors that have been supplied.
318 */
319 private Editor[] getActiveEditors() {
320 return (Editor[]) activeEditors.toArray();
321 }
322
323 /*
324 * (non-Javadoc)
325 * @see java.beans.Customizer#setObject(java.lang.Object)
326 */
327 public void setObject(Object bean) {
328 // reflection work since there is no other alternative.
329
330 try {
331 Object o = bean.getClass().getMethod("getCustomizer", null).invoke(
332 bean, null);
333 if (o != null) {
334 customizer = (com.cosylab.gui.components.customizer.Customizer) o;
335 // JTree aspectTree = customizer.getAspectTree();
336 //
337 // aspectTree.getSelectionModel().addTreeSelectionListener(
338 // new TreeSelectionListener() {
339 // public void valueChanged(TreeSelectionEvent e) {
340 // Object[] aspectPath = ((DefaultMutableTreeNode) e
341 // .getNewLeadSelectionPath()
342 // .getLastPathComponent())
343 // .getUserObjectPath();
344 // String aspect = "";
345 //
346 // for (int i = 1; i < aspectPath.length; i++) {
347 // aspect += "/" + (String) aspectPath[i];
348 // }
349 //
350 // setRightComponent(customizer
351 // .getAspectInPanel(aspect.substring(1)));
352 //
353 // }
354 // });
355 //
356 // setLeftComponent(aspectTree);
357 //
358 // String aspect = aspectTree.getModel().getChild(
359 // aspectTree.getModel().getRoot(), 0).toString();
360 //
361 // setRightComponent(new JScrollPane(customizer
362 // .getAspectInPanel(aspect)));
363 //
364 // aspectTree.setSelectionRow(0);
365
366 setLeftComponent(customizer.getAspectTree());
367 setRightComponent(customizer.getAspectPanel());
368
369 }
370 } catch (SecurityException e) {
371
372 } catch (NoSuchMethodException e) {
373
374 } catch (IllegalArgumentException e) {
375
376 } catch (IllegalAccessException e) {
377
378 } catch (InvocationTargetException e) {
379
380 }
381
382 }
383
384 private com.cosylab.gui.components.customizer.Customizer customizer;
385
386 }