StatusComposite, IStatusComposite : added font awesome refresh icon, updated checkbox...
authorCherian Mathew <c.mathew@bgbm.org>
Wed, 1 Apr 2015 11:27:59 +0000 (11:27 +0000)
committerCherian Mathew <c.mathew@bgbm.org>
Wed, 1 Apr 2015 11:27:59 +0000 (11:27 +0000)
CdmSQLContainer : added methods to disable change ebents and possiblity to add items
LeafNodeTaxonContainer : corrected and split queris for taxon and synonyms
StatusPresenter : moving filter / query logic to container
StatusEditorUI : using new edit theme
CdmQueryFactory : new factory for sql queries
StatusPresenterTest, StatusPresenterTest : added tests for loading synonyms

.gitattributes
src/main/java/eu/etaxonomy/cdm/vaadin/component/StatusComposite.java
src/main/java/eu/etaxonomy/cdm/vaadin/container/CdmSQLContainer.java
src/main/java/eu/etaxonomy/cdm/vaadin/container/LeafNodeTaxonContainer.java
src/main/java/eu/etaxonomy/cdm/vaadin/presenter/StatusPresenter.java
src/main/java/eu/etaxonomy/cdm/vaadin/ui/StatusEditorUI.java
src/main/java/eu/etaxonomy/cdm/vaadin/util/CdmQueryFactory.java [new file with mode: 0644]
src/main/java/eu/etaxonomy/cdm/vaadin/view/IStatusComposite.java
src/test/java/eu/etaxonomy/cdm/vaadin/presenter/StatusPresenterTest.java
src/test/resources/eu/etaxonomy/cdm/vaadin/presenter/StatusPresenterTest.xml

index b4e38841bfc4ebd6faa5afca6a5a9f17dd963033..4d9708e6d47dec4703b3144d6ae0f1ff65c04752 100644 (file)
@@ -30,6 +30,7 @@ src/main/java/eu/etaxonomy/cdm/vaadin/ui/AbstractAuthenticatedUI.java -text
 src/main/java/eu/etaxonomy/cdm/vaadin/ui/CheckUI.java -text
 src/main/java/eu/etaxonomy/cdm/vaadin/ui/DbStatusUI.java -text
 src/main/java/eu/etaxonomy/cdm/vaadin/ui/StatusEditorUI.java -text
+src/main/java/eu/etaxonomy/cdm/vaadin/util/CdmQueryFactory.java -text
 src/main/java/eu/etaxonomy/cdm/vaadin/util/CdmSQLStringDecorator.java -text
 src/main/java/eu/etaxonomy/cdm/vaadin/util/CdmSpringContextHelper.java -text
 src/main/java/eu/etaxonomy/cdm/vaadin/view/AuthenticationView.java -text
index 3812490488aacdb0b336dccdcd739a8659e5f462..564901a06f317025b0c605242f41e997304db170 100644 (file)
@@ -24,9 +24,10 @@ import com.vaadin.data.util.IndexedContainer;
 import com.vaadin.data.util.sqlcontainer.RowId;
 import com.vaadin.event.Action;
 import com.vaadin.event.FieldEvents;
-import com.vaadin.event.FieldEvents.FocusEvent;
 import com.vaadin.event.FieldEvents.TextChangeEvent;
-import com.vaadin.server.ThemeResource;
+import com.vaadin.event.LayoutEvents.LayoutClickEvent;
+import com.vaadin.event.LayoutEvents.LayoutClickListener;
+import com.vaadin.server.FontAwesome;
 import com.vaadin.ui.Alignment;
 import com.vaadin.ui.Button;
 import com.vaadin.ui.Button.ClickEvent;
@@ -42,10 +43,12 @@ import com.vaadin.ui.Notification.Type;
 import com.vaadin.ui.Table;
 import com.vaadin.ui.Table.ColumnHeaderMode;
 import com.vaadin.ui.TextField;
+import com.vaadin.ui.Tree.ExpandEvent;
+import com.vaadin.ui.Tree.ExpandListener;
+import com.vaadin.ui.TreeTable;
 import com.vaadin.ui.VerticalLayout;
-import com.vaadin.ui.themes.Reindeer;
 
-import eu.etaxonomy.cdm.vaadin.presenter.StatusPresenter;
+import eu.etaxonomy.cdm.vaadin.container.LeafNodeTaxonContainer;
 import eu.etaxonomy.cdm.vaadin.view.IStatusComposite;
 
 /**
@@ -62,13 +65,7 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
     @AutoGenerated
     private Label inViewLabel;
     @AutoGenerated
-    private Table taxaTreeTable;
-    @AutoGenerated
-    private HorizontalLayout addRemovehorizontalLayout;
-    @AutoGenerated
-    private Button removeButton;
-    @AutoGenerated
-    private ComboBox addComboBox;
+    private TreeTable taxaTreeTable;
     @AutoGenerated
     private HorizontalLayout searchHorizontalLayout;
     @AutoGenerated
@@ -76,6 +73,12 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
     @AutoGenerated
     private TextField searchTextField;
     @AutoGenerated
+    private HorizontalLayout addRemovehorizontalLayout;
+    @AutoGenerated
+    private Button removeButton;
+    @AutoGenerated
+    private ComboBox addComboBox;
+    @AutoGenerated
     private VerticalLayout filterVerticalLayout;
     @AutoGenerated
     private Table filterTable;
@@ -112,6 +115,15 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
         buildMainLayout();
         setCompositionRoot(mainLayout);
 
+        searchHorizontalLayout.addLayoutClickListener(new LayoutClickListener() {
+
+            @Override
+            public void layoutClick(LayoutClickEvent event) {
+                if (event.getChildComponent() == searchTextField && searchTextField.getValue().equals(FILTER_TAXA_INPUT)) {
+                   searchTextField.setValue("");
+                }
+            }
+        });
         addUIListeners();
         initAddComboBox();
         initSearchTextField();
@@ -130,16 +142,21 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
         taxaTreeTable.setEnabled(enable);
         addComboBox.setEnabled(enable);
         removeButton.setEnabled(enable);
+        searchTextField.setEnabled(enable);
+        clearSearchButton.setEnabled(enable);
     }
 
     private void initTaxaTable(int classificationId) {
 
+        taxaTreeTable.setSelectable(true);
+        taxaTreeTable.setImmediate(false);
+
         if(listener != null) {
             List<String> columnIds = new ArrayList<String>();
-            columnIds.add(StatusPresenter.NAME_ID);
-            taxaTreeTable.setColumnExpandRatio(StatusPresenter.NAME_ID, 1);
-            columnIds.add(StatusPresenter.PB_ID);
-            taxaTreeTable.setColumnWidth(StatusPresenter.PB_ID, -1);
+            columnIds.add(LeafNodeTaxonContainer.NAME_ID);
+            taxaTreeTable.setColumnExpandRatio(LeafNodeTaxonContainer.NAME_ID, 1);
+            columnIds.add(LeafNodeTaxonContainer.PB_ID);
+            taxaTreeTable.setColumnWidth(LeafNodeTaxonContainer.PB_ID, 25);
 
             ValueChangeListener pbListener = new ValueChangeListener() {
                 @Override
@@ -149,13 +166,39 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
                 }
 
             };
-            taxaTreeTable.addGeneratedColumn(StatusPresenter.PB_ID, new BooleanCheckBoxGenerator(pbListener));
+            taxaTreeTable.addGeneratedColumn(LeafNodeTaxonContainer.PB_ID, new BooleanCheckBoxGenerator(pbListener));
             try {
                 taxaTreeTable.setContainerDataSource(listener.loadTaxa(classificationId), columnIds);
             } catch (SQLException e) {
               //TODO : throw up warning dialog
                 e.printStackTrace();
             }
+
+            taxaTreeTable.addExpandListener(new ExpandListener() {
+
+                @Override
+                public void nodeExpand(ExpandEvent event) {
+                    //listener.addChildren(event.getItemId());
+                }
+
+            });
+
+            taxaTreeTable.setCellStyleGenerator(new Table.CellStyleGenerator() {
+
+                @Override
+                public String getStyle(Table source, Object itemId, Object propertyId) {
+                    Property hasSynProperty = source.getItem(itemId).getItemProperty(LeafNodeTaxonContainer.HAS_SYN_ID);
+                    if(hasSynProperty == null) {
+                        // this is a synonym
+                        return "synonym";
+                    }
+                    return null;
+                }
+            });
+
+            // NOTE : Not really sure why we need to refresh the container here.
+            // in the case of 'Table' this is not required
+            listener.refresh();
             updateInViewLabel();
         }
 
@@ -222,12 +265,11 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
 
         filterTable.setContainerDataSource(container);
         filterTable.setColumnHeaderMode(ColumnHeaderMode.HIDDEN);
-        filterTable.addStyleName(Reindeer.TABLE_BORDERLESS);
-
 
 
         ValueChangeListener selectedListener = new ValueChangeListener() {
 
+            private static final long serialVersionUID = -5551250788805117454L;
 
             @Override
             public void valueChange(ValueChangeEvent event) {
@@ -256,19 +298,10 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
         };
         filterTable.addGeneratedColumn(PROPERTY_SELECTED_ID, new BooleanCheckBoxGenerator(selectedListener));
 
-//        filterTable.setCellStyleGenerator(new Table.CellStyleGenerator() {
-//
-//            private static final long serialVersionUID = -3363906932807556720L;
-//
-//            @Override
-//            public String getStyle(Table source, Object itemId, Object propertyId) {
-//                return "removable";
-//            }
-//        });
     }
 
     private void updateInViewLabel() {
-        inViewLabel.setValue(IN_VIEW_PREFIX + String.valueOf(listener.getCurrentSize()) + " / " + String.valueOf(listener.getSize()) + " taxa");
+        inViewLabel.setValue(IN_VIEW_PREFIX + String.valueOf(listener.getCurrentNoOfTaxa()) + " / " + String.valueOf(listener.getTotalNoOfTaxa()) + " taxa");
     }
 
     private void initSearchTextField() {
@@ -287,8 +320,8 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
     }
 
     private void initClearSearchButton() {
-        ThemeResource resource = new ThemeResource("icons/32/cancel.png");
-        clearSearchButton.setIcon(resource);
+        //ThemeResource resource = new ThemeResource("icons/32/cancel.png");
+        clearSearchButton.setIcon(FontAwesome.REFRESH);
         clearSearchButton.setCaption("");
     }
 
@@ -319,23 +352,6 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
         });
     }
 
-//    private void addFilterComboBoxListener() {
-//        filterComboBox.addValueChangeListener(new Property.ValueChangeListener() {
-//
-//            private static final long serialVersionUID = 1314542578509878256L;
-//
-//            @Override
-//            public void valueChange(ValueChangeEvent event) {
-//                if (filterComboBox.getValue() != null) {
-//                    String selected = (String)filterComboBox.getValue();
-//                    if(!selected.equals(SELECT_FILTER)) {
-//                        filterTable.addItem(new Object[]{selected}, filterTable.getItemIds().size() + 1);
-//                        filterComboBox.setValue(SELECT_FILTER);
-//                    }
-//                }
-//            }
-//        });
-//    }
 
     private void addAddComboBoxListener() {
         addComboBox.addValueChangeListener(new Property.ValueChangeListener() {
@@ -363,17 +379,11 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
             @Override
             public void textChange(TextChangeEvent event) {
                listener.setNameFilter(event.getText());
+               updateInViewLabel();
             }
 
         });
-        searchTextField.addFocusListener(new FieldEvents.FocusListener(){
 
-            @Override
-            public void focus(FocusEvent event) {
-                searchTextField.setValue("");
-            }
-
-        });
     }
 
     private void addClearSearchButtonListener() {
@@ -383,21 +393,12 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
             public void buttonClick(ClickEvent event) {
                listener.removeNameFilter();
                searchTextField.setValue(FILTER_TAXA_INPUT);
+               updateInViewLabel();
             }
 
         });
     }
-//    private void addFilterTableListener() {
-//        filterTable.addItemClickListener(new ItemClickEvent.ItemClickListener() {
-//
-//            private static final long serialVersionUID = -4722168300711497739L;
-//
-//            @Override
-//            public void itemClick(ItemClickEvent event) {
-//                filterTable.removeItem(event.getItemId());
-//            }}
-//                );
-//    }
+
 
 
     /* (non-Javadoc)
@@ -422,11 +423,19 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
          */
         @Override
         public Component generateCell(Table source, Object itemId, Object columnId) {
-            Property prop = source.getItem(itemId).getItemProperty(columnId);
-            CheckBox cb = new CheckBox(null, prop);
-            cb.addValueChangeListener(listener);
-            cb.setData(itemId);
-            return cb;
+            if(source.getItem(itemId) != null) {
+                Property prop = source.getItem(itemId).getItemProperty(columnId);
+                if(prop == null) {
+                    return null;
+                }
+                CheckBox cb = new CheckBox(null, prop);
+                cb.addValueChangeListener(listener);
+                cb.setData(itemId);
+                return cb;
+            } else {
+                return null;
+            }
+
         }
     }
 
@@ -458,18 +467,18 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
         mainLayout.addComponent(filterVerticalLayout, 0, 1);
         mainLayout.setComponentAlignment(filterVerticalLayout, new Alignment(20));
 
-        // searchHorizontalLayout
-        searchHorizontalLayout = buildSearchHorizontalLayout();
-        mainLayout.addComponent(searchHorizontalLayout, 0, 3);
-        mainLayout.setComponentAlignment(searchHorizontalLayout, new Alignment(48));
-
         // addRemovehorizontalLayout
         addRemovehorizontalLayout = buildAddRemovehorizontalLayout();
         mainLayout.addComponent(addRemovehorizontalLayout, 0, 2);
         mainLayout.setComponentAlignment(addRemovehorizontalLayout, new Alignment(48));
 
+        // searchHorizontalLayout
+        searchHorizontalLayout = buildSearchHorizontalLayout();
+        mainLayout.addComponent(searchHorizontalLayout, 0, 3);
+        mainLayout.setComponentAlignment(searchHorizontalLayout, new Alignment(48));
+
         // taxaTreeTable
-        taxaTreeTable = new Table();
+        taxaTreeTable = new TreeTable();
         taxaTreeTable.setImmediate(false);
         taxaTreeTable.setWidth("100.0%");
         taxaTreeTable.setHeight("534px");
@@ -515,6 +524,36 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
         return filterVerticalLayout;
     }
 
+    @AutoGenerated
+    private HorizontalLayout buildAddRemovehorizontalLayout() {
+        // common part: create layout
+        addRemovehorizontalLayout = new HorizontalLayout();
+        addRemovehorizontalLayout.setImmediate(false);
+        addRemovehorizontalLayout.setWidth("100.0%");
+        addRemovehorizontalLayout.setHeight("-1px");
+        addRemovehorizontalLayout.setMargin(false);
+        addRemovehorizontalLayout.setSpacing(true);
+
+        // addComboBox
+        addComboBox = new ComboBox();
+        addComboBox.setImmediate(false);
+        addComboBox.setWidth("100.0%");
+        addComboBox.setHeight("-1px");
+        addRemovehorizontalLayout.addComponent(addComboBox);
+        addRemovehorizontalLayout.setExpandRatio(addComboBox, 3.0f);
+
+        // removeButton
+        removeButton = new Button();
+        removeButton.setCaption("Remove");
+        removeButton.setImmediate(true);
+        removeButton.setWidth("100.0%");
+        removeButton.setHeight("-1px");
+        addRemovehorizontalLayout.addComponent(removeButton);
+        addRemovehorizontalLayout.setExpandRatio(removeButton, 2.0f);
+
+        return addRemovehorizontalLayout;
+    }
+
     @AutoGenerated
     private HorizontalLayout buildSearchHorizontalLayout() {
         // common part: create layout
@@ -547,34 +586,4 @@ public class StatusComposite extends CustomComponent implements IStatusComposite
         return searchHorizontalLayout;
     }
 
-    @AutoGenerated
-    private HorizontalLayout buildAddRemovehorizontalLayout() {
-        // common part: create layout
-        addRemovehorizontalLayout = new HorizontalLayout();
-        addRemovehorizontalLayout.setImmediate(false);
-        addRemovehorizontalLayout.setWidth("100.0%");
-        addRemovehorizontalLayout.setHeight("-1px");
-        addRemovehorizontalLayout.setMargin(false);
-        addRemovehorizontalLayout.setSpacing(true);
-
-        // addComboBox
-        addComboBox = new ComboBox();
-        addComboBox.setImmediate(false);
-        addComboBox.setWidth("100.0%");
-        addComboBox.setHeight("-1px");
-        addRemovehorizontalLayout.addComponent(addComboBox);
-        addRemovehorizontalLayout.setExpandRatio(addComboBox, 3.0f);
-
-        // removeButton
-        removeButton = new Button();
-        removeButton.setCaption("Remove");
-        removeButton.setImmediate(true);
-        removeButton.setWidth("100.0%");
-        removeButton.setHeight("-1px");
-        addRemovehorizontalLayout.addComponent(removeButton);
-        addRemovehorizontalLayout.setExpandRatio(removeButton, 2.0f);
-
-        return addRemovehorizontalLayout;
-    }
-
 }
index ce0a5631826ae237d888ace98eb1e7929741c7dd..6181489f74089f970c9b93a69a0f431e46f355aa 100644 (file)
@@ -1,19 +1,32 @@
 package eu.etaxonomy.cdm.vaadin.container;
 
 import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
 
+import org.apache.log4j.Logger;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.sqlcontainer.RowId;
+import com.vaadin.data.util.sqlcontainer.RowItem;
 import com.vaadin.data.util.sqlcontainer.SQLContainer;
 import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool;
 import com.vaadin.data.util.sqlcontainer.query.QueryDelegate;
 import com.vaadin.data.util.sqlcontainer.query.TableQuery;
-import com.vaadin.data.util.sqlcontainer.query.generator.DefaultSQLGenerator;
 
 import eu.etaxonomy.cdm.vaadin.util.CdmSpringContextHelper;
 
 public class CdmSQLContainer extends SQLContainer {
 
+    private static final Logger logger = Logger.getLogger(CdmSQLContainer.class);
+
     JDBCConnectionPool pool;
 
+    private int contentChangedEventsDisabledCount = 0;
+
+    private boolean contentsChangedEventPending;
+
+    private final Map<RowId, RowItem> addedItems = new HashMap<RowId, RowItem>();
 
     public CdmSQLContainer(QueryDelegate delegate) throws SQLException {
         super(delegate);
@@ -21,11 +34,61 @@ public class CdmSQLContainer extends SQLContainer {
 
     public static CdmSQLContainer newInstance(String tableName) throws SQLException {
         // TODO : currently the sql generator is for h2, need to make this compatible for all flavours
-        TableQuery tq = new TableQuery(tableName,CdmSpringContextHelper.getConnectionPool(), new DefaultSQLGenerator());
+        TableQuery tq = new TableQuery(tableName,CdmSpringContextHelper.getConnectionPool());
         tq.setVersionColumn("updated");
-
         return new CdmSQLContainer(tq);
 
     }
 
+    @Override
+    public Item getItem(Object itemId) {
+        RowItem rowItem = addedItems.get(itemId);
+        if(rowItem != null) {
+            return rowItem;
+        } else {
+            return super.getItem(itemId);
+        }
+    }
+
+    public void addRowItem(RowItem rowItem) {
+        addedItems.put(rowItem.getId(), rowItem);
+    }
+
+    @Override
+    protected void fireContentsChange() {
+        if (contentsChangeEventsOn()) {
+            disableContentsChangeEvents();
+            try {
+                super.fireContentsChange();
+            } finally {
+                enableContentsChangeEvents();
+            }
+        } else {
+            contentsChangedEventPending = true;
+        }
+    }
+
+    protected boolean contentsChangeEventsOn() {
+        return contentChangedEventsDisabledCount == 0;
+    }
+
+    protected void disableContentsChangeEvents() {
+        contentChangedEventsDisabledCount++;
+    }
+
+    protected void enableContentsChangeEvents() {
+        if (contentChangedEventsDisabledCount <= 0) {
+            logger.warn("Mismatched calls to disable and enable contents change events in HierarchicalContainer");
+            contentChangedEventsDisabledCount = 0;
+        } else {
+            contentChangedEventsDisabledCount--;
+        }
+        if (contentChangedEventsDisabledCount == 0) {
+            if (contentsChangedEventPending) {
+                //fireContentsChange();
+            }
+            contentsChangedEventPending = false;
+        }
+    }
+
 }
index 2a4e6e1a833dc284e09831e3ab20265ed0e1a7fa..774aa4921f96a7f8b6cdb06a1b3aaaa0b4b8b893 100644 (file)
 // $Id$
 /**
-* Copyright (C) 2015 EDIT
-* European Distributed Institute of Taxonomy
-* http://www.e-taxonomy.eu
-*
-* The contents of this file are subject to the Mozilla Public License Version 1.1
-* See LICENSE.TXT at the top of this package for the full license terms.
-*/
+ * Copyright (C) 2015 EDIT
+ * European Distributed Institute of Taxonomy
+ * http://www.e-taxonomy.eu
+ *
+ * The contents of this file are subject to the Mozilla Public License Version 1.1
+ * See LICENSE.TXT at the top of this package for the full license terms.
+ */
 package eu.etaxonomy.cdm.vaadin.container;
 
 import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
 
-import com.vaadin.data.util.sqlcontainer.SQLContainer;
-import com.vaadin.data.util.sqlcontainer.query.QueryDelegate;
+import com.vaadin.data.Container;
+import com.vaadin.data.Property;
+import com.vaadin.data.util.filter.Compare;
+import com.vaadin.data.util.filter.IsNull;
+import com.vaadin.data.util.filter.Not;
+import com.vaadin.data.util.filter.SimpleStringFilter;
+import com.vaadin.data.util.sqlcontainer.RowItem;
+
+import eu.etaxonomy.cdm.vaadin.util.CdmQueryFactory;
 
 /**
  * @author cmathew
  * @date 10 Mar 2015
  *
  */
-public class LeafNodeTaxonContainer extends SQLContainer {
+public class LeafNodeTaxonContainer extends CdmSQLContainer implements Container.Hierarchical  {
+
+    private static final Logger logger = Logger.getLogger(LeafNodeTaxonContainer.class);
+
+    public static final String ID = "Id";
+    public static final String NAME_ID = "Name";
+    public static final String ACCTAXON_ID = "AccTaxonId";
+    public static final String PB_ID = "Pb";
+    public static final String FN_ID = "Fn";
+    public static final String UNP_ID = "Unp";
+    public static final String UNR_ID = "Unr";
+    public static final String RANK_ID = "Rank";
+    public static final String HAS_SYN_ID = "HasSynonyms";
+
+    public Set<Filter> currentFilters;
+
+
+    private Filter nrFilter, unpFilter, unfFilter, unpbFilter, rankFilter,  classificationFilter, synonymFilter;
+    private SimpleStringFilter nameFilter;
+
+    private int classificationId = -1;
+
+    private final Map<Object,List<Object>> taxonSynonymMap;
+
+    private final CdmSQLContainer synonymContainer;
+
 
     /**
      * @param delegate
      * @throws SQLException
      */
-    public LeafNodeTaxonContainer(QueryDelegate delegate) throws SQLException {
-        super(delegate);
-        // TODO Auto-generated constructor stub
+    public LeafNodeTaxonContainer(int classificationId) throws SQLException {
+        super(CdmQueryFactory.generateTaxonBaseQuery(ID, NAME_ID, PB_ID, UNP_ID, RANK_ID, HAS_SYN_ID));
+        this.synonymContainer = new CdmSQLContainer(CdmQueryFactory.generateSynonymofTaxonQuery(ID, NAME_ID));
+        this.classificationId = classificationId;
+        taxonSynonymMap = new HashMap<Object,List<Object>>();
+        initFilters();
+        addContainerFilter(classificationFilter);
+        addContainerFilter(rankFilter);
+    }
+
+    private void initFilters() {
+        //nrFilter = new Compare.Equal(StatusPresenter.UNR_ID, true);
+        unpFilter = new Compare.Equal("tb.unplaced", true);
+        //unfFilter = new Compare.Equal(StatusPresenter.FN_ID, false);
+        unpbFilter = new Compare.Equal("tb.publish", false);
+        classificationFilter = new Compare.Equal("tn.classification_id",classificationId);
+        rankFilter = new Compare.Equal("dtb.titleCache","Species");
+        synonymFilter = new Not(new IsNull("sr.relatedto_id"));
+
+        currentFilters = new HashSet<Filter>();
+    }
+
+
+
+    public void setUnplacedFilter() {
+        addContainerFilter(unpFilter);
+    }
+
+
+    public void removeUnplacedFilter() {
+        removeContainerFilter(unpFilter);
+    }
+
+
+    public void setUnpublishedFilter() {
+        addContainerFilter(unpbFilter);
+    }
+
+
+    public void removeUnpublishedFilter() {
+        removeContainerFilter(unpbFilter);
+    }
+
+
+    public void setNameFilter(String filterString) {
+        removeNameFilter();
+        nameFilter = new SimpleStringFilter("tnb.titleCache", filterString, true, true);
+        addContainerFilter(nameFilter);
     }
 
+
+    public void removeNameFilter() {
+        removeContainerFilter(nameFilter);
+    }
+
+    public int getTotalNoOfTaxa() {
+        return size();
+    }
+
+
+    /* (non-Javadoc)
+     * @see com.vaadin.data.Container.Hierarchical#getChildren(java.lang.Object)
+     */
+    @Override
+    public Collection<?> getChildren(Object itemId) {
+        List<Object> synList = taxonSynonymMap.get(itemId);
+        if(synList != null) {
+            return synList;
+        }
+        //synonymContainer.disableContentsChangeEvents();
+        try {
+            Filter synonymOfTaxonFilter = new Compare.Equal("sr.relatedto_id", Integer.valueOf(itemId.toString()));
+            synonymContainer.addContainerFilter(synonymOfTaxonFilter);
+            synList = new ArrayList<Object>();
+            synList.addAll(synonymContainer.getItemIds());
+            for(Object synItemId : synList) {
+                addRowItem((RowItem) synonymContainer.getItem(synItemId));
+            }
+            synonymContainer.removeAllContainerFilters();
+            // cache the synonyms for later
+            taxonSynonymMap.put(itemId, synList);
+
+            return synList;
+        } finally {
+            //synonymContainer.enableContentsChangeEvents();
+        }
+
+
+    }
+
+    /* (non-Javadoc)
+     * @see com.vaadin.data.Container.Hierarchical#getParent(java.lang.Object)
+     */
+    @Override
+    public Object getParent(Object itemId) {
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see com.vaadin.data.Container.Hierarchical#rootItemIds()
+     */
+    @Override
+    public Collection<?> rootItemIds() {
+//
+//        disableContentsChangeEvents();
+//        try {
+//            Collection<?> taxontemIds = getItemIds();
+//            return taxontemIds;
+//        } finally {
+//            enableContentsChangeEvents();
+//        }
+
+        return getItemIds();
+    }
+
+    /* (non-Javadoc)
+     * @see com.vaadin.data.Container.Hierarchical#setParent(java.lang.Object, java.lang.Object)
+     */
+    @Override
+    public boolean setParent(Object itemId, Object newParentId) throws UnsupportedOperationException {
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see com.vaadin.data.Container.Hierarchical#areChildrenAllowed(java.lang.Object)
+     */
+    @Override
+    public boolean areChildrenAllowed(Object itemId) {
+
+        Property hasSynProperty = getItem(itemId).getItemProperty(HAS_SYN_ID);
+        if(hasSynProperty == null) {
+            return false;
+        }
+        return (Long)hasSynProperty.getValue() > 0;
+
+
+    }
+
+    /* (non-Javadoc)
+     * @see com.vaadin.data.Container.Hierarchical#setChildrenAllowed(java.lang.Object, boolean)
+     */
+    @Override
+    public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) throws UnsupportedOperationException {
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see com.vaadin.data.Container.Hierarchical#isRoot(java.lang.Object)
+     */
+    @Override
+    public boolean isRoot(Object itemId) {
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see com.vaadin.data.Container.Hierarchical#hasChildren(java.lang.Object)
+     */
+    @Override
+    public boolean hasChildren(Object itemId) {
+        return true;
+    }
+
+
+
 }
index e55b36e9f146c9584f8f0df80d63f93449395394..91517f61d7b4a917acff05855c71312700a2b5c9 100644 (file)
@@ -11,17 +11,10 @@ package eu.etaxonomy.cdm.vaadin.presenter;
 
 import java.sql.SQLException;
 
-import com.vaadin.data.Container.Filter;
-import com.vaadin.data.util.filter.Compare;
-import com.vaadin.data.util.filter.Compare.Equal;
-import com.vaadin.data.util.filter.SimpleStringFilter;
-import com.vaadin.data.util.sqlcontainer.query.FreeformQuery;
 import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder;
 
 import eu.etaxonomy.cdm.vaadin.container.CdmSQLContainer;
 import eu.etaxonomy.cdm.vaadin.container.LeafNodeTaxonContainer;
-import eu.etaxonomy.cdm.vaadin.statement.CdmStatementDelegate;
-import eu.etaxonomy.cdm.vaadin.util.CdmSpringContextHelper;
 import eu.etaxonomy.cdm.vaadin.util.CdmSQLStringDecorator;
 import eu.etaxonomy.cdm.vaadin.view.IStatusComposite;
 import eu.etaxonomy.cdm.vaadin.view.IStatusComposite.StatusComponentListener;
@@ -33,41 +26,28 @@ import eu.etaxonomy.cdm.vaadin.view.IStatusComposite.StatusComponentListener;
  */
 public class StatusPresenter implements StatusComponentListener {
 
-    public static final String NAME_ID = "Name";
-    public static final String PB_ID = "Pb";
-    public static final String FN_ID = "Fn";
-    public static final String UNP_ID = "Unp";
-    public static final String UNR_ID = "Unr";
-
-    private static final String FROM_QUERY = " FROM TaxonNode tn inner join TaxonBase tb on tn.taxon_id=tb.id inner join TaxonNameBase tnb on tb.name_id=tnb.id  inner join DefinedTermBase dtb on tnb.rank_id=dtb.id";
-    private static final String SELECT_QUERY="SELECT tb.id as taxon_id, tnb.titleCache as " + NAME_ID + " , tb.publish as " + PB_ID + " , tb.unplaced as " +  UNP_ID + FROM_QUERY;
-    private static final String COUNT_QUERY = "SELECT count(*) " + FROM_QUERY;
-
-    private static final String CONTAINS_QUERY = "SELECT * FROM TaxonBase tb WHERE tb.id = ?";
-
     private final IStatusComposite composite;
 
     private LeafNodeTaxonContainer container;
 
-    private Equal nrFilter, unpFilter, unfFilter, unpbFilter;
-    private SimpleStringFilter nameFilter;
 
-    private int totalNoOfItems = 0;
+
+    private int totalNoOfTaxa = 0;
 
     public StatusPresenter(IStatusComposite composite) {
         this.composite = composite;
         composite.setListener(this);
-        initFilters();
         // TODO: Need to evaluate the various sql dialects and make sure that these
         // queries are compatible with all
         QueryBuilder.setStringDecorator(new CdmSQLStringDecorator());
     }
 
-    private void initFilters() {
-        //nrFilter = new Compare.Equal(StatusPresenter.UNR_ID, true);
-        unpFilter = new Compare.Equal("tb.unplaced", true);
-        //unfFilter = new Compare.Equal(StatusPresenter.FN_ID, false);
-        unpbFilter = new Compare.Equal("tb.publish", false);
+
+    @Override
+    public void removeFilters() {
+        removeUnplacedFilter();
+        removeUnpublishedFilter();
+        removeNameFilter();
     }
 
     /* (non-Javadoc)
@@ -75,60 +55,58 @@ public class StatusPresenter implements StatusComponentListener {
      */
     @Override
     public LeafNodeTaxonContainer loadTaxa(int classificationId) throws SQLException {
-        FreeformQuery query = new FreeformQuery("This query is not used", CdmSpringContextHelper.getConnectionPool(), "taxon_id");
-        CdmStatementDelegate cdmStatementDelegate = new CdmStatementDelegate(SELECT_QUERY, COUNT_QUERY, CONTAINS_QUERY);
-        query.setDelegate(cdmStatementDelegate);
-
-        Filter rankFilter = new Compare.Equal("dtb.titleCache","Species");
-        Filter classifcationFilter = new Compare.Equal("tn.classification_id",classificationId);
-
-        container = new LeafNodeTaxonContainer(query);
-        //container.addContainerFilter(rankFilter);
-        container.addContainerFilter(classifcationFilter);
-        totalNoOfItems = container.size();
+        container = new LeafNodeTaxonContainer(classificationId);
+        totalNoOfTaxa = container.getTotalNoOfTaxa();
         return container;
     }
 
+    @Override
+    public void refresh() {
+        container.refresh();
+    }
     @Override
     public void setUnplacedFilter() {
-        container.addContainerFilter(unpFilter);
+        container.setUnplacedFilter();
     }
 
     @Override
     public void removeUnplacedFilter() {
-        container.removeContainerFilter(unpFilter);
+        container.removeUnplacedFilter();
     }
 
     @Override
     public void setUnpublishedFilter() {
-        container.addContainerFilter(unpbFilter);
+        container.setUnpublishedFilter();
     }
 
     @Override
     public void removeUnpublishedFilter() {
-        container.removeContainerFilter(unpbFilter);
+        container.removeUnpublishedFilter();
     }
 
     @Override
     public void setNameFilter(String filterString) {
-        removeNameFilter();
-        nameFilter = new SimpleStringFilter("tnb.titleCache", filterString, true, true);
-        container.addContainerFilter(nameFilter);
+        container.setNameFilter(filterString);
     }
 
     @Override
     public void removeNameFilter() {
-        container.removeContainerFilter(nameFilter);
+        container.removeNameFilter();
     }
 
     @Override
-    public int getCurrentSize() {
+    public int getCurrentNoOfTaxa() {
         return container.size();
     }
 
     @Override
-    public int getSize() {
-        return totalNoOfItems;
+    public int getTotalNoOfTaxa() {
+        return totalNoOfTaxa;
+    }
+
+    @Override
+    public void addChildren(Object parentItemId) {
+        //container.addChildren(parentItemId);
     }
 
     /* (non-Javadoc)
@@ -140,4 +118,5 @@ public class StatusPresenter implements StatusComponentListener {
         return container;
     }
 
+
 }
index 6ed32fe7d98fabbe3bc943de4e639c6a24fd4e27..94d1b669bab155f9f63433b7e9e72b2e3075575f 100644 (file)
@@ -29,7 +29,7 @@ import com.vaadin.ui.UI;
 import eu.etaxonomy.cdm.vaadin.view.StatusEditorView;
 
 
-@Theme("mytheme")
+@Theme("edit")
 public class StatusEditorUI extends AbstractAuthenticatedUI {
 
     Navigator navigator;
@@ -47,7 +47,7 @@ public class StatusEditorUI extends AbstractAuthenticatedUI {
     @Override
     protected void doInit() {
         // FIXME: remove this when testing is done
-        setIgnoreAuthentication(true);
+        //setIgnoreAuthentication(true);
 
         getPage().setTitle("Status Editor");
         StatusEditorView statusEditorView = new StatusEditorView();
diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/util/CdmQueryFactory.java b/src/main/java/eu/etaxonomy/cdm/vaadin/util/CdmQueryFactory.java
new file mode 100644 (file)
index 0000000..59c0cb2
--- /dev/null
@@ -0,0 +1,70 @@
+// $Id$
+/**
+* Copyright (C) 2015 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.vaadin.util;
+
+import java.sql.SQLException;
+
+import com.vaadin.data.util.sqlcontainer.query.FreeformQuery;
+import com.vaadin.data.util.sqlcontainer.query.QueryDelegate;
+
+import eu.etaxonomy.cdm.vaadin.statement.CdmStatementDelegate;
+
+/**
+ * @author cmathew
+ * @date 1 Apr 2015
+ *
+ */
+public class CdmQueryFactory {
+
+    public static QueryDelegate generateTaxonBaseQuery(String id,
+            String name_id,
+            String pb_id,
+            String unp_id,
+            String rank_id,
+            String has_syn_id) throws SQLException {
+        String FROM_QUERY = " FROM TaxonBase tb " +
+                "INNER JOIN TaxonNode tn on tn.taxon_id=tb.id " +
+                "INNER JOIN TaxonNameBase tnb on tb.name_id=tnb.id " +
+                "INNER JOIN DefinedTermBase dtb on tnb.rank_id=dtb.id  ";
+        String SELECT_QUERY="SELECT tb.id as " + id +
+                ", tnb.titleCache as " + name_id +
+                ", tb.publish as " + pb_id +
+                ", tb.unplaced as " + unp_id +
+                ", dtb.titleCache as " + rank_id +
+                ", (SELECT COUNT(*) FROM  SynonymRelationship sr WHERE tb.id = sr.relatedto_id) as " + has_syn_id +
+                FROM_QUERY;
+        String COUNT_QUERY = "SELECT count(*) " + FROM_QUERY;
+        String CONTAINS_QUERY = "SELECT * FROM TaxonBase tb WHERE tb.id = ?";
+
+        return generateQueryDelegate(SELECT_QUERY, COUNT_QUERY, CONTAINS_QUERY, id);
+    }
+
+    public static QueryDelegate generateSynonymofTaxonQuery(String id,
+            String name_id) throws SQLException {
+        String FROM_QUERY = " FROM TaxonBase tb " +
+                "INNER JOIN TaxonNameBase tnb on tb.name_id=tnb.id " +
+                "INNER JOIN SynonymRelationship sr on tb.id=sr.relatedfrom_id ";
+        String SELECT_QUERY="SELECT tb.id as " + id +
+                ", tnb.titleCache as " + name_id +
+                FROM_QUERY;
+        String COUNT_QUERY = "SELECT count(*) " + FROM_QUERY;
+        String CONTAINS_QUERY = "SELECT * FROM SynonymRelationship sr WHERE sr.relatedfrom_id = ?";
+
+        return generateQueryDelegate(SELECT_QUERY, COUNT_QUERY, CONTAINS_QUERY, id);
+    }
+
+    public static QueryDelegate generateQueryDelegate(String SELECT_QUERY, String COUNT_QUERY, String CONTAINS_QUERY, String id) throws SQLException {
+        FreeformQuery query = new FreeformQuery("This query is not used", CdmSpringContextHelper.getConnectionPool(), id);
+        CdmStatementDelegate delegate = new CdmStatementDelegate(SELECT_QUERY, COUNT_QUERY, CONTAINS_QUERY);
+        query.setDelegate(delegate);
+        return query;
+    }
+
+}
index ff69c05c62610df71ef0ef239615bde826a9a27c..30521060623539c90ae02b2ff16396df1c10abf2 100644 (file)
@@ -40,22 +40,37 @@ public interface IStatusComposite {
          *
          */
         public void removeUnpublishedFilter();
+
+        /**
+         * @param filterString
+         */
+        public void setNameFilter(String filterString);
+        /**
+         *
+         */
+        public void removeNameFilter();
+
         /**
          * @return
          */
-        public int getCurrentSize();
+        public int getCurrentNoOfTaxa();
+
         /**
          * @return
          */
-        public int getSize();
+        public int getTotalNoOfTaxa();
         /**
-         * @param filterString
+         *
          */
-        public void setNameFilter(String filterString);
+        public void refresh();
         /**
          *
          */
-        public void removeNameFilter();
+        public void removeFilters();
+        /**
+         * @param parentItemId
+         */
+        public void addChildren(Object parentItemId);
     }
 
     public void setListener(StatusComponentListener listener);
index 52f678b3d4c84915ebaaffabf501a71b31980741..f1d407201ab5d3e011f87b18371936907010d47c 100644 (file)
@@ -56,7 +56,7 @@ public class StatusPresenterTest extends CdmVaadinBaseTest {
             String taxon = (String)item.getItemProperty("Name").getValue();
             logger.info("taxon : " + taxon);
         }
-        Assert.assertEquals(4,itemIds.size());
+        Assert.assertEquals(3,itemIds.size());
 
         sp.setUnplacedFilter();
         itemIds = container.getItemIds();
@@ -64,11 +64,29 @@ public class StatusPresenterTest extends CdmVaadinBaseTest {
 
         sp.removeUnplacedFilter();
         itemIds = container.getItemIds();
-        Assert.assertEquals(4,itemIds.size());
+        Assert.assertEquals(3,itemIds.size());
 
         sp.setNameFilter("Taxon A");
         itemIds = container.getItemIds();
         Assert.assertEquals(1,itemIds.size());
+
+
+    }
+
+    @Test
+    public void testLoadSynonyms() throws SQLException {
+        LeafNodeTaxonContainer container = sp.loadTaxa(11);
+        container.refresh();
+        Collection<?> rootItemIds = container.rootItemIds();
+        Assert.assertEquals(3,rootItemIds.size());
+
+        Collection<?> childIds = container.getChildren(10);
+        Assert.assertEquals(2, childIds.size());
+
+        // FIXME : Need to check why these calls thorw a NPE
+        // in the case of h2
+        //Assert.assertEquals(true, container.areChildrenAllowed(10));
+        //Assert.assertEquals(false, container.areChildrenAllowed(11));
     }
 
     @Ignore
index 99fa2f5ba152a0cc314a005c76d7209e3d09ef6a..d09af189e3d414f49f56dabd6f2f465d265d9bb7 100644 (file)
@@ -1,15 +1,16 @@
 <?xml version="1.0" encoding="UTF-8"?><!--
-  generated by Jailer 4.3, Tue Mar 10 14:42:57 CET 2015 from cmathew@cmbgbm-t530
+  generated by Jailer 4.3, Wed Apr 01 11:37:10 CEST 2015 from cmathew@cmbgbm-t530
   
-  Extraction Model:  all rows from Classification (extractionmodel/by-example/SbE-Classification-14-42-42-331.csv)
+  Extraction Model:  all rows from Classification (extractionmodel/by-example/SbE-Classification-11-36-57-404.csv)
   Database URL:      jdbc:mysql://127.0.0.1:3306/local-redlist
   Database User:     root
   
-  Exported Rows:     27
+  Exported Rows:     45
       Classification                 2
       DefinedTermBase                2
-      TaxonBase                      7
-      TaxonNameBase                  7
+      SynonymRelationship            6
+      TaxonBase                      13
+      TaxonNameBase                  13
       TaxonNode                      9
   
 --><dataset>
   <TaxonNode id="20" created="2015-03-10 13:40:31.0" uuid="6a6ee4dd-5727-47ba-a53d-3a985623dd93" updated="2015-03-10 13:40:31.0" countchildren="0" sortindex="3" treeindex="#t11#11#20#" createdby_id="10" updatedby_id="10" classification_id="11" parent_id="11" taxon_id="30"/>
 
   <TaxonNameBase DTYPE="BotanicalName" id="10" created="2015-03-09 15:49:22.0" uuid="9c0b6c13-562e-4642-9494-58dbcedf45f4" updated="2015-03-09 15:49:25.0" protectedtitlecache="false" titleCache="Taxon A" parsingproblem="0" problemends="5" problemstarts="0" protectedfulltitlecache="false" authorshipcache="A" binomhybrid="false" genusoruninomial="Taxon" hybridformula="false" monomhybrid="false" namecache="Taxon" protectedauthorshipcache="false" protectednamecache="false" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="10" rank_id="790" combinationauthorteam_id="10"/>
+  <TaxonNameBase DTYPE="BotanicalName" id="11" created="2015-03-09 15:49:30.0" uuid="82de3687-f90d-4968-951b-456a21659666" updated="2015-03-09 15:50:21.0" protectedtitlecache="true" titleCache="HTSynonym A1" fullTitleCache="HTSynonym A1" parsingproblem="4" problemends="12" problemstarts="0" protectedfulltitlecache="true" authorshipcache="" binomhybrid="false" hybridformula="false" monomhybrid="false" namecache="HTSynonym A1" protectedauthorshipcache="false" protectednamecache="true" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="11"/>
+  <TaxonNameBase DTYPE="BotanicalName" id="12" created="2015-03-09 15:50:25.0" uuid="bd86d4f9-8427-4ac5-a8c2-48add63da449" updated="2015-03-09 15:50:54.0" protectedtitlecache="true" titleCache="HMSynonym A1" fullTitleCache="HMSynonym A1" parsingproblem="4" problemends="12" problemstarts="0" protectedfulltitlecache="true" authorshipcache="" binomhybrid="false" hybridformula="false" monomhybrid="false" namecache="HMSynonym A1" protectedauthorshipcache="false" protectednamecache="true" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="10"/>
   <TaxonNameBase DTYPE="BotanicalName" id="13" created="2015-03-09 15:51:11.0" uuid="fb76b9cb-29d2-4986-a327-19d1d003159a" updated="2015-03-09 15:51:14.0" protectedtitlecache="false" titleCache="Taxon B" fullTitleCache="Taxon B" parsingproblem="0" problemends="5" problemstarts="0" protectedfulltitlecache="false" authorshipcache="B" binomhybrid="false" genusoruninomial="Taxon" hybridformula="false" monomhybrid="false" namecache="Taxon" protectedauthorshipcache="false" protectednamecache="false" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="12" rank_id="790" combinationauthorteam_id="11"/>
   <TaxonNameBase DTYPE="BotanicalName" id="14" created="2015-03-09 15:51:24.0" uuid="a21d5e7c-e8b5-4395-b83b-a219877e80eb" updated="2015-03-09 15:51:25.0" protectedtitlecache="false" titleCache="Taxon C" parsingproblem="0" problemends="5" problemstarts="0" protectedfulltitlecache="false" authorshipcache="C" binomhybrid="false" genusoruninomial="Taxon" hybridformula="false" monomhybrid="false" namecache="Taxon" protectedauthorshipcache="false" protectednamecache="false" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="13" rank_id="790" combinationauthorteam_id="12"/>
+  <TaxonNameBase DTYPE="BotanicalName" id="15" created="2015-03-09 15:51:31.0" uuid="7dd4eaa3-b65f-4d1e-8d2c-26a31ea3ae0b" updated="2015-03-09 15:51:44.0" protectedtitlecache="true" titleCache="HTSynonym C1" fullTitleCache="HTSynonym C1" parsingproblem="4" problemends="12" problemstarts="0" protectedfulltitlecache="true" authorshipcache="" binomhybrid="false" hybridformula="false" monomhybrid="false" namecache="HTSynonym C1" protectedauthorshipcache="false" protectednamecache="true" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="13"/>
   <TaxonNameBase DTYPE="BotanicalName" id="16" created="2015-03-09 15:52:34.0" uuid="81444d5e-122f-46aa-9bee-d7c0ba52f8d6" updated="2015-03-09 15:52:42.0" protectedtitlecache="false" titleCache="Taxon A" parsingproblem="0" problemends="5" problemstarts="0" protectedfulltitlecache="false" authorshipcache="A" binomhybrid="false" genusoruninomial="Taxon" hybridformula="false" monomhybrid="false" namecache="Taxon" protectedauthorshipcache="false" protectednamecache="false" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="14" rank_id="790" combinationauthorteam_id="13"/>
+  <TaxonNameBase DTYPE="BotanicalName" id="17" created="2015-03-09 15:52:53.0" uuid="dcdfbc9f-5596-4ae2-85e0-b9c738d8bcec" updated="2015-03-09 15:52:57.0" protectedtitlecache="true" titleCache="HMSynonym A1" fullTitleCache="HMSynonym A1" parsingproblem="4" problemends="12" problemstarts="0" protectedfulltitlecache="true" authorshipcache="" binomhybrid="false" hybridformula="false" monomhybrid="false" namecache="HMSynonym A1" protectedauthorshipcache="false" protectednamecache="true" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="14"/>
+  <TaxonNameBase DTYPE="BotanicalName" id="18" created="2015-03-09 15:53:06.0" uuid="fa186915-0bb5-4047-a5c5-404d75851f1c" updated="2015-03-09 15:53:07.0" protectedtitlecache="true" titleCache="HTSynonym A1" fullTitleCache="HTSynonym A1" parsingproblem="4" problemends="12" problemstarts="0" protectedfulltitlecache="true" authorshipcache="" binomhybrid="false" hybridformula="false" monomhybrid="false" namecache="HTSynonym A1" protectedauthorshipcache="false" protectednamecache="true" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="15"/>
   <TaxonNameBase DTYPE="BotanicalName" id="19" created="2015-03-09 15:53:21.0" uuid="fddf69fa-4f25-4d10-b693-1a9d5d7bbd5c" updated="2015-03-09 15:53:23.0" protectedtitlecache="false" titleCache="Taxon B" fullTitleCache="Taxon B" parsingproblem="0" problemends="5" problemstarts="0" protectedfulltitlecache="false" authorshipcache="B" binomhybrid="false" genusoruninomial="Taxon" hybridformula="false" monomhybrid="false" namecache="Taxon" protectedauthorshipcache="false" protectednamecache="false" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="16" rank_id="790" combinationauthorteam_id="14"/>
   <TaxonNameBase DTYPE="BotanicalName" id="20" created="2015-03-09 15:53:30.0" uuid="9e644031-9190-4a4f-94bb-fc1f6066bbab" updated="2015-03-09 15:53:32.0" protectedtitlecache="false" titleCache="Taxon C" parsingproblem="0" problemends="5" problemstarts="0" protectedfulltitlecache="false" authorshipcache="C" binomhybrid="false" genusoruninomial="Taxon" hybridformula="false" monomhybrid="false" namecache="Taxon" protectedauthorshipcache="false" protectednamecache="false" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="17" rank_id="790" combinationauthorteam_id="15"/>
+  <TaxonNameBase DTYPE="BotanicalName" id="21" created="2015-03-09 15:53:49.0" uuid="0755d9d7-007a-4d81-a2f8-2ba1b7020cf4" updated="2015-03-09 15:53:52.0" protectedtitlecache="true" titleCache="HTSynonym C1" fullTitleCache="HTSynonym C1" parsingproblem="4" problemends="12" problemstarts="0" protectedfulltitlecache="true" authorshipcache="" binomhybrid="false" hybridformula="false" monomhybrid="false" namecache="HTSynonym C1" protectedauthorshipcache="false" protectednamecache="true" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="17"/>
   <TaxonNameBase DTYPE="BotanicalName" id="30" created="2015-03-10 13:40:30.0" uuid="b1b9abf0-72a6-4a2e-8bd1-3ef189f5b3e9" updated="2015-03-10 13:40:31.0" protectedtitlecache="false" titleCache="Taxon D" fullTitleCache="Taxon D" parsingproblem="1" problemends="5" problemstarts="0" protectedfulltitlecache="false" authorshipcache="D" binomhybrid="false" genusoruninomial="Taxon" hybridformula="false" monomhybrid="false" namecache="Taxon" protectedauthorshipcache="false" protectednamecache="false" trinomhybrid="false" anamorphic="false" createdby_id="10" updatedby_id="10" homotypicalgroup_id="20" rank_id="800" combinationauthorteam_id="20"/>
 
   <Classification id="11" created="2015-03-09 15:48:30.0" uuid="6595638e-4993-421a-9fe5-76b09d94f36a" updated="2015-03-09 15:48:42.0" protectedtitlecache="false" titleCache="Classification1" createdby_id="10" updatedby_id="10" name_id="11" rootnode_id="11"/>
   <Classification id="12" created="2015-03-09 15:52:08.0" uuid="1ef8aada-de72-4023-bbe1-14465b6bc60d" updated="2015-03-09 15:52:24.0" protectedtitlecache="false" titleCache="Classification2" createdby_id="10" updatedby_id="10" name_id="12" rootnode_id="15"/>
 
   <TaxonBase DTYPE="Taxon" id="10" created="2015-03-09 15:49:22.0" uuid="666b484f-dc1e-4578-b404-86bc6d2e47fa" updated="2015-03-09 15:49:25.0" protectedtitlecache="false" titleCache="Taxon A sec. ???" doubtful="false" publish="true" usenamecache="false" excluded="false" taxonstatusunknown="false" taxonomicchildrencount="0" unplaced="true" createdby_id="10" updatedby_id="10" name_id="10"/>
+  <TaxonBase DTYPE="Synonym" id="11" created="2015-03-09 15:49:30.0" uuid="f45a4860-451d-493c-ad42-bbe68325a883" updated="2015-03-09 15:50:21.0" protectedtitlecache="false" titleCache="HTSynonym A1 sec. ???" doubtful="false" publish="true" usenamecache="false" createdby_id="10" updatedby_id="10" name_id="11"/>
+  <TaxonBase DTYPE="Synonym" id="12" created="2015-03-09 15:50:25.0" uuid="cdd8945e-d538-4141-8c1b-78c93a8e3a8b" updated="2015-03-09 15:50:54.0" protectedtitlecache="false" titleCache="HMSynonym A1 sec. ???" doubtful="false" publish="true" usenamecache="false" createdby_id="10" updatedby_id="10" name_id="12"/>
   <TaxonBase DTYPE="Taxon" id="13" created="2015-03-09 15:51:11.0" uuid="77e7d93e-75c6-4dd4-850d-7b5809654378" updated="2015-03-09 15:51:14.0" protectedtitlecache="false" titleCache="Taxon B sec. ???" doubtful="false" publish="true" usenamecache="false" excluded="false" taxonstatusunknown="false" taxonomicchildrencount="0" unplaced="false" createdby_id="10" updatedby_id="10" name_id="13"/>
   <TaxonBase DTYPE="Taxon" id="14" created="2015-03-09 15:51:24.0" uuid="b38d0d73-9a20-4894-99bb-2148ee6b10d0" updated="2015-03-09 15:51:25.0" protectedtitlecache="false" titleCache="Taxon C sec. ???" doubtful="false" publish="true" usenamecache="false" excluded="false" taxonstatusunknown="false" taxonomicchildrencount="0" unplaced="false" createdby_id="10" updatedby_id="10" name_id="14"/>
+  <TaxonBase DTYPE="Synonym" id="15" created="2015-03-09 15:51:31.0" uuid="1e240011-aec1-4f94-a934-f3bd0e9df9a5" updated="2015-03-09 15:51:44.0" protectedtitlecache="false" titleCache="HTSynonym C1 sec. ???" doubtful="false" publish="true" usenamecache="false" createdby_id="10" updatedby_id="10" name_id="15"/>
   <TaxonBase DTYPE="Taxon" id="16" created="2015-03-09 15:52:34.0" uuid="eaac797e-cac7-4649-97cf-c7b580076895" updated="2015-03-09 15:52:42.0" protectedtitlecache="false" titleCache="Taxon A sec. ???" doubtful="false" publish="true" usenamecache="false" excluded="false" taxonstatusunknown="false" taxonomicchildrencount="0" unplaced="true" createdby_id="10" updatedby_id="10" name_id="16"/>
+  <TaxonBase DTYPE="Synonym" id="17" created="2015-03-09 15:52:53.0" uuid="5b6219d0-ae66-4a09-9b5f-af9fc418a085" updated="2015-03-09 15:52:57.0" protectedtitlecache="false" titleCache="HMSynonym A1 sec. ???" doubtful="false" publish="true" usenamecache="false" createdby_id="10" updatedby_id="10" name_id="17"/>
+  <TaxonBase DTYPE="Synonym" id="18" created="2015-03-09 15:53:06.0" uuid="4a85597d-b116-41d1-805c-be8168f5715b" updated="2015-03-09 15:53:07.0" protectedtitlecache="false" titleCache="HTSynonym A1 sec. ???" doubtful="false" publish="true" usenamecache="false" createdby_id="10" updatedby_id="10" name_id="18"/>
   <TaxonBase DTYPE="Taxon" id="19" created="2015-03-09 15:53:21.0" uuid="5004a8e7-b907-4744-b67e-44ccb057ab3b" updated="2015-03-09 15:53:23.0" protectedtitlecache="false" titleCache="Taxon B sec. ???" doubtful="false" publish="true" usenamecache="false" excluded="false" taxonstatusunknown="false" taxonomicchildrencount="0" unplaced="false" createdby_id="10" updatedby_id="10" name_id="19"/>
   <TaxonBase DTYPE="Taxon" id="20" created="2015-03-09 15:53:30.0" uuid="3d71c8b8-3bec-4f5f-ba23-6f9d55ef84e9" updated="2015-03-09 15:53:32.0" protectedtitlecache="false" titleCache="Taxon C sec. ???" doubtful="false" publish="true" usenamecache="false" excluded="false" taxonstatusunknown="false" taxonomicchildrencount="0" unplaced="false" createdby_id="10" updatedby_id="10" name_id="20"/>
+  <TaxonBase DTYPE="Synonym" id="21" created="2015-03-09 15:53:49.0" uuid="cdd27491-1b41-4119-86f5-0ffd33475769" updated="2015-03-09 15:53:52.0" protectedtitlecache="false" titleCache="HTSynonym C1 sec. ???" doubtful="false" publish="true" usenamecache="false" createdby_id="10" updatedby_id="10" name_id="21"/>
   <TaxonBase DTYPE="Taxon" id="30" created="2015-03-10 13:40:30.0" uuid="5f713f69-e03e-4a11-8a55-700fbbf44805" updated="2015-03-10 13:40:31.0" protectedtitlecache="false" titleCache="Taxon D sec. ???" doubtful="false" publish="true" usenamecache="false" excluded="false" taxonstatusunknown="false" taxonomicchildrencount="0" unplaced="false" createdby_id="10" updatedby_id="10" name_id="30"/>
 
+  <SynonymRelationship id="10" created="2015-03-09 15:49:30.0" uuid="f3b087a0-ff03-4a8c-97c1-c06a23d77ac0" updated="2015-03-09 15:50:21.0" doubtful="false" partial="false" proparte="false" createdby_id="10" updatedby_id="10" relatedfrom_id="11" relatedto_id="10" type_id="888"/>
+  <SynonymRelationship id="11" created="2015-03-09 15:50:25.0" uuid="3d0d79b6-37b1-4541-a01d-35f88721a39b" updated="2015-03-09 15:50:54.0" doubtful="false" partial="false" proparte="false" createdby_id="10" updatedby_id="10" relatedfrom_id="12" relatedto_id="10" type_id="889"/>
+  <SynonymRelationship id="12" created="2015-03-09 15:51:31.0" uuid="21e7c6f4-c029-49ad-9cf9-0b14186cd76a" updated="2015-03-09 15:51:44.0" doubtful="false" partial="false" proparte="false" createdby_id="10" updatedby_id="10" relatedfrom_id="15" relatedto_id="14" type_id="889"/>
+  <SynonymRelationship id="13" created="2015-03-09 15:52:53.0" uuid="4bdc85a7-5af4-4744-b372-869bfbdc30e2" updated="2015-03-09 15:52:57.0" doubtful="false" partial="false" proparte="false" createdby_id="10" updatedby_id="10" relatedfrom_id="17" relatedto_id="16" type_id="889"/>
+  <SynonymRelationship id="14" created="2015-03-09 15:53:06.0" uuid="3d2e320c-28cf-4925-b68d-249f95ba684a" updated="2015-03-09 15:53:07.0" doubtful="false" partial="false" proparte="false" createdby_id="10" updatedby_id="10" relatedfrom_id="18" relatedto_id="16" type_id="888"/>
+  <SynonymRelationship id="15" created="2015-03-09 15:53:49.0" uuid="f0e2e376-91a2-459c-b460-1442a0be293a" updated="2015-03-09 15:53:52.0" doubtful="false" partial="false" proparte="false" createdby_id="10" updatedby_id="10" relatedfrom_id="21" relatedto_id="20" type_id="889"/>
+
   <DefinedTermBase DTYPE="Rank" id="790" created="2015-03-09 15:44:33.0" uuid="b301f787-f319-4ccc-a10f-b4ed3b99a86d" updated="2015-03-09 15:44:33.0" protectedtitlecache="false" titleCache="Species" termType="RK" uri="" idinvocabulary="sp." orderindex="44" rankclass="SP" vocabulary_id="15"/>
   <DefinedTermBase DTYPE="Rank" id="800" created="2015-03-09 15:44:33.0" uuid="1b11c34c-48a8-4efa-98d5-84f7f66ef43a" updated="2015-03-09 15:44:33.0" protectedtitlecache="false" titleCache="Genus" termType="RK" uri="" idinvocabulary="gen." orderindex="34" rankclass="GE" vocabulary_id="15"/>