001: /*
002: * Project: AMODA - Abstract Modeled Application
003: * Class: de.gulden.framework.amoda.generic.option.GenericOptionEntry
004: * Version: snapshot-beautyj-1.1
005: *
006: * Date: 2004-09-29
007: *
008: * This is a snapshot version of the AMODA 0.2 development branch,
009: * it is not released as a seperate version.
010: * For AMODA, see http://amoda.berlios.de/.
011: *
012: * This is licensed under the GNU Lesser General Public License (LGPL)
013: * and comes with NO WARRANTY.
014: *
015: * Author: Jens Gulden
016: * Email: amoda@jensgulden.de
017: */
018:
019: package de.gulden.framework.amoda.generic.option;
020:
021: import de.gulden.framework.amoda.environment.gui.*;
022: import de.gulden.framework.amoda.generic.core.GenericFeature;
023: import de.gulden.framework.amoda.generic.data.*;
024: import de.gulden.framework.amoda.generic.data.GenericValue;
025: import de.gulden.framework.amoda.model.behaviour.*;
026: import de.gulden.framework.amoda.model.data.*;
027: import de.gulden.framework.amoda.model.option.OptionEntry;
028: import de.gulden.util.Toolbox;
029: import de.gulden.util.xml.*;
030: import de.gulden.util.xml.XMLToolbox;
031: import de.gulden.util.xml.serializer.*;
032: import de.gulden.util.xml.serializer.XMLSerializableActive;
033: import java.awt.*;
034: import java.awt.event.*;
035: import java.awt.event.ActionListener;
036: import java.awt.event.ItemListener;
037: import java.lang.*;
038: import java.util.*;
039: import javax.swing.*;
040: import javax.swing.event.*;
041: import javax.swing.event.DocumentListener;
042: import org.w3c.dom.*;
043:
044: /**
045: * Class GenericOptionEntry.
046: *
047: * @author Jens Gulden
048: * @version snapshot-beautyj-1.1
049: */
050: public class GenericOptionEntry extends GenericFeature implements
051: ItemListener, ActionListener, OptionEntry,
052: XMLSerializableActive, DocumentListener, ChangeListener {
053:
054: // ------------------------------------------------------------------------
055: // --- fields ---
056: // ------------------------------------------------------------------------
057:
058: public String type;
059:
060: public boolean directory = false;
061:
062: protected Condition validityCondition;
063:
064: protected Value[] value;
065:
066: // ------------------------------------------------------------------------
067: // --- constructor ---
068: // ------------------------------------------------------------------------
069:
070: public GenericOptionEntry() {
071: super ();
072: value = new Value[STATE_EDIT + 1];
073: for (int i = 0; i < value.length; i++) {
074: value[i] = new de.gulden.framework.amoda.generic.data.GenericValue();
075: }
076: }
077:
078: // ------------------------------------------------------------------------
079: // --- methods ---
080: // ------------------------------------------------------------------------
081:
082: public Value getValue() {
083: // get most current value which is set, or null if no value is set
084: for (int i = STATE_CURRENT; i >= 0; i--) {
085: Value v = getValue(i);
086: if (v.get() != null) {
087: return v;
088: }
089: }
090: return null;
091: }
092:
093: public void setValue(Value value) {
094: setValue(STATE_CURRENT, value);
095: }
096:
097: public boolean isValid() {
098: Condition c = getValidityCondition();
099: if (c != null) {
100: return c.test();
101: } else {
102: return (getValue() != null); // default semantics for validity is "non-null"
103: }
104: }
105:
106: public void setType(String _type) {
107: // this allow SmartXMLSerializer to set type name from type attribue
108: //type = _type; - string var stays null!
109: Class clazz = null;
110: try {
111: clazz = Toolbox.getPrimitiveTypeWrapperClass(_type);
112: } catch (ClassNotFoundException cnfe) { // not a primitive type
113: }
114: if (clazz == null) {
115: try {
116: clazz = Class.forName(_type);
117: } catch (ClassNotFoundException cnfe) {
118: // allow mising "java.lang.", try again with it:
119: try {
120: clazz = Class.forName("java.lang." + _type);
121: } catch (ClassNotFoundException cnfe2) {
122: throw new NoClassDefFoundError(
123: "unknown option type " + cnfe.getMessage());
124: }
125: }
126: }
127: setType(clazz);
128: }
129:
130: public Class getType() {
131: Class type = ((GenericValue) getValue(0)).getType();
132: if (type != null) {
133: return type;
134: } else {
135: return String.class; // default type is String
136: }
137: }
138:
139: public void setType(Class type) {
140: if (type != getType()) {
141: for (int i = 0; i < value.length; i++) {
142: ((de.gulden.framework.amoda.generic.data.GenericValue) value[i])
143: .setType(type);
144: }
145: }
146: }
147:
148: public Condition getValidityCondition() {
149: return validityCondition;
150: }
151:
152: public void setValidityCondition(Condition _validityCondition) {
153: validityCondition = _validityCondition;
154: }
155:
156: public Value[] getValues() {
157: return value;
158: }
159:
160: public void setValues(Value[] _value) {
161: value = _value;
162: }
163:
164: public void setValue(int idx, Value _value)
165: throws ArrayIndexOutOfBoundsException {
166: value[idx] = _value;
167: }
168:
169: public Value getValue(int idx)
170: throws ArrayIndexOutOfBoundsException {
171: return value[idx];
172: }
173:
174: public Element xmlSerialize(Document doc, XMLSerializer serializer) {
175: // your code here
176: return null;
177: }
178:
179: public void xmlDeserialize(Element element, XMLSerializer serializer)
180: throws XMLException {
181: ((de.gulden.util.xml.serializer.smart.SmartReflectionXMLSerializer) serializer)
182: .xmlDeserialize(this , element, false); // inherit original deserializaton behaviour
183: xmlDeserializeValueEntry(element, STATE_INIT, "init-value");
184: xmlDeserializeValueEntry(element, STATE_DEFAULT,
185: "default-value");
186: xmlDeserializeValueEntry(element, STATE_SAVED, "save-value");
187: // current value may be set directly in tag body
188: String s = XMLToolbox.getText(element);
189: if (s != null) {
190: s = s.trim();
191: if (s.length() > 0) {
192: GenericValue v = (GenericValue) getValue(STATE_CURRENT);
193: v.parseString(s);
194: setType(v.getType()); // type might have been set by parsing if not explicitly initialized before
195: }
196: }
197: // but an explicit <value>..</value> also set current value
198: xmlDeserializeValueEntry(element, STATE_CURRENT, "value");
199: xmlDeserializeValueEntry(element, STATE_EDIT, "edit-value");
200: }
201:
202: public String toString() {
203: return findTitle();
204: }
205:
206: public void createGUIEditorComponent(JComponent parent,
207: GUIApplicationEnvironment env) {
208: Class type = getType();
209: if (type == null) {
210: type = String.class; // if unknown (empty value), treat as string
211: }
212: GridBagConstraints gbc = new GridBagConstraints();
213: gbc.anchor = GridBagConstraints.WEST;
214: JLabel label = new JLabel(this .findTitle());
215: label
216: .setFont(env
217: .getFont(de.gulden.framework.amoda.environment.gui.GUIApplicationEnvironment.FONT_LABEL));
218: parent.add(label, gbc);
219: JComponent component;
220: if (type == Boolean.class) {
221: component = new JCheckBox();
222: ((JCheckBox) component).addItemListener(this );
223: gbc.gridwidth = GridBagConstraints.REMAINDER;
224: gbc.fill = GridBagConstraints.HORIZONTAL;
225: gbc.weightx = 1.0;
226: Value v = getValue();
227: if (v != null) {
228: ((JCheckBox) component).setSelected(v.getBoolean());
229: }
230: } else if (type == java.awt.Color.class) {
231: component = new JPanel();
232: component.setPreferredSize(new java.awt.Dimension(80, 20));
233: component.setBorder(new javax.swing.border.EtchedBorder());
234: component.setBackground(this .getValue().getColor());
235: } else { // String or File
236: if (Number.class.isAssignableFrom(type)) {
237: component = new JTextField(5);
238: ((JTextField) component)
239: .setInputVerifier(new de.gulden.util.swing.InputVerifierNumber(
240: type));
241: } else if (type == java.io.File.class) {
242: component = new JTextField(50);
243: ((JTextField) component)
244: .setInputVerifier(new de.gulden.util.swing.InputVerifierFile(
245: isDirectory()));
246: } else {
247: Properties style = this .getStyleAttributes();
248: String ml = style.getProperty("multiline");
249: if (ml != null) {
250: component = new JTextArea(Integer.parseInt(ml), 50);
251: ((JTextArea) component).setLineWrap(true);
252: ((JTextArea) component).setWrapStyleWord(true);
253: } else {
254: component = new JTextField(50);
255: }
256: }
257: ((javax.swing.text.JTextComponent) component).getDocument()
258: .addDocumentListener(this );
259: Value v = getValue();
260: if (v != null) {
261: ((javax.swing.text.JTextComponent) component).setText(v
262: .getString());
263: }
264: if (component instanceof JTextArea) {
265: component = new JScrollPane(component);
266: }
267: }
268: if ((type != java.io.File.class)
269: && (type != java.awt.Color.class)) {
270: gbc.gridwidth = GridBagConstraints.REMAINDER;
271: }
272: if ((type != java.awt.Color.class)
273: && (!Number.class.isAssignableFrom(type))) {
274: gbc.fill = GridBagConstraints.HORIZONTAL;
275: }
276: if (type != java.awt.Color.class) {
277: gbc.weightx = 1.0;
278: }
279: parent.add(component, gbc);
280: if ((type == java.io.File.class)
281: || (type == java.awt.Color.class)) {
282: String buttonLabel;
283: if (type == java.io.File.class) {
284: buttonLabel = "Pick...";
285: } else {
286: buttonLabel = "Choose...";
287: }
288: JButton button = new JButton(buttonLabel);
289: button
290: .setFont(env
291: .getFont(de.gulden.framework.amoda.environment.gui.GUIApplicationEnvironment.FONT_BUTTON));
292: button.addActionListener(this );
293: gbc.fill = GridBagConstraints.NONE;
294: gbc.gridwidth = GridBagConstraints.REMAINDER;
295: if (type != java.awt.Color.class) {
296: gbc.weightx = 1.0;
297: gbc.anchor = GridBagConstraints.WEST;
298: } else {
299: gbc.weightx = 0.0;
300: }
301: parent.add(button, gbc);
302: }
303: }
304:
305: public void itemStateChanged(ItemEvent e) {
306: // option type is Boolean
307: getValue(STATE_CURRENT)
308: .set(
309: Boolean
310: .valueOf(e.getStateChange() == ItemEvent.SELECTED));
311: }
312:
313: public void actionPerformed(ActionEvent e) {
314: if (this .getType() == java.io.File.class) {
315: // This is called when the user hits a "Pick..." button close to a file-field
316: //getApplication().message("****FILE REQUESTER****"); //*******************************
317: de.gulden.framework.amoda.generic.interaction.GenericDialog fd = new de.gulden.framework.amoda.generic.interaction.GenericDialog();
318: fd.setParent(this .getParent());
319: fd.setFileDialog(true);
320: fd.setDirectories(true);//this.isDirectory());
321: GenericOptionEntry o = new GenericOptionEntry();
322: o.setName("file");
323: o.setType(java.io.File.class);
324: //o.setValue(STATE_CURRENT,this.getValue()),
325: ((GenericOptions) fd.getOptions()).add(o);
326: de.gulden.framework.amoda.model.data.Value v = this
327: .getValue();
328: if (v != null) {
329: java.io.File file = v.getFile();
330: // pre-set current value as initial file
331: ((GenericValue) o.getValue(STATE_CURRENT)).set(file);
332: }
333: fd.perform();
334: java.io.File file = fd.getOptions().getFile("file");
335: // find text field close to button (HACKING!)
336: if (file != null) {
337: java.awt.Container parent = ((javax.swing.JButton) e
338: .getSource()).getParent();
339: javax.swing.JTextField textfield = (javax.swing.JTextField) Toolbox
340: .findChildComponentCloseTo(parent,
341: javax.swing.JTextField.class,
342: (JComponent) e.getSource());
343: textfield.setText(file.getAbsolutePath()); // ! this will set this options' value through the document listener !
344: }
345: } else if (this .getType() == java.awt.Color.class) {
346: java.awt.Color color = javax.swing.JColorChooser
347: .showDialog(
348: ((de.gulden.framework.amoda.environment.gui.GUIApplicationEnvironment) getApplication()
349: .getEnvironment()).getFrame(),
350: "Choose Color", this .getValue().getColor());
351: // find color panel close to button (HACKING!)
352: if (color != null) {
353: ((GenericValue) getValue(STATE_CURRENT)).set(color);
354: java.awt.Container parent = ((javax.swing.JButton) e
355: .getSource()).getParent();
356: javax.swing.JPanel label = (javax.swing.JPanel) Toolbox
357: .findChildComponent(parent,
358: javax.swing.JPanel.class);
359: label.setBackground(color); // ! this will set this options' value through the document listener !
360: label.repaint();
361: }
362:
363: }
364: }
365:
366: public void insertUpdate(DocumentEvent e) {
367: guiTextValueChanged(e);
368: }
369:
370: public void removeUpdate(DocumentEvent e) {
371: guiTextValueChanged(e);
372: }
373:
374: public void changedUpdate(DocumentEvent e) {
375: guiTextValueChanged(e);
376: }
377:
378: public boolean isDirectory() {
379: return directory;
380: }
381:
382: public void setDirectory(boolean _directory) {
383: directory = _directory;
384: }
385:
386: public void shiftValue(int stateOld, int stateNew) {
387: Object value = getValue(stateOld).get();
388: if (value != null) {
389: ((de.gulden.framework.amoda.generic.data.GenericValue) getValue(stateNew))
390: .set(value);
391: }
392: }
393:
394: public String getQualifiedId() {
395: // overwrites GenericApplicationMemberAbstract.getQualifiedId
396: de.gulden.framework.amoda.generic.core.GenericApplicationMemberAbstract parent = (de.gulden.framework.amoda.generic.core.GenericApplicationMemberAbstract) getParent();
397: if ((parent instanceof GenericOptions)
398: && (parent != getApplication().getOptions())) {
399: return parent.getQualifiedId() + "." + this .getId();
400: } else { // top-most option or option-group, parent feature names are not included
401: return this .getId();
402: }
403: }
404:
405: public void stateChanged(ChangeEvent e) {
406: shiftValue(STATE_EDIT, STATE_CURRENT);
407: }
408:
409: public boolean isSystem() {
410: if (super .isSystem()) {
411: return true;
412: } else {
413: // OptionEntries are also considered "system" if they are member of a group that is "system"
414: de.gulden.framework.amoda.model.data.CompositeMember f = this
415: .getParent();
416: while ((f != null) && (f instanceof GenericFeature)
417: && (!((GenericFeature) f).isSystem())) {
418: f = f.getParent();
419: }
420: return (f != null);
421: }
422: }
423:
424: protected void xmlDeserializeValueEntry(Element element, int state,
425: String tagname) {
426: String s = XMLToolbox.getChildText(element, tagname);
427: if (s != null) {
428: GenericValue v = (GenericValue) getValue(state);
429: v.parseString(s);
430: setType(v.getType()); // type might have been set by parsing if not explicitly initialized before
431: }
432: }
433:
434: private void guiTextValueChanged(DocumentEvent e) {
435: String s = Toolbox.getDocumentText(e.getDocument());
436: try {
437: ((GenericValue) getValue(STATE_EDIT)).parseString(s);
438: } catch (de.gulden.framework.amoda.model.data.IllegalTypeError ite) { // couldn't parse this type - this is another kind of input-verification here
439: /* can't reset value - write lock
440: // reset current value
441: Value v=getValue();
442: String valStr;
443: if (v!=null) {
444: valStr=v.getString();
445: if (valStr==null) {
446: valStr="";
447: }
448: } else {
449: valStr="";
450: }
451: Toolbox.setDocumentText(e.getDocument(),valStr);
452: */
453: }
454: }
455:
456: } // end GenericOptionEntry
|