Merge branch 'hotfix/5.45.1'
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / descriptiveDataSet / character / CharacterEditor.java
index 114940d28f592f86c0e5e8f9277d965948c71add..47875796f977fc20f7e7c94692c0bdc69fe919cb 100644 (file)
@@ -1,4 +1,3 @@
-// $Id$
 /**
 * Copyright (C) 2017 EDIT
 * European Distributed Institute of Taxonomy
@@ -18,14 +17,17 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.e4.core.di.annotations.Optional;
 import org.eclipse.e4.ui.di.Focus;
 import org.eclipse.e4.ui.di.Persist;
+import org.eclipse.e4.ui.di.UIEventTopic;
 import org.eclipse.e4.ui.di.UISynchronize;
 import org.eclipse.e4.ui.model.application.ui.MDirtyable;
 import org.eclipse.e4.ui.services.EMenuService;
@@ -36,8 +38,10 @@ import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.dnd.DND;
 import org.eclipse.swt.dnd.Transfer;
 import org.eclipse.swt.events.ModifyEvent;
 import org.eclipse.swt.events.ModifyListener;
@@ -52,14 +56,15 @@ import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.forms.widgets.FormToolkit;
 
-import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
-import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
-import eu.etaxonomy.cdm.api.service.IFeatureNodeService;
-import eu.etaxonomy.cdm.api.service.ITermService;
+import eu.etaxonomy.cdm.api.service.ITermNodeService;
 import eu.etaxonomy.cdm.api.service.ITermTreeService;
 import eu.etaxonomy.cdm.api.service.IVocabularyService;
+import eu.etaxonomy.cdm.api.service.UpdateResult;
+import eu.etaxonomy.cdm.format.description.CharacterLabelBuilder;
+import eu.etaxonomy.cdm.model.common.Language;
 import eu.etaxonomy.cdm.model.description.Character;
 import eu.etaxonomy.cdm.model.description.Feature;
+import eu.etaxonomy.cdm.model.term.DefinedTerm;
 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
 import eu.etaxonomy.cdm.model.term.Representation;
 import eu.etaxonomy.cdm.model.term.TermNode;
@@ -67,39 +72,51 @@ import eu.etaxonomy.cdm.model.term.TermTree;
 import eu.etaxonomy.cdm.model.term.TermType;
 import eu.etaxonomy.cdm.model.term.TermVocabulary;
 import eu.etaxonomy.cdm.model.term.VocabularyEnum;
-import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
+import eu.etaxonomy.cdm.persistence.dto.CharacterDto;
+import eu.etaxonomy.cdm.persistence.dto.CharacterNodeDto;
+import eu.etaxonomy.cdm.persistence.dto.TermCollectionDto;
+import eu.etaxonomy.cdm.persistence.dto.TermDto;
+import eu.etaxonomy.cdm.persistence.dto.TermNodeDto;
+import eu.etaxonomy.cdm.persistence.dto.TermTreeDto;
 import eu.etaxonomy.taxeditor.editor.AppModelId;
+import eu.etaxonomy.taxeditor.editor.definedterm.TermTreeViewerComparator;
 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
-import eu.etaxonomy.taxeditor.featuretree.CharacterTransfer;
-import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
-import eu.etaxonomy.taxeditor.featuretree.e4.FeatureNodeDragListener;
-import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeDropAdapter;
-import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeEditorComposite;
-import eu.etaxonomy.taxeditor.featuretree.e4.IFeatureTreeEditor;
+import eu.etaxonomy.taxeditor.event.EventUtility;
+import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
+import eu.etaxonomy.taxeditor.model.AbstractUtility;
 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
 import eu.etaxonomy.taxeditor.model.ImageResources;
 import eu.etaxonomy.taxeditor.model.MessagingUtils;
+import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
 import eu.etaxonomy.taxeditor.store.CdmStore;
+import eu.etaxonomy.taxeditor.store.StoreUtil;
+import eu.etaxonomy.taxeditor.termtree.CharacterTransfer;
+import eu.etaxonomy.taxeditor.termtree.TermTreeContentProvider;
+import eu.etaxonomy.taxeditor.termtree.TermTreeLabelProvider;
+import eu.etaxonomy.taxeditor.termtree.e4.ICharacterEditor;
+import eu.etaxonomy.taxeditor.termtree.e4.TermNodeDtoDragListener;
+import eu.etaxonomy.taxeditor.termtree.e4.TermTreeDtoDropAdapter;
+import eu.etaxonomy.taxeditor.termtree.e4.TermTreeDtoEditorComposite;
+import eu.etaxonomy.taxeditor.termtree.e4.TermTreeEditor;
 import eu.etaxonomy.taxeditor.ui.dialog.selection.FeatureTreeSelectionDialog;
 import eu.etaxonomy.taxeditor.ui.dialog.selection.TermVocabularySelectionDialog;
+import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
 import eu.etaxonomy.taxeditor.workbench.part.IE4ViewerPart;
 
 /**
  * Editor for combining structure and property terms to characters.
+ * 
  * @author pplitzner
  * @date 24.05.2017
- *
  */
-public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled, ISelectionChangedListener,
-        ModifyListener, IE4ViewerPart, IPartContentHasDetails, IPartContentHasSupplementalData, IDirtyMarkable {
+public class CharacterEditor implements ICharacterEditor, ISelectionChangedListener, ModifyListener, IE4ViewerPart,
+        IPartContentHasDetails, IPartContentHasSupplementalData, IDirtyMarkable, IE4SavablePart {
 
-    private FeatureTreeEditorComposite<Character> characterTreeEditorComposite;
-    private FeatureTreeEditorComposite<DefinedTermBase> propertiesTreeEditorComposite;
-    private FeatureTreeEditorComposite<DefinedTermBase> structuresTreeEditorComposite;
+    private TermTreeDtoEditorComposite characterTreeEditorComposite;
     private final FormToolkit formToolkit = new FormToolkit(Display.getDefault());
 
     @Inject
@@ -111,12 +128,19 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
     @Inject
     private MDirtyable dirty;
 
-    private ConversationHolder conversation;
-
     private ICdmEntitySession cdmEntitySession;
-    private Composite composite;
 
     private TermVocabulary vocabulary;
+    private TreeViewer structureViewer;
+    private TreeViewer propertyViewer;
+    private Button btnAddCharacter;
+    private Button btnAddRatioTo;
+
+    private List<AbstractPostOperation> operations = new ArrayList<>();
+
+    private List<CharacterNodeDto> nodesToUpdate = new ArrayList<>();
+
+    private Map<Character, CharacterNodeDto> nodesToSave = new HashMap<>();
 
     public CharacterEditor() {
     }
@@ -125,25 +149,24 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
      * Create contents of the view part.
      */
     @PostConstruct
-    public void createControls(Composite parent, EMenuService menuService ) {
-        if (CdmStore.isActive()){
-            if(conversation == null){
-                conversation = CdmStore.createConversation();
-            }
-            if(cdmEntitySession!=null){
+    public void createControls(Composite parent, EMenuService menuService) {
+        if (CdmStore.isActive()) {
+            // if(conversation == null){
+            // conversation = CdmStore.createConversation();
+            // }
+            if (cdmEntitySession == null) {
                 cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
             }
-        }
-        else{
+        } else {
             return;
         }
         parent.setLayout(new GridLayout(1, false));
 
         Composite vocChooserComposite = new Composite(parent, SWT.NONE);
-        vocChooserComposite.setLayout(new GridLayout(3, false));
+        vocChooserComposite.setLayout(new GridLayout(4, false));
         vocChooserComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false, 2, 1));
         Label lblVocImport = new Label(vocChooserComposite, SWT.NONE);
-        lblVocImport.setText("Character vocabulary");
+        lblVocImport.setText("Character vocabulary:");
         Text txtVocabulary = new Text(vocChooserComposite, SWT.NONE);
         txtVocabulary.setEditable(false);
         Button btnChooseVoc = new Button(vocChooserComposite, SWT.PUSH);
@@ -152,15 +175,19 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
 
             @Override
             public void widgetSelected(SelectionEvent e) {
-                // hard-coded filter for "built-in" vocabularies Feature and Name Feature
+                // hard-coded filter for "built-in" vocabularies Feature and
+                // Name Feature
                 Set<TermVocabulary> vocabulariesToBeFiltered = new HashSet<>();
-                vocabulariesToBeFiltered.add(CdmStore.getService(IVocabularyService.class).load(VocabularyEnum.Feature.getUuid()));
-                vocabulariesToBeFiltered.add(CdmStore.getService(IVocabularyService.class).load(VocabularyEnum.NameFeature.getUuid()));
-                if(vocabulary!=null){
+                vocabulariesToBeFiltered
+                        .add(CdmStore.getService(IVocabularyService.class).load(VocabularyEnum.Feature.getUuid()));
+                vocabulariesToBeFiltered
+                        .add(CdmStore.getService(IVocabularyService.class).load(VocabularyEnum.NameFeature.getUuid()));
+                if (vocabulary != null) {
                     vocabulariesToBeFiltered.add(vocabulary);
                 }
-                vocabulary = TermVocabularySelectionDialog.select("Select vocabulary for characters", btnChooseVoc.getShell(), vocabulariesToBeFiltered, TermType.Character);
-                if(vocabulary!=null){
+                vocabulary = TermVocabularySelectionDialog.select("Select vocabulary for characters",
+                        btnChooseVoc.getShell(), vocabulariesToBeFiltered, TermType.Character);
+                if (vocabulary != null) {
                     txtVocabulary.setText(vocabulary.getLabel());
                 }
             }
@@ -171,19 +198,14 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
         formToolkit.adapt(sashForm);
         formToolkit.paintBordersFor(sashForm);
 
-        composite = new Composite(sashForm, SWT.NONE);
+        Composite composite = new Composite(sashForm, SWT.NONE);
         formToolkit.adapt(composite);
         formToolkit.paintBordersFor(composite);
         GridLayout gl_composite = new GridLayout(1, false);
         gl_composite.marginWidth = 0;
         composite.setLayout(gl_composite);
 
-        structuresTreeEditorComposite = addFeatureTreeEditor(composite);
-
-        initFeatureTreeComposite(TermType.Structure, structuresTreeEditorComposite,
-                new FeatureNodeDragListener(structuresTreeEditorComposite.getViewer()), null, null, null, null);
-
-        structuresTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_STRUCTURES);
+        structureViewer = createTreeViewer(composite, TermType.Structure, Messages.CharacterEditor_STRUCTURES);
 
         Composite composite_1 = new Composite(sashForm, SWT.NONE);
         formToolkit.adapt(composite_1);
@@ -192,16 +214,12 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
         gl_composite_1.marginWidth = 0;
         composite_1.setLayout(gl_composite_1);
 
-        propertiesTreeEditorComposite = addFeatureTreeEditor(composite_1);
-        initFeatureTreeComposite(TermType.Property, propertiesTreeEditorComposite,
-                new CharacterDragListener(structuresTreeEditorComposite.getViewer(), propertiesTreeEditorComposite.getViewer()),
-                null,
-                new Transfer[] {CharacterTransfer.getInstance()},
-                null,
-                null
+        propertyViewer = createTreeViewer(composite_1, TermType.Property, Messages.CharacterEditor_PROPERTIES);
+        propertyViewer.addSelectionChangedListener(this);
 
-        );
-        propertiesTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_PROPERTIES);
+        int ops = DND.DROP_COPY | DND.DROP_MOVE;
+        Transfer[] transfers = new Transfer[] { CharacterTransfer.getInstance() };
+        propertyViewer.addDragSupport(ops, transfers, new CharacterDragListener(structureViewer, propertyViewer));
 
         Composite composite_3 = new Composite(sashForm, SWT.NONE);
         formToolkit.adapt(composite_3);
@@ -210,109 +228,265 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
         gl_composite_3.marginWidth = 0;
         composite_3.setLayout(gl_composite_3);
 
-        Button btnAddCharacter = new Button(composite_3, SWT.NONE);
+        Composite composite_4 = new Composite(composite_3, SWT.NONE);
+        formToolkit.adapt(composite_4);
+        formToolkit.paintBordersFor(composite_4);
+        GridLayout gl_composite_4 = new GridLayout(1, false);
+        gl_composite_4.marginWidth = 0;
+        composite_4.setLayout(gl_composite_4);
+
+        btnAddCharacter = new Button(composite_4, SWT.NONE);
         btnAddCharacter.setText(">>"); //$NON-NLS-1$
         formToolkit.adapt(btnAddCharacter, true, true);
         btnAddCharacter.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
-                if(!isVocabularySet()){
+                if (!isVocabularySet()) {
+                    return;
+                }
+                if (confirmSaveDirty()) {
                     return;
                 }
-                ISelection structureTreeSelection = structuresTreeEditorComposite.getViewer().getSelection();
-                ISelection propertyTreeSelection = propertiesTreeEditorComposite.getViewer().getSelection();
-                if(structureTreeSelection==null || propertyTreeSelection==null || characterTreeEditorComposite.getFeatureTree()==null){
+                ISelection structureTreeSelection = structureViewer.getSelection();
+                ISelection propertyTreeSelection = propertyViewer.getSelection();
+                if (structureTreeSelection == null || propertyTreeSelection == null
+                        || characterTreeEditorComposite.getFeatureTree() == null) {
                     MessagingUtils.warningDialog(Messages.CharacterEditor_CANNOT_PERFORM_TITLE, CharacterEditor.this,
                             Messages.CharacterEditor_CANNOT_PERFORM_MESSAGE);
                     return;
                 }
-                Collection<Character> characters = createCharacters((TreeSelection)structureTreeSelection, (TreeSelection)propertyTreeSelection);
-                TermNode<Character> parent = ((TermTree<Character>) characterTreeEditorComposite.getViewer().getInput()).getRoot();
+                Collection<Character> characters = createCharacters((TreeSelection) structureTreeSelection,
+                        (TreeSelection) propertyTreeSelection);
+                TermNodeDto parent = ((TermTreeDto) characterTreeEditorComposite.getFeatureTree()).getRoot();
+                ISelection sel = characterTreeEditorComposite.getViewer().getSelection();
+
+                TermNodeDto parentNode = parent;
+                if (sel instanceof TreeSelection) {
+                    TreeSelection treeSel = (TreeSelection) sel;
+                    Object o = treeSel.getFirstElement();
+                    if (o instanceof CharacterNodeDto) {
+                        parentNode = (TermNodeDto) o;
+                    }
+                }
+
                 for (Character character : characters) {
-                    //add new Character to feature tree
-                    CdmStore.getService(IFeatureNodeService.class).createChildFeatureNode(parent.getUuid(), character, vocabulary.getUuid());
+                    // add new Character to feature tree
+                    TermTreeDto tree = (TermTreeDto)getTreeDtoForUuid(parent.getTreeUuid());
+                    CharacterNodeDto nodeDto = new CharacterNodeDto(CharacterDto.fromCharacter(character), parentNode,
+                            0, tree, null, 0, null, null);
+                    nodesToSave.put(character, nodeDto);
+                    setDirty();
+                    // result =
+                    // CdmStore.getService(ITermNodeService.class).createChildFeatureNode(parent.getUuid(),
+                    // character, vocabulary.getUuid());
+
                 }
-                characterTreeEditorComposite.getViewer().refresh();
+
+                refresh();
             }
         });
+        btnAddCharacter.setEnabled(false);
 
-        characterTreeEditorComposite = addFeatureTreeEditor(composite_3);
-        initFeatureTreeComposite(TermType.Character, characterTreeEditorComposite, new FeatureNodeDragListener(characterTreeEditorComposite.getViewer()),
-                new CharacterDropAdapter(this, characterTreeEditorComposite.getViewer(), sync),
+        btnAddRatioTo = new Button(composite_4, SWT.NONE);
+        btnAddRatioTo.setText("ratio to"); //$NON-NLS-1$
+
+        btnAddRatioTo.setSize(btnAddCharacter.getSize());
+        btnAddRatioTo.setEnabled(false);
+
+        formToolkit.adapt(btnAddRatioTo, true, true);
+        btnAddRatioTo.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+
+                if (confirmSaveDirty()) {
+                    return;
+                }
+                ISelection structureTreeSelection = structureViewer.getSelection();
+                ISelection characterSelection = characterTreeEditorComposite.getViewer().getSelection();
+                if (structureTreeSelection == null || characterSelection == null) {
+                    MessagingUtils.warningDialog(Messages.CharacterEditor_CANNOT_PERFORM_TITLE, CharacterEditor.this,
+                            Messages.CharacterEditor_CANNOT_PERFORM_MESSAGE);
+                    return;
+                }
+
+                CharacterNodeDto character = (CharacterNodeDto) ((TreeSelection) characterSelection).getFirstElement();
+                TermNode ratioToNode = (TermNode) ((TreeSelection) structureTreeSelection).getFirstElement();
+                if (character == null) {
+                    return;
+                }
+                TermDto termDto = character.getTerm();
+                TermNodeDto structure = null;
+                TermNodeDto property = null;
+                Representation structureRepresentation = null;
+                Representation propertyRepresentation = null;
+                Representation ratioToRepresentation = ratioToNode.getTerm()
+                        .getRepresentation(CdmStore.getDefaultLanguage());
+                if (termDto instanceof CharacterDto) {
+                    CharacterDto dto = (CharacterDto) termDto;
+                    dto.setRatioTo(TermNodeDto.fromNode(ratioToNode, null));
+                    structure = dto.getStructure();
+                    structureRepresentation = structure.getTerm()
+                            .getPreferredRepresentation(CdmStore.getDefaultLanguage());
+                    property = dto.getProperty();
+                    propertyRepresentation = property.getTerm()
+                            .getPreferredRepresentation(CdmStore.getDefaultLanguage());
+                }
+
+                String label = null;
+                String abbrevLabel = null;
+
+                if (structureRepresentation != null && propertyRepresentation != null) {
+                    if (structureRepresentation.getLabel() != null && propertyRepresentation.getLabel() != null
+                            && ratioToRepresentation.getLabel() != null) {
+                        label = propertyRepresentation.getLabel() + " ratio " + structureRepresentation.getLabel()
+                                + " to " + ratioToRepresentation.getLabel();
+                    }
+                    if (structureRepresentation.getAbbreviatedLabel() != null
+                            && propertyRepresentation.getAbbreviatedLabel() != null
+                            && ratioToRepresentation.getAbbreviatedLabel() != null) {
+                        abbrevLabel = propertyRepresentation.getAbbreviatedLabel() + " ratio "
+                                + structureRepresentation.getAbbreviatedLabel() + " to "
+                                + ratioToRepresentation.getAbbreviatedLabel();
+                    }
+                }
+                if (label == null) {
+                    // default label
+                    label = property.getTerm().getRepresentation_L10n() + " ratio "
+                            + structure.getTerm().getRepresentation_L10n() + " to " + ratioToNode.getTerm().getLabel();
+                }
+                character.getTerm().getRepresentation(CdmStore.getDefaultLanguage()).setLabel(label);
+                character.getTerm().getRepresentation(CdmStore.getDefaultLanguage()).setAbbreviatedLabel(abbrevLabel);
+
+                setDirty();
+                nodesToUpdate.add(character);
+
+                refresh();
+
+                characterTreeEditorComposite.getViewer().setSelection(new StructuredSelection(character));
+                EventUtility.postEvent(WorkbenchEventConstants.REFRESH_DETAILS, true);
+            }
+        });
 
-                new Transfer[] {FeatureNodeTransfer.getInstance(), CharacterTransfer.getInstance()},
-                this,
-                this);
+        characterTreeEditorComposite = addFeatureTreeEditor(composite_3);
+        initFeatureTreeComposite(TermType.Character, characterTreeEditorComposite,
+                new TermNodeDtoDragListener(characterTreeEditorComposite.getViewer()),
+                new TermTreeDtoDropAdapter(this, characterTreeEditorComposite.getViewer(), sync), null);
 
         characterTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_CHARACTERS);
 
-        //add context menu to character viewer
+        // add context menu to character viewer
         menuService.registerContextMenu(characterTreeEditorComposite.getViewer().getControl(),
                 AppModelId.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_EDITOR_POPUPMENU_CHARACTEREDITOR);
 
     }
 
-    private <T extends DefinedTermBase> FeatureTreeEditorComposite<T> addFeatureTreeEditor(Composite composite_3) {
-        FeatureTreeEditorComposite<T> featureTreeEditorComposite = new FeatureTreeEditorComposite<>(composite_3, SWT.NONE);
-        featureTreeEditorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
-        return featureTreeEditorComposite;
+    private TreeViewer createTreeViewer(Composite parent, TermType termType, String labelString) {
+        Composite composite = new Composite(parent, SWT.NONE);
+        composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+        composite.setLayout(new GridLayout(2, false));
+        Label label = new Label(composite, SWT.NONE);
+        label.setText(labelString);
+        Button btnRefresh = new Button(composite, SWT.PUSH);
+        btnRefresh.setImage(ImageResources.getImage(ImageResources.REFRESH));
+        btnRefresh.setToolTipText("Refresh");
+
+        TreeViewer viewer = new TreeViewer(composite);
+        viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+        viewer.setContentProvider(new TermTreeContentProvider());
+        viewer.setLabelProvider(new TermTreeLabelProvider());
+        viewer.setComparator(new TermTreeViewerComparator());
+        viewer.addSelectionChangedListener(this);
+        viewer.setInput(CdmStore.getService(ITermTreeService.class).list(termType, null, null, null,
+                TermTreeEditor.TREE_PROPERTY_PATH));
+        btnRefresh.addSelectionListener(new SelectionAdapter() {
+
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                viewer.setInput(CdmStore.getService(ITermTreeService.class).list(termType, null, null, null,
+                        TermTreeEditor.TREE_PROPERTY_PATH));
+                refresh(viewer);
+            }
+        });
+        return viewer;
+    }
+
+    private <T extends DefinedTermBase> TermTreeDtoEditorComposite<T> addFeatureTreeEditor(Composite composite_3) {
+        TermTreeDtoEditorComposite<T> TermTreeEditorComposite = new TermTreeDtoEditorComposite<>(composite_3, SWT.NONE);
+        TermTreeEditorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+        return TermTreeEditorComposite;
     }
 
-    private void initFeatureTreeComposite(
-            TermType termType,
-            FeatureTreeEditorComposite featureTreeEditorComposite,
-            FeatureNodeDragListener featureNodeDragListener,
-            FeatureTreeDropAdapter featureNodeDropAdapter,
-            Transfer[] transfers,
-            ISelectionChangedListener viewerSelectionChangedListener,
-            ModifyListener modifyListener) {
+    private void initFeatureTreeComposite(TermType termType, TermTreeDtoEditorComposite TermTreeEditorComposite,
+            TermNodeDtoDragListener featureNodeDragListener, TermTreeDtoDropAdapter featureNodeDropAdapter,
+            Transfer[] transfers) {
 
-        featureTreeEditorComposite.init(
-                featureNodeDragListener,
-                featureNodeDropAdapter,
-                transfers,
-                viewerSelectionChangedListener,
-                new FeatureTreeChooserListener(featureTreeEditorComposite, termType),
-                modifyListener);
+        TermTreeEditorComposite.init(featureNodeDragListener, featureNodeDropAdapter, transfers, this,
+                new FeatureTreeChooserListener(TermTreeEditorComposite, termType), this);
     }
 
     @Focus
-    public void focus(){
-        if(characterTreeEditorComposite!=null){
+    public void focus() {
+        if (characterTreeEditorComposite != null) {
             characterTreeEditorComposite.getViewer().getControl().setFocus();
         }
-        if(conversation!=null && !conversation.isBound()){
-            conversation.bind();
-        }
-        if(cdmEntitySession != null) {
+        if (cdmEntitySession != null) {
             cdmEntitySession.bind();
         }
     }
 
-    public static Collection<Character> createCharacters(TreeSelection structureTreeSelection, TreeSelection propertyTreeSelection){
+    public static Collection<Character> createCharacters(TreeSelection structureTreeSelection,
+            TreeSelection propertyTreeSelection) {
         Set<Character> characters = new HashSet<>();
-        //get selected structures and properties
-        Iterator<TermNode<DefinedTermBase>> structureIterator = structureTreeSelection.iterator();
-
-        //create all combinations of structures and properties
-        while(structureIterator.hasNext()){
-            TermNode<DefinedTermBase> structureNode = structureIterator.next();
-            Iterator<TermNode<DefinedTermBase>> propertiesIterator = propertyTreeSelection.iterator();
-            while(propertiesIterator.hasNext()){
-                TermNode<DefinedTermBase> propertyNode = propertiesIterator.next();
-                Representation structureRepresentation = structureNode.getTerm().getRepresentation(PreferencesUtil.getGlobalLanguage());
-                Representation propertyRepresentation = propertyNode.getTerm().getRepresentation(PreferencesUtil.getGlobalLanguage());
+        // get selected structures and properties
+        Iterator<TermNode<DefinedTerm>> structureIterator = structureTreeSelection.iterator();
+
+        // create all combinations of structures and properties
+        while (structureIterator.hasNext()) {
+            Object o = structureIterator.next();
+            TermNode<DefinedTerm> structureNode = null;
+            if (o instanceof TermNode) {
+                structureNode = (TermNode<DefinedTerm>) o;
+            } else {
+                return null;
+
+            }
+
+            Iterator<TermNode<DefinedTerm>> propertiesIterator = propertyTreeSelection.iterator();
+            while (propertiesIterator.hasNext()) {
+                TermNode<DefinedTerm> propertyNode = propertiesIterator.next();
+                Representation structureRepresentation = structureNode.getTerm()
+                        .getRepresentation(PreferencesUtil.getGlobalLanguage());
+                if (structureRepresentation == null) {
+                    structureRepresentation = structureNode.getTerm().getRepresentation(Language.DEFAULT());
+                }
+                Representation propertyRepresentation = propertyNode.getTerm()
+                        .getRepresentation(PreferencesUtil.getGlobalLanguage());
+                if (propertyRepresentation == null) {
+                    propertyRepresentation = propertyNode.getTerm().getRepresentation(Language.DEFAULT());
+                }
                 String label = null;
                 String abbrevLabel = null;
-                if(structureRepresentation.getLabel()!=null && propertyRepresentation.getLabel()!=null){
-                    label = structureRepresentation.getLabel()+" "+propertyRepresentation.getLabel();
+                if (structureRepresentation != null && propertyRepresentation != null) {
+                    if (structureRepresentation.getLabel() != null && propertyRepresentation.getLabel() != null) {
+                        label = structureRepresentation.getLabel() + " " + propertyRepresentation.getLabel();
+                    }
+                    if (structureRepresentation.getAbbreviatedLabel() != null
+                            && propertyRepresentation.getAbbreviatedLabel() != null) {
+                        abbrevLabel = structureRepresentation.getAbbreviatedLabel() + " "
+                                + propertyRepresentation.getAbbreviatedLabel();
+                    }
                 }
-                if(structureRepresentation.getAbbreviatedLabel()!=null && propertyRepresentation.getAbbreviatedLabel()!=null){
-                    abbrevLabel = structureRepresentation.getAbbreviatedLabel()+" "+propertyRepresentation.getAbbreviatedLabel();
+                if (label != null) {
+                    // default label
+                    label = structureNode.getTerm().getLabel() + " " + propertyNode.getTerm().getLabel();
                 }
-                //create new Character
                 Character character = Character.NewInstance(structureNode, propertyNode, null, label, abbrevLabel);
+                CharacterLabelBuilder labelBuilder = CharacterLabelBuilder.NewDefaultInstance();
+                character.setLabel(labelBuilder.buildLabel(character, CdmStore.getDefaultLanguage()));
+                character.setAvailableForTaxon(true);
+                character.setAvailableForOccurrence(true);
                 characters.add(character);
+
             }
         }
         return characters;
@@ -320,37 +494,59 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
 
     @Override
     @Persist
-    public void save(IProgressMonitor monitor){
-        if (!conversation.isBound()) {
-            conversation.bind();
-        }
+    public void save(IProgressMonitor monitor) {
 
+        UpdateResult result = new UpdateResult();
+        if (nodesToSave != null && this.getVocabulary() != null) {
+            result.includeResult(CdmStore.getService(ITermNodeService.class)
+                    .saveNewCharacterNodeDtoMap(this.nodesToSave, this.getVocabulary().getUuid()));
+        }
+        nodesToSave.clear();
+        TermCollectionDto featureTree = characterTreeEditorComposite.getFeatureTree();
+        if (operations != null && !operations.isEmpty()) {
+            for (AbstractPostOperation<TermNode> operation : operations) {
+                AbstractUtility.executeOperation(operation, sync);
+            }
+            operations.clear();
+        }        
+       
+        result.includeResult(CdmStore.getService(ITermNodeService.class).saveCharacterNodeDtoList(this.nodesToUpdate));
+        
+        nodesToUpdate.clear();
         // commit the conversation and start a new transaction immediately
-        conversation.commit(true);
+        // conversation.commit(true);
+        if (result.getUpdatedObjects() != null && !result.getUpdatedObjects().isEmpty()) {
+            Object o = result.getUpdatedObjects().iterator().next();
+            if (o instanceof TermNode) {
+                TermNode node = (TermNode) o;
+                TermTree updateTree = (TermTree) node.getGraph();
+                if (updateTree != null) {
+                    characterTreeEditorComposite.setSelectedTree(updateTree);
+                }
+            }
 
-        TermTree<Character> featureTree = characterTreeEditorComposite.getFeatureTree();
-        if(featureTree!=null){
-            //save characters because they can be modified in this editor
-            featureTree.getDistinctTerms().forEach(character->CdmStore.getService(ITermService.class).merge(character,true));
         }
-        CdmStore.getService(ITermTreeService.class).saveOrUpdate(featureTree);
 
+        // initializeTrees();
 
         dirty.setDirty(false);
     }
 
+    private void initializeTrees() {
+        Object[] expandedElements = characterTreeEditorComposite.getViewer().getExpandedElements();
+        characterTreeEditorComposite.getViewer().getTree().removeAll();
+        characterTreeEditorComposite.getViewer().setExpandedElements(expandedElements);
+    }
+
     @Override
     public boolean isDirty() {
         return dirty.isDirty();
     }
 
     @PreDestroy
-    public void dispose(){
-        if(conversation!=null){
-            conversation.close();
-            conversation = null;
-        }
-        if(cdmEntitySession != null) {
+    public void dispose() {
+
+        if (cdmEntitySession != null) {
             cdmEntitySession.dispose();
             cdmEntitySession = null;
         }
@@ -358,10 +554,15 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
     }
 
     public boolean isVocabularySet() {
-        if(vocabulary==null){
-            MessagingUtils.warningDialog("Character creation not possible", this.getClass(), "Please select a vocabulary for the characters.");
+        if (vocabulary == null) {
+            MessagingUtils.warningDialog("Character creation not possible", this.getClass(),
+                    "Please select a vocabulary for the characters.");
         }
-        return vocabulary!=null;
+        return vocabulary != null;
+    }
+
+    public boolean confirmSaveDirty() {
+        return StoreUtil.promptCheckIsDirty(this);
     }
 
     public TermVocabulary getVocabulary() {
@@ -370,20 +571,18 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
 
     @Override
     public Map<Object, List<String>> getPropertyPathsMap() {
-        List<String> propertyPaths = Arrays.asList(new String[] {
-                "children", //$NON-NLS-1$
+        List<String> propertyPaths = Arrays.asList(new String[] { "children", //$NON-NLS-1$
                 "feature", //$NON-NLS-1$
                 "featureTree", //$NON-NLS-1$
         });
-        Map<Object, List<String>> propertyPathMap =
-                new HashMap<Object, List<String>>();
-        propertyPathMap.put(TermNode.class,propertyPaths);
+        Map<Object, List<String>> propertyPathMap = new HashMap<Object, List<String>>();
+        propertyPathMap.put(TermNode.class, propertyPaths);
         return propertyPathMap;
     }
 
     @Override
-    public List<TermTree<Character>> getRootEntities() {
-        List<TermTree<Character>> root = new ArrayList<>();
+    public List<TermCollectionDto> getRootEntities() {
+        List<TermCollectionDto> root = new ArrayList<>();
         root.add(characterTreeEditorComposite.getFeatureTree());
         return root;
     }
@@ -395,26 +594,45 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
 
     @Focus
     public void setFocus() {
-        if(conversation!=null && !conversation.isBound()){
-            conversation.bind();
-        }
+
     }
 
     @Override
     public void selectionChanged(SelectionChangedEvent event) {
-        //propagate selection
+        // propagate selection
         selService.setSelection(event.getSelection());
+        ISelection selStructure = null;
+        ISelection selProperty = null;
+        selStructure = structureViewer.getSelection();
+        selProperty = propertyViewer.getSelection();
+
+        if (selStructure != null && selProperty != null && selStructure instanceof TreeSelection
+                && selProperty instanceof TreeSelection
+                && ((TreeSelection) selStructure).getFirstElement() instanceof TermNode
+                && ((TreeSelection) selProperty).getFirstElement() instanceof TermNode && this.vocabulary != null) {
+            btnAddCharacter.setEnabled(true);
+        } else {
+            btnAddCharacter.setEnabled(false);
+        }
+        ISelection selCharacter = this.characterTreeEditorComposite.getViewer().getSelection();
+        if (selStructure != null && selCharacter != null && selStructure instanceof TreeSelection
+                && selCharacter instanceof TreeSelection
+                && ((TreeSelection) selStructure).getFirstElement() instanceof TermNode
+                && ((TreeSelection) selCharacter).getFirstElement() instanceof CharacterNodeDto) {
+            btnAddRatioTo.setEnabled(true);
+        } else {
+            btnAddRatioTo.setEnabled(false);
+        }
     }
 
-
     @Override
     public void modifyText(ModifyEvent e) {
-        characterTreeEditorComposite.getFeatureTree().setTitleCache(((Text) e.widget).getText(), true);
+        characterTreeEditorComposite.getFeatureTree().setTitleCache(((Text) e.widget).getText());
         setDirty();
     }
 
-
-    private void setDirty() {
+    @Override
+    public void setDirty() {
         dirty.setDirty(true);
     }
 
@@ -423,45 +641,43 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
         return (IStructuredSelection) characterTreeEditorComposite.getViewer().getSelection();
     }
 
-    public TermTree<Character> getCharacterTree(){
+    @Override
+    public TermType getTermType() {
+        return TermType.Character;
+    }
+
+    public TermCollectionDto getCharacterTree() {
         return characterTreeEditorComposite.getFeatureTree();
     }
 
-    @Override
-    public void refresh(){
-        structuresTreeEditorComposite.getViewer().refresh();
-        propertiesTreeEditorComposite.getViewer().refresh();
-        characterTreeEditorComposite.getViewer().refresh();
+    public void refresh(TreeViewer viewer) {
+        viewer.refresh();
+
+        characterTreeEditorComposite.getViewer().setInput(characterTreeEditorComposite.getViewer().getInput());
     }
 
-    private class FeatureTreeChooserListener extends SelectionAdapter{
-        private FeatureTreeEditorComposite<Feature> featureTreeEditorComposite;
+    private class FeatureTreeChooserListener extends SelectionAdapter {
+        private TermTreeDtoEditorComposite<Feature> TermTreeEditorComposite;
         private TermType termType;
 
-        public FeatureTreeChooserListener(FeatureTreeEditorComposite<Feature> featureTreeEditorComposite, TermType termType) {
+        public FeatureTreeChooserListener(TermTreeDtoEditorComposite<Feature> TermTreeEditorComposite,
+                TermType termType) {
             super();
-            this.featureTreeEditorComposite = featureTreeEditorComposite;
+            this.TermTreeEditorComposite = TermTreeEditorComposite;
             this.termType = termType;
         }
 
         @Override
         public void widgetSelected(SelectionEvent e) {
-            TermTree tree = FeatureTreeSelectionDialog.select(featureTreeEditorComposite.getDisplay().getActiveShell(), null, termType);
-            if(tree!=null){
-                featureTreeEditorComposite.setSelectedTree(tree);
+            TermTree tree = FeatureTreeSelectionDialog.select(TermTreeEditorComposite.getDisplay().getActiveShell(),
+                    null, termType);
+            if (tree != null) {
+                cdmEntitySession.load(tree, true);
+                TermTreeEditorComposite.setSelectedTree(tree);
             }
         }
     }
 
-    @Override
-    public void update(CdmDataChangeMap arg0) {
-    }
-
-    @Override
-    public ConversationHolder getConversationHolder() {
-        return conversation;
-    }
-
     @Override
     public void changed(Object element) {
         setDirty();
@@ -476,7 +692,7 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
     @Override
     public boolean postOperation(Object objectAffectedByOperation) {
         characterTreeEditorComposite.getViewer().refresh();
-        if(objectAffectedByOperation instanceof TermNode){
+        if (objectAffectedByOperation instanceof TermNode) {
             StructuredSelection selection = new StructuredSelection(objectAffectedByOperation);
             characterTreeEditorComposite.getViewer().setSelection(selection);
         }
@@ -488,4 +704,73 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
         return false;
     }
 
+    @Override
+    public void refresh() {
+        structureViewer.refresh();
+        propertyViewer.refresh();
+        characterTreeEditorComposite.refresh();
+
+    }
+
+    @Override
+    public TermNodeDto getNodeDtoForUuid(UUID nodeUuid) {
+        return (TermNodeDto) this.characterTreeEditorComposite.getNodeUuidMap().get(nodeUuid);
+
+    }
+
+    @Override
+    public void addOperation(AbstractPostOperation operation) {
+        operations.add(operation);
+
+    }
+
+    @Inject
+    @Optional
+    private void addSaveCandidate(
+            @UIEventTopic(WorkbenchEventConstants.ADD_SAVE_CHARACTER) CharacterNodeDto characterNodeDto) {
+
+        if (characterNodeDto != null) {
+            if (nodesToUpdate.contains(characterNodeDto)) {
+                nodesToUpdate.remove(characterNodeDto);
+            }
+            nodesToUpdate.add(characterNodeDto);
+        }
+
+    }
+
+    @Override
+    public TreeViewer getViewer() {
+        return this.characterTreeEditorComposite.getViewer();
+    }
+
+    @Override
+    public TermCollectionDto getTreeDtoForUuid(UUID treeUuid) {
+        if (this.characterTreeEditorComposite.getFeatureTree().getUuid().equals(treeUuid)) {
+            return this.characterTreeEditorComposite.getFeatureTree();
+        }
+        return null;
+    }
+
+    @Override
+    public boolean checkDuplicates(UUID termUuid, UUID treeUuid) {
+        for (TermDto dto : characterTreeEditorComposite.getFeatureTree().getTerms()) {
+            if (dto != null && dto.getUuid().equals(termUuid)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void setNodeDtoForUuid(TermNodeDto node) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void setTreeDtoForUuid(TermTreeDto tree) {
+        // TODO Auto-generated method stub
+
+    }
+
 }