ref #8228: fix NPE
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / view / e4 / AbstractCdmEditorPartE4.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.view.e4;
10
11 import java.util.Set;
12
13 import javax.annotation.PreDestroy;
14 import javax.inject.Inject;
15 import javax.inject.Named;
16
17 import org.apache.log4j.Logger;
18 import org.eclipse.e4.core.contexts.IEclipseContext;
19 import org.eclipse.e4.core.di.annotations.Optional;
20 import org.eclipse.e4.ui.di.PersistState;
21 import org.eclipse.e4.ui.di.UISynchronize;
22 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
23 import org.eclipse.e4.ui.services.IServiceConstants;
24 import org.eclipse.e4.ui.workbench.modeling.EPartService;
25 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
26 import org.eclipse.jface.viewers.ISelectionChangedListener;
27 import org.eclipse.jface.viewers.IStructuredSelection;
28 import org.eclipse.jface.viewers.StructuredSelection;
29 import org.eclipse.jface.viewers.Viewer;
30 import org.eclipse.swt.SWTException;
31
32 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
33 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
34 import eu.etaxonomy.cdm.api.service.ITermService;
35 import eu.etaxonomy.cdm.api.service.IVocabularyService;
36 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
37 import eu.etaxonomy.cdm.model.name.TaxonName;
38 import eu.etaxonomy.cdm.model.taxon.Taxon;
39 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
40 import eu.etaxonomy.cdm.persistence.dto.TermDto;
41 import eu.etaxonomy.cdm.persistence.dto.TermVocabularyDto;
42 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
43 import eu.etaxonomy.taxeditor.editor.ITaxonEditor;
44 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
45 import eu.etaxonomy.taxeditor.model.MessagingUtils;
46 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
47 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
48 import eu.etaxonomy.taxeditor.store.CdmStore;
49 import eu.etaxonomy.taxeditor.view.e4.details.DetailsPartE4;
50 import eu.etaxonomy.taxeditor.view.e4.details.DetailsViewerE4;
51 import eu.etaxonomy.taxeditor.workbench.WorkbenchUtility;
52 import eu.etaxonomy.taxeditor.workbench.part.ISelectionElementEditingPart;
53
54 /**
55 * @author pplitzner
56 * @since Aug 10, 2017
57 *
58 */
59 public abstract class AbstractCdmEditorPartE4
60 implements IConversationEnabled, IDirtyMarkable, ISelectionElementEditingPart, IPostOperationEnabled{
61
62 private DelaySelection delaySelection = null;
63 /**
64 * This is the monitor for the DelaySelection runnable.
65 * If it is <code>true</code> then it is currently delaying a selection.
66 */
67 private boolean isInDelay;
68 private static final Logger logger = Logger.getLogger(AbstractCdmEditorPartE4.class);
69
70 /**
71 * This class invokes internal_selectionChanged() in a separate thread.
72 * This allows an asynchronous and/or delayed handling of selection changes
73 */
74 private class DelaySelection implements Runnable{
75 private Object selection;
76 private MPart activePart;
77 private MPart thisPart;
78
79 public DelaySelection(Object selection, MPart activePart, MPart thisPart) {
80 super();
81 this.selection = selection;
82 this.activePart= activePart;
83 this.thisPart = thisPart;
84 }
85
86 @Override
87 public void run() {
88 try{
89 selectionChanged_internal(selection, activePart, thisPart);
90 }
91 finally{
92 isInDelay = false;
93 }
94 }
95
96 public synchronized void setSelection(Object selection) {
97 this.selection = selection;
98 }
99
100 public synchronized void setActivePart(MPart activePart) {
101 this.activePart = activePart;
102 }
103
104 public synchronized void setThisPart(MPart thisPart) {
105 this.thisPart = thisPart;
106 }
107
108 }
109
110 protected Viewer viewer;
111
112 protected MPart thisPart;
113
114 protected MPart selectionProvidingPart;
115
116 protected Object previousSelection;
117
118 protected ISelectionChangedListener selectionChangedListener;
119
120 public ISelectionChangedListener getSelectionChangedListener() {
121 return selectionChangedListener;
122 }
123
124 @Inject
125 protected ESelectionService selService;
126
127 @Inject
128 protected IEclipseContext context;
129
130 protected abstract void selectionChanged_internal(Object selection, MPart activePart, MPart thisPart);
131
132 @Inject
133 public void selectionChanged(
134 @Optional@Named(IServiceConstants.ACTIVE_SELECTION)Object selection,
135 @Optional@Named(IServiceConstants.ACTIVE_PART)MPart activePart,
136 MPart thisPart, UISynchronize sync, EPartService partService){
137 //multiple selections are not supported
138 if(activePart!=null
139 && thisPart!=null
140 && !activePart.equals(thisPart)
141 && selection instanceof IStructuredSelection
142 && ((IStructuredSelection) selection).size()>1){
143 showEmptyPage();
144 return;
145 }
146 // no active editor found
147 if(activePart==thisPart && WorkbenchUtility.getActiveEditorPart(partService)==null){
148 showEmptyPage();
149 return;
150 }
151 if (viewer != null && viewer.getControl()!= null && viewer.getInput() != null && !viewer.getControl().isDisposed()){
152 try{
153 viewer.getControl().setEnabled(true);
154 }catch(SWTException e){
155 logger.debug("Something went wrong for viewer.getControl().setEnabled(true) in " + this.getClass().getSimpleName(), e);
156 }
157
158 }
159
160 if((previousSelection!=null && selection!=null) && (activePart != null && selectionProvidingPart != null && activePart.equals(selectionProvidingPart)) &&
161 (previousSelection==selection
162 || previousSelection.equals(selection)
163 || new StructuredSelection(selection).equals(previousSelection))
164 ) {
165 return;
166 }
167 if(delaySelection==null){
168 delaySelection = new DelaySelection(selection, activePart, thisPart);
169 }
170 delaySelection.setSelection(selection);
171 delaySelection.setActivePart(activePart);
172 delaySelection.setThisPart(thisPart);
173 if(!isInDelay){
174 isInDelay = true;
175 sync.asyncExec(delaySelection);
176 previousSelection = selection;
177 }
178 }
179
180 /** {@inheritDoc} */
181 @Override
182 public void changed(Object object) {
183 if(selectionProvidingPart!=null){
184 Object part = selectionProvidingPart.getObject();
185 if(part instanceof IDirtyMarkable){
186 ((IDirtyMarkable) part).changed(object);
187 }
188 }
189 }
190
191 public Viewer getViewer() {
192 return viewer;
193 }
194
195 protected void showViewer(IStructuredSelection selection, MPart activePart, Viewer viewer){
196 if(viewer!=null && viewer.getControl()!=null && !viewer.getControl().isDisposed()){
197 Object element = selection.getFirstElement();
198 Object part = createPartObject(activePart);
199 viewer.getControl().setEnabled(true);
200 if(selection.getFirstElement()!=null){
201 if (element instanceof Taxon){
202 Taxon taxon = HibernateProxyHelper.deproxy(element, Taxon.class);
203 if (taxon.isMisapplication() || taxon.isProparteSynonym() || taxon.isInvalidDesignation()){
204
205 if(part instanceof ITaxonEditor){
206 Taxon accepted = ((ITaxonEditor) part).getTaxon();
207 Set<TaxonRelationship> rels = taxon.getTaxonRelations(accepted);
208
209 if (rels != null && rels.iterator().hasNext() && !taxon.equals(accepted)){
210 TaxonRelationship rel = rels.iterator().next();
211 if ((rel.getType().isMisappliedNameOrInvalidDesignation() || rel.getType().isAnySynonym()) && !rel.getFromTaxon().equals(((ITaxonEditor) part).getTaxon())){
212 viewer.setInput(rel);
213 selectionProvidingPart = activePart;
214 return;
215 }
216 }
217 }
218
219
220 }
221 }
222 //unwrap term DTOs
223 if(element instanceof TermDto){
224 element = CdmStore.getService(ITermService.class).load(((TermDto) element).getUuid());
225 }
226 else if(element instanceof TermVocabularyDto){
227 element = CdmStore.getService(IVocabularyService.class).load(((TermVocabularyDto) element).getUuid());
228 }
229
230 selectionProvidingPart = activePart;
231 if (viewer instanceof DetailsViewerE4){
232 ((DetailsViewerE4)viewer).setInput(element, part);
233 ((DetailsViewerE4)viewer).setDetailsEnabled(true);
234
235 }
236
237 else{
238 if (activePart.getObject() instanceof DetailsPartE4 && element instanceof TaxonName){
239 selectionProvidingPart = ((DetailsPartE4)activePart.getObject()).getSelectionProvidingPart();
240 }
241 viewer.setInput(element);
242 }
243 }
244 }
245 }
246
247 protected Object createPartObject(MPart activePart) {
248 Object partObject = activePart;
249 Object wrappedPart = WorkbenchUtility.getE4WrappedPart(activePart);
250 if(wrappedPart!=null){
251 partObject = wrappedPart;
252 }
253 return partObject;
254 }
255
256 protected void showEmptyPage() {
257 if(viewer!=null && viewer.getControl()!=null && !viewer.getControl().isDisposed() ){
258 viewer.setInput(null);
259 try{
260 if (!viewer.getControl().isDisposed()){
261 viewer.getControl().setEnabled(false);
262 }
263 }catch(SWTException e){
264 if (PreferencesUtil.isShowUpWidgetIsDisposedMessages() && e.getMessage().equals("Widget is disposed")){
265 MessagingUtils.errorDialog("Widget is disposed",
266 null,
267 MessagingUtils.WIDGET_IS_DISPOSED_MESSAGE,
268 null,
269 e,
270 true);
271
272 }
273 }
274
275 }
276 reset();
277 if(thisPart!=null){
278 thisPart.setLabel(getViewName());
279 }
280 }
281
282 protected IStructuredSelection createSelection(Object selection) {
283 if(selection==null){
284 return null;
285 }
286 IStructuredSelection structuredSelection;
287 if(!(selection instanceof IStructuredSelection)){
288 structuredSelection = new StructuredSelection(selection);
289 }
290 else{
291 structuredSelection = (IStructuredSelection) selection;
292 }
293 return structuredSelection;
294 }
295
296 /**
297 * {@inheritDoc}
298 */
299 @Override
300 public ConversationHolder getConversationHolder() {
301 if(selectionProvidingPart != null && selectionProvidingPart instanceof IConversationEnabled) {
302 return ((IConversationEnabled) selectionProvidingPart).getConversationHolder();
303 }
304 return null;
305 }
306
307 /**
308 * {@inheritDoc}
309 */
310 @Override
311 public boolean postOperation(Object objectAffectedByOperation) {
312 changed(objectAffectedByOperation);
313 return true;
314 }
315
316 /**
317 * {@inheritDoc}
318 */
319 @Override
320 public boolean onComplete() {
321 viewer.refresh();
322 return true;
323 }
324
325 /**
326 * {@inheritDoc}
327 */
328 @Override
329 public MPart getSelectionProvidingPart() {
330 return selectionProvidingPart;
331 }
332
333 @PreDestroy
334 private void dispose() {
335 }
336
337 private void reset(){
338 previousSelection = null;
339 selectionProvidingPart = null;
340 delaySelection = null;
341 context.deactivate();
342 }
343
344 @PersistState
345 private void persistState(){
346
347 }
348
349 /**
350 * {@inheritDoc}
351 */
352 @Override
353 public void update(CdmDataChangeMap arg0) {
354 }
355
356 /**
357 * {@inheritDoc}
358 */
359 @Override
360 public void forceDirty() {
361 }
362
363 protected abstract String getViewName();
364
365 }