/*
* Copyright 2012 Axel Winkler, Daniel Dunér
*
* This file is part of Daxplore Presenter.
*
* Daxplore Presenter 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 2.1 of the License, or
* (at your option) any later version.
*
* Daxplore Presenter 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 Daxplore Presenter. If not, see <http://www.gnu.org/licenses/>.
*/
package org.daxplore.presenter.chart;
import org.daxplore.presenter.chart.display.Chart;
import org.daxplore.presenter.chart.resources.ChartConfig;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
/**
* A wrapper panel for charts.
*
* <p>When a new chart should be displayed, call the setChart method. It will
* display the new chart, once that chart is loaded.</p>
*/
public class ChartPanelView extends Composite {
interface ChartUiBinder extends UiBinder<Widget, ChartPanelView> { /* Empty UiTemplate interface */ }
private static ChartUiBinder uiBinder = GWT.create(ChartUiBinder.class);
@UiField(provided = true)
protected final SimplePanel headerPanel;
@UiField(provided = true)
protected final SimplePanel chartContainerPanel = new SimplePanel();
/**
* The chart that belongs to this panel.
*/
private Chart chart;
/**
* Fields used to figure out and adjust the size of the chart and
* chartPanel.
*/
private int resizeRecursions;
protected int maxWidth, maxHeight, chartWidth, chartHeight;
private ScrollPanel chartScrollPanel = new ScrollPanel();
private boolean scrolling = false, forceScrolling = false;
@Inject
protected ChartPanelView(ChartConfig chartConfig) {
chartContainerPanel.setStylePrimaryName("daxplore-ChartContainerPanel");
headerPanel = new SimplePanel();
initWidget(uiBinder.createAndBindUi(this));
setStylePrimaryName("daxplore-ChartPanel");
maxWidth = 800; // TODO this is temporary, the wanted value is set using setMaxWidth(int width)
maxHeight = chartConfig.chartHeight();
}
public void setChart(Chart chart) {
headerPanel.setWidget(chart.getExternalHeader());
if (scrolling) {
chartScrollPanel.setWidget(chart);
} else {
chartContainerPanel.setWidget(chart);
}
this.chart = chart;
adjustSizeRecursively();
}
/**
* Set the maximal allowed size of the chart panel, and in turn the chart.
*
* <p>This is not guaranteed to result in the given width due to limitations
* in HTML layout and how GChart works internally.</p>
*
* @param width
* The wanted with of this ChartPanel.
*/
public void setMaxWidth(int width) {
maxWidth = width;
adjustSizeRecursively();
}
/**
* Try to adjust the size of the chartPanel, based on maxWidth and
* maxHeight.
*
* <p>The size will automatically be updated and adjusted in a number of
* iterations. This is needed because the browser must draw the panel before
* its size can be calculated.</p>
*/
private void adjustSizeRecursively() {
resizeRecursions = 0;
forceScrolling = false;
adjustSizeRecursivelySub();
}
/**
* A recursive subprocess started by adjustSizeRecursively. <b>Do not call
* this method directly!</b>
*
* <p>Adjusts the size of the chart based on the chart panel's actual size
* (reported by the browser). Puts the chart in a scrollPanel if the chart
* is too wide.</p>
*
* <p>The method calls itself repeatedly until a correct size has been
* found.</p>
*/
private void adjustSizeRecursivelySub() {
int actualWidth = getOffsetWidth();
int actualHeight = chartContainerPanel.getOffsetHeight() + headerPanel.getOffsetHeight();
int diffWidth = maxWidth - actualWidth;
int diffHeight = maxHeight - actualHeight;
if (chart == null
|| (resizeRecursions != 0 && actualWidth == maxWidth && actualHeight == maxHeight)
|| (resizeRecursions != 0 && diffWidth == 0 && diffHeight == 0)) {
return;
}
chartWidth += diffWidth;
chartWidth = Math.max(0, chartWidth);
chartHeight += diffHeight;
chartHeight = Math.max(0, chartHeight);
if (chartWidth < chart.getMinWidth() || forceScrolling) {
if (!scrolling) {
chartContainerPanel.setWidget(chartScrollPanel);
chartScrollPanel.setWidget(chart);
scrolling = true;
forceScrolling = true;
}
chartScrollPanel.setSize(chartWidth + "px", chartHeight + "px");
chart.setChartSizeSmart(chart.getMinWidth(), chartHeight - 40);
} else if (chartWidth >= chart.getMinWidth()) {
if (scrolling) {
chartContainerPanel.setWidget(chart);
scrolling = false;
}
chart.setChartSizeSmart(chartWidth, chartHeight);
}
resizeRecursions++;
if (resizeRecursions < 10) {
Scheduler.get().scheduleFinally(new ScheduledCommand() {
@Override
public void execute() {
adjustSizeRecursivelySub();
}
});
}
}
}