package eu.etaxonomy.taxeditor.prototype2.controller;\r
\r
import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
import org.eclipse.ui.IEditorInput;\r
import org.eclipse.ui.PartInitException;\r
+import org.eclipse.ui.PlatformUI;\r
\r
import eu.etaxonomy.cdm.model.name.BotanicalName;\r
import eu.etaxonomy.cdm.model.name.Rank;\r
import eu.etaxonomy.cdm.model.taxon.Taxon;\r
import eu.etaxonomy.taxeditor.prototype2.view.MultiPageTaxonView;\r
+import eu.etaxonomy.taxeditor.prototype2.view.NameListView;\r
+import eu.etaxonomy.taxeditor.prototype2.view.TaxonomicTreeViewer;\r
import eu.etaxonomy.taxeditor.prototype2.model.NameEditorInput;\r
import eu.etaxonomy.taxeditor.prototype2.Activator;\r
\r
\r
public void run() {\r
\r
- // if this is a non-empty taxon being opened for the first time,\r
+ // If this is a non-empty taxon being opened for the first time,\r
// add to recent names list \r
if (taxon.getName().getNameCache() != null &&\r
!Activator.getDefault().getObservableRecentNamesList().contains(taxon))\r
- Activator.getDefault().getObservableRecentNamesList().add(taxon);\r
+ Activator.getDefault().getObservableRecentNamesList().add(0, taxon);\r
\r
+ // If this is not visible in the tree, open node\r
+ ((TaxonomicTreeViewer) ((NameListView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().\r
+ findView(NameListView.ID)).getTreeViewer()).revealTaxon(taxon);\r
+ \r
IEditorInput input = new NameEditorInput(taxon);\r
try {\r
Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().\r
}\r
\r
public void run() {\r
-\r
new OpenNameEditorAction(taxon).run();\r
}\r
}
\ No newline at end of file
package eu.etaxonomy.taxeditor.prototype2.controller;\r
\r
import org.eclipse.jface.action.Action;\r
+import org.eclipse.ui.PlatformUI;\r
\r
import eu.etaxonomy.cdm.model.taxon.Taxon;\r
import eu.etaxonomy.taxeditor.prototype2.Activator;\r
+import eu.etaxonomy.taxeditor.prototype2.view.NameListView;\r
+import eu.etaxonomy.taxeditor.prototype2.view.TaxonomicTreeViewer;\r
\r
/**\r
* Commit any changes to this taxon to the CDM\r
\r
public void run() {\r
\r
- // If this is a new taxon, add it to the tax. tree and recent names\r
- if (!Activator.getDefault().getObservableTaxonTreeList().contains(taxon)) { \r
- Activator.getDefault().getObservableTaxonTreeList().add(taxon);\r
- Activator.getDefault().getObservableRecentNamesList().add(taxon);\r
- }\r
+ // If this is a new taxon, add it to the recent names list;\r
+ // if it is already in the tree, remove then re-add it\r
+ // to force a re-sort\r
+ if (!Activator.getDefault().getObservableTaxonTreeList().contains(taxon)) {\r
+ Activator.getDefault().getObservableRecentNamesList().add(0, taxon);\r
+ } else {\r
+ Activator.getDefault().getObservableTaxonTreeList().remove(taxon);\r
+ } \r
+ Activator.getDefault().getObservableTaxonTreeList().add(taxon);\r
\r
+ // Save the taxon to the CDM\r
Activator.getDefault().getCdmApp().getTaxonService().saveTaxon(taxon);\r
\r
// Notify taxon listeners in case name has been updated \r
import eu.etaxonomy.cdm.model.taxon.Taxon;\r
import eu.etaxonomy.taxeditor.prototype2.view.TaxonomicTreeViewer;\r
\r
+/**\r
+ * Adds tree functionality (get parent, get children) to ObservableListContentProvider;\r
+ * much code was copied almost in tact from parent class due to\r
+ * viewer type restrictions and private settings of variables and methods\r
+ * \r
+ * @author p.ciardelli\r
+ *\r
+ */\r
public class NameTreeContentProvider extends ObservableListContentProvider \r
implements ITreeContentProvider {\r
\r
package eu.etaxonomy.taxeditor.prototype2.view;\r
\r
-import java.beans.IntrospectionException;\r
import java.beans.PropertyChangeEvent;\r
import java.beans.PropertyChangeListener;\r
-import java.beans.PropertyDescriptor;\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.lang.reflect.Method;\r
import java.util.ArrayList;\r
import java.util.List;\r
\r
import org.eclipse.core.runtime.IProgressMonitor;\r
import org.eclipse.jface.text.Document;\r
import org.eclipse.jface.text.IDocument;\r
-import org.eclipse.jface.text.IDocumentPartitioner;\r
import org.eclipse.jface.text.Position;\r
-import org.eclipse.jface.text.Region;\r
import org.eclipse.jface.text.source.AnnotationModel;\r
import org.eclipse.jface.text.source.AnnotationPainter;\r
-import org.eclipse.jface.text.source.CompositeRuler;\r
import org.eclipse.jface.text.source.IAnnotationAccess;\r
-import org.eclipse.jface.text.source.ISourceViewer;\r
import org.eclipse.jface.text.source.SourceViewer;\r
import org.eclipse.swt.SWT;\r
import org.eclipse.swt.custom.StyledText;\r
import com.swtdesigner.SWTResourceManager;\r
\r
import eu.etaxonomy.cdm.model.name.BotanicalName;\r
-import eu.etaxonomy.cdm.model.name.NameRelationshipType;\r
import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;\r
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;\r
import eu.etaxonomy.cdm.model.taxon.Taxon;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;\r
import eu.etaxonomy.taxeditor.prototype2.Activator;\r
import eu.etaxonomy.taxeditor.prototype2.controller.DeleteTaxonAction;\r
import eu.etaxonomy.taxeditor.prototype2.controller.OpenNameEditorAction;\r
import eu.etaxonomy.taxeditor.prototype2.model.PropertySheetNode;\r
import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.AnnotationMarkerAccess;\r
import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.ErrorAnnotation;\r
-import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.NameDocument;\r
-import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.NamePartitionScanner;\r
-import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.NamePartitioner;\r
-import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.NameViewerConfig;\r
import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.NameViewerKeyListener;\r
import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.NameViewerModifyListener;\r
-import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.SimpleNamePartitioner;\r
import eu.etaxonomy.taxeditor.prototype2.view.propertysheetsupport.PropertySheetContentProvider;\r
import eu.etaxonomy.taxeditor.prototype2.view.propertysheetsupport.PropertySheetValueEditingSupport;\r
import eu.etaxonomy.taxeditor.prototype2.view.propertysheetsupport.PropertySheetValueLabelProvider;\r
import eu.etaxonomy.taxeditor.prototype2.controller.OpenNameEditorAction;\r
\r
//public class NameListView extends ViewPart implements ICdmEventListener {\r
+/**\r
+ * @author p.ciardelli\r
+ *\r
+ */\r
+/**\r
+ * @author p.ciardelli\r
+ *\r
+ */\r
public class NameListView extends ViewPart {\r
\r
private Text searchText;\r
createExpandBar();\r
top.setLayout(gridLayout);\r
top.setTabList(new Control[] {composite, expandBar});\r
- \r
- initDataBindings();\r
}\r
\r
/**\r
taxTreeExpandItem.setControl(taxTreeComposite);\r
\r
treeViewer = new TaxonomicTreeViewer(taxTreeComposite);\r
- treeViewer.addDoubleClickListener(new IDoubleClickListener(){\r
-\r
- public void doubleClick(DoubleClickEvent event) { \r
- Taxon taxon = null;\r
- try {\r
- taxon = (Taxon) ((StructuredSelection)event.getSelection()).getFirstElement();\r
- }catch (Exception e){\r
- e.printStackTrace();\r
- taxon = null;\r
- }\r
- new OpenNameEditorAction(taxon).run();\r
- }\r
- }); \r
}\r
\r
private void createRecentNamesComposite() {\r
recentNamesExpandItem.setControl(recentNamesComposite);\r
\r
recentNamesViewer = new RecentNamesTableViewer(recentNamesComposite);\r
- recentNamesViewer.addDoubleClickListener(new IDoubleClickListener(){\r
-\r
- public void doubleClick(DoubleClickEvent event) { \r
- Taxon taxon = null;\r
- try {\r
- taxon = (Taxon) ((StructuredSelection)event.getSelection()).getFirstElement();\r
- }catch (Exception e){\r
- e.printStackTrace();\r
- taxon = null;\r
- }\r
- new OpenNameEditorAction(taxon).run();\r
- }\r
- }); \r
- \r
- recentNamesExpandItem.setControl(recentNamesComposite); \r
}\r
\r
private void createSearchComposite() {\r
// Set the focus\r
}\r
\r
- \r
- protected DataBindingContext initDataBindings() {\r
- //\r
-// ObservableListContentProvider viewerContentProviderList = new ObservableListContentProvider();\r
-// viewer.setContentProvider(viewerContentProviderList);\r
-// //\r
-// IObservableMap[] viewerLabelProviderMaps = BeansObservables.observeMaps(viewerContentProviderList.getKnownElements(), TaxonName.class, new String[]{"name"});\r
-// viewer.setLabelProvider(new ObservableMapLabelProvider(viewerLabelProviderMaps));\r
-// //\r
-// IObservableList olObjectListObserveList = BeansObservables.observeList(Realm.getDefault(), Activator.getDefault().getTaxonList(), "objectList");\r
-// viewer.setInput(olObjectListObserveList);\r
- \r
- \r
-// ObservableListContentProvider rnViewerContentProviderList = new ObservableListContentProvider();\r
-// recentNamesViewer.setContentProvider(rnViewerContentProviderList);\r
-// //\r
-// IObservableMap[] rnViewerLabelProviderMaps = BeansObservables.observeMaps(rnViewerContentProviderList.getKnownElements(), TaxonName.class, new String[]{"name"});\r
-// recentNamesViewer.setLabelProvider(new ObservableMapLabelProvider(rnViewerLabelProviderMaps));\r
-// //\r
-// IObservableList rnObjectListObserveList = BeansObservables.observeList(Realm.getDefault(), Activator.getDefault().getRecentNamesList(), "taxonList");\r
-// recentNamesViewer.setInput(rnObjectListObserveList); \r
- \r
- //\r
- DataBindingContext bindingContext = new DataBindingContext();\r
- //\r
- //\r
- return bindingContext;\r
+ /**\r
+ * Expose TreeViewer, i.e. to manipulate tree nodes\r
+ * @return\r
+ */\r
+ public TreeViewer getTreeViewer() {\r
+ return treeViewer;\r
}\r
\r
}\r
import org.eclipse.core.databinding.observable.map.IObservableMap;\r
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;\r
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;\r
+import org.eclipse.jface.viewers.DoubleClickEvent;\r
+import org.eclipse.jface.viewers.IDoubleClickListener;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
import org.eclipse.jface.viewers.TableViewer;\r
import org.eclipse.swt.SWT;\r
import org.eclipse.swt.layout.GridData;\r
\r
import eu.etaxonomy.cdm.model.taxon.Taxon;\r
import eu.etaxonomy.taxeditor.prototype2.Activator;\r
+import eu.etaxonomy.taxeditor.prototype2.controller.OpenNameEditorAction;\r
\r
public class RecentNamesTableViewer extends TableViewer {\r
\r
super(parent, SWT.H_SCROLL | SWT.V_SCROLL);\r
this.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));\r
\r
+ // Add content provider\r
ObservableListContentProvider rnViewerContentProviderList = new ObservableListContentProvider();\r
this.setContentProvider(rnViewerContentProviderList);\r
- //\r
+ \r
+ // Label provider that listens for changes to name cache\r
IObservableMap[] rnViewerLabelProviderMaps = BeansObservables.observeMaps(rnViewerContentProviderList.\r
getKnownElements(), Taxon.class, new String[]{"name"});\r
this.setLabelProvider(new ObservableMapLabelProvider(rnViewerLabelProviderMaps) {\r
return ((Taxon) element).getName().getNameCache();\r
} \r
});\r
- //\r
+ \r
+ // Listens for new taxa opened for editing\r
this.setInput(Activator.getDefault().getObservableRecentNamesList());\r
\r
+ // On double click, open name editor\r
+ this.addDoubleClickListener(new IDoubleClickListener(){\r
+\r
+ public void doubleClick(DoubleClickEvent event) { \r
+ Taxon taxon = null;\r
+ try {\r
+ taxon = (Taxon) ((StructuredSelection)event.getSelection()).getFirstElement();\r
+ }catch (Exception e){\r
+ e.printStackTrace();\r
+ taxon = null;\r
+ }\r
+ new OpenNameEditorAction(taxon).run();\r
+ }\r
+ });\r
}\r
}
\ No newline at end of file
import org.eclipse.core.databinding.observable.map.IObservableMap;\r
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;\r
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;\r
+import org.eclipse.jface.viewers.CellEditor;\r
+import org.eclipse.jface.viewers.DoubleClickEvent;\r
+import org.eclipse.jface.viewers.ICellEditorListener;\r
+import org.eclipse.jface.viewers.ICellModifier;\r
+import org.eclipse.jface.viewers.IDoubleClickListener;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.eclipse.jface.viewers.TextCellEditor;\r
import org.eclipse.jface.viewers.TreeViewer;\r
+import org.eclipse.jface.viewers.ViewerComparator;\r
import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.KeyEvent;\r
+import org.eclipse.swt.events.KeyListener;\r
+import org.eclipse.swt.events.MenuAdapter;\r
+import org.eclipse.swt.events.MenuEvent;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.events.SelectionListener;\r
import org.eclipse.swt.layout.GridData;\r
import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Item;\r
+import org.eclipse.swt.widgets.Menu;\r
+import org.eclipse.swt.widgets.MenuItem;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.swt.widgets.Tree;\r
+import org.eclipse.swt.widgets.TreeItem;\r
\r
import eu.etaxonomy.cdm.model.taxon.Taxon;\r
import eu.etaxonomy.taxeditor.prototype2.Activator;\r
+import eu.etaxonomy.taxeditor.prototype2.controller.AddQuickNameAction;\r
+import eu.etaxonomy.taxeditor.prototype2.controller.OpenNameEditorAction;\r
+import eu.etaxonomy.taxeditor.prototype2.controller.RemoveTaxonFromTreeAction;\r
+import eu.etaxonomy.taxeditor.prototype2.controller.SaveTaxonAction;\r
import eu.etaxonomy.taxeditor.prototype2.model.NameTreeContentProvider;\r
\r
/**\r
+ * Taxon tree viewer which responds to events within individual taxa.\r
* \r
- * Tree viewer which shows TaxonList in taxonomic tree form\r
- * and responds to events within individual taxa\r
- * \r
- * Note following from Tree comments:\r
- * \r
- * Style VIRTUAL is used to create a Tree whose TreeItems are to be populated \r
- * by the client on an on-demand basis instead of up-front. This can provide \r
- * significant performance improvements for trees that are very large or for \r
- * which TreeItem population is expensive (for example, retrieving values from \r
- * an external source).\r
- * Here is an example of using a Tree with style VIRTUAL:\r
- * final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.BORDER);\r
- * ...\r
+ * Good overview of TreeViewer: \r
+ * http://www.eclipse.org/articles/Article-TreeViewer/TreeViewerArticle.htm\r
* \r
* @author p.ciardelli\r
*\r
*/\r
public class TaxonomicTreeViewer extends TreeViewer {\r
\r
+ /**\r
+ * Creates a lazy-loading taxonomic tree that is sorted by NameCache,\r
+ * and which listens for name changes and new taxa\r
+ * \r
+ * @param parent\r
+ */\r
public TaxonomicTreeViewer(Composite parent) {\r
+ \r
+ // SW.VIRTUAL causes nodes to be loaded on-demand, improving performance\r
super(parent, SWT.VIRTUAL);\r
\r
- this.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));\r
- this.getTree().setLinesVisible(false);\r
- this.getTree().setHeaderVisible(false); \r
- initDataBindings();\r
- }\r
-\r
- protected void initDataBindings() {\r
- //\r
+ // Use custom content provider extended to add tree node retrieval\r
ObservableListContentProvider viewerContentProviderList = new NameTreeContentProvider();\r
this.setContentProvider(viewerContentProviderList);\r
- //\r
+ \r
+ // Label provider that listens for changes to name cache\r
IObservableMap[] viewerLabelProviderMaps = BeansObservables.observeMaps(viewerContentProviderList.getKnownElements(), \r
Taxon.class, new String[]{"name"});\r
this.setLabelProvider(new ObservableMapLabelProvider(viewerLabelProviderMaps) {\r
return ((Taxon) element).getName().getNameCache();\r
} \r
});\r
- //\r
+ \r
+ // TaxonTreeList added to every time a node is opened with its\r
+ // children, or when a new taxon is added\r
this.setInput(Activator.getDefault().getObservableTaxonTreeList());\r
+ \r
+ // On double click, open name editor\r
+ this.addDoubleClickListener(new IDoubleClickListener(){\r
+\r
+ public void doubleClick(DoubleClickEvent event) { \r
+ Taxon taxon = null;\r
+ try {\r
+ taxon = (Taxon) ((StructuredSelection)event.getSelection()).getFirstElement();\r
+ }catch (Exception e){\r
+ e.printStackTrace();\r
+ taxon = null;\r
+ }\r
+ new OpenNameEditorAction(taxon).run();\r
+ }\r
+ }); \r
+ \r
+ // Sort according to "getColumnText" above, i.e. by NameCache\r
+ this.setComparator(new ViewerComparator());\r
\r
+ // Tree settings\r
+ final Tree tree = this.getTree();\r
+ tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));\r
+ tree.setLinesVisible(false);\r
+ tree.setHeaderVisible(false);\r
+ \r
+ // Make right-click menu for tree nodes\r
+ final Menu menu = new Menu(tree); \r
+ tree.setMenu(menu);\r
+ menu.addMenuListener(new MenuAdapter() {\r
+ public void menuShown(MenuEvent e) {\r
+ \r
+ // Get rid of existing menu items -\r
+ // same menu is re-used for all nodes\r
+ MenuItem[] items = menu.getItems();\r
+ for (int i = 0; i < items.length; i++) {\r
+ ((MenuItem) items[i]).dispose();\r
+ }\r
+ \r
+ // Get Taxon associated with this node\r
+ final Taxon taxon = (Taxon) tree.getSelection()[0].getData();\r
+ \r
+ // Add menu item to edit Taxon\r
+ MenuItem itemEditTaxon = new MenuItem(menu, SWT.NONE);\r
+ itemEditTaxon.setText("Edit taxon");\r
+ itemEditTaxon.addSelectionListener(new SelectionListener() {\r
+ public void widgetDefaultSelected(SelectionEvent e) {}\r
+ public void widgetSelected(SelectionEvent e) {\r
+ new OpenNameEditorAction(taxon).run();\r
+ }\r
+ });\r
+ \r
+ // Add menu item to add a child node and edit name in place \r
+ MenuItem itemQuickAdd = new MenuItem(menu, SWT.NONE);\r
+ itemQuickAdd.setText("Add quick name");\r
+ itemQuickAdd.addSelectionListener(new SelectionListener() {\r
+ public void widgetDefaultSelected(SelectionEvent e) {}\r
+ public void widgetSelected(SelectionEvent e) {\r
+ new AddQuickNameAction(taxon).run(); \r
+ }\r
+ });\r
+ }\r
+ });\r
+ \r
+ // Taxa with no NameCache - i.e. added with quick name -\r
+ // can be edited in place in the tax. tree\r
+ final TextCellEditor taxTreeNodeEditor = new TextCellEditor(tree);\r
+ taxTreeNodeEditor.addListener(new ICellEditorListener() {\r
+ public void applyEditorValue() {}\r
+ public void cancelEditor() {\r
+ // user has pressed ESC - transfer focus to parent item,\r
+ // remove taxon from tree\r
+ Taxon taxon = (Taxon) tree.getSelection()[0].getData();\r
+ tree.setSelection(tree.getSelection()[0].getParentItem());\r
+ new RemoveTaxonFromTreeAction(taxon).run();\r
+ }\r
+ public void editorValueChanged(boolean oldValidState,\r
+ boolean newValidState) {}\r
+ });\r
+ \r
+ this.setCellEditors(new CellEditor[] {taxTreeNodeEditor});\r
+ this.setColumnProperties(new String[] {"col1"});\r
+ this.setCellModifier(new ICellModifier() {\r
+ public boolean canModify(Object element, String property) {\r
+ // if name element has not been initialized,\r
+ // this is a taxon added with QuickAdd\r
+ if (((Taxon) element).getName().getNameCache() == null)\r
+ return true;\r
+ return false;\r
+ }\r
+ public Object getValue(Object element, String property) {\r
+ // If this node is editable, NameCache is by definition empty\r
+ return "";\r
+ }\r
+ public void modify(Object element, String property, Object value) {\r
+ \r
+ // Get Taxon object from TreeItem\r
+ Taxon taxon = (Taxon)((Item) element).getData();\r
+ \r
+ if (((String) value).equals("")) {\r
+ // Remove temporary Taxon from tree\r
+ new RemoveTaxonFromTreeAction(taxon).run(); \r
+ \r
+ } else {\r
+ // Set Taxon's NameCache, save it to CDM\r
+ taxon.getName().setNameCache((String) value);\r
+ new SaveTaxonAction(taxon).run();\r
+ }\r
+ }\r
+ });\r
+ }\r
+ \r
+ /**\r
+ * If taxon node in the tree is hidden, open and select it\r
+ * \r
+ * @param taxon\r
+ */\r
+ public void revealTaxon(Taxon taxon) {\r
+ this.setSelection(new StructuredSelection(taxon), true);\r
+ this.reveal(taxon);\r
}\r
}\r
\r
*/\r
public class PropertySheetValueLabelProvider extends ColumnLabelProvider {\r
\r
- private PropertySheetViewer viewer;\r
- \r
private DataBindingContext bindingContext;\r
\r
public PropertySheetValueLabelProvider(PropertySheetViewer viewer) {\r
- this.viewer = viewer;\r
this.bindingContext = viewer.getBindingContext();\r
}\r
\r