1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 /***
19 * <p>Title: WSMO Studio</p>
20 * <p>Description: Semantic Web Service Editor</p>
21 * <p>Copyright: Copyright (c) 2004-2006</p>
22 * <p>Company: OntoText Lab. / SIRMA </p>
23 */
24
25 package org.wsmostudio.ui.editors.common;
26
27
28 import java.util.*;
29
30 import org.eclipse.jface.action.*;
31 import org.eclipse.jface.dialogs.*;
32 import org.eclipse.jface.resource.JFaceResources;
33 import org.eclipse.jface.window.Window;
34 import org.eclipse.swt.SWT;
35 import org.eclipse.swt.custom.TreeEditor;
36 import org.eclipse.swt.events.*;
37 import org.eclipse.swt.graphics.*;
38 import org.eclipse.swt.layout.*;
39 import org.eclipse.swt.widgets.*;
40 import org.omwg.ontology.*;
41 import org.wsmo.common.*;
42 import org.wsmo.common.exception.InvalidModelException;
43 import org.wsmo.factory.WsmoFactory;
44 import org.wsmostudio.runtime.*;
45 import org.wsmostudio.ui.*;
46 import org.wsmostudio.ui.editors.model.EntityModel;
47
48
49 /***
50 * An editor component which supports editing of NonFunctionalProperties part of
51 * the WSMO-API objects (where applicable, i.e. implementations of Entity).
52 * The editor appears in a standalone modal window on top of the main studio
53 * workbench.
54 * It can be invoked either from an appropriate editor component, or from the
55 * <i>WSMO Navigator</i> view (via context menu).
56 *
57 * @author not attributable
58 * @version $Revision: 1389 $ $Date: 2007-12-04 17:25:33 +0200 $
59 */
60
61 public class NFPEditor implements MouseListener {
62
63 private static final String[] nfpKeys = new String[] {
64 NFP.DC_TITLE,
65 NFP.DC_CREATOR,
66 NFP.DC_SUBJECT,
67 NFP.DC_DESCRIPTION,
68 NFP.DC_PUBLISHER,
69 NFP.DC_CONTRIBUTOR,
70 NFP.DC_DATE,
71 NFP.DC_TYPE,
72 NFP.DC_FORMAT,
73 NFP.DC_IDENTIFIER,
74 NFP.DC_SOURCE,
75 NFP.DC_LANGUAGE,
76 NFP.DC_RELATION,
77 NFP.DC_COVERAGE,
78 NFP.DC_RIGHTS,
79 NFP.VERSION
80 };
81
82 private EntityModel model;
83
84 private Tree tableTree;
85 private TreeEditor editor;
86 private Shell shell;
87
88 private Map<IRI, Set<Object>> sourceData;
89 private boolean dirty = false;
90
91 private Action addDataValueAction,
92 addInstanceValueAction,
93 addIRIAction,
94 addPropertyAction,
95 editValueAction,
96 removeValueAction,
97 removeValuesAction,
98 removePropertyAction;
99
100
101 public NFPEditor(Shell parent, EntityModel model) {
102 this.model = model;
103 shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.SYSTEM_MODAL);
104 Image icon = JFaceResources.getImageRegistry().get(WsmoImageRegistry.DEFAULT_WINDOW_ICON);
105 shell.setImage(icon);
106 shell.setText("Non Functional Properties");
107 shell.setSize(450, 300);
108 shell.setLayout(new GridLayout(1, false));
109
110 sourceData = new HashMap<IRI, Set<Object>>();
111 readEditorContent (sourceData, (Entity)model.getAdapter(Entity.class));
112 initInputData();
113 createDialogArea(shell);
114 createControlArea(shell);
115 initAtions();
116 createContextMenu();
117
118 shell.pack();
119
120 Point pLocation = parent.getLocation();
121 Point pSize = parent.getSize();
122 shell.setLocation(pLocation.x + pSize.x / 2 - shell.getSize().x / 2,
123 pLocation.y + pSize.y / 2 - shell.getSize().y / 2);
124 }
125
126 private void createDialogArea(Composite comp) {
127
128 tableTree = new Tree(comp, SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER);
129 tableTree.setLayoutData(new GridData(GridData.FILL_BOTH));
130 tableTree.setLinesVisible(true);
131 tableTree.setHeaderVisible(true);
132
133 TreeColumn column = new TreeColumn(tableTree, SWT.CENTER);
134 column.setWidth(comp.getShell().getBounds().width - 10);
135 column.setText("Properties");
136 column.setAlignment(SWT.CENTER);
137
138 for(IRI key : sourceData.keySet()) {
139 Set<Object> values = sourceData.get(key);
140
141 TreeItem item = new TreeItem(tableTree, SWT.NONE);
142 item.setText(0, prepareLabel(key));
143 item.setData(key);
144 if (isPropertyEditable(key)) {
145 item.setForeground(comp.getDisplay().getSystemColor(SWT.COLOR_BLUE));
146 }
147 else {
148 item.setForeground(comp.getDisplay().getSystemColor(SWT.COLOR_DARK_BLUE));
149 }
150 item.setImage(JFaceResources.getImage(WsmoImageRegistry.NFP_KEY_ICON));
151
152 for(Object value : values) {
153 TreeItem subitem = new TreeItem(item, SWT.NONE);
154 subitem.setText(0, (value instanceof Instance)
155 ? ((Instance)value).getIdentifier().toString()
156 : Utils.normalizeSpaces(value.toString()));
157 subitem.setData(value);
158 subitem.setImage(WsmoImageRegistry.getImageForObject(value));
159 }
160 }
161
162 editor = new TreeEditor(tableTree);
163 editor.horizontalAlignment = SWT.TRAIL;
164 editor.grabHorizontal = true;
165 editor.minimumWidth = 50;
166
167 tableTree.addMouseListener(this);
168 }
169
170 private void initInputData() {
171 WsmoFactory factory = WSMORuntime.getRuntime().getWsmoFactory();
172 IRI tempKey;
173 for(int i = 0; i < nfpKeys.length; i++) {
174 try {
175 tempKey = factory.createIRI(nfpKeys[i]);
176 if (false == sourceData.containsKey(tempKey)) {
177 sourceData.put(tempKey, new HashSet<Object>());
178 }
179 }
180 catch(Exception ex) {
181 LogManager.logError("Invalid NFP key : " + nfpKeys[i], ex);
182 }
183 }
184 }
185
186 private void readEditorContent(Map<IRI,Set<Object>> sourceData,
187 Entity nfpHolder) {
188 for (IRI key : nfpHolder.listNFPValues().keySet()) {
189 HashSet<Object> vals = new HashSet<Object>();
190 vals.addAll(nfpHolder.listNFPValues(key));
191 sourceData.put(key, vals);
192 }
193 }
194
195 private void createControlArea(Composite mainContainer) {
196 Composite buttons = new Composite(mainContainer, SWT.NONE);
197 buttons.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
198 FillLayout layout = new FillLayout(SWT.HORIZONTAL);
199 layout.spacing = 3;
200 buttons.setLayout(layout);
201
202 Button okButton = new Button(buttons, SWT.PUSH);
203 okButton.setText("OK");
204 okButton.addSelectionListener(new SelectionAdapter() {
205 public void widgetSelected(SelectionEvent e) {
206 try {
207 doUpdate();
208 }
209 catch(Exception ime) {
210 MessageDialog.openError(shell, "Error", ime.getMessage());
211 LogManager.logError(ime);
212 return;
213 }
214 shell.dispose();
215 }
216 });
217 shell.setDefaultButton(okButton);
218
219 Button noButton = new Button(buttons, SWT.PUSH);
220 noButton.setText("Cancel");
221 noButton.addSelectionListener(new SelectionAdapter() {
222 public void widgetSelected(SelectionEvent e) {
223 dirty = false;
224 shell.dispose();
225 }
226 });
227 }
228
229 public boolean open() {
230 shell.open();
231 Display display = shell.getDisplay();
232 while (!shell.isDisposed()) {
233 if (!display.readAndDispatch()) {
234 display.sleep();
235 }
236 }
237 return dirty;
238 }
239
240 public void dispose() {
241 tableTree.dispose();
242 editor.dispose();
243
244 }
245
246 public String prepareLabel(IRI key) {
247 return Utils.getEntityLocalName(key.toString(),
248 Utils.findTopContainer(this.model));
249 }
250
251 public void mouseDoubleClick(MouseEvent e) {
252 TreeItem[] sel = tableTree.getSelection();
253 if (sel.length == 0) {
254 return;
255 }
256 Control oldEditor = editor.getEditor();
257 if (oldEditor != null) {
258 oldEditor.dispose();
259 }
260 if (sel[0].getParentItem() == null) {
261 return;
262 }
263 if (sel[0].getParentItem().getData() instanceof IRI
264 && false == isPropertyEditable((IRI)sel[0].getParentItem().getData())) {
265 return;
266 }
267 doEditCell(sel[0]);
268 }
269
270 private void doEditCell(TreeItem cell) {
271 if (cell.getData() instanceof Instance) {
272 return;
273 }
274 if (cell.getData() instanceof DataValue) {
275 DataValue newVal = DataValueEditor.createEditor(shell, (DataValue)cell.getData(), null);
276 if (newVal != null &&
277 false == newVal.equals(cell.getData())) {
278 cell.setData(newVal);
279 cell.setText(newVal.toString());
280 dirty = true;
281 }
282 return;
283 }
284
285 if (cell.getData() instanceof Identifier) {
286 IdentifierInputDialog iid = new IdentifierInputDialog(
287 shell,
288 "Edit Identifier",
289 "IRI :",
290 cell.getData().toString(),
291 (TopEntity)model.getAdapter(TopEntity.class),
292 WSMORuntime.getRuntime().getWsmoFactory(),
293 false);
294
295 if (iid.open() != Window.OK) {
296 return;
297 }
298 IRI newIRI = (IRI)iid.getIdentifier();
299 if (newIRI != null &&
300 false == newIRI.equals(cell.getData())) {
301 cell.setData(newIRI);
302 cell.setText(newIRI.toString());
303 dirty = true;
304 }
305 }
306 }
307
308 public void mouseDown(MouseEvent e) {
309 Control oldEditor = editor.getEditor();
310 if (oldEditor == null) {
311 return;
312 }
313 TreeItem[] sel = tableTree.getSelection();
314 if (sel.length == 0) {
315 return;
316 }
317 if (editor.getItem() != sel[0]) {
318 oldEditor.dispose();
319 }
320 }
321 public void mouseUp(MouseEvent e) {}
322
323
324 private void createContextMenu() {
325 final MenuManager menuMgr = new MenuManager();
326 menuMgr.setRemoveAllWhenShown(true);
327 menuMgr.addMenuListener(new IMenuListener() {
328 public void menuAboutToShow(IMenuManager mgr) {
329 fillContextMenu(menuMgr);
330 }
331 });
332
333
334 tableTree.setMenu(menuMgr.createContextMenu(tableTree));
335 }
336
337 private void fillContextMenu(MenuManager menuMgr) {
338
339 if (false == GUIHelper.containsCursor(tableTree)) {
340 return;
341 }
342
343 TreeItem target = tableTree.getSelection()[0];
344 final boolean onAKey = target.getParentItem() == null;
345
346 Action[] actions;
347 if (onAKey) {
348 if (target.getData() instanceof IRI
349 && false == isPropertyEditable((IRI)target.getData())) {
350 actions = new Action[] { addPropertyAction };
351 }
352 else {
353 actions = new Action[] {
354 addDataValueAction,
355 addInstanceValueAction,
356 addIRIAction,
357 null,
358 addPropertyAction,
359 null,
360 removeValuesAction,
361 removePropertyAction };
362 }
363 }
364 else {
365 if (target.getParentItem().getData() instanceof IRI
366 && false == isPropertyEditable((IRI)target.getParentItem().getData())) {
367 return;
368 }
369 actions = new Action[] { editValueAction, null, removeValueAction };
370 }
371
372 for (int i = 0; i < actions.length; i++) {
373 if (actions[i] == null) {
374 menuMgr.add(new Separator());
375 }
376 else {
377 menuMgr.add(actions[i]);
378 if (actions[i].getText().equals("Remove Property")) {
379 actions[i].setEnabled(!isRequiredProperty(target.getData()));
380 }
381 }
382 }
383 }
384
385 @SuppressWarnings("unchecked")
386 public void initAtions() {
387 addDataValueAction = new Action("Add Data Value") {
388 public void run() {
389 DataValue newVal = DataValueEditor.createEditor(shell);
390 if (newVal == null) {
391 return;
392 }
393 TreeItem[] sel = tableTree.getSelection();
394 TreeItem subitem = new TreeItem(sel[0], SWT.NONE);
395 subitem.setData(newVal);
396 subitem.setText(newVal.toString());
397 subitem.setImage(WsmoImageRegistry.getImageForObject(newVal));
398 sel[0].setExpanded(true);
399 tableTree.setSelection(new TreeItem[] { subitem });
400 tableTree.showSelection();
401 tableTree.redraw();
402 sourceData.get(sel[0].getData()).add(newVal);
403 dirty = true;
404 }
405 };
406 addInstanceValueAction = new Action("Add Instance Value") {
407 public void run() {
408 TreeItem[] sel = tableTree.getSelection();
409 WSMOChooser chooser = WSMOChooser.createInstanceChooser(
410 shell,
411 WSMORuntime.getRuntime());
412
413 Instance newInstance = (Instance)chooser.open();
414 if (newInstance == null) {
415 return;
416 }
417 TreeItem subitem = new TreeItem(sel[0], SWT.NONE);
418 subitem.setData(newInstance);
419 subitem.setText(newInstance.getIdentifier().toString());
420 subitem.setImage(WsmoImageRegistry.getImageForObject(newInstance));
421 sel[0].setExpanded(true);
422 tableTree.setSelection(new TreeItem[] { subitem });
423 tableTree.showSelection();
424 tableTree.redraw();
425 sourceData.get(sel[0].getData()).add(newInstance);
426 dirty = true;
427 }
428 };
429 addIRIAction = new Action("Add IRI") {
430 public void run() {
431 TreeItem[] sel = tableTree.getSelection();
432 IdentifierInputDialog iid = new IdentifierInputDialog(shell,
433 "New Identifier",
434 "IRI : ",
435 Utils.findTopContainer(model),
436 WSMORuntime.getRuntime().getWsmoFactory(),
437 false);
438
439 if (iid.open() != Window.OK) {
440 return;
441 }
442 IRI newIRI = (IRI)iid.getIdentifier();
443 TreeItem subitem = new TreeItem(sel[0], SWT.NONE);
444 subitem.setText(0, newIRI.toString());
445 subitem.setData(newIRI);
446 subitem.setImage(WsmoImageRegistry.getImageForObject(newIRI));
447 sel[0].setExpanded(true);
448 tableTree.setSelection(new TreeItem[] { subitem });
449 tableTree.showSelection();
450 tableTree.redraw();
451 sourceData.get(sel[0].getData()).add(newIRI);
452 dirty = true;
453 }
454 };
455
456 addPropertyAction = new Action("Add Property") {
457 public void run() {
458 final IdentifierInputDialog inputDialog = new IdentifierInputDialog(
459 shell,
460 "New Property Name",
461 "Please supply a property URI",
462 "",
463 Utils.findTopContainer(model),
464 WSMORuntime.getRuntime().getWsmoFactory(),
465 false);
466 inputDialog.setInputValidator(new IInputValidator() {
467 public String isValid(String input) {
468 Identifier id = inputDialog.getIdentifier();
469 if (id != null
470 && id instanceof IRI) {
471 if (false == isPropertyEditable((IRI)id)) {
472 return "Using wsmostudio namespace as NFP key is not allowed";
473 }
474 TreeItem[] propsItems = tableTree.getItems();
475 for(int i = 0; i < propsItems.length; i++) {
476 if (id.equals(propsItems[i].getData())) {
477 return "Duplicated NFP key.";
478 }
479 }
480
481 }
482 return null;
483 }
484 });
485
486 if (inputDialog.open() != Window.OK) {
487 return;
488 }
489 IRI newProperty = (IRI)inputDialog.getIdentifier();
490 if (sourceData.containsKey(newProperty)) {
491 return;
492 }
493
494 TreeItem item = new TreeItem(tableTree, SWT.NONE);
495 item.setText(0, prepareLabel(newProperty));
496 item.setData(newProperty);
497 item.setForeground(tableTree.getDisplay().getSystemColor(SWT.COLOR_BLUE));
498 item.setImage(JFaceResources.getImage(WsmoImageRegistry.NFP_KEY_ICON));
499 tableTree.setSelection(new TreeItem[] { item });
500 tableTree.showSelection();
501 tableTree.redraw();
502 sourceData.put(newProperty, new HashSet());
503 dirty = true;
504 }
505 };
506 editValueAction = new Action("Edit Value") {
507 public void run() {
508 TreeItem[] sel = tableTree.getSelection();
509 doEditCell(sel[0]);
510 }
511
512 };
513 removeValueAction = new Action("Remove Value") {
514 public void run() {
515 TreeItem[] sel = tableTree.getSelection();
516 TreeItem parentItem = sel[0].getParentItem();
517 sourceData.get(parentItem.getData()).remove(sel[0].getData());
518
519 sel[0].dispose();
520 tableTree.setSelection(new TreeItem[] { parentItem });
521 tableTree.redraw();
522 dirty = true;
523 }
524 };
525 removeValuesAction = new Action("Remove Values") {
526 public void run() {
527 TreeItem[] sel = tableTree.getSelection();
528 TreeItem[] subItems = sel[0].getItems();
529 if (subItems.length == 0) {
530 return;
531 }
532 for(int i = 0; i < subItems.length; i++) {
533 subItems[i].dispose();
534 }
535 sourceData.get(sel[0].getData()).clear();
536 tableTree.redraw();
537 dirty = true;
538 }
539 };
540 removePropertyAction = new Action("Remove Property") {
541 public void run() {
542 TreeItem[] sel = tableTree.getSelection();
543 if (sel[0].getData() == null) {
544 return;
545 }
546 sourceData.remove(sel[0].getData());
547 sel[0].dispose();
548 tableTree.redraw();
549 dirty = true;
550 }
551 };
552 }
553
554 @SuppressWarnings("unchecked")
555 private void doUpdate() throws Exception {
556 if (!dirty) {
557 return;
558 }
559 Entity targetHolder = (Entity)model.getAdapter(Entity.class);
560 Map oldNFPState = targetHolder.listNFPValues();
561 updateValuesFromUI();
562
563 for (Iterator it = oldNFPState.keySet().iterator(); it.hasNext(); ) {
564 IRI iriKey = (IRI)it.next();
565 if (false == sourceData.containsKey(iriKey)) {
566 clearProperty(iriKey, targetHolder);
567 continue;
568 }
569 Set newValues = sourceData.get(iriKey);
570 if (newValues.size() == 0) {
571 clearProperty(iriKey, targetHolder);
572 continue;
573 }
574
575
576 for (Object oldValue : new HashSet<Object>(targetHolder.listNFPValues(iriKey))) {
577 if (false == newValues.contains(oldValue)) {
578 if (oldValue instanceof Identifier) {
579 model.removeNFPValue(iriKey, (Identifier)oldValue);
580 }
581 else {
582 model.removeNFPValue(iriKey, (Value)oldValue);
583 }
584 }
585 }
586
587 for (Object val : newValues) {
588 if (val instanceof Identifier) {
589 model.addNFPValue(iriKey, (Identifier)val);
590 }
591 else {
592 model.addNFPValue(iriKey, (Value)val);
593 }
594 }
595 }
596
597
598
599 for (Iterator it = sourceData.keySet().iterator(); it.hasNext(); ) {
600 IRI propName = (IRI)it.next();
601 for (Object val : sourceData.get(propName)) {
602 if (val instanceof Identifier) {
603 model.addNFPValue(propName, (Identifier)val);
604 }
605 else {
606 model.addNFPValue(propName, (Value)val);
607 }
608 }
609 }
610 }
611
612 private void updateValuesFromUI() throws Exception {
613 sourceData.clear();
614 TreeItem[] propsItems = tableTree.getItems();
615 WsmoFactory factory = WSMORuntime.getRuntime().getWsmoFactory();
616 for(int i = 0; i < propsItems.length; i++) {
617 IRI property = (IRI)propsItems[i].getData();
618 TreeItem[] valsItems = propsItems[i].getItems();
619 Set<Object> valsSet = new HashSet<Object>();
620 for(int k = 0; k < valsItems.length; k++) {
621 if(valsItems[k].getText(0).trim().length() > 0) {
622 Object oldValue = valsItems[k].getData();
623 if (oldValue instanceof Identifier
624 && false == oldValue.toString().equals(
625 valsItems[k].getText(0).trim())) {
626 try {
627 oldValue = factory.createIRI(valsItems[k].getText(0).trim());
628 }
629 catch(Exception ex) {
630 throw new Exception("Invalid value for property '"
631 + property.toString()
632 + "'\n(" + valsItems[k].getText(0).trim() + ")"
633 + "\n" + ex.getMessage()
634 , ex);
635 }
636 }
637 valsSet.add(oldValue);
638 }
639 sourceData.put(property, valsSet);
640 }
641 }
642 }
643
644 @SuppressWarnings("unchecked")
645 private void clearProperty(IRI property, Entity nfpHolder) {
646 try {
647 for(Object val : new HashSet<Object>(nfpHolder.listNFPValues(property))) {
648 if (val instanceof Identifier) {
649 model.removeNFPValue(property, (Identifier)val);
650 }
651 else {
652 model.removeNFPValue(property, (Value)val);
653 }
654 }
655 }
656 catch(InvalidModelException ime) {
657 LogManager.logError(ime);
658 }
659 dirty = true;
660 }
661
662 private boolean isRequiredProperty(Object propName) {
663 if (propName == null ||
664 false == propName instanceof IRI) {
665 return false;
666 }
667 String name = ((IRI)propName).toString();
668 for(int i = 0; i < nfpKeys.length; i++) {
669 if (nfpKeys[i].equals(name)) {
670 return true;
671 }
672 }
673 return false;
674 }
675
676 /***
677 * Extenders may customize the editability of the properties
678 * @param nfpKey
679 * @return
680 */
681 protected boolean isPropertyEditable(IRI nfpKey) {
682 return false == nfpKey.toString().startsWith("http://www.wsmostudio.org#");
683 }
684 }
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761