ItEr46S17CUListadoRecursosTraballadoresItEr08S08: Create a resource predicate and multiple criterions to filter the machine list, worker list

This commit is contained in:
Susana Montes Pedreira 2010-02-04 09:59:28 +01:00 committed by Javier Moran Rua
parent 5bc7372a9e
commit 7a6e402054
19 changed files with 964 additions and 13 deletions

View file

@ -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;
}

View file

@ -0,0 +1,5 @@
package org.navalplanner.web.common.components.finders;
public interface IFilterEnum {
public String toString();
}

View file

@ -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;
}

View file

@ -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(

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
/**
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
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;
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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 <smontes@wirelessgalicia.com>
*/
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<CriterionType, List<Criterion>> mapCriterions = new HashMap<CriterionType, List<Criterion>>();
private static final List<CostCategory> costCategories = new ArrayList<CostCategory>();
private List<FilterPair> listMatching = new ArrayList<FilterPair>();
private final String headers[] = { _("Filter type"), _("Filter pattern") };
protected ResourcesMultipleFiltersFinder() {
}
@Transactional(readOnly = true)
public void init() {
adHocTransactionService
.runOnReadOnlyTransaction(new IOnTransaction<Void>() {
@Override
public Void execute() {
loadCriterions();
loadCostCategories();
return null;
}
});
}
private void loadCriterions() {
mapCriterions.clear();
List<CriterionType> criterionTypes = criterionTypeDAO
.getCriterionTypes();
for (CriterionType criterionType : criterionTypes) {
List<Criterion> criterions = new ArrayList<Criterion>(criterionDAO
.findByType(criterionType));
mapCriterions.put(criterionType, criterions);
}
}
private void loadCostCategories() {
costCategories.clear();
costCategories.addAll(costCategoryDAO.findActive());
}
public List<FilterPair> getFirstTenFilters() {
listMatching.clear();
fillWithFirstTenFiltersCriterions();
fillWithFirstTenFiltersCostCategories();
listMatching.add(new FilterPair(OrderFilterEnum.None,
OrderFilterEnum.None.toString(), null));
return listMatching;
}
private List<FilterPair> fillWithFirstTenFiltersCriterions() {
Iterator<CriterionType> 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<FilterPair> fillWithFirstTenFiltersCostCategories() {
for (int i = 0; listMatching.size() < 10
&& i < costCategories.size(); i++) {
CostCategory costCategory = costCategories.get(i);
addCostCategory(costCategory);
}
return listMatching;
}
public List<FilterPair> 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<FilterPair>) filterValues) {
String filterPairText = filterPair.getType() + "("
+ filterPair.getPattern() + ")";
if (!isFilterAdded(values, filterPairText)) {
return false;
}
i++;
}
return true;
}
@Override
public List<FilterPair> updateDeletedFilters(List filterValues, String value) {
String[] values = value.split(",");
List<FilterPair> listFilters = (List<FilterPair>) filterValues;
List<FilterPair> list = new ArrayList<FilterPair>();
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 <smontes@wirelessgalicia.com>
*/
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);
}
};
}

View file

@ -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:

View file

@ -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<Machine> getFilteredMachines(ResourcePredicate predicate);
public List<Machine> getAllMachines();
}

View file

@ -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<FilterPair> listFilters = (List<FilterPair>) 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<Machine> 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();
}
}

View file

@ -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<Long,Criterion> criterions = new HashMap<Long,Criterion>();
private Map<Long,Worker> workers = new HashMap<Long,Worker>();
private List<Machine> machineList = new ArrayList<Machine>();
@Autowired
private IResourceDAO resourceDAO;
@ -255,7 +257,8 @@ public class MachineModel implements IMachineModel {
@Override
@Transactional(readOnly = true)
public List<Machine> 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<Machine> getFilteredMachines(ResourcePredicate predicate) {
List<Machine> filteredResourceList = new ArrayList<Machine>();
for (Machine machine : machineList) {
machineDAO.reattach(machine);
if (predicate.accepts(machine)) {
filteredResourceList.add(machine);
}
}
return filteredResourceList;
}
public List<Machine> getAllMachines() {
return machineList;
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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 <smontes@wirelessgalicia.com>
*/
public class ResourcePredicate implements IPredicate {
private List<FilterPair> filters;
private LocalDate startDate;
private LocalDate finishDate;
private String[] personalFilters;
private List<Resource> assignedResourcesInIntervalDates;
public ResourcePredicate(List<FilterPair> 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);
}
}

View file

@ -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<Worker> getFilteredWorker(ResourcePredicate predicate);
public List<Worker> getAllCurrentWorkers();
}

View file

@ -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<FilterPair> listFilters = (List<FilterPair>) 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<Worker> 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();
}
}

View file

@ -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<Worker> currentWorkerList = new ArrayList<Worker>();
@Autowired
public WorkerModel(IResourceDAO resourceDAO,
ICriterionDAO criterionDAO) {
@ -128,7 +131,8 @@ public class WorkerModel implements IWorkerModel {
@Override
@Transactional(readOnly = true)
public List<Worker> 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<Worker> getFilteredWorker(ResourcePredicate predicate) {
List<Worker> filteredResourceList = new ArrayList<Worker>();
for (Worker worker : currentWorkerList) {
resourceDAO.reattach(worker);
if (predicate.accepts(worker)) {
filteredResourceList.add(worker);
}
}
return filteredResourceList;
}
public List<Worker> getAllCurrentWorkers() {
return currentWorkerList;
}
}

View file

@ -42,6 +42,9 @@
<bean id="multipleFiltersFinder" class="org.navalplanner.web.common.components.finders.MultipleFiltersFinder" scope="singleton"
init-method="init" />
<bean id="resourcesMultipleFiltersFinder" class="org.navalplanner.web.common.components.finders.ResourcesMultipleFiltersFinder" scope="singleton"
init-method="init" />
<context:component-scan base-package="org.navalplanner"/>
<!-- CXF -->

View file

@ -17,8 +17,16 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<?component name="filter" inline="true" macroURI="../search/_resourceFilter.zul"?>
<window id="listWindow" title="${i18n:_('Machines list')}">
<separator bar="false" spacing="5px" orient="horizontal"/>
<div align="right">
<filter id="filter"/>
</div>
<separator bar="false" spacing="30px" orient="horizontal"/>
<grid id="listing" model="@{controller.machines}" mold="paging"
pageSize="10" fixedLayout="true">
<columns>

View file

@ -0,0 +1,15 @@
<hbox align="end" sclass="filtering-area">
<label value="${i18n:_('Filter by')}"
tooltiptext="${i18n:_('Select required criteria set and press filter button')}"/>
<bandboxMultipleSearch id="bdFilters" widthBandbox="285px" widthListbox="300px"
finder="resourcesMultipleFiltersFinder"/>
<label value="${i18n:_('Personal details')}"/>
<textbox id="txtfilter" width="200px"/>
<label value="${i18n:_('Active period from')}"/>
<datebox id="filterStartDate" constraint = "@{controller.checkConstraintStartDate}"/>
<label value="${i18n:_('to')}"/>
<datebox id="filterFinishDate" constraint = "@{controller.checkConstraintFinishDate}"/>
<button label="${i18n:_('Filter')}" style="margin-top: -4px"
tooltiptext="${i18n:_('Apply filtering to machines satisfying required criteria')}"
onClick="controller.onApplyFilter()"/>
</hbox>

View file

@ -17,8 +17,15 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<?component name="filter" inline="true" macroURI="../search/_resourceFilter.zul"?>
<window id="${arg.top_id}" title="${i18n:_('Workers list')}">
<separator bar="false" spacing="5px" orient="horizontal"/>
<div align="right">
<filter id="filter"/>
</div>
<separator bar="false" spacing="30px" orient="horizontal"/>
<newdatasortablegrid id="listing" model="@{controller.realWorkers}" mold="paging"
pageSize="10" fixedLayout="true">
<columns>

View file

@ -17,8 +17,15 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<?component name="filter" inline="true" macroURI="../search/_resourceFilter.zul"?>
<window id="${arg.top_id}" title="${i18n:_('Virtual workers list')}">
<separator bar="false" spacing="5px" orient="horizontal"/>
<div align="right">
<filter id="filter"/>
</div>
<separator bar="false" spacing="30px" orient="horizontal"/>
<newdatasortablegrid id="listing" model="@{controller.virtualWorkers}" mold="paging"
pageSize="10" fixedLayout="true">
<columns>