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
.name
;
12 import java
.util
.ArrayList
;
13 import java
.util
.HashSet
;
14 import java
.util
.List
;
17 import org
.apache
.commons
.lang
.StringUtils
;
18 import org
.eclipse
.core
.commands
.operations
.IUndoContext
;
19 import org
.eclipse
.core
.runtime
.IAdaptable
;
20 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
21 import org
.eclipse
.core
.runtime
.OperationCanceledException
;
22 import org
.eclipse
.jface
.action
.MenuManager
;
23 import org
.eclipse
.jface
.viewers
.ISelection
;
24 import org
.eclipse
.jface
.viewers
.ISelectionProvider
;
25 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
26 import org
.eclipse
.swt
.dnd
.DND
;
27 import org
.eclipse
.swt
.dnd
.DropTarget
;
28 import org
.eclipse
.swt
.dnd
.Transfer
;
29 import org
.eclipse
.swt
.widgets
.Composite
;
30 import org
.eclipse
.swt
.widgets
.Menu
;
31 import org
.eclipse
.ui
.IEditorInput
;
32 import org
.eclipse
.ui
.IEditorSite
;
33 import org
.eclipse
.ui
.ISelectionListener
;
34 import org
.eclipse
.ui
.ISelectionService
;
35 import org
.eclipse
.ui
.IWorkbenchPart
;
36 import org
.eclipse
.ui
.IWorkbenchPartReference
;
37 import org
.eclipse
.ui
.PartInitException
;
38 import org
.eclipse
.ui
.forms
.ManagedForm
;
39 import org
.eclipse
.ui
.forms
.widgets
.FormToolkit
;
40 import org
.eclipse
.ui
.forms
.widgets
.ScrolledForm
;
41 import org
.eclipse
.ui
.forms
.widgets
.TableWrapLayout
;
42 import org
.eclipse
.ui
.part
.EditorPart
;
44 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
45 import eu
.etaxonomy
.cdm
.api
.conversation
.IConversationEnabled
;
46 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
47 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
48 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
49 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
50 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
51 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.CdmDataChangeMap
;
52 import eu
.etaxonomy
.taxeditor
.editor
.CdmDataTransfer
;
53 import eu
.etaxonomy
.taxeditor
.editor
.EditorUtil
;
54 import eu
.etaxonomy
.taxeditor
.editor
.IDropTargetable
;
55 import eu
.etaxonomy
.taxeditor
.editor
.IMultiPageTaxonEditorPage
;
56 import eu
.etaxonomy
.taxeditor
.editor
.MultiPageTaxonEditor
;
57 import eu
.etaxonomy
.taxeditor
.editor
.SimpleSelectionProvider
;
58 import eu
.etaxonomy
.taxeditor
.editor
.TaxonEditorInput
;
59 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.AbstractGroup
;
60 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.AbstractGroupedContainer
;
61 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.AcceptedGroup
;
62 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.AcceptedNameContainer
;
63 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.ConceptGroup
;
64 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.ContainerFactory
;
65 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.HomotypicalSynonymGroup
;
66 import eu
.etaxonomy
.taxeditor
.editor
.name
.container
.MisappliedGroup
;
67 import eu
.etaxonomy
.taxeditor
.editor
.name
.dnd
.NameEditorDropTargetListener
;
68 import eu
.etaxonomy
.taxeditor
.model
.IPartChangeListener
;
69 import eu
.etaxonomy
.taxeditor
.model
.IPartContentHasDetails
;
70 import eu
.etaxonomy
.taxeditor
.model
.TaxeditorPartService
;
71 import eu
.etaxonomy
.taxeditor
.operation
.IPostOperationEnabled
;
72 import eu
.etaxonomy
.taxeditor
.preference
.Resources
;
75 * <p>TaxonNameEditor class.</p>
82 public class TaxonNameEditor
extends EditorPart
implements IMultiPageTaxonEditorPage
, IAdaptable
, IConversationEnabled
, IPostOperationEnabled
, IPartContentHasDetails
, IPartChangeListener
83 , ISelectionListener
, IDropTargetable
{
85 /** Constant <code>ID="eu.etaxonomy.taxeditor.editor.taxon.name"</code> */
86 public static final String ID
= "eu.etaxonomy.taxeditor.editor.taxon.name";
90 private ManagedForm managedForm
;
91 private ScrolledForm scrolledForm
;
92 private Composite parent
;
93 private ISelectionProvider provider
;
95 private MultiPageTaxonEditor editor
;
97 private TaxonBase selection
;
99 private ConversationHolder conversation
;
101 private MenuManager menuManager
;
105 private MisappliedGroup misappliedGroup
;
107 private ConceptGroup conceptGroup
;
109 private List
<HomotypicalSynonymGroup
> heterotypicSynonymGroups
= new ArrayList
<HomotypicalSynonymGroup
>();
111 private DropTarget target
;
113 private ISelectionService selectionService
;
115 private AcceptedGroup acceptedGroup
;
117 private TaxonBase objectAffectedByLastOperation
;
120 * <p>Constructor for TaxonNameEditor.</p>
122 * @param editor a {@link eu.etaxonomy.taxeditor.editor.MultiPageTaxonEditor} object.
124 public TaxonNameEditor(MultiPageTaxonEditor editor
){
125 this.editor
= editor
;
126 conversation
= editor
.getConversationHolder();
132 * <p>getUndoContext</p>
134 * @return a {@link org.eclipse.core.commands.operations.IUndoContext} object.
136 public IUndoContext
getUndoContext() {
137 return editor
.getUndoContext();
141 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
144 public void createPartControl(Composite composite
) {
145 selectionService
= getSite().getWorkbenchWindow().getSelectionService();
146 selectionService
.addSelectionListener(this);
148 createManagedForm(composite
);
150 TaxeditorPartService
.getInstance().addListener(TaxeditorPartService
.PART_ACTIVATED
, this);
154 * <p>createManagedForm</p>
156 * @param composite a {@link org.eclipse.swt.widgets.Composite} object.
158 protected void createManagedForm(Composite composite
) {
160 managedForm
= new ManagedForm(composite
) {
162 public void dirtyStateChanged() {
163 firePropertyChange(PROP_DIRTY
);
165 public boolean setInput(Object input
) {
166 if (input
instanceof AbstractGroupedContainer
) {
167 selection
= ((AbstractGroupedContainer
) input
).getData();
168 provider
.setSelection(new StructuredSelection(selection
));
170 return super.setInput(input
);
175 scrolledForm
= managedForm
.getForm();
176 parent
= scrolledForm
.getBody();
178 // register the context menu
179 menuManager
= new MenuManager();
180 ISelectionProvider selectionProvider
= getSite().getSelectionProvider();
181 getSite().registerContextMenu(TaxonNameEditor
.ID
, menuManager
, selectionProvider
);
183 parent
.setData(taxon
);
185 TableWrapLayout layout
= new TableWrapLayout();
186 layout
.leftMargin
= 0;
187 layout
.rightMargin
= 0;
188 layout
.topMargin
= 0;
189 layout
.bottomMargin
= 0;
191 layout
.verticalSpacing
= 0;
192 layout
.horizontalSpacing
= 0;
194 parent
.setLayout(layout
);
195 parent
.setBackground(EditorUtil
.getColor(Resources
.COLOR_COMPOSITE_BACKGROUND
));
197 createOrUpdateNameComposites();
205 * <p>createNameComposites</p>
207 public void createOrUpdateNameComposites(){
209 ContainerFactory
.createOrUpdateAcceptedTaxonsHomotypicGroup(this);
210 ContainerFactory
.createOrUpdateHeterotypicSynonymyGroups(this);
211 ContainerFactory
.createOrUpdateMisapplicationsGroup(this);
212 ContainerFactory
.createOrUpdateConceptGroup(this);
215 managedForm
.reflow(true);
222 * <p>Getter for the field <code>taxon</code>.</p>
224 * @return a {@link eu.etaxonomy.cdm.model.taxon.Taxon} object.
226 public Taxon
getTaxon() {
227 return (Taxon
) HibernateProxyHelper
.deproxy(taxon
);
233 public void setDirty() {
234 managedForm
.dirtyStateChanged();
240 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
244 public void setFocus(){
245 if(getSelectedContainer() == null){
246 throw new IllegalStateException("There should always be a selected object.");
248 getSelectedContainer().setSelected();
252 public void setInput(IEditorInput input
){
253 this.setInputWithNotify(input
);
258 * @see eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder()
261 * <p>getConversationHolder</p>
263 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
265 public ConversationHolder
getConversationHolder(){
271 * @see eu.etaxonomy.cdm.persistence.hibernate.ICdmPostCrudObserver#update(eu.etaxonomy.cdm.persistence.hibernate.CdmCrudEvent)
274 public void update(CdmDataChangeMap events
) {
279 * Redraws this editor
280 * return true on success
284 public boolean redraw(){
291 * Redraws the editor controls
293 public boolean redraw(boolean focus
) {
295 createOrUpdateNameComposites();
306 * <p>getMultiPageTaxonEditor</p>
308 * @return a {@link eu.etaxonomy.taxeditor.editor.MultiPageTaxonEditor} object.
310 public MultiPageTaxonEditor
getMultiPageTaxonEditor() {
317 * @see eu.etaxonomy.taxeditor.store.operations.IPostOperationEnabled#postOperation()
320 public boolean postOperation(CdmBase objectAffectedByOperation
) {
322 editor
.changed(objectAffectedByOperation
);
326 if(objectAffectedByOperation
instanceof TaxonBase
){
327 objectAffectedByLastOperation
= (TaxonBase
) objectAffectedByOperation
;
334 * <p>Getter for the field <code>managedForm</code>.</p>
336 * @return the managedForm
338 public ManagedForm
getManagedForm() {
345 * @return a {@link org.eclipse.swt.widgets.Composite} object.
347 public Composite
getControl() {
348 return this.getManagedForm().getForm().getBody();
353 * <p>Getter for the field <code>menu</code>.</p>
357 public Menu
getMenu() {
358 if(menu
== null || menu
.isDisposed()){
359 // Creating the menu because it was either not initialised or disposed while refreshing the editor
360 menu
= menuManager
.createContextMenu(parent
);
366 * <p>checkForEmptyNames</p>
368 * @return true if there are empty names
370 public boolean checkForEmptyNames() {
371 for(AbstractGroupedContainer container
: getGroupedContainers()){
372 if(container
.getName() == null || StringUtils
.isEmpty(container
.getName().getTitleCache())){
380 public Set
<AbstractGroupedContainer
> getEmptyContainers(){
381 Set
<AbstractGroupedContainer
> containersWithEmptyNames
= new HashSet
<AbstractGroupedContainer
>();
383 for(AbstractGroupedContainer container
: getGroupedContainers()){
384 if(container
.getName() == null || StringUtils
.isEmpty(container
.getName().getTitleCache())){
385 containersWithEmptyNames
.add(container
);
389 return containersWithEmptyNames
;
394 public void doSave(IProgressMonitor monitor
) {
396 monitor
.beginTask("Saving names", getGroupedContainers().size());
399 // check for empty names
400 for(AbstractGroupedContainer container
: getGroupedContainers()){
402 monitor
.subTask("Saving composite: " + container
.getTaxonBase().getTitleCache());
403 container
.persistName();
405 // In case the progress monitor was canceled throw an exception.
406 if (monitor
.isCanceled()) {
407 throw new OperationCanceledException();
410 // Otherwise declare this step as done.
416 // Stop the progress monitor.
424 public void doSaveAs() {}
428 public void init(IEditorSite site
, IEditorInput input
)
429 throws PartInitException
{
431 if (!(input
instanceof IEditorInput
))
432 throw new PartInitException(
433 "Invalid Input: Must be IEditorInput");
435 if (input
.getAdapter(Taxon
.class) != null) {
436 taxon
= (Taxon
) input
.getAdapter(Taxon
.class);
438 throw new PartInitException(
439 "Invalid Input: Taxon cannot be null");
445 provider
= new SimpleSelectionProvider();
446 getSite().setSelectionProvider(provider
);
452 private void createDragSupport() {
453 // Listen for names being dragged outside of existing homotypic groups -
454 // user wants to create a new group
455 Transfer
[] types
= new Transfer
[] {CdmDataTransfer
.getInstance()};
456 int operations
= DND
.DROP_MOVE
;
458 target
= new DropTarget(parent
, operations
);
459 target
.setTransfer(types
);
460 target
.addDropListener(new NameEditorDropTargetListener(this));
465 * <p>Getter for the field <code>acceptedNameContainer</code>.</p>
467 * @return a {@link eu.etaxonomy.taxeditor.editor.name.container.AcceptedNameContainer} object.
469 public AcceptedNameContainer
getAcceptedNameContainer() {
470 return getAcceptedGroup().getAcceptedNameContainer();
474 * <p>getSynonymGroup</p>
476 * @param homotypicalGroup a {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup} object.
477 * @return a {@link eu.etaxonomy.taxeditor.editor.name.container.HomotypicalSynonymGroup} object.
479 public HomotypicalSynonymGroup
getHomotypicalGroupContainer(HomotypicalGroup homotypicalGroup
) {
480 for(HomotypicalSynonymGroup group
: getHeterotypicSynonymGroups()){
481 if(group
.getGroup().equals(homotypicalGroup
)){
490 * <p>Getter for the field <code>conceptGroup</code>.</p>
492 * @return a {@link eu.etaxonomy.taxeditor.editor.name.container.ConceptGroup} object.
494 public ConceptGroup
getConceptGroup() {
499 * <p>getDirtyNames</p>
501 * @return a Set containing all composites that have been edited
503 public Set
<AbstractGroupedContainer
> getDirtyNames(){
504 Set
<AbstractGroupedContainer
> dirtyNames
= new HashSet
<AbstractGroupedContainer
>();
506 for(AbstractGroupedContainer composite
: getGroupedContainers()){
507 if(composite
.isDirty()){
508 dirtyNames
.add(composite
);
516 * <p>getGroupedContainers</p>
518 * @return a {@link java.util.List} object.
520 public List
<AbstractGroupedContainer
> getGroupedContainers(){
521 List
<AbstractGroupedContainer
> groupedComposites
= new ArrayList
<AbstractGroupedContainer
>();
523 for(AbstractGroup group
: getAllGroups()){
524 groupedComposites
.addAll(group
.getGroupedContainers());
527 return groupedComposites
;
531 * <p>getAllGroups</p>
533 * @return a {@link java.util.List} object.
535 public List
<AbstractGroup
> getAllGroups(){
536 List
<AbstractGroup
> allGroups
= new ArrayList
<AbstractGroup
>();
538 allGroups
.add(getAcceptedGroup());
540 allGroups
.addAll(getHeterotypicSynonymGroups());
542 if(misappliedGroup
!= null){
543 allGroups
.add(misappliedGroup
);
546 if(conceptGroup
!= null){
547 allGroups
.add(conceptGroup
);
554 * @see org.eclipse.ui.part.EditorPart#isDirty()
558 public boolean isDirty() {
559 return editor
.isDirty();
563 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
567 public void dispose() {
572 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
576 public boolean isSaveAsAllowed() {
582 * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
585 public void selectionChanged(IWorkbenchPart part
, ISelection selection
) {
590 * <p>getNameEditor</p>
592 * @return a {@link eu.etaxonomy.taxeditor.editor.name.TaxonNameEditor} object.
594 public TaxonNameEditor
getEditor() {
599 * <p>Getter for the field <code>selectedObject</code>.</p>
601 * @return a {@link eu.etaxonomy.taxeditor.editor.name.container.AbstractGroupedContainer} object.
603 public AbstractGroupedContainer
getSelectedContainer(){
605 TaxonBase selectedTaxonBase
= null;
607 TaxonEditorInput input
= (TaxonEditorInput
) editor
.getEditorInput();
608 if(input
.getInitiallySelectedTaxonBase() != null){
609 selectedTaxonBase
= input
.getInitiallySelectedTaxonBase();
611 if(selection
!= null){
612 selectedTaxonBase
= selection
;
616 return (selectedTaxonBase
!= null) ?
getContainer(selectedTaxonBase
) : getAcceptedNameContainer();
622 public void dragEntered() {
624 getControl().setBackground(EditorUtil
.getColor(Resources
.COLOR_DRAG_ENTER
));
630 public void dragLeft() {
631 getControl().setBackground(EditorUtil
.getColor(Resources
.COLOR_COMPOSITE_BACKGROUND
));
635 * <p>Setter for the field <code>conceptGroup</code>.</p>
637 * @param conceptGroup a {@link eu.etaxonomy.taxeditor.editor.name.container.ConceptGroup} object.
639 public void setConceptGroup(ConceptGroup conceptGroup
) {
640 this.conceptGroup
= conceptGroup
;
644 * <p>setMisapplicationsGroup</p>
646 * @param misappliedGroup a {@link eu.etaxonomy.taxeditor.editor.name.container.MisappliedGroup} object.
648 public void setMisapplicationsGroup(MisappliedGroup misappliedGroup
) {
649 this.misappliedGroup
= misappliedGroup
;
654 * @see eu.etaxonomy.taxeditor.editor.IMultiPageTaxonEditorPage#isRedrawing()
661 public boolean isRedrawing() {
668 * @return a {@link org.eclipse.ui.forms.widgets.FormToolkit} object.
670 public FormToolkit
getToolkit() {
671 return managedForm
.getToolkit();
675 * <p>getHeterotypicSynonymGroups</p>
677 * @return a {@link java.util.List} object.
679 public List
<HomotypicalSynonymGroup
> getHeterotypicSynonymGroups(){
680 return heterotypicSynonymGroups
;
685 * <p>addHeterotypicSynonymGroup</p>
687 * @param group a {@link eu.etaxonomy.taxeditor.editor.name.container.HomotypicalSynonymGroup} object.
689 public void addHeterotypicSynonymGroup(HomotypicalSynonymGroup group
) {
690 heterotypicSynonymGroups
.add(group
);
694 * <p>getHomotypicSynonymGroup</p>
696 * @return a {@link eu.etaxonomy.taxeditor.editor.name.container.HomotypicalSynonymGroup} object.
698 public AcceptedGroup
getAcceptedGroup() {
699 return acceptedGroup
;
706 * @param acceptedGroup
708 public void setAcceptedGroup(
709 AcceptedGroup acceptedGroup
) {
710 this.acceptedGroup
= acceptedGroup
;
714 * <p>Getter for the field <code>misappliedGroup</code>.</p>
716 * @return a {@link eu.etaxonomy.taxeditor.editor.name.container.MisappliedGroup} object.
718 public MisappliedGroup
getMisappliedGroup() {
719 return misappliedGroup
;
722 // TODO not very useful at the moment
728 public boolean isActive(){
729 IWorkbenchPart activePart
= EditorUtil
.getActivePart();
730 return editor
.equals(activePart
);
738 public boolean onComplete() {
739 getContainer(objectAffectedByLastOperation
).setSelected();
746 public void partChanged(Integer eventType
, IWorkbenchPartReference partRef
) {
747 if(! partRef
.getPart(false).equals(editor
)){
748 // getSelectedObject().colorSelected(AbstractGroupedContainer.SELECTED_NO_FOCUS);
755 * @param retainedGroup
757 public void removeGroup(AbstractGroup group
) {
760 getHeterotypicSynonymGroups().remove(group
);
768 public AbstractGroupedContainer
getContainer(TaxonBase taxonBase
) {
769 List
<AbstractGroupedContainer
> groupedContainers
= getGroupedContainers();
770 for(AbstractGroupedContainer container
: groupedContainers
){
771 if(container
.getData().equals(taxonBase
) && container
.getNameViewer().getTextWidget() != null){
775 return getAcceptedNameContainer();