--- /dev/null
+/**
+* Copyright (C) 2018 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.service;
+
+import org.vaadin.viritin.fields.LazyComboBox.FilterablePagingProvider;
+
+/**
+ * @author a.kohlbecker
+ * @since Sep 24, 2018
+ *
+ */
+public interface FilterableStringRepresentationPagingProvider<IDTYPE> extends FilterablePagingProvider<String> {
+
+ public IDTYPE idFor(String stringRepresentation);
+
+
+}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import org.apache.log4j.Logger;
import org.hibernate.criterion.Criterion;
import org.vaadin.viritin.fields.LazyComboBox.FilterableCountProvider;
-import org.vaadin.viritin.fields.LazyComboBox.FilterablePagingProvider;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.ui.AbstractField;
import eu.etaxonomy.cdm.persistence.query.OrderHint;
/**
+ * IMPORTANT !!!
+ *
+ * The string representations returned as rankSpecificNamePart must be unique in the database since these are being used as weak references between e.g.
+ * genus name and the TaxonName entity for this genus.
+ *
* @author a.kohlbecker
* @since Jun 7, 2017
*
*/
-public class TaxonNameStringFilterablePagingProvider implements FilterablePagingProvider<String>, FilterableCountProvider {
+public class TaxonNameStringFilterablePagingProvider implements FilterableStringRepresentationPagingProvider<UUID>, FilterableCountProvider {
private static final List<String> DEFAULT_INIT_STRATEGY = Arrays.asList("$");
private Map<AbstractField<String>, ValueChangeListener> registeredToFields = new HashMap<>();
+ private Map<String, UUID> lastPagedEntityUUIDs;
+
public TaxonNameStringFilterablePagingProvider(INameService service) {
this(service, Rank.GENUS(), null);
logger.trace("findEntities() - page: " + taxonNamePager.getCurrentIndex() + "/" + taxonNamePager.getPagesAvailable() + " totalRecords: " + taxonNamePager.getCount() + "\n" + taxonNamePager.getRecords());
}
List<String> namePartStrings = new ArrayList<>(taxonNamePager.getRecords().size());
+ lastPagedEntityUUIDs = new HashMap<>(taxonNamePager.getRecords().size());
for(TaxonNameParts tnp : taxonNamePager.getRecords()){
- namePartStrings.add(tnp.rankSpecificNamePart());
+ String rankSpecificNamePart = tnp.rankSpecificNamePart();
+ String namePartKey = rankSpecificNamePart;
+ if(lastPagedEntityUUIDs.containsKey(namePartKey)){
+ namePartKey = rankSpecificNamePart + " DUPLICATE[" + tnp.getTaxonNameUuid() + "]";
+ }
+ namePartStrings.add(namePartKey);
+ lastPagedEntityUUIDs.put(namePartKey, tnp.getTaxonNameUuid());
}
return namePartStrings;
}
return criteria;
}
+ /**
+ * @return the lastPagedEntityUUIDs
+ */
+ public Map<String, UUID> getLastPagedEntityUUIDs() {
+ return lastPagedEntityUUIDs;
+ }
+
+
public class UnknownFieldException extends Exception {
private static final long serialVersionUID = 1L;
}
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public UUID idFor(String stringRepresentation) {
+ if(lastPagedEntityUUIDs == null){
+ findEntities(0, stringRepresentation);
+ }
+ return lastPagedEntityUUIDs.get(stringRepresentation);
+ }
}
import org.hibernate.criterion.Restrictions;
import org.springframework.context.annotation.Scope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
-import org.vaadin.viritin.fields.LazyComboBox;
import com.vaadin.data.Property;
import com.vaadin.spring.annotation.SpringComponent;
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
+import eu.etaxonomy.vaadin.component.CompositeCustomField;
import eu.etaxonomy.vaadin.component.ReloadableLazyComboBox;
import eu.etaxonomy.vaadin.component.ToOneRelatedEntityCombobox;
+import eu.etaxonomy.vaadin.component.WeaklyRelatedEntityCombobox;
import eu.etaxonomy.vaadin.event.FieldReplaceEvent;
import eu.etaxonomy.vaadin.mvp.AbstractCdmDTOEditorPresenter;
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
if(boundPropertyIdPath != null){
if(boundPropertyIdPath.matches("specificEpithet")){
AbstractField<String> genusOrUninomialField = getView().getGenusOrUninomialField();
- if(event.getNewField() instanceof LazyComboBox){
-
- if(specificEpithetPartPagingProvider == null){
+ if(event.getNewField() instanceof CompositeCustomField){
+ if(specificEpithetPartPagingProvider == null){
specificEpithetPartPagingProvider = new TaxonNameStringFilterablePagingProvider(getRepo().getNameService(), Rank.SPECIES());
}
specificEpithetPartPagingProvider.listenToFields(
genusOrUninomialField,
null, null, null);
specificEpithetPartPagingProvider.updateFromFields();
- LazyComboBox<String> specificEpithetField = (LazyComboBox<String>)event.getNewField();
- refreshSpecificEpithetComboBoxListener = e -> { specificEpithetField.refresh(); specificEpithetField.setValue(null);};
- genusOrUninomialField.addValueChangeListener(refreshSpecificEpithetComboBoxListener);
+ WeaklyRelatedEntityCombobox<TaxonName> specificEpithetField = (WeaklyRelatedEntityCombobox<TaxonName>)event.getNewField();
+ refreshSpecificEpithetComboBoxListener = e -> { specificEpithetField.getSelect().refresh(); specificEpithetField.setValue(null);};
specificEpithetField.loadFrom(specificEpithetPartPagingProvider, specificEpithetPartPagingProvider, specificEpithetPartPagingProvider.getPageSize());
+ specificEpithetField.setValue(event.getOldField().getValue());
+ genusOrUninomialField.addValueChangeListener(refreshSpecificEpithetComboBoxListener);
} else {
if(specificEpithetPartPagingProvider != null){
specificEpithetPartPagingProvider.unlistenAllFields();
}
}
} else if(boundPropertyIdPath.matches("genusOrUninomial")) {
- if(event.getNewField() instanceof LazyComboBox){
+ if(event.getNewField() instanceof CompositeCustomField){
if(genusOrUninomialPartPagingProvider == null){
genusOrUninomialPartPagingProvider = new TaxonNameStringFilterablePagingProvider(getRepo().getNameService());
}
getView().getSpecificEpithetField(),
getView().getInfraSpecificEpithetField()
);
- LazyComboBox<String> genusOrUninomialField = (LazyComboBox<String>)event.getNewField();
+ WeaklyRelatedEntityCombobox<TaxonName> genusOrUninomialField = (WeaklyRelatedEntityCombobox<TaxonName>)event.getNewField();
+ // FIXME genusOrUninomialField.setNestedButtonStateUpdater(new ToOneRelatedEntityButtonUpdater<TaxonName>(genusOrUninomialField));
genusOrUninomialField.loadFrom(genusOrUninomialPartPagingProvider, genusOrUninomialPartPagingProvider, genusOrUninomialPartPagingProvider.getPageSize());
-
+ genusOrUninomialField.setValue(event.getOldField().getValue());
}else {
if(genusOrUninomialPartPagingProvider != null){
genusOrUninomialPartPagingProvider.unlistenAllFields();
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.security.core.GrantedAuthority;
-import org.vaadin.viritin.fields.LazyComboBox;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeListener;
import eu.etaxonomy.vaadin.component.SwitchableTextField;
import eu.etaxonomy.vaadin.component.ToManyRelatedEntitiesComboboxSelect;
import eu.etaxonomy.vaadin.component.ToOneRelatedEntityCombobox;
+import eu.etaxonomy.vaadin.component.WeaklyRelatedEntityCombobox;
import eu.etaxonomy.vaadin.event.EditorActionType;
import eu.etaxonomy.vaadin.mvp.AbstractCdmDTOPopupEditor;
if(isModeEnabled(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART)){
if(isSpeciesOrBelow) {
if(TextField.class.isAssignableFrom(genusOrUninomialField.getClass())){
- genusOrUninomialField = replaceComponent("genusOrUninomial", genusOrUninomialField, new LazyComboBox<String>(String.class), 0, genusOrUninomialRow, 1, genusOrUninomialRow);
+ WeaklyRelatedEntityCombobox<TaxonName> combobox = new WeaklyRelatedEntityCombobox<TaxonName>("-> this caption will be relpaced <-", TaxonName.class);
+ genusOrUninomialField = replaceComponent("genusOrUninomial", genusOrUninomialField, combobox, 0, genusOrUninomialRow, 1, genusOrUninomialRow);
}
} else {
- if(LazyComboBox.class.isAssignableFrom(genusOrUninomialField.getClass())) {
+ if(ToOneRelatedEntityCombobox.class.isAssignableFrom(genusOrUninomialField.getClass())) {
genusOrUninomialField = replaceComponent("genusOrUninomial", genusOrUninomialField, new TextFieldNFix(), 0, genusOrUninomialRow, 1, genusOrUninomialRow);
}
}
if(isModeEnabled(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART)){
if(rank.isInfraSpecific()) {
if(TextField.class.isAssignableFrom(specificEpithetField.getClass())) {
- specificEpithetField = replaceComponent("specificEpithet", specificEpithetField, new LazyComboBox<String>(String.class), 0, specificEpithetFieldRow, 1, specificEpithetFieldRow);
+ WeaklyRelatedEntityCombobox<TaxonName> combobox = new WeaklyRelatedEntityCombobox<TaxonName>("-> this caption will be relpaced <-", TaxonName.class);
+ specificEpithetField = replaceComponent("specificEpithet", specificEpithetField, combobox, 0, specificEpithetFieldRow, 1, specificEpithetFieldRow);
}
} else {
- if(LazyComboBox.class.isAssignableFrom(specificEpithetField.getClass())) {
+ if(ToOneRelatedEntityCombobox.class.isAssignableFrom(specificEpithetField.getClass())) {
specificEpithetField = replaceComponent("specificEpithet", specificEpithetField, new TextFieldNFix(), 0, specificEpithetFieldRow, 1, specificEpithetFieldRow);
}
}
--- /dev/null
+/**
+* Copyright (C) 2017 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.vaadin.component;
+
+import java.util.UUID;
+
+import org.vaadin.viritin.fields.LazyComboBox.FilterableCountProvider;
+import org.vaadin.viritin.fields.LazyComboBox.FilterablePagingProvider;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.fieldgroup.FieldGroup;
+import com.vaadin.data.util.converter.Converter.ConversionException;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.themes.ValoTheme;
+
+import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
+import eu.etaxonomy.cdm.service.FilterableStringRepresentationPagingProvider;
+import eu.etaxonomy.cdm.service.UserHelperAccess;
+import eu.etaxonomy.cdm.vaadin.component.ButtonFactory;
+import eu.etaxonomy.cdm.vaadin.event.NestedButtonStateUpdater;
+
+/**
+ * @author a.kohlbecker
+ * @since May 24, 2017
+ *
+ */
+public class WeaklyRelatedEntityCombobox<V extends IdentifiableEntity<?>> extends CompositeCustomField<String>
+ implements WeaklyRelatedEntityField<V>, ReloadableSelect {
+
+ private static final long serialVersionUID = 6277565876657520311L;
+
+ public static final String PRIMARY_STYLE = "v-related-entity-combobox";
+
+ private Class<V> type;
+
+ private CssLayout container = new CssLayout();
+
+ private ReloadableLazyComboBox<String> lazySelect;
+
+ private Button addButton = ButtonFactory.CREATE_NEW.createButton();
+ private Button editButton = ButtonFactory.EDIT_ITEM.createButton();
+
+ private WeaklyRelatedEntityButtonUpdater buttonUpdater;
+
+ private FilterableStringRepresentationPagingProvider<UUID> filterablePagingProvider;
+
+ public WeaklyRelatedEntityCombobox(String caption, Class<V> type){
+ this.type = type;
+ setCaption(caption);
+ lazySelect = new ReloadableLazyComboBox<String>(String.class);
+ addStyledComponents(lazySelect, addButton, editButton);
+ addSizedComponents(lazySelect, container);
+ buttonUpdater = new WeaklyRelatedEntityButtonUpdater(this, type);
+ lazySelect.addValueChangeListener(buttonUpdater);
+ lazySelect.addValueChangeListener(e -> {
+ // update the itemContainer immediately so that the edit button acts on the chosen item
+ lazySelect.commit();
+ });
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Component initContent() {
+ container.addComponents(lazySelect, addButton, editButton);
+ setPrimaryStyleName(PRIMARY_STYLE);
+ addDefaultStyles();
+ return container;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ @Override
+ public Class<String> getType() {
+ return String.class;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addDefaultStyles() {
+ container.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public FieldGroup getFieldGroup() {
+ return null;
+ }
+
+ /**
+ * @return the select
+ */
+ public ReloadableLazyComboBox<String> getSelect() {
+ return lazySelect;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void loadFrom(FilterablePagingProvider<String> filterablePagingProvider, FilterableCountProvider filterableCountProvider, int pageLength) {
+
+ this.filterablePagingProvider = (FilterableStringRepresentationPagingProvider<UUID>) filterablePagingProvider;
+ lazySelect.loadFrom(filterablePagingProvider, filterableCountProvider, pageLength);
+ buttonUpdater.updateButtons(getValue());
+ }
+
+ /**
+ * reload the selected entity from the persistent storage
+ */
+ @Override
+ public void reload() {
+ getSelect().reload();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setAddButtonEnabled(boolean enabled) {
+ addButton.setEnabled(enabled);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addClickListenerAddEntity(ClickListener listener) {
+ addButton.addClickListener(listener);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setEditButtonEnabled(boolean enabled) {
+ editButton.setEnabled(enabled);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addClickListenerEditEntity(ClickListener listener) {
+ editButton.addClickListener(listener);
+ }
+
+ @Override
+ public void selectNewItem(String bean){
+ setValue(bean);
+ }
+
+ /**
+ * Returns always currently selected item by
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public String getValue() {
+ lazySelect.commit();
+ return lazySelect.getValue();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setValue(String newFieldValue) throws com.vaadin.data.Property.ReadOnlyException, ConversionException {
+ lazySelect.refresh();
+ lazySelect.setValue(newFieldValue);
+ lazySelect.markAsDirty();
+ }
+
+ @Override
+ public void setPropertyDataSource(Property newDataSource) {
+ lazySelect.setPropertyDataSource(newDataSource);
+ if(buttonUpdater != null){
+ buttonUpdater.updateButtons(lazySelect.getValue());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Property getPropertyDataSource() {
+ return lazySelect.getPropertyDataSource();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setReadOnly(boolean readOnly) {
+ super.setReadOnly(readOnly);
+ setDeepReadOnly(readOnly, getContent(), null);
+ if(buttonUpdater != null){
+ buttonUpdater.updateButtons(lazySelect.getValue());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @deprecated NestedButtonStateUpdater should rather be instantiated in the RelatedEntityField instead of passing it as property
+ */
+ @Override
+ @Deprecated
+ public void setNestedButtonStateUpdater(NestedButtonStateUpdater<V> buttonUpdater) {
+ // not needed
+ }
+
+ class WeaklyRelatedEntityButtonUpdater implements NestedButtonStateUpdater<String> {
+
+ private static final long serialVersionUID = 4472031263172275012L;
+
+ WeaklyRelatedEntityCombobox<V> toOneRelatedEntityField;
+
+ private Class<V> type;
+
+
+ public WeaklyRelatedEntityButtonUpdater(WeaklyRelatedEntityCombobox<V> toOneRelatedEntityField, Class<V> type){
+ this.toOneRelatedEntityField = toOneRelatedEntityField;
+ this.type = type;
+ String stringValue = toOneRelatedEntityField.getValue();
+ updateButtons(toOneRelatedEntityField.getValue());
+ toOneRelatedEntityField.setEditButtonEnabled(false);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
+
+ String value = (String)event.getProperty().getValue();
+ updateButtons(value);
+ }
+
+ /**
+ * @param value
+ */
+ @Override
+ public void updateButtons(String value) {
+
+ UUID uuid = null;
+ if(value != null && filterablePagingProvider != null){
+ uuid = filterablePagingProvider.idFor(value);
+ }
+ boolean userIsAllowedToUpdate = uuid != null && UserHelperAccess.userHelper().userHasPermission(type, uuid, CRUD.UPDATE);
+ boolean userIsAllowedToCreate = UserHelperAccess.userHelper().userHasPermission(type, CRUD.CREATE);
+ boolean isReadOnlyField = ((Field)toOneRelatedEntityField).isReadOnly();
+
+ toOneRelatedEntityField.setAddButtonEnabled(!isReadOnlyField && userIsAllowedToCreate);
+ toOneRelatedEntityField.setEditButtonEnabled(!isReadOnlyField && userIsAllowedToUpdate);
+ }
+ }
+
+
+
+}
--- /dev/null
+/**
+* Copyright (C) 2017 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.vaadin.component;
+
+import com.vaadin.ui.Button.ClickListener;
+
+import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
+import eu.etaxonomy.cdm.vaadin.event.NestedButtonStateUpdater;
+
+/**
+ * @author a.kohlbecker
+ * @since May 25, 2017
+ *
+ */
+public interface WeaklyRelatedEntityField<V extends IdentifiableEntity> {
+
+ public void setNestedButtonStateUpdater(NestedButtonStateUpdater<V> buttonUpdater);
+
+ /**
+ * Set the enabled state of the edit button
+ *
+ * @param enabled
+ */
+ public void setEditButtonEnabled(boolean enabled);
+
+ /**
+ * Adds the click listener to the add-entity-button.
+ *
+ * @param listener
+ * the Listener to be added.
+ */
+ public void addClickListenerAddEntity(ClickListener listener);
+
+ /**
+ * Set the enabled state of the add button
+ *
+ * @param enabled
+ */
+ public void setAddButtonEnabled(boolean enabled);
+
+ /**
+ * Adds the click listener to the edit-entity-button.
+ *
+ * @param listener
+ * the Listener to be added.
+ */
+ public void addClickListenerEditEntity(ClickListener listener);
+
+ public void selectNewItem(String stringRepresentation);
+
+ public Class<String> getType();
+
+}