Merge branch 'hotfix/5.18.2'
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / descriptiveDataSet / matrix / CharacterMatrixPart.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.descriptiveDataSet.matrix;
10
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.UUID;
18 import java.util.stream.Collectors;
19
20 import javax.annotation.PostConstruct;
21 import javax.annotation.PreDestroy;
22 import javax.inject.Inject;
23
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.e4.core.contexts.ContextInjectionFactory;
26 import org.eclipse.e4.core.contexts.IEclipseContext;
27 import org.eclipse.e4.core.services.events.IEventBroker;
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.model.application.ui.basic.MPart;
32 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
33 import org.eclipse.jface.viewers.IStructuredSelection;
34 import org.eclipse.nebula.widgets.nattable.NatTable;
35 import org.eclipse.swt.SWT;
36 import org.eclipse.swt.custom.StackLayout;
37 import org.eclipse.swt.widgets.Composite;
38 import org.eclipse.swt.widgets.Label;
39
40 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
41 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
42 import eu.etaxonomy.cdm.api.service.DeleteResult;
43 import eu.etaxonomy.cdm.api.service.IDescriptionService;
44 import eu.etaxonomy.cdm.api.service.IDescriptiveDataSetService;
45 import eu.etaxonomy.cdm.api.service.UpdateResult;
46 import eu.etaxonomy.cdm.api.service.config.RemoveDescriptionsFromDescriptiveDataSetConfigurator;
47 import eu.etaxonomy.cdm.api.service.dto.DescriptionBaseDto;
48 import eu.etaxonomy.cdm.api.service.dto.RowWrapperDTO;
49 import eu.etaxonomy.cdm.api.service.dto.SpecimenRowWrapperDTO;
50 import eu.etaxonomy.cdm.model.common.CdmBase;
51 import eu.etaxonomy.cdm.model.description.DescriptionBase;
52 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
53 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
54 import eu.etaxonomy.cdm.model.term.TermType;
55 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
56 import eu.etaxonomy.taxeditor.editor.internal.TaxeditorEditorPlugin;
57 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
58 import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
59 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
60 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
61 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
62 import eu.etaxonomy.taxeditor.model.MessagingUtils;
63 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
64 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
65 import eu.etaxonomy.taxeditor.store.CdmStore;
66 import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
67
68 /**
69 * Character matrix editor for editing specimen/taxon descriptions in a table
70 * @author pplitzner
71 * @since Nov 26, 2017
72 *
73 */
74 public class CharacterMatrixPart implements IE4SavablePart, IConversationEnabled, IDirtyMarkable,
75 ICdmEntitySessionEnabled, IPartContentHasSupplementalData, IPartContentHasDetails{
76
77 private static final List<String> WS_PROPERTY_PATH = Arrays.asList(new String[] {
78 "descriptions", //$NON-NLS-1$
79 "descriptions.describedSpecimenOrObservation", //$NON-NLS-1$
80 "descriptions.describedSpecimenOrObservation.gatheringEvent", //$NON-NLS-1$
81 "descriptions.describedSpecimenOrObservation.gatheringEvent.actor", //$NON-NLS-1$
82 "descriptions.descriptionElements", //$NON-NLS-1$
83 "descriptions.descriptionElements.stateData", //$NON-NLS-1$
84 "descriptions.descriptionElements.stateData.state", //$NON-NLS-1$
85 "descriptions.descriptionElements.inDescription", //$NON-NLS-1$
86 "descriptions.descriptionElements.inDescription.descriptionElements", //$NON-NLS-1$
87 "descriptions.descriptionElements.feature", //$NON-NLS-1$
88 "representations", //$NON-NLS-1$
89 "descriptiveSystem", //$NON-NLS-1$
90 "taxonSubtreeFilter", //$NON-NLS-1$
91 "taxonSubtreeFilter.parent", //$NON-NLS-1$
92 "taxonSubtreeFilter.classification", //$NON-NLS-1$
93 "taxonSubtreeFilter.taxon", //$NON-NLS-1$
94 "taxonSubtreeFilter.taxon.name", //$NON-NLS-1$
95 "taxonSubtreeFilter.taxon.name.rank", //$NON-NLS-1$
96 "geoFilter", //$NON-NLS-1$
97 "minRank", //$NON-NLS-1$
98 "maxRank", //$NON-NLS-1$
99 });
100
101 private DescriptiveDataSet descriptiveDataSet;
102
103 private ConversationHolder conversation;
104
105 private ICdmEntitySession cdmEntitySession;
106
107 @Inject
108 private ESelectionService selService;
109
110 @Inject
111 private MDirtyable dirty;
112
113 @Inject
114 private MPart thisPart;
115
116 @Inject
117 private IEventBroker eventBroker;
118
119 private CharacterMatrix matrix;
120
121 private StackLayout stackLayout;
122
123 private Label label;
124
125 @PostConstruct
126 public void create(Composite parent, IEclipseContext context) {
127 if(CdmStore.isActive() && conversation==null){
128 conversation = CdmStore.createConversation();
129 }
130 if(cdmEntitySession == null){
131 cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
132 cdmEntitySession.bind();
133 }
134 else{
135 return;
136 }
137 stackLayout = new StackLayout();
138 parent.setLayout(stackLayout);
139 matrix = new CharacterMatrix(parent, this);
140 label = new Label(parent, SWT.NONE);
141 label.setText(Messages.CharacterMatrixPart_LOADING_MATRIX);
142 stackLayout.topControl = label;
143 ContextInjectionFactory.inject(matrix, context);
144 }
145
146 public void init(UUID descriptiveDataSetUuid, boolean treeView) {
147 this.descriptiveDataSet = CdmStore.getService(IDescriptiveDataSetService.class).load(descriptiveDataSetUuid, WS_PROPERTY_PATH);
148 if(descriptiveDataSet!=null){
149 if(descriptiveDataSet.getDescriptiveSystem()==null
150 || descriptiveDataSet.getDescriptiveSystem().getTermType()==null
151 || !descriptiveDataSet.getDescriptiveSystem().getTermType().equals(TermType.Character)){
152 MessagingUtils.informationDialog(Messages.CharacterMatrixPart_COULD_NOT_OPEN, Messages.CharacterMatrixPart_COULD_NOT_OPEN_MESSAGE);
153 loadingFailed();
154 return;
155 }
156 try {
157 matrix.initDescriptiveDataSet();
158 } catch (IllegalArgumentException e) {
159 MessagingUtils.errorDialog("Error during initilization", this, "Could not load matrix", TaxeditorEditorPlugin.PLUGIN_ID, e, false);
160 loadingFailed();
161 return;
162 }
163 matrix.createTable(treeView, true, true);
164 thisPart.setLabel(descriptiveDataSet.getLabel());
165 matrix.loadDescriptions( true, true);
166 }
167 }
168
169 public IStructuredSelection getSelection(){
170 return matrix.getSelection();
171 }
172
173 public void setDirty() {
174 this.dirty.setDirty(true);
175 }
176
177 public DescriptiveDataSet getDescriptiveDataSet() {
178 return descriptiveDataSet;
179 }
180
181 public void setDescriptiveDataSet(DescriptiveDataSet dataSet) {
182 this.descriptiveDataSet = dataSet;
183 }
184
185 public NatTable getNatTable() {
186 return matrix.getNatTable();
187 }
188
189 public ESelectionService getSelectionService() {
190 return selService;
191 }
192
193 public CharacterMatrix getMatrix() {
194 return matrix;
195 }
196
197 @Persist
198 @Override
199 public void save(IProgressMonitor monitor) {
200
201
202 matrix.addSpecimensToDescriptiveDataSet();
203 //newly added descriptions should not be saved again.
204 // descriptions.removeAll(matrix.getRowsToSave().values());
205 // save edited descriptions
206 List<DescriptionBaseDto> descriptionsToMerge = matrix.getRowsToMerge().values().stream()
207 .map(row->row.getDescription())
208 .collect(Collectors.toList());
209
210 if (matrix.getDescriptionsToDelete() != null && !matrix.getDescriptionsToDelete().isEmpty()){
211 DeleteResult result = new DeleteResult();
212 for (RemoveDescriptionsFromDescriptiveDataSetConfigurator config: matrix.getDescriptionsToDelete().keySet()){
213 result.includeResult(CdmStore.getService(IDescriptiveDataSetService.class).removeDescriptions(matrix.getDescriptionsToDelete().get(config), matrix.getDescriptiveDataSet().getUuid(), config));
214 }
215 matrix.getDescriptionsToDelete().clear();
216
217 }
218
219 UpdateResult results = CdmStore.getService(IDescriptionService.class).mergeDescriptions(descriptionsToMerge, matrix.getDescriptiveDataSet().getUuid());
220 matrix.getRowsToMerge().clear();
221 conversation.commit();
222 HashMap<UUID, DescriptionBase> descriptionResults = new HashMap<>();
223 for (CdmBase result: results.getUpdatedObjects()){
224 if (result instanceof DescriptionBase){
225 descriptionResults.put(result.getUuid(), (DescriptionBase)result);
226 }
227 }
228 List<Object> updateRows = matrix.getDescriptions().stream().filter(row->descriptionResults.keySet().contains(((RowWrapperDTO)row).getDescription().getDescription().getUuid())).collect(Collectors.toList());
229 for (Object updateRow: updateRows){
230 if (updateRow instanceof SpecimenRowWrapperDTO){
231 SpecimenRowWrapperDTO dto = (SpecimenRowWrapperDTO)updateRow;
232 dto.getDescription().setDescription(descriptionResults.get(((SpecimenRowWrapperDTO) updateRow).getDescription().getDescription().getUuid()));
233 }
234 }
235 // matrix.loadDescriptions(getDescriptiveDataSet().getUuid(), false);
236 eventBroker.post(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR, null);
237 dirty.setDirty(false);
238 }
239
240 @Override
241 public boolean isDirty() {
242 return dirty.isDirty();
243 }
244
245 @Focus
246 public void setFocus(){
247 if(conversation!=null){
248 conversation.bind();
249 }
250 if(cdmEntitySession != null) {
251 cdmEntitySession.bind();
252 }
253 }
254
255 @PreDestroy
256 public void dispose(){
257 if (conversation != null) {
258 conversation.close();
259 conversation = null;
260 }
261 if(cdmEntitySession != null) {
262 cdmEntitySession.dispose();
263 cdmEntitySession = null;
264 }
265 dirty.setDirty(false);
266 }
267
268 @Override
269 public void update(CdmDataChangeMap arg0) {
270 }
271
272 @Override
273 public ConversationHolder getConversationHolder() {
274 return conversation;
275 }
276
277 @Override
278 public void changed(Object element) {
279 setDirty();
280 matrix.getNatTable().refresh();
281 }
282
283 @Override
284 public void forceDirty() {
285 setDirty();
286 }
287
288 @Override
289 public ICdmEntitySession getCdmEntitySession() {
290 return cdmEntitySession;
291 }
292
293 @Override
294 public Collection<DescriptiveDataSet> getRootEntities() {
295 return Collections.singleton(this.descriptiveDataSet);
296 }
297
298 @Override
299 public Map<Object, List<String>> getPropertyPathsMap() {
300 Map<Object, List<String>> propertyMap = new HashMap<>();
301 propertyMap.put(SpecimenOrObservationBase.class,WS_PROPERTY_PATH);
302 return propertyMap;
303 }
304
305 private void loadingFailed() {
306 label.setText(Messages.CharacterMatrixPart_LOADING_MATRIX_FAILED);
307 }
308
309 void loadingDone() {
310 stackLayout.topControl = matrix;
311 matrix.getParent().layout();
312 }
313
314 }