11 #include <boost/date_time/gregorian/greg_year.hpp>
36 void addHeader(WTable *t,
const char *value) {
37 t->elementAt(0, t->columnCount())->addWidget(
new WText(value));
40 void addEntry(WAbstractItemModel *model,
const char *value) {
41 model->insertRows(model->rowCount(), 1);
42 model->setData(model->rowCount()-1, 0, boost::any(std::string(value)));
45 bool getDouble(WLineEdit *edit,
double& value) {
47 value = WLocale::currentLocale().toDouble(edit->text());
54 int seriesIndexOf(WCartesianChart* chart,
int modelColumn) {
55 for (
unsigned i = 0; i < chart->series().size(); ++i)
56 if (chart->series()[i].modelColumn() == modelColumn)
64 : WContainerWidget(parent),
66 fill_(MinimumValueFill)
68 chart_->setLegendStyle(
chart_->legendFont(), WPen(black),
69 WBrush(WColor(0xFF, 0xFA, 0xE5)));
73 WIntValidator *sizeValidator =
new WIntValidator(200, 2000,
this);
74 sizeValidator->setMandatory(
true);
76 WDoubleValidator *anyNumberValidator =
new WDoubleValidator(
this);
77 anyNumberValidator->setMandatory(
true);
79 WDoubleValidator *angleValidator =
new WDoubleValidator(-90, 90,
this);
80 angleValidator->setMandatory(
true);
84 WStandardItemModel *orientation =
new WStandardItemModel(0, 1,
this);
85 addEntry(orientation,
"Vertical");
86 addEntry(orientation,
"Horizontal");
88 WStandardItemModel *legendLocation =
new WStandardItemModel(0, 1,
this);
89 addEntry(legendLocation,
"Outside");
90 addEntry(legendLocation,
"Inside");
92 WStandardItemModel *legendSide =
new WStandardItemModel(0, 1,
this);
93 addEntry(legendSide,
"Top");
94 addEntry(legendSide,
"Right");
95 addEntry(legendSide,
"Bottom");
96 addEntry(legendSide,
"Left");
98 WStandardItemModel *legendAlignment =
new WStandardItemModel(0, 1,
this);
99 addEntry(legendAlignment,
"AlignLeft");
100 addEntry(legendAlignment,
"AlignCenter");
101 addEntry(legendAlignment,
"AlignRight");
102 addEntry(legendAlignment,
"AlignTop");
103 addEntry(legendAlignment,
"AlignMiddle");
104 addEntry(legendAlignment,
"AlignBottom");
106 WTable *chartConfig =
new WTable();
107 chartConfig->setMargin(WLength::Auto, Left | Right);
110 chartConfig->elementAt(row, 0)->addWidget(
new WText(
"Title:"));
111 titleEdit_ =
new WLineEdit(chartConfig->elementAt(row, 1));
115 chartConfig->elementAt(row, 0)->addWidget(
new WText(
"Width:"));
118 ->setText(WLocale::currentLocale().toString(
chart_->width().value()));
124 chartConfig->elementAt(row, 0)->addWidget(
new WText(
"Height:"));
127 ->setText(WLocale::currentLocale().toString(
chart_->height().value()));
133 chartConfig->elementAt(row, 0)->addWidget(
new WText(
"Orientation:"));
139 chartConfig->elementAt(row, 0)->addWidget(
new WText(
"Legend location:"));
145 chartConfig->elementAt(row, 0)->addWidget(
new WText(
"Legend side:"));
152 chartConfig->elementAt(row, 0)->addWidget(
new WText(
"Legend alignment:"));
159 for (
int i = 0; i < chartConfig->rowCount(); ++i) {
160 chartConfig->elementAt(i, 0)->setStyleClass(
"tdhead");
161 chartConfig->elementAt(i, 1)->setStyleClass(
"tddata");
164 WPanel *p = list->
addWidget(
"Chart properties", chartConfig);
165 p->setMargin(WLength::Auto, Left | Right);
166 p->resize(880, WLength::Auto);
167 p->setMargin(20, Top | Bottom);
171 WStandardItemModel *types =
new WStandardItemModel(0, 1,
this);
172 addEntry(types,
"Points");
173 addEntry(types,
"Line");
174 addEntry(types,
"Curve");
175 addEntry(types,
"Bar");
176 addEntry(types,
"Line Area");
177 addEntry(types,
"Curve Area");
178 addEntry(types,
"Stacked Bar");
179 addEntry(types,
"Stacked Line Area");
180 addEntry(types,
"Stacked Curve Area");
182 WStandardItemModel *markers =
new WStandardItemModel(0, 1,
this);
183 addEntry(markers,
"None");
184 addEntry(markers,
"Square");
185 addEntry(markers,
"Circle");
186 addEntry(markers,
"Cross");
187 addEntry(markers,
"X cross");
188 addEntry(markers,
"Triangle");
189 addEntry(markers,
"Diamond");
191 WStandardItemModel *axes =
new WStandardItemModel(0, 1,
this);
192 addEntry(axes,
"1st Y axis");
193 addEntry(axes,
"2nd Y axis");
195 WStandardItemModel *labels =
new WStandardItemModel(0, 1,
this);
196 addEntry(labels,
"None");
197 addEntry(labels,
"X");
198 addEntry(labels,
"Y");
199 addEntry(labels,
"X: Y");
201 WTable *seriesConfig =
new WTable();
202 seriesConfig->setMargin(WLength::Auto, Left | Right);
204 ::addHeader(seriesConfig,
"Name");
205 ::addHeader(seriesConfig,
"Enabled");
206 ::addHeader(seriesConfig,
"Type");
207 ::addHeader(seriesConfig,
"Marker");
208 ::addHeader(seriesConfig,
"Y axis");
209 ::addHeader(seriesConfig,
"Legend");
210 ::addHeader(seriesConfig,
"Shadow");
211 ::addHeader(seriesConfig,
"Value labels");
213 seriesConfig->rowAt(0)->setStyleClass(
"trhead");
215 for (
int j = 1; j < chart->model()->columnCount(); ++j) {
218 new WText(asString(chart->model()->headerData(j)),
219 seriesConfig->elementAt(j, 0));
221 sc.
enabledEdit =
new WCheckBox(seriesConfig->elementAt(j, 1));
224 sc.
typeEdit =
new WComboBox(seriesConfig->elementAt(j, 2));
228 sc.
markerEdit =
new WComboBox(seriesConfig->elementAt(j, 3));
232 sc.
axisEdit =
new WComboBox(seriesConfig->elementAt(j, 4));
236 sc.
legendEdit =
new WCheckBox(seriesConfig->elementAt(j, 5));
239 sc.
shadowEdit =
new WCheckBox(seriesConfig->elementAt(j, 6));
242 sc.
labelsEdit =
new WComboBox(seriesConfig->elementAt(j, 7));
246 int si = seriesIndexOf(chart, j);
250 const WDataSeries& s =
chart_->series(j);
253 sc.
typeEdit->setCurrentIndex(0);
break;
255 sc.
typeEdit->setCurrentIndex(s.fillRange() != NoFill ?
256 (s.isStacked() ? 7 : 4) : 1);
break;
258 sc.
typeEdit->setCurrentIndex(s.fillRange() != NoFill ?
259 (s.isStacked() ? 8 : 5) : 2);
break;
261 sc.
typeEdit->setCurrentIndex(s.isStacked() ? 6 : 3);
264 sc.
markerEdit->setCurrentIndex((
int)s.marker());
265 sc.
legendEdit->setChecked(s.isLegendEnabled());
266 sc.
shadowEdit->setChecked(s.shadow() != WShadow());
271 seriesConfig->rowAt(j)->setStyleClass(
"trdata");
274 p = list->
addWidget(
"Series properties", seriesConfig);
276 p->setMargin(WLength::Auto, Left | Right);
277 p->resize(880, WLength::Auto);
278 p->setMargin(20, Top | Bottom);
282 WStandardItemModel *yScales =
new WStandardItemModel(0, 1,
this);
283 addEntry(yScales,
"Linear scale");
284 addEntry(yScales,
"Log scale");
286 WStandardItemModel *xScales =
new WStandardItemModel(0, 1,
this);
287 addEntry(xScales,
"Categories");
288 addEntry(xScales,
"Linear scale");
289 addEntry(xScales,
"Log scale");
290 addEntry(xScales,
"Date scale");
292 WTable *axisConfig =
new WTable();
293 axisConfig->setMargin(WLength::Auto, Left | Right);
295 ::addHeader(axisConfig,
"Axis");
296 ::addHeader(axisConfig,
"Visible");
297 ::addHeader(axisConfig,
"Scale");
298 ::addHeader(axisConfig,
"Automatic");
299 ::addHeader(axisConfig,
"Minimum");
300 ::addHeader(axisConfig,
"Maximum");
301 ::addHeader(axisConfig,
"Gridlines");
302 ::addHeader(axisConfig,
"Label angle");
304 axisConfig->rowAt(0)->setStyleClass(
"trhead");
306 for (
int i = 0; i < 3; ++i) {
307 const char *axisName[] = {
"X axis",
"1st Y axis",
"2nd Y axis" };
310 const WAxis& axis =
chart_->axis(static_cast<Axis>(i));
313 new WText(WString(axisName[i], UTF8), axisConfig->elementAt(j, 0));
315 sc.
visibleEdit =
new WCheckBox(axisConfig->elementAt(j, 1));
319 sc.
scaleEdit =
new WComboBox(axisConfig->elementAt(j, 2));
320 if (axis.scale() == CategoryScale)
323 if (axis.id() == XAxis) {
325 sc.
scaleEdit->setCurrentIndex(axis.scale());
328 sc.
scaleEdit->setCurrentIndex(axis.scale() - 1);
333 bool autoValues = axis.autoLimits() == (MinimumValue | MaximumValue);
335 sc.
minimumEdit =
new WLineEdit(axisConfig->elementAt(j, 4));
337 .toString(axis.minimum()));
342 sc.
maximumEdit =
new WLineEdit(axisConfig->elementAt(j, 5));
344 .toString(axis.maximum()));
349 sc.
autoEdit =
new WCheckBox(axisConfig->elementAt(j, 3));
350 sc.
autoEdit->setChecked(autoValues);
357 sc.
gridLinesEdit =
new WCheckBox(axisConfig->elementAt(j, 6));
365 axisConfig->rowAt(j)->setStyleClass(
"trdata");
370 p = list->
addWidget(
"Axis properties", axisConfig);
371 p->setMargin(WLength::Auto, Left | Right);
372 p->resize(880, WLength::Auto);
373 p->setMargin(20, Top | Bottom);
379 if (!WApplication::instance()->environment().javaScript()) {
380 WPushButton *b =
new WPushButton(
this);
381 b->setText(
"Update chart");
383 b->setMargin(WLength::Auto, Left | Right);
395 bool haveLegend =
false;
396 std::vector<WDataSeries> series;
398 for (
int i = 1; i <
chart_->model()->columnCount(); ++i) {
404 switch (sc.
typeEdit->currentIndex()) {
406 s.setType(PointSeries);
411 s.setType(LineSeries);
415 s.setType(CurveSeries);
419 s.setType(BarSeries);
423 s.setType(LineSeries);
424 s.setFillRange(
fill_);
428 s.setType(CurveSeries);
429 s.setFillRange(
fill_);
433 s.setType(BarSeries);
438 s.setType(LineSeries);
439 s.setFillRange(
fill_);
444 s.setType(CurveSeries);
445 s.setFillRange(
fill_);
451 if(sc.
markerEdit->currentIndex() == CustomMarker){
452 WPainterPath pp = WPainterPath();
458 s.setCustomMarker(pp);
461 s.setMarker(static_cast<MarkerType>(sc.
markerEdit->currentIndex()));
463 if (sc.
axisEdit->currentIndex() == 1) {
464 s.bindToAxis(Y2Axis);
468 s.setLegendEnabled(
true);
471 s.setLegendEnabled(
false);
474 s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
476 s.setShadow(WShadow());
480 s.setLabelsEnabled(XAxis);
483 s.setLabelsEnabled(YAxis);
486 s.setLabelsEnabled(XAxis);
487 s.setLabelsEnabled(YAxis);
495 chart_->setSeries(series);
497 for (
int i = 0; i < 3; ++i) {
499 WAxis& axis =
chart_->axis(static_cast<Axis>(i));
505 if (axis.id() != XAxis)
509 chart_->setType(CategoryChart);
511 chart_->setType(ScatterPlot);
516 axis.setScale(LinearScale);
break;
518 axis.setScale(LogScale);
break;
520 axis.setScale(DateScale);
break;
525 axis.setAutoLimits(MinimumValue | MaximumValue);
532 if (axis.scale() == LogScale)
536 if (axis.scale() == DateScale){
538 WDate dMin = WDate(1900,1,1);
539 double gregDaysMin = (double)dMin.toJulianDay();
541 WDate dMax = WDate(3000,1,1);
542 double gregDaysMax = (double)dMax.toJulianDay();
544 bool greg_year_validation =
545 (min > gregDaysMin &&
550 if(!greg_year_validation){
556 axis.setRange(min, max);
564 axis.setLabelAngle(angle);
573 double width, height;
576 chart_->resize(width, height);
581 chart_->setOrientation(Vertical);
break;
583 chart_->setOrientation(Horizontal);
break;
586 chart_->setLegendEnabled(haveLegend);
589 LegendLocation location = LegendOutside;
591 AlignmentFlag alignment = AlignMiddle;
594 case 0: location = LegendOutside;
break;
595 case 1: location = LegendInside;
break;
599 case 0: side = Top;
break;
600 case 1: side = Right;
break;
601 case 2: side = Bottom;
break;
602 case 3: side = Left;
break;
605 if (side == Left || side == Right) {
614 case 0: alignment = AlignLeft;
break;
615 case 1: alignment = AlignCenter;
break;
616 case 2: alignment = AlignRight;
break;
617 case 3: alignment = AlignTop;
break;
618 case 4: alignment = AlignMiddle;
break;
619 case 5: alignment = AlignBottom;
break;
622 chart_->setLegendLocation(location, side, alignment);
624 chart_->setLegendColumns((side == Top || side == Bottom ) ? 2 : 1,
631 bool valid = w->validate() == WValidator::Valid;
633 if (!WApplication::instance()->environment().javaScript()) {
634 w->setStyleClass(valid ?
"" :
"Wt-invalid");
635 w->setToolTip(valid ?
"" :
"Invalid value");
644 if (dynamic_cast<WLineEdit *>(w))
ChartConfig(Wt::Chart::WCartesianChart *chart, Wt::WContainerWidget *parent)
Constructor.
Wt::Chart::FillRangeType fill_
Wt::WComboBox * scaleEdit
Wt::WLineEdit * titleEdit_
Wt::Chart::WCartesianChart * chart_
void connectSignals(Wt::WFormWidget *w)
Wt::WCheckBox * enabledEdit
Struct that holds the controls for one series.
Wt::WCheckBox * visibleEdit
Wt::WComboBox * markerEdit
Wt::WLineEdit * chartWidthEdit_
Struct that holds the controls for one axis.
Wt::WPanel * addWidget(const Wt::WString &text, Wt::WWidget *w)
Wt::WComboBox * chartOrientationEdit_
Wt::WComboBox * legendLocationEdit_
std::vector< SeriesControl > seriesControls_
Controls for series.
Wt::WLineEdit * minimumEdit
Wt::WComboBox * legendSideEdit_
std::vector< AxisControl > axisControls_
Controls for axes.
Wt::WCheckBox * shadowEdit
Wt::WComboBox * labelsEdit
void setValueFill(Wt::Chart::FillRangeType fill)
Wt::WLineEdit * labelAngleEdit
Wt::WCheckBox * legendEdit
Wt::WCheckBox * gridLinesEdit
Wt::WComboBox * legendAlignmentEdit_
Wt::WLineEdit * maximumEdit
static bool validate(Wt::WFormWidget *w)
Wt::WLineEdit * chartHeightEdit_