View Javadoc
1   /* 
2    WSMO Studio - a Semantic Web Service Editor
3    Copyright (c) 2004-2006, OntoText Lab. / SIRMA Group
4    
5    This library is free software; you can redistribute it and/or modify it under
6    the terms of the GNU Lesser General Public License as published by the Free
7    Software Foundation; either version 2.1 of the License, or (at your option)
8    any later version.
9    This library is distributed in the hope that it will be useful, but WITHOUT
10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   details.
13   You should have received a copy of the GNU Lesser General Public License along
14   with this library; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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;
26  
27  
28  
29  import java.util.*;
30  
31  import org.eclipse.jface.action.*;
32  import org.eclipse.jface.resource.JFaceResources;
33  import org.eclipse.swt.SWT;
34  import org.eclipse.swt.events.*;
35  import org.eclipse.swt.graphics.Image;
36  import org.eclipse.swt.graphics.Point;
37  import org.eclipse.swt.layout.*;
38  import org.eclipse.swt.widgets.*;
39  import org.omwg.ontology.*;
40  import org.wsmo.common.*;
41  import org.wsmo.common.exception.InvalidModelException;
42  import org.wsmostudio.runtime.*;
43  import org.wsmostudio.ui.GUIHelper;
44  import org.wsmostudio.ui.Utils;
45  import org.wsmostudio.ui.editors.common.*;
46  import org.wsmostudio.ui.editors.model.AttributeModel;
47  
48  /***
49   * An editor component capable to handle with WSMO-API Attribute objects.
50   * As attributes are highly dependent on their containing Concepts this editor
51   * is dependent on the Concept Editor (i.e. Attribute Editor is a supporting part
52   * of the Concep Editor). In contrast to the most of the other editors, this 
53   * editor appears in a standalone modal window on top of the main studio workbench.
54   *
55   * @author not attributable
56   * @version $Revision: 1382 $ $Date: 2007-11-27 14:49:20 +0200 $
57   */
58  
59  public class AttributeEditor {
60      
61      private AttributeModel model;
62      private Identifier inverseAttrRef = null;
63      
64      private NFPPanel nfpPanel;
65      private Table rangesTable;
66      private Shell shell;
67      
68      private boolean dirty = false;
69      
70      private Button minCheck;
71      private Button maxCheck;
72      private Text minText;
73      private Text maxText;
74  
75      private Button inverseOfCheck;
76      private Text inverseAttrText;
77      private Button inverseSelect;
78  
79      private Button constrCheck;
80      private Button reflexiveCheck;
81      private Button symmetricCheck;
82      private Button transCheck;
83      
84      
85      public AttributeEditor(Shell parentShell,
86                             AttributeModel model) {
87          shell = new Shell(parentShell, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.SYSTEM_MODAL);
88          Image icon = JFaceResources.getImageRegistry().get(WsmoImageRegistry.DEFAULT_WINDOW_ICON);
89          shell.setImage(icon);
90          shell.setText("Attribute Editor");
91          shell.setLayout(new GridLayout(1, false));
92  
93          nfpPanel = new NFPPanel(shell, model);
94          
95          this.model = model;
96  
97          createDomainView(shell);
98          createPropertiesView(shell);
99          createRangesView(shell);
100         createControlArea(shell);
101         createContextMenu();
102         
103         shell.pack();
104         shell.setSize(Math.min(shell.getSize().x, 600),
105                       shell.getSize().y + 40);
106         
107         Point pLocation = parentShell.getLocation();
108         Point pSize = parentShell.getSize();
109         shell.setLocation(pLocation.x + pSize.x / 2 - shell.getSize().x / 2,
110                 pLocation.y + pSize.y / 2 - shell.getSize().y / 2);
111     }
112     
113     private void createDomainView(Composite parent) {
114         Group group = new Group(parent, SWT.NONE);
115         group.setText("Domain Concept");
116         group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
117         group.setLayout(new GridLayout(3, false));
118         
119         new Label(group, SWT.NONE).setText("Concept : ");
120         final Text domainText = new Text(group, SWT.READ_ONLY | SWT.BORDER);
121         domainText.setText(model.getAttribute().getConcept().getIdentifier().toString());
122         domainText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
123         
124         Button changeDomain = new Button(group, SWT.NONE);
125         changeDomain.setText("Change");
126         changeDomain.addSelectionListener(new SelectionAdapter() {
127             public void widgetSelected(SelectionEvent e) {
128                 WSMOChooser chooser = WSMOChooser.createConceptChooser(shell, 
129                         model.getAttribute().getConcept().getOntology());
130                 Concept newDomain = (Concept)chooser.open();
131                 if (newDomain == null ||
132                         newDomain.equals(model.getAttribute().getConcept())) {
133                     return;
134                 }
135                 try {
136                     model.setConcept(newDomain);
137                 }
138                 catch(Exception ime) {
139                     LogManager.logError(ime);
140                 }
141                 model.setChanged();
142                 domainText.setText(
143                         model.getAttribute().getConcept().getIdentifier().toString());
144             }
145         });
146         
147     }
148 
149     private void createPropertiesView(Composite parent) {
150         Group group = new Group(parent, SWT.NONE);
151         group.setText("Attribute Properties");
152         group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
153         group.setLayout(new GridLayout(1, true));
154         
155         Composite comp1 = new Composite(group, SWT.NONE);
156         comp1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
157         GridLayout layout = new GridLayout(7, false); 
158         layout.marginHeight = 2;
159         comp1.setLayout(layout);
160         
161         SelectionAdapter dirtyListener = new SelectionAdapter() {
162             public void widgetSelected(SelectionEvent e) {
163                 dirty = true;
164             }
165          };
166 
167         Label cardLab = new Label(comp1, SWT.NONE);
168         cardLab.setText("Cardinality:  ");
169         
170         minCheck = new Button(comp1, SWT.CHECK);
171         minCheck.setText("set MIN :");
172         minCheck.setSelection(model.getAttribute().getMinCardinality() != 0);
173         minCheck.addSelectionListener(dirtyListener);
174         
175         minText = new Text(comp1, SWT.BORDER);
176         minText.setTextLimit(3);
177         minText.setText(String.valueOf(model.getAttribute().getMinCardinality()));
178         minText.setLayoutData(new GridData(30, SWT.DEFAULT));
179         minText.addModifyListener(new ModifyListener() {
180             public void modifyText(ModifyEvent event) {
181                 dirty = true;
182             }
183         });
184         minText.setEnabled(minCheck.getSelection());
185 
186         minCheck.addSelectionListener(new SelectionAdapter() {
187             public void widgetSelected(SelectionEvent e) {
188                 minText.setEnabled(minCheck.getSelection()); 
189             }
190          });
191         
192         new Label(comp1, SWT.NONE).setLayoutData(new GridData(40, 13));
193         
194 
195         maxCheck = new Button(comp1, SWT.CHECK);
196         maxCheck.setText("set MAX :");
197         maxCheck.setSelection(model.getAttribute().getMaxCardinality() != Integer.MAX_VALUE);
198         maxCheck.addSelectionListener(dirtyListener);
199 
200         maxText = new Text(comp1, SWT.BORDER);
201         maxText.setTextLimit(3);
202         maxText.setLayoutData(new GridData(30, SWT.DEFAULT));
203         if (model.getAttribute().getMaxCardinality() != Integer.MAX_VALUE) {
204             maxText.setText(String.valueOf(model.getAttribute().getMaxCardinality()));
205         }
206         maxText.addModifyListener(new ModifyListener() {
207             public void modifyText(ModifyEvent event) {
208                 dirty = true;
209             }
210         });
211         maxText.setEnabled(maxCheck.getSelection());
212 
213         maxCheck.addSelectionListener(new SelectionAdapter() {
214             public void widgetSelected(SelectionEvent e) {
215                 maxText.setEnabled(maxCheck.getSelection()); 
216             }
217          });
218         
219         Composite comp2 = new Composite(group, SWT.NONE);
220         comp2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
221         layout = new GridLayout(9, false); 
222         layout.marginHeight = 2;
223         comp2.setLayout(layout);
224         
225         Point leadingOffset = cardLab.computeSize(SWT.DEFAULT, SWT.DEFAULT, false);
226         new Label(comp2, SWT.NONE).setLayoutData(
227                 new GridData(leadingOffset.x, leadingOffset.y));
228         
229         constrCheck = new Button(comp2, SWT.CHECK);
230         constrCheck.setText("Constraining");
231         constrCheck.setSelection(model.getAttribute().isConstraining());
232         constrCheck.addSelectionListener(dirtyListener);
233         
234         new Label(comp2, SWT.NONE).setText("   ");
235 
236         reflexiveCheck = new Button(comp2, SWT.CHECK);
237         reflexiveCheck.setText("Reflexive");
238         reflexiveCheck.setSelection(model.getAttribute().isReflexive());
239         reflexiveCheck.addSelectionListener(dirtyListener);
240 
241         new Label(comp2, SWT.NONE).setText("   ");
242 
243         symmetricCheck = new Button(comp2, SWT.CHECK);
244         symmetricCheck.setText("Symmetric");
245         symmetricCheck.setSelection(model.getAttribute().isSymmetric());
246         symmetricCheck.addSelectionListener(dirtyListener);
247 
248         
249         new Label(comp2, SWT.NONE).setText("   ");
250 
251         transCheck = new Button(comp2, SWT.CHECK);
252         transCheck.setText("Transitive");
253         transCheck.setSelection(model.getAttribute().isTransitive());
254         transCheck.addSelectionListener(dirtyListener);
255 
256         Composite comp3 = new Composite(group, SWT.NONE);
257         comp3.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
258         layout = new GridLayout(4, false); 
259         layout.marginHeight = 2;
260         comp3.setLayout(layout);
261 
262         new Label(comp3, SWT.NONE).setLayoutData(
263                 new GridData(leadingOffset.x, leadingOffset.y));
264 
265         Identifier invAttrRef = model.getAttribute().getInverseOf();
266         inverseAttrRef = invAttrRef;
267 
268         inverseOfCheck = new Button(comp3, SWT.CHECK);
269         inverseOfCheck.setText("Inverse of");
270         inverseOfCheck.setSelection(invAttrRef != null);
271         inverseOfCheck.addSelectionListener(dirtyListener);
272         
273         inverseAttrText = new Text(comp3, SWT.BORDER | SWT.READ_ONLY);
274         inverseAttrText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
275         inverseAttrText.setEnabled(inverseOfCheck.getSelection());
276         if (invAttrRef != null) {
277             inverseAttrText.setText(invAttrRef.toString());
278         }
279         
280         inverseSelect = new Button(comp3, SWT.PUSH);
281         inverseSelect.setText("Select");
282         inverseSelect.setEnabled(inverseOfCheck.getSelection());
283         inverseSelect.addSelectionListener(new SelectionAdapter() {
284         	public void widgetSelected(SelectionEvent event) {
285                 WSMOChooser chooser = WSMOChooser.createAttributesChooser(
286                         shell, 
287                         WSMORuntime.getRuntime());
288                 Attribute inverseAttr = (Attribute)chooser.open();
289                 if (inverseAttr == null) {
290                 	return;
291                 }
292                 inverseAttrRef = (IRI)inverseAttr.getIdentifier();
293                 inverseAttrText.setText(inverseAttr.getIdentifier().toString());
294                 dirty = true;
295         	}
296         });
297         
298         inverseOfCheck.addSelectionListener(new SelectionAdapter() {
299             public void widgetSelected(SelectionEvent e) {
300                 inverseAttrText.setEnabled(inverseOfCheck.getSelection());
301                 inverseSelect.setEnabled(inverseOfCheck.getSelection());
302             }
303         });
304         comp1.pack();
305         comp2.pack();
306         comp3.pack();
307     }
308     
309     private void createRangesView(Composite parent) {
310         Group group = new Group(parent, SWT.NONE);
311         group.setLayoutData(new GridData(GridData.FILL_BOTH));
312         group.setText("Range Concepts");
313         group.setLayout(new GridLayout());
314         
315         rangesTable = new Table(group, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
316         rangesTable.setLayoutData(new GridData(GridData.FILL_BOTH));
317         rangesTable.setLinesVisible(false);
318         for(Type type : model.getAttribute().listTypes()) {
319             GUIHelper.createTableItem(rangesTable, type, Utils.findTopContainer(model)); 
320         }
321     }
322 
323 
324     private void createControlArea(Composite mainContainer) {
325         Composite buttons = new Composite(mainContainer, SWT.NONE);
326         buttons.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
327         FillLayout layout = new FillLayout(SWT.HORIZONTAL);
328         layout.spacing = 3;
329         buttons.setLayout(layout);
330 
331         Button okButton = new Button(buttons, SWT.PUSH);
332         okButton.setText("OK");
333         okButton.addSelectionListener(new SelectionAdapter() {
334             public void widgetSelected(SelectionEvent e) {
335                 doUpdate();
336                 shell.dispose();
337             }
338         });
339         shell.setDefaultButton(okButton);
340         
341         Button noButton = new Button(buttons, SWT.PUSH);
342         noButton.setText("Cancel");
343         noButton.addSelectionListener(new SelectionAdapter() {
344             public void widgetSelected(SelectionEvent e) {
345                 shell.dispose();
346             }
347         });
348 
349     }
350     
351     private void createContextMenu() {
352     	final MenuManager menuMgr = new MenuManager();
353     	menuMgr.setRemoveAllWhenShown(true);
354     	menuMgr.addMenuListener(new IMenuListener() {
355     		public void menuAboutToShow(IMenuManager mgr) {
356     			fillContextMenu(menuMgr);
357     		}
358     	});
359     	rangesTable.setMenu(menuMgr.createContextMenu(rangesTable));
360     }
361 
362     private void fillContextMenu(MenuManager menuMgr) {
363 
364     	if (false == GUIHelper.containsCursor(rangesTable)) {
365     		return;
366     	}
367     	menuMgr.add(new Action("Add Concept") {
368     		public void run() {
369     			handleAddConcept();
370     		}
371     	});
372     	menuMgr.add(new Action("Add Data Type") {
373     		public void run() {
374     			handleAddDataType();
375     		}
376     	});
377         TableItem[] sel = rangesTable.getSelection();
378     	if (sel != null 
379     			&& sel.length > 0 
380     			&& GUIHelper.containsCursor(sel[0].getBounds(0), rangesTable)) {
381     		menuMgr.add(new Action("Remove") {
382     			public void run() {
383     				handleRemoveType();
384     			}
385     		});
386     	}
387     }
388 
389     public void open() {
390         shell.open();
391         Display display = shell.getDisplay();
392         while (!shell.isDisposed()) {
393             if (!display.readAndDispatch()) {
394                 display.sleep();
395             }
396         }
397     }
398     
399     public void dispose() {
400         rangesTable.dispose();
401         nfpPanel.dispose();
402         inverseAttrRef = null;
403         model.getMasterModel().removeSubModel(model);
404         model = null;
405     }
406     
407     private void handleAddConcept() {
408         WSMOChooser chooser = WSMOChooser.createConceptChooser(shell, WSMORuntime.getRuntime());
409         Object selected = chooser.open();
410         if (selected == null || false == selected instanceof Concept) {
411             return;
412         }
413         GUIHelper.createTableItem(rangesTable, selected, Utils.findTopContainer(model));
414         dirty = true;
415         rangesTable.redraw();
416     }
417     private void handleAddDataType() {
418         WsmlDataType datatype = DataValueEditor.createTypeSelector(shell);
419         if (datatype == null) {
420             return;
421         }
422         GUIHelper.createTableItem(rangesTable, datatype, (TopEntity)null);
423         dirty = true;
424         rangesTable.redraw();
425     }
426     private void handleRemoveType() {
427         TableItem[] sel = rangesTable.getSelection();
428         sel[0].dispose();
429         dirty = true;
430         rangesTable.redraw();
431     }
432     
433     private void doUpdate() {
434         if (false == dirty) {
435             return; // no need to update
436         }
437         
438         int minValue = 0;
439         if (minCheck.getSelection()) {
440             try {
441                 minValue = Integer.parseInt(minText.getText());
442             }
443             catch (Exception e) {}
444         }
445         int maxValue = Integer.MAX_VALUE;
446         if (maxCheck.getSelection()) {
447             try {
448                 maxValue = Integer.parseInt(maxText.getText());
449             }
450             catch (Exception e) {}
451         }
452         model.setMinCardinality(Math.max(minValue, 0));
453         model.setMaxCardinality(maxValue);
454 
455         if (false == inverseOfCheck.getSelection()) {
456             model.setInverseOf(null);
457         }
458         else {
459             model.setInverseOf(inverseAttrRef);
460         }
461         model.setConstraining(constrCheck.getSelection());
462         model.setReflexive(reflexiveCheck.getSelection());
463         model.setSymmetric(symmetricCheck.getSelection());
464         model.setTransitive(transCheck.getSelection());
465         
466         // updating range types
467         TableItem[] allItems = rangesTable.getItems();
468         Set<Type> typesBuffer = new HashSet<Type>();
469         Set<Type> oldTypes = new HashSet<Type>(model.getAttribute().listTypes());
470         // first add the new ones (if such present)
471         for(int i = 0; i < allItems.length; i++) {
472             Type type = (Type)allItems[i].getData();
473             typesBuffer.add(type);
474             if (false == oldTypes.contains(type)) {
475                 try {
476                     model.addType(type);
477                 }
478                 catch(InvalidModelException ime) {
479                     LogManager.logError(ime);
480                 }
481             }
482         }
483         // then remove the missing ones
484         for(Type oldType : oldTypes) {
485             if (false == typesBuffer.contains(oldType)) {
486                 try {
487                     model.removeType(oldType);
488                 }
489                 catch(InvalidModelException ime) {
490                     LogManager.logError(ime);
491                 }
492             }
493         }
494     }
495 }
496 
497 /*
498  * $Log$
499  * Revision 1.24  2007/07/19 13:08:30  alex_simov
500  * - rfe [1751326] Navigation through the editor tab
501  * - concepts/attributes which are from a different namespace are prefixed
502  *
503  * Revision 1.23  2007/04/17 14:35:32  alex_simov
504  * migration to the latest wsmo4j (java 5)
505  *
506  * Revision 1.22  2007/03/12 17:40:56  alex_simov
507  * 1 constructor signature changed
508  * 2 changes notification improved
509  *
510  * Revision 1.21  2006/08/01 16:07:29  alex_simov
511  * bugfix[1531709]: Context menus relied on right button mouse click instead of
512  * being registered as dedicated context menus for the corresponding UI
513  * controls
514  *
515  * Revision 1.20  2006/07/20 15:15:52  alex_simov
516  * ui fixes
517  *
518  * Revision 1.19  2006/07/18 13:27:14  alex_simov
519  * bugfix/workaround [1484820] : usage of FillLayout replaced by GridLayout,
520  * previously causing empty dialog windows under Linux - gtk
521  *
522  * Revision 1.18  2006/03/28 15:15:17  alex_simov
523  * bugfix[1459987]: cardinality text fields set to show 3 symbols at least
524  *
525  * Revision 1.17  2006/03/08 11:24:01  alex_simov
526  * ui fix: InverseOf identifier field set to be not editable
527  *
528  * Revision 1.16  2006/02/20 12:44:49  alex_simov
529  * wsmo4j api change: attributes handled by IRI instead of object refs
530  *
531  * Revision 1.15  2006/01/09 12:51:13  alex_simov
532  * Copyright message in header updated
533  *
534  * Revision 1.14  2005/11/09 16:17:39  alex_simov
535  * UIModels notification improved
536  *
537  * Revision 1.13  2005/10/14 12:33:04  alex_simov
538  * bugfix (ref 1326585): editor's input not saved correctly
539  *
540  * Revision 1.12  2005/09/16 14:25:11  alex_simov
541  * Identifier.asString() removed, use Object.toString() instead
542  *
543  * Revision 1.11  2005/09/13 10:00:50  alex_simov
544  * imports customization
545  *
546  * Revision 1.10  2005/09/10 09:17:21  alex_simov
547  * bugfix
548  *
549  * Revision 1.9  2005/08/08 12:19:48  alex_simov
550  * Utils.createTableItem() used where appropriate
551  *
552  * Revision 1.8  2005/08/02 10:33:20  alex_simov
553  * minor code and/or javadoc fixes
554  *
555  * Revision 1.7  2005/07/29 15:08:02  alex_simov
556  * added javadoc: class description, footer
557  *
558  *
559  */