ref #7086 Fix focus problem when saving
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / workingSet / WorkingSetEditor.java
1 /**
2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.taxeditor.editor.workingSet;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.UUID;
19
20 import javax.annotation.PostConstruct;
21 import javax.annotation.PreDestroy;
22 import javax.inject.Inject;
23 import javax.inject.Named;
24
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.e4.core.contexts.ContextInjectionFactory;
27 import org.eclipse.e4.core.contexts.IEclipseContext;
28 import org.eclipse.e4.ui.di.Focus;
29 import org.eclipse.e4.ui.di.Persist;
30 import org.eclipse.e4.ui.model.application.ui.MDirtyable;
31 import org.eclipse.e4.ui.services.IServiceConstants;
32 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
33 import org.eclipse.jface.util.LocalSelectionTransfer;
34 import org.eclipse.jface.viewers.IStructuredSelection;
35 import org.eclipse.jface.viewers.Viewer;
36 import org.eclipse.swt.SWT;
37 import org.eclipse.swt.dnd.DND;
38 import org.eclipse.swt.dnd.Transfer;
39 import org.eclipse.swt.events.KeyAdapter;
40 import org.eclipse.swt.events.KeyEvent;
41 import org.eclipse.swt.events.ModifyEvent;
42 import org.eclipse.swt.events.ModifyListener;
43 import org.eclipse.swt.events.SelectionAdapter;
44 import org.eclipse.swt.widgets.Composite;
45 import org.eclipse.swt.widgets.Display;
46 import org.eclipse.swt.widgets.Shell;
47
48 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
49 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
50 import eu.etaxonomy.cdm.api.service.ITermService;
51 import eu.etaxonomy.cdm.api.service.IWorkingSetService;
52 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
53 import eu.etaxonomy.cdm.model.description.FeatureTree;
54 import eu.etaxonomy.cdm.model.description.WorkingSet;
55 import eu.etaxonomy.cdm.model.location.NamedArea;
56 import eu.etaxonomy.cdm.model.name.Rank;
57 import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
58 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
59 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
60 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
61 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
62 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
63 import eu.etaxonomy.taxeditor.model.MessagingUtils;
64 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
65 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
66 import eu.etaxonomy.taxeditor.store.CdmStore;
67 import eu.etaxonomy.taxeditor.ui.dialog.selection.NamedAreaSelectionDialog;
68 import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
69 import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
70
71 /**
72 * Editor for configuring WorkingSets
73 * @author pplitzner
74 * @since Nov 21, 2017
75 *
76 */
77 public class WorkingSetEditor implements IE4SavablePart, IConversationEnabled, ICdmEntitySessionEnabled,
78 IPartContentHasDetails, IDirtyMarkable {
79
80 private WorkingSetComposite composite;
81
82 private ConversationHolder conversation;
83
84 private ICdmEntitySession cdmEntitySession;
85
86 private WorkingSet workingSet;
87
88 private final int dndOperations = DND.DROP_MOVE;
89
90 @Inject
91 private MDirtyable dirty;
92
93 @Inject
94 private ESelectionService selectionService;
95
96 private ModifyListener labelModifyListener;
97
98 @PostConstruct
99 public void create(Composite parent, IEclipseContext context, @Named(IServiceConstants.ACTIVE_SHELL)Shell shell){
100 if (CdmStore.isActive()){
101 if(conversation == null){
102 conversation = CdmStore.createConversation();
103 }
104 if(cdmEntitySession == null){
105 cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
106 }
107 }
108 else{
109 return;
110 }
111 CdmFormFactory cdmFormFactory = new CdmFormFactory(Display.getCurrent());
112 ContextInjectionFactory.inject(cdmFormFactory, context);
113
114 composite = new WorkingSetComposite(parent, SWT.NONE);
115
116 labelModifyListener = new ModifyListener() {
117 @Override
118 public void modifyText(ModifyEvent e) {
119 workingSet.setLabel(composite.getTxt_label().getText());
120 dirty.setDirty(true);
121 }
122 };
123 composite.getRankMin().addSelectionChangedListener(event->dirty.setDirty(true));
124 composite.getRankMax().addSelectionChangedListener(event->dirty.setDirty(true));
125
126 composite.getBtnChooseArea().addSelectionListener(new SelectionAdapter() {
127
128 @Override
129 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
130 NamedArea area = NamedAreaSelectionDialog.select(shell, null, null);
131 if(area!=null){
132 composite.setArea(area);
133 }
134 dirty.setDirty(true);
135 }
136 });
137 composite.getBtnRemoveArea().addSelectionListener(new SelectionAdapter() {
138
139 @Override
140 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
141 composite.removeArea();
142 dirty.setDirty(true);
143 }
144 });
145
146 composite.getFeatureTreeEditorComposite().init(null, null, e->selectionService.setSelection(e.getSelection()), null, null);
147
148 //add drag'n'drop support
149 Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer()};
150 composite.getTaxonNodeTree().addDropSupport(dndOperations, transfers, new TaxonNodeDropAdapter(this));
151
152 composite.getTaxonNodeTree().getTree().addKeyListener(new KeyAdapter() {
153 @Override
154 public void keyPressed(KeyEvent e) {
155 if(e.character==SWT.DEL){
156 IStructuredSelection selection = (IStructuredSelection) composite.getTaxonNodeTree().getSelection();
157 if(selection.toList().stream().anyMatch(object->!(object instanceof TaxonNode))){
158 MessagingUtils.warningDialog(Messages.WorkingSetEditor_DELETE_FAIL_TITLE, this.getClass(), Messages.WorkingSetEditor_DELETE_FAIL_MESSAGE);
159 return;
160 }
161 Iterator<Object> iterator = selection.iterator();
162 while(iterator.hasNext()){
163 Object next = iterator.next();
164 TaxonNode taxonNode = (TaxonNode) next;
165 removeTaxonNode(taxonNode);
166 }
167 }
168 }
169 });
170
171 }
172
173 public void init(UUID workingSetUuid) {
174 this.workingSet = CdmStore.getService(IWorkingSetService.class).load(workingSetUuid);
175 if(workingSet.getLabel()!=null){
176 composite.getTxt_label().setText(workingSet.getLabel());
177 }
178 if(workingSet.getDescriptiveSystem()!=null){
179 composite.setCharacters(workingSet.getDescriptiveSystem());
180 }
181 Rank maxRank = workingSet.getMaxRank();
182 if(maxRank!=null){
183 composite.setRankMax(maxRank);
184 }
185 Rank minRank = workingSet.getMinRank();
186 if(minRank!=null){
187 composite.setRankMin(minRank);
188 }
189 Set<NamedArea> geoFilter = workingSet.getGeoFilter();
190 if(geoFilter!=null && !geoFilter.isEmpty()){
191 composite.setArea(geoFilter.iterator().next());
192 }
193 Set<TaxonNode> taxonSubtreeFilter = workingSet.getTaxonSubtreeFilter();
194 if(taxonSubtreeFilter!=null){
195 composite.getTaxonNodeTree().setInput(taxonSubtreeFilter);
196 }
197
198 composite.getTxt_label().addModifyListener(labelModifyListener);
199 }
200
201 public void addTaxonNode(TaxonNode taxonNode){
202 //load into WS editor session
203 taxonNode = getCdmEntitySession().load(taxonNode, false);
204 Viewer taxonTreeViewer = getTaxonTreeViewer();
205 Object input = taxonTreeViewer.getInput();
206 Collection<TaxonNode> treeNodes;
207 if(input==null){
208 treeNodes = new ArrayList<>();
209 }
210 else{
211 treeNodes = (Collection<TaxonNode>) input;
212 }
213 treeNodes.add(taxonNode);
214 taxonTreeViewer.setInput(treeNodes);
215 dirty.setDirty(true);
216 }
217
218 private void removeTaxonNode(TaxonNode taxonNode){
219 Viewer taxonTreeViewer = getTaxonTreeViewer();
220 Collection<TaxonNode> input = (Collection<TaxonNode>) taxonTreeViewer.getInput();
221 input.remove(taxonNode);
222 workingSet.removeTaxonSubtree(taxonNode);
223 taxonTreeViewer.setInput(input);
224 dirty.setDirty(true);
225 }
226
227 @Persist
228 @Override
229 public void save(IProgressMonitor monitor) {
230 NamedArea area = composite.getArea();
231 Set<NamedArea> areas = new HashSet<>();
232 if(area!=null){
233 areas.add(area);
234 }
235 Object input = composite.getTaxonNodeTree().getInput();
236 if(input!=null){
237 workingSet.setTaxonSubtreeFilter(new HashSet<>());//clear existing filter
238 Collection<ITaxonTreeNode> taxonNodes = (Collection<ITaxonTreeNode>) input;
239 for (ITaxonTreeNode taxonTreeNode : taxonNodes) {
240 if(taxonTreeNode instanceof TaxonNode){
241 TaxonNode taxonNode = (TaxonNode)taxonTreeNode;
242 workingSet.addTaxonSubtree(taxonNode);
243 }
244 }
245 }
246 FeatureTree characters = composite.getCharacters();
247 if(characters!=null){
248 //save characters because they can be modified in this editor
249 characters.getDistinctFeatures().forEach(character->CdmStore.getService(ITermService.class).merge(character,true));
250 }
251
252
253 DefinedTermBase rankMaxSelection = composite.getRankMax().getSelection();
254 Rank rankMax = null;
255 if(rankMaxSelection instanceof Rank){
256 rankMax = (Rank) rankMaxSelection;
257 }
258 DefinedTermBase rankMinSelection = composite.getRankMin().getSelection();
259 Rank rankMin = null;
260 if(rankMinSelection instanceof Rank){
261 rankMin = (Rank) rankMinSelection;
262 }
263
264 workingSet.setMaxRank(rankMax);
265 workingSet.setMinRank(rankMin);
266 workingSet.setDescriptiveSystem(characters);
267 workingSet.setGeoFilter(areas);
268
269 conversation.commit();
270 CdmStore.getService(IWorkingSetService.class).merge(workingSet, true);
271
272 dirty.setDirty(false);
273 }
274
275 @PreDestroy
276 public void dispose() {
277 if (conversation != null) {
278 conversation.close();
279 conversation = null;
280 }
281 if(cdmEntitySession != null) {
282 cdmEntitySession.dispose();
283 cdmEntitySession = null;
284 }
285 dirty.setDirty(false);
286 }
287
288 @Focus
289 public void setFocus() {
290 if(composite!=null){
291 composite.setFocus();
292 }
293 if (getConversationHolder() != null) {
294 getConversationHolder().bind();
295 }
296 if(cdmEntitySession != null) {
297 cdmEntitySession.bind();
298 }
299 }
300
301 public Viewer getTaxonTreeViewer() {
302 return composite.getTaxonNodeTree();
303 }
304
305 public WorkingSet getWorkingSet() {
306 return workingSet;
307 }
308
309 @Override
310 public void update(CdmDataChangeMap arg0) {
311 }
312
313 @Override
314 public ICdmEntitySession getCdmEntitySession() {
315 return cdmEntitySession;
316 }
317
318 @Override
319 public Collection<WorkingSet> getRootEntities() {
320 return null;
321 }
322
323 @Override
324 public Map<Object, List<String>> getPropertyPathsMap() {
325 return null;
326 }
327
328 @Override
329 public ConversationHolder getConversationHolder() {
330 return conversation;
331 }
332
333 @Override
334 public void changed(Object element) {
335 dirty.setDirty(true);
336 }
337
338 @Override
339 public void forceDirty() {
340 dirty.setDirty(true);
341 }
342
343 }