]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Fix for bug 126792: Templatizes showdependencytree.cgi.
authormyk%mozilla.org <>
Thu, 18 Apr 2002 04:58:26 +0000 (04:58 +0000)
committermyk%mozilla.org <>
Thu, 18 Apr 2002 04:58:26 +0000 (04:58 +0000)
Patch by Myk Melez <myk@mozilla.org>.
r=afranke,gerv

showdependencytree.cgi
template/default/show/dependency-tree.html.tmpl [new file with mode: 0644]

index b193022950bef449c44e2131057d0fbd37705b9b..0288faaa175ef8cd84934e0824f9057eb02406cd 100755 (executable)
@@ -21,6 +21,7 @@
 # Contributor(s): Terry Weissman <terry@mozilla.org>
 #                 Andreas Franke <afranke@mathweb.org>
 #                 Christian Reis <kiko@async.com.br>
+#                 Myk Melez <myk@mozilla.org>
 
 use diagnostics;
 use strict;
@@ -28,6 +29,9 @@ use strict;
 use lib qw(.);
 require "CGI.pl";
 
+# Use global template variables.
+use vars qw($template $vars);
+
 use vars %::FORM;
 
 ConnectToDatabase();
@@ -38,384 +42,152 @@ quietly_check_login();
 $::userid = $::userid;
 $::usergroupset = $::usergroupset;
 
-######################################################################
-# Begin Data/Security Validation
-######################################################################
+################################################################################
+# Data/Security Validation                                                     #
+################################################################################
 
 # Make sure the bug ID is a positive integer representing an existing
-# bug that the user is authorized to access
+# bug that the user is authorized to access.
 ValidateBugID($::FORM{'id'});
-
 my $id = $::FORM{'id'};
-my $hide_resolved = $::FORM{'hide_resolved'} || 0;
-my $maxdepth = $::FORM{'maxdepth'} || 0;
-
-if ($maxdepth !~ /^\d+$/) { $maxdepth = 0 };
-if ($hide_resolved !~ /^\d+$/ || $hide_resolved != 1) { $hide_resolved = 0 };
 
-######################################################################
-# End Data/Security Validation
-######################################################################
+my $hide_resolved = $::FORM{'hide_resolved'} ? 1 : 0;
 
-#
-# Globals
-
-# A hash to count visited bugs, and also to avoid processing repeated bugs
-my %seen;
+my $maxdepth = $::FORM{'maxdepth'} || 0;
+if ($maxdepth !~ /^\d+$/) { $maxdepth = 0 };
 
-# A hash to keep track of the bugs we print for the 'as buglist' links.
-my %printed;
+################################################################################
+# Main Section                                                                 #
+################################################################################
 
-# HTML output generated in the parse of the dependency tree. This is a
-# global only to avoid excessive complication in the recursion invocation
-my $html;
+# The column/value to select as the target milestone for bugs,
+# either the target_milestone column or the empty string value
+# (for installations that don't use target milestones).  Makes
+# it easier to query the database for bugs because we don't
+# have to embed a conditional statement into each query.
+my $milestone_column = Param('usetargetmilestone') ? "target_milestone" : "''";
 
-# Saves the largest of the two actual depths of the trees
+# The greatest depth to which either tree goes.
 my $realdepth = 0;
 
-# The scriptname for use as FORM ACTION.
-my $scriptname = $::ENV{'SCRIPT_NAME'}; # showdependencytree.cgi
-
-#
-# Functions
-
-# DumpKids recurses through the bug hierarchy starting at bug i, and
-# appends the bug information found to the html global variable. The
-# parameters are not straightforward, so look at the examples.
-#
-# DumpKids(i, target [, depth])
-#
-# Params
-#   i: The bug id to analyze
-#   target: The type we are looking for; either "blocked" or "dependson"
-# Optional
-#   depth: The current dependency depth we are analyzing, used during
-#          recursion
-# Globals Modified
-#   html: Bug descriptions are appended here
-#   realdepth: We set the maximum depth of recursion reached
-#   seen: We store the bugs analyzed so far
-#   printed: We store those bugs we actually print, for the "buglist" link
-# Globals Referenced
-#   maxdepth
-#   hide_resolved
-#
-# Examples:
-#   DumpKids(163, "blocked");
-#       will look for bugs that depend on bug 163
-#   DumpKids(163, "dependson");
-#       will look for bugs on which bug 163 depends
-
-sub DumpKids {
-    my ($i, $target, $depth) = (@_);
-    my $bgcolor = "#d9d9d9";
-    my $fgcolor = "#000000";
-    my $me;
-    if (! defined $depth) { $depth = 1; }
-
-    if ($target eq "blocked") {
-        $me = "dependson";
-    } else {
-        $me = "blocked";
-    }
-    SendSQL("select $target from dependencies where $me=$i order by $target");
-    my @list;
-    while (MoreSQLData()) {
-        push(@list, FetchOneColumn());
-    }
-    if (@list) {
-        my $list_started = 0;
-        foreach my $kid (@list) {
-            my ($bugid, $stat, $milestone) = ("", "", "");
-            my ($userid, $short_desc) = ("", "");
-            if (Param('usetargetmilestone')) {
-                SendSQL(SelectVisible("select bugs.bug_id, bug_status, target_milestone, assigned_to, short_desc from bugs where bugs.bug_id = $kid", $::userid, $::usergroupset));
-                ($bugid, $stat, $milestone, $userid, $short_desc) = (FetchSQLData());
-            } else {
-                SendSQL(SelectVisible("select bugs.bug_id, bug_status, assigned_to, short_desc from bugs where bugs.bug_id = $kid", $::userid, $::usergroupset));
-                ($bugid, $stat, $userid, $short_desc) = (FetchSQLData());
-
-            }
-            if (! defined $bugid) { next; }
-            my $opened = IsOpenedState($stat);
-            if ($hide_resolved && ! $opened) { next; }
-
-            # If we specify a maximum depth, we hide the output when
-            # that depth has occured, but continue recursing so we know
-            # the real maximum depth of the tree.
-            if (! $maxdepth || $depth <= $maxdepth) {
-                if (! $list_started) { $html .= "<ul>"; $list_started = 1 }
-                $html .= "<li>"; 
-                if (! $opened) {
-                    $html .= qq|<strike><span style="color: $fgcolor; background-color: $bgcolor;">
-                    |;
-                }
-
-                if (exists $printed{$kid}) {     
-                    $short_desc = "&lt;<em>This bug appears elsewhere in this tree</em>&gt;";
-                }
-                else {
-                    $short_desc = html_quote($short_desc);
-                }
-
-                SendSQL("select login_name from profiles where userid = $userid");
-                my ($owner) = (FetchSQLData());
-                if ((Param('usetargetmilestone')) && ($milestone)) {
-                    $html .= qq|
-                    <a href="show_bug.cgi?id=$kid">$kid [$milestone, $owner]
-                        - $short_desc.</a>
-                    |;  
-                } else {
-                    $html .= qq|
-                    <a href="show_bug.cgi?id=$kid">$kid [$owner] -
-                        $short_desc.</a>\n|; 
-                }
-                if (! $opened) { $html .= "</span></strike>"; }
-                
-                $printed{$kid} = 1;
-            } # End hideable output
+# Generate the tree of bugs that this bug depends on and a list of IDs
+# appearing in the tree.
+my $dependson_tree = { $id => GetBug($id) };
+my $dependson_ids = {};
+GenerateTree($id, "dependson", 1, $dependson_tree, $dependson_ids);
+$vars->{'dependson_tree'} = $dependson_tree;
+$vars->{'dependson_ids'} = [keys(%$dependson_ids)];
+
+# Generate the tree of bugs that this bug blocks and a list of IDs
+# appearing in the tree.
+my $blocked_tree = { $id => GetBug($id) };
+my $blocked_ids = {};
+GenerateTree($id, "blocked", 1, $blocked_tree, $blocked_ids);
+$vars->{'blocked_tree'} = $blocked_tree;
+$vars->{'blocked_ids'} = [keys(%$blocked_ids)];
+
+$vars->{'realdepth'}      = $realdepth;
+
+$vars->{'bugid'}          = $id;
+$vars->{'maxdepth'}       = $maxdepth;
+$vars->{'hide_resolved'}  = $hide_resolved;
+$vars->{'canedit'}        = UserInGroup("editbugs");
+
+print "Content-Type: text/html\n\n";
+$template->process("show/dependency-tree.html.tmpl", $vars)
+  || DisplayError("Template process failed: " . $template->error())
+  && exit;
+
+################################################################################
+# Recursive Tree Generation Function                                           #
+################################################################################
+
+sub GenerateTree {
+    # Generates a dependency tree for a given bug.  Calls itself recursively
+    # to generate sub-trees for the bug's dependencies.
+    
+    my ($bug_id, $relationship, $depth, $bugs, $ids) = @_;
+    
+    # Query the database for bugs with the given dependency relationship.
+    my @dependencies = GetDependencies($bug_id, $relationship);
+    
+    # Don't do anything if this bug doesn't have any dependencies.
+    return unless scalar(@dependencies);
+    
+    # Record this depth in the global $realdepth variable if it's farther 
+    # than we've gone before.
+    $realdepth = max($realdepth, $depth);
+
+    foreach my $dep_id (@dependencies) {
+        # Get this dependency's record from the database and generate
+        # its sub-tree if we haven't already done so (which happens
+        # when bugs appear in dependency trees multiple times).
+        if (!$bugs->{$dep_id}) {
+            $bugs->{$dep_id} = GetBug($dep_id);
+            GenerateTree($dep_id, $relationship, $depth+1, $bugs, $ids);
+        }
 
-            # Store the maximum depth so far
-            $realdepth = $realdepth < $depth ? $depth : $realdepth;
-            if (!(exists $seen{$kid})) { 
-                $seen{$kid} = 1;
-                DumpKids($kid, $target, $depth + 1);
-            }
+        # Add this dependency to the list of this bug's dependencies 
+        # if it exists, if we haven't exceeded the maximum depth the user 
+        # wants the tree to go, and if the dependency isn't resolved 
+        # (if we're ignoring resolved dependencies).
+        if ($bugs->{$dep_id}->{'exists'}
+            && (!$maxdepth || $depth <= $maxdepth) 
+            && ($bugs->{$dep_id}->{'open'} || !$hide_resolved))
+        {
+            push (@{$bugs->{$bug_id}->{'dependencies'}}, $dep_id);
+            $ids->{$dep_id} = 1;
         }
-        if ($list_started) { $html .= "</ul>"; }
     }
 }
 
-# makeTreeHTML calls DumpKids and generates the HTML output for a
-# dependency/blocker section.
-#
-# makeTreeHTML(i, linked_id, target);
-#
-# Params
-#   i: Bug id
-#   linked_id: Linkified bug_id used to linkify the bug
-#   target: The type we are looking for; either "blocked" or "dependson"
-# Globals modified
-#   html [Also modified in our call to DumpKids]
-# Globals referenced
-#   seen [Also modified by DumpKids]
-#   maxdepth
-#   realdepth
-#
-# Example:
-#   $depend_html = makeTreeHTML(83058, <A HREF="...">83058</A>, "dependson");
-#       Will generate HTML for bugs that depend on bug 83058
-
-sub makeTreeHTML {
-    my ($i, $linked_id, $target) = @_;
-
-    # Clean up globals for this run
-    $html = "";
-    %seen = ();
-    %printed = ();
-
-    DumpKids($i, $target);
-    my $tmphtml = $html;
-
-    # Output correct heading
-    $html = "<h3>Bugs that bug $linked_id ".($target eq "blocked" ? 
-        "blocks" : "depends on");
-
-    # If there are some bugs in this tree, add a link to view them
-    # as a bug list, and add another link to edit them on the "change
-    # several bugs" page if there is more than one and the user has
-    # "editbugs" privileges.
-    if ((scalar keys %printed) > 0) {
-        my $link = "buglist.cgi?bug_id=" . join(',', keys %printed);
-        $html .= qq~ (<a href="$link">view as bug list</a>~;
-        if (UserInGroup("editbugs") && (scalar keys %printed) > 1) {
-            $html .= qq~ | <a href="$link&tweak=1">change several</a>~;
-        }
-        $html .= ')';
-    }
+sub GetBug {
+    # Retrieves the necessary information about a bug, stores it in the bug cache,
+    # and returns it to the calling code.
+    my ($id) = @_;
     
-    # Provide feedback for omitted bugs
-    if ($maxdepth || $hide_resolved) {
-        $html .= " <small><b>(Only ";
-        if ($hide_resolved) { $html .= "open "; }
-        $html .= "bugs ";
-        if ($maxdepth) { $html .= "whose depth is less than $maxdepth "; }
-        $html .= "will be shown)</b></small>";
-    }
-
-    $html .= "</h3>";
-    $html .= $tmphtml;
-
-    # If no bugs were found, say so
-    if ((scalar keys %printed) == 0) {
-        $html .= "&nbsp;&nbsp;&nbsp;&nbsp;None<p>\n";
-    }
-
-    return $html;
+    SendSQL(SelectVisible("SELECT 1, 
+                                  bug_status, 
+                                  short_desc, 
+                                  $milestone_column, 
+                                  assignee.userid, 
+                                  assignee.login_name
+                             FROM bugs, profiles AS assignee
+                            WHERE bugs.bug_id = $id
+                              AND bugs.assigned_to = assignee.userid", 
+                          $::userid, 
+                          $::usergroupset));
+    
+    my $bug = {};
+    
+    ($bug->{'exists'}, 
+     $bug->{'status'}, 
+     $bug->{'summary'}, 
+     $bug->{'milestone'}, 
+     $bug->{'assignee_id'}, 
+     $bug->{'assignee_email'}) = FetchSQLData();
+    
+    $bug->{'open'} = IsOpenedState($bug->{'status'});
+    $bug->{'dependencies'} = ();
+    
+    return $bug;
 }
 
-# Draw the actual form controls that make up the hide/show resolved and
-# depth control toolbar. 
-#
-# drawDepForm()
-#
-# Params
-#   none
-# Globals modified
-#   none
-# Globals referenced
-#   hide_resolved
-#   maxdepth
-#   realdepth
-
-sub drawDepForm {
-    my $bgcolor = "#d0d0d0";
-    my ($hide_msg, $hide_input);
-
-    # Set the text and action for the hide resolved button.
-    if ($hide_resolved) {
-        $hide_input = '<input type="hidden" name="hide_resolved" value="0">';
-        $hide_msg = "Show Resolved";
-    } else {
-        $hide_input = '<input type="hidden" name="hide_resolved" value="1">';
-        $hide_msg = "Hide Resolved";
-    }
-
-    print qq|
-    <table cellpadding="3" border="0" cellspacing="0">
-    <tr>
-
-    <!-- Hide/show resolved button 
-         Swaps text depending on the state of hide_resolved -->
-    <td bgcolor="$bgcolor" align="center"> 
-    <form method="get" action="$scriptname" 
-        style="display: inline; margin: 0px;">
-    <input name="id" type="hidden" value="$id">
-    | . ( $maxdepth ? 
-        qq|<input name="maxdepth" type="hidden" value="$maxdepth">|
-        : "" ) . qq|
-    $hide_input
-    <input type="submit" value="$hide_msg">
-
-    </form>
-    </td>
-    <td bgcolor="$bgcolor">
-
-    <!-- depth section -->
-    Max Depth:
+sub GetDependencies {
+    # Returns a list of dependencies for a given bug.
     
-    </td>
-    <td bgcolor="$bgcolor">
-
-    </td>
-    <td bgcolor="$bgcolor">
-    <form method="get" action="$scriptname" 
-        style="display: inline; margin: 0px;">
+    my ($id, $relationship) = @_;
     
-    <!-- set to one form -->
-    <input type="submit" value="&nbsp;1&nbsp;" | 
-        . ( $realdepth < 2 || $maxdepth == 1 ? "disabled" : "" ) . qq|>
-    <input name="id" type="hidden" value="$id">
-    <input name="maxdepth" type="hidden" value="1">
-    <input name="hide_resolved" type="hidden" value="$hide_resolved">
-    </form>
-    </td>
-    <td bgcolor="$bgcolor">
-    <form method="get" action="$scriptname" 
-        style="display: inline; margin: 0px;">
-
-    <!-- Minus one form  
-         Allow subtracting only when realdepth and maxdepth > 1 -->
-    <input name="id" type="hidden" value="$id">
-    <input name="maxdepth" type="hidden" value="| 
-        .  ( $maxdepth == 1 ? 1 : ( $maxdepth ? 
-            $maxdepth-1 : $realdepth-1 ) ) . qq|">
-    <input name="hide_resolved" type="hidden" value="$hide_resolved">
-    <input type="submit" value="&nbsp;&lt;&nbsp;" | 
-        . ( $realdepth < 2 || ( $maxdepth && $maxdepth < 2 ) ?
-            "disabled" : "" ) . qq|>
-
-    </form>
-    </td>
-    <td bgcolor="$bgcolor">
-    <form method="get" action="$scriptname" 
-        style="display: inline; margin: 0px;">
-
-    <!-- Limit entry form: the button can not do anything when total depth
-         is less than two, so disable it -->
-    <input name="maxdepth" size="4" maxlength="4" value="| 
-        . ( $maxdepth > 0 ? $maxdepth : "" ) . qq|">
-    <input name="id" type="hidden" value="$id">
-    <input name="hide_resolved" type="hidden"
-        value="$hide_resolved">
-    <noscript>
-    <input type="submit" value="Change" | 
-        . ( $realdepth < 2 ? "disabled" : "" ) . qq|>
-    </noscript>
-
-    </form>
-    </td>
-    <td bgcolor="$bgcolor">
-    <form method="get" action="$scriptname" 
-        style="display: inline; margin: 0px;">
+    my $bug_type = ($relationship eq "blocked") ? "dependson" : "blocked";
     
-    <!-- plus one form 
-        Disable button if total depth < 2, or if depth set to unlimited -->
-    <input name="id" type="hidden" value="$id">
-    | . ( $maxdepth ? qq|
-    <input name="maxdepth" type="hidden" value="|.($maxdepth+1).qq|">| : "" ) 
-    . qq| 
-    <input name="hide_resolved" type="hidden" value="$hide_resolved">
-    <input type="submit" value="&nbsp;&gt;&nbsp;" | 
-        .  ( $realdepth < 2 || ! $maxdepth || $maxdepth >= $realdepth ?
-            "disabled" : "" ) . qq|>
-
-    </form>
-    </td>
-    <td bgcolor="$bgcolor">
-    <form method="get" action="$scriptname" 
-        style="display: inline; margin: 0px;">
+    SendSQL("  SELECT $relationship 
+                 FROM dependencies 
+                WHERE $bug_type = $id 
+             ORDER BY $relationship");
     
-    <!-- Unlimited button -->
-    <input name="id" type="hidden" value="$id">
-    <input name="hide_resolved" type="hidden" value="$hide_resolved">
-    <input type="submit" value="&nbsp;Unlimited&nbsp;">
-
-    </form>
-    </td>
-    </tr></table>
-    |;
+    my @dependencies = ();
+    push(@dependencies, FetchOneColumn()) while MoreSQLData();
+    
+    return @dependencies;
 }
 
-######################################################################
-# Main Section
-######################################################################
-
-my $linked_id = qq|<a href="show_bug.cgi?id=$id">$id</a>|;
-
-# Start the tree walk and save results. The tree walk generates HTML but
-# needs to be called before the page output starts so we have the
-# realdepth, which is necessary for generating the control toolbar.
-
-# Get bugs we depend on
-my $depend_html = makeTreeHTML($id, $linked_id, "dependson");
-
-my $tmpdepth = $realdepth; 
-$realdepth = 0;
-
-# Get bugs we block
-my $block_html = makeTreeHTML($id, $linked_id, "blocked");
-
-# Select maximum depth found for use in the toolbar
-$realdepth = $realdepth < $tmpdepth ? $tmpdepth : $realdepth;
-
-#
-# Actual page output happens here
-
-print "Content-type: text/html\n\n";
-PutHeader("Dependency tree for Bug $id", "Dependency tree for Bug $linked_id");
-drawDepForm();
-print $depend_html;
-print $block_html;
-drawDepForm();
-PutFooter();
diff --git a/template/default/show/dependency-tree.html.tmpl b/template/default/show/dependency-tree.html.tmpl
new file mode 100644 (file)
index 0000000..778d28a
--- /dev/null
@@ -0,0 +1,208 @@
+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the "License"); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  # 
+  # Software distributed under the License is distributed on an "AS
+  # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Tobias Burnus <burnus@net-b.de>
+  #                 Ville Skyttä <ville.skytta@iki.fi>
+  #                 Myk Melez <myk@mozilla.org>
+  #%]
+
+[% PROCESS global/header 
+   title = "Dependency tree for Bug $bugid"
+   h1    = "Dependency tree for bug <a href=\"show_bug.cgi?id=$bugid\">$bugid</a>"
+   style = "strike { background-color: #d9d9d9; color: #000000; }"
+%]
+
+[% PROCESS depthControlToolbar %]
+
+[%# Display the tree of bugs that this bug depends on. %]
+<h3>Bugs that bug <a href="show_bug.cgi?id=[% bugid %]">[% bugid %]</a> depends on
+[% IF dependson_ids.size > 0 %]
+  (<a href="buglist.cgi?bug_id=[% dependson_ids.join(",") %]">view as bug list</a>
+  [% IF canedit && dependson_ids.size > 1 %]
+    | <a href="buglist.cgi?bug_id=[% dependson_ids.join(",") %]&amp;tweak=1">change several</a>
+  [% END %])
+  [% IF maxdepth || hide_resolved %]
+    <small><b>
+      (Only [% "open" IF hide_resolved %] bugs
+            [% " whose depth is less than $maxdepth" IF maxdepth %] 
+            will be shown)
+    </b></small>
+  [% END %]
+  </h3>
+  [% INCLUDE display_tree tree=dependson_tree bug_id=bugid %]
+[% ELSE %]
+  </h3>
+  <p>None</p>
+[% END %]
+
+[%# Display the tree of bugs that this bug blocks. %]
+<h3>Bugs that bug <a href="show_bug.cgi?id=[% bugid %]">[% bugid %]</a> blocks
+[% IF blocked_ids.size > 0 %]
+  (<a href="buglist.cgi?bug_id=[% blocked_ids.join(",") %]">view as bug list</a>
+  [% IF canedit && blocked_ids.size > 1 %]
+    | <a href="buglist.cgi?bug_id=[% blocked_ids.join(",") %]&amp;tweak=1">change several</a>
+  [% END %])
+  [% IF maxdepth || hide_resolved %]
+    <small><b>
+      (Only [% "open" IF hide_resolved %] bugs
+            [% " whose depth is less than $maxdepth" IF maxdepth %] 
+            will be shown)
+    </b></small>
+  [% END %]
+  </h3>
+  [% INCLUDE display_tree tree=blocked_tree bug_id=bugid %]
+[% ELSE %]
+  </h3>
+  <p>None</p>
+[% END %]
+
+[% PROCESS depthControlToolbar %]
+
+[% PROCESS global/footer %]
+
+
+[%###########################################################################%]
+[%# Block to display a tree                                                 #%]
+[%###########################################################################%]
+
+[% BLOCK display_tree %]
+<ul>
+  [% FOREACH dep_id = tree.$bug_id.dependencies %]
+    [% dep = tree.$dep_id %]
+    <li>
+      [% "<strike>" IF !dep.open %]
+      <a href="show_bug.cgi?id=[% dep_id %]">[% dep_id %] 
+        [[% IF dep.milestone %][% dep.milestone FILTER html %], [% END %]
+        [% dep.assignee_email FILTER html %]] - 
+        [% IF dep.seen %]
+          <i>&lt;This bug appears elsewhere in this tree&gt;</i></a>
+        [% ELSE %]
+          [% dep.summary FILTER html %].</a>
+        [% END %]
+      [% "</strike>" IF !dep.open %]
+      [% INCLUDE display_tree bug_id=dep_id 
+           IF dep.dependencies.size > 0 && !dep.seen %]
+    </li>
+    [% dep.seen = 1 %]
+  [% END %]
+</ul>
+[% END %]
+
+[%###########################################################################%]
+[%# Block for depth control toolbar                                         #%]
+[%###########################################################################%]
+
+[% BLOCK depthControlToolbar %]
+ <table cellpadding="3" border="0" cellspacing="0" bgcolor="#d0d0d0">
+ <tr>
+   [%# Hide/show resolved button
+       Swaps text depending on the state of hide_resolved %]
+   <td align="center">
+   <form method="get" action="showdependencytree.cgi" 
+           style="display: inline; margin: 0px;">
+     <input name="id" type="hidden" value="[% bugid %]">
+     [% IF maxdepth %]
+       <input name="maxdepth" type="hidden" value="[% maxdepth %]">
+     [% END %]
+     <input type="hidden" name="hide_resolved" value="[% hide_resolved ? 0 : 1 %]">
+     <input type="submit" value="[% hide_resolved ? "Show" : "Hide" %] Resolved">
+   </form>
+   </td>
+
+   <td>
+     Max Depth:
+   </td>
+
+   <td>
+     &nbsp;
+   </td>
+
+   <td>
+   <form method="get" action="showdependencytree.cgi"
+         style="display: inline; margin: 0px;">
+     [%# set to one form %]
+     <input type="submit" value="&nbsp;1&nbsp;" [% 
+         realdepth < 2 || maxdepth == 1 ? "disabled" : ""
+     %]>
+     <input name="id" type="hidden" value="[% bugid %]">
+     <input name="maxdepth" type="hidden" value="1">
+     <input name="hide_resolved" type="hidden" value="[% hide_resolved %]">
+   </form>
+   </td>
+
+   <td>
+   <form method="get" action="showdependencytree.cgi" 
+         style="display: inline; margin: 0px;">
+     [%# Minus one form  
+         Allow subtracting only when realdepth and maxdepth > 1 %]
+     <input name="id" type="hidden" value="[% bugid %]">
+     <input name="maxdepth" type="hidden" value="[% 
+         maxdepth == 1 ? 1 
+                       : ( maxdepth ? maxdepth - 1 : realdepth - 1 )
+     %]">
+     <input name="hide_resolved" type="hidden" value="[% hide_resolved %]">
+     <input type="submit" value="&nbsp;&lt;&nbsp;" [%
+        realdepth < 2 || ( maxdepth && maxdepth < 2 ) ? "disabled" : "" 
+     %]>
+   </form>
+   </td>
+
+   <td>
+   <form method="get" action="showdependencytree.cgi" 
+         style="display: inline; margin: 0px;">
+     [%# Limit entry form: the button can not do anything when total depth
+         is less than two, so disable it %]
+     <input name="maxdepth" size="4" maxlength="4" value="[% 
+         maxdepth > 0 ? maxdepth : ""
+     %]">
+     <input name="id" type="hidden" value="[% bugid %]">
+     <input name="hide_resolved" type="hidden" value="[% hide_resolved %]">
+     <noscript>
+       <input type="submit" value="Change" [% realdepth < 2 ? "disabled" : "" %]>
+     </noscript>
+   </form>
+   </td>
+
+   <td>
+   <form method="get" action="showdependencytree.cgi" 
+         style="display: inline; margin: 0px;">
+     [%# plus one form 
+         Disable button if total depth < 2, or if depth set to unlimited %]
+     <input name="id" type="hidden" value="[% bugid %]">
+     [% IF maxdepth %]
+       <input name="maxdepth" type="hidden" value="[% maxdepth + 1 %]">
+     [% END %]
+     <input name="hide_resolved" type="hidden" value="[% hide_resolved %]">
+     <input type="submit" value="&nbsp;&gt;&nbsp;" [% 
+            realdepth < 2 || ! maxdepth || maxdepth >= realdepth ?
+            "disabled" : ""
+     %]>
+   </form>
+   </td>
+
+   <td>
+   <form method="get" action="showdependencytree.cgi" 
+         style="display: inline; margin: 0px;">
+     [%# Unlimited button %]
+     <input name="id" type="hidden" value="[% bugid %]">
+     <input name="hide_resolved" type="hidden" value="[% hide_resolved %]">
+     <input type="submit" value="&nbsp;Unlimited&nbsp;">
+   </form>
+   </td>
+ </tr>
+</table>
+[% END %]