]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2069 sanitize ruby code for treemap
authorSimon Brandhof <simon.brandhof@gmail.com>
Tue, 7 Feb 2012 15:23:49 +0000 (16:23 +0100)
committerSimon Brandhof <simon.brandhof@gmail.com>
Tue, 7 Feb 2012 15:24:23 +0000 (16:24 +0100)
18 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/TreemapWidget.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/components_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/filters_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/treemap_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb
sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap_builder.rb [deleted file]
sonar-server/src/main/webapp/WEB-INF/app/models/treemap2.rb [deleted file]
sonar-server/src/main/webapp/WEB-INF/app/views/components/_treemap_settings.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/filters/_customize_treemap.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/filters/treemap.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/treemap/_treemap.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/treemap/_treemap_container.html.erb
sonar-server/src/main/webapp/WEB-INF/lib/treemap.rb
sonar-server/src/main/webapp/WEB-INF/lib/treemap/html_output.rb
sonar-server/src/main/webapp/WEB-INF/lib/treemap/image_output.rb [deleted file]
sonar-server/src/main/webapp/WEB-INF/lib/treemap/svg_output.rb [deleted file]
sonar-server/src/main/webapp/javascripts/application.js
sonar-server/src/main/webapp/stylesheets/style.css

index b7b6640c3256702722628637171c194e914ac3cd..733e0a0778044c17e4404d0445829948268ab62d 100644 (file)
@@ -39,6 +39,6 @@ public class TreemapWidget extends AbstractRubyTemplate implements RubyRailsWidg
 
   @Override
   protected String getTemplatePath() {
-    return "/org/sonar/plugins/core/widgets/treemap.html.erb";
+    return "/Users/sbrandhof/projects/github/sonar/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/treemap.html.erb";
   }
 }
\ No newline at end of file
index 100e11962b0d2dd9749e518c2258692467f9f36b..e232f8389418a5ad282ad2de3a2fe452f90d1789 100644 (file)
@@ -27,6 +27,10 @@ class ComponentsController < ApplicationController
 
   TREEMAP_SIZE = 280
   SECTION = Navigation::SECTION_RESOURCE
+  TREEMAP_DEFAULT_SIZE_METRIC = 'ncloc'
+  TREEMAP_SIZE_METRIC_PROPERTY = 'sonar.core.treemap.sizemetric'
+  TREEMAP_DEFAULT_COLOR_METRIC = 'violations_density'
+  TREEMAP_COLOR_METRIC_PROPERTY = 'sonar.core.treemap.colormetric'
 
   def index
     @components_configuration = Sonar::ComponentsConfiguration.new
@@ -43,27 +47,39 @@ class ComponentsController < ApplicationController
     measures = component_measures(@snapshots, metrics)
     @measures_by_snapshot = measures_by_snapshot(@snapshots, measures)
     if @components_configuration.treemap_enabled? && @snapshots.size>1
-      @treemap = Sonar::TreemapBuilder.build(@snapshots, TREEMAP_SIZE, TREEMAP_SIZE)
+      @treemap = Sonar::Treemap.new(1, default_treemap_size_metric, TREEMAP_SIZE, TREEMAP_SIZE, {
+        :color_metric => default_treemap_color_metric,
+        :root_snapshot => @snapshot,
+        :browsable => false
+      })
     end
   end
 
   def treemap
-    @snapshot=Snapshot.find(params[:sid])
-    @snapshots = Snapshot.find(:all, :conditions => ['parent_snapshot_id=? and qualifier<>?', @snapshot.id, Snapshot::QUALIFIER_UNIT_TEST_CLASS])
-    @treemap = Sonar::TreemapBuilder.build(@snapshots, TREEMAP_SIZE, TREEMAP_SIZE, params[:size_metric], params[:color_metric])
+    snapshot=Snapshot.find(params[:sid])
+    not_found("Snapshot not found") unless snapshot
+    access_denied unless has_role?(:user, snapshot)
+
+    size_metric = (params[:size_metric] ? Metric.by_key(params[:size_metric]) : default_treemap_size_metric)
+    color_metric = (params[:color_metric] ? Metric.by_key(params[:color_metric]) : default_treemap_color_metric)
+
+    @treemap = Sonar::Treemap.new(1, size_metric, TREEMAP_SIZE, TREEMAP_SIZE, {
+      :color_metric => color_metric,
+      :root_snapshot => snapshot,
+      :browsable => false
+    })
 
     render(:update) do |page|
       page.replace_html 'treemap', @treemap.generate_html
-      page.replace_html 'treemap_gradient', :partial => 'components/treemap_gradient',
-                        :locals => {:color_metric => @treemap.color_metric}
+      page.replace_html 'treemap_gradient', :partial => 'treemap/gradient', :locals => {:metric => @treemap.color_metric}
       page.replace_html 'treemap_set_default', :partial => 'components/treemap_set_default',
-                        :locals => {:controller => 'components', :size_metric => params[:size_metric], :color_metric => params[:color_metric], :rid => @snapshot.project_id}
+                        :locals => {:controller => 'components', :size_metric => params[:size_metric], :color_metric => params[:color_metric], :rid => snapshot.project_id}
     end
   end
 
   def update_default_treemap_metrics
-    Property.set(Sonar::TreemapBuilder::CONFIGURATION_DEFAULT_COLOR_METRIC, params[:color_metric])
-    Property.set(Sonar::TreemapBuilder::CONFIGURATION_DEFAULT_SIZE_METRIC, params[:size_metric])
+    Property.set(TREEMAP_SIZE_METRIC_PROPERTY, params[:size_metric])
+    Property.set(TREEMAP_COLOR_METRIC_PROPERTY, params[:color_metric])
     redirect_to :action => 'index', :id => params[:rid], :configuring => true
   end
 
@@ -101,16 +117,33 @@ class ComponentsController < ApplicationController
       page_count.times do |page_index|
         page_sids=sids[page_index*page_size...(page_index+1)*page_size]
         measures.concat(ProjectMeasure.find(:all, :conditions => {
-            'snapshot_id' => page_sids,
-            'metric_id' => mids,
-            'rule_id' => nil,
-            'rule_priority' => nil,
-            'characteristic_id' => nil,
-            'committer' => nil}))
+          'snapshot_id' => page_sids,
+          'metric_id' => mids,
+          'rule_id' => nil,
+          'rule_priority' => nil,
+          'characteristic_id' => nil,
+          'committer' => nil}))
       end
       measures
     else
       []
     end
   end
+
+  def default_treemap_color_metric
+    metric=Metric.by_key(Property.value(TREEMAP_COLOR_METRIC_PROPERTY))
+    if metric.nil?
+      metric = Metric.by_key(TREEMAP_DEFAULT_COLOR_METRIC)
+    end
+    metric
+  end
+
+  def default_treemap_size_metric
+    metric=Metric.by_key(Property.value(TREEMAP_SIZE_METRIC_PROPERTY))
+    if metric.nil?
+      metric = Metric.by_key(TREEMAP_DEFAULT_SIZE_METRIC)
+    end
+    metric
+  end
+
 end
\ No newline at end of file
index e67bb0ce48bbffc342bc3aee1001b105bada0605..4e667e275a2c4a24d453007cf5d9ccf4535d7be7 100644 (file)
@@ -380,7 +380,7 @@ class FiltersController < ApplicationController
     @width=(params[:width]||'800').to_i
     @height=(params[:height]||'500').to_i
 
-    @treemap = Treemap2.new(@filter.id, @size_metric, @width, @height, {
+    @treemap = Sonar::Treemap.new(@filter.id, @size_metric, @width, @height, {
       :color_metric => @color_metric,
       :period_index => @filter_context.period_index,
       :measures_by_snapshot => @filter_context.measures_by_snapshot,
index 6a8151f57d802ed83713248a9412ff6614b2ddc7..9288782b57b6c35fe53d35e738c14f4e46f6245a 100644 (file)
@@ -46,7 +46,7 @@ class TreemapController < ApplicationController
       access_denied unless has_role?(:user, resource)
     end
 
-    treemap = Treemap2.new(html_id, size_metric, width.to_i, height.to_i, {
+    treemap = Sonar::Treemap.new(html_id, size_metric, width.to_i, height.to_i, {
       :color_metric => color_metric,
       :root_snapshot => (resource ? resource.last_snapshot : nil),
       :period_index => params[:period_index].to_i,
index afc4aba476bdc6debcea3a646bc0e75440f793e4..6352a9a283b655e928d30508539fb0fe9a5b57fe 100644 (file)
- #
- # Sonar, entreprise quality control tool.
- # Copyright (C) 2008-2012 SonarSource
- # mailto:contact AT sonarsource DOT com
- #
- # Sonar is free software; you can redistribute it and/or
- # modify it under the terms of the GNU Lesser General Public
- # License as published by the Free Software Foundation; either
- # version 3 of the License, or (at your option) any later version.
- #
- # Sonar 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
- # Lesser General Public License for more details.
- #
- # You should have received a copy of the GNU Lesser General Public
- # License along with Sonar; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
- #
-class Sonar::Treemap 
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2012 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# Sonar 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with Sonar; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+#
+class Sonar::Treemap
   include ActionView::Helpers::UrlHelper
-  
-  attr_accessor :color_metric, :size_metric, :width, :height
-  
-  def initialize(measures_by_snapshot, width, height, size_metric, color_metric, options={})
-    @measures_by_snapshot = measures_by_snapshot
+
+  attr_accessor :size_metric, :color_metric, :width, :height, :root_snapshot, :period_index,
+                :id, :components_size, :measures, :browsable
+
+  def initialize(id, size_metric, width, height, options={})
+    @components_size = 0
+    @id = id
     @size_metric = size_metric
-    @color_metric = color_metric if color_metric && color_metric.treemap_color?
     @width = width
     @height = height
 
+    @color_metric = options[:color_metric]
+    @root_snapshot = options[:root_snapshot]
+    @measures_by_snapshot = options[:measures_by_snapshot] # pre-computed measures, for example by filters
+    @browsable = options[:browsable]
     if options[:period_index] && options[:period_index]>0
       @period_index = options[:period_index]
     end
   end
-  
+
+  def self.size_metrics()
+    Metric.all.select { |metric|
+      metric.treemap_size?
+    }.sort
+  end
+
+  def self.color_metrics
+    Metric.all.select { |metric|
+      metric.treemap_color?
+    }.sort
+  end
+
   def generate_html
-    root = Treemap::Node.new( :id => -1, :label => '' )
+    root = Treemap::Node.new(:id => -1, :label => '')
     build_tree(root)
-    
+
     output = Sonar::HtmlOutput.new do |o|
       o.width = @width
       o.height = @height
       o.full_html = false
       o.details_at_depth = 1
     end
-    output.to_html(root)
+    html = output.to_html(root)
+    html += "<script>enableTreemap(#{@id},#{@components_size})</script>"
+    html
+  end
+
+  def empty?
+    @components_size==0
   end
-  
-  
+
   protected
 
-  def build_tree( node )
-    id_counter = 0
-    @measures_by_snapshot.each_pair do |snapshot, measures|
-      size_measure=measures[@size_metric]
-      color_measure=measures[@color_metric] if @color_metric
+  def measures_by_snapshot
+    @measures_by_snapshot ||=
+      begin
+        metric_ids=[@size_metric.id]
+        metric_ids << @color_metric.id if @color_metric && @color_metric.id!=@size_metric.id
+
+        sql_conditions = 'snapshots.islast=? AND project_measures.characteristic_id IS NULL and project_measures.rule_id IS NULL ' +
+          'and project_measures.rule_priority IS NULL and project_measures.metric_id in (?)'
+        sql_values = [true, metric_ids]
+        if @root_snapshot
+          sql_conditions += " AND snapshots.parent_snapshot_id=?"
+          sql_values << @root_snapshot.id
+        else
+          sql_conditions<<" AND snapshots.scope='PRJ' and snapshots.qualifier='TRK'"
+        end
 
+        hash = {}
+        ProjectMeasure.find(:all, :include => {:snapshot => :project}, :conditions => [sql_conditions].concat(sql_values)).each do |m|
+          hash[m.snapshot]||={}
+          hash[m.snapshot][m.metric]=m
+        end
+        hash
+      end
+  end
+
+  def build_tree(node)
+    measures_by_snapshot.each_pair do |snapshot, measures|
+      size_measure=measures[size_metric]
       if size_measure
+        color_measure=(color_metric ? measures[color_metric] : nil)
         resource = snapshot.project
-        child = Treemap::Node.new( :id => (id_counter += 1), 
-          :size => size_value(size_measure),
-          :label => resource.name(false),
-          :title => escape_javascript(resource.name(true)),
-          :tooltip => get_html_tooltip(snapshot, size_measure, color_measure),
-          :color => html_color(color_measure),
-          :url => get_url(snapshot))
+        child = Treemap::Node.new(:id => "#{@id}-#{@components_size += 1}",
+                                  :size => size_value(size_measure),
+                                  :label => resource.name(false),
+                                  :title => escape_javascript(resource.name(true)),
+                                  :tooltip => tooltip(resource, size_measure, color_measure),
+                                  :color => html_color(color_measure),
+                                  :rid => resource.copy_resource_id || resource.id,
+                                  :browsable => @browsable && resource.display_dashboard?)
         node.add_child(child)
       end
     end
-  end 
-
-  
-  def get_url(snapshot)
-    if snapshot.display_dashboard?
-      "document.location='#{ApplicationController.root_context}/dashboard/index/#{snapshot.project.copy_resource_id || snapshot.project_id}'"
-    else
-      color_metric_key=(@color_metric ? @color_metric.key : nil)
-      "window.open('#{ApplicationController.root_context}/resource/index/#{snapshot.project_id}?metric=#{color_metric_key}','resource','height=800,width=900,scrollbars=1,resizable=1');return false;"
-    end 
   end
-    
-  def get_html_tooltip(snapshot, size_measure, color_measure)
-    html = "<table>"
-    html += "<tr><td align=left>#{escape_javascript(@size_metric.short_name)}</td><td align=right><b>#{escape_javascript(size_measure ? size_measure.formatted_value : '-')}</b></td></tr>"
+
+  def tooltip(resource, size_measure, color_measure)
+    html=CGI::escapeHTML(resource.name(true))
+    html += " - #{CGI::escapeHTML(@size_metric.short_name)}: #{CGI::escapeHTML(size_measure.formatted_value)}"
     if color_measure
-      html += "<tr><td align=left>#{escape_javascript(@color_metric.short_name)}</td><td align=right><b>#{escape_javascript(color_measure ? color_measure.formatted_value : '-')}</b></td></tr>"
+      html += " - #{CGI::escapeHTML(@color_metric.short_name)}: #{CGI::escapeHTML(color_measure.formatted_value)}"
     end
-    html += "</table>"
     html
   end
 
@@ -100,7 +135,7 @@ class Sonar::Treemap
       0.0
     end
   end
-  
+
   def html_color(measure)
     MeasureColor.color(measure).html
   end
@@ -108,42 +143,40 @@ class Sonar::Treemap
 end
 
 class Sonar::HtmlOutput < Treemap::HtmlOutput
-  attr_accessor(:link_url)
-  
+
   def draw_node(node)
     return "" if node.bounds.nil?
 
-    html = ""
+    html = ''
     html += "<div id=\"node-#{node.id}\" style=\""
     html += "overflow:hidden;position:absolute;"
     html += "left:#{node.bounds.x1}px; top:#{node.bounds.y1}px;"
     html += "width:#{node.bounds.width}px;height: #{node.bounds.height}px;"
     html += "background-color:#FFF;"
-    html += "\" class=\"node\">"
-    html += "<div id=\"link_node-#{node.id}\" style='margin: 2px;background-color: #{node.color}; height: #{node.bounds.height-4}px; border: 1px solid #{node.color};' "
-    if node.url && @details_at_depth==node.depth
-      html += "onClick=\"#{node.url}\" onmouseover=\"this.style.borderColor='#111';\" onmouseout=\"this.style.borderColor='#{node.color}';\""
+    html += "\" alt='#{node.tooltip}' title='#{node.tooltip}'>"
+    html += "<div rid='#{node.rid}' id=\"tm-node-#{node.id}\" style='margin: 1px;background-color: #{node.color}; height: #{node.bounds.height-4}px;
+border: 1px solid #{node.color};' "
+    if node.browsable
+      html += "b=1 "
+    end
+    if @details_at_depth==node.depth
+      html += "onmouseover=\"this.style.borderColor='#444';\" onmouseout=\"this.style.borderColor='#{node.color}';\""
     end
     html += ' >'
     html += draw_node_body(node)
 
-    if(!node.children.nil? && node.children.size > 0)
+    if (!node.children.nil? && node.children.size > 0)
       node.children.each do |c|
         html += draw_node(c)
       end
     end
-    html += "</div></div>"
+    html + '</div></div>'
   end
-   
-  def draw_tooltips(node)
-    html='<script type="text/javascript">'
-    
-    node.children.each do |c|
-      if @details_at_depth==c.depth
-        html += "new Tip($('node-#{c.id.to_s}'), '#{c.tooltip}', {title: '#{c.title}'});"
-      end
-    end
-    html += '</script>'
-    html
+
+  def draw_label(node)
+    label= "<a href='#' onclick='return openResource(#{node.rid})'>"
+    label += node_label(node)
+    label += "</a>"
+    label
   end
 end
\ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap_builder.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap_builder.rb
deleted file mode 100644 (file)
index 6ec0a08..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
- #
- # Sonar, entreprise quality control tool.
- # Copyright (C) 2008-2012 SonarSource
- # mailto:contact AT sonarsource DOT com
- #
- # Sonar is free software; you can redistribute it and/or
- # modify it under the terms of the GNU Lesser General Public
- # License as published by the Free Software Foundation; either
- # version 3 of the License, or (at your option) any later version.
- #
- # Sonar 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
- # Lesser General Public License for more details.
- #
- # You should have received a copy of the GNU Lesser General Public
- # License along with Sonar; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
- #
-class Sonar::TreemapBuilder 
-  DEFAULT_WIDTH = 280
-  DEFAULT_HEIGHT = 280
-
-  CONFIGURATION_DEFAULT_COLOR_METRIC = 'sonar.core.treemap.colormetric'
-  CONFIGURATION_DEFAULT_SIZE_METRIC = 'sonar.core.treemap.sizemetric'
-  
-  def self.size_metrics(options={})
-    Metric.all.select{ |metric|
-      metric.treemap_size?
-    }.sort
-  end
-
-  def self.color_metrics
-    Metric.all.select{ |metric|
-      metric.treemap_color?
-    }.sort
-  end
-  
-  def self.build(snapshots, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT, size_metric_key=nil, color_metric_key=nil)
-    size_metric = Metric.by_key(size_metric_key) || default_size_metric
-    color_metric = Metric.by_key(color_metric_key) || default_color_metric
-
-    if snapshots.empty?
-      measures = []
-    else
-      # temporary fix for SONAR-1098
-      snapshots=snapshots[0...999]
-      measures = ProjectMeasure.find(:all,
-        :conditions => ['committer IS NULL and characteristic_id IS NULL and rule_id IS NULL and rule_priority IS NULL and metric_id IN (?) and snapshot_id IN (?)',
-          [size_metric.id, color_metric.id], snapshots.map{|s| s.id}])
-    end
-    Sonar::Treemap.new(measures_hash_by_snapshot(snapshots, measures), width, height, size_metric, color_metric)
-  end
-
-  private
-  
-  def self.default_color_metric
-    metric=Metric.by_key(Property.value(CONFIGURATION_DEFAULT_COLOR_METRIC))
-    if metric.nil?
-      metric = Metric.by_key(Metric::VIOLATIONS_DENSITY)
-    end 
-    metric
-  end
-  
-  def self.default_size_metric
-    metric=Metric.by_key(Property.value(CONFIGURATION_DEFAULT_SIZE_METRIC))
-    if metric.nil?
-      metric = Metric.by_key(Metric::NCLOC)
-    end
-    metric
-  end
-  
-  def self.measures_hash_by_snapshot(snapshots, measures)
-    snapshot_by_id = {}
-    snapshots.each {|s| snapshot_by_id[s.id]=s}
-    hash={}
-    measures.each do |m|
-      hash[snapshot_by_id[m.snapshot_id]] ||= {}
-      hash[snapshot_by_id[m.snapshot_id]][m.metric]=m
-    end
-    hash
-  end
-
-  def self.measures_by_snapshot(snapshots, measures)
-    snapshot_by_id = {}
-    snapshots.each {|s| snapshot_by_id[s.id]=s}
-    hash={}
-    measures.each do |m|
-      hash[snapshot_by_id[m.snapshot_id]] ||= []
-      hash[snapshot_by_id[m.snapshot_id]] << m
-    end
-    hash
-  end
-end
\ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/treemap2.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/treemap2.rb
deleted file mode 100644 (file)
index abf87c4..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-#
-# Sonar, entreprise quality control tool.
-# Copyright (C) 2008-2012 SonarSource
-# mailto:contact AT sonarsource DOT com
-#
-# Sonar is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# Sonar 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with Sonar; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
-#
-class Treemap2
-  include ActionView::Helpers::UrlHelper
-
-  attr_accessor :size_metric, :color_metric, :width, :height, :root_snapshot, :period_index,
-                :id, :id_counter, :measures, :browsable
-
-  def initialize(id, size_metric, width, height, options={})
-    @id_counter = 0
-    @id = id
-    @size_metric = size_metric
-    @width = width
-    @height = height
-
-    @color_metric = options[:color_metric]
-    @root_snapshot = options[:root_snapshot]
-    @measures_by_snapshot = options[:measures_by_snapshot] # pre-computed measures, for example by filters
-    @browsable = options[:browsable]
-    if options[:period_index] && options[:period_index]>0
-      @period_index = options[:period_index]
-    end
-  end
-
-  def generate_html
-    root = Treemap::Node.new(:id => -1, :label => '')
-    build_tree(root)
-
-    output = Sonar::HtmlOutput.new do |o|
-      o.width = @width
-      o.height = @height
-      o.full_html = false
-      o.details_at_depth = 1
-    end
-    output.to_html(root)
-  end
-
-  def empty?
-    @id_counter==0
-  end
-
-  protected
-
-  def measures_by_snapshot
-    @measures_by_snapshot ||=
-      begin
-        metric_ids=[@size_metric.id]
-        metric_ids << @color_metric.id if @color_metric && @color_metric.id!=@size_metric.id
-
-        sql_conditions = 'snapshots.islast=? AND project_measures.characteristic_id IS NULL and project_measures.rule_id IS NULL ' +
-          'and project_measures.rule_priority IS NULL and project_measures.metric_id in (?)'
-        sql_values = [true, metric_ids]
-        if @root_snapshot
-          sql_conditions += " AND snapshots.parent_snapshot_id=?"
-          sql_values << @root_snapshot.id
-        else
-          sql_conditions<<" AND snapshots.scope='PRJ' and snapshots.qualifier='TRK'"
-        end
-
-        hash = {}
-        ProjectMeasure.find(:all, :include => {:snapshot => :project}, :conditions => [sql_conditions].concat(sql_values)).each do |m|
-          hash[m.snapshot]||={}
-          hash[m.snapshot][m.metric]=m
-        end
-        hash
-      end
-  end
-
-  def build_tree(node)
-    measures_by_snapshot.each_pair do |snapshot, measures|
-      size_measure=measures[size_metric]
-      color_measure=(color_metric ? measures[color_metric] : nil)
-      resource = snapshot.project
-      child = Treemap::Node.new(:id => "#{@id}-#{@id_counter += 1}",
-                                :size => size_value(size_measure),
-                                :label => resource.name(false),
-                                :title => escape_javascript(resource.name(true)),
-                                :tooltip => tooltip(resource, size_measure, color_measure),
-                                :color => html_color(color_measure),
-                                :rid => resource.copy_resource_id || resource.id,
-                                :browsable => @browsable && resource.display_dashboard?)
-      node.add_child(child)
-    end
-  end
-
-  def tooltip(resource, size_measure, color_measure)
-    html=CGI::escapeHTML(resource.name(true))
-    html += " - #{CGI::escapeHTML(@size_metric.short_name)}: #{CGI::escapeHTML(size_measure.formatted_value)}"
-    if color_measure
-      html += " - #{CGI::escapeHTML(@color_metric.short_name)}: #{CGI::escapeHTML(color_measure.formatted_value)}"
-    end
-    html
-  end
-
-  def size_value(measure)
-    if @period_index
-      var=measure.variation(@period_index)
-      var ? var.to_f.abs : 0.0
-    elsif measure.value
-      measure.value.to_f.abs||0.0
-    else
-      0.0
-    end
-  end
-
-  def html_color(measure)
-    MeasureColor.color(measure).html
-  end
-
-end
-
-class Sonar::HtmlOutput < Treemap::HtmlOutput
-
-  def draw_node(node)
-    return "" if node.bounds.nil?
-
-    html = ''
-    html += "<div id=\"node-#{node.id}\" style=\""
-    html += "overflow:hidden;position:absolute;"
-    html += "left:#{node.bounds.x1}px; top:#{node.bounds.y1}px;"
-    html += "width:#{node.bounds.width}px;height: #{node.bounds.height}px;"
-    html += "background-color:#FFF;"
-    html += "\" alt='#{node.tooltip}' title='#{node.tooltip}'>"
-    html += "<div rid='#{node.rid}' id=\"tm-node-#{node.id}\" style='margin: 1px;background-color: #{node.color}; height: #{node.bounds.height-4}px;
-border: 1px solid #{node.color};' "
-    if node.browsable
-      html += "b=1 "
-    end
-    if @details_at_depth==node.depth
-      html += "onmouseover=\"this.style.borderColor='#444';\" onmouseout=\"this.style.borderColor='#{node.color}';\""
-    end
-    html += ' >'
-    html += draw_node_body(node)
-
-    if (!node.children.nil? && node.children.size > 0)
-      node.children.each do |c|
-        html += draw_node(c)
-      end
-    end
-    html += "</div></div>"
-  end
-
-  def draw_label(node)
-    label= "<a href='#' onclick='return openResource(#{node.rid})'>"
-    label += node_label(node)
-    label += "</a>"
-    label
-  end
-
-  def draw_tooltips(node)
-    ''
-  end
-end
\ No newline at end of file
index 13d15a144293512ab4699cfebad345042521d7e3..a60e814320c876ec51bac5f9a0216e885a1ea0e8 100644 (file)
@@ -16,7 +16,7 @@ remote_form_for :treemap, :url => url_params, :html => { :id => 'tm_form', :meth
     <td valign="bottom">
       <span class="comments"><%= message('size') -%></span>
       <br/>
-      <%= select_tag 'size_metric', options_grouped_by_domain(Sonar::TreemapBuilder.size_metrics, @treemap.size_metric.key),
+      <%= select_tag 'size_metric', options_grouped_by_domain(Sonar::Treemap.size_metrics, @treemap.size_metric.key),
         :id => 'select_size_metric', :class => 'small',:onchange => "$('submit_treemap').click();" %>
     </td>
   </tr>
@@ -28,7 +28,7 @@ remote_form_for :treemap, :url => url_params, :html => { :id => 'tm_form', :meth
       </span>
       <%= image_tag('loading.gif', {:id => "tm_loading", :style => 'display: none;'}) %>
       <br/>
-      <%= select_tag 'color_metric', options_grouped_by_domain(Sonar::TreemapBuilder.color_metrics, @treemap.color_metric.key),
+      <%= select_tag 'color_metric', options_grouped_by_domain(Sonar::Treemap.color_metrics, @treemap.color_metric.key),
           :id => 'select_color_metric', :class => 'small', :onchange => "$('submit_treemap').click();" %>
     </td>
   </tr>
index dacce6494f50f19dbffc204d6be25e7cc2ad209b..0b40e245251fbc7d7ea0699300790952b9c16ed8 100644 (file)
@@ -7,14 +7,14 @@
   <tr>
     <td class="keyCell"><%= message('size') -%>:</td>
     <td>
-      <%= select_tag 'columns[]', options_grouped_by_domain(Sonar::TreemapBuilder.size_metrics(), size_metric.key),
+      <%= select_tag 'columns[]', options_grouped_by_domain(Sonar::Treemap.size_metrics(), size_metric.key),
         :id => 'size_metric' %>
     </td>
   </tr>
   <tr>
     <td class="keyCell"><%= message('color') -%>:</td>
     <td>
-      <%= select_tag 'columns[]', options_grouped_by_domain(Sonar::TreemapBuilder.color_metrics, color_metric.key),
+      <%= select_tag 'columns[]', options_grouped_by_domain(Sonar::Treemap.color_metrics, color_metric.key),
         :id => 'color_metric' %>
       <span class="comments"><%= render :partial => 'components/treemap_gradient', :locals => {:color_metric => color_metric} %></span>
     </td>
index 9dc29b9844a1e51d97ef684d99dd547ea7839f7c..eabcc80f1516393c653e74d0315eb5864190bc55 100644 (file)
@@ -4,14 +4,14 @@
   <tr>
     <td>
       <span class="comments"><%= message('size') -%>:</span><br/>
-      <%= select_tag 'size_metric', options_grouped_by_domain(Sonar::TreemapBuilder.size_metrics(), @size_metric.key),
+      <%= select_tag 'size_metric', options_grouped_by_domain(Sonar::Treemap.size_metrics(), @size_metric.key),
         :id => 'size_metric', :class => 'small', :onchange => "load_treemap(this.form.size_metric.value,this.form.color_metric.value, false);return false;" %>
     </td>
     <td class="sep"> </td>
     <td>
       <span class="comments"><%= message('color') -%>: <%= render :partial => 'treemap/gradient', :locals => {:metric => @color_metric} %></span>
       <br/>
-      <%= select_tag 'color_metric', options_grouped_by_domain(Sonar::TreemapBuilder.color_metrics, @color_metric.key),
+      <%= select_tag 'color_metric', options_grouped_by_domain(Sonar::Treemap.color_metrics, @color_metric.key),
         :id => 'color_metric', :class => 'small', :onchange => "load_treemap(this.form.size_metric.value,this.form.color_metric.value, false);return false;" %>
     </td>
   </tr>
index d82c2b92b8727a89d33eac656304e1b7c7d2d423..e416740a27e72e74c086b4f46a8b254bbdd1fc97 100644 (file)
@@ -1,8 +1,3 @@
 <div class="treemap" style="width: <%= treemap.width -%>px; height:<%= treemap.height %>px;">
   <%= treemap.generate_html() -%>
-</div>
-<script>
-  for (var i = 1; i <= <%= treemap.id_counter -%>; i++) {
-    addTmEvent(<%= treemap.id -%>, i);
-  }
-</script>
+</div>
\ No newline at end of file
index 211bc5981c4154dd4c329de4ce20130a3c00ff62..0fcad775c8b3e5294cf460d3ce15077f6ca0af25 100644 (file)
@@ -4,14 +4,14 @@
       <td valign="top" class="thin nowrap">
         <span class="comments"><%= message('size') -%></span>
         <br/>
-        <%= select_tag "size", options_grouped_by_domain(Sonar::TreemapBuilder.size_metrics, (size_metric ? size_metric.key : nil), :include_empty => true),
+        <%= select_tag "size", options_grouped_by_domain(Sonar::Treemap.size_metrics, (size_metric ? size_metric.key : nil), :include_empty => true),
                        :id => "tm-size-#{treemap_id}", :class => 'small spacer-right', :onchange => "refreshTm(#{treemap_id}, null)" %>
       </td>
       <td valign="top" class="thin nowrap">
         <span class="comments"><%= message('color') -%></span>
         <span id="tm-gradient-<%= treemap_id -%>" class="note"></span>
         <br/>
-        <%= select_tag 'color', options_grouped_by_domain(Sonar::TreemapBuilder.color_metrics, (color_metric ? color_metric.key : nil), :include_empty => true),
+        <%= select_tag 'color', options_grouped_by_domain(Sonar::Treemap.color_metrics, (color_metric ? color_metric.key : nil), :include_empty => true),
                          :id => "tm-color-#{treemap_id}", :class => 'small', :onchange => "refreshTm(#{treemap_id}, null)" %>
         <%= image_tag 'loading.gif', :id => "tm-loading-#{treemap_id}", :style => 'vertical-align: top;display: none' -%>
       </td>
index c2888c495472e10f1a0a71701a3dfdcd0a12606d..cd96e3fe436762f0e1425915e2f3b026f8dc7f85 100644 (file)
@@ -19,48 +19,3 @@ require File.dirname(__FILE__) + '/treemap/squarified_layout'
 require File.dirname(__FILE__) + '/treemap/html_output'
 require File.dirname(__FILE__) + '/treemap/rectangle'
 require File.dirname(__FILE__) + '/treemap/gradient_color'
-
-# XXX these are still expirmental. Requires RMagick
-# require File.dirname(__FILE__) + '/treemap/image_output'
-# require File.dirname(__FILE__) + '/treemap/svg_output'
-
-module Treemap
-    VERSION = "0.0.1"
-
-    def Treemap::dump_tree(node)
-        puts "#{node.label}: #{node.bounds.to_s}"
-        node.children.each do |c|
-            dump_tree(c)
-        end
-    end
-
-    def Treemap::tree_from_xml(file)
-        doc = REXML::Document.new(file)
-        node_from_xml(doc.root)
-    end
-
-    def Treemap::node_from_xml(xmlnode)
-        node = Treemap::Node.new
-
-        node.label = xmlnode.attributes["label"]
-        id = xmlnode.attributes["id"]
-        if(!id.nil?)
-            node.id = id.to_s
-        end
-
-        node.size = xmlnode.attributes["size"]
-        node.size = node.size.to_f unless node.size.nil?
-
-        node.color = xmlnode.attributes["change"]
-        node.color = node.color.to_f unless node.color.nil?
-
-
-        xmlnode.elements.each do |c|
-            child = node_from_xml(c)
-            node.add_child(child) if !child.nil?
-        end
-
-        return nil if node.size < 5
-        node
-    end
-end
index dac5eddcfa82f6532a159279b47bc69166c89793..63873cc69a6d0127f0d01af8cf8996e567a0805b 100644 (file)
@@ -91,8 +91,7 @@ CSS
         end
 
         html += draw_node(node)
-        html += draw_tooltips(node)
-        
+
         if(@full_html)
             html += "</body></html>"
         end
@@ -132,10 +131,7 @@ CSS
             end
         end
 
-        html += "</div>"
-    end
-    
-    def draw_tooltips(node)
-      ''
+        html + '</div>'
     end
+
 end
diff --git a/sonar-server/src/main/webapp/WEB-INF/lib/treemap/image_output.rb b/sonar-server/src/main/webapp/WEB-INF/lib/treemap/image_output.rb
deleted file mode 100644 (file)
index f6cbedd..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#
-# image_output.rb - RubyTreemap
-#
-# Copyright (c) 2006 by Andrew Bruno <aeb@qnot.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-#
-
-require 'RMagick'
-require File.dirname(__FILE__) + "/output_base"
-
-class Treemap::ImageOutput < Treemap::OutputBase
-    def initialize
-        super
-
-        # default options for ImageOutput
-
-        yield self if block_given?
-    end
-
-    def setup_draw
-        draw = Magick::Draw.new
-        draw.stroke_width(1)
-        draw.stroke("#000000")
-        draw.stroke_opacity(1)
-        draw.fill_opacity(1)
-        draw.font_family = "Verdana"
-        draw.pointsize = 12
-        draw.gravity = Magick::WestGravity
-
-        return draw
-    end
-
-    def new_image
-        Magick::Image.new(@width, @height) {self.background_color = "white"}
-    end
-
-    def to_png(node, filename="treemap.png")
-        #
-        # XXX Need to flesh out this method. Add in label drawing.
-        #
-
-        image = self.new_image
-        draw = self.setup_draw
-
-        @bounds = self.bounds
-
-        # Pad for root border
-        @bounds.x2 -= 1
-        @bounds.y2 -= 1
-
-        @layout.process(node, @bounds)
-
-        draw_map(node, draw, image)
-
-        # render image
-        draw.draw(image)
-        image.write(filename)
-    end
-
-    def draw_map(node, draw, image)
-        return "" if node.nil?
-        if(node.color.nil?)
-            draw.fill("#CCCCCC")
-        else
-            draw.fill("#" + @color.get_hex_color(node.color))
-        end
-        draw.rectangle(node.bounds.x1, node.bounds.y1, node.bounds.x2, node.bounds.y2)
-        node.children.each do |c|
-            draw_map(c, draw, image)
-        end
-    end
-end
diff --git a/sonar-server/src/main/webapp/WEB-INF/lib/treemap/svg_output.rb b/sonar-server/src/main/webapp/WEB-INF/lib/treemap/svg_output.rb
deleted file mode 100644 (file)
index 864d808..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#
-# svg_output.rb - RubyTreemap
-#
-# Copyright (c) 2006 by Andrew Bruno <aeb@qnot.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-#
-
-require 'cgi'
-require 'RMagick'
-
-require File.dirname(__FILE__) + "/output_base"
-
-class Treemap::SvgOutput < Treemap::OutputBase
-
-    def initialize
-        super
-
-        yield self if block_given?
-    end
-
-    def node_label(node)
-        CGI.escapeHTML(node.label)
-    end
-
-    def node_color(node)
-        color = "#CCCCCC"
-
-        if(!node.color.nil?)
-            if(not Numeric === node.color)
-                color = node.color
-            else
-                color = "#" + @color.get_hex_color(node.color)
-            end
-        end
-
-        color
-    end
-
-    def to_png(node, filename="treemap.png")
-        svg = to_svg(node)
-        img = Magick::Image.from_blob(svg) { self.format = "SVG" }
-        img[0].write(filename)
-    end
-
-    def to_svg(node)
-        bounds = self.bounds
-
-        @layout.process(node, bounds)
-
-        draw_map(node)
-    end
-
-    def draw_map(node)
-        svg = "<svg"
-        svg += " xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\""
-        svg += " xmlns:ev=\"http://www.w3.org/2001/xml-events\"" 
-        svg += " width=\"" + (node.bounds.width).to_s + "\" height=\"" + (node.bounds.height).to_s + "\">"
-
-        svg += draw_node(node)
-        svg += "</svg>"
-        svg
-    end
-
-    def draw_node(node)
-        return "" if node.bounds.nil?
-
-        svg = ""
-        svg += "<rect"
-        svg += " id=\"rect-" + node.id.to_s + "\""
-        svg += " x=\"" + node.bounds.x1.to_s + "\""
-        svg += " y=\"" + node.bounds.y1.to_s + "\""
-        svg += " width=\"" + node.bounds.width.to_s + "\""
-        svg += " height=\"" + node.bounds.height.to_s + "\""
-        #svg += " style=\""
-        #svg += " fill: " + node_color(node) + ";"
-        #svg += " stroke: #000000;"
-        #svg += " stroke-width: 1px;"
-        svg += " fill=\"" + node_color(node) + "\""
-        svg += " stroke=\"#000000\""
-        svg += " stroke-width=\"1px\""
-        svg += " />"
-
-        if(!node.children.nil? and node.children.size > 0)
-            node.children.each do |c|
-                svg += draw_node(c)
-            end
-        end
-
-        svg
-    end
-end
index c79ebabffaa11a989f1323c319c0e00abd5cfdee..5cd9cea884b0fec58ba31a6080d66107f29c864d 100644 (file)
@@ -142,17 +142,20 @@ var SelectBox = {
 
 var treemapContexts = {};
 
-function addTmEvent(treemap_id, elt_index) {
-  var elt = $('tm-node-' + treemap_id + '-' + elt_index);
-  elt.oncontextmenu = function () {
-    return false
-  };
-  elt.observe('mouseup', function (event) {
-    context = treemapContexts[treemap_id];
-    onTmClick(treemap_id, event, context);
-  });
+function enableTreemap(treemap_id, components_size) {
+  for (var i = 1; i <= components_size; i++) {
+    var elt = $('tm-node-' + treemap_id + '-' + i);
+    elt.oncontextmenu = function () {
+      return false
+    };
+    elt.observe('mouseup', function (event) {
+      context = treemapContexts[treemap_id];
+      onTmClick(treemap_id, event, context);
+    });
+  }
 }
 
+
 function onTmClick(treemap_id, event, context) {
   if (Event.isLeftClick(event)) {
     var link = event.findElement('a');
@@ -185,8 +188,8 @@ function refreshTm(treemap_id, resource_id) {
   var size = $F('tm-size-' + treemap_id);
   var color = $F('tm-color-' + treemap_id);
   var width = $('tm-' + treemap_id).getWidth() - 10;
-  var height = Math.round(width * parseFloat($F('tm-h-' + treemap_id) / 100.0));
-  var rid = (resource_id!=null ? resource_id : context[context.length-1][0]);
+  var height = Math.round(width * Math.abs(parseFloat($F('tm-h-' + treemap_id)) / 100.0));
+  var rid = (resource_id != null ? resource_id : context[context.length - 1][0]);
 
   context = treemapContexts[treemap_id];
   var output = '';
index afc4f151da13459c239baf7ef12f4f2acb9ced17..24104be5c8e1448f45c945dead78dcb4f319c507 100644 (file)
@@ -517,9 +517,6 @@ h4, .h4 {
   position: relative;
   cursor: pointer;
 }
-.treemap .label {
-  color: #fff;
-}
 .treemap a {
   color: #FFF;
   text-decoration: none;