001: package net.xoetrope.builder.editor;
002:
003: import java.util.Hashtable;
004: import java.util.Vector;
005:
006: import java.awt.BorderLayout;
007: import java.awt.Color;
008: import java.awt.Component;
009: import java.awt.Dimension;
010: import java.awt.event.ActionEvent;
011: import java.awt.event.ActionListener;
012: import java.awt.event.ItemEvent;
013: import java.awt.event.ItemListener;
014: import javax.swing.DefaultCellEditor;
015: import javax.swing.JOptionPane;
016: import javax.swing.JPanel;
017: import javax.swing.JScrollPane;
018: import javax.swing.JTable;
019: import javax.swing.JTextField;
020: import javax.swing.border.EmptyBorder;
021: import javax.swing.event.TableModelEvent;
022: import javax.swing.event.TableModelListener;
023: import javax.swing.table.DefaultTableModel;
024: import javax.swing.table.TableCellEditor;
025:
026: import net.xoetrope.builder.editor.components.ComponentHelper;
027: import net.xoetrope.builder.editor.components.MultipleSelectionHelper;
028: import net.xoetrope.builder.editor.components.PropertyHelper;
029: import net.xoetrope.builder.editor.components.swing.XComboBoxEditor;
030: import net.xoetrope.builder.editor.components.swing.XImageNameEditor;
031: import net.xoetrope.builder.editor.events.EventHandlerEditor;
032: import net.xoetrope.builder.editor.events.ProjectListener;
033: import net.xoetrope.builder.editor.events.PropertiesListener;
034: import net.xoetrope.builder.editor.events.StyleListener;
035: import net.xoetrope.builder.editor.plugin.PropertiesData;
036: import net.xoetrope.xui.style.XStyle;
037:
038: /**
039: * A property editor for the current component
040: * <p>Copyright: Copyright (c) Xoetrope Ltd., 1998-2003</p>
041: * $Revision: 1.20 $
042: */
043: public class XPropertiesEditor extends JPanel implements
044: TableModelListener, ItemListener, StyleListener,
045: ProjectListener {
046: private JScrollPane scrollPane;
047: private Vector selection;
048: private XComponentSizer sizer;
049: private JTable table;
050: private DefaultTableModel dm;
051: private JTextField textField;
052: private DefaultCellEditor textEditor;
053: private XPropertiesEditor propEditor;
054: private EventHandlerEditor eventHandlerEditor;
055: private StyleListener styleListener;
056: private Vector propertiesListeners;
057:
058: private PropertyHelper propertyHelper;
059: private XEditorProject currentProject;
060:
061: private boolean autoChange = false;
062:
063: private Hashtable customPropertyData;
064:
065: private Object oldValue;
066:
067: public XPropertiesEditor(String name) {
068: setLayout(new BorderLayout());
069: setBackground(Color.white);
070: setVisible(false);
071: propEditor = this ;
072: propertiesListeners = new Vector();
073:
074: setBorder(new EmptyBorder(0, 0, 0, 0));
075: }
076:
077: /**
078: * The project has been loaded
079: * @param project the new project reference
080: */
081: public void projectLoaded(XEditorProject project) {
082: currentProject = project;
083: }
084:
085: /**
086: * The project has been updated
087: */
088: public void projectUpdated() {
089: }
090:
091: /**
092: * Apply properties to the new component as dictated by the component's helper
093: * @param c the new component
094: */
095: public void setNewComponent(Component component) {
096: PropertyHelper newCompHelper = ComponentHelper
097: .getPropertyHelper(component);
098: if (newCompHelper.restrictsSize())
099: component.setSize(component.getMaximumSize());
100: }
101:
102: public void setSelectedComponents(Vector selectedComponents) {
103: selection = selectedComponents;
104: refresh();
105: }
106:
107: public void refresh() {
108: sizer = null;
109:
110: if (selection == null)
111: return;
112:
113: int numSelectedComponents = selection.size();
114: if (numSelectedComponents == 0)
115: propertyHelper = null;
116: else if (numSelectedComponents == 1) {
117: Component comp = ((XComponentSizer) selection.elementAt(0))
118: .getTarget();
119: if (comp != null)
120: propertyHelper = ComponentHelper
121: .getPropertyHelper(comp);
122: else
123: propertyHelper = null;
124: } else {
125: propertyHelper = ComponentHelper
126: .getPropertyHelper(selection);
127: ((MultipleSelectionHelper) propertyHelper)
128: .setSelectedComponents(selection);
129: }
130:
131: initialiseTable();
132:
133: if ((styleListener != null) && (propertyHelper != null)) {
134: int numRows = propertyHelper.getNumProperties();
135: for (int i = 0; i < numRows; i++) {
136: if (propertyHelper.getPropertyType(i) == PropertyHelper.STYLE_PROPERTY) {
137: String styleName = (String) table.getValueAt(i, 1);
138: if (styleName != null) {
139: XStyle style = ((XEditorStyleManager) XEditorProjectManager
140: .getStyleManager()).getStyle(styleName);
141: if (styleListener != null)
142: styleListener
143: .styleChanged(styleName, style);
144: } else {
145: Component c = ((XComponentSizer) selection
146: .elementAt(0)).getTarget();
147: String className = XEditorUtilities
148: .getComponentClassName(c);
149: XStyle style = ((XEditorStyleManager) XEditorProjectManager
150: .getStyleManager()).getStyle(className);
151: if (styleListener != null)
152: styleListener
153: .styleChanged(className, style);
154: }
155: break;
156: }
157: }
158: }
159: }
160:
161: /**
162: * Repaint the listed components
163: * @param selectionComponents
164: */
165: protected void repaintSelection(Vector selectionComponents) {
166: if (selectionComponents != null) {
167: int numComponents = selectionComponents.size();
168: for (int i = 0; i < numComponents; i++) {
169: XComponentSizer sizer = (XComponentSizer) selectionComponents
170: .elementAt(i);
171: Component comp = sizer.getTarget();
172: if (comp != null)
173: sizer.repaint();
174: }
175: }
176: }
177:
178: /**
179: * Sets a listener for changes in style made by this editor
180: * @param listener
181: */
182: public void setStyleListener(StyleListener listener) {
183: styleListener = listener;
184: }
185:
186: /**
187: * Create the table, set the renderers and add it to the dialog. This needs to be
188: * modified to handle checkboxes for bold etc and dropdowns for fonts.
189: */
190: private void initialiseTable() {
191: if (scrollPane != null)
192: remove(scrollPane);
193:
194: dm = new DefaultTableModel();
195: dm.addColumn("Property");
196: dm.addColumn("Value");
197: while (dm.getRowCount() > 0)
198: dm.removeRow(0);
199:
200: if ((propertyHelper != null) && (selection.size() > 0)) {
201: int numProps = propertyHelper.getNumProperties();
202: for (int i = 0; i < numProps; i++) {
203: XComponentSizer currentSizer = (XComponentSizer) selection
204: .elementAt(0);
205: XPageResource pageResource = currentSizer
206: .getPageResource();
207: Component comp = currentSizer.getTarget();
208: Object[] obj = new Object[] {
209: propertyHelper.getPropertyName(pageResource,
210: comp, i),
211: propertyHelper.getPropertyValue(pageResource,
212: comp, i) };
213: dm.addRow(obj);
214: }
215: customPropertyData = new Hashtable();
216: for (int i = 0; i < propertiesListeners.size(); i++) {
217: PropertiesListener pListener = (PropertiesListener) propertiesListeners
218: .elementAt(i);
219: PropertiesData[] props = pListener
220: .getProperties(propertyHelper);
221: if (props != null) {
222: for (int iprops = 0; iprops < props.length; iprops++) {
223: boolean propexists = false;
224:
225: for (int tableprops = 0; tableprops < dm
226: .getRowCount(); tableprops++) {
227: if (((String) dm.getValueAt(tableprops, 0))
228: .compareTo(props[iprops]
229: .getPropertyName()) == 0) {
230: propexists = true;
231: }
232: }
233: if (!propexists) {
234: dm.addRow(props[iprops].getProperties());
235: }
236: customPropertyData.put(props[iprops]
237: .getPropertyName(), props[i]);
238: }
239: }
240: }
241: }
242:
243: table = new JTable(dm) {
244: public TableCellEditor getCellEditor(int row, int column) {
245: XComponentSizer currentSizer = (XComponentSizer) selection
246: .elementAt(0);
247: if (column == 0) {
248: return null;
249: } else if (column == 1) {
250: PropertiesData propData = (PropertiesData) customPropertyData
251: .get(table.getValueAt(row, 0));
252: if (propData != null) {
253: TableCellEditor ce = propData.getCellEditor();
254: if (ce != null)
255: return propData.getCellEditor();
256: }
257:
258: Object value0 = getModel().getValueAt(row, 0);
259: oldValue = getModel().getValueAt(row, 1);
260: if (value0 != null) {
261: if (propertyHelper.isReadOnly(value0))
262: return null;
263:
264: int propertyType = propertyHelper
265: .getPropertyType(row);
266: if ((propertyType == PropertyHelper.LIST_PROPERTY)
267: || (propertyType == PropertyHelper.BOOLEAN_PROPERTY)) {
268: XComboBoxEditor editor = new XComboBoxEditor();
269: String listItems[] = propertyHelper
270: .getListItems(row);
271: int numListItems = listItems.length;
272: for (int i = 0; i < numListItems; i++)
273: editor.addItem(listItems[i]);
274: editor.setSelectedItem(propertyHelper
275: .getPropertyValue(currentSizer
276: .getPageResource(),
277: currentSizer.getTarget(),
278: row));
279: editor.addItemListener(propEditor);
280: editor.setFont(XuiDefaults.defaultFont);
281: return (editor);
282: } else if (propertyType == PropertyHelper.STYLE_PROPERTY) {
283: String[] styleArray = ((XEditorStyleManager) XEditorProjectManager
284: .getStyleManager())
285: .getStylesArray();
286: String[] tempArray = new String[styleArray.length + 1];
287: System.arraycopy(styleArray, 0, tempArray,
288: 1, styleArray.length);
289: tempArray[0] = "[None]";
290: XComboBoxEditor editor = new XComboBoxEditor(
291: tempArray);
292: editor.setSelectedItem(propertyHelper
293: .getPropertyValue(currentSizer
294: .getPageResource(),
295: currentSizer.getTarget(),
296: row));
297: editor.addItemListener(propEditor);
298: editor.setFont(XuiDefaults.defaultFont);
299: return (editor);
300: } else if (propertyType == PropertyHelper.VALIDATION_PROPERTY) {
301: XComboBoxEditor editor = new XComboBoxEditor();
302: String listItems[] = currentProject
303: .getValidations();
304: if (listItems != null) {
305: int numListItems = listItems.length;
306: editor.addItem("[None]");
307: for (int i = 0; i < numListItems; i++)
308: editor.addItem(listItems[i]);
309: editor.setSelectedItem(propertyHelper
310: .getPropertyValue(currentSizer
311: .getPageResource(),
312: currentSizer
313: .getTarget(),
314: row));
315: }
316: editor.addItemListener(propEditor);
317: editor.setFont(XuiDefaults.defaultFont);
318: return (editor);
319: } else if (propertyType == PropertyHelper.IMAGE_NAME_PROPERTY) {
320: String currentValue = propertyHelper
321: .getPropertyValue(currentSizer
322: .getPageResource(),
323: currentSizer.getTarget(),
324: row);
325: if ((currentValue == null)
326: || (currentValue.length() == 0))
327: currentValue = currentProject.getPath()
328: + "/resources";
329: XImageNameEditor editor = new XImageNameEditor(
330: currentValue, propertyHelper
331: .getFileExtensions(),
332: propertyHelper
333: .getDefaultExtension(),
334: propertyHelper.getFileDescription());
335: return editor;
336: }
337: } else
338: return super .getCellEditor(row, column);
339: }
340: TableCellEditor editor = super .getCellEditor(row,
341: column);
342: editor.cancelCellEditing();
343: return editor;
344: }
345: };
346:
347: table.getModel().addTableModelListener(this );
348: table.setBackground(Color.white);
349:
350: scrollPane = new JScrollPane(table);
351: scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0));
352: add(scrollPane, BorderLayout.CENTER);
353:
354: table.getColumnModel().getColumn(0).setCellEditor(null);
355:
356: table.setFont(XuiDefaults.defaultFont);
357: }
358:
359: /**
360: * Called when a style is changed. This allows the editor to reset the
361: * components visually.
362: * @param styleName the name of the style which has been changed
363: * @param newstyle The new XStyle
364: */
365: public void styleChanged(String styleName, XStyle style) {
366: if (selection != null) {
367: int numComponents = selection.size();
368: if (numComponents > 0) {
369: int numRows = propertyHelper.getNumProperties();
370: int styleRow = 0;
371: for (; styleRow < numRows; styleRow++) {
372: if (propertyHelper.getPropertyType(styleRow) == PropertyHelper.STYLE_PROPERTY)
373: break;
374: }
375:
376: Component currentComp = null;
377: for (int i = 0; i < numComponents; i++) {
378: XComponentSizer currentSizer = (XComponentSizer) selection
379: .elementAt(i);
380: currentComp = currentSizer.getTarget();
381: currentProject.getStyleFactory().applyStyle(
382: currentComp, styleName);
383: ((XComponentSizer) selection.elementAt(i))
384: .getTarget().repaint();
385: propertyHelper.setPropertyValue(currentSizer
386: .getPageResource(), currentComp, styleRow,
387: styleName);
388: }
389:
390: table.setValueAt(styleName, styleRow, 1);
391: }
392: }
393: }
394:
395: private void settingsChanged(int iRow, int dropDownIdx) {
396: if ((iRow > -1) && (!autoChange)) {
397: int numComponents = selection.size();
398: for (int i = 0; i < numComponents; i++) {
399: XComponentSizer currentSizer = (XComponentSizer) selection
400: .elementAt(i);
401: Component currentComp = currentSizer.getTarget();
402: XPageResource currentScreen = ((XComponentSizer) selection
403: .elementAt(i)).getPageResource();
404:
405: int propType = propertyHelper.getPropertyType(iRow);
406: switch (propType) {
407: case PropertyHelper.STYLE_PROPERTY: {
408: propertyHelper.setPropertyValue(currentSizer
409: .getPageResource(), currentComp, iRow,
410: (String) dm.getValueAt(iRow, 1));
411:
412: String styleName = (String) dm.getValueAt(iRow, 1);
413: XStyle style = ((XEditorStyleManager) XEditorProjectManager
414: .getStyleManager()).getStyle(styleName);
415: ((XComponentSizer) selection.elementAt(i))
416: .getTarget().repaint();
417: if (styleListener != null)
418: styleListener.styleChanged(styleName, style);
419: }
420: break;
421: case PropertyHelper.EVENT_HANDLER_PROPERTY:
422: if ((currentComp.getName() == null)
423: || ("".compareTo(currentComp.getName()) == 0)) {
424: String result = JOptionPane
425: .showInputDialog(
426: this ,
427: "<html>A name is required for any component with events.<br>In order to continue you must enter a name.<br><br>Please enter the component name</html>",
428: "Error while adding event",
429: JOptionPane.ERROR_MESSAGE);
430: currentComp.setName(result);
431: if (result == null) {
432: autoChange = true;
433: dm.setValueAt(null, iRow, 1);
434: autoChange = false;
435: break;
436: }
437: }
438: eventHandlerEditor.showEventHandler(currentScreen,
439: currentComp, (String) dm
440: .getValueAt(iRow, 1),
441: propertyHelper.getEventMask(iRow));
442: break;
443: case PropertyHelper.IMAGE_NAME_PROPERTY: {
444: propertyHelper.setPropertyValue(currentSizer
445: .getPageResource(), currentComp, iRow,
446: (String) dm.getValueAt(iRow, 1));
447: ((XComponentSizer) selection.elementAt(i))
448: .setBounds(currentComp.getBounds());
449: }
450: break;
451: case PropertyHelper.LIST_PROPERTY:
452: if (dropDownIdx >= 0)
453: propertyHelper.setListPropertyValue(
454: currentComp, iRow, dropDownIdx);
455: currentComp.repaint();
456: break;
457: case PropertyHelper.PLAIN_PROPERTY:
458: default:
459: String updateValue = (String) dm
460: .getValueAt(iRow, 1);
461: if (iRow == PropertyHelper.PROP_NAME) {
462: if (updateValue.length() == 0
463: && oldValue.toString().length() > 0) {
464: int ret = JOptionPane
465: .showConfirmDialog(
466: this ,
467: "Setting the name of a control to blank will remove its bindings and events. Do you wish to proceed?",
468: "Rename",
469: JOptionPane.OK_CANCEL_OPTION);
470: if (ret == JOptionPane.CANCEL_OPTION) {
471: updateValue = oldValue.toString();
472: dm.setValueAt(updateValue == null ? ""
473: : updateValue, iRow, 1);
474: }
475: } else {
476: Object o = currentSizer.getPageResource()
477: .getPage().findComponent(
478: (String) dm.getValueAt(
479: iRow, 1));
480: if (o != null && !o.equals(currentComp)) {
481: JOptionPane
482: .showMessageDialog(this ,
483: "A control with this name already exists!");
484: updateValue = oldValue == null ? null
485: : oldValue.toString();
486: dm.setValueAt(updateValue == null ? ""
487: : updateValue, iRow, 1);
488: }
489: }
490: }
491: propertyHelper.setPropertyValue(currentSizer
492: .getPageResource(), currentComp, iRow,
493: updateValue);
494: ((XComponentSizer) selection.elementAt(i))
495: .setBounds(currentComp.getBounds());
496: break;
497: case PropertyHelper.DATA_PROPERTY:
498: if ((currentComp.getName() == null)
499: || ("".compareTo(currentComp.getName()) == 0)) {
500: JOptionPane
501: .showMessageDialog(this ,
502: "Cannot bind data to a control with no name");
503: autoChange = true;
504: dm.setValueAt(null, iRow, 1);
505: autoChange = false;
506: break;
507: }
508: propertyHelper.setPropertyValue(currentSizer
509: .getPageResource(), currentComp, iRow,
510: (String) dm.getValueAt(iRow, 1));
511: break;
512: }
513: }
514: }
515: }
516:
517: public void tableChanged(TableModelEvent event) {
518: if (event.getType() == TableModelEvent.UPDATE) {
519: try {
520: settingsChanged(event.getFirstRow(), -1);
521: } catch (Exception ex) {
522: JOptionPane.showMessageDialog(this ,
523: "Invalid property value");
524: if (oldValue != null)
525: table.setValueAt(oldValue, event.getFirstRow(), 1);
526: }
527: }
528: }
529:
530: public void itemStateChanged(ItemEvent evt) {
531: int selIdx = ((XComboBoxEditor) evt.getSource())
532: .getSelectedIndex();
533: table.setValueAt(((XComboBoxEditor) evt.getSource())
534: .getSelectedItem(), table.getEditingRow(), 1);
535: settingsChanged(table.getEditingRow(), selIdx);
536: }
537:
538: public Dimension getPreferredSize() {
539: return new Dimension(230, 200);
540: }
541:
542: public void setEventHandlerEditor(EventHandlerEditor ehe) {
543: eventHandlerEditor = ehe;
544: }
545:
546: public void addPropertiesListener(PropertiesListener p) {
547: propertiesListeners.add(p);
548: }
549:
550: public XPageResource getSelectedPageResource() {
551: XComponentSizer currentSizer = (XComponentSizer) selection
552: .elementAt(0);
553: XPageResource pageResource = currentSizer.getPageResource();
554: return currentSizer.getPageResource();
555: }
556:
557: public PropertyHelper getSelectedPropertyHelper() {
558: return propertyHelper;
559: }
560: }
|