Merge branch 'develop' into remoting-4.0
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / view / descriptive / DescriptiveViewPart.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10
11 package eu.etaxonomy.taxeditor.editor.view.descriptive;
12
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.UUID;
19
20 import org.eclipse.jface.action.Action;
21 import org.eclipse.jface.action.GroupMarker;
22 import org.eclipse.jface.action.IAction;
23 import org.eclipse.jface.action.IToolBarManager;
24 import org.eclipse.jface.action.MenuManager;
25 import org.eclipse.jface.resource.ImageDescriptor;
26 import org.eclipse.jface.viewers.DoubleClickEvent;
27 import org.eclipse.jface.viewers.IDoubleClickListener;
28 import org.eclipse.jface.viewers.ISelection;
29 import org.eclipse.jface.viewers.IStructuredSelection;
30 import org.eclipse.jface.viewers.ITreeContentProvider;
31 import org.eclipse.jface.viewers.StructuredSelection;
32 import org.eclipse.jface.viewers.TreeNode;
33 import org.eclipse.jface.viewers.TreeSelection;
34 import org.eclipse.jface.viewers.TreeViewer;
35 import org.eclipse.jface.viewers.Viewer;
36 import org.eclipse.swt.SWT;
37 import org.eclipse.swt.dnd.DND;
38 import org.eclipse.swt.dnd.Transfer;
39 import org.eclipse.swt.graphics.ImageData;
40 import org.eclipse.swt.widgets.Composite;
41 import org.eclipse.swt.widgets.Control;
42 import org.eclipse.swt.widgets.Menu;
43 import org.eclipse.swt.widgets.Tree;
44 import org.eclipse.ui.IWorkbenchActionConstants;
45 import org.eclipse.ui.IWorkbenchPart;
46 import org.eclipse.ui.PartInitException;
47
48 import eu.etaxonomy.cdm.model.common.CdmBase;
49 import eu.etaxonomy.cdm.model.description.DescriptionBase;
50 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
51 import eu.etaxonomy.cdm.model.description.IDescribable;
52 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
53 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
54 import eu.etaxonomy.cdm.model.taxon.Taxon;
55 import eu.etaxonomy.taxeditor.bulkeditor.BulkEditor;
56 import eu.etaxonomy.taxeditor.editor.EditorUtil;
57 import eu.etaxonomy.taxeditor.editor.view.checklist.ChecklistEditor;
58 import eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView;
59 import eu.etaxonomy.taxeditor.editor.view.derivate.DerivateViewEditorInput;
60 import eu.etaxonomy.taxeditor.editor.view.media.MediaViewPart;
61 import eu.etaxonomy.taxeditor.model.AbstractUtility;
62 import eu.etaxonomy.taxeditor.model.FeatureNodeContainer;
63 import eu.etaxonomy.taxeditor.model.FeatureNodeContainerTree;
64 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
65 import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
66 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
67 import eu.etaxonomy.taxeditor.model.ImageResources;
68 import eu.etaxonomy.taxeditor.model.MessagingUtils;
69 import eu.etaxonomy.taxeditor.view.AbstractCdmEditorViewPart;
70 import eu.etaxonomy.taxeditor.view.detail.DetailsViewPart;
71 import eu.etaxonomy.taxeditor.view.supplementaldata.SupplementalDataViewPart;
72
73 /**
74 * <p>DescriptiveViewPart class.</p>
75 *
76 * @author n.hoffmann
77 * @created Jun 9, 2010
78 * @version 1.0
79 */
80 public class DescriptiveViewPart extends AbstractCdmEditorViewPart implements IPartContentHasDetails, IPartContentHasSupplementalData {
81
82 /** Constant <code>ID="eu.etaxonomy.taxeditor.editor.view.desc"{trunked}</code> */
83 public static final String ID = "eu.etaxonomy.taxeditor.editor.view.descriptive";
84
85 protected TreeViewer viewer;
86
87 /**
88 * Maps {@link FeatureNodeContainerTree} to their corresponding {@link TaxonDescritpion}.<br>
89 * This serves as input for the {@link ITreeContentProvider} of the {@link TreeViewer}
90 */
91 protected Map<DescriptionBase<?>, FeatureNodeContainerTree> featureNodeContainerCache = new HashMap<DescriptionBase<?>, FeatureNodeContainerTree>();
92
93 protected ToggleDescriptionAction showAllElementsAction;
94
95 protected ToggleDescriptionAction hideAllElementsAction;
96
97 protected int dndOperations = DND.DROP_COPY | DND.DROP_MOVE;
98
99 private DescriptiveContentProvider provider;
100
101 /** {@inheritDoc} */
102 @Override
103 public void createViewer(Composite parent) {
104 viewer = new TreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL
105 | SWT.V_SCROLL | SWT.FULL_SELECTION));
106 provider = new DescriptiveContentProvider(featureNodeContainerCache);
107 viewer.setContentProvider(provider);
108 viewer.setLabelProvider(new DescriptiveLabelProvider());
109 viewer.setSorter(new DescriptiveViewerSorter());
110 viewer.setAutoExpandLevel(2);
111 Transfer[] transfers = new Transfer[] { DescriptionElementTransfer.getInstance() };
112 viewer.addDragSupport(dndOperations, transfers, new DescriptionElementDragListener(
113 this));
114 viewer.addDropSupport(dndOperations, transfers,
115 new DescriptionElementDropAdapter(viewer));
116
117 // Propagate selection from viewer
118 getSite().setSelectionProvider(viewer);
119
120 showAllElementsAction = new ToggleDescriptionAction(false);
121 hideAllElementsAction = new ToggleDescriptionAction(true);
122
123 // Add context menu to tree
124 createMenu();
125
126 createToolbar();
127
128 // set initial input
129 // if(getEditor() != null){
130 // viewer.setInput(getEditor().getEditorInput());
131 // }
132
133 viewer.addDoubleClickListener(new IDoubleClickListener() {
134 @Override
135 public void doubleClick(DoubleClickEvent event) {
136 //Open derivate editor when specimen description element is double clicked
137 TreeSelection selection = (TreeSelection) viewer.getSelection();
138 Iterator iterator = selection.iterator();
139 Set<UUID> specimenUuids = new HashSet<UUID>();
140 while(iterator.hasNext()){
141 Object next = iterator.next();
142 if(next instanceof IndividualsAssociation){
143 SpecimenOrObservationBase<?> specimen = ((IndividualsAssociation)next).getAssociatedSpecimenOrObservation();
144 if(specimen!=null){
145 specimenUuids.add(specimen.getUuid());
146 }
147 }
148 }
149 try {
150 if(!specimenUuids.isEmpty()){
151 EditorUtil.open(new DerivateViewEditorInput(specimenUuids));
152 }
153 } catch (PartInitException e) {
154 MessagingUtils.error(DescriptiveViewPart.class, "Could not open Derivative Editor", e);
155 }
156
157
158 //TODO: extend command to accept parameter to open editor
159 // String commandId = "eu.etaxonomy.taxeditor.editor.handler.openDerivateView";
160 // IHandlerService handlerService = (IHandlerService) AbstractUtility.getService(IHandlerService.class);
161 // try {
162 // handlerService.executeCommand(commandId, null);
163 // } catch (ExecutionException e) {
164 // MessagingUtils.error(DerivateSearchCompositeController.class, e);
165 // } catch (NotDefinedException e) {
166 // MessagingUtils.error(DerivateSearchCompositeController.class, e);
167 // } catch (NotEnabledException e) {
168 // MessagingUtils.error(DerivateSearchCompositeController.class, e);
169 // } catch (NotHandledException e) {
170 // MessagingUtils.error(DerivateSearchCompositeController.class, e);
171 // }
172
173 }
174 });
175 }
176
177 /* (non-Javadoc)
178 * @see eu.etaxonomy.taxeditor.model.AbstractCdmViewPart#getInitialSelection()
179 */
180 /** {@inheritDoc} */
181 @Override
182 protected ISelection getInitialSelection() {
183 if(getEditor() != null){
184 return new StructuredSelection(getEditor().getEditorInput());
185 }
186
187 return super.getInitialSelection();
188 }
189
190 protected void createToolbar() {
191 IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager();
192 toolBarManager.add(showAllElementsAction);
193 toolBarManager.add(hideAllElementsAction);
194 }
195
196 /*
197 * TODO add to the views menu
198 */
199 protected void createMenu(){
200 MenuManager menuManager = new MenuManager();
201 menuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
202
203 getSite().registerContextMenu(menuManager, viewer);
204
205 // FIXME for some reason this is not working
206 menuManager.add(showAllElementsAction);
207 menuManager.add(hideAllElementsAction);
208
209 Control control = viewer.getControl();
210 Menu menu = menuManager.createContextMenu(control);
211
212 control.setMenu(menu);
213 }
214
215 /** {@inheritDoc} */
216 @Override
217 protected void selectionChanged_internal(IWorkbenchPart part, ISelection selection) {
218 if(AbstractUtility.getActiveEditor() == null){
219 setPartName(createPartTitle(null));
220 showEmptyPage();
221 return;
222 }
223
224 if(part == this){
225 return;
226 }
227 if (part instanceof DetailsViewPart || part instanceof SupplementalDataViewPart
228 || part instanceof MediaViewPart) {
229 // do not show empty page as these views are also used to edit the
230 // description selected in this view
231 return;
232 }
233 // unpackage TreeNode of DerivateView
234 else if(part instanceof DerivateView){
235 TreeNode treeNodeOfSelection = EditorUtil.getTreeNodeOfSelection(selection);
236 if(treeNodeOfSelection!=null){
237 selection = new StructuredSelection(treeNodeOfSelection.getValue());
238 }
239 }
240 else if(part instanceof ChecklistEditor){
241 if(selection instanceof StructuredSelection && ((IStructuredSelection) selection).getFirstElement() instanceof Taxon){
242 Taxon taxon = (Taxon)((IStructuredSelection) selection).getFirstElement();
243 selection = new StructuredSelection(taxon);
244 }
245 }
246 if(selection instanceof IStructuredSelection
247 && ((IStructuredSelection) selection).getFirstElement() instanceof IDescribable<?>
248 && part instanceof IPartContentHasFactualData && !(((IStructuredSelection) selection).getFirstElement() instanceof SpecimenOrObservationBase && part instanceof BulkEditor)){
249 featureNodeContainerCache.clear();
250 setPartName(createPartTitle(((IStructuredSelection) selection).getFirstElement()));
251 showViewer(part, (IStructuredSelection) selection);
252 return;
253 }
254 else{
255 setPartName(createPartTitle(null));
256 showEmptyPage();
257 }
258 }
259
260 protected String getViewName(){
261 return "Factual Data";
262 }
263
264 private String createPartTitle(Object selectedObject){
265 if(selectedObject!=null){
266 return getViewName()+": "+selectedObject;
267 }
268 return getViewName();
269 }
270
271 /**
272 *
273 * @author n.hoffmann
274 * @created May 28, 2010
275 * @version 1.0
276 */
277 protected class ToggleDescriptionAction extends Action{
278 private final boolean expanded;
279
280 public ToggleDescriptionAction(boolean expand){
281 super(null, IAction.AS_PUSH_BUTTON);
282 expanded = expand;
283 setImageAndTooltip();
284 }
285
286 private void setImageAndTooltip(){
287 setImageDescriptor(new ImageDescriptor() {
288 @Override
289 public ImageData getImageData() {
290 setText(expanded ? "Collapse All" : "Expand All");
291 String resource = expanded ? ImageResources.COLLAPSE_ALL : ImageResources.EXPAND_ALL;
292 return ImageResources.getImage(resource).getImageData();
293 }
294 });
295
296 String toolTipText = expanded ? "Collapse all" : "Show all factual data";
297 setToolTipText(toolTipText);
298 }
299
300 @Override
301 public void run() {
302 if(expanded){
303 viewer.collapseAll();
304 }else{
305 viewer.expandAll();
306 }
307 setImageAndTooltip();
308 }
309 }
310
311 /** {@inheritDoc} */
312 @Override
313 public boolean postOperation(CdmBase objectAffectedByOperation) {
314 return super.postOperation(objectAffectedByOperation);
315 }
316
317 /** {@inheritDoc} */
318 @Override
319 public void changed(Object object) {
320 for(FeatureNodeContainerTree containerTree : featureNodeContainerCache.values()){
321 containerTree.buildTree();
322 }
323 viewer.expandToLevel(2);
324 viewer.refresh();
325
326 if(object instanceof DescriptionElementBase){
327 DescriptionElementBase descriptionElement = (DescriptionElementBase) object;
328 DescriptionBase description = descriptionElement.getInDescription();
329 FeatureNodeContainerTree containerTree = featureNodeContainerCache.get(description);
330
331 FeatureNodeContainer featureNodeContainer = containerTree.getFeatureNodeContainerForDescriptionElement(descriptionElement);
332 viewer.expandToLevel(featureNodeContainer, 1);
333
334 }
335
336 if(object != null){
337 StructuredSelection selection = new StructuredSelection(object);
338 viewer.setSelection(selection, true);
339 }
340 if(part instanceof BulkEditor && !(object instanceof SpecimenOrObservationBase<?>)){
341 ((BulkEditor) part).forceDirty();
342 }
343
344 super.changed(object);
345 }
346
347 /** {@inheritDoc} */
348 @Override
349 public Viewer getViewer() {
350 return viewer;
351 }
352
353 /**
354 * <p>onComplete</p>
355 *
356 * @return a boolean.
357 */
358 @Override
359 public boolean onComplete() {
360 return false;
361 }
362
363 public void toggleShowOnlyIndividualAssociations(){
364 provider.toggleShowOnlyIndividualAssociations();
365 viewer.refresh();
366 }
367 }