ref #7998 Disabled vocabulary text field
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / descriptiveDataSet / character / CharacterEditor.java
1 // $Id$
2 /**
3 * Copyright (C) 2017 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10 package eu.etaxonomy.taxeditor.editor.descriptiveDataSet.character;
11
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21
22 import javax.annotation.PostConstruct;
23 import javax.annotation.PreDestroy;
24 import javax.inject.Inject;
25
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.e4.ui.di.Focus;
28 import org.eclipse.e4.ui.di.Persist;
29 import org.eclipse.e4.ui.di.UISynchronize;
30 import org.eclipse.e4.ui.model.application.ui.MDirtyable;
31 import org.eclipse.e4.ui.services.EMenuService;
32 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
33 import org.eclipse.jface.viewers.ISelection;
34 import org.eclipse.jface.viewers.ISelectionChangedListener;
35 import org.eclipse.jface.viewers.IStructuredSelection;
36 import org.eclipse.jface.viewers.SelectionChangedEvent;
37 import org.eclipse.jface.viewers.StructuredSelection;
38 import org.eclipse.jface.viewers.TreeSelection;
39 import org.eclipse.swt.SWT;
40 import org.eclipse.swt.custom.SashForm;
41 import org.eclipse.swt.dnd.Transfer;
42 import org.eclipse.swt.events.ModifyEvent;
43 import org.eclipse.swt.events.ModifyListener;
44 import org.eclipse.swt.events.SelectionAdapter;
45 import org.eclipse.swt.events.SelectionEvent;
46 import org.eclipse.swt.layout.GridData;
47 import org.eclipse.swt.layout.GridLayout;
48 import org.eclipse.swt.widgets.Button;
49 import org.eclipse.swt.widgets.Composite;
50 import org.eclipse.swt.widgets.Display;
51 import org.eclipse.swt.widgets.Label;
52 import org.eclipse.swt.widgets.Text;
53 import org.eclipse.ui.forms.widgets.FormToolkit;
54
55 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
56 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
57 import eu.etaxonomy.cdm.api.service.IFeatureNodeService;
58 import eu.etaxonomy.cdm.api.service.IFeatureTreeService;
59 import eu.etaxonomy.cdm.api.service.ITermService;
60 import eu.etaxonomy.cdm.model.common.Representation;
61 import eu.etaxonomy.cdm.model.common.TermVocabulary;
62 import eu.etaxonomy.cdm.model.description.Character;
63 import eu.etaxonomy.cdm.model.description.FeatureNode;
64 import eu.etaxonomy.cdm.model.description.FeatureTree;
65 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
66 import eu.etaxonomy.taxeditor.editor.AppModelId;
67 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
68 import eu.etaxonomy.taxeditor.featuretree.CharacterTransfer;
69 import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
70 import eu.etaxonomy.taxeditor.featuretree.e4.FeatureNodeDragListener;
71 import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeDropAdapter;
72 import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeEditorComposite;
73 import eu.etaxonomy.taxeditor.featuretree.e4.IFeatureTreeEditor;
74 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
75 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
76 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
77 import eu.etaxonomy.taxeditor.model.ImageResources;
78 import eu.etaxonomy.taxeditor.model.MessagingUtils;
79 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
80 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
81 import eu.etaxonomy.taxeditor.store.CdmStore;
82 import eu.etaxonomy.taxeditor.ui.dialog.selection.FeatureTreeSelectionDialog;
83 import eu.etaxonomy.taxeditor.ui.dialog.selection.TermVocabularySelectionDialog;
84 import eu.etaxonomy.taxeditor.workbench.part.IE4ViewerPart;
85
86 /**
87 * Editor for combining structure and property terms to characters.
88 * @author pplitzner
89 * @date 24.05.2017
90 *
91 */
92 public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled, ISelectionChangedListener,
93 ModifyListener, IE4ViewerPart, IPartContentHasDetails, IPartContentHasSupplementalData, IDirtyMarkable {
94
95 private FeatureTreeEditorComposite characterTreeEditorComposite;
96 private FeatureTreeEditorComposite propertiesTreeEditorComposite;
97 private FeatureTreeEditorComposite structuresTreeEditorComposite;
98 private final FormToolkit formToolkit = new FormToolkit(Display.getDefault());
99
100 @Inject
101 private ESelectionService selService;
102
103 @Inject
104 private UISynchronize sync;
105
106 @Inject
107 private MDirtyable dirty;
108
109 private ConversationHolder conversation;
110
111 private ICdmEntitySession cdmEntitySession;
112 private Composite composite;
113
114 private TermVocabulary vocabulary;
115
116 public CharacterEditor() {
117 }
118
119 /**
120 * Create contents of the view part.
121 */
122 @PostConstruct
123 public void createControls(Composite parent, EMenuService menuService ) {
124 if (CdmStore.isActive()){
125 if(conversation == null){
126 conversation = CdmStore.createConversation();
127 }
128 if(cdmEntitySession!=null){
129 cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
130 }
131 }
132 else{
133 return;
134 }
135 parent.setLayout(new GridLayout(1, false));
136
137 Composite vocChooserComposite = new Composite(parent, SWT.NONE);
138 vocChooserComposite.setLayout(new GridLayout(3, false));
139 vocChooserComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false, 2, 1));
140 Label lblVocImport = new Label(vocChooserComposite, SWT.NONE);
141 lblVocImport.setText("Character vocabulary");
142 Text txtVocabulary = new Text(vocChooserComposite, SWT.NONE);
143 txtVocabulary.setEnabled(false);
144 Button btnChooseVoc = new Button(vocChooserComposite, SWT.PUSH);
145 btnChooseVoc.setImage(ImageResources.getImage(ImageResources.BROWSE_ICON));
146 btnChooseVoc.addSelectionListener(new SelectionAdapter() {
147
148 @Override
149 public void widgetSelected(SelectionEvent e) {
150 vocabulary = TermVocabularySelectionDialog.select("Select vocabulary for characters", btnChooseVoc.getShell(), null);
151 if(vocabulary!=null){
152 txtVocabulary.setText(vocabulary.getLabel());
153 }
154 }
155 });
156
157 SashForm sashForm = new SashForm(parent, SWT.NONE);
158 sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
159 formToolkit.adapt(sashForm);
160 formToolkit.paintBordersFor(sashForm);
161
162 composite = new Composite(sashForm, SWT.NONE);
163 formToolkit.adapt(composite);
164 formToolkit.paintBordersFor(composite);
165 GridLayout gl_composite = new GridLayout(1, false);
166 gl_composite.marginWidth = 0;
167 composite.setLayout(gl_composite);
168
169 structuresTreeEditorComposite = addFeatureTreeEditor(composite);
170
171 initFeatureTreeComposite(structuresTreeEditorComposite,
172 new FeatureNodeDragListener(structuresTreeEditorComposite.getViewer()), null, null, null, null);
173
174 structuresTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_STRUCTURES);
175
176 Composite composite_1 = new Composite(sashForm, SWT.NONE);
177 formToolkit.adapt(composite_1);
178 formToolkit.paintBordersFor(composite_1);
179 GridLayout gl_composite_1 = new GridLayout(1, false);
180 gl_composite_1.marginWidth = 0;
181 composite_1.setLayout(gl_composite_1);
182
183 propertiesTreeEditorComposite = addFeatureTreeEditor(composite_1);
184 initFeatureTreeComposite(propertiesTreeEditorComposite,
185
186 new CharacterDragListener(structuresTreeEditorComposite.getViewer(), propertiesTreeEditorComposite.getViewer()),
187 null,
188 new Transfer[] {CharacterTransfer.getInstance()},
189 null,
190 null
191
192 );
193 propertiesTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_PROPERTIES);
194
195 Composite composite_3 = new Composite(sashForm, SWT.NONE);
196 formToolkit.adapt(composite_3);
197 formToolkit.paintBordersFor(composite_3);
198 GridLayout gl_composite_3 = new GridLayout(2, false);
199 gl_composite_3.marginWidth = 0;
200 composite_3.setLayout(gl_composite_3);
201
202 Button btnAddCharacter = new Button(composite_3, SWT.NONE);
203 btnAddCharacter.setText(">>"); //$NON-NLS-1$
204 formToolkit.adapt(btnAddCharacter, true, true);
205 btnAddCharacter.addSelectionListener(new SelectionAdapter() {
206 @Override
207 public void widgetSelected(SelectionEvent e) {
208 if(!isVocabularySet()){
209 return;
210 }
211 ISelection structureTreeSelection = structuresTreeEditorComposite.getViewer().getSelection();
212 ISelection propertyTreeSelection = propertiesTreeEditorComposite.getViewer().getSelection();
213 if(structureTreeSelection==null || propertyTreeSelection==null || characterTreeEditorComposite.getFeatureTree()==null){
214 MessagingUtils.warningDialog(Messages.CharacterEditor_CANNOT_PERFORM_TITLE, CharacterEditor.this,
215 Messages.CharacterEditor_CANNOT_PERFORM_MESSAGE);
216 return;
217 }
218 Collection<Character> characters = createCharacters((TreeSelection)structureTreeSelection, (TreeSelection)propertyTreeSelection);
219 for (Character character : characters) {
220 //add new Character to feature tree
221 FeatureNode parent = ((FeatureTree) characterTreeEditorComposite.getViewer().getInput()).getRoot();
222 vocabulary.addTerm(character);
223 CdmStore.getService(IFeatureNodeService.class).createChildFeatureNode(parent, character);
224 }
225 characterTreeEditorComposite.getViewer().refresh();
226 }
227 });
228
229 characterTreeEditorComposite = addFeatureTreeEditor(composite_3);
230 initFeatureTreeComposite(characterTreeEditorComposite, new FeatureNodeDragListener(characterTreeEditorComposite.getViewer()),
231 new CharacterDropAdapter(this, characterTreeEditorComposite.getViewer(), sync),
232
233 new Transfer[] {FeatureNodeTransfer.getInstance(), CharacterTransfer.getInstance()},
234 this,
235 this);
236
237 characterTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_CHARACTERS);
238
239 //add context menu to character viewer
240 menuService.registerContextMenu(characterTreeEditorComposite.getViewer().getControl(),
241 AppModelId.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_EDITOR_POPUPMENU_CHARACTEREDITOR);
242
243 }
244
245 private FeatureTreeEditorComposite addFeatureTreeEditor(Composite composite_3) {
246 FeatureTreeEditorComposite featureTreeEditorComposite = new FeatureTreeEditorComposite(composite_3, SWT.NONE);
247 featureTreeEditorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
248 return featureTreeEditorComposite;
249 }
250
251 private void initFeatureTreeComposite(
252 FeatureTreeEditorComposite featureTreeEditorComposite,
253 FeatureNodeDragListener featureNodeDragListener,
254 FeatureTreeDropAdapter featureNodeDropAdapter,
255 Transfer[] transfers,
256 ISelectionChangedListener viewerSelectionChangedListener,
257 ModifyListener modifyListener) {
258
259 featureTreeEditorComposite.init(
260 featureNodeDragListener,
261 featureNodeDropAdapter,
262 transfers,
263 viewerSelectionChangedListener,
264 new FeatureTreeChooserListener(featureTreeEditorComposite),
265 modifyListener);
266 }
267
268 @Focus
269 public void focus(){
270 if(characterTreeEditorComposite!=null){
271 characterTreeEditorComposite.getViewer().getControl().setFocus();
272 }
273 if(conversation!=null && !conversation.isBound()){
274 conversation.bind();
275 }
276 if(cdmEntitySession != null) {
277 cdmEntitySession.bind();
278 }
279 }
280
281 public static Collection<Character> createCharacters(TreeSelection structureTreeSelection, TreeSelection propertyTreeSelection){
282 Set<Character> characters = new HashSet<>();
283 //get selected structures and properties
284 Iterator<FeatureNode> structureIterator = structureTreeSelection.iterator();
285
286 //create all combinations of structures and properties
287 while(structureIterator.hasNext()){
288 FeatureNode structureNode = structureIterator.next();
289 Iterator<FeatureNode> propertiesIterator = propertyTreeSelection.iterator();
290 while(propertiesIterator.hasNext()){
291 FeatureNode propertyNode = propertiesIterator.next();
292 Representation structureRepresentation = structureNode.getFeature().getRepresentation(PreferencesUtil.getGlobalLanguage());
293 Representation propertyRepresentation = propertyNode.getFeature().getRepresentation(PreferencesUtil.getGlobalLanguage());
294 String label = null;
295 String abbrevLabel = null;
296 if(structureRepresentation.getLabel()!=null && propertyRepresentation.getLabel()!=null){
297 label = structureRepresentation.getLabel()+" "+propertyRepresentation.getLabel();
298 }
299 if(structureRepresentation.getAbbreviatedLabel()!=null && propertyRepresentation.getAbbreviatedLabel()!=null){
300 abbrevLabel = structureRepresentation.getAbbreviatedLabel()+" "+propertyRepresentation.getAbbreviatedLabel();
301 }
302 //create new Character
303 Character character = Character.NewInstance(structureNode, propertyNode, null, label, abbrevLabel);
304 characters.add(character);
305 }
306 }
307 return characters;
308 }
309
310 @Override
311 @Persist
312 public void save(IProgressMonitor monitor){
313 if (!conversation.isBound()) {
314 conversation.bind();
315 }
316
317 // commit the conversation and start a new transaction immediately
318 conversation.commit(true);
319
320 FeatureTree featureTree = characterTreeEditorComposite.getFeatureTree();
321 if(featureTree!=null){
322 //save characters because they can be modified in this editor
323 featureTree.getDistinctFeatures().forEach(character->CdmStore.getService(ITermService.class).merge(character,true));
324 }
325 CdmStore.getService(IFeatureTreeService.class).saveOrUpdate(featureTree);
326
327
328 dirty.setDirty(false);
329 }
330
331 @Override
332 public boolean isDirty() {
333 return dirty.isDirty();
334 }
335
336 @PreDestroy
337 public void dispose(){
338 if(conversation!=null){
339 conversation.close();
340 conversation = null;
341 }
342 if(cdmEntitySession != null) {
343 cdmEntitySession.dispose();
344 cdmEntitySession = null;
345 }
346 dirty.setDirty(false);
347 }
348
349 public boolean isVocabularySet() {
350 if(vocabulary==null){
351 MessagingUtils.warningDialog("Character creation not possible", this.getClass(), "Please select a vocabulary for the characters.");
352 }
353 return vocabulary!=null;
354 }
355
356 public TermVocabulary getVocabulary() {
357 return vocabulary;
358 }
359
360 @Override
361 public Map<Object, List<String>> getPropertyPathsMap() {
362 List<String> propertyPaths = Arrays.asList(new String[] {
363 "children", //$NON-NLS-1$
364 "feature", //$NON-NLS-1$
365 "featureTree", //$NON-NLS-1$
366 });
367 Map<Object, List<String>> propertyPathMap =
368 new HashMap<Object, List<String>>();
369 propertyPathMap.put(FeatureNode.class,propertyPaths);
370 return propertyPathMap;
371 }
372
373 @Override
374 public List<FeatureTree> getRootEntities() {
375 List<FeatureTree> root = new ArrayList<>();
376 root.add(characterTreeEditorComposite.getFeatureTree());
377 return root;
378 }
379
380 @Override
381 public ICdmEntitySession getCdmEntitySession() {
382 return cdmEntitySession;
383 }
384
385 @Focus
386 public void setFocus() {
387 if(conversation!=null && !conversation.isBound()){
388 conversation.bind();
389 }
390 }
391
392 @Override
393 public void selectionChanged(SelectionChangedEvent event) {
394 //propagate selection
395 selService.setSelection(event.getSelection());
396 }
397
398
399 @Override
400 public void modifyText(ModifyEvent e) {
401 characterTreeEditorComposite.getFeatureTree().setTitleCache(((Text) e.widget).getText(), true);
402 setDirty();
403 }
404
405
406 private void setDirty() {
407 dirty.setDirty(true);
408 }
409
410 @Override
411 public IStructuredSelection getSelection() {
412 return (IStructuredSelection) characterTreeEditorComposite.getViewer().getSelection();
413 }
414
415 public FeatureTree getCharacterTree(){
416 return characterTreeEditorComposite.getFeatureTree();
417 }
418
419 @Override
420 public void refresh(){
421 structuresTreeEditorComposite.getViewer().refresh();
422 propertiesTreeEditorComposite.getViewer().refresh();
423 characterTreeEditorComposite.getViewer().refresh();
424 }
425
426 private class FeatureTreeChooserListener extends SelectionAdapter{
427 FeatureTreeEditorComposite featureTreeEditorComposite;
428
429 public FeatureTreeChooserListener(FeatureTreeEditorComposite featureTreeEditorComposite) {
430 super();
431 this.featureTreeEditorComposite = featureTreeEditorComposite;
432 }
433
434 @Override
435 public void widgetSelected(SelectionEvent e) {
436 FeatureTree tree = FeatureTreeSelectionDialog.select(featureTreeEditorComposite.getDisplay().getActiveShell(), //conversation,
437 null);
438 if(tree!=null){
439 featureTreeEditorComposite.setSelectedTree(tree);
440 featureTreeEditorComposite.getText_title().setEnabled(false);
441 }
442 }
443 }
444
445 @Override
446 public void update(CdmDataChangeMap arg0) {
447 }
448
449 @Override
450 public ConversationHolder getConversationHolder() {
451 return conversation;
452 }
453
454 @Override
455 public void changed(Object element) {
456 setDirty();
457 }
458
459 @Override
460 public void forceDirty() {
461 setDirty();
462 }
463
464 @Override
465 public boolean postOperation(Object objectAffectedByOperation) {
466 characterTreeEditorComposite.getViewer().refresh();
467 if(objectAffectedByOperation instanceof FeatureNode){
468 StructuredSelection selection = new StructuredSelection(objectAffectedByOperation);
469 characterTreeEditorComposite.getViewer().setSelection(selection);
470 }
471 return true;
472 }
473
474 @Override
475 public boolean onComplete() {
476 return false;
477 }
478
479 }