b99aee8d286bf20aea964b4a14e2427f66f8e796
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / view / checklist / ChecklistEditor.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.checklist;
12
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.SortedSet;
20
21 import org.apache.log4j.Logger;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.runtime.jobs.Job;
26 import org.eclipse.jface.viewers.ISelection;
27 import org.eclipse.jface.viewers.StructuredViewer;
28 import org.eclipse.jface.viewers.TableViewer;
29 import org.eclipse.jface.viewers.TableViewerColumn;
30 import org.eclipse.swt.SWT;
31 import org.eclipse.swt.events.ModifyListener;
32 import org.eclipse.swt.events.SelectionAdapter;
33 import org.eclipse.swt.events.SelectionEvent;
34 import org.eclipse.swt.layout.GridData;
35 import org.eclipse.swt.layout.GridLayout;
36 import org.eclipse.swt.widgets.Composite;
37 import org.eclipse.swt.widgets.Display;
38 import org.eclipse.swt.widgets.Label;
39 import org.eclipse.swt.widgets.Menu;
40 import org.eclipse.swt.widgets.Table;
41 import org.eclipse.swt.widgets.TableColumn;
42 import org.eclipse.swt.widgets.Text;
43 import org.eclipse.swt.widgets.ToolBar;
44 import org.eclipse.swt.widgets.ToolItem;
45 import org.eclipse.ui.IEditorInput;
46 import org.eclipse.ui.IEditorSite;
47 import org.eclipse.ui.IMemento;
48 import org.eclipse.ui.ISelectionListener;
49 import org.eclipse.ui.ISelectionService;
50 import org.eclipse.ui.IWorkbenchPart;
51 import org.eclipse.ui.PartInitException;
52 import org.eclipse.ui.part.EditorPart;
53 import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
54
55 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
56 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
57 import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
58 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
59 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
60 import eu.etaxonomy.cdm.model.taxon.Classification;
61 import eu.etaxonomy.cdm.model.taxon.Taxon;
62 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
63 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
64 import eu.etaxonomy.taxeditor.editor.EditorUtil;
65 import eu.etaxonomy.taxeditor.editor.SimpleSelectionProvider;
66 import eu.etaxonomy.taxeditor.editor.view.checklist.edit.DistributionEditingSupport;
67 import eu.etaxonomy.taxeditor.editor.view.checklist.edit.RankEditingSupport;
68 import eu.etaxonomy.taxeditor.editor.view.checklist.filter.ChecklistEditorFilter;
69 import eu.etaxonomy.taxeditor.editor.view.checklist.listener.ChecklistDropdownSelectionListener;
70 import eu.etaxonomy.taxeditor.editor.view.checklist.listener.ChecklistFocusListener;
71 import eu.etaxonomy.taxeditor.editor.view.checklist.listener.ChecklistModifyListener;
72 import eu.etaxonomy.taxeditor.model.IContextListener;
73 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
74 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
75 import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
76 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
77 import eu.etaxonomy.taxeditor.preference.Resources;
78 import eu.etaxonomy.taxeditor.store.CdmStore;
79
80 /**
81 * <p>
82 * ChecklistViewPart class.
83 * </p>
84 *
85 * @author a.oppermann
86 * @created 30.04.2014
87 * @version 1.0
88 */
89 public class ChecklistEditor extends EditorPart implements ISelectionListener, IPartContentHasFactualData,
90 IConversationEnabled, IContextListener, IPartContentHasDetails, IDirtyMarkable {
91
92 private static final Logger logger = Logger.getLogger(ChecklistEditor.class);
93 /**
94 * Key used for storing Checklist Editor View
95 */
96 private static final String CHECKLIST_EDITOR_MEMENTO_KEY = "checklistEditor";
97
98 private class ChecklistJob extends Job {
99
100 private List<TaxonNode> taxonNodes;
101
102 /**
103 * @param name
104 */
105 public ChecklistJob(String title, List<TaxonNode> listTaxonNodes) {
106 super(title);
107 this.taxonNodes = listTaxonNodes;
108
109 }
110
111 /*
112 * (non-Javadoc)
113 *
114 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.
115 * IProgressMonitor)
116 */
117 @Override
118 public IStatus run(final IProgressMonitor monitor) {
119 try {
120 logger.debug("Begin of eclipse core runtime Job to Retrieve datasources");
121 monitor.beginTask("Retrieving TaxonNodes", taxonNodes.size() + 1);
122
123 final List<Taxon> taxonList = new ArrayList<Taxon>();
124
125 for (TaxonNode taxonNode : taxonNodes) {
126 HibernateProxyHelper hh = new HibernateProxyHelper();
127 Taxon taxon = hh.deproxy(taxonNode.getTaxon(), Taxon.class);
128 taxonList.add(taxon);
129 }
130 // set View input
131 Display.getDefault().asyncExec(new Runnable() {
132
133 @Override
134 public void run() {
135 viewer.setInput(taxonList);
136 }
137 });
138 monitor.worked(1);
139
140 } finally {
141 monitor.done();
142 taxonNodes = null;
143 }
144 return Status.OK_STATUS;
145 }
146 }
147
148 /**
149 * Constant
150 * <code>ID="eu.etaxonomy.taxeditor.store.datasource"{trunked}</code>
151 */
152 public static String ID = "eu.etaxonomy.taxeditor.editor.view.checklist.ChecklistEditor";
153
154 private TableViewer viewer;
155
156 private String partNameCache;
157
158 private IWorkbenchSiteProgressService service;
159
160 private ITaxonNodeService taxonNodeService;
161
162 private ChecklistEditorComparator comparator;
163
164 private ChecklistEditorInput checklistEditorInput;
165
166 private SimpleSelectionProvider simpleSelectionProvider;
167
168 private ISelectionService selectionService;
169
170 private ConversationHolder conversation;
171
172 private Integer countNodes;
173
174 private List<TaxonNode> selectedTaxonNodes;
175
176 private boolean dirty;
177
178 private ChecklistEditorFilter filter;
179
180 private Menu headerMenu;
181
182 private Label statusLabel;
183
184 private SortedSet<DefinedTermBase> terms = null;
185
186 /**
187 * @return the selectedTaxonNodes
188 */
189 public List<TaxonNode> getSelectedTaxonNodes() {
190 return selectedTaxonNodes;
191 }
192
193 /**
194 * @param selectedTaxonNodes
195 * the selectedTaxonNodes to set
196 */
197 public void setSelectedTaxonNodes(List<TaxonNode> selectedTaxonNodes) {
198 this.selectedTaxonNodes = selectedTaxonNodes;
199 }
200
201 /**
202 * <p>
203 * Constructor for CdmDataSourceViewPart.
204 * </p>
205 */
206 public ChecklistEditor() {
207 }
208
209 /** {@inheritDoc} */
210 @Override
211 public void createPartControl(Composite parent) {
212 service = (IWorkbenchSiteProgressService) getSite().getAdapter(IWorkbenchSiteProgressService.class);
213 taxonNodeService = CdmStore.getService(ITaxonNodeService.class);
214 selectionService = getSite().getWorkbenchWindow().getSelectionService();
215 selectionService.addSelectionListener(this);
216 filter = new ChecklistEditorFilter();
217 ChecklistLabelProvider labelProvider = new ChecklistLabelProvider();
218 terms = (SortedSet<DefinedTermBase>) labelProvider.getTermsOrderedByLabels(labelProvider.getNamedAreas(),
219 CdmStore.getDefaultLanguage());
220 createTopComposite(parent);
221 loadDataInput();
222 }
223
224 /**
225 * @param parent
226 */
227 private void createTopComposite(Composite parent) {
228 GridLayout gridLayout = new GridLayout(3, false);
229 gridLayout.marginWidth = 0;
230 gridLayout.marginHeight = 0;
231 parent.setLayout(gridLayout);
232
233 final Text searchText = createSearchBar(parent);
234
235 // if (terms != null && !terms.isEmpty()) {
236 createToolbar(parent);
237 // }
238 viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
239 getSite().setSelectionProvider(viewer);
240
241 final ModifyListener modifyListener = new ChecklistModifyListener(viewer, filter, searchText);
242
243 searchText.addFocusListener(new ChecklistFocusListener(searchText, modifyListener));
244 searchText.addModifyListener(modifyListener);
245
246 // Layout the viewer
247 GridData gridData = new GridData();
248 gridData.verticalAlignment = GridData.FILL;
249 gridData.horizontalSpan = 3;
250 gridData.grabExcessHorizontalSpace = true;
251 gridData.grabExcessVerticalSpace = true;
252 gridData.horizontalAlignment = GridData.FILL;
253 viewer.getControl().setLayoutData(gridData);
254
255 viewer.addFilter(filter);
256 createColumns(viewer);
257
258 viewer.setContentProvider(new ChecklistContentProvider());
259 viewer.setLabelProvider(new ChecklistLabelProvider());
260 comparator = new ChecklistEditorComparator();
261 viewer.setComparator(comparator);
262
263 createStatusBar(parent);
264 }
265
266 /**
267 * @param parent
268 * @return
269 */
270 private Text createSearchBar(Composite parent) {
271 Label searchLabel = new Label(parent, SWT.NONE);
272 searchLabel.setText("Search: ");
273 final Text searchText = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.CANCEL);
274 searchText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
275 searchText.setForeground(EditorUtil.getColor(Resources.SEARCH_VIEW_FOREGROUND));
276 searchText.setText("type filter text");
277 return searchText;
278 }
279
280 /**
281 * @param parent
282 */
283 private void createToolbar(Composite parent) {
284 ToolBar toolBar = new ToolBar(parent, SWT.NONE);
285 ToolItem toolItem = new ToolItem(toolBar, SWT.DROP_DOWN | SWT.BORDER);
286 toolItem.setText("Distribution Status");
287 toolItem.setToolTipText("Show Distribution Status for selected Areas");
288 ChecklistDropdownSelectionListener dropListener = new ChecklistDropdownSelectionListener(toolItem, this, terms);
289 for (DefinedTermBase<DefinedTermBase> term : terms) {
290 if(term!=null){
291 dropListener.add(term);
292 }
293 }
294 toolItem.addSelectionListener(dropListener);
295 toolBar.pack();
296 }
297
298 private void createStatusBar(Composite composite) {
299 GridData gridData = new GridData();
300 gridData.horizontalSpan = 3;
301 gridData.grabExcessHorizontalSpace = true;
302 gridData.horizontalAlignment = GridData.FILL;
303
304 statusLabel = new Label(composite, SWT.LEFT);
305 statusLabel.setText("Anzahl der Elemente: " + (countNodes != null ? countNodes : "uknown"));
306 statusLabel.setLayoutData(gridData);
307 }
308
309 // This will create the columns for the table
310 private void createColumns(TableViewer viewer) {
311 Table table = viewer.getTable();
312 List<String> titles = new ArrayList<String>();
313 Collections.addAll(titles, "Taxon", "Author", "Reference", "Rank");
314 List<Integer> bounds = new ArrayList<Integer>();
315 Collections.addAll(bounds, 300, 200, 200, 200);
316 Map<Integer, Boolean>restoreColumnWidth = new HashMap<Integer, Boolean>();
317 if (terms != null) {
318 int i = 4;
319 for (DefinedTermBase<DefinedTermBase> term : terms) {
320 if(term != null){
321 restoreColumnWidth.put(i, PreferencesUtil.getPreferenceStore().getBoolean(term.getUuid().toString()));
322 titles.add(term.getTitleCache());
323 bounds.add(200);
324 i++;
325 }
326 }
327 }
328
329 for (int i = 0; i < titles.size(); i++) {
330 TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
331 column.getColumn().setText(titles.get(i));
332 column.getColumn().setWidth(bounds.get(i));
333 column.getColumn().setResizable(true);
334 column.getColumn().setMoveable(true);
335 column.getColumn().addSelectionListener(getSelectionAdapter(column.getColumn(), i));
336 if (i == 1) {
337 table.setSortColumn(column.getColumn());
338 }
339 if (i == 3) {
340 /** uncommented it for now because no rank editing is wanted **/
341 // column.setEditingSupport(new RankEditingSupport(viewer, this));
342 }
343 if (i >= 4) {
344 //read PrefrenceStore to setWidth according to last saved state
345 if(restoreColumnWidth.get(i)){
346 column.getColumn().setWidth(100);
347 }else{
348 column.getColumn().setWidth(0);
349 }
350 column.setEditingSupport(new DistributionEditingSupport(viewer, this, i));
351 }
352 }
353 table.setSortDirection(SWT.DOWN);
354 table.setHeaderVisible(true);
355 table.setLinesVisible(true);
356 }
357
358 /**
359 *
360 * pull data from database and set input for view
361 *
362 */
363 private void loadDataInput() {
364 Classification classification = checklistEditorInput.getClassification();
365 TaxonNode taxonNode = checklistEditorInput.getTaxonNode();
366 if (classification != null && taxonNode == null) {
367 countNodes = taxonNodeService.countAllNodesForClassification(classification);
368 statusLabel.setText("Anzahl der Elemente: " + (countNodes != null ? countNodes : "uknown"));
369 // This should not kill the view nor the editor if something goes
370 // wrong
371 // TODO: don't load the whole taxonNode Object but rather a small
372 // and simple Solution
373 // FIXME: May be don't open classification which are greater than
374 // 3000 Taxa
375 selectedTaxonNodes = taxonNodeService.listAllNodesForClassification(classification, 0, countNodes);
376 getService().schedule(new ChecklistJob("loading Taxa", selectedTaxonNodes), Job.LONG);
377 }
378 if (taxonNode != null) {
379 selectedTaxonNodes = taxonNodeService.loadChildNodesOfTaxonNode(taxonNode, NODE_INIT_STRATEGY, true, false);
380 getService().schedule(new ChecklistJob("loading Taxa", selectedTaxonNodes), Job.LONG);
381 }
382 }
383
384 /** {@inheritDoc} */
385 @Override
386 public void dispose() {
387 super.dispose();
388 }
389
390 /** {@inheritDoc} */
391 @Override
392 public void setFocus() {
393 viewer.getControl().setFocus();
394 }
395
396 /*
397 * (non-Javadoc)
398 *
399 * @see org.eclipse.ui.part.WorkbenchPart#showBusy(boolean)
400 */
401 /** {@inheritDoc} */
402 @Override
403 public void showBusy(boolean busy) {
404 super.showBusy(busy);
405 // viewer.getTable().setEnabled(!busy);
406 if (busy) {
407 partNameCache = getPartName();
408 setPartName("Loading " + countNodes + " Taxa...");
409 } else {
410 if (partNameCache != null) {
411 setPartName(partNameCache);
412 }
413 }
414 }
415
416 /**
417 * <p>
418 * Getter for the field <code>viewer</code>.
419 * </p>
420 *
421 * @return a {@link org.eclipse.jface.viewers.StructuredViewer} object.
422 */
423 public StructuredViewer getViewer() {
424 return viewer;
425 }
426
427 public void refresh() {
428 viewer.refresh();
429 }
430
431 /**
432 * <p>
433 * Getter for the field <code>service</code>.
434 * </p>
435 *
436 * @return the service
437 */
438 public IWorkbenchSiteProgressService getService() {
439 return service;
440 }
441
442 private SelectionAdapter getSelectionAdapter(final TableColumn column, final int index) {
443 SelectionAdapter selectionAdapter = new SelectionAdapter() {
444 @Override
445 public void widgetSelected(SelectionEvent e) {
446 comparator.setColumn(index);
447 int dir = viewer.getTable().getSortDirection();
448 if (viewer.getTable().getSortColumn() == column) {
449 dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
450 } else {
451 dir = SWT.DOWN;
452 }
453 viewer.getTable().setSortDirection(dir);
454 viewer.getTable().setSortColumn(column);
455 viewer.refresh();
456 }
457 };
458 return selectionAdapter;
459 }
460
461 @Override
462 public void doSave(IProgressMonitor monitor) {
463 try {
464 monitor.beginTask("Saving Editor", 1);
465 getConversationHolder().bind();
466 getConversationHolder().commit(true);
467 setDirty(false);
468 monitor.worked(1);
469 } finally {
470 monitor.done();
471 }
472
473 }
474
475 @Override
476 public void doSaveAs() {
477 // TODO Auto-generated method stub
478
479 }
480
481 @Override
482 public void init(IEditorSite site, IEditorInput input) throws PartInitException {
483 setSite(site);
484 setInput(input);
485 if (input instanceof ChecklistEditorInput) {
486 checklistEditorInput = (ChecklistEditorInput) input;
487 setPartName(getPartName() + ": " + checklistEditorInput.getName());
488 conversation = ((ChecklistEditorInput) input).getConversationHolder();
489 }
490 simpleSelectionProvider = new SimpleSelectionProvider();
491 getSite().setSelectionProvider(simpleSelectionProvider);
492 }
493
494 @Override
495 public boolean isSaveAsAllowed() {
496 // TODO Auto-generated method stub
497 return false;
498 }
499
500 /*
501 * (non-Javadoc)
502 *
503 * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.
504 * IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
505 */
506 @Override
507 public void selectionChanged(IWorkbenchPart part, ISelection selection) {
508 // TODO Auto-generated method stub
509
510 }
511
512 /*
513 * (non-Javadoc)
514 *
515 * @see
516 * eu.etaxonomy.cdm.persistence.hibernate.ICdmPostDataChangeObserver#update
517 * (eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap)
518 */
519 @Override
520 public void update(CdmDataChangeMap changeEvents) {
521
522 }
523
524 /*
525 * (non-Javadoc)
526 *
527 * @see
528 * eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder
529 * ()
530 */
531 @Override
532 public ConversationHolder getConversationHolder() {
533 return conversation;
534 }
535
536 /*
537 * (non-Javadoc)
538 *
539 * @see
540 * eu.etaxonomy.taxeditor.model.IContextListener#contextAboutToStop(org.
541 * eclipse.ui.IMemento, org.eclipse.core.runtime.IProgressMonitor)
542 */
543
544 @Override
545 public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
546
547 }
548
549 /*
550 * (non-Javadoc)
551 *
552 * @see
553 * eu.etaxonomy.taxeditor.model.IContextListener#contextStop(org.eclipse
554 * .ui.IMemento, org.eclipse.core.runtime.IProgressMonitor)
555 */
556 @Override
557 public void contextStop(IMemento memento, IProgressMonitor monitor) {
558 // TODO Auto-generated method stub
559 // IStructuredSelection sel = (IStructuredSelection) this.viewer.getSelection();
560 // if (sel.isEmpty()) {
561 // return;
562 // }
563 // memento = memento.createChild("tree-selections");
564 // Iterator iter = sel.iterator();
565 // while (iter.hasNext()) {
566 // String nodeName = (String) iter.next();
567 // memento.createChild("selected-nodes", nodeName);
568 // }
569 }
570
571 /*
572 * (non-Javadoc)
573 *
574 * @see
575 * eu.etaxonomy.taxeditor.model.IContextListener#contextStart(org.eclipse
576 * .ui.IMemento, org.eclipse.core.runtime.IProgressMonitor)
577 */
578 @Override
579 public void contextStart(IMemento memento, IProgressMonitor monitor) {
580
581 }
582
583 /*
584 * (non-Javadoc)
585 *
586 * @see
587 * eu.etaxonomy.taxeditor.model.IContextListener#contextRefresh(org.eclipse
588 * .core.runtime.IProgressMonitor)
589 */
590 @Override
591 public void contextRefresh(IProgressMonitor monitor) {
592 // TODO Auto-generated method stub
593
594 }
595
596 /*
597 * (non-Javadoc)
598 *
599 * @see
600 * eu.etaxonomy.taxeditor.model.IContextListener#workbenchShutdown(org.eclipse
601 * .ui.IMemento, org.eclipse.core.runtime.IProgressMonitor)
602 */
603 @Override
604 public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
605 conversation.clear();
606 conversation.close();
607 conversation = null;
608 }
609
610 private static final List<String> NODE_INIT_STRATEGY = Arrays.asList(new String[] { "descriptions",
611 "descriptions.*", "description.state", "feature", "feature.*", "childNodes", "childNodes.taxon",
612 "childNodes.taxon.name", "taxonNodes", "taxonNodes.*", "taxonNodes.taxon.*", "taxon.*",
613 "taxon.descriptions", "taxon.sec", "taxon.name.*", "taxon.synonymRelations", "terms", "name.*",
614 "name.rank.representations", "name.status.type.representations", "sources.$", "stateData.$" });
615
616 /*
617 * (non-Javadoc)
618 *
619 * @see
620 * eu.etaxonomy.taxeditor.model.IDirtyMarkableSelectionProvider#changed(
621 * java.lang.Object)
622 */
623 @Override
624 public void changed(Object element) {
625 if (element != null) {
626 viewer.update(element, null);
627 setDirty(true);
628 firePropertyChange(PROP_DIRTY);
629 }
630 }
631
632 /* (non-Javadoc)
633 * @see eu.etaxonomy.taxeditor.model.IDirtyMarkableSelectionProvider#forceDirty()
634 */
635 @Override
636 public void forceDirty() {
637 changed(null);
638 }
639
640 public void setDirty(boolean dirty) {
641 this.dirty = dirty;
642 firePropertyChange(PROP_DIRTY);
643 }
644
645 /*
646 * (non-Javadoc)
647 *
648 * @see org.eclipse.ui.forms.editor.FormEditor#isDirty()
649 */
650 @Override
651 public boolean isDirty() {
652 return dirty;
653 }
654 }