Project

General

Profile

Download (18.4 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.IMemento;
35
import org.eclipse.ui.ISaveablePart2;
36
import org.eclipse.ui.IWorkbenchPart;
37

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

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

    
72
    public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION = Messages.DerivateView_YOU_NEED_TO_SAVE;
73
    public static final String VIEW_HAS_UNSAVED_CHANGES = Messages.DerivateView_UNSAVED_CHANGES;
74

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

    
91
	private ConversationHolder conversation;
92

    
93
	private TreeViewer viewer;
94

    
95
    private boolean isDirty;
96

    
97
    private final int dndOperations = DND.DROP_MOVE;
98

    
99
    private DerivateLabelProvider labelProvider;
100

    
101
    private Set<SingleRead> multiLinkSingleReads;
102

    
103
    private DerivateContentProvider contentProvider;
104

    
105
    private DerivateSearchCompositeController derivateSearchCompositeController;
106

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

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

    
118
    private ICdmEntitySession cdmEntitySession;
119

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

    
125
    private Taxon selectedTaxon;
126

    
127
    /**
128
     * Default constructor
129
     */
130
    public DerivateView() {
131
        init();
132
    }
133

    
134
    /**
135
     *
136
     */
137
    private void init() {
138
        this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
139
        this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
140

    
141
        if (CdmStore.isActive() && conversation == null) {
142
            conversation = CdmStore.createConversation();
143
        }
144
        if (CdmStore.isActive()) {
145
            cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
146
        }
147
        //listen to context changes
148
        CdmStore.getContextManager().addContextListener(this);
149
    }
150

    
151
    @Override
152
    public void createPartControl(Composite parent) {
153

    
154
        parent.setLayout(new GridLayout());
155

    
156
        //---search and filter---
157
        derivateSearchCompositeController = new DerivateSearchCompositeController(parent, this);
158
        derivateSearchCompositeController.setEnabled(CdmStore.isActive());
159
        GridData gridDataSearchBar = new GridData();
160
        gridDataSearchBar.horizontalAlignment = GridData.FILL;
161
        gridDataSearchBar.grabExcessHorizontalSpace = true;
162
        derivateSearchCompositeController.setLayoutData(gridDataSearchBar);
163

    
164
        //---tree viewer---
165
        viewer = new TreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION));
166
        GridData gridDataTree = new GridData();
167
        gridDataTree.horizontalAlignment = GridData.FILL;
168
        gridDataTree.verticalAlignment = GridData.FILL;
169
        gridDataTree.grabExcessVerticalSpace = true;
170
        gridDataTree.grabExcessHorizontalSpace = true;
171
        viewer.getTree().setLayoutData(gridDataTree);
172
        contentProvider = new DerivateContentProvider();
173
        viewer.setContentProvider(contentProvider);
174
        labelProvider = new DerivateLabelProvider();
175
        labelProvider.setConversation(conversation);
176
        viewer.setLabelProvider(labelProvider);
177
        viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
178
        // Propagate selection from viewer
179
        getSite().setSelectionProvider(viewer);
180

    
181
        //listen to selection changes
182
        selectionService = getSite().getWorkbenchWindow().getSelectionService();
183
        selectionService.addSelectionListener(this);
184

    
185
        //create context menu
186
        MenuManager menuManager = new MenuManager();
187
        getSite().registerContextMenu(menuManager, viewer);
188
        Control control = viewer.getControl();
189
        Menu menu = menuManager.createContextMenu(control);
190
        control.setMenu(menu);
191

    
192
        //init tree
193
        updateRootEntities();
194

    
195
        //add drag'n'drop support
196
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer(),};
197
        viewer.addDragSupport(dndOperations, transfers, new DerivateDragListener(this));
198
        viewer.addDropSupport(dndOperations, transfers, new DerivateDropListener(this));
199
    }
200

    
201
    public void updateRootEntities() {
202
        updateRootEntities(null);
203
    }
204

    
205
    public void updateRootEntities(Collection<UUID> derivativeUuids) {
206
        if(conversation!=null){
207
            if (!conversation.isBound()) {
208
                conversation.bind();
209
            }
210
            /*
211
             * If the active session is not the session of the Derivate Editor then we will
212
             * save it, bind temporarily to our session and rebind to the original session.
213
             * This happens e.g. if a selection change happens in the taxon editor and
214
             * "Link with editor" is enabled. The selection change event and thus the
215
             * loading in updateRootEntities() happens in the session of the taxon
216
             * editor.
217
             */
218
            ICdmEntitySession previousCdmEntitySession = CdmStore.getCurrentSessionManager().getActiveSession();
219
            if(cdmEntitySession != null) {
220
                cdmEntitySession.bind();
221
            }
222

    
223
            if(derivativeUuids!=null){
224
                this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
225
                this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
226
                for (UUID uuid : derivativeUuids) {
227
                    SpecimenOrObservationBase<?> derivate = CdmStore.getService(IOccurrenceService.class).load(uuid, SPECIMEN_INIT_STRATEGY);
228
                    if(derivate instanceof FieldUnit){
229
                        derivateToRootEntityMap.put(derivate, derivate);
230
                    }
231
                    else {
232
                        SpecimenOrObservationBase<?> topMostDerivate = EditorUtil.getTopMostDerivate(derivate);
233
                        if(topMostDerivate!=null){
234
                            derivateToRootEntityMap.put(derivate, topMostDerivate);
235
                        }
236
                        else{
237
                            derivateToRootEntityMap.put(derivate, derivate);
238
                        }
239
                    }
240
                }
241
                for (SpecimenOrObservationBase<?> specimen : derivateToRootEntityMap.values()) {
242
                    rootElements.add(specimen);
243
                }
244
            }
245
            viewer.setInput(rootElements);
246
            refreshTree();
247
            previousCdmEntitySession.bind();
248
        }
249
    }
250

    
251
    @Override
252
    public void doSave(IProgressMonitor monitor) {
253
        String taskName = Messages.DerivateView_SAVING_HIERARCHY;
254
        monitor.beginTask(taskName, 3);
255
        if (!conversation.isBound()) {
256
            conversation.bind();
257
        }
258
        monitor.worked(1);
259

    
260
        // commit the conversation and start a new transaction immediately
261
        conversation.commit(true);
262

    
263
        if(CdmStore.getCurrentSessionManager().isRemoting()) {
264
            CdmStore.getService(IOccurrenceService.class).merge(new ArrayList<SpecimenOrObservationBase>(rootElements), true);
265
        }
266
        monitor.worked(1);
267

    
268
        this.setDirty(false);
269
        monitor.worked(1);
270
        monitor.done();
271
        firePropertyChange(PROP_DIRTY);
272
        refreshTree();
273
    }
274

    
275
    @Override
276
    public void doSaveAs() {
277
    }
278

    
279
    @Override
280
    public String getTitleToolTip() {
281
        return Messages.DerivateView_DERIVATIVE_EDITOR;
282
    }
283

    
284
    @Override
285
    public boolean isDirty() {
286
        return isDirty;
287
    }
288

    
289
    /**
290
     * @param isDirty the isDirty to set
291
     */
292
    public void setDirty(boolean isDirty) {
293
        this.isDirty = isDirty;
294
    }
295

    
296
    @Override
297
    public boolean isSaveAsAllowed() {
298
        return false;
299
    }
300

    
301
    @Override
302
    public void setFocus() {
303
        viewer.getControl().setFocus();
304
        //make sure to bind again if maybe in another view the conversation was unbound
305
        if(conversation!=null && !conversation.isBound()){
306
            conversation.bind();
307
        }
308
        if(cdmEntitySession != null) {
309
            cdmEntitySession.bind();
310
        }
311
    }
312

    
313
    @Override
314
    public void update(CdmDataChangeMap changeEvents) {
315
    }
316

    
317
    @Override
318
    public ConversationHolder getConversationHolder() {
319
        return conversation;
320
    }
321

    
322
    /**
323
     * @return the viewer
324
     */
325
    @Override
326
    public TreeViewer getViewer() {
327
        return viewer;
328
    }
329

    
330
    @Override
331
    public void changed(Object element) {
332
        setDirty(true);
333
        firePropertyChange(IEditorPart.PROP_DIRTY);
334
        viewer.refresh();
335
    }
336

    
337
    @Override
338
    public void forceDirty() {
339
        changed(null);
340
    }
341

    
342
    @Override
343
    public Map<Object, List<String>> getPropertyPathsMap() {
344
        List<String> specimenPropertyPaths = Arrays.asList(new String[] {
345
                "descriptions",
346
                "derivationEvents.derivates",
347
                "annotations",
348
                "markers",
349
                "credits",
350
                "extensions",
351
                "rights",
352
                "sources"
353
        });
354
        Map<Object, List<String>> specimenPropertyPathMap =
355
                new HashMap<Object, List<String>>();
356
        specimenPropertyPathMap.put(SpecimenOrObservationBase.class,specimenPropertyPaths);
357
        return specimenPropertyPathMap;
358
    }
359

    
360
    /**
361
     * Refreshes the derivate hierarchy tree and expands the tree
362
     * to show and select the given object.
363
     *
364
     * @param expandTo the object to which the tree should be expanded
365
     */
366
    public void refreshTree(Object expandTo){
367
        refreshTree();
368
        TreeSelection selection = (TreeSelection) viewer.getSelection();
369
        viewer.expandToLevel(selection.getFirstElement(), 1);
370
        viewer.setSelection(new StructuredSelection(new TreeNode(expandTo)));
371
    }
372

    
373
    /**
374
     * Refreshes the derivate hierarchy tree
375
     */
376
    public void refreshTree(){
377
        generateMultiLinkSingleReads();
378
        labelProvider.setMultiLinkSingleReads(multiLinkSingleReads);
379
        viewer.refresh();
380
    }
381

    
382
    //FIXME:Remoting hack to make this work for remoting
383
    //This should actually be resolved using remoting post operations
384
    public void remove(Object obj) {
385
        rootElements.remove(obj);
386
        viewer.setInput(rootElements);
387
    }
388

    
389
    private void generateMultiLinkSingleReads() {
390
        Set<SingleRead> multiLinkSingleReads = new HashSet<SingleRead>();
391
        for(Entry<SingleRead, Collection<Sequence>> entry:CdmStore.getService(ISequenceService.class).getSingleReadSequencesMap().entrySet()){
392
            if(entry.getValue().size()>1){
393
                multiLinkSingleReads.add(entry.getKey());
394
            }
395
        }
396
        this.multiLinkSingleReads = multiLinkSingleReads;
397
    }
398

    
399
    /**
400
     * @return a set of {@link SingleRead}s that have multiple parents
401
     */
402
    public Set<SingleRead> getMultiLinkSingleReads() {
403
        return this.multiLinkSingleReads;
404
    }
405

    
406
    public Object getSelectionInput() {
407
        return selectedTaxon;
408
    }
409

    
410
    public DerivateLabelProvider getLabelProvider() {
411
        return labelProvider;
412
    }
413

    
414
    @Override
415
    public boolean postOperation(CdmBase objectAffectedByOperation) {
416
        refreshTree();
417
        if(objectAffectedByOperation!=null){
418
            changed(objectAffectedByOperation);
419
        }
420
        return true;
421
    }
422

    
423
    @Override
424
    public boolean onComplete() {
425
        return true;
426
    }
427

    
428

    
429
    @Override
430
    public boolean canAttachMedia() {
431
        return true;
432
    }
433

    
434
    public void addHierarchy(FieldUnit fieldUnit) {
435
        rootElements.add(fieldUnit);
436
        derivateToRootEntityMap.put(fieldUnit, fieldUnit);
437
    }
438

    
439
    @Override
440
    public ICdmEntitySession getCdmEntitySession() {
441
        return cdmEntitySession;
442
    }
443

    
444
    @Override
445
    public void dispose() {
446
        super.dispose();
447
        if(conversation!=null){
448
            conversation.close();
449
        }
450
        if(cdmEntitySession != null) {
451
            cdmEntitySession.dispose();
452
        }
453
    }
454

    
455
    @Override
456
    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
457
        if(listenToSelectionChange && selection instanceof IStructuredSelection){
458
            Object selectedElement = ((IStructuredSelection) selection).getFirstElement();
459
            if(selectedElement instanceof CdmBase && ((CdmBase) selectedElement).isInstanceOf(Taxon.class)){
460
                selectedTaxon = HibernateProxyHelper.deproxy(selectedElement, Taxon.class);
461
                Collection<SpecimenOrObservationBase> fieldUnits = CdmStore.getService(IOccurrenceService.class).listFieldUnitsByAssociatedTaxon(selectedTaxon, null, null);
462
                Collection<UUID> uuids = new HashSet<UUID>();
463
                for (SpecimenOrObservationBase specimenOrObservationBase : fieldUnits) {
464
                    uuids.add(specimenOrObservationBase.getUuid());
465
                }
466
                updateRootEntities(uuids);
467
            }
468
        }
469
        if(part instanceof MultiPageTaxonEditor){
470
            Taxon taxon = ((MultiPageTaxonEditor) part).getTaxon();
471
            derivateSearchCompositeController.setTaxon(taxon);
472
        }
473
    }
474

    
475
    /**
476
     * {@inheritDoc}
477
     */
478
    @Override
479
    public List<SpecimenOrObservationBase<?>> getRootEntities() {
480
        return new ArrayList<SpecimenOrObservationBase<?>>(rootElements);
481
    }
482

    
483
    @Override
484
    public void createViewer(Composite parent) {
485
        // TODO Auto-generated method stub
486

    
487
    }
488

    
489
    @Override
490
    public boolean isSaveOnCloseNeeded() {
491
        return isDirty();
492
    }
493

    
494
    @Override
495
    public int promptToSaveOnClose() {
496
        return ISaveablePart2.DEFAULT;
497
    }
498

    
499
    public void toggleListenToSelectionChange() {
500
        listenToSelectionChange = !listenToSelectionChange;
501
        derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
502
        derivateSearchCompositeController.setTaxon(null);
503
        if(!listenToSelectionChange){
504
            selectedTaxon = null;
505
        }
506
    }
507

    
508
    public boolean isListenToSelectionChange(){
509
        return listenToSelectionChange;
510
    }
511

    
512
    /**
513
     * {@inheritDoc}
514
     */
515
    @Override
516
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
517
    }
518

    
519
    /**
520
     * {@inheritDoc}
521
     */
522
    @Override
523
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
524
        derivateSearchCompositeController.setEnabled(false);
525
        viewer.setInput(null);
526
    }
527

    
528
    /**
529
     * {@inheritDoc}
530
     */
531
    @Override
532
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
533
        init();
534
        derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
535
        refreshTree();
536
    }
537

    
538
    /**
539
     * {@inheritDoc}
540
     */
541
    @Override
542
    public void contextRefresh(IProgressMonitor monitor) {
543
    }
544

    
545
    /**
546
     * {@inheritDoc}
547
     */
548
    @Override
549
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
550
    }
551

    
552
}
(3-3/5)