source: contrib/ProjectManager/inc/class.ganttchart.inc.php @ 3594

Revision 3594, 27.1 KB checked in by afernandes, 13 years ago (diff)

Ticket #1416 - Disponibilizado o módulo ProjectManager? para a comunidade

  • Property svn:executable set to *
Line 
1<?php
2/**
3 * ProjectManager - Gantchart creation
4 *
5 * @link http://www.egroupware.org
6 * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
7 * @package projectmanager
8 * @copyright (c) 2005 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
9 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
10 * @version $Id: class.ganttchart.inc.php 24310 2007-07-16 10:08:15Z ralfbecker $
11 */
12
13include_once(PHPGW_INCLUDE_ROOT.'/projectmanager/inc/class.boprojectelements.inc.php');
14
15// JPGraph does not work, if that got somehow set, so unset it
16if (isset($GLOBALS['php_errormsg'])) { unset ($GLOBALS['php_errormsg']); }
17
18// check if the admin installed a recent JPGraph parallel to eGroupWare
19if(file_exists(PHPGW_SERVER_ROOT . '/../jpgraph/src/jpgraph.php'))
20{
21        if (!isset($GLOBALS['phpgw_info']['apps']['projectmanager']['config']))
22        {
23                // read the pm ganttchart configuration and set some default if there's none
24                require_once(PHPGW_API_INC.'/class.config.inc.php');
25                $pm_config = new config('projectmanager');
26                $GLOBALS['phpgw_info']['apps']['projectmanager']['config'] = $pm_config->read_repository();
27                //_debug_array($GLOBALS['phpgw_info']['apps']['projectmanager']['config']);
28                unset($pm_config);
29                foreach(array(
30                        'TTF_DIR'          => '',
31                        'LANGUAGE_CHARSET' => 'iso-8859-1',
32                        'GANTT_FONT'       => 15, //FF_ARIAL
33                        'GANTT_FONT_FILE'  => 'arial.ttf',
34                        'GANTT_STYLE'      => 9002, //FS_BOLD,
35                        'GANTT_CHAR_ENCODE'=> false,
36                ) as $name => $default)
37                {
38                        if (isset($GLOBALS['phpgw_info']['apps']['projectmanager']['config'][$name]))
39                        {
40                                define($name,$GLOBALS['phpgw_info']['apps']['projectmanager']['config'][$name]);
41                        }
42                        elseif($default)
43                        {
44                                define($name,$default);
45                        }
46                }
47        }
48        if (!defined('TTF_DIR'))
49        {
50                // using the OS font dir if we can find it, otherwise fall back to our bundled Vera font
51                foreach(array(
52                        '/usr/X11R6/lib/X11/fonts/truetype/',   // linux / *nix default
53                        '/usr/share/fonts/ja/TrueType/',                // japanese fonts
54                        '/usr/share/fonts/msttcorefonts/',              // manual for install this fonts search at http://www.aditus.nu/jpgraph/jpdownload.php
55                        'C:/windows/fonts/',                                    // windows default
56                        // add your location here ...
57                        PHPGW_SERVER_ROOT.'/projectmanager/inc/ttf-bitstream-vera-1.10/',       // our bundled Vera font
58                ) as $dir)
59                {
60                        if (@is_dir($dir) && (is_readable($dir.GANTT_FONT_FILE) || is_readable($dir.'Vera.ttf')))
61                        {
62                                define('TTF_DIR',$dir);
63                                unset($dir);
64                                break;
65                        }
66                }
67        }
68        if (!defined('MBTTF_DIR')) define('MBTTF_DIR',TTF_DIR);
69
70        include(PHPGW_SERVER_ROOT . '/../jpgraph/src/jpgraph.php');
71        include(PHPGW_SERVER_ROOT . '/../jpgraph/src/jpgraph_gantt.php');
72}
73else
74{
75        include(PHPGW_SERVER_ROOT . '/projectmanager/inc/jpgraph-1.5.2/src/jpgraph.php');
76        include(PHPGW_SERVER_ROOT . '/projectmanager/inc/jpgraph-1.5.2/src/jpgraph_gantt.php');
77        define('TTF_DIR',PHPGW_SERVER_ROOT.'/projectmanager/inc/ttf-bitstream-vera-1.10/');
78        define('GANTT_FONT',FF_VERA);
79        define('GANTT_STYLE',FS_BOLD);
80        define('LANGUAGE_CHARSET','iso-8859-1');
81        define('GANTT_CHAR_ENCODE',true);
82}
83
84// some constanst for pre php4.3
85if (!defined('PHP_SHLIB_SUFFIX'))
86{
87        define('PHP_SHLIB_SUFFIX',strtoupper(substr(PHP_OS, 0,3)) == 'WIN' ? 'dll' : 'so');
88}
89if (!defined('PHP_SHLIB_PREFIX'))
90{
91        define('PHP_SHLIB_PREFIX',PHP_SHLIB_SUFFIX == 'dll' ? 'php_' : '');
92}
93
94/**
95 * ProjectManager: Ganttchart creation
96 *
97 * @package projectmanager
98 * @author RalfBecker-AT-outdoor-training.de
99 * @copyright (c) 2005 by RalfBecker-AT-outdoor-training.de
100 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
101 */
102class ganttchart extends boprojectelements 
103{
104        /**
105         * @var array $public_functions Functions to call via menuaction
106         */
107        var $public_functions = array(
108                'create' => true,
109                'show'   => true,
110        );
111        /**
112         * true if JPGraph version > 1.13
113         *
114         * @var boolean
115         */
116        var $modernJPGraph;
117        /**
118         * Charset used internaly by eGW, $GLOBALS['phpgw']->translation->charset()
119         *
120         * @var string
121         */
122        var $charset;
123        /**
124         * Font used for the Gantt Chart, in the form used by JPGraphs SetFont method
125         *
126         * @var string
127         */
128        var $gantt_font = GANTT_FONT;
129        /**
130         * Charset used by the above font
131         *
132         * @var string
133         */
134        var $gantt_charset = LANGUAGE_CHARSET;
135        /**
136         * Should non-ascii chars be encoded
137         *
138         * @var boolean
139         */
140        var $gantt_char_encode = GANTT_CHAR_ENCODE;
141
142        var $debug;
143        var $scale_start,$scale_end;
144        var $tmpl;
145        var $prefs;
146
147        /**
148         * Constructor, calls the constructor of the extended class
149         */
150        function ganttchart()
151        {
152                $this->tmpl =& CreateObject('etemplate.etemplate');
153
154                $php_extension = 'gd';
155                if (!extension_loaded($php_extension) && (!function_exists('dl') ||
156                        !dl(PHP_SHLIB_PREFIX.$php_extension.'.'.PHP_SHLIB_SUFFIX)) ||
157                        !function_exists('imagecopyresampled'))
158                {
159                        $this->tmpl->Location(array(
160                                'menuaction' => 'projectmanager.uiprojectmanager.index',
161                                'msg'        => lang("Necessary PHP extentions %1 not loaded and can't be loaded !!!",$php_extension.' ('.PHP_SHLIB_PREFIX.$php_extension.'.'.PHP_SHLIB_SUFFIX.')'),
162                        ));
163                }
164                $this->modernJPGraph = version_compare('1.13',JPG_VERSION) < 0;
165                //echo "version=".JPG_VERSION.", modernJPGraph=".(int)$this->modernJPGraph; exit;
166                error_log("JPG_VERSION=".JPG_VERSION.", modernJPGraph=".(int)$this->modernJPGraph);
167
168                if (isset($_REQUEST['pm_id']))
169                {
170                        $pm_id = (int) $_REQUEST['pm_id'];
171                        $GLOBALS['phpgw']->session->appsession('pm_id','projectmanager',$pm_id);
172                }
173                else
174                {
175                        $pm_id = $GLOBALS['phpgw']->session->appsession('pm_id','projectmanager');
176                }
177                if (!$pm_id)
178                {
179                        $this->tmpl->Location(array(
180                                'menuaction' => 'projectmanager.uiprojectmanager.index',
181                                'msg'        => lang('You need to select a project first'),
182                        ));
183                }
184                $this->boprojectelements($pm_id);
185               
186                // check if we have at least read-access to this project
187                if (!$this->project->check_acl(PHPGW_ACL_READ))
188                {
189                        $GLOBALS['phpgw']->redirect_link('/index.php',array(
190                                'menuaction' => 'projectmanager.uiprojectmanager.index',
191                                'msg'        => lang('Permission denied !!!'),
192                        ));
193                }
194                $this->charset = $GLOBALS['phpgw']->translation->charset();
195                $this->prefs =& $GLOBALS['phpgw_info']['user']['preferences'];
196
197                // check if a arial font is availible and set FF_VERA (or bundled font) if not
198                if (!is_readable((FF_MINCHO <= GANTT_FONT && GANTT_FONT <= FF_PGOTHI ? MBTTF_DIR : TTF_DIR).GANTT_FONT_FILE))
199                {
200                        $this->gantt_font = FF_VERA;
201                }
202        }
203       
204        /**
205         * Converts text from eGW's internal encoding to something understood by JPGraph / GD
206         *
207         * The only working thing I found so far is numeric html-entities from iso-8859-1.
208         * If you found other encoding do work, please let mit know: RalfBecker-AT-outdoor-training.de
209         * It would be nice if we could use the full utf-8 charset, if supported by the used font.
210         *
211         * @param string $text
212         * @return string
213         */
214        function text_encode($text)
215        {
216                // convert to the charset used for the gantchart
217                $text = $GLOBALS['phpgw']->translation->convert($text,$this->charset,$this->gantt_charset);
218
219                // convert everything above ascii to nummeric html entities
220                // not sure if this is necessary for non iso-8859-1 charsets, try to comment it out if you have problems
221                if ($this->gantt_char_encode) $text = preg_replace('/[^\x00-\x7F]/e', '"&#".ord("$0").";"',$text);
222               
223                return $text;
224        }
225       
226        /**
227         * Try to guess a locale supported by the server, with fallback to 'en_EN' and 'C'
228         *
229         * @return string
230         */
231        function guess_locale()
232        {
233                $lang = $this->prefs['common']['lang'];
234                $country = $this->prefs['common']['country'];
235               
236                if (strlen($lang) == 2)
237                {
238                        $country_from_lang = strtoupper($lang);
239                }
240                else
241                {
242                        list($lang,$country_from_lang) = explode('-',$lang);
243                        $country_from_lang = strtoupper($country_from_lang);
244                }
245                if (setlocale(LC_ALL,$locale=$lang.'_'.$country)) return $locale;
246                if (setlocale(LC_ALL,$locale=$lang.'_'.$country_from_lang)) return $locale;
247                if (setlocale(LC_ALL,$locale=$lang)) return $locale;
248                if (setlocale(LC_ALL,$locale='en_EN')) return $locale;
249               
250                return 'C';
251        }
252
253        /**
254         * create a new JPGraph Ganttchart object and setup a fitting scale
255         *
256         * @param string $title
257         * @param string $subtile
258         * @param int $start startdate of the ganttchart
259         * @param int $end enddate of the ganttchart
260         * @return object GantGraph
261         */
262        function &new_gantt($title,$subtitle,$start,$end,$width=940)
263        {
264                // create new graph object
265                $graph =& new GanttGraph($width,-1,'auto');
266               
267                $graph->SetShadow();
268                $graph->SetBox();       
269
270                // set the start and end date
271                $graph->SetDateRange(date('Y-m-d',$start), date('Y-m-d',$end));
272               
273                // some localizations
274                if ($this->modernJPGraph)
275                {
276                        $graph->scale->SetDateLocale($this->guess_locale());
277                }
278                elseif ($this->prefs['common']['lang'] == 'de')
279                {
280                        $graph->scale->SetDateLocale(LOCALE_DE);        // others use english
281                }               
282                // set start-day of the week from the cal-pref weekdaystarts
283                $weekdaystarts2day = array(
284                        'Sunday'   => 0,
285                        'Monday'   => 1,
286                        'Saturday' => 6,
287                );
288                $weekdaystarts = $this->prefs['calendar']['weekdaystarts'];
289                if ($this->modernJPGraph && isset($weekdaystarts2day[$weekdaystarts]))
290                {
291                        $graph->scale->SetWeekStart($weekdaystarts2day[$weekdaystarts]);
292                }
293                // get and remember the real start- & enddates, to clip the bar for old JPGraph versions
294                $this->scale_start = $graph->scale->iStartDate;
295                $this->scale_end   = $graph->scale->iEndDate;
296
297                $days = round(($this->scale_end - $this->scale_start) / 86400);
298                $month = $days / 31;
299                //echo date('Y-m-d',$this->scale_start).' - '.date('Y-m-d',$this->scale_end).' '.$month;
300                // 2 weeks and less: day (weekday date) and hour headers, only possible with modern JPGraph
301                if($this->modernJPGraph && $days <= 14)
302                {
303                        $graph->ShowHeaders(GANTT_HDAY | GANTT_HHOUR);
304                        $graph->scale->day->SetStyle($days < 7 ? DAYSTYLE_LONGDAYDATE1 : DAYSTYLE_SHORTDATE3);
305                        $graph->scale->hour->SetStyle($this->prefs['common']['timeformat'] == 12 ? HOURSTYLE_HAMPM : HOURSTYLE_H24);
306                        foreach(array(8=>6,5=>4,3=>2,2=>1) as $max => $int)
307                        {
308                                if ($days >= $max) break;
309                        }
310                        //echo "days=$days => $int ($max)";
311                        $graph->scale->hour->SetIntervall($int);
312                }
313                // 1.5 month and less: month (with year), week and day (date) headers
314                elseif($month <= 1.5)
315                {
316                        $graph->ShowHeaders(GANTT_HMONTH | GANTT_HWEEK | GANTT_HDAY);
317                        $graph->scale->month->SetStyle(MONTHSTYLE_LONGNAMEYEAR4);
318                        if ($this->modernJPGraph) $graph->scale->day->SetStyle(DAYSTYLE_SHORTDATE4);
319                }
320                // 2.5 month and less: month (with year), week (week and startday) and day headers
321                elseif($month <= 2.5)
322                {
323                        $graph->ShowHeaders(GANTT_HMONTH | GANTT_HWEEK | GANTT_HDAY);
324                        if ($this->modernJPGraph) $graph->scale->week->SetStyle(WEEKSTYLE_FIRSTDAYWNBR);
325                        $graph->scale->month->SetStyle(MONTHSTYLE_LONGNAMEYEAR4);
326                }
327                // 6 month and less: year, month and week (with weeknumber) headers
328                elseif($month <= 6) // half year
329                {
330                        $graph->ShowHeaders(GANTT_HYEAR | GANTT_HMONTH | GANTT_HWEEK);
331                        $graph->scale->month->SetStyle(MONTHSTYLE_LONGNAME);
332                }
333                // more then 6 month: only year and month headers
334                else
335                {
336                        $graph->ShowHeaders(GANTT_HYEAR | GANTT_HMONTH);
337                }
338                // Change the font scale
339                $graph->scale->week->SetFont($this->gantt_font,FS_NORMAL,8);
340                $graph->scale->year->SetFont($this->gantt_font,GANTT_STYLE,10);
341               
342                // Title & subtitle
343                $graph->title->Set($this->text_encode($title));
344                $graph->title->SetFont($this->gantt_font,GANTT_STYLE,12);
345                $graph->subtitle->Set($this->text_encode($subtitle));
346                $graph->subtitle->SetFont($this->gantt_font,FS_NORMAL,10);
347               
348                return $graph;
349        }
350       
351        /**
352         * Ganttbar for a project
353         *
354         * @param array $pm project or project-element data array
355         * @param int $level hierarchy level, 0=main project
356         * @param int $line line-number of the gantchart, starting with 0
357         * @param boolean $planned_times=false show planned or real start- and end-dates
358         * @return object GanttBar
359         */
360        function &project2bar($pm,$level,$line,$planned_times=false)
361        {
362                if ($pm['pe_id'])
363                {
364                        $pe =& $pm;
365                }
366                else
367                {
368                        $pe = array(
369                                'pm_id' => $pm['pm_id'],
370                                'pe_id' => 0,
371                        );
372                        foreach($pm as $key => $val)
373                        {
374                                if ($key != 'pm_id') $pe[str_replace('pm_','pe_',$key)] =& $pm[$key];
375                        }
376                }
377                $bar =& $this->element2bar($pe,$level,$line,$planned_times);
378
379                // set project-specific attributes: bold, solid bar, ...
380                $bar->title->SetFont($this->gantt_font,GANTT_STYLE,!$level ? 9 : 8);
381                $bar->SetPattern(BAND_SOLID,"#9999FF");
382               
383                if ($this->modernJPGraph && !$pe['pe_id'])      // main-project
384                {
385                        $link = $GLOBALS['phpgw']->link('/index.php',array(
386                                'menuaction' => 'projectmanager.uiprojectmanager.view',
387                                'pm_id'      => $pe['pm_id'],
388                        ));
389                        $title = lang('View this project');
390                       
391                        $bar->SetCSIMTarget($link,$title);
392                        $bar->title->SetCSIMTarget($link,$title);
393                }
394                return $bar;
395        }
396       
397        /**
398         * Ganttbar for a project-element
399         *
400         * @param array $pe projectelement-data array
401         * @param int $level hierarchy level, 0=main project
402         * @param int $line line-number of the gantchart, starting with 0
403         * @param boolean $planned_times=false show planned or real start- and end-dates
404         * @return object GanttBar
405         */
406        function &element2bar($pe,$level,$line,$planned_times=false)
407        {
408                // create a shorter title (removes dates from calendar-titles and project-numbers from sub-projects
409                if ($pe['pe_app'] == 'calendar' || $pe['pe_app'] == 'projectmanager')
410                {
411                        list(,$title) = explode(': ',$pe['pe_title'],2);
412                }
413                if (!$title) $title = $pe['pe_title'];
414               
415                if ((int) $this->debug >= 1)
416                {
417                        echo "<p>GanttBar($line,'".($level ? str_repeat(' ',$level) : '').
418                                $this->text_encode($title).'   '."','".
419                                date('Y-m-d H:i',$pe['pe_start'])."','".date('Y-m-d H:i',$pe['pe_end'])."','".
420                                round($pe['pe_completion']).'%'."',0.5)</p>\n";
421                }               
422                if (!$this->modernJPGraph)      // for an old JPGraph we have to clip the bar ourself
423                {
424                        if ($pe['pe_start'] < $this->scale_start) $pe['pe_start'] = $this->scale_start;
425                        if ($pe['pe_end'] > $this->scale_end) $pe['pe_end'] = $this->scale_end-1;
426                }
427                $bar =& new GanttBar($line,($level ? str_repeat(' ',$level) : '').
428                        $this->text_encode($title).
429                        ($level ? '  ' : ''),   // fix for wrong length calculation in JPGraph
430                        date('Y-m-d'.($this->modernJPGraph ? ' H:i' : ''),$pe['pe_start']),
431                        date('Y-m-d'.($this->modernJPGraph ? ' H:i' : ''),$pe['pe_end']),
432                        round($pe['pe_completion']).'%',0.5);
433                       
434                $bar->progress->Set($pe['pe_completion']/100);
435                $bar->progress->SetHeight(0.5);
436               
437                if ($this->modernJPGraph && $pe['pe_id'])
438                {
439                        $bar->SetCSIMTarget('@600x450'.$GLOBALS['phpgw']->link('/index.php',array(      // @ = popup
440                                'menuaction' => 'projectmanager.uiprojectelements.view',
441                                'pm_id'      => $pe['pm_id'],
442                                'pe_id'      => $pe['pe_id'],
443                        )),$pe['pe_remark'] ? $pe['pe_remark'] : lang('View this project-element'));
444                       
445                        if (($popup = $GLOBALS['phpgw']->link->is_popup($pe['pe_app']))) $popup = '@'.$popup;
446                        $bar->title->SetCSIMTarget($popup.$GLOBALS['phpgw']->link('/index.php',$this->link->view($pe['pe_app'],$pe['pe_app_id'])),
447                                lang('View this element in %1',lang($pe['pe_app'])));
448                }
449                $bar->title->SetFont($this->gantt_font,FS_NORMAL,!$level ? 9 : 8);
450
451                return $bar;
452        }
453
454        /**
455         * Milestone
456         *
457         * @param array $milestone data-array
458         * @param int $level hierarchy level, 0=main project
459         * @param int $line line-number of the gantchart, starting with 0
460         * @return object MileStone
461         */
462        function &milestone2bar($milestone,$level,$line)
463        {
464                if ((int) $this->debug >= 1)
465                {
466                        echo "<p>MileStone($line,'$milestone[ms_title],".
467                                date('Y-m-d',$milestone['ms_date']).','.
468                                date($this->prefs['common']['dateformat'],$milestone['ms_date']).")</p>\n";
469                }
470                $ms =& new MileStone($line,($level ? str_repeat(' ',$level) : '').
471                        $this->text_encode($milestone['ms_title']),
472                        date('Y-m-d',$milestone['ms_date']),
473                        date($this->prefs['common']['dateformat'],$milestone['ms_date']));
474               
475                $ms->title->SetFont($this->gantt_font,FS_ITALIC,8);
476                $ms->title->SetColor('blue');
477                $ms->mark->SetColor('black');
478                $ms->mark->SetFillColor('blue');
479
480                if ($this->modernJPGraph)
481                {
482                        $link = $GLOBALS['phpgw']->link('/index.php',array(
483                                'menuaction' => 'projectmanager.uimilestones.view',
484                                'pm_id'      => $milestone['pm_id'],
485                                'ms_id'      => $milestone['ms_id'],
486                        ));
487                        $title = lang('View this milestone');
488                        $ms->SetCSIMTarget('@600x450'.$link,$title);    // @ = popup
489                        $ms->title->SetCSIMTarget('@600x450'.$link,$title);
490                }
491                return $ms;
492        }
493
494        /**
495         * Adds all elements of project $pm_id to the ganttchart, calls itself recursive for subprojects
496         *
497         * @param int $pm_id project-id
498         * @param array $params
499         * @param int &$line line-number of the gantchart, starting with 0, gets incremented
500         * @param array &$bars bars are added here, with their pe_id as key
501         * @param int $level hierarchy level starting with 1, function stops if $level > $params['deepth']
502         */
503        function add_elements($pm_id,$params,&$line,&$bars,$level=1)
504        {
505                static $filter=false;
506                static $extra_cols;
507
508                if (!$filter)   // we do this only once for all shown projects
509                {
510                        // defining start- and end-times depending on $params['planned_times'] and the availible data
511                        foreach(array('start','end') as $var)
512                        {
513                                if ($params['planned_times'])
514                                {
515                                        $$var = "CASE WHEN pe_planned_$var IS NULL THEN pe_real_$var ELSE pe_planned_$var END";
516                                }
517                                else
518                                {
519                                        $$var = "CASE WHEN pe_real_$var IS NULL THEN pe_planned_$var ELSE pe_real_$var END";
520                                }
521                        }
522                        $filter = array(
523                                "pe_status != 'ignore'",
524                                "$start IS NOT NULL",
525                                "$end IS NOT NULL",
526                                "$start <= ".(int)$this->scale_end,     // starts befor the end of our period AND
527                                "$end >= ".(int)$this->scale_start,     // ends after the start of our period
528                                'cumulate' => true,
529                        );
530                        switch ($params['filter'])
531                        {
532                                case 'not':
533                                        $filter['pe_completion'] = 0;
534                                        break;
535                                case 'ongoing':
536                                        $filter[] = 'pe_completion!=100';
537                                        break;
538                                case 'done':
539                                        $filter['pe_completion'] = 100;
540                                        break;
541                        }
542                        if ($params['pe_resources'])
543                        {
544                                $filter['pe_resources'] = $params['pe_resources'];
545                        }
546                        $extra_cols = array(
547                                $start.' AS pe_start',
548                                $end.' AS pe_end',
549                        );
550                }
551                $filter['pm_id'] = $pm_id;      // this is NOT static
552
553                $pe_id2line = array();
554                foreach((array) $this->search(array(),false,'pe_start,pe_end',$extra_cols,
555                        '',false,'AND',false,$filter) as $pe)
556                {
557                        //echo "$line: ".print_r($pe,true)."<br>\n";
558                        if (!$pe) continue;
559                       
560                        $pe_id = $pe['pe_id'];
561                        $pe_id2line[$pe_id] = $line;    // need to remember the line to draw the constraints
562                        $pes[$pe_id] = $pe;
563
564                        if ($pe['pe_app'] == 'projectmanager')
565                        {
566                                $bars[$pe_id] =& $this->project2bar($pe,$level,$line++,$params['planned_times']);
567                        }
568                        else
569                        {
570                                $bars[$pe_id] =& $this->element2bar($pe,$level,$line++,$params['planned_times']);
571                        }
572                        // if we should display further levels, we call ourself recursive
573                        if ($pe['pe_app'] == 'projectmanager' && $level < $params['depth'])
574                        {
575                                $this->add_elements($pe['pe_app_id'],$params,$line,$bars,$level+1);
576                        }
577                }
578                if ($params['constraints'] && $this->modernJPGraph)             // the old jpgraph does not support constrains
579                {
580                        // adding milestones
581                        foreach((array)$this->milestones->search(array(),'pm_id,ms_id,ms_title,ms_date','ms_date','','',false,'AND',false,array(
582                                'pm_id' => $pm_id,
583                                (int)$this->scale_start.' <= ms_date',
584                                'ms_date <= '.(int)$this->scale_end,
585                        )) as $milestone)
586                        {
587                                if (!$milestone || !($ms_id = $milestone['ms_id'])) continue;
588
589                                $ms_id2line[$ms_id] = $line;
590                                $milestones[$ms_id] = $milestone;
591                                $bars[-$ms_id] =& $this->milestone2bar($milestone,$level,$line++);
592                        }
593                        // adding the constraints to the bars
594                        foreach((array)$this->constraints->search(array('pm_id'=>$pm_id)) as $constraint)
595                        {
596                                $pe_id = $constraint['pe_id_end'];      // start of the array at the end of this pe
597                                if (isset($bars[$pe_id]))
598                                {
599                                        $bar =& $bars[$pe_id];
600                                       
601                                        if ($constraint['pe_id_start'] && isset($pe_id2line[$constraint['pe_id_start']]))
602                                        {
603                                                // show violated constrains in red
604                                                $color = $pes[$constraint['pe_id_start']]['pe_start'] >= $pes[$pe_id]['pe_end'] ? 'black' : 'red';
605                                                $bar->SetConstrain($pe_id2line[$constraint['pe_id_start']],CONSTRAIN_ENDSTART,$color);
606                                        }
607                                        if ($constraint['ms_id'] && isset($ms_id2line[$constraint['ms_id']]))
608                                        {
609                                                // show violated constrains in red
610                                                $color = $milestones[$constraint['ms_id']]['ms_date'] >= $pes[$pe_id]['pe_end'] ? 'black' : 'red';
611                                                $bar->SetConstrain($ms_id2line[$constraint['ms_id']],CONSTRAIN_ENDSTART,$color);
612                                        }
613                                }
614                        }
615                }
616        }
617
618        /**
619         * Create a ganttchart
620         *
621         * @param array $params=null params, if (default) null, use them from the URL
622         * @param string $filename='' filename to store the chart or (default) empty to send it direct to the browser
623         */
624        function create($params=null,$filename='',$imagemap='ganttchar')
625        {
626                if (!$params) $params = $this->url2params($params);
627
628                $title = lang('project overview').': '.(is_numeric($params['pm_id']) ? $this->project->data['pm_title'] : '');
629                $subtitle = lang('from %1 to %2',date($this->prefs['common']['dateformat'],$params['start']),date($this->prefs['common']['dateformat'],$params['end']));
630                // create new graph-object and set scale_{start|end}
631                $graph =& $this->new_gantt($title,$subtitle,$params['start'],$params['end'],$params['width']);
632
633                if ($params['start'] < $this->now_su && $this->now_su < $params['end'])
634                {
635                        // add a vertical line to mark today
636                        $graph->add(new GanttVLine($this->now_su-24*60*60,
637                                date($GLOBALS['phpgw_info']['user']['preferences']['common']['dateformat'],$this->now_su)));
638                }
639                $line = 0;
640                $bars = array();
641                foreach(explode(',',$params['pm_id']) as $pm_id)
642                {
643                        if ($pm_id != $this->project->data['pm_id'])
644                        {
645                                if (!$this->project->read($pm_id) || !$this->project->check_acl(PHPGW_ACL_READ))
646                                {
647                                        continue;
648                                }
649                        }
650                        $graph->Add($this->project2bar($this->project->data,0,$line++,$params['planned_times']));
651       
652                        if ($params['depth'] > 0)
653                        {
654                                $this->add_elements($this->project->data['pm_id'],$params,$line,$bars);
655                        }
656                }
657                foreach($bars as $pe_id => $bar)
658                {
659                        $graph->Add($bar);
660                }
661                if (!$this->debug) $graph->Stroke($filename);
662               
663                if ($filename && $imagemap) return $graph->GetHTMLImageMap($imagemap);
664        }
665       
666        /**
667         * read the ganttchart params from the URL
668         *
669         * @param array $params already set parameters, default empty array
670         * @return array with params
671         */
672        function url2params($params = array())
673        {
674                if ((int) $this->debug >= 1) echo "<p>ganttchart::url2params(".print_r($params,true).")</p>\n";
675               
676                if (!count($params))
677                {
678                        if (!($params = $GLOBALS['phpgw']->session->appsession('ganttchart','projectmanager')))
679                        {
680                                $params = array(                                // some defaults, if called the first time
681                                        'constraints' => true,
682                                );
683                        }                       
684                        // check if project changed => not use start and end
685                        if ($params['pm_id'] != $this->project->data['pm_id'])
686                        {
687                                $params['pm_id'] = $this->project->data['pm_id'];
688                                unset($params['start']);
689                                unset($params['end']);
690                        }
691                }
692                $data =& $this->project->data;
693                foreach(array('start','end') as $var)
694                {
695                        // set used start- and end-times of the project
696                        if ($params['planned_times'] && $data['pe_planned_'.$var] || !$data['pe_real_'.$var])
697                        {
698                                $data['pm_'.$var] = $data['pm_planned_'.$var];
699                        }
700                        else
701                        {
702                                $data['pm_'.$var] = $data['pm_real_'.$var];
703                        }
704                        // set start- and end-times of the ganttchart
705                        if (isset($_GET[$var]))
706                        {
707                                $params[$var] = $_GET[$var];
708                        }
709                        elseif (isset($params[$var]) && $params[$var])
710                        {
711                                // already set
712                        }
713                        elseif ($data['pm_id'] && $data['pm_'.$var])
714                        {
715                                $params[$var] = $data['pm_'.$var];
716                        }
717                        else
718                        {
719                                $params[$var] = $var == 'start' ? date('Y-m-1') : date('Y-m-1',time()+61*24*60*60);
720                        }
721                        $params[$var] = is_numeric($params[$var]) ? (int) $params[$var] : strtotime($params[$var]);
722                       
723                        if ((int) $this->debug >= 1) echo "<p>$var=".$params[$var].'='.date('Y-m-d',$params[$var])."</p>\n";
724                }
725                if ((int) $_GET['width'])
726                {
727                        $params['width'] = (int) $_GET['width'];
728                }
729                else
730                {
731                        $params['width'] = $this->tmpl->innerWidth -
732                                ($this->prefs['common']['auto_hide_sidebox'] ? 60 : 245);
733                }
734                if (!isset($params['pm_id']) && $this->project->data['pm_id'])
735                {
736                        $params['pm_id'] = $this->project->data['pm_id'];
737                }
738                if (!isset($params['depth'])) $params['depth'] = 1;
739               
740                if ($_GET['pm_id'] && !is_numeric($_GET['pm_id']))
741                {
742                        $params['pm_id'] = $_GET['pm_id'];
743                }
744                $GLOBALS['phpgw']->session->appsession('ganttchart','projectmanager',$params);
745                if ((int) $this->debug >= 1) _debug_array($params);
746
747                return $params;         
748        }
749       
750        /**
751         * Return message to install a new jpgraph version
752         *
753         * @static
754         * @return string/boolean message or false if a new version is installed
755         */
756        function msg_install_new_jpgraph()
757        {
758                return version_compare('1.13',JPG_VERSION) < 0 ? false :
759                        lang('You are using the old version of JPGraph, bundled with eGroupWare. It has only limited functionality.').
760                        "<br />\n".lang('Please download a recent version from %1 and install it in %2.',
761                        '<a href="http://www.aditus.nu/jpgraph/jpdownload.php" target="_blank">www.aditus.nu/jpgraph</a>',
762                        realpath(PHPGW_SERVER_ROOT.'/..').SEP.'jpgraph');
763        }
764
765        /**
766         * Shows a ganttchart
767         *
768         * As ganttcharts contain an image-map and the image, we save the image as a temporary file.
769         * This for performance reasons, it saves a second creation / script-run.
770         * projectmanager/ganttchart.php reads and output the temporary file/image and unlinks it after.
771         */
772        function show($content=array(),$msg='')
773        {
774                if ($content['sync_all'] && $this->project->check_acl(PHPGW_ACL_ADD))
775                {
776                        $msg = lang('%1 element(s) updated',$this->sync_all());
777                        unset($content['sync_all']);
778                }               
779                // run $_GET[msg] through htmlspecialchars, as we output it raw, to allow the link in the jpgraph message.
780                if (!$msg) $msg = $this->tmpl->html->htmlspecialchars($_GET['msg']);
781
782                if (!$GLOBALS['phpgw']->session->appsession('ganttchart','projectmanager') && !$this->modernJPGraph)
783                {
784                        $msg .= $this->msg_install_new_jpgraph();
785                }
786                unset($content['update']);
787                $content = $this->url2params($content);
788       
789                $tmp = $GLOBALS['phpgw_info']['server']['temp_dir'];
790                if (!is_dir($tmp) || !is_writable($tmp))
791                {
792                        $tmp = '';
793                }
794                $img = tempnam($tmp,'ganttchart');
795                $img_name = basename($img);
796                $map = $this->create($content,$img,'ganttchart');
797                // replace the regular links with popups
798                $map = preg_replace('/href="@(\d+)x(\d+)([^"]+)"/i','href="#" onclick="phpgw_openWindowCentered2(\'\\3\',\'_blank\',\'dependent=yes,width=\\1,height=\\2,scrollbars=yes,status=yes\'); return false;"'
799                ,$map);
800               
801                $content['ganttchart'] = $GLOBALS['phpgw']->link('/projectmanager/ganttchart.php',$content+array(
802                        'img'   => $img_name,
803                ));
804                $content['map'] = $map;
805                $content['msg'] = $msg;
806               
807                $sel_options = array(
808                        'depth' => array(
809                                0  => '0: '.lang('Mainproject only'),
810                                1  => '1: '.lang('Project-elements'),
811                                2  => '2: '.lang('Elements of elements'),
812                                3  => '3: '.lang('Elements of elements'),
813                                99 => lang('Everything recursive'),
814                        ),
815                        'filter' => array(
816                                ''        => lang('All'),
817                                'not'     => lang('Not started (0%)'),
818                                'ongoing' => lang('0ngoing (0 < % < 100)'),
819                                'done'    => lang('Done (100%)'),
820                        ),
821                );
822                $GLOBALS['phpgw_info']['flags']['app_header'] = lang('projectmanager').' - '.lang('Ganttchart').': '.$this->project->data['pm_title'];;
823                $this->tmpl->read('projectmanager.ganttchart');
824                return $this->tmpl->exec('projectmanager.ganttchart.show',$content,$sel_options,'',array('pm_id'=>$content['pm_id']));
825        }
826}
Note: See TracBrowser for help on using the repository browser.