diff --git a/ganttzk-demo-webapp/pom.xml b/ganttzk-demo-webapp/pom.xml new file mode 100644 index 000000000..2ebd74928 --- /dev/null +++ b/ganttzk-demo-webapp/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + + org.navalplanner + navalplanner + 1.0.0 + + ganttzk-demo-webapp + war + Naval Planner Web Client Module + + + ganttzk-demo-webapp + + + + + + org.springframework + spring + + + + org.beanshell + bsh + + + + commons-fileupload + commons-fileupload + + + + org.zkoss.zk + zul + + + org.zkoss.zk + zkplus + + + org.zkoss.zk + zk + + + org.zkoss.zk + zkex + + + + org.navalplanner + navalplanner-gantt-zk + + + org.easymock + easymock + + + junit + junit + + + org.hibernate + hibernate-validator + + + javax.servlet + servlet-api + + + + diff --git a/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/Level.java b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/Level.java new file mode 100644 index 000000000..6c5f612e0 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/Level.java @@ -0,0 +1,5 @@ +package org.navalplanner.web.common; + +public enum Level { + INFO, WARNING, ERROR; +} \ No newline at end of file diff --git a/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/OnlyOneVisible.java b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/OnlyOneVisible.java new file mode 100644 index 000000000..fdc22db90 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/OnlyOneVisible.java @@ -0,0 +1,29 @@ +package org.navalplanner.web.common; + +import java.util.Arrays; +import java.util.List; + +import org.zkoss.zk.ui.Component; + +/** + * Utility for enforcing that only one of the supplied component is visible.
+ * @author Óscar González Fernández + */ +public class OnlyOneVisible { + + private List components; + + public OnlyOneVisible(Component... components) { + this.components = Arrays.asList(components); + showOnly(null); + } + + public void showOnly(Component component) { + for (Component c : components) { + if (c != null) { + c.setVisible(component != null && c.equals(component)); + } + } + } + +} diff --git a/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/Util.java b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/Util.java new file mode 100644 index 000000000..c6f6c2fe2 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/Util.java @@ -0,0 +1,312 @@ +package org.navalplanner.web.common; + +import java.math.BigDecimal; +import java.util.Date; + +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventListener; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zk.ui.event.InputEvent; +import org.zkoss.zkplus.databind.DataBinder; +import org.zkoss.zul.Checkbox; +import org.zkoss.zul.Datebox; +import org.zkoss.zul.Decimalbox; +import org.zkoss.zul.Intbox; +import org.zkoss.zul.Textbox; + +/** + * Utilities class.
+ * + * @author Óscar González Fernández + * @author Manuel Rego Casasnovas + */ +public class Util { + + public static void reloadBindings(Component... toReload) { + for (Component reload : toReload) { + DataBinder binder = Util.getBinder(reload); + if (binder != null) { + binder.loadComponent(reload); + } + } + } + + 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); + } + + /** + * Generic interface to represent a class with a typical get method. + * + * @author Manuel Rego Casasnovas + * + * @param + * The type of the variable to be returned. + */ + public static interface Getter { + /** + * Typical get method that returns a variable. + * + * @return A variable of type . + */ + public T get(); + } + + /** + * Generic interface to represent a class with a typical set method. + * + * @author Manuel Rego Casasnovas + * + * @param + * The type of the variable to be set. + */ + public static interface Setter { + /** + * Typical set method to store a variable. + * + * @param value + * A variable of type to be set. + */ + public void set(T value); + } + + /** + * Binds a {@link Textbox} with a {@link Getter}. The {@link Getter} will be + * used to get the value that is going to be showed in the {@link Textbox}. + * + * @param textBox + * The {@link Textbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @return The {@link Textbox} bound + */ + public static Textbox bind(Textbox textBox, Getter getter) { + textBox.setValue(getter.get()); + textBox.setDisabled(true); + return textBox; + } + + /** + * Binds a {@link Textbox} with a {@link Getter}. The {@link Getter} will be + * used to get the value that is going to be showed in the {@link Textbox}. + * The {@link Setter} will be used to store the value inserted by the user + * in the {@link Textbox}. + * + * @param textBox + * The {@link Textbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @param setter + * The {@link Setter} interface that will implement a set method. + * @return The {@link Textbox} bound + */ + public static Textbox bind(final Textbox textBox, + final Getter getter, final Setter setter) { + textBox.setValue(getter.get()); + textBox.addEventListener("onChange", new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + InputEvent newInput = (InputEvent) event; + String value = newInput.getValue(); + setter.set(value); + textBox.setValue(getter.get()); + } + }); + return textBox; + } + + /** + * Binds a {@link Intbox} with a {@link Getter}. The {@link Getter} will be + * used to get the value that is going to be showed in the {@link Intbox}. + * + * @param intBox + * The {@link Intbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @return The {@link Intbox} bound + */ + public static Intbox bind(Intbox intBox, Getter getter) { + intBox.setValue(getter.get()); + intBox.setDisabled(true); + return intBox; + } + + /** + * Binds a {@link Intbox} with a {@link Getter}. The {@link Getter} will be + * used to get the value that is going to be showed in the {@link Intbox}. + * The {@link Setter} will be used to store the value inserted by the user + * in the {@link Intbox}. + * + * @param intBox + * The {@link Intbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @param setter + * The {@link Setter} interface that will implement a set method. + * @return The {@link Intbox} bound + */ + public static Intbox bind(final Intbox intBox, + final Getter getter, final Setter setter) { + intBox.setValue(getter.get()); + intBox.addEventListener("onChange", new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + InputEvent newInput = (InputEvent) event; + String value = newInput.getValue(); + setter.set(Integer.valueOf(value)); + intBox.setValue(getter.get()); + } + }); + return intBox; + } + + /** + * Binds a {@link Datebox} with a {@link Getter}. The {@link Getter} will be + * used to get the value that is going to be showed in the {@link Datebox}. + * + * @param dateBox + * The {@link Datebox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @return The {@link Datebox} bound + */ + public static Datebox bind(final Datebox dateBox, + final Getter getter) { + dateBox.setValue(getter.get()); + dateBox.setDisabled(true); + return dateBox; + } + + /** + * Binds a {@link Datebox} with a {@link Getter}. The {@link Getter} will be + * used to get the value that is going to be showed in the {@link Datebox}. + * The {@link Setter} will be used to store the value inserted by the user + * in the {@link Datebox}. + * + * @param dateBox + * The {@link Datebox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @param setter + * The {@link Setter} interface that will implement a set method. + * @return The {@link Datebox} bound + */ + public static Datebox bind(final Datebox dateBox, + final Getter getter, final Setter setter) { + dateBox.setValue(getter.get()); + dateBox.addEventListener("onChange", new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + setter.set(dateBox.getValue()); + dateBox.setValue(getter.get()); + } + }); + return dateBox; + } + + /** + * Binds a {@link Decimalbox} with a {@link Getter}. The {@link Getter} will + * be used to get the value that is going to be showed in the + * {@link Decimalbox}. + * + * @param decimalBox + * The {@link Decimalbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @return The {@link Decimalbox} bound + */ + public static Decimalbox bind(final Decimalbox decimalBox, + final Getter getter) { + decimalBox.setValue(getter.get()); + decimalBox.setDisabled(true); + return decimalBox; + } + + /** + * Binds a {@link Decimalbox} with a {@link Getter}. The {@link Getter} will + * be used to get the value that is going to be showed in the + * {@link Decimalbox}. The {@link Setter} will be used to store the value + * inserted by the user in the {@link Decimalbox}. + * + * @param decimalBox + * The {@link Decimalbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @param setter + * The {@link Setter} interface that will implement a set method. + * @return The {@link Decimalbox} bound + */ + public static Decimalbox bind(final Decimalbox decimalBox, + final Getter getter, final Setter setter) { + decimalBox.setValue(getter.get()); + decimalBox.addEventListener("onChange", new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + setter.set(decimalBox.getValue()); + decimalBox.setValue(getter.get()); + } + }); + return decimalBox; + } + + /** + * Binds a {@link Checkbox} with a {@link Getter}. The {@link Getter} will + * be used to get the value that is going to be showed in the + * {@link Checkbox}. + * + * @param decimalBox + * The {@link Checkbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @return The {@link Checkbox} bound + */ + public static Checkbox bind(final Checkbox checkBox, + final Getter getter) { + checkBox.setChecked(getter.get()); + checkBox.setDisabled(true); + return checkBox; + } + + /** + * Binds a {@link Checkbox} with a {@link Getter}. The {@link Getter} will + * be used to get the value that is going to be showed in the + * {@link Checkbox}. The {@link Setter} will be used to store the value + * inserted by the user in the {@link Checkbox}. + * + * @param decimalBox + * The {@link Checkbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @param setter + * The {@link Setter} interface that will implement a set method. + * @return The {@link Checkbox} bound + */ + public static Checkbox bind(final Checkbox checkBox, + final Getter getter, final Setter setter) { + checkBox.setChecked(getter.get()); + checkBox.addEventListener(Events.ON_CHECK, new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + setter.set(checkBox.isChecked()); + checkBox.setChecked(getter.get()); + } + }); + return checkBox; + } + +} diff --git a/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/components/TwoWaySelector.java b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/components/TwoWaySelector.java new file mode 100644 index 000000000..d6c7e5f1a --- /dev/null +++ b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/components/TwoWaySelector.java @@ -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 + */ +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 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 + */ + private ListitemRenderer renderer = new ListitemRenderer() { + @Override + public void render(Listitem item, Object data) throws Exception { + + Class klass = data.getClass(); + Map 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, Map> propertiesMapsCached = new HashMap, Map>(); + + /** + * 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 buildPropertyDescriptorsMap( + BeanInfo info) { + PropertyDescriptor[] propertyDescriptors = info + .getPropertyDescriptors(); + Map propertiesByName = new HashMap(); + 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 getProperties( + Class klass) throws IntrospectionException { + // If it's already cached + if (propertiesMapsCached.containsKey(klass)) { + return propertiesMapsCached.get(klass); + } + + BeanInfo beanInfo = Introspector.getBeanInfo(klass); + Map 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 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 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 selectedItems = assignedObjectsListbox.getSelectedItems(); + for (Listitem listitem : selectedItems) { + Object value = listitem.getValue(); + assignedObjects.remove(value); + unassignedObjects.add(value); + } + Util.reloadBindings(assignedObjectsListbox.getParent()); + Util.saveBindings(this); + } + +} \ No newline at end of file diff --git a/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/typeconverters/DateConverter.java b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/typeconverters/DateConverter.java new file mode 100644 index 000000000..208e28c54 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/common/typeconverters/DateConverter.java @@ -0,0 +1,26 @@ +package org.navalplanner.web.common.typeconverters; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.zkoss.zk.ui.Component; +import org.zkoss.zkplus.databind.TypeConverter; + +/** + * Converter for the type java.util.Date + * + * @author Diego Pino Garcia + * + */ +public class DateConverter implements TypeConverter { + + @Override + public Object coerceToBean(Object arg0, Component arg1) { + return null; + } + + @Override + public Object coerceToUi(Object object, Component component) { + return (new SimpleDateFormat("dd/MM/yyyy")).format((Date) object); + } +} diff --git a/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/error/PageForErrorOnEvent.java b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/error/PageForErrorOnEvent.java new file mode 100644 index 000000000..91c042e33 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/error/PageForErrorOnEvent.java @@ -0,0 +1,48 @@ +package org.navalplanner.web.error; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.Executions; +import org.zkoss.zk.ui.util.GenericForwardComposer; + +public class PageForErrorOnEvent extends GenericForwardComposer { + + private static final Log LOG = LogFactory.getLog(PageForErrorOnEvent.class); + + private Component modalWindow; + + @Override + public void doAfterCompose(Component comp) throws Exception { + super.doAfterCompose(comp); + logError(); + modalWindow = comp; + + } + + private void logError() { + Throwable exception = (Throwable) Executions.getCurrent().getAttribute( + "javax.servlet.error.exception"); + String errorMessage = (String) Executions.getCurrent().getAttribute( + "javax.servlet.error.message"); + LOG.error(errorMessage, exception); + } + + public void onClick$continueWorking() { + modalWindow.detach(); + } + + public void onClick$reload() { + Executions.sendRedirect(null); + } + + public void onClick$quitSession() { + HttpServletRequest nativeRequest = (HttpServletRequest) Executions + .getCurrent().getNativeRequest(); + nativeRequest.getSession().invalidate(); + Executions.sendRedirect("/"); + } + +} diff --git a/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/planner/DataForPlanner.java b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/planner/DataForPlanner.java new file mode 100644 index 000000000..642b269ca --- /dev/null +++ b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/planner/DataForPlanner.java @@ -0,0 +1,206 @@ +package org.navalplanner.web.planner; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import org.zkoss.ganttz.TaskEditFormComposer; +import org.zkoss.ganttz.adapters.AutoAdapter; +import org.zkoss.ganttz.adapters.DomainDependency; +import org.zkoss.ganttz.adapters.IStructureNavigator; +import org.zkoss.ganttz.adapters.PlannerConfiguration; +import org.zkoss.ganttz.data.DefaultFundamentalProperties; +import org.zkoss.ganttz.data.DependencyType; +import org.zkoss.ganttz.data.GanttDiagramGraph; +import org.zkoss.ganttz.data.ITaskFundamentalProperties; +import org.zkoss.ganttz.data.Task; +import org.zkoss.ganttz.data.TaskContainer; +import org.zkoss.ganttz.data.TaskLeaf; +import org.zkoss.ganttz.extensions.ICommand; +import org.zkoss.ganttz.extensions.ICommandOnTask; +import org.zkoss.ganttz.extensions.IContext; +import org.zkoss.ganttz.extensions.IContextWithPlannerTask; + +/** + * Some test data for planner
+ * @author Óscar González Fernández + */ +public class DataForPlanner { + + private TaskEditFormComposer taskEditForm = new TaskEditFormComposer(); + + public DataForPlanner() { + + } + + public GanttDiagramGraph getEmpty() { + return new GanttDiagramGraph(); + } + + private PlannerConfiguration addCommands( + PlannerConfiguration configuration) { + configuration + .addGlobalCommand(new ICommand() { + + @Override + public String getName() { + return "Add Task"; + } + + @Override + public void doAction( + IContext context) { + addNewTask(context); + } + }); + configuration + .setGoingDownInLastArrowCommand(new ICommand() { + + @Override + public void doAction( + IContext context) { + addNewTask(context); + } + + @Override + public String getName() { + return ""; + } + }); + configuration + .addCommandOnTask(new ICommandOnTask() { + @Override + public void doAction( + IContextWithPlannerTask context, + ITaskFundamentalProperties task) { + context.remove(task); + } + + @Override + public String getName() { + return "Remove"; + } + + }); + configuration.setEditTaskCommand(new ICommandOnTask() { + + @Override + public void doAction( + IContextWithPlannerTask context, + ITaskFundamentalProperties task) { + taskEditForm.showEditFormFor(context.getRelativeTo(), + context.getTask()); + } + + @Override + public String getName() { + return ""; + } + }); + return configuration; + } + + public PlannerConfiguration getLightLoad() { + return addCommands(getModelWith(20)); + } + + public PlannerConfiguration getMediumLoad() { + return addCommands(getModelWith(300)); + } + + public PlannerConfiguration getHighLoad() { + return addCommands(getModelWith(500)); + } + + private PlannerConfiguration getModelWith( + int tasksToCreate) { + List list = new ArrayList(); + Date now = new Date(); + Date end = twoMonthsLater(now); + final ITaskFundamentalProperties container = createTask("container", + now, end); + final List containerChildren = new ArrayList(); + final ITaskFundamentalProperties child1 = createTask("child 1", now, + end); + containerChildren.add(child1); + final DefaultFundamentalProperties child2 = createTask("another", now, + end); + containerChildren.add(child2); + list.add(container); + final ITaskFundamentalProperties first = createTask("tarefa1", now, end); + final ITaskFundamentalProperties second = createTask("tarefa2", now, + end); + list.add(first); + list.add(second); + for (int i = 2; i < tasksToCreate - 3; i++) { + String name = "tarefa " + (i + 1); + ITaskFundamentalProperties task = createTask(name, now, end); + list.add(task); + } + IStructureNavigator navigator = new IStructureNavigator() { + + @Override + public List getChildren( + ITaskFundamentalProperties object) { + if (object == container) + return containerChildren; + return new ArrayList(); + } + + @Override + public boolean isLeaf(ITaskFundamentalProperties object) { + return object != container; + } + }; + return new PlannerConfiguration( + new AutoAdapter() { + @Override + public List> getOutcomingDependencies( + ITaskFundamentalProperties object) { + List> result = new ArrayList>(); + if (child1 == object) { + result.add(DomainDependency.createDependency( + child1, child2, DependencyType.END_START)); + } else if (first == object) { + result.add(DomainDependency.createDependency(first, + second, DependencyType.END_START)); + } + return result; + } + }, navigator, list); + } + + private TaskContainer createContainer(String name, Date start, Date end) { + TaskContainer container = new TaskContainer(); + container.setBeginDate(start); + container.setEndDate(end); + container.setName(name); + return container; + } + + private DefaultFundamentalProperties createTask(String name, Date now, + Date end) { + return new DefaultFundamentalProperties(name, end, end.getTime() + - now.getTime(), "bla"); + } + + private void addNewTask(IContext context) { + Task newTask = new TaskLeaf(); + newTask.setName("Nova Tarefa"); + newTask.setBeginDate(new Date()); + newTask.setEndDate(twoMonthsLater(newTask.getBeginDate())); + context.add(newTask); + } + + private static Date twoMonthsLater(Date now) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(now); + calendar.add(Calendar.MONTH, 2); + return calendar.getTime(); + } + + public TaskEditFormComposer getTaskEditForm() { + return taskEditForm; + } +} diff --git a/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/planner/ShareBean.java b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/planner/ShareBean.java new file mode 100644 index 000000000..c650fad52 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/planner/ShareBean.java @@ -0,0 +1,68 @@ +package org.navalplanner.web.planner; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; + +public class ShareBean { + + public static int[] toHours(ShareBean... shares) { + Validate.noNullElements(shares); + int[] result = new int[shares.length]; + for (int i = 0; i < result.length; i++) { + result[i] = shares[i].getHours(); + } + return result; + } + + public static int sum(Collection shareBeans) { + Validate.noNullElements(shareBeans); + int result = 0; + for (ShareBean shareBean : shareBeans) { + result += shareBean.getHours(); + } + return result; + } + + public static List toShareBeans(String name, int[] hours) { + ArrayList result = new ArrayList(); + for (int i = 0; i < hours.length; i++) { + ShareBean s = new ShareBean(); + s.setName(name + "." + (i + 1)); + s.setHours(hours[i]); + result.add(s); + } + return result; + } + + private String name; + + private Integer hours; + + public ShareBean() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + if (StringUtils.isEmpty(name)) + return; + this.name = name; + } + + public Integer getHours() { + return hours; + } + + public void setHours(Integer share) { + if (share == null || share <= 0) + return; + this.hours = share; + } + +} diff --git a/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/planner/SplittingController.java b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/planner/SplittingController.java new file mode 100644 index 000000000..bc0810446 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/java/org/navalplanner/web/planner/SplittingController.java @@ -0,0 +1,81 @@ +package org.navalplanner.web.planner; + +import java.util.List; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.zkoss.zk.ui.WrongValueException; +import org.zkoss.zk.ui.util.Clients; +import org.zkoss.zk.ui.util.GenericForwardComposer; +import org.zkoss.zul.Label; +import org.zkoss.zul.SimpleListModel; +import org.zkoss.zul.Window; +import org.zkoss.zul.api.Grid; + +@Component +@Scope(BeanDefinition.SCOPE_PROTOTYPE) +public class SplittingController extends GenericForwardComposer { + + private IActionOnOk curentAction; + private Window window; + + private Grid sharesListing; + + private Label totalHoursLabel; + private List sharesList; + private Integer totalHours; + + public interface IActionOnOk { + public void doOkAction(ShareBean[] shares); + } + + public void show(List initialSharesList, Integer totalHours, + IActionOnOk ok) { + this.sharesList = initialSharesList; + this.totalHours = totalHours; + this.curentAction = ok; + this.totalHoursLabel.setValue(totalHours + ""); + this.sharesListing.setModel(new SimpleListModel(initialSharesList)); + showWindow(); + } + + public void onClick$splitOk() { + checkSumIsEqualToTotal(); + Clients.closeErrorBox(totalHoursLabel); + hideWindow(); + curentAction.doOkAction(this.sharesList.toArray(new ShareBean[0])); + } + + private void checkSumIsEqualToTotal() { + int sum = ShareBean.sum(sharesList); + if (sum != totalHours) { + throw new WrongValueException(totalHoursLabel, + "the sum is not equal: " + sum); + } + } + + public void onClick$splitCancel() { + hideWindow(); + } + + private void showWindow() { + try { + window.setMode("modal"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private void hideWindow() { + window.setVisible(false); + } + + @Override + public void doAfterCompose(org.zkoss.zk.ui.Component comp) throws Exception { + super.doAfterCompose(comp); + window = (Window) comp; + + } + +} diff --git a/ganttzk-demo-webapp/src/main/resources/metainfo/zk/lang-addon.xml b/ganttzk-demo-webapp/src/main/resources/metainfo/zk/lang-addon.xml new file mode 100755 index 000000000..ad28e0255 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/resources/metainfo/zk/lang-addon.xml @@ -0,0 +1,14 @@ + + + + + navalplanner-webapp + xul/html + + + twowayselector + org.navalplanner.web.common.components.TwoWaySelector + /common/components/twowayselector.zul + + + \ No newline at end of file diff --git a/ganttzk-demo-webapp/src/main/resources/navalplanner-webapp-spring-config.xml b/ganttzk-demo-webapp/src/main/resources/navalplanner-webapp-spring-config.xml new file mode 100644 index 000000000..acf049dd7 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/resources/navalplanner-webapp-spring-config.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/ganttzk-demo-webapp/src/main/webapp/META-INF/context.xml b/ganttzk-demo-webapp/src/main/webapp/META-INF/context.xml new file mode 100644 index 000000000..2811d9186 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/META-INF/context.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/ganttzk-demo-webapp/src/main/webapp/WEB-INF/i3-label.properties b/ganttzk-demo-webapp/src/main/webapp/WEB-INF/i3-label.properties new file mode 100644 index 000000000..e86778d96 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/WEB-INF/i3-label.properties @@ -0,0 +1,46 @@ +task.name=Nome +task.start=Comezo +task.end=Final +task.notes=Notas +task.ok=Aceptar +listdetails.add_task=Engadir +task.new_task_name=Nova Tarefa +DETAIL_ONE=Detalle 1 +DETAIL_TWO=Detalle 2 +DETAIL_THREE=Detalle 3 +DETAIL_FOUR=Detalle 4 +mainmenu.new=Novo +mainmenu.open=Abrir +mainmenu.save=Gardar +mainmenu.project=Proxecto +mainmenu.exit=Saír +mainmenu.resources=Recursos +mainmenu.list_workers=Lista traballadores +mainmenu.add_resources=Engadir recurso +mainmenu.manage_resources=Administrar recursos +mainmenu.check_plannification=Revisar conflitos de planificación +mainmenu.plannification=Planificación +mainmenu.add_task=Engadir tarefa +mainmenu.manage_tasks=Administrar tarefas +mainmenu.set_complection_data=Establecer nivel de complección +mainmenu.add_dependency=Engadir dependencia +mainmenu.manage_dependencies=Administrar dependencias +mainmenu.help=Axuda +mainmenu.about=Acerca de +mainmenu.aclunaga=Aclunaga +mainmenu.manage_criterions=Administrar criterios +mainmenu.orders=Pedidos +mainmenu.list_orders=Lista de pedidos +mainmenu.company_overview=Vista de empresa +mainmenu.plannifications_list=Listado de planificacións +mainmenu.manage_machines=Xestionar máquinas +mainmenu.activity_work_types=Tipos de actividad de traballo +mainmenu.models=Modelos +mainmenu.work_reports=Partes de traballo +mainmenu.work_report_list=Listado de partes de traballo +mainmenu.work_report_types=Tipos de partes de traballo +mainmenu.work_report_import=Importación de partes de traballo +mainmenu.administration=Administración +mainmenu.manage_users=Xestionar usuarios e permisos +mainmenu.quality_management=Xestión da calidade +mainmenu.manageAdvancesTypes=Xestionar tipos de avance \ No newline at end of file diff --git a/ganttzk-demo-webapp/src/main/webapp/WEB-INF/i3-label_en_US.properties b/ganttzk-demo-webapp/src/main/webapp/WEB-INF/i3-label_en_US.properties new file mode 100644 index 000000000..be5fc1657 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/WEB-INF/i3-label_en_US.properties @@ -0,0 +1,46 @@ +task.name=Name +task.start=Start +task.end=End +task.notes=Notes +task.ok=Ok +listdetails.add_task=Add +task.new_task_name=New Task +DETAIL_ONE=Detail 1 +DETAIL_TWO=Detail 2 +DETAIL_THREE=Detail 3 +DETAIL_FOUR=Detail 4 +mainmenu.new=New +mainmenu.open=Open +mainmenu.save=Save +mainmenu.project=Project +mainmenu.exit=Exit +mainmenu.resources=Resources +mainmenu.list_workers=Workers list +mainmenu.add_resources=Add resource +mainmenu.manage_resources=Manage resources +mainmenu.check_plannification=Check for plannification conflicts +mainmenu.plannification=Plannification +mainmenu.add_task=Add task +mainmenu.manage_tasks=Manage tasks +mainmenu.set_complection_data=Set complection data +mainmenu.add_dependency=Add dependency +mainmenu.manage_dependencies=Manage dependences +mainmenu.help=Help +mainmenu.about=About +mainmenu.aclunaga=Aclunaga +mainmenu.manage_criterions=Manage criterions +mainmenu.orders=Orders +mainmenu.list_orders=Orders list +mainmenu.company_overview=Company overview +mainmenu.plannifications_list=Plannifications list +mainmenu.manage_machines=Manage machines +mainmenu.activity_work_types=Activity work types +mainmenu.models=Models +mainmenu.work_reports=Work reports +mainmenu.work_report_list=Work report list +mainmenu.work_report_types=Work report types +mainmenu.work_report_import=Work report importation +mainmenu.administration=Administration +mainmenu.manage_users=Manage users and permissions +mainmenu.quality_management=Quality management +mainmenu.manageAdvancesTypes=Manage Advance types \ No newline at end of file diff --git a/ganttzk-demo-webapp/src/main/webapp/WEB-INF/web.xml b/ganttzk-demo-webapp/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..2e3200426 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,105 @@ + + + ganttzk-demo-webapp + + + + contextConfigLocation + classpath*:/navalplanner-override-spring-config.xml + + + + + + + + dspLoader + org.zkoss.web.servlet.dsp.InterpreterServlet + + + dspLoader + *.dsp + + + + + + + Used to cleanup when a session is destroyed + ZK Session Cleaner + org.zkoss.zk.ui.http.HttpSessionListener + + + + + + org.springframework.web.context.ContextLoaderListener + + + + org.springframework.web.context.request.RequestContextListener + + + + + + + + + ZK loader for ZUML pages + zkLoader + org.zkoss.zk.ui.http.DHtmlLayoutServlet + + + update-uri + /zkau + + 1 + + + zkLoader + *.zul + + + zkLoader + *.zhtml + + + The asynchronous update engine for ZK + auEngine + org.zkoss.zk.au.http.DHtmlUpdateServlet + + + auEngine + /zkau/* + + + + + /planner/main.zul + + + + java.lang.Throwable + /common/error.zul + + + + 404 + /common/page_not_found.zul + + diff --git a/ganttzk-demo-webapp/src/main/webapp/WEB-INF/zk.xml b/ganttzk-demo-webapp/src/main/webapp/WEB-INF/zk.xml new file mode 100644 index 000000000..d0ed26c16 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/WEB-INF/zk.xml @@ -0,0 +1,11 @@ + + + + + + java.lang.Throwable + + /common/event_error.zul + + + diff --git a/ganttzk-demo-webapp/src/main/webapp/common/components/twowayselector.zul b/ganttzk-demo-webapp/src/main/webapp/common/components/twowayselector.zul new file mode 100644 index 000000000..f79bb275e --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/common/components/twowayselector.zul @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ganttzk-demo-webapp/src/main/webapp/common/event_error.zul b/ganttzk-demo-webapp/src/main/webapp/common/event_error.zul new file mode 100644 index 000000000..2e9b46a5f --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/common/event_error.zul @@ -0,0 +1,14 @@ + + + Prodúxose un erro na execución: + "${requestScope['javax.servlet.error.message']}". O erro + gardouse e procurarase arreglalo no menor tempo posible. + + + + + diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/axuda.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/axuda.gif new file mode 100644 index 000000000..f9e71a752 Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/axuda.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/degradado_azul.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/degradado_azul.gif new file mode 100644 index 000000000..d18778ee2 Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/degradado_azul.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/flechitas.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/flechitas.gif new file mode 100644 index 000000000..b2725099a Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/flechitas.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/ganttzk-demo.png b/ganttzk-demo-webapp/src/main/webapp/common/img/ganttzk-demo.png new file mode 100644 index 000000000..f25696615 Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/ganttzk-demo.png differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/linea_down.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/linea_down.gif new file mode 100644 index 000000000..05c12041b Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/linea_down.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/linea_pie_login.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/linea_pie_login.gif new file mode 100644 index 000000000..db7e1c892 Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/linea_pie_login.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/logos_aplicacion.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/logos_aplicacion.gif new file mode 100644 index 000000000..25b743bd3 Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/logos_aplicacion.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/migas_separacion.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/migas_separacion.gif new file mode 100644 index 000000000..78808e4ee Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/migas_separacion.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/pestana1.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/pestana1.gif new file mode 100644 index 000000000..6209c5f50 Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/pestana1.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/pestana_activa.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/pestana_activa.gif new file mode 100644 index 000000000..6817b7bed Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/pestana_activa.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/pestana_sobre.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/pestana_sobre.gif new file mode 100644 index 000000000..9ee16e794 Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/pestana_sobre.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/img/sub_separacion.gif b/ganttzk-demo-webapp/src/main/webapp/common/img/sub_separacion.gif new file mode 100644 index 000000000..35ea03455 Binary files /dev/null and b/ganttzk-demo-webapp/src/main/webapp/common/img/sub_separacion.gif differ diff --git a/ganttzk-demo-webapp/src/main/webapp/common/layout/template_ganttzk_demo.zul b/ganttzk-demo-webapp/src/main/webapp/common/layout/template_ganttzk_demo.zul new file mode 100644 index 000000000..a7819a2f4 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/common/layout/template_ganttzk_demo.zul @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + about + ganttZK + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/ganttzk-demo-webapp/src/main/webapp/common/page_not_found.zul b/ganttzk-demo-webapp/src/main/webapp/common/page_not_found.zul new file mode 100644 index 000000000..99a392ea4 --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/common/page_not_found.zul @@ -0,0 +1,19 @@ + + + + + + + + A páxina que está solicitando non existe. + Se introduciu a dirección directamente na barra de navegación + do navegador revísea ou pulse na seguinte ligazón para ir á páxina + inicial: Ir a inicio + Se chegou a esta páxina dende outra páxina do portal + rogámoslle nolo notifique para que sexa subsanado no menor + intervalo de tempo posible. + Desculpe as molestias. + + + diff --git a/ganttzk-demo-webapp/src/main/webapp/planner/css/ganttzk.css b/ganttzk-demo-webapp/src/main/webapp/planner/css/ganttzk.css new file mode 100644 index 000000000..d649bfd7b --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/planner/css/ganttzk.css @@ -0,0 +1,335 @@ +/* +* ganttz.css Ganttz specific styles +* / + +The next constants are used within the planner styling: + +Ganntz.ListdetailsWidth = 280 + + +zkTasklist.HEIGHT_PER_ROW = 15 +zkTasklist.HEIGHT_TIME_TRACKER = 120 + +zkTasklist.SCROLLBAR_WIDTH = 15 + +zkTasklist.SCROLL_CONTAINER_INITIAL_HEIGHT = 500 +zkTasklist.SCROLL_CONTAINER_INITIAL_WIDTH = 600 + +zkTasklist.GANTT_PANEL_LEFT = 300 + +*/ + +/* -------------- Listdetails -------------- */ + +/* External listdetails box */ +.listdetails { + width:280px; /* Ganntz.ListdetailsWidth */ + float:left; + margin-top: 0px; +/* border-bottom: 1px solid #86A4BE; */ + font-size:10px !important; + margin-top:0px; +} + +#listdetails_container { + float:left; + height:500px; /* zkTasklist.SCROLL_CONTAINER_INITIAL_HEIGHT */ + position:relative; + top:27px; + overflow-y: hidden; + border-bottom: 1px solid #86A4BE; + border-right: 1px solid #86A4BE; +} + +.listdetails img { + display:none; +} + +#listdetails_container td { + border-bottom:1px solid #86A4BE; + border-left:1px solid #86A4BE; + border:0px; +} + +#listdetails_container td { + padding:0px; +} + +.listdetails input { + width: 65px; + font-size:10px !important; + border-bottom:0px; + border-right:0px; + height:17px; +} + +#listdetails_container .z-datebox-inp, +#listdetails_container div.z-tree-col-cnt { + font-family:"Verdana,Tahoma,Arial,Helvetica,sans-serif"; + font-size:10px !important; + border-bottom:0px; + border-right:0px; +} + +.depth_1 .task_title { + width: 121px !important; +} +.depth_2 .task_title { + width: 104px !important; +} +.depth_3 .task_title { + width: 85px; +} +.depth_4 .task_title { + width: 64px; +} + + +.taskdetail_grid table { + height:30px; + width:285px; /* Ganntz.ListdetailsWidth */ +} + + + +#listtasks { + position:relative; + width:600px; + top:0px; +} + +/* Task box properties */ +.box { + border: 1px solid; + text-align:center; + vertical-align: middle; + z-index:10; + cursor: pointer; + cursor: hand; +} + +/* Task lane properties */ +.row { + height: 9px; /* 19 */ + border-bottom: dotted 1px #CCCCCC; + margin-bottom: 10px; + margin-top: 10px; + width: 10000px; /* Defined to be larger than the maximum scroll_inner_x */ +} + + +/* -------------- Dependencies -------------- */ +#listdependencies { + position:relative; + width:400px; + float:left; + top:0px; +} + +.dependence { + z-index:1; + position: absolute; +} + +.end, .start, .mid, .arrow { + position:absolute; + padding:4px; + cursor: crosshair; +} + +.end, .start { + height:1px; +} + +.mid { + width:1px; +} + +.completion { + display: none; + width: 30%; + margin-top:0px; + height: 10px; + background-color: #FFCC99; + z-index:5; + border:0px; +} + +.row span { + display:none; + position:relative; + z-index:5; + color:#BBBBBB; + white-space:nowrap; +} + +/* -------------- TaskGroup -------------- */ +.taskgroup_start { + background-image: url("/ganttzk-demo-webapp/zkau/web/ganttz/img/group_left.png"); + height: 10px; + width: 10px; + float:left; +} + +.taskgroup_end { + background-image: url("/ganttzk-demo-webapp/zkau/web/ganttz/img/group_right.png"); + height: 10px; + width: 10px; + float:right; +} + +.taskgroup, .row .expanded { + border-top: solid black 2px; + border-bottom: 0px; + border-left: 0px; + border-right: 0px; + background-color: transparent !important; +} + +.row .closed { + border-top: solid black 2px; +} + + + + +.zk #ganttpanel .z-button-cm { + border: 0px; +} + +#ganttpanel { + height:400px; /* 800 */ + width: 900px; +} + +#ganttpanel table { + float:left; + padding:0; + margin:0; + overflow:hidden; +} + +#ganttpanel table td { + padding:0; +} + +/* -------------- Timetracker -------------- */ +.timetracker_fake_row { + height: 80px; +} + +/* Forces every zoom level the same table width */ +#timetracker table { + border-collapse: collapse; +} + +#timetracker .second_level_ tr { + height:14px; +} + +/* Watermark alternate row color */ +#watermark .timetracker_column_even { + background-color: #EEEEEE; +} + +/* Background image for current day vertical line */ +#watermark .timetracker_column_today { + background-image: url("/ganttzk-demo-webapp/zkau/web/ganttz/img/watermark_today.png"); + background-repeat: repeat-y; +} + +#watermark .bankHoliday { + background-color: #FFEEEE; !important; +} + + +/* Reduce spacing and font-size for watermark legend */ +.z-columns, .z-column { + font-size: 8px !important; + text-align: center; + padding:0 0 0 0 !important; +} + +table { + margin:0px; + padding:0px; + border:0px; +} + +#scroll_container { + margin-top:70px; + height:300px; /* Recalculated based on window */ + width:500px; /* Recalculated based on window */ + overflow:hidden; + float:left; + position:absolute; + left:285px; /* Ganntz.ListdetailsWidth + borders = 280 + 5 */ + /* border:solid green 1px; */ +} + +#timetracker { + /* border: solid 1px red; */ + position:absolute; + left:285px; /* Ganntz.ListdetailsWidth + borders = 280 + 5 */ + height:500px; /* zkTasklist.SCROLL_CONTAINER_INITIAL_HEIGHT (dynamic) */ + width:600px; /* zkTasklist.SCROLL_CONTAINER_INITIAL_WIDTH (dynamic) */ + position:absolute; + overflow-x:hidden; + float:left; +} + +#zoom_buttons { + position:relative; +} + +tr.z-vbox-sep { + height: 0px; + padding: 0px; + margin: 0px; +} + + +#ganttpanel_scroller_x, #ganttpanel_scroller_y { + position:absolute; + float:left; + overflow:auto; +} + +#ganttpanel_scroller_x { + + top: 600px; /* (dynamic) */ + left: 285px; /* Ganntz.ListdetailsWidth + borders = 280 + 5 */ + width:635px; + height:15px; +} + +#ganttpanel_inner_scroller_x { + /* must be resized on ganttpanel javascript adjust size */ + width:9000px; /* Real canvas dimensions */ + height:15px; /* Scroll constant */ +} + +#ganttpanel_scroller_y { + top: 160px; /* Fixed top position */ + left: 920px; + width:15px; + height:330px; +} +#ganttpanel_inner_scroller_y { + width:15px; /* Scroll constant */ + height:1350px; /* Modified when added or removed tasks, or zoom adjustments */ +} + + +.footer { + /* Pending to calculate general position */ + display:none; +} + +/* Hide at the beginning */ +#ganttpanel_scroller_x { + display:none; +} +#ganttpanel_scroller_y { + display:none; +} diff --git a/ganttzk-demo-webapp/src/main/webapp/planner/main.zul b/ganttzk-demo-webapp/src/main/webapp/planner/main.zul new file mode 100644 index 000000000..8ac3f1ddf --- /dev/null +++ b/ganttzk-demo-webapp/src/main/webapp/planner/main.zul @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + +
+
+ + + + + + ${c:l('task.name')} + + + + ${c:l('task.start')} + + + + ${c:l('task.end')} + + + + ${c:l('task.notes')} + + + + +