package com.constellio.app.ui.framework.components.fields.lookup; import static com.constellio.app.services.factories.ConstellioFactories.getInstance; import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.fromAllSchemasIn; import static com.constellio.model.services.search.query.logical.valueCondition.ConditionTemplateFactory.autocompleteFieldMatching; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; import com.constellio.app.services.factories.ConstellioFactories; import com.constellio.app.ui.application.ConstellioUI; import com.constellio.app.ui.entities.UserVO; import com.constellio.app.ui.framework.components.converters.RecordIdToCaptionConverter; import com.constellio.app.ui.framework.components.converters.TaxonomyCodeToCaptionConverter; import com.constellio.app.ui.framework.components.tree.LazyTree; import com.constellio.app.ui.framework.data.LazyTreeDataProvider; import com.constellio.app.ui.framework.data.RecordLazyTreeDataProvider; import com.constellio.app.ui.pages.base.SessionContext; import com.constellio.model.entities.Taxonomy; import com.constellio.model.entities.records.Record; import com.constellio.model.entities.records.wrappers.User; import com.constellio.model.entities.schemas.Schemas; import com.constellio.model.services.factories.ModelLayerFactory; import com.constellio.model.services.search.SPEQueryResponse; import com.constellio.model.services.search.StatusFilter; import com.constellio.model.services.search.query.logical.LogicalSearchQuery; import com.constellio.model.services.search.query.logical.condition.LogicalSearchCondition; import com.constellio.model.services.taxonomies.TaxonomiesManager; import com.constellio.model.services.users.UserServices; import com.vaadin.server.Resource; public class PathLookupField extends LookupField<String> { private final TaxonomyCodeToCaptionConverter captionConverter; public PathLookupField() { super(new PathInputDataProvider( ConstellioFactories.getInstance().getModelLayerFactory(), ConstellioUI.getCurrentSessionContext()), getTreeDataProviders()); setItemConverter(new RecordIdToCaptionConverter()); captionConverter = new TaxonomyCodeToCaptionConverter(); } @Override public Class<? extends String> getType() { return String.class; } @Override protected String getCaptionForLazyTree(LazyTreeDataProvider<String> lazyTreeDataProvider) { String taxonomyCode = lazyTreeDataProvider.getTaxonomyCode(); return captionConverter.convertToPresentation(taxonomyCode, String.class, getLocale()); } @SuppressWarnings("unchecked") @Override protected LazyTree<String> newLazyTree( LookupTreeDataProvider<String> lookupTreeDataProvider, int treeBufferSize) { return new LazyTree<String>(lookupTreeDataProvider, treeBufferSize) { @Override public String getItemCaption(String itemId) { return PathLookupField.this.getCaption(itemId); } @Override public Resource getItemIcon(Object itemId) { boolean expanded = isExpanded(itemId); return getDataProvider().getIcon((String) itemId, expanded); } }; } private static LookupTreeDataProvider<String>[] getTreeDataProviders() { SessionContext sessionContext = ConstellioUI.getCurrentSessionContext(); String collection = sessionContext.getCurrentCollection(); UserVO currentUserVO = sessionContext.getCurrentUser(); ConstellioFactories constellioFactories = ConstellioFactories.getInstance(); ModelLayerFactory modelLayerFactory = constellioFactories.getModelLayerFactory(); UserServices userServices = modelLayerFactory.newUserServices(); TaxonomiesManager taxonomiesManager = modelLayerFactory.getTaxonomiesManager(); User currentUser = userServices.getUserInCollection(currentUserVO.getUsername(), collection); List<Taxonomy> taxonomies = taxonomiesManager.getAvailableTaxonomiesInHomePage(currentUser); List<PathLookupTreeDataProvider> dataProviders = new ArrayList<>(); for (Taxonomy taxonomy : taxonomies) { String taxonomyCode = taxonomy.getCode(); if (StringUtils.isNotBlank(taxonomyCode)) { dataProviders.add(new PathLookupTreeDataProvider(taxonomyCode)); } } return !dataProviders.isEmpty() ? dataProviders.toArray(new PathLookupTreeDataProvider[dataProviders.size()]) : null; } public static class PathInputDataProvider extends TextInputDataProvider<String> { private transient int lastStartIndex; private transient String lastQuery; private transient SPEQueryResponse response; private transient ModelLayerFactory modelLayerFactory; private transient SessionContext sessionContext; public PathInputDataProvider(ModelLayerFactory modelLayerFactory, SessionContext sessionContext) { this.modelLayerFactory = modelLayerFactory; this.sessionContext = sessionContext; } @Override public List<String> getData(String text, int startIndex, int count) { User user = getCurrentUser(); if (lastQuery == null || !lastQuery.equals(text) || lastStartIndex != startIndex) { lastQuery = text; lastStartIndex = startIndex; response = searchAutocompleteField(user, text, startIndex, count); } return toRecordIds(response.getRecords()); } @Override public int size(String text) { User user = getCurrentUser(); if (lastQuery == null || !lastQuery.equals(text)) { lastQuery = text; lastStartIndex = -1; response = searchAutocompleteField(user, text, 0, 1); } return (int) response.getNumFound(); } @Override public User getCurrentUser() { UserServices userServices = modelLayerFactory.newUserServices(); return userServices.getUserInCollection( sessionContext.getCurrentUser().getUsername(), sessionContext.getCurrentCollection()); } @Override public void setOnlyLinkables(boolean onlyLinkables) { // Ignore } private SPEQueryResponse searchAutocompleteField(User user, String text, int startIndex, int count) { LogicalSearchCondition condition = fromAllSchemasIn(sessionContext.getCurrentCollection()) .where(autocompleteFieldMatching(text)).andWhere(Schemas.PATH).isNotNull(); LogicalSearchQuery query = new LogicalSearchQuery(condition) .filteredWithUser(user).filteredByStatus(StatusFilter.ACTIVES) .setStartRow(startIndex).setNumberOfRows(count); return modelLayerFactory.newSearchServices().query(query); } private List<String> toRecordIds(List<Record> matches) { List<String> recordIds = new ArrayList<>(); for (Record match : matches) { recordIds.add(match.getId()); } return recordIds; } private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); modelLayerFactory = ConstellioFactories.getInstance().getModelLayerFactory(); sessionContext = ConstellioUI.getCurrentSessionContext(); } @Override public ModelLayerFactory getModelLayerFactory() { return modelLayerFactory; } } public static class PathLookupTreeDataProvider extends RecordLazyTreeDataProvider implements LookupTreeDataProvider<String> { public PathLookupTreeDataProvider(String taxonomyCode) { super(taxonomyCode); } @Override public TextInputDataProvider<String> search() { ModelLayerFactory modelLayerFactory = getInstance().getModelLayerFactory(); SessionContext sessionContext = ConstellioUI.getCurrentSessionContext(); return new PathInputDataProvider(modelLayerFactory, sessionContext); } @Override public boolean isSelectable(String selection) { return true; } } // public static class PathLookupTreeDataProvider implements LookupTreeDataProvider<String> { // private transient ModelLayerFactory modelLayerFactory; // private transient SessionContext sessionContext; // private final String taxonomyCode; // private final Map<String, Integer> childrenCounts = new HashMap<>(); // private final Map<String, String> parentCache = new HashMap<>(); // private int rootObjectsCount = -1; // // public PathLookupTreeDataProvider(ModelLayerFactory modelLayerFactory, SessionContext sessionContext, // String taxonomyCode) { // this.modelLayerFactory = modelLayerFactory; // this.sessionContext = sessionContext; // this.taxonomyCode = taxonomyCode; // } // // @Override // public TextInputDataProvider<String> search() { // return new PathInputDataProvider(modelLayerFactory, sessionContext); // } // // @Override // public boolean isSelectable(String selection) { // return true; // } // // @Override // public ObjectsResponse<String> getRootObjects(int start, int maxSize) { // TaxonomiesSearchServices taxonomiesSearchServices = modelLayerFactory.newTaxonomiesSearchService(); // TaxonomiesSearchOptions taxonomiesSearchOptions = new TaxonomiesSearchOptions(maxSize, start, StatusFilter.ACTIVES); // LinkableTaxonomySearchResponse response = taxonomiesSearchServices.getVisibleRootConceptResponse( // getCurrentUser(), sessionContext.getCurrentCollection(), taxonomyCode, taxonomiesSearchOptions); // // List<String> recordIds = new ArrayList<>(); // for (TaxonomySearchRecord match : response.getRecords()) { // String recordId = match.getId(); // recordIds.add(recordId); // } // return new ObjectsResponse<String>(recordIds, response.getNumFound()); // } // // @Override // public String getParent(String child) { // return parentCache.get(child); // } // // @Override // public ObjectsResponse<String> getChildren(String parent, int start, int maxSize) { // TaxonomiesSearchServices taxonomiesSearchServices = modelLayerFactory.newTaxonomiesSearchService(); // // RecordServices recordServices = modelLayerFactory.newRecordServices(); // Record record = recordServices.getDocumentById(parent); // // TaxonomiesSearchOptions taxonomiesSearchOptions = new TaxonomiesSearchOptions(maxSize, start, StatusFilter.ACTIVES); // LinkableTaxonomySearchResponse response = taxonomiesSearchServices.getVisibleChildConceptResponse( // getCurrentUser(), taxonomyCode, record, taxonomiesSearchOptions); // // List<String> recordIds = new ArrayList<>(); // for (TaxonomySearchRecord match : response.getRecords()) { // String recordId = match.getId(); // recordIds.add(recordId); // parentCache.put(recordId, parent); // } // return new ObjectsResponse<>(recordIds, response.getNumFound()); // } // // @Override // public boolean hasChildren(String parent) { // return getChildren(parent, 0, 1).getCount() > 0; // } // // @Override // public boolean isLeaf(String object) { // return !hasChildren(object); // } // // @Override // public String getTaxonomyCode() { // return taxonomyCode; // } // // private User getCurrentUser() { // UserServices userServices = modelLayerFactory.newUserServices(); // return userServices.getUserInCollection( // sessionContext.getCurrentUser().getUsername(), sessionContext.getCurrentCollection()); // } // // private void readObject(java.io.ObjectInputStream stream) // throws IOException, ClassNotFoundException { // stream.defaultReadObject(); // modelLayerFactory = ConstellioFactories.getInstance().getModelLayerFactory(); // sessionContext = ConstellioUI.getCurrentSessionContext(); // } // } }