Project

General

Profile

Download (15.8 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.ISelectionChangedListener;
20
import org.eclipse.jface.viewers.SelectionChangedEvent;
21
import org.eclipse.jface.viewers.StructuredSelection;
22
import org.eclipse.jface.viewers.TreeNode;
23
import org.eclipse.jface.viewers.TreeSelection;
24
import org.eclipse.jface.viewers.TreeViewer;
25
import org.eclipse.swt.SWT;
26
import org.eclipse.swt.dnd.DND;
27
import org.eclipse.swt.dnd.Transfer;
28
import org.eclipse.swt.layout.GridData;
29
import org.eclipse.swt.layout.GridLayout;
30
import org.eclipse.swt.widgets.Composite;
31
import org.eclipse.swt.widgets.Control;
32
import org.eclipse.swt.widgets.Menu;
33
import org.eclipse.swt.widgets.Tree;
34
import org.eclipse.ui.IEditorInput;
35
import org.eclipse.ui.IEditorPart;
36
import org.eclipse.ui.IEditorSite;
37
import org.eclipse.ui.PartInitException;
38
import org.eclipse.ui.part.EditorPart;
39

    
40
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
41
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
42
import eu.etaxonomy.cdm.api.service.IOccurrenceService;
43
import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
44
import eu.etaxonomy.cdm.model.common.CdmBase;
45
import eu.etaxonomy.cdm.model.molecular.Sequence;
46
import eu.etaxonomy.cdm.model.molecular.SingleRead;
47
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
48
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
49
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
50
import eu.etaxonomy.taxeditor.editor.EditorUtil;
51
import eu.etaxonomy.taxeditor.editor.Messages;
52
import eu.etaxonomy.taxeditor.editor.view.derivate.searchFilter.DerivateSearchCompositeController;
53
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
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.operation.IPostOperationEnabled;
59
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
60
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
61
import eu.etaxonomy.taxeditor.store.CdmStore;
62
import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateContentProvider;
63
import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateLabelProvider;
64

    
65
/**
66
 * Displays the derivate hierarchy of the specimen specified in the editor input.
67
 *
68
 */
69
public class DerivateView extends EditorPart implements IPartContentHasFactualData, IDirtyMarkable,
70
        IConversationEnabled, IPartContentHasDetails, IPartContentHasSupplementalData, IPartContentHasMedia,
71

    
72
        ISelectionChangedListener, IPostOperationEnabled, ICdmEntitySessionEnabled{
73
    public static final String ID = "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView"; //$NON-NLS-1$
74

    
75
    public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION = Messages.DerivateView_YOU_NEED_TO_SAVE;
76
    public static final String VIEW_HAS_UNSAVED_CHANGES = Messages.DerivateView_UNSAVED_CHANGES;
77

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

    
94
	private ConversationHolder conversation;
95

    
96
	private TreeViewer viewer;
97

    
98
    private boolean isDirty;
99

    
100
    private final int dndOperations = DND.DROP_MOVE;
101

    
102
    private DerivateLabelProvider labelProvider;
103

    
104
    private Set<SingleRead> multiLinkSingleReads;
105

    
106
    private ISelection selection = null;
107

    
108

    
109
    private DerivateContentProvider contentProvider;
110

    
111
    private DerivateSearchCompositeController derivateSearchCompositeController;
112

    
113
    /**
114
     * A map with keys being the derivative entities belonging to the {@link UUID}s passed to the constructor
115
     * and values being the root elements of the hierarchy (may be the same objects as the derivative entities)
116
     */
117
    private Map<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>> derivateToRootEntityMap;
118

    
119
    /**
120
     * The set of root elements
121
     */
122
    private Set<SpecimenOrObservationBase<?>> rootElements;
123

    
124
    private ICdmEntitySession cdmEntitySession;
125

    
126
    /**
127
     * Default constructor
128
     */
129
    public DerivateView() {
130
    }
131

    
132
    @Override
133
    public void createPartControl(Composite parent) {
134

    
135
        parent.setLayout(new GridLayout());
136

    
137
        //---search and filter---
138
        derivateSearchCompositeController = new DerivateSearchCompositeController(parent, this);
139
        derivateSearchCompositeController.setEnabled(CdmStore.isActive());
140
        GridData gridDataSearchBar = new GridData();
141
        gridDataSearchBar.horizontalAlignment = GridData.FILL;
142
        gridDataSearchBar.grabExcessHorizontalSpace = true;
143
        derivateSearchCompositeController.setLayoutData(gridDataSearchBar);
144

    
145
        //---tree viewer---
146
        viewer = new TreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION));
147
        GridData gridDataTree = new GridData();
148
        gridDataTree.horizontalAlignment = GridData.FILL;
149
        gridDataTree.verticalAlignment = GridData.FILL;
150
        gridDataTree.grabExcessVerticalSpace = true;
151
        gridDataTree.grabExcessHorizontalSpace = true;
152
        viewer.getTree().setLayoutData(gridDataTree);
153
        contentProvider = new DerivateContentProvider();
154
        viewer.setContentProvider(contentProvider);
155
        labelProvider = new DerivateLabelProvider();
156
        labelProvider.setConversation(conversation);
157
        viewer.setLabelProvider(labelProvider);
158
        viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
159
        // Propagate selection from viewer
160
        getSite().setSelectionProvider(viewer);
161
        //listen to selection changes
162
        viewer.addSelectionChangedListener(this);
163

    
164
        //create context menu
165
        MenuManager menuManager = new MenuManager();
166
        getSite().registerContextMenu(menuManager, viewer);
167
        Control control = viewer.getControl();
168
        Menu menu = menuManager.createContextMenu(control);
169
        control.setMenu(menu);
170

    
171
        //single read multi links
172
        generateMultiLinkSingleReads();
173
        labelProvider.setMultiLinkSingleReads(multiLinkSingleReads);
174

    
175
        //init tree
176
        DerivateViewEditorInput editorInput = (DerivateViewEditorInput) getEditorInput();
177
        if(editorInput.getDerivativeUUIDs()!=null){
178
            updateRootEntities(editorInput.getDerivativeUUIDs());
179
        }
180
        else{
181
            updateRootEntities();
182
        }
183

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

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

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

    
221
    @Override
222
    public void doSave(IProgressMonitor monitor) {
223
        String taskName = Messages.DerivateView_SAVING_HIERARCHY;
224
        if(getEditorInput() instanceof DerivateViewEditorInput){
225
            DerivateViewEditorInput derivateViewEditorInput = (DerivateViewEditorInput) getEditorInput();
226
            taskName += " "+derivateViewEditorInput.getName(); //$NON-NLS-1$
227
        }
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(getRootEntities()), 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
        if(getEditorInput() instanceof DerivateViewEditorInput){
260
            DerivateViewEditorInput derivateViewEditorInput = (DerivateViewEditorInput) getEditorInput();
261
            return derivateViewEditorInput.getName();
262
        }
263
        return Messages.DerivateView_DERIVATIVE_EDITOR;
264
    }
265

    
266
    @Override
267
    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
268
        setSite(site);
269
        setInput(input);
270
        this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
271
        this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
272

    
273
        if (CdmStore.isActive() && conversation == null) {
274
            conversation = CdmStore.createConversation();
275
        }
276
        if (CdmStore.isActive()) {
277
            cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
278
        }
279
    }
280

    
281
    @Override
282
    public boolean isDirty() {
283
        return isDirty;
284
    }
285

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

    
293
    @Override
294
    public boolean isSaveAsAllowed() {
295
        return false;
296
    }
297

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

    
310
    @Override
311
    public void update(CdmDataChangeMap changeEvents) {
312
    }
313

    
314
    @Override
315
    public ConversationHolder getConversationHolder() {
316
        return conversation;
317
    }
318

    
319
    /**
320
     * @return the viewer
321
     */
322
    public TreeViewer getViewer() {
323
        return viewer;
324
    }
325

    
326
    @Override
327
    public void changed(Object element) {
328
        setDirty(true);
329
        firePropertyChange(IEditorPart.PROP_DIRTY);
330
        viewer.refresh();
331
    }
332

    
333
    @Override
334
    public void forceDirty() {
335
        changed(null);
336
    }
337

    
338
    @Override
339
    public Set<SpecimenOrObservationBase<?>> getRootEntities() {
340
        return rootElements;
341
    }
342

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

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

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

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

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

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

    
407
    @Override
408
    public void selectionChanged(SelectionChangedEvent event) {
409
        this.selection  = event.getSelection();
410
    }
411

    
412
    public ISelection getSelection() {
413
        return selection;
414
    }
415

    
416
    public DerivateLabelProvider getLabelProvider() {
417
        return labelProvider;
418
    }
419

    
420
    @Override
421
    public boolean postOperation(CdmBase objectAffectedByOperation) {
422
        refreshTree();
423
        if(objectAffectedByOperation!=null){
424
            changed(objectAffectedByOperation);
425
        }
426
        return true;
427
    }
428

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

    
434

    
435
    @Override
436
    public boolean canAttachMedia() {
437
        return true;
438
    }
439

    
440
    public void removeHierarchy(SpecimenOrObservationBase<?> specimenOrObservationBase) {
441
        SpecimenOrObservationBase<?> rootElement = derivateToRootEntityMap.remove(specimenOrObservationBase);
442
        rootElements.remove(rootElement);
443
    }
444

    
445
    public void addHierarchy(FieldUnit fieldUnit) {
446
        rootElements.add(fieldUnit);
447
        derivateToRootEntityMap.put(fieldUnit, fieldUnit);
448
    }
449

    
450
    @Override
451
    public ICdmEntitySession getCdmEntitySession() {
452
        return cdmEntitySession;
453
    }
454

    
455
    @Override
456
    public void dispose() {
457
        super.dispose();
458
        if(conversation!=null){
459
            conversation.close();
460
        }
461
        if(cdmEntitySession != null) {
462
            cdmEntitySession.dispose();
463
        }
464
    }
465
}
(3-3/5)