]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-249 add variation values to Ruby API
authorsimonbrandhof <simon.brandhof@gmail.com>
Tue, 30 Nov 2010 15:19:54 +0000 (15:19 +0000)
committersimonbrandhof <simon.brandhof@gmail.com>
Tue, 30 Nov 2010 15:19:54 +0000 (15:19 +0000)
34 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/DifferentialValueDecorator.java [deleted file]
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/CodeCoverageWidget.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/CommentsDuplicationsWidget.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/ComplexityWidget.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/RulesWidget.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/SizeWidget.java
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/code_coverage.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/comments_duplications.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/complexity.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/rules.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/size.html.erb
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/DifferentialValueDecoratorTest.java [deleted file]
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/VariationDecoratorTest.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/DifferentialValueDecoratorTest/shared.xml [deleted file]
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/VariationDecoratorTest/shared.xml [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/web/SupportVariationDashboard.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
sonar-server/src/main/java/org/sonar/server/ui/ViewProxy.java
sonar-server/src/main/java/org/sonar/server/ui/Views.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/columns_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/components_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboard_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb
sonar-server/src/main/webapp/WEB-INF/app/models/api/dashboard_configuration.rb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb
sonar-server/src/main/webapp/WEB-INF/app/models/sonar/components_configuration.rb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/models/sonar/dashboard_configuration.rb [deleted file]
sonar-server/src/main/webapp/WEB-INF/app/views/dashboard/_configure_widget.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/dashboard/_widget.html.erb
sonar-server/src/main/webapp/WEB-INF/db/migrate/052_remove_columns_views_table.rb
sonar-server/src/test/java/org/sonar/server/ui/ViewsTest.java

index a354846e9a9e324c5e01c174ee70742894b34edb..a3495af0c0bafa659a320a31f6867ca51860ed30 100644 (file)
@@ -40,7 +40,7 @@ import org.sonar.plugins.core.metrics.UserManagedMetrics;
 import org.sonar.plugins.core.security.ApplyProjectRolesDecorator;
 import org.sonar.plugins.core.sensors.*;
 import org.sonar.plugins.core.testdetailsviewer.TestsViewerDefinition;
-import org.sonar.plugins.core.timemachine.DifferentialValueDecorator;
+import org.sonar.plugins.core.timemachine.VariationDecorator;
 import org.sonar.plugins.core.timemachine.PeriodLocator;
 import org.sonar.plugins.core.timemachine.TendencyDecorator;
 import org.sonar.plugins.core.timemachine.TimeMachineConfiguration;
@@ -195,7 +195,7 @@ public class CorePlugin implements Plugin {
     // time machine
     extensions.add(TendencyDecorator.class);
     extensions.add(PeriodLocator.class);
-    extensions.add(DifferentialValueDecorator.class);
+    extensions.add(VariationDecorator.class);
     extensions.add(TimeMachineConfiguration.class);
 
     return extensions;
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/DifferentialValueDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/DifferentialValueDecorator.java
deleted file mode 100644 (file)
index 2ece3f8..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2009 SonarSource SA
- * 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
- */
-package org.sonar.plugins.core.timemachine;
-
-import com.google.common.collect.Maps;
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.lang.ObjectUtils;
-import org.sonar.api.batch.*;
-import org.sonar.api.database.DatabaseSession;
-import org.sonar.api.database.model.MeasureModel;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.measures.*;
-import org.sonar.api.qualitymodel.Characteristic;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.ResourceUtils;
-import org.sonar.api.rules.RulePriority;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-@DependedUpon(DecoratorBarriers.END_OF_TIME_MACHINE)
-public class DifferentialValueDecorator implements Decorator {
-
-  private Snapshot[] projectTargetSnapshots;
-  private Map<Integer, Metric> metricByIds;
-  private DatabaseSession session;
-
-  public DifferentialValueDecorator(DatabaseSession session, PeriodLocator periodLocator, Configuration configuration, MetricFinder metricFinder) {
-    this.session = session;
-    Snapshot snapshot = periodLocator.locate(5);
-    projectTargetSnapshots = new Snapshot[]{snapshot};
-    initMetrics(metricFinder.findAll());
-  }
-
-  /**
-   * only for unit tests
-   */
-  DifferentialValueDecorator(DatabaseSession session, Snapshot[] projectTargetSnapshots, Collection<Metric> metrics) {
-    this.session = session;
-    this.projectTargetSnapshots = projectTargetSnapshots;
-    initMetrics(metrics);
-  }
-
-  private void initMetrics(Collection<Metric> metrics) {
-    this.metricByIds = Maps.newHashMap();
-    for (Metric metric : metrics) {
-      if (metric.isNumericType()) {
-        metricByIds.put(metric.getId(), metric);
-      }
-    }
-  }
-
-  public boolean shouldExecuteOnProject(Project project) {
-    return true;
-  }
-
-  @DependsUpon
-  public Collection<Metric> dependsUponMetrics() {
-    return metricByIds.values();
-  }
-
-  static boolean shouldCalculateDiffValues(Resource resource) {
-    // measures on files are currently purged, so past measures are not available
-    return !ResourceUtils.isEntity(resource);
-  }
-
-  public void decorate(Resource resource, DecoratorContext context) {
-    if (shouldCalculateDiffValues(resource)) {
-      for (int index = 0; index < projectTargetSnapshots.length; index++) {
-        Snapshot projectTargetSnapshot = projectTargetSnapshots[index];
-        if (projectTargetSnapshot != null) {
-          calculateDiffValues(resource, context, index, projectTargetSnapshot);
-        }
-      }
-    }
-  }
-
-  private void calculateDiffValues(Resource resource, DecoratorContext context, int index, Snapshot projectTargetSnapshot) {
-    List<MeasureModel> pastMeasures = selectPastMeasures(resource.getId(), projectTargetSnapshot);
-    compareWithPastMeasures(context, index, pastMeasures);
-  }
-
-  void compareWithPastMeasures(DecoratorContext context, int index, List<MeasureModel> pastMeasures) {
-    Map<MeasureKey, MeasureModel> pastMeasuresByKey = Maps.newHashMap();
-    for (MeasureModel pastMeasure : pastMeasures) {
-      pastMeasuresByKey.put(new MeasureKey(pastMeasure), pastMeasure);
-    }
-
-    // for each measure, search equivalent past measure
-    for (Measure measure : context.getMeasures(MeasuresFilters.all())) {
-      // compare with past measure
-      MeasureModel pastMeasure = pastMeasuresByKey.get(new MeasureKey(measure));
-      if (updateDiffValue(measure, pastMeasure, index)) {
-        context.saveMeasure(measure);
-      }
-    }
-  }
-
-  boolean updateDiffValue(Measure measure, MeasureModel pastMeasure, int index) {
-    boolean updated = false;
-    if (pastMeasure != null && pastMeasure.getValue() != null && measure.getValue() != null) {
-      double diff = (measure.getValue().doubleValue() - pastMeasure.getValue().doubleValue());
-      updated = true;
-      switch (index) {
-        case 0:
-          measure.setDiffValue1(diff);
-          break;
-        case 1:
-          measure.setDiffValue2(diff);
-          break;
-        case 2:
-          measure.setDiffValue3(diff);
-          break;
-        default:
-          updated = false;
-      }
-    }
-    return updated;
-  }
-
-  List<MeasureModel> selectPastMeasures(int resourceId, Snapshot projectTargetSnapshot) {
-    // improvements : keep query in cache ? select only some columns ?
-    // TODO support measure on rules and characteristics
-    String hql = "select m from " + MeasureModel.class.getSimpleName() + " m, " + Snapshot.class.getSimpleName() + " s " +
-        "where m.snapshotId=s.id and m.metricId in (:metricIds) and m.ruleId=null and m.rulePriority=null and m.rulesCategoryId=null and m.characteristic=null "
-        + "and (s.rootId=:rootSnapshotId or s.id=:rootSnapshotId) and s.resourceId=:resourceId and s.status=:status";
-    return session.createQuery(hql)
-        .setParameter("metricIds", metricByIds.keySet())
-        .setParameter("rootSnapshotId", ObjectUtils.defaultIfNull(projectTargetSnapshot.getRootId(), projectTargetSnapshot.getId()))
-        .setParameter("resourceId", resourceId)
-        .setParameter("status", Snapshot.STATUS_PROCESSED)
-        .getResultList();
-  }
-
-  @Override
-  public String toString() {
-    return getClass().toString();
-  }
-
-  static class MeasureKey {
-    Integer metricId;
-    Integer ruleId;
-    Integer categoryId;
-    RulePriority priority;
-    Characteristic characteristic;
-
-    MeasureKey(MeasureModel model) {
-      metricId = model.getMetricId();
-      ruleId = model.getRuleId();
-      categoryId = model.getRulesCategoryId();
-      priority = model.getRulePriority();
-      characteristic = model.getCharacteristic();
-    }
-
-    MeasureKey(Measure measure) {
-      metricId = measure.getMetric().getId();
-      characteristic = measure.getCharacteristic();
-      // TODO merge RuleMeasure into Measure
-      if (measure instanceof RuleMeasure) {
-        RuleMeasure rm = (RuleMeasure) measure;
-        categoryId = rm.getRuleCategory();
-        ruleId = (rm.getRule()==null ? null : rm.getRule().getId());
-        priority = rm.getRulePriority();
-      }
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) return true;
-      if (o == null || getClass() != o.getClass()) return false;
-
-      MeasureKey that = (MeasureKey) o;
-
-      if (categoryId != null ? !categoryId.equals(that.categoryId) : that.categoryId != null) return false;
-      if (characteristic != null ? !characteristic.equals(that.characteristic) : that.characteristic != null)
-        return false;
-      if (!metricId.equals(that.metricId)) return false;
-      if (priority != that.priority) return false;
-      if (ruleId != null ? !ruleId.equals(that.ruleId) : that.ruleId != null) return false;
-
-      return true;
-    }
-
-    @Override
-    public int hashCode() {
-      int result = metricId.hashCode();
-      result = 31 * result + (ruleId != null ? ruleId.hashCode() : 0);
-      result = 31 * result + (categoryId != null ? categoryId.hashCode() : 0);
-      result = 31 * result + (priority != null ? priority.hashCode() : 0);
-      result = 31 * result + (characteristic != null ? characteristic.hashCode() : 0);
-      return result;
-    }
-  }
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java
new file mode 100644 (file)
index 0000000..d4bdf23
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * 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
+ */
+package org.sonar.plugins.core.timemachine;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.lang.ObjectUtils;
+import org.sonar.api.batch.*;
+import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.database.model.MeasureModel;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.measures.*;
+import org.sonar.api.qualitymodel.Characteristic;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.ResourceUtils;
+import org.sonar.api.rules.RulePriority;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+@DependedUpon(DecoratorBarriers.END_OF_TIME_MACHINE)
+public class VariationDecorator implements Decorator {
+
+  private Snapshot[] projectTargetSnapshots;
+  private Map<Integer, Metric> metricByIds;
+  private DatabaseSession session;
+
+  public VariationDecorator(DatabaseSession session, PeriodLocator periodLocator, Configuration configuration, MetricFinder metricFinder) {
+    this.session = session;
+    Snapshot snapshot = periodLocator.locate(5);
+    projectTargetSnapshots = new Snapshot[]{snapshot};
+    initMetrics(metricFinder.findAll());
+  }
+
+  /**
+   * only for unit tests
+   */
+  VariationDecorator(DatabaseSession session, Snapshot[] projectTargetSnapshots, Collection<Metric> metrics) {
+    this.session = session;
+    this.projectTargetSnapshots = projectTargetSnapshots;
+    initMetrics(metrics);
+  }
+
+  private void initMetrics(Collection<Metric> metrics) {
+    this.metricByIds = Maps.newHashMap();
+    for (Metric metric : metrics) {
+      if (metric.isNumericType()) {
+        metricByIds.put(metric.getId(), metric);
+      }
+    }
+  }
+
+  public boolean shouldExecuteOnProject(Project project) {
+    return true;
+  }
+
+  @DependsUpon
+  public Collection<Metric> dependsUponMetrics() {
+    return metricByIds.values();
+  }
+
+  static boolean shouldCalculateDiffValues(Resource resource) {
+    // measures on files are currently purged, so past measures are not available
+    return !ResourceUtils.isEntity(resource);
+  }
+
+  public void decorate(Resource resource, DecoratorContext context) {
+    if (shouldCalculateDiffValues(resource)) {
+      for (int index = 0; index < projectTargetSnapshots.length; index++) {
+        Snapshot projectTargetSnapshot = projectTargetSnapshots[index];
+        if (projectTargetSnapshot != null) {
+          calculateDiffValues(resource, context, index, projectTargetSnapshot);
+        }
+      }
+    }
+  }
+
+  private void calculateDiffValues(Resource resource, DecoratorContext context, int index, Snapshot projectTargetSnapshot) {
+    List<MeasureModel> pastMeasures = selectPastMeasures(resource.getId(), projectTargetSnapshot);
+    compareWithPastMeasures(context, index, pastMeasures);
+  }
+
+  void compareWithPastMeasures(DecoratorContext context, int index, List<MeasureModel> pastMeasures) {
+    Map<MeasureKey, MeasureModel> pastMeasuresByKey = Maps.newHashMap();
+    for (MeasureModel pastMeasure : pastMeasures) {
+      pastMeasuresByKey.put(new MeasureKey(pastMeasure), pastMeasure);
+    }
+
+    // for each measure, search equivalent past measure
+    for (Measure measure : context.getMeasures(MeasuresFilters.all())) {
+      // compare with past measure
+      MeasureModel pastMeasure = pastMeasuresByKey.get(new MeasureKey(measure));
+      if (updateDiffValue(measure, pastMeasure, index)) {
+        context.saveMeasure(measure);
+      }
+    }
+  }
+
+  boolean updateDiffValue(Measure measure, MeasureModel pastMeasure, int index) {
+    boolean updated = false;
+    if (pastMeasure != null && pastMeasure.getValue() != null && measure.getValue() != null) {
+      double diff = (measure.getValue().doubleValue() - pastMeasure.getValue().doubleValue());
+      updated = true;
+      switch (index) {
+        case 0:
+          measure.setDiffValue1(diff);
+          break;
+        case 1:
+          measure.setDiffValue2(diff);
+          break;
+        case 2:
+          measure.setDiffValue3(diff);
+          break;
+        default:
+          updated = false;
+      }
+    }
+    return updated;
+  }
+
+  List<MeasureModel> selectPastMeasures(int resourceId, Snapshot projectTargetSnapshot) {
+    // improvements : keep query in cache ? select only some columns ?
+    // TODO support measure on rules and characteristics
+    String hql = "select m from " + MeasureModel.class.getSimpleName() + " m, " + Snapshot.class.getSimpleName() + " s " +
+        "where m.snapshotId=s.id and m.metricId in (:metricIds) and m.ruleId=null and m.rulePriority=null and m.rulesCategoryId=null and m.characteristic=null "
+        + "and (s.rootId=:rootSnapshotId or s.id=:rootSnapshotId) and s.resourceId=:resourceId and s.status=:status";
+    return session.createQuery(hql)
+        .setParameter("metricIds", metricByIds.keySet())
+        .setParameter("rootSnapshotId", ObjectUtils.defaultIfNull(projectTargetSnapshot.getRootId(), projectTargetSnapshot.getId()))
+        .setParameter("resourceId", resourceId)
+        .setParameter("status", Snapshot.STATUS_PROCESSED)
+        .getResultList();
+  }
+
+  @Override
+  public String toString() {
+    return getClass().toString();
+  }
+
+  static class MeasureKey {
+    Integer metricId;
+    Integer ruleId;
+    Integer categoryId;
+    RulePriority priority;
+    Characteristic characteristic;
+
+    MeasureKey(MeasureModel model) {
+      metricId = model.getMetricId();
+      ruleId = model.getRuleId();
+      categoryId = model.getRulesCategoryId();
+      priority = model.getRulePriority();
+      characteristic = model.getCharacteristic();
+    }
+
+    MeasureKey(Measure measure) {
+      metricId = measure.getMetric().getId();
+      characteristic = measure.getCharacteristic();
+      // TODO merge RuleMeasure into Measure
+      if (measure instanceof RuleMeasure) {
+        RuleMeasure rm = (RuleMeasure) measure;
+        categoryId = rm.getRuleCategory();
+        ruleId = (rm.getRule()==null ? null : rm.getRule().getId());
+        priority = rm.getRulePriority();
+      }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      MeasureKey that = (MeasureKey) o;
+
+      if (categoryId != null ? !categoryId.equals(that.categoryId) : that.categoryId != null) return false;
+      if (characteristic != null ? !characteristic.equals(that.characteristic) : that.characteristic != null)
+        return false;
+      if (!metricId.equals(that.metricId)) return false;
+      if (priority != that.priority) return false;
+      if (ruleId != null ? !ruleId.equals(that.ruleId) : that.ruleId != null) return false;
+
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      int result = metricId.hashCode();
+      result = 31 * result + (ruleId != null ? ruleId.hashCode() : 0);
+      result = 31 * result + (categoryId != null ? categoryId.hashCode() : 0);
+      result = 31 * result + (priority != null ? priority.hashCode() : 0);
+      result = 31 * result + (characteristic != null ? characteristic.hashCode() : 0);
+      return result;
+    }
+  }
+}
index fc028d5b8cff83bfbf90f2f1a2800b23eadaea0f..cdc3054543cc379f8856f2f58cd096c33c434871 100644 (file)
@@ -23,6 +23,7 @@ import org.sonar.api.web.*;
 \r
 @WidgetCategory({"Tests"})\r
 @Description("Reports on units tests and code coverage by unit tests.")\r
+@SupportVariationDashboard\r
 public class CodeCoverageWidget extends AbstractRubyTemplate implements RubyRailsWidget {\r
   public String getId() {\r
     return "code_coverage";\r
index 6244640336674767ae7d5b0d5375f966b4670d71..deaf2312209474ccfda31927ee2cc2599147baaf 100644 (file)
@@ -22,8 +22,10 @@ package org.sonar.plugins.core.widgets;
 import org.sonar.api.web.AbstractRubyTemplate;\r
 import org.sonar.api.web.Description;\r
 import org.sonar.api.web.RubyRailsWidget;\r
+import org.sonar.api.web.SupportVariationDashboard;\r
 \r
 @Description("Reports on copy/paste and documentation")\r
+@SupportVariationDashboard\r
 public class CommentsDuplicationsWidget extends AbstractRubyTemplate implements RubyRailsWidget {\r
   public String getId() {\r
     return "comments_duplications";\r
index 90dba687ae3e778b33d79f609657f872149f107d..48253c89b825b5e6b550d13d39f39b6318e0f91a 100644 (file)
@@ -22,8 +22,10 @@ package org.sonar.plugins.core.widgets;
 import org.sonar.api.web.AbstractRubyTemplate;\r
 import org.sonar.api.web.Description;\r
 import org.sonar.api.web.RubyRailsWidget;\r
+import org.sonar.api.web.SupportVariationDashboard;\r
 \r
 @Description("Reports on complexity, average complexity and complexity distribution.")\r
+@SupportVariationDashboard\r
 public class ComplexityWidget extends AbstractRubyTemplate implements RubyRailsWidget {\r
   public String getId() {\r
     return "complexity";\r
index d9d166aefdada24c827bcf435d638e81ac8b2300..da43347c7c007e732997133fec61a7a1f6675e7a 100644 (file)
@@ -23,6 +23,7 @@ import org.sonar.api.web.*;
 \r
 @WidgetCategory({"Rules"})\r
 @Description("Reports violations and compliance index on coding standards.")\r
+@SupportVariationDashboard\r
 public class RulesWidget extends AbstractRubyTemplate implements RubyRailsWidget {\r
   public String getId() {\r
     return "rules";\r
index 3c6a5c4205599e139d83d496c635e335ad879983..df04453f03c65bb60a134e21d6e1acbc49243844 100644 (file)
@@ -22,8 +22,10 @@ package org.sonar.plugins.core.widgets;
 import org.sonar.api.web.AbstractRubyTemplate;\r
 import org.sonar.api.web.Description;\r
 import org.sonar.api.web.RubyRailsWidget;\r
+import org.sonar.api.web.SupportVariationDashboard;\r
 \r
 @Description("Reports general metrics on the size of the project.")\r
+@SupportVariationDashboard\r
 public class SizeWidget extends AbstractRubyTemplate implements RubyRailsWidget {\r
   public String getId() {\r
     return "size";\r
index 53f08f4d8496075a2c0033cbf229225bbfe80427..3ca7e36b1b52caa24e7e3fb228471a52397faf0f 100644 (file)
@@ -7,22 +7,22 @@ if code_coverage_measure || tests_measure %>
                <td valign="top" width="50%" nowrap>
       <div class="dashbox">
         <p class="title">Code coverage</p>
-        <p><span class="big"><%= format_measure(code_coverage_measure, :suffix => '', :url => url_for_drilldown(Metric::COVERAGE), :default => '-') %> <%= tendency_icon(code_coverage_measure, false) %></span></p>
+        <p><span class="big"><%= format_measure(code_coverage_measure, :suffix => '', :url => url_for_drilldown(Metric::COVERAGE), :default => '-') %> <%= trend_icon(code_coverage_measure, :big => true) %></span></p>
         <% line_coverage=measure(Metric::LINE_COVERAGE)
           if line_coverage %>
-          <p><%= format_measure(line_coverage, :suffix => ' line coverage', :url => url_for_drilldown(Metric::UNCOVERED_LINES, :highlight =>  Metric::LINE_COVERAGE)) %> <%= tendency_icon(line_coverage) %></p>
+          <p><%= format_measure(line_coverage, :suffix => ' line coverage', :url => url_for_drilldown(Metric::UNCOVERED_LINES, :highlight =>  Metric::LINE_COVERAGE)) %> <%= trend_icon(line_coverage) %></p>
         <% end %>
         <% branch_coverage=measure(Metric::BRANCH_COVERAGE)
           if branch_coverage %>
-          <p><%= format_measure(branch_coverage, :suffix => ' branch coverage', :url => url_for_drilldown(Metric::UNCOVERED_CONDITIONS, :highlight =>  Metric::BRANCH_COVERAGE)) %> <%= tendency_icon(branch_coverage) %></p>
+          <p><%= format_measure(branch_coverage, :suffix => ' branch coverage', :url => url_for_drilldown(Metric::UNCOVERED_CONDITIONS, :highlight =>  Metric::BRANCH_COVERAGE)) %> <%= trend_icon(branch_coverage) %></p>
         <% end %>
-        <p><%= format_measure(tests_measure, :suffix => ' tests', :url => url_for_drilldown(Metric::TESTS)) %> <%= tendency_icon(tests_measure) %></p>
+        <p><%= format_measure(tests_measure, :suffix => ' tests', :url => url_for_drilldown(Metric::TESTS)) %> <%= trend_icon(tests_measure) %></p>
         <% skipped_measure=measure(Metric::SKIPPED_TESTS)
            if skipped_measure && skipped_measure.value>0
         %>
-        <p>+<%= format_measure(skipped_measure, :suffix => ' skipped', :url => url_for_drilldown(Metric::SKIPPED_TESTS)) %> <%= tendency_icon(skipped_measure) %></p>
+        <p>+<%= format_measure(skipped_measure, :suffix => ' skipped', :url => url_for_drilldown(Metric::SKIPPED_TESTS)) %> <%= trend_icon(skipped_measure) %></p>
         <% end %>
-        <p><%= format_measure(Metric::TEST_EXECUTION_TIME, :suffix => '', :url => url_for_drilldown(Metric::TEST_EXECUTION_TIME)) %> <%= tendency_icon(measure(Metric::TEST_EXECUTION_TIME)) %></p>
+        <p><%= format_measure(Metric::TEST_EXECUTION_TIME, :suffix => '', :url => url_for_drilldown(Metric::TEST_EXECUTION_TIME)) %> <%= trend_icon(measure(Metric::TEST_EXECUTION_TIME)) %></p>
       </div>
     </td>
     <td valign="top" width="50%" nowrap>
@@ -32,12 +32,12 @@ if code_coverage_measure || tests_measure %>
   %>
   <div class="dashbox">
       <h3>Test success</h3>
-      <p><span class="big"><%= format_measure(success_percentage, :suffix => '', :url => url_for_drilldown(success_percentage)) %> <%= tendency_icon(measure(Metric::TEST_SUCCESS_DENSITY), false) %></span></p>
+      <p><span class="big"><%= format_measure(success_percentage, :suffix => '', :url => url_for_drilldown(success_percentage)) %> <%= trend_icon(measure(Metric::TEST_SUCCESS_DENSITY), :big => true) %></span></p>
       <p>
-        <%= format_measure(Metric::TEST_FAILURES, :suffix => ' failures', :url => url_for_drilldown(Metric::TEST_FAILURES)) %> <%= tendency_icon(measure(Metric::TEST_FAILURES)) %>
+        <%= format_measure(Metric::TEST_FAILURES, :suffix => ' failures', :url => url_for_drilldown(Metric::TEST_FAILURES)) %> <%= trend_icon(measure(Metric::TEST_FAILURES)) %>
       </p>
       <p>
-        <%= format_measure(Metric::TEST_ERRORS, :suffix => ' errors', :url => url_for_drilldown(Metric::TEST_ERRORS)) %> <%= tendency_icon(measure(Metric::TEST_ERRORS)) %>
+        <%= format_measure(Metric::TEST_ERRORS, :suffix => ' errors', :url => url_for_drilldown(Metric::TEST_ERRORS)) %> <%= trend_icon(measure(Metric::TEST_ERRORS)) %>
       </p>
   </div>
   <% end %>
index 078822eb55698ea52093c5531af6fa206e2c537d..53582cd0f27814a6a1825bd6ce73ffb0a6f47451 100644 (file)
@@ -5,17 +5,17 @@
                        <% if (measure(Metric::COMMENT_LINES)) %>
                    <div class="dashbox">
                      <h3>Comments</h3>
-                     <p><span class="big"><%= format_measure(Metric::COMMENT_LINES_DENSITY, :suffix => '', :url => url_for_drilldown(Metric::COMMENT_LINES_DENSITY)) -%> <%= tendency_icon(Metric::COMMENT_LINES_DENSITY, false) -%></span></p>
-                     <p><%= format_measure(Metric::COMMENT_LINES, :suffix => ' lines', :url => url_for_drilldown(Metric::COMMENT_LINES)) -%> <%= tendency_icon(Metric::COMMENT_LINES) -%></p>
+                     <p><span class="big"><%= format_measure(Metric::COMMENT_LINES_DENSITY, :suffix => '', :url => url_for_drilldown(Metric::COMMENT_LINES_DENSITY)) -%> <%= trend_icon(Metric::COMMENT_LINES_DENSITY, :big => true) -%></span></p>
+                     <p><%= format_measure(Metric::COMMENT_LINES, :suffix => ' lines', :url => url_for_drilldown(Metric::COMMENT_LINES)) -%> <%= trend_icon(Metric::COMMENT_LINES) -%></p>
                      <%
                      comment_blank_lines=measure('comment_blank_lines')
                      if comment_blank_lines && comment_blank_lines.value>0
                      %>
-                     <p>+<%= format_measure(comment_blank_lines, :suffix => ' blank', :url => url_for_drilldown(comment_blank_lines)) -%> <%= tendency_icon(comment_blank_lines) -%></p>
+                     <p>+<%= format_measure(comment_blank_lines, :suffix => ' blank', :url => url_for_drilldown(comment_blank_lines)) -%> <%= trend_icon(comment_blank_lines) -%></p>
                      <% end %>
-                     <p><%= format_measure(Metric::PUBLIC_DOCUMENTED_API_DENSITY, :suffix => ' docu. API', :url => url_for_drilldown(Metric::PUBLIC_UNDOCUMENTED_API, :highlight => Metric::PUBLIC_DOCUMENTED_API_DENSITY)) -%> <%= tendency_icon(Metric::PUBLIC_DOCUMENTED_API_DENSITY) -%></p>
-                     <p><%= format_measure(Metric::PUBLIC_UNDOCUMENTED_API, :suffix => ' undocu. API', :url => url_for_drilldown(Metric::PUBLIC_UNDOCUMENTED_API, :highlight => Metric::PUBLIC_UNDOCUMENTED_API)) -%> <%= tendency_icon(Metric::PUBLIC_UNDOCUMENTED_API) -%></p>
-                     <p><%= format_measure(Metric::COMMENTED_OUT_CODE_LINES, :suffix => ' commented LOCs', :url => url_for_drilldown(Metric::COMMENTED_OUT_CODE_LINES, :highlight => Metric::COMMENTED_OUT_CODE_LINES)) -%> <%= tendency_icon(Metric::COMMENTED_OUT_CODE_LINES) -%></p>
+                     <p><%= format_measure(Metric::PUBLIC_DOCUMENTED_API_DENSITY, :suffix => ' docu. API', :url => url_for_drilldown(Metric::PUBLIC_UNDOCUMENTED_API, :highlight => Metric::PUBLIC_DOCUMENTED_API_DENSITY)) -%> <%= trend_icon(Metric::PUBLIC_DOCUMENTED_API_DENSITY) -%></p>
+                     <p><%= format_measure(Metric::PUBLIC_UNDOCUMENTED_API, :suffix => ' undocu. API', :url => url_for_drilldown(Metric::PUBLIC_UNDOCUMENTED_API, :highlight => Metric::PUBLIC_UNDOCUMENTED_API)) -%> <%= trend_icon(Metric::PUBLIC_UNDOCUMENTED_API) -%></p>
+                     <p><%= format_measure(Metric::COMMENTED_OUT_CODE_LINES, :suffix => ' commented LOCs', :url => url_for_drilldown(Metric::COMMENTED_OUT_CODE_LINES, :highlight => Metric::COMMENTED_OUT_CODE_LINES)) -%> <%= trend_icon(Metric::COMMENTED_OUT_CODE_LINES) -%></p>
                    </div>
                    <% end %>
                </td>
                    <% if (measure(Metric::DUPLICATED_LINES_DENSITY)) %>
                    <div class="dashbox">
                      <h3>Duplications</h3>
-                     <p><span class="big"><%= format_measure(Metric::DUPLICATED_LINES_DENSITY, :suffix => '', :url => url_for_drilldown(Metric::DUPLICATED_LINES, :highlight =>  Metric::DUPLICATED_LINES_DENSITY)) -%> <%= tendency_icon(Metric::DUPLICATED_LINES_DENSITY, false) -%></span></p>
-                     <p><%= format_measure(Metric::DUPLICATED_LINES, :suffix => ' lines', :url => url_for_drilldown(Metric::DUPLICATED_LINES)) -%> <%= tendency_icon(Metric::DUPLICATED_LINES) -%></p>
-                     <p><%= format_measure(Metric::DUPLICATED_BLOCKS, :suffix => ' blocks', :url => url_for_drilldown(Metric::DUPLICATED_BLOCKS)) -%> <%= tendency_icon(Metric::DUPLICATED_BLOCKS) -%></p>
-                     <p><%= format_measure(Metric::DUPLICATED_FILES, :suffix => ' files', :url => url_for_drilldown(Metric::DUPLICATED_FILES)) -%> <%= tendency_icon(Metric::DUPLICATED_FILES) -%></p>
+                     <p><span class="big"><%= format_measure(Metric::DUPLICATED_LINES_DENSITY, :suffix => '', :url => url_for_drilldown(Metric::DUPLICATED_LINES, :highlight =>  Metric::DUPLICATED_LINES_DENSITY)) -%> <%= trend_icon(Metric::DUPLICATED_LINES_DENSITY, :big => true) -%></span></p>
+                     <p><%= format_measure(Metric::DUPLICATED_LINES, :suffix => ' lines', :url => url_for_drilldown(Metric::DUPLICATED_LINES)) -%> <%= trend_icon(Metric::DUPLICATED_LINES) -%></p>
+                     <p><%= format_measure(Metric::DUPLICATED_BLOCKS, :suffix => ' blocks', :url => url_for_drilldown(Metric::DUPLICATED_BLOCKS)) -%> <%= trend_icon(Metric::DUPLICATED_BLOCKS) -%></p>
+                     <p><%= format_measure(Metric::DUPLICATED_FILES, :suffix => ' files', :url => url_for_drilldown(Metric::DUPLICATED_FILES)) -%> <%= trend_icon(Metric::DUPLICATED_FILES) -%></p>
                    </div>
                    <% end %>
 
index 43bc5683a5d13017e7dbbf6dbc65888f09fc66d1..df900e95bbb37b8775e1a2766dd726f2f475ad7c 100644 (file)
@@ -16,27 +16,27 @@ complexity=measure('complexity')
          <h3>Complexity</h3>
          <% if function_complexity %>
            <p>
-             <span class="big"><%= format_measure(function_complexity, :suffix => '', :url => url_for_drilldown(function_complexity)) -%> <%= tendency_icon(function_complexity, false) -%></span>/ method
+             <span class="big"><%= format_measure(function_complexity, :suffix => '', :url => url_for_drilldown(function_complexity)) -%> <%= trend_icon(function_complexity, :big => true) -%></span>/ method
            </p>
          <% end %>
          <% if paragraph_complexity %>
            <p>
-              <span class="big"><%= format_measure(paragraph_complexity, :suffix => '', :url => url_for_drilldown(paragraph_complexity)) -%> <%= tendency_icon(paragraph_complexity, false) -%></span>/ paragraph
+              <span class="big"><%= format_measure(paragraph_complexity, :suffix => '', :url => url_for_drilldown(paragraph_complexity)) -%> <%= trend_icon(paragraph_complexity, :big => true) -%></span>/ paragraph
            </p>
          <% end %>
          <% if class_complexity %>
            <p>
-             <span class="big"><%= format_measure(class_complexity, :suffix => '', :url => url_for_drilldown(class_complexity)) -%> <%= tendency_icon(class_complexity, false) -%></span>/ class
+             <span class="big"><%= format_measure(class_complexity, :suffix => '', :url => url_for_drilldown(class_complexity)) -%> <%= trend_icon(class_complexity, :big => true) -%></span>/ class
            </p>
          <% end %>
          <% if file_complexity %>
            <p>
-              <span class="big"><%= format_measure(file_complexity, :suffix => '', :url => url_for_drilldown(file_complexity)) -%> <%= tendency_icon(file_complexity, false) -%></span>/ file
+              <span class="big"><%= format_measure(file_complexity, :suffix => '', :url => url_for_drilldown(file_complexity)) -%> <%= trend_icon(file_complexity, :big => true) -%></span>/ file
            </p>
          <% end %>
          <% if complexity %>
          <p>
-           Total: <%= format_measure(complexity, :url => url_for_drilldown(complexity)) -%> <%= tendency_icon(complexity) -%>
+           Total: <%= format_measure(complexity, :url => url_for_drilldown(complexity)) -%> <%= trend_icon(complexity) -%>
          </p>
          <% end %>
         </div>
@@ -52,7 +52,7 @@ complexity=measure('complexity')
  if distributions.size>0
    selected_distribution=distributions.first
  end
- if selected_distribution
+ if selected_distribution && !dashboard_configuration.variation?
 %>
 <div class="dashbox" id="cmp_charts">
  <script type='text/javascript'>
index ed5aa6e43da0caaab94d3d55274deb62abce4e3e..d5f617a164967b5723accfb3054f31a94fe2695a 100644 (file)
@@ -5,7 +5,7 @@
                                <div class="dashbox">
                                    <h3>Rules compliance</h3>
                                    <div class="big">
-                                     <%= format_measure(Metric::VIOLATIONS_DENSITY, :url => url_for_drilldown(Metric::WEIGHTED_VIOLATIONS, {:highlight => Metric::WEIGHTED_VIOLATIONS})) -%> <%= tendency_icon(Metric::VIOLATIONS_DENSITY) -%>
+                                     <%= format_measure(Metric::VIOLATIONS_DENSITY, :url => url_for_drilldown(Metric::WEIGHTED_VIOLATIONS, {:highlight => Metric::WEIGHTED_VIOLATIONS})) -%> <%= trend_icon(Metric::VIOLATIONS_DENSITY) -%>
                                    </div>
                                          <%
                                     maintainability=@snapshot.measure(Metric::MAINTAINABILITY)
                                            <tr>
                                              <td align="left" nowrap>Efficiency &nbsp;</td>
                                              <td align="right" id="m_efficiency"><%=  formatted_value(efficiency) %></td>
-                                             <td nowrap> &nbsp;<%= tendency_icon(efficiency) -%></td>
+                                             <td nowrap> &nbsp;<%= trend_icon(efficiency) -%></td>
                                            </tr>
                                            <tr>
                                              <td align="left" nowrap>Maintainability  &nbsp;</td>
                                              <td align="right" id="m_maintainability"><%=  formatted_value(maintainability) %></td>
-                                             <td nowrap> &nbsp;<%= tendency_icon(maintainability) -%></td>
+                                             <td nowrap> &nbsp;<%= trend_icon(maintainability) -%></td>
                                            </tr>
                                            <tr>
                                              <td align="left" nowrap>Portability  &nbsp;</td>
                                              <td align="right" id="m_portability"><%=  formatted_value(portability) %></td>
-                                             <td nowrap> &nbsp;<%= tendency_icon(portability) -%></td>
+                                             <td nowrap> &nbsp;<%= trend_icon(portability) -%></td>
                                            </tr>
                                            <tr>
                                              <td align="left" nowrap>Reliability  &nbsp;</td>
                                              <td align="right" id="m_reliability"><%=  formatted_value(reliability) %></td>
-                                             <td nowrap> &nbsp;<%= tendency_icon(reliability) -%></td>
+                                             <td nowrap> &nbsp;<%= trend_icon(reliability) -%></td>
                                            </tr>
                                            <tr>
                                              <td align="left" nowrap>Usability  &nbsp;</td>
                                              <td align="right" id="m_usability"><%=  formatted_value(usability) %></td>
-                                             <td nowrap> &nbsp;<%= tendency_icon(usability) -%></td>
+                                             <td nowrap> &nbsp;<%= trend_icon(usability) -%></td>
                                            </tr>
                                          </table>
                                        </span>
@@ -54,7 +54,7 @@
                          <div class="dashbox">
                            <h3>Violations</h3>
                            <div class="big">
-                             <%= format_measure(Metric::VIOLATIONS, :url => url_for(:controller => 'drilldown', :action => 'violations', :id => @project.key)) -%> <%= tendency_icon(Metric::VIOLATIONS) -%>
+                             <%= format_measure(Metric::VIOLATIONS, :url => url_for(:controller => 'drilldown', :action => 'violations', :id => @project.key)) -%> <%= trend_icon(Metric::VIOLATIONS) -%>
                            </div>
                          </div>
                        <%
@@ -75,7 +75,7 @@
                                <td style="padding-left: 10px;" align="right">
                                  <%= format_measure(blocker_violations) -%>
                                </td>
-                               <td width="1%"><%= tendency_icon(blocker_violations) -%></td>
+                               <td width="1%"><%= trend_icon(blocker_violations) -%></td>
                                <td align="left" style="padding-bottom:2px; padding-top:2px;">
                                 <%= barchart(:width => 60, :percent => (blocker_violations ? (100 * blocker_violations.value / max).to_i : 0), :color => '#777777') if max>0 %>
                                </td>
@@ -86,7 +86,7 @@
                                <td style="padding-left: 10px;" align="right">
                                    <%= format_measure(critical_violations) -%>
                                </td>
-                               <td width="1%"><%= tendency_icon(critical_violations) -%></td>
+                               <td width="1%"><%= trend_icon(critical_violations) -%></td>
                                <td align="left" style="padding-bottom:2px; padding-top:2px;">
                                  <%= barchart(:width => 60, :percent => (critical_violations ? (100 * critical_violations.value / max).to_i : 0), :color => '#777777') if max>0 %>
                                </td>
@@ -97,7 +97,7 @@
                                <td style="padding-left: 10px;" align="right">
                                  <%= format_measure(major_violations) -%>
                               </td>
-                              <td width="1%"><%= tendency_icon(major_violations) -%></td>
+                              <td width="1%"><%= trend_icon(major_violations) -%></td>
                               <td align="left" style="padding-bottom:2px; padding-top:2px;">
                                  <%= barchart(:width => 60, :percent => (major_violations ? (100 * major_violations.value / max).to_i : 0), :color => '#777777') if max>0 %>
                                </td>
                                <td style="padding-left: 10px;" align="right">
                                    <%= format_measure(minor_violations) -%>
                               </td>
-                              <td width="1%"><%= tendency_icon(minor_violations) -%></td>
+                              <td width="1%"><%= trend_icon(minor_violations) -%></td>
                               <td align="left" style="padding-bottom:2px; padding-top:2px;">
                                  <%= barchart(:width => 60, :percent => (minor_violations ? (100 * minor_violations.value / max).to_i : 0), :color => '#777777') if max>0 %>
                                </td>
                                <td style="padding-left: 10px;" align="right">
                                              <%= format_measure(info_violations) -%>
                               </td>
-                              <td width="1%"><%= tendency_icon(info_violations) -%></td>
+                              <td width="1%"><%= trend_icon(info_violations) -%></td>
                               <td align="left" style="padding-bottom:2px; padding-top:2px;">
                                  <%= barchart(:width => 60, :percent => (info_violations ? (100 * info_violations.value / max).to_i : 0), :color => '#777777') if max>0 %>
                                </td>
index f8baf7ad4d3c001a027c8293d311122284a08425..3dcce9a099e7b476b474bac9acd3f8d4f20ff9e0 100644 (file)
@@ -10,30 +10,30 @@ if measure('lines') || measure('ncloc')
                      <h3>Lines of code</h3>
                            <% if measure('ncloc') %>
                              <p><span class="big">
-                             <%= format_measure('ncloc', :suffix => '', :url => url_for_drilldown('ncloc')) -%> <%= tendency_icon('ncloc', false) -%></span></p>
+                             <%= format_measure('ncloc', :suffix => '', :url => url_for_drilldown('ncloc')) -%> <%= trend_icon('ncloc', :big => true) -%></span></p>
                              <%
                                generated_ncloc=measure('generated_ncloc')
                                if generated_ncloc && generated_ncloc.value>0
                              %>
-                             <p>+<%= format_measure(generated_ncloc, :suffix => ' generated', :url => url_for_drilldown(generated_ncloc)) -%> <%= tendency_icon(generated_ncloc) -%></p>
+                             <p>+<%= format_measure(generated_ncloc, :suffix => ' generated', :url => url_for_drilldown(generated_ncloc)) -%> <%= trend_icon(generated_ncloc) -%></p>
                              <% end %>
-                             <p><%= format_measure('lines', :suffix => ' lines', :url => url_for_drilldown('lines')) -%> <%= tendency_icon('lines') -%></p>
+                             <p><%= format_measure('lines', :suffix => ' lines', :url => url_for_drilldown('lines')) -%> <%= trend_icon('lines') -%></p>
                            <% else%>
-                             <p><span class="big"><%= format_measure('lines', :suffix => '', :url => url_for_drilldown('lines')) -%> <%= tendency_icon('lines', false) -%></span></p>
+                             <p><span class="big"><%= format_measure('lines', :suffix => '', :url => url_for_drilldown('lines')) -%> <%= trend_icon('lines', :big => true) -%></span></p>
                            <% end %>
                            <%
                              generated_lines=measure('generated_lines')
                              if generated_lines && generated_lines.value>0
                            %>
-                             <p>incl. <%= format_measure(generated_lines, :suffix => ' generated', :url => url_for_drilldown(generated_lines)) -%> <%= tendency_icon(generated_lines) -%></p>
+                             <p>incl. <%= format_measure(generated_lines, :suffix => ' generated', :url => url_for_drilldown(generated_lines)) -%> <%= trend_icon(generated_lines) -%></p>
                            <% end %>
                            <% if statements %>
           <p>
-          <%= format_measure(statements, :suffix => ' statements', :url => url_for_drilldown(statements)) -%> <%= tendency_icon(statements) -%>
+          <%= format_measure(statements, :suffix => ' statements', :url => url_for_drilldown(statements)) -%> <%= trend_icon(statements) -%>
           </p>
           <% end %>
                            <% if files && measure('classes') %>
-                             <p><%= format_measure(files, :suffix => ' files', :url => url_for_drilldown(files)) -%> <%= tendency_icon(files) -%></p>
+                             <p><%= format_measure(files, :suffix => ' files', :url => url_for_drilldown(files)) -%> <%= trend_icon(files) -%></p>
                            <% end %>
                    </div>
                </td>
@@ -42,19 +42,19 @@ if measure('lines') || measure('ncloc')
                        <div class="dashbox">
                          <% if measure('classes') %>
                        <h3>Classes</h3>
-                       <p><span class="big"><%= format_measure('classes', :url => url_for_drilldown('classes')) -%> <%= tendency_icon('classes') -%></span></p>
-                           <p><%= format_measure('packages', :suffix => ' packages', :url => url_for_drilldown('packages')) -%> <%= tendency_icon('packages') -%></p>
+                       <p><span class="big"><%= format_measure('classes', :url => url_for_drilldown('classes')) -%> <%= trend_icon('classes') -%></span></p>
+                           <p><%= format_measure('packages', :suffix => ' packages', :url => url_for_drilldown('packages')) -%> <%= trend_icon('packages') -%></p>
                      <% else %>
                        <h3>Files</h3>
-                       <p><span class="big"><%= format_measure('files', :url => url_for_drilldown('files')) -%> <%= tendency_icon('files') -%></span></p>
-                           <p><%= format_measure('directories', :suffix => ' directories', :url => url_for_drilldown('directories')) -%> <%= tendency_icon('directories') -%></p>
+                       <p><span class="big"><%= format_measure('files', :url => url_for_drilldown('files')) -%> <%= trend_icon('files') -%></span></p>
+                           <p><%= format_measure('directories', :suffix => ' directories', :url => url_for_drilldown('directories')) -%> <%= trend_icon('directories') -%></p>
                      <% end %>
-                     <p><%= format_measure('functions', :suffix => ' methods', :url => url_for_drilldown('functions')) -%> <%= tendency_icon('functions') -%></p>
+                     <p><%= format_measure('functions', :suffix => ' methods', :url => url_for_drilldown('functions')) -%> <%= trend_icon('functions') -%></p>
                      <% if (measure('accessors')) %>
-                       <p><%= format_measure('accessors', :prefix => '+', :suffix => ' accessors', :url => url_for_drilldown('accessors')) -%> <%= tendency_icon('accessors') -%></p>
+                       <p><%= format_measure('accessors', :prefix => '+', :suffix => ' accessors', :url => url_for_drilldown('accessors')) -%> <%= trend_icon('accessors') -%></p>
                      <% end %>
                      <% if measure('paragraphs') %>
-                             <p><%= format_measure('paragraphs', :suffix => ' paragraphs', :url => url_for_drilldown('paragraphs')) -%> <%= tendency_icon('paragraphs') -%></p>
+                             <p><%= format_measure('paragraphs', :suffix => ' paragraphs', :url => url_for_drilldown('paragraphs')) -%> <%= trend_icon('paragraphs') -%></p>
                            <% end %>
                    </div>
                </td>
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/DifferentialValueDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/DifferentialValueDecoratorTest.java
deleted file mode 100644 (file)
index fd4b724..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2009 SonarSource SA
- * 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
- */
-package org.sonar.plugins.core.timemachine;
-
-import org.junit.Test;
-import org.sonar.api.database.model.MeasureModel;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.resources.*;
-import org.sonar.jpa.test.AbstractDbUnitTestCase;
-
-import java.util.List;
-
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-public class DifferentialValueDecoratorTest extends AbstractDbUnitTestCase {
-
-  private static final int PROJECT_SNAPSHOT_ID = 1000;
-  private static final int PROJECT_ID = 1;
-  private static final int FILE_ID = 3;
-
-  @Test
-  public void shouldSelectPastResourceMeasures() {
-    setupData("shared");
-
-    List<Metric> metrics = selectMetrics();
-    Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);
-
-    DifferentialValueDecorator decorator = new DifferentialValueDecorator(getSession(), new Snapshot[0], metrics);
-    List<MeasureModel> measures = decorator.selectPastMeasures(FILE_ID, projectSnapshot);
-    assertThat(measures.size(), is(2));
-
-    for (MeasureModel measure : measures) {
-      assertThat(measure.getId(), anyOf(is(5L), is(6L)));
-      assertThat(measure.getValue(), anyOf(is(5.0), is(60.0)));
-    }
-  }
-
-  @Test
-  public void shouldSelectPastProjectMeasures() {
-    setupData("shared");
-
-    List<Metric> metrics = selectMetrics();
-    Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);
-
-    DifferentialValueDecorator decorator = new DifferentialValueDecorator(getSession(), new Snapshot[0], metrics);
-    List<MeasureModel> measures = decorator.selectPastMeasures(PROJECT_ID, projectSnapshot);
-    assertThat(measures.size(), is(2));
-
-    for (MeasureModel measure : measures) {
-      assertThat(measure.getId(), anyOf(is(1L), is(2L)));
-      assertThat(measure.getValue(), anyOf(is(60.0), is(80.0)));
-    }
-  }
-
-  @Test
-  public void shouldNotCalculateDiffValuesOnFiles() {
-    assertThat(DifferentialValueDecorator.shouldCalculateDiffValues(new Project("foo")), is(true));
-    assertThat(DifferentialValueDecorator.shouldCalculateDiffValues(new JavaPackage("org.foo")), is(true));
-    assertThat(DifferentialValueDecorator.shouldCalculateDiffValues(new Directory("org/foo")), is(true));
-
-    assertThat(DifferentialValueDecorator.shouldCalculateDiffValues(new JavaFile("org.foo.Bar")), is(false));
-    assertThat(DifferentialValueDecorator.shouldCalculateDiffValues(new JavaFile("org.foo.Bar", true)), is(false));
-    assertThat(DifferentialValueDecorator.shouldCalculateDiffValues(new File("org/foo/Bar.php")), is(false));
-  }
-
-  private List<Metric> selectMetrics() {
-    return getSession().getResults(Metric.class);
-  }
-}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/VariationDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/VariationDecoratorTest.java
new file mode 100644 (file)
index 0000000..7e2e86d
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * 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
+ */
+package org.sonar.plugins.core.timemachine;
+
+import org.junit.Test;
+import org.sonar.api.database.model.MeasureModel;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.resources.*;
+import org.sonar.jpa.test.AbstractDbUnitTestCase;
+
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.anyOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class VariationDecoratorTest extends AbstractDbUnitTestCase {
+
+  private static final int PROJECT_SNAPSHOT_ID = 1000;
+  private static final int PROJECT_ID = 1;
+  private static final int FILE_ID = 3;
+
+  @Test
+  public void shouldSelectPastResourceMeasures() {
+    setupData("shared");
+
+    List<Metric> metrics = selectMetrics();
+    Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);
+
+    VariationDecorator decorator = new VariationDecorator(getSession(), new Snapshot[0], metrics);
+    List<MeasureModel> measures = decorator.selectPastMeasures(FILE_ID, projectSnapshot);
+    assertThat(measures.size(), is(2));
+
+    for (MeasureModel measure : measures) {
+      assertThat(measure.getId(), anyOf(is(5L), is(6L)));
+      assertThat(measure.getValue(), anyOf(is(5.0), is(60.0)));
+    }
+  }
+
+  @Test
+  public void shouldSelectPastProjectMeasures() {
+    setupData("shared");
+
+    List<Metric> metrics = selectMetrics();
+    Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);
+
+    VariationDecorator decorator = new VariationDecorator(getSession(), new Snapshot[0], metrics);
+    List<MeasureModel> measures = decorator.selectPastMeasures(PROJECT_ID, projectSnapshot);
+    assertThat(measures.size(), is(2));
+
+    for (MeasureModel measure : measures) {
+      assertThat(measure.getId(), anyOf(is(1L), is(2L)));
+      assertThat(measure.getValue(), anyOf(is(60.0), is(80.0)));
+    }
+  }
+
+  @Test
+  public void shouldNotCalculateDiffValuesOnFiles() {
+    assertThat(VariationDecorator.shouldCalculateDiffValues(new Project("foo")), is(true));
+    assertThat(VariationDecorator.shouldCalculateDiffValues(new JavaPackage("org.foo")), is(true));
+    assertThat(VariationDecorator.shouldCalculateDiffValues(new Directory("org/foo")), is(true));
+
+    assertThat(VariationDecorator.shouldCalculateDiffValues(new JavaFile("org.foo.Bar")), is(false));
+    assertThat(VariationDecorator.shouldCalculateDiffValues(new JavaFile("org.foo.Bar", true)), is(false));
+    assertThat(VariationDecorator.shouldCalculateDiffValues(new File("org/foo/Bar.php")), is(false));
+  }
+
+  private List<Metric> selectMetrics() {
+    return getSession().getResults(Metric.class);
+  }
+}
diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/DifferentialValueDecoratorTest/shared.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/DifferentialValueDecoratorTest/shared.xml
deleted file mode 100644 (file)
index 48fe462..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<dataset>
-
-  <metrics id="1" name="ncloc" VAL_TYPE="INT" DESCRIPTION="[null]"  domain="[null]" short_name=""
-           enabled="true" worst_value="[null]" optimized_best_value="[null]" best_value="[null]" direction="0" hidden="false"/>
-  <metrics id="2" name="coverage" VAL_TYPE="INT" DESCRIPTION="[null]"  domain="[null]" short_name=""
-           enabled="true" worst_value="0" optimized_best_value="true" best_value="100" direction="1" hidden="false"/>
-
-
-  <rules_categories id="1" name="Efficiency" description="[null]"/>
-  <rules_categories id="6" name="Usability" description="[null]"/>
-
-  <rules id="30" name="Check Header" rules_category_id="6" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
-         plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
-         cardinality="SINGLE" parent_id="[null]"/>
-
-  <rules id="31" name="Equals Avoid Null" rules_category_id="6" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"
-         plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
-         cardinality="SINGLE" parent_id="[null]"/>
-
-  <!-- project -->
-  <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
-            root_id="[null]"
-            description="[null]"
-            enabled="true" language="java" copy_resource_id="[null]"/>
-
-  <!-- package -->
-  <projects long_name="[null]" id="2" scope="DIR" qualifier="PAC" kee="project:org.foo" name="org.foo"
-            root_id="1"
-            description="[null]"
-            enabled="true" language="java" copy_resource_id="[null]"/>
-
-  <!-- file -->
-  <projects long_name="org.foo.Bar" id="3" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar"
-            name="Bar" root_id="[null]"
-            description="[null]"
-            enabled="true" language="java" copy_resource_id="[null]"/>
-
-
-  <!-- snapshots -->
-  <snapshots id="1000" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" created_at="2008-11-01 13:58:00.00" version="[null]" path=""
-             status="P" islast="false" depth="0" />
-
-  <snapshots id="1001" project_id="2" parent_snapshot_id="1000" root_project_id="1" root_snapshot_id="1000"
-             scope="DIR" qualifier="PAC" created_at="2008-11-01 13:58:00.00" version="[null]" path="1000."
-             status="P" islast="false" depth="1" />
-
-  <snapshots id="1002" project_id="3" parent_snapshot_id="1001" root_project_id="1" root_snapshot_id="1000"
-             scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="1000.1001."
-             status="P" islast="false" depth="2" />
-
-
-  <!-- project measures -->
-  <project_measures id="1" VALUE="60" METRIC_ID="1" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
-                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
-
-  <project_measures id="2" VALUE="80" METRIC_ID="2" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
-                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
-
-  <!-- package measures -->
-  <project_measures id="3" VALUE="20" METRIC_ID="1" SNAPSHOT_ID="1001" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
-                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
-
-  <project_measures id="4" VALUE="70" METRIC_ID="2" SNAPSHOT_ID="1001" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
-                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
-
-  <!-- file measures -->
-  <project_measures id="5" VALUE="5" METRIC_ID="1" SNAPSHOT_ID="1002" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
-                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
-
-  <project_measures id="6" VALUE="60" METRIC_ID="2" SNAPSHOT_ID="1002" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
-                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
-</dataset>
\ No newline at end of file
diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/VariationDecoratorTest/shared.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/VariationDecoratorTest/shared.xml
new file mode 100644 (file)
index 0000000..48fe462
--- /dev/null
@@ -0,0 +1,85 @@
+<dataset>
+
+  <metrics id="1" name="ncloc" VAL_TYPE="INT" DESCRIPTION="[null]"  domain="[null]" short_name=""
+           enabled="true" worst_value="[null]" optimized_best_value="[null]" best_value="[null]" direction="0" hidden="false"/>
+  <metrics id="2" name="coverage" VAL_TYPE="INT" DESCRIPTION="[null]"  domain="[null]" short_name=""
+           enabled="true" worst_value="0" optimized_best_value="true" best_value="100" direction="1" hidden="false"/>
+
+
+  <rules_categories id="1" name="Efficiency" description="[null]"/>
+  <rules_categories id="6" name="Usability" description="[null]"/>
+
+  <rules id="30" name="Check Header" rules_category_id="6" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
+         plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+         cardinality="SINGLE" parent_id="[null]"/>
+
+  <rules id="31" name="Equals Avoid Null" rules_category_id="6" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"
+         plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+         cardinality="SINGLE" parent_id="[null]"/>
+
+  <!-- project -->
+  <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
+            root_id="[null]"
+            description="[null]"
+            enabled="true" language="java" copy_resource_id="[null]"/>
+
+  <!-- package -->
+  <projects long_name="[null]" id="2" scope="DIR" qualifier="PAC" kee="project:org.foo" name="org.foo"
+            root_id="1"
+            description="[null]"
+            enabled="true" language="java" copy_resource_id="[null]"/>
+
+  <!-- file -->
+  <projects long_name="org.foo.Bar" id="3" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar"
+            name="Bar" root_id="[null]"
+            description="[null]"
+            enabled="true" language="java" copy_resource_id="[null]"/>
+
+
+  <!-- snapshots -->
+  <snapshots id="1000" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" created_at="2008-11-01 13:58:00.00" version="[null]" path=""
+             status="P" islast="false" depth="0" />
+
+  <snapshots id="1001" project_id="2" parent_snapshot_id="1000" root_project_id="1" root_snapshot_id="1000"
+             scope="DIR" qualifier="PAC" created_at="2008-11-01 13:58:00.00" version="[null]" path="1000."
+             status="P" islast="false" depth="1" />
+
+  <snapshots id="1002" project_id="3" parent_snapshot_id="1001" root_project_id="1" root_snapshot_id="1000"
+             scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="1000.1001."
+             status="P" islast="false" depth="2" />
+
+
+  <!-- project measures -->
+  <project_measures id="1" VALUE="60" METRIC_ID="1" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
+                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
+
+  <project_measures id="2" VALUE="80" METRIC_ID="2" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
+                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
+
+  <!-- package measures -->
+  <project_measures id="3" VALUE="20" METRIC_ID="1" SNAPSHOT_ID="1001" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
+                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
+
+  <project_measures id="4" VALUE="70" METRIC_ID="2" SNAPSHOT_ID="1001" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
+                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
+
+  <!-- file measures -->
+  <project_measures id="5" VALUE="5" METRIC_ID="1" SNAPSHOT_ID="1002" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
+                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
+
+  <project_measures id="6" VALUE="60" METRIC_ID="2" SNAPSHOT_ID="1002" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]"
+                    diff_value_1="[null]" diff_value_2="[null]" diff_value_3="[null]"/>
+</dataset>
\ No newline at end of file
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/web/SupportVariationDashboard.java b/sonar-plugin-api/src/main/java/org/sonar/api/web/SupportVariationDashboard.java
new file mode 100644 (file)
index 0000000..ab477c1
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * 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
+ */
+package org.sonar.api.web;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotated widgets support the variation view of dashboards
+ *
+ * @since 2.5
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface SupportVariationDashboard {
+  
+}
index d6681e35148c2f893261a675a4215abf85dc23a9..259fcb9f06a5d2e707b5dad6b1c41ffe6962eedc 100644 (file)
@@ -111,8 +111,8 @@ public final class JRubyFacade implements ServerComponent {
     }
   }
 
-  public List<ViewProxy<Widget>> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage) {
-    return getContainer().getComponent(Views.class).getWidgets(resourceScope, resourceQualifier, resourceLanguage);
+  public List<ViewProxy<Widget>> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage, boolean differentialDashboard) {
+    return getContainer().getComponent(Views.class).getWidgets(resourceScope, resourceQualifier, resourceLanguage, differentialDashboard);
   }
 
   public List<ViewProxy<Widget>> getWidgets() {
index 59fae3ac6a505dc39bc7b050f18a989243ad80bb..791d1c17ff88397e5c6d3ae059187d6c0e355b0e 100644 (file)
@@ -42,6 +42,7 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
   private WidgetLayoutType widgetLayout = WidgetLayoutType.DEFAULT;
   private boolean isDefaultTab = false;
   private boolean isWidget = false;
+  private boolean supportsVariationDashboard = false;
 
   public ViewProxy(final V view) {
     this.view = view;
@@ -103,6 +104,10 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
       widgetLayout = layoutAnnotation.value();
     }
 
+    if (AnnotationUtils.getClassAnnotation(view, SupportVariationDashboard.class)!=null) {
+      supportsVariationDashboard = true;
+    }
+
     isWidget = (view instanceof Widget);
   }
 
@@ -174,6 +179,10 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
     return !ArrayUtils.isEmpty(widgetProperties);
   }
 
+  public boolean supportsVariationDashboard() {
+    return supportsVariationDashboard;
+  }
+
   public boolean hasRequiredProperties() {
     boolean requires = false;
     for (WidgetProperty property : widgetProperties) {
index de6a55fe980a3f0df44426ff2a30c5564c559ca0..2f0ccfba48ae93117aba75bf5fc6db1754b48283 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.ui;
 
+import com.google.common.collect.Lists;
 import org.apache.commons.lang.ArrayUtils;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.web.Page;
@@ -62,7 +63,7 @@ public class Views implements ServerComponent {
   }
 
   public List<ViewProxy<Page>> getPages(String section, String resourceScope, String resourceQualifier, String resourceLanguage) {
-    List<ViewProxy<Page>> result = new ArrayList<ViewProxy<Page>>();
+    List<ViewProxy<Page>> result = Lists.newArrayList();
     for (ViewProxy<Page> proxy : pages) {
       if (accept(proxy, section, resourceScope, resourceQualifier, resourceLanguage)) {
         result.add(proxy);
@@ -75,10 +76,10 @@ public class Views implements ServerComponent {
     return widgetsPerId.get(id);
   }
 
-  public List<ViewProxy<Widget>> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage) {
-    List<ViewProxy<Widget>> result = new ArrayList<ViewProxy<Widget>>();
+  public List<ViewProxy<Widget>> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage, boolean variationDashboard) {
+    List<ViewProxy<Widget>> result = Lists.newArrayList();
     for (ViewProxy<Widget> proxy : widgets) {
-      if (accept(proxy, null, resourceScope, resourceQualifier, resourceLanguage)) {
+      if (accept(proxy, null, resourceScope, resourceQualifier, resourceLanguage) && (!variationDashboard || proxy.supportsVariationDashboard())) {
         result.add(proxy);
       }
     }
@@ -86,7 +87,7 @@ public class Views implements ServerComponent {
   }
 
   public List<ViewProxy<Widget>> getWidgets() {
-    return new ArrayList<ViewProxy<Widget>>(widgets);
+    return Lists.newArrayList(widgets);
   }
 
   private static boolean accept(ViewProxy proxy, String section, String resourceScope, String resourceQualifier, String resourceLanguage) {
index 1adb3052f96bd3926eb64a98a249a5cc2d70cbf9..a574008d741f29e68cd1eb70ec7d2f7974979dad 100644 (file)
@@ -63,7 +63,7 @@ class ColumnsController < ApplicationController
   private
   
   def init
-    @dashboard_configuration = Sonar::DashboardConfiguration.new
+    @dashboard_configuration = Sonar::ComponentsConfiguration.new
     @column_id = params[:id]
   end
 
index 40a154feed6b02b8e7f8e37b86a2dd786c11dad9..55be91961e20971daebd6a12751e0bff366a2337 100644 (file)
@@ -29,7 +29,7 @@ class ComponentsController < ApplicationController
   SECTION = Navigation::SECTION_RESOURCE
 
   def index
-    @dashboard_configuration = Sonar::DashboardConfiguration.new
+    @dashboard_configuration = Sonar::ComponentsConfiguration.new
 
     @project = Project.by_key(params[:id])
     return access_denied unless has_role?(:user, @project)
index b9194b180d7e45d28fe307bdacf16aa91808a6e7..02baac0c617d50d32f38c247d0ac76ad8e9cfdcb 100644 (file)
@@ -169,6 +169,7 @@ class DashboardController < ApplicationController
       end
     end
     @dashboard=(@active ? @active.dashboard : nil)
+    @dashboard_configuration=Api::DashboardConfiguration.new(@dashboard, :variation_index => params[:var])
   end
 
   def load_resource
@@ -184,7 +185,7 @@ class DashboardController < ApplicationController
   end
 
   def load_authorized_widget_definitions()
-    @widget_definitions = java_facade.getWidgets(@resource.scope, @resource.qualifier, @resource.language)
+    @widget_definitions = java_facade.getWidgets(@resource.scope, @resource.qualifier, @resource.language, @dashboard_configuration.variation?)
     @widget_definitions=@widget_definitions.select do |widget|
       authorized=widget.getUserRoles().size==0
       unless authorized
index 11392d5046426f61860f3d03a16a79fd1d08d818..1cbe2a1c06a85f5a053b9c729d6ab8e92b6e1de6 100644 (file)
@@ -186,17 +186,4 @@ class ProjectController < ApplicationController
     redirect_to home_path
   end
 
-  def load_widgets
-    @widgets = java_facade.getWidgets(@project.scope, @project.qualifier, @project.language)
-    @widgets=@widgets.select do |widget|
-      authorized=widget.getUserRoles().size==0
-      unless authorized
-        widget.getUserRoles().each do |role|
-          authorized=(role=='user') || (role=='viewer') || has_role?(role, @project)
-          break if authorized
-        end
-      end
-      authorized
-    end
-  end
 end
\ No newline at end of file
index ef27c1109befd04653abf8e2841681a5470069e6..6aebf2254f3e1e131f0dda0d2914ee9297ed43eb 100644 (file)
@@ -55,28 +55,10 @@ module ApplicationHelper
     end
   end
 
-  def tendency_icon(metric_or_measure, small=true, no_tendency_img=true)
-    if metric_or_measure.is_a? ProjectMeasure
-      m = metric_or_measure
-    elsif @snapshot
-      m = @snapshot.measure(metric_or_measure)
-    end
-
-    suffix = (small ? '-small' : '')
-    if small.nil? || m.nil? || m.tendency.nil? || m.tendency==0
-      return no_tendency_img ? "" : image_tag("transparent.gif", :width => small ? "16" : "18", :alt => "")
-    end
-    filename = m.tendency.to_s
 
-    case m.tendency_qualitative
-    when 0
-      filename+= '-black'
-    when -1
-      filename+= '-red'
-    when 1
-      filename+= '-green'
-    end
-    image_tag("tendency/#{filename}#{suffix}.png")
+  # deprecated since 2.5. Use trend_icon() instead
+  def tendency_icon(metric_or_measure, small=true, no_tendency_img=true)
+    return trend_icon(metric_or_measure, {:big => !small})
   end
 
   def boolean_icon(boolean_value, options={})
@@ -220,6 +202,7 @@ module ApplicationHelper
     end
   end
 
+  #
   # Display a measure
   #
   # === Optional parameters
@@ -228,11 +211,14 @@ module ApplicationHelper
   # * <tt>:prefix</tt> - add a prefix. Default is ''.
   # * <tt>:suffix</tt> - add a suffix. Default is ''.
   # * <tt>:default</tt> - text to return if metric or measure not found. Default is blank string.
+  # * <tt>:mode</tt> - display the measure value (:value) or the variation (:variation). The default mode is :auto, according to the mode selected in the dashboard
+  # * <tt>:variation</tt> - the configuration index between 1 and 3. Only when :mode => :variation
   #
   # === Examples
   #
   #   format_measure('ncloc')
   #   format_measure('ncloc', {:suffix => '', :url => url_for_drilldown('ncloc'), :default => '-'})
+  #
   def format_measure(metric_or_measure, options={})
     html=''
 
@@ -250,23 +236,39 @@ module ApplicationHelper
       link_rel=''
       show_link= !options[:url].blank?
 
+      variation_mode = false
       if m.metric.val_type==Metric::VALUE_TYPE_LEVEL
         html=image_tag("levels/#{m.data.downcase}.png") unless m.data.blank?
       else
-        html=m.formatted_value
+        mode=options[:mode]||:auto
+        if mode==:value
+          html=m.formatted_value
+        elsif mode==:variation
+          html=m.formatted_var_value(options[:variation_index]||1)
+          variation_mode = true
+        else
+          if @dashboard_configuration && @dashboard_configuration.variation?
+            html=m.formatted_variation_value(@dashboard_configuration.variation_index)
+            variation_mode = true
+          else
+            html=m.formatted_value
+          end
+        end
       end
 
       alert_class=''
       alert_link = false
       style = ''
-      if !(m.alert_status.blank?)
-        alert_class="class='alert_#{m.alert_status}'" unless m.metric.val_type==Metric::VALUE_TYPE_LEVEL
-        link_rel=h(m.alert_text)
-        show_link=true
-        alert_link = true
-
-      elsif m.metric.val_type==Metric::VALUE_TYPE_RATING && m.color
-        style = "style='background-color: #{m.color.html};padding: 2px 5px'"
+      if !variation_mode
+        if !(m.alert_status.blank?)
+          alert_class="class='alert_#{m.alert_status}'" unless m.metric.val_type==Metric::VALUE_TYPE_LEVEL
+          link_rel=h(m.alert_text)
+          show_link=true
+          alert_link = true
+
+        elsif m.metric.val_type==Metric::VALUE_TYPE_RATING && m.color
+          style = "style='background-color: #{m.color.html};padding: 2px 5px'"
+        end
       end
 
       span_id=''
@@ -296,7 +298,11 @@ module ApplicationHelper
   end
 
 
+  #
+  #
   # link to the current page with the given resource. If file, then open a popup to display resource viewers.
+  #
+  #
   def link_to_resource(resource, name=nil, options={})
     if resource.display_dashboard?
       if options[:dashboard]
@@ -310,12 +316,22 @@ module ApplicationHelper
     end
   end
 
+
+  #
+  #
   # JFree Eastwood is a partial implementation of Google Chart Api
+  #
+  #
   def gchart(parameters, options={})
     image_tag("#{ApplicationController.root_context}/gchart?#{parameters}", options)
   end
 
+
+  #
+  #
   # Piechart for a distribution string or measure (foo=1;bar=2)
+  #
+  #
   def piechart(distribution, options={})
     chart = ""
     data=nil
@@ -371,4 +387,46 @@ module ApplicationHelper
     link_to_remote('', :url => { :controller => 'favourites', :action => 'toggle', :id => resource_id, :elt => html_id},
       :method => :post, :html => {:class => initial_class, :id => html_id, :alt => initial_tooltip, :title => initial_tooltip})
   end
+
+  #
+  #
+  # Display the trend icon :
+  #
+  # === Optional parameters
+  # * big: true|false. Default is false.
+  # * force: true|false. By default trend icons are hidden when the dashboard variation mode is selected.
+  #
+  # === Examples
+  # trend_icon('ncloc')
+  # trend_icon(measure('ncloc'))
+  # trend_icon('ncloc', :big => true)
+  #
+  def trend_icon(metric_or_measure, options={})
+    if metric_or_measure.is_a? ProjectMeasure
+      m = metric_or_measure
+    elsif @snapshot
+      m = @snapshot.measure(metric_or_measure)
+    end
+
+    if @dashboard_configuration && @dashboard_configuration.variation?
+      return nil unless options[:force]
+    end
+
+    big=options[:big]||false
+    if m.nil? || m.tendency.nil? || m.tendency==0
+      return image_tag("transparent.gif", :width => big ? "18" : "16", :alt => "")
+    end
+    filename = m.tendency.to_s
+
+    case m.tendency_qualitative
+    when 0
+      filename+= '-black'
+    when -1
+      filename+= '-red'
+    when 1
+      filename+= '-green'
+    end
+    suffix = (big ? '' : '-small')
+    image_tag("tendency/#{filename}#{suffix}.png")
+  end
 end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/api/dashboard_configuration.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/api/dashboard_configuration.rb
new file mode 100644 (file)
index 0000000..8e7bd6c
--- /dev/null
@@ -0,0 +1,50 @@
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2009 SonarSource SA
+# 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 Api::DashboardConfiguration
+
+  attr_accessor :dashboard, :variation_index, :variation
+
+  def initialize(dashboard, options={})
+    @dashboard=dashboard
+    @variation_index=options[:variation_index].to_i
+    @variation=(@variation_index>0)
+  end
+
+  def name
+    @dashboard.name
+  end
+
+  def description
+    @dashboard.description
+  end
+
+  def layout
+    @dashboard.column_layout
+  end
+
+  def number_of_columns
+    @dashboard.number_of_columns
+  end
+
+  def variation?
+    @variation
+  end
+
+end
index d7ac66adfb9c88f209cb1d0dd926a1739cc35828..3cb777ef9ff4f2d0c0e63c86dfaa9736438e4bb4 100644 (file)
@@ -101,6 +101,24 @@ class ProjectMeasure < ActiveRecord::Base
     end
   end
 
+  def formatted_variation_value(variation_index)
+    variation=nil
+    case variation_index
+    when 1
+      variation=diff_value_1
+    when 2
+      variation=diff_value_2
+    when 3
+      variation=diff_value_3
+    end
+    if variation
+      label=format_numeric_value(variation)
+      variation<0 ? label : "+#{label}"
+    else
+      nil
+    end
+  end
+
   def millisecs_formatted_value( value )
     # bugfix with jruby 1.0 release does not support % for BigDecimal
     value = value.to_i if value.kind_of? BigDecimal
@@ -295,6 +313,26 @@ class ProjectMeasure < ActiveRecord::Base
     [Metric::VALUE_TYPE_INT, Metric::VALUE_TYPE_FLOAT, Metric::VALUE_TYPE_PERCENT, Metric::VALUE_TYPE_MILLISEC].include?(metric.val_type)
   end
 
+
+  def format_numeric_value(val)
+    if metric.nil?
+      return val.to_s
+    end
+
+    case metric().val_type
+    when Metric::VALUE_TYPE_INT
+      number_with_precision(val, :precision => 0)
+    when Metric::VALUE_TYPE_FLOAT
+      number_with_precision(val, :precision => 1)
+    when Metric::VALUE_TYPE_PERCENT
+      number_to_percentage(val, {:precision => 1})
+    when Metric::VALUE_TYPE_MILLISEC
+      millisecs_formatted_value( val )
+    else
+      val.to_s
+    end
+  end
+
   def validate_date
     if not measure_date
       errors.add_to_base('A valid date must be provided')
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/components_configuration.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/components_configuration.rb
new file mode 100644 (file)
index 0000000..03c34f9
--- /dev/null
@@ -0,0 +1,233 @@
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2009 SonarSource SA
+# 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::ComponentsConfiguration
+
+  COLUMN_SEPARATOR = '.'
+  COLUMNS_SEPARATOR = ';'
+
+  COLUMNS_SELECTED_KEY = 'sonar.core.projectsdashboard.columns'
+  COLUMNS_DEFAULT_SORT_KEY = 'sonar.core.projectsdashboard.defaultSortedColumn'
+  TREEMAP_ENABLED_KEY = 'sonar.core.projectsdashboard.showTreemap'
+
+  def initialize
+    @sorted_column_id=Property.value(COLUMNS_DEFAULT_SORT_KEY) || Sonar::ColumnsView::TYPE_PROJECT
+    @enabled_treemap=(Property.value(TREEMAP_ENABLED_KEY) || 'true')=='true'
+    @text_columns=Property.value(COLUMNS_SELECTED_KEY) || default_text_columns
+  end
+
+  def selected_columns
+    columns_from_text(@text_columns)
+  end
+
+  def homepage_metrics()
+    metrics = selected_columns.select{|col| col.metric_column?}.collect{|col| Metric.by_name(col.id)}
+    metrics<<Metric.by_name(Metric::ALERT_STATUS)
+    metrics.uniq.compact
+  end
+
+  def addeable_columns
+    addeable_columns = available_columns
+    addeable_columns.each_key { |domain|
+      domain_addeable_columns = addeable_columns[domain]
+      domain_addeable_columns.delete_if { |columns_view|
+        deleteable = false
+        selected_columns.each do |selected_column|
+          deleteable = true if columns_view.name == selected_column.name
+        end
+        deleteable
+      }
+    }
+    addeable_columns
+  end
+  
+  def find_selected_column(column_id)
+    selected_columns.detect {|column| column.id == column_id}
+  end
+
+  def add_column(column)
+    columns = selected_columns + [column]
+    Property.set(COLUMNS_SELECTED_KEY, columns_to_text(columns))
+  end
+
+  def remove_column(column)
+    columns = selected_columns.reject {|col| col.id == column.id}
+    Property.set(COLUMNS_SELECTED_KEY, columns_to_text(columns))
+  end
+
+  def move_column(column, direction)
+    position = column.position
+    columns = selected_columns.reject {|col| col.id == column.id}
+    new_position = (direction == "left") ? position - 1 : position + 1
+    columns = columns.insert(new_position, column)
+    Property.set(COLUMNS_SELECTED_KEY, columns_to_text(columns))
+  end
+
+  def find_available_column(column_id)
+    available_columns.each_pair do |domain, columns|
+      columns.each do |column|
+        if column.id == column_id
+          return column
+        end
+      end
+    end
+    nil
+  end
+
+  def sorted_column_id
+    @sorted_column_id
+  end
+  
+  def sorted_by_project_name?
+    @sorted_column_id=='project'
+  end
+
+  def set_column_sort_default(column_id)
+    Property.set(COLUMNS_DEFAULT_SORT_KEY, column_id)
+  end
+
+  def treemap_enabled?
+    @enabled_treemap
+  end
+
+  def toggle_treemap_enabled
+    Property.set(TREEMAP_ENABLED_KEY, !treemap_enabled?)
+  end
+
+
+  @@available_columns = nil
+
+  DEFAULT_DOMAIN='General'
+
+  def available_columns
+    if @@available_columns.nil?
+      @@available_columns = {}
+
+      @@available_columns[DEFAULT_DOMAIN] = []
+      col = Sonar::ColumnsView.new
+      col.name = "Links"
+      col.id = 'links'
+      col.col_type = Sonar::ColumnsView::TYPE_LINKS
+      @@available_columns[DEFAULT_DOMAIN] << col
+
+      col = Sonar::ColumnsView.new
+      col.name = "Build time"
+      col.id = 'build_time'
+      col.col_type = Sonar::ColumnsView::TYPE_BUILD_TIME
+      @@available_columns[DEFAULT_DOMAIN] << col
+
+      col = Sonar::ColumnsView.new
+      col.name = "Language"
+      col.id = 'language'
+      col.col_type = Sonar::ColumnsView::TYPE_LANGUAGE
+      @@available_columns[DEFAULT_DOMAIN] << col
+
+      col = Sonar::ColumnsView.new
+      col.name = "Version"
+      col.id = 'version'
+      col.col_type = Sonar::ColumnsView::TYPE_VERSION
+      @@available_columns[DEFAULT_DOMAIN] << col
+      
+      Metric.all.select {|m| m.display?}.each do |metric|
+        col = Sonar::ColumnsView.new
+        col.name = metric.short_name
+        col.id = metric.name
+        col.col_type = Sonar::ColumnsView::TYPE_METRIC
+
+        if col.name
+          if metric.domain
+            @@available_columns[metric.domain] ||= []
+            @@available_columns[metric.domain] << col
+          end
+        end
+      end
+
+      @@available_columns.each_value {|columns|
+        columns.sort! { |x, y|
+          x.name = "" if x.name.nil?
+          y.name = "" if y.name.nil?
+          x.name <=> y.name if x.name and y.name
+        }
+      }
+
+    end
+    # must return a copy of the hash !
+    available_columns_clone = {}
+    @@available_columns.each_pair {|domain, columns|
+      available_columns_clone[domain] = columns.clone
+    }
+    available_columns_clone
+  end
+
+
+  protected
+
+  @@default_columns=nil
+  
+  def default_text_columns
+    unless @@default_columns
+      @@default_columns = ""
+      @@default_columns << Sonar::ColumnsView::TYPE_METRIC + COLUMN_SEPARATOR + Metric::VIOLATIONS_DENSITY + COLUMNS_SEPARATOR
+      @@default_columns << Sonar::ColumnsView::TYPE_METRIC + COLUMN_SEPARATOR + Metric::COVERAGE + COLUMNS_SEPARATOR
+      @@default_columns << Sonar::ColumnsView::TYPE_BUILD_TIME + COLUMN_SEPARATOR + 'build_time' + COLUMNS_SEPARATOR
+      @@default_columns << Sonar::ColumnsView::TYPE_LINKS + COLUMN_SEPARATOR + "links"
+    end
+    @@default_columns
+  end
+
+  def columns_from_text(text)
+    columns = []
+    text.split(COLUMNS_SEPARATOR).each_with_index do |column_text, position|
+      column = column_from_text(column_text)
+      if column
+        column.position = position
+        column.sort_default = (column.id==@sorted_column_id)
+        columns << column
+      end
+    end
+    columns
+  end
+
+  def column_from_text(text)
+    column_split = text.split(COLUMN_SEPARATOR)
+    column = Sonar::ColumnsView.new
+    column.id = column_split[1]
+    column.col_type = column_split[0]
+    available_col=find_available_column(column.id)
+    if available_col
+      column.name = available_col.name
+      column
+    else 
+      nil
+    end
+  end
+
+  def columns_to_text(columns)
+    text = ""
+    columns.each do |column|
+      text << column_to_text(column) + COLUMNS_SEPARATOR
+    end
+    text
+  end
+
+  def column_to_text(column)
+    text = column.col_type + COLUMN_SEPARATOR + column.id
+  end
+
+end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/dashboard_configuration.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/dashboard_configuration.rb
deleted file mode 100644 (file)
index db6a37c..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-#
-# Sonar, entreprise quality control tool.
-# Copyright (C) 2009 SonarSource SA
-# 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::DashboardConfiguration
-
-  COLUMN_SEPARATOR = '.'
-  COLUMNS_SEPARATOR = ';'
-
-  COLUMNS_SELECTED_KEY = 'sonar.core.projectsdashboard.columns'
-  COLUMNS_DEFAULT_SORT_KEY = 'sonar.core.projectsdashboard.defaultSortedColumn'
-  TREEMAP_ENABLED_KEY = 'sonar.core.projectsdashboard.showTreemap'
-
-  def initialize
-    @sorted_column_id=Property.value(COLUMNS_DEFAULT_SORT_KEY) || Sonar::ColumnsView::TYPE_PROJECT
-    @enabled_treemap=(Property.value(TREEMAP_ENABLED_KEY) || 'true')=='true'
-    @text_columns=Property.value(COLUMNS_SELECTED_KEY) || default_text_columns
-  end
-
-  def selected_columns
-    columns_from_text(@text_columns)
-  end
-
-  def homepage_metrics()
-    metrics = selected_columns.select{|col| col.metric_column?}.collect{|col| Metric.by_name(col.id)}
-    metrics<<Metric.by_name(Metric::ALERT_STATUS)
-    metrics.uniq.compact
-  end
-
-  def addeable_columns
-    addeable_columns = available_columns
-    addeable_columns.each_key { |domain|
-      domain_addeable_columns = addeable_columns[domain]
-      domain_addeable_columns.delete_if { |columns_view|
-        deleteable = false
-        selected_columns.each do |selected_column|
-          deleteable = true if columns_view.name == selected_column.name
-        end
-        deleteable
-      }
-    }
-    addeable_columns
-  end
-  
-  def find_selected_column(column_id)
-    selected_columns.detect {|column| column.id == column_id}
-  end
-
-  def add_column(column)
-    columns = selected_columns + [column]
-    Property.set(COLUMNS_SELECTED_KEY, columns_to_text(columns))
-  end
-
-  def remove_column(column)
-    columns = selected_columns.reject {|col| col.id == column.id}
-    Property.set(COLUMNS_SELECTED_KEY, columns_to_text(columns))
-  end
-
-  def move_column(column, direction)
-    position = column.position
-    columns = selected_columns.reject {|col| col.id == column.id}
-    new_position = (direction == "left") ? position - 1 : position + 1
-    columns = columns.insert(new_position, column)
-    Property.set(COLUMNS_SELECTED_KEY, columns_to_text(columns))
-  end
-
-  def find_available_column(column_id)
-    available_columns.each_pair do |domain, columns|
-      columns.each do |column|
-        if column.id == column_id
-          return column
-        end
-      end
-    end
-    nil
-  end
-
-  def sorted_column_id
-    @sorted_column_id
-  end
-  
-  def sorted_by_project_name?
-    @sorted_column_id=='project'
-  end
-
-  def set_column_sort_default(column_id)
-    Property.set(COLUMNS_DEFAULT_SORT_KEY, column_id)
-  end
-
-  def treemap_enabled?
-    @enabled_treemap
-  end
-
-  def toggle_treemap_enabled
-    Property.set(TREEMAP_ENABLED_KEY, !treemap_enabled?)
-  end
-
-
-  @@available_columns = nil
-
-  DEFAULT_DOMAIN='General'
-
-  def available_columns
-    if @@available_columns.nil?
-      @@available_columns = {}
-
-      @@available_columns[DEFAULT_DOMAIN] = []
-      col = Sonar::ColumnsView.new
-      col.name = "Links"
-      col.id = 'links'
-      col.col_type = Sonar::ColumnsView::TYPE_LINKS
-      @@available_columns[DEFAULT_DOMAIN] << col
-
-      col = Sonar::ColumnsView.new
-      col.name = "Build time"
-      col.id = 'build_time'
-      col.col_type = Sonar::ColumnsView::TYPE_BUILD_TIME
-      @@available_columns[DEFAULT_DOMAIN] << col
-
-      col = Sonar::ColumnsView.new
-      col.name = "Language"
-      col.id = 'language'
-      col.col_type = Sonar::ColumnsView::TYPE_LANGUAGE
-      @@available_columns[DEFAULT_DOMAIN] << col
-
-      col = Sonar::ColumnsView.new
-      col.name = "Version"
-      col.id = 'version'
-      col.col_type = Sonar::ColumnsView::TYPE_VERSION
-      @@available_columns[DEFAULT_DOMAIN] << col
-      
-      Metric.all.select {|m| m.display?}.each do |metric|
-        col = Sonar::ColumnsView.new
-        col.name = metric.short_name
-        col.id = metric.name
-        col.col_type = Sonar::ColumnsView::TYPE_METRIC
-
-        if col.name
-          if metric.domain
-            @@available_columns[metric.domain] ||= []
-            @@available_columns[metric.domain] << col
-          end
-        end
-      end
-
-      @@available_columns.each_value {|columns|
-        columns.sort! { |x, y|
-          x.name = "" if x.name.nil?
-          y.name = "" if y.name.nil?
-          x.name <=> y.name if x.name and y.name
-        }
-      }
-
-    end
-    # must return a copy of the hash !
-    available_columns_clone = {}
-    @@available_columns.each_pair {|domain, columns|
-      available_columns_clone[domain] = columns.clone
-    }
-    available_columns_clone
-  end
-
-
-  protected
-
-  @@default_columns=nil
-  
-  def default_text_columns
-    unless @@default_columns
-      @@default_columns = ""
-      @@default_columns << Sonar::ColumnsView::TYPE_METRIC + COLUMN_SEPARATOR + Metric::VIOLATIONS_DENSITY + COLUMNS_SEPARATOR
-      @@default_columns << Sonar::ColumnsView::TYPE_METRIC + COLUMN_SEPARATOR + Metric::COVERAGE + COLUMNS_SEPARATOR
-      @@default_columns << Sonar::ColumnsView::TYPE_BUILD_TIME + COLUMN_SEPARATOR + 'build_time' + COLUMNS_SEPARATOR
-      @@default_columns << Sonar::ColumnsView::TYPE_LINKS + COLUMN_SEPARATOR + "links"
-    end
-    @@default_columns
-  end
-
-  def columns_from_text(text)
-    columns = []
-    text.split(COLUMNS_SEPARATOR).each_with_index do |column_text, position|
-      column = column_from_text(column_text)
-      if column
-        column.position = position
-        column.sort_default = (column.id==@sorted_column_id)
-        columns << column
-      end
-    end
-    columns
-  end
-
-  def column_from_text(text)
-    column_split = text.split(COLUMN_SEPARATOR)
-    column = Sonar::ColumnsView.new
-    column.id = column_split[1]
-    column.col_type = column_split[0]
-    available_col=find_available_column(column.id)
-    if available_col
-      column.name = available_col.name
-      column
-    else 
-      nil
-    end
-  end
-
-  def columns_to_text(columns)
-    text = ""
-    columns.each do |column|
-      text << column_to_text(column) + COLUMNS_SEPARATOR
-    end
-    text
-  end
-
-  def column_to_text(column)
-    text = column.col_type + COLUMN_SEPARATOR + column.id
-  end
-
-end
index 5a181c19c7d4f224be263be8709b0caf78216a64..10e27fa1ac89d3ca9f628f592ab1451d96060c02 100644 (file)
@@ -1,6 +1,6 @@
  <%
    begin
-     widget_body=render :inline => definition.getTarget().getTemplate(), :locals => {:widget_properties => widget.properties_as_hash, :widget => widget, :dashboard => @dashboard}
+     widget_body=render :inline => definition.getTarget().getTemplate(), :locals => {:widget_properties => widget.properties_as_hash, :widget => widget, :dashboard_configuration => @dashboard_configuration}
    rescue => error
       logger.error("Can not render widget #{definition.getId()}: " + error)
       logger.error(error.backtrace.join("\n"))
index c97d62e69ae4c0761de815526935cc5578f0376c..d9b61337aa0d092551e6d5af386f8c7f5d046f6a 100644 (file)
@@ -2,7 +2,7 @@
 <% if widget.configured %>
   <%
     begin
-      widget_body=render :inline => definition.getTarget().getTemplate(), :locals => {:widget_properties => widget.properties_as_hash, :widget => widget, :dashboard => @dashboard}
+      widget_body=render :inline => definition.getTarget().getTemplate(), :locals => {:widget_properties => widget.properties_as_hash, :widget => widget, :dashboard_configuration => @dashboard_configuration}
     rescue => error
        logger.error("Can not render widget #{definition.getId()}: " + error)
        logger.error(error.backtrace.join("\n"))
index 32d16329748c46ebff1eefe2c779e4db41be3150..9c55b3c559cc873a2139b50400d317122d6b0ae1 100644 (file)
@@ -41,28 +41,28 @@ class RemoveColumnsViewsTable < ActiveRecord::Migration
   private
 
   def self.migrate_columns_selected
-    dashboard_configuration = Sonar::DashboardConfiguration.new(nil)
+    dashboard_configuration = Sonar::ComponentsConfiguration.new(nil)
 
     columns_text = ""
     ColumnsView052.find(:all).each do |col|
       column = find_column_by_name_or_by_id(col.name, dashboard_configuration)
-      columns_text << column.col_type + Sonar::DashboardConfiguration::COLUMN_SEPARATOR + column.id + Sonar::DashboardConfiguration::COLUMNS_SEPARATOR if column
+      columns_text << column.col_type + Sonar::ComponentsConfiguration::COLUMN_SEPARATOR + column.id + Sonar::ComponentsConfiguration::COLUMNS_SEPARATOR if column
     end
-    create_property(Sonar::DashboardConfiguration::COLUMNS_SELECTED_KEY.to_s, columns_text)
+    create_property(Sonar::ComponentsConfiguration::COLUMNS_SELECTED_KEY.to_s, columns_text)
   end
 
   def self.migrate_column_default_sort
-    dashboard_configuration = Sonar::DashboardConfiguration.new(nil)
+    dashboard_configuration = Sonar::ComponentsConfiguration.new(nil)
 
     default_sort_column = ColumnsView052.find(:first, :conditions => {:sort_default => true})
     column = find_column_by_name_or_by_id(default_sort_column.name, dashboard_configuration) if default_sort_column
-    create_property(Sonar::DashboardConfiguration::COLUMNS_DEFAULT_SORT_KEY, column.id) if column
+    create_property(Sonar::ComponentsConfiguration::COLUMNS_DEFAULT_SORT_KEY, column.id) if column
   end
 
   def self.migrate_treemap_enable
     treemap_enable = ColumnsView052.find(:first, :conditions => {:name => "Treemap"})
     is_enabled = treemap_enable ? "true" : "false"
-    create_property(Sonar::DashboardConfiguration::TREEMAP_ENABLED_KEY, is_enabled)
+    create_property(Sonar::ComponentsConfiguration::TREEMAP_ENABLED_KEY, is_enabled)
   end
 
 
index 69584d249f0cd4b4b288f01c96cfc1669a605c53..e1ae897c0070941552294e048ce6d1459eb958d0 100644 (file)
@@ -71,7 +71,7 @@ public class ViewsTest {
   @Test
   public void getWidgets() {
     final Views views = new Views(VIEWS);
-    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null);
+    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null, false);
     assertThat(widgets.size(), is(1));
     assertThat(widgets.get(0).getTarget(), is(FakeWidget.class));
   }
@@ -79,7 +79,7 @@ public class ViewsTest {
   @Test
   public void sortViewsByTitle() {
     final Views views = new Views(new View[]{new FakeWidget("ccc", "ccc"), new FakeWidget("aaa", "aaa"), new FakeWidget("bbb", "bbb")});
-    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null);
+    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null, false);
     assertThat(widgets.size(), is(3));
     assertThat(widgets.get(0).getId(), is("aaa"));
     assertThat(widgets.get(1).getId(), is("bbb"));
@@ -89,7 +89,7 @@ public class ViewsTest {
   @Test
   public void prefixTitleByNumberToDisplayFirst() {
     final Views views = new Views(new View[]{new FakeWidget("other", "Other"), new FakeWidget("1id", "1widget"), new FakeWidget("2id", "2widget")});
-    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null);
+    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null, false);
     assertThat(widgets.size(), is(3));
     assertThat(widgets.get(0).getId(), is("1id"));
     assertThat(widgets.get(1).getId(), is("2id"));