diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/bandboxsearch/BandboxMultipleSearch.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/bandboxsearch/BandboxMultipleSearch.java index 3b9b1b002..c37c58e28 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/bandboxsearch/BandboxMultipleSearch.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/bandboxsearch/BandboxMultipleSearch.java @@ -29,6 +29,7 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; +import org.navalplanner.web.common.components.finders.FilterPair; import org.navalplanner.web.common.components.finders.IMultipleFiltersFinder; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; @@ -76,8 +77,7 @@ public class BandboxMultipleSearch extends HtmlMacroComponent { bandbox = (Bandbox) getFellowIfAny("bandbox"); if (multipleFiltersFinder != null) { - listbox.setModel(new SimpleListModel(multipleFiltersFinder - .getMatching(""))); + listbox.setModel(getSubModel()); listbox.setItemRenderer(multipleFiltersFinder.getItemRenderer()); addHeaders(); @@ -91,15 +91,9 @@ public class BandboxMultipleSearch extends HtmlMacroComponent { final String inputText = ((InputEvent) event).getValue(); if ((inputText == null) || (inputText.isEmpty())) { clear(); + searchMultipleFilters(); } else { - String newFilterText = getNewFilterText(inputText); - if ((newFilterText != null) - && (newFilterText.length() > 2)) { - listbox.setModel(getSubModel(newFilterText)); - listbox.invalidate(); - } else { - clearListbox(); - } + searchMultipleFilters(inputText); } } }); @@ -112,9 +106,11 @@ public class BandboxMultipleSearch extends HtmlMacroComponent { @Override public void onEvent(Event event) throws Exception { final Object object = getSelectedItem().getValue(); - addSelectedElement(object); + if (multipleFiltersFinder.isValidNewFilter(object)) { + addSelectedElement(object); + clearListbox(); + } bandbox.close(); - clearListbox(); } }); } @@ -122,21 +118,20 @@ public class BandboxMultipleSearch extends HtmlMacroComponent { updateWidth(); } - private String getNewFilterText(String inputText){ - String newFilterText = new String(""); - String[] filtersText = inputText.split(","); - newFilterText = getLastText(filtersText); - newFilterText = newFilterText.replace(" ", ""); - newFilterText = newFilterText.trim(); - return newFilterText; + private void searchMultipleFilters() { + listbox.setModel(getSubModel()); + listbox.invalidate(); } - private String getLastText(String[] texts) { - Integer last = texts.length - 1; - if (texts.length > 0) { - return texts[last]; + private void searchMultipleFilters(String inputText) { + String newFilterText = multipleFiltersFinder + .getNewFilterText(inputText); + selectedFiltersText = inputText.replace(newFilterText, ""); + if ((newFilterText != null) && (!newFilterText.isEmpty())) { + listbox.setModel(getSubModel(newFilterText)); + listbox.invalidate(); } else { - return ""; + searchMultipleFilters(); } } @@ -151,10 +146,25 @@ public class BandboxMultipleSearch extends HtmlMacroComponent { selectedFiltersText = selectedFiltersText .concat(multipleFiltersFinder.objectToString(obj)); bandbox.setValue(selectedFiltersText); - selectedFilters.add(obj); + + addFilter(obj); + selectedFilters = multipleFiltersFinder.updateDeletedFilters( + selectedFilters, selectedFiltersText); } } + private void addFilter(Object obj) { + FilterPair newFilter = (FilterPair) obj; + for (FilterPair filter : (List) selectedFilters) { + if ((filter.getType().equals(newFilter.getType())) + && (filter.getPattern().equals(newFilter.getPattern()))) { + throw new WrongValueException(bandbox, + _("filter already exists")); + } + } + selectedFilters.add(obj); + } + public List getSelectedElements() { if (this.multipleFiltersFinder != null) { if (!multipleFiltersFinder.isValidFormatText(selectedFilters, @@ -167,7 +177,16 @@ public class BandboxMultipleSearch extends HtmlMacroComponent { } /** - * Find {@link Label} which name or type start with prefix + * Find the first ten filters + */ + @SuppressWarnings("unchecked") + private ListModel getSubModel() { + List result = multipleFiltersFinder.getFirstTenFilters(); + return new SimpleListModel(result); + } + + /** + * Find filter which contains the expression * @param inputText */ @SuppressWarnings("unchecked") @@ -227,7 +246,6 @@ public class BandboxMultipleSearch extends HtmlMacroComponent { * @param bandbox */ public void clear() { - clearListbox(); clearSelectedElement(); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/IMultipleFiltersFinder.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/IMultipleFiltersFinder.java index 055eb6d63..7005dbd92 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/IMultipleFiltersFinder.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/IMultipleFiltersFinder.java @@ -35,10 +35,18 @@ public interface IMultipleFiltersFinder { List getMatching(String filter); + List getFirstTenFilters(); + String objectToString(Object obj); + String getNewFilterText(String inputText); + + boolean isValidNewFilter(Object obj); + boolean isValidFormatText(List filterValues, String value); + List updateDeletedFilters(List filterValues, String value); + String[] getHeaders(); ListitemRenderer getItemRenderer(); diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/MultipleFiltersFinder.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/MultipleFiltersFinder.java index a090a2a40..ab58fcb02 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/MultipleFiltersFinder.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/MultipleFiltersFinder.java @@ -24,6 +24,7 @@ import static org.navalplanner.web.I18nHelper._; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -91,6 +92,8 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { private static OrderStatusEnum[] ordersStatusEnums; + private static boolean updating = false; + private static final List ordersCodes = new ArrayList(); private List listMatching = new ArrayList(); @@ -163,6 +166,85 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { } } + public List getFirstTenFilters() { + listMatching.clear(); + fillWithFirstTenFiltersLabels(); + fillWithFirstTenFiltersLabels(); + fillWithFirstTenFiltersCustomer(); + fillWithFirstTenFiltersState(); + fillWihtFirstTenFiltersCodes(); + fillWihtFirstTenFiltersCustomerReferences(); + listMatching.add(new FilterPair(OrderFilterEnum.None, + OrderFilterEnum.None.toString(), null)); + return listMatching; + } + + private List fillWithFirstTenFiltersLabels() { + Iterator iteratorLabelType = mapLabels.keySet().iterator(); + while (iteratorLabelType.hasNext() && listMatching.size() < 10) { + LabelType type = iteratorLabelType.next(); + for (int i = 0; listMatching.size() < 10 + && i < mapLabels.get(type).size(); i++) { + Label label = mapLabels.get(type).get(i); + String pattern = type.getName() + " :: " + label.getName(); + listMatching.add(new FilterPair(OrderFilterEnum.Label, pattern, + label)); + } + } + return listMatching; + } + + private List fillWithFirstTenFiltersCriterions() { + Iterator iteratorCriterionType = mapCriterions.keySet() + .iterator(); + while (iteratorCriterionType.hasNext() && listMatching.size() < 10) { + CriterionType type = iteratorCriterionType.next(); + for (int i = 0; listMatching.size() < 10 + && i < mapCriterions.get(type).size(); i++) { + Criterion criterion = mapCriterions.get(type).get(i); + String pattern = type.getName() + " :: " + criterion.getName(); + listMatching.add(new FilterPair(OrderFilterEnum.Criterion, + pattern, criterion)); + } + } + return listMatching; + } + + private List fillWithFirstTenFiltersCustomer() { + for (int i = 0; listMatching.size() < 10 + && i < externalCompanies.size(); i++) { + ExternalCompany externalCompany = externalCompanies.get(i); + addExternalCompany(externalCompany); + } + return listMatching; + } + + private List fillWithFirstTenFiltersState() { + for (int i = 0; listMatching.size() < 10 + && i < OrderStatusEnum.values().length; i++) { + OrderStatusEnum state = OrderStatusEnum.values()[i]; + addState(state); + } + return listMatching; + } + + private List fillWihtFirstTenFiltersCodes() { + for (int i = 0; listMatching.size() < 10 && i < ordersCodes.size(); i++) { + String code = ordersCodes.get(i); + addCode(code); + } + return listMatching; + } + + private List fillWihtFirstTenFiltersCustomerReferences() { + for (int i = 0; listMatching.size() < 10 + && i < customerReferences.size(); i++) { + String reference = customerReferences.get(i); + addCustomerReference(reference); + } + return listMatching; + } + public List getMatching(String filter) { listMatching.clear(); if ((filter != null) && (!filter.isEmpty())) { @@ -178,13 +260,16 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { searchInOrderStatus(filter); } } + + addNoneFilter(); return listMatching; } private void searchInCriterionTypes(String filter) { + boolean limited = (filter.length() < 3); for (CriterionType type : mapCriterions.keySet()) { if (type.getName().toLowerCase().contains(filter)) { - setFilterPairCriterionType(type); + setFilterPairCriterionType(type, limited); } else { searchInCriterions(type, filter); } @@ -194,26 +279,28 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { private void searchInCriterions(CriterionType type, String filter) { for (Criterion criterion : mapCriterions.get(type)) { if (criterion.getName().toLowerCase().contains(filter)) { - String pattern = type.getName() + " :: " + criterion.getName(); - listMatching.add(new FilterPair(OrderFilterEnum.Criterion, - pattern, - criterion)); + addCriterion(type, criterion); + if ((filter.length() < 3) && (listMatching.size() > 9)) { + return; + } } } } - private void setFilterPairCriterionType(CriterionType type) { + private void setFilterPairCriterionType(CriterionType type, boolean limited) { for (Criterion criterion : mapCriterions.get(type)) { - String pattern = type.getName() + " :: " + criterion.getName(); - listMatching.add(new FilterPair(OrderFilterEnum.Criterion, pattern, - criterion)); + addCriterion(type, criterion); + if ((limited) && (listMatching.size() > 9)) { + return; + } } } private void searchInLabelTypes(String filter) { + boolean limited = (filter.length() < 3); for (LabelType type : mapLabels.keySet()) { if (type.getName().toLowerCase().contains(filter)) { - setFilterPairLabelType(type); + setFilterPairLabelType(type, limited); } else { searchInLabels(type, filter); } @@ -223,18 +310,20 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { private void searchInLabels(LabelType type, String filter) { for (Label label : mapLabels.get(type)) { if (label.getName().toLowerCase().contains(filter)) { - String pattern = type.getName() + " :: " + label.getName(); - listMatching.add(new FilterPair(OrderFilterEnum.Label, pattern, - label)); + addLabel(type, label); + if ((filter.length() < 3) && (listMatching.size() > 9)) { + return; + } } } } - private void setFilterPairLabelType(LabelType type) { + private void setFilterPairLabelType(LabelType type, boolean limited) { for (Label label : mapLabels.get(type)) { - String pattern = type.getName() + " :: " + label.getName(); - listMatching.add(new FilterPair(OrderFilterEnum.Label, pattern, - label)); + addLabel(type, label); + if ((limited) && (listMatching.size() > 9)) { + return; + } } } @@ -242,11 +331,10 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { for(ExternalCompany externalCompany : externalCompanies){ if ((externalCompany.getName().toLowerCase().contains(filter)) || (externalCompany.getNif().toLowerCase().contains(filter))) { - String pattern = externalCompany.getName() + " :: " - + externalCompany.getNif(); - listMatching.add(new FilterPair( - OrderFilterEnum.ExternalCompany, pattern, - externalCompany)); + addExternalCompany(externalCompany); + if ((filter.length() < 3) && (listMatching.size() > 9)) { + return; + } } } } @@ -254,8 +342,10 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { private void searchInOrderStatus(String filter) { for (OrderStatusEnum state : ordersStatusEnums) { if (state.name().toLowerCase().contains(filter)) { - listMatching.add(new FilterPair(OrderFilterEnum.State, state - .name(), state)); + addState(state); + if ((filter.length() < 3) && (listMatching.size() > 9)) { + return; + } } } } @@ -266,8 +356,7 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { codeFilter = codeFilter.replace(" ", ""); for (String code : ordersCodes) { if (code.toLowerCase().equals(codeFilter)) { - listMatching.add(new FilterPair(OrderFilterEnum.Code, code, - code)); + addCode(code); return; } } @@ -280,15 +369,50 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { referenceFilter = referenceFilter.replace(" ", ""); for (String reference : customerReferences) { if (reference.toLowerCase().equals(referenceFilter)) { - listMatching.add(new FilterPair( - OrderFilterEnum.CustomerReference, - reference, reference)); + addCustomerReference(reference); return; } } } } + private void addCriterion(CriterionType type, Criterion criterion) { + String pattern = type.getName() + " :: " + criterion.getName(); + listMatching.add(new FilterPair(OrderFilterEnum.Criterion, pattern, + criterion)); + } + + private void addLabel(LabelType type, Label label) { + String pattern = type.getName() + " :: " + label.getName(); + listMatching.add(new FilterPair(OrderFilterEnum.Label, pattern, label)); + } + + private void addExternalCompany(ExternalCompany externalCompany) { + String pattern = externalCompany.getName() + " :: " + + externalCompany.getNif(); + listMatching.add(new FilterPair(OrderFilterEnum.ExternalCompany, + pattern, externalCompany)); + } + + private void addState(OrderStatusEnum state) { + listMatching.add(new FilterPair(OrderFilterEnum.State, state.name(), + state)); + } + + private void addCode(String code) { + listMatching.add(new FilterPair(OrderFilterEnum.Code, code, code)); + } + + private void addCustomerReference(String reference) { + listMatching.add(new FilterPair(OrderFilterEnum.CustomerReference, + reference, reference)); + } + + private void addNoneFilter() { + listMatching.add(new FilterPair(OrderFilterEnum.None, + OrderFilterEnum.None.toString(), null)); + } + public String objectToString(Object obj) { FilterPair filterPair = (FilterPair) obj; String text = filterPair.getType() + "(" + filterPair.getPattern() @@ -296,11 +420,40 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { return text; } + @Override + public String getNewFilterText(String inputText) { + String newFilterText = new String(""); + String[] filtersText = inputText.split(","); + newFilterText = getLastText(filtersText); + newFilterText = newFilterText.replace(" ", ""); + newFilterText = newFilterText.trim(); + return newFilterText; + } + + private String getLastText(String[] texts) { + Integer last = texts.length - 1; + if (texts.length > 0) { + return texts[last]; + } else { + return ""; + } + } + + public boolean isValidNewFilter(Object obj) { + FilterPair filter = (FilterPair) obj; + if (filter.getType().equals(OrderFilterEnum.None)) { + return false; + } + return true; + } + public boolean isValidFormatText(List filterValues, String value) { if (filterValues.isEmpty()) { return true; } + filterValues = updateDeletedFilters(filterValues, value); + String[] values = value.split(","); if (values.length != filterValues.size() + 1) { return false; @@ -308,11 +461,9 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { int i = 0; for (FilterPair filterPair : (List) filterValues) { - String filterValue = values[i].replace(" ", ""); String filterPairText = filterPair.getType() + "(" + filterPair.getPattern() + ")"; - filterPairText = filterPairText.replace(" ", ""); - if (!filterValue.equals(filterPairText)) { + if (!isFilterAdded(values, filterPairText)) { return false; } i++; @@ -320,6 +471,37 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder { return true; } + @Override + public List updateDeletedFilters(List filterValues, String value) { + String[] values = value.split(","); + List listFilters = (List) filterValues; + List list = new ArrayList(); + list.addAll(listFilters); + + if (values.length < filterValues.size() + 1) { + for (FilterPair filterPair : list) { + String filter = filterPair.getType() + "(" + + filterPair.getPattern() + ")"; + if (!isFilterAdded(values, filter)) { + listFilters.remove(filterPair); + } + } + } + return listFilters; + } + + private boolean isFilterAdded(String[] values, String filter) { + for (int i = 0; i < values.length; i++) { + String value = values[i].replace(" ", ""); + filter = filter.replace(" ", ""); + + if (filter.equals(value)) { + return true; + } + } + return false; + } + public String[] getHeaders() { return headers; } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/OrderFilterEnum.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/OrderFilterEnum.java index 22e8d0e64..c6abc16b3 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/OrderFilterEnum.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/OrderFilterEnum.java @@ -25,7 +25,8 @@ package org.navalplanner.web.common.components.finders; public enum OrderFilterEnum { - Criterion("Criterion"), Label("Label"), ExternalCompany("Customer"), State( + None("..."), Criterion("Criterion"), Label("Label"), ExternalCompany( + "Customer"), State( "State"), Code("Code"), CustomerReference("Customer Reference"); private String description; diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderCRUDController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderCRUDController.java index 06d779f03..481ab4651 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderCRUDController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderCRUDController.java @@ -176,7 +176,7 @@ public class OrderCRUDController extends GenericForwardComposer { private Grid listing; - private Vbox orderFilter; + private Hbox orderFilter; private Vbox filter; diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderElementTreeController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderElementTreeController.java index 21369d03e..5d5eac5d6 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderElementTreeController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderElementTreeController.java @@ -57,6 +57,7 @@ import org.zkoss.zul.Button; import org.zkoss.zul.Checkbox; import org.zkoss.zul.Constraint; import org.zkoss.zul.Datebox; +import org.zkoss.zul.Hbox; import org.zkoss.zul.Intbox; import org.zkoss.zul.Label; import org.zkoss.zul.Messagebox; @@ -75,7 +76,7 @@ public class OrderElementTreeController extends TreeController { private Vbox filter; - private Vbox orderFilter; + private Hbox orderFilter; private BandboxSearch bdFilter; diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderPredicate.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderPredicate.java index cad73dc59..fe4a74703 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderPredicate.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderPredicate.java @@ -156,8 +156,8 @@ public class OrderPredicate implements IPredicate { private boolean acceptExternalCompany(FilterPair filter,Order order) { ExternalCompany filterCustomer = (ExternalCompany) filter.getValue(); - if ((order.getCustomer() == null) - || (order.getCustomer().getId().equals(filterCustomer.getId()))) { + if ((order.getCustomer() != null) + && (order.getCustomer().getId().equals(filterCustomer.getId()))) { return true; } return false; @@ -165,8 +165,8 @@ public class OrderPredicate implements IPredicate { private boolean acceptState(FilterPair filter,Order order) { OrderStatusEnum filterState = (OrderStatusEnum) filter.getValue(); - if ((order.getState() == null) - || (order.getState().equals(filterState))) { + if ((order.getState() != null) + && (order.getState().equals(filterState))) { return true; } return false; @@ -185,9 +185,8 @@ public class OrderPredicate implements IPredicate { private boolean acceptFiltersDates(Order order) { // Check if exist work report items into interval between the start date // and finish date. - if ((isInTheRangeFilterDates(order.getInitDate()) || isInTheRangeFilterDates(order.getDeadline())) - || ((isInTheRangeWorkReportDates(startDate, order)) || (isInTheRangeWorkReportDates( - finishDate, order)))) { + if (isInTheRangeFilterDates(order.getInitDate()) + && isInTheRangeFilterDates(order.getDeadline())) { return true; } return false; diff --git a/navalplanner-webapp/src/main/webapp/orders/_orderElementTreeFilter.zul b/navalplanner-webapp/src/main/webapp/orders/_orderElementTreeFilter.zul index 4017c9313..63af646a2 100644 --- a/navalplanner-webapp/src/main/webapp/orders/_orderElementTreeFilter.zul +++ b/navalplanner-webapp/src/main/webapp/orders/_orderElementTreeFilter.zul @@ -1,7 +1,8 @@ - +