aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server/src/main/webapp/WEB-INF/app/models/sonar
diff options
context:
space:
mode:
Diffstat (limited to 'sonar-server/src/main/webapp/WEB-INF/app/models/sonar')
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb195
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap_builder.rb94
2 files changed, 114 insertions, 175 deletions
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb
index afc4aba476b..6352a9a283b 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb
@@ -1,92 +1,127 @@
- #
- # 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
index 6ec0a08b225..00000000000
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap_builder.rb
+++ /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