2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.taxeditor
.editor
;
12 import java
.util
.ArrayList
;
13 import java
.util
.List
;
15 import org
.apache
.log4j
.Logger
;
16 import org
.eclipse
.core
.commands
.operations
.IUndoContext
;
17 import org
.eclipse
.core
.runtime
.IAdaptable
;
18 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
19 import org
.eclipse
.jface
.action
.IMenuManager
;
20 import org
.eclipse
.jface
.action
.IStatusLineManager
;
21 import org
.eclipse
.jface
.action
.IToolBarManager
;
22 import org
.eclipse
.jface
.action
.MenuManager
;
23 import org
.eclipse
.jface
.viewers
.ISelectionProvider
;
24 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
25 import org
.eclipse
.swt
.SWT
;
26 import org
.eclipse
.swt
.widgets
.Composite
;
27 import org
.eclipse
.swt
.widgets
.Control
;
28 import org
.eclipse
.swt
.widgets
.Display
;
29 import org
.eclipse
.swt
.widgets
.Menu
;
30 import org
.eclipse
.swt
.widgets
.Tree
;
31 import org
.eclipse
.ui
.IEditorInput
;
32 import org
.eclipse
.ui
.IEditorSite
;
33 import org
.eclipse
.ui
.PartInitException
;
34 import org
.eclipse
.ui
.forms
.ManagedForm
;
35 import org
.eclipse
.ui
.forms
.widgets
.ScrolledForm
;
36 import org
.eclipse
.ui
.forms
.widgets
.TableWrapLayout
;
37 import org
.eclipse
.ui
.part
.EditorPart
;
38 import org
.eclipse
.ui
.views
.properties
.IPropertySheetEntry
;
39 import org
.eclipse
.ui
.views
.properties
.IPropertySheetPage
;
40 import org
.eclipse
.ui
.views
.properties
.IPropertySource
;
41 import org
.eclipse
.ui
.views
.properties
.PropertySheetPage
;
42 import org
.eclipse
.ui
.views
.properties
.PropertySheetSorter
;
43 import org
.eclipse
.ui
.views
.properties
.tabbed
.ITabbedPropertySheetPageContributor
;
45 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
46 import eu
.etaxonomy
.cdm
.api
.conversation
.IConversationEnabled
;
47 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
48 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
49 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.CdmDataChangeMap
;
50 import eu
.etaxonomy
.taxeditor
.model
.Resources
;
51 import eu
.etaxonomy
.taxeditor
.operations
.IPostOperationEnabled
;
52 import eu
.etaxonomy
.taxeditor
.propertysheet
.EditorPropertySheetEntry
;
53 import eu
.etaxonomy
.taxeditor
.propertysheet
.PropertySheetUtil
;
56 * The abstract editor for displaying a category of <code>Taxon</code> data, corresponding
57 * to the tabs ("Name", "Descriptive", etc.) at the bottom of a <code>Taxon</code> view. Implements
58 * <code>IAdaptable</code> in order to display properties of the objects whose UI elements have focus.
60 * Implementing classes can choose to show an object in the property sheet when the
61 * <code>AbstractTaxonEditor</code> gets focus, by passing the object to the method
62 * <code>setDefaultPropertySheetObject</code>, for instance, in the method<code>init</code>.
69 public abstract class AbstractTaxonEditor
extends EditorPart
implements IAdaptable
, IConversationEnabled
, IPostOperationEnabled
, ITabbedPropertySheetPageContributor
{
70 private static final Logger logger
= Logger
71 .getLogger(AbstractTaxonEditor
.class);
73 protected Taxon taxon
;
76 * When this <code>EditorPart</code> gets focus, the data structure of
77 * <code>defaultPropertyObject</code> is displayed in the property sheet.
80 protected ManagedForm managedForm
;
81 protected ScrolledForm scrolledForm
;
82 protected Composite parent
;
83 protected ISelectionProvider provider
;
85 protected MultiPageTaxonEditor editor
;
87 protected IHasPropertySource selectedObject
;
89 protected Composite partComposite
;
90 protected GroupedComposite firstGroupedComposite
;
92 protected Object selectedData
;
94 protected ConversationHolder conversation
;
96 private MenuManager menuManager
;
101 * The object that was affected by last operation.
103 private CdmBase objectAffectedByLastOperation
;
105 private boolean isRedrawing
;
107 protected AbstractTaxonEditor(MultiPageTaxonEditor editor
){
108 this.editor
= editor
;
109 this.conversation
= editor
.getConversationHolder();
113 * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
115 public void doSave(IProgressMonitor monitor
) {
116 conversation
.commit();
120 * @see org.eclipse.ui.part.EditorPart#doSaveAs()
122 public void doSaveAs() {}
125 * @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
127 public void init(IEditorSite site
, IEditorInput input
)
128 throws PartInitException
{
129 if (!(input
instanceof IEditorInput
))
130 throw new PartInitException(
131 "Invalid Input: Must be IEditorInput");
133 if (input
.getAdapter(Taxon
.class) != null) {
134 taxon
= (Taxon
) input
.getAdapter(Taxon
.class);
136 throw new PartInitException(
137 "Invalid Input: Taxon cannot be null");
143 provider
= new SimpleSelectionProvider();
144 getSite().setSelectionProvider(provider
);
147 logger
.trace("New Editor instance created.");
150 public IUndoContext
getUndoContext() {
151 return editor
.getUndoContext();
155 * If there is a default property sheet object with a corresponding property source class,
156 * display it in the property sheet. Otherwise, empty the property sheet with an empty
157 * <code>StructuredSelection</code>.
159 * @param selectedObject
161 protected void setSelection(IHasPropertySource selectedObject
) {
163 // Unpaint last selection - last selection will only be unpainted
164 // when something else on this page is selected
165 if (this.selectedObject
instanceof GroupedComposite
) {
166 GroupedComposite composite
= ((GroupedComposite
) this.selectedObject
);
167 composite
.unpaintBorder();
168 composite
.setBackground(Resources
.getColor(Resources
.COLOR_COMPOSITE_BACKGROUND
));
171 // Set the selection to this editor's selected object
172 this.selectedObject
= selectedObject
;
174 // set background on selection TODO wanted to move this to setFocus() on the selectedObject but that doesn't work (infinite loop)
175 ((GroupedComposite
) selectedObject
).setBackground(Resources
.getColor(Resources
.COLOR_COMPOSITE_SELECTED
));
178 if (selectedObject
instanceof Composite
) {
179 this.selectedData
= ((Composite
) selectedObject
).getData();
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();
187 if (propertySource
== null) {
188 provider
.setSelection(new StructuredSelection());
190 provider
.setSelection(new StructuredSelection(propertySource
));
193 // TabbedPropertySheet stuff
194 // provider.setSelection(new StructuredSelection(this.selectedData));
199 * @see org.eclipse.ui.part.EditorPart#isDirty()
201 public boolean isDirty() {
206 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
208 public boolean isSaveAsAllowed() {
213 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
215 public void createPartControl(Composite composite
) {
217 this.partComposite
= composite
;
219 createManagedForm(composite
);
222 protected void createManagedForm(Composite composite
) {
224 managedForm
= new ManagedForm(composite
) {
225 public void dirtyStateChanged() {
226 firePropertyChange(PROP_DIRTY
);
228 public boolean setInput(Object input
) {
229 if (input
instanceof IHasPropertySource
) {
230 setSelection((IHasPropertySource
)input
);
232 return super.setInput(input
);
236 scrolledForm
= managedForm
.getForm();
237 parent
= scrolledForm
.getBody();
239 // register the context menu
240 menuManager
= new MenuManager();
241 ISelectionProvider selectionProvider
= getSite().getSelectionProvider();
242 getSite().registerContextMenu(getID(), menuManager
, selectionProvider
);
244 menu
= menuManager
.createContextMenu(parent
);
245 scrolledForm
.setMenu(menu
);
247 parent
.setData(taxon
);
249 parent
.setLayout(new TableWrapLayout());
250 parent
.setBackground(Display
.getCurrent().getSystemColor(SWT
.COLOR_WHITE
));
253 @SuppressWarnings("unchecked")
254 public Object
getAdapter(Class type
) {
255 if (type
== IPropertySheetPage
.class) {
257 PropertySheetPage page
= new EditorPropertySheetPage();
259 PropertySheetUtil
.setPropertySheetPage(page
);
261 EditorPropertySheetEntry entry
= new EditorPropertySheetEntry(taxon
, this);
262 page
.setRootEntry(entry
);
267 // TabbedPropertySheet stuff
268 // TabbedPropertySheetPage page = new TabbedPropertySheetPage(this);
272 return super.getAdapter(type
);
275 public Taxon
getTaxon() {
279 public void setDirty() {
280 managedForm
.dirtyStateChanged();
283 public void setFocus(){
287 if(selectedData
== null){
288 selection
= (objectAffectedByLastOperation
== null) ?
null : objectAffectedByLastOperation
;
290 selection
= (objectAffectedByLastOperation
== null) ? selectedData
: objectAffectedByLastOperation
;
294 if (selection
== null){
295 GroupedComposite focusComposite
= firstGroupedComposite
;
296 setSelection(focusComposite
);
297 focusComposite
.drawBorder();
299 selectedData
= selection
;
301 for (GroupedComposite composite
: getGroupedComposites()) {
302 if (selectedData
.equals(composite
.getData())) {
303 setSelection((GroupedComposite
) composite
);
304 ((GroupedComposite
) composite
).drawBorder();
305 ((GroupedComposite
) composite
).setSelected();
312 objectAffectedByLastOperation
= null;
316 * This method returns all <code>GroupedComposite</code> controls currently attached to this editor.
318 * @return a <code>List</code> of <code>GroupedComposite</code> controls.
320 public List
<GroupedComposite
> getGroupedComposites(){
321 return getGroupedCompositesRecursively(scrolledForm
.getBody(), new ArrayList
<GroupedComposite
>());
326 * Recursively traverse the composite hierarchy and collect all <code>GroupedComposite</code> controls.
328 * @param composite the composite to start recursing from
329 * @param groupedComposites a <code>List</code> the found composites are stored in
330 * @return a <code>List</code> containing all found <code>GroupedComposite</code> controls
332 private List
<GroupedComposite
> getGroupedCompositesRecursively(Composite composite
, List
<GroupedComposite
> groupedComposites
){
333 for(Control child
: composite
.getChildren()){
334 if(child
instanceof GroupedComposite
){
335 groupedComposites
.add((GroupedComposite
) child
);
336 }else if(child
instanceof Composite
){
337 getGroupedCompositesRecursively((Composite
) child
, groupedComposites
);
340 return groupedComposites
;
346 public List
<GroupComposite
> getGroupComposites() {
347 return getGroupCompositesRecursively(scrolledForm
.getBody(), new ArrayList
<GroupComposite
>());
351 * Recursively traverse the composite hierarchy and collect all <code>GroupComposite</code> controls.
353 * @param composite the composite to start recursing from
354 * @param groupComposites a <code>List</code> the found composites are stored in
355 * @return a <code>List</code> containing all found <code>GroupComposite</code> controls
357 private List
<GroupComposite
> getGroupCompositesRecursively(Composite composite
, List
<GroupComposite
> groupComposites
){
358 for(Control child
: composite
.getChildren()){
359 if(child
instanceof GroupComposite
){
360 groupComposites
.add((GroupComposite
) child
);
361 getGroupCompositesRecursively((Composite
) child
, groupComposites
);
364 return groupComposites
;
367 public void setInput(IEditorInput input
){
368 this.setInputWithNotify(input
);
373 * @see eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder()
375 public ConversationHolder
getConversationHolder(){
381 * @see eu.etaxonomy.cdm.persistence.hibernate.ICdmPostCrudObserver#update(eu.etaxonomy.cdm.persistence.hibernate.CdmCrudEvent)
383 public void update(CdmDataChangeMap events
) {
388 * Redraws this editor
390 public boolean redraw() {
394 this.selectedObject
= null;
395 managedForm
.getForm().dispose();
396 createManagedForm(partComposite
);
406 public boolean getIsRedrawing() {
410 public MultiPageTaxonEditor
getMultiPageTaxonEditor() {
417 * @see eu.etaxonomy.taxeditor.store.operations.IPostOperationEnabled#postOperation()
419 public boolean postOperation(CdmBase objectAffectedByOperation
) {
425 if (objectAffectedByOperation
== null && selectedData
instanceof CdmBase
) {
426 this.objectAffectedByLastOperation
= (CdmBase
) selectedData
;
428 this.objectAffectedByLastOperation
= objectAffectedByOperation
;
436 * @return the managedForm
438 public ManagedForm
getManagedForm() {
442 public Composite
getTopLevelComposite() {
443 return this.getManagedForm().getForm().getBody();
448 * @return the ID as defined in plugin.xml
450 public abstract String
getID();
455 public Menu
getMenu() {
460 * @return the firstGroupedComposite
462 public GroupedComposite
getFirstGroupedComposite() {
463 return firstGroupedComposite
;
466 class EditorPropertySheetPage
extends PropertySheetPage
{
468 EditorPropertySheetPage() {
471 // Override sorter to simply display names as first-in-first-out
472 setSorter(new PropertySheetSorter() {
473 public int compare(IPropertySheetEntry entryA
, IPropertySheetEntry entryB
) {
476 public int compareCategories(String categoryA
, String categoryB
) {
479 public void sort(IPropertySheetEntry
[] entries
) {
485 public void makeContributions(IMenuManager menuManager
,
486 IToolBarManager toolBarManager
, IStatusLineManager statusLineManager
) {
487 super.makeContributions(menuManager
, toolBarManager
, statusLineManager
);
489 // Remove "Show categories", "Show advanced properties", "Restore default value"
490 toolBarManager
.removeAll();
491 menuManager
.removeAll();
494 public Control
getControl() {
495 Control control
= super.getControl();
497 // Save the property sheet tree for easy access as needed
498 if (!control
.isDisposed()) {
499 if (control
instanceof Tree
) {
500 PropertySheetUtil
.setPropertySheetTree((Tree
) control
);
510 public void navigateToNextMember() {
512 List
<GroupedComposite
> composites
= getGroupedCompositesRecursively(scrolledForm
.getBody(), new ArrayList
<GroupedComposite
>());
514 for(int i
= 0; i
< composites
.size(); i
++){
515 if(selectedData
== composites
.get(i
).getData()){
516 selectedData
= composites
.get(i
+1).getData();
521 }catch(IndexOutOfBoundsException e
){}
527 public void navigateToPreviousMember() {
529 List
<GroupedComposite
> composites
= getGroupedCompositesRecursively(scrolledForm
.getBody(), new ArrayList
<GroupedComposite
>());
531 for(int i
= 0; i
< composites
.size(); i
++){
532 if(selectedData
== composites
.get(i
).getData()){
533 selectedData
= composites
.get(i
-1).getData();
538 }catch(IndexOutOfBoundsException e
){}
542 * Used by ITabbedPropertySheet...
544 public String
getContributorId() {