Merge branch 'master' into ldap

Conflicts:
	navalplanner-business/src/main/java/org/navalplanner/business/common/Configuration.java
	navalplanner-business/src/main/java/org/navalplanner/business/common/entities/Configuration.java
	navalplanner-business/src/main/java/org/navalplanner/business/users/entities/User.java
	navalplanner-business/src/main/resources/org/navalplanner/business/users/entities/Users.hbm.xml
	navalplanner-webapp/src/main/java/org/navalplanner/web/common/ConfigurationController.java
	navalplanner-webapp/src/main/java/org/navalplanner/web/common/ConfigurationModel.java
	navalplanner-webapp/src/main/java/org/navalplanner/web/common/IConfigurationModel.java
	navalplanner-webapp/src/main/webapp/common/configuration.zul
This commit is contained in:
Manuel Rego Casasnovas 2011-06-30 08:25:36 +02:00
commit 93294940f9
602 changed files with 8730 additions and 45519 deletions

View file

@ -1,10 +1,12 @@
Authors
=======
* Cristina Alavariño Pérez <cristina.alvarino@comtecsf.es>
* Jacobo Aragunde Pérez <jaragunde@igalia.com>
* Fernando Bellas Permuy <fbellas@udc.es>
* José María Casanova Crespo <jmcasanova@igalia.com>
* Xavier Castaño García <xcastanho@igalia.com>
* Ignacio Díaz Teijido <ignacio.diaz@comtecsf.es>
* Óscar González Fernández <ogonzalez@igalia.com>
* Susana Montes Pedreira <smontes@wirelessgalicia.com>
* Francisco Javier Morán Rúa <jmoran@igalia.com>

375
HACKING
View file

@ -1,7 +1,376 @@
Hacking
=======
If you want to hack on the *NavalPlan* project you should visit the wiki where
you can find all the information related with project development.
This is a guide about how to start hacking on *NavalPlan* project. If you want
more information about *NavalPlan* development you should visit the wiki
available at: http://wiki.navalplan.org/.
*NavalPlan* wiki is available at: http://wiki.navalplan.org/.
.. contents::
Compilation requirements
------------------------
* *Git* - Version Control System
Needed to clone source code repository
* *Maven 2* - Java software project management and comprehension tool
Needed to build and compile the project
* *JDK 6* - Java Development Kit
Project depends on Java 6 and JDK is needed in order to compile it
* *PostgreSQL* - Object-relational SQL database
Database server
* *Python Docutils* - Utilities for the documentation of Python modules
Used to generate HTMLs help files from RST files (reStructuredText)
* *Make* - An utility for Directing compilation
Needed to compile the help
* *gettext* - GNU Internationalization utilities
Used for i18n support in the project
* *GNU FreeFont* - Freefont Serif, Sans and Mono Truetype fonts
Font family used in reports
* *CutyCapt* - Utility to capture WebKit's rendering of a web page
Required for printing
NavalPlan compilation
---------------------
Debian/Ubuntu
~~~~~~~~~~~~~
* Install requirements::
# apt-get install git-core maven2 openjdk-6-jdk postgresql postgresql-client python-docutils make gettext ttf-freefont cutycapt
* Connect to database::
# su postgres -c psql
* Use SQL sentences::
CREATE DATABASE navaldev;
CREATE DATABASE navaldevtest;
CREATE USER naval WITH PASSWORD 'naval';
GRANT ALL PRIVILEGES ON DATABASE navaldev TO naval;
GRANT ALL PRIVILEGES ON DATABASE navaldevtest TO naval;
* Download source code::
$ git clone git://navalplan.git.sourceforge.net/gitroot/navalplan/navalplan
* Compile project::
$ mvn clean install
* Launch application::
$ cd navalplanner-webapp/
$ mvn jetty:run
* Go to http://localhost:8080/navalplanner-webapp/
Fedora
~~~~~~
* Install requirements::
# yum install git maven java-1.6.0-openjdk postgresql postgresql-server python-docutils make gettext gnu-free-fonts-compat
* Start database service::
# service postgresql initdb
# service postgresql start
* Connect to database::
# su postgres -c psql
* Use SQL sentences::
CREATE DATABASE navaldev;
CREATE DATABASE navaldevtest;
CREATE USER naval WITH PASSWORD 'naval';
GRANT ALL PRIVILEGES ON DATABASE navaldev TO naval;
GRANT ALL PRIVILEGES ON DATABASE navaldevtest TO naval;
* Set ``postgres`` user password::
ALTER USER postgres WITH PASSWORD 'postgres';
* Edit ``/var/lib/pgsql/data/pg_hba.conf`` and replace ``ident`` by ``md5``
* Reload database configuration::
# service postgresql reload
* Download source code::
$ git clone git://navalplan.git.sourceforge.net/gitroot/navalplan/navalplan
* Compile project::
$ mvn clean install
* Launch application::
$ cd navalplanner-webapp/
$ mvn jetty:run
* Go to http://localhost:8080/navalplanner-webapp/
openSUSE
~~~~~~~~
* Install requirements::
# zypper install git-core java-1_6_0-openjdk-devel postgresql-server postgresql docutils make gettext-tools freefont
* Install Maven::
# cd /opt/
# wget http://www.apache.org/dist//maven/binaries/apache-maven-2.2.1-bin.tar.gz
# tar -xzvf apache-maven-2.2.1-bin.tar.gz
Edit ``/etc/bash.bashrc.local`` and add the following lines::
export M2_HOME=/opt/apache-maven-2.2.1
export M2=$M2_HOME/bin
export PATH=$M2:$PATH
* Start database service::
# /etc/init.d/postgresql start
* Connect to database::
# su postgres -c psql
* Use SQL sentences::
CREATE DATABASE navaldev;
CREATE DATABASE navaldevtest;
CREATE USER naval WITH PASSWORD 'naval';
GRANT ALL PRIVILEGES ON DATABASE navaldev TO naval;
GRANT ALL PRIVILEGES ON DATABASE navaldevtest TO naval;
* Set ``postgres`` user password::
ALTER USER postgres WITH PASSWORD 'postgres';
* Edit ``/var/lib/pgsql/data/pg_hba.conf`` and replace ``ident`` by ``md5``
* Restart database service::
# /etc/init.d/postgresql restart
* Download source code::
$ git clone git://navalplan.git.sourceforge.net/gitroot/navalplan/navalplan
* Compile project::
$ mvn clean install
* Launch application::
$ cd navalplanner-webapp/
$ mvn jetty:run
* Go to http://localhost:8080/navalplanner-webapp/
CutyCapt compilation
--------------------
Like *CutyCapt* is not packaged for all distributions here are the instructions.
Ubuntu/Debian
~~~~~~~~~~~~~
* Install requirements::
# apt-get install subversion libqt4-dev libqtwebkit-dev qt4-qmake g++ make
In Ubuntu Lucid 10.04 remove ``libqtwebkit-dev`` package.
* Download source code::
$ svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt cutycapt
* Compile::
$ cd CutyCapt
$ qmake CutyCapt.pro
$ make
* Install::
# cp CutyCapt /user/bin/cutycapt
Fedora
~~~~~~
* Install requirements::
# yum install subversion qt-devel qt-webkit-devel gcc-c++ make
* Download source code::
$ svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt cutycapt
* Compile::
$ cd cutycapt/CutyCapt
$ qmake-qt4 CutyCapt.pro
$ make
* Install::
# cp CutyCapt /user/bin/cutycapt
openSUSE
~~~~~~~~
* Install requirements::
# zypper install subversion libqt4-devel libQtWebKit-devel gcc-c++ make
* Download source code::
$ svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt cutycapt
* Compile::
$ cd cutycapt/CutyCapt
$ qmake-qt4 CutyCapt.pro
$ make
* Install::
# cp CutyCapt /user/bin/cutycapt
Compilation profiles
--------------------
There are different compilation profiles in *NavalPlan*. Check ``<profiles>``
section in root ``pom.xml`` to see the different profiles (there are also some
profiles defined in ``pom.xml`` of business and webapp modules).
* *dev* - Development environment (default)
It uses databases ``navaldev`` and ``navaldevtest``.
* *prod* - Production environment
Unlike *dev* it uses database ``navalprod`` and `navalprodtest``.
It is needed to use it in combination with *postgresql* or *mysql* profiles.
This is usually used while testing the stable branch in the repository. This
allows developers to easily manage 2 different databases one for last
development in master branch and another for bugfixing over stable branch.
* *postgresql* - PostgreSQL database (default)
It uses PostgreSQL database server getting database names from *dev* or *prod*
profiles.
* *mysql* - MySQL database
It uses MySQL database server getting database names from *dev* or *prod*
profiles.
* *reports* - JasperReports (default)
If it is active *NavalPlan* reports are compiled.
It is useful to disable this profile to save compilation time during
development.
* *userguide* - User documentation (default)
If it is active *NavalPlan* help is compiled and HTML files are generated.
User documentation is written in *reStructuredText* and it is generated
automatically thanks to this profile.
Like for *reports*, it is useful deactivate this profile during development
to save compilation time.
* *liquibase-update* - Liquibase update (default)
If it is active Liquibase changes are applied in the database.
* *liquibase-updatesql* - Liquibase update SQL
If it is active it is generated a file with SQL sentences for Liquibase
changes needed to apply on database.
This is used to generate upgrade files in releases.
How to use profiles
~~~~~~~~~~~~~~~~~~~
Profiles active by default are used always if not deactivated. In order to
activate or deactivate a profile you should use parameter ``-P`` for Maven
command. For example:
* Deactivate *reports* and *userguide* to save compilation time::
mvn -P-reports,-userguide clean install
* Use production environment::
mvn -Pprod,postgresql clean install
Tests
-----
*NavalPlan* has a lot of JUnit test that by default are passed when you compile
the project with Maven. You can use ``-DskipTests`` to avoid tests are passed
always. Anyway, you should check that tests are not broken before sending or
pushing a patch.
::
mvn -DskipTests clean install
MySQL
-----
For MySQL users here are specific instructions.
* SQL sentences to create database::
CREATE DATABASE navaldev;
CREATE DATABASE navaldevtest;
GRANT ALL ON navaldev.* to 'naval'@'localhost' identified by 'naval';
GRANT ALL ON navaldevtest.* to 'naval'@'localhost' identified by 'naval';
* Compile project::
$ mvn -Pdev,mysql clean install
* Launch application::
$ cd navalplanner-webapp/
$ mvn -Pdev,mysql jetty:run

321
INSTALL
View file

@ -1,120 +1,221 @@
Installation instructions
=========================
Install
=======
Visit the wiki for an updated version of these instructions:
http://wiki.navalplan.org/twiki/bin/view/NavalPlan/InstallNavalPlan.
This is a guide about how to install *NavalPlan* project in your system. If you
want to upgrade your *NavalPlan* version see ``UPDATE`` file. If you want to
know how to compile it manually see ``HACKING`` file.
Database creation
-----------------
* Current databases supported: PostgreSQL (default) and MySQL.
* For PostgreSQL and MySQL:
- Create a database with name ``navaldev`` (for development)::
CREATE DATABASE navaldev;
- Create a database with name ``navaldevtest`` (for the test fase in
development)::
CREATE DATABASE navaldevtest;
- Create user ``naval`` with password ``naval`` with necessary privileges for
accessing (creating tables, selecting data from tables, etc.) the
previous databases:
+ PostgreSQL::
CREATE USER naval WITH PASSWORD 'naval';
GRANT ALL PRIVILEGES ON DATABASE navaldev TO naval;
GRANT ALL PRIVILEGES ON DATABASE navaldevtest TO naval;
+ MySQL::
GRANT ALL ON navaldev.* to 'naval'@'localhost' identified by 'naval';
GRANT ALL ON navaldevtest.* to 'naval'@'localhost' identified by 'naval';
.. contents::
Compilation
-----------
NavalPlan automatic installation
--------------------------------
* Execute the following commands::
cd navalplan
mvn install
cd navalplanner-webapp
mvn jetty:run
* Access to http://localhost:8080/navalplanner-webapp.
* To install the web application in a web container, use the WAR file:
``navalplanner-webapp/target/navalplanner-webapp.war``.
* *Notes for using other databases*:
+ MySQL:
- Remember to start MySQL with ``--default-table-type=InnoDB`` option for
enabling support for transactions.
- Use ``mvn -Pdev,mysql <<goal|fase>>``::
e.g. mvn -Pdev,mysql install
Profiles
--------
Check ``<profiles>`` section in the root ``pom.xml`` to see the profile-based
approach used in the project. The default profiles (the one assumed by the above
instructions) are ``dev`` and ``postgresql`` (meaning "use PostgreSQL assuming a
development environment").
Print
-----
Printing system is based on a tool that produces several output formats
rendering the specified URLs with the WebKit engine. To be able to print local
diagrams this tool and a lightweight X server must be installed.
The capturing tool is CutyCapt [1]_, which has to be either compiled or
installed from an external package. Once compiled from the tarball the binary
CutyCapt must be located under ``/usr/bin/`` to be available to the application.
X virtual framebuffer xvfb [2]_ package needs to be installed for the
application running on a non-desktop server is capable of launching an X
instance to create the print capture of the selected page.
.. [1] http://cutycapt.sourceforge.net/
.. [2] http://www.xfree86.org/4.0.1/Xvfb.1.html
User Documentation
------------------
User documentation is done in *reStructuredText*. It is necessary to have
installed the following packages:
* ``automake`` package in order to be able to execute ``make``.
* ``python-docutils`` package version 0.4 or higher.
* ``texlive-latex-base`` package in order to have ``pdflatex`` available.
Compilation
Ubuntu PPAs
~~~~~~~~~~~
The compilation is included in Maven build. If you execute ``mvn install``
documentation is generated.
There are Ubuntu PPAs for different versions (Lucid, Maverick and Natty), you
can find more info in the following URL:
https://launchpad.net/~libreplan/+archive/ppa
* For manual compilation, inside ``doc/src/es``, ``doc/src/gl`` or
``doc/src/es`` directories:
Instructions::
make html
make pdf
$ sudo add-apt-repository ppa:libreplan/ppa
$ sudo apt-get update
$ sudo apt-get install navalplan
* Output is created in ``doc/src/es/html`` and ``/doc/src/es/pdf`` directories.
Debian packages
~~~~~~~~~~~~~~~
There are Debian packages for Squeeze (i386 and amd64), you can download them
from: http://sourceforge.net/projects/navalplan/files/NavalPlan/
Instructions:
* Download the package::
$ wget http://downloads.sourceforge.net/project/navalplan/NavalPlan/navalplan_1.1.1-1_amd64.deb
* Install package::
# dpkg -i navalplan_1.1.1-1_amd64.deb
* Install dependencies::
# apt-get install -f
NavalPlan manual installation
-----------------------------
Debian/Ubuntu
~~~~~~~~~~~~~
* Install requirements::
# apt-get install openjdk-6-jre postgresql postgresql-client tomcat6 libpg-java ttf-freefont cutycapt xvfb
* Connect to database::
# su postgres -c psql
* Use SQL sentences to create database::
CREATE DATABASE navalplan;
CREATE USER navalplan WITH PASSWORD 'navalplan';
GRANT ALL PRIVILEGES ON DATABASE navalplan TO naval;
* Download database installation script::
$ wget -O install.sql http://downloads.sourceforge.net/project/navalplan/NavalPlan/install_1.1.1.sql
* Create database structure::
$ psql -h localhost -U navalplan -W navalplan < install.sql
* Download ``.war`` file from SourceForge.net::
$ wget -O navalplan.war http://downloads.sourceforge.net/project/navalplan/NavalPlan/navalplan_1.1.1.war
* Create a new file ``/etc/tomcat6/Catalina/localhost/navalplan.xml`` (file
name has to match with ``.war`` name) with database configuration for
Tomcat 6::
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="">
<Resource name="jdbc/navalplanner-ds" auth="Container"
type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="navalplan" password="navalplan"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost/navalplan" />
</Context>
* Add a new Tomcat 6 policy file ``/etc/tomcat6/policy.d/51navalplan.policy``
with the following content::
grant codeBase "file:/var/lib/tomcat6/webapps/navalplanner-webapp/-" {
permission java.security.AllPermission;
};
grant codeBase "file:/var/lib/tomcat6/webapps/navalplanner-webapp.war" {
permission java.security.AllPermission;
};
* Add next lines to Tomcat 6 policy file
``/etc/tomcat6/policy.d/03catalina.policy`` file::
grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" {
...
// begin:navalplan
permission java.io.FilePermission "${catalina.base}${file.separator}webapps${file.separator}navalplanner-webapp${file.separator}WEB-INF${file.separator}classes${file.separator}logging.properties", "read";
// end:navalplan
...
};
* Add link to Java JDBC driver for PostgreSQL in Tomcat6 libraries directory::
# ln -s /usr/share/java/postgresql-jdbc3.jar /usr/share/tomcat6/lib/
* Copy war to Tomcat 6 web applications directory::
# cp navalplan.war /var/lib/tomcat6/webapps/
* Restart Tomcat 6::
# /etc/init.d/tomcat6 restart
* Go to http://localhost:8080/navalplan/
openSUSE
~~~~~~~~
* Install requirements::
# zypper install java-1_6_0-openjdk postgresql-server postgresql tomcat6 freefont xorg-x11-server
* JDBC Driver manual installation::
# cd /usr/share/java/
# wget http://jdbc.postgresql.org/download/postgresql-9.0-801.jdbc3.jar
# mv postgresql-9.0-801.jdbc3.jar postgresql-jdbc3.jar
* Follow instructions at ``HACKING`` file to compile and install CutyCapt
* Start database service::
# /etc/init.d/postgresql start
* Connect to database::
# su postgres -c psql
* SQL sentences to create database::
CREATE DATABASE navalplan;
CREATE USER navalplan WITH PASSWORD 'navalplan';
GRANT ALL PRIVILEGES ON DATABASE navalplan TO navalplan;
* Set ``postgres`` user password::
ALTER USER postgres WITH PASSWORD 'postgres';
* Edit ``/var/lib/pgsql/data/pg_hba.conf`` and replace ``ident`` by ``md5``
* Restart database service::
# /etc/init.d/postgresql restart
* Download database installation script::
$ wget -O install.sql http://downloads.sourceforge.net/project/navalplan/NavalPlan/install_1.1.1.sql
* Create database structure::
$ psql -h localhost -U navalplan -W navalplan < install.sql
* Download ``.war`` file from SourceForge.net::
$ wget -O navalplan.war http://downloads.sourceforge.net/project/navalplan/NavalPlan/navalplan_1.1.1.war
* Create a new file ``/etc/tomcat6/Catalina/localhost/navalplan.xml`` (file
name has to match with ``.war`` name) with database configuration for
Tomcat 6::
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="">
<Resource name="jdbc/navalplanner-ds" auth="Container"
type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="navalplan" password="navalplan"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost/navalplan" />
</Context>
* Add link to Java JDBC driver for PostgreSQL in Tomcat6 libraries directory::
# ln -s /usr/share/java/postgresql-jdbc3.jar /usr/share/tomcat6/lib/
* Copy war to Tomcat 6 web applications directory::
# cp navalplan.war /srv/tomcat6/webapps/
* Restart Tomcat 6::
# /etc/init.d/tomcat6 restart
* Go to http://localhost:8080/navalplan/
Logs
----
Since *NavalPlan 1.1.1* log system is configured automatically creating a new
folder under ``/var/log/tomcat6/`` with ``.war`` name. For example:
``/var/log/tomcat6/navalplan.war``.
Inside this new directory there will be two files (``navalplan.log`` and
``navalplan-error.log``) that will be rotated every day.

74
NEWS
View file

@ -1,6 +1,79 @@
NEWS
====
Version 1.1.1 (07 Jun 2011)
---------------------------
First minor version for 1.1.x cycle with lots of bugfixes. The most important
ones:
* Fixed several memory leaks which will make application use less memory now.
* Improved log system configuration.
* Solved a translation issue with some strings in the Gantt view.
* Resolved some bugs moving tasks due to new dependencies.
Changes
~~~~~~~
* Updated TODO file with roadmap for 1.2 version.
* Changed OpenJDK dependency in Debian package for default-jdk or default-jre.
* [i18n] Fixed wrong translation of project in some reports.
* [i18n] Fixed uppercase/lowercases incoherences.
* [Bug #1084] Fix bug
* [Bug #789] Script for parsing ZUL files should look for 'ganttzk_i18n' tag too
* [Bug #789] Renamed 'i18n' prefix in ganttzk to 'ganttzk_i18n'
* Fix possible NPE
* Fix NPE if provided allocation is null
* [Bug #1083] Fix bug
* [Bug #1014] add borders in the table of the report of worked hours per each
resource.
* [Bug #1014] include the name of the assigned task to each report line, in the
report worked hours per each resource.
* [Bug #1014] return the date time at start of day to perform the grouping by
date correctly.
* Avoid NPE if editedValue is null
* [Bug #1013] increase the width in filter search box.
* [Bug #1086] Fix bug
* Changed test to avoid it fails if it's launched on Saturday.
* [i18n] Fixed typo in progress with all tasks.
* [i18n] Fixed typo in "criterions" using "criteria".
* [i18n] Updated Spanish and Galician translations.
* [i18n] Fixed issue in keys generator and updated keys.pot files.
* [i18n] Updated Spanish and Galician translations.
* [i18n] Fixed translation of "progress" to Galician and Spanish.
* [i18n] Marked "Choosing template" for translate.
* [i18n] Changed "order sequence" for "entity sequence"
* [i18n] Updated keys.pot files
* Fixed two translation issues.
* [Bug #1082] Fix bug
* Revert "Fix bug"
* [Bug #954] Fix bug
* Revert "[Bug #954] Handle concurrency support in Configuration window"
* The new support for parametrizing the clearing of handlers is used
* Now the clearing behaviour can be parametrized
* More aggresive discarding of sessions and desktops
* [Bug #1080] Fixed issue with Montecarlo method when critical path has more
than 10 tasks.
* [Bug #1079] Fixed lazy exception initializing parent calendar too.
* Improve toString message
* Fix bug
* [Bug #1074] check if exists indicators of the earned value for that date.
* [Bug #1076] Fixed NullPointerException going to Gantt view when project is
not scheduled.
* Reduce the time that request handlers are kept around in CallbackServlet
* Fix memory leak in TemplateController
* Refactor password not changed controller code
* Allow to GC the page before the desktop is discarded
* Don't let the thread local hang forever in the threads local map
* Fix leak
* Remove unnecessary timers.
* Reduce the live time of desktops
* Fix memory leak
* Determine the log directory dinamically
* Use asynchronous appender
* Move default log4j.properties to application
Version 1.1.0 (19 May 2011)
---------------------------
@ -1416,7 +1489,6 @@ Changes
* [Bug #809] Fixed marking to translate missing label.
* Fixed wrong e-mail on debian/changelog.
Version 1.0.1 (14 Jan 2011)
---------------------------

32
README
View file

@ -36,11 +36,39 @@ Features
Requirements
------------
Visit the following wiki page for a comprehensive list of requirements:
http://wiki.navalplan.org/twiki/bin/view/NavalPlan/InstallNavalPlan.
* *JRE 6* - Java Runtime Environment
Project depends on Java 6 and 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 6* - Servlet and JSP engine
Server to deploy the application. You could use *Jetty* instead.
* *JDBC Driver* - Java database (JDBC) driver for PostgreSQL
To connect application with *PostgreSQL* database in *Tomcat*
* *GNU FreeFont* - Freefont Serif, Sans and Mono Truetype fonts
Font family used in reports
* *CutyCapt* - Utility to capture WebKit's rendering of a web page
Required for printing
* *Xvfb* - Virtual Framebuffer 'fake' X server
Used by CutyCapt for printing
See ``INSTALL`` file for installation instructions.
See ``HACKING`` file for compilation requirements and instructions.
Availability
------------

79
TODO
View file

@ -1,65 +1,57 @@
TODO
====
Version 1.1 - 2011w14
Version 1.2 - 2011w36
---------------------
Dates
~~~~~
* *IRC coordination meeting*: 2011w2
* *Feature freeze*: 2011w11
* *Release date*: 2011w14
* *IRC coordination meeting*: 2011w26
* *Feature freeze*: 2011w31
* *Release date*: 2011w36
Features
~~~~~~~~
* Printing support improvement.
* Help improvement.
* Chromium browser complete support.
* Limiting resources. New appropriative insertion algorithm.
* Resource levelling.
* Over allocation control.
* Heuristics in general allocations.
* Allocation functions (steps, S-curve) in simple allocation pop-up and some
usability improvements.
* Support of intraday operations. Possibility to establish not integer number of
hours in allocations, task work (hours, minutes, seconds).
* Advance allocation fix.
* *Very high priority*
Small tasks
~~~~~~~~~~~
* Start to use new name LibrePlan with a new logo
* Merge and finish migration for ZK5 version
* Fix allocation model
* Dependency violation mark in Gantt chart.
* Default login auto-completion configuration.
* Entity Identification improvement in reports (e.g. inclusion of both task and
project names in *Work report lines report*)
* *High priority*
* Help improvement (documentation)
* Fix last issues on printing
* Prevent perspective change without saving
Version 1.2 - 2011w27
---------------------
* *Normal priority*
Dates
~~~~~
* Fix issues in templates when using related entities like criteria,
progresses, ...
* Translation issues (common problems and specific issues with Galician)
* LDAP integration
* *IRC coordination meeting*: 2011w15
* *Feature freeze*: 2011w24
* *Release date*: 2011w27
* *Low priority*
Features
~~~~~~~~
* New feature for simple users. Users would be related to application
resources, and would be able to specify hours, progresses, ... on their
assigned tasks
* Improve subcontractor system
* Resource load view performance improvement.
* Gantt window performance improvement.
* Dependency type ``START-TO-FINISH``.
* Dependencies with lag.
* Periodic allocation schemes.
* Earned value improvements.
* Critical chain project management critical chain paradigm in project planning.
* Interface to resolve allocation conflicts.
* Add export/import operations for different format files from other projects
like OpenProj, MicrosoftProject, ...
* Documentation attachment.
* *Minor tasks*
* Default login auto-completion configuration
* Permissions enhancements
* Show information about current entity being edited
* Improvements on work reports: allow specify minutes, add button to copy
work report line
* Add an operation to reassign a single task
* Web services: Add method to export only one entity by code
* Report: Add a new report which allows to check progress by task in a
project (tasks could be filtered by criteria, labels, ...)
* Save language per user in user configuration
Future
@ -71,8 +63,7 @@ Future
* New features in Gantt window.
* Complex features disabled by default.
* Quick start wizard.
* Integration services scripts that don't depend on Ruby (maybe directly with
Java).
* Integration services scripts directly with Java.
* ZK 5 migration.
* Permission enhancements.
* *Exit without saving* detection.

112
UPDATE Normal file
View file

@ -0,0 +1,112 @@
Update
======
This is a guide about how to upgrade *NavalPlan* when a new version is released.
If you want to know how to install the application ``INSTALL`` file.
.. contents::
NavalPlan automatic update
--------------------------
Ubuntu PPAs
~~~~~~~~~~~
Instructions::
$ sudo apt-get update
$ sudo apt-get install navalplan
Debian packages
~~~~~~~~~~~~~~~
Instructions:
* Download the new package::
$ wget http://downloads.sourceforge.net/project/navalplan/NavalPlan/navalplan_1.1.1-1_amd64.deb
* Install package::
# dpkg -i navalplan_1.1.1-1_amd64.deb
* Install new dependencies if needed::
# apt-get install -f
NavalPlan manual update
-----------------------
Debian/Ubuntu
~~~~~~~~~~~~~
* Stop Tomcat::
# /etc/init.d/tomcat6 stop
* Download database upgrade scripts from previous version. For example, if you
are upgrading from *NavalPlan 1.0.4* to *NavalPlan 1.1.1* you should download
``upgrade_1.1.0.sql``::
$ wget http://downloads.sourceforge.net/project/navalplan/NavalPlan/upgrade_1.1.0.sql
* Upgrade database::
$ psql -h localhost -U navalplan -W navalplan < upgrade_1.1.0.sql
* Download ``.war`` file of new version from SourceForge.net::
$ wget -O navalplan.war http://downloads.sourceforge.net/project/navalplan/NavalPlan/navalplan_1.1.1.war
* Backup current deployed application::
# mv /var/lib/tomcat6/webapps/navalplan/ /tmp/
* Copy war to Tomcat 6 web applications directory::
# cp navalplan.war /var/lib/tomcat6/webapps/
* Start Tomcat 6::
# /etc/init.d/tomcat6 start
* Go to http://localhost:8080/navalplan/
openSUSE
~~~~~~~~
* Stop Tomcat::
# /etc/init.d/tomcat6 stop
* Download database upgrade scripts from previous version. For example, if you
are upgrading from *NavalPlan 1.0.4* to *NavalPlan 1.1.1* you should download
``upgrade_1.1.0.sql``::
$ wget http://downloads.sourceforge.net/project/navalplan/NavalPlan/upgrade_1.1.0.sql
* Upgrade database::
$ psql -h localhost -U navalplan -W navalplan < upgrade_1.1.0.sql
* Download ``.war`` file of new version from SourceForge.net::
$ wget -O navalplan.war http://downloads.sourceforge.net/project/navalplan/NavalPlan/navalplan_1.1.1.war
* Backup current deployed application::
# mv /srv/tomcat6/webapps/navalplan/ /tmp/
* Copy war to Tomcat 6 web applications directory::
# cp navalplan.war /srv/tomcat6/webapps/
* Start Tomcat 6::
# /etc/init.d/tomcat6 start
* Go to http://localhost:8080/navalplan/

View file

@ -1,3 +1,9 @@
cutycapt (20110107-2) lenny lucid maverick; urgency=low
* Changing command to use "cutycapt" instead of "CutyCapt".
-- Manuel Rego Casasnovas <mrego@igalia.com> Fri, 06 Jun 2011 19:34:22 +0200
cutycapt (20110107-1) lenny squeeze intrepid karmic lucid maverick; urgency=low
* Updated to NavalPlan package naming.

View file

@ -7,4 +7,4 @@
override_dh_auto_install:
install -g root -o root -m 755 -d $(CURDIR)/debian/cutycapt/usr/bin
install -g root -o root -m 755 CutyCapt $(CURDIR)/debian/cutycapt/usr/bin
install -g root -o root -m 755 CutyCapt $(CURDIR)/debian/cutycapt/usr/bin/cutycapt

8
debian/changelog vendored
View file

@ -1,3 +1,11 @@
navalplan (1.1.1-1) maverick; urgency=low
* Changed dependency from OpenJDK to default-jdk or default-jre.
* Added bugs fixed from stable branch.
* Released version 1.1.1.
-- Manuel Rego Casasnovas <rego@igalia.com> Wed, 07 Jun 2011 09:15:00 +0200
navalplan (1.1.0-1) maverick; urgency=low
* Removed unnecessary dependency with texlive-latex-recommended and pgf

4
debian/control vendored
View file

@ -3,14 +3,14 @@ Section: web
Priority: optional
Maintainer: Adrian Perez <aperez@igalia.com>
Build-Depends: debhelper (>= 7.0.50), maven2, python-docutils,
gettext (>= 0.17), openjdk-6-jdk
gettext (>= 0.17), default-jdk
Standards-Version: 3.8.4
Homepage: http://www.navalplan.org/en/
Package: navalplan
Architecture: any
Depends: cutycapt, postgresql, postgresql-client, xvfb, dbconfig-common, ucf,
tomcat6, openjdk-6-jre-headless | openjdk-6-jre, libpg-java, ttf-freefont,
tomcat6, default-jre-headless | default-jre, libpg-java, ttf-freefont,
${misc:Depends}
Description: Web application for project management.
NavalPlan is a planning tool for users based on some concepts: company and

23
debian/control.lucid vendored Normal file
View file

@ -0,0 +1,23 @@
Source: navalplan
Section: web
Priority: optional
Maintainer: Adrian Perez <aperez@igalia.com>
Build-Depends: debhelper (>= 7.0.50), maven2, python-docutils,
gettext (>= 0.17), texlive-latex-recommended, pgf, openjdk-6-jdk
Standards-Version: 3.8.4
Homepage: http://www.navalplan.org/en/
Package: navalplan
Architecture: any
Depends: cutycapt, postgresql, postgresql-client, xvfb, dbconfig-common, ucf,
tomcat6, openjdk-6-jre-headless | openjdk-6-jre, libpg-java, ttf-freefont,
${misc:Depends}
Description: Web application for project management.
NavalPlan is a planning tool for users based on some concepts: company and
multi-project overview, criteria assignments, tasks tagging, resources
management, resource allocation (specific and generic), company load control,
external integration, etc.
.
Although its name is clearly related to shipbuilding, NavalPlan is a fully
useful planning tool for any type of company whose workflow requires project
and order administration and scheduling.

23
debian/control.squeeze vendored Normal file
View file

@ -0,0 +1,23 @@
Source: navalplan
Section: web
Priority: optional
Maintainer: Adrian Perez <aperez@igalia.com>
Build-Depends: debhelper (>= 7.0.50), maven2, python-docutils,
gettext (>= 0.17), texlive-latex-recommended, pgf, openjdk-6-jdk
Standards-Version: 3.8.4
Homepage: http://www.navalplan.org/en/
Package: navalplan
Architecture: any
Depends: cutycapt, postgresql, postgresql-client, xvfb, dbconfig-common, ucf,
tomcat6, openjdk-6-jre-headless | openjdk-6-jre, libpg-java, ttf-freefont,
${misc:Depends}
Description: Web application for project management.
NavalPlan is a planning tool for users based on some concepts: company and
multi-project overview, criteria assignments, tasks tagging, resources
management, resource allocation (specific and generic), company load control,
external integration, etc.
.
Although its name is clearly related to shipbuilding, NavalPlan is a fully
useful planning tool for any type of company whose workflow requires project
and order administration and scheduling.

View file

@ -709,9 +709,6 @@ Steps:
@Override
protected JRDataSource getDataSource() {
return new JRBeanCollectionDataSource(resourcesListReportModel
.getResourcesListReportDTOs());
List<ResourcesListReportDTO> dtos = resourcesListReportModel
.getResourcesListReportDTOs();
if (dtos.isEmpty()) {

View file

@ -1,6 +1,6 @@
---------------------------------------
How To Develop An Use Case In NavalPlan
---------------------------------------
--------------------------------------
How To Develop A Use Case In NavalPlan
--------------------------------------
.. sectnum::
@ -12,7 +12,7 @@ How To Develop An Use Case In NavalPlan
Commons Attribution-ShareAlike 3.0 licence, available in
http://creativecommons.org/licenses/by-sa/3.0/.
:Abstract:
This is a guide about how to develop an use case in NavalPlan_. Following the
This is a guide about how to develop a use case in NavalPlan_. Following the
different sections of this document you will end up developing a complete
CRUD_ (create, read, update and delete) use case in the project.
@ -415,6 +415,17 @@ Then you will have the following files:
always use these interface classes. Spring framework instantiates a class for
each interface type and injects it in the corresponding variable.
.. NOTE::
As you can see DAO class is being defined as a singleton with the following
line::
@Scope(BeanDefinition.SCOPE_SINGLETON)
This is because of DAO classes are not going to store any state variable, so
methods only depends on parameters. Thus, just an instance of a DAO class is
enough for any place where it is used.
Summarizing, persistence layer encapsulates all operations related to Hibernate
communication for retrieving, querying and storing entities on database.
Therefore, you will not need to use Hibernate API directly in NavalPlan source
@ -1228,6 +1239,15 @@ in order to use model from controller (which is not inside Spring context). This
is why ``@Autowired`` is not needed, but on the other hand you need to use a
specific name for variable.
.. NOTE::
Model classes are defined with prototype scope::
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
The reason is that models are going to keep conversation state in a variable,
so in that case new instance are going to be needed every time model is used.
Developing the conversation
---------------------------
@ -2341,7 +2361,7 @@ following content::
Now you are ready to test your web service. If you go to this URL
http://localhost:8080/navalplanner-webapp/ws/rest/stretchesfunctiontemplates/,
and login with an user that has permission to access web services (e.g. user
and login with a user that has permission to access web services (e.g. user
``wsreader`` with password ``wsreader``) you will get a XML with the list of
``StretchesFunctionTemplate`` stored in the application.
@ -2367,37 +2387,21 @@ created in project repository inside ``scripts/rest-clients`` directory.
.. NOTE::
Currently these scripts depends on Tidy and Ruby to be installed in your
system. You could install them in a Debian based distribution with the
following command as root::
Currently these scripts recommends Tidy to be installed in your system
for a better output. You could install them in a Debian based distribution
with the following command as root::
apt-get install tidy ruby
apt-get install tidy
Then for this example you will create a script called
``export-stretches-function-templates.sh``, that will be very similar to the
rest of export scripts just changing web service path::
#!/bin/sh
#!/bin/sh
. ./rest-common-env.sh
. ./rest-common-env.sh
printf "Login name: "
read loginName
printf "Password: "
read password
if [ "$1" = "--prod" ]; then
baseServiceURL=$PRODUCTION_BASE_SERVICE_URL
certificate=$PRODUCTION_CERTIFICATE
else
baseServiceURL=$DEVELOPMENT_BASE_SERVICE_URL
certificate=$DEVELOPMENT_CERTIFICATE
fi
authorization=`./base64.sh $loginName:$password`
curl -sv -X GET $certificate --header "Authorization: Basic $authorization" \
$baseServiceURL/stretchesfunctiontemplates | tidy -xml -i -q -utf8
. ./export.sh stretchesfunctiontemplates $*
Script will request user and password in order to access to web service, so you
could use ``wsreader`` user to check that it works properly.

View file

@ -142,7 +142,7 @@ consta el ejercicio para realizar la subcontratación son los siguientes:
* Crear una nueva tarea en el proyecto denominada *Subcontratación pruebas*.
La tarea consistirá en 100h de pruebas.
* Crear una dependencia *FIN-COMIENZO* desde la tarea de *Modulo de facturas*
* Crear una dependencia *FIN-INICIO* desde la tarea de *Modulo de facturas*
como origen hacia la tarea.
* Realizar la subcontratación con los siguientes datos:
* Empresa a la que se subcontrata: Empresa subcontratada.
@ -193,9 +193,9 @@ Crear un nuevo proyecto de planificación con los siguientes datos:
* Acceder a la planificación del proyecto:
* Establecer dependencia entre tarea 3 y tarea 4 de tipo Inicio-Fin.
* Establecer dependencia entre tarea 2 y tarea 3 de tipo Inicio-Fin.
* Establecer dependencia entre tarea 1 y tarea 2 de tipo Inicio-Fin.
* Establecer dependencia entre tarea 3 y tarea 4 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarea 2 y tarea 3 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarea 1 y tarea 2 de tipo *FIN-INICIO*.
* ¿Cómo se van colocando las tareas? ___________________________________________
* Realizar las siguientes asignaciones de recursos:

View file

@ -120,9 +120,9 @@ Acceder ós datos xerais do pedido e modificar o modo de planificación a "Atrá
Acceder á planificación do proxecto:
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo *FIN-INICIO*.
¿Como se van colocando as tarefas?

View file

@ -120,9 +120,9 @@ Acceder ós datos xerais do pedido e modificar o modo de planificación a "Atrá
Acceder á planificación do proxecto:
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo *FIN-INICIO*.
¿Como se van colocando as tarefas?

View file

@ -120,9 +120,9 @@ Acceder ós datos xerais do pedido e modificar o modo de planificación a "Atrá
Acceder á planificación do proxecto:
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo *FIN-INICIO*.
¿Como se van colocando as tarefas?

View file

@ -120,9 +120,9 @@ Acceder ós datos xerais do pedido e modificar o modo de planificación a "Atrá
Acceder á planificación do proxecto:
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo *FIN-INICIO*.
¿Como se van colocando as tarefas?

View file

@ -120,9 +120,9 @@ Acceder ós datos xerais do pedido e modificar o modo de planificación a "Atrá
Acceder á planificación do proxecto:
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo Inicio-Fin.
* Establecer dependencia entre tarefa 3 e tarefa 4 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 2 e tarefa 3 de tipo *FIN-INICIO*.
* Establecer dependencia entre tarefa 1 e tarefa 2 de tipo *FIN-INICIO*.
¿Como se van colocando as tarefas?

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.navalplanner</groupId>
<artifactId>navalplanner</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</parent>
<artifactId>ganttzk</artifactId>
<packaging>jar</packaging>
@ -31,6 +31,21 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>default</id>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

View file

@ -65,7 +65,7 @@ class CommandContextualized<T> {
result.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
doAction();
}
});

View file

@ -24,6 +24,7 @@ package org.zkoss.ganttz;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import org.apache.commons.lang.Validate;
import org.zkoss.ganttz.data.Dependency;
@ -35,6 +36,7 @@ import org.zkoss.ganttz.data.constraint.Constraint.IConstraintViolationListener;
import org.zkoss.ganttz.util.WeakReferencedListeners.Mode;
import org.zkoss.zk.au.out.AuInvoke;
import org.zkoss.zk.ui.ext.AfterCompose;
import org.zkoss.zk.ui.sys.ContentRenderer;
import org.zkoss.zul.impl.XulElement;
/**
@ -95,8 +97,13 @@ public class DependencyComponent extends XulElement implements AfterCompose {
return violated ? "violated-dependency" : "dependency";
}
private boolean listenerAdded = false;
@Override
public void afterCompose() {
if (listenerAdded) {
return;
}
PropertyChangeListener listener = new PropertyChangeListener() {
@Override
@ -106,6 +113,7 @@ public class DependencyComponent extends XulElement implements AfterCompose {
};
this.source.getTask().addFundamentalPropertiesChangeListener(listener);
this.destination.getTask().addFundamentalPropertiesChangeListener(listener);
listenerAdded = true;
}
/**
@ -140,7 +148,7 @@ public class DependencyComponent extends XulElement implements AfterCompose {
}
public void redrawDependency() {
response("zoomChanged", new AuInvoke(this, "draw"));
response("redrawDependency" + getId(), new AuInvoke(this, "draw"));
}
public boolean contains(Task task) {
@ -172,6 +180,14 @@ public class DependencyComponent extends XulElement implements AfterCompose {
&& destinationTask.equals(dependency.getDestination());
}
protected void renderProperties(ContentRenderer renderer) throws IOException{
super.renderProperties(renderer);
render(renderer, "_idTaskOrig", getIdTaskOrig());
render(renderer, "_idTaskEnd", getIdTaskEnd());
render(renderer, "_dependencyType", getDependencyType());
}
public boolean hasLimitingTasks() {
return (source.isLimiting() || destination.isLimiting());
}

View file

@ -25,7 +25,6 @@ import static org.zkoss.ganttz.i18n.I18nHelper._;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
@ -105,6 +104,7 @@ public class DependencyList extends XulElement implements AfterCompose {
void toggleDependencyExistence(boolean visible) {
if (visible) {
appendChild(dependencyComponent);
dependencyComponent.afterCompose();
addContextMenu(dependencyComponent);
} else {
removeChild(dependencyComponent);
@ -265,24 +265,6 @@ public class DependencyList extends XulElement implements AfterCompose {
return getGanttPanel().getTimeTrackerComponent();
}
public void redrawDependenciesConnectedTo(TaskComponent taskComponent) {
redrawDependencyComponents(getDependencyComponentsConnectedTo(taskComponent));
}
private List<DependencyComponent> getDependencyComponentsConnectedTo(
TaskComponent taskComponent) {
ArrayList<DependencyComponent> result = new ArrayList<DependencyComponent>();
List<DependencyComponent> dependencies = getDependencyComponents();
for (DependencyComponent dependencyComponent : dependencies) {
if (dependencyComponent.getSource().equals(taskComponent)
|| dependencyComponent.getDestination().equals(
taskComponent)) {
result.add(dependencyComponent);
}
}
return result;
}
public void redrawDependencies() {
redrawDependencyComponents(getDependencyComponents());
}

View file

@ -511,7 +511,7 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
Button printButton = (Button) printProperties.getFellow("printButton");
printButton.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
printProperties.detach();
configuration.print(buildParameters(printProperties),planner);
}

View file

@ -28,6 +28,7 @@ import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
import org.zkoss.ganttz.data.GanttDiagramGraph;
import org.zkoss.ganttz.timetracker.TimeTracker;
import org.zkoss.ganttz.timetracker.TimeTrackerComponent;
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.Interval;
import org.zkoss.zk.au.out.AuInvoke;
@ -46,6 +47,8 @@ public class GanttPanel extends XulElement implements AfterCompose {
private final Planner planner;
private transient IZoomLevelChangedListener zoomLevelChangedListener;
private LocalDate previousStart;
private Interval previousInterval;
@ -84,6 +87,7 @@ public class GanttPanel extends XulElement implements AfterCompose {
moveCurrentPositionScroll();
}
// FIXME: this is quite awful, it should be simple
@Override
protected void moveCurrentPositionScroll() {
// get the previous data.
@ -129,6 +133,7 @@ public class GanttPanel extends XulElement implements AfterCompose {
planner.getPredicate().setFilterContainers(true);
planner.setTaskListPredicate(planner.getPredicate());
}
registerZoomLevelChangedListener();
}
public TimeTrackerComponent getTimeTrackerComponent() {
@ -163,10 +168,10 @@ public class GanttPanel extends XulElement implements AfterCompose {
return timeTrackerComponent.getTimeTracker();
}
public void setZoomLevel(ZoomLevel zoomLevel) {
public void setZoomLevel(ZoomLevel zoomLevel, int scrollLeft) {
savePreviousData();
getTimeTrackerComponent().updateDayScroll();
getTimeTracker().setZoomLevel(zoomLevel);
getTimeTrackerComponent().setZoomLevel(zoomLevel, scrollLeft);
}
private void savePreviousData() {
@ -178,6 +183,22 @@ public class GanttPanel extends XulElement implements AfterCompose {
return planner;
}
private void registerZoomLevelChangedListener() {
if (zoomLevelChangedListener == null) {
zoomLevelChangedListener = new IZoomLevelChangedListener() {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
adjustZoomColumnsHeight();
}
};
getTimeTracker().addZoomListener(zoomLevelChangedListener);
}
}
public void adjustZoomColumnsHeight() {
response("adjust_height", new AuInvoke(this, "adjust_height"));
}
public LocalDate getPreviousStart() {
return previousStart;
}

View file

@ -107,7 +107,7 @@ public class LeftTasksTree extends HtmlMacroComponent {
Treeitem item) {
item.addEventListener("onOpen", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
OpenEvent openEvent = (OpenEvent) event;
taskBean.setExpanded(openEvent.isOpen());
}
@ -120,7 +120,8 @@ public class LeftTasksTree extends HtmlMacroComponent {
return task.isLeaf() || task.isExpanded();
}
private final class DetailsForBeans {
private static final class DetailsForBeans {
private Map<Task, LeftTasksTreeRow> map = new HashMap<Task, LeftTasksTreeRow>();
private Set<Task> focusRequested = new HashSet<Task>();

View file

@ -316,7 +316,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
textBox.addEventListener("onCtrlKey", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
userWantsToMove(textBox, (KeyEvent) event);
}
});
@ -326,7 +326,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
component.addEventListener("onChange", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
updateBean(component);
}
});
@ -336,7 +336,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
textBox.addEventListener("onOK", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
userWantsDateBox(textBox);
}
});
@ -346,7 +346,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
datebox.addEventListener("onOK", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
datebox.setOpen(true);
}
});
@ -375,7 +375,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
datebox.addEventListener("onBlur", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
dateBoxHasLostFocus(datebox);
}
});

View file

@ -55,34 +55,27 @@ import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
import org.zkoss.ganttz.util.OnZKDesktopRegistry;
import org.zkoss.ganttz.util.WeakReferencedListeners;
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
import org.zkoss.ganttz.util.script.IScriptsRegister;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.au.AuService;
import org.zkoss.zk.mesg.MZk;
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.zkex.zul.api.South;
import org.zkoss.zul.Button;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Separator;
import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.South;
public class Planner extends HtmlMacroComponent {
public static void registerNeededScripts() {
IScriptsRegister register = getScriptsRegister();
register.register(ScriptsRequiredByPlanner.class);
}
private static IScriptsRegister getScriptsRegister() {
return OnZKDesktopRegistry.getLocatorFor(IScriptsRegister.class)
.retrieve();
}
public static boolean guessContainersExpandedByDefaultGivenPrintParameters(
Map<String, String> printParameters) {
return guessContainersExpandedByDefault(convertToURLParameters(printParameters));
@ -174,7 +167,6 @@ public class Planner extends HtmlMacroComponent {
.create();
public Planner() {
registerNeededScripts();
}
TaskList getTaskList() {
@ -265,13 +257,13 @@ public class Planner extends HtmlMacroComponent {
return new SimpleListModel(selectableZoomlevels);
}
public void setZoomLevel(final ZoomLevel zoomLevel) {
public void setZoomLevel(final ZoomLevel zoomLevel, int scrollLeft) {
if (ganttPanel == null) {
return;
}
this.fixedZoomByUser = true;
initialZoomLevel = zoomLevel;
ganttPanel.setZoomLevel(zoomLevel);
ganttPanel.setZoomLevel(zoomLevel, scrollLeft);
}
public void zoomIncrease() {
@ -286,7 +278,7 @@ public class Planner extends HtmlMacroComponent {
}
@Override
public void doAction() throws Exception {
public void doAction() {
ganttPanel.zoomIncrease();
}
});
@ -303,7 +295,7 @@ public class Planner extends HtmlMacroComponent {
}
@Override
public void doAction() throws Exception {
public void doAction() {
ganttPanel.zoomDecrease();
}
});
@ -373,6 +365,35 @@ public class Planner extends HtmlMacroComponent {
this.visibleChart = configuration.isExpandPlanningViewCharts();
((South) getFellow("graphics")).setOpen(this.visibleChart);
setAuService(new AuService(){
public boolean service(AuRequest request, boolean everError){
String command = request.getCommand();
String[] requestData;
int zoomindex;
int scrollLeft;
if (command.equals("onZoomLevelChange")){
zoomindex= (Integer) retrieveData(request, "zoomindex");
scrollLeft = (Integer) retrieveData(request, "scrollLeft");
setZoomLevel((ZoomLevel)((Listbox)getFellow("listZoomLevels"))
.getModel().getElementAt(zoomindex),
scrollLeft);
return true;
}
return false;
}
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 });
return value;
}
});
}
private void resettingPreviousComponentsToNull() {
@ -484,7 +505,7 @@ public class Planner extends HtmlMacroComponent {
getDependencyList().taskRemoved(task);
leftPane.taskRemoved(task);
setHeight(getHeight());// forcing smart update
taskList.adjustZoomColumnsHeight();
ganttPanel.adjustZoomColumnsHeight();
getDependencyList().redrawDependencies();
}
@ -497,7 +518,7 @@ public class Planner extends HtmlMacroComponent {
westContainer.addEventListener(Events.ON_SIZE, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
Clients.evalJavaScript("zkTaskContainer.legendResize();");
}
@ -605,10 +626,10 @@ public class Planner extends HtmlMacroComponent {
public void showAllLabels() {
Button showAllLabelsButton = (Button) getFellow("showAllLabels");
if (isShowingLabels) {
Clients.evalJavaScript("zkTasklist.hideAllTooltips();");
Clients.evalJavaScript("ganttz.TaskList.getInstance().hideAllTaskLabels()");
showAllLabelsButton.setSclass("planner-command show-labels");
} else {
Clients.evalJavaScript("zkTasklist.showAllTooltips();");
Clients.evalJavaScript("ganttz.TaskList.getInstance().showAllTaskLabels()");
showAllLabelsButton
.setSclass("planner-command show-labels clicked");
}
@ -618,10 +639,10 @@ public class Planner extends HtmlMacroComponent {
public void showAllResources() {
Button showAllLabelsButton = (Button) getFellow("showAllResources");
if (isShowingResources) {
Clients.evalJavaScript("zkTasklist.hideResourceTooltips();");
Clients.evalJavaScript("ganttz.TaskList.getInstance().hideResourceTooltips()");
showAllLabelsButton.setSclass("planner-command show-resources");
} else {
Clients.evalJavaScript("zkTasklist.showResourceTooltips();");
Clients.evalJavaScript("ganttz.TaskList.getInstance().showResourceTooltips()");
showAllLabelsButton
.setSclass("planner-command show-resources clicked");
}
@ -820,6 +841,10 @@ public class Planner extends HtmlMacroComponent {
return null;
}
public String getWidgetClass(){
return getDefinition().getDefaultWidgetClass();
}
public List getCriticalPath() {
return context.getCriticalPath();
}

View file

@ -1,43 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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;
import org.zkoss.ganttz.util.script.ScriptsRequiredDeclaration;
@ScriptsRequiredDeclaration(dependsOn = { YUIMin.class, ScrollSyncScript.class })
public class ScriptsRequiredByPlanner {
private ScriptsRequiredByPlanner() {
}
public static final String SELECTOR = "/zkau/web/js/yui/2.7.0/selector/selector-min.js";
public static final String YAHOO_DOM_EVENT = "/zkau/web/js/yui/2.7.0/yahoo-dom-event/yahoo-dom-event.js";
public static final String DRAGDROPMIN = "/zkau/web/js/yui/2.7.0/dragdrop/dragdrop-min.js";
public static final String ELEMENT_MIN = "/zkau/web/js/yui/2.7.0/element/element-min.js";
public static final String RESIZE_MIN = "/zkau/web/js/yui/2.7.0/resize/resize-min.js";
public static final String LOGGER_MIN = "/zkau/web/js/yui/2.7.0/logger/logger-min.js";
// adding manually js associated to components since they can be used by
// other files with no dependencies being present
public static final String DEPENDENCY_LIST = "/zkau/web/js/ganttz/dependencylist.js";
public static final String DEPENDENCY = "/zkau/web/js/ganttz/dependency.js";
}

View file

@ -1,36 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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;
import org.zkoss.ganttz.util.script.ScriptsRequiredDeclaration;
@ScriptsRequiredDeclaration(dependsOn = YUIMin.class)
public class ScrollSyncScript {
private ScrollSyncScript() {
}
public static final String SCROLL_SYNC = "/zkau/web/js/ganttz/scrollSync.js";
public static final String YAHOO_DOM_EVENT = "/zkau/web/js/yui/2.7.0/yahoo-dom-event/yahoo-dom-event.js";
}

View file

@ -117,7 +117,7 @@ public class TabsRegistry {
new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
if (_("Limiting resources").equals(t.getName())) {
Executions.sendRedirect("/planner/index.zul;limiting_resources");
} else {

View file

@ -23,10 +23,9 @@ package org.zkoss.ganttz;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
@ -43,10 +42,8 @@ import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.data.constraint.Constraint.IConstraintViolationListener;
import org.zkoss.ganttz.util.WeakReferencedListeners.Mode;
import org.zkoss.lang.Objects;
import org.zkoss.xml.HTMLs;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.au.Command;
import org.zkoss.zk.au.ComponentCommand;
import org.zkoss.zk.au.AuService;
import org.zkoss.zk.au.out.AuInvoke;
import org.zkoss.zk.mesg.MZk;
import org.zkoss.zk.ui.Component;
@ -54,6 +51,7 @@ import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.ext.AfterCompose;
import org.zkoss.zk.ui.sys.ContentRenderer;
import org.zkoss.zul.Div;
/**
@ -70,94 +68,6 @@ public class TaskComponent extends Div implements AfterCompose {
private static final int HALF_DEADLINE_MARK = 3;
private static Pattern pixelsSpecificationPattern = Pattern
.compile("\\s*(\\d+)px\\s*;?\\s*");
private static int stripPx(String pixels) {
Matcher matcher = pixelsSpecificationPattern.matcher(pixels);
if (!matcher.matches()) {
throw new IllegalArgumentException("pixels " + pixels
+ " is not valid. It must be "
+ pixelsSpecificationPattern.pattern());
}
return Integer.valueOf(matcher.group(1));
}
private static Command _updatecmd = new ComponentCommand(
"onUpdatePosition", 0) {
protected void process(AuRequest request) {
final TaskComponent ta = (TaskComponent) request.getComponent();
if (ta == null) {
throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED,
this);
}
String[] requestData = request.getData();
if (requestData == null || requestData.length != 2) {
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA,
new Object[] { Objects.toString(requestData), this });
} else {
ta.doUpdatePosition(requestData[0], requestData[1]);
Events.postEvent(new Event(getId(), ta, request.getData()));
}
}
};
private static Command _updatewidthcmd = new ComponentCommand(
"onUpdateWidth", 0) {
protected void process(AuRequest request) {
final TaskComponent ta = (TaskComponent) request.getComponent();
if (ta == null) {
throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED,
this);
}
String[] requestData = request.getData();
if (requestData == null || requestData.length != 1) {
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA,
new Object[] { Objects.toString(requestData), this });
} else {
ta.doUpdateSize(requestData[0]);
Events.postEvent(new Event(getId(), ta, request.getData()));
}
}
};
private static Command _adddependencycmd = new ComponentCommand(
"onAddDependency", 0) {
protected void process(AuRequest request) {
final TaskComponent taskComponent = (TaskComponent) request.getComponent();
if (taskComponent == null) {
throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED,
this);
}
String[] requestData = request.getData();
if (requestData == null || requestData.length != 1) {
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA,
new Object[] { Objects.toString(requestData), this });
} else {
taskComponent.doAddDependency(requestData[0]);
Events.postEvent(new Event(getId(), taskComponent, request.getData()));
}
}
};
protected final IDisabilityConfiguration disabilityConfiguration;
private PropertyChangeListener criticalPathPropertyListener;
@ -195,7 +105,6 @@ public class TaskComponent extends Div implements AfterCompose {
setContext("idContextMenuTaskAssignment");
this.task = task;
setClass(calculateCSSClass());
setId(UUID.randomUUID().toString());
this.disabilityConfiguration = disabilityConfiguration;
taskViolationListener = Constraint
@ -234,6 +143,64 @@ public class TaskComponent extends Div implements AfterCompose {
};
this.task.addReloadListener(reloadResourcesTextRequested);
setAuService(new AuService(){
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")),
toInteger(retrieveData(request, "top")));
Events.postEvent(new Event(getId(), ta, request.getData()));
return true;
}
if (command.equals("onUpdateWidth")){
ta = retrieveTaskComponent(request);
ta.doUpdateSize(toInteger(retrieveData(request, "width")));
Events.postEvent(new Event(getId(), ta, request.getData()));
return true;
}
if (command.equals("onAddDependency")){
ta = retrieveTaskComponent(request);
ta.doAddDependency((String) retrieveData(request, "dependencyId"));
Events.postEvent(new Event(getId(), ta, request.getData()));
return true;
}
return false;
}
private int toInteger(Object valueFromRequestData) {
return ((Number) valueFromRequestData).intValue();
}
private TaskComponent retrieveTaskComponent(AuRequest request){
final TaskComponent ta = (TaskComponent) request.getComponent();
if (ta == null) {
throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED,
this);
}
return ta;
}
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 });
return value;
}
});
}
/* Generate CSS class attribute depending on task properties */
@ -261,8 +228,7 @@ public class TaskComponent extends Div implements AfterCompose {
}
protected void updateClass() {
response(null, new AuInvoke(this, "setClass",
new Object[] { calculateCSSClass() }));
setSclass(calculateCSSClass());
}
public final void afterCompose() {
@ -369,20 +335,6 @@ public class TaskComponent extends Div implements AfterCompose {
return null;
}
public Command getCommand(String cmdId) {
Command result = null;
if ("updatePosition".equals(cmdId)
&& isMovingTasksEnabled()) {
result = _updatecmd;
} else if ("updateSize".equals(cmdId)
&& isResizingTasksEnabled()) {
result = _updatewidthcmd;
} else if ("addDependency".equals(cmdId)) {
result = _adddependencycmd;
}
return result;
}
public boolean isResizingTasksEnabled() {
return (disabilityConfiguration != null)
&& disabilityConfiguration.isResizingTasksEnabled()
@ -395,9 +347,10 @@ public class TaskComponent extends Div implements AfterCompose {
&& task.canBeExplicitlyMoved();
}
void doUpdatePosition(String leftX, String topY) {
void doUpdatePosition(int leftX, int topY) {
GanttDate startBeforeMoving = this.task.getBeginDate();
LocalDate newPosition = getMapper().toDate(stripPx(leftX));
LocalDate newPosition = getMapper().toDate(leftX);
this.task.moveTo(GanttDate.createFrom(newPosition));
boolean remainsInOriginalPosition = this.task.getBeginDate().equals(
startBeforeMoving);
@ -406,11 +359,10 @@ public class TaskComponent extends Div implements AfterCompose {
}
}
void doUpdateSize(String size) {
int pixels = stripPx(size);
void doUpdateSize(int size) {
DateTime end = new DateTime(this.task.getBeginDate()
.toDayRoundedDate().getTime()).plus(getMapper().toDuration(
pixels));
size));
this.task.resizeTo(end.toLocalDate());
updateProperties();
}
@ -436,20 +388,26 @@ public class TaskComponent extends Div implements AfterCompose {
}
/*
* We override the method of getRealStyle to put the color property as part
* 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());
protected String getRealStyle() {
setWidgetAttribute("movingTasksEnabled",((Boolean)isMovingTasksEnabled()).toString());
setWidgetAttribute("resizingTasksEnabled", ((Boolean)isResizingTasksEnabled()).toString());
final StringBuffer sb = new StringBuffer(super.getRealStyle());
/*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");
if (getColor() != null) {
HTMLs.appendStyle(sb, "background-color", getColor());
}
HTMLs.appendStyle(sb, "position", "absolute");
render(renderer, "_labelsText", getLabelsText());
render(renderer, "_resourcesText", getResourcesText());
render(renderer, "_tooltipText", getTooltipText());
return sb.toString();
super.renderProperties(renderer);
}
/*
@ -487,10 +445,6 @@ public class TaskComponent extends Div implements AfterCompose {
setLeft(this.task.getBeginDate().toPixels(getMapper()) + "px");
updateWidth();
smartUpdate("name", this.task.getName());
DependencyList dependencyList = getDependencyList();
if (dependencyList != null) {
dependencyList.redrawDependenciesConnectedTo(this);
}
updateDeadline();
updateCompletionIfPossible();
updateClass();

View file

@ -93,7 +93,7 @@ public class TaskEditFormComposer extends GenericForwardComposer {
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
public class TaskDTO {
public static class TaskDTO {
public String name;
public Date beginDate;
public Date endDate;

View file

@ -49,7 +49,6 @@ 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.au.out.AuInvoke;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.ext.AfterCompose;
@ -144,7 +143,7 @@ public class TaskList extends XulElement implements AfterCompose {
taskComponent.afterCompose();
if (relocate) {
setHeight(getHeight());// forcing smart update
adjustZoomColumnsHeight();
getGanttPanel().adjustZoomColumnsHeight();
getGanttPanel().getDependencyList().redrawDependencies();
}
}
@ -180,24 +179,14 @@ public class TaskList extends XulElement implements AfterCompose {
taskComponent.addEventListener("onDoubleClick", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
doubleClickCommand.doAction(taskComponent);
}
});
}
private void addContextMenu(final TaskComponent taskComponent) {
taskComponent.addEventListener("onRightClick", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
try {
getContextMenuFor(taskComponent).open(taskComponent);
} catch (Exception e) {
e.printStackTrace();
}
}
});
taskComponent.setContext(getContextMenuFor(taskComponent));
}
@Override
@ -295,7 +284,6 @@ public class TaskList extends XulElement implements AfterCompose {
for (TaskComponent taskComponent : getTaskComponents()) {
taskComponent.zoomChanged();
}
adjustZoomColumnsHeight();
adjustZoomPositionScroll();
}
};
@ -344,10 +332,6 @@ public class TaskList extends XulElement implements AfterCompose {
return (GanttPanel) getParent();
}
public void adjustZoomColumnsHeight() {
response("adjust_height", new AuInvoke(TaskList.this, "adjust_height"));
}
private void adjustZoomPositionScroll() {
getTimeTrackerComponent().movePositionScroll();
}

View file

@ -1,34 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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;
import org.zkoss.ganttz.util.script.ScriptsRequiredDeclaration;
@ScriptsRequiredDeclaration
public class YUIMin {
private YUIMin() {
}
public static final String YUI_MIN = "/zkau/web/js/yui/2.7.0/yahoo/yahoo-min.js";
}

View file

@ -360,7 +360,8 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
Collection<? extends V> tasks) {
List<V> result = new ArrayList<V>();
for (V each : tasks) {
if (noVisibleDependencies(graph.incomingEdgesOf(each))) {
if (noVisibleDependencies(isScheduleForward() ? graph
.incomingEdgesOf(each) : graph.outgoingEdgesOf(each))) {
result.add(each);
}
}
@ -469,8 +470,8 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
+ o2.taskPoint);
int result = o1Depth - o2Depth;
if (result == 0) {
return asInt(o2.parentRecalculation)
- asInt(o1.parentRecalculation);
return asInt(o1.parentRecalculation)
- asInt(o2.parentRecalculation);
}
return result;
}
@ -1765,7 +1766,8 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
@Override
public String toString() {
return String.format("%s, parentRecalculation: %s, parents: %s",
return String.format(
"%s, parentRecalculation: %s, predecessors: %s",
taskPoint, parentRecalculation,
asSimpleString(recalculationsCouldAffectThis));
}

View file

@ -23,6 +23,7 @@ package org.zkoss.ganttz.resourceload;
import static org.zkoss.ganttz.i18n.I18nHelper._;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -42,6 +43,7 @@ import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
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;
import org.zkoss.zul.impl.XulElement;
@ -97,7 +99,7 @@ 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) throws Exception {
public void onEvent(Event event) {
schedule(loadLine);
}
});
@ -105,9 +107,18 @@ public class ResourceLoadComponent extends XulElement {
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.
* 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) throws Exception {
public void onEvent(Event event) {
try {
getContextMenuFor(divs, div, loadLine).open(div);
} catch (Exception e) {
@ -213,4 +224,11 @@ public class ResourceLoadComponent extends XulElement {
return datesMapper.toPixels(loadPeriod.getStart());
}
protected void renderProperties(ContentRenderer renderer) throws IOException{
render(renderer, "_resourceLoadName", getResourceLoadName());
render(renderer, "_resourceLoadType", getResourceLoadType());
super.renderProperties(renderer);
}
}

View file

@ -74,7 +74,7 @@ MutableTreeModel<LoadTimeLine> modelForTree,
return new TreeitemRenderer() {
@Override
public void render(Treeitem item, Object data)
throws Exception {
{
LoadTimeLine line = (LoadTimeLine) data;
item.setOpen(false);
item.setValue(line);
@ -111,7 +111,7 @@ MutableTreeModel<LoadTimeLine> modelForTree,
buttonPlan.setTooltiptext(_("See scheduling"));
buttonPlan.addEventListener("onClick", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
schedule(taskLine);
}
});
@ -134,7 +134,7 @@ MutableTreeModel<LoadTimeLine> modelForTree,
final LoadTimeLine line) {
item.addEventListener("onOpen", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
OpenEvent openEvent = (OpenEvent) event;
if (openEvent.isOpen()) {
List<LoadTimeLine> closed = calculatedClosedItems(item);

View file

@ -35,16 +35,14 @@ import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.MutableTreeModel;
import org.zkoss.zk.au.out.AuInvoke;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zk.ui.ext.AfterCompose;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.impl.XulElement;
/**
* Component to include a list of ResourceLoads inside the ResourcesLoadPanel.
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
public class ResourceLoadList extends HtmlMacroComponent implements
AfterCompose {
public class ResourceLoadList extends XulElement {
private final IZoomLevelChangedListener zoomListener;
@ -97,8 +95,8 @@ public class ResourceLoadList extends HtmlMacroComponent implements
for (LoadTimeLine l : line.getAllChildren()) {
getComponentFor(l).detach();
}
Clients
.evalJavaScript("zkResourcesLoadList.recalculateTimetrackerHeight();");
Clients.evalJavaScript(getWidgetClass() + ".getInstance().recalculateTimeTrackerHeight();");
}
private ResourceLoadComponent getComponentFor(LoadTimeLine l) {
@ -119,8 +117,8 @@ public class ResourceLoadList extends HtmlMacroComponent implements
insertBefore(child, nextSibling);
nextSibling = child;
}
Clients
.evalJavaScript("zkResourcesLoadList.recalculateTimetrackerHeight();");
Clients.evalJavaScript(getWidgetClass() + ".getInstance().recalculateTimeTrackerHeight();");
}
private List<LoadTimeLine> getChildrenReverseOrderFor(LoadTimeLine line) {
@ -129,11 +127,6 @@ public class ResourceLoadList extends HtmlMacroComponent implements
return childrenOf;
}
@Override
public void afterCompose() {
super.afterCompose();
}
public void addSeeScheduledOfListener(
ISeeScheduledOfListener seeScheduledOfListener) {
for (Entry<LoadTimeLine, ResourceLoadComponent> entry : fromTimeLineToComponent

View file

@ -35,19 +35,16 @@ import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.ComponentsFinder;
import org.zkoss.ganttz.util.Interval;
import org.zkoss.ganttz.util.LongOperationFeedback;
import org.zkoss.ganttz.util.MutableTreeModel;
import org.zkoss.ganttz.util.OnZKDesktopRegistry;
import org.zkoss.ganttz.util.WeakReferencedListeners;
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.ganttz.util.script.IScriptsRegister;
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.zkex.zul.api.South;
import org.zkoss.zul.Button;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ListModel;
@ -55,6 +52,7 @@ 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;
public class ResourcesLoadPanel extends HtmlMacroComponent {
public interface IToolbarCommand {
@ -128,7 +126,6 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
resourceLoadList = new ResourceLoadList(timeTracker, treeModel);
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
registerNeededScripts();
}
public ListModel getFilters() {
@ -158,7 +155,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
new ILongOperation() {
@Override
public void doAction() throws Exception {
public void doAction() {
applyFilter();
}
@ -252,7 +249,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
Button result = new Button();
result.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
c.doAction();
}
});
@ -278,15 +275,6 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
return toolbar;
}
private void registerNeededScripts() {
getScriptsRegister().register(ScriptsRequiredByResourceLoadPanel.class);
}
private IScriptsRegister getScriptsRegister() {
return OnZKDesktopRegistry.getLocatorFor(IScriptsRegister.class)
.retrieve();
}
private MutableTreeModel<LoadTimeLine> createModelForTree() {
MutableTreeModel<LoadTimeLine> result = MutableTreeModel
.create(LoadTimeLine.class);
@ -444,7 +432,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
Comboitem item = new Comboitem();
item.setLabel(firstName.substring(0, 1) + " - " + lastName.substring(0, 1));
item.setDescription(firstName + " - " + lastName);
item.setValue(new Integer(position));
item.setValue(position);
filterByNameCombo.appendChild(item);
position = newPosition;
}
@ -506,14 +494,13 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
new ILongOperation() {
@Override
public void doAction() throws Exception {
public void doAction() {
if(paginationType == PaginationType.INTERNAL_PAGINATION) {
//if the pagination is internal, we are in charge of repainting the graph
treeModel = createModelForTree();
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
resourceLoadList = new ResourceLoadList(timeTracker, treeModel);
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
registerNeededScripts();
}
nameFilterListener.fireEvent(new IListenerNotification<IPaginationFilterChangedListener>() {
@Override

View file

@ -1,37 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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.resourceload;
import org.zkoss.ganttz.ScrollSyncScript;
import org.zkoss.ganttz.YUIMin;
import org.zkoss.ganttz.util.script.ScriptsRequiredDeclaration;
@ScriptsRequiredDeclaration(dependsOn = { YUIMin.class, ScrollSyncScript.class })
public class ScriptsRequiredByResourceLoadPanel {
private ScriptsRequiredByResourceLoadPanel() {
}
public static final String SELECTOR = "/zkau/web/js/yui/2.7.0/selector/selector-min.js";
public static final String YAHOO_DOM_EVENT = "/zkau/web/js/yui/2.7.0/yahoo-dom-event/yahoo-dom-event.js";
}

View file

@ -21,14 +21,16 @@
package org.zkoss.ganttz.servlets;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
@ -47,15 +49,13 @@ public class CallbackServlet extends HttpServlet {
private static final String MAPPING = "/callback/";
private static final long CLEANING_PERIOD_MILLIS = 1000 * 60 * 10; // ten
private static final long CLEANING_PERIOD_MILLIS = 1000 * 60 * 1; // one
// minute
// minutes
private static final long EXPIRATION_TIME_MILLIS = 1000 * 60 * 30; // half
// hour;
private static Random random = new Random();
private static ConcurrentMap<String, HandlerWithRegisterTime> handlersCallbacks = new ConcurrentHashMap<String, HandlerWithRegisterTime>();
private static ConcurrentMap<String, IHandler> handlersCallbacks = new ConcurrentHashMap<String, IHandler>();
private static Timer cleaningTimer = new Timer(true);
@ -65,32 +65,105 @@ public class CallbackServlet extends HttpServlet {
IOException;
}
private static class HandlerWithRegisterTime {
private final IServletRequestHandler handler;
private final long creationTime;
public enum DisposalMode {
WHEN_NO_LONGER_REFERENCED {
@Override
public IHandler create(IServletRequestHandler handler) {
return new WeakReferencedHandler(handler);
}
},
AFTER_TEN_MINUTES {
@Override
public IHandler create(IServletRequestHandler handler) {
return new BasedOnExpirationTimeHandler(handler,
tenMinutesInMillis);
}
};
public HandlerWithRegisterTime(IServletRequestHandler handler) {
private static final long tenMinutesInMillis = TimeUnit.MILLISECONDS
.convert(10, TimeUnit.MINUTES);
public abstract IHandler create(
IServletRequestHandler handler);
}
private interface IHandler {
abstract boolean hasExpired();
abstract IServletRequestHandler getHandler();
}
private static class BasedOnExpirationTimeHandler implements IHandler {
private IServletRequestHandler handler;
private final long creationTime;
private final long expirationTimeMilliseconds;
public BasedOnExpirationTimeHandler(IServletRequestHandler handler,
long expirationTimeMilliseconds) {
Validate.notNull(handler);
this.handler = handler;
this.creationTime = System.currentTimeMillis();
this.expirationTimeMilliseconds = expirationTimeMilliseconds;
}
boolean hasExpired() {
return System.currentTimeMillis() - creationTime > EXPIRATION_TIME_MILLIS;
@Override
public IServletRequestHandler getHandler() {
return handler;
}
@Override
public boolean hasExpired() {
return System.currentTimeMillis() - creationTime > expirationTimeMilliseconds;
}
}
private static class WeakReferencedHandler implements IHandler {
private final WeakReference<IServletRequestHandler> handler;
WeakReferencedHandler(IServletRequestHandler handler) {
this.handler = new WeakReference<IServletRequestHandler>(handler);
}
@Override
public boolean hasExpired() {
return handler.get() == null;
}
@Override
public IServletRequestHandler getHandler() {
return handler.get();
}
}
public static String registerAndCreateURLFor(HttpServletRequest request,
IServletRequestHandler handler) {
return registerAndCreateURLFor(request, handler, true);
return registerAndCreateURLFor(request, handler,
DisposalMode.AFTER_TEN_MINUTES);
}
public static String registerAndCreateURLFor(HttpServletRequest request,
IServletRequestHandler handler, DisposalMode disposalMode) {
return registerAndCreateURLFor(request, handler, true, disposalMode);
}
public static String registerAndCreateURLFor(HttpServletRequest request,
IServletRequestHandler handler, boolean withContextPath) {
return registerAndCreateURLFor(request, handler, withContextPath,
DisposalMode.AFTER_TEN_MINUTES);
}
public static String registerAndCreateURLFor(HttpServletRequest request,
IServletRequestHandler handler, boolean withContextPath,
DisposalMode disposalMode) {
Validate.notNull(disposalMode);
// theoretically could be an infinite loop, could be improved.
String generatedKey = "";
HandlerWithRegisterTime toBeRegistered = new HandlerWithRegisterTime(
handler);
IHandler toBeRegistered = disposalMode.create(handler);
do {
generatedKey = generateKey();
} while (handlersCallbacks.putIfAbsent(generatedKey, toBeRegistered) != null);
@ -126,10 +199,10 @@ public class CallbackServlet extends HttpServlet {
}
private static List<String> findExpired() {
ArrayList<Entry<String, HandlerWithRegisterTime>> handlersList = new ArrayList<Entry<String, HandlerWithRegisterTime>>(
ArrayList<Entry<String, IHandler>> handlersList = new ArrayList<Entry<String, IHandler>>(
handlersCallbacks.entrySet());
List<String> expired = new ArrayList<String>();
for (Entry<String, HandlerWithRegisterTime> entry : handlersList) {
for (Entry<String, IHandler> entry : handlersList) {
if (entry.getValue().hasExpired()) {
expired.add(entry.getKey());
}
@ -170,8 +243,8 @@ public class CallbackServlet extends HttpServlet {
}
private IServletRequestHandler handlerFor(String callbackId) {
HandlerWithRegisterTime h = handlersCallbacks.get(callbackId);
return h != null ? h.handler : null;
IHandler h = handlersCallbacks.get(callbackId);
return h != null ? h.getHandler() : null;
}
}

View file

@ -111,7 +111,7 @@ public class TimeTrackedTableWithLeftPane<A, B> {
return new Callable<List<B>>() {
@Override
public List<B> call() throws Exception {
public List<B> call() {
return loadPairOfListsFromCallable().getSecond();
}
};

View file

@ -234,7 +234,7 @@ public class TimeTracker {
new ILongOperation() {
@Override
public void doAction() throws Exception {
public void doAction() {
invalidatingChangeHappened();
}

View file

@ -30,9 +30,6 @@ import org.zkoss.ganttz.timetracker.zoom.DetailItem;
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
import org.zkoss.ganttz.timetracker.zoom.TimeTrackerState;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.au.Command;
import org.zkoss.zk.au.ComponentCommand;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.HtmlMacroComponent;
@ -46,6 +43,7 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
private IZoomLevelChangedListener zoomListener;
private final String secondLevelZul;
private String timeTrackerElementId;
private int scrollLeft;
public TimeTrackerComponent(TimeTracker timeTracker) {
this(timeTracker,
@ -63,6 +61,7 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
public void zoomLevelChanged(ZoomLevel detailLevel) {
if (isInPage()) {
recreate();
changeDetailLevel(getDaysFor(scrollLeft));
}
}
};
@ -82,9 +81,15 @@ 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.
* */
@Override
public void afterCompose() {
super.afterCompose();
public void compose() {
super.compose();
Component fellow = getFellow("firstleveldetails");
addSecondLevels(fellow.getParent());
}
@ -116,49 +121,6 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
return getTimeTracker().getTimeTrackerState();
}
private Command _onincreasecmd = new ComponentCommand("onIncrease", 0) {
protected void process(AuRequest request) {
String[] requestData = request.getData();
int pixelsOffset = Integer.parseInt(requestData[0]);
onIncrease(pixelsOffset);
}
};
private Command _ondecreasecmd = new ComponentCommand("onDecrease", 0) {
protected void process(AuRequest request) {
String[] requestData = request.getData();
int pixelsOffset = Integer.parseInt(requestData[0]);
onDecrease(pixelsOffset);
}
};
private Command[] commands = { _onincreasecmd, _ondecreasecmd };
public Command getCommand(String cmdId) {
for (Command command : commands) {
if (command.getId().equals(cmdId)) {
return command;
}
}
return super.getCommand(cmdId);
}
public void onIncrease(int offset) {
double daysOffset = getDaysFor(offset);
getTimeTracker().zoomIncrease();
changeDetailLevel(daysOffset);
}
public void onDecrease(int offset) {
double daysOffset = getDaysFor(offset);
getTimeTracker().zoomDecrease();
changeDetailLevel(daysOffset);
}
public TimeTracker getTimeTracker() {
return timeTracker;
}
@ -198,4 +160,13 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
return timeTracker.getDetailLevel() == ZoomLevel.DETAIL_FOUR;
}
public void setZoomLevel(ZoomLevel zoomlevel, int scrollLeft){
this.scrollLeft = scrollLeft;
getTimeTracker().setZoomLevel(zoomlevel);
}
public String getWidgetClass(){
return getDefinition().getDefaultWidgetClass();
}
}

View file

@ -31,12 +31,13 @@ public class GanttUtils {
private GanttUtils() {
}
public static int getIntFromStylePosition(String position) throws Exception {
public static int getIntFromStylePosition(String position) {
String[] tokens = position.split("px");
if (tokens.length != 1) {
throw new Exception("Bad formatting for input parameter");
throw new IllegalArgumentException(
"Bad formatting for input parameter");
}
return Integer.parseInt(tokens[0]);

View file

@ -39,6 +39,7 @@ import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.Clients;
/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
*
@ -71,7 +72,7 @@ public class LongOperationFeedback {
return;
}
Clients.showBusy(longOperation.getName(), true);
Clients.showBusy(longOperation.getName());
executeLater(component, new Runnable() {
public void run() {
try {
@ -80,8 +81,8 @@ public class LongOperationFeedback {
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
alreadyInside.set(false);
Clients.showBusy(null, false);
alreadyInside.remove();
Clients.clearBusy();
}
}
});
@ -95,10 +96,11 @@ public class LongOperationFeedback {
component.addEventListener(eventName, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
try {
runnable.run();
} finally {
Clients.clearBusy();
component.removeEventListener(eventName, this);
}
}

View file

@ -116,7 +116,7 @@ public class MenuBuilder<T extends XulElement> {
result.addEventListener("onOpen", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
OpenEvent openEvent = (OpenEvent) event;
referenced = (T) openEvent.getReference();
}
@ -126,7 +126,7 @@ public class MenuBuilder<T extends XulElement> {
Menuitem menuItem = item.createMenuItem();
menuItem.addEventListener("onClick", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
public void onEvent(Event event) {
ItemAction<T> action = item.action;
action.onEvent(referenced, event);
}

View file

@ -27,12 +27,14 @@ import org.apache.commons.lang.Validate;
*/
public abstract class PreAndPostNotReentrantActionsWrapper {
private final ThreadLocal<Boolean> inside = new ThreadLocal<Boolean>() {
private static final class BooleanThreadLocal extends ThreadLocal<Boolean> {
@Override
protected Boolean initialValue() {
return false;
}
};
}
private final ThreadLocal<Boolean> inside = new BooleanThreadLocal();
public void doAction(IAction action) {
Validate.notNull(action);
@ -49,7 +51,7 @@ public abstract class PreAndPostNotReentrantActionsWrapper {
try {
action.doAction();
} finally {
inside.set(false);
inside.remove();
postAction();
}
}

View file

@ -1,29 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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.util.script;
public interface IScriptsRegister {
public void register(Class<?> klassContainingScripts)
throws IllegalArgumentException;
}

View file

@ -1,137 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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.util.script;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.Validate;
public class ScriptDependenciesSorter implements IScriptsRegister {
public static List<ScriptDependency> extractFrom(Class<?> classWithScripts) {
ScriptsRequiredDeclaration annotation = classWithScripts
.getAnnotation(ScriptsRequiredDeclaration.class);
if (annotation == null) {
throw new IllegalArgumentException(classWithScripts
+ " must be annotated with "
+ ScriptsRequiredDeclaration.class.getName());
}
List<ScriptDependency> dependsOn = getDependencies(annotation);
List<ScriptDependency> result = new ArrayList<ScriptDependency>();
for (Field field : getStringFields(getStaticFields(classWithScripts
.getFields()))) {
result.add(new ScriptDependency(getValueFromStringField(field),
dependsOn));
}
return result;
}
static ArrayList<ScriptDependency> getDependencies(
ScriptsRequiredDeclaration declaration) {
Class<?>[] dependsOn = declaration.dependsOn();
ArrayList<ScriptDependency> result = new ArrayList<ScriptDependency>();
for (Class<?> klass : dependsOn) {
result.addAll(extractFrom(klass));
}
return result;
}
static String getValueFromStringField(Field stringField) {
try {
return (String) stringField.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static List<Field> getStaticFields(Field[] fields) {
List<Field> result = new ArrayList<Field>();
for (Field field : fields) {
if (Modifier.isStatic(field.getModifiers())) {
result.add(field);
}
}
return result;
}
static List<Field> getStringFields(Collection<Field> fields) {
List<Field> stringFields = new ArrayList<Field>();
for (Field field : fields) {
if (field.getType().equals(String.class)) {
stringFields.add(field);
}
}
return stringFields;
}
private List<ScriptDependency> allScripts = new ArrayList<ScriptDependency>();
public ScriptDependenciesSorter() {
}
public void add(ScriptDependency scriptDependency) {
addAll(Arrays.asList(scriptDependency));
}
public void addAll(List<ScriptDependency> dependencies) {
Validate.noNullElements(dependencies);
allScripts.addAll(dependencies);
}
public List<ScriptDependency> getScriptDependenciesOrderered() {
List<ScriptDependency> result = new ArrayList<ScriptDependency>();
Set<ScriptDependency> alreadyAdded = new HashSet<ScriptDependency>();
for (ScriptDependency scriptDependency : allScripts) {
result.addAll(extract(alreadyAdded, scriptDependency));
}
return Collections.unmodifiableList(result);
}
private List<ScriptDependency> extract(Set<ScriptDependency> alreadyAdded,
ScriptDependency scriptDependency) {
List<ScriptDependency> result = new ArrayList<ScriptDependency>();
if (alreadyAdded.contains(scriptDependency)) {
return result;
}
for (ScriptDependency d : scriptDependency.getDependsOn()) {
result.addAll(extract(alreadyAdded, d));
}
result.add(scriptDependency);
alreadyAdded.add(scriptDependency);
return result;
}
@Override
public void register(Class<?> klassContainingScripts)
throws IllegalArgumentException {
addAll(extractFrom(klassContainingScripts));
}
}

View file

@ -1,91 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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.util.script;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.HashCodeBuilder;
/**
* Represents a dependency to a script
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class ScriptDependency {
public static List<String> getOnlyURLs(
Collection<? extends ScriptDependency> dependencies) {
List<String> result = new ArrayList<String>();
for (ScriptDependency scriptDependency : dependencies) {
result.add(scriptDependency.getURL());
}
return result;
}
private final String url;
private final List<ScriptDependency> dependsOn;
public ScriptDependency(String url) {
this(url, Collections.<ScriptDependency> emptyList());
}
public ScriptDependency(String url, Collection<? extends ScriptDependency> dependencies) {
Validate.notEmpty(url);
Validate.noNullElements(dependencies);
this.url = url;
this.dependsOn = Collections.unmodifiableList(new ArrayList<ScriptDependency>(
dependencies));
}
public String getURL() {
return this.url;
}
public List<ScriptDependency> getDependsOn() {
return dependsOn;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other instanceof ScriptDependency) {
return url.equals(((ScriptDependency) other).url);
}
return false;
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(url).toHashCode();
}
@Override
public String toString() {
return url;
}
}

View file

@ -1,102 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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.util.script;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.zkoss.ganttz.util.OnZKDesktopRegistry;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.HtmlMacroComponent;
public class ScriptsComponent extends HtmlMacroComponent {
private List<ScriptDependency> current = Collections.emptyList();
public ScriptsComponent() {
OnZKDesktopRegistry<IScriptsRegister> singleton = getScriptsRegister();
ScriptRegister register;
if (singleton.isRegistered()) {
register = (ScriptRegister) singleton.retrieve();
} else {
register = new ScriptRegister();
singleton.store(register);
}
register.addDependant(this);
}
private OnZKDesktopRegistry<IScriptsRegister> getScriptsRegister() {
return OnZKDesktopRegistry.getLocatorFor(IScriptsRegister.class);
}
public List<ScriptDependency> getScriptDependencies() {
return current;
}
void setDependencies(List<ScriptDependency> current) {
this.current = current;
if (!executionIsUpdatingPage()) {
recreate();
}
}
private boolean executionIsUpdatingPage() {
return Executions.getCurrent().isAsyncUpdate(null);
}
}
class ScriptRegister implements IScriptsRegister {
private ScriptDependenciesSorter dependenciesSorter = new ScriptDependenciesSorter();
private List<ScriptsComponent> dependant = new ArrayList<ScriptsComponent>();
void addDependant(ScriptsComponent component) {
dependant.add(component);
}
@Override
public void register(Class<?> klassContainingScripts)
throws IllegalArgumentException {
dependenciesSorter.register(klassContainingScripts);
notifyDependant(encodeURLs(dependenciesSorter
.getScriptDependenciesOrderered()));
}
private List<ScriptDependency> encodeURLs(
List<ScriptDependency> scriptDependenciesOrderered) {
List<ScriptDependency> result = new ArrayList<ScriptDependency>();
Execution execution = Executions.getCurrent();
for (ScriptDependency s : scriptDependenciesOrderered) {
result.add(new ScriptDependency(execution.encodeURL(s.getURL())));
}
return result;
}
private void notifyDependant(List<ScriptDependency> current) {
for (ScriptsComponent d : dependant) {
d.setDependencies(current);
}
}
}

View file

@ -1,34 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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.util.script;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ScriptsRequiredDeclaration {
public Class<?>[] dependsOn() default {};
}

View file

@ -12,8 +12,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 1.1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-11 18:16+0200\n"
"PO-Revision-Date: 2011-04-08 11:11+0200\n"
"POT-Creation-Date: 2011-06-06 22:45+0200\n"
"PO-Revision-Date: 2011-06-06 22:51+0200\n"
"Last-Translator: Manuel Rego Casasnovas <mrego@igalia.com>\n"
"Language-Team: Spanish <>\n"
"Language: es\n"
@ -43,20 +43,16 @@ msgstr "Inicio"
msgid "Show reported hours"
msgstr "Mostrar horas reportadas"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:78
msgid "Show/Hide Progress"
msgstr "Mostrar/ocultar progreso"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:92
msgid "by criteria"
msgstr "por criterios"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:70
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:72
msgid "Show/Hide reported hours"
msgstr "Mostrar/ocultar horas reportardas"
msgstr "Mostrar/Ocultar horas reportardas"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:45
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:36
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:46
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:35
msgid "Zoom"
msgstr "Zoom"
@ -72,6 +68,10 @@ msgstr "La dependencia especificada no está permitida"
msgid "Set End-End"
msgstr "Definir Fin-Fin"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:80
msgid "Show/Hide progress"
msgstr "Mostrar/Ocultar progreso"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Task"
msgstr "Tarea"
@ -84,7 +84,7 @@ msgstr "por recursos"
msgid "Criterion"
msgstr "Criterio"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:40
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:41
msgid "Print"
msgstr "Imprimir"
@ -108,6 +108,10 @@ msgstr "filtrando por nombre"
msgid "End"
msgstr "Fin"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:37
msgid "Choosing Template"
msgstr "Selección de plantilla"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/TimeTracker.java:243
msgid "changing zoom"
msgstr "cambiando zoom"
@ -120,24 +124,24 @@ msgstr "Trimestre"
msgid "None"
msgstr "Ninguno"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:44
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:43
msgid "Filter"
msgstr "Filtro"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:67
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:69
msgid "Flatten/Unflatten tree"
msgstr "Aplanar/expandir árbol"
msgstr "Aplanar/Expandir árbol"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Project"
msgstr "Proyecto"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:51
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:50
msgid "Name filter"
msgstr "Filtro por nombres"
#: ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:28
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:69
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:68
msgid "Name"
msgstr "Nombre"
@ -145,9 +149,13 @@ msgstr "Nombre"
msgid "Show progress"
msgstr "Mostrar progreso"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:64
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:66
msgid "Expand/Collapse all"
msgstr "Expandir/plegar todo"
msgstr "Expandir/Plegar todo"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:56
msgid "Show/Hide critical path"
msgstr "Mostrar/Ocultar camino crítico"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:36
msgid "Create Project"
@ -165,9 +173,9 @@ msgstr "mostrando criterios"
msgid "Month"
msgstr "Mes"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:61
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:63
msgid "Show/Hide resources"
msgstr "Mostrar/ocultar recursos"
msgstr "Mostrar/Ocultar recursos"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:246
msgid "Set End-Start"
@ -189,10 +197,6 @@ msgstr "Ocultar horas reportadas"
msgid "Day"
msgstr "Día"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:55
msgid "Show/Hide Critical path"
msgstr "Mostrar/ocultar camino crítico"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:142
msgid "showing resources"
msgstr "mostrando recursos"
@ -201,16 +205,16 @@ msgstr "mostrando recursos"
msgid "Load: {0}%"
msgstr "Carga: {0}%"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:58
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:60
msgid "Show/Hide labels"
msgstr "Mostrar/ocultar etiquetas"
msgstr "Mostrar/Ocultar etiquetas"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:97
msgid "Hour"
msgstr "Hora"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:114
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:92
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:116
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:91
msgid "Graphics"
msgstr "Gráficas"
@ -234,7 +238,7 @@ msgstr "Mostrar todos los elementos"
msgid "All"
msgstr "Todos"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:38
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:39
msgid "Refresh"
msgstr "Actualizar"

View file

@ -3,7 +3,7 @@
# 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 file is distributed under the same license as the PACKAGE package.
# This file is distributed under the same license as the NavalPlan package.
# Igalia <dpino@igalia.com>, 2009.
# Jacobo Aragunde Pérez <jaragunde@igalia.com>, 2010.
# Manuel Rego Casasnovas <mrego@igalia.com>, 2010, 2011.
@ -12,8 +12,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 1.1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-11 18:16+0200\n"
"PO-Revision-Date: 2011-04-08 11:11+0200\n"
"POT-Creation-Date: 2011-06-06 22:45+0200\n"
"PO-Revision-Date: 2011-06-06 22:50+0200\n"
"Last-Translator: Manuel Rego Casasnovas <mrego@igalia.com>\n"
"Language-Team: Galician <>\n"
"Language: gl\n"
@ -43,20 +43,16 @@ msgstr "Inicio"
msgid "Show reported hours"
msgstr "Mostrar horas reportadas"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:78
msgid "Show/Hide Progress"
msgstr "Mostrar/ocultar progreso"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:92
msgid "by criteria"
msgstr "por criterios"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:70
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:72
msgid "Show/Hide reported hours"
msgstr "Mostrar/ocultar horas reportadas"
msgstr "Mostrar/Ocultar horas reportadas"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:45
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:36
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:46
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:35
msgid "Zoom"
msgstr "Zoom"
@ -72,6 +68,10 @@ msgstr "A dependencia especificada non está permitida"
msgid "Set End-End"
msgstr "Definir Fin-Fin"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:80
msgid "Show/Hide progress"
msgstr "Mostrar/Ocultar progreso"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Task"
msgstr "Tarefa"
@ -84,7 +84,7 @@ msgstr "por recursos"
msgid "Criterion"
msgstr "Criterio"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:40
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:41
msgid "Print"
msgstr "Imprimir"
@ -108,6 +108,10 @@ msgstr "filtrando por nome"
msgid "End"
msgstr "Fin"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:37
msgid "Choosing Template"
msgstr "Selección de modelo"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/TimeTracker.java:243
msgid "changing zoom"
msgstr "cambiando zoom"
@ -120,24 +124,24 @@ msgstr "Trimestre"
msgid "None"
msgstr "Ningún"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:44
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:43
msgid "Filter"
msgstr "Filtro"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:67
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:69
msgid "Flatten/Unflatten tree"
msgstr "Aplanar/expandir árbore"
msgstr "Aplanar/Expandir árbore"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Project"
msgstr "Proxecto"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:51
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:50
msgid "Name filter"
msgstr "Filtro por nomes"
#: ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:28
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:69
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:68
msgid "Name"
msgstr "Nome"
@ -145,9 +149,13 @@ msgstr "Nome"
msgid "Show progress"
msgstr "Mostrar progreso"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:64
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:66
msgid "Expand/Collapse all"
msgstr "Expandir/pregar todo"
msgstr "Expandir/Pregar todo"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:56
msgid "Show/Hide critical path"
msgstr "Mostrar/Ocultar camiño crítico"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:36
msgid "Create Project"
@ -165,9 +173,9 @@ msgstr "mostrando criterios"
msgid "Month"
msgstr "Mes"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:61
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:63
msgid "Show/Hide resources"
msgstr "Mostrar/ocultar recursos"
msgstr "Mostrar/Ocultar recursos"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:246
msgid "Set End-Start"
@ -189,10 +197,6 @@ msgstr "Ocultar horas reportadas"
msgid "Day"
msgstr "Día"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:55
msgid "Show/Hide Critical path"
msgstr "Ocultar/ocultar camiño crítico"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:142
msgid "showing resources"
msgstr "mostrando recursos"
@ -201,16 +205,16 @@ msgstr "mostrando recursos"
msgid "Load: {0}%"
msgstr "Carga: {0}%"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:58
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:60
msgid "Show/Hide labels"
msgstr "Mostrar/ocultar etiquetas"
msgstr "Mostrar/Ocultar etiquetas"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:97
msgid "Hour"
msgstr "Hora"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:114
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:92
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:116
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:91
msgid "Graphics"
msgstr "Gráficas"
@ -234,7 +238,7 @@ msgstr "Mostrar tódolos elementos"
msgid "All"
msgstr "Todos"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:38
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:39
msgid "Refresh"
msgstr "Actualizar"

View file

@ -10,9 +10,9 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 1.1.0\n"
"Project-Id-Version: 1.1.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-11 18:16+0200\n"
"POT-Creation-Date: 2011-06-06 22:45+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -42,20 +42,16 @@ msgstr ""
msgid "Show reported hours"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:78
msgid "Show/Hide Progress"
msgstr ""
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:92
msgid "by criteria"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:70
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:72
msgid "Show/Hide reported hours"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:45
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:36
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:46
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:35
msgid "Zoom"
msgstr ""
@ -71,6 +67,10 @@ msgstr ""
msgid "Set End-End"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:80
msgid "Show/Hide progress"
msgstr ""
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Task"
msgstr ""
@ -83,7 +83,7 @@ msgstr ""
msgid "Criterion"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:40
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:41
msgid "Print"
msgstr ""
@ -107,6 +107,10 @@ msgstr ""
msgid "End"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:37
msgid "Choosing Template"
msgstr ""
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/TimeTracker.java:243
msgid "changing zoom"
msgstr ""
@ -119,11 +123,11 @@ msgstr ""
msgid "None"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:44
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:43
msgid "Filter"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:67
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:69
msgid "Flatten/Unflatten tree"
msgstr ""
@ -131,12 +135,12 @@ msgstr ""
msgid "Project"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:51
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:50
msgid "Name filter"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:28
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:69
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:68
msgid "Name"
msgstr ""
@ -144,10 +148,14 @@ msgstr ""
msgid "Show progress"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:64
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:66
msgid "Expand/Collapse all"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:56
msgid "Show/Hide critical path"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:36
msgid "Create Project"
msgstr ""
@ -164,7 +172,7 @@ msgstr ""
msgid "Month"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:61
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:63
msgid "Show/Hide resources"
msgstr ""
@ -188,10 +196,6 @@ msgstr ""
msgid "Day"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:55
msgid "Show/Hide Critical path"
msgstr ""
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:142
msgid "showing resources"
msgstr ""
@ -200,7 +204,7 @@ msgstr ""
msgid "Load: {0}%"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:58
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:60
msgid "Show/Hide labels"
msgstr ""
@ -208,8 +212,8 @@ msgstr ""
msgid "Hour"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:114
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:92
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:116
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:91
msgid "Graphics"
msgstr ""
@ -233,7 +237,7 @@ msgstr ""
msgid "All"
msgstr ""
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:38
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:39
msgid "Refresh"
msgstr ""

View file

@ -14,6 +14,7 @@
<component>
<component-name>planner</component-name>
<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>
@ -36,9 +37,11 @@
<component>
<component-name>resourcesLoadList</component-name>
<component-class>org.zkoss.ganttz.resourceload.ResourceLoadList</component-class>
<widget-class>ganttz.resourceload.ResourceLoadList</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/resourceload/resourceloadlist.dsp</mold-uri>
<mold-uri>mold/resource-load-list.js</mold-uri>
<!-- <mold-uri>~./ganttz/resourceload/resourceloadlist.dsp</mold-uri> -->
</mold>
</component>
@ -64,9 +67,11 @@
<component>
<component-name>ganttpanel</component-name>
<component-class>org.zkoss.ganttz.GanttPanel</component-class>
<widget-class>ganttz.GanttPanel</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/ganttpanel.dsp</mold-uri>
<!-- <mold-uri>~./ganttz/ganttpanel.dsp</mold-uri> -->
<mold-uri>mold/gantt-panel.js</mold-uri>
</mold>
</component>
@ -74,9 +79,11 @@
<component-name>resourceload</component-name>
<component-class>org.zkoss.ganttz.resourceload.ResourceLoadComponent
</component-class>
<widget-class>ganttz.resourceload.ResourceLoadComponent</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/resourceload/resourceload.dsp</mold-uri>
<mold-uri>mold/resource-load-component.js</mold-uri>
<!-- <mold-uri>~./ganttz/resourceload/resourceload.dsp</mold-uri> -->
</mold>
</component>
@ -84,27 +91,33 @@
<component>
<component-name>taskRow</component-name>
<component-class>org.zkoss.ganttz.TaskRow</component-class>
<widget-class>ganttz.TaskRow</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/row.dsp</mold-uri>
<!-- <mold-uri>~./ganttz/row.dsp</mold-uri> -->
<mold-uri>mold/task-row.js</mold-uri>
</mold>
</component>
<component>
<component-name>task</component-name>
<component-class>org.zkoss.ganttz.TaskComponent</component-class>
<widget-class>ganttz.TaskComponent</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/task.dsp</mold-uri>
<!-- <mold-uri>~./ganttz/task.dsp</mold-uri> -->
<mold-uri>mold/task-component.js</mold-uri>
</mold>
</component>
<component>
<component-name>milestone</component-name>
<component-class>org.zkoss.ganttz.MilestoneComponent</component-class>
<widget-class>ganttz.Milestone</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/milestone.dsp</mold-uri>
<!-- <mold-uri>~./ganttz/milestone.dsp</mold-uri> -->
<mold-uri>mold/milestone.js</mold-uri>
</mold>
</component>
@ -113,27 +126,33 @@
<component-name>taskcontainer</component-name>
<component-class>org.zkoss.ganttz.TaskContainerComponent
</component-class>
<widget-class>ganttz.TaskContainerComponent</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/taskcontainer.dsp</mold-uri>
<mold-uri>mold/task-container.js</mold-uri>
<!-- <mold-uri>~./ganttz/taskcontainer.dsp</mold-uri> -->
</mold>
</component>
<component>
<component-name>tasklist</component-name>
<component-class>org.zkoss.ganttz.TaskList</component-class>
<widget-class>ganttz.TaskList</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/tasklist.dsp</mold-uri>
<!-- <mold-uri>~./ganttz/tasklist.dsp</mold-uri> -->
<mold-uri>mold/task-list.js</mold-uri>
</mold>
</component>
<component>
<component-name>dependencylist</component-name>
<component-class>org.zkoss.ganttz.DependencyList</component-class>
<widget-class>ganttz.DependencyList</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/dependencylist.dsp</mold-uri>
<!-- <mold-uri>~./ganttz/dependencylist.dsp</mold-uri> -->
<mold-uri>mold/dependency-list.js</mold-uri>
</mold>
</component>
@ -141,9 +160,11 @@
<component-name>dependency</component-name>
<component-class>org.zkoss.ganttz.DependencyComponent
</component-class>
<widget-class>ganttz.DependencyComponent</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>~./ganttz/dependency.dsp</mold-uri>
<mold-uri>mold/dependency-component.js</mold-uri>
<!-- <mold-uri>~./ganttz/dependency.dsp</mold-uri> -->
</mold>
</component>
@ -151,7 +172,8 @@
<component>
<component-name>timetracker</component-name>
<component-class>org.zkoss.ganttz.timetracker.TimeTrackerComponent</component-class>
<macro-uri>~./ganttz/zul/timetracker/timetracker.zul</macro-uri>
<widget-class>ganttz.TimeTracker</widget-class>
<macro-uri>~./ganttz/zul/timetracker/timetracker.zul</macro-uri>
</component>
<component>
@ -160,10 +182,4 @@
<macro-uri>~./ganttz/zul/timetracker/timetrackedtable.zul</macro-uri>
</component>
<component>
<component-name>scripts</component-name>
<component-class>org.zkoss.ganttz.util.script.ScriptsComponent</component-class>
<macro-uri>~./ganttz/zul/scripts.zul</macro-uri>
</component>
</language-addon>

View file

@ -19,7 +19,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
<n:div id="listdetails_container">
</n:div>
<zk>
<div id="listdetails_container">
</div>
</zk>

View file

@ -19,15 +19,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<?xel-method prefix="i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
signature="java.lang.String _(java.lang.String name)" ?>
<div>
<tree id="tasksTree" fixedLayout="true" sclass="taskTreeCols">
<treecols sizable="false" height="33px">
<treecol label="${i18n:_('Name')}" sclass="tree-text" />
<treecol label="${i18n:_('Start')}" width="76px" />
<treecol label="${i18n:_('End')}" width="76px" />
<treecol label="${ganttzk_i18n:_('Name')}" sclass="tree-text" />
<treecol label="${ganttzk_i18n:_('Start')}" width="76px" />
<treecol label="${ganttzk_i18n:_('End')}" width="76px" />
</treecols>
</tree>
</div>
</div>

View file

@ -18,102 +18,99 @@
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/>.
-->
<?taglib uri="/WEB-INF/tld/i18n.tld" prefix="i18n" ?>
<borderlayout width="auto" height="100%" class="inner-layout">
<north height="32px" border="0" sclass="toolbar-box">
<zscript><![CDATA[
<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>
</zscript>
<borderlayout sclass="plannerlayout" width="auto">
<north height="30px" border="0" sclass="toolbar-box">
<hbox align="center" id="toolbar">
<hbox align="center" id="toolbar">
<separator/>
<!-- Commands -->
<templateFinderPopup id="templateFinderPopup" acceptButtonLabel="${ganttzk_i18n:_('Create Project')}" caption="${i18n:_('Choosing Template')}" />
<separator />
<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/>
<!-- Commands -->
<templateFinderPopup id="templateFinderPopup"
acceptButtonLabel="${i18n:_('Create Project')}" caption="${i18n:_('Choosing Template')}" />
<button onClick="planner.invalidate()" image="/common/img/ico_refresh.png"
tooltiptext="${i18n:_('Refresh')}" visible="false" />
<button id="btnPrint" onClick="planner.print()"
image="/common/img/ico_print.png" tooltiptext="${i18n:_('Print')}" />
<!-- Visualization modes -->
<label>${ganttzk_i18n:_('Zoom')}:</label>
<listbox id="listZoomLevels" mold="select" rows="1"
model="${planner.zoomLevels}">
</listbox>
<separator />
<!-- Progress type -->
<!-- Visualization modes -->
<label>${i18n:_('Zoom')}:</label>
<listbox id="listZoomLevels" mold="select" rows="1"
model="${planner.zoomLevels}" onSelect="planner.setZoomLevel(self.selectedItem.value);">
</listbox>
<!-- Progress type -->
<hbox sclass="view-options">
<button id="showCriticalPath" onClick="planner.showCriticalPath();"
image="/common/img/ico_criticalpath.png"
tooltiptext="${i18n:_('Show/Hide Critical path')}"
sclass="planner-command" />
<button id="showAllLabels" onClick="planner.showAllLabels();"
image="/common/img/ico_labels.png" tooltiptext="${i18n:_('Show/Hide labels')}"
sclass="planner-command show-labels" />
<button id="showAllResources" onClick="planner.showAllResources();"
image="/common/img/ico_resources.png" tooltiptext="${i18n:_('Show/Hide resources')}"
sclass="planner-command show-resources" />
<button id="expandAll" onClick="planner.expandAll();"
image="/common/img/ico_expand.png" tooltiptext="${i18n:_('Expand/Collapse all')}"
sclass="planner-command" />
<button id="flattenTree" onClick="planner.flattenTree();"
image="/common/img/ico_flatten.png" tooltiptext="${i18n:_('Flatten/Unflatten tree')}"
sclass="planner-command" />
<button id="showReportedHours" onClick="planner.showReportedHours();"
image="/common/img/ico_costs.png" tooltiptext="${i18n:_('Show/Hide reported hours')}"
sclass="planner-command" />
</hbox>
<hbox class="show-advances" align="center">
<button id="showAdvances" onClick="planner.showAdvances();"
image="/common/img/ico_progress.png" style="width:46px"
tooltiptext="${i18n:_('Show/Hide Progress')}"
sclass="planner-command" />
<combobox id="cbProgressTypes" width="1px"
visible="false" sclass="progress-types" />
</hbox>
<separator />
<!-- Filtering -->
<vbox id="orderFilter" />
<vbox id="orderElementFilter" />
<separator />
<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" />
<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>
</north>
<center border="0">
<borderlayout sclass="plannerlayout_center" height="100%">
<west flex="false" collapsible="true" splittable="true"
width="300px" id="taskdetailsContainer" sclass="taskdetailsContainer">
<div sclass="leftpanelgap" id="insertionPointLeftPanel"></div>
</west>
<center id="taskpanel" sclass="taskspanel">
<borderlayout>
<north border="0">
<div sclass="timetrackergap" id="insertionPointTimetracker"></div>
</north>
<center id="centerPanel" autoscroll="true"
border="10" sclass="rightpanellayout">
<div id="insertionPointRightPanel" sclass="taskspanelgap"></div>
</center>
</borderlayout>
<button id="showReportedHours" onClick="planner.showReportedHours();"
image="/common/img/ico_costs.png"
tooltiptext="${ganttzk_i18n:_('Show/Hide reported hours')}"
sclass="planner-command"/>
<separator />
</center>
</borderlayout>
</center>
<south collapsible="true" title="${i18n:_('Graphics')}"
sclass="scheduling-graphics" id="graphics"
onOpen="planner.changeChartVisibility(event.open);" height="200px">
<div id="insertionPointChart" />
</south>
</borderlayout>
<!-- 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="300px"
id="taskdetailsContainer" sclass="taskdetailsContainer">
<div sclass="leftpanelgap" id="insertionPointLeftPanel"></div>
</west>
<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>
</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>
</borderlayout>
</zk>

View file

@ -19,7 +19,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<?xel-method prefix="i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
signature="java.lang.String _(java.lang.String name)" ?>
<zk xmlns:n="http://www.zkoss.org/2005/zk/native" height="100%">
@ -28,12 +28,11 @@ resourcesLoadPanel = self;
]]>
</zscript>
<borderlayout sclass="resourcesloadlayout" width="auto" height="100%">
<north height="30px" border="0" sclass="toolbar-box">
<hbox align="center" id="toolbar">
<separator/>
<label>${i18n:_('Zoom')}:</label>
<label>${ganttzk_i18n:_('Zoom')}:</label>
<listbox id="listZoomLevels" mold="select" rows="1"
model="${resourcesLoadPanel.zoomLevels}"
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" >
@ -41,14 +40,14 @@ resourcesLoadPanel = self;
<separator/>
<hbox id="additionalFilterInsertionPoint1" />
<separator/>
${i18n:_('Filter')}:
${ganttzk_i18n:_('Filter')}:
<listbox id="listFilters" mold="select" rows="1" width="100px"
model="${resourcesLoadPanel.filters}"
selectedIndex="0"
onSelect="resourcesLoadPanel.setFilter(self.selectedItem.value);">
</listbox>
<separator/>
<label id="filterByNameLabel">${i18n:_('Name filter')}:</label>
<label id="filterByNameLabel">${ganttzk_i18n:_('Name filter')}:</label>
<combobox id="filterByNameCombo" width="50px"
onChange="resourcesLoadPanel.onSelectFilterByName(self)" />
<separator/>
@ -63,10 +62,10 @@ resourcesLoadPanel = self;
<borderlayout >
<north border="0" height="35px" flex="true" collapsible="true">
<vbox pack="top" align="center" width="100%">
<tree fixedLayout="true" width="100%">
<vbox pack="top" align="center">
<tree fixedLayout="true" hflex="true">
<treecols>
<treecol label="${i18n:_('Name')}" height="29px"/>
<treecol label="${ganttzk_i18n:_('Name')}" height="29px"/>
</treecols>
</tree>
@ -89,7 +88,7 @@ resourcesLoadPanel = self;
</center>
</borderlayout>
</center>
<south height="200px" collapsible="true" title="${i18n:_('Graphics')}"
<south height="200px" collapsible="true" title="${ganttzk_i18n:_('Graphics')}"
sclass="scheduling-graphics" id="graphics"
onOpen="resourcesLoadPanel.changeChartVisibility(event.open);">
<div id="insertionPointChart" />

View file

@ -27,29 +27,6 @@ top = self;
</zscript>
<div>
<n:script language="javascript">
function getHorizontalScroll(timetracker) {
return document.getElementById('${top.timeTrackerId}').scrollLeft;
}
function onIncrease(timetracker) {
zkau.send( {
uuid : timetracker.id,
cmd : "onIncrease",
data : [ getHorizontalScroll(timetracker) ]
});
}
function onDecrease(timetracker) {
zkau.send( {
uuid : timetracker.id,
cmd : "onDecrease",
data : [ getHorizontalScroll(timetracker) ]
});
}
</n:script>
<n:div id="${top.timeTrackerId}">
<vbox>
<grid id="firstleveldetails" width="${top.horizontalSizePixels}px;">

View file

@ -0,0 +1,72 @@
zk.$package("common");
common.Common = zk.$extends(zk.Widget,{},{
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);
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.
*/
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;
}
}
};
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;
}
}
};
}
});

View file

@ -0,0 +1,3 @@
<package name="common" language="xul/html">
<widget name="Common"/>
</package>

View file

@ -0,0 +1,345 @@
zk.$package("ganttz");
ganttz.DependencyComponentBase = zk.$extends(zul.Widget,{
$define : {
idTaskOrig : null,
idTaskEnd : null,
dependencyType : null
},
bind_ : function(){
this.$supers('bind_', arguments);
this.setupArrow_();
},
setCSSClass: function(newClass) {
this.$n().setAttribute("class", newClass);
},
draw : function(){throw "draw method must be overwriten by extending classes"},
drawArrow_ : function(coordOrig, coordDest){
switch(this.getDependencyType())
{
case this.$class.START_START:
this._drawArrowStartStart(coordOrig, coordDest);
break;
case this.$class.END_END:
this._drawArrowEndEnd(coordOrig, coordDest);
break;
case this.$class.END_START:
default:
this._drawArrowEndStart(coordOrig, coordDest);
}
},
_drawArrowStartStart : function(coordOrig, coordDest){
var yorig = coordOrig.top -
ganttz.TaskComponent.CORNER_WIDTH/2 +
this.$class.HALF_DEPENDENCY_PADDING;
var xorig = coordOrig.left - this.$class.HALF_DEPENDENCY_PADDING;
var xend = coordDest.left + this.$class.HALF_DEPENDENCY_PADDING;
var yend = coordDest.top - this.$class.HALF_DEPENDENCY_PADDING;
if (yend < yorig) yorig = coordOrig.top + this.$class.DEPENDENCY_PADDING;
var width1 = ganttz.TaskComponent.CORNER_WIDTH;
var width2 = Math.abs(xend - xorig) + ganttz.TaskComponent.CORNER_WIDTH;
var height = Math.abs(yend - yorig);
if (xorig > xend) {
width1 = width2;
width2 = ganttz.TaskComponent.CORNER_WIDTH;
}
// First segment
var depstart = this._findImageElement('start');
depstart.css({ top : yorig,
left : (xorig - width1),
width : width1 ,
display : 'inline'})
// Second segment
var depmid = this._findImageElement('mid');
var depmidcss = {left : depstart.css('left'), height : height};
if (yend > yorig) {
depmidcss.top = yorig;
} else {
depmidcss.top = yend;
}
depmid.css(depmidcss);
// Third segment
var depend = this._findImageElement('end');
depend.css({ top : yend,
left : depstart.css('left'),
width : width2 - ganttz.TaskComponent.HALF_HEIGHT});
var deparrow = this._findImageElement('arrow');
deparrow.css({top : (yend - ganttz.TaskComponent.HALF_HEIGHT),left : xend - 15});
},
_drawArrowEndEnd : function(coordOrig, coordDest){
var xorig = coordOrig.left - this.$class.DEPENDENCY_PADDING;
var yorig = coordOrig.top - ganttz.TaskComponent.CORNER_WIDTH/2 + this.$class.HALF_DEPENDENCY_PADDING;
var xend = coordDest.left + this.$class.HALF_DEPENDENCY_PADDING;
var yend = coordDest.top - this.$class.DEPENDENCY_PADDING;
var width1 = Math.abs(xend - xorig) + ganttz.TaskComponent.CORNER_WIDTH;
var width2 = ganttz.TaskComponent.CORNER_WIDTH;
var height = Math.abs(yend - yorig);
if (xorig > xend) {
width2 = width1;
width1 = ganttz.TaskComponent.CORNER_WIDTH;
}
// First segment
var depstart = this._findImageElement('start');
var depstartcss = {left : xorig, width : width1, display : 'inline'}
if (yend > yorig)
depstartcss.top = yorig ;
else
depstartcss.top = yorig + ganttz.TaskComponent.HEIGHT;
depstart.css(depstartcss);
// Second segment
var depmid = this._findImageElement('mid');
var depmidcss = {left : (xorig + width1), height : height};
if (yend > yorig) {
depmidcss.top = yorig;
} else {
depmidcss.top = yend;
depmidcss.height = height + 10;
}
depmid.css(depmidcss);
// Third segment
var depend = this._findImageElement('end');
depend.css({ left : (xorig + width1 - width2),
top:yend,
width:width2 });
var deparrow = this._findImageElement('arrow');
deparrow.attr('src', this.$class.getImagesDir() + "arrow3.png");
deparrow.css({top : yend - 5, left : xend - 8});
},
_drawArrowEndStart : function(coordOrig, coordDest){
var xorig = coordOrig.left - this.$class.DEPENDENCY_PADDING;
var yorig = coordOrig.top - this.$class.HALF_DEPENDENCY_PADDING;
var xend = coordDest.left - this.$class.DEPENDENCY_PADDING;
var yend = coordDest.top - this.$class.HALF_DEPENDENCY_PADDING;
var width = (xend - xorig);
var xmid = xorig + width;
// First segment not used
var depstart = this._findImageElement('start');
depstart.hide();
// Second segment not used
var depmid = this._findImageElement('mid');
var depmidcss;
if (yend > yorig)
depmidcss = {top : yorig, height : yend - yorig};
else
depmidcss = {top : yend, height : (yorig - yend)};
depmidcss.left = xorig;
depmid.css(depmidcss);
var depend = this._findImageElement('end');
var dependcss = {top : yend, left : xorig, width : width};
if(width < 0) {
dependcss.left = xend;
dependcss.width = Math.abs(width);
}
depend.css(dependcss);
var deparrow = this._findImageElement('arrow');
var deparrowsrc, deparrowcss;
if ( width == 0 ) {
deparrowcss = {top : (yend - 10) , left : (xend - 5)};
deparrowsrc = this.$class.getImagesDir() + "arrow2.png";
if ( yorig > yend ) {
deparrowcss = {top : yend};
deparrowsrc = this.$class.getImagesDir() + "arrow4.png";
}
} else {
deparrowcss = {top : (yend -5), left : (xend - 10)};
deparrowsrc = this.$class.getImagesDir() + "arrow.png";
if (width < 0) {
deparrowcss = {top : (yend - 5), left : xend}
deparrowsrc = this.$class.getImagesDir() + "arrow3.png";
}
}
deparrow.attr('src', deparrowsrc);
deparrow.css(deparrowcss);
},
findPos_ : function(element){
var pos1 = jq('#listdependencies').offset();
var pos2 = element.offset();
return {left : (pos2.left - pos1.left), top : (pos2.top - pos1.top)};
},
_findImageElement : function(name) {
var img = jq('.' + name + '', this.$n());
return img;
},
setupArrow_ : function(){
var image_data = [ [ "start", "pixel.gif" ], [ "mid", "pixel.gif" ],
[ "end", "pixel.gif" ], [ "arrow", "arrow.png" ] ];
var img;
var insertPoint = jq(this.$n());
for ( var i = 0; i < image_data.length; i++) {
img = jq(document.createElement('img'));
img.attr({
'class' : image_data[i][0] + " extra_padding",
'src' : this.$class.getImagesDir() + image_data[i][1]
});
insertPoint.append(img);
}
}
},{
END_END : "END_END",
END_START : "END_START",
START_START : "START_START",
HALF_DEPENDENCY_PADDING : 2,
DEPENDENCY_PADDING : 4,
DRAGABLE_PADDING : 20, // Drag padding for dependency creation
getImagesDir : function(){
return "/" + common.Common.webAppContextPath() + "/zkau/web/ganttz/img/";
}
})
ganttz.DependencyComponent = zk.$extends(ganttz.DependencyComponentBase,{
$define : {
idTaskOrig : null,
idTaskEnd : null,
dependencyType : null
},
bind_ : function(){
this.$supers('bind_', arguments);
//this.setupArrow_();
/*maybe move this listener to the $init method*/
YAHOO.util.Event.onDOMReady(this.proxy(function() {
this.draw();
}));
},
draw : function() {
this._withOriginAndDestination(function(origin, destination) {
var orig = this.findPos_(origin);
var dest = this.findPos_(destination);
// This corner case may depend on dependence type
var offsetX = origin.outerWidth() - ganttz.TaskComponent.CORNER_WIDTH;
var separation = orig.left + origin.outerWidth() - dest.left;
if (separation > 0) {
offsetX = offsetX - separation;
}
if (this.getDependencyType() == this.$class.END_START
|| this.getDependencyType() == null) {
orig.left = orig.left + Math.max(0, offsetX);
} else if (this.getDependencyType() == this.$class.END_END) {
orig.left = orig.left + origin.outerWidth();
dest.left = dest.left + destination.outerWidth();
}
orig.top = orig.top + ganttz.TaskComponent.HEIGHT;
dest.top = dest.top + ganttz.TaskComponent.HALF_HEIGHT;
if (orig.top > dest.top) {
orig.top = orig.top - ganttz.TaskComponent.HEIGHT;
}
this.drawArrow_(orig, dest);
});
},
_withOriginAndDestination : function(f) {
f.call(this, jq('#' + this.getIdTaskOrig()), jq('#' + this.getIdTaskEnd()));
}
},{});
ganttz.UnlinkedDependencyComponent = zk.$extends(ganttz.DependencyComponentBase,{
$init : function(){
this.$supers('$init', arguments);
this._DOMlisttasks = jq('#listtasks');
this._DOMlistdependencies = jq('#listdependencies');
this._WGTganttpanel = ganttz.GanttPanel.getInstance();
},
bind_ : function(){
this.$supers('bind_', arguments);
/*We use document.documentElement as the DOM element to attach this listener
* because document.documentElement always gets the key events (in all browsers)*/
this.domListen_(document.documentElement,'onKeyup','_handleKeyUp');
this._updateArrow();
},
unbind_ : function(){
this.domUnlisten_(document.documentElement,'onKeyup','_handleKeyUp');
this.domUnlisten_(this._WGTganttpanel.$n(), 'onMousemove', '_updateArrow');
this.domUnlisten_(this._WGTganttpanel.$n(), 'onClick', '_consolidateDependency');
this.$supers('unbind_', arguments);
},
draw : function(){
this.domListen_(this._WGTganttpanel.$n(), 'onMousemove', '_updateArrow');
this.domListen_(this._WGTganttpanel.$n(), 'onClick', '_consolidateDependency');
},
setOrigin : function(origin){
this._DOMorigin = jq(origin);
this._WGTorigin = ganttz.TaskComponent.$(origin.id);
},
_consolidateDependency : function(){
var dependency = null;
if ((dependency = this._isOverTask()) != null){
this._WGTorigin.consolidateNewDependency(dependency);
}
/* We remove the dependency line. If the user clicked over a
* task, a new dependecy line will be created */
ganttz.DependencyList.getInstance().removeChild(this);
},
_isOverTask : function() {
var tasksArray = jq('div[z\\.type="ganttz.task.Task"]');
var overTask = null;
tasksArray.each(function(index, element){
if(ganttz.TaskComponent.$(element.id).mouseOverTask) overTask = ganttz.TaskComponent.$(element.id);
});
return overTask;
},
updateCoordOrigin : function(){
var coordOrigin = this.findPos_(this._DOMorigin);
coordOrigin.left = coordOrigin.left
+ Math.max(0, this._DOMorigin.outerWidth() -
ganttz.TaskComponent.CORNER_WIDTH);
coordOrigin.top = coordOrigin.top - this._DOMlisttasks.position().top +
this._DOMlistdependencies.position().top +
ganttz.TaskComponent.HEIGHT;
this._coordOrigin = coordOrigin;
return this._coordOrigin;
},
_updateArrow : function(event){
if (! this._coordOrigin ) this.updateCoordOrigin();
var coordDest;
coordDest = this._findCoordsForMouse();
this.drawArrow_(this._coordOrigin, coordDest);
},
_findCoordsForMouse : function(){
var pos1 = YAHOO.util.Dom.getXY('listtasks');
return { left : this._WGTganttpanel.getXMouse() - pos1[0],
top: this._WGTganttpanel.getYMouse() - pos1[1]};
},
_handleKeyUp: function(event){
if ( event.keyCode != 27 )
return;
event.stop();
ganttz.DependencyList.getInstance().removeChild(this);
}
})
zk.afterLoad('ganttz',function(){
ganttz.UnlinkedDependencyComponent.molds = ganttz.DependencyComponent.molds;
})

View file

@ -0,0 +1,15 @@
zk.$package("ganttz");
ganttz.DependencyList = zk.$extends(zk.Widget, {
$init : function(){
this.$supers('$init', arguments);
this.$class.setInstance(this);
}
},{
setInstance : function(instance){
this._instance = instance;
},
getInstance : function(){
return this._instance;
}
});

View file

@ -0,0 +1,77 @@
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);
this._initializeProperties();
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._timeplotcontainer.each(jq.proxy(function(index, element){
jq(element).css("left", "-" + this._rightpannellayout.scrollLeft() + "px")
}, this));
},
adjust_height : function(){
jq(this.$n()).height(jq('#scroll_container').height());
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();
},
_initializeProperties : function(){
/*The canvas is inserted in the DOM after this component so
* it's not available right now. We set up a handler to do
* job*/
jq(document).ready(jq.proxy(
function(){ this._timeplotcontainer = jq('canvas.timeplot-canvas');
},this));
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;
}
});

View file

@ -0,0 +1,2 @@
zk.$package("ganttz");
ganttz.Milestone = zk.$extends(ganttz.TaskComponent, {},{});

View file

@ -0,0 +1,75 @@
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');
},
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());
DOMTimetracker.width(DOMScrollContainer.innerWidth());
DOMTimetracker.height(
Math.max(
jq(window).height() -
this.$class.TIMETRACKER_OFFSET_TOP +
26),
(
jq('#listdetails_container').height() +
12));
DOMScrollContainer.height(
jq(window).height() -
this.$class.TIMETRACKER_OFFSET_TOP -
this.$class.FOOTER_HEIGHT +
this.$class.SCROLLBAR_WIDTH * 2);
// Inner divs need recalculation to adjust to new scroll displacement lenght
ganttz.GanttPanel.getInstance().reScrollY(jq('#listdetails_container').height());
// Inner divs need recalculation to adjust to new scroll displacement lenght
ganttz.GanttPanel.getInstance().reScrollX(DOMWatermark.outerWidth());
},
_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}));
}
},{
FOOTER_HEIGHT : 40, // Design-relative footer height
TIMETRACKER_OFFSET_TOP : 120, // Design-relative height above timetracker
TASKDETAILS_WIDTH : 300, // Taskdetails column fixed width (300)
TASKDETAILS_HEIGHT : 180, // 260 // Design-relative reservated height for taskdetails (300,260)
SCROLLBAR_WIDTH : 15, // Scrollbars default width
getInstance : function(){
return this._instance;
},
setInstance : function(instance){
this._instance = instance;
}
})

View file

@ -0,0 +1,232 @@
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
* */
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
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() {
this.initConstraints();
}, this, true);
},
initConstraints : function() {
// Get the top, right, bottom and left positions
var region = myDom.getRegion(this.cont);
// Get the element we are working on
var el = this.getEl();
// Get the xy position of it
var xy = myDom.getXY(el);
// Get the width and height
var width = parseInt(myDom.getStyle(el, 'width'), 10);
var height = parseInt(myDom.getStyle(el, 'height'), 10);
// Set left to x minus left
var left = xy[0] - region.left;
// Set right to right minus x minus width
var right = region.right - xy[0] - width;
// Set top to y minus top
var top = xy[1] - region.top;
// 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
},
$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}));
},
_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
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());
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!=null) {
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);
},
resizeCompletionAdvance : function(width){
jq('#' + this.uuid + ' > .completion:first').css('width', width);
},
resizeCompletion2Advance : function(width){
jq('#' + this.uuid + ' > .completion2:first').css('width', width);
},
showTaskLabel : function(){
jq('#'+ this.uuid + ' .task-labels').show();
},
hideTaskLabel : function(){
jq('#'+ this.uuid + ' .task-labels').hide();
},
showResourceTooltip : function(){
jq('#'+ this.uuid + ' .task-resources').show();
},
hideResourceTooltip : function(){
jq('#'+ this.uuid + ' .task-resources').hide();
},
setClass : function(cssClass){
jq(this.$n()).addClass(cssClass);
}
},{
//"Class" methods and properties
_TOOLTIP_DELAY : 10, // 10 milliseconds
_PERSPECTIVES_WIDTH : 80,
CORNER_WIDTH : 20,
HEIGHT : 10,
HALF_HEIGHT : 5
});

View file

@ -0,0 +1,3 @@
zk.$package("ganttz");
ganttz.TaskContainerComponent = zk.$extends(ganttz.TaskComponent,{})

View file

@ -0,0 +1,31 @@
zk.$package("ganttz");
ganttz.TaskList = zk.$extends(zk.Widget, {
$init : function(){
this.$supers('$init', arguments);
this.$class.setInstance(this);
},
showAllTaskLabels : function(){
for(var child = this.firstChild; child; child = child.nextSibling)
child.showTaskLabel();
},
hideAllTaskLabels : function(){
for(var child = this.firstChild; child; child = child.nextSibling)
child.hideTaskLabel();
},
showResourceTooltips : function(){
for(var child = this.firstChild; child; child = child.nextSibling)
child.showResourceTooltip();
},
hideResourceTooltips : function(){
for(var child = this.firstChild; child; child = child.nextSibling)
child.hideResourceTooltip();
}
},{//Class stuff
setInstance : function(instance){
this.instance = instance;
},
getInstance : function(){
return this.instance;
}
});

View file

@ -0,0 +1,16 @@
zk.$package("ganttz");
ganttz.TaskRow = zk.$extends(zk.Widget, {
hideTaskLabel : function(){
this.firstChild.hideTaskLabel();
},
showTaskLabel : function(){
this.firstChild.showTaskLabel();
},
hideResourceTooltip : function(){
this.firstChild.hideResourceTooltip();
},
showResourceTooltip : function(){
this.firstChild.showResourceTooltip();
}
});

View file

@ -0,0 +1,26 @@
zk.$package("ganttz");
ganttz.TimeTracker = zk.$extends(zk.Macro,{
$init : function(){
this.$supers('$init', arguments);
this.$class.setInstance(this);
},
bind_ : function (){
this.$supers('bind_', arguments);
this._timetrackerGap = jq('.timetrackergap');
this._timetrackerHeader = jq('#timetrackerheader .z-vbox');
},
realWidth : function(){
return this._timetrackerHeader.width();
},
scrollLeft : function(ammount){
this._timetrackerGap.css({left : -ammount});
}
},{
getInstance : function(){
return this._instance;
},
setInstance : function(instance){
this._instance = instance;
}
})

View file

@ -1,318 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
/**
* Javascript behaviuor for TaskList elements
* @author Javier Morán Rúa <jmoran@igalia.com>
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
webapp_context_path = window.location.pathname.split( '/' )[1];
zkPlanner = {};
zkPlanner.constants = {
END_START: "END_START",
START_START: "START_START",
END_END: "END_END"
};
zkPlanner.getImagesDir = function() {
return "/" + webapp_context_path + "/zkau/web/ganttz/img/";
}
zkPlanner.init = function(planner){
}
zkPlanner.findImageElement = function(arrow, name) {
var children = arrow.getElementsByTagName("div");
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.getAttribute("class").indexOf(name) != -1) {
return child;
}
}
return null;
}
function get_origin() {
return YAHOO.util.Dom.getXY('listdependencies');
}
zkPlanner.findPos = function(obj) {
var pos1 = get_origin();
var pos2 = YAHOO.util.Dom.getXY(obj.id);
return [ pos2[0] - pos1[0], pos2[1] - pos1[1] ];
}
zkPlanner.findPosForMouseCoordinates = function(x, y){
/* var pos1 = get_origin() */
var pos1 = YAHOO.util.Dom.getXY('listtasks');
return [x - pos1[0], y - pos1[1]];
}
function getContextPath(element){
return element.getAttribute('contextpath');
}
zkPlanner.setupArrow = function(arrowDiv){
var image_data = [ [ "start", "pixel.gif" ], [ "mid", "pixel.gif" ],
[ "end", "pixel.gif" ], [ "arrow", "arrow.png" ] ];
for ( var i = 0; i < image_data.length; i++) {
var img = document.createElement('div');
img.setAttribute("class", image_data[i][0] );
img.src = this.getImagesDir() + image_data[i][1];
arrowDiv.appendChild(img);
}
}
zkPlanner.drawArrow = function(dependency, orig, dest) {
switch(dependency.getAttribute('type'))
{
case zkPlanner.constants.START_START:
zkPlanner.drawArrowStartStart(dependency, orig, dest);
break;
case zkPlanner.constants.END_END:
zkPlanner.drawArrowEndEnd(dependency, orig, dest);
break;
case zkPlanner.constants.END_START:
default:
zkPlanner.drawArrowEndStart(dependency, orig, dest);
}
}
zkPlanner.drawArrowStartStart = function(arrow, orig, dest){
var xorig = orig[0] - zkTask.HALF_DEPENDENCY_PADDING;
var yorig = orig[1] - zkTask.CORNER_WIDTH/2 + zkTask.HALF_DEPENDENCY_PADDING;
var xend = dest[0] + zkTask.HALF_DEPENDENCY_PADDING;
var yend = dest[1] - zkTask.HALF_DEPENDENCY_PADDING;
if (yend < yorig) {
yorig = orig[1] + zkTask.DEPENDENCY_PADDING;
}
width1 = zkTask.CORNER_WIDTH;
width2 = Math.abs(xend - xorig) + zkTask.CORNER_WIDTH;
height = Math.abs(yend - yorig);
if (xorig > xend) {
width1 = width2;
width2 = zkTask.CORNER_WIDTH;
}
// First segment
var depstart = this.findImageElement(arrow, 'start');
depstart.style.left = (xorig - width1) + "px";
depstart.style.top = yorig + "px";
depstart.style.width = width1 + "px";
depstart.style.display = "inline";
// Second segment
var depmid = this.findImageElement(arrow, 'mid');
depmid.style.left = depstart.style.left;
if (yend > yorig) {
depmid.style.top = yorig + "px";
} else {
depmid.style.top = yend + "px";
}
depmid.style.height = height + "px";
// Third segment
var depend = this.findImageElement(arrow, 'end');
depend.style.left = depstart.style.left;
depend.style.top = yend + "px";
depend.style.width = width2 - zkTask.HALF_HEIGHT + "px";
var deparrow = this.findImageElement(arrow, 'arrow');
// deparrow.src = this.getImagesDir()+"arrow.png";
deparrow.setAttribute("class", "arrow point-east");
deparrow.style.top = yend - zkTask.HALF_HEIGHT + "px";
deparrow.style.left = xend - 15 + "px";
}
zkPlanner.drawArrowEndEnd = function(arrow, orig, dest){
var xorig = orig[0] - zkTask.DEPENDENCY_PADDING;
var yorig = orig[1] - zkTask.CORNER_WIDTH/2 + zkTask.HALF_DEPENDENCY_PADDING;
var xend = dest[0] + zkTask.HALF_DEPENDENCY_PADDING;
var yend = dest[1] - zkTask.DEPENDENCY_PADDING;
width1 = Math.abs(xend - xorig) + zkTask.CORNER_WIDTH;
width2 = zkTask.CORNER_WIDTH;
height = Math.abs(yend - yorig);
if (xorig > xend) {
width2 = width1;
width1 = zkTask.CORNER_WIDTH;
}
// First segment
var depstart = this.findImageElement(arrow, 'start');
depstart.style.left = xorig + "px";
if (yend > yorig) {
depstart.style.top = yorig + "px";
} else {
depstart.style.top = yorig + zkTask.HEIGHT + "px";
}
depstart.style.width = width1 + "px";
depstart.style.display = "inline";
// Second segment
var depmid = this.findImageElement(arrow, 'mid');
depmid.style.left = (xorig + width1) + "px";
if (yend > yorig) {
depmid.style.top = yorig + "px";
} else {
depmid.style.top = yend + "px";
height = height + 10;
}
depmid.style.height = height + "px";
// Third segment
var depend = this.findImageElement(arrow, 'end');
depend.style.left = (xorig + width1 - width2) + "px";
depend.style.top = yend + "px";
depend.style.width = width2 + "px";
var deparrow = this.findImageElement(arrow, 'arrow');
// deparrow.src = this.getImagesDir()+"arrow3.png";
deparrow.setAttribute("class", "arrow point-west");
deparrow.style.top = yend - 5 + "px";
deparrow.style.left = xend - 8 + "px";
}
zkPlanner.drawArrowEndStart = function(arrow, orig, dest){
var xorig = orig[0] - zkTask.DEPENDENCY_PADDING;
var yorig = orig[1] - zkTask.HALF_DEPENDENCY_PADDING;
var xend = dest[0] - zkTask.DEPENDENCY_PADDING;
var yend = dest[1] - zkTask.HALF_DEPENDENCY_PADDING;
var width = (xend - xorig);
var xmid = xorig + width;
// First segment not used
var depstart = this.findImageElement(arrow, 'start');
depstart.style.display = "none";
// Second segment not used
var depmid = this.findImageElement(arrow, 'mid');
if (yend > yorig) {
depmid.style.top = yorig + "px";
depmid.style.height = yend - yorig + "px";
} else {
depmid.style.top = yend + "px";
depmid.style.height = yorig - yend + "px";
}
depmid.style.left = xorig + "px";
var depend = this.findImageElement(arrow, 'end');
depend.style.top = yend + "px";
depend.style.left = xorig + "px";
depend.style.width = width + "px";
if (width < 0) {
depend.style.left = xend + "px";
depend.style.width = Math.abs(width) + "px";
}
var deparrow = this.findImageElement(arrow, 'arrow');
if ( width == 0 ) {
deparrow.setAttribute("class", "arrow point-south");
deparrow.style.top = yend - 10 + "px";
deparrow.style.left = xend - 5 + "px";
if ( yorig > yend ) {
deparrow.setAttribute("class", "arrow point-north");
deparrow.style.top = yend + "px";
}
} else {
deparrow.style.top = yend - 5 + "px";
deparrow.style.left = xend - 10 + "px";
deparrow.setAttribute("class", "arrow point-east");
if (width < 0) {
deparrow.setAttribute("class", "arrow point-west");
deparrow.style.left = xend + "px";
deparrow.style.top = yend - 5 + "px";
}
}
}
zkDependency = {};
zkDependency.origin = function(dependency) {
var id = dependency.getAttribute("idTaskOrig");
return document.getElementById(id);
}
zkDependency.destination = function(dependency) {
var id = dependency.getAttribute("idTaskEnd");
return document.getElementById(id);
}
zkDependency.setCSSClass = function(dependency,value) {
dependency.setAttribute("class", value);
}
zkDependency.draw = function(dependency) {
var orig = zkPlanner.findPos(this.origin(dependency));
var dest = zkPlanner.findPos(this.destination(dependency));
// This corner case may depend on dependence type
offsetX = this.origin(dependency).offsetWidth - zkTask.CORNER_WIDTH;
separation = orig[0] + this.origin(dependency).offsetWidth - dest[0];
if (separation > 0) {
offsetX = offsetX - separation;
}
if (dependency.getAttribute('type') == zkPlanner.constants.END_START
|| dependency.getAttribute('type') == null) {
orig[0] = orig[0] + Math.max(0, offsetX);
} else if (dependency.getAttribute('type') == zkPlanner.constants.END_END) {
orig[0] = orig[0] + this.origin(dependency).offsetWidth;
dest[0] = dest[0] + this.destination(dependency).offsetWidth;
}
orig[1] = orig[1] + zkTask.HEIGHT;
dest[1] = dest[1] + zkTask.HALF_HEIGHT;
if ((orig[1] > dest[1])) {
orig[1] = orig[1] - zkTask.HEIGHT;
}
zkPlanner.drawArrow(dependency, orig, dest);
}
zkDependency.init = function(dependency) {
zkPlanner.setupArrow(dependency);
var parent = dependency.parentNode;
if (parent.id !== "listdependencies") {
document.getElementById("listdependencies").appendChild(dependency);
}
YAHOO.util.Event.onDOMReady(function() {
var origin = zkDependency.origin(dependency);
var destination = zkDependency.destination(dependency);
zkDependency.draw(dependency);
zkTask.addRelatedDependency(origin, dependency);
zkTask.addRelatedDependency(destination, dependency);
});
}

View file

@ -1,25 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
zkDependencylist = {};
zkDependencylist.init = function (cmp) {
}

View file

@ -1,86 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
/**
* Javascript behaviuor for GanttPanel element
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
zkGanttPanel = {};
SCROLL_DAY = 0;
zkGanttPanel.init = function(cmp){
}
zkGanttPanel.update_day_scroll = function(cmp,previousPixelPerDay) {
fromPixelToDay(previousPixelPerDay);
}
/**
* Scrolls horizontally the ganttpanel when the zoom has resized the component
* width.
*/
zkGanttPanel.scroll_horizontal = function(cmp,daysDisplacement) {
SCROLL_DAY = daysDisplacement;
}
zkGanttPanel.move_scroll = function(cmp,diffDays,pixelPerDay) {
fromDayToPixel(diffDays,pixelPerDay);
}
function fromPixelToDay(previousPixelPerDay){
var div1 = document.getElementById ("ganttpanel").parentNode;
var div2 = div1.parentNode;
var div3 = div2.parentNode;
var maxHPosition = div3.scrollWidth - div3.clientWidth;
if( maxHPosition > 0 ){
var proportion = div3.scrollWidth / maxHPosition;
var positionInScroll = div3.scrollLeft;
var positionInPx = positionInScroll * proportion;
if(positionInPx > 0){
var position = positionInPx / previousPixelPerDay;
var day = position;
SCROLL_DAY = position;
}
}
}
function fromDayToPixel(diffDays,pixelPerDay){
var div1 = document.getElementById ("ganttpanel").parentNode;
var div2 = div1.parentNode;
var div3 = div2.parentNode;
var day = SCROLL_DAY;
day += parseInt(diffDays);
var newPosInPx = parseInt(day * pixelPerDay);
var maxHPosition = div3.scrollWidth - div3.clientWidth;
var newProportion = div3.scrollWidth / maxHPosition;
if( newProportion > 0){
var newPosInScroll = newPosInPx / newProportion;
if(newPosInScroll < 0){
newPosInScroll = 0;
}
div1.scrollLeft = newPosInScroll;
div2.scrollLeft = newPosInScroll;
div3.scrollLeft = newPosInScroll;
}
}

View file

@ -1,25 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
// making believe to zk that milestone.js exists, so it doesn't throw error.
// zkMilestone code is in tasklist.js
//This way there can be a schedule showing only tasks or taskcontainers.

View file

@ -0,0 +1,10 @@
function(out){
out.push('<div ', this.domAttrs_(),
'class="dependency"',
'z.type="ganttz.dependency.Dependency"',
'idTaskOrig="', this.getIdTaskOrig(),'"',
'idTaskEnd="', this.getIdTaskEnd(),'"',
'type="', this.getDependencyType(),'"',
'>');
out.push('</div>');
}

View file

@ -0,0 +1,11 @@
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>');
out.push('</div>');
}

View file

@ -0,0 +1,23 @@
function(out){
out.push('<div ',
'z.type="ganttz.ganttpanel.GanttPanel" ',
this.domAttrs_(),
'>');
out.push('<div id="ganttpanel">');
for (var w = this.firstChild; w; w = w.nextSibling)
w.redraw(out);
out.push('</div>');
out.push('</div>');
out.push('<br>');
out.push('<div id="ganttpanel_scroller_x">',
'<div id="ganttpanel_inner_scroller_x"></div>',
'</div>');
out.push('<div id="ganttpanel_scroller_y">',
'<div id="ganttpanel_inner_scroller_y"/></div>',
'</div>');
}

View file

@ -0,0 +1,12 @@
function(out){
out.push('<div ', this.domAttrs_(),
'z.type="ganttz.task.Task"',
'idTask="', this.id,'"',
'z.autoz="true"',
'class="milestone"',
'>');
out.push('<div class="completion"></div>');
out.push('<div class="completion2"></div>');
out.push('<div class="milestone_end"></div>');
out.push('</div>');
}

View file

@ -0,0 +1,19 @@
function(out){
out.push('<div ',this.domAttrs_(),
' z.type="ganttz.task.Task" idTask="', this.id,'"',
' class="box" >');
out.push('<div class="task-labels">', this.getLabelsText(),'</div>');
out.push('<div class="task-resources">');
out.push('<div class="task-resources-inner">', this.getResourcesText(),'</div>');
out.push('</div>');
out.push('<div class="completion"></div>');
out.push('<div class="completion2"></div>');
out.push('<div id="tasktooltip', this.uuid,'" class="task_tooltip">',
this.getTooltipText(),
'</div>');
out.push('</div>');
}

View file

@ -0,0 +1,35 @@
function(out){
out.push('<div ', this.domAttrs_(),
'z.type="ganttz.taskcontainer.TaskContainer"',
'idTask="', this.id,'"',
'z.autoz="true"',
'class="taskgroup"',
'>');
out.push('<div class="task-labels">',
this.getLabelsText(),
'</div>');
out.push('<div class="task-resources">',
'<div class="task-resources-inner">',
this.getResourcesText(),
'</div>',
'</div>');
out.push('<div class="taskcontainer_completion">',
'<div class="completion"></div>',
'<div class="completion2"></div>',
'</div>');
out.push('<div class="border-container">',
'<div class="taskgroup_start"></div>',
'<div class="taskgroup_end"></div>',
'</div>');
out.push('<div id="tasktooltip', this.uuid, '"',
'class="task_tooltip">',
this.getTooltipText(),
'</div>');
out.push('</div>');
}

View file

@ -0,0 +1,14 @@
function(out){
out.push('<script type="text/javascript">',
'document.body.class = "yui-skin-sam";',
'</script>');
out.push('<div id="scroll_container">');
out.push('<div z.type="gantt.tasklist.TaskList" z.autoz="true" ' + this.domAttrs_() + '>');
out.push('<div id="listtasks">');
for(var w = this.firstChild; w; w = w.nextSibling)
w.redraw(out);
out.push('</div>');
out.push('</div>');
out.push('</div>');
}

View file

@ -0,0 +1,8 @@
function(out){
out.push('<div id="'+ this.uuid + '" class="row" z.valor="boxid=' + this.uuid +'">');
for(var w = this.firstChild; w; w = w.nextSibling)
w.redraw(out);
out.push('<div id="deadline'+ this.uuid + '" class="deadline"></div>');
out.push('<div id="consolidatedline' + this.uuid + '" class="consolidatedline"></div>');
out.push('</div>');
}

View file

@ -1,94 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
/**
* Javascript behaviuor for Planner elements
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
zkPlanner = {};
zkPlanner.constants = {
END_START: "END_START",
START_START: "START_START",
END_END: "END_END"
};
zkPlanner.getImagesDir = function() {
return webapp_context_path + "/zkau/web/ganttz/img/";
}
zkPlanner.init = function(planner){
}
zkPlanner.findImageElement = function(arrow, name) {
var children = arrow.getElementsByTagName("div");
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.getAttribute("class").indexOf(name) != -1) {
return child;
}
}
return null;
}
function get_origin() {
return YAHOO.util.Dom.getXY('listdependencies');
}
zkPlanner.findPos = function(obj) {
var pos1 = get_origin();
var pos2 = YAHOO.util.Dom.getXY(obj.id);
return [ pos2[0] - pos1[0], pos2[1] - pos1[1] ];
}
zkPlanner.findPosForMouseCoordinates = function(x, y){
/* var pos1 = get_origin() */
var pos1 = YAHOO.util.Dom.getXY('listtasks');
return [x - pos1[0], y - pos1[1]];
}
function getContextPath(element){
return element.getAttribute('contextpath');
}
zkPlanner.setupArrow = function(arrowDiv){
var image_data2 = [ "start", "mid", "end", "arrow" ];
for ( var i = 0; i < image_data2.length; i++) {
var img = document.createElement('div');
img.setAttribute("class", image_data[i]+" extra_padding");
arrowDiv.appendChild(img);
}
}
zkPlanner.drawArrow = function(dependency, orig, dest) {
switch(dependency.getAttribute('type'))
{
case zkPlanner.constants.START_START:
zkPlanner.drawArrowStartStart(dependency, orig, dest);
break;
case zkPlanner.constants.END_END:
zkPlanner.drawArrowEndEnd(dependency, orig, dest);
break;
case zkPlanner.constants.END_START:
default:
zkPlanner.drawArrowEndStart(dependency, orig, dest);
}
}

View file

@ -0,0 +1,8 @@
zk.$package("ganttz.resourceload");
ganttz.resourceload.ResourceLoadComponent = zk.$extends(zk.Widget,{
$define : {
resourceLoadName : null,
resourceLoadType : null
}
});

View file

@ -0,0 +1,73 @@
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');
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
*
* 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());
jq('#timetracker').width(jq(this.$n()).innerWidth());
/*this.$n() is <div class="resourceloadlist" ...>*/
jq(this.$n()).width(jq('.second_level_ :first'));
},
adjustResourceLoadRows : function(){
jq('.row_resourceload').each(jq.proxy(function(index, element){
jq(element).width( jq(this.$n()).innerWidth() );
}, this));
},
_listenToScroll : function(){
var scrolledPannelScrollLeft = jq('.rightpanellayout div:first').scrollLeft();
var scrolledPannelScrollTop = jq('.rightpanellayout div:first').scrollTop();
jq('canvas.timeplot-canvas').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");
}
},{ //Class stuff
WATERMARK_MIN_HEIGHT : 450,
WATERMARK_MARGIN_BOTTOM : 40,
setInstance : function(instance){
this._instance = instance;
},
getInstance : function(){
return this._instance;
}
});

View file

@ -0,0 +1,10 @@
function(out){
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);
out.push('</div>');
}

View file

@ -0,0 +1,8 @@
function(out){
out.push('<div ' + this.domAttrs_(),
' class="resourceloadlist"',
' z.type="ganttz.resourceload.resourceloadlist.ResourceLoadList">');
for(var w = this.firstChild; w; w = w.nextSibling)
w.redraw(out);
out.push('</div>');
}

View file

@ -1,183 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
zkResourcesLoadList = addResourcesLoadListMethods( {});
zkResourcesLoadList.WATERMARK_MIN_HEIGHT = 450;
zkResourcesLoadList.WATERMARK_MARGIN_BOTTOM = 40;
zkResourcesLoadList.recalculateTimetrackerHeight = function (cmp) {
zkResourcesLoadList.resourceloadlist = function(elem) {
return YAHOO.util.Selector.query('.resourceloadlist')[0];
}
zkResourcesLoadList.firstWatermarkColumn = function(elem) {
return YAHOO.util.Selector.query('.rightpanellayout tr#watermark td')[0];
}
if (zkResourcesLoadList.resourceloadlist() != undefined && zkResourcesLoadList.firstWatermarkColumn() != undefined) {
var height = Math.max(
zkResourcesLoadList.resourceloadlist().clientHeight + zkResourcesLoadList.WATERMARK_MARGIN_BOTTOM,
zkResourcesLoadList.WATERMARK_MIN_HEIGHT);
zkResourcesLoadList.firstWatermarkColumn().style.height = height + "px";
}
}
function addResourcesLoadListMethods(object) {
var scrollSync;
var SCROLL_DAY = 0;
function watermark() {
return document.getElementById('watermark');
}
function timetracker() {
return document.getElementById('timetracker');
}
function resourceloadlist() {
return YAHOO.util.Selector.query('.resourceloadlist')[0];
}
function taskspanelgap() {
return YAHOO.util.Selector.query('.taskspanelgap')[0];
}
function resourcesloadgraph() {
return YAHOO.util.Selector.query('.resourcesloadgraph div')[0];
}
function scrolledpannel() {
return YAHOO.util.Selector.query('.rightpanellayout div')[0];
}
function timetrackergap() {
return YAHOO.util.Selector.query('.timetrackergap')[0];
}
function leftpanel() {
return YAHOO.util.Selector.query('.leftpanelgap .z-tree-body')[0];
}
function rightpanel() {
return YAHOO.util.Selector.query('.rightpanellayout div')[0];
}
object.init = function(cmp) {
this.adjustTimeTrackerSize(cmp);
YAHOO.util.Event.addListener(window, 'resize',
zkResourcesLoadList.adjustTimeTrackerSize, cmp);
scrollSync = new ScrollSync(cmp);
scrollSync.synchXChangeTo(timetracker);
listenToScroll();
};
function listenToScroll() {
var timetrackergap_ = timetrackergap();
var scrolledpannel_ = scrolledpannel();
var resourcesloadgraph_ = resourcesloadgraph();
var leftpanel_ = leftpanel();
var rightpanel_ = rightpanel();
var onScroll = function() {
var timeplotcontainer_ = YAHOO.util.Selector.query('canvas.timeplot-canvas')[0];
timeplotcontainer_.style["left"] = "-" + scrolledpannel_.scrollLeft + "px";
timetrackergap_.style["left"] = "-" + scrolledpannel_.scrollLeft + "px";
leftpanel_.style["top"] = "-" + scrolledpannel_.scrollTop + "px";
resourcesloadgraph_.scrollLeft = scrolledpannel_.scrollLeft;
};
rightpanel_.onscroll = onScroll;
}
object.adjustTimeTrackerSize = function(cmp) {
zkResourcesLoadList.recalculateTimetrackerHeight();
watermark().style["height"] = cmp.clientHeight + "px";
timetracker().style["width"] = cmp.clientWidth + "px";
/* Set watermark width */
YAHOO.util.Selector.query('.resourceloadlist')[0].style["width"] = YAHOO.util.Selector
.query('.second_level_')[0].clientWidth + "px";
};
object.adjustResourceLoadRows = function(cmp) {
YAHOO.util.Selector.query('.row_resourceload').each(function(node) {
node.style["width"] = cmp.clientWidth + "px";
});
};
object.adjustScrollHorizontalPosition = function(cmp, offsetInPx) {
cmp.scrollLeft = offsetInPx;
}
object.update_day_scroll = function(cmp,previousPixelPerDay) {
var div1 = cmp;
var div2 = div1.parentNode;
var div3 = div2.parentNode;
var maxHPosition = div3.scrollWidth - div3.clientWidth;
if( maxHPosition > 0 ){
var proportion = div3.scrollWidth / maxHPosition;
var positionInScroll = div3.scrollLeft;
var positionInPx = positionInScroll * proportion;
if(positionInPx > 0){
var position = positionInPx / previousPixelPerDay;
var day = position;
SCROLL_DAY = position;
}
}
};
/**
* Scrolls horizontally the ganttpanel when the zoom has resized the component
* width.
*/
object.scroll_horizontal = function(cmp,daysDisplacement) {
SCROLL_DAY = daysDisplacement;
};
object.move_scroll = function(cmp,diffDays,pixelPerDay) {
var div1 = cmp;
var div2 = div1.parentNode;
var div3 = div2.parentNode;
var day = SCROLL_DAY;
day += parseInt(diffDays);
var newPosInPx = parseInt(day * pixelPerDay);
var maxHPosition = div3.scrollWidth - div3.clientWidth;
var newProportion = div3.scrollWidth / maxHPosition;
if( newProportion > 0){
var newPosInScroll = newPosInPx / newProportion;
if(newPosInScroll < 0){
newPosInScroll = 0;
}
div1.scrollLeft = newPosInScroll;
div2.scrollLeft = newPosInScroll;
div3.scrollLeft = newPosInScroll;
}
};
return object;
}

View file

@ -1,29 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
/**
* Javascript behaviuor for ResourcesLoadPanel element
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
zkResourcesLoadPanel = {};
zkResourcesLoadPanel.init = function(cmp){
}

View file

@ -0,0 +1,4 @@
<package name="ganttz.resourceload" language="xul/html">
<widget name="ResourceLoadList"/>
<widget name="ResourceLoadComponent"/>
</package>

View file

@ -1,70 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
function ScrollSync(element){
var xChanges = [];
var yChanges = [];
var notifyScrollX = function(){
for ( var i = 0; i < xChanges.length; i++) {
xChanges[i]();
}
};
var notifyScrollY = function(){
for ( var i = 0; i < yChanges.length; i++) {
yChanges[i]();
}
};
var notifyListeners = function(){
notifyScrollX();
notifyScrollY();
};
var toFunction = function(value){
var result = value;
if(typeof(value) !== 'function'){
result = function(){return synched};
}
return result;
};
this.synchXChangeTo = function(synched){
var target = toFunction(synched);
xChanges.push(function(){ target().scrollLeft = element.scrollLeft; });
};
this.synchYChangeTo = function(synched){
var target = toFunction(synched);
yChanges.push(function(){ target().scrollTop = element.scrollTop; });
};
this.notifyXChangeTo = function(listenerReceivingScroll){
xChanges.push(function(){
listenerReceivingScroll(element.scrollLeft);
});
};
this.notifyYChangeTo = function(listenerReceivingScroll){
yChanges.push(function() {
listenerReceivingScroll(element.scrollTop);
});
};
YAHOO.util.Event.addListener(element,'scroll', notifyListeners);
return this;
}

View file

@ -1,25 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
// making believe to zk that task.js exists, so it doesn't throw error.
// zkTask code is in tasklist.js
//This way there can be a schedule showing only tasks or taskcontainers.

View file

@ -1,25 +0,0 @@
/*
* This file is part of NavalPlan
*
* 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/>.
*/
// making believe to zk that taskcontainer.js exists, so it doesn't throw error.
// zkTaskContainer code is in tasklist.js
//This way there can be a schedule showing only tasks or taskcontainers.

Some files were not shown because too many files have changed in this diff Show more