This project has retired. For details please refer to its
Attic page.
PropertyEditorFrame xref
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.workbench;
20
21 import java.awt.BorderLayout;
22 import java.awt.Color;
23 import java.awt.Cursor;
24 import java.awt.Dimension;
25 import java.awt.FlowLayout;
26 import java.awt.Font;
27 import java.awt.event.ActionEvent;
28 import java.awt.event.ActionListener;
29 import java.awt.event.KeyEvent;
30 import java.awt.event.KeyListener;
31 import java.math.BigDecimal;
32 import java.text.DecimalFormat;
33 import java.text.Format;
34 import java.util.ArrayList;
35 import java.util.Calendar;
36 import java.util.Collections;
37 import java.util.GregorianCalendar;
38 import java.util.HashMap;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.TimeZone;
43
44 import javax.swing.BorderFactory;
45 import javax.swing.BoxLayout;
46 import javax.swing.ImageIcon;
47 import javax.swing.JButton;
48 import javax.swing.JComboBox;
49 import javax.swing.JComponent;
50 import javax.swing.JFormattedTextField;
51 import javax.swing.JFrame;
52 import javax.swing.JLabel;
53 import javax.swing.JPanel;
54 import javax.swing.JScrollPane;
55 import javax.swing.JSpinner;
56 import javax.swing.JTextField;
57 import javax.swing.SpinnerListModel;
58 import javax.swing.SpinnerNumberModel;
59 import javax.swing.UIManager;
60 import javax.swing.event.ChangeEvent;
61 import javax.swing.event.ChangeListener;
62
63 import org.apache.chemistry.opencmis.client.api.CmisObject;
64 import org.apache.chemistry.opencmis.client.api.ObjectId;
65 import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
66 import org.apache.chemistry.opencmis.commons.enums.Action;
67 import org.apache.chemistry.opencmis.commons.enums.Cardinality;
68 import org.apache.chemistry.opencmis.commons.enums.Updatability;
69 import org.apache.chemistry.opencmis.workbench.PropertyEditorFrame.UpdateStatus.StatusFlag;
70 import org.apache.chemistry.opencmis.workbench.model.ClientModel;
71
72
73
74
75 public class PropertyEditorFrame extends JFrame {
76
77 private static final long serialVersionUID = 1L;
78
79 private static final String WINDOW_TITLE = "Property Editor";
80 private static final ImageIcon ICON_ADD = ClientHelper.getIcon("add.png");
81
82 private final ClientModel model;
83 private final CmisObject object;
84 private List<PropertyInputPanel> propertyPanels;
85
86 public PropertyEditorFrame(final ClientModel model, final CmisObject object) {
87 super();
88
89 this.model = model;
90 this.object = object;
91
92 createGUI();
93 }
94
95 private void createGUI() {
96 setTitle(WINDOW_TITLE);
97 setPreferredSize(new Dimension(800, 600));
98 setMinimumSize(new Dimension(300, 120));
99
100 setLayout(new BorderLayout());
101
102 final JPanel panel = new JPanel();
103 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
104
105 final Font labelFont = UIManager.getFont("Label.font");
106 final Font boldFont = labelFont.deriveFont(Font.BOLD, labelFont.getSize2D() * 1.2f);
107
108 final JPanel topPanel = new JPanel();
109 topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.Y_AXIS));
110 topPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
111 final JLabel nameLabel = new JLabel(object.getName());
112 nameLabel.setFont(boldFont);
113 topPanel.add(nameLabel);
114 topPanel.add(new JLabel(object.getId()));
115 add(topPanel, BorderLayout.PAGE_START);
116
117 JScrollPane scrollPane = new JScrollPane(panel);
118 add(scrollPane, BorderLayout.CENTER);
119
120 propertyPanels = new ArrayList<PropertyEditorFrame.PropertyInputPanel>();
121
122 int position = 0;
123 for (PropertyDefinition<?> propDef : object.getType().getPropertyDefinitions().values()) {
124 boolean isUpdatable = (propDef.getUpdatability() == Updatability.READWRITE)
125 || (propDef.getUpdatability() == Updatability.WHENCHECKEDOUT && object.getAllowableActions()
126 .getAllowableActions().contains(Action.CAN_CHECK_IN));
127
128 if (isUpdatable) {
129 PropertyInputPanel propertyPanel = new PropertyInputPanel(propDef, object.getPropertyValue(propDef
130 .getId()), position++);
131
132 propertyPanels.add(propertyPanel);
133 panel.add(propertyPanel);
134 }
135 }
136
137 JButton updateButton = new JButton("Update");
138 updateButton.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
139 updateButton.setDefaultCapable(true);
140 updateButton.addActionListener(new ActionListener() {
141 public void actionPerformed(ActionEvent event) {
142 if (doUpdate()) {
143 dispose();
144 }
145 }
146 });
147
148 add(updateButton, BorderLayout.PAGE_END);
149
150 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
151 pack();
152 setLocationRelativeTo(null);
153 setVisible(true);
154 }
155
156
157
158
159 private boolean doUpdate() {
160 try {
161 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
162
163 Map<String, Object> properties = new HashMap<String, Object>();
164 for (PropertyInputPanel propertyPanel : propertyPanels) {
165 if (propertyPanel.includeInUpdate()) {
166 properties.put(propertyPanel.getId(), propertyPanel.getValue());
167 }
168 }
169
170 if (properties.isEmpty()) {
171 return false;
172 }
173
174 ObjectId newId = object.updateProperties(properties, false);
175
176 if ((newId != null) && newId.getId().equals(model.getCurrentObject().getId())) {
177 try {
178 model.reloadObject();
179 model.reloadFolder();
180 } catch (Exception ex) {
181 ClientHelper.showError(null, ex);
182 }
183 }
184
185 return true;
186 } catch (Exception ex) {
187 ClientHelper.showError(this, ex);
188 return false;
189 } finally {
190 setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
191 }
192 }
193
194 interface UpdateStatus {
195 enum StatusFlag {
196 DontChange, Update, Unset
197 }
198
199 void setStatus(StatusFlag status);
200
201 StatusFlag getStatus();
202 }
203
204 interface MultivalueManager {
205 void addNewValue();
206
207 void removeValue(int pos);
208
209 void moveUp(int pos);
210
211 void moveDown(int pos);
212 }
213
214
215
216
217 public static class PropertyInputPanel extends JPanel implements UpdateStatus, MultivalueManager {
218 private static final long serialVersionUID = 1L;
219
220 private static final Color BACKGROUND1 = UIManager.getColor("Table:\"Table.cellRenderer\".background");
221 private static final Color BACKGROUND2 = UIManager.getColor("Table.alternateRowColor");
222 private static final Color LINE = new Color(0xB8, 0xB8, 0xB8);
223
224 private final PropertyDefinition<?> propDef;
225 private final Object value;
226 private final Color bgColor;
227 private JComboBox changeBox;
228 private LinkedList<JComponent> valueComponents;
229
230 public PropertyInputPanel(PropertyDefinition<?> propDef, Object value, int position) {
231 super();
232 this.propDef = propDef;
233 this.value = value;
234 bgColor = (position % 2 == 0 ? BACKGROUND1 : BACKGROUND2);
235 createGUI();
236 }
237
238 private void createGUI() {
239 setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
240
241 setBackground(bgColor);
242 setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, LINE),
243 BorderFactory.createEmptyBorder(10, 5, 10, 5)));
244
245 Font labelFont = UIManager.getFont("Label.font");
246 Font boldFont = labelFont.deriveFont(Font.BOLD, labelFont.getSize2D() * 1.2f);
247
248 JPanel titlePanel = new JPanel();
249 titlePanel.setLayout(new BorderLayout());
250 titlePanel.setBackground(bgColor);
251 titlePanel.setToolTipText("<html><b>" + propDef.getPropertyType().value() + "</b> ("
252 + propDef.getCardinality().value() + " value)"
253 + (propDef.getDescription() != null ? "<br>" + propDef.getDescription() : ""));
254 add(titlePanel);
255
256 JPanel namePanel = new JPanel();
257 namePanel.setLayout(new BoxLayout(namePanel, BoxLayout.Y_AXIS));
258 namePanel.setBackground(bgColor);
259 JLabel displayNameLabel = new JLabel(propDef.getDisplayName());
260 displayNameLabel.setFont(boldFont);
261 namePanel.add(displayNameLabel);
262 JLabel idLabel = new JLabel(propDef.getId());
263 namePanel.add(idLabel);
264
265 titlePanel.add(namePanel, BorderLayout.LINE_START);
266
267 changeBox = new JComboBox(new Object[] { "Don't change ", "Update ", "Unset " });
268 titlePanel.add(changeBox, BorderLayout.LINE_END);
269
270 valueComponents = new LinkedList<JComponent>();
271 if (propDef.getCardinality() == Cardinality.SINGLE) {
272 JComponent valueField = createInputField(value);
273 valueComponents.add(valueField);
274 add(valueField);
275 } else {
276 if (value instanceof List<?>) {
277 for (Object v : (List<?>) value) {
278 JComponent valueField = new MultiValuePropertyInputField(createInputField(v), this, bgColor);
279 valueComponents.add(valueField);
280 add(valueField);
281 }
282 }
283
284 JPanel addPanel = new JPanel(new BorderLayout());
285 addPanel.setBackground(bgColor);
286 JButton addButton = new JButton(ICON_ADD);
287 addButton.addActionListener(new ActionListener() {
288 @Override
289 public void actionPerformed(ActionEvent e) {
290 addNewValue();
291 setStatus(StatusFlag.Update);
292 }
293 });
294 addPanel.add(addButton, BorderLayout.LINE_END);
295 add(addPanel);
296
297 updatePositions();
298 }
299
300 setMaximumSize(new Dimension(Short.MAX_VALUE, getPreferredSize().height));
301 }
302
303 protected JComponent createInputField(Object value) {
304 switch (propDef.getPropertyType()) {
305 case INTEGER:
306 return new IntegerPropertyInputField(value, this, bgColor);
307 case DECIMAL:
308 return new DecimalPropertyInputField(value, this, bgColor);
309 case DATETIME:
310 return new DateTimePropertyInputField(value, this, bgColor);
311 case BOOLEAN:
312 return new BooleanPropertyInputField(value, this, bgColor);
313 default:
314 return new StringPropertyInputField(value, this, bgColor);
315 }
316 }
317
318 private void updatePositions() {
319 int n = valueComponents.size();
320 for (int i = 0; i < n; i++) {
321 MultiValuePropertyInputField comp = (MultiValuePropertyInputField) valueComponents.get(i);
322 comp.updatePosition(i, i + 1 == n);
323 }
324 }
325
326 public void addNewValue() {
327 JComponent valueField = new MultiValuePropertyInputField(createInputField(null), this, bgColor);
328 valueComponents.add(valueField);
329 add(valueField, getComponentCount() - 1);
330
331 updatePositions();
332 setStatus(StatusFlag.Update);
333
334 revalidate();
335 }
336
337 public void removeValue(int pos) {
338 remove(valueComponents.remove(pos));
339
340 updatePositions();
341 setStatus(StatusFlag.Update);
342
343 revalidate();
344 }
345
346 public void moveUp(int pos) {
347 JComponent comp = valueComponents.get(pos);
348 Collections.swap(valueComponents, pos, pos - 1);
349
350 remove(comp);
351 add(comp, pos);
352
353 updatePositions();
354 setStatus(StatusFlag.Update);
355
356 revalidate();
357 }
358
359 public void moveDown(int pos) {
360 JComponent comp = valueComponents.get(pos);
361 Collections.swap(valueComponents, pos, pos + 1);
362
363 remove(comp);
364 add(comp, pos + 2);
365
366 updatePositions();
367 setStatus(StatusFlag.Update);
368
369 revalidate();
370 }
371
372 public String getId() {
373 return propDef.getId();
374 }
375
376 public Object getValue() {
377 Object result = null;
378
379 if (getStatus() == StatusFlag.Update) {
380 try {
381 if (propDef.getCardinality() == Cardinality.SINGLE) {
382 result = ((PropertyValue) valueComponents.get(0)).getPropertyValue();
383 } else {
384 List<Object> list = new ArrayList<Object>();
385 for (JComponent comp : valueComponents) {
386 list.add(((PropertyValue) comp).getPropertyValue());
387 }
388 result = list;
389 }
390 } catch (Exception ex) {
391 ClientHelper.showError(this, ex);
392 }
393 }
394
395 return result;
396 }
397
398 public boolean includeInUpdate() {
399 return getStatus() != StatusFlag.DontChange;
400 }
401
402 public void setStatus(StatusFlag status) {
403 switch (status) {
404 case Update:
405 changeBox.setSelectedIndex(1);
406 break;
407 case Unset:
408 changeBox.setSelectedIndex(2);
409 break;
410 default:
411 changeBox.setSelectedIndex(0);
412 }
413 }
414
415 public StatusFlag getStatus() {
416 switch (changeBox.getSelectedIndex()) {
417 case 1:
418 return StatusFlag.Update;
419 case 2:
420 return StatusFlag.Unset;
421 default:
422 return StatusFlag.DontChange;
423 }
424 }
425
426 public Dimension getMaximumSize() {
427 Dimension size = getPreferredSize();
428 size.width = Short.MAX_VALUE;
429 return size;
430 }
431 }
432
433
434
435
436 public interface PropertyValue {
437 Object getPropertyValue() throws Exception;
438 }
439
440
441
442
443 public static class StringPropertyInputField extends JTextField implements PropertyValue {
444 private static final long serialVersionUID = 1L;
445
446 public StringPropertyInputField(final Object value, final UpdateStatus status, final Color bgColor) {
447 super(value == null ? "" : value.toString());
448
449 addKeyListener(new KeyListener() {
450 @Override
451 public void keyTyped(KeyEvent e) {
452 }
453
454 @Override
455 public void keyReleased(KeyEvent e) {
456 status.setStatus(StatusFlag.Update);
457 }
458
459 @Override
460 public void keyPressed(KeyEvent e) {
461 }
462 });
463 }
464
465 public Object getPropertyValue() {
466 return getText();
467 }
468 }
469
470
471
472
473 public static class AbstractFormattedPropertyInputField extends JFormattedTextField implements PropertyValue {
474 private static final long serialVersionUID = 1L;
475
476 public AbstractFormattedPropertyInputField(final Object value, final Format format, final UpdateStatus status,
477 final Color bgColor) {
478 super(format);
479 if (value != null) {
480 setValue(value);
481 }
482
483 addKeyListener(new KeyListener() {
484 @Override
485 public void keyTyped(KeyEvent e) {
486 }
487
488 @Override
489 public void keyReleased(KeyEvent e) {
490 status.setStatus(StatusFlag.Update);
491 }
492
493 @Override
494 public void keyPressed(KeyEvent e) {
495 }
496 });
497 }
498
499 public Object getPropertyValue() throws Exception {
500 commitEdit();
501 return getValue();
502 }
503 }
504
505
506
507
508 public static class IntegerPropertyInputField extends AbstractFormattedPropertyInputField {
509 private static final long serialVersionUID = 1L;
510
511 public IntegerPropertyInputField(final Object value, final UpdateStatus status, final Color bgColor) {
512 super(value, createFormat(), status, bgColor);
513 setHorizontalAlignment(JTextField.RIGHT);
514 }
515
516 private static DecimalFormat createFormat() {
517 DecimalFormat result = new DecimalFormat("#,##0");
518 result.setParseBigDecimal(true);
519 result.setParseIntegerOnly(true);
520 return result;
521 }
522
523 public Object getPropertyValue() throws Exception {
524 return ((BigDecimal) super.getValue()).toBigIntegerExact();
525 }
526 }
527
528
529
530
531 public static class DecimalPropertyInputField extends AbstractFormattedPropertyInputField {
532 private static final long serialVersionUID = 1L;
533
534 public DecimalPropertyInputField(final Object value, final UpdateStatus status, final Color bgColor) {
535 super(value, createFormat(), status, bgColor);
536 setHorizontalAlignment(JTextField.RIGHT);
537 }
538
539 private static DecimalFormat createFormat() {
540 DecimalFormat result = new DecimalFormat("#,##0.#############################");
541 result.setParseBigDecimal(true);
542 return result;
543 }
544 }
545
546
547
548
549 public static class BooleanPropertyInputField extends JComboBox implements PropertyValue {
550 private static final long serialVersionUID = 1L;
551
552 public BooleanPropertyInputField(final Object value, final UpdateStatus status, final Color bgColor) {
553 super(new Object[] { true, false });
554 setSelectedItem(value == null ? true : value);
555
556 addActionListener(new ActionListener() {
557 @Override
558 public void actionPerformed(ActionEvent e) {
559 status.setStatus(StatusFlag.Update);
560 }
561 });
562 }
563
564 public Object getPropertyValue() {
565 return getSelectedItem();
566 }
567 }
568
569
570
571
572 public static class DateTimePropertyInputField extends JPanel implements PropertyValue {
573 private static final long serialVersionUID = 1L;
574
575 private static final String[] MONTH_STRINGS;
576
577 static {
578 String[] months = new java.text.DateFormatSymbols().getMonths();
579 int lastIndex = months.length - 1;
580
581 if (months[lastIndex] == null || months[lastIndex].length() <= 0) {
582 String[] monthStrings = new String[lastIndex];
583 System.arraycopy(months, 0, monthStrings, 0, lastIndex);
584 MONTH_STRINGS = monthStrings;
585 } else {
586 MONTH_STRINGS = months;
587 }
588 }
589
590 private final SpinnerNumberModel day;
591 private final SpinnerListModel month;
592 private final SpinnerNumberModel year;
593 private final SpinnerNumberModel hour;
594 private final SpinnerNumberModel min;
595 private final SpinnerNumberModel sec;
596 private final TimeZone timezone;
597
598 public DateTimePropertyInputField(final Object value, final UpdateStatus status, final Color bgColor) {
599 setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
600 setBackground(bgColor);
601
602 GregorianCalendar cal = (value == null ? new GregorianCalendar() : (GregorianCalendar) value);
603 timezone = cal.getTimeZone();
604
605 day = new SpinnerNumberModel(cal.get(Calendar.DATE), 1, 31, 1);
606 addSpinner(new JSpinner(day), status);
607
608 month = new SpinnerListModel(MONTH_STRINGS);
609 month.setValue(MONTH_STRINGS[cal.get(Calendar.MONTH)]);
610 JSpinner monthSpinner = new JSpinner(month);
611 JComponent editor = monthSpinner.getEditor();
612 if (editor instanceof JSpinner.DefaultEditor) {
613 JFormattedTextField tf = ((JSpinner.DefaultEditor) editor).getTextField();
614 tf.setColumns(6);
615 tf.setHorizontalAlignment(JTextField.RIGHT);
616 }
617 addSpinner(monthSpinner, status);
618
619 year = new SpinnerNumberModel(cal.get(Calendar.YEAR), 0, 9999, 1);
620 JSpinner yearSpinner = new JSpinner(year);
621 yearSpinner.setEditor(new JSpinner.NumberEditor(yearSpinner, "#"));
622 yearSpinner.getEditor().setBackground(bgColor);
623 addSpinner(yearSpinner, status);
624
625 add(new JLabel(" "));
626
627 hour = new SpinnerNumberModel(cal.get(Calendar.HOUR_OF_DAY), 0, 23, 1);
628 JSpinner hourSpinner = new JSpinner(hour);
629 addSpinner(hourSpinner, status);
630
631 add(new JLabel(":"));
632
633 min = new SpinnerNumberModel(cal.get(Calendar.MINUTE), 0, 59, 1);
634 JSpinner minSpinner = new JSpinner(min);
635 addSpinner(minSpinner, status);
636
637 add(new JLabel(":"));
638
639 sec = new SpinnerNumberModel(cal.get(Calendar.SECOND), 0, 59, 1);
640 JSpinner secSpinner = new JSpinner(sec);
641 addSpinner(secSpinner, status);
642
643 add(new JLabel(" " + timezone.getDisplayName(true, TimeZone.SHORT)));
644 }
645
646 private void addSpinner(final JSpinner spinner, final UpdateStatus status) {
647 spinner.addChangeListener(new ChangeListener() {
648 @Override
649 public void stateChanged(ChangeEvent e) {
650 status.setStatus(StatusFlag.Update);
651 }
652 });
653
654 add(spinner);
655 }
656
657 public Object getPropertyValue() {
658 GregorianCalendar result = new GregorianCalendar();
659
660 result.setTimeZone(timezone);
661
662 result.set(Calendar.YEAR, year.getNumber().intValue());
663 int mi = 0;
664 String ms = month.getValue().toString();
665 for (int i = 0; i < MONTH_STRINGS.length; i++) {
666 if (MONTH_STRINGS[i].equals(ms)) {
667 mi = i;
668 break;
669 }
670 }
671 result.set(Calendar.MONTH, mi);
672 result.set(Calendar.DATE, day.getNumber().intValue());
673 result.set(Calendar.HOUR_OF_DAY, hour.getNumber().intValue());
674 result.set(Calendar.MINUTE, min.getNumber().intValue());
675 result.set(Calendar.SECOND, sec.getNumber().intValue());
676
677 return result;
678 }
679 }
680
681
682
683
684 public static class MultiValuePropertyInputField extends JPanel implements PropertyValue {
685 private static final long serialVersionUID = 1L;
686
687 private static final ImageIcon ICON_UP = ClientHelper.getIcon("up.png");
688 private static final ImageIcon ICON_DOWN = ClientHelper.getIcon("down.png");
689 private static final ImageIcon ICON_REMOVE = ClientHelper.getIcon("remove.png");
690
691 private final JComponent component;
692 private int position;
693
694 private JButton upButton;
695 private JButton downButton;
696
697 public MultiValuePropertyInputField(final JComponent component, final MultivalueManager mutlivalueManager,
698 final Color bgColor) {
699 super();
700 this.component = component;
701
702 setLayout(new BorderLayout());
703 setBackground(bgColor);
704
705 add(component, BorderLayout.CENTER);
706
707 JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
708 buttonPanel.setBackground(bgColor);
709
710 upButton = new JButton(ICON_UP);
711 upButton.addActionListener(new ActionListener() {
712 @Override
713 public void actionPerformed(ActionEvent e) {
714 mutlivalueManager.moveUp(MultiValuePropertyInputField.this.position);
715 }
716 });
717 buttonPanel.add(upButton);
718
719 downButton = new JButton(ICON_DOWN);
720 downButton.addActionListener(new ActionListener() {
721 @Override
722 public void actionPerformed(ActionEvent e) {
723 mutlivalueManager.moveDown(MultiValuePropertyInputField.this.position);
724 }
725 });
726 buttonPanel.add(downButton);
727
728 JButton removeButton = new JButton(ICON_REMOVE);
729 removeButton.addActionListener(new ActionListener() {
730 @Override
731 public void actionPerformed(ActionEvent e) {
732 mutlivalueManager.removeValue(MultiValuePropertyInputField.this.position);
733 }
734 });
735 buttonPanel.add(removeButton);
736
737 add(buttonPanel, BorderLayout.LINE_END);
738 }
739
740 public void updatePosition(int position, boolean isLast) {
741 this.position = position;
742 upButton.setEnabled(position > 0);
743 downButton.setEnabled(!isLast);
744 }
745
746 public Object getPropertyValue() throws Exception {
747 return ((PropertyValue) component).getPropertyValue();
748 }
749 }
750 }