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