diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/FilterPair.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/FilterPair.java
index 2c24259c9..be3ca8746 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/FilterPair.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/FilterPair.java
@@ -25,7 +25,7 @@ package org.navalplanner.web.common.components.finders;
*/
public class FilterPair extends Object {
- private OrderFilterEnum type;
+ private IFilterEnum type;
private String pattern;
@@ -34,13 +34,13 @@ public class FilterPair extends Object {
public FilterPair() {
}
- public FilterPair(OrderFilterEnum type, String pattern, Object value) {
+ public FilterPair(IFilterEnum type, String pattern, Object value) {
this.type = type;
this.value = value;
this.pattern = pattern;
}
- public OrderFilterEnum getType() {
+ public IFilterEnum getType() {
return type;
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/IFilterEnum.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/IFilterEnum.java
new file mode 100644
index 000000000..6dac4617c
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/IFilterEnum.java
@@ -0,0 +1,5 @@
+package org.navalplanner.web.common.components.finders;
+
+public interface IFilterEnum {
+ public String toString();
+}
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 c7a627edb..d84449c33 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
@@ -449,9 +449,9 @@ public class MultipleFiltersFinder implements IMultipleFiltersFinder {
}
filterValues = updateDeletedFilters(filterValues, value);
-
+ value = value.replace(" ", "");
String[] values = value.split(",");
- if (values.length != filterValues.size() + 1) {
+ if (values.length != filterValues.size()) {
return false;
}
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 d75590d55..cd7006da2 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
@@ -23,7 +23,7 @@
*/
package org.navalplanner.web.common.components.finders;
-public enum OrderFilterEnum {
+public enum OrderFilterEnum implements IFilterEnum {
None("..."), Criterion("Criterion"), Label("Label"), ExternalCompany(
"Customer"), State(
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourceFilterEnum.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourceFilterEnum.java
new file mode 100644
index 000000000..6a76838f1
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourceFilterEnum.java
@@ -0,0 +1,41 @@
+/*
+ * This file is part of ###PROJECT_NAME###
+ *
+ * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
+ * Desenvolvemento Tecnolóxico de Galicia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @author Susana Montes Pedreira
+ */
+package org.navalplanner.web.common.components.finders;
+
+public enum ResourceFilterEnum implements IFilterEnum {
+
+ None("..."), Criterion("Criterion"), CostCategory("Cost category");
+
+ private String description;
+
+ private ResourceFilterEnum(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public String toString() {
+ return description;
+ }
+
+}
\ No newline at end of file
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourcesMultipleFiltersFinder.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourcesMultipleFiltersFinder.java
new file mode 100644
index 000000000..6a5ea09d0
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourcesMultipleFiltersFinder.java
@@ -0,0 +1,333 @@
+/*
+ * This file is part of ###PROJECT_NAME###
+ *
+ * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
+ * Desenvolvemento Tecnolóxico de Galicia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.navalplanner.web.common.components.finders;
+
+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;
+
+import org.navalplanner.business.common.IAdHocTransactionService;
+import org.navalplanner.business.common.IOnTransaction;
+import org.navalplanner.business.costcategories.daos.ICostCategoryDAO;
+import org.navalplanner.business.costcategories.entities.CostCategory;
+import org.navalplanner.business.resources.daos.ICriterionDAO;
+import org.navalplanner.business.resources.daos.ICriterionTypeDAO;
+import org.navalplanner.business.resources.daos.IResourceDAO;
+import org.navalplanner.business.resources.entities.Criterion;
+import org.navalplanner.business.resources.entities.CriterionType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.zkoss.zul.Listcell;
+import org.zkoss.zul.Listitem;
+import org.zkoss.zul.ListitemRenderer;
+
+/**
+ * Implements all the methods needed to search the criterion to filter the
+ * resources. Provides multiples criterions to filter like {@link Criterion},
+ * {@link Category} or filter by name or nif.
+ * @author Susana Montes Pedreira
+ */
+
+public class ResourcesMultipleFiltersFinder implements IMultipleFiltersFinder {
+
+ @Autowired
+ private ICriterionTypeDAO criterionTypeDAO;
+
+ @Autowired
+ private ICriterionDAO criterionDAO;
+
+ @Autowired
+ private ICostCategoryDAO costCategoryDAO;
+
+ @Autowired
+ private IResourceDAO resourceDAO;
+
+ @Autowired
+ private IAdHocTransactionService adHocTransactionService;
+
+ private static final Map> mapCriterions = new HashMap>();
+
+ private static final List costCategories = new ArrayList();
+
+ private List listMatching = new ArrayList();
+
+ private final String headers[] = { _("Filter type"), _("Filter pattern") };
+
+ protected ResourcesMultipleFiltersFinder() {
+
+ }
+
+ @Transactional(readOnly = true)
+ public void init() {
+ adHocTransactionService
+ .runOnReadOnlyTransaction(new IOnTransaction() {
+ @Override
+ public Void execute() {
+ loadCriterions();
+ loadCostCategories();
+ return null;
+ }
+ });
+ }
+
+ private void loadCriterions() {
+ mapCriterions.clear();
+ List criterionTypes = criterionTypeDAO
+ .getCriterionTypes();
+ for (CriterionType criterionType : criterionTypes) {
+ List criterions = new ArrayList(criterionDAO
+ .findByType(criterionType));
+
+ mapCriterions.put(criterionType, criterions);
+ }
+ }
+
+ private void loadCostCategories() {
+ costCategories.clear();
+ costCategories.addAll(costCategoryDAO.findActive());
+ }
+
+ public List getFirstTenFilters() {
+ listMatching.clear();
+ fillWithFirstTenFiltersCriterions();
+ fillWithFirstTenFiltersCostCategories();
+ listMatching.add(new FilterPair(OrderFilterEnum.None,
+ OrderFilterEnum.None.toString(), null));
+ 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);
+ addCriterion(type, criterion);
+ }
+ }
+ return listMatching;
+ }
+
+ private List fillWithFirstTenFiltersCostCategories() {
+ for (int i = 0; listMatching.size() < 10
+ && i < costCategories.size(); i++) {
+ CostCategory costCategory = costCategories.get(i);
+ addCostCategory(costCategory);
+ }
+ return listMatching;
+ }
+
+ public List getMatching(String filter) {
+ listMatching.clear();
+ if ((filter != null) && (!filter.isEmpty())) {
+ filter = filter.toLowerCase();
+ searchInCriterionTypes(filter);
+ searchInCostCategories(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, limited);
+ } else {
+ searchInCriterions(type, filter);
+ }
+ }
+ }
+
+ private void searchInCriterions(CriterionType type, String filter) {
+ for (Criterion criterion : mapCriterions.get(type)) {
+ if (criterion.getName().toLowerCase().contains(filter)) {
+ addCriterion(type, criterion);
+ if ((filter.length() < 3) && (listMatching.size() > 9)) {
+ return;
+ }
+ }
+ }
+ }
+
+ private void setFilterPairCriterionType(CriterionType type, boolean limited) {
+ for (Criterion criterion : mapCriterions.get(type)) {
+ addCriterion(type, criterion);
+ if ((limited) && (listMatching.size() > 9)) {
+ return;
+ }
+ }
+ }
+
+ private void searchInCostCategories(String filter) {
+ for (CostCategory costCategory : costCategories) {
+ if (costCategory.getName().toLowerCase().contains(filter)) {
+ addCostCategory(costCategory);
+ if ((filter.length() < 3) && (listMatching.size() > 9)) {
+ return;
+ }
+ }
+ }
+ }
+
+ private void addCriterion(CriterionType type, Criterion criterion) {
+ String pattern = type.getName() + " :: " + criterion.getName();
+ listMatching.add(new FilterPair(ResourceFilterEnum.Criterion, pattern,
+ criterion));
+ }
+
+ private void addCostCategory(CostCategory costCategory) {
+ String pattern = costCategory.getName();
+ listMatching.add(new FilterPair(ResourceFilterEnum.CostCategory,
+ pattern, costCategory));
+ }
+
+ private void addNoneFilter() {
+ listMatching.add(new FilterPair(ResourceFilterEnum.None,
+ ResourceFilterEnum.None.toString(), null));
+ }
+
+ public String objectToString(Object obj) {
+ FilterPair filterPair = (FilterPair) obj;
+ String text = filterPair.getType() + "(" + filterPair.getPattern()
+ + "), ";
+ 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);
+ value = value.replace(" ", "");
+ String[] values = value.split(",");
+ if (values.length != filterValues.size()) {
+ return false;
+ }
+
+ int i = 0;
+ for (FilterPair filterPair : (List) filterValues) {
+ String filterPairText = filterPair.getType() + "("
+ + filterPair.getPattern() + ")";
+ if (!isFilterAdded(values, filterPairText)) {
+ return false;
+ }
+ i++;
+ }
+ 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;
+ }
+
+ public ListitemRenderer getItemRenderer() {
+ return filterPairRenderer;
+ }
+
+ /**
+ * Render for {@link FilterPair}
+ * @author Susana Montes Pedreira
+ */
+ private final ListitemRenderer filterPairRenderer = new ListitemRenderer() {
+
+ @Override
+ public void render(Listitem item, Object data) throws Exception {
+ FilterPair filterPair = (FilterPair) data;
+ item.setValue(data);
+
+ final Listcell labelType = new Listcell();
+ labelType.setLabel(filterPair.getType().toString());
+ labelType.setParent(item);
+
+ final Listcell labelPattern = new Listcell();
+ labelPattern.setLabel(filterPair.getPattern());
+ labelPattern.setParent(item);
+
+ }
+ };
+
+}
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 ead663b3b..92332de70 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
@@ -33,6 +33,7 @@ import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.workreports.entities.WorkReport;
import org.navalplanner.business.workreports.entities.WorkReportType;
import org.navalplanner.web.common.components.finders.FilterPair;
+import org.navalplanner.web.common.components.finders.OrderFilterEnum;
/**
* Checks if {@link WorkReportType}, the start date and finish date from
@@ -87,7 +88,7 @@ public class OrderPredicate implements IPredicate {
}
private boolean acceptFilter(FilterPair filter,Order order){
- switch (filter.getType()) {
+ switch ((OrderFilterEnum) filter.getType()) {
case Criterion:
return acceptCriterion(filter, order);
case Label:
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/IMachineModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/IMachineModel.java
index f51d3e3e7..1ccf8e5c7 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/IMachineModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/IMachineModel.java
@@ -30,6 +30,7 @@ import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.Machine;
import org.navalplanner.business.resources.entities.MachineWorkersConfigurationUnit;
import org.navalplanner.business.resources.entities.Worker;
+import org.navalplanner.web.resources.search.ResourcePredicate;
/*
* This interface contains the operations to create/edit a machine.
@@ -95,4 +96,7 @@ public interface IMachineModel {
BaseCalendar getDefaultCalendar();
+ List getFilteredMachines(ResourcePredicate predicate);
+
+ public List getAllMachines();
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/MachineCRUDController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/MachineCRUDController.java
index f6b7015d7..ca7b37bed 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/MachineCRUDController.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/MachineCRUDController.java
@@ -28,6 +28,7 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.validator.InvalidValue;
+import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.BaseCalendar;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.common.exceptions.ValidationException;
@@ -40,8 +41,11 @@ import org.navalplanner.web.common.Level;
import org.navalplanner.web.common.MessagesForUser;
import org.navalplanner.web.common.OnlyOneVisible;
import org.navalplanner.web.common.Util;
+import org.navalplanner.web.common.components.bandboxsearch.BandboxMultipleSearch;
+import org.navalplanner.web.common.components.finders.FilterPair;
import org.navalplanner.web.common.entrypoints.IURLHandlerRegistry;
import org.navalplanner.web.costcategories.ResourcesCostCategoryAssignmentController;
+import org.navalplanner.web.resources.search.ResourcePredicate;
import org.navalplanner.web.resources.worker.CriterionsController;
import org.navalplanner.web.resources.worker.CriterionsMachineController;
import org.zkoss.zk.ui.Component;
@@ -50,7 +54,12 @@ import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ComboitemRenderer;
+import org.zkoss.zul.Constraint;
+import org.zkoss.zul.Datebox;
+import org.zkoss.zul.Grid;
+import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.Tab;
+import org.zkoss.zul.Textbox;
import org.zkoss.zul.api.Window;
/**
@@ -82,6 +91,16 @@ public class MachineCRUDController extends GenericForwardComposer {
private ResourcesCostCategoryAssignmentController resourcesCostCategoryAssignmentController;
+ private Grid listing;
+
+ private Datebox filterStartDate;
+
+ private Datebox filterFinishDate;
+
+ private Textbox txtfilter;
+
+ private BandboxMultipleSearch bdFilters;
+
private static final Log LOG = LogFactory
.getLog(MachineCRUDController.class);
@@ -108,12 +127,25 @@ public class MachineCRUDController extends GenericForwardComposer {
setupConfigurationController();
setupResourcesCostCategoryAssignmentController(comp);
showListWindow();
+ initFilterComponent();
}
private void showListWindow() {
getVisibility().showOnly(listWindow);
}
+ private void initFilterComponent() {
+ this.filterFinishDate = (Datebox) listWindow
+ .getFellowIfAny("filterFinishDate");
+ this.filterStartDate = (Datebox) listWindow
+ .getFellowIfAny("filterStartDate");
+ this.bdFilters = (BandboxMultipleSearch) listWindow
+ .getFellowIfAny("bdFilters");
+ this.txtfilter = (Textbox) listWindow.getFellowIfAny("txtfilter");
+ this.listing = (Grid) listWindow.getFellowIfAny("listing");
+ clearFilterDates();
+ }
+
private OnlyOneVisible getVisibility() {
if (visibility == null) {
visibility = new OnlyOneVisible(listWindow, editWindow);
@@ -416,4 +448,94 @@ public class MachineCRUDController extends GenericForwardComposer {
}
+ /**
+ * Operations to filter the machines by multiple filters
+ */
+
+ public Constraint checkConstraintFinishDate() {
+ return new Constraint() {
+ @Override
+ public void validate(Component comp, Object value)
+ throws WrongValueException {
+ Date finishDate = (Date) value;
+ if ((finishDate != null)
+ && (filterStartDate.getValue() != null)
+ && (finishDate.compareTo(filterStartDate.getValue()) < 0)) {
+ filterFinishDate.setValue(null);
+ throw new WrongValueException(comp,
+ _("must be greater than start date"));
+ }
+ }
+ };
+ }
+
+ public Constraint checkConstraintStartDate() {
+ return new Constraint() {
+ @Override
+ public void validate(Component comp, Object value)
+ throws WrongValueException {
+ Date startDate = (Date) value;
+ if ((startDate != null)
+ && (filterFinishDate.getValue() != null)
+ && (startDate.compareTo(filterFinishDate.getValue()) > 0)) {
+ filterStartDate.setValue(null);
+ throw new WrongValueException(comp,
+ _("must be lower than finish date"));
+ }
+ }
+ };
+ }
+
+ public void onApplyFilter() {
+ ResourcePredicate predicate = createPredicate();
+ if (predicate != null) {
+ filterByPredicate(predicate);
+ } else {
+ showAllMachines();
+ }
+ }
+
+ private ResourcePredicate createPredicate() {
+ List listFilters = (List) bdFilters
+ .getSelectedElements();
+
+ String personalFilter = txtfilter.getValue();
+ // Get the dates filter
+ LocalDate startDate = null;
+ LocalDate finishDate = null;
+ if (filterStartDate.getValue() != null) {
+ startDate = LocalDate.fromDateFields(filterStartDate
+ .getValue());
+ }
+ if (filterFinishDate.getValue() != null) {
+ finishDate = LocalDate.fromDateFields(filterFinishDate
+ .getValue());
+ }
+
+ if (listFilters.isEmpty()
+ && (personalFilter == null || personalFilter.isEmpty())
+ && startDate == null && finishDate == null) {
+ return null;
+ }
+ return new ResourcePredicate(listFilters, personalFilter, startDate,
+ finishDate);
+ }
+
+ private void filterByPredicate(ResourcePredicate predicate) {
+ List filteredResources = machineModel
+ .getFilteredMachines(predicate);
+ listing.setModel(new SimpleListModel(filteredResources.toArray()));
+ listing.invalidate();
+ }
+
+ private void clearFilterDates() {
+ filterStartDate.setValue(null);
+ filterFinishDate.setValue(null);
+ }
+
+ public void showAllMachines() {
+ listing.setModel(new SimpleListModel(machineModel.getAllMachines()
+ .toArray()));
+ listing.invalidate();
+ }
}
\ No newline at end of file
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/MachineModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/MachineModel.java
index b30642cc4..0796c8821 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/MachineModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/machine/MachineModel.java
@@ -51,6 +51,7 @@ import org.navalplanner.business.resources.entities.MachineWorkersConfigurationU
import org.navalplanner.business.resources.entities.ResourceEnum;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.web.calendars.IBaseCalendarModel;
+import org.navalplanner.web.resources.search.ResourcePredicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -80,6 +81,7 @@ public class MachineModel implements IMachineModel {
private Machine machine;
private Map criterions = new HashMap();
private Map workers = new HashMap();
+ private List machineList = new ArrayList();
@Autowired
private IResourceDAO resourceDAO;
@@ -255,7 +257,8 @@ public class MachineModel implements IMachineModel {
@Override
@Transactional(readOnly = true)
public List getMachines() {
- return machineDAO.getAll();
+ machineList = machineDAO.getAll();
+ return machineList;
}
public MachineWorkersConfigurationUnit getConfigurationUnitById(Long id)
@@ -316,4 +319,20 @@ public class MachineModel implements IMachineModel {
baseCalendar.getExceptions().size();
}
+ @Override
+ @Transactional(readOnly = true)
+ public List getFilteredMachines(ResourcePredicate predicate) {
+ List filteredResourceList = new ArrayList();
+ for (Machine machine : machineList) {
+ machineDAO.reattach(machine);
+ if (predicate.accepts(machine)) {
+ filteredResourceList.add(machine);
+ }
+ }
+ return filteredResourceList;
+ }
+
+ public List getAllMachines() {
+ return machineList;
+ }
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/search/ResourcePredicate.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/search/ResourcePredicate.java
new file mode 100644
index 000000000..6746efcaa
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/search/ResourcePredicate.java
@@ -0,0 +1,239 @@
+/*
+ * This file is part of ###PROJECT_NAME###
+ *
+ * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
+ * Desenvolvemento Tecnolóxico de Galicia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.navalplanner.web.resources.search;
+
+import java.util.List;
+
+import org.joda.time.DateTime;
+import org.joda.time.Interval;
+import org.joda.time.LocalDate;
+import org.navalplanner.business.calendars.entities.CalendarAvailability;
+import org.navalplanner.business.costcategories.entities.CostCategory;
+import org.navalplanner.business.costcategories.entities.ResourcesCostCategoryAssignment;
+import org.navalplanner.business.resources.entities.Criterion;
+import org.navalplanner.business.resources.entities.CriterionSatisfaction;
+import org.navalplanner.business.resources.entities.Machine;
+import org.navalplanner.business.resources.entities.Resource;
+import org.navalplanner.business.resources.entities.Worker;
+import org.navalplanner.web.common.components.finders.FilterPair;
+import org.navalplanner.web.common.components.finders.ResourceFilterEnum;
+import org.navalplanner.web.orders.IPredicate;
+
+/**
+ * Checks if {@link Resource} matches with this predicate.
+ * @author Susana Montes Pedreira
+ */
+
+public class ResourcePredicate implements IPredicate {
+
+ private List filters;
+
+ private LocalDate startDate;
+
+ private LocalDate finishDate;
+
+ private String[] personalFilters;
+
+ private List assignedResourcesInIntervalDates;
+
+ public ResourcePredicate(List filters, String personalFilters,
+ LocalDate startDate,
+ LocalDate finishDate) {
+ this.filters = filters;
+ this.startDate = startDate;
+ this.finishDate = finishDate;
+ this.personalFilters = personalFilters.split(" ");
+ }
+
+ @Override
+ public boolean accepts(Object object) {
+ final Resource resource = (Resource) object;
+ return accepts(resource);
+ }
+
+ private boolean accepts(Resource resource) {
+ if (resource == null) {
+ return false;
+ }
+ if (acceptFilters(resource) && acceptPersonalFilters(resource)
+ && acceptFiltersDates(resource)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean acceptFilters(Resource resource) {
+ if ((filters == null) || (filters.isEmpty())) {
+ return true;
+ }
+ for (FilterPair filter : filters) {
+ if (!acceptFilter(filter, resource)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean acceptFilter(FilterPair filter, Resource resource) {
+ switch ((ResourceFilterEnum) filter.getType()) {
+ case Criterion:
+ return acceptCriterion(filter, resource);
+ case CostCategory:
+ return acceptCostCategory(filter, resource);
+ }
+ return false;
+ }
+
+ private boolean acceptCriterion(FilterPair filter, Resource resource) {
+ Criterion filterCriterion = (Criterion) filter.getValue();
+ for (CriterionSatisfaction criterionSatisfaction : resource
+ .getCriterionSatisfactions()) {
+ if (criterionSatisfaction.getCriterion().getId().equals(
+ filterCriterion.getId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean acceptCostCategory(FilterPair filter, Resource resource) {
+ CostCategory filterCostCategory = (CostCategory) filter.getValue();
+ for (ResourcesCostCategoryAssignment assignedCostCategory : resource
+ .getResourcesCostCategoryAssignments()) {
+ if (assignedCostCategory.getCostCategory().getId().equals(
+ filterCostCategory.getId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean acceptPersonalFilters(Resource resource) {
+ for (String filter : personalFilters) {
+ filter = filter.replace(" ", "");
+ filter = filter.toLowerCase();
+ if (filter.isEmpty()) {
+ continue;
+ }
+
+ if ((!acceptName(filter, resource))
+ && (!acceptApel(filter, resource))
+ && (!acceptNif(filter, resource))
+ && (!acceptCode(filter, resource))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean acceptName(String filterName, Resource resource) {
+ if (resource instanceof Worker) {
+ return ((Worker) resource).getFirstName().toLowerCase().contains(
+ filterName);
+ }
+ return resource.getName().toLowerCase().contains(filterName);
+ }
+
+ private boolean acceptApel(String filterApel, Resource resource) {
+ if (resource instanceof Worker) {
+ return ((Worker) resource).getSurname().toLowerCase().contains(
+ filterApel);
+ }
+ return false;
+ }
+
+ private boolean acceptCode(String filterCode, Resource resource) {
+ if (resource instanceof Machine) {
+ return ((Machine) resource).getCode().toLowerCase().contains(
+ filterCode);
+ }
+ return false;
+ }
+
+ private boolean acceptNif(String filterNif, Resource resource) {
+ if (resource instanceof Worker) {
+ return ((Worker) resource).getNif().toLowerCase().contains(
+ filterNif);
+ }
+ return false;
+ }
+
+ private boolean acceptFiltersDates(Resource resource) {
+ // Check if exist some day of the active period into interval between
+ // the start date and finish date.
+ if (startDate == null && finishDate == null) {
+ return true;
+ }
+ if ((resource.getCalendar() != null)) {
+ for (CalendarAvailability calendar : resource.getCalendar()
+ .getCalendarAvailabilities()) {
+ if (isOverlap(calendar)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isOverlap(CalendarAvailability calendar) {
+ if (calendar.getEndDate() == null) {
+ if (finishDate != null) {
+ return (finishDate.compareTo(calendar.getStartDate()) >= 0);
+ } else {
+ return true;
+ }
+ } else {
+ if (finishDate == null) {
+ return (startDate.compareTo(calendar.getEndDate()) <= 0);
+ }
+ if (startDate == null) {
+ return (finishDate.compareTo(calendar.getStartDate()) >= 0);
+ }
+ }
+ Interval filter = getIntervalFilter();
+ Interval activePeriod = getIntervalActivePeriod(calendar);
+ return filter.overlaps(activePeriod);
+ }
+
+ private Interval getIntervalFilter() {
+ DateTime startDateTime = null;
+ if (startDate != null) {
+ startDateTime = startDate.toDateTimeAtStartOfDay();
+ }
+
+ DateTime endDateTime = null;
+ if (finishDate != null) {
+ endDateTime = (finishDate.plusDays(1)).toDateTimeAtStartOfDay();
+ }
+ return new Interval(startDateTime, endDateTime);
+ }
+
+ private Interval getIntervalActivePeriod(CalendarAvailability calendar) {
+ DateTime endDateTime = null;
+ if (calendar.getEndDate() != null) {
+ endDateTime = (calendar.getEndDate().plusDays(1))
+ .toDateTimeAtStartOfDay();
+ }
+ return new Interval(calendar.getStartDate().toDateTimeAtStartOfDay(),
+ endDateTime);
+ }
+
+}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/IWorkerModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/IWorkerModel.java
index c2ccd52a0..8f2a69692 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/IWorkerModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/IWorkerModel.java
@@ -34,6 +34,7 @@ import org.navalplanner.business.resources.entities.ICriterion;
import org.navalplanner.business.resources.entities.ICriterionType;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
+import org.navalplanner.web.resources.search.ResourcePredicate;
/**
* This interface contains the operations to create/edit a worker. The
@@ -137,4 +138,8 @@ public interface IWorkerModel {
void setCapacity(Integer capacity);
+ public List getFilteredWorker(ResourcePredicate predicate);
+
+ public List getAllCurrentWorkers();
+
}
\ No newline at end of file
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java
index 11a0d69d2..8829033cb 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java
@@ -26,6 +26,7 @@ import static org.navalplanner.web.common.ConcurrentModificationDetector.addAuto
import java.util.Date;
import java.util.List;
+import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.BaseCalendar;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.common.exceptions.ValidationException;
@@ -39,16 +40,24 @@ import org.navalplanner.web.common.Level;
import org.navalplanner.web.common.MessagesForUser;
import org.navalplanner.web.common.OnlyOneVisible;
import org.navalplanner.web.common.Util;
+import org.navalplanner.web.common.components.bandboxsearch.BandboxMultipleSearch;
+import org.navalplanner.web.common.components.finders.FilterPair;
import org.navalplanner.web.common.entrypoints.IURLHandlerRegistry;
import org.navalplanner.web.common.entrypoints.URLHandler;
import org.navalplanner.web.costcategories.ResourcesCostCategoryAssignmentController;
+import org.navalplanner.web.resources.search.ResourcePredicate;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ComboitemRenderer;
+import org.zkoss.zul.Constraint;
+import org.zkoss.zul.Datebox;
+import org.zkoss.zul.Grid;
+import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.Tab;
+import org.zkoss.zul.Textbox;
import org.zkoss.zul.api.Window;
/**
@@ -93,6 +102,16 @@ public class WorkerCRUDController extends GenericForwardComposer implements
private BaseCalendarsComboitemRenderer baseCalendarsComboitemRenderer = new BaseCalendarsComboitemRenderer();
+ private Grid listing;
+
+ private Datebox filterStartDate;
+
+ private Datebox filterFinishDate;
+
+ private BandboxMultipleSearch bdFilters;
+
+ private Textbox txtfilter;
+
public WorkerCRUDController() {
}
@@ -255,6 +274,19 @@ public class WorkerCRUDController extends GenericForwardComposer implements
.getRedirectorFor(IWorkerCRUDControllerEntryPoints.class);
handler.registerListener(this, page);
getVisibility().showOnly(listWindow);
+ initFilterComponent();
+ }
+
+ private void initFilterComponent() {
+ this.filterFinishDate = (Datebox) listWindow
+ .getFellowIfAny("filterFinishDate");
+ this.filterStartDate = (Datebox) listWindow
+ .getFellowIfAny("filterStartDate");
+ this.bdFilters = (BandboxMultipleSearch) listWindow
+ .getFellowIfAny("bdFilters");
+ this.txtfilter = (Textbox) listWindow.getFellowIfAny("txtfilter");
+ this.listing = (Grid) listWindow.getFellowIfAny("listing");
+ clearFilterDates();
}
private void setupResourcesCostCategoryAssignmentController(Component comp)
@@ -495,4 +527,93 @@ public class WorkerCRUDController extends GenericForwardComposer implements
this.workerModel.setCapacity(capacity);
}
+ /**
+ * Operations to filter the machines by multiple filters
+ */
+
+ public Constraint checkConstraintFinishDate() {
+ return new Constraint() {
+ @Override
+ public void validate(Component comp, Object value)
+ throws WrongValueException {
+ Date finishDate = (Date) value;
+ if ((finishDate != null)
+ && (filterStartDate.getValue() != null)
+ && (finishDate.compareTo(filterStartDate.getValue()) < 0)) {
+ filterFinishDate.setValue(null);
+ throw new WrongValueException(comp,
+ _("must be greater than start date"));
+ }
+ }
+ };
+ }
+
+ public Constraint checkConstraintStartDate() {
+ return new Constraint() {
+ @Override
+ public void validate(Component comp, Object value)
+ throws WrongValueException {
+ Date startDate = (Date) value;
+ if ((startDate != null)
+ && (filterFinishDate.getValue() != null)
+ && (startDate.compareTo(filterFinishDate.getValue()) > 0)) {
+ filterStartDate.setValue(null);
+ throw new WrongValueException(comp,
+ _("must be lower than finish date"));
+ }
+ }
+ };
+ }
+
+ public void onApplyFilter() {
+ ResourcePredicate predicate = createPredicate();
+ if (predicate != null) {
+ filterByPredicate(predicate);
+ } else {
+ showAllWorkers();
+ }
+ }
+
+ private ResourcePredicate createPredicate() {
+ List listFilters = (List) bdFilters
+ .getSelectedElements();
+
+ String personalFilter = txtfilter.getValue();
+
+ // Get the dates filter
+ LocalDate startDate = null;
+ LocalDate finishDate = null;
+ if (filterStartDate.getValue() != null) {
+ startDate = LocalDate.fromDateFields(filterStartDate.getValue());
+ }
+ if (filterFinishDate.getValue() != null) {
+ finishDate = LocalDate.fromDateFields(filterFinishDate.getValue());
+ }
+
+ if (listFilters.isEmpty()
+ && (personalFilter == null || personalFilter.isEmpty())
+ && startDate == null && finishDate == null) {
+ return null;
+ }
+ return new ResourcePredicate(listFilters, personalFilter, startDate,
+ finishDate);
+ }
+
+ private void filterByPredicate(ResourcePredicate predicate) {
+ List filteredResources = workerModel
+ .getFilteredWorker(predicate);
+ listing.setModel(new SimpleListModel(filteredResources.toArray()));
+ listing.invalidate();
+ }
+
+ private void clearFilterDates() {
+ filterStartDate.setValue(null);
+ filterFinishDate.setValue(null);
+ }
+
+ public void showAllWorkers() {
+ listing.setModel(new SimpleListModel(workerModel.getAllCurrentWorkers()
+ .toArray()));
+ listing.invalidate();
+ }
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerModel.java
index 631edbdbe..4ac5b3427 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerModel.java
@@ -54,6 +54,7 @@ import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.VirtualWorker;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.web.calendars.IBaseCalendarModel;
+import org.navalplanner.web.resources.search.ResourcePredicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -95,6 +96,8 @@ public class WorkerModel implements IWorkerModel {
@Autowired
private IConfigurationDAO configurationDAO;
+ private List currentWorkerList = new ArrayList();
+
@Autowired
public WorkerModel(IResourceDAO resourceDAO,
ICriterionDAO criterionDAO) {
@@ -128,7 +131,8 @@ public class WorkerModel implements IWorkerModel {
@Override
@Transactional(readOnly = true)
public List getRealWorkers() {
- return resourceDAO.getRealWorkers();
+ currentWorkerList = resourceDAO.getRealWorkers();
+ return currentWorkerList;
}
@Override
@@ -138,7 +142,8 @@ public class WorkerModel implements IWorkerModel {
for (Worker each : list) {
each.getCalendar().getCapacity();
}
- return list;
+ currentWorkerList = list;
+ return currentWorkerList;
}
@Override
@@ -541,4 +546,20 @@ public class WorkerModel implements IWorkerModel {
return defaultCalendar;
}
+ @Override
+ @Transactional(readOnly = true)
+ public List getFilteredWorker(ResourcePredicate predicate) {
+ List filteredResourceList = new ArrayList();
+ for (Worker worker : currentWorkerList) {
+ resourceDAO.reattach(worker);
+ if (predicate.accepts(worker)) {
+ filteredResourceList.add(worker);
+ }
+ }
+ return filteredResourceList;
+ }
+
+ public List getAllCurrentWorkers() {
+ return currentWorkerList;
+ }
}
diff --git a/navalplanner-webapp/src/main/resources/navalplanner-webapp-spring-config.xml b/navalplanner-webapp/src/main/resources/navalplanner-webapp-spring-config.xml
index 8abc41e1e..55e42901c 100644
--- a/navalplanner-webapp/src/main/resources/navalplanner-webapp-spring-config.xml
+++ b/navalplanner-webapp/src/main/resources/navalplanner-webapp-spring-config.xml
@@ -42,6 +42,9 @@
+
+
diff --git a/navalplanner-webapp/src/main/webapp/resources/machine/_listMachines.zul b/navalplanner-webapp/src/main/webapp/resources/machine/_listMachines.zul
index 5a07bb078..173724b4a 100644
--- a/navalplanner-webapp/src/main/webapp/resources/machine/_listMachines.zul
+++ b/navalplanner-webapp/src/main/webapp/resources/machine/_listMachines.zul
@@ -17,8 +17,16 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
-->
-
+
+
+
+
+
+
+
+
+
diff --git a/navalplanner-webapp/src/main/webapp/resources/search/_resourceFilter.zul b/navalplanner-webapp/src/main/webapp/resources/search/_resourceFilter.zul
new file mode 100644
index 000000000..3b5f3e728
--- /dev/null
+++ b/navalplanner-webapp/src/main/webapp/resources/search/_resourceFilter.zul
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/navalplanner-webapp/src/main/webapp/resources/worker/_list.zul b/navalplanner-webapp/src/main/webapp/resources/worker/_list.zul
index d74e6cf1e..daad66efd 100644
--- a/navalplanner-webapp/src/main/webapp/resources/worker/_list.zul
+++ b/navalplanner-webapp/src/main/webapp/resources/worker/_list.zul
@@ -17,8 +17,15 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
-->
-
+
+
+
+
+
+
+
+
diff --git a/navalplanner-webapp/src/main/webapp/resources/worker/_listVirtualWorkers.zul b/navalplanner-webapp/src/main/webapp/resources/worker/_listVirtualWorkers.zul
index 7f0d0686b..922633055 100644
--- a/navalplanner-webapp/src/main/webapp/resources/worker/_listVirtualWorkers.zul
+++ b/navalplanner-webapp/src/main/webapp/resources/worker/_listVirtualWorkers.zul
@@ -17,8 +17,15 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
-->
-
+
+
+
+