Project

General

Profile

Download (16 KB) Statistics
| Branch: | Tag: | Revision:
1
package eu.etaxonomy.taxeditor.editor.view.derivate;
2

    
3
import java.util.ArrayList;
4
import java.util.Arrays;
5
import java.util.Collection;
6
import java.util.HashMap;
7
import java.util.HashSet;
8
import java.util.List;
9
import java.util.Map;
10
import java.util.Map.Entry;
11
import java.util.Set;
12
import java.util.UUID;
13

    
14
import org.eclipse.core.runtime.IProgressMonitor;
15
import org.eclipse.jface.action.MenuManager;
16
import org.eclipse.jface.util.LocalSelectionTransfer;
17
import org.eclipse.jface.viewers.AbstractTreeViewer;
18
import org.eclipse.jface.viewers.ISelection;
19
import org.eclipse.jface.viewers.IStructuredSelection;
20
import org.eclipse.jface.viewers.StructuredSelection;
21
import org.eclipse.jface.viewers.TreeNode;
22
import org.eclipse.jface.viewers.TreeSelection;
23
import org.eclipse.jface.viewers.TreeViewer;
24
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.dnd.DND;
26
import org.eclipse.swt.dnd.Transfer;
27
import org.eclipse.swt.layout.GridData;
28
import org.eclipse.swt.layout.GridLayout;
29
import org.eclipse.swt.widgets.Composite;
30
import org.eclipse.swt.widgets.Control;
31
import org.eclipse.swt.widgets.Menu;
32
import org.eclipse.swt.widgets.Tree;
33
import org.eclipse.ui.IEditorPart;
34
import org.eclipse.ui.ISaveablePart2;
35
import org.eclipse.ui.IWorkbenchPart;
36

    
37
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
38
import eu.etaxonomy.cdm.api.service.IOccurrenceService;
39
import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
40
import eu.etaxonomy.cdm.model.common.CdmBase;
41
import eu.etaxonomy.cdm.model.molecular.Sequence;
42
import eu.etaxonomy.cdm.model.molecular.SingleRead;
43
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
44
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
45
import eu.etaxonomy.cdm.model.taxon.Taxon;
46
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
47
import eu.etaxonomy.taxeditor.editor.EditorUtil;
48
import eu.etaxonomy.taxeditor.editor.Messages;
49
import eu.etaxonomy.taxeditor.editor.view.derivate.searchFilter.DerivateSearchCompositeController;
50
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
51
import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
52
import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
53
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
54
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
55
import eu.etaxonomy.taxeditor.store.CdmStore;
56
import eu.etaxonomy.taxeditor.view.AbstractCdmViewPart;
57
import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateContentProvider;
58
import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateLabelProvider;
59

    
60
/**
61
 * Displays the derivate hierarchy of the specimen specified in the editor input.
62
 *
63
 */
64
public class DerivateView extends AbstractCdmViewPart implements IPartContentHasFactualData, ISaveablePart2,
65
        IPartContentHasDetails, IPartContentHasSupplementalData, IPartContentHasMedia {
66
    public static final String ID = "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView"; //$NON-NLS-1$
67

    
68
    public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION = Messages.DerivateView_YOU_NEED_TO_SAVE;
69
    public static final String VIEW_HAS_UNSAVED_CHANGES = Messages.DerivateView_UNSAVED_CHANGES;
70

    
71
    private static final List<String> SPECIMEN_INIT_STRATEGY = Arrays.asList(new String[] {
72
            "descriptions",
73
            "annotations",
74
            "markers",
75
            "credits",
76
            "extensions",
77
            "rights",
78
            "sources",
79
            "derivationEvents.derivatives.annotations",
80
            "derivationEvents.derivatives.markers",
81
            "derivationEvents.derivatives.credits",
82
            "derivationEvents.derivatives.extensions",
83
            "derivationEvents.derivatives.rights",
84
            "derivationEvents.derivatives.sources"
85
    });
86

    
87
	private ConversationHolder conversation;
88

    
89
	private TreeViewer viewer;
90

    
91
    private boolean isDirty;
92

    
93
    private final int dndOperations = DND.DROP_MOVE;
94

    
95
    private DerivateLabelProvider labelProvider;
96

    
97
    private Set<SingleRead> multiLinkSingleReads;
98

    
99
    private ISelection selection = null;
100

    
101

    
102
    private DerivateContentProvider contentProvider;
103

    
104
    private DerivateSearchCompositeController derivateSearchCompositeController;
105

    
106
    /**
107
     * A map with keys being the derivative entities belonging to the {@link UUID}s passed to the constructor
108
     * and values being the root elements of the hierarchy (may be the same objects as the derivative entities)
109
     */
110
    private Map<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>> derivateToRootEntityMap;
111

    
112
    /**
113
     * The set of root elements
114
     */
115
    private Set<SpecimenOrObservationBase<?>> rootElements;
116

    
117
    private ICdmEntitySession cdmEntitySession;
118

    
119
    /**
120
     * <code>true</code> if this view is listening to selection  changes
121
     */
122
    private boolean listenToSelectionChange;
123

    
124
    /**
125
     * Default constructor
126
     */
127
    public DerivateView() {
128
        this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
129
        this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
130

    
131
        if (CdmStore.isActive() && conversation == null) {
132
            conversation = CdmStore.createConversation();
133
        }
134
        if (CdmStore.isActive()) {
135
            cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
136
        }
137
    }
138

    
139
    @Override
140
    public void createPartControl(Composite parent) {
141

    
142
        parent.setLayout(new GridLayout());
143

    
144
        //---search and filter---
145
        derivateSearchCompositeController = new DerivateSearchCompositeController(parent, this);
146
        derivateSearchCompositeController.setEnabled(CdmStore.isActive());
147
        GridData gridDataSearchBar = new GridData();
148
        gridDataSearchBar.horizontalAlignment = GridData.FILL;
149
        gridDataSearchBar.grabExcessHorizontalSpace = true;
150
        derivateSearchCompositeController.setLayoutData(gridDataSearchBar);
151

    
152
        //---tree viewer---
153
        viewer = new TreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION));
154
        GridData gridDataTree = new GridData();
155
        gridDataTree.horizontalAlignment = GridData.FILL;
156
        gridDataTree.verticalAlignment = GridData.FILL;
157
        gridDataTree.grabExcessVerticalSpace = true;
158
        gridDataTree.grabExcessHorizontalSpace = true;
159
        viewer.getTree().setLayoutData(gridDataTree);
160
        contentProvider = new DerivateContentProvider();
161
        viewer.setContentProvider(contentProvider);
162
        labelProvider = new DerivateLabelProvider();
163
        labelProvider.setConversation(conversation);
164
        viewer.setLabelProvider(labelProvider);
165
        viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
166
        // Propagate selection from viewer
167
        getSite().setSelectionProvider(viewer);
168

    
169
        //listen to selection changes
170
        selectionService = getSite().getWorkbenchWindow().getSelectionService();
171
        selectionService.addSelectionListener(this);
172

    
173
        //create context menu
174
        MenuManager menuManager = new MenuManager();
175
        getSite().registerContextMenu(menuManager, viewer);
176
        Control control = viewer.getControl();
177
        Menu menu = menuManager.createContextMenu(control);
178
        control.setMenu(menu);
179

    
180
        //init tree
181
        updateRootEntities();
182

    
183
        //add drag'n'drop support
184
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer(),};
185
        viewer.addDragSupport(dndOperations, transfers, new DerivateDragListener(this));
186
        viewer.addDropSupport(dndOperations, transfers, new DerivateDropListener(this));
187
    }
188

    
189
    public void updateRootEntities() {
190
        updateRootEntities(null);
191
    }
192

    
193
    public void updateRootEntities(Collection<UUID> derivativeUuids) {
194
        if(conversation!=null){
195
            if (!conversation.isBound()) {
196
                conversation.bind();
197
            }
198
            if(derivativeUuids!=null){
199
                this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
200
                this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
201
                for (UUID uuid : derivativeUuids) {
202
                    SpecimenOrObservationBase<?> derivate = CdmStore.getService(IOccurrenceService.class).load(uuid, SPECIMEN_INIT_STRATEGY);
203
                    if(derivate instanceof FieldUnit){
204
                        derivateToRootEntityMap.put(derivate, derivate);
205
                    }
206
                    else {
207
                        SpecimenOrObservationBase<?> topMostDerivate = EditorUtil.getTopMostDerivate(derivate);
208
                        if(topMostDerivate!=null){
209
                            derivateToRootEntityMap.put(derivate, topMostDerivate);
210
                        }
211
                        else{
212
                            derivateToRootEntityMap.put(derivate, derivate);
213
                        }
214
                    }
215
                }
216
                for (SpecimenOrObservationBase<?> specimen : derivateToRootEntityMap.values()) {
217
                    rootElements.add(specimen);
218
                }
219
            }
220
            viewer.setInput(rootElements);
221
            refreshTree();
222
        }
223
    }
224

    
225
    @Override
226
    public void doSave(IProgressMonitor monitor) {
227
        String taskName = Messages.DerivateView_SAVING_HIERARCHY;
228
        monitor.beginTask(taskName, 3);
229
        if (!conversation.isBound()) {
230
            conversation.bind();
231
        }
232
        monitor.worked(1);
233

    
234
        // commit the conversation and start a new transaction immediately
235
        conversation.commit(true);
236

    
237
        if(CdmStore.getCurrentSessionManager().isRemoting()) {
238
            CdmStore.getService(IOccurrenceService.class).merge(new ArrayList<SpecimenOrObservationBase>(rootElements), true);
239
        }
240
        monitor.worked(1);
241

    
242
        this.setDirty(false);
243
        monitor.worked(1);
244
        monitor.done();
245
        firePropertyChange(PROP_DIRTY);
246
        refreshTree();
247
    }
248

    
249
    @Override
250
    public void doSaveAs() {
251
    }
252

    
253
    public Set<SpecimenOrObservationBase<?>> getRootElements() {
254
        return rootElements;
255
    }
256

    
257
    @Override
258
    public String getTitleToolTip() {
259
        return Messages.DerivateView_DERIVATIVE_EDITOR;
260
    }
261

    
262
    @Override
263
    public boolean isDirty() {
264
        return isDirty;
265
    }
266

    
267
    /**
268
     * @param isDirty the isDirty to set
269
     */
270
    public void setDirty(boolean isDirty) {
271
        this.isDirty = isDirty;
272
    }
273

    
274
    @Override
275
    public boolean isSaveAsAllowed() {
276
        return false;
277
    }
278

    
279
    @Override
280
    public void setFocus() {
281
        viewer.getControl().setFocus();
282
        //make sure to bind again if maybe in another view the conversation was unbound
283
        if(!conversation.isBound()){
284
            conversation.bind();
285
        }
286
        if(cdmEntitySession != null) {
287
            cdmEntitySession.bind();
288
        }
289
    }
290

    
291
    @Override
292
    public void update(CdmDataChangeMap changeEvents) {
293
    }
294

    
295
    @Override
296
    public ConversationHolder getConversationHolder() {
297
        return conversation;
298
    }
299

    
300
    /**
301
     * @return the viewer
302
     */
303
    @Override
304
    public TreeViewer getViewer() {
305
        return viewer;
306
    }
307

    
308
    @Override
309
    public void changed(Object element) {
310
        setDirty(true);
311
        firePropertyChange(IEditorPart.PROP_DIRTY);
312
        viewer.refresh();
313
    }
314

    
315
    @Override
316
    public void forceDirty() {
317
        changed(null);
318
    }
319

    
320
    @Override
321
    public Map<Object, List<String>> getPropertyPathsMap() {
322
        List<String> specimenPropertyPaths = Arrays.asList(new String[] {
323
                "descriptions",
324
                "derivationEvents.derivates",
325
                "annotations",
326
                "markers",
327
                "credits",
328
                "extensions",
329
                "rights",
330
                "sources"
331
        });
332
        Map<Object, List<String>> specimenPropertyPathMap =
333
                new HashMap<Object, List<String>>();
334
        specimenPropertyPathMap.put(SpecimenOrObservationBase.class,specimenPropertyPaths);
335
        return specimenPropertyPathMap;
336
    }
337

    
338
    /**
339
     * Refreshes the derivate hierarchy tree and expands the tree
340
     * to show and select the given object.
341
     *
342
     * @param expandTo the object to which the tree should be expanded
343
     */
344
    public void refreshTree(Object expandTo){
345
        refreshTree();
346
        TreeSelection selection = (TreeSelection) viewer.getSelection();
347
        viewer.expandToLevel(selection.getFirstElement(), 1);
348
        viewer.setSelection(new StructuredSelection(new TreeNode(expandTo)));
349
    }
350

    
351
    /**
352
     * Refreshes the derivate hierarchy tree
353
     */
354
    public void refreshTree(){
355
        generateMultiLinkSingleReads();
356
        labelProvider.setMultiLinkSingleReads(multiLinkSingleReads);
357
        viewer.refresh();
358
    }
359

    
360
    //FIXME:Remoting hack to make this work for remoting
361
    //This should actually be resolved using remoting post operations
362
    public void remove(Object obj) {
363
        rootElements.remove(obj);
364
        viewer.setInput(rootElements);
365
    }
366

    
367
    private void generateMultiLinkSingleReads() {
368
        Set<SingleRead> multiLinkSingleReads = new HashSet<SingleRead>();
369
        for(Entry<SingleRead, Collection<Sequence>> entry:CdmStore.getService(ISequenceService.class).getSingleReadSequencesMap().entrySet()){
370
            if(entry.getValue().size()>1){
371
                multiLinkSingleReads.add(entry.getKey());
372
            }
373
        }
374
        this.multiLinkSingleReads = multiLinkSingleReads;
375
    }
376

    
377
    /**
378
     * @return a set of {@link SingleRead}s that have multiple parents
379
     */
380
    public Set<SingleRead> getMultiLinkSingleReads() {
381
        return this.multiLinkSingleReads;
382
    }
383

    
384
    public ISelection getSelection() {
385
        return selection;
386
    }
387

    
388
    public DerivateLabelProvider getLabelProvider() {
389
        return labelProvider;
390
    }
391

    
392
    @Override
393
    public boolean postOperation(CdmBase objectAffectedByOperation) {
394
        refreshTree();
395
        if(objectAffectedByOperation!=null){
396
            changed(objectAffectedByOperation);
397
        }
398
        return true;
399
    }
400

    
401
    @Override
402
    public boolean onComplete() {
403
        return true;
404
    }
405

    
406

    
407
    @Override
408
    public boolean canAttachMedia() {
409
        return true;
410
    }
411

    
412
    public void removeHierarchy(SpecimenOrObservationBase<?> specimenOrObservationBase) {
413
        SpecimenOrObservationBase<?> rootElement = derivateToRootEntityMap.remove(specimenOrObservationBase);
414
        rootElements.remove(rootElement);
415
    }
416

    
417
    public void addHierarchy(FieldUnit fieldUnit) {
418
        rootElements.add(fieldUnit);
419
        derivateToRootEntityMap.put(fieldUnit, fieldUnit);
420
    }
421

    
422
    @Override
423
    public ICdmEntitySession getCdmEntitySession() {
424
        return cdmEntitySession;
425
    }
426

    
427
    @Override
428
    public void dispose() {
429
        super.dispose();
430
        if(conversation!=null){
431
            conversation.close();
432
        }
433
        if(cdmEntitySession != null) {
434
            cdmEntitySession.dispose();
435
        }
436
    }
437

    
438
    @Override
439
    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
440
        if(listenToSelectionChange && selection instanceof IStructuredSelection){
441
            Object selectedElement = ((IStructuredSelection) selection).getFirstElement();
442
            if(selectedElement instanceof Taxon){
443
                Collection<SpecimenOrObservationBase> fieldUnits = CdmStore.getService(IOccurrenceService.class).listFieldUnitsByAssociatedTaxon((Taxon) selectedElement, null, null);
444
                Collection<UUID> uuids = new HashSet<UUID>();
445
                for (SpecimenOrObservationBase specimenOrObservationBase : fieldUnits) {
446
                    uuids.add(specimenOrObservationBase.getUuid());
447
                }
448
                updateRootEntities(uuids);
449
            }
450
        }
451
    }
452

    
453
    @Override
454
    public void createViewer(Composite parent) {
455
        // TODO Auto-generated method stub
456

    
457
    }
458

    
459
    @Override
460
    public boolean isSaveOnCloseNeeded() {
461
        return isDirty();
462
    }
463

    
464
    @Override
465
    public int promptToSaveOnClose() {
466
        return ISaveablePart2.DEFAULT;
467
    }
468

    
469
    public void toggleListenToSelectionChange() {
470
        listenToSelectionChange = !listenToSelectionChange;
471
        derivateSearchCompositeController.setEnabled(listenToSelectionChange);
472
    }
473

    
474
}
(3-3/5)