ItEr17S12CUAltaTipoParteDeTraballo: Creating a macro component called TwoWaySelector.
This commit is contained in:
parent
1d7532d759
commit
cdd8560676
4 changed files with 333 additions and 0 deletions
|
|
@ -32,6 +32,15 @@ public class Util {
|
|||
}
|
||||
}
|
||||
|
||||
public static void saveBindings(Component... toReload) {
|
||||
for (Component reload : toReload) {
|
||||
DataBinder binder = Util.getBinder(reload);
|
||||
if (binder != null) {
|
||||
binder.saveComponent(reload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static DataBinder getBinder(Component component) {
|
||||
return (DataBinder) component.getVariable("binder", false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,268 @@
|
|||
package org.navalplanner.web.common.components;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.navalplanner.web.common.Util;
|
||||
import org.zkoss.lang.Objects;
|
||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||
import org.zkoss.zul.Listbox;
|
||||
import org.zkoss.zul.Listcell;
|
||||
import org.zkoss.zul.Listitem;
|
||||
import org.zkoss.zul.ListitemRenderer;
|
||||
|
||||
/**
|
||||
* ZK macro component that shows two {@link Listbox} allowing to move objects
|
||||
* between each other.
|
||||
*
|
||||
* In the {@link Listbox} on the left you will have the assigned objects and in
|
||||
* the right the possible other objects to be assigned.
|
||||
*
|
||||
* Finally it provides methods to get the current assigned and unassigned
|
||||
* objects.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
public class TwoWaySelector extends HtmlMacroComponent {
|
||||
|
||||
/**
|
||||
* A {@link Set} of objects that are assigned (so they're shown on the left
|
||||
* {@link Listbox})
|
||||
*/
|
||||
private Set assignedObjects = new HashSet();
|
||||
|
||||
/**
|
||||
* Title for the left {@link Listbox} (where assigned objects are shown)
|
||||
*/
|
||||
private String assignedTitle = "Assigned";
|
||||
|
||||
/**
|
||||
* A {@link Set} of objects that are not assigned (so they're shown on the
|
||||
* right {@link Listbox})
|
||||
*/
|
||||
private Set unassignedObjects = new HashSet();
|
||||
|
||||
/**
|
||||
* Title for the right {@link Listbox} (where unassigned objects are shown)
|
||||
*/
|
||||
private String unassignedTitle = "Unassigned";
|
||||
|
||||
/**
|
||||
* A {@link List} of properties to be shown on the {@link Listbox} for each
|
||||
* object.
|
||||
*/
|
||||
private List<String> columns = null;
|
||||
|
||||
/**
|
||||
* {@link ListitemRenderer} that knows how to paint an object according to
|
||||
* the {@link List} stored in the columns attribute. If columns is null then
|
||||
* the object will be rendered as a string.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
private ListitemRenderer renderer = new ListitemRenderer() {
|
||||
@Override
|
||||
public void render(Listitem item, Object data) throws Exception {
|
||||
|
||||
Class<? extends Object> klass = data.getClass();
|
||||
Map<String, PropertyDescriptor> propertiesByName = getProperties(klass);
|
||||
|
||||
// If a list of attributes is defined
|
||||
if (columns != null) {
|
||||
// For each attribute
|
||||
for (String column : columns) {
|
||||
// Call the method to get the information
|
||||
PropertyDescriptor propertyDescriptor = propertiesByName
|
||||
.get(column);
|
||||
if (propertyDescriptor == null) {
|
||||
throw new RuntimeException(
|
||||
"Unknown attribute '"
|
||||
+ column + "' in class " + klass.getName());
|
||||
}
|
||||
|
||||
String label = Objects.toString(propertyDescriptor
|
||||
.getReadMethod().invoke(data));
|
||||
|
||||
// Add a new Listcell
|
||||
item.appendChild(new Listcell(label));
|
||||
}
|
||||
} else { // If the list of attributes is not defined
|
||||
// Render the object as string
|
||||
item.setLabel(Objects.toString(data));
|
||||
}
|
||||
|
||||
item.setValue(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link Map} that stores the information about the attributes for a
|
||||
* class.
|
||||
*
|
||||
* The information about attributes is stored with another Map where
|
||||
* keys are the properties name and the values the
|
||||
* {@link PropertyDescriptor}.
|
||||
*/
|
||||
private Map<Class<?>, Map<String, PropertyDescriptor>> propertiesMapsCached = new HashMap<Class<?>, Map<String, PropertyDescriptor>>();
|
||||
|
||||
/**
|
||||
* Creates a {@link Map} that relates the properties and their
|
||||
* {@link PropertyDescriptor} from the {@link BeanInfo}.
|
||||
*
|
||||
* @param info
|
||||
* Information about the bean
|
||||
* @return A {@link Map} that relates properties name and
|
||||
* {@link PropertyDescriptor}
|
||||
*/
|
||||
private Map<String, PropertyDescriptor> buildPropertyDescriptorsMap(
|
||||
BeanInfo info) {
|
||||
PropertyDescriptor[] propertyDescriptors = info
|
||||
.getPropertyDescriptors();
|
||||
Map<String, PropertyDescriptor> propertiesByName = new HashMap<String, PropertyDescriptor>();
|
||||
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
|
||||
propertiesByName.put(propertyDescriptor.getName(),
|
||||
propertyDescriptor);
|
||||
}
|
||||
return propertiesByName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the attributes of a {@link Class} together with the
|
||||
* {@link PropertyDescriptor} of each property.
|
||||
*
|
||||
* @param klass
|
||||
* The {@link Class} to get the properties
|
||||
* @return A {@link Map} that relates properties name and
|
||||
* {@link PropertyDescriptor}
|
||||
* @throws IntrospectionException
|
||||
*/
|
||||
private Map<String, PropertyDescriptor> getProperties(
|
||||
Class<? extends Object> klass) throws IntrospectionException {
|
||||
// If it's already cached
|
||||
if (propertiesMapsCached.containsKey(klass)) {
|
||||
return propertiesMapsCached.get(klass);
|
||||
}
|
||||
|
||||
BeanInfo beanInfo = Introspector.getBeanInfo(klass);
|
||||
Map<String, PropertyDescriptor> result = buildPropertyDescriptorsMap(beanInfo);
|
||||
|
||||
// Store in cache
|
||||
propertiesMapsCached.put(klass, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
public void setAssignedTitle(String assignedTitle) {
|
||||
if (assignedTitle != null) {
|
||||
this.assignedTitle = assignedTitle;
|
||||
}
|
||||
}
|
||||
|
||||
public String getAssignedTitle() {
|
||||
return assignedTitle;
|
||||
}
|
||||
|
||||
public void setUnassignedTitle(String unassignedTitle) {
|
||||
if (unassignedTitle != null) {
|
||||
this.unassignedTitle = unassignedTitle;
|
||||
}
|
||||
}
|
||||
|
||||
public String getUnassignedTitle() {
|
||||
return unassignedTitle;
|
||||
}
|
||||
|
||||
public void setAssignedObjects(Set assignedObjects) {
|
||||
if (assignedObjects != null) {
|
||||
this.assignedObjects = assignedObjects;
|
||||
}
|
||||
}
|
||||
|
||||
public Set getAssignedObjects() {
|
||||
return assignedObjects;
|
||||
}
|
||||
|
||||
public void setUnassignedObjects(Set unassignedObjects) {
|
||||
if (assignedObjects != null) {
|
||||
this.unassignedObjects = unassignedObjects;
|
||||
}
|
||||
}
|
||||
|
||||
public Set getUnassignedObjects() {
|
||||
return unassignedObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of attributes to be shown when an object is renderer.
|
||||
*
|
||||
* @param columns
|
||||
* A comma-separated string
|
||||
*/
|
||||
public void setColumns(String columns) {
|
||||
if (columns != null) {
|
||||
// Remove white spaces
|
||||
columns = columns.replaceAll("\\s", "");
|
||||
|
||||
if (!columns.isEmpty()) {
|
||||
// Split the string
|
||||
this.columns = Arrays.asList(columns.split(","));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public ListitemRenderer getRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign (move to the left {@link Listbox}) the selected items from the
|
||||
* right {@link Listbox}. And reload both {@link Listbox} in order to
|
||||
* relfect the changes.
|
||||
*
|
||||
* @param unassignedObjectsListbox
|
||||
* The right {@link Listbox}
|
||||
*/
|
||||
public void assign(Listbox unassignedObjectsListbox) {
|
||||
Set<Listitem> selectedItems = unassignedObjectsListbox
|
||||
.getSelectedItems();
|
||||
for (Listitem listitem : selectedItems) {
|
||||
Object value = listitem.getValue();
|
||||
unassignedObjects.remove(value);
|
||||
assignedObjects.add(value);
|
||||
}
|
||||
Util.reloadBindings(unassignedObjectsListbox.getParent());
|
||||
Util.saveBindings(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unassign (move to the rigth {@link Listbox}) the selected items from the
|
||||
* left {@link Listbox}. And reload both {@link Listbox} in order to relfect
|
||||
* the changes.
|
||||
*
|
||||
* @param assignedObjectsListbox
|
||||
* The left {@link Listbox}
|
||||
*/
|
||||
public void unassign(Listbox assignedObjectsListbox) {
|
||||
Set<Listitem> selectedItems = assignedObjectsListbox.getSelectedItems();
|
||||
for (Listitem listitem : selectedItems) {
|
||||
Object value = listitem.getValue();
|
||||
assignedObjects.remove(value);
|
||||
unassignedObjects.add(value);
|
||||
}
|
||||
Util.reloadBindings(assignedObjectsListbox.getParent());
|
||||
Util.saveBindings(this);
|
||||
}
|
||||
|
||||
}
|
||||
14
navalplanner-webapp/src/main/resources/metainfo/zk/lang-addon.xml
Executable file
14
navalplanner-webapp/src/main/resources/metainfo/zk/lang-addon.xml
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<language-addon>
|
||||
|
||||
<addon-name>navalplanner-webapp</addon-name>
|
||||
<language-name>xul/html</language-name>
|
||||
|
||||
<component>
|
||||
<component-name>twowayselector</component-name>
|
||||
<component-class>org.navalplanner.web.common.components.TwoWaySelector</component-class>
|
||||
<macro-uri>/common/components/twowayselector.zul</macro-uri>
|
||||
</component>
|
||||
|
||||
</language-addon>
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<zk>
|
||||
|
||||
<zscript>
|
||||
<![CDATA[
|
||||
top = self;
|
||||
]]>
|
||||
</zscript>
|
||||
|
||||
<vbox>
|
||||
|
||||
<hbox>
|
||||
|
||||
<listbox id="assignedObjects"
|
||||
model="@{top.assignedObjects}"
|
||||
itemRenderer="@{top.renderer}"
|
||||
multiple="true" checkmark="true">
|
||||
<listhead>
|
||||
<listheader label="@{top.assignedTitle}" />
|
||||
</listhead>
|
||||
</listbox>
|
||||
|
||||
<vbox>
|
||||
<button id="assignButton" label="<<"
|
||||
onClick="top.assign(unassignedObjects);" />
|
||||
<button id="unassignButton" label=">>"
|
||||
onClick="top.unassign(assignedObjects);" />
|
||||
</vbox>
|
||||
|
||||
<listbox id="unassignedObjects"
|
||||
model="@{top.unassignedObjects}"
|
||||
itemRenderer="@{top.renderer}"
|
||||
multiple="true" checkmark="true">
|
||||
<listhead>
|
||||
<listheader label="@{top.unassignedTitle}" />
|
||||
</listhead>
|
||||
</listbox>
|
||||
|
||||
</hbox>
|
||||
|
||||
</vbox>
|
||||
|
||||
</zk>
|
||||
Loading…
Add table
Reference in a new issue