*/
package org.sonar.plugins.core;
+import org.sonar.plugins.core.widgets.DemoWidget;
+
import com.google.common.collect.ImmutableList;
import org.sonar.api.CoreProperties;
import org.sonar.api.Extension;
ReviewsMetricsWidget.class,
TreemapWidget.class,
FilterWidget.class,
+ DemoWidget.class,
// dashboards
DefaultDashboard.class,
import org.sonar.api.web.*;
-@WidgetProperties(
- {
- @WidgetProperty(key = "metric1", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric2", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric3", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric4", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric5", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric6", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric7", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric8", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric9", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric10", type = WidgetPropertyType.METRIC)
- }
-)
+@WidgetProperties({
+ @WidgetProperty(key = "metric1", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric2", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric3", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric4", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric5", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric6", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric7", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric8", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric9", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric10", type = WidgetPropertyType.METRIC)
+})
public class CustomMeasuresWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
return "custom_measures";
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/custom_measures.html.erb";
}
-}
\ No newline at end of file
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.plugins.core.widgets;
+
+import org.sonar.api.web.WidgetPropertySet;
+
+import org.sonar.api.web.AbstractRubyTemplate;
+import org.sonar.api.web.RubyRailsWidget;
+import org.sonar.api.web.WidgetCategory;
+import org.sonar.api.web.WidgetProperties;
+import org.sonar.api.web.WidgetProperty;
+import org.sonar.api.web.WidgetPropertyType;
+import org.sonar.api.web.WidgetScope;
+
+import static org.sonar.api.web.WidgetScope.*;
+
+@WidgetCategory("Global")
+@WidgetScope(GLOBAL)
+@WidgetProperties(sets = {
+ @WidgetPropertySet(key = "set1",
+ value = {
+ @WidgetProperty(key = "key1", type = WidgetPropertyType.STRING),
+ @WidgetProperty(key = "key2", type = WidgetPropertyType.STRING)
+ }), @WidgetPropertySet(key = "set2",
+ value = {
+ @WidgetProperty(key = "key3", type = WidgetPropertyType.STRING)
+ })}, value = {
+ @WidgetProperty(key = "key4", type = WidgetPropertyType.STRING)
+})
+public class DemoWidget extends AbstractRubyTemplate implements RubyRailsWidget {
+ public String getId() {
+ return "demo";
+ }
+
+ public String getTitle() {
+ return "Demo";
+ }
+
+ @Override
+ protected String getTemplatePath() {
+ return "/org/sonar/plugins/core/widgets/demo.html.erb";
+ }
+}
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
-@WidgetCategory({ "Hotspots" })
-@WidgetProperties(
- {
- @WidgetProperty(key = "title", type = WidgetPropertyType.STRING),
- @WidgetProperty(key = "metric", type = WidgetPropertyType.METRIC, defaultValue = "ncloc"),
- @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5")
- }
-)
+@WidgetCategory("Hotspots")
+@WidgetProperties({
+ @WidgetProperty(key = "title", type = WidgetPropertyType.STRING),
+ @WidgetProperty(key = "metric", type = WidgetPropertyType.METRIC, defaultValue = "ncloc"),
+ @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5")
+})
public class HotspotMetricWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
return "hotspot_metric";
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/hotspots/hotspot_metric.html.erb";
}
-}
\ No newline at end of file
+}
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
-@WidgetCategory({ "Hotspots" })
-@WidgetProperties(
- {
- @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5")
- }
-)
+@WidgetCategory("Hotspots")
+@WidgetProperties({
+ @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5")
+})
public class HotspotMostViolatedResourcesWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/hotspots/hotspot_most_violated_resources.html.erb";
}
-}
\ No newline at end of file
+}
import org.sonar.api.web.*;
@WidgetCategory("Hotspots")
-@WidgetProperties(
- {
- @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5"),
- @WidgetProperty(key = "defaultSeverity", type = WidgetPropertyType.STRING, description = "Values: BLOCKER, CRITICAL, MAJOR, MINOR, INFO")
- }
-)
+@WidgetProperties({
+ @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5"),
+ @WidgetProperty(key = "defaultSeverity", type = WidgetPropertyType.STRING, description = "Values: BLOCKER, CRITICAL, MAJOR, MINOR, INFO")
+})
public class HotspotMostViolatedRulesWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
return "hotspot_most_violated_rules";
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/hotspots/hotspot_most_violated_rules.html.erb";
}
-}
\ No newline at end of file
+}
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
-@WidgetCategory({"History"})
+@WidgetCategory("History")
@WidgetProperties({
@WidgetProperty(key = "title", type = WidgetPropertyType.STRING),
@WidgetProperty(key = "numberOfColumns", type = WidgetPropertyType.INTEGER, defaultValue = "3"),
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
-@WidgetCategory({ "History" })
-@WidgetProperties(
- {
- @WidgetProperty(key = "chartTitle", type = WidgetPropertyType.STRING),
- @WidgetProperty(key = "metric1", type = WidgetPropertyType.METRIC, defaultValue = "ncloc"),
- @WidgetProperty(key = "metric2", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "metric3", type = WidgetPropertyType.METRIC),
- @WidgetProperty(key = "hideEvents", type = WidgetPropertyType.BOOLEAN),
- @WidgetProperty(key = "chartHeight", type = WidgetPropertyType.INTEGER, defaultValue = "80")
- }
-)
+@WidgetCategory("History")
+@WidgetProperties({
+ @WidgetProperty(key = "chartTitle", type = WidgetPropertyType.STRING),
+ @WidgetProperty(key = "metric1", type = WidgetPropertyType.METRIC, defaultValue = "ncloc"),
+ @WidgetProperty(key = "metric2", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "metric3", type = WidgetPropertyType.METRIC),
+ @WidgetProperty(key = "hideEvents", type = WidgetPropertyType.BOOLEAN),
+ @WidgetProperty(key = "chartHeight", type = WidgetPropertyType.INTEGER, defaultValue = "80")
+})
public class TimelineWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
return "timeline";
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/timeline.html.erb";
}
-}
\ No newline at end of file
+}
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
-@WidgetCategory({ "Reviews" })
-@WidgetProperties(
- {
- @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
- description="Maximum number of reviews displayed at the same time.")
- }
-)
+@WidgetCategory("Reviews")
+@WidgetProperties({
+ @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
+ description = "Maximum number of reviews displayed at the same time.")
+})
public class FalsePositiveReviewsWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
return "false_positive_reviews";
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/reviews/false_positive_reviews.html.erb";
}
-}
\ No newline at end of file
+}
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
-@WidgetCategory({ "Reviews" })
-@WidgetProperties(
- {
- @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
- description="Maximum number of reviews displayed at the same time.")
- }
-)
+@WidgetCategory("Reviews")
+@WidgetProperties({
+ @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
+ description = "Maximum number of reviews displayed at the same time.")
+})
public class MyReviewsWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
return "my_reviews";
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/reviews/my_reviews.html.erb";
}
-}
\ No newline at end of file
+}
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
-@WidgetCategory({ "Action plans", "Reviews" })
-@WidgetProperties(
- {
- @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
- description="Maximum number of reviews displayed at the same time.")
- }
-)
+@WidgetCategory({"Action plans", "Reviews"})
+@WidgetProperties({
+ @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
+ description = "Maximum number of reviews displayed at the same time.")
+})
public class PlannedReviewsWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
return "planned_reviews";
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/reviews/planned_reviews.html.erb";
}
-}
\ No newline at end of file
+}
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
-@WidgetCategory({ "Reviews" })
-@WidgetProperties(
- {
- @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
- description="Maximum number of reviews displayed at the same time.")
- }
-)
+@WidgetCategory("Reviews")
+@WidgetProperties({
+ @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
+ description = "Maximum number of reviews displayed at the same time.")
+})
public class ProjectReviewsWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
return "project_reviews";
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/reviews/project_reviews.html.erb";
}
-}
\ No newline at end of file
+}
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
-@WidgetCategory({ "Action plans", "Reviews" })
-@WidgetProperties(
- {
- @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
- description="Maximum number of reviews displayed at the same time.")
- }
-)
+@WidgetCategory({"Action plans", "Reviews"})
+@WidgetProperties({
+ @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5",
+ description = "Maximum number of reviews displayed at the same time.")
+})
public class UnplannedReviewsWidget extends AbstractRubyTemplate implements RubyRailsWidget {
public String getId() {
return "unplanned_reviews";
protected String getTemplatePath() {
return "/org/sonar/plugins/core/widgets/reviews/unplanned_reviews.html.erb";
}
-}
\ No newline at end of file
+}
--- /dev/null
+Key1: <%= widget_properties['key1'] -%>
+Key2: <%= widget_properties['key2'] -%>
+Key3: <%= widget_properties['key3'] -%>
+Key4: <%= widget_properties['key4'] -%>
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.web;
+
+public interface PropertyValidation {
+ boolean validate(String value);
+
+ class None implements PropertyValidation {
+ public boolean validate(String value) {
+ return true;
+ }
+ };
+}
@Retention(RetentionPolicy.RUNTIME)
public @interface WidgetProperties {
WidgetProperty[] value() default {};
+
+ WidgetPropertySet[] sets() default {};
}
String description() default "";
boolean optional() default true;
+
+ Class<? extends PropertyValidation> validation() default PropertyValidation.None.class;
}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.web;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface WidgetPropertySet {
+ String key();
+
+ WidgetProperty[] value();
+
+ static WidgetPropertySet DEFAULT = new WidgetPropertySet() {
+ public Class<WidgetPropertySet> annotationType() {
+ return WidgetPropertySet.class;
+ }
+
+ public WidgetProperty[] value() {
+ return null;
+ }
+
+ public String key() {
+ return "";
+ }
+ };
+}
package org.sonar.server.ui;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.sonar.api.web.WidgetLayoutType;
import org.sonar.api.web.WidgetProperties;
import org.sonar.api.web.WidgetProperty;
+import org.sonar.api.web.WidgetPropertySet;
import org.sonar.api.web.WidgetScope;
import java.util.Collection;
@SuppressWarnings("rawtypes")
public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
- private V view;
+ private final V view;
+ private final boolean isWidget;
private String[] sections = {NavigationSection.HOME};
private String[] userRoles = {};
private String[] resourceScopes = {};
private String[] defaultForMetrics = {};
private String description = "";
private Map<String, WidgetProperty> widgetPropertiesByKey = Maps.newHashMap();
+ private SetMultimap<WidgetPropertySet, WidgetProperty> widgetPropertiesBySet = LinkedHashMultimap.create();
private String[] widgetCategories = {};
private WidgetLayoutType widgetLayout = WidgetLayoutType.DEFAULT;
private boolean isDefaultTab = false;
- private boolean isWidget = false;
private boolean isGlobal = false;
private String[] mandatoryMeasures = {};
private String[] needOneOfMeasures = {};
- public ViewProxy(final V view) {
+ public ViewProxy(V view) {
this.view = view;
+ this.isWidget = (view instanceof Widget);
initUserRoles(view);
initSections(view);
initWidgetLayout(view);
initWidgetGlobal(view);
initRequiredMeasures(view);
-
- isWidget = (view instanceof Widget);
}
private void initRequiredMeasures(V view) {
}
}
- private void initWidgetLayout(final V view) {
+ private void initWidgetLayout(V view) {
WidgetLayout layoutAnnotation = AnnotationUtils.getAnnotation(view, WidgetLayout.class);
if (layoutAnnotation != null) {
widgetLayout = layoutAnnotation.value();
}
}
- private void initWidgetCategory(final V view) {
+ private void initWidgetCategory(V view) {
WidgetCategory categAnnotation = AnnotationUtils.getAnnotation(view, WidgetCategory.class);
if (categAnnotation != null) {
widgetCategories = categAnnotation.value();
}
}
- private void initWidgetProperties(final V view) {
+ private void initWidgetProperties(V view) {
WidgetProperties propAnnotation = AnnotationUtils.getAnnotation(view, WidgetProperties.class);
if (propAnnotation != null) {
+ for (WidgetPropertySet set : propAnnotation.sets()) {
+ for (WidgetProperty property : set.value()) {
+ widgetPropertiesBySet.put(set, property);
+ widgetPropertiesByKey.put(property.key(), property);
+ }
+ }
for (WidgetProperty property : propAnnotation.value()) {
+ widgetPropertiesBySet.put(WidgetPropertySet.DEFAULT, property);
widgetPropertiesByKey.put(property.key(), property);
}
}
}
- private void initDescription(final V view) {
+ private void initDescription(V view) {
Description descriptionAnnotation = AnnotationUtils.getAnnotation(view, Description.class);
if (descriptionAnnotation != null) {
description = descriptionAnnotation.value();
}
}
- private void initDefaultTabInfo(final V view) {
+ private void initDefaultTabInfo(V view) {
DefaultTab defaultTabAnnotation = AnnotationUtils.getAnnotation(view, DefaultTab.class);
if (defaultTabAnnotation != null) {
if (defaultTabAnnotation.metrics().length == 0) {
isDefaultTab = true;
defaultForMetrics = new String[0];
-
} else {
isDefaultTab = false;
defaultForMetrics = defaultTabAnnotation.metrics();
}
}
- private void initResourceLanguage(final V view) {
+ private void initResourceLanguage(V view) {
ResourceLanguage languageAnnotation = AnnotationUtils.getAnnotation(view, ResourceLanguage.class);
if (languageAnnotation != null) {
resourceLanguages = languageAnnotation.value();
}
}
- private void initResourceQualifier(final V view) {
+ private void initResourceQualifier(V view) {
ResourceQualifier qualifierAnnotation = AnnotationUtils.getAnnotation(view, ResourceQualifier.class);
if (qualifierAnnotation != null) {
resourceQualifiers = qualifierAnnotation.value();
}
}
- private void initResourceScope(final V view) {
+ private void initResourceScope(V view) {
ResourceScope scopeAnnotation = AnnotationUtils.getAnnotation(view, ResourceScope.class);
if (scopeAnnotation != null) {
resourceScopes = scopeAnnotation.value();
}
}
- private void initSections(final V view) {
+ private void initSections(V view) {
NavigationSection sectionAnnotation = AnnotationUtils.getAnnotation(view, NavigationSection.class);
if (sectionAnnotation != null) {
sections = sectionAnnotation.value();
}
}
- private void initUserRoles(final V view) {
+ private void initUserRoles(V view) {
UserRole userRoleAnnotation = AnnotationUtils.getAnnotation(view, UserRole.class);
if (userRoleAnnotation != null) {
userRoles = userRoleAnnotation.value();
public boolean isController() {
String id = view.getId();
- return id !=null && id.length()>0 && id.charAt(0)=='/';
+ return id != null && !id.isEmpty() && id.charAt(0) == '/';
}
public String getTitle() {
return widgetPropertiesByKey.values();
}
+ public SetMultimap<WidgetPropertySet, WidgetProperty> getWidgetPropertiesBySet() {
+ return ImmutableSetMultimap.copyOf(widgetPropertiesBySet);
+ }
+
public WidgetProperty getWidgetProperty(String propertyKey) {
return widgetPropertiesByKey.get(propertyKey);
}
public boolean supportsMetric(String metricKey) {
return ArrayUtils.contains(defaultForMetrics, metricKey);
}
-
+
public boolean acceptsAvailableMeasures(String[] availableMeasures) {
for (String mandatoryMeasure : mandatoryMeasures) {
if (!ArrayUtils.contains(availableMeasures, mandatoryMeasure)) {
return false;
}
}
+
if (needOneOfMeasures.length == 0) {
return true;
- } else {
- for (String neededMeasure : needOneOfMeasures) {
- if (ArrayUtils.contains(availableMeasures, neededMeasure)) {
- return true;
- }
+ }
+
+ for (String neededMeasure : needOneOfMeasures) {
+ if (ArrayUtils.contains(availableMeasures, neededMeasure)) {
+ return true;
}
- return false;
}
+ return false;
}
public boolean isWidget() {
}
public boolean hasRequiredProperties() {
- boolean requires = false;
for (WidgetProperty property : getWidgetProperties()) {
if (!property.optional() && StringUtils.isEmpty(property.defaultValue())) {
- requires = true;
+ return true;
}
}
- return requires;
+ return false;
+ }
+
+ public boolean validate(WidgetProperty property, String value) {
+ try {
+ return property.validation().newInstance().validate(value);
+ } catch (Exception e) {
+ }
+ return true;
}
@Override
.append("languages", resourceLanguages)
.append("metrics", defaultForMetrics)
.toString();
-
}
public int compareTo(ViewProxy other) {
.append(getTitle(), other.getTitle())
.append(getId(), other.getId())
.toComparison();
-
}
}
</tr>
<% end %>
- <% widget.java_definition.getWidgetProperties().sort { |w1, w2| natural_comparison(w1.key, w2.key) }.each do |property_def| %>
- <tr>
- <td class="form-key-cell"><%= property_def.key() -%><%= " *" unless property_def.optional() -%></td>
- <td class="form-val-cell" id="row_<%= property_def.key() -%>">
- <%= property_value_field(property_def, widget.property_text_value(property_def.key())) -%>
- <div class="form-val-note">
- <%= message("widget." + widget.key + ".param." + property_def.key(), :default => property_def.description()) -%>
- </div>
- </td>
- </tr>
+ <% widget.java_definition.getWidgetPropertiesBySet().asMap().sort { |(s1,p1), (s2,p2)| natural_comparison(s1.key, s2.key) }.each do |set,properties| %>
+ <% if widget.java_definition.getWidgetPropertiesBySet().asMap().size > 1 %>
+ <% if set.key().empty? %>
+ <tr>
+ <td celspan="2"><h3>other</h3></td>
+ </tr>
+ <% else %>
+ <tr>
+ <td celspan="2"><h3><%= set.key() -%></h3></td>
+ </tr>
+ <% end %>
+ <% end %>
+ <% properties.sort { |w1, w2| natural_comparison(w1.key, w2.key) }.each do |property_def| %>
+ <tr>
+ <td class="form-key-cell"><%= property_def.key() -%><%= " *" unless property_def.optional() -%></td>
+ <td class="form-val-cell" id="row_<%= property_def.key() -%>">
+ <%= property_value_field(property_def, widget.property_text_value(property_def.key())) -%>
+ <div class="form-val-note">
+ <%= message("widget." + widget.key + ".param." + property_def.key(), :default => property_def.description()) -%>
+ </div>
+ </td>
+ </tr>
+ <% end %>
<% end %>
<tr>
*/
package org.sonar.server.ui;
+import org.sonar.api.web.WidgetPropertySet;
+
import org.junit.rules.ExpectedException;
import org.junit.Rule;
assertThat(proxy.getWidgetProperties()).hasSize(2);
}
+ @Test
+ public void should_support_property_sets() {
+ ViewProxy proxy = new ViewProxy<Widget>(new EditableWidgetWithSets());
+
+ assertThat(proxy.getWidgetProperties()).hasSize(4);
+ assertThat(proxy.getWidgetPropertiesBySet().keySet()).hasSize(3);
+ assertThat(proxy.getWidgetPropertiesBySet().values()).hasSize(4);
+ }
+
@Test
public void widget_should_not_be_global_by_default() {
ViewProxy proxy = new ViewProxy<Widget>(new EditableWidget());
exception.expect(IllegalArgumentException.class);
exception.expectMessage("INVALID");
exception.expectMessage("WidgetWithInvalidScope");
-
+
new ViewProxy<Widget>(new WidgetWithInvalidScope());
}
@WidgetProperty(key = "bar", defaultValue = "30", type = WidgetPropertyType.INTEGER)
})
class EditableWidget implements Widget {
-
public String getId() {
return "w1";
}
}
}
+@WidgetProperties(sets = {
+ @WidgetPropertySet(key = "set1",
+ value = {
+ @WidgetProperty(key = "foo", optional = false),
+ @WidgetProperty(key = "bar", optional = false),
+ }),
+ @WidgetPropertySet(key = "set2",
+ value = {
+ @WidgetProperty(key = "qix", optional = false),
+ })},
+ value = {
+ @WidgetProperty(key = "fizz", optional = false)
+ })
+class EditableWidgetWithSets implements Widget {
+ public String getId() {
+ return "w3";
+ }
+
+ public String getTitle() {
+ return "W3";
+ }
+}
+
@WidgetScope("GLOBAL")
class GlobalWidget implements Widget {
public String getId() {
@WidgetProperty(key = "bar")
})
class WidgetWithOptionalProperties implements Widget {
-
public String getId() {
return "w2";
}