5f1b091cf619517e7cc86813bdfcc64ab717f935
[taxeditor.git] / taxeditor-editor / src / main / java / eu / etaxonomy / taxeditor / editor / AbstractTaxonEditor.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.taxeditor.editor;
11
12 import java.util.HashSet;
13
14 import org.apache.log4j.Logger;
15 import org.eclipse.core.commands.operations.IUndoContext;
16 import org.eclipse.core.runtime.IAdaptable;
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.jface.action.IMenuManager;
19 import org.eclipse.jface.action.IStatusLineManager;
20 import org.eclipse.jface.action.IToolBarManager;
21 import org.eclipse.jface.action.MenuManager;
22 import org.eclipse.jface.viewers.ISelectionProvider;
23 import org.eclipse.jface.viewers.StructuredSelection;
24 import org.eclipse.swt.SWT;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.swt.widgets.Control;
27 import org.eclipse.swt.widgets.Display;
28 import org.eclipse.swt.widgets.Menu;
29 import org.eclipse.swt.widgets.Tree;
30 import org.eclipse.ui.IEditorInput;
31 import org.eclipse.ui.IEditorSite;
32 import org.eclipse.ui.PartInitException;
33 import org.eclipse.ui.forms.ManagedForm;
34 import org.eclipse.ui.forms.widgets.ScrolledForm;
35 import org.eclipse.ui.forms.widgets.TableWrapLayout;
36 import org.eclipse.ui.part.EditorPart;
37 import org.eclipse.ui.views.properties.IPropertySheetEntry;
38 import org.eclipse.ui.views.properties.IPropertySheetPage;
39 import org.eclipse.ui.views.properties.IPropertySource;
40 import org.eclipse.ui.views.properties.PropertySheetPage;
41 import org.eclipse.ui.views.properties.PropertySheetSorter;
42
43 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
44 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
45 import eu.etaxonomy.cdm.model.common.CdmBase;
46 import eu.etaxonomy.cdm.model.taxon.Taxon;
47 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
48 import eu.etaxonomy.taxeditor.propertysheet.EditorPropertySheetEntry;
49 import eu.etaxonomy.taxeditor.propertysheet.PropertySheetUtil;
50 import eu.etaxonomy.taxeditor.store.model.Resources;
51 import eu.etaxonomy.taxeditor.store.operations.IPostOperationEnabled;
52
53 /**
54 * The abstract editor for displaying a category of <code>Taxon</code> data, corresponding
55 * to the tabs ("Name", "Descriptive", etc.) at the bottom of a <code>Taxon</code> view. Implements
56 * <code>IAdaptable</code> in order to display properties of the objects whose UI elements have focus.
57 * <p>
58 * Implementing classes can choose to show an object in the property sheet when the
59 * <code>AbstractTaxonEditor</code> gets focus, by passing the object to the method
60 * <code>setDefaultPropertySheetObject</code>, for instance, in the method<code>init</code>.
61 * </p>
62 * @author p.ciardelli
63 * @author n.hoffmann
64 * @created 10.09.2008
65 * @version 1.0
66 */
67 public abstract class AbstractTaxonEditor extends EditorPart implements IAdaptable, IConversationEnabled, IPostOperationEnabled {
68 private static final Logger logger = Logger
69 .getLogger(AbstractTaxonEditor.class);
70
71 protected Taxon taxon;
72
73 /**
74 * When this <code>EditorPart</code> gets focus, the data structure of
75 * <code>defaultPropertyObject</code> is displayed in the property sheet.
76 */
77
78 protected ManagedForm managedForm;
79 protected ScrolledForm scrolledForm;
80 protected Composite parent;
81 protected ISelectionProvider provider;
82
83 protected MultiPageTaxonEditor editor;
84
85 protected IHasPropertySource selectedObject;
86
87 protected Composite partComposite;
88 protected GroupedComposite firstGroupedComposite;
89
90 protected Object selectedData;
91
92 protected ConversationHolder conversation;
93
94 private MenuManager menuManager;
95
96 private Menu menu;
97
98 /**
99 * The object that was affected by last operation.
100 */
101 private CdmBase objectAffectedByLastOperation;
102
103 private boolean isRedrawing;
104
105 protected AbstractTaxonEditor(MultiPageTaxonEditor editor){
106 this.editor = editor;
107 this.conversation = editor.getConversationHolder();
108 }
109
110 /* (non-Javadoc)
111 * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
112 */
113 public void doSave(IProgressMonitor monitor) {
114 conversation.commit();
115 }
116
117 /* (non-Javadoc)
118 * @see org.eclipse.ui.part.EditorPart#doSaveAs()
119 */
120 public void doSaveAs() {}
121
122 /* (non-Javadoc)
123 * @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
124 */
125 public void init(IEditorSite site, IEditorInput input)
126 throws PartInitException {
127 // bind the session
128
129
130 if (!(input instanceof IEditorInput))
131 throw new PartInitException(
132 "Invalid Input: Must be IEditorInput");
133
134 if (input.getAdapter(Taxon.class) != null) {
135 taxon = (Taxon) input.getAdapter(Taxon.class);
136 } else {
137 throw new PartInitException(
138 "Invalid Input: Taxon cannot be null");
139 }
140
141 setSite(site);
142 setInput(input);
143
144 this.provider = new SimpleSelectionProvider();
145 this.getSite().setSelectionProvider(provider);
146
147 }
148
149 public IUndoContext getUndoContext() {
150 return editor.getUndoContext();
151 }
152
153 /**
154 * If there is a default property sheet object with a corresponding property source class,
155 * display it in the property sheet. Otherwise, empty the property sheet with an empty
156 * <code>StructuredSelection</code>.
157 *
158 * @param selectedObject
159 */
160 protected void setSelection(IHasPropertySource selectedObject) {
161
162 // Unpaint last selection - last selection will only be unpainted
163 // when something else on this page is selected
164 if (this.selectedObject instanceof GroupedComposite) {
165 GroupedComposite composite = ((GroupedComposite) this.selectedObject);
166 composite.unpaintBorder();
167 composite.setBackground(Resources.getColor(Resources.COLOR_COMPOSITE_BACKGROUND));
168 }
169
170 // Set the selection to this editor's selected object
171 this.selectedObject = selectedObject;
172
173 // set background on selection TODO wanted to move this to setFocus() on the selectedObject but that doesn't work (infinite loop)
174 // ((GroupedComposite) selectedObject).setSelected();
175 ((GroupedComposite) selectedObject).setBackground(Resources.getColor(Resources.COLOR_COMPOSITE_SELECTED));
176
177
178 if (selectedObject instanceof Composite) {
179 this.selectedData = ((Composite) selectedObject).getData();
180 }
181
182 // Get the selection's property source, pass it to the selection provider
183 IPropertySource propertySource = null;
184 if (selectedObject != null) {
185 propertySource = selectedObject.getPropertySource();
186 }
187 if (propertySource == null) {
188 provider.setSelection(new StructuredSelection());
189 } else {
190 provider.setSelection(new StructuredSelection(propertySource));
191 }
192
193 }
194
195 /* (non-Javadoc)
196 * @see org.eclipse.ui.part.EditorPart#isDirty()
197 */
198 public boolean isDirty() {
199 return false;
200 }
201
202 /* (non-Javadoc)
203 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
204 */
205 public boolean isSaveAsAllowed() {
206 return false;
207 }
208
209 /* (non-Javadoc)
210 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
211 */
212 public void createPartControl(Composite composite) {
213
214 this.partComposite = composite;
215
216 createManagedForm(composite);
217 }
218
219 protected void createManagedForm(Composite composite) {
220
221 managedForm = new ManagedForm(composite) {
222 public void dirtyStateChanged() {
223 firePropertyChange(PROP_DIRTY);
224 }
225 public boolean setInput(Object input) {
226 if (input instanceof IHasPropertySource) {
227 setSelection((IHasPropertySource)input);
228 }
229 return super.setInput(input);
230 }
231 };
232 scrolledForm = managedForm.getForm();
233 parent = scrolledForm.getBody();
234
235 // register the context menu
236 menuManager = new MenuManager();
237 ISelectionProvider selectionProvider = getSite().getSelectionProvider();
238 getSite().registerContextMenu(getID(), menuManager, selectionProvider);
239
240 menu = menuManager.createContextMenu(parent);
241 scrolledForm.setMenu(menu);
242
243 parent.setData(taxon);
244
245 parent.setLayout(new TableWrapLayout());
246 parent.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
247 }
248
249 @SuppressWarnings("unchecked")
250 public Object getAdapter(Class type) {
251 if (type == IPropertySheetPage.class) {
252
253 PropertySheetPage page = new EditorPropertySheetPage();
254
255 PropertySheetUtil.setPropertySheetPage(page);
256
257 EditorPropertySheetEntry entry = new EditorPropertySheetEntry(taxon, this);
258 page.setRootEntry(entry);
259 page.refresh();
260
261 return page;
262 }
263 return super.getAdapter(type);
264 }
265
266 public Taxon getTaxon() {
267 return taxon;
268 }
269
270 public void setDirty() {
271 managedForm.dirtyStateChanged();
272 }
273
274 public void setFocus(){
275
276 Object selection;
277
278 if(selectedData == null){
279 selection = (objectAffectedByLastOperation == null) ? null : objectAffectedByLastOperation;
280 }else{
281 selection = (objectAffectedByLastOperation == null) ? selectedData : objectAffectedByLastOperation;
282 }
283
284 // make selection
285 if (selection == null){
286 GroupedComposite focusComposite = firstGroupedComposite;
287 setSelection(focusComposite);
288 focusComposite.drawBorder();
289 } else {
290 selectedData = selection;
291
292 for (Composite composite : getAllComposites()) {
293 if (composite instanceof GroupedComposite && selectedData.equals(composite.getData())) {
294 setSelection((GroupedComposite) composite);
295 ((GroupedComposite) composite).drawBorder();
296 ((GroupedComposite) composite).setSelected();
297 break;
298 }
299 }
300 }
301
302 // reset
303 objectAffectedByLastOperation = null;
304 }
305
306 protected HashSet<Composite> getAllComposites(){
307 HashSet<Composite> composites = new HashSet<Composite>();
308 composites.add(parent);
309 composites.addAll(getComposites(parent));
310 return composites;
311 }
312
313 public void setInput(IEditorInput input){
314 this.setInputWithNotify(input);
315 }
316
317 private HashSet<Composite> getComposites(Composite composite){
318 HashSet<Composite> composites = new HashSet<Composite>();
319 for(Control child : composite.getChildren()){
320 if(child instanceof Composite){
321 composites.add((Composite)child);
322 composites.addAll(getComposites((Composite)child));
323 }
324 }
325 return composites;
326 }
327
328 /*
329 * (non-Javadoc)
330 * @see eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder()
331 */
332 public ConversationHolder getConversationHolder(){
333 return conversation;
334 }
335
336 /*
337 * (non-Javadoc)
338 * @see eu.etaxonomy.cdm.persistence.hibernate.ICdmPostCrudObserver#update(eu.etaxonomy.cdm.persistence.hibernate.CdmCrudEvent)
339 */
340 public void update(CdmDataChangeMap events) {
341 //redraw();
342 }
343
344 /**
345 *
346 */
347 public boolean redraw() {
348
349 isRedrawing = true;
350
351 this.selectedObject = null;
352 managedForm.getForm().dispose();
353 createManagedForm(partComposite);
354
355 setFocus();
356
357 isRedrawing = false;
358
359 return true;
360
361 }
362
363 public boolean getIsRedrawing() {
364 return isRedrawing;
365 }
366
367 public MultiPageTaxonEditor getMultiPageTaxonEditor() {
368 return editor;
369 }
370
371
372 /*
373 * (non-Javadoc)
374 * @see eu.etaxonomy.taxeditor.store.operations.IPostOperationEnabled#postOperation()
375 */
376 public boolean postOperation(CdmBase objectAffectedByOperation) {
377
378 if (isRedrawing) {
379 return false;
380 }
381
382 if (objectAffectedByOperation == null && selectedData instanceof CdmBase) {
383 this.objectAffectedByLastOperation = (CdmBase) selectedData;
384 } else {
385 this.objectAffectedByLastOperation = objectAffectedByOperation;
386 }
387 editor.setDirty();
388 return redraw();
389 }
390
391
392 /**
393 * @return the managedForm
394 */
395 public ManagedForm getManagedForm() {
396 return managedForm;
397 }
398
399 public Composite getTopLevelComposite() {
400 return this.getManagedForm().getForm().getBody();
401 }
402
403 /**
404 *
405 * @return the ID as defined in plugin.xml
406 */
407 public abstract String getID();
408
409 /**
410 * @return the menu
411 */
412 public Menu getMenu() {
413 return menu;
414 }
415
416 /**
417 * @return the firstGroupedComposite
418 */
419 public GroupedComposite getFirstGroupedComposite() {
420 return firstGroupedComposite;
421 }
422
423 class EditorPropertySheetPage extends PropertySheetPage {
424
425 EditorPropertySheetPage() {
426 super();
427
428 // Override sorter to simply display names as first-in-first-out
429 setSorter(new PropertySheetSorter() {
430 public int compare(IPropertySheetEntry entryA, IPropertySheetEntry entryB) {
431 return 0;
432 }
433 public int compareCategories(String categoryA, String categoryB) {
434 return 0;
435 }
436 public void sort(IPropertySheetEntry[] entries) {
437 // do nothing
438 }
439 });
440 }
441
442 public void makeContributions(IMenuManager menuManager,
443 IToolBarManager toolBarManager, IStatusLineManager statusLineManager) {
444 super.makeContributions(menuManager, toolBarManager, statusLineManager);
445
446 // Remove "Show categories", "Show advanced properties", "Restore default value"
447 toolBarManager.removeAll();
448 menuManager.removeAll();
449 }
450
451 public Control getControl() {
452 Control control = super.getControl();
453
454 // Save the property sheet tree for easy access as needed
455 if (!control.isDisposed()) {
456 if (control instanceof Tree) {
457 PropertySheetUtil.setPropertySheetTree((Tree) control);
458 }
459 }
460 return control;
461 }
462 }
463 }