All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.plugins.timeline.client.GwtTimeline Maven / Gradle / Ivy

/*
 * Sonar, open source software quality management tool.
 * Copyright (C) 2009 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.timeline.client;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.visualization.client.AbstractDataTable.ColumnType;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.visualizations.AnnotatedTimeLine;
import com.google.gwt.visualization.client.visualizations.AnnotatedTimeLine.Options;
import com.google.gwt.visualization.client.visualizations.AnnotatedTimeLine.ScaleType;
import org.sonar.api.web.gwt.client.widgets.LoadingLabel;
import org.sonar.gwt.JsonUtils;
import org.sonar.gwt.ui.Page;
import org.sonar.wsclient.gwt.AbstractCallback;
import org.sonar.wsclient.gwt.AbstractListCallback;
import org.sonar.wsclient.gwt.Sonar;
import org.sonar.wsclient.services.*;

import java.util.*;

public class GwtTimeline extends Page {

  public static final String GWT_ID = "org.sonar.plugins.timeline.GwtTimeline";

  public static final List SUPPORTED_METRIC_TYPES = Arrays.asList("INT", "FLOAT", "PERCENT", "MILLISEC");

  public static final int DEFAULT_HEIGHT = 480;

  public static final String DEFAULT_METRICS_KEY = "sonar.timeline.defaultmetrics";
  public static final String DEFAULT_METRICS_VALUE = "ncloc,violations_density,coverage";

  private SortedSet metrics = null;
  private String[] defaultMetrics = null;
  private ListBox metricsListBox1 = new ListBox();
  private ListBox metricsListBox2 = new ListBox();
  private ListBox metricsListBox3 = new ListBox();
  private List metricsListBoxes = null;
  private CheckBox singleScaleCheckBox = new CheckBox("Single scale");
  private SimplePanel tlPanel = null;

  private VerticalPanel panel;

  private Map loadedMetrics = new HashMap();

  private Resource resource;

  private DataTable dataTable;

  @Override
  protected Widget doOnResourceLoad(Resource resource) {
    panel = new VerticalPanel();
    panel.add(new LoadingLabel());
    this.resource = resource;
    load();
    return panel;
  }

  private void load() {
    Sonar.getInstance().find(PropertyQuery.createForKey(DEFAULT_METRICS_KEY), new AbstractCallback() {
      @Override
      protected void doOnResponse(Property result) {
        defaultMetrics = result.getValue().split(",");
        loadMetrics();
      }

      @Override
      protected void doOnError(int errorCode, String errorMessage) {
        defaultMetrics = DEFAULT_METRICS_VALUE.split(",");
        loadMetrics();
      }
    });
  }

  private void loadMetrics() {
    Sonar.getInstance().findAll(MetricQuery.all(), new AbstractListCallback() {
      @Override
      protected void doOnResponse(List result) {
        for (Metric metric : result) {
          if (isSupported(metric)) {
            loadedMetrics.put(metric.getKey(), metric);
          }
        }

        metrics = filterAndOrderMetrics(result);
        metricsListBoxes = Arrays.asList(metricsListBox1, metricsListBox2, metricsListBox3);
        loadListBox(metricsListBox1, defaultMetrics.length > 0 ? defaultMetrics[0] : null);
        loadListBox(metricsListBox2, defaultMetrics.length > 1 ? defaultMetrics[1] : null);
        loadListBox(metricsListBox3, defaultMetrics.length > 2 ? defaultMetrics[2] : null);

        ChangeHandler metricSelection = new ChangeHandler() {
          public void onChange(ChangeEvent event) {
            if (!allMetricsUnSelected() && !sameMetricsSelection()) {
              loadTimeline();
            }
          }
        };
        for (ListBox metricLb : metricsListBoxes) {
          metricLb.addChangeHandler(metricSelection);
        }
        singleScaleCheckBox.addClickHandler(new ClickHandler() {
          public void onClick(ClickEvent event) {
            renderDataTable(dataTable);
          }
        });

        loadVisualizationApi();
      }

      private void loadListBox(ListBox metricsLb, String selectedKey) {
        metricsLb.setStyleName("small");
        metricsLb.addItem("", "");
        int index = 1;
        for (Metric metric : metrics) {
          metricsLb.addItem(metric.getName(), metric.getKey());
          if (selectedKey != null && metric.getKey().equals(selectedKey.trim())) {
            metricsLb.setSelectedIndex(index);
          }
          index++;
        }
      }

      private Boolean allMetricsUnSelected() {
        for (ListBox metricLb : metricsListBoxes) {
          if (getSelectedMetric(metricLb) != null) {
            return false;
          }
        }
        return true;
      }

      private boolean sameMetricsSelection() {
        List selected = new ArrayList();
        for (ListBox metricLb : metricsListBoxes) {
          Metric metric = getSelectedMetric(metricLb);
          if (metric != null) {
            if (selected.contains(metric)) {
              return true;
            }
            selected.add(metric);
          }
        }
        return false;
      }
    });
  }

  private void loadVisualizationApi() {
    Runnable onLoadCallback = new Runnable() {
      public void run() {
        render();
        loadTimeline();
      }
    };
    VisualizationUtils.loadVisualizationApi(onLoadCallback, AnnotatedTimeLine.PACKAGE);
  }

  private static SortedSet filterAndOrderMetrics(Collection metrics) {
    TreeSet ordered = new TreeSet(new Comparator() {
      public int compare(Metric o1, Metric o2) {
        return o1.getName().compareTo(o2.getName());
      }
    });
    for (Metric metric : metrics) {
      if (isSupported(metric)) {
        ordered.add(metric);
      }
    }
    return ordered;
  }

  private static boolean isSupported(Metric metric) {
    return SUPPORTED_METRIC_TYPES.contains(metric.getType()) && !metric.getHidden();
  }

  private void loadTimeline() {
    lockMetricsList(true);
    tlPanel.clear();
    tlPanel.add(new LoadingLabel());

    new TimelineLoader(resource.getKey(), getSelectedMetrics()) {
      @Override
      void noData() {
        renderNoData();
      }

      @Override
      void data(String[] metrics, TimeMachine timemachine, List events) {
        dataTable = getDataTable(metrics, timemachine, events);
        renderDataTable(dataTable);
      }
    };
  }

  private void renderDataTable(DataTable table) {
    if (table != null && table.getNumberOfRows() > 0) {
      Element content = DOM.getElementById("content");
      int width = content.getClientWidth() > 0 ? content.getClientWidth() : 800;
      Widget toRender = new AnnotatedTimeLine(table, createOptions(), width + "px", GwtTimeline.DEFAULT_HEIGHT + "px");
      renderTimeline(toRender);
    } else {
      renderNoData();
    }
  }

  private void renderNoData() {
    renderTimeline(new HTML("

No data

")); } private void renderTimeline(Widget toRender) { lockMetricsList(false); tlPanel.clear(); tlPanel.add(toRender); } private DataTable getDataTable(String[] metrics, TimeMachine timeMachine, List events) { DataTable table = DataTable.create(); table.addColumn(ColumnType.DATE, "d", "Date"); for (String metric : metrics) { table.addColumn(ColumnType.NUMBER, loadedMetrics.get(metric).getName(), metric); } table.addColumn(ColumnType.STRING, "e", "Event"); for (TimeMachineCell cell : timeMachine.getCells()) { int rowIndex = table.addRow(); table.setValue(rowIndex, 0, cell.getDate()); for (int i = 0; i < metrics.length; i++) { Double value = JsonUtils.getAsDouble((JSONValue) cell.getValues()[i]); if (value != null) { table.setValue(rowIndex, i + 1, value); } } } for (Event event : events) { int rowIndex = table.addRow(); String eventStr = event.getName(); if (event.getDescription() != null) { eventStr += " : " + event.getDescription(); } table.setValue(rowIndex, 0, event.getDate()); table.setValue(rowIndex, metrics.length + 1, eventStr); } return table; } private void lockMetricsList(boolean locked) { for (ListBox metricLb : metricsListBoxes) { metricLb.setEnabled(!locked); } } private String[] getSelectedMetrics() { List metrics = new ArrayList(); for (ListBox metricLb : metricsListBoxes) { Metric metric = getSelectedMetric(metricLb); if (metric != null) { // inverting metrics metrics.add(0, metric.getKey()); } } return metrics.toArray(new String[metrics.size()]); } private Metric getSelectedMetric(ListBox metricsLb) { String selected = metricsLb.getValue(metricsLb.getSelectedIndex()); return selected.length() > 0 ? loadedMetrics.get(selected) : null; } private void render() { HorizontalPanel hPanel = new HorizontalPanel(); Label label = new Label("Metrics:"); label.setStyleName("note"); hPanel.add(label); for (ListBox metricLb : metricsListBoxes) { hPanel.add(new HTML(" ")); hPanel.add(metricLb); } hPanel.add(singleScaleCheckBox); VerticalPanel vPanel = new VerticalPanel(); vPanel.add(hPanel); tlPanel = new SimplePanel(); vPanel.add(tlPanel); displayView(vPanel); } private void displayView(Widget widget) { panel.clear(); panel.add(widget); } private Options createOptions() { Options options = Options.create(); options.setAllowHtml(true); options.setDisplayAnnotations(true); options.setDisplayAnnotationsFilter(true); options.setAnnotationsWidth(15); options.setOption("fill", 15); options.setOption("thickness", 2); resetNumberFormats(); int selectedCols = 0; for (ListBox metricLb : metricsListBoxes) { if (getSelectedMetric(metricLb) != null) { setNumberFormats(selectedCols++, getNumberFormat(getSelectedMetric(metricLb))); } } options.setOption("numberFormats", getNumberFormats()); if (!singleScaleCheckBox.getValue()) { int[] scaledCols = new int[selectedCols]; for (int i = 0; i < selectedCols; i++) { scaledCols[i] = i; } options.setScaleType(ScaleType.ALLFIXED); options.setScaleColumns(scaledCols); } return options; } private String getNumberFormat(Metric metric) { return metric.getType().equals("PERCENT") ? "0.0" : "0.##"; } private native JavaScriptObject getNumberFormats() /*-{ return this.numberFormats; }-*/; private native void resetNumberFormats() /*-{ this.numberFormats = {}; }-*/; private native void setNumberFormats(int key, String numberFormat) /*-{ this.numberFormats[key] = numberFormat; }-*/; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy