package com.intland.codebeamer.dashboard.component.widgets.wiki;
import org.springframework.stereotype.Component;
import com.intland.codebeamer.dashboard.component.common.interfaces.WidgetInformation;
import com.intland.codebeamer.dashboard.component.widgets.common.WidgetCategory;
// Annotation required to make it available in the system.
@Component
public class WikiMarkupWidgetInformation implements WidgetInformation {
// Defines the category, which affects on which tab in Widget popup it appears.
//Possible values: ALL, CHART, PROJECT, AGILE, TEST, PERSONAL_CONTENT, OTHER
@Override
public String getCategory() {
return WidgetCategory.OTHER.getName();
}
// Custom icon for the Widget.
@Override
public String getImagePreviewUrl() {
return "/images/newskin/dashboard/thumbnails/icon_wiki_markup.png";
}
// Knowledgebase url on codebeamer.com, reserved for built-in widgets.
@Override
public String getKnowledgeBaseUrl() {
return "";
}
// Vendor information.
@Override
public String getVendor() {
return "Intland";
}
// Key in ApplicationResources.properties, which defines the short name of the Widget.
@Override
public String getName() {
return "dashboard.wiki.markup.widget.name";
}
// Key in ApplicationProperties.properties, which contains the description for the Widget.
@Override
public String getShortDescription() {
return "dashboard.wiki.markup.widget.short.description";
}
// Reserved for future use.
@Override
public WikiMarkupWidgetFactory getFactory() {
return null;
}
// Type name of the related Widget class.
@Override
public String getType() {
return WikiMarkupWidget.class.getCanonicalName();
}
}
|
|
Instead of the direct implementation, the inheritance from the AbstractWidget class is recommended, which already has the implementation for common features.
|
package com.intland.codebeamer.dashboard.component.common.interfaces;
import com.intland.codebeamer.dashboard.component.common.RenderingContext;
public interface LayoutComponent {
// Unique identifier of the component
String getId();
// Renders the component as HTML fragment (not a standalone HTML page)
String renderToHtml(RenderingContext renderingContext);
}
package com.intland.codebeamer.dashboard.component.common.interfaces;
import java.util.Map;
import com.intland.codebeamer.dashboard.component.common.RenderingContext;
import com.intland.codebeamer.dashboard.component.serializer.JacksonSerializableObject;
import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute;
public interface Widget extends LayoutComponent, JacksonSerializableObject {
// Renders the editor for the Widget as HTML fragment (not a standalone HTML page)
String renderEditorToHtml(RenderingContext renderingContext);
// Attributes of the widget. These are typed values, which might represent just a simple text or more complex entities like a list of projects.
Map<String, WidgetAttribute> getAttributes();
// Setter for the title of the Widget.
void setTitle(String title);
// Reserved for future use.
void setFullWidth(boolean isFullWidth);
// Reserved for future use.
boolean isFullWidth();
// Sets the color of the Widget header.
void setColor(String color);
// Reserved for future use.
void setHeaderHidden(boolean headerHidden);
// Returns a key from ApplicationResources.properties, which defines the default title for the Widget.
String getDefaultTitleKey();
}
package com.intland.codebeamer.dashboard.component.widgets.common;
import java.util.Map;
import org.apache.commons.lang3.Validate;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.intland.codebeamer.dashboard.component.common.interfaces.Widget;
import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute;
// Important to have these annotations to ensure that the persistence layer saves the Widget properly
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
public abstract class AbstractWidget implements Widget {
protected static final String NULL_MESSAGE_FORMAT = "The value %s must not be null.";
// Identifier of the Widget
protected final String id;
// CURRENT attributes of the widget
protected final Map<String, WidgetAttribute> attributes;
// Title of the widget
protected String title;
// Reserved for future use
protected boolean isFullWidth;
// Color of the header
protected String color;
// Reserved for future use.
protected boolean headerHidden;
public AbstractWidget(String id, Map<String, WidgetAttribute> attributes) {
Validate.notBlank(id, NULL_MESSAGE_FORMAT, "id");
Validate.notNull(attributes, NULL_MESSAGE_FORMAT, "attributes");
this.id = id;
this.attributes = attributes;
}
// Getters and setter omitted.
}
|
|
Extending the AbstractRendererWidget class is recommended, as it already implements this pattern and contains important error handling code as well.
|
package com.intland.codebeamer.dashboard.component.widgets.wiki;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.Validate;
import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.intland.codebeamer.dashboard.component.common.RenderingContext;
import com.intland.codebeamer.dashboard.component.common.interfaces.Renderer;
import com.intland.codebeamer.dashboard.component.widgets.common.AbstractWidget;
import com.intland.codebeamer.dashboard.component.widgets.common.attribute.TextAttribute;
import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic=true)
public class WikiMarkupWidget extends AbstractWidget {
public static final String MARKUP_ATTRIBUTE_NAME = "markup";
public static final WidgetAttribute<String> DEFAULT_MARKUP_ATTRIBUTE = new TextAttribute("", true, false);
// Preferred method to define default attributes
public static Map<String, WidgetAttribute> getDescriptor() {
final Map<String, WidgetAttribute> result = new HashMap<String, WidgetAttribute>();
result.put(MARKUP_ATTRIBUTE_NAME, DEFAULT_MARKUP_ATTRIBUTE);
return result;
}
// Renderer instance, which can create the content of the Widget
private final Renderer<WikiMarkupWidget> htmlRenderer;
// Renderer instance, which can create the editor form for the Widget
private final Renderer<WikiMarkupWidget> editorRenderer;
// Annotated constructor used by the persistence layer. Do not forget to add these annotations!
public WikiMarkupWidget(@JsonProperty("id") final String id, @JsonProperty("attributes") final Map<String, WidgetAttribute> attributes,
@JacksonInject("wikiMarkupWidgetHtmlRenderer") final Renderer<WikiMarkupWidget> htmlRenderer,
@JacksonInject("wikiMarkupWidgetEditorRenderer") final Renderer<WikiMarkupWidget> editorRenderer) {
super(id, attributes);
Validate.notNull(htmlRenderer, NULL_MESSAGE_FORMAT, "htmlRenderer");
Validate.notNull(editorRenderer, NULL_MESSAGE_FORMAT, "editorRenderer");
this.htmlRenderer = htmlRenderer;
this.editorRenderer = editorRenderer;
}
@Override
public String getTypeName() {
return WikiMarkupWidget.class.getCanonicalName();
}
// Recommended way to render the content of the Widget.
@Override
public String renderToHtml(final RenderingContext renderingContext) {
return htmlRenderer.render(renderingContext, this);
}
// Recommended way to render the editor for of the Widget.
@Override
public String renderEditorToHtml(final RenderingContext renderingContext) {
return editorRenderer.render(renderingContext, this);
}
@Override
public String getDefaultTitleKey() {
return "dashboard.wiki.markup.widget.name";
}
}
package com.intland.codebeamer.dashboard.component.widgets.common.attribute;
import java.util.Map;
import org.apache.commons.lang3.Validate;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
// Important annotations, which fine the persistence mechanism.
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="typeName")
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic=true)
public abstract class WidgetAttribute<T> {
protected static final String NULL_MESSAGE_FORMAT = "The value %s must not be null.";
// CURRRENT value of the attribute.
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.WRAPPER_OBJECT, property="valueTypeName")
T value;
// Shows whether this attribute has to be filled on the editor form.
protected final boolean required;
// Shows whether this attribute has to be validated using additional validation logic.
protected final boolean validationRequired;
public WidgetAttribute(final T value, final boolean required, final boolean validationRequired) {
Validate.notNull(value, NULL_MESSAGE_FORMAT, "value");
this.value = value;
this.required = required;
this.validationRequired = validationRequired;
}
// Getters and setters omited.
// Important method, all attributes has to provide a way to parse values from a String representation.
public abstract WidgetAttribute<T> convert(final String newValue);
// If the attribute is affected by export / import mechanism (like using project ids), then the identifiers will be mapped by calling this method during the import.
public void replaceIdsAfterImport(Map<Integer, Map<Integer, Integer>> ids) {
}
protected void setValue(T value) {
this.value = value;
}
}
|
Class Name
|
Value Type
|
|---|---|
|
BooleanAttribute
|
Boolean
|
|
StringAttribute
|
String
|
|
TextAttribute
|
String, but has a rich text editor
|
|
IntegerAttribute
|
Integer
|
|
IntegerListAttribute
|
List of integers
|
|
StringListAttribute
|
List of strings
|
|
FixedChoiceWidgetAttribute
|
Can be used with an enum as a type parameter, containing a single value from that enum.
|
|
MultiChoiceWidgetAttribute
|
Similar to FixedChoiceWidgetAttribute, but can contain more than one value.
|
|
Class Name
|
Value Type
|
|---|---|
|
ProjectListAttribute
|
List of project identifiers
|
|
ProjectAttribute
|
Single project identifier
|
|
ReleaseListAttribute
|
List of release identifiers
|
|
ReleaseAttribute
|
Single release identifier
|
|
TeamListAttribute
|
List of team identifiers
|
|
TeamAttribute
|
Single team identifier
|
|
TrackerListAttribute
|
List of tracker identifiers
|
|
TrackerAttribute
|
Single tracker identifier
|
|
TrackerTypeListAttribute
|
List of TrackerType identifiers
|
|
TypedTrackerListAttribute
|
Similar to TrackerListAttribute, but only allows the given tracker types
|
|
UserListAttribute
|
List of user identifiers
|
|
UserAttribute
|
Single user identifier
|
import com.intland.codebeamer.dashboard.component.common.RenderingContext;
public interface Renderer<T> {
String render(RenderingContext renderingContext, T object);
}
<div id="${id}">
${html}
</div>
package com.intland.codebeamer.dashboard.component.widgets.wiki;
// Imports removed
@Component
@Qualifier("wikiMarkupWidgetHtmlRenderer")
public class WikiMarkupWidgetHtmlRenderer implements Renderer<WikiMarkupWidget> {
private static final String TEMPLATE = "wikimarkup-widget.vm";
@Autowired
private WikiPageManager wikiPageManager;
@Autowired
private WikiMarkupProcessor wikiMarkupProcessor;
@Override
public String render(final RenderingContext renderingContext, final WikiMarkupWidget object) {
// Initialization and argument checks (omitted)
// Use the arguments to retrieve the information required to render the wiki markup to html.
final String id = object.getId();
final Map<String, WidgetAttribute> attributes = object.getAttributes();
final WidgetAttribute wikiMarkupAttribute = attributes.get(WikiMarkupWidget.MARKUP_ATTRIBUTE_NAME);
final String markup = wikiMarkupAttribute.getValue() != null ? (String) wikiMarkupAttribute.getValue() : "";
// Transforming Wiki markup to HTML (omitted)
// Add data to Velocity context
velocityContext.put("id", id);
velocityContext.put("html", html);
final TemplateRenderer templateRenderer = TemplateRenderer.getInstance();
// Render Velocity template
return templateRenderer.renderTemplateOnPath(TEMPLATE, velocityContext, new Parameters(renderingContext.getRequest().getLocale(), false));
}
// Helper methods (omitted)
}
|
|
Using velocity is mandatory in this type of renderer implementations.
|
package com.intland.codebeamer.dashboard.component.widgets.wiki;
import org.apache.commons.lang3.Validate;
import org.apache.velocity.VelocityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.intland.codebeamer.dashboard.component.common.RenderingContext;
import com.intland.codebeamer.dashboard.component.common.interfaces.Renderer;
import com.intland.codebeamer.dashboard.component.widgets.common.ModelPopulator;
import com.intland.codebeamer.utils.TemplateRenderer;
import com.intland.codebeamer.utils.TemplateRenderer.Parameters;
@Component
@Qualifier("wikiMarkupWidgetEditorRenderer")
public class WikiMarkupWidgetEditorRenderer implements Renderer<WikiMarkupWidget> {
private static final String NULL_MESSAGE_FORMAT = "The value %s must not be null.";
private static final String EDITOR_TEMPLATE = "wikimarkup-widget-editor.vm";
// This is the required helper class, which will generate the editor form elements
private final ModelPopulator<VelocityContext> modelPopulator;
private final TemplateRenderer templateRenderer;
@Autowired
public WikiMarkupWidgetEditorRenderer(final ModelPopulator<VelocityContext> modelPopulator, final TemplateRenderer templateRenderer) {
Validate.notNull(modelPopulator, NULL_MESSAGE_FORMAT, "modelPopulator");
Validate.notNull(templateRenderer, NULL_MESSAGE_FORMAT, "templateRenderer");
this.modelPopulator = modelPopulator;
this.templateRenderer = templateRenderer;
}
@Override
public String render(final RenderingContext renderingContext, final WikiMarkupWidget wikiMarkupWidget) {
Validate.notNull(renderingContext, NULL_MESSAGE_FORMAT, "renderingContext");
Validate.notNull(wikiMarkupWidget, NULL_MESSAGE_FORMAT, "wikiMarkupWidget");
// Create the Velocity context
final VelocityContext velocityContext = new VelocityContext();
// Let the populator create the right HTML fragments for each attribute
modelPopulator.populateAttributes(renderingContext, wikiMarkupWidget, WikiMarkupWidget.getDescriptor(), velocityContext);
// Return the rendererd template
return templateRenderer.renderTemplateOnPath(EDITOR_TEMPLATE, velocityContext, new Parameters(renderingContext.getRequest().getLocale(), false));
}
}
${markup}
<br/>
// Imports omitted
public class RenderingContext {
// The current user, who is viewing or editing the dashboard.
private final UserDto user;
// The current request instance.
private final HttpServletRequest request;
// WikiPageDto representing the actual Dashboard.
private final WikiPageDto dashboard;
// Utility class, which can be used to translate keys from ApplicationResources.properties to text
private final LocalizedTextRetriever localizedTextRetriever;
// Constructor, getters omitted
}
package com.intland.codebeamer.dashboard.component.serializer;
import com.fasterxml.jackson.databind.InjectableValues;
public interface JacksonObjectDeserializeContext<T> {
// Class of the Widget
Class<T> getType();
// Full class name of the Widget
String getTypeName();
// All the properties, which must be injected through dependency injection into Widgets. (See the Jackson annotation on the example Widget constructor.)
InjectableValues getInjectableValues();
}
package com.intland.codebeamer.dashboard.component.common.interfaces;
import com.intland.codebeamer.dashboard.component.serializer.JacksonObjectDeserializeContext;
// Marker interface
public interface LayoutComponentFactory<T extends LayoutComponent> extends JacksonObjectDeserializeContext<T> {
}
package com.intland.codebeamer.dashboard.component.common.interfaces;
import java.util.Map;
public interface WidgetFactory<T extends Widget> extends LayoutComponentFactory<T> {
// Create an instance with the given attributes
T createInstance(String id, Map<String, String> attributes);
// Create an instance with the given attributes, run validations
T createInstance(String id, Map<String, String> attributes, boolean validate);
// Create an instance with default attribute values
T createInstance();
}
package com.intland.codebeamer.dashboard.component.widgets.wiki;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.InjectableValues;
import com.intland.codebeamer.dashboard.component.common.interfaces.Renderer;
import com.intland.codebeamer.dashboard.component.common.interfaces.WidgetFactory;
import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute;
import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttributeMapper;
@Component
public class WikiMarkupWidgetFactory implements WidgetFactory<WikiMarkupWidget> {
private static final String NULL_MESSAGE_FORMAT = "The value %s must not be null.";
// The HMTL renderer
private final Renderer<WikiMarkupWidget> htmlRenderer;
// The editor form renderer
private final Renderer<WikiMarkupWidget> editorRenderer;
private final WidgetAttributeMapper widgetAttributeMapper;
// Qualifiers are important here!
@Autowired
public WikiMarkupWidgetFactory(@Qualifier("wikiMarkupWidgetHtmlRenderer") final Renderer<WikiMarkupWidget> htmlRenderer,
@Qualifier("wikiMarkupWidgetEditorRenderer") final Renderer<WikiMarkupWidget> editorRenderer,
final WidgetAttributeMapper widgetAttributeMapper) {
Validate.notNull(htmlRenderer, NULL_MESSAGE_FORMAT, "htmlRenderer");
Validate.notNull(editorRenderer, NULL_MESSAGE_FORMAT, "editorRenderer");
Validate.notNull(widgetAttributeMapper, NULL_MESSAGE_FORMAT, "widgetAttributeMapper");
this.htmlRenderer = htmlRenderer;
this.editorRenderer = editorRenderer;
this.widgetAttributeMapper = widgetAttributeMapper;
}
@Override
public WikiMarkupWidget createInstance(String id, Map<String, String> attributes) {
return createInstance(id, attributes, true);
}
@Override
public WikiMarkupWidget createInstance(String id, Map<String, String> attributes, boolean validate) {
Validate.notBlank(id, NULL_MESSAGE_FORMAT, "id");
Validate.notNull(attributes, NULL_MESSAGE_FORMAT, "attributes");
final Map<String, WidgetAttribute> widgetAttributes = widgetAttributeMapper.map(attributes, WikiMarkupWidget.getDescriptor(), validate);
return new WikiMarkupWidget(id, widgetAttributes, htmlRenderer, editorRenderer);
}
// The default attributes of the Widget are accessed via a static method
@Override
public WikiMarkupWidget createInstance() {
return new WikiMarkupWidget(UUID.randomUUID().toString(), WikiMarkupWidget.getDescriptor(), htmlRenderer, editorRenderer);
}
@Override
public Class<WikiMarkupWidget> getType() {
return WikiMarkupWidget.class;
}
@Override
public String getTypeName() {
return WikiMarkupWidget.class.getCanonicalName();
}
// Add all the constructor attributes of the Widget class, which needs to be injected via dependency injection. Make sure that the name of the value here matches the Jackson annotation on the Widget itself! ("wikiMarkupWidgetHtmlRenderer" for example)
@Override
public InjectableValues getInjectableValues() {
final InjectableValues inject = new InjectableValues.Std()
.addValue("wikiMarkupWidgetHtmlRenderer", htmlRenderer)
.addValue("wikiMarkupWidgetEditorRenderer",editorRenderer);
return inject;
}
}
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.intland.codebeamer.dashboard.component.common.interfaces.Widget;
import com.intland.codebeamer.dashboard.component.widgets.common.DefaultWidgetHtmlRenderer;
import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute;
import com.intland.codebeamer.dashboard.component.widgets.provider.WidgetAttributeValueProvider;
import com.intland.codebeamer.wiki.plugins.base.AbstractCodeBeamerWikiPlugin;
public abstract class AbstractDefaultWidgetHtmlRenderer<U extends Widget, Z extends AbstractCodeBeamerWikiPlugin> extends DefaultWidgetHtmlRenderer<U, Z>{
@Autowired
public AbstractDefaultWidgetHtmlRenderer(ObjectFactory<Z> factory) {
super(factory);
}
protected Map<String, String> createPluginParameters(Map<String, WidgetAttribute> attributes) {
final Map<String, String> parameters = new HashMap<String, String>();
// Generates the parameters of the plugin using the WidgetAttributeValueProviders, code omitted
createAdditionalParameters(attributes, parameters);
return parameters;
}
// You can add any parameter here, which is not generated by a WidgetAttributeValueProvider instance
protected void createAdditionalParameters(final Map<String, WidgetAttribute> attributes, final Map<String, String> parameters) {
}
// Returns the WidgetAttributes defined in the Widget itself
protected abstract WidgetAttributeWrapper[] getWidgetAttributes();
// A list of WidgetAttributeValueProvider instances. These can map a WidgetAttribute to a Wiki plugin parameter.
protected Map<WidgetAttributeWrapper, WidgetAttributeValueProvider> getValueProviders() {
return Collections.emptyMap();
}
}
import java.util.Map;
import com.intland.codebeamer.dashboard.component.widgets.common.WidgetAttributeWrapper;
import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute;
public interface WidgetAttributeValueProvider {
String obtainValue(WidgetAttributeWrapper attribute, Map<String, WidgetAttribute> attributes);
}
import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute;
public abstract class AbstractIntegerValueProvider extends AbstractWidgetAttributeValueProvider<WidgetAttribute<Integer>> {
@Override
protected String convertWidgetAttributeToString(final WidgetAttribute<Integer> widgetAttribute) {
return widgetAttribute.getValue().toString();
}
}
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Qualifier("widthIntegerValueProvider")
@Component
public class WidthIntegerValueProvider extends AbstractIntegerValueProvider {
public static final String WIDTH = "width";
@Override
public String getWidgetAttributeKey() {
return WIDTH;
}
}
package com.intland.codebeamer.dashboard.component.widgets.project;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.intland.codebeamer.dashboard.component.widgets.common.AbstractDefaultWidgetHtmlRenderer;
import com.intland.codebeamer.dashboard.component.widgets.common.WidgetAttributeWrapper;
import com.intland.codebeamer.dashboard.component.widgets.provider.WidgetAttributeValueProvider;
import com.intland.codebeamer.wiki.plugins.releaseganttchart.ReleaseGanttChartPlugin;
@Component
@Qualifier("releaseGanttChartWidgetHtmlRenderer")
public class ReleaseGanttChartWidgetHtmlRenderer extends AbstractDefaultWidgetHtmlRenderer<ReleaseGanttChartWidget, ReleaseGanttChartPlugin> {
private static final String NULL_MESSAGE_FORMAT = "The value %s must not be null.";
private final WidgetAttributeValueProvider releaseListAttributeValueProvider;
private final WidgetAttributeValueProvider heightAttributeValueProvider;
@Autowired
public ReleaseGanttChartWidgetHtmlRenderer(ObjectFactory<ReleaseGanttChartPlugin> objectFactory,
@Qualifier("ganttReleaseListAttributeValueProvider") final WidgetAttributeValueProvider releaseListAttributeValueProvider,
@Qualifier("ganttHeightAttributeProvider") final WidgetAttributeValueProvider heightAttributeValueProvider) {
super(objectFactory);
Validate.notNull(releaseListAttributeValueProvider, NULL_MESSAGE_FORMAT, "releaseListAttributeValueProvider");
Validate.notNull(heightAttributeValueProvider, NULL_MESSAGE_FORMAT, "heightAttributeValueProvider");
this.releaseListAttributeValueProvider = releaseListAttributeValueProvider;
this.heightAttributeValueProvider = heightAttributeValueProvider;
}
@Override
protected WidgetAttributeWrapper[] getWidgetAttributes() {
return ReleaseGanttChartWidget.Attribute.values();
}
@Override
protected Map<WidgetAttributeWrapper, WidgetAttributeValueProvider> getValueProviders() {
final Map<WidgetAttributeWrapper, WidgetAttributeValueProvider> valueProviders =
new HashMap<WidgetAttributeWrapper, WidgetAttributeValueProvider>();
valueProviders.put(ReleaseGanttChartWidget.Attribute.RELEASE_IDS, releaseListAttributeValueProvider);
valueProviders.put(ReleaseGanttChartWidget.Attribute.HEIGHT, heightAttributeValueProvider);
return valueProviders;
}
}
$(CSS_SELECTOR).trigger("renderfinished")