From fc16568b79315454077349f34f361d4b56505f1a Mon Sep 17 00:00:00 2001 From: Eric Bollengier Date: Fri, 29 Dec 2006 21:21:40 +0000 Subject: [PATCH] ebl add fileview tool git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@3857 91ce42f0-d328-0410-95d8-f526ca767f89 --- gui/bweb/INSTALL | 27 ++ gui/bweb/ReleaseNotes | 9 +- gui/bweb/cgi/bfileview.pl | 346 ++++++++++++++ gui/bweb/html/colorscm.png | Bin 0 -> 1434 bytes gui/bweb/lang/fr/tpl/begin.tpl | 36 +- gui/bweb/lang/fr/tpl/config_edit.tpl | 3 + gui/bweb/lang/fr/tpl/config_view.tpl | 1 + gui/bweb/lang/fr/tpl/display_job_zoom.tpl | 24 +- gui/bweb/lang/fr/tpl/fv_file_attribs.tpl | 2 + gui/bweb/lang/fr/tpl/update_media.tpl | 2 +- gui/bweb/lib/Bweb.pm | 1 + gui/bweb/lib/CCircle.pm | 543 ++++++++++++++++++++++ gui/bweb/tpl/begin.tpl | 36 +- gui/bweb/tpl/config_edit.tpl | 17 +- gui/bweb/tpl/config_view.tpl | 1 + gui/bweb/tpl/display_job_zoom.tpl | 24 +- gui/bweb/tpl/fv_file_attribs.tpl | 2 + gui/bweb/tpl/update_media.tpl | 2 +- 18 files changed, 1018 insertions(+), 58 deletions(-) create mode 100755 gui/bweb/cgi/bfileview.pl create mode 100644 gui/bweb/html/colorscm.png create mode 100644 gui/bweb/lang/fr/tpl/fv_file_attribs.tpl create mode 100644 gui/bweb/lib/CCircle.pm create mode 100644 gui/bweb/tpl/fv_file_attribs.tpl diff --git a/gui/bweb/INSTALL b/gui/bweb/INSTALL index 11a97141e9..eec169a285 100644 --- a/gui/bweb/INSTALL +++ b/gui/bweb/INSTALL @@ -12,6 +12,7 @@ Bweb works well with 1.39 release. 6) get bacula log more useful 7) bweb limitation 8) using sudo with autochanger +9) using bfileview.pl ################ FILE COPY ##################################### # you must get bweb cvs files @@ -54,6 +55,7 @@ Simply use lang/fr/tpl/*.tpl files instead of tpl/*.tpl - perl modules - DBI (with mysql or postgresql support DBD::Pg and DBD::mysql) - Gd::Graph + - Gd - HTML::Template - CGI - Expect @@ -171,5 +173,30 @@ www-data ALL = (root) NOPASSWD: /usr/sbin/mtx -f /dev/changer status www-data ALL = (root) NOPASSWD: /usr/sbin/mtx -f /dev/changer load * www-data ALL = (root) NOPASSWD: /usr/sbin/mtx -f /dev/changer unload * +################ BFILEVIEW SETUP ############################### + +At this time, bfileview works only with postgresql. + +Alias /bweb/fv /var/spool/bweb + + Options None + AllowOverride AuthConfig + Order allow,deny + Allow from all + + +mkdir /var/spool/bweb +chmod 700 /var/spool/bweb +chown www-data /var/spool/bweb + +You must use brestore.pl -b to initialise the database, and +you can use bfileview.pl mode=batch jobid=xxx where=/ to compute tree size. + +At this time, it's a good idea to schedule brestore.pl -g after your BackupCatalog +job. + +To upgrade from an old installation, you can use : +ALTER TABLE brestore_pathvisibility ADD Size int8; + Enjoy ! diff --git a/gui/bweb/ReleaseNotes b/gui/bweb/ReleaseNotes index 1b971eddcf..6095a109e0 100644 --- a/gui/bweb/ReleaseNotes +++ b/gui/bweb/ReleaseNotes @@ -1,4 +1,11 @@ - Release Notes for bweb 1.39.28 + Release Notes for bweb 1.39.32 + +2006/12/29 + - Add graphical backup view. See INSTALL to enable it. It's usefull + for tuning backup. + NOTES : + - You must use brestore -b to initialise database after BackupCatalog job + - If you have an old installation, you must alter your schema (see INSTALL) 2006/12/14 - Add pool filter to job form diff --git a/gui/bweb/cgi/bfileview.pl b/gui/bweb/cgi/bfileview.pl new file mode 100755 index 0000000000..0d9c043fab --- /dev/null +++ b/gui/bweb/cgi/bfileview.pl @@ -0,0 +1,346 @@ +#!/usr/bin/perl -w + +=head1 LICENSE + + Bweb - A Bacula web interface + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2006 Free Software Foundation Europe e.V. + + The main author of Bweb is Eric Bollengier. + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation plus additions + that are listed in the file LICENSE. + + 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich, + Switzerland, email:ftf@fsfeurope.org. + +=head1 VERSION + + $Id$ + +=cut + +# TODO: +# Si c'est un fichier selectionne, afficher ses attributs +# ajouter le base_fic et base_url dans les options bweb +# + +use strict; +use Bweb; +use CCircle ; +use Digest::MD5 qw(md5_hex); +use File::Basename qw/basename dirname/; + +my $conf = new Bweb::Config(config_file => '/etc/bweb/config'); +$conf->load(); +my $bweb = new Bweb(info => $conf); +$bweb->connect_db(); + +my $arg = $bweb->get_form('where', 'jobid'); +my $where = $arg->{where}; +my $jobid = $arg->{jobid}; +my $jobid_url = "jobid=$jobid"; +my $opt_level = 2 ; +my $max_file = 20; +my $batch = CGI::param("mode") || ''; + +my $md5_rep = md5_hex("$where:$jobid") ; +my $base_url = '/bweb/fv' ; +my $base_fich = $conf->{fv_write_path}; + +die "Can't get where" unless ($where and $jobid); + +if ($batch eq 'batch') { + my $root = fv_get_root_pathid($where); + if ($root) { + fv_compute_size($jobid, $root); + exit 0; + } + exit 1; +} + +my $url_action = "bfileview.pl?opt_level=$opt_level" ; +my $top = new CCircle( + display_other => 1, + base_url => "$url_action;$jobid_url;where=$where", + ) ; + +print CGI::header('text/html'); +$bweb->display_begin(); +$bweb->display_job_zoom($jobid); + +if (-f "$base_fich/$md5_rep.png" and -f "$base_fich/$md5_rep.tpl") +{ + $bweb->display({}, "$base_fich/$md5_rep.tpl"); + $bweb->display_end(); + exit 0; +} + +my $attribs = fv_get_file_attribute($jobid, $where); +if ($attribs->{found}) { + $bweb->display($attribs, 'fv_file_attribs.tpl'); + $bweb->display_end(); + exit 0; +} + +if ($where !~ m!/$!) { + $where = $where . "/" ; +} + +my $root = fv_get_root_pathid($where); +if (!$root) { + $bweb->error("Can't find $where in catalog"); + $bweb->display_end(); + exit 0; +} + +my $total = fv_compute_size($jobid, $root); + +fv_display_rep($top, $total, $root, $opt_level) ; + +$top->draw_labels() ; +$top->set_title(Bweb::human_size($total)) ; + +open(OUT, ">$base_fich/$md5_rep.png") or die "$base_fich/$md5_rep.png $!"; +# make sure we are writing to a binary stream +binmode OUT; +# Convert the image to PNG and print it on standard output +print OUT $CCircle::gd->png; +close(OUT) ; + +open(OUT, ">$base_fich/$md5_rep.tpl") or die "$base_fich/$md5_rep.tpl $!"; +print OUT " +
+
+ + + +
+
+
+" ; + +print OUT $top->get_imagemap($where, "$base_url/$md5_rep.png") ; +close(OUT) ; + +$bweb->display({}, "$base_fich/$md5_rep.tpl"); +$bweb->display_end(); + +sub fv_display_rep +{ + my ($ccircle, $max, $rep, $level) = @_ ; + return if ($max < 1); + + my $sum = 0; + my $dirs = fv_list_dirs($jobid, $rep); # 0: pathid, 1: pathname + + foreach my $dir (@{$dirs}) + { + my $size = fv_compute_size($jobid, $dir->[0]); + $sum += $size; + + my $chld = $ccircle->add_part($size * 100 / $max, + basename($dir->[1]) . '/', + basename($dir->[1]) + . "\n" + . Bweb::human_size($size) + ) ; + + if ($chld and $level > 0) { + fv_display_rep($chld, $size, $dir->[0], $level - 1) ; + } + } + + # 0: name, 1: size + my $files = fv_get_big_files($jobid, $rep, 3*100/$max, $max_file/($level+1)); + foreach my $f (@{$files}) { + $ccircle->add_part($f->[1] * 100 / $max, + $f->[0], + $f->[0] . "\n" . Bweb::human_size($f->[1])); + $sum += $f->[1]; + } + + if ($sum < $max) { + $ccircle->add_part(($max - $sum) * 100 / $max, + "other files < 3", + "other\n" . Bweb::human_size($max - $sum)); + } + + $ccircle->finalize() ; +} + +sub fv_compute_size +{ + my ($jobid, $rep) = @_; + + my $size = fv_get_size($jobid, $rep); + if ($size) { + return $size; + } + + $size = fv_get_files_size($jobid, $rep); + + my $dirs = fv_list_dirs($jobid, $rep); + foreach my $dir (@{$dirs}) { + $size += fv_compute_size($jobid, $dir->[0]); + } + + fv_update_size($jobid, $rep, $size); + return $size; +} + +sub fv_list_dirs +{ + my ($jobid, $rep) = @_; + + my $ret = $bweb->dbh_selectall_arrayref(" + SELECT P.PathId, + ( + SELECT Path FROM Path WHERE PathId = P.PathId + UNION + SELECT Path FROM brestore_missing_path WHERE PathId = P.PathId + ) AS Path + FROM ( + SELECT PathId + FROM brestore_pathvisibility + INNER JOIN brestore_pathhierarchy USING (PathId) + WHERE PPathId = $rep + AND JobId = $jobid + ) AS P +"); + + return $ret; +} + +sub fv_get_file_attribute +{ + my ($jobid, $full_name) = @_; + + my $filename = $bweb->dbh_quote(basename($full_name)); + my $path = $bweb->dbh_quote(dirname($full_name) . "/"); + + my $attr = $bweb->dbh_selectrow_hashref(" + SELECT 1 AS found, + base64_decode_lstat(8, lstat) AS size + FROM File INNER JOIN Filename USING (FilenameId) + INNER JOIN Path USING (PathId) + WHERE Name = $filename + AND Path = $path + AND JobId = $jobid +"); + + $attr->{filename} = $full_name; + $attr->{size} = Bweb::human_size($attr->{size}); + return $attr; +} + +sub fv_get_size +{ + my ($jobid, $rep) = @_; + + my $ret = $bweb->dbh_selectrow_hashref(" + SELECT Size AS size + FROM brestore_pathvisibility + WHERE PathId = $rep + AND JobId = $jobid +"); + + return $ret->{size}; +} + +sub fv_get_files_size +{ + my ($jobid, $rep) = @_; + + my $ret = $bweb->dbh_selectrow_hashref(" + SELECT sum(base64_decode_lstat(8,lstat)) AS size + FROM File + WHERE PathId = $rep + AND JobId = $jobid +"); + + return $ret->{size}; +} + +sub fv_get_big_files +{ + my ($jobid, $rep, $min, $limit) = @_; + + my $ret = $bweb->dbh_selectall_arrayref(" + SELECT Name, size + FROM ( + SELECT FilenameId,base64_decode_lstat(8,lstat) AS size + FROM File + WHERE PathId = $rep + AND JobId = $jobid + ) AS S INNER JOIN Filename USING (FilenameId) + WHERE S.size > $min + ORDER BY S.size DESC + LIMIT $limit +"); + + return $ret; +} + +sub fv_update_size +{ + my ($jobid, $rep, $size) = @_; + + my $nb = $bweb->dbh_do(" + UPDATE brestore_pathvisibility SET Size = $size + WHERE JobId = $jobid + AND PathId = $rep +"); + + return $nb; +} + +sub fv_get_root_pathid +{ + my ($path) = @_; + $path = $bweb->dbh_quote($path); + my $ret = $bweb->dbh_selectrow_hashref(" +SELECT PathId FROM Path WHERE Path = $path + UNION +SELECT PathId FROM brestore_missing_path WHERE PATH = $path +"); + return $ret->{pathid}; +} + +__END__ + +CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$ +DECLARE +val int8; +b64 varchar(64); +size varchar(64); +i int; +BEGIN +size := split_part($2, ' ', $1); +b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; +val := 0; +FOR i IN 1..length(size) LOOP +val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i)); +END LOOP; +RETURN val; +END; +$$ language 'plpgsql'; + +ALTER TABLE brestore_pathvisibility ADD Size int8; diff --git a/gui/bweb/html/colorscm.png b/gui/bweb/html/colorscm.png new file mode 100644 index 0000000000000000000000000000000000000000..cf2ccefb54c44b2873cede7dc35aca9cba8a4310 GIT binary patch literal 1434 zcmV;L1!ek)P)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ>5J^NqRCwBAY-w%p7ZwsIV4xz%$jD#>2p|@AZV^QW zhCd7%ju{Nhj0_AvelsvUdh>@tn3suxkCTz%@!MYvo6me=`1kiO!}s5RfcPK7_g{Y* ze*OmXfBpfg|IhI4*B^#ApMNu?y2&sY{agn&93TLXV~hhK5CbvqD(FBo{QrscoK{Pc zAv9EW;gQB7L$Aoikgz6>&ADrE4srdR{WtNM6$NC`oSs3mpv!6HV{z6#zt@idV&Ufk zIumH1y*7|$U}X3YCYixB1DMUgko<>_;m6Pa46JPb88}&hz5-hE3+UoM|NaBD{$uzL zvw+S9&rYS z?{66x-o0aB`1s>5gNy(RL!y;1!^wBY80Ozt%)rjV0nzjGCyE&W0mSnE|9@0duPkI> zf4_vmDw2=k!3|f2r*A|V*q9j@p2+=Wcq{yif%zXB!#}Qb47LW38P?v~!l2Ht!eA_5 z%m6ZnnVA`G3_t*(xfp24*=fL7P+(wqb(}$guakl4^9_bamw^U92PVA_Obl1PZe=*~ zX%54#hX)xhzPrTGb+L=#4=@=rF)=YPGBUzV0tg_mi{S#F?gFFy4bWfQK+a1B297@r z2D-O_VO`8{=CujKS&=q|8($YN-1_ho7(NW3vZ56eG>_Y6V|KY>0K zWMu}s8U_FY2-U^xLJSPgzX4+ki1~nuI6#I2Y0c*h8iFDW3ZIJ^o^zZ4dYyye?@yqf z@BbKh*aaB4Sh#=*{y&O~0Ro5xluST2{rvNfft62^fk^=vzF!^y4FXAi&Pa@E4d-kO4pd!Gq%W&+iPs*|-=u zo$?r%k2EkaNB~{02~5Z;Kv%G{13kdZAk7LC{uRW)`-6$$4);Zdm#mx&mD-lT5Mu>8 z{tt@5009I~Zp@(Y`TL9Emqk7U=UQ}HK7z{zAx1FCdCVQdQwKP?7X zRs#lZ9$@?e%b7@EHIlui5nE&Kfixr`1bub!xx4k2KKjC z8Th_GVBqEg#yBgmJopJLaK3zGkpK0L;W1E8T52i-BU1XEF=GZpW@e@uusmh}2q2W4 z2QpklM1*|>2d$WSRD^EtX2fB<4tS67cNC@5G$ oPNfMnR18SHMi&Rg8$f^o0OT3dT>CBKt^fc407*qoM6N<$f+%HbfB*mh literal 0 HcmV?d00001 diff --git a/gui/bweb/lang/fr/tpl/begin.tpl b/gui/bweb/lang/fr/tpl/begin.tpl index 3d6408fff5..b604b2827b 100644 --- a/gui/bweb/lang/fr/tpl/begin.tpl +++ b/gui/bweb/lang/fr/tpl/begin.tpl @@ -19,44 +19,44 @@ if (navigator.appName == 'Konqueror') { -
+ diff --git a/gui/bweb/lang/fr/tpl/config_edit.tpl b/gui/bweb/lang/fr/tpl/config_edit.tpl index 23ee9d3438..d5fdb7cf3c 100644 --- a/gui/bweb/lang/fr/tpl/config_edit.tpl +++ b/gui/bweb/lang/fr/tpl/config_edit.tpl @@ -35,6 +35,9 @@ template_dir : + fv_write_path : + + bconsole : diff --git a/gui/bweb/lang/fr/tpl/config_view.tpl b/gui/bweb/lang/fr/tpl/config_view.tpl index 6dffabf0a3..c36d5ba914 100644 --- a/gui/bweb/lang/fr/tpl/config_view.tpl +++ b/gui/bweb/lang/fr/tpl/config_view.tpl @@ -13,6 +13,7 @@ Configuration Bweb template_dir : graph_font : + fv_write_path : bconsole : debug : diff --git a/gui/bweb/lang/fr/tpl/display_job_zoom.tpl b/gui/bweb/lang/fr/tpl/display_job_zoom.tpl index 0f3d8958c6..9a52d63ab9 100644 --- a/gui/bweb/lang/fr/tpl/display_job_zoom.tpl +++ b/gui/bweb/lang/fr/tpl/display_job_zoom.tpl @@ -4,7 +4,7 @@
+
- + -
+ @@ -24,7 +24,7 @@
-
+
-
+ @@ -43,14 +43,26 @@
-
+
diff --git a/gui/bweb/lang/fr/tpl/fv_file_attribs.tpl b/gui/bweb/lang/fr/tpl/fv_file_attribs.tpl new file mode 100644 index 0000000000..bb4dd24b2e --- /dev/null +++ b/gui/bweb/lang/fr/tpl/fv_file_attribs.tpl @@ -0,0 +1,2 @@ +Filename :
+Size :
diff --git a/gui/bweb/lang/fr/tpl/update_media.tpl b/gui/bweb/lang/fr/tpl/update_media.tpl index 16b57b3e2e..d43eebff6d 100644 --- a/gui/bweb/lang/fr/tpl/update_media.tpl +++ b/gui/bweb/lang/fr/tpl/update_media.tpl @@ -106,7 +106,7 @@ diff --git a/gui/bweb/lib/Bweb.pm b/gui/bweb/lib/Bweb.pm index c3d7ee65f1..74b3c69040 100644 --- a/gui/bweb/lib/Bweb.pm +++ b/gui/bweb/lib/Bweb.pm @@ -208,6 +208,7 @@ use CGI; our %k_re = ( dbi => qr/^(dbi:(Pg|mysql):(?:\w+=[\w\d\.-]+;?)+)$/i, user => qr/^([\w\d\.-]+)$/i, password => qr/^(.*)$/i, + fv_write_path => qr!^([/\w\d\.-]+)$!, template_dir => qr!^([/\w\d\.-]+)$!, debug => qr/^(on)?$/, email_media => qr/^([\w\d\.-]+@[\d\w\.-]+)$/, diff --git a/gui/bweb/lib/CCircle.pm b/gui/bweb/lib/CCircle.pm new file mode 100644 index 0000000000..4b1ef12c7f --- /dev/null +++ b/gui/bweb/lib/CCircle.pm @@ -0,0 +1,543 @@ +package CCircle ; + +=head1 LICENSE + + Bweb - A Bacula web interface + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2006 Free Software Foundation Europe e.V. + + The main author of Bweb is Eric Bollengier. + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation plus additions + that are listed in the file LICENSE. + + 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich, + Switzerland, email:ftf@fsfeurope.org. + +=head1 VERSION + + $Id$ + +=cut + +use strict ; +use GD ; + +my $pi = 3.14159265; + +our $gd ; +our @color_tab ; + +our $black ; +our $white ; + +our $last_level = 1 ; +our @draw_label ; +our $height ; +our $width ; + +our $cur_color = 1 ; + +my $debug = 0 ; +my $font_size = 6 ; + +our @image_map ; + +sub new +{ + my ($class, %arg) = @_ ; + + my $self = { + start_degrees => 0, + degrees_complete => 0, + parent_percent => 100, + level => 1, + center_x => 600, + center_y => 300, + diameter => 75, + percent_total => 0, + min_percent => 2, + min_total => 0, + width => 1200, + height => 600, + min_label => 4, + min_degrees => 2, + max_label_level => 2, + display_other => 0, + base_url => '', + } ; + + map { $self->{$_} = $arg{$_} } keys %arg ; + + unless(defined $gd) { + $height = $self->{height} ; + $width = $self->{width} ; + + $gd = new GD::Image($width,$height); + $white = $gd->colorAllocate(255,255,255); + + push @color_tab, ($gd->colorAllocate(135,236,88), + $gd->colorAllocate(255,95,95), + $gd->colorAllocate(245,207,91), + $gd->colorAllocate( 255, 236, 139), + $gd->colorAllocate( 255, 174, 185), + $gd->colorAllocate( 179, 255, 58), + $gd->colorAllocate( 205, 133, 0), + $gd->colorAllocate(205, 133, 0 ), + $gd->colorAllocate(238, 238, 209), + + ) ; + + + $black = $gd->colorAllocate(0,0,0); + #$gd->>transparent($white); + $gd->interlaced('true'); + + $gd->arc($self->{center_x},$self->{center_y}, + $self->{diameter},$self->{diameter}, + $self->{start_degrees},360, $black) ; + + } + + $self->{rayon} = $self->{diameter} / 2 ; + + bless $self ; + + # pour afficher les labels tout propre + if ($self->{level} > $last_level) { + $last_level = $self->{level} ; + } + + return $self ; +} + +sub calc_xy +{ + my ($self, $level, $deg) = @_ ; + + my $x1 = $self->{center_x}+$self->{rayon} * $level * cos($deg*$pi/180) ; + my $y1 = $self->{center_y}+$self->{rayon} * $level * sin($deg*$pi/180) ; + + return ($x1, $y1) ; + +} + +sub add_part +{ + my ($self, $percent, $label, $tips) = @_ ; + + $tips = $tips || $label ; + + if (($percent + $self->{percent_total}) > 100.05) { + print STDERR "Attention $label ($percent\% + $self->{percent_total}\%) > 100\%\n" ; + return undef; + } + + if ($percent <= 0) { + print STDERR "Attention $label <= 0\%\n" ; + return undef; + } + + # angle de depart de l'arc + my $start_degrees = (($self->{degrees_complete})? + $self->{degrees_complete}:$self->{start_degrees}) ; + + # angle de fin de l'arc + my $end_degrees = $start_degrees + + ($percent * ( ( $self->{parent_percent} * 360 )/100 ) ) /100 ; + +# print STDERR "-------- $debug -------- +#percent = $percent% +#label = $label +#level = $self->{level} +#start = $start_degrees +#end = $end_degrees +#parent= $self->{parent_percent} +#" ; + if (($end_degrees - $start_degrees) < $self->{min_degrees}) { + $self->{min_total} += $percent ; + return undef ; + } + + if ($percent <= $self->{min_percent}) { + $self->{min_total} += $percent ; + return undef ; + } + + # on totalise les % en cours + $self->{percent_total} += $percent ; + + #print STDERR "percent_total = $self->{percent_total}\n" ; + + # position dans le cercle + my $n = $self->{level} ; # on ajoute/retire 0.005 pour depasser un peu + my $m = $n+1 ; + + # si c'est la premiere tranche de la nouvelle serie, il faut dessiner + # la premiere limite + + if ($self->{degrees_complete} == 0) { + my ($x1, $y1) = $self->calc_xy($n-0.005, $self->{start_degrees}) ; + my ($x2, $y2) = $self->calc_xy($m+0.005, $self->{start_degrees}) ; + + $gd->line($x1, $y1, $x2, $y2, $black) ; + } + + # seconde ligne + my ($x3, $y3) = $self->calc_xy($n-0.005, $end_degrees) ; + + my ($x4, $y4) = $self->calc_xy($m+0.005, $end_degrees) ; + + # ligne de bord exterieur + $gd->line($x3, $y3, $x4, $y4, $black); + + # on dessine le bord + $gd->arc($self->{center_x},$self->{center_y}, + $self->{diameter}*($self->{level}+1), + $self->{diameter}*($self->{level}+1), + + $start_degrees-0.5, + $end_degrees+0.5, $black) ; + + # on calcule le point qui est au milieu de la tranche + # angle = (angle nouvelle tranche)/2 + + # rayon = n*rayon - 0.5*rayon + # n=1 -> 0.5 + # n=2 -> 1.5 + # n=3 -> 2.5 + + my $mid_rad = ($end_degrees - $start_degrees) /2 + $start_degrees; + + my $moy_x = ($self->{center_x}+ + ($self->{rayon}*$m - 0.5*$self->{rayon}) + *cos($mid_rad*$pi/180)) ; + + my $moy_y = ($self->{center_y}+ + ($self->{rayon}*$m - 0.5*$self->{rayon}) + *sin($mid_rad*$pi/180)) ; + + $gd->fillToBorder($moy_x, + $moy_y, + $black, + $cur_color) ; + + # on prend une couleur au hasard + $cur_color = ($cur_color % $#color_tab) + 1 ; + + # si le % est assez grand, on affiche le label + if ($percent > $self->{min_label}) { + push @draw_label, [$label, + $moy_x, $moy_y, + $self->{level}] ; + + $self->push_image_map($label, $tips, $start_degrees, $end_degrees) ; + } + + # pour pourvoir ajouter des sous donnees + my $ret = new CCircle(start_degrees => $start_degrees, + parent_percent => $percent*$self->{parent_percent}/100, + level => $m, + center_x => $self->{center_x}, + center_y => $self->{center_y}, + min_percent => $self->{min_percent}, + min_degrees => $self->{min_degrees}, + base_url => $self->{base_url} . $label, + ) ; + + $self->{degrees_complete} = $end_degrees ; + + #print STDERR "$debug : [$self->{level}] $label ($percent)\n" ; + #open(FP, sprintf(">/tmp/img.%.3i.png", $debug)) ; + #print FP $gd->png; + #close(FP) ; + + $debug++ ; + + return $ret ; +} + +# on dessine le restant < min_percent +sub finalize +{ + my ($self) = @_ ; + + $self->add_part($self->{min_total}, + "other < $self->{min_percent}", + $black) ; + +} + +sub set_title +{ + my ($self, $title) = @_ ; + + $gd->string(GD::gdSmallFont, $self->{center_x} - $self->{rayon}*0.7, + $self->{center_y}, $title, $black) ; +} + +my $_image_map = ''; + +sub get_imagemap +{ + my ($self, $title, $img) = @_ ; + + return " + + $_image_map + + +" ; + +} + +sub push_image_map +{ + my ($self, $label, $tips, $start_degrees, $end_degrees) = @_ ; + + if ($label =~ /^other {display_other}) { + return ; + } + $label = ''; + } + + # on prend des points tous les $delta sur l'arc interieur et exterieur + + my $delta = 3 ; + + if (($end_degrees - $start_degrees) < $delta) { + return ; + } + + my @pts ; + + for (my $i = $start_degrees ; + $i <= $end_degrees ; + $i = $i + $delta) + { + my ($x1, $y1) = $self->calc_xy($self->{level}, $i) ; + my ($x2, $y2) = $self->calc_xy($self->{level} + 1, $i) ; + + push @pts, sprintf("%.2f,%.2f",$x1,$y1) ; + unshift @pts, sprintf("%.2f,%.2f",$x2, $y2) ; + } + + my ($x1, $y1) = $self->calc_xy($self->{level}, $end_degrees) ; + my ($x2, $y2) = $self->calc_xy($self->{level} + 1, $end_degrees) ; + + push @pts, sprintf("%.2f,%.2f",$x1,$y1) ; + unshift @pts, sprintf("%.2f,%.2f",$x2, $y2) ; + + my $ret = join(",", @pts) ; + + # on refait le traitement avec $i = $end_degrees + $_image_map .= "\n" ; + +} + +sub get_labels_imagemap +{ + my ($self) = @_ ; + my @ret ; + + for my $l (@draw_label) + { + # translation + my ($label, $x, $y, $level) = @{ $l } ; + + next if ($level > $self->{max_label_level}) ; + + next if (!$self->{display_other} and $label =~ /^other .*{center_y})*($last_level - $level) + $y ; + + my $x2 ; + my $xp ; + + if ($x < $self->{center_x}) { + $x2 = $self->{center_x} + - $self->{rayon} * ($last_level + 3.7) ; + $xp = $x2 - (length($label) *6 + 2) ; # moins la taille de la police + } else { + $x2 = $self->{center_x} + $self->{rayon} * ($last_level + 3.7) ; + $xp = $x2 + 10 ; + } + + push @ret, $xp - 1 . ";" . $dy - 6 . ";" . $xp + length($label) * $font_size . ";" . $dy + 10 . "\n" ; + + $gd->rectangle($xp - 1, $dy - 6, + $xp + length($label) * $font_size, + $dy + 10, $black) ; + } +} + +my $_label_hauteur ; +my $_label_max ; +my $_label_pos ; +my $_label_init = 0 ; + +# on va stocker les positions dans un bitmap $_label_pos +# +# si on match pas la position exacte, on essaye la case +# au dessus ou en dessous +# +# on a un bitmap pour les labels de gauche et un pour la droite +# $_label_pos->[0] et $_label_pos->[1] +sub get_label_pos +{ + my ($self, $x, $y) = @_ ; + + unless ($_label_init) { + $_label_hauteur = $self->{rayon} * 2 * $last_level ; + # nombre max de label = hauteur max / taille de la font + $_label_max = $_label_hauteur / 12 ; + $_label_pos = [ [], [] ] ; + $_label_init = 1 ; + } + + # on calcule la position du label dans le bitmap + use integer ; + my $num = $y * $_label_max / $_label_hauteur ; + no integer ; + + my $n = 0 ; # nombre d'iteration + my $l ; + + # on prend le bon bitmap + if ($x < $self->{center_x}) { + $l = $_label_pos->[0] ; + } else { + $l = $_label_pos->[1] ; + } + + # on parcours le bitmap pour trouver la bonne position + while (($num - $n) > 0) { + if (not $l->[$num]) { + last ; + } elsif (not $l->[$num + $n]) { + $num = $num + $n ; + last ; + } elsif (not $l->[$num - $n]) { + $num = $num - $n ; + last ; + } + $n++ ; + } + + $l->[$num] = 1 ; # on prend la position + + if ($num <= 0) { + return 0 ; + } + + # calcul de la position + $y = $num * $_label_hauteur / $_label_max ; + + return $y ; +} + +sub draw_labels +{ + my ($self) = @_ ; + + $gd->fillToBorder(1, + 1, + $black, + $white) ; + + for my $l (@draw_label) + { + # translation + my ($label, $x, $y, $level) = @{ $l } ; + + next if ($level > $self->{max_label_level}) ; + + next if (!$self->{display_other} and $label =~ /^other {center_x})*($last_level - $level) + $x ; + my $dy = ($y - $self->{center_y})*($last_level - $level) + $y ; + + $dy = $self->get_label_pos($dx, $dy) ; + + next unless ($dy) ; # pas d'affichage si pas de place + + $gd->line( $x, $y, + $dx, $dy, + $black) ; + + my $x2 ; + my $xp ; + + if ($x < $self->{center_x}) { + $x2 = $self->{center_x} + - $self->{rayon} * ($last_level + 3.7) ; + $xp = $x2 - (length($label) * $font_size + 2) ; # moins la taille de la police + } else { + $x2 = $self->{center_x} + $self->{rayon} * ($last_level + 3.7) ; + $xp = $x2 + 10 ; + } + + $gd->line($dx, $dy, + $x2, $dy, + $black) ; + + $gd->string(GD::gdSmallFont, $xp, $dy - 5, $label, $black) ; + } +} + +1; +__END__ + +package main ; + +my $top = new CCircle() ; + +my $chld1 = $top->add_part(50, 'test') ; +my $chld2 = $top->add_part(20, 'test') ; +my $chld3 = $top->add_part(10, 'test') ; +my $chld4 = $top->add_part(20, 'test') ; + + +$chld1->add_part(20, 'test1') ; +$chld1->add_part(20, 'test1') ; + +$chld2->add_part(20, 'test1') ; +$chld2->add_part(20, 'test1') ; + +$chld3->add_part(20, 'test1') ; +my $chld5 = $chld3->add_part(20, 'test1') ; + +$chld5->add_part(50, 'test3') ; + +$top->finalize() ; +$chld1->finalize() ; +$chld2->finalize() ; +$chld3->finalize() ; +$chld4->finalize() ; +$chld5->finalize() ; + +$top->draw_labels() ; +# make sure we are writing to a binary stream +binmode STDOUT; + +# Convert the image to PNG and print it on standard output +print $CCircle::gd->png; diff --git a/gui/bweb/tpl/begin.tpl b/gui/bweb/tpl/begin.tpl index 47c8e38a8a..8ac9df276f 100644 --- a/gui/bweb/tpl/begin.tpl +++ b/gui/bweb/tpl/begin.tpl @@ -19,44 +19,44 @@ if (navigator.appName == 'Konqueror') { -
+ diff --git a/gui/bweb/tpl/config_edit.tpl b/gui/bweb/tpl/config_edit.tpl index b7c6f1774c..3e7fe994fe 100644 --- a/gui/bweb/tpl/config_edit.tpl +++ b/gui/bweb/tpl/config_edit.tpl @@ -9,34 +9,37 @@ DBI : - + user : - + password : - + General Options email_media : - + Bweb Configuration graph_font : - + template_dir : - + + + fv_write_path : + bconsole : - + debug : diff --git a/gui/bweb/tpl/config_view.tpl b/gui/bweb/tpl/config_view.tpl index a55cbe1d44..3e778c4cb5 100644 --- a/gui/bweb/tpl/config_view.tpl +++ b/gui/bweb/tpl/config_view.tpl @@ -13,6 +13,7 @@ Bweb Configuration template_dir : graph_font : + fv_write_path : bconsole : debug : diff --git a/gui/bweb/tpl/display_job_zoom.tpl b/gui/bweb/tpl/display_job_zoom.tpl index 0c2f29487e..b0534e1083 100644 --- a/gui/bweb/tpl/display_job_zoom.tpl +++ b/gui/bweb/tpl/display_job_zoom.tpl @@ -4,7 +4,7 @@
+
- + -
+ @@ -24,7 +24,7 @@
-
+
-
+ @@ -43,7 +43,7 @@
-
+
@@ -114,4 +126,4 @@ nrsTable.setup( } ); - \ No newline at end of file + diff --git a/gui/bweb/tpl/fv_file_attribs.tpl b/gui/bweb/tpl/fv_file_attribs.tpl new file mode 100644 index 0000000000..bb4dd24b2e --- /dev/null +++ b/gui/bweb/tpl/fv_file_attribs.tpl @@ -0,0 +1,2 @@ +Filename :
+Size :
diff --git a/gui/bweb/tpl/update_media.tpl b/gui/bweb/tpl/update_media.tpl index dac62fdce2..2dc7416ca2 100644 --- a/gui/bweb/tpl/update_media.tpl +++ b/gui/bweb/tpl/update_media.tpl @@ -107,7 +107,7 @@ -- 2.39.2