Merge pull request #115 from dgray16/master
Migration from ZK5 to ZK8. This is a big change!
This commit is contained in:
commit
747c61f372
890 changed files with 37963 additions and 38451 deletions
|
|
@ -7,9 +7,11 @@ LibrePlan Team
|
|||
--------------
|
||||
|
||||
* Jeroen Baten <jeroen@libreplan-enterprise.com>
|
||||
* Edwin Zuijdendorp <edwin@zuydendorp.nl>
|
||||
* Bjørn Vos <bjorn@libreplan-enterprise.com>
|
||||
* Vova Perebykivskiy <vova@libreplan-enterprise.com>
|
||||
* Міша Гожда <misha@libreplan-enterprise.com>
|
||||
* Philippe Poumaroux <philippe.poumaroux@free.fr>
|
||||
* Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||
* Paul Luchyn <ddiamondbbackk@gmail.com>
|
||||
|
||||
|
||||
Previous Team Members
|
||||
|
|
@ -30,6 +32,8 @@ Previous Team Members
|
|||
* Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* Pablo Fernández de la Cigoña Nóvoa <pcigonha@igalia.com>
|
||||
* Farruco Sanjurjo Arcay <fsanjurjo@igalia.com>
|
||||
* Misha Gozda <misha@libreplan-enterprise.com>
|
||||
* Bogdan Bodnarjuk <b.bodnarjuk@libreplan-enterprise.com
|
||||
|
||||
|
||||
Translators
|
||||
|
|
|
|||
11
HACKING.rst
11
HACKING.rst
|
|
@ -332,6 +332,12 @@ Ubuntu/Debian
|
|||
|
||||
In Ubuntu Lucid 10.04 remove ``libqtwebkit-dev`` package.
|
||||
|
||||
* Install::
|
||||
|
||||
# apt-get install cutycapt
|
||||
|
||||
If it doesn't work. Try to do it:
|
||||
|
||||
* Download source code::
|
||||
|
||||
$ svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt cutycapt
|
||||
|
|
@ -409,9 +415,8 @@ Debian/Ubuntu
|
|||
|
||||
# apt-get install make python-docutils texlive-latex-base texlive-latex-recommended texlive-latex-extra textlive-fonts-recommended
|
||||
|
||||
* Go to the directory where the documentation you want to generate
|
||||
is. For example, if you want to generate the user manual in
|
||||
English::
|
||||
* Go to the directory where the documentation you want to generate is.
|
||||
For example, if you want to generate the user manual in English::
|
||||
|
||||
# cd doc/src/user/en
|
||||
|
||||
|
|
|
|||
|
|
@ -427,6 +427,9 @@ Instructions:
|
|||
|
||||
# Example location: C:/Program Files/Apache Software Foundation/Tomcat 6.0/bin/Tomcat6.exe
|
||||
|
||||
If you will face SKIP_IDENTIFIER_CHECK error, refer to:
|
||||
http://stackoverflow.com/questions/24546304/how-to-skip-java-reserve-keyword-identifier-check-in-tomcat
|
||||
|
||||
* Go to http://localhost:8080/libreplan
|
||||
|
||||
Logs
|
||||
|
|
@ -528,3 +531,4 @@ Where the different parameters have the following meaning:
|
|||
.. NOTE::
|
||||
|
||||
Take into account that size of PermGen is additional to heap size.
|
||||
Since JDK8(b75) you will not see java.lang.OutOfMemoryError: PermGen space.
|
||||
|
|
|
|||
17
NEWS.rst
17
NEWS.rst
|
|
@ -10,7 +10,8 @@ Summary
|
|||
These are the most representative changes:
|
||||
|
||||
* Update SDK to JDK8
|
||||
* Update all libraries
|
||||
* Update ZK5 to ZK8
|
||||
* Update all other libraries
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
|
@ -20,6 +21,7 @@ Thanks to all the contributors to this new version:
|
|||
* Vova Perebykivskyi
|
||||
* Bodgan Bodnarjuk
|
||||
* Jeroen Baten
|
||||
* Paul Luchyn
|
||||
|
||||
Changes
|
||||
~~~~~~~
|
||||
|
|
@ -80,15 +82,16 @@ Changes
|
|||
* Update BeanShell
|
||||
* Update Quartz Framework
|
||||
* Update Usertype.Core
|
||||
* Update ZK Framework
|
||||
|
||||
* Add Javax EL
|
||||
|
||||
* Update LibrePlan version to 1.6.0
|
||||
|
||||
|
||||
* Remove Ezmorph
|
||||
* Remove Json-lib
|
||||
* Remove M2E plugin
|
||||
* Remove DBUnit
|
||||
|
||||
* Code refactoring
|
||||
|
||||
|
|
@ -265,7 +268,7 @@ Changes
|
|||
* jira and tim-connector: Constraints for JobSchedulerConfiguration
|
||||
* Fix NonUniqueObjectException on the project gantt when loading the same criteria of the user filter setting
|
||||
* Sort the list of resources and triggers the sort after refreshing it.
|
||||
* Adds graphic representation of the avaliability as a color progress bar and a icon for warning non-zero overload.
|
||||
* Adds graphic representation of the availability as a color progress bar and a icon for warning non-zero overload.
|
||||
* Adds margins additional to task limits(start, end) for default load ratios calculation in resource allocation advance search.
|
||||
* Recalculates the load ratios on changing the filtering dates and incorporates interface validations in the filtering dates dateboxes
|
||||
* Add the suitable casting on getting items of the list of resources with their load ratios.
|
||||
|
|
@ -1268,7 +1271,7 @@ Changes
|
|||
* Bug: Configures right ascending sorting in companies list.
|
||||
* Bug #1527: Several interface disabling configurations modified.
|
||||
* Bug #1528: Check if name is null before truncating it.
|
||||
* Bug #1528: Change datatype for field TaskElement.notes to TEXT, which has no lenght limit.
|
||||
* Bug #1528: Change datatype for field TaskElement.notes to TEXT, which has no length limit.
|
||||
* Bug #1528: Trucate too long task names so they don't cause problems on save.
|
||||
* Small code refactor.
|
||||
* Bug #1523: Fix NPE in company view returning zero if progress is null
|
||||
|
|
@ -2039,7 +2042,7 @@ Changes
|
|||
* set the fields "Subcontracting date" and "Subcontracting communication date" in the subcontractor pop-up in read only mode.
|
||||
* Remove unneeded throws in MoneyCostCalculatorTest
|
||||
* Add unit tests to check MoneyCostCalculator with a different type of hours
|
||||
* set the progress values, which are sent from a subcontrated task, in read only mode.
|
||||
* set the progress values, which are sent from a subcontracted task, in read only mode.
|
||||
* Remove commented lines in MoneyCostCalculatorTest
|
||||
* Update Copyright info in user documentation
|
||||
* Update Copyright info in user documentation
|
||||
|
|
@ -2562,7 +2565,7 @@ Changes
|
|||
* [Bug #1291] Fix NPE when a task with a dependency is removed
|
||||
* [Bug #1291] Fix NPE when a task with a dependency is removed
|
||||
* Remove duplicated method in TaskElement
|
||||
* creates a new field in the SubcontratedTaskData to store the collection of subcontrator delivering dates.
|
||||
* creates a new field in the SubcontractedTaskData to store the collection of subcontrator delivering dates.
|
||||
* create the interface DeliverDate and the comparator DeliverDateComparator to sort the SubcontractorDeliverDate and the DeadlineCommunications.
|
||||
* [Bug #1229] Look for new resources when moving a task
|
||||
* [Bug #1229] Wrap all position mofications
|
||||
|
|
@ -2661,7 +2664,7 @@ Changes
|
|||
* Update the routing of the css with libreplan.
|
||||
* Add the relationship from order entity with its customer comunications.
|
||||
* Create a customer comunication when a subcontractor receives the communication of a new project to be developed.
|
||||
* Add the external code when a whole order is imported as subcontrated task.
|
||||
* Add the external code when a whole order is imported as subcontracted task.
|
||||
* Create a list of incoming projects accepted by customers and contracted with the company
|
||||
* Create the entity CustomerComunication, the dao CustomerComunicationDAO, the test CustomerComunicationDAOTest and add the changes of the database in a new file db.changelog-1.2.xml
|
||||
* Fix 2 style mini-issues
|
||||
|
|
|
|||
20
README.rst
20
README.rst
|
|
@ -88,16 +88,16 @@ Features
|
|||
Requirements
|
||||
------------
|
||||
|
||||
* *JRE 7* or *JRE 6* - Java Runtime Environment
|
||||
* *JRE 8* - Java Runtime Environment
|
||||
|
||||
Project depends on Java 6 or 7 and JRE is needed in order to run it
|
||||
Project depends on Java 8 JRE is needed in order to run it
|
||||
|
||||
* *PostgreSQL* - Object-relational SQL database
|
||||
|
||||
A database server is needed. You could use *PostgreSQL* or *MySQL* as you
|
||||
prefer.
|
||||
|
||||
* *Tomcat 7* or Tomcat 6* - Servlet and JSP engine
|
||||
* *Tomcat 8* - Servlet and JSP engine
|
||||
|
||||
Server to deploy the application. You could use *Jetty* instead.
|
||||
|
||||
|
|
@ -122,26 +122,26 @@ Availability
|
|||
------------
|
||||
|
||||
The cutting-edge version of this project is always available from the Git
|
||||
repository at https://github.com/Igalia/libreplan.
|
||||
repository at https://github.com/LibrePlan/libreplan
|
||||
|
||||
Released versions are available at
|
||||
http://sourceforge.net/projects/libreplan/files/.
|
||||
http://sourceforge.net/projects/libreplan/files/
|
||||
|
||||
|
||||
Webpage
|
||||
-------
|
||||
|
||||
You can find more information about *LibrePlan* at
|
||||
http://www.libreplan.com/.
|
||||
http://www.libreplan.org/home/
|
||||
|
||||
For information related with *LibrePlan* development you can visit the wiki at
|
||||
http://wiki.libreplan.org/.
|
||||
http://wiki.libreplan.org/twiki/bin/view/LibrePlan
|
||||
|
||||
|
||||
Reporting bugs
|
||||
--------------
|
||||
|
||||
Please use the bug tracker to report bugs at http://bugs.libreplan.org/.
|
||||
Please use the bug tracker to report bugs at http://bugs.libreplan.org/
|
||||
|
||||
|
||||
License
|
||||
|
|
@ -165,5 +165,5 @@ Please see ``AUTHORS`` file for more information about the authors.
|
|||
|
||||
.. [1] http://en.wikipedia.org/wiki/Work_Breakdown_Structure
|
||||
.. [2] http://en.wikipedia.org/wiki/Earned_Value_Management
|
||||
.. [3] http://www.fsf.org/licensing/licenses/agpl.html
|
||||
.. [4] http://www.fundacioncalidade.org/
|
||||
.. [3] http://www.gnu.org/licenses/agpl.html
|
||||
.. [4] http://gain.xunta.gal/
|
||||
|
|
|
|||
|
|
@ -7,15 +7,14 @@ How To Create A New Report In LibrePlan
|
|||
:Contact: mrego@igalia.com
|
||||
:Date: 11/09/2012
|
||||
:Copyright:
|
||||
Some rights reserved. This document is distributed under the Creative
|
||||
Commons Attribution-ShareAlike 3.0 licence, available in
|
||||
http://creativecommons.org/licenses/by-sa/3.0/.
|
||||
Some rights reserved. This document is distributed under the Creative
|
||||
Commons Attribution-ShareAlike 3.0 licence, available in
|
||||
http://creativecommons.org/licenses/by-sa/3.0/.
|
||||
:Abstract:
|
||||
LibrePlan uses **JasperReports** [1]_ to create reports in the application. This
|
||||
document tries to explain how to create a new report in LibrePlan.
|
||||
LibrePlan uses **JasperReports** [1]_ to create reports in the application.
|
||||
This document tries to explain how to create a new report in LibrePlan.
|
||||
|
||||
During this tutorial you are going to create a report that will show the list of
|
||||
resources in LibrePlan.
|
||||
During this tutorial you are going to create a report that will show the list of resources in LibrePlan.
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
|
|
@ -105,7 +104,7 @@ Steps:
|
|||
|
||||
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
|
||||
|
||||
<?component name="combobox_output_format" macroURI="combobox_output_format.zul"
|
||||
<?component name="comboboxOutputFormat" macroURI="comboboxOutputFormat.zul"
|
||||
class="org.libreplan.web.reports.ComboboxOutputFormat" ?>
|
||||
|
||||
<zk>
|
||||
|
|
@ -127,7 +126,7 @@ Steps:
|
|||
<rows>
|
||||
<row>
|
||||
<label value="${i18n:_('Output format:')}" />
|
||||
<combobox_output_format id="outputFormat" />
|
||||
<comboboxOutputFormat id="outputFormat" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
|
|
@ -167,8 +166,8 @@ charge to manage users interaction with report interface and call the proper
|
|||
methods to generate the report itself and show it to the user.
|
||||
|
||||
There is already a controller called ``LibrePlanReportController`` which
|
||||
implements most of the stuff needed for report controllers. So, controllers for
|
||||
new reports are going to extend this class and re-implement some methods.
|
||||
implements most of the stuff needed for report controllers.
|
||||
So, controllers for new reports are going to extend this class and re-implement some methods.
|
||||
|
||||
Steps:
|
||||
|
||||
|
|
@ -335,8 +334,7 @@ Steps:
|
|||
layout and save it with the name of the new report
|
||||
``resourcesListReport.jrxml`` in the same folder.
|
||||
|
||||
This will allow us to keep coherence between reports in regard to design,
|
||||
header, footer, etc.
|
||||
This will allow us to keep coherence between reports in regard to design, header, footer, etc.
|
||||
|
||||
* Set report name to ``resourcesList``.
|
||||
|
||||
|
|
@ -381,18 +379,24 @@ with other LibrePlan reports like header and footer. The result in iReport would
|
|||
be something similar to the screenshot.
|
||||
|
||||
.. figure:: img/ireport-resources-list-report.png
|
||||
:alt: iRerpot screenshot for Resources List report
|
||||
:alt: iRerpot screenshot for Resources List report
|
||||
:width: 100%
|
||||
|
||||
iReport screenshot for Resources List report
|
||||
iReport screenshot for Resources List report
|
||||
|
||||
You can even check the XML ``resourcesListReport.jrxml`` that should have
|
||||
You can even check the XML ``resourcesListReport.jrxml`` that should have
|
||||
something similar to the following content:
|
||||
|
||||
::
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="resourcesList" pageWidth="595" pageHeight="842" columnWidth="535" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" resourceBundle="resourcesList" uuid="f83422af-00de-4fa5-b137-580b559f1453">
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports
|
||||
http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="resourcesList" pageWidth="595" pageHeight="842"
|
||||
columnWidth="535" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"
|
||||
resourceBundle="resourcesList" uuid="f83422af-00de-4fa5-b137-580b559f1453">
|
||||
|
||||
<property name="ireport.zoom" value="1.0"/>
|
||||
<property name="ireport.x" value="0"/>
|
||||
<property name="ireport.y" value="0"/>
|
||||
|
|
@ -419,7 +423,7 @@ something similar to the following content:
|
|||
</textElement>
|
||||
<textFieldExpression><![CDATA[$R{subtitle}]]></textFieldExpression>
|
||||
</textField>
|
||||
<image scaleImage="RetainShape">
|
||||
<image scaleImage="RetainShape" isLazy="true">
|
||||
<reportElement uuid="e033fa20-c68f-4716-9b43-e1435be185a8" x="318" y="0" width="180" height="53"/>
|
||||
<imageExpression><![CDATA[$P{logo}]]></imageExpression>
|
||||
</image>
|
||||
|
|
@ -552,27 +556,25 @@ Steps:
|
|||
}
|
||||
|
||||
Then if you run LibrePlan and go to the new menu entry called *Resources List*
|
||||
in *Reports* you will be able to generate a report with the resources added as
|
||||
example data. The report still lacks a good design and format, but at least you
|
||||
are able to see how the basic functionality of JasperReports in LibrePlan is
|
||||
integrated. The next step will be to show real data in the report getting it
|
||||
from database.
|
||||
in *Reports* you will be able to generate a report with the resources added as example data.
|
||||
The report still lacks a good design and format, but at least you
|
||||
are able to see how the basic functionality of JasperReports in LibrePlan is integrated.
|
||||
The next step will be to show real data in the report getting it from database.
|
||||
|
||||
.. figure:: img/resources-list-report-example-data-pdf.png
|
||||
:alt: Resources List report with example data in PDF format
|
||||
:alt: Resources List report with example data in PDF format
|
||||
:width: 100%
|
||||
|
||||
Resources List report with example data in PDF format
|
||||
Resources List report with example data in PDF format
|
||||
|
||||
|
||||
Show real data from database
|
||||
----------------------------
|
||||
|
||||
Now you need to query database and get information about resources. In order to
|
||||
follow LibrePlan architecture you are going to create a model that will be in
|
||||
charge to retrieve information from database, process it if needed and return
|
||||
the information to the controller. Then controller will send this information to
|
||||
JasperReports in order to generate the report with real data.
|
||||
Now you need to query database and get information about resources.
|
||||
In order to follow LibrePlan architecture you are going to create a model that will be in
|
||||
charge to retrieve information from database, process it if needed and return the information to the controller.
|
||||
Then controller will send this information to JasperReports in order to generate the report with real data.
|
||||
|
||||
Steps:
|
||||
|
||||
|
|
@ -828,8 +830,8 @@ Steps:
|
|||
}
|
||||
|
||||
* Modify report file ``resourcesListReport.jrxml`` with iReport to add the new
|
||||
parameter and show it in some part of the report layout. You could use iReport
|
||||
for this task, or, for example, add the following lines in XML file::
|
||||
parameter and show it in some part of the report layout.
|
||||
You could use iReport for this task, or, for example, add the following lines in XML file::
|
||||
|
||||
<parameter name="type" class="java.lang.String"/>
|
||||
|
||||
|
|
|
|||
|
|
@ -602,7 +602,7 @@ content:
|
|||
|
||||
<zk>
|
||||
<window self="@{define(content)}"
|
||||
apply="org.libreplan.web.planner.allocation.streches.StretchesFunctionTemplateCRUDController">
|
||||
apply="org.libreplan.web.planner.allocation.stretches.StretchesFunctionTemplateCRUDController">
|
||||
<vbox id="messagesContainer"/>
|
||||
<list id="listWindow"/>
|
||||
<edit id="editWindow"/>
|
||||
|
|
@ -680,7 +680,7 @@ The basis for implementing MVC pattern in ZK is ``apply`` attribute.
|
|||
Your page defines a component ``Window`` with an ``apply`` attribute assigned::
|
||||
|
||||
<window self="@{define(content)}"
|
||||
apply="org.libreplan.web.planner.allocation.streches.StretchesFunctionTemplateCRUDController">
|
||||
apply="org.libreplan.web.planner.allocation.stretches.StretchesFunctionTemplateCRUDController">
|
||||
|
||||
It links this ``Window`` component with a ``.java`` file, thereby the Java class
|
||||
will be able to access and manipulate components defined inside ``window`` tag.
|
||||
|
|
@ -766,7 +766,7 @@ For this example you will create a new controller
|
|||
|
||||
::
|
||||
|
||||
package org.libreplan.web.planner.allocation.streches;
|
||||
package org.libreplan.web.planner.allocation.stretches;
|
||||
|
||||
...
|
||||
|
||||
|
|
@ -1253,7 +1253,7 @@ folder:
|
|||
|
||||
* ``IStretchesFunctionTemplateModel.java``::
|
||||
|
||||
package org.libreplan.web.planner.allocation.streches;
|
||||
package org.libreplan.web.planner.allocation.stretches;
|
||||
|
||||
...
|
||||
|
||||
|
|
@ -1263,7 +1263,7 @@ folder:
|
|||
|
||||
* ``StretchesFunctionTemplateModel.java``::
|
||||
|
||||
package org.libreplan.web.planner.allocation.streches;
|
||||
package org.libreplan.web.planner.allocation.stretches;
|
||||
|
||||
...
|
||||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@
|
|||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="vbfrWGfCLBGl" type="hAf0l1kIOBtM" name="cantidad_que_hacer" />
|
||||
</UML:Classifier.feature>
|
||||
</UML:Class>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="UwUp5iYgVB85" name="AdvanceAssigment" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="UwUp5iYgVB85" name="AdvanceAssignment" >
|
||||
<UML:Classifier.feature>
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="T39teAln6AUS" type="qdTUeCLBaJts" name="reportGlobalAdvance" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="oAXoyRcNetbF" type="2zQEOGZFsPzF" name="maxValue" />
|
||||
|
|
@ -245,8 +245,8 @@
|
|||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="Db7E4ky5iW8v" type="dCHs9h07Z9Vb" name="duration" />
|
||||
</UML:Classifier.feature>
|
||||
</UML:Class>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="o5mCGv6T0zJ1" name="AssigmentFunction" />
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="YpNtsZci2NR9" name="DayAssigment" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="o5mCGv6T0zJ1" name="AssignmentFunction" />
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="YpNtsZci2NR9" name="DayAssignment" >
|
||||
<UML:Classifier.feature>
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="SEQVgSVQf1jQ" type="dCHs9h07Z9Vb" name="hours" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="NyFsBrpPm7dW" type="ECeqpWy8psFU" initialValue="{criterion,especifica}" name="tipo" />
|
||||
|
|
@ -257,13 +257,13 @@
|
|||
<UML:Generalization xmi.idref="GvUkFUrye1Yl" />
|
||||
</UML:GeneralizableElement.generalization>
|
||||
</UML:Class>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="0WUme5I6QUAL" name="GenericDayAssigment" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="0WUme5I6QUAL" name="GenericDayAssignment" >
|
||||
<UML:GeneralizableElement.generalization>
|
||||
<UML:Generalization xmi.idref="G2AvGRcerKjs" />
|
||||
<UML:Generalization xmi.idref="c5awcauVaslZ" />
|
||||
</UML:GeneralizableElement.generalization>
|
||||
</UML:Class>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="GpZEcpFG3HuR" name="SpecificDayAssigment" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="GpZEcpFG3HuR" name="SpecificDayAssignment" >
|
||||
<UML:GeneralizableElement.generalization>
|
||||
<UML:Generalization xmi.idref="7deCbLvUjYef" />
|
||||
</UML:GeneralizableElement.generalization>
|
||||
|
|
@ -278,12 +278,12 @@
|
|||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="O6eT5AUWOLWC" type="q0K4uDt3Em1T" name="name" />
|
||||
</UML:Classifier.feature>
|
||||
</UML:Class>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="o5RjRxAkOrU1" name="DirectAdvanceAssigment" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="o5RjRxAkOrU1" name="DirectAdvanceAssignment" >
|
||||
<UML:GeneralizableElement.generalization>
|
||||
<UML:Generalization xmi.idref="t9QzWAWJNjCI" />
|
||||
</UML:GeneralizableElement.generalization>
|
||||
</UML:Class>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="KgJE71ZrTa4N" name="IndirectAdvanceAssigment" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="KgJE71ZrTa4N" name="IndirectAdvanceAssignment" >
|
||||
<UML:GeneralizableElement.generalization>
|
||||
<UML:Generalization xmi.idref="u0gIjsab6Z3N" />
|
||||
</UML:GeneralizableElement.generalization>
|
||||
|
|
@ -454,7 +454,7 @@
|
|||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="GeLKfWmQuIBU" type="Cq6BA0nXsCXx" name="machineHumanHourRate" />
|
||||
</UML:Classifier.feature>
|
||||
</UML:Class>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Kw2aCKPV84kE" name="MachineWorkerAssigment" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Kw2aCKPV84kE" name="MachineWorkerAssignment" >
|
||||
<UML:Classifier.feature>
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="OfmZd8GsCYKE" type="DtuyEvXi0kBC" name="start_date" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="SkF33CAV0aTV" type="f7oGUkbSGEeR" name="end_date" />
|
||||
|
|
@ -1251,7 +1251,7 @@
|
|||
<UML:Class stereotype="ValueObject" visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="DvJMqK9uqyoj" name="DescriptionField" >
|
||||
<UML:Classifier.feature>
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="EktSfldrewDU" type="6zMANtkSKpsl" name="fieldName" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="YA0kxe2sGVdU" type="dCHs9h07Z9Vb" name="lenght" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="YA0kxe2sGVdU" type="dCHs9h07Z9Vb" name="length" />
|
||||
</UML:Classifier.feature>
|
||||
</UML:Class>
|
||||
<UML:Association visibility="public" isSpecification="false" namespace="Logical View" xmi.id="NabCwmZxpxX4" name="lineFields" >
|
||||
|
|
@ -1291,7 +1291,7 @@
|
|||
</UML:Association.connection>
|
||||
</UML:Association>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="jxLogAx66lof" name="DerivedAllocation" />
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="ZcejaipLWSlT" name="DerivedDayAssigment" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="ZcejaipLWSlT" name="DerivedDayAssignment" >
|
||||
<UML:GeneralizableElement.generalization>
|
||||
<UML:Generalization xmi.idref="OHtc23XcYxcn" />
|
||||
</UML:GeneralizableElement.generalization>
|
||||
|
|
@ -1574,7 +1574,7 @@
|
|||
<UML:AssociationEnd changeability="changeable" visibility="public" isNavigable="true" isSpecification="false" xmi.id="MYzp4P0l7Sfh" type="93SIJpAVZgSA" name="" aggregation="none" />
|
||||
</UML:Association.connection>
|
||||
</UML:Association>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="UUktVVzv8eYw" name="AdvanceAssigmentTemplate" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="UUktVVzv8eYw" name="AdvanceAssignmentTemplate" >
|
||||
<UML:Classifier.feature>
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="ZpKZ9EpZ43xr" type="qdTUeCLBaJts" name="reportGlobalAdvance" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="7BAGgpu8Ke1n" type="2zQEOGZFsPzF" name="maxValue" />
|
||||
|
|
@ -1586,7 +1586,7 @@
|
|||
<UML:AssociationEnd changeability="changeable" visibility="public" isNavigable="true" isSpecification="false" xmi.id="RqC7SswCmRjc" type="UUktVVzv8eYw" name="" aggregation="none" />
|
||||
</UML:Association.connection>
|
||||
</UML:Association>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="BLUiq39f9WT0" name="AdvanceAssigment_1" >
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="BLUiq39f9WT0" name="AdvanceAssignment_1" >
|
||||
<UML:Classifier.feature>
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="OVE8Cs0Kfgrz" type="qdTUeCLBaJts" name="reportGlobalAdvance" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="0GkbGqWR908z" type="2zQEOGZFsPzF" name="maxValue" />
|
||||
|
|
@ -1802,10 +1802,10 @@
|
|||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="0" x="201" showattsigs="601" y="181" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="134" isinstance="0" usefillcolor="1" fillcolor="#ffffc0" xmi.id="oRwdH97rBGn9" showscope="1" height="88" showopsigs="601" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="0" x="634" showattsigs="601" y="183" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="200" isinstance="0" usefillcolor="1" fillcolor="#ffffc0" xmi.id="xC9oqvTbtqno" showscope="1" height="56" showopsigs="601" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="0" x="891" showattsigs="601" y="362" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="207" isinstance="0" usefillcolor="1" fillcolor="#ffffc0" xmi.id="zOVY0BwVHuvE" showscope="1" height="32" showopsigs="601" />
|
||||
<notewidget width="137" x="471" noteType="0" y="20" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="137" linecolor="none" xmi.id="PFaYRnK1tp0B" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,5,50,0,0,0,0,0" text="The assigment is going to be from the startDate to the endDate of the task" />
|
||||
<notewidget width="137" x="471" noteType="0" y="20" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="137" linecolor="none" xmi.id="PFaYRnK1tp0B" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,5,50,0,0,0,0,0" text="The assignment is going to be from the startDate to the endDate of the task" />
|
||||
<classwidget linecolor="none" usesdiagramfillcolor="1" linewidth="none" showoperations="1" usesdiagramusefillcolor="1" showpubliconly="0" showpackage="0" x="682" showattsigs="601" y="31" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="152" isinstance="0" usefillcolor="1" fillcolor="none" xmi.id="o5mCGv6T0zJ1" showscope="1" height="36" showopsigs="601" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="0" x="397" showattsigs="601" y="743" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="215" isinstance="0" usefillcolor="1" fillcolor="#ffffc0" xmi.id="YpNtsZci2NR9" showscope="1" height="56" showopsigs="601" />
|
||||
<notewidget width="190" x="207" noteType="0" y="31" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="127" linecolor="none" xmi.id="q8fcVDfvP5R3" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,5,50,0,0,0,0,0" text="The percentage indicates in the case of an AssigmentFunction the maximum value to calculate the days assigments
" />
|
||||
<notewidget width="190" x="207" noteType="0" y="31" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="127" linecolor="none" xmi.id="q8fcVDfvP5R3" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,5,50,0,0,0,0,0" text="The percentage indicates in the case of an AssignmentFunction the maximum value to calculate the days assignments
" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="0" x="57" showattsigs="601" y="368" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="206" isinstance="0" usefillcolor="1" fillcolor="#ffffc0" xmi.id="ip8LnfNpfMJo" showscope="1" height="32" showopsigs="601" />
|
||||
<classwidget linecolor="none" usesdiagramfillcolor="1" linewidth="none" showoperations="1" usesdiagramusefillcolor="1" showpubliconly="0" showpackage="0" x="449" showattsigs="601" y="445" showattributes="1" font="Sans Serif,10,-1,5,75,0,0,0,0,0" width="123" isinstance="0" usefillcolor="1" fillcolor="none" xmi.id="pXwBgpXvFPTv" showscope="1" height="56" showopsigs="601" />
|
||||
<classwidget linecolor="none" usesdiagramfillcolor="1" linewidth="none" showoperations="1" usesdiagramusefillcolor="1" showpubliconly="0" showpackage="0" x="169" showattsigs="601" y="532" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="171" isinstance="0" usefillcolor="1" fillcolor="none" xmi.id="0WUme5I6QUAL" showscope="1" height="32" showopsigs="601" />
|
||||
|
|
@ -1954,10 +1954,10 @@
|
|||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="0" x="297" showattsigs="601" y="245" showattributes="1" font="Sans Serif,10,-1,5,75,0,0,0,0,0" width="220" isinstance="0" usefillcolor="1" fillcolor="#71ff4a" xmi.id="UwUp5iYgVB85" showscope="1" height="56" showopsigs="601" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="0" x="655" showattsigs="601" y="223" showattributes="1" font="Sans Serif,10,-1,5,75,0,0,0,0,0" width="364" isinstance="0" usefillcolor="1" fillcolor="#ffffc0" xmi.id="bmRPNtkrYrn4" showscope="1" height="128" showopsigs="601" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="0" x="156" showattsigs="601" y="441" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="173" isinstance="0" usefillcolor="1" fillcolor="#ffffc0" xmi.id="QX7KUtq8V8Jy" showscope="1" height="56" showopsigs="601" />
|
||||
<notewidget width="461" x="173" noteType="0" y="19" usesdiagramusefillcolor="1" usesdiagramfillcolor="0" isinstance="0" fillcolor="#b9fff7" height="184" linecolor="none" xmi.id="BRWpZJn9t6Gg" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,0,50,0,0,0,0,0" text="Hai que introducir a regra de negocio de que non pode haber dous obxectos AdvanceAssigment do mesmo AdvanceType sobre o OrderElement

Tamen hai que introducir a restriccion de que non se pode definir un obxecto AdvanceAssigment sobre un OrderElement se existe algun pai deste OrderElement que ten un obxecto AdvanceAssigment do mesmo AdvanceType" />
|
||||
<notewidget width="461" x="173" noteType="0" y="19" usesdiagramusefillcolor="1" usesdiagramfillcolor="0" isinstance="0" fillcolor="#b9fff7" height="184" linecolor="none" xmi.id="BRWpZJn9t6Gg" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,0,50,0,0,0,0,0" text="Hai que introducir a regra de negocio de que non pode haber dous obxectos AdvanceAssignment do mesmo AdvanceType sobre o OrderElement

Tamen hai que introducir a restriccion de que non se pode definir un obxecto AdvanceAssignment sobre un OrderElement se existe algun pai deste OrderElement que ten un obxecto AdvanceAssignment do mesmo AdvanceType" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="0" x="146" showattsigs="601" y="367" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="193" isinstance="0" usefillcolor="1" fillcolor="#ffffc0" xmi.id="o5RjRxAkOrU1" showscope="1" height="32" showopsigs="601" />
|
||||
<classwidget linecolor="none" usesdiagramfillcolor="1" linewidth="none" showoperations="1" usesdiagramusefillcolor="1" showpubliconly="0" showpackage="0" x="387" showattsigs="601" y="367" showattributes="1" font="Sans Serif,10,-1,0,50,0,0,0,0,0" width="205" isinstance="0" usefillcolor="1" fillcolor="none" xmi.id="KgJE71ZrTa4N" showscope="1" height="32" showopsigs="601" />
|
||||
<notewidget width="292" x="611" noteType="0" y="472" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="189" linecolor="none" xmi.id="zSuD3L47lpuA" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,0,50,0,0,0,0,0" text="Hai que crear un novo tipo de avance predefinido: ChildrenAdvanceType. Este tipo de avance se cargara se non existe na base de datos. Ademais cando se cree un OrderElement de tipo OrderLineGroup haberá sempre que crearlle un IndirectAdvanceAssigment de tipo ChildrenAdvanceType" />
|
||||
<notewidget width="292" x="611" noteType="0" y="472" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="189" linecolor="none" xmi.id="zSuD3L47lpuA" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,0,50,0,0,0,0,0" text="Hai que crear un novo tipo de avance predefinido: ChildrenAdvanceType. Este tipo de avance se cargara se non existe na base de datos. Ademais cando se cree un OrderElement de tipo OrderLineGroup haberá sempre que crearlle un IndirectAdvanceAssignment de tipo ChildrenAdvanceType" />
|
||||
</widgets>
|
||||
<messages/>
|
||||
<associations>
|
||||
|
|
@ -2692,7 +2692,7 @@
|
|||
<classwidget linecolor="none" usesdiagramfillcolor="1" linewidth="none" showoperations="1" usesdiagramusefillcolor="1" showpubliconly="1" showpackage="1" x="94" showattsigs="601" showstereotype="1" y="206" showattributes="1" font="DejaVu Sans,8,-1,5,50,0,0,0,0,0" width="43" isinstance="0" usefillcolor="1" fillcolor="none" xmi.id="J8SsPhfYKZmW" showscope="1" height="28" showopsigs="601" />
|
||||
<classwidget linecolor="none" usesdiagramfillcolor="1" linewidth="none" showoperations="1" usesdiagramusefillcolor="1" showpubliconly="1" showpackage="1" x="266" showattsigs="601" showstereotype="1" y="77" showattributes="1" font="DejaVu Sans,8,-1,5,50,0,0,0,0,0" width="86" isinstance="0" usefillcolor="1" fillcolor="none" xmi.id="MMYIYbrnQlAN" showscope="1" height="28" showopsigs="601" />
|
||||
<notewidget width="151" showstereotype="1" x="55" noteType="0" y="13" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="157" linecolor="none" xmi.id="Px9F2MBrplzS" usefillcolor="1" linewidth="none" font="DejaVu Sans,8,-1,5,50,0,0,0,0,0" text="QualityFormTask has a relation with OrderElement but is QualityForm the one that has a direct relation in the case of template. So aplying the template will generate a QualityFormTask" />
|
||||
<notewidget width="205" showstereotype="1" x="745" noteType="0" y="24" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="111" linecolor="none" xmi.id="lJ17VZ75s1O3" usefillcolor="1" linewidth="none" font="DejaVu Sans,8,-1,5,50,0,0,0,0,0" text="the value unitPrice, and totalPrice and stimatedAvaliability doesn't have sense, and will be get by Material information at the time of application of the template.
The status will be pending in the moment of creation." />
|
||||
<notewidget width="205" showstereotype="1" x="745" noteType="0" y="24" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="111" linecolor="none" xmi.id="lJ17VZ75s1O3" usefillcolor="1" linewidth="none" font="DejaVu Sans,8,-1,5,50,0,0,0,0,0" text="the value unitPrice, and totalPrice and estimatedAvailability doesn't have sense, and will be get by Material information at the time of application of the template.
The status will be pending in the moment of creation." />
|
||||
<notewidget width="182" showstereotype="1" x="34" noteType="0" y="261" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="136" linecolor="none" xmi.id="bLm48FbWtpXE" usefillcolor="1" linewidth="none" font="DejaVu Sans,8,-1,5,50,0,0,0,0,0" text="Codes will be regenerated at the moment of application of the template acording to the Order that receives the template. Init and End date will be relative to the init of the template." />
|
||||
<classwidget linecolor="none" usesdiagramfillcolor="1" linewidth="none" showoperations="1" usesdiagramusefillcolor="1" showpubliconly="0" showpackage="1" x="577" showattsigs="601" showstereotype="1" y="175" showattributes="1" font="DejaVu Sans,8,-1,5,50,0,0,0,0,0" width="195" isinstance="0" usefillcolor="1" fillcolor="none" xmi.id="UUktVVzv8eYw" showscope="1" height="49" showopsigs="601" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="0" usesdiagramusefillcolor="0" showpubliconly="1" showpackage="0" x="829" showattsigs="601" y="183" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="105" isinstance="0" usefillcolor="1" fillcolor="#ffffc0" xmi.id="bmRPNtkrYrn4" showscope="1" height="32" showopsigs="601" />
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ There are several mandatory parameters. They are:
|
|||
|
||||
* **Reference date**. It is the date which is wanted to have as reference to make the comparison with the planned foreseen status of the project at that date with the real performance of the project at that date according. *The default value for this field is the current date*.
|
||||
|
||||
* **Progres type**. It is the progress type it is wanted to be used to measure the projects progress. In the application a project can be measured simultaneously with different progress types, and the one selected with the pulldown component by the user is the one used for calculating the report data. The default value for the *progress type* is *spread*, which is a special progress type consisting of using the preferred way of measuring the progress configured in each WBS element.
|
||||
* **Progress type**. It is the progress type it is wanted to be used to measure the projects progress. In the application a project can be measured simultaneously with different progress types, and the one selected with the pulldown component by the user is the one used for calculating the report data. The default value for the *progress type* is *spread*, which is a special progress type consisting of using the preferred way of measuring the progress configured in each WBS element.
|
||||
|
||||
With regard to the optional fields, they are the following:
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,21 @@ Written by
|
|||
LibrePlan Team
|
||||
--------------
|
||||
|
||||
* Jeroen Baten <jeroen@libreplan-enterprise.com>
|
||||
* Edwin Zuijdendorp <edwin@zuydendorp.nl>
|
||||
* Bjørn Vos <bjorn@libreplan-enterprise.com>
|
||||
* Philippe Poumaroux <philippe.poumaroux@free.fr>
|
||||
* Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||
* Paul Luchyn <ddiamondbbackk@gmail.com>
|
||||
|
||||
Previous Team Members
|
||||
---------------------
|
||||
|
||||
* Fernando Bellas Permuy <fbellas@udc.es>
|
||||
* José María Casanova Crespo <jmcasanova@igalia.com>
|
||||
* Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* Pablo Fernández de la Cigoña Nóvoa <pcigonha@igalia.com>
|
||||
* Farruco Sanjurjo Arcay <fsanjurjo@igalia.com>
|
||||
* Cristina Alvariño Pérez <cristina.alvarino@cafedered.es>
|
||||
* Jacobo Aragunde Pérez <jaragunde@igalia.com>
|
||||
* Nacho Barrientos Arias <nacho@igalia.com>
|
||||
|
|
@ -53,15 +68,8 @@ LibrePlan Team
|
|||
* Diego Pino García <dpino@igalia.com>
|
||||
* Manuel Rego Casasnovas <rego@igalia.com>
|
||||
* Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
|
||||
Previous Team Members
|
||||
---------------------
|
||||
|
||||
* Fernando Bellas Permuy <fbellas@udc.es>
|
||||
* José María Casanova Crespo <jmcasanova@igalia.com>
|
||||
* Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* Pablo Fernández de la Cigoña Nóvoa <pcigonha@igalia.com>
|
||||
* Farruco Sanjurjo Arcay <fsanjurjo@igalia.com>
|
||||
* Misha Gozda <misha@libreplan-enterprise.com>
|
||||
* Bogdan Bodnarjuk <b.bodnarjuk@libreplan-enterprise.com>
|
||||
|
||||
Translators
|
||||
-----------
|
||||
|
|
@ -106,10 +114,10 @@ Public funding
|
|||
Inside the global scope that LibrePlan is designed for regarding planning management, a project was developed to solve some common polanning problems. This project is partially financed by Xunta de Galicia, Ministerio de Industria, Turismo e Comercio, and by the European Union, Fondo Europeo de Desenvolvemento Rexional.
|
||||
|
||||
.. figure:: images/logos.png
|
||||
:scale: 100
|
||||
:scale: 100
|
||||
|
||||
This project was part of Plan Avanza:
|
||||
|
||||
.. figure:: images/avanza.png
|
||||
:scale: 100
|
||||
:scale: 100
|
||||
|
||||
|
|
|
|||
9
doc/src/user/en/21-communications.rst
Normal file
9
doc/src/user/en/21-communications.rst
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Subcontractor work description
|
||||
###############################
|
||||
|
||||
It is possible to keep this field empty.
|
||||
|
||||
But if you do, you could get errors in communication functionality when multiple emtpy fields exist.
|
||||
|
||||
We recommend to always use a unique work description.
|
||||
|
||||
|
|
@ -10,7 +10,6 @@ body {
|
|||
background: #ffffff;
|
||||
color: black;
|
||||
margin: 2em;
|
||||
/* padding: 0em 2em; */
|
||||
}
|
||||
|
||||
p.topic-title {
|
||||
|
|
@ -19,7 +18,7 @@ p.topic-title {
|
|||
|
||||
table.docinfo {
|
||||
text-align: left;
|
||||
margin: 2em 0em;
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
a[href] {
|
||||
|
|
@ -78,18 +77,18 @@ p.rubric {
|
|||
h1.title {
|
||||
color: #003a6b;
|
||||
font-size: 250%;
|
||||
margin-bottom: 0em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h2.subtitle {
|
||||
color: #003a6b;
|
||||
border-bottom: 0px;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #555;
|
||||
background-color: transparent;
|
||||
margin: 0em;
|
||||
margin: 0;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +137,7 @@ dd {
|
|||
|
||||
div.admonition, div.note, div.tip, div.caution, div.important, div.warning {
|
||||
margin: 2em 2em;
|
||||
padding: 0em 1em;
|
||||
padding: 0 1em;
|
||||
border-top: 1px solid #aaa;
|
||||
border-left: 1px solid #aaa;
|
||||
border-bottom: 2px solid #555;
|
||||
|
|
@ -180,7 +179,7 @@ table.docutils {
|
|||
border: 1px solid gray;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 1.5em 0em;
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
table.docutils caption {
|
||||
|
|
@ -198,8 +197,8 @@ table.docutils th {
|
|||
div.sidebar {
|
||||
width: 33%;
|
||||
float: right;
|
||||
margin: 0em 2em;
|
||||
padding: 0em 1em;
|
||||
margin: 0 2em;
|
||||
padding: 0 1em;
|
||||
border-top: 1px solid #aaa;
|
||||
border-left: 1px solid #aaa;
|
||||
border-bottom: 2px solid #555;
|
||||
|
|
@ -207,45 +206,45 @@ div.sidebar {
|
|||
}
|
||||
|
||||
p.sidebar-title {
|
||||
margin-bottom: 0em;
|
||||
margin-bottom: 0;
|
||||
color: #003a6b;
|
||||
border-bottom: 1px solid #aaa;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
p.sidebar-subtitle {
|
||||
margin-top: 0em;
|
||||
margin-top: 0;
|
||||
font-style: italic;
|
||||
color: #003a6b;
|
||||
}
|
||||
|
||||
div.figure {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.figure img {
|
||||
background: #f8f8f8;
|
||||
padding: 0.25em;
|
||||
border: 1px solid #888;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
background: #f8f8f8;
|
||||
padding: 0.25em;
|
||||
border: 1px solid #888;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
div.figure img:hover {
|
||||
background: #e0e0e0;
|
||||
background: #e0e0e0;
|
||||
}
|
||||
|
||||
div.figure p.caption {
|
||||
text-align: center;
|
||||
margin-top: 0.1em;
|
||||
font-style: italic;
|
||||
color: #444;
|
||||
text-align: center;
|
||||
margin-top: 0.1em;
|
||||
font-style: italic;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
pre.literal-block {
|
||||
padding: 0.15em;
|
||||
background: #f8f8f8;
|
||||
border: 1px solid #dfdfdf;
|
||||
border-left: 0.25em solid #dfdfdf
|
||||
padding: 0.15em;
|
||||
background: #f8f8f8;
|
||||
border: 1px solid #dfdfdf;
|
||||
border-left: 0.25em solid #dfdfdf
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
|
|
@ -50,6 +51,7 @@
|
|||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
|
@ -89,17 +91,19 @@
|
|||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
</dependency>
|
||||
</dependency>
|
||||
|
||||
<!-- ZK -->
|
||||
<dependency>
|
||||
<groupId>org.zkoss.zk</groupId>
|
||||
<artifactId>zul</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.zkoss.zk</groupId>
|
||||
<artifactId>zkplus</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.zkoss.zk</groupId>
|
||||
<artifactId>zk</artifactId>
|
||||
|
|
@ -123,6 +127,7 @@
|
|||
<artifactId>easymock</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymockclassextension</artifactId>
|
||||
|
|
|
|||
|
|
@ -24,17 +24,11 @@ package org.zkoss.ganttz;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.zkoss.ganttz.extensions.ICommand;
|
||||
import org.zkoss.ganttz.extensions.IContext;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zul.Button;
|
||||
|
||||
class CommandContextualized<T> {
|
||||
|
||||
public static <T> CommandContextualized<T> create(ICommand<T> command, IContext<T> context) {
|
||||
return new CommandContextualized<T>(command, context);
|
||||
}
|
||||
|
||||
private final ICommand<T> command;
|
||||
|
||||
private final IContext<T> context;
|
||||
|
|
@ -46,6 +40,10 @@ class CommandContextualized<T> {
|
|||
this.context = context;
|
||||
}
|
||||
|
||||
public static <T> CommandContextualized<T> create(ICommand<T> command, IContext<T> context) {
|
||||
return new CommandContextualized<>(command, context);
|
||||
}
|
||||
|
||||
public void doAction() {
|
||||
command.doAction(context);
|
||||
}
|
||||
|
|
@ -66,12 +64,7 @@ class CommandContextualized<T> {
|
|||
if ( command.isDisabled() ) {
|
||||
result.setDisabled(true);
|
||||
} else {
|
||||
result.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
doAction();
|
||||
}
|
||||
});
|
||||
result.addEventListener(Events.ON_CLICK, event -> doAction());
|
||||
}
|
||||
|
||||
button = result;
|
||||
|
|
|
|||
|
|
@ -29,29 +29,33 @@ import org.zkoss.ganttz.extensions.ICommandOnTask;
|
|||
import org.zkoss.ganttz.extensions.IContext;
|
||||
import org.zkoss.ganttz.extensions.IContextWithPlannerTask;
|
||||
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
|
||||
public class CommandOnTaskContextualized<T> {
|
||||
|
||||
public static <T> CommandOnTaskContextualized<T> create(ICommandOnTask<T> commandOnTask,
|
||||
IDomainAndBeansMapper<T> mapper, IContext<T> context) {
|
||||
|
||||
return new CommandOnTaskContextualized<T>(commandOnTask, mapper, context);
|
||||
}
|
||||
|
||||
private final ICommandOnTask<T> commandOnTask;
|
||||
|
||||
private final IContext<T> context;
|
||||
|
||||
private final IDomainAndBeansMapper<T> mapper;
|
||||
|
||||
private CommandOnTaskContextualized(ICommandOnTask<T> commandOnTask, IDomainAndBeansMapper<T> mapper,
|
||||
private CommandOnTaskContextualized(ICommandOnTask<T> commandOnTask,
|
||||
IDomainAndBeansMapper<T> mapper,
|
||||
IContext<T> context) {
|
||||
|
||||
this.commandOnTask = commandOnTask;
|
||||
this.mapper = mapper;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public static <T> CommandOnTaskContextualized<T> create(ICommandOnTask<T> commandOnTask,
|
||||
IDomainAndBeansMapper<T> mapper,
|
||||
IContext<T> context) {
|
||||
|
||||
return new CommandOnTaskContextualized<>(commandOnTask, mapper, context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void doAction(TaskComponent taskComponent) {
|
||||
doAction(
|
||||
ContextRelativeToOtherComponent.makeRelativeTo(context, taskComponent),
|
||||
|
|
@ -82,12 +86,7 @@ public class CommandOnTaskContextualized<T> {
|
|||
}
|
||||
|
||||
ItemAction<TaskComponent> toItemAction() {
|
||||
return new ItemAction<TaskComponent>() {
|
||||
@Override
|
||||
public void onEvent(TaskComponent choosen, Event event) {
|
||||
doAction(choosen);
|
||||
}
|
||||
};
|
||||
return (chosen, event) -> doAction(chosen);
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
|
|
@ -95,8 +94,7 @@ public class CommandOnTaskContextualized<T> {
|
|||
}
|
||||
|
||||
public boolean accepts(TaskComponent taskComponent) {
|
||||
T domainObject = domainObjectFor(taskComponent.getTask());
|
||||
return commandOnTask.isApplicableTo(domainObject);
|
||||
return commandOnTask.isApplicableTo(domainObjectFor(taskComponent.getTask()));
|
||||
}
|
||||
|
||||
public IDomainAndBeansMapper<T> getMapper() {
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ import java.beans.PropertyChangeEvent;
|
|||
import java.beans.PropertyChangeListener;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.zkoss.ganttz.data.Dependency;
|
||||
import org.zkoss.ganttz.data.DependencyType;
|
||||
import org.zkoss.ganttz.data.Task;
|
||||
|
|
@ -39,6 +37,7 @@ import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
|||
import org.zkoss.ganttz.util.ComponentsFinder;
|
||||
import org.zkoss.ganttz.util.MenuBuilder;
|
||||
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.ext.AfterCompose;
|
||||
import org.zkoss.zul.Menupopup;
|
||||
|
|
@ -51,8 +50,8 @@ import org.zkoss.zul.impl.XulElement;
|
|||
*/
|
||||
public class DependencyList extends XulElement implements AfterCompose {
|
||||
|
||||
private final class ChangeTypeAction implements
|
||||
ItemAction<DependencyComponent> {
|
||||
private final class ChangeTypeAction implements ItemAction<DependencyComponent> {
|
||||
|
||||
private final DependencyType type;
|
||||
|
||||
private ChangeTypeAction(DependencyType type) {
|
||||
|
|
@ -60,32 +59,28 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(final DependencyComponent choosen, Event event) {
|
||||
boolean canBeAdded = context.changeType(choosen.getDependency(),
|
||||
type);
|
||||
if (!canBeAdded) {
|
||||
public void onEvent(final DependencyComponent chosen, Event event) {
|
||||
boolean canBeAdded = context.changeType(chosen.getDependency(), type);
|
||||
|
||||
if ( !canBeAdded ) {
|
||||
warnUser(_("The specified dependency is not allowed"));
|
||||
}
|
||||
}
|
||||
|
||||
private void warnUser(String message) {
|
||||
try {
|
||||
Messagebox.show(message, null, Messagebox.OK,
|
||||
Messagebox.EXCLAMATION, 0, null);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Messagebox.show(message, null, Messagebox.OK, Messagebox.EXCLAMATION, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
private final class DependencyVisibilityToggler implements
|
||||
PropertyChangeListener {
|
||||
private final class DependencyVisibilityToggler implements PropertyChangeListener {
|
||||
|
||||
private final Task source;
|
||||
|
||||
private final Task destination;
|
||||
|
||||
private final DependencyComponent dependencyComponent;
|
||||
|
||||
private DependencyVisibilityToggler(Task source, Task destination,
|
||||
DependencyComponent dependencyComponent) {
|
||||
private DependencyVisibilityToggler(Task source, Task destination, DependencyComponent dependencyComponent) {
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
this.dependencyComponent = dependencyComponent;
|
||||
|
|
@ -93,16 +88,17 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (!evt.getPropertyName().equals("visible")) {
|
||||
if ( !"visible".equals(evt.getPropertyName()) ) {
|
||||
return;
|
||||
}
|
||||
if (dependencyMustBeVisible() != isDependencyNowVisible()) {
|
||||
|
||||
if ( dependencyMustBeVisible() != isDependencyNowVisible() ) {
|
||||
toggleDependencyExistence(dependencyMustBeVisible());
|
||||
}
|
||||
}
|
||||
|
||||
void toggleDependencyExistence(boolean visible) {
|
||||
if (visible) {
|
||||
if ( visible ) {
|
||||
appendChild(dependencyComponent);
|
||||
dependencyComponent.afterCompose();
|
||||
addContextMenu(dependencyComponent);
|
||||
|
|
@ -120,8 +116,6 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
}
|
||||
}
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(DependencyList.class);
|
||||
|
||||
private transient IZoomLevelChangedListener listener;
|
||||
|
||||
private final FunctionalityExposedForExtensions<?> context;
|
||||
|
|
@ -135,33 +129,32 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
}
|
||||
|
||||
private List<DependencyComponent> getDependencyComponents() {
|
||||
List<Object> children = getChildren();
|
||||
return ComponentsFinder
|
||||
.findComponentsOfType(DependencyComponent.class, children);
|
||||
List<Component> children = getChildren();
|
||||
return ComponentsFinder.findComponentsOfType(DependencyComponent.class, children);
|
||||
}
|
||||
|
||||
void addDependencyComponent(final DependencyComponent dependencyComponent) {
|
||||
TaskComponent source = dependencyComponent.getSource();
|
||||
TaskComponent destination = dependencyComponent.getDestination();
|
||||
DependencyVisibilityToggler visibilityToggler = new DependencyVisibilityToggler(
|
||||
source.getTask(), destination.getTask(), dependencyComponent);
|
||||
source.getTask().addVisibilityPropertiesChangeListener(
|
||||
visibilityToggler);
|
||||
destination.getTask().addVisibilityPropertiesChangeListener(
|
||||
visibilityToggler);
|
||||
|
||||
DependencyVisibilityToggler visibilityToggler =
|
||||
new DependencyVisibilityToggler(source.getTask(), destination.getTask(), dependencyComponent);
|
||||
|
||||
source.getTask().addVisibilityPropertiesChangeListener(visibilityToggler);
|
||||
destination.getTask().addVisibilityPropertiesChangeListener(visibilityToggler);
|
||||
dependencyComponent.setVisibilityChangeListener(visibilityToggler);
|
||||
boolean dependencyMustBeVisible = visibilityToggler
|
||||
.dependencyMustBeVisible();
|
||||
|
||||
boolean dependencyMustBeVisible = visibilityToggler.dependencyMustBeVisible();
|
||||
visibilityToggler.toggleDependencyExistence(dependencyMustBeVisible);
|
||||
if (dependencyMustBeVisible) {
|
||||
|
||||
if ( dependencyMustBeVisible ) {
|
||||
dependencyComponent.redrawDependency();
|
||||
}
|
||||
}
|
||||
|
||||
private void addContextMenu(DependencyComponent dependencyComponent) {
|
||||
Menupopup contextMenu = dependencyComponent.hasLimitingTasks() ?
|
||||
getLimitingContextMenu()
|
||||
: getContextMenu();
|
||||
Menupopup contextMenu = dependencyComponent.hasLimitingTasks() ? getLimitingContextMenu() : getContextMenu();
|
||||
|
||||
dependencyComponent.setContext(contextMenu);
|
||||
}
|
||||
|
||||
|
|
@ -169,8 +162,7 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
return (GanttPanel) getParent();
|
||||
}
|
||||
|
||||
public void setDependencyComponents(
|
||||
List<DependencyComponent> dependencyComponents) {
|
||||
void setDependencyComponents(List<DependencyComponent> dependencyComponents) {
|
||||
for (DependencyComponent dependencyComponent : dependencyComponents) {
|
||||
addDependencyComponent(dependencyComponent);
|
||||
}
|
||||
|
|
@ -178,11 +170,13 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
|
||||
@Override
|
||||
public void afterCompose() {
|
||||
if (listener == null) {
|
||||
if ( listener == null ) {
|
||||
|
||||
/* Do not replace it with lambda */
|
||||
listener = new IZoomLevelChangedListener() {
|
||||
@Override
|
||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||
if (!isInPage()) {
|
||||
if ( !isInPage() ) {
|
||||
return;
|
||||
}
|
||||
for (DependencyComponent dependencyComponent : getDependencyComponents()) {
|
||||
|
|
@ -190,14 +184,15 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
getTimeTracker().addZoomListener(listener);
|
||||
}
|
||||
|
||||
addContextMenu();
|
||||
}
|
||||
|
||||
private boolean isInPage() {
|
||||
return getParent() != null && getGanttPanel() != null
|
||||
&& getGanttPanel().getParent() != null;
|
||||
return getParent() != null && getGanttPanel() != null && getGanttPanel().getParent() != null;
|
||||
}
|
||||
|
||||
private TimeTracker getTimeTracker() {
|
||||
|
|
@ -211,54 +206,39 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
}
|
||||
|
||||
private Menupopup getLimitingContextMenu() {
|
||||
if (limitingContextMenu == null) {
|
||||
MenuBuilder<DependencyComponent> contextMenuBuilder = MenuBuilder
|
||||
.on(getPage(), getDependencyComponents()).item(_("Erase"),
|
||||
if ( limitingContextMenu == null ) {
|
||||
|
||||
MenuBuilder<DependencyComponent> contextMenuBuilder =
|
||||
MenuBuilder.on(getPage(), getDependencyComponents()).item(
|
||||
_("Erase"),
|
||||
"/common/img/ico_borrar.png",
|
||||
new ItemAction<DependencyComponent>() {
|
||||
@Override
|
||||
public void onEvent(
|
||||
final DependencyComponent choosen,
|
||||
Event event) {
|
||||
context
|
||||
.removeDependency(choosen.getDependency());
|
||||
}
|
||||
});
|
||||
(chosen, event) -> context.removeDependency(chosen.getDependency()));
|
||||
|
||||
limitingContextMenu = contextMenuBuilder.create();
|
||||
}
|
||||
|
||||
return limitingContextMenu;
|
||||
}
|
||||
|
||||
private Menupopup getContextMenu() {
|
||||
if (contextMenu == null) {
|
||||
MenuBuilder<DependencyComponent> contextMenuBuilder = MenuBuilder
|
||||
.on(getPage(), getDependencyComponents()).item(_("Erase"),
|
||||
if ( contextMenu == null ) {
|
||||
|
||||
MenuBuilder<DependencyComponent> contextMenuBuilder =
|
||||
MenuBuilder.on(getPage(), getDependencyComponents()).item(
|
||||
_("Erase"),
|
||||
"/common/img/ico_borrar.png",
|
||||
new ItemAction<DependencyComponent>() {
|
||||
@Override
|
||||
public void onEvent(
|
||||
final DependencyComponent choosen,
|
||||
Event event) {
|
||||
context
|
||||
.removeDependency(choosen.getDependency());
|
||||
}
|
||||
});
|
||||
((chosen, event) -> context.removeDependency(chosen.getDependency())));
|
||||
|
||||
contextMenuBuilder.item(_("Set End-Start"), null,
|
||||
new ChangeTypeAction(
|
||||
DependencyType.END_START));
|
||||
contextMenuBuilder.item(_("Set End-Start"), null, new ChangeTypeAction(DependencyType.END_START));
|
||||
|
||||
contextMenuBuilder.item(_("Set Start-Start"), null,
|
||||
new ChangeTypeAction(
|
||||
DependencyType.START_START));
|
||||
contextMenuBuilder.item(_("Set Start-Start"), null, new ChangeTypeAction(DependencyType.START_START));
|
||||
|
||||
contextMenuBuilder.item(_("Set End-End"), null,
|
||||
new ChangeTypeAction(
|
||||
DependencyType.END_END));
|
||||
contextMenuBuilder.item(_("Set End-End"), null, new ChangeTypeAction(DependencyType.END_END));
|
||||
|
||||
contextMenu = contextMenuBuilder.create();
|
||||
|
||||
}
|
||||
|
||||
return contextMenu;
|
||||
}
|
||||
|
||||
|
|
@ -266,48 +246,45 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
return getGanttPanel().getTimeTrackerComponent();
|
||||
}
|
||||
|
||||
public void redrawDependencies() {
|
||||
void redrawDependencies() {
|
||||
redrawDependencyComponents(getDependencyComponents());
|
||||
}
|
||||
|
||||
public void redrawDependencyComponents(
|
||||
List<DependencyComponent> dependencyComponents) {
|
||||
private void redrawDependencyComponents(List<DependencyComponent> dependencyComponents) {
|
||||
for (DependencyComponent dependencyComponent : dependencyComponents) {
|
||||
dependencyComponent.redrawDependency();
|
||||
}
|
||||
}
|
||||
|
||||
public void taskRemoved(Task task) {
|
||||
for (DependencyComponent dependencyComponent : DependencyList.this
|
||||
.getDependencyComponents()) {
|
||||
if (dependencyComponent.contains(task)) {
|
||||
void taskRemoved(Task task) {
|
||||
for (DependencyComponent dependencyComponent : DependencyList.this.getDependencyComponents()) {
|
||||
if ( dependencyComponent.contains(task) ) {
|
||||
removeDependencyComponent(dependencyComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(Dependency dependency) {
|
||||
for (DependencyComponent dependencyComponent : DependencyList.this
|
||||
.getDependencyComponents()) {
|
||||
if (dependencyComponent.hasSameSourceAndDestination(dependency)) {
|
||||
for (DependencyComponent dependencyComponent : DependencyList.this.getDependencyComponents()) {
|
||||
if ( dependencyComponent.hasSameSourceAndDestination(dependency) ) {
|
||||
removeDependencyComponent(dependencyComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeDependencyComponent(DependencyComponent dependencyComponent) {
|
||||
//remove the visibility listener attached to the tasks
|
||||
// Remove the visibility listener attached to the tasks
|
||||
TaskComponent source = dependencyComponent.getSource();
|
||||
TaskComponent destination = dependencyComponent.getDestination();
|
||||
PropertyChangeListener listener =
|
||||
dependencyComponent.getVisibilityChangeListener();
|
||||
PropertyChangeListener listener = dependencyComponent.getVisibilityChangeListener();
|
||||
|
||||
source.getTask().removeVisibilityPropertiesChangeListener(listener);
|
||||
destination.getTask().removeVisibilityPropertiesChangeListener(listener);
|
||||
|
||||
//remove other change listeners
|
||||
// Remove other change listeners
|
||||
dependencyComponent.removeChangeListeners();
|
||||
|
||||
//remove the dependency itself
|
||||
// Remove the dependency itself
|
||||
this.removeChild(dependencyComponent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ import org.zkoss.ganttz.data.TaskLeaf;
|
|||
import org.zkoss.ganttz.data.criticalpath.CriticalPathCalculator;
|
||||
import org.zkoss.ganttz.extensions.IContext;
|
||||
import org.zkoss.ganttz.timetracker.TimeTracker;
|
||||
import org.zkoss.ganttz.timetracker.zoom.IDetailItemModificator;
|
||||
import org.zkoss.ganttz.timetracker.zoom.IDetailItemModifier;
|
||||
import org.zkoss.ganttz.timetracker.zoom.TimeTrackerState;
|
||||
import org.zkoss.ganttz.util.Interval;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
|
|
@ -174,11 +174,17 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
}
|
||||
|
||||
private final Planner planner;
|
||||
|
||||
private final IAdapterToTaskFundamentalProperties<T> adapter;
|
||||
|
||||
private final IStructureNavigator<T> navigator;
|
||||
private final OneToOneMapper<T> mapper = new OneToOneMapper<T>();
|
||||
|
||||
private final OneToOneMapper<T> mapper = new OneToOneMapper<>();
|
||||
|
||||
private final GanttZKDiagramGraph diagramGraph;
|
||||
|
||||
private TimeTracker timeTracker;
|
||||
|
||||
private final PlannerConfiguration<T> configuration;
|
||||
|
||||
public FunctionalityExposedForExtensions(
|
||||
|
|
@ -190,8 +196,8 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
this.navigator = configuration.getNavigator();
|
||||
this.diagramGraph = diagramGraph;
|
||||
|
||||
final IDetailItemModificator firstLevelModificators = configuration.getFirstLevelModificators();
|
||||
final IDetailItemModificator secondLevelModificators = configuration.getSecondLevelModificators();
|
||||
final IDetailItemModifier firstLevelModifiers = configuration.getFirstLevelModifiers();
|
||||
final IDetailItemModifier secondLevelModifiers = configuration.getSecondLevelModifiers();
|
||||
|
||||
Calendar calendarRightNow = Calendar.getInstance();
|
||||
LocalDate localDateRightNow = LocalDate.fromCalendarFields(calendarRightNow);
|
||||
|
|
@ -201,19 +207,18 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
this.timeTracker = new TimeTracker(
|
||||
new Interval(TimeTrackerState.year(initDate.getYear()), TimeTrackerState.year(endDate.getYear())),
|
||||
planner.getZoomLevel(),
|
||||
firstLevelModificators,
|
||||
secondLevelModificators,
|
||||
firstLevelModifiers,
|
||||
secondLevelModifiers,
|
||||
planner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param insertionPosition the position in which to register the task at top level.
|
||||
* @param position the position in which to register the task at top level.
|
||||
* It can be <code>null</code>
|
||||
* @param accumulatedDependencies
|
||||
* @param data
|
||||
* @param parent
|
||||
*
|
||||
* @return
|
||||
* @return {@link Task}
|
||||
*/
|
||||
private Task buildAndRegister(Position position, List<DomainDependency<T>> accumulatedDependencies, T data) {
|
||||
accumulatedDependencies.addAll(adapter.getOutcomingDependencies(data));
|
||||
|
|
@ -226,8 +231,7 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
int i = 0;
|
||||
|
||||
for (T child : navigator.getChildren(data)) {
|
||||
container.add(buildAndRegister(position.down(container, i),
|
||||
accumulatedDependencies, child));
|
||||
container.add(buildAndRegister(position.down(container, i), accumulatedDependencies, child));
|
||||
i++;
|
||||
}
|
||||
|
||||
|
|
@ -349,9 +353,8 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
private DomainDependency<T> toDomainDependency(Dependency bean) {
|
||||
T source = mapper.findAssociatedDomainObject(bean.getSource());
|
||||
T destination = mapper.findAssociatedDomainObject(bean.getDestination());
|
||||
DomainDependency<T> dep = DomainDependency.createDependency(source, destination, bean.getType());
|
||||
|
||||
return dep;
|
||||
return DomainDependency.createDependency(source, destination, bean.getType());
|
||||
}
|
||||
|
||||
public void addDependency(Dependency dependency) {
|
||||
|
|
@ -383,9 +386,8 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Substitutes the dependency for a new one with the same source and
|
||||
* destination but with the specified type. If the new dependency cannot be
|
||||
* added, the old one remains.
|
||||
* Substitutes the dependency for a new one with the same source and destination but with the specified type.
|
||||
* If the new dependency cannot be added, the old one remains.
|
||||
*
|
||||
* @param dependency
|
||||
* @param type
|
||||
|
|
|
|||
|
|
@ -60,56 +60,60 @@ public class GanttPanel extends XulElement implements AfterCompose {
|
|||
CommandOnTaskContextualized<?> doubleClickCommand,
|
||||
IDisabilityConfiguration disabilityConfiguration,
|
||||
FilterAndParentExpandedPredicates predicate) {
|
||||
|
||||
this.planner = planner;
|
||||
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner
|
||||
.getContext();
|
||||
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner.getContext();
|
||||
|
||||
if (planner.isShowingCriticalPath()) {
|
||||
context.showCriticalPath();
|
||||
}
|
||||
|
||||
this.diagramGraph = context.getDiagramGraph();
|
||||
timeTrackerComponent = timeTrackerForGanttPanel(context
|
||||
.getTimeTracker());
|
||||
timeTrackerComponent = timeTrackerForGanttPanel(context.getTimeTracker());
|
||||
|
||||
appendChild(timeTrackerComponent);
|
||||
dependencyList = new DependencyList(context);
|
||||
tasksLists = TaskList.createFor(context, doubleClickCommand,
|
||||
commandsOnTasksContextualized, disabilityConfiguration,
|
||||
predicate);
|
||||
|
||||
tasksLists = TaskList.createFor(
|
||||
context, doubleClickCommand, commandsOnTasksContextualized, disabilityConfiguration, predicate);
|
||||
|
||||
appendChild(tasksLists);
|
||||
appendChild(dependencyList);
|
||||
}
|
||||
|
||||
private TimeTrackerComponent timeTrackerForGanttPanel(
|
||||
TimeTracker timeTracker) {
|
||||
private TimeTrackerComponent timeTrackerForGanttPanel(TimeTracker timeTracker) {
|
||||
return new TimeTrackerComponent(timeTracker) {
|
||||
@Override
|
||||
protected void scrollHorizontalPercentage(int daysDisplacement) {
|
||||
response("scroll_horizontal", new AuInvoke(GanttPanel.this,
|
||||
"scroll_horizontal", "" + daysDisplacement));
|
||||
|
||||
response(
|
||||
"scroll_horizontal",
|
||||
new AuInvoke(GanttPanel.this, "scroll_horizontal", Integer.toString(daysDisplacement)));
|
||||
|
||||
moveCurrentPositionScroll();
|
||||
}
|
||||
|
||||
// FIXME: this is quite awful, it should be simple
|
||||
@Override
|
||||
protected void moveCurrentPositionScroll() {
|
||||
// get the previous data.
|
||||
// Get the previous data.
|
||||
LocalDate previousStart = getPreviousStart();
|
||||
|
||||
// get the current data
|
||||
int diffDays = getTimeTrackerComponent().getDiffDays(
|
||||
previousStart);
|
||||
// Get the current data
|
||||
int diffDays = getTimeTrackerComponent().getDiffDays(previousStart);
|
||||
double pixelPerDay = getTimeTrackerComponent().getPixelPerDay();
|
||||
|
||||
response("move_scroll", new AuInvoke(GanttPanel.this,
|
||||
"move_scroll", "" + diffDays, "" + pixelPerDay));
|
||||
response("move_scroll", new AuInvoke(GanttPanel.this, "move_scroll",
|
||||
Integer.toString(diffDays),
|
||||
Double.toString(pixelPerDay)));
|
||||
}
|
||||
|
||||
protected void updateCurrentDayScroll() {
|
||||
double previousPixelPerDay = getTimeTracker().getMapper()
|
||||
.getPixelsPerDay()
|
||||
.doubleValue();
|
||||
double previousPixelPerDay = getTimeTracker().getMapper().getPixelsPerDay().doubleValue();
|
||||
|
||||
response("update_day_scroll", new AuInvoke(GanttPanel.this,
|
||||
"update_day_scroll", "" + previousPixelPerDay));
|
||||
response(
|
||||
"update_day_scroll",
|
||||
new AuInvoke(GanttPanel.this, "update_day_scroll", Double.toString(previousPixelPerDay)));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -119,14 +123,16 @@ public class GanttPanel extends XulElement implements AfterCompose {
|
|||
@Override
|
||||
public void afterCompose() {
|
||||
tasksLists.afterCompose();
|
||||
dependencyList.setDependencyComponents(tasksLists
|
||||
.asDependencyComponents(diagramGraph.getVisibleDependencies()));
|
||||
|
||||
dependencyList.setDependencyComponents(
|
||||
tasksLists.asDependencyComponents(diagramGraph.getVisibleDependencies()));
|
||||
|
||||
timeTrackerComponent.afterCompose();
|
||||
dependencyList.afterCompose();
|
||||
savePreviousData();
|
||||
|
||||
if (planner.isExpandAll()) {
|
||||
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner
|
||||
.getContext();
|
||||
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner.getContext();
|
||||
context.expandAll();
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +147,7 @@ public class GanttPanel extends XulElement implements AfterCompose {
|
|||
for (Task task : this.tasksLists.getAllTasks()) {
|
||||
task.updateTooltipText();
|
||||
}
|
||||
|
||||
for (TaskComponent taskComponent : this.tasksLists.getTaskComponents()) {
|
||||
taskComponent.invalidate();
|
||||
}
|
||||
|
|
@ -195,12 +202,7 @@ public class GanttPanel extends XulElement implements AfterCompose {
|
|||
|
||||
private void registerZoomLevelChangedListener() {
|
||||
if (zoomLevelChangedListener == null) {
|
||||
zoomLevelChangedListener = new IZoomLevelChangedListener() {
|
||||
@Override
|
||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||
adjustZoomColumnsHeight();
|
||||
}
|
||||
};
|
||||
zoomLevelChangedListener = detailLevel -> adjustZoomColumnsHeight();
|
||||
getTimeTracker().addZoomListener(zoomLevelChangedListener);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import org.zkoss.ganttz.util.Interval;
|
|||
|
||||
public interface IDatesMapper {
|
||||
|
||||
final long MILISECONDS_PER_HOUR = 3600000;
|
||||
long MILISECONDS_PER_HOUR = 3600000;
|
||||
|
||||
int toPixels(LocalDate date);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,14 +31,13 @@ import org.zkoss.zk.ui.Component;
|
|||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||
|
||||
/**
|
||||
* LeftPane of the planner. Responsible of showing global commands and the
|
||||
* leftTasksTree <br />
|
||||
* LeftPane of the planner. Responsible of showing global commands and the leftTasksTree
|
||||
* <br />
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*/
|
||||
public class LeftPane extends HtmlMacroComponent {
|
||||
|
||||
private final List<Task> topLevelTasks;
|
||||
|
||||
private LeftTasksTree leftTasksTree;
|
||||
|
||||
private final IDisabilityConfiguration disabilityConfiguration;
|
||||
|
|
@ -47,16 +46,14 @@ public class LeftPane extends HtmlMacroComponent {
|
|||
|
||||
private Planner planner;
|
||||
|
||||
public void setGoingDownInLastArrowCommand(
|
||||
CommandContextualized<?> goingDownInLastArrowCommand) {
|
||||
this.leftTasksTree
|
||||
.setGoingDownInLastArrowCommand(goingDownInLastArrowCommand);
|
||||
public void setGoingDownInLastArrowCommand(CommandContextualized<?> goingDownInLastArrowCommand) {
|
||||
this.leftTasksTree.setGoingDownInLastArrowCommand(goingDownInLastArrowCommand);
|
||||
}
|
||||
|
||||
public LeftPane(IDisabilityConfiguration disabilityConfiguration,
|
||||
Planner planner,
|
||||
FilterAndParentExpandedPredicates predicate) {
|
||||
this.topLevelTasks = planner.getDiagramGraph().getTopLevelTasks();
|
||||
Planner planner,
|
||||
FilterAndParentExpandedPredicates predicate) {
|
||||
|
||||
this.disabilityConfiguration = disabilityConfiguration;
|
||||
this.predicate = predicate;
|
||||
this.planner = planner;
|
||||
|
|
@ -65,15 +62,14 @@ public class LeftPane extends HtmlMacroComponent {
|
|||
@Override
|
||||
public void afterCompose() {
|
||||
super.afterCompose();
|
||||
leftTasksTree = new LeftTasksTree(disabilityConfiguration, planner,
|
||||
predicate);
|
||||
|
||||
leftTasksTree = new LeftTasksTree(disabilityConfiguration, planner, predicate);
|
||||
getContainer().appendChild(leftTasksTree);
|
||||
leftTasksTree.afterCompose();
|
||||
}
|
||||
|
||||
private Component getContainer() {
|
||||
Component container = getFellow("listdetails_container");
|
||||
return container;
|
||||
return getFellow("listdetails_container");
|
||||
}
|
||||
|
||||
public void taskRemoved(Task task) {
|
||||
|
|
|
|||
|
|
@ -23,39 +23,32 @@ package org.zkoss.ganttz;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.zkoss.ganttz.LeftTasksTreeRow.ILeftTasksTreeNavigator;
|
||||
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
||||
import org.zkoss.ganttz.data.Position;
|
||||
import org.zkoss.ganttz.data.Task;
|
||||
import org.zkoss.ganttz.data.TaskContainer;
|
||||
import org.zkoss.ganttz.data.TaskContainer.IExpandListener;
|
||||
import org.zkoss.ganttz.util.ComponentsFinder;
|
||||
import org.zkoss.ganttz.util.MutableTreeModel;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.OpenEvent;
|
||||
import org.zkoss.zul.Tree;
|
||||
import org.zkoss.zul.TreeModel;
|
||||
import org.zkoss.zul.Treecell;
|
||||
import org.zkoss.zul.Treeitem;
|
||||
import org.zkoss.zul.TreeitemRenderer;
|
||||
|
||||
/**
|
||||
* Tree element to display tasks structure in the planning Gantt <br />
|
||||
* Tree element to display tasks structure in the planning Gantt.
|
||||
* <br />
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
|
|
@ -63,258 +56,8 @@ import org.zkoss.zul.TreeitemRenderer;
|
|||
*/
|
||||
public class LeftTasksTree extends HtmlMacroComponent {
|
||||
|
||||
private final class TaskBeanRenderer implements TreeitemRenderer {
|
||||
private Map<TaskContainer, IExpandListener> expandListeners = new HashMap<TaskContainer, IExpandListener>();
|
||||
|
||||
public void render(final Treeitem item, Object data) throws Exception {
|
||||
Task task = (Task) data;
|
||||
item.setOpen(isOpened(task));
|
||||
|
||||
if ( task instanceof TaskContainer ) {
|
||||
|
||||
final TaskContainer container = (TaskContainer) task;
|
||||
|
||||
IExpandListener expandListener = new IExpandListener() {
|
||||
|
||||
@Override
|
||||
public void expandStateChanged(boolean isNowExpanded) {
|
||||
item.setOpen(isNowExpanded);
|
||||
}
|
||||
};
|
||||
|
||||
expandListeners.put(container, expandListener);
|
||||
container.addExpandListener(expandListener);
|
||||
|
||||
}
|
||||
LeftTasksTreeRow leftTasksTreeRow = LeftTasksTreeRow
|
||||
.create(disabilityConfiguration, task, new TreeNavigator(tasksTreeModel, task), planner);
|
||||
|
||||
if ( task.isContainer() ) {
|
||||
expandWhenOpened((TaskContainer) task, item);
|
||||
}
|
||||
Component row;
|
||||
if ( disabilityConfiguration.isTreeEditable() ) {
|
||||
row = Executions.getCurrent().createComponents(
|
||||
"~./ganttz/zul/leftTasksTreeRow.zul", item, null);
|
||||
} else {
|
||||
row = Executions.getCurrent().createComponents(
|
||||
"~./ganttz/zul/leftTasksTreeRowLabels.zul", item, null);
|
||||
}
|
||||
leftTasksTreeRow.doAfterCompose(row);
|
||||
detailsForBeans.put(task, leftTasksTreeRow);
|
||||
deferredFiller.isBeingRendered(task, item);
|
||||
}
|
||||
|
||||
private void expandWhenOpened(final TaskContainer taskBean, Treeitem item) {
|
||||
item.addEventListener("onOpen", new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
OpenEvent openEvent = (OpenEvent) event;
|
||||
taskBean.setExpanded(openEvent.isOpen());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isOpened(Task task) {
|
||||
return task.isLeaf() || task.isExpanded();
|
||||
}
|
||||
|
||||
private static final class DetailsForBeans {
|
||||
|
||||
private Map<Task, LeftTasksTreeRow> map = new HashMap<Task, LeftTasksTreeRow>();
|
||||
|
||||
private Set<Task> focusRequested = new HashSet<Task>();
|
||||
|
||||
public void put(Task task, LeftTasksTreeRow leftTasksTreeRow) {
|
||||
map.put(task, leftTasksTreeRow);
|
||||
if (focusRequested.contains(task)) {
|
||||
focusRequested.remove(task);
|
||||
leftTasksTreeRow.receiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
public void requestFocusFor(Task task) {
|
||||
focusRequested.add(task);
|
||||
}
|
||||
|
||||
public LeftTasksTreeRow get(Task taskbean) {
|
||||
return map.get(taskbean);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private DetailsForBeans detailsForBeans = new DetailsForBeans();
|
||||
|
||||
private final class TreeNavigator implements ILeftTasksTreeNavigator {
|
||||
private final int[] pathToNode;
|
||||
private final Task task;
|
||||
|
||||
private TreeNavigator(TreeModel treemodel, Task task) {
|
||||
this.task = task;
|
||||
this.pathToNode = tasksTreeModel.getPath(tasksTreeModel.getRoot(),
|
||||
task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeftTasksTreeRow getAboveRow() {
|
||||
Task parent = getParent(pathToNode);
|
||||
int lastPosition = pathToNode[pathToNode.length - 1];
|
||||
if (lastPosition != 0) {
|
||||
return getChild(parent, lastPosition - 1);
|
||||
} else if (tasksTreeModel.getRoot() != parent) {
|
||||
return getDetailFor(parent);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private LeftTasksTreeRow getChild(Task parent, int position) {
|
||||
Task child = tasksTreeModel.getChild(parent, position);
|
||||
return getDetailFor(child);
|
||||
}
|
||||
|
||||
private LeftTasksTreeRow getDetailFor(Task child) {
|
||||
return detailsForBeans.get(child);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeftTasksTreeRow getBelowRow() {
|
||||
if (isExpanded() && hasChildren()) {
|
||||
return getChild(task, 0);
|
||||
}
|
||||
for (ChildAndParent childAndParent : group(task, tasksTreeModel
|
||||
.getParents(task))) {
|
||||
if (childAndParent.childIsNotLast()) {
|
||||
return getDetailFor(childAndParent.getNextToChild());
|
||||
}
|
||||
}
|
||||
// it's the last one, it has none below
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ChildAndParent> group(Task origin, List<Task> parents) {
|
||||
ArrayList<ChildAndParent> result = new ArrayList<ChildAndParent>();
|
||||
Task child = origin;
|
||||
Task parent;
|
||||
ListIterator<Task> listIterator = parents.listIterator();
|
||||
while (listIterator.hasNext()) {
|
||||
parent = listIterator.next();
|
||||
result.add(new ChildAndParent(child, parent));
|
||||
child = parent;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private class ChildAndParent {
|
||||
private final Task parent;
|
||||
|
||||
private final Task child;
|
||||
|
||||
private Integer positionOfChildCached;
|
||||
|
||||
private ChildAndParent(Task child, Task parent) {
|
||||
this.parent = parent;
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
public Task getNextToChild() {
|
||||
return tasksTreeModel
|
||||
.getChild(parent, getPositionOfChild() + 1);
|
||||
}
|
||||
|
||||
public boolean childIsNotLast() {
|
||||
return getPositionOfChild() < numberOfChildrenForParent() - 1;
|
||||
}
|
||||
|
||||
private int numberOfChildrenForParent() {
|
||||
return tasksTreeModel.getChildCount(parent);
|
||||
}
|
||||
|
||||
private int getPositionOfChild() {
|
||||
if (positionOfChildCached != null) {
|
||||
return positionOfChildCached;
|
||||
}
|
||||
int[] path = tasksTreeModel.getPath(parent, child);
|
||||
return positionOfChildCached = path[path.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasChildren() {
|
||||
return task.isContainer() && task.getTasks().size() > 0;
|
||||
}
|
||||
|
||||
private boolean isExpanded() {
|
||||
return task.isContainer() && task.isExpanded();
|
||||
}
|
||||
|
||||
private Task getParent(int[] path) {
|
||||
Task current = tasksTreeModel.getRoot();
|
||||
for (int i = 0; i < path.length - 1; i++) {
|
||||
current = tasksTreeModel.getChild(current, path[i]);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is a workaround for an issue with zk {@link Tree}. Once the
|
||||
* tree is created, adding a node with children is troublesome. Only the top
|
||||
* element is added to the tree, although the element has children. The Tree
|
||||
* discards the adding event for the children because the parent says it's
|
||||
* not loaded. This is the condition that is not satisfied:<br />
|
||||
* <code>if(parent != null &&
|
||||
(!(parent instanceof Treeitem) || ((Treeitem)parent).isLoaded())){</code><br />
|
||||
* This problem is present in zk 3.6.1 at least.
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @see Tree#onTreeDataChange
|
||||
*/
|
||||
private class DeferredFiller {
|
||||
|
||||
private Set<Task> pendingToAddChildren = new HashSet<Task>();
|
||||
|
||||
public void addParentOfPendingToAdd(Task parent) {
|
||||
pendingToAddChildren.add(parent);
|
||||
}
|
||||
|
||||
public void isBeingRendered(final Task parent, final Treeitem item) {
|
||||
if (!pendingToAddChildren.contains(parent)) {
|
||||
return;
|
||||
}
|
||||
markLoaded(item);
|
||||
fillModel(parent, 0, parent.getTasks(), false);
|
||||
pendingToAddChildren.remove(parent);
|
||||
}
|
||||
|
||||
private void markLoaded(Treeitem item) {
|
||||
try {
|
||||
Method method = getSetLoadedMethod();
|
||||
method.invoke(item, true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Method setLoadedMethod = null;
|
||||
|
||||
private Method getSetLoadedMethod() {
|
||||
if (setLoadedMethod != null) {
|
||||
return setLoadedMethod;
|
||||
}
|
||||
try {
|
||||
Method method = Treeitem.class.getDeclaredMethod("setLoaded",
|
||||
Boolean.TYPE);
|
||||
method.setAccessible(true);
|
||||
return setLoadedMethod = method;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Log LOG = LogFactory.getLog(LeftTasksTree.class);
|
||||
|
||||
private final DeferredFiller deferredFiller = new DeferredFiller();
|
||||
|
||||
private final List<Task> tasks;
|
||||
|
|
@ -329,67 +72,376 @@ public class LeftTasksTree extends HtmlMacroComponent {
|
|||
|
||||
private FilterAndParentExpandedPredicates predicate;
|
||||
|
||||
private final List<Task> visibleTasks = new ArrayList<Task>();
|
||||
private final List<Task> visibleTasks = new ArrayList<>();
|
||||
|
||||
private Planner planner;
|
||||
|
||||
public LeftTasksTree(IDisabilityConfiguration disabilityConfiguration,
|
||||
Planner planner,
|
||||
FilterAndParentExpandedPredicates predicate) {
|
||||
Planner planner,
|
||||
FilterAndParentExpandedPredicates predicate) {
|
||||
|
||||
this.disabilityConfiguration = disabilityConfiguration;
|
||||
this.tasks = planner.getTaskList().getAllTasks();
|
||||
this.predicate = predicate;
|
||||
this.planner = planner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompose() {
|
||||
setClass("listdetails");
|
||||
super.afterCompose();
|
||||
tasksTree = (Tree) getFellow("tasksTree");
|
||||
tasksTreeModel = MutableTreeModel.create(Task.class);
|
||||
fillModel(tasks, true);
|
||||
tasksTree.setModel(tasksTreeModel);
|
||||
tasksTree.setItemRenderer(getTaskBeanRenderer());
|
||||
|
||||
/* Force call overridden render() */
|
||||
try {
|
||||
if ( !tasks.isEmpty() ) {
|
||||
getTaskBeanRenderer().render(new Treeitem(""), tasks.get(0), 0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class TaskBeanRenderer implements TreeitemRenderer<Task> {
|
||||
@Override
|
||||
public void render(final Treeitem treeitem, Task o, int i) throws Exception {
|
||||
Task task = o;
|
||||
treeitem.setOpen(isOpened(task));
|
||||
|
||||
if ( task instanceof TaskContainer ) {
|
||||
|
||||
final TaskContainer container = (TaskContainer) task;
|
||||
|
||||
IExpandListener expandListener = new IExpandListener() {
|
||||
@Override
|
||||
public void expandStateChanged(boolean isNowExpanded) {
|
||||
treeitem.setOpen(isNowExpanded);
|
||||
}
|
||||
};
|
||||
|
||||
container.addExpandListener(expandListener);
|
||||
|
||||
}
|
||||
|
||||
LeftTasksTreeRow leftTasksTreeRow =
|
||||
LeftTasksTreeRow.create(disabilityConfiguration, task, new TreeNavigator(task), planner);
|
||||
|
||||
if ( task.isContainer() ) {
|
||||
expandWhenOpened((TaskContainer) task, treeitem);
|
||||
}
|
||||
|
||||
/* Clear existing Treerows */
|
||||
if ( !treeitem.getChildren().isEmpty() ) {
|
||||
treeitem.getChildren().clear();
|
||||
}
|
||||
|
||||
Component row = disabilityConfiguration.isTreeEditable()
|
||||
? Executions
|
||||
.getCurrent()
|
||||
.createComponents("~./ganttz/zul/leftTasksTreeRow.zul", treeitem, null)
|
||||
: Executions
|
||||
.getCurrent()
|
||||
.createComponents("~./ganttz/zul/leftTasksTreeRowLabels.zul", treeitem, null);
|
||||
|
||||
leftTasksTreeRow.doAfterCompose(row);
|
||||
detailsForBeans.put(task, leftTasksTreeRow);
|
||||
deferredFiller.isBeingRendered(task, treeitem);
|
||||
}
|
||||
|
||||
private void expandWhenOpened(final TaskContainer taskBean, Treeitem item) {
|
||||
item.addEventListener("onOpen", event -> {
|
||||
OpenEvent openEvent = (OpenEvent) event;
|
||||
taskBean.setExpanded(openEvent.isOpen());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private TaskBeanRenderer getTaskBeanRenderer() {
|
||||
return new TaskBeanRenderer();
|
||||
}
|
||||
|
||||
public boolean isOpened(Task task) {
|
||||
return task.isLeaf() || task.isExpanded();
|
||||
}
|
||||
|
||||
private static final class DetailsForBeans {
|
||||
|
||||
private Map<Task, LeftTasksTreeRow> map = new HashMap<>();
|
||||
|
||||
private Set<Task> focusRequested = new HashSet<>();
|
||||
|
||||
public void put(Task task, LeftTasksTreeRow leftTasksTreeRow) {
|
||||
map.put(task, leftTasksTreeRow);
|
||||
|
||||
if ( focusRequested.contains(task) ) {
|
||||
focusRequested.remove(task);
|
||||
leftTasksTreeRow.receiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
public void requestFocusFor(Task task) {
|
||||
focusRequested.add(task);
|
||||
}
|
||||
|
||||
public LeftTasksTreeRow get(Task taskbean) {
|
||||
return map.get(taskbean);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class TreeNavigator implements ILeftTasksTreeNavigator {
|
||||
|
||||
private final int[] pathToNode;
|
||||
|
||||
private final Task task;
|
||||
|
||||
private TreeNavigator(Task task) {
|
||||
this.task = task;
|
||||
this.pathToNode = tasksTreeModel.getPath(tasksTreeModel.getRoot(), task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeftTasksTreeRow getAboveRow() {
|
||||
Task parent = getParent(pathToNode);
|
||||
int lastPosition = pathToNode[pathToNode.length - 1];
|
||||
|
||||
if ( lastPosition != 0 ) {
|
||||
return getChild(parent, lastPosition - 1);
|
||||
} else if ( tasksTreeModel.getRoot() != parent ) {
|
||||
return getDetailFor(parent);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private LeftTasksTreeRow getChild(Task parent, int position) {
|
||||
return getDetailFor(tasksTreeModel.getChild(parent, position));
|
||||
}
|
||||
|
||||
private LeftTasksTreeRow getDetailFor(Task child) {
|
||||
return detailsForBeans.get(child);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeftTasksTreeRow getBelowRow() {
|
||||
if ( isExpanded() && hasChildren() ) {
|
||||
return getChild(task, 0);
|
||||
}
|
||||
|
||||
for (ChildAndParent childAndParent : group(task, tasksTreeModel.getParents(task))) {
|
||||
if ( childAndParent.childIsNotLast() ) {
|
||||
return getDetailFor(childAndParent.getNextToChild());
|
||||
}
|
||||
}
|
||||
|
||||
// It's the last one, it has none below
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ChildAndParent> group(Task origin, List<Task> parents) {
|
||||
ArrayList<ChildAndParent> result = new ArrayList<>();
|
||||
Task child = origin;
|
||||
|
||||
for (Task parent : parents) {
|
||||
result.add(new ChildAndParent(child, parent));
|
||||
child = parent;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private class ChildAndParent {
|
||||
|
||||
private final Task parent;
|
||||
|
||||
private final Task child;
|
||||
|
||||
private Integer positionOfChildCached;
|
||||
|
||||
private ChildAndParent(Task child, Task parent) {
|
||||
this.parent = parent;
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
public Task getNextToChild() {
|
||||
return tasksTreeModel.getChild(parent, getPositionOfChild() + 1);
|
||||
}
|
||||
|
||||
public boolean childIsNotLast() {
|
||||
return getPositionOfChild() < numberOfChildrenForParent() - 1;
|
||||
}
|
||||
|
||||
private int numberOfChildrenForParent() {
|
||||
return tasksTreeModel.getChildCount(parent);
|
||||
}
|
||||
|
||||
private int getPositionOfChild() {
|
||||
if ( positionOfChildCached != null ) {
|
||||
return positionOfChildCached;
|
||||
}
|
||||
|
||||
int[] path = tasksTreeModel.getPath(parent, child);
|
||||
|
||||
positionOfChildCached = path[path.length - 1];
|
||||
|
||||
return positionOfChildCached;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasChildren() {
|
||||
return task.isContainer() && !task.getTasks().isEmpty();
|
||||
}
|
||||
|
||||
private boolean isExpanded() {
|
||||
return task.isContainer() && task.isExpanded();
|
||||
}
|
||||
|
||||
private Task getParent(int[] path) {
|
||||
Task current = tasksTreeModel.getRoot();
|
||||
|
||||
for (int i = 0; i < path.length - 1; i++) {
|
||||
current = tasksTreeModel.getChild(current, path[i]);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is a workaround for an issue with zk {@link Tree}.
|
||||
* Once the tree is created, adding a node with children is troublesome.
|
||||
* Only the top element is added to the tree, although the element has children.
|
||||
* The Tree discards the adding event for the children because the parent says it's not loaded.
|
||||
*
|
||||
* This is the condition that is not satisfied:
|
||||
* <br />
|
||||
* <code>
|
||||
* if( parent != null && (!(parent instanceof Treeitem) || ((Treeitem) parent).isLoaded()) ) {
|
||||
* // ...
|
||||
* }
|
||||
* </code>
|
||||
* <br />
|
||||
*
|
||||
* This problem is present in zk 3.6.1 at least.
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @see Tree#onTreeDataChange
|
||||
*/
|
||||
private class DeferredFiller {
|
||||
|
||||
private Set<Task> pendingToAddChildren = new HashSet<>();
|
||||
|
||||
private Method setLoadedMethod = null;
|
||||
|
||||
public void addParentOfPendingToAdd(Task parent) {
|
||||
pendingToAddChildren.add(parent);
|
||||
}
|
||||
|
||||
public void isBeingRendered(final Task parent, final Treeitem item) {
|
||||
if ( !pendingToAddChildren.contains(parent) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
markLoaded(item);
|
||||
fillModel(parent, 0, parent.getTasks(), false);
|
||||
pendingToAddChildren.remove(parent);
|
||||
}
|
||||
|
||||
private void markLoaded(Treeitem item) {
|
||||
try {
|
||||
Method method = getSetLoadedMethod();
|
||||
method.invoke(item, true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Method getSetLoadedMethod() {
|
||||
if ( setLoadedMethod != null ) {
|
||||
return setLoadedMethod;
|
||||
}
|
||||
|
||||
try {
|
||||
Method method = Treeitem.class.getDeclaredMethod("setLoaded", Boolean.TYPE);
|
||||
method.setAccessible(true);
|
||||
setLoadedMethod = method;
|
||||
|
||||
return setLoadedMethod;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillModel(Collection<? extends Task> tasks, boolean firstTime) {
|
||||
fillModel(this.tasksTreeModel.getRoot(), 0, tasks, firstTime);
|
||||
}
|
||||
|
||||
private void fillModel(Task parent, Integer insertionPosition,
|
||||
Collection<? extends Task> children, final boolean firstTime) {
|
||||
if (predicate.isFilterContainers()) {
|
||||
private void fillModel(Task parent,
|
||||
Integer insertionPosition,
|
||||
Collection<? extends Task> children,
|
||||
final boolean firstTime) {
|
||||
|
||||
if ( predicate.isFilterContainers() ) {
|
||||
parent = this.tasksTreeModel.getRoot();
|
||||
}
|
||||
|
||||
if (firstTime) {
|
||||
if ( firstTime ) {
|
||||
|
||||
for (Task node : children) {
|
||||
if (predicate.accpetsFilterPredicateAndContainers(node)) {
|
||||
if (!visibleTasks.contains(node)) {
|
||||
|
||||
if ( predicate.accpetsFilterPredicateAndContainers(node) ) {
|
||||
|
||||
if ( !visibleTasks.contains(node) ) {
|
||||
this.tasksTreeModel.add(parent, node);
|
||||
visibleTasks.add(node);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (visibleTasks.contains(node)) {
|
||||
|
||||
if ( visibleTasks.contains(node) ) {
|
||||
this.tasksTreeModel.remove(node);
|
||||
visibleTasks.remove(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.isContainer()) {
|
||||
if ( node.isContainer() ) {
|
||||
fillModel(node, 0, node.getTasks(), firstTime);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (Task node : children) {
|
||||
if (node.isContainer()) {
|
||||
if (predicate.accpetsFilterPredicateAndContainers(node)) {
|
||||
if (!visibleTasks.contains(node)) {
|
||||
|
||||
if ( node.isContainer() ) {
|
||||
|
||||
if ( predicate.accpetsFilterPredicateAndContainers(node) ) {
|
||||
|
||||
if ( !visibleTasks.contains(node) ) {
|
||||
this.deferredFiller.addParentOfPendingToAdd(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// the node must be added after, so the multistepTreeFiller is
|
||||
// ready
|
||||
|
||||
// The node must be added after, so the multistepTreeFiller is ready
|
||||
for (Task node : children) {
|
||||
if (predicate.accpetsFilterPredicateAndContainers(node)) {
|
||||
if (!visibleTasks.contains(node)) {
|
||||
this.tasksTreeModel.add(parent, insertionPosition,
|
||||
Arrays.asList(node));
|
||||
|
||||
if ( predicate.accpetsFilterPredicateAndContainers(node) ) {
|
||||
|
||||
if ( !visibleTasks.contains(node) ) {
|
||||
this.tasksTreeModel.add(parent, insertionPosition, Collections.singletonList(node));
|
||||
visibleTasks.add(node);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (visibleTasks.contains(node)) {
|
||||
this.tasksTreeModel.remove(node);
|
||||
|
|
@ -411,7 +463,7 @@ public class LeftTasksTree extends HtmlMacroComponent {
|
|||
private void removeTaskAndAllChildren(List<Task> visibleTasks, Task task) {
|
||||
visibleTasks.remove(task);
|
||||
|
||||
if (task.isContainer()) {
|
||||
if ( task.isContainer() ) {
|
||||
for (Task node : task.getTasks()) {
|
||||
removeTaskAndAllChildren(visibleTasks, node);
|
||||
}
|
||||
|
|
@ -422,38 +474,25 @@ public class LeftTasksTree extends HtmlMacroComponent {
|
|||
tasksTreeModel.remove(taskRemoved);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompose() {
|
||||
setClass("listdetails");
|
||||
super.afterCompose();
|
||||
tasksTree = (Tree) getFellow("tasksTree");
|
||||
tasksTreeModel = MutableTreeModel.create(Task.class);
|
||||
fillModel(tasks, true);
|
||||
tasksTree.setModel(tasksTreeModel);
|
||||
tasksTree.setTreeitemRenderer(new TaskBeanRenderer());
|
||||
}
|
||||
|
||||
void addTask(Position position, Task task) {
|
||||
if (position.isAppendToTop()) {
|
||||
fillModel(Arrays.asList(task), false);
|
||||
if ( position.isAppendToTop() ) {
|
||||
fillModel(Collections.singletonList(task), false);
|
||||
detailsForBeans.requestFocusFor(task);
|
||||
} else {
|
||||
List<Task> toAdd = Arrays.asList(task);
|
||||
fillModel(position.getParent(), position.getInsertionPosition(),
|
||||
toAdd, false);
|
||||
List<Task> toAdd = Collections.singletonList(task);
|
||||
fillModel(position.getParent(), position.getInsertionPosition(), toAdd, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void addTasks(Position position, Collection<? extends Task> newTasks) {
|
||||
Task root = tasksTreeModel.getRoot();
|
||||
if (position.isAppendToTop()) {
|
||||
|
||||
if ( position.isAppendToTop() ) {
|
||||
fillModel(root, tasksTreeModel.getChildCount(root), newTasks, false);
|
||||
} else if (position.isAtTop()) {
|
||||
fillModel(root,
|
||||
position.getInsertionPosition(), newTasks, false);
|
||||
} else if ( position.isAtTop() ) {
|
||||
fillModel(root, position.getInsertionPosition(), newTasks, false);
|
||||
} else {
|
||||
fillModel(position.getParent(), position.getInsertionPosition(),
|
||||
newTasks, false);
|
||||
fillModel(position.getParent(), position.getInsertionPosition(), newTasks, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -461,8 +500,7 @@ public class LeftTasksTree extends HtmlMacroComponent {
|
|||
return goingDownInLastArrowCommand;
|
||||
}
|
||||
|
||||
public void setGoingDownInLastArrowCommand(
|
||||
CommandContextualized<?> goingDownInLastArrowCommand) {
|
||||
public void setGoingDownInLastArrowCommand(CommandContextualized<?> goingDownInLastArrowCommand) {
|
||||
this.goingDownInLastArrowCommand = goingDownInLastArrowCommand;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,16 +39,12 @@ import org.joda.time.DateTime;
|
|||
import org.joda.time.LocalDate;
|
||||
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
||||
import org.zkoss.ganttz.data.GanttDate;
|
||||
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IModifications;
|
||||
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IUpdatablePosition;
|
||||
import org.zkoss.ganttz.data.Task;
|
||||
import org.zkoss.ganttz.util.ComponentsFinder;
|
||||
import org.zkoss.util.Locales;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.WrongValueException;
|
||||
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.KeyEvent;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
|
|
@ -56,10 +52,10 @@ import org.zkoss.zul.Constraint;
|
|||
import org.zkoss.zul.Datebox;
|
||||
import org.zkoss.zul.Textbox;
|
||||
import org.zkoss.zul.Treecell;
|
||||
import org.zkoss.zul.api.Div;
|
||||
import org.zkoss.zul.api.Hlayout;
|
||||
import org.zkoss.zul.api.Label;
|
||||
import org.zkoss.zul.api.Treerow;
|
||||
import org.zkoss.zul.Div;
|
||||
import org.zkoss.zul.Hlayout;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Treerow;
|
||||
|
||||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||
|
||||
|
|
@ -74,6 +70,7 @@ import static org.zkoss.ganttz.i18n.I18nHelper._;
|
|||
public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||
|
||||
public interface ILeftTasksTreeNavigator {
|
||||
|
||||
LeftTasksTreeRow getBelowRow();
|
||||
|
||||
LeftTasksTreeRow getAboveRow();
|
||||
|
|
@ -287,7 +284,11 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
private enum Navigation {
|
||||
LEFT, UP, RIGHT, DOWN;
|
||||
LEFT,
|
||||
UP,
|
||||
RIGHT,
|
||||
DOWN;
|
||||
|
||||
public static Navigation getIntentFrom(KeyEvent keyEvent) {
|
||||
return values()[keyEvent.getKeyCode() - 37];
|
||||
}
|
||||
|
|
@ -332,15 +333,15 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
int position = textBoxes.indexOf(textbox);
|
||||
switch (navigation) {
|
||||
case UP:
|
||||
focusGoUp(position);
|
||||
break;
|
||||
focusGoUp(position);
|
||||
break;
|
||||
|
||||
case DOWN:
|
||||
focusGoDown(position);
|
||||
break;
|
||||
focusGoDown(position);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("case not covered: " + navigation);
|
||||
throw new RuntimeException("case not covered: " + navigation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -394,7 +395,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
private void findComponents(Treerow row) {
|
||||
List<Object> rowChildren = row.getChildren();
|
||||
List<Component> rowChildren = row.getChildren();
|
||||
List<Treecell> treeCells = ComponentsFinder.findComponentsOfType(Treecell.class, rowChildren);
|
||||
assert treeCells.size() == 4;
|
||||
|
||||
|
|
@ -405,7 +406,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
private static Textbox findTextBoxOfCell(Treecell treecell) {
|
||||
List<Object> children = treecell.getChildren();
|
||||
List<Component> children = treecell.getChildren();
|
||||
return ComponentsFinder.findComponentsOfType(Textbox.class, children).get(0);
|
||||
}
|
||||
|
||||
|
|
@ -418,54 +419,26 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
private void registerKeyboardListener(final Textbox textBox) {
|
||||
textBox.addEventListener("onCtrlKey", new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
userWantsToMove(textBox, (KeyEvent) event);
|
||||
}
|
||||
});
|
||||
textBox.addEventListener("onCtrlKey", event -> userWantsToMove(textBox, (KeyEvent) event));
|
||||
}
|
||||
|
||||
private void registerOnChange(final Component component) {
|
||||
component.addEventListener("onChange", new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
updateBean(component);
|
||||
}
|
||||
});
|
||||
component.addEventListener("onChange", event -> updateBean(component));
|
||||
}
|
||||
|
||||
private void registerOnChangeDatebox(final Datebox datebox, final Textbox textbox) {
|
||||
datebox.addEventListener("onChange", new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
textbox.setValue(dateFormat.format(datebox.getValue()));
|
||||
updateBean(textbox);
|
||||
}
|
||||
datebox.addEventListener("onChange", event -> {
|
||||
textbox.setValue(dateFormat.format(datebox.getValue()));
|
||||
updateBean(textbox);
|
||||
});
|
||||
}
|
||||
|
||||
private void registerOnEnterListener(final Textbox textBox) {
|
||||
textBox.addEventListener("onOK", new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
userWantsDateBox(textBox);
|
||||
}
|
||||
});
|
||||
textBox.addEventListener("onOK", event -> userWantsDateBox(textBox));
|
||||
}
|
||||
|
||||
private void registerOnEnterOpenDateBox(final Datebox datebox) {
|
||||
datebox.addEventListener("onOK", new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
datebox.setOpen(true);
|
||||
}
|
||||
});
|
||||
datebox.addEventListener("onOK", event -> datebox.setOpen(true));
|
||||
}
|
||||
|
||||
private void findComponentsForStartDateCell(Treecell treecell) {
|
||||
|
|
@ -485,7 +458,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
private void findComponentsForStatusCell(Treecell treecell) {
|
||||
List<Object> children = treecell.getChildren();
|
||||
List<Component> children = treecell.getChildren();
|
||||
|
||||
Hlayout hlayout = ComponentsFinder.findComponentsOfType(Hlayout.class, children).get(0);
|
||||
|
||||
|
|
@ -496,13 +469,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
private void registerBlurListener(final Datebox datebox) {
|
||||
datebox.addEventListener("onBlur", new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
dateBoxHasLostFocus(datebox);
|
||||
}
|
||||
});
|
||||
datebox.addEventListener("onBlur", event -> dateBoxHasLostFocus(datebox));
|
||||
}
|
||||
|
||||
public void updateBean(Component updatedComponent) {
|
||||
|
|
@ -518,13 +485,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
|
||||
try {
|
||||
final Date begin = dateFormat.parse(getStartDateTextBox().getValue());
|
||||
task.doPositionModifications(new IModifications() {
|
||||
|
||||
@Override
|
||||
public void doIt(IUpdatablePosition position) {
|
||||
position.moveTo(GanttDate.createFrom(begin));
|
||||
}
|
||||
});
|
||||
task.doPositionModifications(position -> position.moveTo(GanttDate.createFrom(begin)));
|
||||
} catch (ParseException e) {
|
||||
// Do nothing as textbox is rested in the next sentence
|
||||
}
|
||||
|
|
@ -562,12 +523,8 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
nameLabel.setTooltiptext(task.getName());
|
||||
nameLabel.setSclass("clickable-rows");
|
||||
|
||||
nameLabel.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event arg0) throws Exception {
|
||||
Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode());
|
||||
}
|
||||
});
|
||||
nameLabel.addEventListener(Events.ON_CLICK,
|
||||
arg0 -> Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode()));
|
||||
|
||||
startDateLabel.setValue(asString(task.getBeginDate().toDayRoundedDate()));
|
||||
endDateLabel.setValue(asString(task.getEndDate().toDayRoundedDate()));
|
||||
|
|
@ -627,17 +584,17 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
|
||||
switch (status) {
|
||||
case MARGIN_EXCEEDED:
|
||||
cssClass = "status-red";
|
||||
break;
|
||||
cssClass = "status-red";
|
||||
break;
|
||||
|
||||
case WITHIN_MARGIN:
|
||||
cssClass = "status-orange";
|
||||
break;
|
||||
cssClass = "status-orange";
|
||||
break;
|
||||
|
||||
case AS_PLANNED:
|
||||
|
||||
default:
|
||||
cssClass = "status-green";
|
||||
cssClass = "status-green";
|
||||
}
|
||||
|
||||
return cssClass;
|
||||
|
|
@ -645,12 +602,9 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
|||
|
||||
private void onProjectStatusClick(Component statucComp) {
|
||||
if ( !disabilityConfiguration.isTreeEditable() ) {
|
||||
statucComp.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event arg0) throws Exception {
|
||||
Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode());
|
||||
}
|
||||
});
|
||||
statucComp.addEventListener(
|
||||
Events.ON_CLICK,
|
||||
arg0 -> Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,16 +23,15 @@ package org.zkoss.ganttz;
|
|||
|
||||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
||||
|
|
@ -56,7 +55,6 @@ import org.zkoss.ganttz.util.LongOperationFeedback;
|
|||
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
||||
import org.zkoss.ganttz.util.ProfilingLogFactory;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
||||
import org.zkoss.zk.au.AuRequest;
|
||||
import org.zkoss.zk.au.AuService;
|
||||
import org.zkoss.zk.mesg.MZk;
|
||||
|
|
@ -64,8 +62,6 @@ import org.zkoss.zk.ui.Component;
|
|||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||
import org.zkoss.zk.ui.UiException;
|
||||
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.util.Clients;
|
||||
import org.zkoss.zul.Button;
|
||||
|
|
@ -74,57 +70,17 @@ import org.zkoss.zul.Listbox;
|
|||
import org.zkoss.zul.Listitem;
|
||||
import org.zkoss.zul.SimpleListModel;
|
||||
import org.zkoss.zul.South;
|
||||
import org.zkoss.zul.api.Combobox;
|
||||
import org.zkoss.zul.Combobox;
|
||||
|
||||
public class Planner extends HtmlMacroComponent {
|
||||
|
||||
private static final Log PROFILING_LOG = ProfilingLogFactory.getLog(Planner.class);
|
||||
|
||||
public static boolean guessContainersExpandedByDefaultGivenPrintParameters(Map<String, String> printParameters) {
|
||||
return guessContainersExpandedByDefault(convertToURLParameters(printParameters));
|
||||
}
|
||||
private static int PIXELS_PER_TASK_LEVEL = 21;
|
||||
|
||||
private static Map<String, String[]> convertToURLParameters(Map<String, String> printParameters) {
|
||||
Map<String, String[]> result = new HashMap<>();
|
||||
for (Entry<String, String> each : printParameters.entrySet()) {
|
||||
result.put(each.getKey(), new String[] { each.getValue() });
|
||||
}
|
||||
private static int PIXELS_PER_CHARACTER = 5;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean guessContainersExpandedByDefault(Map<String, String[]> queryURLParameters) {
|
||||
String[] values = queryURLParameters.get("expanded");
|
||||
|
||||
return values != null && toLowercaseSet(values).contains("all");
|
||||
}
|
||||
|
||||
public static boolean guessShowAdvancesByDefault(Map<String, String[]> queryURLParameters) {
|
||||
String[] values = queryURLParameters.get("advances");
|
||||
|
||||
return values != null && toLowercaseSet(values).contains("all");
|
||||
}
|
||||
|
||||
public static boolean guessShowReportedHoursByDefault(Map<String, String[]> queryURLParameters) {
|
||||
String[] values = queryURLParameters.get("reportedHours");
|
||||
|
||||
return values != null && toLowercaseSet(values).contains("all");
|
||||
}
|
||||
|
||||
public static boolean guessShowMoneyCostBarByDefault(Map<String, String[]> queryURLParameters) {
|
||||
String[] values = queryURLParameters.get("moneyCostBar");
|
||||
|
||||
return values != null && toLowercaseSet(values).contains("all");
|
||||
}
|
||||
|
||||
private static Set<String> toLowercaseSet(String[] values) {
|
||||
Set<String> result = new HashSet<>();
|
||||
for (String each : values) {
|
||||
result.add(each.toLowerCase());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
private String EXPAND_ALL_BUTTON = "expandAll";
|
||||
|
||||
private GanttZKDiagramGraph diagramGraph;
|
||||
|
||||
|
|
@ -134,6 +90,8 @@ public class Planner extends HtmlMacroComponent {
|
|||
|
||||
private List<? extends CommandContextualized<?>> contextualizedGlobalCommands;
|
||||
|
||||
private CommandContextualized<?> goingDownInLastArrowCommand;
|
||||
|
||||
private List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized;
|
||||
|
||||
private CommandOnTaskContextualized<?> doubleClickCommand;
|
||||
|
|
@ -165,16 +123,102 @@ public class Planner extends HtmlMacroComponent {
|
|||
private WeakReferencedListeners<IChartVisibilityChangedListener> chartVisibilityListeners =
|
||||
WeakReferencedListeners.create();
|
||||
|
||||
public Planner() {
|
||||
private IGraphChangeListener showCriticalPathOnChange = new IGraphChangeListener() {
|
||||
@Override
|
||||
public void execute() {
|
||||
context.showCriticalPath();
|
||||
}
|
||||
};
|
||||
|
||||
private IGraphChangeListener showAdvanceOnChange = new IGraphChangeListener() {
|
||||
@Override
|
||||
public void execute() {
|
||||
context.showAdvances();
|
||||
}
|
||||
};
|
||||
|
||||
private IGraphChangeListener showReportedHoursOnChange = new IGraphChangeListener() {
|
||||
@Override
|
||||
public void execute() {
|
||||
context.showReportedHours();
|
||||
}
|
||||
};
|
||||
|
||||
private IGraphChangeListener showMoneyCostBarOnChange = new IGraphChangeListener() {
|
||||
@Override
|
||||
public void execute() {
|
||||
context.showMoneyCostBar();
|
||||
}
|
||||
};
|
||||
|
||||
private boolean containersExpandedByDefault = false;
|
||||
|
||||
private boolean shownAdvanceByDefault = false;
|
||||
|
||||
private boolean shownReportedHoursByDefault = false;
|
||||
|
||||
private boolean shownMoneyCostBarByDefault = false;
|
||||
|
||||
private FilterAndParentExpandedPredicates predicate;
|
||||
|
||||
private boolean visibleChart;
|
||||
|
||||
public Planner() {}
|
||||
|
||||
public static boolean guessContainersExpandedByDefaultGivenPrintParameters(Map<String, String> printParameters) {
|
||||
return guessContainersExpandedByDefault(convertToURLParameters(printParameters));
|
||||
}
|
||||
|
||||
private static Map<String, String[]> convertToURLParameters(Map<String, String> printParameters) {
|
||||
Map<String, String[]> result = new HashMap<>();
|
||||
for (Entry<String, String> each : printParameters.entrySet()) {
|
||||
result.put(each.getKey(), new String[] { each.getValue() });
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean guessContainersExpandedByDefault(Map<String, String[]> queryURLParameters) {
|
||||
String[] values = queryURLParameters.get("expanded");
|
||||
|
||||
return values != null && toLowercaseSet(values).contains("all");
|
||||
|
||||
}
|
||||
|
||||
public static boolean guessShowAdvancesByDefault(Map<String, String[]> queryURLParameters) {
|
||||
String[] values = queryURLParameters.get("advances");
|
||||
|
||||
return values != null && toLowercaseSet(values).contains("all");
|
||||
|
||||
}
|
||||
|
||||
public static boolean guessShowReportedHoursByDefault(Map<String, String[]> queryURLParameters) {
|
||||
String[] values = queryURLParameters.get("reportedHours");
|
||||
|
||||
return values != null && toLowercaseSet(values).contains("all");
|
||||
|
||||
}
|
||||
|
||||
public static boolean guessShowMoneyCostBarByDefault(Map<String, String[]> queryURLParameters) {
|
||||
String[] values = queryURLParameters.get("moneyCostBar");
|
||||
|
||||
return values != null && toLowercaseSet(values).contains("all");
|
||||
|
||||
}
|
||||
|
||||
private static Set<String> toLowercaseSet(String[] values) {
|
||||
Set<String> result = new HashSet<>();
|
||||
for (String each : values) {
|
||||
result.add(each.toLowerCase());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TaskList getTaskList() {
|
||||
if ( ganttPanel == null ) {
|
||||
return null;
|
||||
}
|
||||
List<Object> children = ganttPanel.getChildren();
|
||||
|
||||
return ComponentsFinder.findComponentsOfType(TaskList.class, children).get(0);
|
||||
return ganttPanel == null
|
||||
? null
|
||||
: ComponentsFinder.findComponentsOfType(TaskList.class, ganttPanel.getChildren()).get(0);
|
||||
}
|
||||
|
||||
public int getTaskNumber() {
|
||||
|
|
@ -186,20 +230,19 @@ public class Planner extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
private int calculateMinimumWidthForTaskNameColumn(boolean expand, List<Task> tasks) {
|
||||
|
||||
IDomainAndBeansMapper<?> mapper = getContext().getMapper();
|
||||
int widest = 0;
|
||||
|
||||
for(Task task : tasks) {
|
||||
for (Task task : tasks) {
|
||||
int numberOfAncestors = mapper.findPositionFor(task).getAncestors().size();
|
||||
int numberOfCharacters = task.getName().length();
|
||||
int PIXELS_PER_TASK_LEVEL = 21;
|
||||
int PIXELS_PER_CHARACTER = 5;
|
||||
|
||||
widest = Math.max(
|
||||
widest,
|
||||
numberOfCharacters * PIXELS_PER_CHARACTER + numberOfAncestors * PIXELS_PER_TASK_LEVEL);
|
||||
|
||||
if( expand && !task.isLeaf() ) {
|
||||
if ( expand && !task.isLeaf() ) {
|
||||
widest = Math.max(widest, calculateMinimumWidthForTaskNameColumn(expand, task.getTasks()));
|
||||
}
|
||||
}
|
||||
|
|
@ -220,7 +263,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
return null;
|
||||
}
|
||||
|
||||
List<Object> children = ganttPanel.getChildren();
|
||||
List<Component> children = ganttPanel.getChildren();
|
||||
List<DependencyList> found = ComponentsFinder.findComponentsOfType(DependencyList.class, children);
|
||||
|
||||
if ( found.isEmpty() ) {
|
||||
|
|
@ -232,6 +275,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
|
||||
public void addTasks(Position position, Collection<? extends Task> newTasks) {
|
||||
TaskList taskList = getTaskList();
|
||||
|
||||
if ( taskList != null && leftPane != null ) {
|
||||
taskList.addTasks(position, newTasks);
|
||||
leftPane.addTasks(position, newTasks);
|
||||
|
|
@ -244,6 +288,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
|
||||
void addDependencies(Collection<? extends Dependency> dependencies) {
|
||||
DependencyList dependencyList = getDependencyList();
|
||||
|
||||
if ( dependencyList == null ) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -253,21 +298,23 @@ public class Planner extends HtmlMacroComponent {
|
|||
}
|
||||
}
|
||||
|
||||
public ListModel getZoomLevels() {
|
||||
public ListModel<ZoomLevel> getZoomLevels() {
|
||||
ZoomLevel[] selectableZoomlevels = {
|
||||
ZoomLevel.DETAIL_ONE,
|
||||
ZoomLevel.DETAIL_TWO,
|
||||
ZoomLevel.DETAIL_THREE,
|
||||
ZoomLevel.DETAIL_FOUR,
|
||||
ZoomLevel.DETAIL_FIVE };
|
||||
ZoomLevel.DETAIL_FIVE
|
||||
};
|
||||
|
||||
return new SimpleListModel(selectableZoomlevels);
|
||||
return new SimpleListModel<>(selectableZoomlevels);
|
||||
}
|
||||
|
||||
public void setZoomLevel(final ZoomLevel zoomLevel, int scrollLeft) {
|
||||
if ( ganttPanel == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.zoomLevel = zoomLevel;
|
||||
ganttPanel.setZoomLevel(zoomLevel, scrollLeft);
|
||||
}
|
||||
|
|
@ -294,6 +341,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
if ( ganttPanel == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
LongOperationFeedback.execute(ganttPanel, new ILongOperation() {
|
||||
@Override
|
||||
public String getName() {
|
||||
|
|
@ -328,18 +376,22 @@ public class Planner extends HtmlMacroComponent {
|
|||
new FunctionalityExposedForExtensions<>(this, configuration, diagramGraph);
|
||||
|
||||
addGraphChangeListenersFromConfiguration(configuration);
|
||||
|
||||
this.contextualizedGlobalCommands = contextualize(newContext, configuration.getGlobalCommands());
|
||||
|
||||
this.commandsOnTasksContextualized = contextualize(newContext, configuration.getCommandsOnTasks());
|
||||
|
||||
CommandContextualized<?> goingDownInLastArrowCommand =
|
||||
contextualize(newContext, configuration.getGoingDownInLastArrowCommand());
|
||||
goingDownInLastArrowCommand = contextualize(newContext, configuration.getGoingDownInLastArrowCommand());
|
||||
|
||||
doubleClickCommand = contextualize(newContext, configuration.getDoubleClickCommand());
|
||||
|
||||
this.context = newContext;
|
||||
this.disabilityConfiguration = configuration;
|
||||
|
||||
resettingPreviousComponentsToNull();
|
||||
long timeAddingData = System.currentTimeMillis();
|
||||
newContext.add(configuration.getData());
|
||||
|
||||
PROFILING_LOG.debug("It took to add data: " + (System.currentTimeMillis() - timeAddingData) + " ms");
|
||||
long timeSetupingAndAddingComponents = System.currentTimeMillis();
|
||||
setupComponents();
|
||||
|
|
@ -356,6 +408,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
timetrackerheader.afterCompose();
|
||||
|
||||
Component chartComponent = configuration.getChartComponent();
|
||||
|
||||
if ( chartComponent != null ) {
|
||||
setAt("insertionPointChart", chartComponent);
|
||||
}
|
||||
|
|
@ -366,11 +419,11 @@ public class Planner extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
if ( !configuration.isExpandAllEnabled() ) {
|
||||
Button expandAllButton = (Button) getFellow("expandAll");
|
||||
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
|
||||
expandAllButton.setVisible(false);
|
||||
}
|
||||
|
||||
if ( !configuration.isFlattenTreeEnabled() ) {
|
||||
if (!configuration.isFlattenTreeEnabled()) {
|
||||
Button flattenTree = (Button) getFellow("flattenTree");
|
||||
flattenTree.setVisible(false);
|
||||
}
|
||||
|
|
@ -390,22 +443,26 @@ public class Planner extends HtmlMacroComponent {
|
|||
this.visibleChart = configuration.isExpandPlanningViewCharts();
|
||||
((South) getFellow("graphics")).setOpen(this.visibleChart);
|
||||
|
||||
PROFILING_LOG.debug(
|
||||
"It took doing the setup of components and adding them: " +
|
||||
(System.currentTimeMillis() - timeSetupingAndAddingComponents) + " ms");
|
||||
if (!visibleChart) {
|
||||
((South) getFellow("graphics")).setTitle(_("Graphics are disabled"));
|
||||
}
|
||||
|
||||
setAuService(new AuService(){
|
||||
PROFILING_LOG.debug("it took doing the setup of components and adding them: "
|
||||
+ (System.currentTimeMillis() - timeSetupingAndAddingComponents) + " ms");
|
||||
|
||||
setAuService(new AuService() {
|
||||
public boolean service(AuRequest request, boolean everError){
|
||||
String command = request.getCommand();
|
||||
int zoomindex;
|
||||
int scrollLeft;
|
||||
|
||||
if ( command.equals("onZoomLevelChange") ){
|
||||
if ( "onZoomLevelChange".equals(command) ) {
|
||||
zoomindex= (Integer) retrieveData(request, "zoomindex");
|
||||
scrollLeft = (Integer) retrieveData(request, "scrollLeft");
|
||||
|
||||
setZoomLevel((ZoomLevel)((Listbox)getFellow("listZoomLevels"))
|
||||
.getModel().getElementAt(zoomindex), scrollLeft);
|
||||
setZoomLevel(
|
||||
(ZoomLevel)((Listbox) getFellow("listZoomLevels")).getModel().getElementAt(zoomindex),
|
||||
scrollLeft);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -413,7 +470,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
return false;
|
||||
}
|
||||
|
||||
private Object retrieveData(AuRequest request, String key){
|
||||
private Object retrieveData(AuRequest request, String key) {
|
||||
Object value = request.getData().get(key);
|
||||
if ( value == null )
|
||||
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, new Object[] { key, this });
|
||||
|
|
@ -434,9 +491,8 @@ public class Planner extends HtmlMacroComponent {
|
|||
insertionPoint.appendChild(component);
|
||||
}
|
||||
|
||||
private <T> List<CommandOnTaskContextualized<T>> contextualize(
|
||||
FunctionalityExposedForExtensions<T> context, List<ICommandOnTask<T>> commands) {
|
||||
|
||||
private <T> List<CommandOnTaskContextualized<T>> contextualize(FunctionalityExposedForExtensions<T> context,
|
||||
List<ICommandOnTask<T>> commands) {
|
||||
List<CommandOnTaskContextualized<T>> result = new ArrayList<>();
|
||||
for (ICommandOnTask<T> c : commands) {
|
||||
result.add(contextualize(context, c));
|
||||
|
|
@ -445,18 +501,14 @@ public class Planner extends HtmlMacroComponent {
|
|||
return result;
|
||||
}
|
||||
|
||||
private <T> CommandOnTaskContextualized<T> contextualize(
|
||||
FunctionalityExposedForExtensions<T> context, ICommandOnTask<T> commandOnTask) {
|
||||
private <T> CommandOnTaskContextualized<T> contextualize(FunctionalityExposedForExtensions<T> context,
|
||||
ICommandOnTask<T> commandOnTask) {
|
||||
|
||||
return CommandOnTaskContextualized.create(commandOnTask, context.getMapper(), context);
|
||||
}
|
||||
|
||||
private <T> CommandContextualized<T> contextualize(IContext<T> context, ICommand<T> command) {
|
||||
if (command == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return CommandContextualized.create(command, context);
|
||||
return command == null ? null : CommandContextualized.create(command, context);
|
||||
}
|
||||
|
||||
private <T> List<CommandContextualized<T>> contextualize(
|
||||
|
|
@ -510,6 +562,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
|
||||
// Comparison through icon as name is internationalized
|
||||
if ( c.getCommand().isPlannerCommand() ) {
|
||||
|
||||
// FIXME Avoid hard-coding the number of planner commands
|
||||
// At this moment we have 2 planner commands: reassign and adapt planning
|
||||
if ( plannerToolbar.getChildren().size() < 2 ) {
|
||||
|
|
@ -535,10 +588,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
taskList.remove(task);
|
||||
getDependencyList().taskRemoved(task);
|
||||
leftPane.taskRemoved(task);
|
||||
|
||||
// forcing smart update
|
||||
setHeight(getHeight());
|
||||
|
||||
setHeight(getHeight());// forcing smart update
|
||||
ganttPanel.adjustZoomColumnsHeight();
|
||||
getDependencyList().redrawDependencies();
|
||||
}
|
||||
|
|
@ -549,14 +599,10 @@ public class Planner extends HtmlMacroComponent {
|
|||
listZoomLevels = (Listbox) getFellow("listZoomLevels");
|
||||
|
||||
Component westContainer = getFellow("taskdetailsContainer");
|
||||
westContainer.addEventListener(Events.ON_SIZE, new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
Clients.evalJavaScript("ganttz.TaskList.getInstance().legendResize();");
|
||||
}
|
||||
|
||||
});
|
||||
westContainer.addEventListener(
|
||||
Events.ON_SIZE,
|
||||
event -> Clients.evalJavaScript("ganttz.TaskList.getInstance().legendResize();"));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -564,60 +610,14 @@ public class Planner extends HtmlMacroComponent {
|
|||
return ganttPanel.getTimeTracker();
|
||||
}
|
||||
|
||||
private IGraphChangeListener showCriticalPathOnChange = new IGraphChangeListener() {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
context.showCriticalPath();
|
||||
}
|
||||
};
|
||||
|
||||
private IGraphChangeListener showAdvanceOnChange = new IGraphChangeListener() {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
context.showAdvances();
|
||||
}
|
||||
};
|
||||
|
||||
private IGraphChangeListener showReportedHoursOnChange = new IGraphChangeListener() {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
context.showReportedHours();
|
||||
}
|
||||
};
|
||||
|
||||
private IGraphChangeListener showMoneyCostBarOnChange = new IGraphChangeListener() {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
context.showMoneyCostBar();
|
||||
}
|
||||
};
|
||||
|
||||
private boolean containersExpandedByDefault = false;
|
||||
|
||||
private boolean shownAdvanceByDefault = false;
|
||||
|
||||
private boolean shownReportedHoursByDefault = false;
|
||||
|
||||
private boolean shownMoneyCostBarByDefault = false;
|
||||
|
||||
private FilterAndParentExpandedPredicates predicate;
|
||||
|
||||
private boolean visibleChart;
|
||||
|
||||
public void showCriticalPath() {
|
||||
Button showCriticalPathButton = (Button) getFellow("showCriticalPath");
|
||||
|
||||
if ( disabilityConfiguration.isCriticalPathEnabled() ) {
|
||||
if ( isShowingCriticalPath ) {
|
||||
context.hideCriticalPath();
|
||||
diagramGraph.removePostGraphChangeListener(showCriticalPathOnChange);
|
||||
showCriticalPathButton.setSclass("planner-command");
|
||||
showCriticalPathButton.setTooltiptext(_("Show critical path"));
|
||||
|
||||
} else {
|
||||
context.showCriticalPath();
|
||||
diagramGraph.addPostGraphChangeListener(showCriticalPathOnChange);
|
||||
|
|
@ -638,10 +638,9 @@ public class Planner extends HtmlMacroComponent {
|
|||
public void showAdvances() {
|
||||
Button showAdvancesButton = (Button) getFellow("showAdvances");
|
||||
if ( disabilityConfiguration.isAdvancesEnabled() ) {
|
||||
|
||||
Combobox progressTypesCombo = (Combobox) getFellow("cbProgressTypes");
|
||||
if ( isShowingAdvances ) {
|
||||
|
||||
if ( isShowingAdvances ) {
|
||||
context.hideAdvances();
|
||||
diagramGraph.removePostGraphChangeListener(showAdvanceOnChange);
|
||||
showAdvancesButton.setSclass("planner-command");
|
||||
|
|
@ -650,40 +649,39 @@ public class Planner extends HtmlMacroComponent {
|
|||
if ( progressTypesCombo.getItemCount() > 0 ) {
|
||||
progressTypesCombo.setSelectedIndex(0);
|
||||
}
|
||||
|
||||
} else {
|
||||
context.showAdvances();
|
||||
diagramGraph.addPostGraphChangeListener(showAdvanceOnChange);
|
||||
showAdvancesButton.setSclass("planner-command clicked");
|
||||
showAdvancesButton.setTooltiptext(_("Hide progress"));
|
||||
}
|
||||
|
||||
isShowingAdvances = !isShowingAdvances;
|
||||
}
|
||||
}
|
||||
|
||||
public void showReportedHours() {
|
||||
Button showReportedHoursButton = (Button) getFellow("showReportedHours");
|
||||
|
||||
if ( disabilityConfiguration.isReportedHoursEnabled() ) {
|
||||
|
||||
if ( isShowingReportedHours ) {
|
||||
context.hideReportedHours();
|
||||
diagramGraph.removePostGraphChangeListener(showReportedHoursOnChange);
|
||||
showReportedHoursButton.setSclass("planner-command");
|
||||
showReportedHoursButton.setTooltiptext(_("Show reported hours"));
|
||||
|
||||
} else {
|
||||
context.showReportedHours();
|
||||
diagramGraph.addPostGraphChangeListener(showReportedHoursOnChange);
|
||||
showReportedHoursButton.setSclass("planner-command clicked");
|
||||
showReportedHoursButton.setTooltiptext(_("Hide reported hours"));
|
||||
}
|
||||
|
||||
isShowingReportedHours = !isShowingReportedHours;
|
||||
}
|
||||
}
|
||||
|
||||
public void showMoneyCostBar() {
|
||||
Button showMoneyCostBarButton = (Button) getFellow("showMoneyCostBar");
|
||||
|
||||
if ( disabilityConfiguration.isMoneyCostBarEnabled() ) {
|
||||
if ( isShowingMoneyCostBar ) {
|
||||
context.hideMoneyCostBar();
|
||||
|
|
@ -696,6 +694,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
showMoneyCostBarButton.setSclass("planner-command clicked");
|
||||
showMoneyCostBarButton.setTooltiptext(_("Hide money cost bar"));
|
||||
}
|
||||
|
||||
isShowingMoneyCostBar = !isShowingMoneyCostBar;
|
||||
}
|
||||
}
|
||||
|
|
@ -709,6 +708,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
Clients.evalJavaScript("ganttz.TaskList.getInstance().showAllTaskLabels()");
|
||||
showAllLabelsButton.setSclass("planner-command show-labels clicked");
|
||||
}
|
||||
|
||||
isShowingLabels = !isShowingLabels;
|
||||
}
|
||||
|
||||
|
|
@ -721,6 +721,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
Clients.evalJavaScript("ganttz.TaskList.getInstance().showResourceTooltips()");
|
||||
showAllLabelsButton.setSclass("planner-command show-resources clicked");
|
||||
}
|
||||
|
||||
isShowingResources = !isShowingResources;
|
||||
}
|
||||
|
||||
|
|
@ -731,11 +732,9 @@ public class Planner extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
public ZoomLevel getZoomLevel() {
|
||||
if ( ganttPanel == null ) {
|
||||
return zoomLevel != null ? zoomLevel : ZoomLevel.DETAIL_ONE;
|
||||
}
|
||||
|
||||
return ganttPanel.getTimeTracker().getDetailLevel();
|
||||
return ganttPanel == null
|
||||
? zoomLevel != null ? zoomLevel : ZoomLevel.DETAIL_ONE
|
||||
: ganttPanel.getTimeTracker().getDetailLevel();
|
||||
}
|
||||
|
||||
public void setInitialZoomLevel(final ZoomLevel zoomLevel) {
|
||||
|
|
@ -755,7 +754,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
public boolean showAdvancesRightNow() {
|
||||
return (areShownAdvancesByDefault() || isShowingAdvances);
|
||||
return areShownAdvancesByDefault() || isShowingAdvances;
|
||||
}
|
||||
|
||||
public void setAreShownAdvancesByDefault(boolean shownAdvanceByDefault) {
|
||||
|
|
@ -772,7 +771,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
public boolean showReportedHoursRightNow() {
|
||||
return (areShownReportedHoursByDefault() || isShowingReportedHours);
|
||||
return areShownReportedHoursByDefault() || isShowingReportedHours;
|
||||
}
|
||||
|
||||
public void setAreShownMoneyCostBarByDefault(boolean shownMoneyCostBarByDefault) {
|
||||
|
|
@ -784,13 +783,13 @@ public class Planner extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
public boolean showMoneyCostBarRightNow() {
|
||||
return (areShownMoneyCostBarByDefault() || isShowingMoneyCostBar);
|
||||
return areShownMoneyCostBarByDefault() || isShowingMoneyCostBar;
|
||||
}
|
||||
|
||||
public void expandAll() {
|
||||
Button expandAllButton = (Button) getFellow("expandAll");
|
||||
|
||||
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
|
||||
if ( disabilityConfiguration.isExpandAllEnabled() ) {
|
||||
|
||||
if ( isExpandAll ) {
|
||||
context.collapseAll();
|
||||
expandAllButton.setSclass("planner-command");
|
||||
|
|
@ -799,25 +798,26 @@ public class Planner extends HtmlMacroComponent {
|
|||
expandAllButton.setSclass("planner-command clicked");
|
||||
}
|
||||
}
|
||||
|
||||
isExpandAll = !isExpandAll;
|
||||
}
|
||||
|
||||
public void expandAllAlways() {
|
||||
Button expandAllButton = (Button) getFellow("expandAll");
|
||||
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
|
||||
if ( disabilityConfiguration.isExpandAllEnabled() ) {
|
||||
context.expandAll();
|
||||
expandAllButton.setSclass("planner-command clicked");
|
||||
context.expandAll();
|
||||
expandAllButton.setSclass("planner-command clicked");
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSelectedZoomLevel() {
|
||||
ganttPanel.getTimeTracker().setZoomLevel(zoomLevel);
|
||||
Listitem selectedItem = (Listitem) listZoomLevels.getItems().get(zoomLevel.ordinal());
|
||||
Listitem selectedItem = listZoomLevels.getItems().get(zoomLevel.ordinal());
|
||||
listZoomLevels.setSelectedItem(selectedItem);
|
||||
listZoomLevels.invalidate();
|
||||
}
|
||||
|
||||
public IContext<?> getContext() {
|
||||
public IContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -838,17 +838,18 @@ public class Planner extends HtmlMacroComponent {
|
|||
|
||||
public void flattenTree() {
|
||||
Button flattenTreeButton = (Button) getFellow("flattenTree");
|
||||
|
||||
if ( disabilityConfiguration.isFlattenTreeEnabled() ) {
|
||||
if ( isFlattenTree ) {
|
||||
if (isFlattenTree) {
|
||||
predicate.setFilterContainers(false);
|
||||
flattenTreeButton.setSclass("planner-command");
|
||||
} else {
|
||||
predicate.setFilterContainers(true);
|
||||
flattenTreeButton.setSclass("planner-command clicked");
|
||||
}
|
||||
|
||||
setTaskListPredicate(predicate);
|
||||
}
|
||||
|
||||
isFlattenTree = !isFlattenTree;
|
||||
Clients.evalJavaScript("ganttz.Planner.getInstance().adjustScrollableDimensions()");
|
||||
}
|
||||
|
|
@ -859,12 +860,7 @@ public class Planner extends HtmlMacroComponent {
|
|||
|
||||
public void changeChartVisibility(boolean visible) {
|
||||
visibleChart = visible;
|
||||
chartVisibilityListeners.fireEvent(new IListenerNotification<IChartVisibilityChangedListener>() {
|
||||
@Override
|
||||
public void doNotify(IChartVisibilityChangedListener listener) {
|
||||
listener.chartVisibilityChanged(visibleChart);
|
||||
}
|
||||
});
|
||||
chartVisibilityListeners.fireEvent(listener -> listener.chartVisibilityChanged(visibleChart));
|
||||
}
|
||||
|
||||
public boolean isVisibleChart() {
|
||||
|
|
@ -914,8 +910,9 @@ public class Planner extends HtmlMacroComponent {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWidgetClass(){
|
||||
return getDefinition().getDefaultWidgetClass();
|
||||
return getDefinition().getDefaultWidgetClass(this);
|
||||
}
|
||||
|
||||
public List getCriticalPath() {
|
||||
|
|
@ -926,17 +923,19 @@ public class Planner extends HtmlMacroComponent {
|
|||
TaskList taskList = getTaskList();
|
||||
if ( taskList != null ) {
|
||||
taskList.updateCompletion(progressType);
|
||||
// FIXME Bug #1270
|
||||
|
||||
for (TaskComponent each : taskList.getTaskComponents()) {
|
||||
each.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TaskComponent getTaskComponentRelatedTo(org.zkoss.ganttz.data.Task task) {
|
||||
public TaskComponent getTaskComponentRelatedTo(Task task) {
|
||||
TaskList taskList = getTaskList();
|
||||
if ( taskList != null ) {
|
||||
|
||||
for (TaskComponent each : taskList.getTaskComponents()) {
|
||||
|
||||
if ( each.getTask().equals(task) ) {
|
||||
return each;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,16 +29,14 @@ import java.util.Map;
|
|||
import org.zkoss.ganttz.extensions.ITab;
|
||||
import org.zkoss.ganttz.util.IMenuItemsRegister;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
|
||||
public class TabsRegistry {
|
||||
|
||||
private List<ITab> tabs = new ArrayList<ITab>();
|
||||
private List<ITab> tabs = new ArrayList<>();
|
||||
|
||||
private final Component parent;
|
||||
|
||||
private Map<ITab, Object> fromTabToMenuKey = new HashMap<ITab, Object>();
|
||||
private Map<ITab, Object> fromTabToMenuKey = new HashMap<>();
|
||||
|
||||
private IMenuItemsRegister menu;
|
||||
|
||||
|
|
@ -52,14 +50,10 @@ public class TabsRegistry {
|
|||
}
|
||||
|
||||
public interface IBeforeShowAction {
|
||||
public void doAction();
|
||||
void doAction();
|
||||
}
|
||||
|
||||
private static final IBeforeShowAction DO_NOTHING = new IBeforeShowAction() {
|
||||
@Override
|
||||
public void doAction() {
|
||||
}
|
||||
};
|
||||
private static final IBeforeShowAction DO_NOTHING = () -> {};
|
||||
|
||||
public void show(ITab tab) {
|
||||
show(tab, DO_NOTHING);
|
||||
|
|
@ -101,23 +95,10 @@ public class TabsRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
public void showFirst() {
|
||||
if (!tabs.isEmpty()) {
|
||||
show(tabs.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerAtMenu(IMenuItemsRegister menu) {
|
||||
this.menu = menu;
|
||||
for (final ITab t : tabs) {
|
||||
Object key = menu.addMenuItem(t.getName(), t.getCssClass(),
|
||||
new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
show(t);
|
||||
}
|
||||
});
|
||||
Object key = menu.addMenuItem(t.getName(), t.getCssClass(), event -> show(t));
|
||||
fromTabToMenuKey.put(t, key);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
package org.zkoss.ganttz;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
|
@ -34,6 +35,8 @@ import org.joda.time.Duration;
|
|||
import org.joda.time.LocalDate;
|
||||
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
||||
import org.zkoss.ganttz.data.GanttDate;
|
||||
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IModifications;
|
||||
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IUpdatablePosition;
|
||||
import org.zkoss.ganttz.data.Milestone;
|
||||
import org.zkoss.ganttz.data.Task;
|
||||
import org.zkoss.ganttz.data.Task.IReloadResourcesTextRequested;
|
||||
|
|
@ -62,9 +65,12 @@ import org.zkoss.zul.Div;
|
|||
public class TaskComponent extends Div implements AfterCompose {
|
||||
|
||||
private static final int HEIGHT_PER_TASK = 10;
|
||||
|
||||
private static final int CONSOLIDATED_MARK_HALF_WIDTH = 3;
|
||||
|
||||
private static final int HALF_DEADLINE_MARK = 3;
|
||||
|
||||
private String FUNCTION_RESIZE = "resizeCompletion2Advance";
|
||||
|
||||
protected final IDisabilityConfiguration disabilityConfiguration;
|
||||
|
||||
|
|
@ -76,6 +82,18 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
|
||||
private PropertyChangeListener showingMoneyCostBarPropertyListener;
|
||||
|
||||
private IReloadResourcesTextRequested reloadResourcesTextRequested;
|
||||
|
||||
private String _color;
|
||||
|
||||
private boolean isTopLevel;
|
||||
|
||||
private final Task task;
|
||||
|
||||
private transient PropertyChangeListener propertiesListener;
|
||||
|
||||
private String progressType;
|
||||
|
||||
public static TaskComponent asTaskComponent(Task task,
|
||||
IDisabilityConfiguration disabilityConfiguration,
|
||||
boolean isTopLevel) {
|
||||
|
|
@ -99,8 +117,6 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
return asTaskComponent(task, disabilityConfiguration, true);
|
||||
}
|
||||
|
||||
private IReloadResourcesTextRequested reloadResourcesTextRequested;
|
||||
|
||||
public TaskComponent(Task task, IDisabilityConfiguration disabilityConfiguration) {
|
||||
setHeight(HEIGHT_PER_TASK + "px");
|
||||
setContext("idContextMenuTaskAssignment");
|
||||
|
|
@ -108,9 +124,7 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
setClass(calculateCSSClass());
|
||||
setId(UUID.randomUUID().toString());
|
||||
this.disabilityConfiguration = disabilityConfiguration;
|
||||
|
||||
IConstraintViolationListener<GanttDate> taskViolationListener =
|
||||
Constraint.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
|
||||
IConstraintViolationListener<GanttDate> taskViolationListener = Constraint.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
|
||||
|
||||
@Override
|
||||
public void constraintViolated(Constraint<GanttDate> constraint, GanttDate value) {
|
||||
|
|
@ -124,32 +138,38 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
});
|
||||
|
||||
this.task.addConstraintViolationListener(taskViolationListener, Mode.RECEIVE_PENDING);
|
||||
reloadResourcesTextRequested = () -> {
|
||||
if ( canShowResourcesText() ) {
|
||||
smartUpdate("resourcesText", getResourcesText());
|
||||
|
||||
reloadResourcesTextRequested = new IReloadResourcesTextRequested() {
|
||||
@Override
|
||||
public void reloadResourcesTextRequested() {
|
||||
if ( canShowResourcesText() ) {
|
||||
smartUpdate("resourcesText", getResourcesText());
|
||||
}
|
||||
|
||||
String cssClass = calculateCSSClass();
|
||||
|
||||
response("setClass", new AuInvoke(TaskComponent.this, "setClass", cssClass));
|
||||
|
||||
// FIXME: Refactor to another listener
|
||||
updateDeadline();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
String cssClass = calculateCSSClass();
|
||||
|
||||
response("setClass", new AuInvoke(TaskComponent.this, "setClass", cssClass));
|
||||
|
||||
// FIXME: Refactor to another listener
|
||||
updateDeadline();
|
||||
invalidate();
|
||||
};
|
||||
|
||||
this.task.addReloadListener(reloadResourcesTextRequested);
|
||||
|
||||
setAuService(new AuService(){
|
||||
setAuService(new AuService() {
|
||||
|
||||
public boolean service(AuRequest request, boolean everError){
|
||||
public boolean service(AuRequest request, boolean everError) {
|
||||
String command = request.getCommand();
|
||||
final TaskComponent ta;
|
||||
|
||||
if ( command.equals("onUpdatePosition") ){
|
||||
ta = retrieveTaskComponent(request);
|
||||
|
||||
ta.doUpdatePosition(toInteger(retrieveData(request, "left")));
|
||||
ta.doUpdatePosition(toInteger(retrieveData(request, "left"))
|
||||
);
|
||||
|
||||
Events.postEvent(new Event(getId(), ta, request.getData()));
|
||||
|
||||
|
|
@ -181,7 +201,7 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
return ((Number) valueFromRequestData).intValue();
|
||||
}
|
||||
|
||||
private TaskComponent retrieveTaskComponent(AuRequest request){
|
||||
private TaskComponent retrieveTaskComponent(AuRequest request) {
|
||||
final TaskComponent ta = (TaskComponent) request.getComponent();
|
||||
|
||||
if ( ta == null ) {
|
||||
|
|
@ -191,7 +211,7 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
return ta;
|
||||
}
|
||||
|
||||
private Object retrieveData(AuRequest request, String key){
|
||||
private Object retrieveData(AuRequest request, String key) {
|
||||
Object value = request.getData().get(key);
|
||||
if ( value == null )
|
||||
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, new Object[] { key, this });
|
||||
|
|
@ -240,15 +260,25 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
public final void afterCompose() {
|
||||
updateProperties();
|
||||
if ( propertiesListener == null ) {
|
||||
propertiesListener = evt -> updateProperties();
|
||||
|
||||
propertiesListener = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
updateProperties();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this.task.addFundamentalPropertiesChangeListener(propertiesListener);
|
||||
|
||||
if ( showingAdvancePropertyListener == null ) {
|
||||
showingAdvancePropertyListener = evt -> {
|
||||
if ( isInPage() && !(task instanceof Milestone) ) {
|
||||
updateCompletionAdvance();
|
||||
|
||||
showingAdvancePropertyListener = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if ( isInPage() && !(task instanceof Milestone) ) {
|
||||
updateCompletionAdvance();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -256,9 +286,13 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
this.task.addAdvancesPropertyChangeListener(showingAdvancePropertyListener);
|
||||
|
||||
if ( showingReportedHoursPropertyListener == null ) {
|
||||
showingReportedHoursPropertyListener = evt -> {
|
||||
if ( isInPage() && !(task instanceof Milestone) ) {
|
||||
updateCompletionReportedHours();
|
||||
|
||||
showingReportedHoursPropertyListener = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if ( isInPage() && !(task instanceof Milestone) ) {
|
||||
updateCompletionReportedHours();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -266,9 +300,13 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
this.task.addReportedHoursPropertyChangeListener(showingReportedHoursPropertyListener);
|
||||
|
||||
if ( showingMoneyCostBarPropertyListener == null ) {
|
||||
showingMoneyCostBarPropertyListener = evt -> {
|
||||
if ( isInPage() && !(task instanceof Milestone) ) {
|
||||
updateCompletionMoneyCostBar();
|
||||
|
||||
showingMoneyCostBarPropertyListener = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if ( isInPage() && !(task instanceof Milestone) ) {
|
||||
updateCompletionMoneyCostBar();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -276,7 +314,14 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
this.task.addMoneyCostBarPropertyChangeListener(showingMoneyCostBarPropertyListener);
|
||||
|
||||
if ( criticalPathPropertyListener == null ) {
|
||||
criticalPathPropertyListener = evt -> updateClass();
|
||||
|
||||
criticalPathPropertyListener = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
updateClass();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
this.task.addCriticalPathPropertyChangeListener(criticalPathPropertyListener);
|
||||
|
|
@ -291,15 +336,6 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
return true;
|
||||
}
|
||||
|
||||
private String _color;
|
||||
|
||||
private boolean isTopLevel;
|
||||
|
||||
private final Task task;
|
||||
private transient PropertyChangeListener propertiesListener;
|
||||
|
||||
private String progressType;
|
||||
|
||||
public TaskRow getRow() {
|
||||
if ( getParent() == null ) {
|
||||
throw new IllegalStateException(
|
||||
|
|
@ -337,9 +373,16 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
void doUpdatePosition(int leftX) {
|
||||
GanttDate startBeforeMoving = this.task.getBeginDate();
|
||||
final LocalDate newPosition = getMapper().toDate(leftX);
|
||||
this.task.doPositionModifications(position -> position.moveTo(GanttDate.createFrom(newPosition)));
|
||||
|
||||
this.task.doPositionModifications(new IModifications() {
|
||||
@Override
|
||||
public void doIt(IUpdatablePosition position) {
|
||||
position.moveTo(GanttDate.createFrom(newPosition));
|
||||
}
|
||||
});
|
||||
|
||||
boolean remainsInOriginalPosition = this.task.getBeginDate().equals(startBeforeMoving);
|
||||
|
||||
if ( remainsInOriginalPosition ) {
|
||||
updateProperties();
|
||||
}
|
||||
|
|
@ -372,20 +415,18 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We override the method of renderProperties to put the color property as part
|
||||
* of the style
|
||||
*/
|
||||
/* We override the method of renderProperties to put the color property as part of the style */
|
||||
protected void renderProperties(ContentRenderer renderer) throws IOException{
|
||||
|
||||
if ( getColor() != null )
|
||||
setStyle("background-color : " + getColor());
|
||||
|
||||
setWidgetAttribute("movingTasksEnabled", ((Boolean)isMovingTasksEnabled()).toString());
|
||||
setWidgetAttribute("resizingTasksEnabled", ((Boolean)isResizingTasksEnabled()).toString());
|
||||
|
||||
/* We can't use setStyle because of restrictions
|
||||
* involved with UiVisualizer#getResponses and the
|
||||
* smartUpdate method (when the request is asynchronous) */
|
||||
/* We can't use setStyle because of restrictions involved with UiVisualizer#getResponses and the
|
||||
* smartUpdate method (when the request is asynchronous)
|
||||
*/
|
||||
render(renderer, "style", "position : absolute");
|
||||
|
||||
render(renderer, "_labelsText", getLabelsText());
|
||||
|
|
@ -395,10 +436,7 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
super.renderProperties(renderer);
|
||||
}
|
||||
|
||||
/*
|
||||
* We send a response to the client to create the arrow we are going to use
|
||||
* to create the dependency
|
||||
*/
|
||||
/* We send a response to the client to create the arrow we are going to use to create the dependency */
|
||||
|
||||
public void addDependency() {
|
||||
response("depkey", new AuInvoke(this, "addDependency"));
|
||||
|
|
@ -540,9 +578,9 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
if ( task.isShowingAdvances() ) {
|
||||
int startPixels = this.task.getBeginDate().toPixels(getMapper());
|
||||
String widthAdvancePercentage = pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate()) + "px";
|
||||
response(null, new AuInvoke(this, "resizeCompletion2Advance", widthAdvancePercentage));
|
||||
response(null, new AuInvoke(this, FUNCTION_RESIZE, widthAdvancePercentage));
|
||||
} else {
|
||||
response(null, new AuInvoke(this, "resizeCompletion2Advance", "0px"));
|
||||
response(null, new AuInvoke(this, FUNCTION_RESIZE, "0px"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -553,9 +591,9 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
String widthAdvancePercentage =
|
||||
pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate(progressType)) + "px";
|
||||
|
||||
response(null, new AuInvoke(this, "resizeCompletion2Advance", widthAdvancePercentage));
|
||||
response(null, new AuInvoke(this, FUNCTION_RESIZE, widthAdvancePercentage));
|
||||
} else {
|
||||
response(null, new AuInvoke(this, "resizeCompletion2Advance", "0px"));
|
||||
response(null, new AuInvoke(this, FUNCTION_RESIZE, "0px"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,11 +33,7 @@ import org.zkoss.zk.ui.util.GenericForwardComposer;
|
|||
import org.zkoss.zul.Datebox;
|
||||
import org.zkoss.zul.Textbox;
|
||||
|
||||
public class TaskEditFormComposer extends GenericForwardComposer {
|
||||
|
||||
public TaskEditFormComposer() {
|
||||
|
||||
}
|
||||
public class TaskEditFormComposer extends GenericForwardComposer<Component> {
|
||||
|
||||
private Task currentTask;
|
||||
|
||||
|
|
@ -53,19 +49,22 @@ public class TaskEditFormComposer extends GenericForwardComposer {
|
|||
|
||||
private Textbox notes;
|
||||
|
||||
public TaskEditFormComposer() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
}
|
||||
|
||||
public void init(Component openRelativeTo, Task task) {
|
||||
public void init(Task task) {
|
||||
this.currentTask = task;
|
||||
this.taskDTO = toDTO(task);
|
||||
updateComponentValuesForTask(taskDTO);
|
||||
}
|
||||
|
||||
private void updateComponentValuesForTask(
|
||||
TaskDTO taskDTO) {
|
||||
private void updateComponentValuesForTask(TaskDTO taskDTO) {
|
||||
name.setValue(taskDTO.name);
|
||||
startDateBox.setValue(taskDTO.beginDate);
|
||||
endDateBox.setValue(taskDTO.endDate);
|
||||
|
|
@ -96,10 +95,15 @@ public class TaskEditFormComposer extends GenericForwardComposer {
|
|||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
public static class TaskDTO {
|
||||
|
||||
public String name;
|
||||
|
||||
public Date beginDate;
|
||||
|
||||
public Date endDate;
|
||||
|
||||
public Date deadlineDate;
|
||||
|
||||
public String notes;
|
||||
}
|
||||
|
||||
|
|
@ -122,18 +126,12 @@ public class TaskEditFormComposer extends GenericForwardComposer {
|
|||
return localDate.toDateTimeAtStartOfDay().toDate();
|
||||
}
|
||||
|
||||
private void copyFromDTO(final TaskDTO taskDTO, Task currentTask,
|
||||
boolean copyDates) {
|
||||
private void copyFromDTO(final TaskDTO taskDTO, Task currentTask, boolean copyDates) {
|
||||
currentTask.setName(taskDTO.name);
|
||||
if (copyDates) {
|
||||
currentTask.doPositionModifications(new IModifications() {
|
||||
|
||||
@Override
|
||||
public void doIt(IUpdatablePosition position) {
|
||||
position.setBeginDate(GanttDate
|
||||
.createFrom(taskDTO.beginDate));
|
||||
position.resizeTo(GanttDate.createFrom(taskDTO.endDate));
|
||||
}
|
||||
currentTask.doPositionModifications(position -> {
|
||||
position.setBeginDate(GanttDate.createFrom(taskDTO.beginDate));
|
||||
position.resizeTo(GanttDate.createFrom(taskDTO.endDate));
|
||||
});
|
||||
}
|
||||
currentTask.setNotes(taskDTO.notes);
|
||||
|
|
|
|||
|
|
@ -23,16 +23,6 @@ package org.zkoss.ganttz;
|
|||
|
||||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.apache.commons.lang3.math.Fraction;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
||||
|
|
@ -48,15 +38,23 @@ import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
|||
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
||||
import org.zkoss.ganttz.util.Interval;
|
||||
import org.zkoss.ganttz.util.MenuBuilder;
|
||||
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.ext.AfterCompose;
|
||||
import org.zkoss.zul.Menupopup;
|
||||
import org.zkoss.zul.impl.XulElement;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Component to show the list of task in the planner
|
||||
* Component to show the list of task in the planner.
|
||||
*
|
||||
* @author Javier Moran Rua <jmoran@igalia.com>
|
||||
*/
|
||||
public class TaskList extends XulElement implements AfterCompose {
|
||||
|
|
@ -79,6 +77,10 @@ public class TaskList extends XulElement implements AfterCompose {
|
|||
|
||||
private Map<Task, TaskComponent> taskComponentByTask;
|
||||
|
||||
private Map<TaskContainer, IExpandListener> autoRemovedListers = new WeakHashMap<>();
|
||||
|
||||
private Map<TaskComponent, Menupopup> contextMenus = new HashMap<>();
|
||||
|
||||
public TaskList(
|
||||
FunctionalityExposedForExtensions<?> context,
|
||||
CommandOnTaskContextualized<?> doubleClickCommand,
|
||||
|
|
@ -114,15 +116,13 @@ public class TaskList extends XulElement implements AfterCompose {
|
|||
IDisabilityConfiguration disabilityConfiguration,
|
||||
FilterAndParentExpandedPredicates predicate) {
|
||||
|
||||
TaskList result = new TaskList(
|
||||
return new TaskList(
|
||||
context,
|
||||
doubleClickCommand,
|
||||
context.getDiagramGraph().getTopLevelTasks(),
|
||||
commandsOnTasksContextualized,
|
||||
disabilityConfiguration,
|
||||
predicate);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<DependencyComponent> asDependencyComponents(Collection<? extends Dependency> dependencies) {
|
||||
|
|
@ -137,11 +137,11 @@ public class TaskList extends XulElement implements AfterCompose {
|
|||
}
|
||||
|
||||
public DependencyComponent asDependencyComponent(Dependency dependency) {
|
||||
return asDependencyComponents(Arrays.asList(dependency)).get(0);
|
||||
return asDependencyComponents(Collections.singletonList(dependency)).get(0);
|
||||
}
|
||||
|
||||
private synchronized void addTaskComponent(TaskRow beforeThis, final TaskComponent taskComponent,
|
||||
boolean relocate) {
|
||||
private synchronized void addTaskComponent(
|
||||
TaskRow beforeThis, final TaskComponent taskComponent, boolean relocate) {
|
||||
|
||||
insertBefore(taskComponent.getRow(), beforeThis);
|
||||
addContextMenu(taskComponent);
|
||||
|
|
@ -163,7 +163,7 @@ public class TaskList extends XulElement implements AfterCompose {
|
|||
currentTotalTasks.addAll(insertionPosition, newTasks);
|
||||
}
|
||||
|
||||
// if the position is children of some already existent task when
|
||||
// If the position is children of some already existent task when
|
||||
// reloading it will be added if the predicate tells so
|
||||
reload(true);
|
||||
}
|
||||
|
|
@ -182,13 +182,7 @@ public class TaskList extends XulElement implements AfterCompose {
|
|||
if ( doubleClickCommand == null ) {
|
||||
return;
|
||||
}
|
||||
taskComponent.addEventListener("onDoubleClick", new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
doubleClickCommand.doAction(taskComponent);
|
||||
}
|
||||
});
|
||||
taskComponent.addEventListener("onDoubleClick", event -> doubleClickCommand.doAction(taskComponent));
|
||||
}
|
||||
|
||||
private void addContextMenu(final TaskComponent taskComponent) {
|
||||
|
|
@ -262,20 +256,12 @@ public class TaskList extends XulElement implements AfterCompose {
|
|||
return result;
|
||||
}
|
||||
|
||||
private Map<TaskContainer, IExpandListener> autoRemovedListers = new WeakHashMap<>();
|
||||
|
||||
private void addExpandListenerTo(TaskContainer container) {
|
||||
if ( autoRemovedListers.containsKey(container) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
IExpandListener expandListener = new IExpandListener() {
|
||||
|
||||
@Override
|
||||
public void expandStateChanged(boolean isNowExpanded) {
|
||||
reload(true);
|
||||
}
|
||||
};
|
||||
IExpandListener expandListener = (isNowExpanded -> reload(true));
|
||||
|
||||
container.addExpandListener(expandListener);
|
||||
autoRemovedListers.put(container, expandListener);
|
||||
|
|
@ -283,6 +269,7 @@ public class TaskList extends XulElement implements AfterCompose {
|
|||
|
||||
private void registerZoomLevelChangedListener() {
|
||||
if ( zoomLevelChangedListener == null ) {
|
||||
/* Do not replace it with lambda */
|
||||
zoomLevelChangedListener = new IZoomLevelChangedListener() {
|
||||
@Override
|
||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||
|
|
@ -301,25 +288,20 @@ public class TaskList extends XulElement implements AfterCompose {
|
|||
return interval.getStart().plusDays(daysInto);
|
||||
}
|
||||
|
||||
private Map<TaskComponent, Menupopup> contextMenus = new HashMap<>();
|
||||
|
||||
private Menupopup getContextMenuFor(TaskComponent taskComponent) {
|
||||
if ( contextMenus.get(taskComponent) == null ) {
|
||||
MenuBuilder<TaskComponent> menuBuilder = MenuBuilder.on(getPage(), getTaskComponents());
|
||||
|
||||
if ( disabilityConfiguration.isAddingDependenciesEnabled() ) {
|
||||
menuBuilder.item(_("Add Dependency"), "/common/img/ico_dependency.png",
|
||||
new ItemAction<TaskComponent>() {
|
||||
@Override
|
||||
public void onEvent(TaskComponent choosen, Event event) {
|
||||
choosen.addDependency();
|
||||
}
|
||||
});
|
||||
|
||||
menuBuilder.item(
|
||||
_("Add Dependency"), "/common/img/ico_dependency.png",
|
||||
(chosen, event) -> chosen.addDependency());
|
||||
}
|
||||
|
||||
for (CommandOnTaskContextualized<?> command : commandsOnTasksContextualized) {
|
||||
if ( command.accepts(taskComponent) ) {
|
||||
menuBuilder.item(command.getName(), command.getIcon(), command.toItemAction());
|
||||
menuBuilder.item(command.getName(), command.getIcon(), command.toItemAction());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,12 +33,26 @@ import org.zkoss.ganttz.data.IDependency;
|
|||
|
||||
/**
|
||||
* Represents a dependency in the domain.
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*/
|
||||
public class DomainDependency<T> implements IDependency<T> {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(DomainDependency.class);
|
||||
|
||||
private final T source;
|
||||
|
||||
private final T destination;
|
||||
|
||||
private final DependencyType type;
|
||||
|
||||
private DomainDependency(T source, T destination, DependencyType type) {
|
||||
super();
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static <T> List<Dependency> toDependencies(
|
||||
IDomainAndBeansMapper<T> mapper, Collection<DomainDependency<T>> dependencies) {
|
||||
|
||||
|
|
@ -55,20 +69,7 @@ public class DomainDependency<T> implements IDependency<T> {
|
|||
}
|
||||
|
||||
public static <T> DomainDependency<T> createDependency(T source, T destination, DependencyType type) {
|
||||
return new DomainDependency<T>(source, destination, type);
|
||||
}
|
||||
|
||||
private final T source;
|
||||
|
||||
private final T destination;
|
||||
|
||||
private final DependencyType type;
|
||||
|
||||
private DomainDependency(T source, T destination, DependencyType type) {
|
||||
super();
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
this.type = type;
|
||||
return new DomainDependency<>(source, destination, type);
|
||||
}
|
||||
|
||||
public T getSource() {
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@ import org.zkoss.ganttz.extensions.ICommand;
|
|||
import org.zkoss.ganttz.extensions.ICommandOnTask;
|
||||
import org.zkoss.ganttz.extensions.IContext;
|
||||
import org.zkoss.ganttz.extensions.IContextWithPlannerTask;
|
||||
import org.zkoss.ganttz.timetracker.zoom.IDetailItemModificator;
|
||||
import org.zkoss.ganttz.timetracker.zoom.SeveralModificators;
|
||||
import org.zkoss.ganttz.timetracker.zoom.IDetailItemModifier;
|
||||
import org.zkoss.ganttz.timetracker.zoom.SeveralModifiers;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
|
||||
/**
|
||||
* A object that defines several extension points for gantt planner
|
||||
* A object that defines several extension points for gantt planner.
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
|
|
@ -68,7 +68,7 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
|
|||
|
||||
@Override
|
||||
public void doAction(IContext<T> context) {
|
||||
// do nothing
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -97,7 +97,7 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
|
|||
|
||||
@Override
|
||||
public void doAction(IContextWithPlannerTask<T> context, T task) {
|
||||
// do nothing
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -165,11 +165,9 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
|
|||
|
||||
private boolean treeEditable = true;
|
||||
|
||||
// private String identifier = null;
|
||||
private IDetailItemModifier firstLevelModifiers = SeveralModifiers.empty();
|
||||
|
||||
private IDetailItemModificator firstLevelModificators = SeveralModificators.empty();
|
||||
|
||||
private IDetailItemModificator secondLevelModificators = SeveralModificators.empty();
|
||||
private IDetailItemModifier secondLevelModifiers = SeveralModifiers.empty();
|
||||
|
||||
private List<IReloadChartListener> reloadChartListeners = new ArrayList<>();
|
||||
|
||||
|
|
@ -395,20 +393,20 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
|
|||
return renamingTasksEnabled;
|
||||
}
|
||||
|
||||
public IDetailItemModificator getSecondLevelModificators() {
|
||||
return secondLevelModificators;
|
||||
public IDetailItemModifier getSecondLevelModifiers() {
|
||||
return secondLevelModifiers;
|
||||
}
|
||||
|
||||
public void setSecondLevelModificators(IDetailItemModificator... secondLevelModificators) {
|
||||
this.secondLevelModificators = SeveralModificators.create(secondLevelModificators);
|
||||
public void setSecondLevelModifiers(IDetailItemModifier... secondLevelModifiers) {
|
||||
this.secondLevelModifiers = SeveralModifiers.create(secondLevelModifiers);
|
||||
}
|
||||
|
||||
public IDetailItemModificator getFirstLevelModificators() {
|
||||
return firstLevelModificators;
|
||||
public IDetailItemModifier getFirstLevelModifiers() {
|
||||
return firstLevelModifiers;
|
||||
}
|
||||
|
||||
public void setFirstLevelModificators(IDetailItemModificator... firstLevelModificators) {
|
||||
this.firstLevelModificators = SeveralModificators.create(firstLevelModificators);
|
||||
public void setFirstLevelModifiers(IDetailItemModifier... firstLevelModifiers) {
|
||||
this.firstLevelModifiers = SeveralModifiers.create(firstLevelModifiers);
|
||||
}
|
||||
|
||||
public void addReloadChartListener(IReloadChartListener reloadChartListener) {
|
||||
|
|
|
|||
|
|
@ -126,14 +126,7 @@ public abstract class Task implements ITaskFundamentalProperties {
|
|||
|
||||
@Override
|
||||
public void doPositionModifications(final IModifications modifications) {
|
||||
fundamentalProperties.doPositionModifications(new IModifications() {
|
||||
|
||||
@Override
|
||||
public void doIt(IUpdatablePosition p) {
|
||||
modifications.doIt(position);
|
||||
|
||||
}
|
||||
});
|
||||
fundamentalProperties.doPositionModifications(p -> modifications.doIt(position));
|
||||
}
|
||||
|
||||
private final IUpdatablePosition position = new IUpdatablePosition() {
|
||||
|
|
@ -174,12 +167,7 @@ public abstract class Task implements ITaskFundamentalProperties {
|
|||
|
||||
private IUpdatablePosition getFundamentalPropertiesPosition() {
|
||||
final IUpdatablePosition[] result = new IUpdatablePosition[1];
|
||||
fundamentalProperties.doPositionModifications(new IModifications() {
|
||||
@Override
|
||||
public void doIt(IUpdatablePosition position) {
|
||||
result[0] = position;
|
||||
}
|
||||
});
|
||||
fundamentalProperties.doPositionModifications(position1 -> result[0] = position1);
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
|
@ -342,12 +330,7 @@ public abstract class Task implements ITaskFundamentalProperties {
|
|||
return;
|
||||
}
|
||||
|
||||
doPositionModifications(new IModifications() {
|
||||
@Override
|
||||
public void doIt(IUpdatablePosition position) {
|
||||
position.resizeTo(GanttDate.createFrom(date));
|
||||
}
|
||||
});
|
||||
doPositionModifications(position1 -> position1.resizeTo(GanttDate.createFrom(date)));
|
||||
}
|
||||
|
||||
public void removed() {
|
||||
|
|
|
|||
|
|
@ -37,18 +37,18 @@ import org.zkoss.zk.ui.util.Clients;
|
|||
*/
|
||||
public class TaskContainer extends Task {
|
||||
|
||||
public TaskContainer(ITaskFundamentalProperties fundamentalProperties,
|
||||
boolean expanded) {
|
||||
public TaskContainer(ITaskFundamentalProperties fundamentalProperties, boolean expanded) {
|
||||
super(fundamentalProperties);
|
||||
this.expanded = expanded;
|
||||
}
|
||||
|
||||
public interface IExpandListener {
|
||||
public void expandStateChanged(boolean isNowExpanded);
|
||||
void expandStateChanged(boolean isNowExpanded);
|
||||
}
|
||||
|
||||
private static <T> List<T> removeNulls(Collection<T> elements) {
|
||||
ArrayList<T> result = new ArrayList<T>();
|
||||
ArrayList<T> result = new ArrayList<>();
|
||||
|
||||
for (T e : elements) {
|
||||
if (e != null) {
|
||||
result.add(e);
|
||||
|
|
@ -57,22 +57,19 @@ public class TaskContainer extends Task {
|
|||
return result;
|
||||
}
|
||||
|
||||
private static <T extends Comparable<? super T>> T getSmallest(
|
||||
Collection<T> elements) {
|
||||
private static <T extends Comparable<? super T>> T getSmallest(Collection<T> elements) {
|
||||
return Collections.min(removeNulls(elements));
|
||||
}
|
||||
|
||||
private static <T extends Comparable<? super T>> T getBiggest(
|
||||
Collection<T> elements) {
|
||||
private static <T extends Comparable<? super T>> T getBiggest(Collection<T> elements) {
|
||||
return Collections.max(removeNulls(elements));
|
||||
}
|
||||
|
||||
private List<Task> tasks = new ArrayList<Task>();
|
||||
private List<Task> tasks = new ArrayList<>();
|
||||
|
||||
private boolean expanded = false;
|
||||
|
||||
private WeakReferencedListeners<IExpandListener> expandListeners = WeakReferencedListeners
|
||||
.create();
|
||||
private WeakReferencedListeners<IExpandListener> expandListeners = WeakReferencedListeners.create();
|
||||
|
||||
public void addExpandListener(IExpandListener expandListener) {
|
||||
expandListeners.addListener(expandListener);
|
||||
|
|
@ -89,17 +86,20 @@ public class TaskContainer extends Task {
|
|||
}
|
||||
|
||||
private List<GanttDate> getEndDates() {
|
||||
ArrayList<GanttDate> result = new ArrayList<GanttDate>();
|
||||
ArrayList<GanttDate> result = new ArrayList<>();
|
||||
|
||||
for (Task task : tasks) {
|
||||
result.add(task.getEndDate());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public GanttDate getBiggestDateFromChildren() {
|
||||
if (tasks.isEmpty()) {
|
||||
if ( tasks.isEmpty() ) {
|
||||
return getEndDate();
|
||||
}
|
||||
|
||||
return getBiggest(getEndDates());
|
||||
}
|
||||
|
||||
|
|
@ -111,9 +111,11 @@ public class TaskContainer extends Task {
|
|||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
super.setVisible(visible);
|
||||
if (!this.expanded) {
|
||||
|
||||
if ( !this.expanded ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Task task : tasks) {
|
||||
task.setVisible(true);
|
||||
}
|
||||
|
|
@ -133,6 +135,7 @@ public class TaskContainer extends Task {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
refreshTooltips();
|
||||
}
|
||||
|
||||
|
|
@ -171,10 +174,12 @@ public class TaskContainer extends Task {
|
|||
|
||||
@Override
|
||||
public List<Task> getAllTaskLeafs() {
|
||||
List<Task> result = new ArrayList<Task>();
|
||||
List<Task> result = new ArrayList<>();
|
||||
|
||||
for (Task task : tasks) {
|
||||
result.addAll(task.getAllTaskLeafs());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ package org.zkoss.ganttz.data.resourceload;
|
|||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
/**
|
||||
* Represents level of load of some {@link Resource}.
|
||||
*/
|
||||
public class LoadLevel {
|
||||
|
||||
public enum Category {
|
||||
|
|
@ -56,6 +59,7 @@ public class LoadLevel {
|
|||
};
|
||||
|
||||
protected abstract boolean contains(int percentage);
|
||||
|
||||
public static Category categoryFor(int percentage) {
|
||||
for (Category category : values()) {
|
||||
if ( category.contains(percentage) ) {
|
||||
|
|
|
|||
|
|
@ -37,30 +37,17 @@ public class LoadTimeLine {
|
|||
@SuppressWarnings("unchecked")
|
||||
private static final Comparator<GanttDate> nullSafeComparator = new NullComparator<>(false);
|
||||
|
||||
public static Comparator<LoadTimeLine> byStartAndEndDate() {
|
||||
return new Comparator<LoadTimeLine>() {
|
||||
@Override
|
||||
public int compare(LoadTimeLine o1, LoadTimeLine o2) {
|
||||
int result = nullSafeComparator.compare(o1.getStartPeriod(), o2.getStartPeriod());
|
||||
|
||||
if ( result == 0 ) {
|
||||
return nullSafeComparator.compare(o1.getEndPeriod(), o2.getEndPeriod());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final String conceptName;
|
||||
|
||||
private final List<LoadPeriod> loadPeriods;
|
||||
|
||||
private final TimeLineRole<?> timeLineRole;
|
||||
|
||||
private final String type;
|
||||
|
||||
private final List<LoadTimeLine> children;
|
||||
|
||||
|
||||
public LoadTimeLine(String conceptName,
|
||||
List<LoadPeriod> loadPeriods,
|
||||
TimeLineRole<?> role) {
|
||||
|
|
@ -101,6 +88,22 @@ public class LoadTimeLine {
|
|||
|
||||
}
|
||||
|
||||
public static Comparator<LoadTimeLine> byStartAndEndDate() {
|
||||
return new Comparator<LoadTimeLine>() {
|
||||
@Override
|
||||
public int compare(LoadTimeLine o1, LoadTimeLine o2) {
|
||||
int result = nullSafeComparator.compare(o1.getStartPeriod(), o2.getStartPeriod());
|
||||
|
||||
if ( result == 0 ) {
|
||||
return nullSafeComparator.compare(o1.getEndPeriod(), o2.getEndPeriod());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public List<LoadPeriod> getLoadPeriods() {
|
||||
return loadPeriods;
|
||||
}
|
||||
|
|
@ -122,11 +125,7 @@ public class LoadTimeLine {
|
|||
}
|
||||
|
||||
public GanttDate getStartPeriod() {
|
||||
if ( isEmpty() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getFirst().getStart();
|
||||
return isEmpty() ? null : getFirst().getStart();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
|
|
@ -134,11 +133,7 @@ public class LoadTimeLine {
|
|||
}
|
||||
|
||||
public GanttDate getEndPeriod() {
|
||||
if ( isEmpty() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getLast().getEnd();
|
||||
return isEmpty() ? null : getLast().getEnd();
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
|
|
@ -192,7 +187,7 @@ public class LoadTimeLine {
|
|||
}
|
||||
|
||||
public boolean hasChildren() {
|
||||
return (!children.isEmpty());
|
||||
return !children.isEmpty();
|
||||
}
|
||||
|
||||
public List<LoadTimeLine> getChildren() {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
package org.zkoss.ganttz.data.resourceload;
|
||||
|
||||
import org.zkoss.ganttz.i18n.I18nHelper;
|
||||
|
||||
/**
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
|
|
@ -39,7 +37,7 @@ public class TimeLineRole<T> {
|
|||
}
|
||||
|
||||
public boolean isVisibleScheduled() {
|
||||
return type != null ? type.isVisibleScheduled() : false;
|
||||
return type != null && type.isVisibleScheduled();
|
||||
}
|
||||
|
||||
public T getEntity() {
|
||||
|
|
@ -55,7 +53,10 @@ public class TimeLineRole<T> {
|
|||
*/
|
||||
public enum TimeLineRoleEnum {
|
||||
|
||||
NONE(_("None")), WORKER(_("Worker")), ORDER(_("Project")), TASK(_("Task")) {
|
||||
NONE(_("None")),
|
||||
WORKER(_("Worker")),
|
||||
ORDER(_("Project")),
|
||||
TASK(_("Task")) {
|
||||
@Override
|
||||
public boolean isVisibleScheduled() {
|
||||
return true;
|
||||
|
|
@ -63,19 +64,19 @@ public class TimeLineRole<T> {
|
|||
},
|
||||
CRITERION(_("Criterion"));
|
||||
|
||||
private String name;
|
||||
|
||||
TimeLineRoleEnum(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces to mark the string as needing translation
|
||||
* Forces to mark the string as needing translation.
|
||||
*/
|
||||
private static String _(String string) {
|
||||
return string;
|
||||
}
|
||||
|
||||
private String name;
|
||||
|
||||
private TimeLineRoleEnum(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static TimeLineRoleEnum create(String name) {
|
||||
TimeLineRoleEnum requiredTimeLineRole = TimeLineRoleEnum.NONE;
|
||||
if (name != null) {
|
||||
|
|
@ -88,8 +89,9 @@ public class TimeLineRole<T> {
|
|||
return requiredTimeLineRole;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return I18nHelper._(this.name);
|
||||
return _(this.name);
|
||||
}
|
||||
|
||||
public boolean isVisibleScheduled() {
|
||||
|
|
|
|||
|
|
@ -23,25 +23,24 @@ package org.zkoss.ganttz.extensions;
|
|||
|
||||
|
||||
/**
|
||||
* An action that can be applied to the planner and it's wanted to be available
|
||||
* to the user <br />
|
||||
* An action that can be applied to the planner and it's wanted to be available to the user <br />
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public interface ICommand<T> {
|
||||
|
||||
public String getName();
|
||||
String getName();
|
||||
|
||||
public void doAction(IContext<T> context);
|
||||
void doAction(IContext<T> context);
|
||||
|
||||
public String getImage();
|
||||
String getImage();
|
||||
|
||||
boolean isDisabled();
|
||||
|
||||
/**
|
||||
* Describes if a command is for the planner toolbar. Otherwise it'll be
|
||||
* inserted in the common toolbar.
|
||||
* Describes if a command is for the planner toolbar.
|
||||
* Otherwise it will be inserted in the common toolbar.
|
||||
*/
|
||||
boolean isPlannerCommand();
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class I18nHelper {
|
|||
private static HashMap<Locale, I18n> localesCache = new HashMap<>();
|
||||
|
||||
public static I18n getI18n() {
|
||||
if ( localesCache.keySet().contains(Locales.getCurrent()) ) {
|
||||
if (localesCache.keySet().contains(Locales.getCurrent())) {
|
||||
return localesCache.get(Locales.getCurrent());
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +48,15 @@ public class I18nHelper {
|
|||
|
||||
return i18n;
|
||||
}
|
||||
// TODO refactor symbol _
|
||||
|
||||
|
||||
//TODO It should be changed since JDK9.
|
||||
/**
|
||||
* Use of '_' as an identifier might not be supported in releases after Java SE 8.
|
||||
*
|
||||
* @param str
|
||||
* @return Text depends on locale
|
||||
*/
|
||||
public static String _(String str) {
|
||||
return getI18n().tr(str);
|
||||
}
|
||||
|
|
@ -65,8 +73,7 @@ public class I18nHelper {
|
|||
return getI18n().tr(text, o1, o2, o3);
|
||||
}
|
||||
|
||||
public static String _(String text, Object o1, Object o2, Object o3,
|
||||
Object o4) {
|
||||
public static String _(String text, Object o1, Object o2, Object o3, Object o4) {
|
||||
return getI18n().tr(text, o1, o2, o3, o4);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,6 @@ package org.zkoss.ganttz.resourceload;
|
|||
|
||||
public interface IFilterChangedListener {
|
||||
|
||||
public void filterChanged(boolean filter);
|
||||
void filterChanged(boolean filter);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,6 @@ package org.zkoss.ganttz.resourceload;
|
|||
|
||||
public interface IPaginationFilterChangedListener {
|
||||
|
||||
public void filterChanged(int initialPosition);
|
||||
void filterChanged(int initialPosition);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,6 @@ import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
|
|||
|
||||
public interface ISeeScheduledOfListener {
|
||||
|
||||
public void seeScheduleOf(LoadTimeLine taskLine);
|
||||
void seeScheduleOf(LoadTimeLine taskLine);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,11 +36,7 @@ import org.zkoss.ganttz.timetracker.TimeTracker;
|
|||
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
||||
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
||||
import org.zkoss.ganttz.util.MenuBuilder;
|
||||
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.sys.ContentRenderer;
|
||||
import org.zkoss.zul.Div;
|
||||
import org.zkoss.zul.Menupopup;
|
||||
|
|
@ -48,38 +44,54 @@ import org.zkoss.zul.impl.XulElement;
|
|||
|
||||
/**
|
||||
* This class wraps ResourceLoad data inside an specific HTML Div component.
|
||||
*
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||
*/
|
||||
public class ResourceLoadComponent extends XulElement {
|
||||
|
||||
public static ResourceLoadComponent create(TimeTracker timeTracker,
|
||||
LoadTimeLine loadLine) {
|
||||
return new ResourceLoadComponent(timeTracker, loadLine);
|
||||
}
|
||||
|
||||
private final LoadTimeLine loadLine;
|
||||
private final TimeTracker timeTracker;
|
||||
private transient IZoomLevelChangedListener zoomChangedListener;
|
||||
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners
|
||||
.create();
|
||||
|
||||
private ResourceLoadComponent(final TimeTracker timeTracker,
|
||||
final LoadTimeLine loadLine) {
|
||||
private final TimeTracker timeTracker;
|
||||
|
||||
private transient IZoomLevelChangedListener zoomChangedListener;
|
||||
|
||||
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners.create();
|
||||
|
||||
private Map<Div, Menupopup> contextMenus = new HashMap<>();
|
||||
|
||||
private ResourceLoadComponent(final TimeTracker timeTracker, final LoadTimeLine loadLine) {
|
||||
this.loadLine = loadLine;
|
||||
this.timeTracker = timeTracker;
|
||||
createChildren(loadLine, timeTracker.getMapper());
|
||||
|
||||
/* Do not replace it with lambda */
|
||||
zoomChangedListener = new IZoomLevelChangedListener() {
|
||||
|
||||
/**
|
||||
* In general it is working like, on every zoomChanged :
|
||||
* 1. Remove all LoadLines ( divs ).
|
||||
* 2. Create new ones ( for selected zoom mode ).
|
||||
* 3. Redraw insertionPointRightPanel component ( Div ).
|
||||
*/
|
||||
@Override
|
||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||
getChildren().clear();
|
||||
createChildren(loadLine, timeTracker.getMapper());
|
||||
if ( !getFellows().isEmpty() ) {
|
||||
getFellow("insertionPointRightPanel").invalidate();
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
this.timeTracker.addZoomListener(zoomChangedListener);
|
||||
}
|
||||
|
||||
public static ResourceLoadComponent create(TimeTracker timeTracker, LoadTimeLine loadLine) {
|
||||
return new ResourceLoadComponent(timeTracker, loadLine);
|
||||
}
|
||||
|
||||
private void createChildren(final LoadTimeLine loadLine, IDatesMapper mapper) {
|
||||
List<Div> divs = createDivsForPeriods(mapper, loadLine.getLoadPeriods());
|
||||
for (Div div : divs) {
|
||||
|
|
@ -95,71 +107,50 @@ public class ResourceLoadComponent extends XulElement {
|
|||
}
|
||||
|
||||
private void addDoubleClickAction(final Div div, final LoadTimeLine loadLine) {
|
||||
div.addEventListener("onDoubleClick", new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
schedule(loadLine);
|
||||
}
|
||||
});
|
||||
div.addEventListener("onDoubleClick", event -> schedule(loadLine));
|
||||
}
|
||||
|
||||
private void addContextMenu(final List<Div> divs, final Div div,
|
||||
final LoadTimeLine loadLine) {
|
||||
private void addContextMenu(final List<Div> divs, final Div div, final LoadTimeLine loadLine) {
|
||||
/*
|
||||
* This EventListener could be replaced with
|
||||
* div.setContext(getContextMenuFor(divs, div, loadLine)) but
|
||||
* on this case this is not valid as we'll got an exception.
|
||||
* in this case this is not valid as we'll got an exception.
|
||||
*
|
||||
* As this component (ResourceLoadComponent) hasn't be added to
|
||||
* a page yet, its getPage() method will return null and a
|
||||
* non-null page is required by MenuBuilder or a NullPointerException
|
||||
* will be raised.
|
||||
* */
|
||||
div.addEventListener("onRightClick", new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
try {
|
||||
getContextMenuFor(divs, div, loadLine).open(div);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
* non-null page is required by MenuBuilder or a NullPointerException will be raised.
|
||||
*/
|
||||
|
||||
div.addEventListener("onRightClick", event -> {
|
||||
try {
|
||||
getContextMenuFor(divs, div, loadLine).open(div);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void schedule(final LoadTimeLine taskLine) {
|
||||
|
||||
scheduleListeners
|
||||
.fireEvent(new IListenerNotification<ISeeScheduledOfListener>() {
|
||||
@Override
|
||||
public void doNotify(ISeeScheduledOfListener listener) {
|
||||
listener.seeScheduleOf(taskLine);
|
||||
}
|
||||
});
|
||||
scheduleListeners.fireEvent(listener -> listener.seeScheduleOf(taskLine));
|
||||
}
|
||||
|
||||
public void addSeeScheduledOfListener(
|
||||
ISeeScheduledOfListener seeScheduledOfListener) {
|
||||
public void addSeeScheduledOfListener(ISeeScheduledOfListener seeScheduledOfListener) {
|
||||
scheduleListeners.addListener(seeScheduledOfListener);
|
||||
}
|
||||
|
||||
private Map<Div, Menupopup> contextMenus = new HashMap<Div, Menupopup>();
|
||||
|
||||
private Menupopup getContextMenuFor(final List<Div> divs, final Div div,
|
||||
final LoadTimeLine loadLine) {
|
||||
private Menupopup getContextMenuFor(final List<Div> divs, final Div div, final LoadTimeLine loadLine) {
|
||||
if (contextMenus.get(div) == null) {
|
||||
|
||||
MenuBuilder<Div> menuBuilder = MenuBuilder.on(getPage(), divs);
|
||||
menuBuilder.item(_("See resource allocation"),
|
||||
"/common/img/ico_allocation.png", new ItemAction<Div>() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Div choosen, Event event) {
|
||||
schedule(loadLine);
|
||||
}
|
||||
});
|
||||
menuBuilder.item(
|
||||
_("See resource allocation"),
|
||||
"/common/img/ico_allocation.png",
|
||||
(chosen, event) -> schedule(loadLine));
|
||||
|
||||
Menupopup result = menuBuilder.createWithoutSettingContext();
|
||||
contextMenus.put(div, result);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
|
@ -174,52 +165,56 @@ public class ResourceLoadComponent extends XulElement {
|
|||
return loadLine.getType();
|
||||
}
|
||||
|
||||
LoadTimeLine getLoadLine() {
|
||||
return loadLine;
|
||||
}
|
||||
|
||||
private static List<Div> createDivsForPeriods(IDatesMapper datesMapper,
|
||||
List<LoadPeriod> loadPeriods) {
|
||||
List<Div> result = new ArrayList<Div>();
|
||||
private static List<Div> createDivsForPeriods(IDatesMapper datesMapper, List<LoadPeriod> loadPeriods) {
|
||||
List<Div> result = new ArrayList<>();
|
||||
for (LoadPeriod loadPeriod : loadPeriods) {
|
||||
result.add(createDivForPeriod(datesMapper, loadPeriod));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Div createDivForPeriod(IDatesMapper datesMapper,
|
||||
LoadPeriod loadPeriod) {
|
||||
private static Div createDivForPeriod(IDatesMapper datesMapper, LoadPeriod loadPeriod) {
|
||||
Div result = new Div();
|
||||
result.setClass(String.format("taskassignmentinterval %s", loadPeriod
|
||||
.getLoadLevel().getCategory()));
|
||||
result.setClass(String.format("taskassignmentinterval %s", loadPeriod.getLoadLevel().getCategory()));
|
||||
|
||||
String load = _("Load: {0}%", loadPeriod.getLoadLevel().getPercentage()) + ", ";
|
||||
|
||||
String load = _("Load: {0}%", loadPeriod.getLoadLevel().getPercentage())
|
||||
+ ", ";
|
||||
if (loadPeriod.getLoadLevel().getPercentage() == Integer.MAX_VALUE) {
|
||||
load = "";
|
||||
}
|
||||
result.setTooltiptext(load
|
||||
+ _("available effort: {0}, assigned effort: {1}",
|
||||
loadPeriod.getAvailableEffort(),
|
||||
loadPeriod.getAssignedEffort()));
|
||||
|
||||
result.setTooltiptext(
|
||||
load +
|
||||
_("available effort: {0}, assigned effort: {1}",
|
||||
loadPeriod.getAvailableEffort(),
|
||||
loadPeriod.getAssignedEffort()));
|
||||
|
||||
result.setLeft(forCSS(getStartPixels(datesMapper, loadPeriod)));
|
||||
result.setWidth(forCSS(getWidthPixels(datesMapper, loadPeriod)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int getWidthPixels(IDatesMapper datesMapper,
|
||||
LoadPeriod loadPeriod) {
|
||||
return Math.max(loadPeriod.getEnd().toPixels(datesMapper)
|
||||
- getStartPixels(datesMapper, loadPeriod), 0);
|
||||
private static int getWidthPixels(IDatesMapper datesMapper, LoadPeriod loadPeriod) {
|
||||
return Math.max(loadPeriod.getEnd().toPixels(datesMapper) - getStartPixels(datesMapper, loadPeriod), 0);
|
||||
}
|
||||
|
||||
private static String forCSS(int pixels) {
|
||||
return String.format("%dpx", pixels);
|
||||
}
|
||||
|
||||
private static int getStartPixels(IDatesMapper datesMapper,
|
||||
LoadPeriod loadPeriod) {
|
||||
private static int getStartPixels(IDatesMapper datesMapper, LoadPeriod loadPeriod) {
|
||||
return loadPeriod.getStart().toPixels(datesMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* It is drawing chart on right pane for each ResourceLoad row.
|
||||
*/
|
||||
@Override
|
||||
protected void renderProperties(ContentRenderer renderer) throws IOException{
|
||||
render(renderer, "_resourceLoadName", getResourceLoadName());
|
||||
render(renderer, "_resourceLoadType", getResourceLoadType());
|
||||
|
|
|
|||
|
|
@ -24,65 +24,106 @@ package org.zkoss.ganttz.resourceload;
|
|||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
|
||||
import org.zkoss.ganttz.util.MutableTreeModel;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.OpenEvent;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Div;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Popup;
|
||||
import org.zkoss.zul.Treecell;
|
||||
import org.zkoss.zul.Treechildren;
|
||||
import org.zkoss.zul.Treeitem;
|
||||
import org.zkoss.zul.TreeitemRenderer;
|
||||
import org.zkoss.zul.Treerow;
|
||||
import org.zkoss.zul.api.Tree;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Div;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Tree;
|
||||
import org.zkoss.zul.Treechildren;
|
||||
|
||||
/**
|
||||
* Works with left pane of Resource Load page. Also works with right pane ( a little bit ).
|
||||
*
|
||||
* @author Óscar González Fernández
|
||||
* @author Manuel Rego Casasnovas
|
||||
* @author Susana Montes Pedreira
|
||||
* @author Lorenzo Tilve
|
||||
* @author Jacobo Aragunde Pérez
|
||||
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||
*/
|
||||
public class ResourceLoadLeftPane extends HtmlMacroComponent {
|
||||
|
||||
private MutableTreeModel<LoadTimeLine> modelForTree;
|
||||
|
||||
private final ResourceLoadList resourceLoadList;
|
||||
|
||||
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners
|
||||
.create();
|
||||
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners.create();
|
||||
|
||||
public ResourceLoadLeftPane(
|
||||
MutableTreeModel<LoadTimeLine> modelForTree,
|
||||
ResourceLoadList resourceLoadList) {
|
||||
/**
|
||||
* {@link ResourceLoadLeftPane#onOpenEventQueue}, {@link OnOpenEvent} and proceedOnOpenEventQueue()
|
||||
* were created because of problem:
|
||||
* after migration from ZK5 to ZK8 onOpen event had been calling before render().
|
||||
* It produced a problem.
|
||||
* On onOpen event we are calculating closest items to treeItem.
|
||||
* render() was not called so, treeItem row had no value.
|
||||
* It made calculatedClosedItems(treeItem).isEmpty() to return true, even if it is not!
|
||||
*
|
||||
* http://forum.zkoss.org/question/101294/event-before-render-treeitem/
|
||||
*/
|
||||
private OnOpenEvent onOpenEventQueue = null;
|
||||
|
||||
/**
|
||||
* Made to know if {@link LoadTimeLine} was rendered.
|
||||
*/
|
||||
private HashSet<LoadTimeLine> renderedLines;
|
||||
|
||||
|
||||
public ResourceLoadLeftPane(MutableTreeModel<LoadTimeLine> modelForTree, ResourceLoadList resourceLoadList) {
|
||||
this.resourceLoadList = resourceLoadList;
|
||||
this.modelForTree = modelForTree;
|
||||
this.renderedLines = new HashSet<>();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterCompose() {
|
||||
super.afterCompose();
|
||||
|
||||
getContainerTree().setModel(modelForTree);
|
||||
getContainerTree().setTreeitemRenderer(getRendererForTree());
|
||||
getContainerTree().setItemRenderer(getRendererForTree());
|
||||
|
||||
/* Force call overridden render() */
|
||||
try {
|
||||
if ( !this.resourceLoadList.getChildren().isEmpty() ) {
|
||||
getRendererForTree().render(
|
||||
new Treeitem(""),
|
||||
((ResourceLoadComponent) this.resourceLoadList.getFirstChild()).getLoadLine(),
|
||||
0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private TreeitemRenderer getRendererForTree() {
|
||||
return new TreeitemRenderer() {
|
||||
@Override
|
||||
public void render(Treeitem item, Object data)
|
||||
{
|
||||
LoadTimeLine line = (LoadTimeLine) data;
|
||||
item.setOpen(false);
|
||||
item.setValue(line);
|
||||
public void render(Treeitem treeitem, Object o, int index) throws Exception {
|
||||
LoadTimeLine line = (LoadTimeLine) o;
|
||||
treeitem.setOpen(false);
|
||||
treeitem.setValue(line);
|
||||
|
||||
Treerow row = new Treerow();
|
||||
Treecell cell = new Treecell();
|
||||
Component component = createComponent(line);
|
||||
item.appendChild(row);
|
||||
|
||||
/* Clear existing Treerows */
|
||||
if ( !treeitem.getChildren().isEmpty() ) {
|
||||
treeitem.getChildren().clear();
|
||||
}
|
||||
|
||||
treeitem.appendChild(row);
|
||||
row.appendChild(cell);
|
||||
|
||||
appendOperations(cell, line);
|
||||
|
|
@ -90,70 +131,86 @@ MutableTreeModel<LoadTimeLine> modelForTree,
|
|||
cell.appendChild(component);
|
||||
|
||||
collapse(line);
|
||||
addExpandedListener(item, line);
|
||||
addExpandedListener(treeitem, line);
|
||||
|
||||
row.setSclass("resourceload-leftpanel-row");
|
||||
|
||||
if ( onOpenEventQueue != null ) {
|
||||
processOnOpenEventQueue();
|
||||
}
|
||||
|
||||
renderedLines.add(line);
|
||||
}
|
||||
|
||||
private void appendOperations(final Treecell cell,
|
||||
final LoadTimeLine line) {
|
||||
if (line.getRole().isVisibleScheduled()) {
|
||||
private void processOnOpenEventQueue() {
|
||||
if ( onOpenEventQueue.event.isOpen() ) {
|
||||
List<LoadTimeLine> closed = calculatedClosedItems(onOpenEventQueue.treeitem);
|
||||
expand(onOpenEventQueue.line, closed);
|
||||
} else {
|
||||
collapse(onOpenEventQueue.line);
|
||||
}
|
||||
|
||||
/*
|
||||
* When queue processed, clean object, to make it kind of "unique" or "one time only".
|
||||
*/
|
||||
onOpenEventQueue = null;
|
||||
}
|
||||
|
||||
private void appendOperations(final Treecell cell, final LoadTimeLine line) {
|
||||
if ( line.getRole().isVisibleScheduled() ) {
|
||||
appendButtonPlan(cell, line);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendButtonPlan(final Treecell cell,
|
||||
final LoadTimeLine taskLine) {
|
||||
private void appendButtonPlan(final Treecell cell, final LoadTimeLine taskLine) {
|
||||
Button buttonPlan = new Button();
|
||||
buttonPlan.setSclass("icono");
|
||||
buttonPlan.setImage("/common/img/ico_planificador1.png");
|
||||
buttonPlan.setHoverImage("/common/img/ico_planificador.png");
|
||||
buttonPlan.setTooltiptext(_("See scheduling"));
|
||||
buttonPlan.addEventListener("onClick", new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
schedule(taskLine);
|
||||
}
|
||||
});
|
||||
buttonPlan.addEventListener("onClick", event -> schedule(taskLine));
|
||||
|
||||
cell.appendChild(buttonPlan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not replace it with lambda.
|
||||
*/
|
||||
public void schedule(final LoadTimeLine taskLine) {
|
||||
|
||||
scheduleListeners
|
||||
.fireEvent(new IListenerNotification<ISeeScheduledOfListener>() {
|
||||
scheduleListeners.fireEvent(
|
||||
new WeakReferencedListeners.IListenerNotification<ISeeScheduledOfListener>() {
|
||||
@Override
|
||||
public void doNotify(
|
||||
ISeeScheduledOfListener listener) {
|
||||
public void doNotify(ISeeScheduledOfListener listener) {
|
||||
listener.seeScheduleOf(taskLine);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addExpandedListener(final Treeitem item,
|
||||
final LoadTimeLine line) {
|
||||
item.addEventListener("onOpen", new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
OpenEvent openEvent = (OpenEvent) event;
|
||||
if (openEvent.isOpen()) {
|
||||
List<LoadTimeLine> closed = calculatedClosedItems(item);
|
||||
expand(line, closed);
|
||||
} else {
|
||||
collapse(line);
|
||||
private void addExpandedListener(final Treeitem item, final LoadTimeLine line) {
|
||||
item.addEventListener("onOpen", event -> {
|
||||
OpenEvent openEvent = (OpenEvent) event;
|
||||
|
||||
if ( openEvent.isOpen() ) {
|
||||
|
||||
onOpenEventQueue = new OnOpenEvent(item, line, openEvent);
|
||||
|
||||
/* If line was rendered than we need to call expand manually */
|
||||
if ( renderedLines.contains(line) ) {
|
||||
processOnOpenEventQueue();
|
||||
}
|
||||
|
||||
} else {
|
||||
collapse(line);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Component createComponent(LoadTimeLine line) {
|
||||
return isTopLevel(line) ? createFirstLevel(line)
|
||||
: createSecondLevel(line);
|
||||
return isTopLevel(line) ? createFirstLevel(line) : createSecondLevel(line);
|
||||
}
|
||||
|
||||
private boolean isTopLevel(LoadTimeLine line) {
|
||||
int[] path = modelForTree.getPath(modelForTree.getRoot(), line);
|
||||
return path.length == 0;
|
||||
return modelForTree.getPath(modelForTree.getRoot(), line).length == 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -167,40 +224,45 @@ MutableTreeModel<LoadTimeLine> modelForTree,
|
|||
}
|
||||
|
||||
private List<LoadTimeLine> calculatedClosedItems(Treeitem item) {
|
||||
List<LoadTimeLine> result = new ArrayList<LoadTimeLine>();
|
||||
List<LoadTimeLine> result = new ArrayList<>();
|
||||
Treechildren treeChildren = item.getTreechildren();
|
||||
if (treeChildren != null) {
|
||||
List<Treeitem> myTreeItems = (List<Treeitem>) treeChildren
|
||||
.getChildren();
|
||||
Iterator<Treeitem> iterator = myTreeItems.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Treeitem child = (Treeitem) iterator.next();
|
||||
if (!child.isOpen()) {
|
||||
|
||||
if ( treeChildren != null ) {
|
||||
|
||||
List<Treeitem> myTreeItems = treeChildren.getChildren();
|
||||
for (Treeitem child : myTreeItems) {
|
||||
|
||||
if ( !child.isOpen() ) {
|
||||
result.addAll(getLineChildrenBy(child));
|
||||
} else {
|
||||
result.addAll(calculatedClosedItems(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<LoadTimeLine> getLineChildrenBy(Treeitem item) {
|
||||
List<LoadTimeLine> result = new ArrayList<LoadTimeLine>();
|
||||
List<LoadTimeLine> result = new ArrayList<>();
|
||||
LoadTimeLine line = getLineByTreeitem(item);
|
||||
if (line != null) {
|
||||
|
||||
if ( line != null ) {
|
||||
result.addAll(line.getAllChildren());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private LoadTimeLine getLineByTreeitem(Treeitem child) {
|
||||
LoadTimeLine line = null;
|
||||
LoadTimeLine line;
|
||||
|
||||
try {
|
||||
line = (LoadTimeLine) child.getValue();
|
||||
line = child.getValue();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
|
|
@ -211,12 +273,14 @@ MutableTreeModel<LoadTimeLine> modelForTree,
|
|||
private Component createFirstLevel(LoadTimeLine main) {
|
||||
Div result = createLabelWithName(main);
|
||||
result.setSclass("firstlevel");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Component createSecondLevel(LoadTimeLine loadTimeLine) {
|
||||
Div result = createLabelWithName(loadTimeLine);
|
||||
result.setSclass("secondlevel");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -224,20 +288,32 @@ MutableTreeModel<LoadTimeLine> modelForTree,
|
|||
Div result = new Div();
|
||||
Label label = new Label();
|
||||
final String conceptName = main.getConceptName();
|
||||
|
||||
label.setValue(conceptName);
|
||||
result.appendChild(label);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Popup createPopup(Div parent, String originalValue) {
|
||||
Popup result = new Popup();
|
||||
result.appendChild(new Label(originalValue));
|
||||
parent.appendChild(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addSeeScheduledOfListener(
|
||||
ISeeScheduledOfListener seeScheduledOfListener) {
|
||||
public void addSeeScheduledOfListener(ISeeScheduledOfListener seeScheduledOfListener) {
|
||||
scheduleListeners.addListener(seeScheduledOfListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Info about onOpenEvent.
|
||||
*/
|
||||
private class OnOpenEvent {
|
||||
|
||||
private LoadTimeLine line;
|
||||
|
||||
private Treeitem treeitem;
|
||||
|
||||
private OpenEvent event;
|
||||
|
||||
OnOpenEvent(Treeitem treeitem, LoadTimeLine line, OpenEvent event) {
|
||||
this.line = line;
|
||||
this.treeitem = treeitem;
|
||||
this.event = event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,27 +40,26 @@ import org.zkoss.zul.impl.XulElement;
|
|||
|
||||
/**
|
||||
* Component to include a list of ResourceLoads inside the ResourcesLoadPanel.
|
||||
*
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||
*/
|
||||
public class ResourceLoadList extends XulElement {
|
||||
|
||||
private final IZoomLevelChangedListener zoomListener;
|
||||
private Map<LoadTimeLine, ResourceLoadComponent> fromTimeLineToComponent = new HashMap<>();
|
||||
|
||||
private Map<LoadTimeLine, ResourceLoadComponent> fromTimeLineToComponent = new HashMap<LoadTimeLine, ResourceLoadComponent>();
|
||||
|
||||
public ResourceLoadList(TimeTracker timeTracker,
|
||||
MutableTreeModel<LoadTimeLine> timelinesTree) {
|
||||
zoomListener = adjustTimeTrackerSizeListener();
|
||||
public ResourceLoadList(TimeTracker timeTracker, MutableTreeModel<LoadTimeLine> timelinesTree) {
|
||||
IZoomLevelChangedListener zoomListener = adjustTimeTrackerSizeListener();
|
||||
timeTracker.addZoomListener(zoomListener);
|
||||
LoadTimeLine current = timelinesTree.getRoot();
|
||||
List<LoadTimeLine> toInsert = new ArrayList<LoadTimeLine>();
|
||||
List<LoadTimeLine> toInsert = new ArrayList<>();
|
||||
fill(timelinesTree, current, toInsert);
|
||||
insertAsComponents(timeTracker, toInsert);
|
||||
}
|
||||
|
||||
private void fill(MutableTreeModel<LoadTimeLine> timelinesTree,
|
||||
LoadTimeLine current, List<LoadTimeLine> result) {
|
||||
private void fill(MutableTreeModel<LoadTimeLine> timelinesTree, LoadTimeLine current, List<LoadTimeLine> result) {
|
||||
final int length = timelinesTree.getChildCount(current);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
LoadTimeLine child = timelinesTree.getChild(current, i);
|
||||
result.add(child);
|
||||
|
|
@ -70,41 +69,48 @@ public class ResourceLoadList extends XulElement {
|
|||
|
||||
private IZoomLevelChangedListener adjustTimeTrackerSizeListener() {
|
||||
return new IZoomLevelChangedListener() {
|
||||
|
||||
@Override
|
||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||
response(null, new AuInvoke(ResourceLoadList.this,
|
||||
"adjustTimeTrackerSize"));
|
||||
response(null, new AuInvoke(ResourceLoadList.this,
|
||||
"adjustResourceLoadRows"));
|
||||
response(null, new AuInvoke(ResourceLoadList.this, "adjustTimeTrackerSize"));
|
||||
response(null, new AuInvoke(ResourceLoadList.this, "adjustResourceLoadRows"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void insertAsComponents(TimeTracker timetracker,
|
||||
List<LoadTimeLine> children) {
|
||||
private void insertAsComponents(TimeTracker timetracker, List<LoadTimeLine> children) {
|
||||
for (LoadTimeLine loadTimeLine : children) {
|
||||
ResourceLoadComponent component = ResourceLoadComponent.create(
|
||||
timetracker, loadTimeLine);
|
||||
ResourceLoadComponent component = ResourceLoadComponent.create(timetracker, loadTimeLine);
|
||||
appendChild(component);
|
||||
fromTimeLineToComponent.put(loadTimeLine, component);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On Resources Load page it will collapse inherited resources.
|
||||
*
|
||||
* @param line
|
||||
*/
|
||||
public void collapse(LoadTimeLine line) {
|
||||
for (LoadTimeLine l : line.getAllChildren()) {
|
||||
getComponentFor(l).detach();
|
||||
}
|
||||
|
||||
/* In ZK8, after detaching component, component will be still visible, so we need to redraw it */
|
||||
this.invalidate();
|
||||
|
||||
Clients.evalJavaScript(getWidgetClass() + ".getInstance().recalculateTimeTrackerHeight();");
|
||||
}
|
||||
|
||||
private ResourceLoadComponent getComponentFor(LoadTimeLine l) {
|
||||
ResourceLoadComponent resourceLoadComponent = fromTimeLineToComponent
|
||||
.get(l);
|
||||
return resourceLoadComponent;
|
||||
return fromTimeLineToComponent.get(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* On Resources Load page it will expand inherited resources.
|
||||
*
|
||||
* @param line
|
||||
* @param closed
|
||||
*/
|
||||
public void expand(LoadTimeLine line, List<LoadTimeLine> closed) {
|
||||
ResourceLoadComponent parentComponent = getComponentFor(line);
|
||||
Component nextSibling = parentComponent.getNextSibling();
|
||||
|
|
@ -118,19 +124,21 @@ public class ResourceLoadList extends XulElement {
|
|||
nextSibling = child;
|
||||
}
|
||||
|
||||
/* In ZK8, after detaching component, component will be still visible, so we need to redraw it */
|
||||
this.invalidate();
|
||||
|
||||
Clients.evalJavaScript(getWidgetClass() + ".getInstance().recalculateTimeTrackerHeight();");
|
||||
}
|
||||
|
||||
private List<LoadTimeLine> getChildrenReverseOrderFor(LoadTimeLine line) {
|
||||
List<LoadTimeLine> childrenOf = line.getAllChildren();
|
||||
Collections.reverse(childrenOf);
|
||||
|
||||
return childrenOf;
|
||||
}
|
||||
|
||||
public void addSeeScheduledOfListener(
|
||||
ISeeScheduledOfListener seeScheduledOfListener) {
|
||||
for (Entry<LoadTimeLine, ResourceLoadComponent> entry : fromTimeLineToComponent
|
||||
.entrySet()) {
|
||||
public void addSeeScheduledOfListener(ISeeScheduledOfListener seeScheduledOfListener) {
|
||||
for (Entry<LoadTimeLine, ResourceLoadComponent> entry : fromTimeLineToComponent.entrySet()) {
|
||||
entry.getValue().addSeeScheduledOfListener(seeScheduledOfListener);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,25 +38,24 @@ import org.zkoss.ganttz.util.LongOperationFeedback;
|
|||
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
||||
import org.zkoss.ganttz.util.MutableTreeModel;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
||||
import org.zkoss.zk.au.out.AuInvoke;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Comboitem;
|
||||
import org.zkoss.zul.ListModel;
|
||||
import org.zkoss.zul.Separator;
|
||||
import org.zkoss.zul.SimpleListModel;
|
||||
import org.zkoss.zul.api.Combobox;
|
||||
import org.zkoss.zul.api.Listbox;
|
||||
import org.zkoss.zul.api.South;
|
||||
import org.zkoss.zul.Combobox;
|
||||
import org.zkoss.zul.Listbox;
|
||||
import org.zkoss.zul.South;
|
||||
import org.zkoss.zul.Div;
|
||||
|
||||
public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||
|
||||
public interface IToolbarCommand {
|
||||
|
||||
void doAction();
|
||||
|
||||
String getLabel();
|
||||
|
|
@ -84,17 +83,24 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
|
||||
private WeakReferencedListeners<IFilterChangedListener> zoomListeners = WeakReferencedListeners.create();
|
||||
|
||||
private Listbox listZoomLevels;
|
||||
|
||||
private final String FILTER_RESOURCES = _("Resources");
|
||||
|
||||
private final String FILTER_CRITERIA = _("Generic allocation criteria");
|
||||
|
||||
private final String FILTER_BY_NAME_COMBO_COMPONENT = "filterByNameCombo";
|
||||
|
||||
private String feedBackMessage;
|
||||
|
||||
private Boolean filterbyResources;
|
||||
|
||||
private boolean refreshNameFilter = true;
|
||||
|
||||
private int filterByNamePosition = 0;
|
||||
|
||||
private int numberOfGroupsByName = 10;
|
||||
|
||||
private int lastSelectedName = 0;
|
||||
|
||||
private final PaginationType paginationType;
|
||||
|
||||
private WeakReferencedListeners<IPaginationFilterChangedListener> nameFilterListener =
|
||||
|
|
@ -113,12 +119,14 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
|
||||
private Component secondOptionalFilter;
|
||||
|
||||
public ResourcesLoadPanel(
|
||||
List<LoadTimeLine> groups,
|
||||
TimeTracker timeTracker,
|
||||
Component componentOnWhichGiveFeedback,
|
||||
boolean expandResourceLoadViewCharts,
|
||||
PaginationType paginationType) {
|
||||
private Combobox filterByNameCombo;
|
||||
|
||||
|
||||
public ResourcesLoadPanel(List<LoadTimeLine> groups,
|
||||
TimeTracker timeTracker,
|
||||
Component componentOnWhichGiveFeedback,
|
||||
boolean expandResourceLoadViewCharts,
|
||||
PaginationType paginationType) {
|
||||
|
||||
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
|
||||
this.expandResourceLoadViewCharts = expandResourceLoadViewCharts;
|
||||
|
|
@ -141,14 +149,12 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
return timeTracker;
|
||||
}
|
||||
|
||||
public ListModel getFilters() {
|
||||
String[] filters = new String[] { FILTER_RESOURCES, FILTER_CRITERIA };
|
||||
|
||||
return new SimpleListModel(filters);
|
||||
public ListModel<String> getFilters() {
|
||||
return new SimpleListModel<>(new String[] { FILTER_RESOURCES, FILTER_CRITERIA });
|
||||
}
|
||||
|
||||
public void setFilter(String filterby) {
|
||||
if ( filterby.equals(FILTER_RESOURCES) ) {
|
||||
public void setFilter(String filterBy) {
|
||||
if ( filterBy.equals(FILTER_RESOURCES) ) {
|
||||
this.filterbyResources = true;
|
||||
this.feedBackMessage = _("showing resources");
|
||||
} else {
|
||||
|
|
@ -184,27 +190,23 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
private void applyFilter() {
|
||||
zoomListeners.fireEvent(new IListenerNotification<IFilterChangedListener>() {
|
||||
@Override
|
||||
public void doNotify(IFilterChangedListener listener) {
|
||||
listener.filterChanged(getFilter());
|
||||
}
|
||||
});
|
||||
zoomListeners.fireEvent(listener -> listener.filterChanged(getFilter()));
|
||||
}
|
||||
|
||||
public void addFilterListener(IFilterChangedListener listener) {
|
||||
zoomListeners.addListener(listener);
|
||||
}
|
||||
|
||||
public ListModel getZoomLevels() {
|
||||
public ListModel<ZoomLevel> getZoomLevels() {
|
||||
ZoomLevel[] selectableZoomlevels = {
|
||||
ZoomLevel.DETAIL_ONE,
|
||||
ZoomLevel.DETAIL_TWO,
|
||||
ZoomLevel.DETAIL_THREE,
|
||||
ZoomLevel.DETAIL_FOUR,
|
||||
ZoomLevel.DETAIL_FIVE };
|
||||
ZoomLevel.DETAIL_FIVE
|
||||
};
|
||||
|
||||
return new SimpleListModel(selectableZoomlevels);
|
||||
return new SimpleListModel<>(selectableZoomlevels);
|
||||
}
|
||||
|
||||
public void setZoomLevel(final ZoomLevel zoomLevel) {
|
||||
|
|
@ -213,6 +215,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
timeTracker.setZoomLevel(zoomLevel);
|
||||
}
|
||||
|
||||
|
||||
public void zoomIncrease() {
|
||||
savePreviousData();
|
||||
getTimeTrackerComponent().updateDayScroll();
|
||||
|
|
@ -265,12 +268,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
private Button asButton(final IToolbarCommand c) {
|
||||
Button result = new Button();
|
||||
|
||||
result.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
c.doAction();
|
||||
}
|
||||
});
|
||||
result.addEventListener(Events.ON_CLICK, event -> c.doAction());
|
||||
|
||||
if ( !StringUtils.isEmpty(c.getImage()) ) {
|
||||
result.setImage(c.getImage());
|
||||
|
|
@ -290,13 +288,12 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
private Component getToolbar() {
|
||||
Component toolbar = getFellow("toolbar");
|
||||
|
||||
return toolbar;
|
||||
return getFellow("toolbar");
|
||||
}
|
||||
|
||||
private MutableTreeModel<LoadTimeLine> createModelForTree() {
|
||||
MutableTreeModel<LoadTimeLine> result = MutableTreeModel.create(LoadTimeLine.class);
|
||||
|
||||
for (LoadTimeLine loadTimeLine : this.getGroupsToShow()) {
|
||||
result.addToRoot(loadTimeLine);
|
||||
result = addNodes(result, loadTimeLine);
|
||||
|
|
@ -322,20 +319,21 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
return new TimeTrackerComponent(timeTracker) {
|
||||
@Override
|
||||
protected void scrollHorizontalPercentage(int daysDisplacement) {
|
||||
response("", new AuInvoke(resourceLoadList, "scroll_horizontal", daysDisplacement + ""));
|
||||
response("", new AuInvoke(resourceLoadList, "scroll_horizontal", Integer.toString(daysDisplacement)));
|
||||
moveCurrentPositionScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveCurrentPositionScroll() {
|
||||
// get the previous data.
|
||||
// Get the previous data
|
||||
LocalDate previousStart = getPreviousStart();
|
||||
|
||||
// get the current data
|
||||
// Get the current data
|
||||
int diffDays = getTimeTrackerComponent().getDiffDays(previousStart);
|
||||
double pixelPerDay = getTimeTrackerComponent().getPixelPerDay();
|
||||
|
||||
response("move_scroll", new AuInvoke(resourceLoadList, "move_scroll", "" + diffDays, "" + pixelPerDay));
|
||||
response("move_scroll", new AuInvoke(
|
||||
resourceLoadList, "move_scroll", Integer.toString(diffDays), Double.toString(pixelPerDay)));
|
||||
}
|
||||
|
||||
protected void updateCurrentDayScroll() {
|
||||
|
|
@ -343,7 +341,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
|
||||
response(
|
||||
"update_day_scroll",
|
||||
new AuInvoke(resourceLoadList, "update_day_scroll", "" + previousPixelPerDay));
|
||||
new AuInvoke(resourceLoadList, "update_day_scroll", Double.toString(previousPixelPerDay)));
|
||||
|
||||
}
|
||||
};
|
||||
|
|
@ -356,8 +354,10 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
getFellow("insertionPointLeftPanel").appendChild(leftPane);
|
||||
leftPane.afterCompose();
|
||||
|
||||
getFellow("insertionPointRightPanel").appendChild(timeTrackerComponent);
|
||||
getFellow("insertionPointRightPanel").appendChild(resourceLoadList);
|
||||
Div insertionPointRightPanel = (Div) getFellow("insertionPointRightPanel");
|
||||
insertionPointRightPanel.appendChild(timeTrackerComponent);
|
||||
insertionPointRightPanel.appendChild(resourceLoadList);
|
||||
|
||||
TimeTrackerComponent timeTrackerHeader = createTimeTrackerHeader();
|
||||
getFellow("insertionPointTimetracker").appendChild(timeTrackerHeader);
|
||||
|
||||
|
|
@ -374,21 +374,30 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
|
||||
timeTrackerHeader.afterCompose();
|
||||
timeTrackerComponent.afterCompose();
|
||||
listZoomLevels = (Listbox) getFellow("listZoomLevels");
|
||||
Listbox listZoomLevels = (Listbox) getFellow("listZoomLevels");
|
||||
listZoomLevels.setSelectedIndex(timeTracker.getDetailLevel().ordinal());
|
||||
|
||||
filterByNameCombo = (Combobox) getFellow(FILTER_BY_NAME_COMBO_COMPONENT);
|
||||
filterByNameCombo.setWidth("85px");
|
||||
|
||||
if ( paginationType == PaginationType.INTERNAL_PAGINATION && refreshNameFilter ) {
|
||||
setupNameFilter();
|
||||
}
|
||||
else if ( paginationType == PaginationType.NONE ) {
|
||||
getFellow("filterByNameCombo").setVisible(false);
|
||||
getFellow(FILTER_BY_NAME_COMBO_COMPONENT).setVisible(false);
|
||||
getFellow("filterByNameLabel").setVisible(false);
|
||||
}
|
||||
|
||||
getFellow("insertionPointChart").appendChild(loadChart);
|
||||
|
||||
this.visibleChart = expandResourceLoadViewCharts;
|
||||
this.visibleChart = expandResourceLoadViewCharts;
|
||||
((South) getFellow("graphics")).setOpen(this.visibleChart);
|
||||
|
||||
if (!visibleChart) {
|
||||
((South) getFellow("graphics")).setTitle(_("Graphics are disabled"));
|
||||
}
|
||||
|
||||
savePreviousData();
|
||||
}
|
||||
|
||||
|
|
@ -417,18 +426,14 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
|
||||
private TimeTrackerComponent createTimeTrackerHeader() {
|
||||
return new TimeTrackerComponent(timeTracker) {
|
||||
|
||||
@Override
|
||||
protected void scrollHorizontalPercentage(int pixelsDisplacement) {
|
||||
}
|
||||
@Override
|
||||
protected void scrollHorizontalPercentage(int pixelsDisplacement) {}
|
||||
|
||||
@Override
|
||||
protected void moveCurrentPositionScroll() {
|
||||
}
|
||||
protected void moveCurrentPositionScroll() {}
|
||||
|
||||
@Override
|
||||
protected void updateCurrentDayScroll() {
|
||||
}
|
||||
protected void updateCurrentDayScroll() {}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -438,7 +443,6 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
private void setupNameFilter() {
|
||||
Combobox filterByNameCombo = (Combobox) getFellow("filterByNameCombo");
|
||||
filterByNameCombo.getChildren().clear();
|
||||
int size = groups.size();
|
||||
|
||||
|
|
@ -469,7 +473,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
Comboitem lastItem = new Comboitem();
|
||||
lastItem.setLabel(_("All"));
|
||||
lastItem.setDescription(_("Show all elements"));
|
||||
lastItem.setValue(new Integer(-1));
|
||||
lastItem.setValue(-1);
|
||||
filterByNameCombo.appendChild(lastItem);
|
||||
|
||||
filterByNameCombo.setSelectedIndex(0);
|
||||
|
|
@ -477,26 +481,28 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns only the LoadTimeLine objects that have to be show
|
||||
* according to the name filter.
|
||||
* @return
|
||||
* @return only the LoadTimeLine objects that have to be show according to the name filter.
|
||||
*/
|
||||
private List<LoadTimeLine> getGroupsToShow() {
|
||||
if ( paginationType != PaginationType.INTERNAL_PAGINATION || filterByNamePosition == -1 ) {
|
||||
return groups;
|
||||
}
|
||||
|
||||
boolean condition = (filterByNamePosition + numberOfGroupsByName < groups.size());
|
||||
boolean condition = filterByNamePosition + numberOfGroupsByName < groups.size();
|
||||
int endPosition = condition ? filterByNamePosition + numberOfGroupsByName : groups.size();
|
||||
|
||||
return groups.subList(filterByNamePosition, endPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be public!
|
||||
* Used in resourcesLoadLayout.zul
|
||||
*/
|
||||
public void onSelectFilterByName(Combobox comboByName) {
|
||||
if ( comboByName.getSelectedItemApi() == null ) {
|
||||
if ( comboByName.getSelectedItem() == null ) {
|
||||
resetComboByName(comboByName);
|
||||
} else {
|
||||
Integer filterByNamePosition = (Integer) comboByName.getSelectedItemApi().getValue();
|
||||
Integer filterByNamePosition = comboByName.getSelectedItem().getValue();
|
||||
|
||||
if ( paginationType != PaginationType.NONE ) {
|
||||
this.filterByNamePosition = filterByNamePosition;
|
||||
|
|
@ -523,7 +529,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
public void doAction() {
|
||||
if ( paginationType == PaginationType.INTERNAL_PAGINATION ) {
|
||||
|
||||
//if the pagination is internal, we are in charge of repainting the graph
|
||||
// If the pagination is internal, we are in charge of repainting the graph
|
||||
treeModel = createModelForTree();
|
||||
|
||||
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
|
||||
|
|
@ -531,12 +537,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
|
||||
}
|
||||
|
||||
nameFilterListener.fireEvent(new IListenerNotification<IPaginationFilterChangedListener>() {
|
||||
@Override
|
||||
public void doNotify(IPaginationFilterChangedListener listener) {
|
||||
listener.filterChanged(filterByNamePosition);
|
||||
}
|
||||
});
|
||||
nameFilterListener.fireEvent(listener -> listener.filterChanged(filterByNamePosition));
|
||||
|
||||
afterCompose();
|
||||
}
|
||||
|
|
@ -549,9 +550,9 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
public void setInternalPaginationDisabled(boolean disabled) {
|
||||
Combobox combo = ((Combobox) getFellow("filterByNameCombo"));
|
||||
Combobox combo = (Combobox) getFellow(FILTER_BY_NAME_COMBO_COMPONENT);
|
||||
if ( combo != null && combo.isDisabled() != disabled ) {
|
||||
filterByNamePosition = disabled? -1 : (Integer) combo.getSelectedItemApi().getValue();
|
||||
filterByNamePosition = disabled? -1 : (Integer) combo.getSelectedItem().getValue();
|
||||
combo.setDisabled(disabled);
|
||||
}
|
||||
}
|
||||
|
|
@ -560,15 +561,12 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
nameFilterListener.addListener(iFilterChangedListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* It should be public!
|
||||
*/
|
||||
public void changeChartVisibility(boolean visible) {
|
||||
visibleChart = visible;
|
||||
|
||||
chartVisibilityListeners.fireEvent(new IListenerNotification<IChartVisibilityChangedListener>() {
|
||||
@Override
|
||||
public void doNotify(IChartVisibilityChangedListener listener) {
|
||||
listener.chartVisibilityChanged(visibleChart);
|
||||
}
|
||||
});
|
||||
chartVisibilityListeners.fireEvent(listener -> listener.chartVisibilityChanged(visibleChart));
|
||||
}
|
||||
|
||||
public boolean isVisibleChart() {
|
||||
|
|
@ -588,11 +586,9 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
public Combobox getPaginationFilterCombobox() {
|
||||
if ( paginationType == PaginationType.EXTERNAL_PAGINATION ) {
|
||||
return (Combobox) getFellow("filterByNameCombo");
|
||||
}
|
||||
|
||||
return null;
|
||||
return paginationType == PaginationType.EXTERNAL_PAGINATION
|
||||
? (Combobox) getFellow(FILTER_BY_NAME_COMBO_COMPONENT)
|
||||
: null;
|
||||
}
|
||||
|
||||
public enum PaginationType {
|
||||
|
|
@ -600,14 +596,16 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
|||
* Sets the widget to take care of the pagination of all the LoadTimeLine objects received.
|
||||
*/
|
||||
INTERNAL_PAGINATION,
|
||||
|
||||
/**
|
||||
* The widget will only show the combo box but its content has to be configured externally.
|
||||
* The pagination has to be managed externally too: the widget will show all the LoadTimeLine
|
||||
* objects received.
|
||||
* The pagination has to be managed externally too: the widget will show all the LoadTimeLine objects received.
|
||||
*/
|
||||
EXTERNAL_PAGINATION,
|
||||
|
||||
/**
|
||||
* Disables pagination. Shows all the LoadTimeLine objects received.
|
||||
* Disables pagination.
|
||||
* Shows all the LoadTimeLine objects received.
|
||||
*/
|
||||
NONE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,11 +34,12 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.zkoss.web.servlet.http.HttpServlet;
|
||||
|
||||
|
||||
/**
|
||||
* Servlet that allows to register custom responses. It must be declared at
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
package org.zkoss.ganttz.timetracker;
|
||||
|
||||
import org.zkoss.zul.api.Column;
|
||||
import org.zkoss.zul.Column;
|
||||
|
||||
public interface IConvertibleToColumn {
|
||||
|
||||
|
|
|
|||
|
|
@ -34,15 +34,20 @@ import org.zkoss.zul.RowRenderer;
|
|||
|
||||
public class OnColumnsRowRenderer<C, T> implements RowRenderer {
|
||||
|
||||
private final List<C> columns;
|
||||
|
||||
private final ICellForDetailItemRenderer<C, T> cellRenderer;
|
||||
|
||||
private Class<T> type;
|
||||
|
||||
public static <C, T> OnColumnsRowRenderer<C, T> create(ICellForDetailItemRenderer<C, T> cellRenderer,
|
||||
Collection<C> columns) {
|
||||
|
||||
return create(inferGenericType(cellRenderer), cellRenderer, columns);
|
||||
}
|
||||
|
||||
public static <C, T> OnColumnsRowRenderer<C, T> create(Class<T> type,
|
||||
ICellForDetailItemRenderer<C, T> cellRenderer,
|
||||
Collection<C> columns) {
|
||||
public static <C, T> OnColumnsRowRenderer<C, T> create(
|
||||
Class<T> type, ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) {
|
||||
|
||||
return new OnColumnsRowRenderer<>(type, cellRenderer, columns);
|
||||
}
|
||||
|
|
@ -95,19 +100,12 @@ public class OnColumnsRowRenderer<C, T> implements RowRenderer {
|
|||
|
||||
private static void informCannotBeInferred(ICellForDetailItemRenderer<?, ?> renderer) {
|
||||
throw new IllegalArgumentException(
|
||||
"the generic type cannot be inferred " +
|
||||
"if actual type parameters are not declared " +
|
||||
"or implements the raw interface: " +
|
||||
renderer.getClass().getName());
|
||||
"the generic type cannot be inferred if actual type parameters are not declared " +
|
||||
"or implements the raw interface: " + renderer.getClass().getName());
|
||||
}
|
||||
|
||||
private final List<C> columns;
|
||||
private final ICellForDetailItemRenderer<C, T> cellRenderer;
|
||||
private Class<T> type;
|
||||
private OnColumnsRowRenderer(Class<T> type, ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) {
|
||||
|
||||
private OnColumnsRowRenderer(Class<T> type,
|
||||
ICellForDetailItemRenderer<C, T> cellRenderer,
|
||||
Collection<C> columns) {
|
||||
Validate.notNull(type);
|
||||
Validate.notNull(columns);
|
||||
Validate.notNull(cellRenderer);
|
||||
|
|
@ -119,15 +117,16 @@ public class OnColumnsRowRenderer<C, T> implements RowRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) {
|
||||
if ( !type.isInstance(data) ) {
|
||||
throw new IllegalArgumentException(data + " is not instance of " + type);
|
||||
public void render(Row row, Object o, int index) throws Exception {
|
||||
if ( !type.isInstance(o) ) {
|
||||
throw new IllegalArgumentException(o + " is not instance of " + type);
|
||||
}
|
||||
|
||||
for (C item : columns) {
|
||||
Component child = cellRenderer.cellFor(item, type.cast(data));
|
||||
Component child = cellRenderer.cellFor(item, type.cast(o));
|
||||
child.setParent(row);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ public class TimeTrackedTable<T> extends HtmlMacroComponent {
|
|||
private transient IZoomLevelChangedListener zoomListener;
|
||||
|
||||
public TimeTrackedTable(Callable<List<T>> dataSource,
|
||||
ICellForDetailItemRenderer<DetailItem, T> cellRenderer,
|
||||
TimeTracker timeTracker) {
|
||||
ICellForDetailItemRenderer<DetailItem, T> cellRenderer,
|
||||
TimeTracker timeTracker) {
|
||||
|
||||
this.data = dataSource;
|
||||
this.cellRenderer = cellRenderer;
|
||||
this.timeTracker = timeTracker;
|
||||
|
|
@ -56,8 +57,8 @@ public class TimeTrackedTable<T> extends HtmlMacroComponent {
|
|||
this.timeTracker.addZoomListener(zoomListener);
|
||||
}
|
||||
|
||||
public ListModel getTableModel() {
|
||||
return new ListModelList(getData());
|
||||
public ListModel<T> getTableModel() {
|
||||
return new ListModelList<>(getData());
|
||||
}
|
||||
|
||||
private List<T> getData() {
|
||||
|
|
@ -69,8 +70,7 @@ public class TimeTrackedTable<T> extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
public RowRenderer getRowRenderer() {
|
||||
return OnColumnsRowRenderer.create(cellRenderer, timeTracker
|
||||
.getDetailsSecondLevel());
|
||||
return OnColumnsRowRenderer.create(cellRenderer, timeTracker.getDetailsSecondLevel());
|
||||
}
|
||||
|
||||
public Collection<DetailItem> getDetailsSecondLevel() {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import org.zkoss.zul.Columns;
|
|||
import org.zkoss.zul.Grid;
|
||||
import org.zkoss.zul.ListModel;
|
||||
import org.zkoss.zul.ListModelList;
|
||||
import org.zkoss.zul.api.Column;
|
||||
import org.zkoss.zul.Column;
|
||||
|
||||
public class TimeTrackedTableWithLeftPane<A, B> {
|
||||
|
||||
|
|
@ -48,10 +48,13 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
|||
ICellForDetailItemRenderer<C, A> leftPaneCellRenderer,
|
||||
ICellForDetailItemRenderer<DetailItem, B> cellRendererForTimeTracker,
|
||||
TimeTracker timeTracker) {
|
||||
|
||||
this.dataSource = dataSource;
|
||||
timeTrackedTable = new TimeTrackedTable<B>(
|
||||
|
||||
timeTrackedTable = new TimeTrackedTable<>(
|
||||
dataForTimeTracker(dataSource), cellRendererForTimeTracker,
|
||||
timeTracker);
|
||||
|
||||
timeTrackedTable.setSclass("inner-timetracked-table");
|
||||
leftPane = new Grid();
|
||||
zoomLevelListener = new IZoomLevelChangedListener() {
|
||||
|
|
@ -60,28 +63,32 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
|||
loadModelForLeftPane();
|
||||
}
|
||||
};
|
||||
|
||||
timeTracker.addZoomListener(zoomLevelListener);
|
||||
|
||||
leftPane.appendChild(createColumns(leftPaneColumns));
|
||||
leftPane.setRowRenderer(OnColumnsRowRenderer.create(
|
||||
leftPaneCellRenderer, leftPaneColumns));
|
||||
leftPane.setRowRenderer(OnColumnsRowRenderer.create(leftPaneCellRenderer, leftPaneColumns));
|
||||
|
||||
loadModelForLeftPane();
|
||||
}
|
||||
|
||||
private static Columns createColumns(
|
||||
Collection<? extends IConvertibleToColumn> convertibleToColumns) {
|
||||
private static Columns createColumns(Collection<? extends IConvertibleToColumn> convertibleToColumns) {
|
||||
Columns result = new Columns();
|
||||
|
||||
for (Column column : toColumns(convertibleToColumns)) {
|
||||
result.appendChild(column);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<Column> toColumns(
|
||||
Collection<? extends IConvertibleToColumn> convertibleToColumns) {
|
||||
List<Column> columns = new ArrayList<Column>();
|
||||
private static List<Column> toColumns(Collection<? extends IConvertibleToColumn> convertibleToColumns) {
|
||||
List<Column> columns = new ArrayList<>();
|
||||
|
||||
for (IConvertibleToColumn c : convertibleToColumns) {
|
||||
columns.add(c.toColumn());
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
|
|
@ -89,12 +96,13 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
|||
leftPane.setModel(createModelForLeftPane());
|
||||
}
|
||||
|
||||
private ListModel createModelForLeftPane() {
|
||||
return new ListModelList(retrieveLeftPaneList());
|
||||
private ListModel<A> createModelForLeftPane() {
|
||||
return new ListModelList<>(retrieveLeftPaneList());
|
||||
}
|
||||
|
||||
private List<A> retrieveLeftPaneList() {
|
||||
PairOfLists<A, B> pair = loadPairOfListsFromCallable();
|
||||
|
||||
return pair.getFirst();
|
||||
}
|
||||
|
||||
|
|
@ -106,8 +114,7 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
|||
}
|
||||
}
|
||||
|
||||
private Callable<List<B>> dataForTimeTracker(
|
||||
final Callable<PairOfLists<A, B>> dataSource) {
|
||||
private Callable<List<B>> dataForTimeTracker(final Callable<PairOfLists<A, B>> dataSource) {
|
||||
return new Callable<List<B>>() {
|
||||
|
||||
@Override
|
||||
|
|
@ -120,10 +127,11 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
|||
private boolean afterComposeCalled = false;
|
||||
|
||||
public TimeTrackedTable<B> getTimeTrackedTable() {
|
||||
if (!afterComposeCalled) {
|
||||
if ( !afterComposeCalled ) {
|
||||
timeTrackedTable.afterCompose();
|
||||
afterComposeCalled = true;
|
||||
}
|
||||
|
||||
return timeTrackedTable;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ package org.zkoss.ganttz.timetracker;
|
|||
|
||||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
|
|
@ -34,16 +32,15 @@ import org.zkoss.ganttz.DatesMapperOnInterval;
|
|||
import org.zkoss.ganttz.IDatesMapper;
|
||||
import org.zkoss.ganttz.data.Task;
|
||||
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
||||
import org.zkoss.ganttz.timetracker.zoom.IDetailItemModificator;
|
||||
import org.zkoss.ganttz.timetracker.zoom.IDetailItemModifier;
|
||||
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
||||
import org.zkoss.ganttz.timetracker.zoom.SeveralModificators;
|
||||
import org.zkoss.ganttz.timetracker.zoom.SeveralModifiers;
|
||||
import org.zkoss.ganttz.timetracker.zoom.TimeTrackerState;
|
||||
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
||||
import org.zkoss.ganttz.util.Interval;
|
||||
import org.zkoss.ganttz.util.LongOperationFeedback;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
|
||||
public class TimeTracker {
|
||||
|
|
@ -72,9 +69,9 @@ public class TimeTracker {
|
|||
|
||||
private Interval interval;
|
||||
|
||||
private final IDetailItemModificator firstLevelModificator;
|
||||
private final IDetailItemModifier firstLevelModifier;
|
||||
|
||||
private final IDetailItemModificator secondLevelModificator;
|
||||
private final IDetailItemModifier secondLevelModifier;
|
||||
|
||||
private final Component componentOnWhichGiveFeedback;
|
||||
|
||||
|
|
@ -82,46 +79,48 @@ public class TimeTracker {
|
|||
|
||||
private IDetailItemFilter filter = null;
|
||||
|
||||
public IDetailItemFilter getFilter() {
|
||||
return filter;
|
||||
}
|
||||
private Interval realIntervalCached;
|
||||
|
||||
public TimeTracker(Interval interval, ZoomLevel zoomLevel, Component parent) {
|
||||
this(interval, zoomLevel, SeveralModificators.empty(), SeveralModificators.empty(), parent);
|
||||
this(interval, zoomLevel, SeveralModifiers.empty(), SeveralModifiers.empty(), parent);
|
||||
}
|
||||
|
||||
public TimeTracker(Interval interval, Component componentOnWhichGiveFeedback) {
|
||||
this(interval, SeveralModificators.empty(), SeveralModificators.empty(), componentOnWhichGiveFeedback);
|
||||
this(interval, SeveralModifiers.empty(), SeveralModifiers.empty(), componentOnWhichGiveFeedback);
|
||||
}
|
||||
|
||||
public TimeTracker(
|
||||
Interval interval,
|
||||
IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator,
|
||||
IDetailItemModifier firstLevelModifier,
|
||||
IDetailItemModifier secondLevelModifier,
|
||||
Component componentOnWhichGiveFeedback) {
|
||||
|
||||
Validate.notNull(interval);
|
||||
Validate.notNull(firstLevelModificator);
|
||||
Validate.notNull(secondLevelModificator);
|
||||
Validate.notNull(firstLevelModifier);
|
||||
Validate.notNull(secondLevelModifier);
|
||||
Validate.notNull(componentOnWhichGiveFeedback);
|
||||
|
||||
this.interval = interval;
|
||||
this.firstLevelModificator = firstLevelModificator;
|
||||
this.secondLevelModificator = secondLevelModificator;
|
||||
this.firstLevelModifier = firstLevelModifier;
|
||||
this.secondLevelModifier = secondLevelModifier;
|
||||
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
|
||||
}
|
||||
|
||||
public TimeTracker(
|
||||
Interval interval,
|
||||
ZoomLevel zoomLevel,
|
||||
IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator,
|
||||
IDetailItemModifier firstLevelModifier,
|
||||
IDetailItemModifier secondLevelModifier,
|
||||
Component componentOnWhichGiveFeedback) {
|
||||
|
||||
this(interval, firstLevelModificator, secondLevelModificator, componentOnWhichGiveFeedback);
|
||||
this(interval, firstLevelModifier, secondLevelModifier, componentOnWhichGiveFeedback);
|
||||
detailLevel = zoomLevel;
|
||||
}
|
||||
|
||||
public IDetailItemFilter getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public void setFilter(IDetailItemFilter filter) {
|
||||
this.filter = filter;
|
||||
datesMapper = null;
|
||||
|
|
@ -144,11 +143,7 @@ public class TimeTracker {
|
|||
}
|
||||
|
||||
private Collection<DetailItem> filterFirstLevel(Collection<DetailItem> firstLevelDetails) {
|
||||
if ( filter == null ) {
|
||||
return firstLevelDetails;
|
||||
}
|
||||
|
||||
return filter.selectsFirstLevel(firstLevelDetails);
|
||||
return filter == null ? firstLevelDetails : filter.selectsFirstLevel(firstLevelDetails);
|
||||
}
|
||||
|
||||
public Collection<DetailItem> getDetailsSecondLevel() {
|
||||
|
|
@ -160,15 +155,9 @@ public class TimeTracker {
|
|||
}
|
||||
|
||||
private Collection<DetailItem> filterSecondLevel(Collection<DetailItem> secondLevelDetails) {
|
||||
if ( filter == null ) {
|
||||
return secondLevelDetails;
|
||||
}
|
||||
|
||||
return filter.selectsSecondLevel(secondLevelDetails);
|
||||
return filter == null ? secondLevelDetails : filter.selectsSecondLevel(secondLevelDetails);
|
||||
}
|
||||
|
||||
private Interval realIntervalCached;
|
||||
|
||||
public Interval getRealInterval() {
|
||||
if ( realIntervalCached == null ) {
|
||||
realIntervalCached = getTimeTrackerState().getRealIntervalFor(interval);
|
||||
|
|
@ -178,11 +167,12 @@ public class TimeTracker {
|
|||
}
|
||||
|
||||
public TimeTrackerState getTimeTrackerState() {
|
||||
return detailLevel.getTimeTrackerState(firstLevelModificator, secondLevelModificator);
|
||||
return detailLevel.getTimeTrackerState(firstLevelModifier, secondLevelModifier);
|
||||
}
|
||||
|
||||
private void fireZoomChanged() {
|
||||
zoomListeners.fireEvent(new IListenerNotification<IZoomLevelChangedListener>() {
|
||||
/* Do not replace it with lambda */
|
||||
zoomListeners.fireEvent(new WeakReferencedListeners.IListenerNotification<IZoomLevelChangedListener>() {
|
||||
@Override
|
||||
public void doNotify(IZoomLevelChangedListener listener) {
|
||||
listener.zoomLevelChanged(detailLevel);
|
||||
|
|
@ -257,13 +247,7 @@ public class TimeTracker {
|
|||
}
|
||||
|
||||
public void trackPosition(final Task task) {
|
||||
task.addFundamentalPropertiesChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
updateIntervalIfNeeded(task);
|
||||
}
|
||||
});
|
||||
|
||||
task.addFundamentalPropertiesChangeListener(evt -> updateIntervalIfNeeded(task));
|
||||
updateIntervalIfNeeded(task);
|
||||
}
|
||||
|
||||
|
|
@ -319,16 +303,14 @@ public class TimeTracker {
|
|||
}
|
||||
|
||||
private LocalDate endPlusOneMonth(Task task) {
|
||||
Date taskEnd = max(task.getEndDate().toDayRoundedDate(), task.getDeadline());
|
||||
|
||||
return new LocalDate(taskEnd).plusMonths(1);
|
||||
return new LocalDate(max(task.getEndDate().toDayRoundedDate(), task.getDeadline())).plusMonths(1);
|
||||
}
|
||||
|
||||
private LocalDate startMinusTwoWeeks(Task task) {
|
||||
// the deadline could be before the start
|
||||
// The deadline could be before the start
|
||||
Date start = min(task.getBeginDate().toDayRoundedDate(), task.getDeadline());
|
||||
|
||||
// the last consolidated value could be before the start
|
||||
// The last consolidated value could be before the start
|
||||
if ( task.getConsolidatedline() != null ) {
|
||||
start = min(start, task.getConsolidatedline().toDayRoundedDate());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import java.util.Collection;
|
|||
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.zkoss.ganttz.IDatesMapper;
|
||||
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
||||
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
||||
import org.zkoss.ganttz.timetracker.zoom.TimeTrackerState;
|
||||
|
|
@ -35,36 +34,35 @@ import org.zkoss.zk.ui.Executions;
|
|||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||
|
||||
/**
|
||||
* Works with time header of some pages.
|
||||
*
|
||||
* @author Javier Moran Rua <jmoran@igalia.com>
|
||||
*/
|
||||
public abstract class TimeTrackerComponent extends HtmlMacroComponent {
|
||||
|
||||
private final TimeTracker timeTracker;
|
||||
private IZoomLevelChangedListener zoomListener;
|
||||
|
||||
private final String secondLevelZul;
|
||||
|
||||
private String timeTrackerElementId;
|
||||
|
||||
private int scrollLeft;
|
||||
|
||||
public TimeTrackerComponent(TimeTracker timeTracker) {
|
||||
this(timeTracker,
|
||||
"~./ganttz/zul/timetracker/timetrackersecondlevel.zul",
|
||||
"timetracker");
|
||||
this(timeTracker, "~./ganttz/zul/timetracker/timetrackersecondlevel.zul", "timetracker");
|
||||
}
|
||||
|
||||
protected TimeTrackerComponent(TimeTracker timeTracker,
|
||||
String secondLevelZul, String timetrackerId) {
|
||||
TimeTrackerComponent(TimeTracker timeTracker, String secondLevelZul, String timetrackerId) {
|
||||
this.secondLevelZul = secondLevelZul;
|
||||
this.timeTracker = timeTracker;
|
||||
zoomListener = new IZoomLevelChangedListener() {
|
||||
|
||||
@Override
|
||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||
if (isInPage()) {
|
||||
recreate();
|
||||
changeDetailLevel(getDaysFor(scrollLeft));
|
||||
}
|
||||
IZoomLevelChangedListener zoomListener = detailLevel -> {
|
||||
if ( isInPage() ) {
|
||||
recreate();
|
||||
changeDetailLevel(getDaysFor(scrollLeft));
|
||||
}
|
||||
};
|
||||
|
||||
this.timeTracker.addZoomListener(zoomListener);
|
||||
timeTrackerElementId = timetrackerId;
|
||||
}
|
||||
|
|
@ -81,22 +79,24 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
|
|||
return timeTrackerElementId;
|
||||
}
|
||||
|
||||
/*
|
||||
* fsanjurjo: I'm temporary changing the name of this method
|
||||
* (from afterCompose to compose) to get it called after calling recreate().
|
||||
* To understand why, please read this: http://www.zkoss.org/forum/listComment/14905
|
||||
* Also renamed the call to its parent.
|
||||
* */
|
||||
/**
|
||||
* fsanjurjo:
|
||||
* I'm temporary changing the name of this method (from afterCompose to compose)
|
||||
* to get it called after calling recreate().
|
||||
*
|
||||
* To understand why, please read this: http://www.zkoss.org/forum/listComment/14905
|
||||
* Also renamed the call to its parent.
|
||||
*/
|
||||
@Override
|
||||
public void compose() {
|
||||
super.compose();
|
||||
|
||||
Component fellow = getFellow("firstleveldetails");
|
||||
addSecondLevels(fellow.getParent());
|
||||
}
|
||||
|
||||
private void addSecondLevels(Component parent) {
|
||||
Executions.getCurrent().createComponents(secondLevelZul, parent,
|
||||
getAttributes());
|
||||
Executions.getCurrent().createComponents(secondLevelZul, parent, getAttributes());
|
||||
}
|
||||
|
||||
public ZoomLevel getZoomLevel() {
|
||||
|
|
@ -146,9 +146,9 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
public int getDiffDays(LocalDate previousStart) {
|
||||
// get the current data
|
||||
IDatesMapper mapper = getTimeTracker().getMapper();
|
||||
// Get the current data
|
||||
LocalDate start = getTimeTracker().getRealInterval().getStart();
|
||||
|
||||
return Days.daysBetween(start, previousStart).getDays();
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
|
|||
}
|
||||
|
||||
public String getWidgetClass(){
|
||||
return getDefinition().getDefaultWidgetClass();
|
||||
return getDefinition().getDefaultWidgetClass(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,16 +21,14 @@
|
|||
package org.zkoss.ganttz.timetracker;
|
||||
|
||||
/**
|
||||
* A {@link TimeTrackerComponent} that doesn't show columns as watermark
|
||||
* A {@link TimeTrackerComponent} that doesn't show columns as watermark.
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*/
|
||||
public class TimeTrackerComponentWithoutColumns extends TimeTrackerComponent {
|
||||
|
||||
public TimeTrackerComponentWithoutColumns(TimeTracker timeTracker,
|
||||
String timeTrackerId) {
|
||||
super(timeTracker,
|
||||
"~./ganttz/zul/timetracker/secondlevelwithoutwatermark.zul",
|
||||
timeTrackerId);
|
||||
public TimeTrackerComponentWithoutColumns(TimeTracker timeTracker, String timeTrackerId) {
|
||||
super(timeTracker, "~./ganttz/zul/timetracker/secondlevelwithoutwatermark.zul", timeTrackerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -38,14 +36,8 @@ public class TimeTrackerComponentWithoutColumns extends TimeTrackerComponent {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void moveCurrentPositionScroll() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
protected void moveCurrentPositionScroll() {}
|
||||
|
||||
@Override
|
||||
protected void updateCurrentDayScroll() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
protected void updateCurrentDayScroll() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,57 +21,51 @@
|
|||
|
||||
package org.zkoss.ganttz.timetracker.zoom;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.ReadablePeriod;
|
||||
|
||||
/**
|
||||
* Zoom level for weeks in the first level and days in the second level
|
||||
* Zoom level for weeks in the first level and days in the second level.
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
public class DetailFiveTimeTrackerState extends
|
||||
TimeTrackerStateWithSubintervalsFitting {
|
||||
public class DetailFiveTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
|
||||
|
||||
private static final int NUMBER_OF_DAYS_MINIMUM = 50;
|
||||
public static final int FIRST_LEVEL_SIZE = 210;
|
||||
public static final int SECOND_LEVEL_SIZE = 30;
|
||||
|
||||
DetailFiveTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator) {
|
||||
super(firstLevelModificator, secondLevelModificator);
|
||||
private static final int FIRST_LEVEL_SIZE = 210;
|
||||
|
||||
private static final int SECOND_LEVEL_SIZE = 30;
|
||||
|
||||
DetailFiveTimeTrackerState(
|
||||
IDetailItemModifier firstLevelModifier, IDetailItemModifier secondLevelModifier) {
|
||||
|
||||
super(firstLevelModifier, secondLevelModifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double daysPerPixel() {
|
||||
return ((double) 1 / SECOND_LEVEL_SIZE);
|
||||
return (double) 1 / SECOND_LEVEL_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(FIRST_LEVEL_SIZE, dateTime
|
||||
.getWeekOfWeekyear()
|
||||
+ dateTime.toString(", MMM YYYY"), dateTime, dateTime
|
||||
.plusDays(7));
|
||||
}
|
||||
};
|
||||
return dateTime -> new DetailItem(
|
||||
FIRST_LEVEL_SIZE,
|
||||
dateTime.getWeekOfWeekyear() + dateTime.toString(", MMM YYYY"),
|
||||
dateTime,
|
||||
dateTime.plusDays(7));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(SECOND_LEVEL_SIZE, dateTime
|
||||
.getDayOfMonth()
|
||||
+ "", dateTime, dateTime.plusDays(1));
|
||||
}
|
||||
};
|
||||
return dateTime -> new DetailItem(
|
||||
SECOND_LEVEL_SIZE,
|
||||
Integer.toString(dateTime.getDayOfMonth()),
|
||||
dateTime,
|
||||
dateTime.plusDays(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -87,11 +81,12 @@ public class DetailFiveTimeTrackerState extends
|
|||
@Override
|
||||
protected LocalDate round(LocalDate date, boolean down) {
|
||||
int dayOfWeek = date.getDayOfWeek();
|
||||
|
||||
if (dayOfWeek == 1) {
|
||||
return date;
|
||||
}
|
||||
return down ? date.withDayOfWeek(1) : date.withDayOfWeek(1)
|
||||
.plusWeeks(1);
|
||||
|
||||
return down ? date.withDayOfWeek(1) : date.withDayOfWeek(1).plusWeeks(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ import org.joda.time.LocalDate;
|
|||
import org.joda.time.Months;
|
||||
|
||||
/**
|
||||
* Zoom level for months and years and weeks in the second level
|
||||
* Zoom level for months and years and weeks in the second level.
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
|
|
@ -39,53 +40,39 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
|
|||
|
||||
private static final int NUMBER_OF_WEEKS_MINIMUM = 40;
|
||||
|
||||
DetailFourTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator) {
|
||||
super(firstLevelModificator, secondLevelModificator);
|
||||
}
|
||||
|
||||
private static final int SECOND_LEVEL_SIZE = 56;
|
||||
|
||||
DetailFourTimeTrackerState(
|
||||
IDetailItemModifier firstLevelModifier, IDetailItemModifier secondLevelModifier) {
|
||||
|
||||
super(firstLevelModifier, secondLevelModifier);
|
||||
}
|
||||
|
||||
public final double pixelPerDay() {
|
||||
return (SECOND_LEVEL_SIZE / (double) 7);
|
||||
return SECOND_LEVEL_SIZE / (double) 7;
|
||||
}
|
||||
|
||||
public final double daysPerPixel() {
|
||||
return ((double) 7 / SECOND_LEVEL_SIZE);
|
||||
return (double) 7 / SECOND_LEVEL_SIZE;
|
||||
}
|
||||
|
||||
|
||||
private IDetailItemCreator firstLevelCreator;
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||
firstLevelCreator = new IDetailItemCreator() {
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(getSizeMonth(dateTime), dateTime
|
||||
.toString("MMMM,YYYY"), dateTime, dateTime
|
||||
.plusMonths(1));
|
||||
}
|
||||
};
|
||||
return firstLevelCreator;
|
||||
return dateTime -> new DetailItem(
|
||||
getSizeMonth(dateTime), dateTime.toString("MMMM,YYYY"), dateTime, dateTime.plusMonths(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
return dateTime -> {
|
||||
int daysUntilFirstDayNextWeek = getDaysUntilFirstDayNextWeek(dateTime.toLocalDate());
|
||||
int sizeWeek = BigDecimal.valueOf(pixelPerDay() * daysUntilFirstDayNextWeek).intValue();
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
int daysUntilFirstDayNextWeek = getDaysUntilFirstDayNextWeek(dateTime
|
||||
.toLocalDate());
|
||||
int sizeWeek = new BigDecimal(pixelPerDay()
|
||||
* daysUntilFirstDayNextWeek).intValue();
|
||||
|
||||
return new DetailItem(sizeWeek, dateTime.getWeekOfWeekyear()
|
||||
+ "", dateTime,
|
||||
dateTime.plusDays(daysUntilFirstDayNextWeek));
|
||||
}
|
||||
return new DetailItem(
|
||||
sizeWeek,
|
||||
Integer.toString(dateTime.getWeekOfWeekyear()),
|
||||
dateTime,
|
||||
dateTime.plusDays(daysUntilFirstDayNextWeek));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -94,8 +81,8 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
|
|||
if (date.getDayOfMonth() == 1) {
|
||||
return date;
|
||||
}
|
||||
return down ? date.withDayOfMonth(1) : date.plusMonths(1)
|
||||
.withDayOfMonth(1);
|
||||
|
||||
return down ? date.withDayOfMonth(1) : date.plusMonths(1).withDayOfMonth(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -114,17 +101,18 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
|
|||
}
|
||||
|
||||
private int getSizeMonth(DateTime dateTime) {
|
||||
Calendar cal = new GregorianCalendar(dateTime.getYear(), dateTime
|
||||
.getMonthOfYear() - 1, dateTime.getDayOfMonth());
|
||||
Calendar cal =
|
||||
new GregorianCalendar(dateTime.getYear(), dateTime.getMonthOfYear() - 1, dateTime.getDayOfMonth());
|
||||
|
||||
// Get the number of days in that month
|
||||
int days = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
return new BigDecimal(pixelPerDay() * days).intValue();
|
||||
|
||||
return BigDecimal.valueOf(pixelPerDay() * days).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterator<LocalDate> getPeriodsFirstLevelGenerator(LocalDate start) {
|
||||
return new LazyGenerator<LocalDate>(start) {
|
||||
|
||||
@Override
|
||||
protected LocalDate next(LocalDate last) {
|
||||
return last.plus(Months.ONE);
|
||||
|
|
@ -135,14 +123,9 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
|
|||
@Override
|
||||
protected Iterator<LocalDate> getPeriodsSecondLevelGenerator(LocalDate start) {
|
||||
return new LazyGenerator<LocalDate>(start) {
|
||||
|
||||
@Override
|
||||
protected LocalDate next(LocalDate last) {
|
||||
if (last.getDayOfWeek() != 1) {
|
||||
return last.plusDays(getDaysUntilFirstDayNextWeek(last));
|
||||
} else {
|
||||
return last.plusWeeks(1);
|
||||
}
|
||||
return last.getDayOfWeek() != 1 ? last.plusDays(getDaysUntilFirstDayNextWeek(last)) : last.plusWeeks(1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,42 +25,40 @@ import org.joda.time.DateTime;
|
|||
import org.joda.time.Days;
|
||||
|
||||
/**
|
||||
* One of each of the subintervals a time line is divided into
|
||||
* One of each of the subintervals a time line is divided into.
|
||||
*
|
||||
* @author Francisco Javier Moran Rúa <jmoran@igalia.com>
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
public final class DetailItem {
|
||||
|
||||
private int size;
|
||||
|
||||
private String name;
|
||||
|
||||
private boolean even;
|
||||
|
||||
private boolean bankHoliday;
|
||||
|
||||
private String bankHolidayWeek;
|
||||
|
||||
public String getBankHolidayWeek() {
|
||||
return bankHolidayWeek;
|
||||
}
|
||||
|
||||
public void setBankHolidayWeek(String bankHolidayWeek) {
|
||||
this.bankHolidayWeek = bankHolidayWeek;
|
||||
}
|
||||
|
||||
private boolean currentPeriod;
|
||||
|
||||
private int currentDayOffset;
|
||||
|
||||
private boolean projectStart = false;
|
||||
|
||||
private int projectStartOffset = 0;
|
||||
|
||||
private boolean deadlinePeriod;
|
||||
|
||||
private int deadlineOffset;
|
||||
|
||||
private DateTime startDate;
|
||||
|
||||
private DateTime endDate;
|
||||
|
||||
public DetailItem(int size, String name, DateTime startDate,
|
||||
DateTime endDate) {
|
||||
public DetailItem(int size, String name, DateTime startDate, DateTime endDate) {
|
||||
this(size, name, false);
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
|
|
@ -88,32 +86,41 @@ public final class DetailItem {
|
|||
this.currentDayOffset = currentdayoffset;
|
||||
}
|
||||
|
||||
public DetailItem(int size, String name, int currentdayoffset,
|
||||
int deadlineoffset) {
|
||||
public DetailItem(int size, String name, int currentdayoffset, int deadlineoffset) {
|
||||
this(size, name, currentdayoffset);
|
||||
this.deadlinePeriod = true;
|
||||
this.deadlineOffset = deadlineoffset;
|
||||
}
|
||||
|
||||
public String getBankHolidayWeek() {
|
||||
return bankHolidayWeek;
|
||||
}
|
||||
|
||||
public void setBankHolidayWeek(String bankHolidayWeek) {
|
||||
this.bankHolidayWeek = bankHolidayWeek;
|
||||
}
|
||||
|
||||
public void markCurrentDay() {
|
||||
if (this.startDate.isBeforeNow() && this.endDate.isAfterNow()) {
|
||||
int offsetInPx = Math
|
||||
.round(((((float) Days.daysBetween(this.startDate,
|
||||
new DateTime()).getDays()) + (float) 0.5) / ((float) Days
|
||||
.daysBetween(this.startDate, this.endDate).getDays()))
|
||||
* this.size);
|
||||
|
||||
int offsetInPx = Math.round(
|
||||
( (((float) Days.daysBetween(this.startDate, new DateTime()).getDays()) + (float) 0.5) /
|
||||
((float) Days.daysBetween(this.startDate, this.endDate).getDays()) )
|
||||
* this.size );
|
||||
|
||||
// 1px per column side, 1px for right border and 1px own bg-width
|
||||
this.markCurrentDay(Math.min(this.size - 4, offsetInPx));
|
||||
}
|
||||
}
|
||||
|
||||
public void markProjectStart(DateTime projectStart) {
|
||||
if (!this.startDate.isAfter(projectStart)
|
||||
&& projectStart.isBefore(endDate)) {
|
||||
int offsetInPx = Math.round((((float) Days.daysBetween(
|
||||
this.startDate, projectStart).getDays()) / ((float) Days
|
||||
.daysBetween(this.startDate, this.endDate).getDays()))
|
||||
* this.size);
|
||||
if (!this.startDate.isAfter(projectStart) && projectStart.isBefore(endDate)) {
|
||||
|
||||
int offsetInPx = Math.round(
|
||||
( ((float) Days.daysBetween(this.startDate, projectStart).getDays()) /
|
||||
((float) Days.daysBetween(this.startDate, this.endDate).getDays()) )
|
||||
* this.size);
|
||||
|
||||
this.markprojectStart(offsetInPx);
|
||||
}
|
||||
}
|
||||
|
|
@ -121,10 +128,12 @@ public final class DetailItem {
|
|||
public void markDeadlineDay(DateTime maxdeadline) {
|
||||
DateTime deadline = maxdeadline.plusDays(1);
|
||||
if (!this.startDate.isAfter(deadline) && deadline.isBefore(endDate)) {
|
||||
int offsetInPx = Math.round((((float) Days.daysBetween(
|
||||
this.startDate, deadline).getDays()) / ((float) Days
|
||||
.daysBetween(this.startDate, this.endDate).getDays()))
|
||||
* this.size);
|
||||
|
||||
int offsetInPx = Math.round(
|
||||
( ((float) Days.daysBetween(this.startDate, deadline).getDays()) /
|
||||
((float) Days.daysBetween(this.startDate, this.endDate).getDays()) )
|
||||
* this.size);
|
||||
|
||||
// 1px per column side, 1px for right border and 1px own bg-width
|
||||
this.markDeadlineDay(Math.min(this.size - 4, offsetInPx));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,27 +27,26 @@ import org.joda.time.Months;
|
|||
import org.joda.time.ReadablePeriod;
|
||||
import org.joda.time.Years;
|
||||
|
||||
|
||||
/**
|
||||
* Zoom level with years in the first level and semesters in the second level
|
||||
* Zoom level with years in the first level and semesters in the second level.
|
||||
*
|
||||
* @author Francisco Javier Moran Rúa
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
public class DetailOneTimeTrackerState extends
|
||||
TimeTrackerStateWithSubintervalsFitting {
|
||||
public class DetailOneTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
|
||||
|
||||
public static final Period MINIMUN_PERIOD = PeriodType.YEARS.amount(6);
|
||||
static final Period MINIMUM_PERIOD = PeriodType.YEARS.amount(6);
|
||||
|
||||
private static final int FIRST_LEVEL_ITEM_SIZE = 200;
|
||||
|
||||
private static final int SECOND_LEVEL_ITEM_SIZE = 100;
|
||||
|
||||
public final double daysPerPixel() {
|
||||
return ((double) 365 / FIRST_LEVEL_ITEM_SIZE);
|
||||
return (double) 365 / FIRST_LEVEL_ITEM_SIZE;
|
||||
}
|
||||
|
||||
DetailOneTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator) {
|
||||
super(firstLevelModificator, secondLevelModificator);
|
||||
DetailOneTimeTrackerState(IDetailItemModifier firstLevelModifier, IDetailItemModifier secondLevelModifier) {
|
||||
super(firstLevelModifier, secondLevelModifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -62,15 +61,11 @@ public class DetailOneTimeTrackerState extends
|
|||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
@Override
|
||||
public DetailItem create(DateTime start) {
|
||||
int year = start.getYear();
|
||||
DateTime end = new LocalDate(year + 1, 1, 1)
|
||||
.toDateTimeAtStartOfDay();
|
||||
return new DetailItem(FIRST_LEVEL_ITEM_SIZE, start.getYear()
|
||||
+ "", start, end);
|
||||
}
|
||||
return start -> {
|
||||
int year = start.getYear();
|
||||
DateTime end = new LocalDate(year + 1, 1, 1).toDateTimeAtStartOfDay();
|
||||
|
||||
return new DetailItem(FIRST_LEVEL_ITEM_SIZE, Integer.toString(start.getYear()), start, end);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -81,15 +76,8 @@ public class DetailOneTimeTrackerState extends
|
|||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(SECOND_LEVEL_ITEM_SIZE,
|
||||
dateTime.getMonthOfYear() == 1 ? "H1" : "H2", dateTime,
|
||||
dateTime.plusMonths(6));
|
||||
}
|
||||
};
|
||||
return dateTime -> new DetailItem(
|
||||
SECOND_LEVEL_ITEM_SIZE, dateTime.getMonthOfYear() == 1 ? "H1" : "H2", dateTime, dateTime.plusMonths(6));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -103,12 +91,12 @@ public class DetailOneTimeTrackerState extends
|
|||
}
|
||||
|
||||
public static LocalDate doYearRound(LocalDate date, boolean down) {
|
||||
return new LocalDate(date.getYear() + (down?0:1), 1, 1);
|
||||
return new LocalDate(date.getYear() + (down ? 0 : 1), 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Period getMinimumPeriod() {
|
||||
return MINIMUN_PERIOD;
|
||||
return MINIMUM_PERIOD;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* 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.zkoss.ganttz.timetracker.zoom;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.ReadablePeriod;
|
||||
|
||||
/**
|
||||
* Zoom level for weeks in the first level and days in the second level
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
public class DetailSixTimeTrackerState extends
|
||||
TimeTrackerStateWithSubintervalsFitting {
|
||||
|
||||
private static final int NUMBER_OF_DAYS_MINIMUM = 50;
|
||||
public static final int FIRST_LEVEL_SIZE = 672;
|
||||
public static final int SECOND_LEVEL_SIZE = 96;
|
||||
|
||||
DetailSixTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator) {
|
||||
super(firstLevelModificator, secondLevelModificator);
|
||||
}
|
||||
|
||||
public final double daysPerPixel() {
|
||||
return ((double) 1 / SECOND_LEVEL_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(FIRST_LEVEL_SIZE, dateTime
|
||||
.getWeekOfWeekyear()
|
||||
+ dateTime.toString(", MMM YYYY"), dateTime, dateTime
|
||||
.plusDays(7));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(SECOND_LEVEL_SIZE, dateTime
|
||||
.getDayOfMonth()
|
||||
+ "", dateTime, dateTime.plusDays(1));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReadablePeriod getPeriodFirstLevel() {
|
||||
return Days.days(7);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReadablePeriod getPeriodSecondLevel() {
|
||||
return Days.days(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalDate round(LocalDate date, boolean down) {
|
||||
int dayOfWeek = date.getDayOfWeek();
|
||||
if (dayOfWeek == 1) {
|
||||
return date;
|
||||
}
|
||||
return down ? date.withDayOfWeek(1) : date.withDayOfWeek(1)
|
||||
.plusWeeks(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Period getMinimumPeriod() {
|
||||
return PeriodType.DAYS.amount(NUMBER_OF_DAYS_MINIMUM);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ZoomLevel getZoomLevel() {
|
||||
return ZoomLevel.DETAIL_FIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSecondLevelSize() {
|
||||
return SECOND_LEVEL_SIZE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -28,25 +28,25 @@ import org.joda.time.ReadablePeriod;
|
|||
import org.zkoss.util.Locales;
|
||||
|
||||
/**
|
||||
* Zoom level with semesters in the first level and months in the second level
|
||||
* Zoom level with semesters in the first level and months in the second level.
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
public class DetailThreeTimeTrackerState extends
|
||||
TimeTrackerStateWithSubintervalsFitting {
|
||||
public class DetailThreeTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
|
||||
|
||||
private static final int NUMBER_OF_MONTHS_MINIMUM = 30;
|
||||
|
||||
DetailThreeTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator) {
|
||||
super(firstLevelModificator, secondLevelModificator);
|
||||
}
|
||||
|
||||
private static final int FIRST_LEVEL_SIZE = 300;
|
||||
|
||||
protected static final int SECOND_LEVEL_SIZE = 50;
|
||||
|
||||
DetailThreeTimeTrackerState(IDetailItemModifier firstLevelModifier, IDetailItemModifier secondLevelModifier) {
|
||||
super(firstLevelModifier, secondLevelModifier);
|
||||
}
|
||||
|
||||
public final double daysPerPixel() {
|
||||
return ((double) 182.5 / FIRST_LEVEL_SIZE);
|
||||
return 182.5 / FIRST_LEVEL_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -61,31 +61,22 @@ public class DetailThreeTimeTrackerState extends
|
|||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(SECOND_LEVEL_SIZE,
|
||||
getMonthString(dateTime),
|
||||
dateTime, dateTime.plusMonths(1));
|
||||
}
|
||||
};
|
||||
return dateTime -> new DetailItem(
|
||||
SECOND_LEVEL_SIZE, getMonthString(dateTime), dateTime, dateTime.plusMonths(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalDate round(LocalDate date, boolean down) {
|
||||
if (date.getMonthOfYear() == 1 && date.getDayOfMonth() == 1) {
|
||||
return date;
|
||||
}
|
||||
if (date.getMonthOfYear() == 7 && date.getDayOfMonth() == 1) {
|
||||
if ( (date.getMonthOfYear() == 1 || date.getMonthOfYear() == 7) && date.getDayOfMonth() == 1) {
|
||||
return date;
|
||||
}
|
||||
|
||||
date = date.withDayOfMonth(1);
|
||||
|
||||
if (date.getMonthOfYear() < 7) {
|
||||
return down ? date.withMonthOfYear(1) : date.withMonthOfYear(7);
|
||||
} else {
|
||||
return down ? date.withMonthOfYear(7) : date.plusYears(1)
|
||||
.withMonthOfYear(1);
|
||||
return down ? date.withMonthOfYear(7) : date.plusYears(1).withMonthOfYear(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,20 +85,13 @@ public class DetailThreeTimeTrackerState extends
|
|||
}
|
||||
|
||||
private String getYearWithSemesterString(DateTime dateTime) {
|
||||
return dateTime.getYear() + ","
|
||||
+ (dateTime.getMonthOfYear() < 6 ? "H1" : "H2");
|
||||
return dateTime.getYear() + "," + (dateTime.getMonthOfYear() < 6 ? "H1" : "H2");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(FIRST_LEVEL_SIZE,
|
||||
getYearWithSemesterString(dateTime), dateTime, dateTime
|
||||
.plusMonths(6));
|
||||
}
|
||||
};
|
||||
return dateTime -> new DetailItem(
|
||||
FIRST_LEVEL_SIZE, getYearWithSemesterString(dateTime), dateTime, dateTime.plusMonths(6));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -21,38 +21,31 @@
|
|||
|
||||
package org.zkoss.ganttz.timetracker.zoom;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.Months;
|
||||
import org.joda.time.ReadablePeriod;
|
||||
import org.joda.time.Years;
|
||||
|
||||
/**
|
||||
* Zoom level with years in the first level and quarters in the second level
|
||||
* Zoom level with years in the first level and quarters in the second level.
|
||||
*
|
||||
* @author Francisco Javier Moran Rúa
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
public class DetailTwoTimeTrackerState extends
|
||||
TimeTrackerStateWithSubintervalsFitting {
|
||||
public class DetailTwoTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
|
||||
|
||||
private static final int FIRST_LEVEL_ITEM_SIZE = 400;
|
||||
|
||||
private static final int SECOND_LEVEL_ITEM_SIZE = 100;
|
||||
|
||||
protected DetailTwoTimeTrackerState(
|
||||
IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator) {
|
||||
super(firstLevelModificator, secondLevelModificator);
|
||||
protected DetailTwoTimeTrackerState(IDetailItemModifier firstLevelModifier, IDetailItemModifier secondLevelModifier) {
|
||||
super(firstLevelModifier, secondLevelModifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(FIRST_LEVEL_ITEM_SIZE, dateTime.getYear()
|
||||
+ "", dateTime, dateTime);
|
||||
}
|
||||
};
|
||||
return dateTime ->
|
||||
new DetailItem(FIRST_LEVEL_ITEM_SIZE, Integer.toString(dateTime.getYear()), dateTime, dateTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -62,14 +55,11 @@ public class DetailTwoTimeTrackerState extends
|
|||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
int quarterNumber = dateTime.getMonthOfYear() / 3 + 1;
|
||||
String quarterCaption = "Q" + quarterNumber;
|
||||
return new DetailItem(SECOND_LEVEL_ITEM_SIZE, quarterCaption,
|
||||
dateTime, dateTime.plusMonths(3));
|
||||
}
|
||||
return dateTime -> {
|
||||
int quarterNumber = dateTime.getMonthOfYear() / 3 + 1;
|
||||
String quarterCaption = "Q" + quarterNumber;
|
||||
|
||||
return new DetailItem(SECOND_LEVEL_ITEM_SIZE, quarterCaption, dateTime, dateTime.plusMonths(3));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -85,12 +75,12 @@ public class DetailTwoTimeTrackerState extends
|
|||
|
||||
@Override
|
||||
protected Period getMinimumPeriod() {
|
||||
return DetailOneTimeTrackerState.MINIMUN_PERIOD;
|
||||
return DetailOneTimeTrackerState.MINIMUM_PERIOD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double daysPerPixel() {
|
||||
return ((double) 365 / FIRST_LEVEL_ITEM_SIZE);
|
||||
return (double) 365 / FIRST_LEVEL_ITEM_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ package org.zkoss.ganttz.timetracker.zoom;
|
|||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*
|
||||
*/
|
||||
public interface IDetailItemModificator {
|
||||
public interface IDetailItemModifier {
|
||||
|
||||
public DetailItem applyModificationsTo(DetailItem item, ZoomLevel z);
|
||||
DetailItem applyModificationsTo(DetailItem item, ZoomLevel z);
|
||||
|
||||
}
|
||||
|
|
@ -24,6 +24,6 @@ package org.zkoss.ganttz.timetracker.zoom;
|
|||
|
||||
public interface IZoomLevelChangedListener {
|
||||
|
||||
public void zoomLevelChanged(ZoomLevel detailLevel);
|
||||
void zoomLevelChanged(ZoomLevel detailLevel);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,33 +30,32 @@ import org.apache.commons.lang3.Validate;
|
|||
|
||||
/**
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*
|
||||
*/
|
||||
public class SeveralModificators implements IDetailItemModificator {
|
||||
public class SeveralModifiers implements IDetailItemModifier {
|
||||
|
||||
public static IDetailItemModificator empty() {
|
||||
return new SeveralModificators(Collections.<IDetailItemModificator> emptyList());
|
||||
private final List<IDetailItemModifier> modifiers;
|
||||
|
||||
public static IDetailItemModifier empty() {
|
||||
return new SeveralModifiers(Collections.emptyList());
|
||||
}
|
||||
|
||||
public static IDetailItemModificator create(IDetailItemModificator... modificators) {
|
||||
return new SeveralModificators(Arrays.asList(modificators));
|
||||
public static IDetailItemModifier create(IDetailItemModifier... modifiers) {
|
||||
return new SeveralModifiers(Arrays.asList(modifiers));
|
||||
}
|
||||
|
||||
public static IDetailItemModificator create(Collection<? extends IDetailItemModificator> modificators) {
|
||||
return new SeveralModificators(modificators);
|
||||
public static IDetailItemModifier create(Collection<? extends IDetailItemModifier> modifiers) {
|
||||
return new SeveralModifiers(modifiers);
|
||||
}
|
||||
|
||||
private final List<IDetailItemModificator> modificators;
|
||||
|
||||
private SeveralModificators(Collection<? extends IDetailItemModificator> modificators) {
|
||||
Validate.noNullElements(modificators);
|
||||
this.modificators = new ArrayList<>(modificators);
|
||||
private SeveralModifiers(Collection<? extends IDetailItemModifier> modifiers) {
|
||||
Validate.noNullElements(modifiers);
|
||||
this.modifiers = new ArrayList<>(modifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetailItem applyModificationsTo(DetailItem item, ZoomLevel z) {
|
||||
DetailItem result = item;
|
||||
for (IDetailItemModificator each : modificators) {
|
||||
for (IDetailItemModifier each : modifiers) {
|
||||
result = each.applyModificationsTo(result, z);
|
||||
}
|
||||
|
||||
|
|
@ -47,6 +47,16 @@ import org.zkoss.ganttz.util.Interval;
|
|||
*/
|
||||
public abstract class TimeTrackerState {
|
||||
|
||||
private final IDetailItemModifier firstLevelModifier;
|
||||
|
||||
private final IDetailItemModifier secondLevelModifier;
|
||||
|
||||
protected TimeTrackerState(IDetailItemModifier firstLevelModifier, IDetailItemModifier secondLevelModifier) {
|
||||
|
||||
this.firstLevelModifier = firstLevelModifier;
|
||||
this.secondLevelModifier = secondLevelModifier;
|
||||
}
|
||||
|
||||
public static Date year(int year) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.clear();
|
||||
|
|
@ -54,7 +64,7 @@ public abstract class TimeTrackerState {
|
|||
return calendar.getTime();
|
||||
}
|
||||
|
||||
public static abstract class LazyGenerator<T> implements Iterator<T> {
|
||||
public abstract static class LazyGenerator<T> implements Iterator<T> {
|
||||
|
||||
private T current;
|
||||
|
||||
|
|
@ -69,7 +79,9 @@ public abstract class TimeTrackerState {
|
|||
|
||||
@Override
|
||||
public T next() {
|
||||
return this.current = next(this.current);
|
||||
this.current = next(this.current);
|
||||
|
||||
return this.current;
|
||||
}
|
||||
|
||||
protected abstract T next(T last);
|
||||
|
|
@ -80,27 +92,15 @@ public abstract class TimeTrackerState {
|
|||
}
|
||||
}
|
||||
|
||||
protected static final long MILLSECONDS_IN_DAY = 1000 * 60 * 60 * 24;
|
||||
|
||||
// Pending to calculate interval dinamically
|
||||
protected static final int NUMBER_OF_ITEMS_MINIMUM = 4;
|
||||
|
||||
private final IDetailItemModificator firstLevelModificator;
|
||||
|
||||
private final IDetailItemModificator secondLevelModificator;
|
||||
|
||||
protected TimeTrackerState(IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator) {
|
||||
this.firstLevelModificator = firstLevelModificator;
|
||||
this.secondLevelModificator = secondLevelModificator;
|
||||
}
|
||||
|
||||
// When applied after setting current day, removes extra data as current day
|
||||
// or bank holidays, and must proccess the array twice. May be refactorized
|
||||
private static List<DetailItem> markEvens(
|
||||
Collection<? extends DetailItem> items) {
|
||||
/**
|
||||
* When applied after setting current day, removes extra data as current day or bank holidays,
|
||||
* and must process the array twice.
|
||||
*
|
||||
* May be refactorized.
|
||||
*/
|
||||
private static List<DetailItem> markEvens(Collection<? extends DetailItem> items) {
|
||||
boolean even = false;
|
||||
ArrayList<DetailItem> result = new ArrayList<DetailItem>();
|
||||
ArrayList<DetailItem> result = new ArrayList<>();
|
||||
|
||||
for (DetailItem detailItem : items) {
|
||||
detailItem.setEven(even);
|
||||
|
|
@ -120,68 +120,73 @@ public abstract class TimeTrackerState {
|
|||
|
||||
public Collection<DetailItem> getSecondLevelDetails(Interval interval) {
|
||||
if (getZoomLevel() == ZoomLevel.DETAIL_FIVE) {
|
||||
// Evens are not highlighted in day view
|
||||
// Events are not highlighted in day view
|
||||
return applyConfiguredModifications(
|
||||
secondLevelModificator,
|
||||
createDetailsForSecondLevel(interval), getZoomLevel());
|
||||
secondLevelModifier,
|
||||
createDetailsForSecondLevel(interval),
|
||||
getZoomLevel());
|
||||
} else {
|
||||
return markEvens(applyConfiguredModifications(
|
||||
secondLevelModificator,
|
||||
createDetailsForSecondLevel(interval), getZoomLevel()));
|
||||
secondLevelModifier,
|
||||
createDetailsForSecondLevel(interval),
|
||||
getZoomLevel()));
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<DetailItem> getFirstLevelDetails(Interval interval) {
|
||||
return applyConfiguredModifications(firstLevelModificator,
|
||||
createDetailsForFirstLevel(interval), getZoomLevel());
|
||||
return applyConfiguredModifications(
|
||||
firstLevelModifier, createDetailsForFirstLevel(interval), getZoomLevel());
|
||||
}
|
||||
|
||||
private static List<DetailItem> applyConfiguredModifications(
|
||||
IDetailItemModificator modificator,
|
||||
Collection<? extends DetailItem> detailsItems, ZoomLevel zoomlevel) {
|
||||
List<DetailItem> result = new ArrayList<DetailItem>(detailsItems.size());
|
||||
private static List<DetailItem> applyConfiguredModifications(IDetailItemModifier modifier,
|
||||
Collection<? extends DetailItem> detailsItems,
|
||||
ZoomLevel zoomlevel) {
|
||||
|
||||
List<DetailItem> result = new ArrayList<>(detailsItems.size());
|
||||
for (DetailItem each : detailsItems) {
|
||||
result.add(modificator.applyModificationsTo(each, zoomlevel));
|
||||
result.add(modifier.applyModificationsTo(each, zoomlevel));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Collection<DetailItem> createDetails(Interval interval,
|
||||
Iterator<LocalDate> datesGenerator,
|
||||
IDetailItemCreator detailItemCreator) {
|
||||
Iterator<LocalDate> datesGenerator,
|
||||
IDetailItemCreator detailItemCreator) {
|
||||
|
||||
List<DetailItem> result = new ArrayList<>();
|
||||
LocalDate current = interval.getStart();
|
||||
LocalDate end = interval.getFinish();
|
||||
List<DetailItem> result = new ArrayList<DetailItem>();
|
||||
|
||||
while (current.isBefore(end)) {
|
||||
result.add(detailItemCreator.create(current
|
||||
.toDateTimeAtStartOfDay()));
|
||||
result.add(detailItemCreator.create(current.toDateTimeAtStartOfDay()));
|
||||
assert datesGenerator.hasNext();
|
||||
current = datesGenerator.next();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private final Collection<DetailItem> createDetailsForFirstLevel(
|
||||
Interval interval) {
|
||||
private final Collection<DetailItem> createDetailsForFirstLevel(Interval interval) {
|
||||
Interval realInterval = getRealIntervalFor(interval);
|
||||
return createDetails(realInterval,
|
||||
|
||||
return createDetails(
|
||||
realInterval,
|
||||
getPeriodsFirstLevelGenerator(realInterval.getStart()),
|
||||
getDetailItemCreatorFirstLevel());
|
||||
}
|
||||
|
||||
protected abstract Iterator<LocalDate> getPeriodsFirstLevelGenerator(
|
||||
LocalDate start);
|
||||
protected abstract Iterator<LocalDate> getPeriodsFirstLevelGenerator(LocalDate start);
|
||||
|
||||
private final Collection<DetailItem> createDetailsForSecondLevel(
|
||||
Interval interval) {
|
||||
private final Collection<DetailItem> createDetailsForSecondLevel(Interval interval) {
|
||||
Interval realInterval = getRealIntervalFor(interval);
|
||||
return createDetails(realInterval,
|
||||
|
||||
return createDetails(
|
||||
realInterval,
|
||||
getPeriodsSecondLevelGenerator(realInterval.getStart()),
|
||||
getDetailItemCreatorSecondLevel());
|
||||
}
|
||||
|
||||
protected abstract Iterator<LocalDate> getPeriodsSecondLevelGenerator(
|
||||
LocalDate start);
|
||||
protected abstract Iterator<LocalDate> getPeriodsSecondLevelGenerator(LocalDate start);
|
||||
|
||||
protected abstract IDetailItemCreator getDetailItemCreatorFirstLevel();
|
||||
|
||||
|
|
@ -201,6 +206,7 @@ public abstract class TimeTrackerState {
|
|||
return Years.yearsBetween(start, end);
|
||||
}
|
||||
},
|
||||
|
||||
MONTHS {
|
||||
@Override
|
||||
public ReadablePeriod toPeriod(int amount) {
|
||||
|
|
@ -212,6 +218,7 @@ public abstract class TimeTrackerState {
|
|||
return Months.monthsBetween(start, end);
|
||||
}
|
||||
},
|
||||
|
||||
WEEKS {
|
||||
@Override
|
||||
public ReadablePeriod toPeriod(int amount) {
|
||||
|
|
@ -223,6 +230,7 @@ public abstract class TimeTrackerState {
|
|||
return Weeks.weeksBetween(start, end);
|
||||
}
|
||||
},
|
||||
|
||||
DAYS {
|
||||
@Override
|
||||
public ReadablePeriod toPeriod(int amount) {
|
||||
|
|
@ -237,8 +245,7 @@ public abstract class TimeTrackerState {
|
|||
|
||||
public abstract ReadablePeriod toPeriod(int amount);
|
||||
|
||||
public abstract BaseSingleFieldPeriod differenceBetween(
|
||||
LocalDate start, LocalDate end);
|
||||
public abstract BaseSingleFieldPeriod differenceBetween(LocalDate start, LocalDate end);
|
||||
|
||||
public Period amount(int amount) {
|
||||
return new Period(this, amount);
|
||||
|
|
@ -262,18 +269,16 @@ public abstract class TimeTrackerState {
|
|||
}
|
||||
|
||||
BaseSingleFieldPeriod asPeriod(Interval interval) {
|
||||
return type.differenceBetween(interval.getStart(),
|
||||
interval.getFinish());
|
||||
return type.differenceBetween(interval.getStart(), interval.getFinish());
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Period getMinimumPeriod();
|
||||
|
||||
private Interval ensureMinimumInterval(Interval interval) {
|
||||
LocalDate newEnd = interval.getStart().plus(
|
||||
getMinimumPeriod().toPeriod());
|
||||
return new Interval(interval.getStart(), Collections.max(asList(newEnd,
|
||||
interval.getFinish())));
|
||||
LocalDate newEnd = interval.getStart().plus(getMinimumPeriod().toPeriod());
|
||||
|
||||
return new Interval(interval.getStart(), Collections.max(asList(newEnd, interval.getFinish())));
|
||||
}
|
||||
|
||||
public Interval getRealIntervalFor(Interval testInterval) {
|
||||
|
|
@ -283,9 +288,8 @@ public abstract class TimeTrackerState {
|
|||
private Interval calculateForAtLeastMinimum(Interval atLeastMinimum) {
|
||||
LocalDate start = round(atLeastMinimum.getStart(), true);
|
||||
LocalDate finish = round(atLeastMinimum.getFinish(), false);
|
||||
Interval result = new Interval(start.toDateTimeAtStartOfDay().toDate(),
|
||||
finish.toDateTimeAtStartOfDay().toDate());
|
||||
return result;
|
||||
|
||||
return new Interval(start.toDateTimeAtStartOfDay().toDate(), finish.toDateTimeAtStartOfDay().toDate());
|
||||
}
|
||||
|
||||
public abstract double daysPerPixel();
|
||||
|
|
|
|||
|
|
@ -32,11 +32,10 @@ import org.joda.time.ReadablePeriod;
|
|||
*/
|
||||
public abstract class TimeTrackerStateWithSubintervalsFitting extends TimeTrackerState {
|
||||
|
||||
protected TimeTrackerStateWithSubintervalsFitting(
|
||||
IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator) {
|
||||
protected TimeTrackerStateWithSubintervalsFitting(IDetailItemModifier firstLevelModifier,
|
||||
IDetailItemModifier secondLevelModifier) {
|
||||
|
||||
super(firstLevelModificator, secondLevelModificator);
|
||||
super(firstLevelModifier, secondLevelModifier);
|
||||
}
|
||||
|
||||
private final class PeriodicalGenerator extends LazyGenerator<LocalDate> {
|
||||
|
|
|
|||
|
|
@ -23,17 +23,17 @@ package org.zkoss.ganttz.timetracker.zoom;
|
|||
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.zkoss.ganttz.i18n.I18nHelper;
|
||||
|
||||
/**
|
||||
* Describes levels of zooming (time-zooming) on Gantt panel.
|
||||
*
|
||||
* @author Francisco Javier Moran Rúa
|
||||
*/
|
||||
public enum ZoomLevel {
|
||||
|
||||
DETAIL_ONE(_("Year")) {
|
||||
@Override
|
||||
public TimeTrackerState getTimeTrackerState(
|
||||
IDetailItemModificator firstLevel,
|
||||
IDetailItemModificator secondLevel) {
|
||||
public TimeTrackerState getTimeTrackerState(IDetailItemModifier firstLevel, IDetailItemModifier secondLevel) {
|
||||
return new DetailOneTimeTrackerState(firstLevel, secondLevel);
|
||||
}
|
||||
|
||||
|
|
@ -42,11 +42,10 @@ public enum ZoomLevel {
|
|||
return days > 950;
|
||||
}
|
||||
},
|
||||
|
||||
DETAIL_TWO(_("Quarter")) {
|
||||
@Override
|
||||
public TimeTrackerState getTimeTrackerState(
|
||||
IDetailItemModificator firstLevel,
|
||||
IDetailItemModificator secondLevel) {
|
||||
public TimeTrackerState getTimeTrackerState(IDetailItemModifier firstLevel, IDetailItemModifier secondLevel) {
|
||||
return new DetailTwoTimeTrackerState(firstLevel, secondLevel);
|
||||
}
|
||||
|
||||
|
|
@ -55,11 +54,10 @@ public enum ZoomLevel {
|
|||
return days > 550;
|
||||
}
|
||||
},
|
||||
|
||||
DETAIL_THREE(_("Month")) {
|
||||
@Override
|
||||
public TimeTrackerState getTimeTrackerState(
|
||||
IDetailItemModificator firstLevel,
|
||||
IDetailItemModificator secondLevel) {
|
||||
public TimeTrackerState getTimeTrackerState(IDetailItemModifier firstLevel, IDetailItemModifier secondLevel) {
|
||||
return new DetailThreeTimeTrackerState(firstLevel, secondLevel);
|
||||
}
|
||||
|
||||
|
|
@ -68,11 +66,10 @@ public enum ZoomLevel {
|
|||
return days > 175;
|
||||
}
|
||||
},
|
||||
|
||||
DETAIL_FOUR(_("Week")) {
|
||||
@Override
|
||||
public TimeTrackerState getTimeTrackerState(
|
||||
IDetailItemModificator firstLevel,
|
||||
IDetailItemModificator secondLevel) {
|
||||
public TimeTrackerState getTimeTrackerState(IDetailItemModifier firstLevel, IDetailItemModifier secondLevel) {
|
||||
return new DetailFourTimeTrackerState(firstLevel, secondLevel);
|
||||
}
|
||||
|
||||
|
|
@ -81,84 +78,63 @@ public enum ZoomLevel {
|
|||
return days > 50;
|
||||
}
|
||||
},
|
||||
|
||||
DETAIL_FIVE(_("Day")) {
|
||||
@Override
|
||||
public TimeTrackerState getTimeTrackerState(
|
||||
IDetailItemModificator firstLevel,
|
||||
IDetailItemModificator secondLevel) {
|
||||
public TimeTrackerState getTimeTrackerState(IDetailItemModifier firstLevel, IDetailItemModifier secondLevel) {
|
||||
return new DetailFiveTimeTrackerState(firstLevel, secondLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuitableFor(int days) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
DETAIL_SIX(_("Hour")) {
|
||||
@Override
|
||||
public TimeTrackerState getTimeTrackerState(
|
||||
IDetailItemModificator firstLevel,
|
||||
IDetailItemModificator secondLevel) {
|
||||
return new DetailSixTimeTrackerState(firstLevel, secondLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuitableFor(int days) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private String internalName;
|
||||
|
||||
ZoomLevel(String name) {
|
||||
this.internalName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces to mark the string as needing translation
|
||||
* Forces to mark the string as needing translation.
|
||||
*/
|
||||
private static String _(String string) {
|
||||
return string;
|
||||
}
|
||||
|
||||
private String internalName;
|
||||
|
||||
public String getInternalName() {
|
||||
return internalName;
|
||||
}
|
||||
|
||||
private ZoomLevel(String name) {
|
||||
this.internalName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if there is no next, returns <code>this</code>. Otherwise returns
|
||||
* the next one.
|
||||
* @return if there is no next, returns <code>this</code>. Otherwise returns the next one.
|
||||
*/
|
||||
public ZoomLevel next() {
|
||||
final int next = ordinal() + 1;
|
||||
if (next == ZoomLevel.values().length) {
|
||||
return this;
|
||||
}
|
||||
return ZoomLevel.values()[next];
|
||||
|
||||
return next == ZoomLevel.values().length ? this : ZoomLevel.values()[next];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if there is no previous, returns <code>this</code>. Otherwise
|
||||
* returns the previous one.
|
||||
* @return if there is no previous, returns <code>this</code>. Otherwise returns the previous one.
|
||||
*/
|
||||
public ZoomLevel previous() {
|
||||
if (ordinal() == 0) {
|
||||
return this;
|
||||
}
|
||||
return ZoomLevel.values()[ordinal() - 1];
|
||||
return ordinal() == 0 ? this : ZoomLevel.values()[ordinal() - 1];
|
||||
}
|
||||
|
||||
public abstract TimeTrackerState getTimeTrackerState(
|
||||
IDetailItemModificator firstLevel,
|
||||
IDetailItemModificator secondLevel);
|
||||
IDetailItemModifier firstLevel, IDetailItemModifier secondLevel);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return I18nHelper._(internalName);
|
||||
return _(internalName);
|
||||
}
|
||||
|
||||
public static ZoomLevel getFromString(String zoomLevelParameter) {
|
||||
ZoomLevel requiredZoomLevel = ZoomLevel.DETAIL_ONE;
|
||||
|
||||
if (zoomLevelParameter != null) {
|
||||
for (ZoomLevel z : ZoomLevel.values()) {
|
||||
if (zoomLevelParameter.equals(z.internalName)) {
|
||||
|
|
@ -170,10 +146,10 @@ public enum ZoomLevel {
|
|||
|
||||
}
|
||||
|
||||
public static ZoomLevel getDefaultZoomByDates(LocalDate initDate,
|
||||
LocalDate endDate) {
|
||||
public static ZoomLevel getDefaultZoomByDates(LocalDate initDate, LocalDate endDate) {
|
||||
if (initDate != null && endDate != null) {
|
||||
int days = Days.daysBetween(initDate, endDate).getDays();
|
||||
|
||||
for (ZoomLevel each : ZoomLevel.values()) {
|
||||
if (each.isSuitableFor(days)) {
|
||||
return each;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import org.zkoss.zul.Grid;
|
|||
import org.zkoss.zul.Listbox;
|
||||
import org.zkoss.zul.Listitem;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.api.Rows;
|
||||
import org.zkoss.zul.Rows;
|
||||
|
||||
/**
|
||||
* Utility methods to find components
|
||||
|
|
@ -40,55 +40,63 @@ public class ComponentsFinder {
|
|||
private ComponentsFinder() {
|
||||
}
|
||||
|
||||
public static <T> List<T> findComponentsOfType(Class<T> type,
|
||||
List<? extends Object> children) {
|
||||
ArrayList<T> result = new ArrayList<T>();
|
||||
public static <T> List<T> findComponentsOfType(Class<T> type, List<?> children) {
|
||||
ArrayList<T> result = new ArrayList<>();
|
||||
for (Object child : children) {
|
||||
if (type.isInstance(child)) {
|
||||
|
||||
if ( type.isInstance(child) ) {
|
||||
result.add(type.cast(child));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Component findById(String id,
|
||||
List<? extends Component> children) {
|
||||
public static Component findById(String id, List<? extends Component> children) {
|
||||
for (Component child : children) {
|
||||
if (child.getId().equals(id)) {
|
||||
|
||||
if ( child.getId().equals(id) ) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Row findRowByValue(Grid grid, Object needle) {
|
||||
if (grid == null || needle == null) {
|
||||
if ( grid == null || needle == null ) {
|
||||
return null;
|
||||
}
|
||||
Rows rows = grid.getRows();
|
||||
for (Object each : rows.getChildren()) {
|
||||
if (each instanceof Row) {
|
||||
|
||||
if ( each instanceof Row ) {
|
||||
Row row = (Row) each;
|
||||
Object value = row.getValue();
|
||||
if (needle.equals(value)) {
|
||||
|
||||
if ( needle.equals(value) ) {
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Listitem findItemByValue(Listbox listbox, Object needle) {
|
||||
if (listbox == null || needle == null) {
|
||||
if ( listbox == null || needle == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Object each : listbox.getItems()) {
|
||||
Listitem item = (Listitem) each;
|
||||
Object value = item.getValue();
|
||||
if (needle.toString().equals(value.toString())) {
|
||||
|
||||
if ( needle.toString().equals(value.toString()) ) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ import org.zkoss.zk.ui.util.Clients;
|
|||
|
||||
|
||||
/**
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* Handler of long operations ( {@link Clients#showBusy(String)}, {@link Clients#clearBusy()} ).
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*/
|
||||
public class LongOperationFeedback {
|
||||
|
||||
|
|
@ -61,16 +62,20 @@ public class LongOperationFeedback {
|
|||
}
|
||||
};
|
||||
|
||||
public static void execute(final Component component, final ILongOperation longOperation) {
|
||||
public static void execute(final Component component,
|
||||
final ILongOperation longOperation) {
|
||||
|
||||
Validate.notNull(component);
|
||||
Validate.notNull(longOperation);
|
||||
|
||||
if ( alreadyInside.get() ) {
|
||||
if (alreadyInside.get()) {
|
||||
dispatchActionDirectly(longOperation);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Clients.showBusy(longOperation.getName());
|
||||
|
||||
executeLater(component, new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
|
|
@ -86,13 +91,13 @@ public class LongOperationFeedback {
|
|||
});
|
||||
}
|
||||
|
||||
public static void executeLater(final Component component, final Runnable runnable) {
|
||||
public static void executeLater(final Component component,
|
||||
final Runnable runnable) {
|
||||
Validate.notNull(runnable);
|
||||
Validate.notNull(component);
|
||||
|
||||
final String eventName = generateEventName();
|
||||
component.addEventListener(eventName, new EventListener() {
|
||||
|
||||
component.addEventListener(eventName, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
try {
|
||||
|
|
@ -131,13 +136,9 @@ public class LongOperationFeedback {
|
|||
}
|
||||
|
||||
public static IDesktopUpdate and(final IDesktopUpdate... desktopUpdates) {
|
||||
return new IDesktopUpdate() {
|
||||
|
||||
@Override
|
||||
public void doUpdate() {
|
||||
for (IDesktopUpdate each : desktopUpdates) {
|
||||
each.doUpdate();
|
||||
}
|
||||
return () -> {
|
||||
for (IDesktopUpdate each : desktopUpdates) {
|
||||
each.doUpdate();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -149,50 +150,39 @@ public class LongOperationFeedback {
|
|||
private static final ExecutorService executor = Executors.newCachedThreadPool();
|
||||
|
||||
public static <T> IDesktopUpdatesEmitter<T> doNothingEmitter() {
|
||||
return new IDesktopUpdatesEmitter<T>() {
|
||||
@Override
|
||||
public void doUpdate(T value) {
|
||||
}
|
||||
};
|
||||
return value -> {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a long operation. The background operation can send
|
||||
* {@link IDesktopUpdate} objects that can update desktop state. Trying to
|
||||
* update the components in any other way would fail
|
||||
*/
|
||||
public static void progressive(final Desktop desktop, final IBackGroundOperation<IDesktopUpdate> operation) {
|
||||
progressive(desktop, operation, new IDesktopUpdatesEmitter<IDesktopUpdate>() {
|
||||
@Override
|
||||
public void doUpdate(IDesktopUpdate update) {
|
||||
update.doUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a long operation. The background operation can send
|
||||
* <code>T</code> objects that can update desktop state. A
|
||||
* {@link IDesktopUpdatesEmitter} that handle these objects is necessary.
|
||||
* Executes a long operation.
|
||||
* The background operation can send {@link IDesktopUpdate} objects that can update desktop state.
|
||||
* Trying to update the components in any other way would fail.
|
||||
*/
|
||||
public static <T> void progressive(
|
||||
final Desktop desktop,
|
||||
final IBackGroundOperation<T> operation,
|
||||
final IDesktopUpdatesEmitter<T> emitter) {
|
||||
public static void progressive(final Desktop desktop,
|
||||
final IBackGroundOperation<IDesktopUpdate> operation) {
|
||||
|
||||
progressive(desktop, operation, (update) -> update.doUpdate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a long operation.
|
||||
* The background operation can send
|
||||
* <code>T</code> objects that can update desktop state.
|
||||
* A {@link IDesktopUpdatesEmitter} that handle these objects is necessary.
|
||||
* Trying to update the components in any other way would fail.
|
||||
*/
|
||||
public static <T> void progressive(final Desktop desktop,
|
||||
final IBackGroundOperation<T> operation,
|
||||
final IDesktopUpdatesEmitter<T> emitter) {
|
||||
desktop.enableServerPush(true);
|
||||
executor.execute(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
IBackGroundOperation<T> operationWithAsyncUpates = withAsyncUpates(operation, desktop);
|
||||
operationWithAsyncUpates.doOperation(emitter);
|
||||
} catch (Exception e) {
|
||||
LOG.error("error executing background operation", e);
|
||||
} finally {
|
||||
desktop.enableServerPush(false);
|
||||
}
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
IBackGroundOperation<T> operationWithAsyncUpates = withAsyncUpates(operation, desktop);
|
||||
operationWithAsyncUpates.doOperation(emitter);
|
||||
} catch (Exception e) {
|
||||
LOG.error("error executing background operation", e);
|
||||
} finally {
|
||||
desktop.enableServerPush(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -202,14 +192,14 @@ public class LongOperationFeedback {
|
|||
final Desktop desktop) {
|
||||
|
||||
return new IBackGroundOperation<T>() {
|
||||
|
||||
@Override
|
||||
public void doOperation(IDesktopUpdatesEmitter<T> originalEmitter) {
|
||||
|
||||
NotBlockingDesktopUpdates<T> notBlockingDesktopUpdates =
|
||||
new NotBlockingDesktopUpdates<T>(desktop, originalEmitter);
|
||||
new NotBlockingDesktopUpdates<>(desktop, originalEmitter);
|
||||
|
||||
Future<?> future = executor.submit(notBlockingDesktopUpdates);
|
||||
|
||||
try {
|
||||
backgroundOperation.doOperation(notBlockingDesktopUpdates);
|
||||
} finally {
|
||||
|
|
@ -231,7 +221,9 @@ public class LongOperationFeedback {
|
|||
private static class NotBlockingDesktopUpdates<T> implements IDesktopUpdatesEmitter<T>, Runnable {
|
||||
|
||||
private BlockingQueue<EndOrValue<T>> queue = new LinkedBlockingQueue<>();
|
||||
|
||||
private final IDesktopUpdatesEmitter<T> original;
|
||||
|
||||
private final Desktop desktop;
|
||||
|
||||
NotBlockingDesktopUpdates(Desktop desktop, IDesktopUpdatesEmitter<T> original) {
|
||||
|
|
@ -245,30 +237,28 @@ public class LongOperationFeedback {
|
|||
}
|
||||
|
||||
void finish() {
|
||||
queue.add(EndOrValue.<T> end());
|
||||
queue.add(EndOrValue.end());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
List<T> batch = new ArrayList<>();
|
||||
|
||||
while (true) {
|
||||
batch.clear();
|
||||
EndOrValue<T> current;
|
||||
|
||||
try {
|
||||
current = queue.take();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if ( current.isEnd() ) {
|
||||
if (current.isEnd())
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !desktop.isAlive() || !desktop.isServerPushEnabled() ) {
|
||||
if (!desktop.isAlive() || !desktop.isServerPushEnabled())
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Executions.activate(desktop);
|
||||
|
|
@ -279,27 +269,30 @@ public class LongOperationFeedback {
|
|||
|
||||
try {
|
||||
original.doUpdate(current.getValue());
|
||||
while ((current = queue.poll()) != null) {
|
||||
|
||||
if ( current.isEnd() ) {
|
||||
while ((current = queue.poll()) != null) {
|
||||
if (current.isEnd()) {
|
||||
break;
|
||||
}
|
||||
|
||||
batch.add(current.getValue());
|
||||
original.doUpdate(current.getValue());
|
||||
}
|
||||
|
||||
} finally {
|
||||
Executions.deactivate(desktop);
|
||||
}
|
||||
if ( current != null && current.isEnd() ) {
|
||||
|
||||
if (current != null && current.isEnd()) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static abstract class EndOrValue<T> {
|
||||
private abstract static class EndOrValue<T> {
|
||||
public static <T> EndOrValue<T> end() {
|
||||
return new End<>();
|
||||
}
|
||||
|
|
@ -309,6 +302,7 @@ public class LongOperationFeedback {
|
|||
}
|
||||
|
||||
public abstract boolean isEnd();
|
||||
|
||||
public abstract T getValue() throws UnsupportedOperationException;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,32 +31,48 @@ import org.zkoss.zk.ui.Component;
|
|||
import org.zkoss.zk.ui.HtmlNativeComponent;
|
||||
import org.zkoss.zk.ui.Page;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.OpenEvent;
|
||||
import org.zkoss.zul.Menuitem;
|
||||
import org.zkoss.zul.Menupopup;
|
||||
import org.zkoss.zul.Menuseparator;
|
||||
import org.zkoss.zul.impl.api.XulElement;
|
||||
import org.zkoss.zul.impl.XulElement;
|
||||
|
||||
/**
|
||||
* Create context menu for right-click mouse.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class MenuBuilder<T extends XulElement> {
|
||||
|
||||
public static <T extends XulElement> MenuBuilder<T> on(Page page,
|
||||
Collection<T> elements) {
|
||||
return new MenuBuilder<T>(page, elements);
|
||||
private final List<T> elements;
|
||||
|
||||
private final List<Item> items = new ArrayList<>();
|
||||
|
||||
private Component root;
|
||||
|
||||
private T referenced;
|
||||
|
||||
private MenuBuilder(Page page, Collection<? extends T> elements) {
|
||||
this.elements = new ArrayList<>(elements);
|
||||
this.root = findVisibleOn(getRoots(page));
|
||||
}
|
||||
|
||||
public static <T extends XulElement> MenuBuilder<T> on(Page page,
|
||||
T... elements) {
|
||||
public static <T extends XulElement> MenuBuilder<T> on(Page page, Collection<T> elements) {
|
||||
return new MenuBuilder<>(page, elements);
|
||||
}
|
||||
|
||||
public static <T extends XulElement> MenuBuilder<T> on(Page page, T... elements) {
|
||||
return on(page, Arrays.asList(elements));
|
||||
}
|
||||
|
||||
public static interface ItemAction<T> {
|
||||
|
||||
void onEvent(T choosen, Event event);
|
||||
public interface ItemAction<T> {
|
||||
void onEvent(T chosen, Event event);
|
||||
}
|
||||
|
||||
private class Item {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String icon;
|
||||
|
||||
private final ItemAction<T> action;
|
||||
|
|
@ -70,60 +86,50 @@ public class MenuBuilder<T extends XulElement> {
|
|||
Menuitem createMenuItem() {
|
||||
Menuitem result = new Menuitem();
|
||||
result.setLabel(name);
|
||||
if (icon != null) {
|
||||
|
||||
if ( icon != null ) {
|
||||
result.setImage(icon);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final List<T> elements;
|
||||
|
||||
private final List<Item> items = new ArrayList<Item>();
|
||||
|
||||
private Component root;
|
||||
|
||||
private MenuBuilder(Page page, Collection<? extends T> elements) {
|
||||
this.elements = new ArrayList<T>(elements);
|
||||
this.root = findVisibleOn(getRoots(page));
|
||||
}
|
||||
|
||||
private static List<Component> getRoots(Page page) {
|
||||
List<Component> result = new ArrayList<Component>();
|
||||
List<Component> result = new ArrayList<>();
|
||||
Component current = page.getFirstRoot();
|
||||
|
||||
while (current != null) {
|
||||
result.add(current);
|
||||
current = current.getNextSibling();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Component findVisibleOn(
|
||||
Collection<? extends Component> candidates) {
|
||||
private static Component findVisibleOn(Collection<? extends Component> candidates) {
|
||||
for (Component each : candidates) {
|
||||
if (each.isVisible()) {
|
||||
if ( each.isVisible() ) {
|
||||
return each;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException(
|
||||
"not found visible component on which to attach the menu");
|
||||
|
||||
throw new RuntimeException("not found visible component on which to attach the menu");
|
||||
}
|
||||
|
||||
public MenuBuilder<T> item(String name, String icon,
|
||||
ItemAction<T> itemAction) {
|
||||
if (name == null) {
|
||||
public MenuBuilder<T> item(String name, String icon, ItemAction<T> itemAction) {
|
||||
if ( name == null ) {
|
||||
throw new IllegalArgumentException("name cannot be null");
|
||||
}
|
||||
if (itemAction == null) {
|
||||
if ( itemAction == null ) {
|
||||
throw new IllegalArgumentException("itemAction cannot be null");
|
||||
}
|
||||
items.add(new Item(name, icon, itemAction));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private T referenced;
|
||||
|
||||
public Menupopup createWithoutSettingContext() {
|
||||
return create(false);
|
||||
}
|
||||
|
|
@ -134,55 +140,55 @@ public class MenuBuilder<T extends XulElement> {
|
|||
|
||||
private Menupopup create(boolean setContext) {
|
||||
Menupopup result = new Menupopup();
|
||||
result.addEventListener("onOpen", new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
OpenEvent openEvent = (OpenEvent) event;
|
||||
referenced = (T) openEvent.getReference();
|
||||
}
|
||||
result.addEventListener("onOpen", event -> {
|
||||
OpenEvent openEvent = (OpenEvent) event;
|
||||
referenced = (T) openEvent.getReference();
|
||||
});
|
||||
|
||||
for (final Item item : items) {
|
||||
if (!item.name.equals("separator")) {
|
||||
|
||||
if ( !"separator".equals(item.name) ) {
|
||||
Menuitem menuItem = item.createMenuItem();
|
||||
menuItem.addEventListener("onClick", new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
ItemAction<T> action = item.action;
|
||||
action.onEvent(referenced, event);
|
||||
}
|
||||
|
||||
menuItem.addEventListener("onClick", event -> {
|
||||
ItemAction<T> action = item.action;
|
||||
action.onEvent(referenced, event);
|
||||
});
|
||||
|
||||
result.appendChild(menuItem);
|
||||
} else {
|
||||
Menuseparator separator = new Menuseparator();
|
||||
result.appendChild(separator);
|
||||
}
|
||||
}
|
||||
|
||||
insertInRootComponent(result);
|
||||
if (setContext) {
|
||||
|
||||
if ( setContext ) {
|
||||
for (T element : elements) {
|
||||
element.setContext(result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void insertInRootComponent(Menupopup result) {
|
||||
ArrayList<Component> children = new ArrayList<Component>(root
|
||||
.getChildren());
|
||||
ArrayList<Component> children = new ArrayList<>(root.getChildren());
|
||||
Collections.reverse(children);
|
||||
// the Menupopup cannot be inserted after a HtmlNativeComponent, so we
|
||||
// try to avoid it
|
||||
if (children.isEmpty()) {
|
||||
// The Menupopup cannot be inserted after a HtmlNativeComponent, so we try to avoid it
|
||||
if ( children.isEmpty() ) {
|
||||
root.appendChild(result);
|
||||
}
|
||||
|
||||
for (Component child : children) {
|
||||
if (!(child instanceof HtmlNativeComponent)) {
|
||||
if ( !(child instanceof HtmlNativeComponent) ) {
|
||||
root.insertBefore(result, child);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("all children of " + root
|
||||
+ " are html native");
|
||||
|
||||
throw new RuntimeException("all children of " + root + " are html native");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,25 +38,29 @@ import org.zkoss.zul.event.TreeDataEvent;
|
|||
|
||||
/**
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||
* @author Bogdan Bodnarjuk <b.bodnarjuk@libreplan-enterprise.com>
|
||||
*/
|
||||
|
||||
public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(MutableTreeModel.class);
|
||||
|
||||
public interface IChildrenExtractor<T> {
|
||||
|
||||
public List<? extends T> getChildren(T parent);
|
||||
List<? extends T> getChildren(T parent);
|
||||
|
||||
}
|
||||
|
||||
private static class Node<T> {
|
||||
public static class Node<T> {
|
||||
|
||||
private T value;
|
||||
|
||||
private List<Node<T>> children = new LinkedList<Node<T>>();
|
||||
private List<Node<T>> children = new LinkedList<>();
|
||||
|
||||
private Node<T> parentNode;
|
||||
|
||||
private Node(T value) {
|
||||
public Node(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +68,8 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
for (Node<T> n : nodes) {
|
||||
n.parentNode = this;
|
||||
}
|
||||
if (position == null) {
|
||||
|
||||
if ( position == null ) {
|
||||
children.addAll(nodes);
|
||||
} else {
|
||||
children.addAll(position, nodes);
|
||||
|
|
@ -73,44 +78,54 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
|
||||
public int[] down(Node<T> node) {
|
||||
ListIterator<Node<T>> listIterator = children.listIterator();
|
||||
|
||||
while (listIterator.hasNext()) {
|
||||
Node<T> current = listIterator.next();
|
||||
if (current == node && listIterator.hasNext()) {
|
||||
|
||||
if ( current == node && listIterator.hasNext() ) {
|
||||
int nextIndex = listIterator.nextIndex();
|
||||
listIterator.remove();
|
||||
listIterator.next();
|
||||
listIterator.add(node);
|
||||
|
||||
return new int[] { nextIndex - 1, nextIndex };
|
||||
}
|
||||
}
|
||||
|
||||
return new int[] {};
|
||||
}
|
||||
|
||||
public int[] up(Node<T> node) {
|
||||
ListIterator<Node<T>> listIterator = children.listIterator(children
|
||||
.size());
|
||||
while (listIterator.hasPrevious()) {
|
||||
ListIterator<Node<T>> listIterator = children.listIterator(children.size());
|
||||
|
||||
while ( listIterator.hasPrevious() ) {
|
||||
Node<T> current = listIterator.previous();
|
||||
if (current == node && listIterator.hasPrevious()) {
|
||||
|
||||
if ( current == node && listIterator.hasPrevious() ) {
|
||||
listIterator.remove();
|
||||
int previousIndex = listIterator.previousIndex();
|
||||
listIterator.previous();
|
||||
listIterator.add(current);
|
||||
|
||||
return new int[] { previousIndex, previousIndex + 1 };
|
||||
}
|
||||
}
|
||||
|
||||
return new int[] {};
|
||||
}
|
||||
|
||||
private void until(LinkedList<Integer> result, Node<T> parent) {
|
||||
if (parent.equals(this)) {
|
||||
return;
|
||||
} else if (isRoot()) {
|
||||
// final reached, but parent not found
|
||||
result.clear();
|
||||
} else {
|
||||
result.add(0, this.parentNode.getIndexOf(this));
|
||||
this.parentNode.until(result, parent);
|
||||
if ( !parent.equals(this) ) {
|
||||
|
||||
if ( isRoot() ) {
|
||||
|
||||
/* Final reached, but parent not found */
|
||||
result.clear();
|
||||
|
||||
} else {
|
||||
result.add(0, this.parentNode.getIndexOf(this));
|
||||
this.parentNode.until(result, parent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -124,14 +139,16 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
}
|
||||
|
||||
public LinkedList<Integer> until(Node<T> parent) {
|
||||
LinkedList<Integer> result = new LinkedList<Integer>();
|
||||
LinkedList<Integer> result = new LinkedList<>();
|
||||
until(result, parent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int remove() {
|
||||
int positionInParent = parentNode.getIndexOf(this);
|
||||
parentNode.children.remove(positionInParent);
|
||||
|
||||
return positionInParent;
|
||||
}
|
||||
|
||||
|
|
@ -143,10 +160,10 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
|
||||
private final Node<T> root;
|
||||
|
||||
private transient Map<T, Node<T>> nodesByDomainObject = new WeakHashMap<T, Node<T>>();
|
||||
private transient Map<T, Node<T>> nodesByDomainObject = new WeakHashMap<>();
|
||||
|
||||
private static <T> Node<T> wrapOne(T object) {
|
||||
return new Node<T>(object);
|
||||
return new Node<>(object);
|
||||
}
|
||||
|
||||
private static <T> List<Node<T>> wrap(T... objects) {
|
||||
|
|
@ -154,14 +171,22 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
}
|
||||
|
||||
private static <T> List<Node<T>> wrap(Collection<? extends T> objects) {
|
||||
List<Node<T>> result = new ArrayList<Node<T>>();
|
||||
List<Node<T>> result = new ArrayList<>();
|
||||
|
||||
for (T o : objects) {
|
||||
result.add(wrapOne(o));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Node<T> find(Object domainObject) {
|
||||
for (Map.Entry<T, Node<T>> item : nodesByDomainObject.entrySet()) {
|
||||
if ( item.getKey() != null && item.getKey().equals(domainObject) ) {
|
||||
return item.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return nodesByDomainObject.get(domainObject);
|
||||
}
|
||||
|
||||
|
|
@ -170,33 +195,65 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
}
|
||||
|
||||
public static <T> MutableTreeModel<T> create(Class<T> type) {
|
||||
return new MutableTreeModel<T>(type, new Node<T>(null));
|
||||
return new MutableTreeModel<>(type, new Node<>(null));
|
||||
}
|
||||
|
||||
public static <T> MutableTreeModel<T> create(Class<T> type, T root) {
|
||||
return new MutableTreeModel<T>(type, wrapOne(root));
|
||||
return new MutableTreeModel<>(type, wrapOne(root));
|
||||
}
|
||||
|
||||
private MutableTreeModel(Class<T> type, Node<T> root) {
|
||||
super(root);
|
||||
if (type == null) {
|
||||
|
||||
if ( type == null ) {
|
||||
throw new IllegalArgumentException("type cannot be null");
|
||||
}
|
||||
nodesByDomainObject.put(unwrap(root), root);
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Is some cases it was returning new int[0], but should return new path instead.
|
||||
* Reason of that: API changes. Before it was looking for child index manually.
|
||||
* Now it is not looking at all.
|
||||
* So I decided to return value by our own
|
||||
* {@link MutableTreeModel#shouldILookForLastValue(Object, Node), {@link #shouldILookForParentValue(Object, Node)}}
|
||||
* Not to use {@link AbstractTreeModel#getIndexOfChild(Object parent, Object child)}.
|
||||
*/
|
||||
public int[] getPath(Object parent, Object last) {
|
||||
Node<T> parentNode = find(parent);
|
||||
Node<T> lastNode = find(last);
|
||||
if (parentNode == null || lastNode == null) {
|
||||
|
||||
if ( shouldILookForParentValue(parent, parentNode) ) {
|
||||
parentNode = find( ((Node) parent).value );
|
||||
}
|
||||
|
||||
if ( shouldILookForLastValue(last, lastNode) ) {
|
||||
lastNode = find( ((Node) last).value );
|
||||
}
|
||||
|
||||
if ( parentNode == null || lastNode == null) {
|
||||
return new int[0];
|
||||
}
|
||||
List<Integer> path = lastNode.until(parentNode);
|
||||
|
||||
return asIntArray(path);
|
||||
}
|
||||
|
||||
private boolean shouldILookForParentValue(Object parent, Node<T> parentNode) {
|
||||
return parent != null &&
|
||||
parentNode == null &&
|
||||
parent.getClass().toString().contains("Node") &&
|
||||
((Node) parent).value != null;
|
||||
}
|
||||
private boolean shouldILookForLastValue(Object last, Node<T> lastNode) {
|
||||
return last != null &&
|
||||
lastNode == null &&
|
||||
last.getClass().toString().contains("Node") &&
|
||||
((Node) last).value != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getPath(Object last) {
|
||||
return getPath(getRoot(), last);
|
||||
}
|
||||
|
|
@ -205,30 +262,33 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
T current = getRoot();
|
||||
for (int i = 0; i < path.length; i++) {
|
||||
int position = path[i];
|
||||
if (position >= getChildCount(current)) {
|
||||
|
||||
if ( position >= getChildCount(current) ) {
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Failure acessing the path at: "
|
||||
+ stringRepresentationUntil(path, i));
|
||||
"Failure acessing the path at: " + stringRepresentationUntil(path, i));
|
||||
}
|
||||
current = getChild(current, position);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
private static String stringRepresentationUntil(int[] path, int endExclusive) {
|
||||
String valid = Arrays.toString(Arrays
|
||||
.copyOfRange(path, 0, endExclusive));
|
||||
String invalid = Arrays.toString(Arrays.copyOfRange(path, endExclusive,
|
||||
path.length));
|
||||
String valid = Arrays.toString(Arrays.copyOfRange(path, 0, endExclusive));
|
||||
String invalid = Arrays.toString(Arrays.copyOfRange(path, endExclusive, path.length));
|
||||
|
||||
return valid + "^" + invalid;
|
||||
}
|
||||
|
||||
private int[] asIntArray(List<Integer> path) {
|
||||
int[] result = new int[path.size()];
|
||||
int i = 0;
|
||||
|
||||
for (Integer integer : path) {
|
||||
result[i++] = integer;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -237,21 +297,74 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
return unwrap(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getChild(int[] path){
|
||||
T node = getRoot();
|
||||
|
||||
for (int item : path) {
|
||||
if (item < 0 || item > _childCount(node))
|
||||
return null;
|
||||
|
||||
node = getChild(node, item);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private int _childCount(T parent) {
|
||||
return isLeaf(parent) ? 0 : getChildCount(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Previously index was correct,
|
||||
* because ZK API was calling {@link AbstractTreeModel#getIndexOfChild(Object, Object)} method.
|
||||
* Now it is not calling that method and sometimes index could be incorrect.
|
||||
* So I decided to make --index if it will throw exception.
|
||||
*/
|
||||
@Override
|
||||
public T getChild(Object parent, int index) {
|
||||
Node<T> node = find(parent);
|
||||
return unwrap(node.children.get(index));
|
||||
Node<T> node;
|
||||
|
||||
if (parent instanceof MutableTreeModel.Node) {
|
||||
node = find(((Node) parent).value);
|
||||
} else {
|
||||
node = find(parent);
|
||||
}
|
||||
|
||||
T nodeToReturn;
|
||||
|
||||
try {
|
||||
nodeToReturn = unwrap(node.children.get(index));
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
if (parent != null) {
|
||||
nodeToReturn = unwrap(node.parentNode.children.get(index));
|
||||
} else if (index - 1 >= 0) {
|
||||
nodeToReturn = unwrap(node.children.get(index - 1));
|
||||
} else {
|
||||
throw new IndexOutOfBoundsException("Something wrong with indexes");
|
||||
}
|
||||
}
|
||||
|
||||
return nodeToReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount(Object parent) {
|
||||
Node<T> node = find(parent);
|
||||
Node<T> node;
|
||||
|
||||
if (parent instanceof MutableTreeModel.Node) {
|
||||
node = find(((Node) parent).value);
|
||||
} else {
|
||||
node = find(parent);
|
||||
}
|
||||
|
||||
return node.children.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeaf(Object object) {
|
||||
Node<T> node = find(object);
|
||||
|
||||
return node.children.isEmpty();
|
||||
}
|
||||
|
||||
|
|
@ -265,35 +378,31 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
}
|
||||
|
||||
private IChildrenExtractor<T> noChildrenExtractor() {
|
||||
return new IChildrenExtractor<T>() {
|
||||
|
||||
@Override
|
||||
public List<? extends T> getChildren(T parent) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
return parent -> Collections.emptyList();
|
||||
}
|
||||
|
||||
private void add(Node<T> parent, Integer position, List<Node<T>> children,
|
||||
IChildrenExtractor<T> extractor) {
|
||||
if (children.isEmpty()) {
|
||||
private void add(Node<T> parent, Integer position, List<Node<T>> children, IChildrenExtractor<T> extractor) {
|
||||
if ( children.isEmpty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
int indexFrom = position == null ? parent.children.size() : position;
|
||||
int indexTo = indexFrom + children.size() - 1;
|
||||
addWithoutSendingEvents(parent, position, children, extractor);
|
||||
fireEvent(unwrap(parent), indexFrom, indexTo,
|
||||
TreeDataEvent.INTERVAL_ADDED);
|
||||
fireEvent(TreeDataEvent.INTERVAL_ADDED, getPath(parent), indexFrom, indexTo);
|
||||
}
|
||||
|
||||
private void addWithoutSendingEvents(Node<T> parent, Integer position,
|
||||
List<Node<T>> children, IChildrenExtractor<T> extractor) {
|
||||
private void addWithoutSendingEvents(Node<T> parent,
|
||||
Integer position,
|
||||
List<Node<T>> children,
|
||||
IChildrenExtractor<T> extractor) {
|
||||
|
||||
parent.addAll(position, children);
|
||||
addToNodesAndDomainMapping(children);
|
||||
|
||||
for (Node<T> each : children) {
|
||||
T value = each.value;
|
||||
addWithoutSendingEvents(each, 0,
|
||||
wrap(extractor.getChildren(value)), extractor);
|
||||
addWithoutSendingEvents(each, 0, wrap(extractor.getChildren(value)), extractor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -304,7 +413,7 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
}
|
||||
|
||||
public void add(T parent, T child) {
|
||||
ArrayList<T> children = new ArrayList<T>();
|
||||
ArrayList<T> children = new ArrayList<>();
|
||||
children.add(child);
|
||||
add(parent, children);
|
||||
}
|
||||
|
|
@ -314,7 +423,7 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
T parent = getParent(object);
|
||||
Node<T> parentNode = find(parent);
|
||||
int position = parentNode.getIndexOf(node);
|
||||
fireEvent(parent, position, position, TreeDataEvent.CONTENTS_CHANGED);
|
||||
fireEvent(TreeDataEvent.CONTENTS_CHANGED,getPath(parent), position, position);
|
||||
}
|
||||
|
||||
public void add(T parent, int position, Collection<? extends T> children) {
|
||||
|
|
@ -326,64 +435,64 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
add(parentNode, null, wrap(children));
|
||||
}
|
||||
|
||||
public void add(T parent, int position, Collection<? extends T> children,
|
||||
IChildrenExtractor<T> childrenExtractor) {
|
||||
public void add(T parent, int position, Collection<? extends T> children, IChildrenExtractor<T> childrenExtractor) {
|
||||
add(find(parent), position, wrap(children), childrenExtractor);
|
||||
}
|
||||
|
||||
public void add(T parent, Collection<? extends T> children,
|
||||
IChildrenExtractor<T> childrenExtractor) {
|
||||
public void add(T parent, Collection<? extends T> children, IChildrenExtractor<T> childrenExtractor) {
|
||||
add(find(parent), null, wrap(children), childrenExtractor);
|
||||
}
|
||||
|
||||
public void remove(T node) {
|
||||
Node<T> found = find(node);
|
||||
if (found.isRoot()) {
|
||||
throw new IllegalArgumentException(node
|
||||
+ " is root. It can't be removed");
|
||||
|
||||
if ( found.isRoot() ) {
|
||||
throw new IllegalArgumentException(node + " is root. It can't be removed");
|
||||
}
|
||||
|
||||
int positionInParent = found.remove();
|
||||
nodesByDomainObject.remove(node);
|
||||
fireEvent(unwrap(found.parentNode), positionInParent, positionInParent,
|
||||
TreeDataEvent.INTERVAL_REMOVED);
|
||||
fireEvent(TreeDataEvent.INTERVAL_REMOVED, getPath(found.parentNode), positionInParent, positionInParent);
|
||||
}
|
||||
|
||||
public T getParent(T node) {
|
||||
Node<T> associatedNode = find(node);
|
||||
if (associatedNode.equals(root)) {
|
||||
if ( associatedNode.equals(root) ) {
|
||||
throw new IllegalArgumentException(node + " is root");
|
||||
}
|
||||
|
||||
return unwrap(associatedNode.getParent());
|
||||
}
|
||||
|
||||
public List<T> getParents(T node) {
|
||||
ArrayList<T> result = new ArrayList<T>();
|
||||
ArrayList<T> result = new ArrayList<>();
|
||||
|
||||
try {
|
||||
T current = node;
|
||||
while (!isRoot(current)) {
|
||||
|
||||
while ( !isRoot(current) ) {
|
||||
current = getParent(current);
|
||||
result.add(current);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Trying to get the parent of a removed node", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isRoot(T node) {
|
||||
Node<T> associatedNode = find(node);
|
||||
return associatedNode.isRoot();
|
||||
return find(node).isRoot();
|
||||
}
|
||||
|
||||
public void replace(T nodeToRemove, T nodeToAdd,
|
||||
IChildrenExtractor<T> childrenExtractor) {
|
||||
public void replace(T nodeToRemove, T nodeToAdd, IChildrenExtractor<T> childrenExtractor) {
|
||||
T parent = getParent(nodeToRemove);
|
||||
Node<T> parentNode = find(parent);
|
||||
final int insertionPosition = parentNode.getIndexOf(find(nodeToRemove));
|
||||
remove(nodeToRemove);
|
||||
if (childrenExtractor != null) {
|
||||
add(parent, insertionPosition,
|
||||
Collections.singletonList(nodeToAdd), childrenExtractor);
|
||||
|
||||
if ( childrenExtractor != null ) {
|
||||
add(parent, insertionPosition, Collections.singletonList(nodeToAdd), childrenExtractor);
|
||||
} else {
|
||||
add(parent, insertionPosition, Collections.singletonList(nodeToAdd));
|
||||
}
|
||||
|
|
@ -397,7 +506,8 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
T parent = getParent(node);
|
||||
Node<T> parentNode = find(parent);
|
||||
int[] changed = parentNode.down(find(node));
|
||||
if (changed.length != 0) {
|
||||
|
||||
if ( changed.length != 0 ) {
|
||||
fireRecreationOfInterval(parentNode, changed[0], changed[1]);
|
||||
}
|
||||
}
|
||||
|
|
@ -406,27 +516,21 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
T parent = getParent(node);
|
||||
Node<T> parentNode = find(parent);
|
||||
int[] changed = parentNode.up(find(node));
|
||||
if (changed.length != 0) {
|
||||
|
||||
if ( changed.length != 0 ) {
|
||||
fireRecreationOfInterval(parentNode, changed[0], changed[1]);
|
||||
}
|
||||
}
|
||||
|
||||
private void fireRecreationOfInterval(Node<T> parentNode, int start,
|
||||
int endInclusive) {
|
||||
fireEvent(parentNode.value, start, endInclusive,
|
||||
TreeDataEvent.INTERVAL_REMOVED);
|
||||
fireEvent(parentNode.value, start, endInclusive,
|
||||
TreeDataEvent.INTERVAL_ADDED);
|
||||
private void fireRecreationOfInterval(Node<T> parentNode, int start, int endInclusive) {
|
||||
fireEvent(TreeDataEvent.INTERVAL_REMOVED,getPath(parentNode.value), start, endInclusive);
|
||||
fireEvent(TreeDataEvent.INTERVAL_ADDED, getPath(parentNode.value), start, endInclusive);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return getChildCount(getRoot()) == 0;
|
||||
}
|
||||
|
||||
public boolean hasChildren(T node) {
|
||||
return getChildCount(node) > 0;
|
||||
}
|
||||
|
||||
public boolean contains(T object) {
|
||||
return find(object) != null;
|
||||
}
|
||||
|
|
@ -435,21 +539,25 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
|||
Node<T> parentNode = find(parent);
|
||||
Node<T> childNode = find(child);
|
||||
|
||||
return parentNode != null && childNode != null
|
||||
&& childNode.getParent() != null
|
||||
&& childNode.getParent().equals(parentNode);
|
||||
return parentNode != null &&
|
||||
childNode != null &&
|
||||
childNode.getParent() != null &&
|
||||
childNode.getParent().equals(parentNode);
|
||||
}
|
||||
|
||||
public List<T> asList() {
|
||||
List<T> result = new ArrayList<T>();
|
||||
List<T> result = new ArrayList<>();
|
||||
asList(getRoot(), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void asList(T root, List<T> result) {
|
||||
List<T> list = new ArrayList<T>();
|
||||
List<T> list = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < getChildCount(root); i++) {
|
||||
final T child = getChild(root, i);
|
||||
|
||||
list.add(child);
|
||||
result.add(child);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,18 +37,19 @@ public class WeakReferencedListeners<T> {
|
|||
|
||||
}
|
||||
|
||||
private LinkedList<WeakReference<T>> listeners = new LinkedList<>();
|
||||
|
||||
private List<IListenerNotification<? super T>> pendingOfNotification = new ArrayList<>();
|
||||
|
||||
private WeakReferencedListeners() {}
|
||||
|
||||
public static <T> WeakReferencedListeners<T> create() {
|
||||
return new WeakReferencedListeners<>();
|
||||
}
|
||||
|
||||
private LinkedList<WeakReference<T>> listeners = new LinkedList<>();
|
||||
|
||||
private WeakReferencedListeners() {
|
||||
|
||||
}
|
||||
|
||||
public enum Mode {
|
||||
RECEIVE_PENDING, FROM_NOW_ON;
|
||||
RECEIVE_PENDING,
|
||||
FROM_NOW_ON
|
||||
}
|
||||
|
||||
public void addListener(T listener) {
|
||||
|
|
@ -61,11 +62,9 @@ public class WeakReferencedListeners<T> {
|
|||
if ( getActiveListeners().isEmpty() && mode == Mode.RECEIVE_PENDING ) {
|
||||
notifyPendingOfNotificationTo(listener);
|
||||
}
|
||||
listeners.add(new WeakReference<T>(listener));
|
||||
listeners.add(new WeakReference<>(listener));
|
||||
}
|
||||
|
||||
private List<IListenerNotification<? super T>> pendingOfNotification = new ArrayList<>();
|
||||
|
||||
private void notifyPendingOfNotificationTo(T listener) {
|
||||
for (IListenerNotification<? super T> each : pendingOfNotification) {
|
||||
each.doNotify(listener);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
<addon-name>ganttz</addon-name>
|
||||
<language-name>xul/html</language-name>
|
||||
|
||||
<!-- When the version is changed, the browser will reload the
|
||||
JavaScript modules. -->
|
||||
<!-- When the version is changed, the browser will reload the JavaScript modules -->
|
||||
<javascript-module name="ganttz" version="1.6.0" />
|
||||
<javascript-module name="ganttz.resourceload" version="1.6.0" />
|
||||
<javascript-module name="common" version="1.6.0" />
|
||||
|
|
@ -22,22 +21,18 @@
|
|||
<component-class>org.zkoss.ganttz.Planner</component-class>
|
||||
<widget-class>ganttz.Planner</widget-class>
|
||||
<macro-uri>~./ganttz/zul/plannerLayout.zul</macro-uri>
|
||||
<!-- mold>
|
||||
<mold-name>default</mold-name>
|
||||
<mold-uri>~./ganttz/planner.dsp</mold-uri>
|
||||
</mold -->
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<component-name>tabSwitcher</component-name>
|
||||
<component-class>org.zkoss.ganttz.TabSwitcher</component-class>
|
||||
<macro-uri>~./ganttz/zul/tabSwitcher.zul</macro-uri>
|
||||
<component-name>tabSwitcher</component-name>
|
||||
<component-class>org.zkoss.ganttz.TabSwitcher</component-class>
|
||||
<macro-uri>~./ganttz/zul/tabSwitcher.zul</macro-uri>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<component-name>resourcesLoadPanel</component-name>
|
||||
<component-class>org.zkoss.ganttz.resourceload.ResourcesLoadPanel</component-class>
|
||||
<macro-uri>~./ganttz/zul/resourcesLoadLayout.zul</macro-uri>
|
||||
<macro-uri>~./ganttz/zul/resourcesLoadLayout.zul</macro-uri>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
|
|
@ -47,7 +42,6 @@
|
|||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<mold-uri>mold/resource-load-list.js</mold-uri>
|
||||
<!-- <mold-uri>~./ganttz/resourceload/resourceloadlist.dsp</mold-uri> -->
|
||||
</mold>
|
||||
</component>
|
||||
|
||||
|
|
@ -76,20 +70,17 @@
|
|||
<widget-class>ganttz.GanttPanel</widget-class>
|
||||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<!-- <mold-uri>~./ganttz/ganttpanel.dsp</mold-uri> -->
|
||||
<mold-uri>mold/gantt-panel.js</mold-uri>
|
||||
</mold>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<component-name>resourceload</component-name>
|
||||
<component-class>org.zkoss.ganttz.resourceload.ResourceLoadComponent
|
||||
</component-class>
|
||||
<component-class>org.zkoss.ganttz.resourceload.ResourceLoadComponent</component-class>
|
||||
<widget-class>ganttz.resourceload.ResourceLoadComponent</widget-class>
|
||||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<mold-uri>mold/resource-load-component.js</mold-uri>
|
||||
<!-- <mold-uri>~./ganttz/resourceload/resourceload.dsp</mold-uri> -->
|
||||
</mold>
|
||||
</component>
|
||||
|
||||
|
|
@ -100,7 +91,6 @@
|
|||
<widget-class>ganttz.TaskRow</widget-class>
|
||||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<!-- <mold-uri>~./ganttz/row.dsp</mold-uri> -->
|
||||
<mold-uri>mold/task-row.js</mold-uri>
|
||||
</mold>
|
||||
</component>
|
||||
|
|
@ -111,7 +101,6 @@
|
|||
<widget-class>ganttz.TaskComponent</widget-class>
|
||||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<!-- <mold-uri>~./ganttz/task.dsp</mold-uri> -->
|
||||
<mold-uri>mold/task-component.js</mold-uri>
|
||||
</mold>
|
||||
</component>
|
||||
|
|
@ -122,21 +111,17 @@
|
|||
<widget-class>ganttz.Milestone</widget-class>
|
||||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<!-- <mold-uri>~./ganttz/milestone.dsp</mold-uri> -->
|
||||
<mold-uri>mold/milestone.js</mold-uri>
|
||||
</mold>
|
||||
</component>
|
||||
|
||||
|
||||
<component>
|
||||
<component-name>taskcontainer</component-name>
|
||||
<component-class>org.zkoss.ganttz.TaskContainerComponent
|
||||
</component-class>
|
||||
<component-class>org.zkoss.ganttz.TaskContainerComponent</component-class>
|
||||
<widget-class>ganttz.TaskContainerComponent</widget-class>
|
||||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<mold-uri>mold/task-container.js</mold-uri>
|
||||
<!-- <mold-uri>~./ganttz/taskcontainer.dsp</mold-uri> -->
|
||||
</mold>
|
||||
</component>
|
||||
|
||||
|
|
@ -146,7 +131,6 @@
|
|||
<widget-class>ganttz.TaskList</widget-class>
|
||||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<!-- <mold-uri>~./ganttz/tasklist.dsp</mold-uri> -->
|
||||
<mold-uri>mold/task-list.js</mold-uri>
|
||||
</mold>
|
||||
</component>
|
||||
|
|
@ -157,24 +141,20 @@
|
|||
<widget-class>ganttz.DependencyList</widget-class>
|
||||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<!-- <mold-uri>~./ganttz/dependencylist.dsp</mold-uri> -->
|
||||
<mold-uri>mold/dependency-list.js</mold-uri>
|
||||
</mold>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<component-name>dependency</component-name>
|
||||
<component-class>org.zkoss.ganttz.DependencyComponent
|
||||
</component-class>
|
||||
<component-class>org.zkoss.ganttz.DependencyComponent</component-class>
|
||||
<widget-class>ganttz.DependencyComponent</widget-class>
|
||||
<mold>
|
||||
<mold-name>default</mold-name>
|
||||
<mold-uri>mold/dependency-component.js</mold-uri>
|
||||
<!-- <mold-uri>~./ganttz/dependency.dsp</mold-uri> -->
|
||||
</mold>
|
||||
</component>
|
||||
|
||||
|
||||
<component>
|
||||
<component-name>timetracker</component-name>
|
||||
<component-class>org.zkoss.ganttz.timetracker.TimeTrackerComponent</component-class>
|
||||
|
|
@ -183,9 +163,9 @@
|
|||
</component>
|
||||
|
||||
<component>
|
||||
<component-name>timeTrackedTable</component-name>
|
||||
<component-class>org.zkoss.ganttz.timetracker.TimeTrackedTable</component-class>
|
||||
<macro-uri>~./ganttz/zul/timetracker/timetrackedtable.zul</macro-uri>
|
||||
<component-name>timeTrackedTable</component-name>
|
||||
<component-class>org.zkoss.ganttz.timetracker.TimeTrackedTable</component-class>
|
||||
<macro-uri>~./ganttz/zul/timetracker/timetrackedtable.zul</macro-uri>
|
||||
</component>
|
||||
|
||||
</language-addon>
|
||||
|
|
|
|||
1
ganttzk/src/main/resources/web/css/jqplot/jquery.jqplot.min.css
vendored
Normal file
1
ganttzk/src/main/resources/web/css/jqplot/jquery.jqplot.min.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.jqplot-target{position:relative;color:#666;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:1em;}.jqplot-axis{font-size:.75em;}.jqplot-xaxis{margin-top:10px;}.jqplot-x2axis{margin-bottom:10px;}.jqplot-yaxis{margin-right:10px;}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px;}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre;}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top;}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom;}.jqplot-yaxis-tick{right:0;top:15px;text-align:right;}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em;}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left;}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap;}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute;}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute;}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute;}.jqplot-yMidAxis-label{font-size:11pt;position:absolute;}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute;}.jqplot-meterGauge-tick{font-size:.75em;color:#999;}.jqplot-meterGauge-label{font-size:1em;color:#999;}table.jqplot-table-legend{margin-top:12px;margin-bottom:12px;margin-left:12px;margin-right:12px;}table.jqplot-table-legend,table.jqplot-cursor-legend{background-color:rgba(255,255,255,0.6);border:1px solid #ccc;position:absolute;font-size:.75em;}td.jqplot-table-legend{vertical-align:middle;}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer;}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through;}div.jqplot-table-legend-swatch-outline{border:1px solid #ccc;padding:1px;}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid;}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em;}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-point-label{font-size:.75em;z-index:2;}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center;}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em;}.jqplot-error{text-align:center;}.jqplot-error-message{position:relative;top:46%;display:inline-block;}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%);}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7);}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3);}
|
||||
|
|
@ -20,10 +20,10 @@
|
|||
-->
|
||||
|
||||
<zk>
|
||||
<zscript><![CDATA[
|
||||
top = self;
|
||||
]]>
|
||||
</zscript>
|
||||
<tree id="loadsTree" sclass="resourceloadleftpane" fixedLayout="true">
|
||||
</tree>
|
||||
<zscript>
|
||||
<![CDATA[
|
||||
top = self;
|
||||
]]>
|
||||
</zscript>
|
||||
<tree id="loadsTree" sclass="resourceloadleftpane" fixedLayout="true"/>
|
||||
</zk>
|
||||
|
|
@ -20,6 +20,5 @@
|
|||
-->
|
||||
|
||||
<zk>
|
||||
<div id="listdetails_container">
|
||||
</div>
|
||||
<div id="listdetails_container"/>
|
||||
</zk>
|
||||
|
|
@ -20,15 +20,15 @@
|
|||
-->
|
||||
|
||||
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
||||
signature="java.lang.String _(java.lang.String name)" ?>
|
||||
signature="java.lang.String _(java.lang.String name)" ?>
|
||||
|
||||
<div>
|
||||
<tree id="tasksTree" fixedLayout="true" sclass="taskTreeCols">
|
||||
<treecols sizable="false" height="33px">
|
||||
<treecol label="${ganttzk_i18n:_('Name')}" sclass="tree-text" />
|
||||
<treecol label="${ganttzk_i18n:_('Start')}" width="60px" />
|
||||
<treecol label="${ganttzk_i18n:_('End')}" width="60px" />
|
||||
<treecol label="${ganttzk_i18n:_('T / M')}" width="55px" />
|
||||
</treecols>
|
||||
</tree>
|
||||
<tree id="tasksTree" fixedLayout="true" sclass="taskTreeCols" hflex="1" >
|
||||
<treecols sizable="false" height="33px">
|
||||
<treecol label="${ganttzk_i18n:_('Name')}" sclass="tree-text" />
|
||||
<treecol label="${ganttzk_i18n:_('Start')}" width="60px" />
|
||||
<treecol label="${ganttzk_i18n:_('End')}" width="60px" />
|
||||
<treecol label="${ganttzk_i18n:_('T / M')}" width="55px" />
|
||||
</treecols>
|
||||
</tree>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -20,20 +20,20 @@
|
|||
-->
|
||||
|
||||
<treerow sclass="taskdetail_grid">
|
||||
<zscript><![CDATA[
|
||||
]]>
|
||||
</zscript>
|
||||
<treecell>
|
||||
<treecell hflex="min">
|
||||
<textbox ctrlKeys="#down#up" hflex="1" sclass="task-name" />
|
||||
</treecell>
|
||||
|
||||
<treecell>
|
||||
<textbox value="" ctrlKeys="#down#up" />
|
||||
</treecell>
|
||||
|
||||
<treecell>
|
||||
<textbox value="" ctrlKeys="#down#up" />
|
||||
</treecell>
|
||||
|
||||
<treecell>
|
||||
<hlayout class="projectstatus-layout">
|
||||
<hlayout sclass="projectstatus-layout">
|
||||
<div />
|
||||
<label>/</label>
|
||||
<div />
|
||||
|
|
|
|||
|
|
@ -20,20 +20,21 @@
|
|||
-->
|
||||
|
||||
<treerow sclass="taskdetail_grid taskdetail-company-view">
|
||||
<zscript><![CDATA[
|
||||
]]>
|
||||
</zscript>
|
||||
|
||||
<treecell>
|
||||
<label class="task_title"/>
|
||||
<label sclass="task_title"/>
|
||||
</treecell>
|
||||
|
||||
<treecell>
|
||||
<label class="order-startdate" />
|
||||
<label sclass="order-startdate" />
|
||||
</treecell>
|
||||
|
||||
<treecell>
|
||||
<label class="order-enddate" />
|
||||
<label sclass="order-enddate" />
|
||||
</treecell>
|
||||
|
||||
<treecell>
|
||||
<hlayout class="projectstatus-layout">
|
||||
<hlayout sclass="projectstatus-layout">
|
||||
<div />
|
||||
<label>/</label>
|
||||
<div />
|
||||
|
|
|
|||
|
|
@ -18,108 +18,127 @@
|
|||
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/>.
|
||||
-->
|
||||
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
|
||||
<?component name="button" extends="button" mold="trendy"?>
|
||||
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
||||
signature="java.lang.String _(java.lang.String name)" ?>
|
||||
<zscript><![CDATA[
|
||||
planner = self;
|
||||
]]>
|
||||
</zscript>
|
||||
<zk>
|
||||
<?component name="button" extends="button" mold="trendy"?>
|
||||
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
||||
signature="java.lang.String _(java.lang.String name)" ?>
|
||||
|
||||
<zscript>
|
||||
<![CDATA[
|
||||
planner = self;
|
||||
]]>
|
||||
</zscript>
|
||||
|
||||
<borderlayout sclass="plannerlayout" width="auto">
|
||||
<north height="30px" border="0" sclass="toolbar-box">
|
||||
<hbox align="center" id="toolbar">
|
||||
<north height="30px" border="0" sclass="toolbar-box">
|
||||
<hbox align="center" id="toolbar" sclass="filtering-area">
|
||||
|
||||
<separator/>
|
||||
<!-- Commands -->
|
||||
<separator/>
|
||||
|
||||
<button onClick="planner.invalidate()"
|
||||
image="/common/img/ico_refresh.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Refresh')}" visible="false" />
|
||||
<!-- Commands -->
|
||||
|
||||
<hbox id="plannerButtonsInsertionPoint" />
|
||||
<button onClick="planner.invalidate()"
|
||||
image="/common/img/ico_refresh.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Refresh')}" visible="false" />
|
||||
|
||||
<button id="btnPrint" onClick="planner.print()"
|
||||
image="/common/img/ico_print.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Print')}" />
|
||||
<separator/>
|
||||
<hbox id="plannerButtonsInsertionPoint" />
|
||||
|
||||
<!-- Visualization modes -->
|
||||
<space bar="true" />
|
||||
<label>${ganttzk_i18n:_('Zoom')}:</label>
|
||||
<listbox id="listZoomLevels" mold="select" rows="1"
|
||||
model="${planner.zoomLevels}">
|
||||
</listbox>
|
||||
<button id="btnPrint" onClick="planner.print()"
|
||||
image="/common/img/ico_print.png"
|
||||
style="background: none; box-shadow: none;"
|
||||
tooltiptext="${ganttzk_i18n:_('Print')}" />
|
||||
<separator/>
|
||||
|
||||
<!-- Progress type -->
|
||||
<!-- Visualization modes -->
|
||||
<space bar="true" />
|
||||
<label>${ganttzk_i18n:_('Zoom')}:</label>
|
||||
<listbox id="listZoomLevels" mold="select" rows="1" model="${planner.zoomLevels}">
|
||||
</listbox>
|
||||
|
||||
<button id="showCriticalPath" onClick="planner.showCriticalPath();"
|
||||
image="/common/img/ico_criticalpath.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide critical path')}" />
|
||||
<button id="showAllLabels" onClick="planner.showAllLabels();"
|
||||
image="/common/img/ico_labels.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide labels')}" sclass="planner-command show-labels" />
|
||||
<button id="showAllResources" onClick="planner.showAllResources();"
|
||||
image="/common/img/ico_resources.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide resources')}" sclass="planner-command show-resources" />
|
||||
<button id="expandAll" onClick="planner.expandAll();"
|
||||
image="/common/img/ico_expand.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Expand/Collapse all')}"
|
||||
sclass="planner-command" />
|
||||
<button id="flattenTree" onClick="planner.flattenTree();"
|
||||
image="/common/img/ico_flatten.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Flatten/Unflatten tree')}"
|
||||
sclass="planner-command" />
|
||||
<!-- Progress type -->
|
||||
|
||||
<hbox class="show-advances" align="center">
|
||||
<button id="showAdvances" onClick="planner.showAdvances();"
|
||||
image="/common/img/ico_progress.png"
|
||||
style="width:46px"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide progress')}"
|
||||
sclass="planner-command" />
|
||||
<combobox id="cbProgressTypes" width="1px" visible="false" sclass="progress-types"/>
|
||||
</hbox>
|
||||
<button id="showCriticalPath" onClick="planner.showCriticalPath();"
|
||||
image="/common/img/ico_criticalpath.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide critical path')}" />
|
||||
|
||||
<button id="showReportedHours" onClick="planner.showReportedHours();"
|
||||
image="/common/img/ico_costs.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide reported hours')}"
|
||||
sclass="planner-command"/>
|
||||
<separator />
|
||||
<button id="showAllLabels" onClick="planner.showAllLabels();"
|
||||
image="/common/img/ico_labels.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide labels')}" sclass="planner-command show-labels" />
|
||||
|
||||
<button id="showMoneyCostBar" onClick="planner.showMoneyCostBar();"
|
||||
image="/common/img/ico_money_cost_bar.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide money cost bar')}"
|
||||
sclass="planner-command"/>
|
||||
<separator />
|
||||
<button id="showAllResources" onClick="planner.showAllResources();"
|
||||
image="/common/img/ico_resources.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide resources')}"
|
||||
sclass="planner-command show-resources" />
|
||||
|
||||
<!-- Filtering -->
|
||||
<vbox id="orderFilter"/>
|
||||
<vbox id="orderElementFilter"/>
|
||||
<separator />
|
||||
<button id="expandAll" onClick="planner.expandAll();"
|
||||
image="/common/img/ico_expand.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Expand/Collapse all')}"
|
||||
sclass="planner-command" />
|
||||
|
||||
</hbox>
|
||||
</north>
|
||||
<button id="flattenTree" onClick="planner.flattenTree();"
|
||||
image="/common/img/ico_flatten.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Flatten/Unflatten tree')}"
|
||||
sclass="planner-command" />
|
||||
|
||||
<hbox class="show-advances" align="center">
|
||||
<button id="showAdvances" onClick="planner.showAdvances();"
|
||||
image="/common/img/ico_progress.png"
|
||||
style="width:46px; margin-right: -5px;"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide progress')}"
|
||||
sclass="planner-command" />
|
||||
|
||||
<combobox id="cbProgressTypes" width="1px" visible="false" sclass="progress-types"/>
|
||||
</hbox>
|
||||
|
||||
<button id="showReportedHours" onClick="planner.showReportedHours();"
|
||||
image="/common/img/ico_costs.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide reported hours')}"
|
||||
sclass="planner-command"/>
|
||||
<separator />
|
||||
|
||||
<button id="showMoneyCostBar" onClick="planner.showMoneyCostBar();"
|
||||
image="/common/img/ico_money_cost_bar.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide money cost bar')}"
|
||||
sclass="planner-command"/>
|
||||
<separator />
|
||||
|
||||
<!-- Filtering -->
|
||||
<vbox id="orderFilter"/>
|
||||
<vbox id="orderElementFilter"/>
|
||||
<separator />
|
||||
|
||||
</hbox>
|
||||
</north>
|
||||
|
||||
<center border="0">
|
||||
<borderlayout sclass="plannerlayout_center" height="100%">
|
||||
<west flex="false" collapsible="true" splittable="true" width="375px"
|
||||
id="taskdetailsContainer" sclass="taskdetailsContainer">
|
||||
<div sclass="leftpanelgap" id="insertionPointLeftPanel"></div>
|
||||
<west id="taskdetailsContainer"
|
||||
vflex="0" collapsible="true" splittable="true" width="375px"
|
||||
sclass="taskdetailsContainer">
|
||||
|
||||
<div sclass="leftpanelgap" id="insertionPointLeftPanel"/>
|
||||
</west>
|
||||
<center sclass="taskspanel">
|
||||
|
||||
<center sclass="taskspanel" >
|
||||
<borderlayout>
|
||||
<north border="0"><div sclass="timetrackergap" id="insertionPointTimetracker"></div></north>
|
||||
<center autoscroll="true" border="0" sclass="rightpanellayout">
|
||||
<div id="insertionPointRightPanel" sclass="taskspanelgap"></div>
|
||||
<north border="0" height="32px" vflex="min" >
|
||||
<div sclass="timetrackergap" id="insertionPointTimetracker"/>
|
||||
</north>
|
||||
|
||||
<center autoscroll="true" border="0" sclass="rightpanel-layout">
|
||||
<div id="insertionPointRightPanel" sclass="taskspanel-gap"/>
|
||||
</center>
|
||||
</borderlayout>
|
||||
|
||||
</center>
|
||||
</borderlayout>
|
||||
</center>
|
||||
<south collapsible="true" title="${ganttzk_i18n:_('Graphics')}" sclass="scheduling-graphics"
|
||||
id="graphics" onOpen="planner.changeChartVisibility(event.open);" height="200px">
|
||||
<div id="insertionPointChart" />
|
||||
|
||||
<south height="200px" collapsible="true" title="${ganttzk_i18n:_('Graphics')}"
|
||||
sclass="scheduling-graphics" id="graphics"
|
||||
onOpen="planner.changeChartVisibility(event.open);" >
|
||||
|
||||
<div id="insertionPointChart"/>
|
||||
</south>
|
||||
</borderlayout>
|
||||
</zk>
|
||||
|
|
|
|||
|
|
@ -20,76 +20,90 @@
|
|||
-->
|
||||
|
||||
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
||||
signature="java.lang.String _(java.lang.String name)" ?>
|
||||
signature="java.lang.String _(java.lang.String name)" ?>
|
||||
|
||||
<zk xmlns:n="http://www.zkoss.org/2005/zk/native" height="100%">
|
||||
<zscript><![CDATA[
|
||||
resourcesLoadPanel = self;
|
||||
]]>
|
||||
</zscript>
|
||||
<zk>
|
||||
<zscript>
|
||||
<![CDATA[
|
||||
resourcesLoadPanel = self;
|
||||
]]>
|
||||
</zscript>
|
||||
|
||||
<borderlayout sclass="resourcesloadlayout" width="auto" height="100%">
|
||||
<north height="30px" border="0" sclass="toolbar-box">
|
||||
<hbox align="center" id="toolbar" >
|
||||
<separator height="30px"/>
|
||||
<label>${ganttzk_i18n:_('Zoom')}:</label>
|
||||
<listbox id="listZoomLevels" mold="select" rows="1"
|
||||
model="${resourcesLoadPanel.zoomLevels}"
|
||||
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" >
|
||||
</listbox>
|
||||
<separator/>
|
||||
<hbox id="additionalFilterInsertionPoint1" />
|
||||
<separator/>
|
||||
<label id="filterByNameLabel">${ganttzk_i18n:_('Page')}:</label>
|
||||
<combobox id="filterByNameCombo" width="50px"
|
||||
onChange="resourcesLoadPanel.onSelectFilterByName(self)" />
|
||||
<separator/>
|
||||
${ganttzk_i18n:_('Group by')}:
|
||||
<listbox id="listFilters" mold="select" rows="1" width="150px"
|
||||
model="${resourcesLoadPanel.filters}"
|
||||
selectedIndex="0"
|
||||
onSelect="resourcesLoadPanel.setFilter(self.selectedItem.value);">
|
||||
</listbox>
|
||||
<separator/>
|
||||
<hbox id="additionalFilterInsertionPoint2" />
|
||||
</hbox>
|
||||
</north>
|
||||
<borderlayout id="resourcesloadlayout" sclass="resourcesloadlayout" width="auto" height="100%">
|
||||
<north height="30px" border="0" sclass="toolbar-box">
|
||||
<hbox align="center" id="toolbar" >
|
||||
|
||||
<separator height="30px"/>
|
||||
|
||||
<label>${ganttzk_i18n:_('Zoom')}:</label>
|
||||
|
||||
<listbox id="listZoomLevels" mold="select" rows="1"
|
||||
model="${resourcesLoadPanel.zoomLevels}"
|
||||
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" />
|
||||
|
||||
<separator/>
|
||||
|
||||
<hbox id="additionalFilterInsertionPoint1" />
|
||||
|
||||
<separator/>
|
||||
|
||||
<label id="filterByNameLabel">${ganttzk_i18n:_('Page')}:</label>
|
||||
|
||||
<combobox id="filterByNameCombo" width="62px" onChange="resourcesLoadPanel.onSelectFilterByName(self)" />
|
||||
|
||||
<separator/>
|
||||
|
||||
${ganttzk_i18n:_('Group by')}:
|
||||
|
||||
<listbox id="listFilters" mold="select" rows="1" width="150px"
|
||||
model="${resourcesLoadPanel.filters}"
|
||||
selectedIndex="0"
|
||||
onSelect="resourcesLoadPanel.setFilter(self.selectedItem.value);">
|
||||
</listbox>
|
||||
<separator/>
|
||||
<hbox id="additionalFilterInsertionPoint2" />
|
||||
</hbox>
|
||||
</north>
|
||||
|
||||
<center border="0">
|
||||
<borderlayout sclass="resourcesload">
|
||||
<west size="250px" flex="true" collapsible="true"
|
||||
splittable="true" autoscroll="false" border="0">
|
||||
<borderlayout sclass="resources-load">
|
||||
<west size="250px" vflex="1" hflex="min" collapsible="true"
|
||||
splittable="true" autoscroll="false" border="0">
|
||||
<borderlayout>
|
||||
<north border="0" height="35px" flex="true" collapsible="true">
|
||||
<north border="0" height="35px" hflex="true" collapsible="true">
|
||||
<vbox pack="top" align="center">
|
||||
<tree fixedLayout="true" hflex="true" sclass="resourceloaddetailsContainer">
|
||||
<treecols>
|
||||
<treecol label="${ganttzk_i18n:_('Name')}" height="29px"/>
|
||||
</treecols>
|
||||
</tree>
|
||||
|
||||
<tree fixedLayout="true" hflex="true" sclass="resourceload-details-container">
|
||||
<treecols>
|
||||
<treecol label="${ganttzk_i18n:_('Name')}" height="29px"/>
|
||||
</treecols>
|
||||
</tree>
|
||||
</vbox>
|
||||
</north>
|
||||
<center border="0" style="overflow-x:scroll">
|
||||
<div sclass="leftpanelgap" id="insertionPointLeftPanel"></div>
|
||||
<div sclass="leftpanelgap" id="insertionPointLeftPanel"/>
|
||||
</center>
|
||||
</borderlayout>
|
||||
</west>
|
||||
|
||||
<center sclass="taskspanel">
|
||||
<borderlayout>
|
||||
<north border="0"><div sclass="timetrackergap" height="30px" id="insertionPointTimetracker"></div></north>
|
||||
<center autoscroll="true" border="0" sclass="rightpanellayout">
|
||||
<div id="insertionPointRightPanel" sclass="taskspanelgap"></div>
|
||||
<north border="0">
|
||||
<div sclass="timetrackergap" height="30px" id="insertionPointTimetracker"/>
|
||||
</north>
|
||||
|
||||
<center autoscroll="true" border="0" sclass="rightpanel-layout">
|
||||
<div id="insertionPointRightPanel" sclass="taskspanel-gap"/>
|
||||
</center>
|
||||
</borderlayout>
|
||||
|
||||
</center>
|
||||
</borderlayout>
|
||||
</center>
|
||||
|
||||
<south height="200px" collapsible="true" title="${ganttzk_i18n:_('Graphics')}"
|
||||
sclass="scheduling-graphics" id="graphics"
|
||||
onOpen="resourcesLoadPanel.changeChartVisibility(event.open);">
|
||||
sclass="scheduling-graphics" id="graphics"
|
||||
onOpen="resourcesLoadPanel.changeChartVisibility(event.open);">
|
||||
|
||||
<div id="insertionPointChart" />
|
||||
</south>
|
||||
</borderlayout>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,5 @@
|
|||
-->
|
||||
|
||||
<zk>
|
||||
<div id="container">
|
||||
</div>
|
||||
<div id="container" sclass="tabSwitcher" self="@{insert(content_tabSwitcher)}" height="100%"/>
|
||||
</zk>
|
||||
|
|
@ -20,13 +20,11 @@
|
|||
-->
|
||||
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
|
||||
|
||||
<n:div class="z-grid-header">
|
||||
<n:div class="z-grid-header">
|
||||
<n:table style="width: ${top.horizontalSize+2}px;" class="second_level_">
|
||||
|
||||
<n:tr class="z-columns">
|
||||
<n:td class="z-column" forEach="${top.detailsSecondLevel}"
|
||||
style="width: ${each.size}px">
|
||||
${each.name}
|
||||
<n:td class="z-column" forEach="${top.detailsSecondLevel}" style="width: ${each.size}px">
|
||||
${each.name}
|
||||
</n:td>
|
||||
</n:tr>
|
||||
</n:table>
|
||||
|
|
|
|||
|
|
@ -20,15 +20,16 @@
|
|||
-->
|
||||
|
||||
<zk>
|
||||
<zscript><![CDATA[
|
||||
top = self;
|
||||
]]>
|
||||
</zscript>
|
||||
<grid width="${top.horizontalSize+2}" model="${top.tableModel}"
|
||||
rowRenderer="${top.rowRenderer}" fixedLayout="${true}">
|
||||
<columns visible="${false}">
|
||||
<column label="${each.name}" width="${each.size}px"
|
||||
forEach="${top.detailsSecondLevel}"></column>
|
||||
</columns>
|
||||
</grid>
|
||||
<zscript>
|
||||
<![CDATA[
|
||||
top = self;
|
||||
]]>
|
||||
</zscript>
|
||||
<grid width="${top.horizontalSize+2}" model="${top.tableModel}"
|
||||
rowRenderer="${top.rowRenderer}" fixedLayout="${true}">
|
||||
|
||||
<columns visible="${false}">
|
||||
<column label="${each.name}" width="${each.size}px" forEach="${top.detailsSecondLevel}"/>
|
||||
</columns>
|
||||
</grid>
|
||||
</zk>
|
||||
|
|
@ -21,21 +21,21 @@
|
|||
|
||||
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>
|
||||
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
|
||||
<zscript><![CDATA[
|
||||
top = self;
|
||||
]]>
|
||||
</zscript>
|
||||
<zscript>
|
||||
<![CDATA[
|
||||
top = self;
|
||||
]]>
|
||||
</zscript>
|
||||
|
||||
<div>
|
||||
<n:div id="${top.timeTrackerId}">
|
||||
<vbox>
|
||||
<grid id="firstleveldetails" width="${top.horizontalSizePixels}px;">
|
||||
<columns>
|
||||
<column label="${each.name}" width="${each.size}px"
|
||||
forEach="${top.detailsFirstLevel}"></column>
|
||||
</columns>
|
||||
</grid>
|
||||
</vbox>
|
||||
</n:div>
|
||||
</div>
|
||||
<div>
|
||||
<n:div id="${top.timeTrackerId}">
|
||||
<vbox>
|
||||
<grid id="firstleveldetails" width="${top.horizontalSizePixels}px;">
|
||||
<columns>
|
||||
<column label="${each.name}" width="${each.size}px" forEach="${top.detailsFirstLevel}"/>
|
||||
</columns>
|
||||
</grid>
|
||||
</vbox>
|
||||
</n:div>
|
||||
</div>
|
||||
</zk>
|
||||
|
|
|
|||
|
|
@ -25,17 +25,26 @@
|
|||
|
||||
<n:tr class="z-columns">
|
||||
<n:th class="z-column" forEach="${top.detailsSecondLevel}" style="width: ${each.size}px">
|
||||
${each.name}
|
||||
${each.name}
|
||||
</n:th>
|
||||
</n:tr>
|
||||
|
||||
<n:tr id="watermark">
|
||||
<n:td class="${(top.weekLevel)?'week-level':''} timetracker_column${(each.even)?'_even':''}${(each.bankHoliday?' bankHoliday':'')}"
|
||||
forEach="${top.detailsSecondLevel}"
|
||||
style="width: ${each.size}px;background-position: ${each.bankHolidayWeek}; ">
|
||||
<n:div if="${each.projectStart}" class="timetracker_column_start" style="background-position: ${each.projectStartOffset}px;" />
|
||||
<n:div if="${each.currentPeriod and !(each.deadlinePeriod)}" class="timetracker_column_today" style="background-position: ${each.currentDayOffset}px; width:auto;height:100%" />
|
||||
<n:div if="${each.deadlinePeriod and !(each.currentPeriod)}" class="timetracker_column_deadline" style="background-position: ${each.deadlineOffset}px; width:auto;height:100%" />
|
||||
<n:div if="${each.currentPeriod and each.deadlinePeriod}" class="timetracker_column_today_deadline" style="background-position: ${each.currentDayOffset}px 0, ${each.deadlineOffset}px 0; width:auto;height:100%" />
|
||||
forEach="${top.detailsSecondLevel}"
|
||||
style="width: ${each.size}px;background-position: ${each.bankHolidayWeek}; ">
|
||||
|
||||
<n:div if="${each.projectStart}" class="timetracker_column_start"
|
||||
style="background-position: ${each.projectStartOffset}px;" />
|
||||
|
||||
<n:div if="${each.currentPeriod and !(each.deadlinePeriod)}" class="timetracker_column_today"
|
||||
style="background-position: ${each.currentDayOffset}px; width:auto;height:100%" />
|
||||
|
||||
<n:div if="${each.deadlinePeriod and !(each.currentPeriod)}" class="timetracker_column_deadline"
|
||||
style="background-position: ${each.deadlineOffset}px; width:auto;height:100%" />
|
||||
|
||||
<n:div if="${each.currentPeriod and each.deadlinePeriod}" class="timetracker_column_today_deadline"
|
||||
style="background-position: ${each.currentDayOffset}px 0, ${each.deadlineOffset}px 0; width:auto;height:100%" />
|
||||
</n:td>
|
||||
</n:tr>
|
||||
</n:table>
|
||||
|
|
|
|||
|
|
@ -1,72 +1,89 @@
|
|||
zk.$package("common");
|
||||
|
||||
common.Common = zk.$extends(zk.Widget,{},{
|
||||
common.Common = zk.$extends(
|
||||
zk.Widget,
|
||||
{},
|
||||
{
|
||||
webAppContextPath : function() {
|
||||
return window.location.pathname.split( '/' )[1];
|
||||
},
|
||||
|
||||
webAppContextPath : function(){ return window.location.pathname.split( '/' )[1];},
|
||||
throttle : function(timeoutTimeMillis, functionToExecute) {
|
||||
var lastTimeCalled = null;
|
||||
var cachedResult = null;
|
||||
|
||||
return function() {
|
||||
var now = Date.now();
|
||||
|
||||
if (lastTimeCalled !== null && ((now - lastTimeCalled) < timeoutTimeMillis)) {
|
||||
return cachedResult;
|
||||
}
|
||||
|
||||
lastTimeCalled = now;
|
||||
cachedResult = functionToExecute.apply(null, arguments);
|
||||
|
||||
throttle: function(timeoutTimeMillis, functionToExecute) {
|
||||
var lastTimeCalled = null;
|
||||
var cachedResult = null;
|
||||
return function() {
|
||||
var now = Date.now();
|
||||
if (lastTimeCalled !== null && ((now - lastTimeCalled) < timeoutTimeMillis)) {
|
||||
return cachedResult;
|
||||
}
|
||||
lastTimeCalled = now;
|
||||
cachedResult = functionToExecute.apply(null, arguments);
|
||||
return cachedResult;
|
||||
};
|
||||
},
|
||||
/**
|
||||
* It can be called in the constructor of a widget.
|
||||
* It is required that the widget has the method _divsToRestoreDayInto that returns
|
||||
* the divs which their scroll must be changed back to the previous day.
|
||||
*/
|
||||
};
|
||||
},
|
||||
|
||||
// TODO: Refactoring should be done, not so many methods should be needed to synchronize the day.
|
||||
mixInDayPositionRestorer: function(widget) {
|
||||
if (! ('_divsToRestoreDayInto' in widget)) {
|
||||
throw '_divsToRestoreDayInto function must be present in widget';
|
||||
}
|
||||
var scrollDay = 0;
|
||||
/**
|
||||
* Scrolls horizontally the ganttpanel when the zoom has resized the component
|
||||
* width.
|
||||
* It can be called in the constructor of a widget.
|
||||
* It is required that the widget has the method _divsToRestoreDayInto that returns
|
||||
* the divs which their scroll must be changed back to the previous day.
|
||||
*/
|
||||
widget.scroll_horizontal = function(daysDisplacement) {
|
||||
scrollDay = daysDisplacement;
|
||||
};
|
||||
widget.update_day_scroll = function(previousPixelPerDay) {
|
||||
var divs = this._divsToRestoreDayInto();
|
||||
var topScrollDiv = divs[divs.length - 1];
|
||||
|
||||
var maxHPosition = topScrollDiv.scrollWidth - topScrollDiv.clientWidth;
|
||||
if (maxHPosition > 0) {
|
||||
var proportion = topScrollDiv.scrollWidth / maxHPosition;
|
||||
var positionInScroll = topScrollDiv.scrollLeft;
|
||||
var positionInPx = positionInScroll * proportion;
|
||||
if (positionInPx > 0) {
|
||||
scrollDay = positionInPx / previousPixelPerDay;
|
||||
}
|
||||
// TODO: Refactoring should be done, not so many methods should be needed to synchronize the day.
|
||||
mixInDayPositionRestorer : function(widget) {
|
||||
if (! ('_divsToRestoreDayInto' in widget)) {
|
||||
throw '_divsToRestoreDayInto function must be present in widget';
|
||||
}
|
||||
};
|
||||
widget.move_scroll = function(diffDays, pixelPerDay) {
|
||||
var divs = this._divsToRestoreDayInto();
|
||||
var topScrollDiv = divs[divs.length - 1];
|
||||
|
||||
var day = this.scrollDay + parseInt(diffDays);
|
||||
var newPosInPx = parseInt(day * pixelPerDay);
|
||||
var maxHPosition = topScrollDiv.scrollWidth - topScrollDiv.clientWidth;
|
||||
var newProportion = topScrollDiv.scrollWidth / maxHPosition;
|
||||
if (newProportion > 0) {
|
||||
var newPosInScroll = newPosInPx / newProportion;
|
||||
if (newPosInScroll < 0) {
|
||||
newPosInScroll = 0;
|
||||
var scrollDay = 0;
|
||||
|
||||
/**
|
||||
* Scrolls horizontally the ganttPanel when the zoom has resized the component width.
|
||||
*/
|
||||
widget.scroll_horizontal = function(daysDisplacement) {
|
||||
scrollDay = daysDisplacement;
|
||||
};
|
||||
|
||||
widget.update_day_scroll = function(previousPixelPerDay) {
|
||||
var divs = this._divsToRestoreDayInto();
|
||||
var topScrollDiv = divs[divs.length - 1];
|
||||
|
||||
var maxHPosition = topScrollDiv.scrollWidth - topScrollDiv.clientWidth;
|
||||
|
||||
if (maxHPosition > 0) {
|
||||
var proportion = topScrollDiv.scrollWidth / maxHPosition;
|
||||
var positionInScroll = topScrollDiv.scrollLeft;
|
||||
var positionInPx = positionInScroll * proportion;
|
||||
|
||||
if (positionInPx > 0) {
|
||||
scrollDay = positionInPx / previousPixelPerDay;
|
||||
}
|
||||
}
|
||||
for ( var i = 0; i < divs.length; i++) {
|
||||
divs[i].scrollLeft = newPosInScroll;
|
||||
};
|
||||
|
||||
widget.move_scroll = function(diffDays, pixelPerDay) {
|
||||
var divs = this._divsToRestoreDayInto();
|
||||
var topScrollDiv = divs[divs.length - 1];
|
||||
|
||||
var day = this.scrollDay + parseInt(diffDays);
|
||||
var newPosInPx = parseInt(day * pixelPerDay);
|
||||
var maxHPosition = topScrollDiv.scrollWidth - topScrollDiv.clientWidth;
|
||||
var newProportion = topScrollDiv.scrollWidth / maxHPosition;
|
||||
|
||||
if (newProportion > 0) {
|
||||
var newPosInScroll = newPosInPx / newProportion;
|
||||
|
||||
if (newPosInScroll < 0) {
|
||||
newPosInScroll = 0;
|
||||
}
|
||||
|
||||
for ( var i = 0; i < divs.length; i++) {
|
||||
divs[i].scrollLeft = newPosInScroll;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
@ -1,75 +1,96 @@
|
|||
zk.$package("ganttz");
|
||||
|
||||
ganttz.GanttPanel = zk.$extends(zk.Widget,{
|
||||
$define: {
|
||||
xMouse : null,
|
||||
yMouse : null
|
||||
},
|
||||
scrollDay: 0,
|
||||
$init : function(){
|
||||
this.$supers('$init', arguments);
|
||||
this.$class.setInstance(this);
|
||||
common.Common.mixInDayPositionRestorer(this);
|
||||
},
|
||||
bind_ : function(evt){
|
||||
this.$supers('bind_', arguments);
|
||||
ganttz.GanttPanel = zk.$extends(
|
||||
|
||||
this._initializeProperties();
|
||||
zk.Widget,
|
||||
|
||||
this.domListen_(this.$n(), 'onMousemove', '_calcXY');
|
||||
this.domListen_(this._rightpannellayout, 'onScroll', '_listenToScroll');
|
||||
},
|
||||
unbind_ : function(evt){
|
||||
this.domUnlisten_(this._rightpannellayout, 'onScroll', '_listenToScroll');
|
||||
this.domUnlisten_(this.$n(), 'onMousemove', '_calcXY');
|
||||
this.$supers('unbind_', arguments);
|
||||
},
|
||||
_divsToRestoreDayInto: function() {
|
||||
var first = jq("#ganttpanel").get(0);
|
||||
return [first, first.parentNode, first.parentNode.parentNode];
|
||||
},
|
||||
timeplotContainerRescroll : function(){
|
||||
this._getTimeplotContainer().each(jq.proxy(function(index, element){
|
||||
jq(element).css("left", "-" + this._rightpannellayout.scrollLeft() + "px")
|
||||
{
|
||||
$define: {
|
||||
xMouse : null,
|
||||
yMouse : null
|
||||
},
|
||||
|
||||
scrollDay: 0,
|
||||
|
||||
$init : function() {
|
||||
this.$supers('$init', arguments);
|
||||
this.$class.setInstance(this);
|
||||
common.Common.mixInDayPositionRestorer(this);
|
||||
},
|
||||
|
||||
bind_ : function(evt) {
|
||||
this.$supers('bind_', arguments);
|
||||
|
||||
this._initializeProperties();
|
||||
|
||||
this.domListen_(this.$n(), 'onMousemove', '_calcXY');
|
||||
this.domListen_(this._rightPanelLayout, 'onScroll', '_listenToScroll');
|
||||
},
|
||||
|
||||
unbind_ : function(evt){
|
||||
this.domUnlisten_(this._rightPanelLayout, 'onScroll', '_listenToScroll');
|
||||
this.domUnlisten_(this.$n(), 'onMousemove', '_calcXY');
|
||||
this.$supers('unbind_', arguments);
|
||||
},
|
||||
|
||||
_divsToRestoreDayInto: function() {
|
||||
var first = jq("#ganttpanel").get(0);
|
||||
return [first, first.parentNode, first.parentNode.parentNode];
|
||||
},
|
||||
|
||||
timeplotContainerRescroll : function() {
|
||||
this._getTimeplotContainer().each(jq.proxy(function(index, element){
|
||||
jq(element).css("left", "-" + this._rightPanelLayout.scrollLeft() + "px")
|
||||
}, this));
|
||||
},
|
||||
|
||||
adjust_dimensions : function() {
|
||||
ganttz.Planner.getInstance().adjustScrollableDimensions();
|
||||
},
|
||||
|
||||
_calcXY : function(event) {
|
||||
var arrPos = YAHOO.util.Event.getXY(event);
|
||||
this.setXMouse(arrPos[0]);
|
||||
this.setYMouse(arrPos[1]);
|
||||
},
|
||||
|
||||
_listenToScroll : function() {
|
||||
this._timetrackergap.css("left","-" + this._rightPanelLayout.scrollLeft() + "px");
|
||||
this._taskdetails.css("top", "-" + this._rightPanelLayout.scrollTop() + "px");
|
||||
this._plannergraph.scrollLeft( this._rightPanelLayout.scrollLeft() );
|
||||
this.timeplotContainerRescroll();
|
||||
},
|
||||
|
||||
/*
|
||||
* The canvas is inserted in the DOM after this component, so it's not available right now.
|
||||
* It is queried instead.
|
||||
* Using throttle to not re-query it constantly
|
||||
*/
|
||||
_getTimeplotContainer: common.Common.throttle(500, function() {
|
||||
return jq('canvas.timeplot-canvas').parent();
|
||||
}),
|
||||
|
||||
_initializeProperties : function() {
|
||||
this._timetrackergap = jq('.timetrackergap');
|
||||
this._rightPanelLayout = jq('.rightpanel-layout div:first');
|
||||
this._taskdetails = jq('.listdetails .z-tree-body');
|
||||
this._plannergraph = jq('.plannergraph:first');
|
||||
},
|
||||
|
||||
reScrollY : function(px) {
|
||||
jq('#ganttpanel_inner_scroller_y').height(px);
|
||||
},
|
||||
|
||||
reScrollX : function(px){
|
||||
jq('#ganttpanel_inner_scroller_x').width(px);
|
||||
}
|
||||
},
|
||||
adjust_dimensions : function(){
|
||||
ganttz.Planner.getInstance().adjustScrollableDimensions();
|
||||
},
|
||||
_calcXY : function(event){
|
||||
var arrPos = YAHOO.util.Event.getXY(event);
|
||||
this.setXMouse(arrPos[0]);
|
||||
this.setYMouse(arrPos[1]);
|
||||
},
|
||||
_listenToScroll : function(){
|
||||
this._timetrackergap.css("left","-" + this._rightpannellayout.scrollLeft() + "px");
|
||||
this._taskdetails.css("top", "-" + this._rightpannellayout.scrollTop() + "px");
|
||||
this._plannergraph.scrollLeft( this._rightpannellayout.scrollLeft() );
|
||||
this.timeplotContainerRescroll();
|
||||
},
|
||||
/*The canvas is inserted in the DOM after this component so
|
||||
* it's not available right now. It is queried instead. Using throttle
|
||||
* to not re-query it constantly */
|
||||
_getTimeplotContainer: common.Common.throttle(500, function() {
|
||||
return jq('canvas.timeplot-canvas').parent();
|
||||
}),
|
||||
_initializeProperties : function(){
|
||||
this._timetrackergap = jq('.timetrackergap');
|
||||
this._rightpannellayout = jq('.rightpanellayout div:first');
|
||||
this._taskdetails = jq('.listdetails .z-tree-body');
|
||||
this._plannergraph = jq('.plannergraph:first');
|
||||
},
|
||||
reScrollY : function(px){
|
||||
jq('#ganttpanel_inner_scroller_y').height(px);
|
||||
},
|
||||
reScrollX : function(px){
|
||||
jq('#ganttpanel_inner_scroller_x').width(px);
|
||||
}
|
||||
},{
|
||||
getInstance : function(){
|
||||
return this._instance;
|
||||
},
|
||||
setInstance : function(instance){
|
||||
this._instance = instance;
|
||||
}
|
||||
});
|
||||
{
|
||||
getInstance : function() {
|
||||
return this._instance;
|
||||
},
|
||||
|
||||
setInstance : function(instance){
|
||||
this._instance = instance;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,69 +1,82 @@
|
|||
zk.$package("ganttz");
|
||||
|
||||
ganttz.Planner = zk.$extends(zk.Macro,{
|
||||
$init : function(){
|
||||
this.$supers('$init', arguments);
|
||||
this.$class.setInstance(this);
|
||||
},
|
||||
bind_ : function(){
|
||||
this.$supers('bind_', arguments);
|
||||
this.adjustScrollableDimensions();
|
||||
//Zoomlevel selector
|
||||
this.domListen_(jq('.plannerlayout .toolbar-box select'), 'onChange', '_zoomLevelChanged');
|
||||
this.domListen_(jq(window), 'onResize', 'adjustWatermark');
|
||||
},
|
||||
unbind_ : function(){
|
||||
this.$supers('unbind_', arguments);
|
||||
this.domUnlisten_(jq('.plannerlayout .toolbar-box select'), 'onChange', '_zoomLevelChanged');
|
||||
},
|
||||
adjustScrollableDimensions : function(){
|
||||
ganttz.Planner = zk.$extends(
|
||||
|
||||
// Timetracker is recalculated when the window is resized and when zoom
|
||||
// level is changed as the component is recreated
|
||||
zk.Macro,
|
||||
|
||||
var DOMTimetracker = jq('#timetracker');
|
||||
var DOMWatermark = jq('#watermark');
|
||||
var DOMScrollContainer = jq('#scroll_container');
|
||||
{
|
||||
$init : function(){
|
||||
this.$supers('$init', arguments);
|
||||
this.$class.setInstance(this);
|
||||
},
|
||||
bind_ : function(){
|
||||
this.$supers('bind_', arguments);
|
||||
this.adjustScrollableDimensions();
|
||||
|
||||
DOMTimetracker.width(
|
||||
// Zoomlevel selector
|
||||
this.domListen_(jq('.plannerlayout .toolbar-box select'), 'onChange', '_zoomLevelChanged');
|
||||
|
||||
this.domListen_(jq(window), 'onResize', 'adjustWatermark');
|
||||
},
|
||||
unbind_ : function(){
|
||||
this.$supers('unbind_', arguments);
|
||||
this.domUnlisten_(jq('.plannerlayout .toolbar-box select'), 'onChange', '_zoomLevelChanged');
|
||||
},
|
||||
adjustScrollableDimensions : function(){
|
||||
|
||||
// Timetracker is recalculated when the window is resized and when zoom
|
||||
// level is changed as the component is recreated
|
||||
|
||||
var DOMTimetracker = jq('#timetracker');
|
||||
var DOMWatermark = jq('#watermark');
|
||||
var DOMScrollContainer = jq('#scroll_container');
|
||||
|
||||
DOMTimetracker.width(
|
||||
jq(window).width() -
|
||||
this.$class.TASKDETAILS_WIDTH -
|
||||
this.$class.SCROLLBAR_WIDTH * 2);
|
||||
|
||||
DOMScrollContainer.width(
|
||||
jq('.second_level_ :first').innerWidth());
|
||||
DOMScrollContainer.width(jq('.second_level_ :first').innerWidth());
|
||||
|
||||
DOMTimetracker.width(DOMScrollContainer.innerWidth());
|
||||
this.adjustWatermark();
|
||||
// Inner divs need recalculation to adjust to new scroll displacement lenght
|
||||
ganttz.GanttPanel.getInstance().reScrollY(jq('#listdetails_container').height());
|
||||
DOMTimetracker.width(DOMScrollContainer.innerWidth());
|
||||
this.adjustWatermark();
|
||||
|
||||
// Inner divs need recalculation to adjust to new scroll displacement lenght
|
||||
ganttz.GanttPanel.getInstance().reScrollX(DOMWatermark.outerWidth());
|
||||
},
|
||||
adjustWatermark : function() {
|
||||
jq('#timetracker').height(
|
||||
Math.max(
|
||||
jq(window).height() - this.$class.UNSCROLLABLE_AREA,
|
||||
jq('#scroll_container').height() + this.$class.BOTTOM_WATERMARK_PADDING,
|
||||
this.$class.MIN_WATERMARK_HEIGHT
|
||||
// Inner divs need recalculation to adjust to new scroll displacement length
|
||||
ganttz.GanttPanel.getInstance().reScrollY(jq('#listdetails_container').height());
|
||||
|
||||
// Inner divs need recalculation to adjust to new scroll displacement length
|
||||
ganttz.GanttPanel.getInstance().reScrollX(DOMWatermark.outerWidth());
|
||||
},
|
||||
adjustWatermark : function() {
|
||||
jq('#timetracker').height(
|
||||
Math.max(
|
||||
jq(window).height() - this.$class.UNSCROLLABLE_AREA,
|
||||
jq('#scroll_container').height() + this.$class.BOTTOM_WATERMARK_PADDING,
|
||||
this.$class.MIN_WATERMARK_HEIGHT
|
||||
));
|
||||
},
|
||||
_zoomLevelChanged : function(event) {
|
||||
var zoomindex = event.domTarget.selectedIndex;
|
||||
var scrollLeft = parseFloat(jq('.timetrackergap').css('left').replace(/px/, ""));
|
||||
zAu.send(new zk.Event(this, 'onZoomLevelChange', { zoomindex : zoomindex, scrollLeft : scrollLeft }));
|
||||
}
|
||||
},
|
||||
_zoomLevelChanged : function(event){
|
||||
var zoomindex = event.domTarget.selectedIndex;
|
||||
var scrollLeft = parseFloat(jq('.timetrackergap').css('left').replace(/px/, ""));
|
||||
zAu.send(new zk.Event(this, 'onZoomLevelChange', {zoomindex : zoomindex, scrollLeft : scrollLeft}));
|
||||
}
|
||||
},{
|
||||
TASKDETAILS_WIDTH : 300, // Taskdetails column fixed width (300)
|
||||
UNSCROLLABLE_AREA : 170, // Design-relative reservated height for taskdetails (300,260)
|
||||
MIN_WATERMARK_HEIGHT: 440, // Minimum vertical area for watermark
|
||||
SCROLLBAR_WIDTH : 15, // Scrollbars default width
|
||||
BOTTOM_WATERMARK_PADDING : 40, // Space left behind last task
|
||||
getInstance : function(){
|
||||
return this._instance;
|
||||
},
|
||||
setInstance : function(instance){
|
||||
this._instance = instance;
|
||||
}
|
||||
})
|
||||
|
||||
{
|
||||
TASKDETAILS_WIDTH : 300, // Taskdetails column fixed width (300)
|
||||
|
||||
UNSCROLLABLE_AREA : 170, // Design-relative reservated height for taskdetails (300,260)
|
||||
|
||||
MIN_WATERMARK_HEIGHT: 440, // Minimum vertical area for watermark
|
||||
|
||||
SCROLLBAR_WIDTH : 15, // Scrollbars default width
|
||||
|
||||
BOTTOM_WATERMARK_PADDING : 40, // Space left behind last task
|
||||
|
||||
getInstance : function() {
|
||||
return this._instance;
|
||||
},
|
||||
setInstance : function(instance) {
|
||||
this._instance = instance;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,268 +1,280 @@
|
|||
zk.$package("ganttz");
|
||||
|
||||
/*
|
||||
* This YAHOO code is here because it's used for the Drag&Drop. Once the Drag&Drop is implemented with jQuery
|
||||
* this code must be removed
|
||||
* */
|
||||
* This YAHOO code is here because it's used for the Drag&Drop.
|
||||
* Once the Drag&Drop is implemented with jQuery this code must be removed.
|
||||
*/
|
||||
YAHOO.example.DDRegion = function(id, sGroup, config) {
|
||||
this.cont = config.cont;
|
||||
YAHOO.example.DDRegion.superclass.constructor.apply(this, arguments);
|
||||
};
|
||||
|
||||
var myDom = YAHOO.util.Dom, myEvent = YAHOO.util.Event
|
||||
var myDom = YAHOO.util.Dom, myEvent = YAHOO.util.Event;
|
||||
|
||||
YAHOO.extend(YAHOO.example.DDRegion, YAHOO.util.DD, {
|
||||
cont : null,
|
||||
init : function() {
|
||||
// Call the parent's init method
|
||||
YAHOO.example.DDRegion.superclass.init.apply(this, arguments);
|
||||
this.initConstraints();
|
||||
|
||||
myEvent.on(window, 'resize', function() {
|
||||
YAHOO.example.DDRegion.superclass.init.apply(this, arguments);
|
||||
this.initConstraints();
|
||||
}, this, true);
|
||||
},
|
||||
initConstraints : function() {
|
||||
|
||||
// Get the top, right, bottom and left positions
|
||||
var region = myDom.getRegion(this.cont);
|
||||
myEvent.on(window, 'resize', function() {this.initConstraints();}, this, true);
|
||||
},
|
||||
initConstraints : function() {
|
||||
|
||||
// Get the element we are working on
|
||||
var el = this.getEl();
|
||||
// Get the top, right, bottom and left positions
|
||||
var region = myDom.getRegion(this.cont);
|
||||
|
||||
// Get the xy position of it
|
||||
var xy = myDom.getXY(el);
|
||||
// Get the element we are working on
|
||||
var el = this.getEl();
|
||||
|
||||
// Get the width and height
|
||||
var width = parseInt(myDom.getStyle(el, 'width'), 10);
|
||||
var height = parseInt(myDom.getStyle(el, 'height'), 10);
|
||||
// Get the xy position of it
|
||||
var xy = myDom.getXY(el);
|
||||
|
||||
// Set left to x minus left
|
||||
var left = xy[0] - region.left;
|
||||
// Get the width and height
|
||||
var width = parseInt(myDom.getStyle(el, 'width'), 10);
|
||||
var height = parseInt(myDom.getStyle(el, 'height'), 10);
|
||||
|
||||
// Set right to right minus x minus width
|
||||
var right = region.right - xy[0] - width;
|
||||
// Set left to x minus left
|
||||
var left = xy[0] - region.left;
|
||||
|
||||
// Set top to y minus top
|
||||
var top = xy[1] - region.top;
|
||||
// Set right to right minus x minus width
|
||||
var right = region.right - xy[0] - width;
|
||||
|
||||
// Set bottom to bottom minus y minus height
|
||||
var bottom = region.bottom - xy[1] - height;
|
||||
// Set top to y minus top
|
||||
var top = xy[1] - region.top;
|
||||
|
||||
// Set the constraints based on the above calculations
|
||||
this.setXConstraint(left, right);
|
||||
this.setYConstraint(top, bottom);
|
||||
}
|
||||
// Set bottom to bottom minus y minus height
|
||||
var bottom = region.bottom - xy[1] - height;
|
||||
|
||||
// Set the constraints based on the above calculations
|
||||
this.setXConstraint(left, right);
|
||||
this.setYConstraint(top, bottom);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ganttz.TaskComponent = zk.$extends(zul.Widget, {
|
||||
$define :{
|
||||
resourcesText : null,
|
||||
labelsText : null,
|
||||
tooltipText : null,
|
||||
left: function() {
|
||||
this.$supers('setLeft', arguments);
|
||||
this._getRelatedDependencies().forEach(function(dependency) {
|
||||
dependency.draw();
|
||||
});
|
||||
}
|
||||
},
|
||||
$init : function(){
|
||||
this.$supers('$init', arguments);
|
||||
ganttz.TaskComponent = zk.$extends(
|
||||
zul.Widget,
|
||||
{
|
||||
$define :{
|
||||
resourcesText : null,
|
||||
labelsText : null,
|
||||
tooltipText : null,
|
||||
left: function() {
|
||||
this.$supers('setLeft', arguments);
|
||||
this._getRelatedDependencies().forEach(function(dependency) {
|
||||
dependency.draw();
|
||||
});
|
||||
}
|
||||
},
|
||||
$init : function(){
|
||||
this.$supers('$init', arguments);
|
||||
|
||||
/*
|
||||
* We have to implement the setLeft method because if we use the one provided by ZK
|
||||
* the tasks won't we moved back to its original position when they are dropped on an invalid position (i.e before the end
|
||||
* of the main task) on a dependency relation
|
||||
*
|
||||
* This is the default boddy for a ZK set<AttributeName>
|
||||
*
|
||||
* function (v, opts) {
|
||||
if (before) v = before.apply(this, arguments);
|
||||
var o = this[nm];
|
||||
this[nm] = v;
|
||||
if (after && (o !== v || (opts && opts.force)))
|
||||
after.apply(this, arguments);
|
||||
return this;
|
||||
};
|
||||
*
|
||||
* The before and and after properties can be set to something different to the default using the $define property.
|
||||
*
|
||||
*
|
||||
* Our problem happens because if the dependent task is already aligned at the end of the main tasks
|
||||
* and thats (for example) style. left = 800px, when we move it to an invalid position the server will try to set again
|
||||
* the left property to 800px but when the default setter works it checks if we are trying to set a value equal to the previous
|
||||
* one and in that case it doesn't apply the after function.
|
||||
*
|
||||
* Setting the force option to true does the trick
|
||||
* */
|
||||
var oldSetLeft = this.setLeft;
|
||||
this.setLeft = this.proxy(function(left, options){
|
||||
oldSetLeft.call(this, left, {force : true});
|
||||
})
|
||||
},
|
||||
bind_ : function(event){
|
||||
this.$supers('bind_', arguments);
|
||||
this.domListen_(this.$n(), "onMouseover", '_showTooltip');
|
||||
this.domListen_(this.$n(), "onMouseout", '_hideTooltip');
|
||||
if( jq(this.$n()).attr('movingtasksenabled') == "true" ) this._addDragDrop();
|
||||
if( jq(this.$n()).attr('resizingtasksenabled') == "true" ) this._addResize();
|
||||
},
|
||||
unbind_ : function(event){
|
||||
this.domUnlisten_(this.$n(), "onMouseout", '_hideTooltip');
|
||||
this.domUnlisten_(this.$n(), "onMouseover", '_showTooltip');
|
||||
this.$supers('unbind_', arguments);
|
||||
},
|
||||
addDependency : function(){
|
||||
this._createArrow();
|
||||
},
|
||||
consolidateNewDependency : function(task){
|
||||
zAu.send(new zk.Event(this, 'onAddDependency', {dependencyId : task.id}));
|
||||
},
|
||||
_getRelatedDependencies: function() {
|
||||
return jq('.dependency[idtaskorig='+ this.uuid + ']')
|
||||
/*
|
||||
* We have to implement the setLeft method because if we use the one provided by ZK.
|
||||
* The tasks won't we moved back to its original position when they are dropped on an invalid position
|
||||
* (i.e before the end of the main task) on a dependency relation.
|
||||
*
|
||||
* This is the default body for a ZK set<AttributeName>
|
||||
*
|
||||
* function (v, opts) {
|
||||
* if (before) v = before.apply(this, arguments);
|
||||
* var o = this[nm];
|
||||
* this[nm] = v;
|
||||
*
|
||||
* if (after && (o !== v || (opts && opts.force)))
|
||||
* after.apply(this, arguments);
|
||||
*
|
||||
* return this;
|
||||
* };
|
||||
*
|
||||
* The before and and after properties can be set to something different
|
||||
* to the default using the $define property.
|
||||
*
|
||||
* Our problem happens because if the dependent task is already aligned at the end of the main tasks
|
||||
* and that is (for example) style.
|
||||
* left = 800px, when we move it to an invalid position the server will try to set again
|
||||
* the left property to 800px but when the default setter works,
|
||||
* it checks if we are trying to set a value equal to the previous
|
||||
* one and in that case it doesn't apply the after function.
|
||||
*
|
||||
* Setting the force option to true does the trick
|
||||
* */
|
||||
var oldSetLeft = this.setLeft;
|
||||
this.setLeft = this.proxy(function(left, options){
|
||||
oldSetLeft.call(this, left, {force : true});
|
||||
})
|
||||
},
|
||||
bind_ : function(event) {
|
||||
this.$supers('bind_', arguments);
|
||||
this.domListen_(this.$n(), "onMouseover", '_showTooltip');
|
||||
this.domListen_(this.$n(), "onMouseout", '_hideTooltip');
|
||||
if( jq(this.$n()).attr('movingtasksenabled') == "true" ) this._addDragDrop();
|
||||
if( jq(this.$n()).attr('resizingtasksenabled') == "true" ) this._addResize();
|
||||
},
|
||||
unbind_ : function(event) {
|
||||
this.domUnlisten_(this.$n(), "onMouseout", '_hideTooltip');
|
||||
this.domUnlisten_(this.$n(), "onMouseover", '_showTooltip');
|
||||
this.$supers('unbind_', arguments);
|
||||
},
|
||||
addDependency : function() {
|
||||
this._createArrow();
|
||||
},
|
||||
consolidateNewDependency : function(task) {
|
||||
zAu.send(new zk.Event(this, 'onAddDependency', {dependencyId : task.id}));
|
||||
},
|
||||
_getRelatedDependencies: function() {
|
||||
return jq('.dependency[idtaskorig='+ this.uuid + ']')
|
||||
.add('.dependency[idtaskend='+ this.uuid + ']')
|
||||
.get()
|
||||
.map(function(dep) {
|
||||
return ganttz.DependencyComponentBase.$(dep);
|
||||
});
|
||||
},
|
||||
_addDragDrop : function(){
|
||||
var dragdropregion = this._getDragDropRegion();
|
||||
var thisTaskId = this.$n().id;
|
||||
var relatedDependencies = common.Common.throttle(3000, function() {
|
||||
return jq('.dependency[idtaskorig='+ thisTaskId + ']')
|
||||
},
|
||||
_addDragDrop : function() {
|
||||
var dragdropregion = this._getDragDropRegion();
|
||||
var thisTaskId = this.$n().id;
|
||||
|
||||
var relatedDependencies = common.Common.throttle(3000, function() {
|
||||
return jq('.dependency[idtaskorig='+ thisTaskId + ']')
|
||||
.add('.dependency[idtaskend='+ thisTaskId + ']')
|
||||
.get()
|
||||
.map(function(dep) {
|
||||
return ganttz.DependencyComponentBase.$(dep);
|
||||
});
|
||||
});
|
||||
var drawDependencies = common.Common.throttle(25, function() {
|
||||
relatedDependencies().forEach(function(dependency) {
|
||||
dependency.draw();
|
||||
});
|
||||
});
|
||||
dragdropregion.on('dragEvent', this.proxy(function(ev) {
|
||||
// Slight overload. It could be more efficent to overwrite the YUI
|
||||
// method
|
||||
// that is setting the top property
|
||||
|
||||
var drawDependencies = common.Common.throttle(25, function() {
|
||||
relatedDependencies().forEach(function(dependency) {
|
||||
dependency.draw();
|
||||
});
|
||||
});
|
||||
|
||||
dragdropregion.on('dragEvent', this.proxy(function(ev) {
|
||||
// Slight overload.
|
||||
// It could be more efficent to overwrite the YUI method that is setting the top property.
|
||||
jq(this.$n()).css('top','');
|
||||
drawDependencies();
|
||||
}), null, false);
|
||||
// Register the event endDragEvent
|
||||
dragdropregion.on('endDragEvent', this.proxy(function(ev) {
|
||||
var position = jq(this.$n()).position();
|
||||
zAu.send(new zk.Event(this, 'onUpdatePosition',{left : position.left, top : position.top}))
|
||||
}), null, false);
|
||||
},
|
||||
_addResize : function(){
|
||||
// Configure the task element to be resizable
|
||||
var resize = new YAHOO.util.Resize(this.uuid, {
|
||||
handles : [ 'r' ],
|
||||
proxy : true
|
||||
});
|
||||
|
||||
resize.on("resize", function(event){
|
||||
jq(this.$n()).css({top : ""});
|
||||
zAu.send(new zk.Event(this, 'onUpdateWidth', { width : jq(this.$n()).width() }));
|
||||
},null , this);
|
||||
},
|
||||
_createArrow : function(){
|
||||
var WGTdependencylist = ganttz.DependencyList.getInstance();
|
||||
var unlinkedDependency = new ganttz.UnlinkedDependencyComponent();
|
||||
unlinkedDependency.setOrigin(this.$n());
|
||||
// Register the event endDragEvent
|
||||
dragdropregion.on('endDragEvent', this.proxy(function(ev) {
|
||||
var position = jq(this.$n()).position();
|
||||
zAu.send(new zk.Event(this, 'onUpdatePosition',{left : position.left, top : position.top}))
|
||||
}), null, false);
|
||||
},
|
||||
_addResize : function(){
|
||||
// Configure the task element to be resizable
|
||||
var resize = new YAHOO.util.Resize(this.uuid, {
|
||||
handles : [ 'r' ],
|
||||
proxy : true
|
||||
});
|
||||
|
||||
WGTdependencylist.appendChild(unlinkedDependency, false);
|
||||
resize.on("resize", function(event){
|
||||
jq(this.$n()).css({top : ""});
|
||||
zAu.send(new zk.Event(this, 'onUpdateWidth', { width : jq(this.$n()).width() }));
|
||||
},null , this);
|
||||
},
|
||||
_createArrow : function(){
|
||||
var WGTdependencylist = ganttz.DependencyList.getInstance();
|
||||
var unlinkedDependency = new ganttz.UnlinkedDependencyComponent();
|
||||
unlinkedDependency.setOrigin(this.$n());
|
||||
|
||||
unlinkedDependency.draw();
|
||||
WGTdependencylist.appendChild(unlinkedDependency, false);
|
||||
|
||||
unlinkedDependency.draw();
|
||||
},
|
||||
_getDragDropRegion : function(){
|
||||
if (typeof (this._dragDropRegion) == 'undefined') {
|
||||
// Create the laned drag&drop component
|
||||
this._dragDropRegion = new YAHOO.example.DDRegion(this.uuid, '', {
|
||||
cont : this.parent.getId()
|
||||
});
|
||||
}
|
||||
return this._dragDropRegion;
|
||||
},
|
||||
_showTooltip : function(){
|
||||
this.mouseOverTask = true;
|
||||
this._tooltipTimeout = setTimeout(jq.proxy(function(offset) {
|
||||
var element = jq("#tasktooltip" + this.uuid);
|
||||
|
||||
if (element.length > 0) {
|
||||
element.show();
|
||||
|
||||
offset = ganttz.GanttPanel.getInstance().getXMouse() -
|
||||
element.parent().offset().left -
|
||||
jq('.leftpanelcontainer').offsetWidth -
|
||||
this.$class._PERSPECTIVES_WIDTH +
|
||||
jq('.rightpanel-layout div').scrollLeft();
|
||||
|
||||
element.css( 'left' , offset +'px' );
|
||||
}
|
||||
}, this), this.$class._TOOLTIP_DELAY);
|
||||
},
|
||||
_hideTooltip : function() {
|
||||
this.mouseOverTask = false;
|
||||
if (this._tooltipTimeout) {
|
||||
clearTimeout(this._tooltipTimeout);
|
||||
}
|
||||
jq('#tasktooltip' + this.uuid).hide();
|
||||
},
|
||||
moveDeadline : function(width) {
|
||||
jq('#deadline' + this.parent.uuid).css('left', width);
|
||||
},
|
||||
moveConsolidatedline : function(width) {
|
||||
jq('#consolidatedline' + this.parent.uuid).css('left', width);
|
||||
},
|
||||
resizeCompletionMoneyCostBar : function(width) {
|
||||
jq('#' + this.uuid + ' .completionMoneyCostBar:first').css('width', width);
|
||||
},
|
||||
resizeCompletionAdvance : function(width) {
|
||||
jq('#' + this.uuid + ' .completion:first').css('width', width);
|
||||
},
|
||||
showTimsheetDateMarks : function(positionFirst, postionLast) {
|
||||
var firstTimesheetDateMark = jq('#' + this.uuid + ' .first-timesheet-date');
|
||||
var lastTimesheetDateMark = jq('#' + this.uuid + ' .last-timesheet-date');
|
||||
firstTimesheetDateMark.css('left', positionFirst);
|
||||
lastTimesheetDateMark.css('left', postionLast);
|
||||
firstTimesheetDateMark.show();
|
||||
lastTimesheetDateMark.show();
|
||||
},
|
||||
hideTimsheetDateMarks : function() {
|
||||
jq('#' + this.uuid + ' .first-timesheet-date').hide();
|
||||
jq('#' + this.uuid + ' .last-timesheet-date').hide();
|
||||
},
|
||||
resizeCompletion2Advance : function(width) {
|
||||
jq('#' + this.uuid + ' .completion2:first').css('width', width);
|
||||
},
|
||||
showResourceTooltip : function() {
|
||||
jq('#'+ this.uuid + ' .task-resources').show();
|
||||
},
|
||||
hideResourceTooltip : function() {
|
||||
jq('#'+ this.uuid + ' .task-resources').hide();
|
||||
},
|
||||
showLabels : function() {
|
||||
jq('#'+ this.uuid + ' .task-labels').show();
|
||||
},
|
||||
hideLabels : function() {
|
||||
jq('#'+ this.uuid + ' .task-labels').hide();
|
||||
},
|
||||
setClass : function(cssClass) {
|
||||
jq(this.$n()).removeClass().addClass(cssClass);
|
||||
}
|
||||
},
|
||||
_getDragDropRegion : function(){
|
||||
if (typeof (this._dragDropRegion) == 'undefined') {
|
||||
// Create the laned drag&drop component
|
||||
this._dragDropRegion = new YAHOO.example.DDRegion(this.uuid, '', {
|
||||
cont : this.parent.getId()
|
||||
{
|
||||
//"Class" methods and properties
|
||||
_TOOLTIP_DELAY : 10, // 10 milliseconds
|
||||
_PERSPECTIVES_WIDTH : 80,
|
||||
CORNER_WIDTH : 20,
|
||||
HEIGHT : 10,
|
||||
HALF_HEIGHT : 5,
|
||||
allTaskComponents: function() {
|
||||
var tasksArray = jq('div[z\\.type="ganttz.task.Task"]')
|
||||
.add('div[z\\.type="ganttz.taskcontainer.TaskContainer"]');
|
||||
|
||||
return jq.map(tasksArray, function(element) {
|
||||
return ganttz.TaskComponent.$(element.id);
|
||||
});
|
||||
}
|
||||
return this._dragDropRegion;
|
||||
},
|
||||
_showTooltip : function(){
|
||||
this.mouseOverTask = true;
|
||||
this._tooltipTimeout = setTimeout(jq.proxy(function(offset) {
|
||||
var element = jq("#tasktooltip" + this.uuid);
|
||||
if (element.length > 0) {
|
||||
element.show();
|
||||
offset = ganttz.GanttPanel.getInstance().getXMouse()
|
||||
- element.parent().offset().left
|
||||
- jq('.leftpanelcontainer').offsetWidth
|
||||
- this.$class._PERSPECTIVES_WIDTH
|
||||
+ jq('.rightpanellayout div').scrollLeft();
|
||||
element.css( 'left' , offset +'px' );
|
||||
}
|
||||
}, this), this.$class._TOOLTIP_DELAY);
|
||||
},
|
||||
_hideTooltip : function(){
|
||||
this.mouseOverTask = false;
|
||||
if (this._tooltipTimeout) {
|
||||
clearTimeout(this._tooltipTimeout);
|
||||
}
|
||||
jq('#tasktooltip' + this.uuid).hide();
|
||||
},
|
||||
moveDeadline : function(width){
|
||||
jq('#deadline' + this.parent.uuid).css('left', width);
|
||||
},
|
||||
moveConsolidatedline : function(width){
|
||||
jq('#consolidatedline' + this.parent.uuid).css('left', width);
|
||||
},
|
||||
resizeCompletionMoneyCostBar : function(width){
|
||||
jq('#' + this.uuid + ' .completionMoneyCostBar:first').css('width', width);
|
||||
},
|
||||
resizeCompletionAdvance : function(width){
|
||||
jq('#' + this.uuid + ' .completion:first').css('width', width);
|
||||
},
|
||||
showTimsheetDateMarks : function(positionFirst, postionLast) {
|
||||
var firstTimesheetDateMark = jq('#' + this.uuid + ' .first-timesheet-date');
|
||||
var lastTimesheetDateMark = jq('#' + this.uuid + ' .last-timesheet-date');
|
||||
firstTimesheetDateMark.css('left', positionFirst);
|
||||
lastTimesheetDateMark.css('left', postionLast);
|
||||
firstTimesheetDateMark.show();
|
||||
lastTimesheetDateMark.show();
|
||||
},
|
||||
hideTimsheetDateMarks : function() {
|
||||
jq('#' + this.uuid + ' .first-timesheet-date').hide();
|
||||
jq('#' + this.uuid + ' .last-timesheet-date').hide();
|
||||
},
|
||||
resizeCompletion2Advance : function(width){
|
||||
jq('#' + this.uuid + ' .completion2:first').css('width', width);
|
||||
},
|
||||
showResourceTooltip : function(){
|
||||
jq('#'+ this.uuid + ' .task-resources').show();
|
||||
},
|
||||
hideResourceTooltip : function(){
|
||||
jq('#'+ this.uuid + ' .task-resources').hide();
|
||||
},
|
||||
showLabels : function(){
|
||||
jq('#'+ this.uuid + ' .task-labels').show();
|
||||
},
|
||||
hideLabels : function(){
|
||||
jq('#'+ this.uuid + ' .task-labels').hide();
|
||||
},
|
||||
setClass : function(cssClass){
|
||||
jq(this.$n()).removeClass().addClass(cssClass);
|
||||
}
|
||||
},{
|
||||
//"Class" methods and properties
|
||||
_TOOLTIP_DELAY : 10, // 10 milliseconds
|
||||
_PERSPECTIVES_WIDTH : 80,
|
||||
CORNER_WIDTH : 20,
|
||||
HEIGHT : 10,
|
||||
HALF_HEIGHT : 5,
|
||||
allTaskComponents: function() {
|
||||
var tasksArray = jq('div[z\\.type="ganttz.task.Task"]')
|
||||
.add('div[z\\.type="ganttz.taskcontainer.TaskContainer"]');
|
||||
return jq.map(tasksArray, function(element) {
|
||||
return ganttz.TaskComponent.$(element.id);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -2,33 +2,35 @@ zk.$package("ganttz");
|
|||
|
||||
ganttz.TimeTracker = zk.$extends(
|
||||
|
||||
zk.Macro,{
|
||||
$init : function(){
|
||||
zk.Macro,
|
||||
|
||||
{
|
||||
$init : function() {
|
||||
this.$supers('$init', arguments);
|
||||
this.$class.setInstance(this);
|
||||
},
|
||||
|
||||
bind_ : function (){
|
||||
bind_ : function () {
|
||||
this.$supers('bind_', arguments);
|
||||
this._timetrackerGap = jq('.timetrackergap');
|
||||
this._timetrackerHeader = jq('#timetrackerheader .z-vbox');
|
||||
},
|
||||
|
||||
realWidth : function(){
|
||||
realWidth : function() {
|
||||
return this._timetrackerHeader.width();
|
||||
},
|
||||
|
||||
scrollLeft : function(ammount){
|
||||
scrollLeft : function(ammount) {
|
||||
this._timetrackerGap.css({left : -ammount});
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
getInstance : function(){
|
||||
getInstance : function() {
|
||||
return this._instance;
|
||||
},
|
||||
|
||||
setInstance : function(instance){
|
||||
setInstance : function(instance) {
|
||||
this._instance = instance;
|
||||
}
|
||||
})
|
||||
|
|
@ -25,14 +25,15 @@ ADVANCE_ALLOCATIONS = {};
|
|||
ADVANCE_ALLOCATIONS.listenToScroll = function() {
|
||||
var scrollableArea = jq('.advanced-assignment-area');
|
||||
var innerScrollableArea = jq('.z-center-body', scrollableArea);
|
||||
var taskDetails = jq('.advancedassignmentdetails .z-grid-body');
|
||||
var taskDetails = jq('.advanced-assignment-details .z-grid-body');
|
||||
var timeTracker = ganttz.TimeTracker.getInstance();
|
||||
|
||||
scrollableArea.bind('scroll', function() {
|
||||
timeTracker.scrollLeft(scrollableArea.scrollLeft());
|
||||
taskDetails.css({top : -scrollableArea.scrollTop()});
|
||||
timeTracker.scrollLeft(scrollableArea.scrollLeft());
|
||||
taskDetails.css({top : -scrollableArea.scrollTop()});
|
||||
});
|
||||
|
||||
if (timeTracker != undefined ) innerScrollableArea.width(timeTracker.realWidth());
|
||||
if (timeTracker != undefined )
|
||||
innerScrollableArea.width(timeTracker.realWidth());
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
function(out){
|
||||
function (out) {
|
||||
|
||||
out.push('<div ', this.domAttrs_(),
|
||||
'z.type="ganttz.dependencylist.Dependencylist"',
|
||||
'z.autoz="true"',
|
||||
'>');
|
||||
out.push('<div id="listdependencies">');
|
||||
for (var w = this.firstChild; w; w = w.nextSibling)
|
||||
w.redraw(out);
|
||||
out.push('</div>');
|
||||
'z.type="ganttz.dependencylist.Dependencylist"',
|
||||
'z.autoz="true"',
|
||||
'>');
|
||||
|
||||
out.push('<div id="listdependencies">');
|
||||
for (var w = this.firstChild; w; w = w.nextSibling) {
|
||||
w.redraw(out);
|
||||
}
|
||||
out.push('</div>');
|
||||
|
||||
out.push('</div>');
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
zk.$package("ganttz.resourceload");
|
||||
|
||||
ganttz.resourceload.ResourceLoadComponent = zk.$extends(zk.Widget,{
|
||||
$define : {
|
||||
resourceLoadName : null,
|
||||
resourceLoadType : null
|
||||
}
|
||||
});
|
||||
ganttz.resourceload.ResourceLoadComponent = zk.$extends(
|
||||
zk.Widget,
|
||||
{
|
||||
$define : {
|
||||
resourceLoadName : null,
|
||||
resourceLoadType : null
|
||||
}
|
||||
});
|
||||
|
|
@ -1,72 +1,84 @@
|
|||
zk.$package("ganttz.resourceload");
|
||||
|
||||
ganttz.resourceload.ResourceLoadList = zk.$extends(zk.Widget,{
|
||||
$init : function(){
|
||||
this.$supers('$init', arguments);
|
||||
this.$class.setInstance(this);
|
||||
common.Common.mixInDayPositionRestorer(this);
|
||||
},
|
||||
bind_ : function(evt){
|
||||
this.$supers('bind_', arguments);
|
||||
this.domListen_(jq(window), 'onResize', 'adjustTimeTrackerSize');
|
||||
this.domListen_(jq('.rightpanellayout div:first'), 'onScroll', '_listenToScroll');
|
||||
},
|
||||
unbind_ : function(evt){
|
||||
this.domUnlisten_(jq(window), 'onResize', 'adjustTimeTrackerSize');
|
||||
this.domUnlisten_(jq('.rightpanellayout div:first'), 'onScroll', '_listenToScroll');
|
||||
this.$supers('unbind_', arguments);
|
||||
},
|
||||
_divsToRestoreDayInto: function() {
|
||||
var first = this.$n();
|
||||
return [first, first.parentNode, first.parentNode.parentNode];
|
||||
},
|
||||
recalculateTimeTrackerHeight : function(){
|
||||
var DOMResourceLoadList = jq('.resourceloadlist');
|
||||
var DOMfirstWatermarkColumn = jq('.rightpanellayout tr#watermark td :first');
|
||||
ganttz.resourceload.ResourceLoadList = zk.$extends(
|
||||
zk.Widget,
|
||||
{
|
||||
$init : function() {
|
||||
this.$supers('$init', arguments);
|
||||
this.$class.setInstance(this);
|
||||
common.Common.mixInDayPositionRestorer(this);
|
||||
},
|
||||
|
||||
if ( DOMResourceLoadList != undefined && DOMfirstWatermarkColumn != undefined){
|
||||
DOMResourceLoadList.height(
|
||||
Math.max(
|
||||
DOMResourceLoadList.innerHeight() + this.$class.WATERMARK_MARGIN_BOTTOM,
|
||||
this.$class.WATERMARK_MIN_HEIGHT));
|
||||
bind_ : function(evt) {
|
||||
this.$supers('bind_', arguments);
|
||||
this.domListen_(jq(window), 'onResize', 'adjustTimeTrackerSize');
|
||||
this.domListen_(jq('.rightpanel-layout div:first'), 'onScroll', '_listenToScroll');
|
||||
},
|
||||
|
||||
unbind_ : function(evt) {
|
||||
this.domUnlisten_(jq(window), 'onResize', 'adjustTimeTrackerSize');
|
||||
this.domUnlisten_(jq('.rightpanel-layout div:first'), 'onScroll', '_listenToScroll');
|
||||
this.$supers('unbind_', arguments);
|
||||
},
|
||||
|
||||
_divsToRestoreDayInto : function() {
|
||||
var first = this.$n();
|
||||
return [first, first.parentNode, first.parentNode.parentNode];
|
||||
},
|
||||
|
||||
recalculateTimeTrackerHeight : function() {
|
||||
var DOMResourceLoadList = jq('.z-resourceloadlist');
|
||||
|
||||
var DOMfirstWatermarkColumn = jq('.rightpanel-layout tr#watermark td :first');
|
||||
|
||||
|
||||
if ( DOMResourceLoadList != undefined && DOMfirstWatermarkColumn != undefined ) {
|
||||
|
||||
DOMResourceLoadList.height(Math.max(
|
||||
DOMResourceLoadList.innerHeight() + this.$class.WATERMARK_MARGIN_BOTTOM,
|
||||
this.$class.WATERMARK_MIN_HEIGHT));
|
||||
}
|
||||
},
|
||||
|
||||
adjustTimeTrackerSize : function() {
|
||||
this.recalculateTimeTrackerHeight();
|
||||
|
||||
/*
|
||||
* We can't use this.getHeight() as the _height property won't be set for this object and even when
|
||||
* it changes (recalculateTimeTrackerHeight) so, we avoid using DOM selectors.
|
||||
* TODO: maybe create a _height property and update it
|
||||
*/
|
||||
jq('#watermark').height(jq(this.$n()).innerHeight());
|
||||
|
||||
jq(this.$n()).width(jq('#timetracker .z-vbox').innerWidth());
|
||||
},
|
||||
|
||||
adjustResourceLoadRows : function() {
|
||||
jq(this.$n()).width(jq('#timetracker .z-vbox').innerWidth());
|
||||
},
|
||||
|
||||
_listenToScroll : function() {
|
||||
var scrolledPanelScrollLeft = jq('.rightpanel-layout div:first').scrollLeft();
|
||||
var scrolledPanelScrollTop = jq('.rightpanel-layout div:first').scrollTop();
|
||||
|
||||
jq('canvas.timeplot-canvas').parent().css("left", "-" + scrolledPanelScrollLeft + "px");
|
||||
jq('.timetrackergap').css("left", "-" + scrolledPanelScrollLeft + "px");
|
||||
jq('.leftpanelgap .z-tree-body').css("top", "-" + scrolledPanelScrollTop + "px");
|
||||
jq('.resourcesloadgraph div').scrollLeft(scrolledPanelScrollLeft + "px");
|
||||
|
||||
this.adjustResourceLoadRows();
|
||||
}
|
||||
},
|
||||
adjustTimeTrackerSize : function(){
|
||||
this.recalculateTimeTrackerHeight();
|
||||
{
|
||||
// Class stuff
|
||||
WATERMARK_MIN_HEIGHT : 450,
|
||||
WATERMARK_MARGIN_BOTTOM : 40,
|
||||
|
||||
/*We can't use this.getHeight() as the _height property
|
||||
* won't be set for this object and even
|
||||
*
|
||||
* TODO: maybe create a _height property and update it
|
||||
* when it changes (recalculateTimeTrackerHeight) son we avoid
|
||||
* using DOM selectors
|
||||
* */
|
||||
jq('#watermark').height(jq(this.$n()).innerHeight());
|
||||
setInstance : function(instance) {
|
||||
this._instance = instance;
|
||||
},
|
||||
|
||||
/*this.$n() is <div class="resourceloadlist" ...>*/
|
||||
jq(this.$n()).width(jq('#timetracker .z-vbox').innerWidth());
|
||||
},
|
||||
adjustResourceLoadRows : function(){
|
||||
jq(this.$n()).width(jq('#timetracker .z-vbox').innerWidth());
|
||||
},
|
||||
_listenToScroll : function(){
|
||||
var scrolledPannelScrollLeft = jq('.rightpanellayout div:first').scrollLeft();
|
||||
var scrolledPannelScrollTop = jq('.rightpanellayout div:first').scrollTop();
|
||||
|
||||
jq('canvas.timeplot-canvas').parent().css("left", "-" + scrolledPannelScrollLeft + "px");
|
||||
jq('.timetrackergap').css("left", "-" + scrolledPannelScrollLeft + "px");
|
||||
jq('.leftpanelgap .z-tree-body').css("top", "-" + scrolledPannelScrollTop + "px");
|
||||
jq('.resourcesloadgraph div').scrollLeft(scrolledPannelScrollLeft + "px");
|
||||
|
||||
this.adjustResourceLoadRows();
|
||||
}
|
||||
},{ //Class stuff
|
||||
WATERMARK_MIN_HEIGHT : 450,
|
||||
WATERMARK_MARGIN_BOTTOM : 40,
|
||||
setInstance : function(instance){
|
||||
this._instance = instance;
|
||||
},
|
||||
getInstance : function(){
|
||||
return this._instance;
|
||||
}
|
||||
});
|
||||
getInstance : function() {
|
||||
return this._instance;
|
||||
}
|
||||
});
|
||||
|
|
@ -1,10 +1,30 @@
|
|||
function(out){
|
||||
out.push('<div ', this.domAttrs_(),
|
||||
function (out) {
|
||||
/*
|
||||
* This method draws graphic lines ( charts ) for every resource, if needed.
|
||||
*
|
||||
* After we migrated from ZK5 to ZK8, this.domAttrs_() started to return NaN.
|
||||
* Possible reason: not enough time to load library.
|
||||
*/
|
||||
if ( !isNaN(this.domAttrs_()) ) {
|
||||
out.push(
|
||||
'<div ',
|
||||
this.domAttrs_(),
|
||||
' class="row_resourceload resourceload-'+ this.getResourceLoadType(),'"',
|
||||
' z.autoz="true"',
|
||||
'>');
|
||||
out.push('<span class="resourceload_name">', this.getResourceLoadName(),'</span>');
|
||||
for(var w = this.firstChild; w; w = w.nextSibling)
|
||||
w.redraw(out);
|
||||
} else {
|
||||
out.push(
|
||||
'<div ',
|
||||
' class="row_resourceload resourceload-'+ this.getResourceLoadType(),'"',
|
||||
' z.autoz="true"',
|
||||
'>');
|
||||
}
|
||||
|
||||
out.push('<span class="resourceload_name">', this.getResourceLoadName(),'</span>');
|
||||
|
||||
for (var w = this.firstChild; w; w = w.nextSibling) {
|
||||
w.redraw(out);
|
||||
}
|
||||
|
||||
out.push('</div>');
|
||||
}
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
function(out){
|
||||
function (out) {
|
||||
|
||||
out.push('<div ' + this.domAttrs_(),
|
||||
' class="resourceloadlist"',
|
||||
' z.type="ganttz.resourceload.resourceloadlist.ResourceLoadList">');
|
||||
for(var w = this.firstChild; w; w = w.nextSibling)
|
||||
' z.type="ganttz.resourceload.resourceloadlist.ResourceLoadList">');
|
||||
|
||||
for (var w = this.firstChild; w; w = w.nextSibling) {
|
||||
w.redraw(out);
|
||||
}
|
||||
|
||||
out.push('</div>');
|
||||
|
||||
}
|
||||
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.barRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.barRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasAxisLabelRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasAxisLabelRenderer.min.js
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.4r1121
|
||||
*
|
||||
* Copyright (c) 2009-2011 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
* included jsDate library by Chris Leonello:
|
||||
*
|
||||
* Copyright (c) 2010-2011 Chris Leonello
|
||||
*
|
||||
* jsDate is currently available for use in all personal or commercial projects
|
||||
* under both the MIT and GPL version 2.0 licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* jsDate borrows many concepts and ideas from the Date Instance
|
||||
* Methods by Ken Snyder along with some parts of Ken's actual code.
|
||||
*
|
||||
* Ken's origianl Date Instance Methods and copyright notice:
|
||||
*
|
||||
* Ken Snyder (ken d snyder at gmail dot com)
|
||||
* 2008-09-10
|
||||
* version 2.0.2 (http://kendsnyder.com/sandbox/date/)
|
||||
* Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
|
||||
*
|
||||
* jqplotToImage function based on Larry Siden's export-jqplot-to-png.js.
|
||||
* Larry has generously given permission to adapt his code for inclusion
|
||||
* into jqPlot.
|
||||
*
|
||||
* Larry's original code can be found here:
|
||||
*
|
||||
* https://github.com/lsiden/export-jqplot-to-png
|
||||
*
|
||||
*
|
||||
*/
|
||||
(function(a){a.jqplot.CanvasAxisLabelRenderer=function(b){this.angle=0;this.axis;this.show=true;this.showLabel=true;this.label="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="11pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=true;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);if(b.angle==null&&this.axis!="xaxis"&&this.axis!="x2axis"){this.angle=-90}var c={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){c.pt2px=this.pt2px}if(this.enableFontSupport){if(a.jqplot.support_canvas_text()){this._textRenderer=new a.jqplot.CanvasFontRenderer(c)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}};a.jqplot.CanvasAxisLabelRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisLabelRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisLabelRenderer.prototype.draw=function(c,f){if(this._elem){if(a.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==undefined){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce();this._elem=null}var e=f.canvasManager.getCanvas();this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e=f.canvasManager.initCanvas(e);this._elem=a(e);this._elem.css({position:"absolute"});this._elem.addClass("jqplot-"+this.axis+"-label");e=null;return this._elem};a.jqplot.CanvasAxisLabelRenderer.prototype.pack=function(){this._textRenderer.draw(this._elem.get(0).getContext("2d"),this.label)}})(jQuery);
|
||||
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasTextRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasTextRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.categoryAxisRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.categoryAxisRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.pieRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.pieRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jquery.jqplot.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jquery.jqplot.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue