1 /***************************************************************************
2 File : Graph.cpp
3 Project : QtiPlot
4 --------------------------------------------------------------------
5 Copyright : (C) 2004-2011 by Ion Vasilief
6 Email (use @ for *) : ion_vasilief*yahoo.fr
7 Description : Graph widget
8
9 ***************************************************************************/
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 * This program is distributed in the hope that it will be useful, *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21 * GNU General Public License for more details. *
22 * *
23 * You should have received a copy of the GNU General Public License *
24 * along with this program; if not, write to the Free Software *
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
26 * Boston, MA 02110-1301 USA *
27 * *
28 ***************************************************************************/
29
30 #include <QVarLengthArray>
31 #include <PenStyleBox.h>
32 #include <ScreenPickerTool.h>
33
34 #include "Graph.h"
35 #include "MultiLayer.h"
36 #include "Grid.h"
37 #include "CanvasPicker.h"
38 #include "ErrorBarsCurve.h"
39 #include "TexWidget.h"
40 #include "LegendWidget.h"
41 #include "ArrowMarker.h"
42 #include "ScalePicker.h"
43 #include "TitlePicker.h"
44 #include "PieCurve.h"
45 #include "ImageWidget.h"
46 #include "QwtBarCurve.h"
47 #include "BoxCurve.h"
48 #include "QwtHistogram.h"
49 #include "VectorCurve.h"
50 #include "ScaleDraw.h"
51 #include "FunctionCurve.h"
52 #include "Spectrogram.h"
53 #include "SelectionMoveResizer.h"
54 #include "RangeSelectorTool.h"
55 #include "PlotCurve.h"
56 #include "ApplicationWindow.h"
57 #include "ScaleEngine.h"
58 #include "RectangleWidget.h"
59 #include "EllipseWidget.h"
60 #include <FrameWidget.h>
61 #include <ImageSymbol.h>
62 #include <ImportExportPlugin.h>
63
64 #ifdef TEX_OUTPUT
65 #include <QTeXEngine.h>
66 #endif
67
68 #ifdef Q_OS_WIN
69 #include <windows.h>
70 #endif
71
72 #include <ColorBox.h>
73 #include <PatternBox.h>
74 #include <SymbolBox.h>
75 #include <LinearColorMap.h>
76
77 #include <QApplication>
78 #include <QBitmap>
79 #include <QClipboard>
80 #include <QCursor>
81 #include <QImage>
82 #include <QBuffer>
83 #include <QImageReader>
84 #include <QImageWriter>
85 #include <QMessageBox>
86 #include <QPixmap>
87 #include <QPainter>
88 #include <QPaintEngine>
89 #include <QMenu>
90 #include <QTextStream>
91 #include <QLocale>
92 #include <QPrintDialog>
93 #include <QFileInfo>
94 #include <QSvgGenerator>
95 #include <QDir>
96 #if QT_VERSION >= 0x040500
97 #include <QTextDocumentWriter>
98 #endif
99
100 #include <qwt_painter.h>
101 #include <qwt_plot_canvas.h>
102 #include <qwt_plot_layout.h>
103 #include <qwt_plot_zoomer.h>
104 #include <qwt_plot_magnifier.h>
105 #include <qwt_plot_panner.h>
106 #include <qwt_scale_widget.h>
107 #include <qwt_scale_engine.h>
108 #include <qwt_text_label.h>
109 #include <qwt_curve_fitter.h>
110
111 #include <math.h>
112 #include <stdlib.h>
113 #include <stdio.h>
114 #include <stddef.h>
115
Graph(int x,int y,int width,int height,QWidget * parent,Qt::WFlags f)116 Graph::Graph(int x, int y, int width, int height, QWidget* parent, Qt::WFlags f)
117 : QwtPlot(parent)
118 {
119 setWindowFlags(f);
120 setAttribute(Qt::WA_DeleteOnClose);
121 setAcceptDrops(true);
122
123 d_canvas_bkg_path = QString();
124 d_canvas_bkg_pix = QPixmap();
125
126 d_waterfall_offset_x = 0;
127 d_waterfall_offset_y = 0;
128
129 d_active_tool = NULL;
130 d_image_profiles_tool = NULL;
131 d_range_selector = NULL;
132 d_peak_fit_tool = NULL;
133 d_active_enrichment = NULL;
134 d_selected_arrow = NULL;
135 drawLineOn = false;
136 drawArrowOn = false;
137 drawAxesBackbone = true;
138 d_auto_scale = true;
139 autoScaleFonts = false;
140 d_antialiasing = false;
141 d_is_printing = false;
142 #ifdef TEX_OUTPUT
143 d_is_exporting_tex = false;
144 d_tex_escape_strings = true;
145 #endif
146 d_axis_title_policy = ColComment;
147 d_Douglas_Peuker_tolerance = 0.0;
148 d_speed_mode_points = 3000;
149 d_synchronize_scales = false;
150 d_missing_data_gap = false;
151 d_page_rect = QRectF();
152
153 setGeometry(x, y, width, height);
154 setAutoReplot(false);
155
156 d_min_tick_length = 5;
157 d_maj_tick_length = 9;
158
159 d_axis_titles << "%(?Y)" << "%(?Y)" << "%(?X)" << "";
160 updateAxesTitles();
161
162 // grid
163 d_grid = new Grid();
164 d_grid->attach(this);
165 d_grid->setZ(INT_MIN);
166 d_grid_on_top = false;
167
168 //custom scale
169 d_user_step = QVector<double>(QwtPlot::axisCnt);
170 for (int i = 0; i < QwtPlot::axisCnt; i++){
171 d_user_step[i] = 0.0;
172
173 QwtScaleWidget *scale = (QwtScaleWidget *) axisWidget(i);
174 if (scale){
175 scale->setMargin(0);
176
177 if (i == QwtPlot::yRight)
178 scale->setLayoutFlag(QwtScaleWidget::TitleInverted, false);
179
180 //the axis title color must be initialized...
181 QwtText title = scale->title();
182 title.setColor(Qt::black);
183 scale->setTitle(title);
184
185 //...same for axis color
186 QPalette pal = scale->palette();
187 pal.setColor(QPalette::Foreground, QColor(Qt::black));
188 scale->setPalette(pal);
189
190 ScaleDraw *sd = new ScaleDraw(this);
191 sd->setTickLength(QwtScaleDiv::MinorTick, d_min_tick_length);
192 sd->setTickLength(QwtScaleDiv::MediumTick, d_min_tick_length);
193 sd->setTickLength(QwtScaleDiv::MajorTick, d_maj_tick_length);
194
195 setAxisScaleDraw (i, sd);
196 setAxisScaleEngine (i, new ScaleEngine());
197 }
198 }
199
200 QwtPlotLayout *pLayout = plotLayout();
201 pLayout->setCanvasMargin(0);
202 pLayout->setAlignCanvasToScales (true);
203
204 QwtPlotCanvas* plCanvas = canvas();
205 plCanvas->setFocusPolicy(Qt::StrongFocus);
206 plCanvas->setFocusIndicator(QwtPlotCanvas::ItemFocusIndicator);
207 plCanvas->setFocus();
208 plCanvas->setFrameShadow(QwtPlot::Plain);
209 plCanvas->setCursor(Qt::arrowCursor);
210 plCanvas->setLineWidth(0);
211 plCanvas->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
212 plCanvas->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
213
214 QColor background = QColor(Qt::white);
215 background.setAlpha(255);
216
217 QPalette palette;
218 palette.setColor(QPalette::Window, background);
219 setPalette(palette);
220
221 setCanvasBackground (background);
222 setFocusPolicy(Qt::StrongFocus);
223 setFocusProxy(plCanvas);
224 setFrameShape(QFrame::Box);
225 setLineWidth(0);
226 setMouseTracking(true);
227
228 cp = new CanvasPicker(this);
229
230 titlePicker = new TitlePicker(this);
231 scalePicker = new ScalePicker(this);
232
233 d_zoomer[0]= new QwtPlotZoomer(QwtPlot::xBottom, QwtPlot::yLeft,
234 QwtPicker::DragSelection | QwtPicker::CornerToCorner, QwtPicker::AlwaysOff, canvas());
235 d_zoomer[0]->setRubberBandPen(QPen(Qt::black));
236 d_zoomer[1] = new QwtPlotZoomer(QwtPlot::xTop, QwtPlot::yRight,
237 QwtPicker::DragSelection | QwtPicker::CornerToCorner,
238 QwtPicker::AlwaysOff, canvas());
239 zoom(false);
240
241 d_magnifier = NULL;
242 d_panner = NULL;
243
244 connect (cp,SIGNAL(viewLineDialog()),this,SIGNAL(viewLineDialog()));
245 connect (cp,SIGNAL(showPlotDialog(int)),this,SIGNAL(showPlotDialog(int)));
246 connect (cp,SIGNAL(showMarkerPopupMenu()),this,SIGNAL(showMarkerPopupMenu()));
247 connect (cp,SIGNAL(modified()), this, SIGNAL(modifiedGraph()));
248
249 connect (titlePicker,SIGNAL(showTitleMenu()),this,SLOT(showTitleContextMenu()));
250 connect (titlePicker,SIGNAL(doubleClicked()),this, SLOT(enableTextEditor()));
251 connect (titlePicker,SIGNAL(removeTitle()),this,SLOT(removeTitle()));
252 connect (titlePicker,SIGNAL(clicked()), this,SLOT(selectTitle()));
253
254 connect (scalePicker,SIGNAL(clicked()),this,SLOT(activateGraph()));
255 connect (scalePicker,SIGNAL(clicked()),this,SLOT(deselectMarker()));
256 connect (scalePicker,SIGNAL(axisDblClicked(int)),this,SIGNAL(axisDblClicked(int)));
257 connect (scalePicker,SIGNAL(axisTicksDblClicked(int)),this,SIGNAL(showAxisDialog(int)));
258 connect (scalePicker, SIGNAL(axisTitleDblClicked()), this, SLOT(enableTextEditor()));
259 connect (scalePicker,SIGNAL(axisTitleRightClicked()),this,SLOT(showAxisTitleMenu()));
260 connect (scalePicker,SIGNAL(axisRightClicked(int)),this,SLOT(showAxisContextMenu(int)));
261
262 connect (d_zoomer[0],SIGNAL(zoomed (const QwtDoubleRect &)),this,SLOT(zoomed (const QwtDoubleRect &)));
263 }
264
multiLayer() const265 MultiLayer* Graph::multiLayer() const
266 {
267 if (!parent())
268 return NULL;
269
270 return (MultiLayer *)(this->parent()->parent()->parent());
271 }
272
notifyChanges()273 void Graph::notifyChanges()
274 {
275 emit modifiedGraph();
276 }
277
selectCanvas()278 void Graph::selectCanvas()
279 {
280 selectedCanvas(this);
281 setFocus();
282 }
283
activateGraph()284 void Graph::activateGraph()
285 {
286 emit selectedGraph(this);
287 setFocus();
288 }
289
deselectMarker()290 void Graph::deselectMarker()
291 {
292 if (d_selected_arrow && d_lines.contains(d_selected_arrow))
293 d_selected_arrow->setEditable(false);
294
295 deselect(d_active_enrichment);
296 d_active_enrichment = NULL;
297 d_selected_arrow = NULL;
298
299 if (d_markers_selector){
300 delete d_markers_selector;
301 d_markers_selector = NULL;
302 }
303
304 emit enableTextEditor(NULL);
305
306 cp->disableEditing();
307 setFocus();
308 }
309
enableTextEditor()310 void Graph::enableTextEditor()
311 {
312 ApplicationWindow *app = multiLayer()->applicationWindow();
313 if (!app)
314 return;
315
316 if (app->d_in_place_editing)
317 emit enableTextEditor(this);
318 else if (titlePicker->selected())
319 viewTitleDialog();
320 else
321 showAxisTitleDialog();
322 }
323
textsList()324 QList <LegendWidget *> Graph::textsList()
325 {
326 QList <LegendWidget *> texts;
327 foreach(FrameWidget *f, d_enrichments){
328 LegendWidget *l = qobject_cast<LegendWidget *>(f);
329 if (l)
330 texts << l;
331 }
332 return texts;
333 }
334
areaLessThan(FrameWidget * fw1,FrameWidget * fw2)335 bool areaLessThan(FrameWidget* fw1, FrameWidget* fw2)
336 {
337 return fw1->width()*fw1->height() < fw2->width()*fw2->height();
338 }
339
increasingAreaEnrichmentsList()340 QList <FrameWidget *> Graph::increasingAreaEnrichmentsList()
341 {
342 int size = d_enrichments.size();
343 if (size < 2)
344 return d_enrichments;
345
346 QList <FrameWidget *> lst;
347 foreach(FrameWidget *f, d_enrichments)
348 lst << f;
349
350 qSort(lst.begin(), lst.end(), areaLessThan);
351
352 return lst;
353 }
354
selectorDeleted()355 void Graph::selectorDeleted()
356 {
357 d_markers_selector = NULL;
358 selectionChanged(NULL);
359 }
360
select(QWidget * l,bool add)361 void Graph::select(QWidget *l, bool add)
362 {
363 if (!l){
364 d_active_enrichment = NULL;
365 selectionChanged(NULL);
366 return;
367 }
368
369 selectTitle(false);
370 scalePicker->deselect();
371 deselectCurves();
372
373 d_active_enrichment = qobject_cast<LegendWidget *>(l);
374 if (d_active_enrichment){
375 currentFontChanged(((LegendWidget *)l)->font());
376 currentColorChanged(((LegendWidget *)l)->textColor());
377 } else
378 d_active_enrichment = qobject_cast<FrameWidget *>(l);
379
380 if (add){
381 if (d_markers_selector && d_markers_selector->contains(l))
382 return;
383 else if (d_markers_selector)
384 d_markers_selector->add(l);
385 else {
386 d_markers_selector = new SelectionMoveResizer(l);
387 connect(d_markers_selector, SIGNAL(targetsChanged()), this, SIGNAL(modifiedGraph()));
388 connect(d_markers_selector, SIGNAL(destroyed(QObject*)), this, SLOT(selectorDeleted()));
389 }
390 } else {
391 if (d_markers_selector)
392 delete d_markers_selector;
393
394 d_markers_selector = new SelectionMoveResizer(l);
395 connect(d_markers_selector, SIGNAL(targetsChanged()), this, SIGNAL(modifiedGraph()));
396 connect(d_markers_selector, SIGNAL(destroyed(QObject*)), this, SLOT(selectorDeleted()));
397 }
398
399 selectionChanged(d_markers_selector);
400 }
401
hasSeletedItems()402 bool Graph::hasSeletedItems()
403 {
404 if (d_markers_selector || titlePicker->selected() || scalePicker->selectedAxis())
405 return true;
406 return false;
407 }
408
deselect(QWidget * l)409 void Graph::deselect(QWidget *l)
410 {
411 if(!l)
412 return;
413
414 if (d_markers_selector && d_markers_selector->contains(l))
415 d_markers_selector->removeAll(l);
416 }
417
setSelectedArrow(ArrowMarker * mrk,bool add)418 void Graph::setSelectedArrow(ArrowMarker *mrk, bool add)
419 {
420 if (!mrk)
421 return;
422
423 selectTitle(false);
424 scalePicker->deselect();
425
426 d_selected_arrow = mrk;
427 if (add){
428 if (d_markers_selector){
429 if (d_lines.contains(mrk))
430 d_markers_selector->add(mrk);
431 else
432 return;
433 } else {
434 if (d_lines.contains(mrk))
435 d_markers_selector = new SelectionMoveResizer(mrk);
436 else
437 return;
438 connect(d_markers_selector, SIGNAL(targetsChanged()), this, SIGNAL(modifiedGraph()));
439 }
440 } else {
441 if (d_lines.contains(mrk)){
442 if (mrk->editable()){
443 if (d_markers_selector)
444 delete d_markers_selector;
445 return;
446 }
447
448 if (d_markers_selector && d_markers_selector->contains(mrk))
449 return;
450 else
451 d_markers_selector = new SelectionMoveResizer(mrk);
452 } else
453 return;
454 connect(d_markers_selector, SIGNAL(targetsChanged()), this, SIGNAL(modifiedGraph()));
455 }
456 }
457
initFonts(const QFont & scaleTitleFnt,const QFont & numbersFnt)458 void Graph::initFonts(const QFont &scaleTitleFnt, const QFont &numbersFnt)
459 {
460 for (int i = 0; i<QwtPlot::axisCnt; i++){
461 setAxisFont (i,numbersFnt);
462 QwtText t = axisTitle (i);
463 t.setFont (scaleTitleFnt);
464 ((QwtPlot *)this)->setAxisTitle(i, t);
465 }
466 }
467
setAxisFont(int axis,const QFont & fnt)468 void Graph::setAxisFont(int axis, const QFont &fnt)
469 {
470 ((QwtPlot *)this)->setAxisFont (axis, fnt);
471 replot();
472 emit modifiedGraph();
473 }
474
enableAxis(int axis,bool on)475 void Graph::enableAxis(int axis, bool on)
476 {
477 ((QwtPlot *)this)->enableAxis(axis, on);
478 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
479 if (scale)
480 scale->setMargin(0);
481
482 scalePicker->refresh();
483 }
484
setAxisMargin(int axis,int margin)485 void Graph::setAxisMargin(int axis, int margin)
486 {
487 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
488 if (scale)
489 scale->setMargin(margin);
490 }
491
axisType(int axis)492 ScaleDraw::ScaleType Graph::axisType(int axis)
493 {
494 if (!axisEnabled(axis))
495 return ScaleDraw::Numeric;
496
497 return ((ScaleDraw *)axisScaleDraw(axis))->scaleType();
498 }
499
setLabelsNumericFormat(int axis,int format,int prec,const QString & formula)500 void Graph::setLabelsNumericFormat(int axis, int format, int prec, const QString& formula)
501 {
502 ScaleDraw *sd = new ScaleDraw(this, formula.ascii());
503 sd->setNumericFormat((ScaleDraw::NumericFormat)format);
504 sd->setNumericPrecision(prec);
505 sd->setScaleDiv(axisScaleDraw(axis)->scaleDiv());
506 setAxisScaleDraw (axis, sd);
507 }
508
setLabelsNumericFormat(const QStringList & l)509 void Graph::setLabelsNumericFormat(const QStringList& l)
510 {
511 for (int axis = 0; axis<4; axis++){
512 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
513 if (!sd || !sd->hasComponent(QwtAbstractScaleDraw::Labels))
514 continue;
515
516 int aux = 2*axis;
517 setLabelsNumericFormat(axis, l[aux].toInt(), l[aux + 1].toInt(), sd->formula());
518 }
519 }
520
saveAxesLabelsType()521 QString Graph::saveAxesLabelsType()
522 {
523 QString s = "AxisType\t";
524 for (int i = 0; i < 4; i++){
525 if (!axisEnabled(i)){
526 s += QString::number((int)ScaleDraw::Numeric) + "\t";
527 continue;
528 }
529
530 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(i);
531 int type = (int) sd->scaleType();
532 s += QString::number(type);
533 if (type == ScaleDraw::Time || type == ScaleDraw::Date || type == ScaleDraw::Text ||
534 type == ScaleDraw::ColHeader || type == ScaleDraw::Day || type == ScaleDraw::Month)
535 s += ";" + sd->formatString();
536 s += "\t";
537 }
538 return s+"\n";
539 }
540
saveTicksType()541 QString Graph::saveTicksType()
542 {
543 QList<int> ticksTypeList = getMajorTicksType();
544 QString s = "MajorTicks";
545 for (int i = 0; i < 4; i++)
546 s += "\t" + QString::number(ticksTypeList[i]);
547 s += "\n";
548
549 ticksTypeList = getMinorTicksType();
550 s += "MinorTicks";
551 for (int i = 0; i < 4; i++)
552 s += "\t" + QString::number(ticksTypeList[i]);
553
554 return s + "\n";
555 }
556
saveEnabledTickLabels()557 QString Graph::saveEnabledTickLabels()
558 {
559 QString s = "EnabledTickLabels";
560 for (int axis = 0; axis < QwtPlot::axisCnt; axis++){
561 const QwtScaleDraw *sd = axisScaleDraw (axis);
562 s += "\t" + QString::number(sd->hasComponent(QwtAbstractScaleDraw::Labels));
563 }
564 return s + "\n";
565 }
566
saveLabelsFormat()567 QString Graph::saveLabelsFormat()
568 {
569 QString s = "LabelsFormat";
570 for (int axis = 0; axis < QwtPlot::axisCnt; axis++){
571 s += "\t" + QString::number(axisLabelFormat(axis));
572 s += "\t" + QString::number(axisLabelPrecision(axis));
573 }
574 return s + "\n";
575 }
576
saveAxesBaseline()577 QString Graph::saveAxesBaseline()
578 {
579 QString s = "AxesBaseline\t";
580 for (int i = 0; i<QwtPlot::axisCnt; i++){
581 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(i);
582 if (scale)
583 s += QString::number(scale->margin()) + "\t";
584 else
585 s += "0\t";
586 }
587 return s + "\n";
588 }
589
saveAxesBackbones()590 QString Graph::saveAxesBackbones()
591 {
592 QString s = "DrawAxesBackbone\t" + QString::number(drawAxesBackbone);
593 for (int i = 0; i < QwtPlot::axisCnt; i++){
594 const QwtScaleDraw *sd = axisScaleDraw (i);
595 s += "\t" + QString::number(sd->hasComponent(QwtAbstractScaleDraw::Backbone));
596 }
597 return s + "\n";
598 }
599
saveTickLabelsSpace()600 QString Graph::saveTickLabelsSpace()
601 {
602 QString s = "TickLabelsSpace";
603 for (int i = 0; i < QwtPlot::axisCnt; i++){
604 const QwtScaleDraw *sd = axisScaleDraw (i);
605 s += "\t" + QString::number(sd->spacing());
606 }
607 s += "\n";
608
609 s += "ShowTicksPolicy";
610 for (int axis = 0; axis < QwtPlot::axisCnt; axis++){
611 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
612 s += "\t" + QString::number(sd->showTicksPolicy());
613 }
614 return s + "\n";
615 }
616
saveLabelsPrefixAndSuffix()617 QString Graph::saveLabelsPrefixAndSuffix()
618 {
619 QString s = "LabelsPrefix";
620 for (int i = 0; i < QwtPlot::axisCnt; i++){
621 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (i);
622 s += "\t" + sd->prefix();
623 }
624 s += "\n";
625
626 s += "LabelsSuffix";
627 for (int axis = 0; axis < QwtPlot::axisCnt; axis++){
628 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
629 s += "\t" + sd->suffix();
630 }
631 return s + "\n";
632 }
633
saveLabelsRotation()634 QString Graph::saveLabelsRotation()
635 {
636 QString s = "LabelsRotation\t";
637 s += QString::number(labelsRotation(QwtPlot::xBottom)) + "\t";
638 s += QString::number(labelsRotation(QwtPlot::xTop)) + "\t";
639 s += QString::number(labelsRotation(QwtPlot::yLeft)) + "\t";
640 s += QString::number(labelsRotation(QwtPlot::yRight)) + "\n";
641 return s;
642 }
643
enableAxisLabels(int axis,bool on)644 void Graph::enableAxisLabels(int axis, bool on)
645 {
646 QwtScaleWidget *sc = axisWidget(axis);
647 if (sc){
648 QwtScaleDraw *sd = axisScaleDraw (axis);
649 sd->enableComponent (QwtAbstractScaleDraw::Labels, on);
650 }
651 }
652
setMajorTicksType(const QList<int> & lst)653 void Graph::setMajorTicksType(const QList<int>& lst)
654 {
655 if (getMajorTicksType() == lst)
656 return;
657
658 for (int i=0;i<(int)lst.count();i++)
659 {
660 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (i);
661 if (lst[i]==ScaleDraw::None || lst[i]==ScaleDraw::In)
662 sd->enableComponent (QwtAbstractScaleDraw::Ticks, false);
663 else
664 {
665 sd->enableComponent (QwtAbstractScaleDraw::Ticks);
666 sd->setTickLength (QwtScaleDiv::MinorTick, minorTickLength());
667 sd->setTickLength (QwtScaleDiv::MediumTick, minorTickLength());
668 sd->setTickLength (QwtScaleDiv::MajorTick, majorTickLength());
669 }
670 sd->setMajorTicksStyle((ScaleDraw::TicksStyle)lst[i]);
671 }
672 }
673
setMajorTicksType(const QStringList & lst)674 void Graph::setMajorTicksType(const QStringList& lst)
675 {
676 for (int i=0; i<(int)lst.count(); i++)
677 setMajorTicksType(i, lst[i].toInt());
678 }
679
setMinorTicksType(const QList<int> & lst)680 void Graph::setMinorTicksType(const QList<int>& lst)
681 {
682 if (getMinorTicksType() == lst)
683 return;
684
685 for (int i=0;i<(int)lst.count();i++)
686 setMinorTicksType(i, lst[i]);
687 }
688
setMinorTicksType(const QStringList & lst)689 void Graph::setMinorTicksType(const QStringList& lst)
690 {
691 for (int i=0;i<(int)lst.count();i++)
692 setMinorTicksType(i,lst[i].toInt());
693 }
694
setAxisTicksLength(int axis,int majTicksType,int minTicksType,int minLength,int majLength)695 void Graph::setAxisTicksLength(int axis, int majTicksType, int minTicksType,
696 int minLength, int majLength)
697 {
698 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
699 if (!scale)
700 return;
701
702 setTickLength(minLength, majLength);
703
704 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
705 sd->setMajorTicksStyle((ScaleDraw::TicksStyle)majTicksType);
706 sd->setMinorTicksStyle((ScaleDraw::TicksStyle)minTicksType);
707
708 if (majTicksType == ScaleDraw::None && minTicksType == ScaleDraw::None)
709 sd->enableComponent (QwtAbstractScaleDraw::Ticks, false);
710 else
711 sd->enableComponent (QwtAbstractScaleDraw::Ticks);
712
713 if (majTicksType == ScaleDraw::None || majTicksType == ScaleDraw::In)
714 majLength = 1;
715 if (minTicksType == ScaleDraw::None || minTicksType == ScaleDraw::In)
716 minLength = 0;
717
718 sd->setTickLength (QwtScaleDiv::MinorTick, minLength);
719 sd->setTickLength (QwtScaleDiv::MediumTick, minLength);
720 sd->setTickLength (QwtScaleDiv::MajorTick, majLength);
721 }
722
setTicksLength(int minLength,int majLength)723 void Graph::setTicksLength(int minLength, int majLength)
724 {
725 QList<int> majTicksType = getMajorTicksType();
726 QList<int> minTicksType = getMinorTicksType();
727
728 for (int i=0; i<4; i++)
729 setAxisTicksLength (i, majTicksType[i], minTicksType[i], minLength, majLength);
730 }
731
changeTicksLength(int minLength,int majLength)732 void Graph::changeTicksLength(int minLength, int majLength)
733 {
734 if (minorTickLength() == minLength && majorTickLength() == majLength)
735 return;
736
737 setTicksLength(minLength, majLength);
738
739 hide();
740 for (int i = 0; i < 4; i++){
741 if (axisEnabled(i)){
742 enableAxis (i,false);
743 enableAxis (i,true);
744 }
745 }
746 replot();
747 show();
748
749 emit modifiedGraph();
750 }
751
showAxis(int axis,int type,const QString & formatInfo,Table * table,bool axisOn,int majTicksType,int minTicksType,bool labelsOn,const QColor & c,int format,int prec,int rotation,int baselineDist,const QString & formula,const QColor & labelsColor,int spacing,bool backbone,const ScaleDraw::ShowTicksPolicy & showTicks,const QString & prefix,const QString & suffix)752 void Graph::showAxis(int axis, int type, const QString& formatInfo, Table *table,
753 bool axisOn, int majTicksType, int minTicksType, bool labelsOn,
754 const QColor& c, int format, int prec, int rotation, int baselineDist,
755 const QString& formula, const QColor& labelsColor, int spacing, bool backbone,
756 const ScaleDraw::ShowTicksPolicy& showTicks, const QString& prefix, const QString& suffix)
757 {
758 enableAxis(axis, axisOn);
759 if (!axisOn)
760 return;
761
762 QList<int> majTicksTypeList = getMajorTicksType();
763 QList<int> minTicksTypeList = getMinorTicksType();
764
765 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
766 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
767
768 if (axisEnabled (axis) == axisOn &&
769 majTicksTypeList[axis] == majTicksType &&
770 minTicksTypeList[axis] == minTicksType &&
771 axisColor(axis) == c &&
772 axisLabelsColor(axis) == labelsColor &&
773 prec == axisLabelPrecision (axis) &&
774 format == axisLabelFormat (axis) &&
775 labelsRotation(axis) == rotation &&
776 (int)sd->scaleType() == type &&
777 sd->formatString() == formatInfo &&
778 sd->formula() == formula &&
779 scale->margin() == baselineDist &&
780 sd->hasComponent(QwtAbstractScaleDraw::Labels) == labelsOn &&
781 sd->spacing() == spacing &&
782 sd->hasComponent(QwtAbstractScaleDraw::Backbone) == backbone &&
783 sd->showTicksPolicy() == showTicks &&
784 sd->prefix() == prefix && sd->suffix() == suffix)
785 return;
786
787 scale->setMargin(baselineDist);
788 QPalette pal = scale->palette();
789 if (pal.color(QPalette::Active, QColorGroup::Foreground) != c)
790 pal.setColor(QColorGroup::Foreground, c);
791 if (pal.color(QPalette::Active, QColorGroup::Text) != labelsColor)
792 pal.setColor(QColorGroup::Text, labelsColor);
793 scale->setPalette(pal);
794
795 if (axis == yLeft && d_grid->xZeroLineMarker()){
796 QPen pen = d_grid->xZeroLineMarker()->linePen();
797 pen.setColor(c);
798 d_grid->xZeroLineMarker()->setLinePen(pen);
799 } else if (axis == xBottom && d_grid->yZeroLineMarker()){
800 QPen pen = d_grid->yZeroLineMarker()->linePen();
801 pen.setColor(c);
802 d_grid->yZeroLineMarker()->setLinePen(pen);
803 }
804
805 if (!labelsOn)
806 sd->enableComponent (QwtAbstractScaleDraw::Labels, false);
807 else {
808 if (type == ScaleDraw::Numeric)
809 setLabelsNumericFormat(axis, format, prec, formula);
810 else if (type == ScaleDraw::Day)
811 setLabelsDayFormat (axis, format);
812 else if (type == ScaleDraw::Month)
813 setLabelsMonthFormat (axis, format);
814 else if (type == ScaleDraw::Time || type == ScaleDraw::Date)
815 setLabelsDateTimeFormat (axis, type, formatInfo);
816 else
817 setLabelsTextFormat(axis, type, formatInfo, table);
818
819 setAxisLabelRotation(axis, rotation);
820 }
821
822 sd = (ScaleDraw *)axisScaleDraw (axis);
823 sd->enableComponent(QwtAbstractScaleDraw::Backbone, backbone);
824 sd->setSpacing(spacing);
825 sd->setShowTicksPolicy(showTicks);
826 sd->setPrefix(prefix);
827 sd->setSuffix(suffix);
828
829 setAxisTicksLength(axis, majTicksType, minTicksType, minorTickLength(), majorTickLength());
830
831 if (d_synchronize_scales && axisOn && (axis == QwtPlot::xTop || axis == QwtPlot::yRight))
832 updateSecondaryAxis(axis);//synchronize scale divisions
833
834 scalePicker->refresh();
835 updateLayout(); //This is necessary in order to enable/disable tick labels
836 scale->repaint();
837 replot();
838 emit modifiedGraph();
839 }
840
setLabelsDayFormat(int axis,int format)841 void Graph::setLabelsDayFormat(int axis, int format)
842 {
843 ScaleDraw *sd = new ScaleDraw(this);
844 sd->setDayFormat((ScaleDraw::NameFormat)format);
845 sd->setScaleDiv(axisScaleDraw(axis)->scaleDiv());
846 setAxisScaleDraw (axis, sd);
847 }
848
setLabelsMonthFormat(int axis,int format)849 void Graph::setLabelsMonthFormat(int axis, int format)
850 {
851 ScaleDraw *sd = new ScaleDraw(this);
852 sd->setMonthFormat((ScaleDraw::NameFormat)format);
853 sd->setScaleDiv(axisScaleDraw(axis)->scaleDiv());
854 setAxisScaleDraw (axis, sd);
855 }
856
setLabelsTextFormat(int axis,int type,const QString & name,const QStringList & lst)857 void Graph::setLabelsTextFormat(int axis, int type, const QString& name, const QStringList& lst)
858 {
859 if (type != ScaleDraw::Text && type != ScaleDraw::ColHeader)
860 return;
861
862 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(axis);
863 if (sd && sd->scaleType() == type && sd->labelsList() == lst && sd->formatString() == name)
864 return;
865
866 setAxisScaleDraw(axis, new ScaleDraw(this, lst, name, (ScaleDraw::ScaleType)type));
867 }
868
setLabelsTextFormat(int axis,int type,const QString & labelsColName,Table * table)869 void Graph::setLabelsTextFormat(int axis, int type, const QString& labelsColName, Table *table)
870 {
871 if (type != ScaleDraw::Text && type != ScaleDraw::ColHeader)
872 return;
873
874 QStringList list = QStringList();
875 if (type == ScaleDraw::Text){
876 if (!table)
877 return;
878
879 int r = table->numRows();
880 int col = table->colIndex(labelsColName);
881 for (int i=0; i < r; i++){
882 QString s = table->text(i, col);
883 if (!s.isEmpty())
884 list << s;
885 }
886 setAxisScaleDraw(axis, new ScaleDraw(this, list, labelsColName, ScaleDraw::Text));
887 } else if (type == ScaleDraw::ColHeader) {
888 if (!table)
889 return;
890
891 for (int i=0; i<table->numCols(); i++){
892 if (table->colPlotDesignation(i) == Table::Y)
893 list << table->colLabel(i);
894 }
895 setAxisScaleDraw(axis, new ScaleDraw(this, list, table->objectName(), ScaleDraw::ColHeader));
896 }
897 }
898
setLabelsDateTimeFormat(int axis,int type,const QString & formatInfo)899 void Graph::setLabelsDateTimeFormat(int axis, int type, const QString& formatInfo)
900 {
901 if (type < ScaleDraw::Time)
902 return;
903
904 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(axis);
905 if (sd->scaleType() == type && sd->formatString() == formatInfo)
906 return;
907
908 ScaleDraw *nsd = 0;
909 if (sd->scaleType() == type)
910 nsd = new ScaleDraw(this, sd);
911 else
912 nsd = new ScaleDraw(this);
913
914 if (type == ScaleDraw::Time)
915 nsd->setTimeFormat(formatInfo);
916 else if (type == ScaleDraw::Date)
917 nsd->setDateFormat(formatInfo);
918
919 nsd->enableComponent (QwtAbstractScaleDraw::Backbone, drawAxesBackbone);
920 setAxisScaleDraw (axis, nsd);
921 }
922
recoverObsoleteDateTimeScale(int axis,int type,const QString & origin,const QString & format)923 void Graph::recoverObsoleteDateTimeScale(int axis, int type, const QString& origin, const QString& format)
924 {
925 QwtScaleDiv *div = this->axisScaleDiv(axis);
926 double start = div->lowerBound();
927 double end = div->upperBound();
928 double step = d_user_step[axis];
929 double newStep = 0.0;
930 if (type == ScaleDraw::Date){
931 QDateTime dt = QDateTime::fromString(origin, Qt::ISODate);
932 if (dt.isNull())
933 dt = QDateTime::fromString(origin, format);
934 QDateTime sdt = dt.addSecs(int(start));
935 QDateTime edt = dt.addSecs(int(end));
936 if (step != 0.0)
937 newStep = step/864.0e2;
938 setAxisScale(axis, Table::fromDateTime(sdt), Table::fromDateTime(edt), newStep);
939 } else if (type == ScaleDraw::Time){
940 QTime t = QTime::fromString(origin, Qt::ISODate);
941 QTime st = t.addMSecs(int(start));
942 QTime et = t.addMSecs(int(end));
943 if (step != 0.0)
944 newStep = step/864.0e5;
945 setAxisScale(axis, Table::fromTime(st), Table::fromTime(et), newStep);
946 }
947 d_user_step[axis] = newStep;
948 }
949
setAxisLabelRotation(int axis,int rotation)950 void Graph::setAxisLabelRotation(int axis, int rotation)
951 {
952 if (axis == QwtPlot::xBottom){
953 if (rotation > 0)
954 setAxisLabelAlignment(axis, Qt::AlignRight|Qt::AlignVCenter);
955 else if (rotation < 0)
956 setAxisLabelAlignment(axis, Qt::AlignLeft|Qt::AlignVCenter);
957 else if (rotation == 0)
958 setAxisLabelAlignment(axis, Qt::AlignHCenter|Qt::AlignBottom);
959 } else if (axis == QwtPlot::xTop){
960 if (rotation > 0)
961 setAxisLabelAlignment(axis, Qt::AlignLeft|Qt::AlignVCenter);
962 else if (rotation < 0)
963 setAxisLabelAlignment(axis, Qt::AlignRight|Qt::AlignVCenter);
964 else if (rotation == 0)
965 setAxisLabelAlignment(axis, Qt::AlignHCenter|Qt::AlignTop);
966 }
967 ((QwtPlot *)this)->setAxisLabelRotation (axis, rotation);
968 }
969
labelsRotation(int axis)970 int Graph::labelsRotation(int axis)
971 {
972 ScaleDraw *sclDraw = (ScaleDraw *)axisScaleDraw (axis);
973 return (int)sclDraw->labelRotation();
974 }
975
setAxisTitleFont(int axis,const QFont & fnt)976 void Graph::setAxisTitleFont(int axis,const QFont &fnt)
977 {
978 QwtText t = axisTitle (axis);
979 t.setFont (fnt);
980 ((QwtPlot *)this)->setAxisTitle(axis, t);
981 replot();
982 emit modifiedGraph();
983 }
984
axisTitleFont(int axis)985 QFont Graph::axisTitleFont(int axis)
986 {
987 return axisTitle(axis).font();
988 }
989
axisTitleColor(int axis)990 QColor Graph::axisTitleColor(int axis)
991 {
992 QColor c;
993 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
994 if (scale)
995 c = scale->title().color();
996 return c;
997 }
998
setAxisLabelsColor(int axis,const QColor & color)999 void Graph::setAxisLabelsColor(int axis, const QColor& color)
1000 {
1001 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
1002 if (scale){
1003 QPalette pal = scale->palette();
1004 pal.setColor(QColorGroup::Text, color);
1005 scale->setPalette(pal);
1006 }
1007 }
1008
setAxisColor(int axis,const QColor & color)1009 void Graph::setAxisColor(int axis, const QColor& color)
1010 {
1011 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
1012 if (!scale)
1013 return;
1014
1015 QPalette pal = scale->palette();
1016 pal.setColor(QColorGroup::Foreground, color);
1017 scale->setPalette(pal);
1018
1019 if (axis == yLeft && d_grid->xZeroLineMarker()){
1020 QPen pen = d_grid->xZeroLineMarker()->linePen();
1021 pen.setColor(color);
1022 d_grid->xZeroLineMarker()->setLinePen(pen);
1023 } else if (axis == xBottom && d_grid->yZeroLineMarker()){
1024 QPen pen = d_grid->yZeroLineMarker()->linePen();
1025 pen.setColor(color);
1026 d_grid->yZeroLineMarker()->setLinePen(pen);
1027 }
1028 }
1029
saveAxesColors()1030 QString Graph::saveAxesColors()
1031 {
1032 QString s="AxesColors\t";
1033 QStringList colors, numColors;
1034 QPalette pal;
1035 int i;
1036 for (i=0;i<4;i++)
1037 {
1038 colors<<QColor(Qt::black).name();
1039 numColors<<QColor(Qt::black).name();
1040 }
1041
1042 for (i=0;i<4;i++)
1043 {
1044 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(i);
1045 if (scale)
1046 {
1047 pal=scale->palette();
1048 colors[i]=pal.color(QPalette::Active, QColorGroup::Foreground).name();
1049 numColors[i]=pal.color(QPalette::Active, QColorGroup::Text).name();
1050 }
1051 }
1052 s+=colors.join ("\t")+"\n";
1053 s+="AxesNumberColors\t"+numColors.join ("\t")+"\n";
1054 return s;
1055 }
1056
axisColor(int axis)1057 QColor Graph::axisColor(int axis)
1058 {
1059 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
1060 if (scale)
1061 return scale->palette().color(QPalette::Active, QColorGroup::Foreground);
1062 else
1063 return QColor(Qt::black);
1064 }
1065
axisLabelsColor(int axis)1066 QColor Graph::axisLabelsColor(int axis)
1067 {
1068 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
1069 if (scale)
1070 return scale->palette().color(QPalette::Active, QColorGroup::Text);
1071 else
1072 return QColor(Qt::black);
1073 }
1074
setTitleColor(const QColor & c)1075 void Graph::setTitleColor(const QColor & c)
1076 {
1077 QwtText t = title();
1078 t.setColor(c);
1079 setTitle(t);
1080 replot();
1081 emit modifiedGraph();
1082 }
1083
setTitleAlignment(int align)1084 void Graph::setTitleAlignment(int align)
1085 {
1086 QwtText t = title();
1087 t.setRenderFlags(align);
1088 setTitle(t);
1089 replot();
1090 emit modifiedGraph();
1091 }
1092
setTitleFont(const QFont & fnt)1093 void Graph::setTitleFont(const QFont &fnt)
1094 {
1095 QwtText t = title();
1096 t.setFont(fnt);
1097 setTitle(t);
1098 replot();
1099 emit modifiedGraph();
1100 }
1101
setYAxisTitle(const QString & text)1102 void Graph::setYAxisTitle(const QString& text)
1103 {
1104 setAxisTitle(QwtPlot::yLeft, text);
1105 replot();
1106 emit modifiedGraph();
1107 }
1108
setXAxisTitle(const QString & text)1109 void Graph::setXAxisTitle(const QString& text)
1110 {
1111 setAxisTitle(QwtPlot::xBottom, text);
1112 replot();
1113 emit modifiedGraph();
1114 }
1115
setRightAxisTitle(const QString & text)1116 void Graph::setRightAxisTitle(const QString& text)
1117 {
1118 setAxisTitle(QwtPlot::yRight, text);
1119 replot();
1120 emit modifiedGraph();
1121 }
1122
setTopAxisTitle(const QString & text)1123 void Graph::setTopAxisTitle(const QString& text)
1124 {
1125 setAxisTitle(QwtPlot::xTop, text);
1126 replot();
1127 emit modifiedGraph();
1128 }
1129
axisTitleAlignment(int axis)1130 int Graph::axisTitleAlignment (int axis)
1131 {
1132 return axisTitle(axis).renderFlags();
1133 }
1134
setAxisTitleAlignment(int axis,int align)1135 void Graph::setAxisTitleAlignment(int axis, int align)
1136 {
1137 QwtText t = axisTitle(axis);
1138 t.setRenderFlags(align);
1139 ((QwtPlot *)this)->setAxisTitle(axis, t);
1140 }
1141
axisTitleDistance(int axis)1142 int Graph::axisTitleDistance(int axis)
1143 {
1144 if (!axisEnabled(axis))
1145 return 0;
1146
1147 return axisWidget(axis)->spacing();
1148 }
1149
setAxisTitleDistance(int axis,int dist)1150 void Graph::setAxisTitleDistance(int axis, int dist)
1151 {
1152 if (!axisEnabled(axis))
1153 return;
1154
1155 QwtScaleWidget *scale = axisWidget(axis);
1156 if (scale)
1157 scale->setSpacing(dist);
1158 }
1159
setScaleTitle(int axis,const QString & text)1160 void Graph::setScaleTitle(int axis, const QString& text)
1161 {
1162 int a = 0;
1163 switch (axis){
1164 case 0:
1165 a=2;
1166 break;
1167 case 1:
1168 a=0;
1169 break;
1170 case 2:
1171 a=3;
1172 break;
1173 case 3:
1174 a=1;
1175 break;
1176 }
1177 setAxisTitle(a, text);
1178 }
1179
parseAxisTitle(int axis)1180 QString Graph::parseAxisTitle(int axis)
1181 {
1182 if (axis < 0 || axis >= QwtPlot::axisCnt)
1183 return QString::null;
1184
1185 QString s = d_axis_titles[axis];
1186 if (s.trimmed().isEmpty() || !(s.contains("%(?X)", Qt::CaseInsensitive) || s.contains("%(?Y)", Qt::CaseInsensitive)))
1187 return s;
1188
1189 QString name = QString::null;
1190 QString comment = QString::null;
1191 if (s.contains("%(?Y)", Qt::CaseInsensitive)){// parse Origin tag
1192 PlotCurve *c = NULL;
1193 int index = -1;
1194 for (int i = 0; i < d_curves.size(); i++){
1195 PlotCurve *cv = curve(i);
1196 if (cv && cv->yAxis() == axis){
1197 c = cv;
1198 index = i;
1199 break;
1200 }
1201 }
1202 if (!c)
1203 c = curve(0);
1204
1205 if (c){
1206 name = c->title().text();
1207 int pos = name.lastIndexOf("_");
1208 if (pos > 0)
1209 name = name.right(name.length() - pos - 1);
1210
1211 if (d_axis_title_policy > 1){
1212 DataCurve *dc = dataCurve(index);
1213 if (dc){
1214 Table *t = dc->table();
1215 if (t)
1216 comment = t->comment(t->colIndex(name)).trimmed().replace("\n", " ");
1217 }
1218 }
1219
1220 switch(d_axis_title_policy){
1221 case Default:
1222 s.replace("%(?Y)", tr("Y Axis Title"), Qt::CaseInsensitive);
1223 break;
1224 case ColName:
1225 s.replace("%(?Y)", name, Qt::CaseInsensitive);
1226 break;
1227 case ColComment:
1228 if (!comment.isEmpty())
1229 s.replace("%(?Y)", comment, Qt::CaseInsensitive);
1230 else
1231 s.replace("%(?Y)", name, Qt::CaseInsensitive);
1232 break;
1233 case NameAndComment:
1234 if (!comment.isEmpty())
1235 name += " (" + comment + ")";
1236 s.replace("%(?Y)", name, Qt::CaseInsensitive);
1237 break;
1238 default:
1239 break;
1240 }
1241 } else
1242 s.replace("%(?Y)", tr("Y Axis Title"), Qt::CaseInsensitive);
1243 }
1244
1245 if (s.contains("%(?X)", Qt::CaseInsensitive)){
1246 DataCurve *c = dataCurve(0);
1247 if (c){
1248 name = c->xColumnName();
1249 int pos = name.lastIndexOf("_");
1250 if (pos > 0)
1251 name = name.right(name.length() - pos - 1);
1252
1253 if (d_axis_title_policy > 1){
1254 Table *t = c->table();
1255 if (t)
1256 comment = t->comment(t->colIndex(c->xColumnName())).trimmed().replace("\n", " ");
1257 }
1258
1259 switch(d_axis_title_policy){
1260 case Default:
1261 s.replace("%(?X)", tr("X Axis Title"), Qt::CaseInsensitive);
1262 break;
1263 case ColName:
1264 s.replace("%(?X)", name, Qt::CaseInsensitive);
1265 break;
1266 case ColComment:
1267 if (!comment.isEmpty())
1268 s.replace("%(?X)", comment, Qt::CaseInsensitive);
1269 else
1270 s.replace("%(?X)", name, Qt::CaseInsensitive);
1271 break;
1272 case NameAndComment:
1273 if (!comment.isEmpty())
1274 name += " (" + comment + ")";
1275 s.replace("%(?X)", name, Qt::CaseInsensitive);
1276 break;
1277 default:
1278 break;
1279 }
1280 } else
1281 s.replace("%(?X)", tr("X Axis Title"), Qt::CaseInsensitive);
1282 }
1283 return s;
1284 }
1285
axisTitleString(int axis)1286 QString Graph::axisTitleString(int axis)
1287 {
1288 if (axis >= 0 && axis < d_axis_titles.size())
1289 return d_axis_titles[axis];
1290
1291 return QString::null;
1292 }
1293
setAxisTitleString(int axis,const QString & text)1294 void Graph::setAxisTitleString(int axis, const QString& text)
1295 {
1296 if (axis >= 0 && axis < d_axis_titles.size())
1297 d_axis_titles[axis] = text;
1298
1299 ((QwtPlot *)this)->setAxisTitle(axis, parseAxisTitle(axis));
1300 }
1301
setAxisTitle(int axis,const QString & text)1302 void Graph::setAxisTitle(int axis, const QString& text)
1303 {
1304 setAxisTitleString(axis, text);
1305 replot();
1306 emit modifiedGraph();
1307 }
1308
updateSecondaryAxis(int axis,bool changeFormat)1309 void Graph::updateSecondaryAxis(int axis, bool changeFormat)
1310 {
1311 foreach (QwtPlotItem *it, d_curves){
1312 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram){
1313 Spectrogram *sp = (Spectrogram *)it;
1314 if (sp->colorScaleAxis() == axis)
1315 return;
1316 }
1317
1318 if ((axis == QwtPlot::yRight && it->yAxis() == QwtPlot::yRight) ||
1319 (axis == QwtPlot::xTop && it->xAxis () == QwtPlot::xTop))
1320 return;
1321 }
1322
1323 int a = oppositeAxis(axis);
1324 if (!axisEnabled(a))
1325 return;
1326
1327 if (changeFormat && axisScaleDraw(axis)->hasComponent(QwtAbstractScaleDraw::Labels)){
1328 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(a);
1329 ScaleDraw::ScaleType type = sd->scaleType();
1330 if (type == ScaleDraw::Day)
1331 setLabelsDayFormat(axis, sd->nameFormat());
1332 else if (type == ScaleDraw::Month)
1333 setLabelsMonthFormat(axis, sd->nameFormat());
1334 else if (type == ScaleDraw::Time || type == ScaleDraw::Date)
1335 setLabelsDateTimeFormat(axis, type, sd->formatString());
1336 else
1337 setAxisScaleDraw(axis, new ScaleDraw(this, sd));
1338 }
1339
1340 updateOppositeScaleDiv(axis);
1341 }
1342
oppositeAxis(int axis)1343 int Graph::oppositeAxis(int axis)
1344 {
1345 int a = -1;
1346 switch (axis){
1347 case QwtPlot::yLeft:
1348 a = QwtPlot::yRight;
1349 break;
1350 case QwtPlot::yRight:
1351 a = QwtPlot::yLeft;
1352 break;
1353 case QwtPlot::xBottom:
1354 a = QwtPlot::xTop;
1355 break;
1356 case QwtPlot::xTop:
1357 a = QwtPlot::xBottom;
1358 break;
1359 }
1360 return a;
1361 }
1362
updateOppositeScaleDiv(int axis)1363 void Graph::updateOppositeScaleDiv(int axis)
1364 {
1365 int a = oppositeAxis(axis);
1366 if (!axisEnabled(a))
1367 return;
1368
1369 ScaleEngine *sc_engine = (ScaleEngine *)axisScaleEngine(axis);
1370 sc_engine->clone((ScaleEngine *)axisScaleEngine(a));
1371
1372 int minorTicks = axisMaxMinor(a);
1373 int max_min_intervals = minorTicks;
1374 if (minorTicks == 1)
1375 max_min_intervals = 3;
1376 if (minorTicks > 1)
1377 max_min_intervals = minorTicks + 1;
1378
1379 setAxisMaxMajor(axis, axisMaxMajor(a));
1380 setAxisMaxMinor(axis, minorTicks);
1381
1382 setAxisScaleDiv (axis, *axisScaleDiv(a));
1383 d_user_step[axis] = d_user_step[a];
1384 }
1385
invertScale(int axis)1386 void Graph::invertScale(int axis)
1387 {
1388 QwtScaleDiv *scaleDiv = axisScaleDiv(axis);
1389 if (scaleDiv)
1390 scaleDiv->invert();
1391 }
1392
axisBoundingInterval(int axis)1393 QwtDoubleInterval Graph::axisBoundingInterval(int axis)
1394 {
1395 // Find bounding interval of the plot data
1396
1397 QwtDoubleInterval intv;
1398 const QwtPlotItemList& itmList = itemList();
1399 QwtPlotItemIterator it;
1400 for ( it = itmList.begin(); it != itmList.end(); ++it ){
1401 const QwtPlotItem *item = *it;
1402 if (item->rtti() != QwtPlotItem::Rtti_PlotCurve)
1403 continue;
1404
1405 if(axis != item->xAxis() && axis != item->yAxis())
1406 continue;
1407
1408 const QwtDoubleRect rect = item->boundingRect();
1409
1410 if (axis == QwtPlot::xBottom || axis == QwtPlot::xTop)
1411 intv |= QwtDoubleInterval(rect.left(), rect.right());
1412 else
1413 intv |= QwtDoubleInterval(rect.top(), rect.bottom());
1414 }
1415 return intv;
1416 }
1417
setScale(int axis,double start,double end,double step,int majorTicks,int minorTicks,int type,bool inverted,double left_break,double right_break,int breakPos,double stepBeforeBreak,double stepAfterBreak,int minTicksBeforeBreak,int minTicksAfterBreak,bool log10AfterBreak,int breakWidth,bool breakDecoration)1418 void Graph::setScale(int axis, double start, double end, double step,
1419 int majorTicks, int minorTicks, int type, bool inverted,
1420 double left_break, double right_break, int breakPos,
1421 double stepBeforeBreak, double stepAfterBreak, int minTicksBeforeBreak,
1422 int minTicksAfterBreak, bool log10AfterBreak, int breakWidth, bool breakDecoration)
1423 {
1424 ScaleEngine *sc_engine = (ScaleEngine *)axisScaleEngine(axis);
1425 sc_engine->setBreakRegion(left_break, right_break);
1426 sc_engine->setBreakPosition(breakPos);
1427 sc_engine->setBreakWidth(breakWidth);
1428 sc_engine->drawBreakDecoration(breakDecoration);
1429 sc_engine->setStepBeforeBreak(stepBeforeBreak);
1430 sc_engine->setStepAfterBreak(stepAfterBreak);
1431 sc_engine->setMinTicksBeforeBreak(minTicksBeforeBreak);
1432 sc_engine->setMinTicksAfterBreak(minTicksAfterBreak);
1433 sc_engine->setLog10ScaleAfterBreak(log10AfterBreak);
1434 sc_engine->setAttribute(QwtScaleEngine::Inverted, inverted);
1435 sc_engine->setType((ScaleTransformation::Type)type);
1436
1437 bool limitInterval = false;
1438 switch(type){
1439 case ScaleTransformation::Log10:
1440 case ScaleTransformation::Ln:
1441 case ScaleTransformation::Log2:
1442 if (start <= 0 || end <= 0)
1443 limitInterval = true;
1444 break;
1445 case ScaleTransformation::Reciprocal:
1446 if (start == 0 || end == 0)
1447 limitInterval = true;
1448 break;
1449 default:
1450 break;
1451 }
1452 if (limitInterval){
1453 QwtDoubleInterval intv = axisBoundingInterval(axis);
1454 if (start < end)
1455 start = intv.minValue();
1456 else
1457 end = intv.minValue();
1458
1459 if (start <= 0.0)
1460 start = 1e-4;
1461 if (end <= 0.0)
1462 end = 1e-3;
1463 }
1464
1465 int max_min_intervals = minorTicks;
1466 if (minorTicks == 1)
1467 max_min_intervals = 3;
1468 if (minorTicks > 1)
1469 max_min_intervals = minorTicks + 1;
1470
1471 QwtScaleDiv div = sc_engine->divideScale (QMIN(start, end), QMAX(start, end), majorTicks, max_min_intervals, step);
1472 setAxisMaxMajor(axis, majorTicks);
1473 setAxisMaxMinor(axis, minorTicks);
1474
1475 if (inverted)
1476 div.invert();
1477 setAxisScaleDiv(axis, div);
1478
1479 d_zoomer[0]->setZoomBase();
1480 d_zoomer[1]->setZoomBase();
1481
1482 d_user_step[axis] = step;
1483
1484 if (d_synchronize_scales){
1485 if (axis == QwtPlot::xBottom)
1486 updateSecondaryAxis(QwtPlot::xTop);
1487 else if (axis == QwtPlot::yLeft)
1488 updateSecondaryAxis(QwtPlot::yRight);
1489 }
1490
1491 replot();
1492
1493 updateMarkersBoundingRect();//keep markers on canvas area
1494
1495 replot();
1496 axisWidget(axis)->repaint();
1497 emit axisDivChanged(this, axis);
1498 }
1499
setCanvasCoordinates(const QRectF & r)1500 void Graph::setCanvasCoordinates(const QRectF& r)
1501 {
1502 setScale(QwtPlot::xBottom, r.left(), r.right());
1503 setScale(QwtPlot::yLeft, r.top(), r.top() - r.height());
1504 }
1505
analysableCurvesList()1506 QStringList Graph::analysableCurvesList()
1507 {
1508 QStringList cList;
1509 foreach(QwtPlotItem *it, d_curves){
1510 if (it->rtti() != QwtPlotItem::Rtti_PlotSpectrogram){
1511 PlotCurve *c = (PlotCurve*)it;
1512 if (c->type() == ErrorBars)
1513 continue;
1514 if (c->type() != Function){
1515 DataCurve *dc = (DataCurve*)it;
1516 cList << dc->title().text() + " [" + QString::number(dc->startRow() + 1) + ":" + QString::number(dc->endRow() + 1) + "]";
1517 } else
1518 cList << c->title().text();
1519 }
1520 }
1521 return cList;
1522 }
1523
curveRange(QwtPlotCurve * c)1524 QString Graph::curveRange(QwtPlotCurve *c)
1525 {
1526 if (!c)
1527 return QString();
1528 PlotCurve *pc = (PlotCurve *)c;
1529 if (pc->type() == ErrorBars)
1530 return QString();
1531
1532 if (pc->type() != Function){
1533 DataCurve *dc = (DataCurve*)c;
1534 return dc->title().text() + " [" + QString::number(dc->startRow() + 1) + ":" + QString::number(dc->endRow() + 1) + "]";
1535 }
1536 return c->title().text();
1537 }
1538
curveNamesList()1539 QStringList Graph::curveNamesList()
1540 {
1541 QStringList cList;
1542 foreach(QwtPlotItem *it, d_curves){
1543 if (it->rtti() != QwtPlotItem::Rtti_PlotSpectrogram)
1544 cList << it->title().text();
1545 }
1546 return cList;
1547 }
1548
plotItemsList()1549 QStringList Graph::plotItemsList()
1550 {
1551 if (d_curves.isEmpty())
1552 return QStringList();
1553
1554 QStringList cList;
1555 foreach(QwtPlotItem *it, d_curves)
1556 cList << it->title().text();
1557 return cList;
1558 }
1559
copyImage()1560 void Graph::copyImage()
1561 {
1562 #ifdef Q_OS_WIN
1563 if (OpenClipboard(0)){
1564 EmptyClipboard();
1565
1566 QString path = QDir::tempPath();
1567 QString name = path + "/" + "qtiplot_clipboard.emf";
1568 name = QDir::cleanPath(name);
1569 exportEMF(name);
1570 HENHMETAFILE handle = GetEnhMetaFile(name.toStdWString().c_str());
1571
1572 SetClipboardData(CF_ENHMETAFILE, handle);
1573 CloseClipboard();
1574 QFile::remove(name);
1575 }
1576 #else
1577 QApplication::clipboard()->setPixmap(graphPixmap(), QClipboard::Clipboard);
1578 #endif
1579 }
1580
graphPixmap(const QSize & size,double scaleFontsFactor,bool transparent)1581 QPixmap Graph::graphPixmap(const QSize& size, double scaleFontsFactor, bool transparent)
1582 {
1583 QRect r = rect();
1584 QRect br = boundingRect();
1585 if (!size.isValid()){
1586 QPixmap pixmap(br.size());
1587 if (transparent)
1588 pixmap.fill(Qt::transparent);
1589 else
1590 pixmap.fill();
1591 QPainter p(&pixmap);
1592 print(&p, r, ScaledFontsPrintFilter(1.0));
1593 p.end();
1594 return pixmap;
1595 }
1596
1597 if (br.width() != width() || br.height() != height()){
1598 double wfactor = (double)br.width()/(double)width();
1599 double hfactor = (double)br.height()/(double)height();
1600 r.setSize(QSize(qRound(size.width()/wfactor), qRound(size.height()/hfactor)));
1601 } else
1602 r.setSize(size);
1603
1604 if (scaleFontsFactor == 0)
1605 scaleFontsFactor = (double)size.height()/(double)height();
1606
1607 QPixmap pixmap(size);
1608 if (transparent)
1609 pixmap.fill(Qt::transparent);
1610 else
1611 pixmap.fill();
1612 QPainter p(&pixmap);
1613 print(&p, r, ScaledFontsPrintFilter(scaleFontsFactor));
1614 p.end();
1615
1616 return pixmap;
1617 }
1618
exportToFile(const QString & fileName)1619 void Graph::exportToFile(const QString& fileName)
1620 {
1621 if ( fileName.isEmpty() ){
1622 QMessageBox::critical(this, tr("QtiPlot - Error"), tr("Please provide a valid file name!"));
1623 return;
1624 }
1625
1626 if (fileName.contains(".eps") || fileName.contains(".pdf") || fileName.contains(".ps")){
1627 exportVector(fileName);
1628 return;
1629 } else if(fileName.contains(".svg")){
1630 exportSVG(fileName);
1631 return;
1632 }
1633 #ifdef TEX_OUTPUT
1634 else if(fileName.contains(".tex")){
1635 exportTeX(fileName);
1636 return;
1637 }
1638 #endif
1639 else if(fileName.contains(".emf")){
1640 exportEMF(fileName);
1641 return;
1642 } else {
1643 QList<QByteArray> list = QImageWriter::supportedImageFormats();
1644 for(int i=0 ; i<list.count() ; i++){
1645 if (fileName.contains( "." + list[i].toLower())){
1646 exportImage(fileName);
1647 return;
1648 }
1649 }
1650 QMessageBox::critical(this, tr("QtiPlot - Error"), tr("File format not handled, operation aborted!"));
1651 }
1652 }
1653
exportImage(const QString & fileName,int quality,bool transparent,int dpi,const QSizeF & customSize,int unit,double fontsFactor,int compression)1654 void Graph::exportImage(const QString& fileName, int quality, bool transparent, int dpi,
1655 const QSizeF& customSize, int unit, double fontsFactor, int compression)
1656 {
1657 if (!dpi)
1658 dpi = logicalDpiX();
1659
1660 QSize size = QSize();
1661 if (customSize.isValid())
1662 size = customPrintSize(customSize, unit, dpi);
1663
1664 QPixmap pic = graphPixmap(size, fontsFactor, transparent);
1665 QImage image = pic.toImage();
1666 int dpm = (int)ceil(100.0/2.54*dpi);
1667 image.setDotsPerMeterX(dpm);
1668 image.setDotsPerMeterY(dpm);
1669
1670 #if QT_VERSION >= 0x040500
1671 if (fileName.endsWith(".odf")){
1672 QTextDocument *document = new QTextDocument();
1673 QTextCursor cursor = QTextCursor(document);
1674 cursor.movePosition(QTextCursor::End);
1675 MultiLayer *ml = multiLayer();
1676 if (ml)
1677 cursor.insertText(ml->objectName() + ", " + tr("layer") + " " + QString::number(ml->layerIndex(this) + 1));
1678 cursor.insertBlock();
1679 cursor.insertImage(image);
1680
1681 QTextDocumentWriter writer(fileName);
1682 writer.write(document);
1683 } else
1684 #endif
1685 {
1686 QImageWriter writer(fileName);
1687 if (compression > 0 && writer.supportsOption(QImageIOHandler::CompressionRatio)){
1688 writer.setQuality(quality);
1689 writer.setCompression(compression);
1690 writer.write(image);
1691 } else
1692 image.save(fileName, 0, quality);
1693 }
1694 }
1695
exportVector(QPrinter * printer,int res,bool color,const QSizeF & customSize,int unit,double fontsFactor)1696 void Graph::exportVector(QPrinter *printer, int res, bool color,
1697 const QSizeF& customSize, int unit, double fontsFactor)
1698 {
1699 if (!printer)
1700 return;
1701 if (!printer->resolution())
1702 printer->setResolution(logicalDpiX());//we set screen resolution as default
1703
1704 printer->setDocName(multiLayer()->objectName());
1705 printer->setFontEmbeddingEnabled(true);
1706 printer->setCreator("QtiPlot");
1707 printer->setFullPage(true);
1708 QRect r = rect();
1709 QRect br = boundingRect();
1710
1711 if (customSize.isValid()){
1712 QSize size = customPrintSize(customSize, unit, res);
1713
1714 if (fontsFactor == 0.0)
1715 fontsFactor = customPrintSize(customSize, unit, logicalDpiX()).height()/(double)height();
1716
1717 if (res && res != printer->resolution())
1718 printer->setResolution(res);
1719 printer->setPaperSize (QSizeF(size), QPrinter::DevicePixel);
1720
1721 if (br.width() != width() || br.height() != height()){
1722 double wfactor = (double)br.width()/(double)width();
1723 double hfactor = (double)br.height()/(double)height();
1724 r.setSize(QSize(qRound(size.width()/wfactor), qRound(size.height()/hfactor)));
1725 } else
1726 r.setSize(size);
1727 } else if (res && res != printer->resolution()){
1728 double wfactor = (double)res/(double)logicalDpiX();
1729 double hfactor = (double)res/(double)logicalDpiY();
1730 printer->setResolution(res);
1731
1732 // LegendWidget size doesn't increase linearly with resolution.
1733 // The extra width multiplication factor bellow accounts for this.
1734 // We could calculate it precisely, but it's quite complicated...
1735 printer->setPaperSize (QSizeF(br.width()*wfactor*1.05, br.height()*hfactor), QPrinter::DevicePixel);
1736 r.setSize(QSize(qRound(width()*wfactor), qRound(height()*hfactor)));
1737 } else
1738 printer->setPaperSize (QSizeF(br.size()), QPrinter::DevicePixel);
1739
1740 if (color)
1741 printer->setColorMode(QPrinter::Color);
1742 else
1743 printer->setColorMode(QPrinter::GrayScale);
1744
1745 printer->setOrientation(QPrinter::Portrait);
1746
1747 QPainter paint(printer);
1748 print(&paint, r, ScaledFontsPrintFilter(fontsFactor));
1749 paint.end();
1750 }
1751
exportVector(const QString & fileName,int res,bool color,const QSizeF & customSize,int unit,double fontsFactor)1752 void Graph::exportVector(const QString& fileName, int res, bool color,
1753 const QSizeF& customSize, int unit, double fontsFactor)
1754 {
1755 if (fileName.isEmpty()){
1756 QMessageBox::critical(this, tr("QtiPlot - Error"), tr("Please provide a valid file name!"));
1757 return;
1758 }
1759
1760 QPrinter printer;
1761 printer.setOutputFileName(fileName);
1762 if (fileName.contains(".eps"))
1763 printer.setOutputFormat(QPrinter::PostScriptFormat);
1764
1765 exportVector(&printer, res, color, customSize, unit, fontsFactor);
1766 }
1767
print()1768 void Graph::print()
1769 {
1770 QPrinter printer;
1771 printer.setColorMode (QPrinter::Color);
1772 printer.setFullPage(true);
1773 #ifdef Q_OS_LINUX
1774 printer.setOutputFileName(multiLayer()->objectName());
1775 #endif
1776 //printing should preserve plot aspect ratio, if possible
1777 double aspect = double(width())/double(height());
1778 if (aspect < 1)
1779 printer.setOrientation(QPrinter::Portrait);
1780 else
1781 printer.setOrientation(QPrinter::Landscape);
1782
1783 QPrintDialog printDialog(&printer, multiLayer()->applicationWindow());
1784 if (printDialog.exec() == QDialog::Accepted){
1785 #ifdef Q_OS_LINUX
1786 if (printDialog.enabledOptions() & QAbstractPrintDialog::PrintToFile){
1787 QString fn = printer.outputFileName();
1788 if (printer.outputFormat() == QPrinter::PostScriptFormat && !fn.contains(".ps"))
1789 printer.setOutputFileName(fn + ".ps");
1790 else if (printer.outputFormat() == QPrinter::PdfFormat && !fn.contains(".pdf"))
1791 printer.setOutputFileName(fn + ".pdf");
1792 }
1793 #endif
1794
1795 QRect plotRect = rect();
1796 QRect paperRect = printer.paperRect();
1797 double fontFactor = 1.0;
1798 if (multiLayer()->scaleLayersOnPrint()){
1799 int margin = (int)((1/2.54)*printer.logicalDpiY()); // 1 cm margins
1800
1801 int width = qRound(aspect*printer.height()) - 2*margin;
1802 int x = qRound(abs(printer.width()- width)*0.5);
1803
1804 plotRect = QRect(x, margin, width, printer.height() - 2*margin);
1805 if (x < margin){
1806 plotRect.setLeft(margin);
1807 plotRect.setWidth(printer.width() - 2*margin);
1808 }
1809
1810 fontFactor = (double)plotRect.height()/(double)this->height();
1811 } else {
1812 int x_margin = (paperRect.width() - plotRect.width())/2;
1813 if (x_margin <= 0)
1814 x_margin = (int)((0.5/2.54)*printer.logicalDpiY()); // 0.5 cm margins
1815 int y_margin = (paperRect.height() - plotRect.height())/2;
1816 if (y_margin <= 0)
1817 y_margin = x_margin;
1818 plotRect.moveTo(x_margin, y_margin);
1819 }
1820
1821 QPainter paint(&printer);
1822 if (multiLayer()->printCropmarksEnabled()){
1823 QRect cr = plotRect; // cropmarks rectangle
1824 cr.addCoords(-1, -1, 2, 2);
1825 paint.save();
1826 paint.setPen(QPen(QColor(Qt::black), 0.5, Qt::DashLine));
1827 paint.drawLine(paperRect.left(), cr.top(), paperRect.right(), cr.top());
1828 paint.drawLine(paperRect.left(), cr.bottom(), paperRect.right(), cr.bottom());
1829 paint.drawLine(cr.left(), paperRect.top(), cr.left(), paperRect.bottom());
1830 paint.drawLine(cr.right(), paperRect.top(), cr.right(), paperRect.bottom());
1831 paint.restore();
1832 }
1833
1834 print(&paint, plotRect, ScaledFontsPrintFilter(fontFactor));
1835 }
1836 }
1837
exportSVG(const QString & fname,const QSizeF & customSize,int unit,double fontsFactor)1838 void Graph::exportSVG(const QString& fname, const QSizeF& customSize, int unit, double fontsFactor)
1839 {
1840 int res = 96;
1841 #ifdef Q_OS_MAC
1842 res = 72;
1843 #endif
1844
1845 QSize size = boundingRect().size();
1846 if (customSize.isValid())
1847 size = Graph::customPrintSize(customSize, unit, res);
1848
1849 QSvgGenerator svg;
1850 svg.setFileName(fname);
1851 svg.setSize(size);
1852 svg.setResolution(res);
1853
1854 draw(&svg, size, fontsFactor);
1855 }
1856
draw(QPaintDevice * device,const QSize & size,double fontsFactor)1857 void Graph::draw(QPaintDevice *device, const QSize& size, double fontsFactor)
1858 {
1859 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1860
1861 if (fontsFactor == 0.0)
1862 fontsFactor = size.height()/(double)height();
1863
1864 QRect r = rect();
1865 QRect br = boundingRect();
1866 if (size != br.size()){
1867 if (br.width() != width() || br.height() != height()){
1868 double wfactor = (double)br.width()/(double)width();
1869 double hfactor = (double)br.height()/(double)height();
1870 r.setSize(QSize(qRound(size.width()/wfactor), qRound(size.height()/hfactor)));
1871 } else
1872 r.setSize(size);
1873 }
1874
1875 QPainter p(device);
1876 print(&p, r, ScaledFontsPrintFilter(fontsFactor));
1877 p.end();
1878
1879 QApplication::restoreOverrideCursor();
1880 }
1881
exportEMF(const QString & fname,const QSizeF & customSize,int unit,double fontsFactor)1882 void Graph::exportEMF(const QString& fname, const QSizeF& customSize, int unit, double fontsFactor)
1883 {
1884 if (!multiLayer()->applicationWindow())
1885 return;
1886 ImportExportPlugin *ep = multiLayer()->applicationWindow()->exportPlugin("emf");
1887 if (!ep)
1888 return;
1889
1890 ep->exportGraph(this, fname, customSize, unit, fontsFactor);
1891 }
1892
exportTeX(const QString & fname,bool color,bool escapeStrings,bool fontSizes,const QSizeF & customSize,int unit,double fontsFactor)1893 void Graph::exportTeX(const QString& fname, bool color, bool escapeStrings, bool fontSizes, const QSizeF& customSize, int unit, double fontsFactor)
1894 {
1895 #ifdef TEX_OUTPUT
1896 int res = logicalDpiX();
1897 QSize size = boundingRect().size();
1898 if (customSize.isValid())
1899 size = Graph::customPrintSize(customSize, unit, res);
1900
1901 d_is_exporting_tex = true;
1902 d_tex_escape_strings = escapeStrings;
1903
1904 QTeXPaintDevice tex(fname, size);
1905 tex.setEscapeTextMode(false);
1906 tex.exportFontSizes(fontSizes);
1907 if (!color)
1908 tex.setColorMode(QPrinter::GrayScale);
1909
1910 if (!fontSizes)
1911 fontsFactor = 1.0;
1912
1913 draw(&tex, size, fontsFactor);
1914
1915 d_is_exporting_tex = false;
1916 #endif
1917 }
1918
markerSelected()1919 bool Graph::markerSelected()
1920 {
1921 if (d_selected_arrow)
1922 return true;
1923 if (d_active_enrichment)
1924 return true;
1925 return false;
1926 }
1927
removeMarker()1928 void Graph::removeMarker()
1929 {
1930 if (d_selected_arrow && d_lines.contains(d_selected_arrow))
1931 remove(d_selected_arrow);
1932 else if (d_markers_selector){
1933 QList <QWidget *> lst = d_markers_selector->widgetsList();
1934 foreach(QWidget *w, lst){
1935 FrameWidget *fw = qobject_cast<FrameWidget *>(w);
1936 if (fw)
1937 remove(fw);
1938 }
1939 }
1940 }
1941
remove(ArrowMarker * arrow)1942 void Graph::remove(ArrowMarker* arrow)
1943 {
1944 if (!arrow)
1945 return;
1946
1947 if (d_markers_selector && d_lines.contains(arrow))
1948 d_markers_selector->removeAll(arrow);
1949
1950 if (d_lines.contains(arrow)){
1951 cp->disableEditing();
1952
1953 int index = d_lines.indexOf(arrow);
1954 if (index >= 0 && index < d_lines.size())
1955 d_lines.removeAt(index);
1956 }
1957
1958 if (arrow == d_selected_arrow)
1959 d_selected_arrow = NULL;
1960
1961 arrow->detach();
1962 replot();
1963
1964 emit modifiedGraph();
1965 }
1966
remove(FrameWidget * f)1967 void Graph::remove(FrameWidget* f)
1968 {
1969 if (!f)
1970 return;
1971
1972 PieLabel *l = qobject_cast<PieLabel *>(f);
1973 if (!l){
1974 int index = d_enrichments.indexOf (f);
1975 if (index >= 0 && index < d_enrichments.size())
1976 d_enrichments.removeAt(index);
1977
1978 if (f == d_active_enrichment)
1979 d_active_enrichment = NULL;
1980 }
1981
1982 emit modifiedGraph();
1983 f->close();
1984 }
1985
arrowMarkerSelected()1986 bool Graph::arrowMarkerSelected()
1987 {
1988 return (d_selected_arrow && d_lines.contains(d_selected_arrow));
1989 }
1990
imageMarkerSelected()1991 bool Graph::imageMarkerSelected()
1992 {
1993 ImageWidget *i = qobject_cast<ImageWidget *>(d_active_enrichment);
1994 if (i)
1995 return true;
1996 return false;
1997 }
1998
deselect()1999 void Graph::deselect()
2000 {
2001 deselectMarker();
2002 scalePicker->deselect();
2003 titlePicker->setSelected(false);
2004 deselectCurves();
2005 if (multiLayer())
2006 multiLayer()->deselect();
2007 }
2008
deselectCurves()2009 void Graph::deselectCurves()
2010 {
2011 QList<QwtPlotItem *> curves = curvesList();
2012 foreach(QwtPlotItem *i, curves){
2013 if(i->rtti() == QwtPlotItem::Rtti_PlotSpectrogram &&
2014 ((Spectrogram *)i)->hasSelectedLabels()){
2015 ((Spectrogram *)i)->selectLabel(false);
2016 } else if (i->rtti() == QwtPlotItem::Rtti_PlotCurve && ((PlotCurve *)i)->type() != Graph::Function){
2017 ((DataCurve *)i)->setLabelsSelected(false);
2018 }
2019 }
2020 }
2021
selectedCurveLabels()2022 QwtPlotItem* Graph::selectedCurveLabels()
2023 {
2024 QList<QwtPlotItem *> curves = curvesList();
2025 foreach(QwtPlotItem *i, curves){
2026 if(i->rtti() == QwtPlotItem::Rtti_PlotSpectrogram && ((Spectrogram *)i)->hasSelectedLabels())
2027 return i;
2028
2029 if(i->rtti() == QwtPlotItem::Rtti_PlotCurve && ((PlotCurve *)i)->type() != Graph::Function &&
2030 ((DataCurve *)i)->hasSelectedLabels())
2031 return i;
2032 }
2033 return NULL;
2034 }
2035
titleSelected()2036 bool Graph::titleSelected()
2037 {
2038 return titlePicker->selected();
2039 }
2040
selectTitle(bool select)2041 void Graph::selectTitle(bool select)
2042 {
2043 titlePicker->setSelected(select);
2044
2045 if (select){
2046 deselect();
2047 emit selectedGraph(this);
2048 currentFontChanged(title().font());
2049 currentColorChanged(title().color());
2050 }
2051 }
2052
clearTitle()2053 void Graph::clearTitle()
2054 {
2055 setTitle(" ");
2056 emit modifiedGraph();
2057 }
2058
removeTitle()2059 void Graph::removeTitle()
2060 {
2061 setTitle("");
2062 emit modifiedGraph();
2063 }
2064
initTitle(bool on,const QFont & fnt)2065 void Graph::initTitle(bool on, const QFont& fnt)
2066 {
2067 if (on){
2068 QwtText t = title();
2069 t.setFont(fnt);
2070 t.setText(tr("Title"));
2071 setTitle (t);
2072 }
2073 }
2074
legendText(bool layerSpec,int fromIndex)2075 QString Graph::legendText(bool layerSpec, int fromIndex)
2076 {
2077 QString text = QString();
2078
2079 if (layerSpec){
2080 int layerIndex = 1;
2081 MultiLayer *ml = multiLayer();
2082 if (ml)
2083 layerIndex = ml->layerIndex(this);
2084
2085 for (int i = fromIndex; i < d_curves.size(); i++){
2086 PlotCurve* c = curve(i);
2087 if (!c)
2088 continue;
2089
2090 if (c->type() != ErrorBars){
2091 text += "\\l(";
2092 text += QString::number(layerIndex + 1);
2093 text += ".";
2094 text += QString::number(i + 1);
2095 text += ")%(";
2096 text += QString::number(layerIndex + 1);
2097 text += ".";
2098 text += QString::number(i + 1);
2099 text += ")\n";
2100 i++;
2101 }
2102 }
2103 } else {
2104 for (int i = fromIndex; i < d_curves.size(); i++){
2105 PlotCurve* c = curve(i);
2106 if (!c)
2107 continue;
2108
2109 int type = c->type();
2110 if (type == Function){
2111 text += "\\l(";
2112 text += QString::number(i + 1);
2113 text += ")%(";
2114 text += QString::number(i + 1);
2115 text += ")\n";
2116 continue;
2117 }
2118
2119 if (type != ErrorBars){
2120 text += "\\l(";
2121 text += QString::number(i + 1);
2122 text += ")%(";
2123 text += QString::number(i + 1);
2124
2125 LegendDisplayMode mode = ColumnName;
2126 ApplicationWindow *app = multiLayer()->applicationWindow();
2127 if (app)
2128 mode = app->d_graph_legend_display;
2129
2130 switch(mode){
2131 case ColumnName:
2132 text += ",@C";
2133 break;
2134 case ColumnComment:
2135 text += ",@L";
2136 break;
2137 case TableName:
2138 text += ",@W";
2139 break;
2140 case TableLegend:
2141 text += ",@WL";
2142 break;
2143 case DataSetName:
2144 text += ",@D";
2145 break;
2146 default:
2147 break;
2148 }
2149
2150 text += ")\n";
2151 }
2152 }
2153 }
2154 return text.trimmed();
2155 }
2156
pieLegendText()2157 QString Graph::pieLegendText()
2158 {
2159 if (d_curves.isEmpty())
2160 return QString::null;
2161
2162 QString text;
2163 const QwtPlotCurve *c = (QwtPlotCurve *)d_curves.first();
2164 if (c){
2165 for (int i = 0; i < int(c->dataSize()); i++){
2166 text += "\\l(1,";
2167 text += QString::number(i+1);
2168 text += ") %(1,@L,";
2169 text += QString::number(i+1);
2170 text += ")\n";
2171 }
2172 }
2173 return text.trimmed();
2174 }
2175
updateCurvesData(Table * w,const QString & yColName)2176 void Graph::updateCurvesData(Table* w, const QString& yColName)
2177 {
2178 int updated_curves = 0;
2179 foreach(QwtPlotItem *it, d_curves){
2180 if (it->rtti() != QwtPlotItem::Rtti_PlotSpectrogram){
2181 PlotCurve *c = (PlotCurve*)it;
2182 if (c->type() == Function)
2183 continue;
2184 if(((DataCurve *)it)->updateData(w, yColName))
2185 updated_curves++;
2186 }
2187 }
2188
2189 if (updated_curves){
2190 for (int i = 0; i < QwtPlot::axisCnt; i++){
2191 QwtScaleWidget *scale = axisWidget(i);
2192 if (scale)
2193 connect(scale, SIGNAL(scaleDivChanged()), this, SLOT(updateMarkersBoundingRect()));
2194 }
2195 updatePlot();
2196 }
2197 }
2198
reloadCurvesData()2199 void Graph::reloadCurvesData()
2200 {
2201 foreach(QwtPlotItem *it, d_curves){
2202 if (it->rtti() != QwtPlotItem::Rtti_PlotSpectrogram){
2203 PlotCurve *c = (PlotCurve*)it;
2204 if (c->type() == Function)
2205 continue;
2206 ((DataCurve *)it)->loadData();
2207 }
2208 }
2209 }
2210
saveEnabledAxes()2211 QString Graph::saveEnabledAxes()
2212 {
2213 QString list="EnabledAxes\t";
2214 for (int i = 0;i<QwtPlot::axisCnt;i++)
2215 list+=QString::number(axisEnabled (i))+"\t";
2216
2217 list+="\n";
2218 return list;
2219 }
2220
canvasFrameColor()2221 QColor Graph::canvasFrameColor()
2222 {
2223 QPalette pal = canvas()->palette();
2224 return pal.color(QPalette::Active, QColorGroup::Foreground);
2225 }
2226
canvasFrameWidth()2227 int Graph::canvasFrameWidth()
2228 {
2229 return canvas()->lineWidth();
2230 }
2231
setCanvasFrame(int width,const QColor & color)2232 void Graph::setCanvasFrame(int width, const QColor& color)
2233 {
2234 QwtPlotCanvas* canvas = (QwtPlotCanvas*)this->canvas();
2235 QPalette pal = canvas->palette();
2236
2237 if (canvas->lineWidth() == width &&
2238 pal.color(QPalette::Active, QColorGroup::Foreground) == color)
2239 return;
2240
2241 canvas->setLineWidth(width);
2242 pal.setColor(QColorGroup::Foreground,color);
2243 canvas->setPalette(pal);
2244 emit modifiedGraph();
2245 }
2246
drawAxesBackbones(bool yes)2247 void Graph::drawAxesBackbones(bool yes)
2248 {
2249 if (drawAxesBackbone == yes)
2250 return;
2251
2252 drawAxesBackbone = yes;
2253
2254 for (int i=0; i<QwtPlot::axisCnt; i++)
2255 {
2256 QwtScaleWidget *scale=(QwtScaleWidget*) axisWidget(i);
2257 if (scale)
2258 {
2259 ScaleDraw *sclDraw = (ScaleDraw *)axisScaleDraw (i);
2260 sclDraw->enableComponent (QwtAbstractScaleDraw::Backbone, yes);
2261 scale->repaint();
2262 }
2263 }
2264
2265 replot();
2266 emit modifiedGraph();
2267 }
2268
loadAxesOptions(const QStringList & lst)2269 void Graph::loadAxesOptions(const QStringList& lst)
2270 {
2271 if (lst.size() < 2)
2272 return;
2273
2274 drawAxesBackbone = (lst[1] == "1");
2275
2276 if (lst.size() == 6){
2277 for (int i = 0; i<QwtPlot::axisCnt; i++){
2278 QwtScaleWidget *scale = (QwtScaleWidget*) axisWidget(i);
2279 if (scale){
2280 ScaleDraw *sclDraw = (ScaleDraw *)axisScaleDraw (i);
2281 sclDraw->enableComponent (QwtAbstractScaleDraw::Backbone, lst[i + 2].toInt());
2282 scale->repaint();
2283 }
2284 }
2285 } else if (!drawAxesBackbone){
2286 for (int i=0; i<QwtPlot::axisCnt; i++){
2287 QwtScaleWidget *scale=(QwtScaleWidget*) axisWidget(i);
2288 if (scale){
2289 ScaleDraw *sclDraw = (ScaleDraw *)axisScaleDraw (i);
2290 sclDraw->enableComponent (QwtAbstractScaleDraw::Backbone, false);
2291 scale->repaint();
2292 }
2293 }
2294 }
2295 }
2296
setAxesLinewidth(int width)2297 void Graph::setAxesLinewidth(int width)
2298 {
2299 if (axesLinewidth() == width)
2300 return;
2301
2302 for (int i=0; i<QwtPlot::axisCnt; i++){
2303 QwtScaleWidget *scale=(QwtScaleWidget*) axisWidget(i);
2304 if (scale){
2305 scale->setPenWidth(width);
2306 scale->repaint();
2307 }
2308 }
2309
2310 if (d_grid){
2311 if (d_grid->xZeroLineMarker()){
2312 QPen pen = d_grid->xZeroLineMarker()->linePen();
2313 pen.setWidth(width);
2314 d_grid->xZeroLineMarker()->setLinePen(pen);
2315 }
2316 if (d_grid->yZeroLineMarker()){
2317 QPen pen = d_grid->yZeroLineMarker()->linePen();
2318 pen.setWidth(width);
2319 d_grid->yZeroLineMarker()->setLinePen(pen);
2320 }
2321 }
2322
2323 replot();
2324 emit modifiedGraph();
2325 }
2326
loadAxesLinewidth(int width)2327 void Graph::loadAxesLinewidth(int width)
2328 {
2329 setAxesLinewidth(width);
2330 }
2331
saveCanvas()2332 QString Graph::saveCanvas()
2333 {
2334 QString s="";
2335 int w = canvas()->lineWidth();
2336 if (w>0)
2337 {
2338 s += "CanvasFrame\t" + QString::number(w)+"\t";
2339 s += canvasFrameColor().name()+"\n";
2340 }
2341 s += "CanvasBackground\t" + canvasBackground().name()+"\t";
2342 s += QString::number(canvasBackground().alpha())+"\n";
2343 return s;
2344 }
2345
saveFonts()2346 QString Graph::saveFonts()
2347 {
2348 int i;
2349 QString s;
2350 QStringList list,axesList;
2351 QFont f;
2352 list<<"TitleFont";
2353 f=title().font();
2354 list<<f.family();
2355 list<<QString::number(f.pointSize());
2356 list<<QString::number(f.weight());
2357 list<<QString::number(f.italic());
2358 list<<QString::number(f.underline());
2359 list<<QString::number(f.strikeOut());
2360 s=list.join ("\t")+"\n";
2361
2362 for (i=0;i<axisCnt;i++)
2363 {
2364 f=axisTitle(i).font();
2365 list[0]="ScaleFont"+QString::number(i);
2366 list[1]=f.family();
2367 list[2]=QString::number(f.pointSize());
2368 list[3]=QString::number(f.weight());
2369 list[4]=QString::number(f.italic());
2370 list[5]=QString::number(f.underline());
2371 list[6]=QString::number(f.strikeOut());
2372 s+=list.join ("\t")+"\n";
2373 }
2374
2375 for (i=0;i<axisCnt;i++)
2376 {
2377 f=axisFont(i);
2378 list[0]="AxisFont"+QString::number(i);
2379 list[1]=f.family();
2380 list[2]=QString::number(f.pointSize());
2381 list[3]=QString::number(f.weight());
2382 list[4]=QString::number(f.italic());
2383 list[5]=QString::number(f.underline());
2384 list[6]=QString::number(f.strikeOut());
2385 s+=list.join ("\t")+"\n";
2386 }
2387 return s;
2388 }
2389
saveAxesFormulas()2390 QString Graph::saveAxesFormulas()
2391 {
2392 QString s;
2393 for (int i=0; i<4; i++){
2394 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(i);
2395 if (!sd)
2396 continue;
2397
2398 if (!sd->formula().isEmpty())
2399 {
2400 s += "<AxisFormula pos=\"" + QString::number(i) + "\">\n";
2401 s += sd->formula();
2402 s += "\n</AxisFormula>\n";
2403 }
2404 }
2405 return s;
2406 }
2407
saveScale()2408 QString Graph::saveScale()
2409 {
2410 QString s;
2411 for (int i = 0; i < QwtPlot::axisCnt; i++){
2412 s += "scale\t" + QString::number(i) + "\t";
2413
2414 const QwtScaleDiv *scDiv = axisScaleDiv(i);
2415
2416 s += QString::number(QMIN(scDiv->lowerBound(), scDiv->upperBound()), 'g', 15) + "\t";
2417 s += QString::number(QMAX(scDiv->lowerBound(), scDiv->upperBound()), 'g', 15) + "\t";
2418 s += QString::number(d_user_step[i], 'g', 15) + "\t";
2419 s += QString::number(scDiv->ticks(QwtScaleDiv::MajorTick).count()) + "\t";
2420 s += QString::number(axisMaxMinor(i)) + "\t";
2421
2422 const ScaleEngine *sc_eng = (ScaleEngine *)axisScaleEngine(i);
2423 s += QString::number((int)sc_eng->type()) + "\t";
2424 s += QString::number(sc_eng->testAttribute(QwtScaleEngine::Inverted));
2425
2426 ScaleEngine *se = (ScaleEngine *)axisScaleEngine(i);
2427 if (se->hasBreak()){
2428 s += "\t" + QString::number(se->axisBreakLeft(), 'g', 15);
2429 s += "\t" + QString::number(se->axisBreakRight(), 'g', 15);
2430 s += "\t" + QString::number(se->breakPosition());
2431 s += "\t" + QString::number(se->stepBeforeBreak(), 'g', 15);
2432 s += "\t" + QString::number(se->stepAfterBreak(), 'g', 15);
2433 s += "\t" + QString::number(se->minTicksBeforeBreak());
2434 s += "\t" + QString::number(se->minTicksAfterBreak());
2435 s += "\t" + QString::number(se->log10ScaleAfterBreak());
2436 s += "\t" + QString::number(se->breakWidth());
2437 s += "\t" + QString::number(se->hasBreakDecoration()) + "\n";
2438 } else
2439 s += "\n";
2440 }
2441 return s;
2442 }
2443
setAxisTitleColor(int axis,const QColor & c)2444 void Graph::setAxisTitleColor(int axis, const QColor& c)
2445 {
2446 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(axis);
2447 if (scale){
2448 QwtText title = scale->title();
2449 title.setColor(c);
2450 scale->setTitle(title);
2451 }
2452 }
2453
saveAxesTitleColors()2454 QString Graph::saveAxesTitleColors()
2455 {
2456 QString s="AxesTitleColors\t";
2457 for (int i=0;i<4;i++)
2458 {
2459 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(i);
2460 QColor c;
2461 if (scale)
2462 c=scale->title().color();
2463 else
2464 c=QColor(Qt::black);
2465
2466 s+=c.name()+"\t";
2467 }
2468 return s+"\n";
2469 }
2470
saveTitle()2471 QString Graph::saveTitle()
2472 {
2473 QString s="PlotTitle\t";
2474 s += title().text().replace("\n", "<br>")+"\t";
2475 s += title().color().name()+"\t";
2476 s += QString::number(title().renderFlags())+"\n";
2477 return s;
2478 }
2479
saveScaleTitles()2480 QString Graph::saveScaleTitles()
2481 {
2482 int a = 0;
2483 QString s = "";
2484 for (int i = 0; i < 4; i++){
2485 switch (i){
2486 case 0:
2487 a = 2;
2488 break;
2489 case 1:
2490 a = 0;
2491 break;
2492 case 2:
2493 a = 3;
2494 break;
2495 case 3:
2496 a = 1;
2497 break;
2498 }
2499 QString title = axisTitleString(a);//axisTitle(a).text();
2500 if (!title.isEmpty())
2501 s += title.replace("\n", "<br>") + "\t";
2502 else
2503 s += "\t";
2504 }
2505 return s + "\n";
2506 }
2507
saveAxesTitleAlignement()2508 QString Graph::saveAxesTitleAlignement()
2509 {
2510 QString s = "AxesTitleAlignment\t";
2511
2512 QStringList axes;
2513 for (int i = 0; i < QwtPlot::axisCnt; i++){
2514 axes << QString::number(Qt::AlignHCenter);
2515 if (axisEnabled(i))
2516 axes[i] = QString::number(axisTitle(i).renderFlags());
2517 }
2518 s += axes.join("\t") + "\n";
2519
2520 QStringList invertedTitles;
2521 for (int i = 0; i < QwtPlot::axisCnt; i++){
2522 axes[i] = "-1";
2523 invertedTitles << "0";
2524 if (axisEnabled(i)){
2525 const QwtScaleWidget *scale = axisWidget(i);
2526 axes[i] = QString::number(scale->spacing());
2527 if (scale->testLayoutFlag(QwtScaleWidget::TitleInverted))
2528 invertedTitles[i] = "1";
2529 }
2530 }
2531
2532 s += "AxesTitleDistance\t" + axes.join("\t") + "\n";
2533 s += "InvertedTitle\t" + invertedTitles.join("\t") + "\n";
2534 return s;
2535 }
2536
savePieCurveLayout()2537 QString Graph::savePieCurveLayout()
2538 {
2539 QString s="PieCurve\t";
2540
2541 PieCurve *pie = (PieCurve*)curve(0);
2542 s+= pie->title().text()+"\t";
2543 QPen pen = pie->pen();
2544 s+=QString::number(pen.widthF())+"\t";
2545 s+=pen.color().name()+"\t";
2546 s+=penStyleName(pen.style()) + "\t";
2547 s+=QString::number(PatternBox::patternIndex(pie->pattern()))+"\t";
2548 s+=QString::number(pie->radius())+"\t";
2549 s+=QString::number(pie->firstColor())+"\t";
2550 s+=QString::number(pie->startRow())+"\t"+QString::number(pie->endRow())+"\t";
2551 s+=QString::number(pie->isVisible())+"\t";
2552
2553 //Starting with version 0.9.3-rc3
2554 s+=QString::number(pie->startAzimuth())+"\t";
2555 s+=QString::number(pie->viewAngle())+"\t";
2556 s+=QString::number(pie->thickness())+"\t";
2557 s+=QString::number(pie->horizontalOffset())+"\t";
2558 s+=QString::number(pie->labelsEdgeDistance())+"\t";
2559 s+=QString::number(pie->counterClockwise())+"\t";
2560 s+=QString::number(pie->labelsAutoFormat())+"\t";
2561 s+=QString::number(pie->labelsValuesFormat())+"\t";
2562 s+=QString::number(pie->labelsPercentagesFormat())+"\t";
2563 s+=QString::number(pie->labelCategories())+"\t";
2564 s+=QString::number(pie->fixedLabelsPosition())+"\n";
2565 return s;
2566 }
2567
rgbaName(const QColor & color)2568 QString Graph::rgbaName(const QColor& color)
2569 {
2570 if (color.alpha() == 255)
2571 return color.name();
2572
2573 return color.name() + "," + QString::number(color.alphaF());
2574 }
2575
saveCurveLayout(int index)2576 QString Graph::saveCurveLayout(int index)
2577 {
2578 QString s = QString::null;
2579 PlotCurve *c = (PlotCurve*)curve(index);
2580 int style = c->plotStyle();
2581 if (c){
2582 s += QString::number(style)+"\t";
2583 if (style == Spline)
2584 s+="5\t";
2585 else if (style == VerticalSteps)
2586 s+="6\t";
2587 else
2588 s+=QString::number(c->style())+"\t";
2589 s += rgbaName(c->pen().color()) + "\t";
2590 s += QString::number(c->pen().style()-1)+"\t";
2591 s += QString::number(c->pen().widthF())+"\t";
2592
2593 const QwtSymbol symbol = c->symbol();
2594 s += QString::number(symbol.size().width()) + "\t";
2595 s += QString::number(SymbolBox::symbolIndex(symbol.style())) + "\t";
2596 s += rgbaName(symbol.pen().color()) + "\t";
2597 if (symbol.brush().style() != Qt::NoBrush)
2598 s += rgbaName(symbol.brush().color()) + "\t";
2599 else
2600 s += QString::number(-1) + "\t";
2601
2602 bool filled = c->brush().style() == Qt::NoBrush ? false : true;
2603 if (filled)
2604 s += QString::number(c->brush().color().alphaF()) + "\t";
2605 else
2606 s += "0\t";
2607 s += c->brush().color().name() + "\t";
2608 s += QString::number(PatternBox::patternIndex(c->brush().style()))+"\t";
2609 if (style <= LineSymbols || style == Box)
2610 s += QString::number(symbol.pen().widthF())+"\t";
2611 }
2612
2613 if(style == VerticalBars || style == HorizontalBars || style == Histogram){
2614 QwtBarCurve *b = (QwtBarCurve*)c;
2615 s+=QString::number(b->gap())+"\t";
2616 s+=QString::number(b->offset())+"\t";
2617 }
2618
2619 if (style == Histogram){
2620 QwtHistogram *h = (QwtHistogram*)c;
2621 s+=QString::number(h->autoBinning())+"\t";
2622 s+=QString::number(h->binSize())+"\t";
2623 s+=QString::number(h->begin())+"\t";
2624 s+=QString::number(h->end())+"\t";
2625 } else if(style == VectXYXY || style == VectXYAM){
2626 VectorCurve *v = (VectorCurve*)c;
2627 s+=v->color().name()+"\t";
2628 s+=QString::number(v->width())+"\t";
2629 s+=QString::number(v->headLength())+"\t";
2630 s+=QString::number(v->headAngle())+"\t";
2631 s+=QString::number(v->filledArrowHead())+"\t";
2632
2633 QStringList colsList = v->plotAssociation();
2634 s+=colsList[2].remove("(X)").remove("(A)")+"\t";
2635 s+=colsList[3].remove("(Y)").remove("(M)");
2636 if (style == VectXYAM)
2637 s+="\t"+QString::number(v->position());
2638 s+="\t";
2639 } else if(style == Box){
2640 BoxCurve *b = (BoxCurve*)c;
2641 s+=QString::number(SymbolBox::symbolIndex(b->maxStyle()))+"\t";
2642 s+=QString::number(SymbolBox::symbolIndex(b->p99Style()))+"\t";
2643 s+=QString::number(SymbolBox::symbolIndex(b->meanStyle()))+"\t";
2644 s+=QString::number(SymbolBox::symbolIndex(b->p1Style()))+"\t";
2645 s+=QString::number(SymbolBox::symbolIndex(b->minStyle()))+"\t";
2646 s+=QString::number(b->boxStyle())+"\t";
2647 s+=QString::number(b->boxWidth())+"\t";
2648 s+=QString::number(b->boxRangeType())+"\t";
2649 s+=QString::number(b->boxRange())+"\t";
2650 s+=QString::number(b->whiskersRangeType())+"\t";
2651 s+=QString::number(b->whiskersRange())+"\t";
2652 }
2653 return s;
2654 }
2655
restoreSymbolImage(int index,const QStringList & lst)2656 void Graph::restoreSymbolImage(int index, const QStringList& lst)
2657 {
2658 if (index < 0 || index >= d_curves.count())
2659 return;
2660
2661 PlotCurve *c = this->curve(index);
2662 if (!c)
2663 return;
2664
2665 QString path;
2666 QStringList::const_iterator line;
2667 for (line = lst.begin(); line != lst.end(); line++){
2668 QString s = *line;
2669 if (s.contains("<path>"))
2670 path = s.remove("<path>").remove("</path>");
2671 else if (s.contains("<xpm>")){
2672 QString xpm;
2673 while ( s != "</xpm>" ){
2674 s = *(++line);
2675 xpm += s + "\n";
2676 }
2677 QPixmap pix;
2678 pix.loadFromData(xpm.toAscii());
2679 c->setSymbol(ImageSymbol(pix, path));
2680 }
2681 }
2682 }
2683
saveCurves()2684 QString Graph::saveCurves()
2685 {
2686 QString s;
2687 if (isPiePlot())
2688 s += savePieCurveLayout();
2689 else {
2690 int i = -1;
2691 foreach (QwtPlotItem *it, d_curves){
2692 i++;
2693 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram){
2694 s += ((Spectrogram *)it)->saveToString();
2695 continue;
2696 }
2697
2698 DataCurve *c = (DataCurve *)it;
2699 if (c->type() != ErrorBars){
2700 if (c->type() == Function){
2701 s += ((FunctionCurve *)c)->saveToString();
2702 continue;
2703 } else if (c->type() == Box)
2704 s += "curve\t" + QString::number(c->x(0)) + "\t" + c->title().text() + "\t";
2705 else if (c->type() == Histogram)
2706 s += "curve\t-\t" + c->title().text() + "\t";//ugly hack to avoid having an empty string for c->xColumnName()
2707 else
2708 s += "curve\t" + c->xColumnName() + "\t" + c->title().text() + "\t";
2709
2710 s += saveCurveLayout(i);
2711 s += QString::number(c->xAxis())+"\t"+QString::number(c->yAxis())+"\t";
2712 s += QString::number(c->startRow())+"\t"+QString::number(c->endRow())+"\t";
2713 s += QString::number(c->isVisible())+"\n";
2714 s += c->saveToString();
2715 } else if (c->type() == ErrorBars){
2716 ErrorBarsCurve *er = (ErrorBarsCurve *)it;
2717 s += "ErrorBars\t";
2718 s += QString::number(er->direction()) + "\t";
2719 s += er->masterCurve()->xColumnName() + "\t";
2720 s += er->masterCurve()->title().text() + "\t";
2721 s += er->title().text() + "\t";
2722 s += QString::number(er->width()) + "\t";
2723 s += QString::number(er->capLength()) + "\t";
2724 s += er->color().name() + "\t";
2725 s += QString::number(er->throughSymbol()) + "\t";
2726 s += QString::number(er->plusSide()) + "\t";
2727 s += QString::number(er->minusSide()) + "\t";
2728 s += QString::number(curveIndex(er->masterCurve())) + "\n";
2729 s += er->saveToString();
2730 }
2731 }
2732 }
2733 return s;
2734 }
2735
legend()2736 LegendWidget* Graph::legend()
2737 {
2738 foreach (FrameWidget *w, d_enrichments){
2739 LegendWidget *l = qobject_cast<LegendWidget *>(w);
2740 if (l && l->isAutoUpdateEnabled())
2741 return l;
2742 }
2743 return NULL;
2744 }
2745
setLegend(const QString & s)2746 void Graph::setLegend(const QString& s)
2747 {
2748 LegendWidget *l = legend();
2749 if (l){
2750 l->setText(s);
2751 l->repaint();
2752 }
2753 }
2754
removeLegend()2755 void Graph::removeLegend()
2756 {
2757 remove(legend());
2758 }
2759
newLegend(const QString & text)2760 LegendWidget* Graph::newLegend(const QString& text)
2761 {
2762 LegendWidget* l = new LegendWidget(this);
2763 if (!l)
2764 return NULL;
2765
2766 QString s = text;
2767 if (s.isEmpty()){
2768 if (isPiePlot())
2769 s = pieLegendText();
2770 else
2771 s = legendText();
2772 }
2773 l->setText(s);
2774 ApplicationWindow *app = multiLayer()->applicationWindow();
2775 if (app){
2776 l->setFrameStyle(app->legendFrameStyle);
2777 l->setFont(app->plotLegendFont);
2778 l->setTextColor(app->legendTextColor);
2779 l->setBackgroundColor(app->legendBackground);
2780 }
2781
2782 l->setAutoUpdate(true);
2783 d_enrichments << l;
2784 emit modifiedGraph();
2785 return l;
2786 }
2787
addTimeStamp()2788 LegendWidget* Graph::addTimeStamp()
2789 {
2790 LegendWidget* l = newLegend(QDateTime::currentDateTime().toString(Qt::LocalDate));
2791 l->setAutoUpdate(false);
2792
2793 QPoint p = canvas()->pos() + QPoint(canvas()->width()/2, 10);
2794 l->move(mapToParent(p));
2795 emit modifiedGraph();
2796 return l;
2797 }
2798
insertLegend(const QStringList & lst,int fileVersion)2799 void Graph::insertLegend(const QStringList& lst, int fileVersion)
2800 {
2801 LegendWidget *l = insertText(lst, fileVersion);
2802 l->setAutoUpdate(true);
2803 }
2804
insertText(const QStringList & list,int fileVersion)2805 LegendWidget* Graph::insertText(const QStringList& list, int fileVersion)
2806 {
2807 QStringList fList = list;
2808 bool pieLabel = (list[0] == "<PieLabel>") ? true : false;
2809 LegendWidget* l = NULL;
2810 if (pieLabel)
2811 l = new PieLabel(this);
2812 else {
2813 l = new LegendWidget(this);
2814 d_enrichments << l;
2815 d_active_enrichment = l;
2816 }
2817
2818 if (fileVersion < 86 || (fileVersion > 91 && fileVersion < 96))
2819 l->move(QPoint(fList[1].toInt(),fList[2].toInt()));
2820 else {
2821 updateLayout();
2822 l->setOriginCoord(fList[1].toDouble(), fList[2].toDouble());
2823 }
2824
2825 QFont fnt=QFont (fList[3],fList[4].toInt(),fList[5].toInt(),fList[6].toInt());
2826 fnt.setUnderline(fList[7].toInt());
2827 fnt.setStrikeOut(fList[8].toInt());
2828 l->setFont(fnt);
2829
2830 l->setAngle(fList[11].toInt());
2831
2832 QString text = QString();
2833 if (fileVersion < 71){
2834 int bkg=fList[10].toInt();
2835 if (bkg <= 2)
2836 l->setFrameStyle(bkg);
2837 else if (bkg == 3){
2838 l->setFrameStyle(0);
2839 l->setBackgroundColor(QColor(255, 255, 255));
2840 }
2841 else if (bkg == 4){
2842 l->setFrameStyle(0);
2843 l->setBackgroundColor(QColor(Qt::black));
2844 }
2845
2846 int n =(int)fList.count();
2847 text += fList[12];
2848 for (int i=1; i<n-12; i++)
2849 text += "\n" + fList[12+i];
2850 } else if (fileVersion < 90) {
2851 l->setTextColor(QColor(fList[9]));
2852 l->setFrameStyle(fList[10].toInt());
2853 l->setBackgroundColor(QColor(fList[12]));
2854
2855 int n=(int)fList.count();
2856 text += fList[13];
2857 for (int i=1; i<n-13; i++)
2858 text += "\n" + fList[13+i];
2859 } else {
2860 l->setTextColor(QColor(fList[9]));
2861 l->setFrameStyle(fList[10].toInt());
2862 QColor c = QColor(fList[12]);
2863 c.setAlpha(fList[13].toInt());
2864 l->setBackgroundColor(c);
2865
2866 int n = (int)fList.count();
2867 if (n > 14)
2868 text += fList[14];
2869
2870 for (int i=1; i<n-14; i++){
2871 int j = 14+i;
2872 if (n > j)
2873 text += "\n" + fList[j];
2874 }
2875 }
2876
2877 if (fileVersion < 91)
2878 text = text.replace("\\c{", "\\l(").replace("}", ")");
2879
2880 l->setText(text);
2881 if (pieLabel){
2882 PieCurve *pie = (PieCurve *)curve(0);
2883 if(pie)
2884 pie->addLabel((PieLabel *)l);
2885 }
2886 return l;
2887 }
2888
addArrow(QStringList list,int fileVersion)2889 void Graph::addArrow(QStringList list, int fileVersion)
2890 {
2891 ArrowMarker* mrk = new ArrowMarker();
2892 if(!mrk)
2893 return;
2894
2895 insertMarker(mrk);
2896 d_lines.append(mrk);
2897
2898 if (fileVersion < 86){
2899 mrk->setStartPoint(QPoint(list[1].toInt(), list[2].toInt()));
2900 mrk->setEndPoint(QPoint(list[3].toInt(), list[4].toInt()));
2901 } else
2902 mrk->setBoundingRect(list[1].toDouble(), list[2].toDouble(),
2903 list[3].toDouble(), list[4].toDouble());
2904
2905 mrk->setWidth(list[5].toDouble());
2906 mrk->setColor(QColor(list[6]));
2907 mrk->setStyle(getPenStyle(list[7]));
2908 mrk->drawEndArrow(list[8]=="1");
2909 mrk->drawStartArrow(list[9]=="1");
2910 if (list.count()>10){
2911 mrk->setHeadLength(list[10].toInt());
2912 mrk->setHeadAngle(list[11].toInt());
2913 mrk->fillArrowHead(list[12]=="1");
2914 }
2915
2916 if (list.count()>13)//introduced in file version 0.9.7.10
2917 mrk->setAttachPolicy((ArrowMarker::AttachPolicy)list[13].toInt());
2918 }
2919
addArrow(ArrowMarker * mrk)2920 ArrowMarker* Graph::addArrow(ArrowMarker* mrk)
2921 {
2922 ArrowMarker* aux = new ArrowMarker();
2923 if (aux){
2924 d_lines.append(aux);
2925 insertMarker(aux);
2926
2927 aux->setBoundingRect(mrk->startPointCoord().x(), mrk->startPointCoord().y(),
2928 mrk->endPointCoord().x(), mrk->endPointCoord().y());
2929 aux->setWidth(mrk->width());
2930 aux->setColor(mrk->color());
2931 aux->setStyle(mrk->style());
2932 aux->drawEndArrow(mrk->hasEndArrow());
2933 aux->drawStartArrow(mrk->hasStartArrow());
2934 aux->setHeadLength(mrk->headLength());
2935 aux->setHeadAngle(mrk->headAngle());
2936 aux->fillArrowHead(mrk->filledArrowHead());
2937 aux->setAttachPolicy(mrk->attachPolicy());
2938 }
2939 return aux;
2940 }
2941
addText(LegendWidget * t)2942 LegendWidget* Graph::addText(LegendWidget* t)
2943 {
2944 LegendWidget* aux = new LegendWidget(this);
2945 aux->clone(t);
2946 d_active_enrichment = aux;
2947 d_enrichments << aux;
2948 t->raise();
2949 return aux;
2950 }
2951
saveMarkers()2952 QString Graph::saveMarkers()
2953 {
2954 QString s;
2955 foreach (QwtPlotMarker *i, d_lines){
2956 ArrowMarker* mrkL = (ArrowMarker*)i;
2957 s+="<line>\t";
2958
2959 QwtDoublePoint sp = mrkL->startPointCoord();
2960 s+=(QString::number(sp.x(), 'g', 15))+"\t";
2961 s+=(QString::number(sp.y(), 'g', 15))+"\t";
2962
2963 QwtDoublePoint ep = mrkL->endPointCoord();
2964 s+=(QString::number(ep.x(), 'g', 15))+"\t";
2965 s+=(QString::number(ep.y(), 'g', 15))+"\t";
2966
2967 s+=QString::number(mrkL->width())+"\t";
2968 s+=mrkL->color().name()+"\t";
2969 s+=penStyleName(mrkL->style())+"\t";
2970 s+=QString::number(mrkL->hasEndArrow())+"\t";
2971 s+=QString::number(mrkL->hasStartArrow())+"\t";
2972 s+=QString::number(mrkL->headLength())+"\t";
2973 s+=QString::number(mrkL->headAngle())+"\t";
2974 s+=QString::number(mrkL->filledArrowHead())+"\t";
2975 s+=QString::number(mrkL->attachPolicy())+"</line>\n";
2976 }
2977
2978 foreach(FrameWidget *f, d_enrichments)
2979 s += f->saveToString();
2980
2981 return s;
2982 }
2983
selectedXStartValue()2984 double Graph::selectedXStartValue()
2985 {
2986 if (d_range_selector && d_range_selector->isVisible())
2987 return d_range_selector->minXValue();
2988 else
2989 return 0;
2990 }
2991
selectedXEndValue()2992 double Graph::selectedXEndValue()
2993 {
2994 if (d_range_selector && d_range_selector->isVisible())
2995 return d_range_selector->maxXValue();
2996 else
2997 return 0;
2998 }
2999
plotItem(int index)3000 QwtPlotItem* Graph::plotItem(int index)
3001 {
3002 int curves = d_curves.size();
3003 if (!curves || index >= curves || index < 0)
3004 return 0;
3005
3006 return d_curves.at(index);
3007 }
3008
curve(int index)3009 PlotCurve *Graph::curve(int index)
3010 {
3011 int curves = d_curves.size();
3012 if (!curves || index >= curves || index < 0)
3013 return 0;
3014
3015 QwtPlotItem *it = d_curves.at(index);
3016 if (it && it->rtti() != QwtPlotItem::Rtti_PlotSpectrogram)
3017 return (PlotCurve*)it;
3018
3019 return 0;
3020 }
3021
dataCurve(int index)3022 DataCurve * Graph::dataCurve(int index)
3023 {
3024 PlotCurve *c = curve(index);
3025 if (c && c->type() != Function)
3026 return (DataCurve*)c;
3027
3028 return 0;
3029 }
3030
functionCurve(int index)3031 FunctionCurve * Graph::functionCurve(int index)
3032 {
3033 PlotCurve *c = curve(index);
3034 if (c && c->type() == Function)
3035 return (FunctionCurve*)c;
3036
3037 return 0;
3038 }
3039
boxCurve(int index)3040 BoxCurve * Graph::boxCurve(int index)
3041 {
3042 DataCurve *c = dataCurve(index);
3043 if (c && c->type() == Box)
3044 return (BoxCurve*)c;
3045
3046 return 0;
3047 }
3048
3049 //! get curve title string by inde (convenience function for scripts)
curveTitle(int index)3050 QString Graph::curveTitle(int index)
3051 {
3052 QwtPlotItem *item = plotItem(index);
3053 if (item)
3054 return item->title().text();
3055
3056 return QString::null;
3057 }
3058
range(const QString & curveTitle,double * start,double * end)3059 int Graph::range(const QString& curveTitle, double *start, double *end)
3060 {
3061 QwtPlotCurve *c = curve(curveTitle);
3062 if (!c)
3063 return 0;
3064
3065 return range(c, start, end);
3066 }
3067
range(QwtPlotCurve * c,double * start,double * end)3068 int Graph::range(QwtPlotCurve *c, double *start, double *end)
3069 {
3070 if (!c)
3071 return 0;
3072
3073 if (c->curveType() == QwtPlotCurve::Yfx){
3074 if (d_range_selector && d_range_selector->isVisible() &&
3075 d_range_selector->selectedCurve() == c) {
3076 *start = d_range_selector->minXValue();
3077 *end = d_range_selector->maxXValue();
3078 return d_range_selector->dataSize();
3079 } else {
3080 const QwtData *data = &(c->data());
3081 *start = data->boundingRect().left();
3082 *end = data->boundingRect().right();
3083 return c->dataSize();
3084 }
3085 } else {
3086 if (d_range_selector && d_range_selector->isVisible() &&
3087 d_range_selector->selectedCurve() == c) {
3088 *start = d_range_selector->minYValue();
3089 *end = d_range_selector->maxYValue();
3090 return d_range_selector->dataSize();
3091 } else {
3092 const QwtData *data = &(c->data());
3093 *start = data->boundingRect().bottom();
3094 *end = data->boundingRect().top();
3095 return c->dataSize();
3096 }
3097 }
3098 return 0;
3099 }
3100
initCurveLayout()3101 CurveLayout Graph::initCurveLayout()
3102 {
3103 CurveLayout cl;
3104 cl.connectType = 1;
3105 cl.lStyle = 0;
3106 cl.lWidth = 1;
3107 cl.sSize = 3;
3108 cl.sType = 0;
3109 cl.filledArea = 0;
3110 cl.aCol = Qt::black;
3111 cl.aStyle = 0;
3112 cl.lCol = Qt::black;
3113 cl.penWidth = 1;
3114 cl.symCol = Qt::black;
3115 cl.fillCol = Qt::black;
3116 return cl;
3117 }
3118
initCurveLayout(int style,int curves,bool guessLayout)3119 CurveLayout Graph::initCurveLayout(int style, int curves, bool guessLayout)
3120 {
3121 int i = d_curves.size() - 1;
3122
3123 CurveLayout cl = initCurveLayout();
3124 int color = 0, sIndex = 0;
3125 if (guessLayout)
3126 guessUniqueCurveLayout(color, sIndex);
3127
3128 QList<QColor> indexedColors = ColorBox::defaultColors();
3129 MultiLayer *ml = multiLayer();
3130 ApplicationWindow *app = 0;
3131 if (ml){
3132 app = ml->applicationWindow();
3133 if (app){
3134 indexedColors = app->indexedColors();
3135 if (app->d_indexed_symbols){
3136 QList<int> indexedSymbols = app->indexedSymbols();
3137 if (sIndex >= 0 && sIndex < indexedSymbols.size())
3138 cl.sType = indexedSymbols[sIndex] + 1;
3139 } else
3140 cl.sType = app->d_symbol_style;
3141
3142 if (style == Area || style == VerticalBars || style == HorizontalBars || style == StackBar || style == StackColumn || style == Histogram){
3143 cl.aStyle = app->defaultCurveBrush;
3144 cl.filledArea = 0.01*app->defaultCurveAlpha;
3145 }
3146
3147 cl.lStyle = app->d_curve_line_style;
3148 }
3149 }
3150 int colorsCount = indexedColors.size();
3151
3152 if (color >= 0 && color < colorsCount)
3153 cl.lCol = indexedColors[color];
3154 cl.symCol = cl.lCol;
3155 cl.fillCol = (app && app->d_fill_symbols) ? cl.lCol : QColor();
3156 if (app)
3157 cl.penWidth = app->defaultSymbolEdge;
3158
3159 if (style == Line)
3160 cl.sType = 0;
3161 else if (style == Scatter)
3162 cl.connectType = 0;
3163 else if (style == VerticalDropLines)
3164 cl.connectType = 2;
3165 else if (style == HorizontalSteps || style == VerticalSteps){
3166 cl.connectType = 3;
3167 cl.sType = 0;
3168 } else if (style == Spline)
3169 cl.connectType = 5;
3170 else if (curves && (style == VerticalBars || style == HorizontalBars)){
3171 cl.lCol = Qt::black;
3172 if (i >= 0 && i < colorsCount)
3173 cl.aCol = indexedColors[i];
3174 cl.sType = 0;
3175 QwtBarCurve *b = (QwtBarCurve*)curve(i);
3176 if (b && (b->type() == VerticalBars || b->type() == HorizontalBars)){
3177 b->setGap(qRound(100*(1-1.0/(double)curves)));
3178 b->setOffset(-50*(curves-1) + i*100);
3179 }
3180 } else if (style == StackBar || style == StackColumn){
3181 cl.lCol = Qt::black;
3182 if (i >= 0 && i < colorsCount)
3183 cl.aCol = indexedColors[i];
3184 cl.sType = 0;
3185 } else if (style == Histogram){
3186 if (i >= 0 && i < colorsCount)
3187 cl.lCol = indexedColors[i];
3188 cl.aCol = cl.lCol;
3189 cl.sType = 0;
3190 cl.aStyle = 4;
3191 } else if (style == Area){
3192 cl.aCol = cl.lCol;
3193 cl.sType = 0;
3194 cl.connectType = 1;
3195 }
3196 return cl;
3197 }
3198
updateCurveLayout(PlotCurve * c,const CurveLayout * cL)3199 void Graph::updateCurveLayout(PlotCurve* c, const CurveLayout *cL)
3200 {
3201 if (!c)
3202 return;
3203
3204 int index = curveIndex(c);
3205 if (d_curves.size() < index)
3206 return;
3207
3208 QPen pen = QPen(cL->symCol, cL->penWidth, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin);
3209 pen.setCosmetic(true);
3210 if (cL->fillCol.isValid())
3211 c->setSymbol(QwtSymbol(SymbolBox::style(cL->sType), QBrush(cL->fillCol), pen, QSize(cL->sSize, cL->sSize)));
3212 else
3213 c->setSymbol(QwtSymbol(SymbolBox::style(cL->sType), QBrush(), pen, QSize(cL->sSize, cL->sSize)));
3214
3215 pen = QPen(cL->lCol, cL->lWidth, getPenStyle(cL->lStyle), Qt::SquareCap, Qt::MiterJoin);
3216 pen.setCosmetic(true);
3217 c->setPen(pen);
3218
3219 switch (c->plotStyle()){
3220 case Scatter:
3221 c->setStyle(QwtPlotCurve::NoCurve);
3222 break;
3223 case Spline:
3224 c->setStyle(QwtPlotCurve::Lines);
3225 c->setCurveAttribute(QwtPlotCurve::Fitted);
3226 break;
3227 case VerticalSteps:
3228 c->setStyle(QwtPlotCurve::Steps);
3229 c->setCurveAttribute(QwtPlotCurve::Inverted);
3230 break;
3231 default:
3232 c->setStyle((QwtPlotCurve::CurveStyle)cL->connectType);
3233 break;
3234 }
3235
3236 QBrush brush = QBrush(cL->aCol);
3237 if (cL->filledArea){
3238 brush.setStyle(PatternBox::brushStyle(cL->aStyle));
3239 QColor color = brush.color();
3240 color.setAlphaF(cL->filledArea);
3241 brush.setColor(color);
3242 }else
3243 brush.setStyle(Qt::NoBrush);
3244
3245 c->setBrush(brush);
3246 }
3247
updateErrorBars(ErrorBarsCurve * er,bool xErr,double width,int cap,const QColor & c,bool plus,bool minus,bool through)3248 void Graph::updateErrorBars(ErrorBarsCurve *er, bool xErr, double width, int cap, const QColor& c,
3249 bool plus, bool minus, bool through)
3250 {
3251 if (!er)
3252 return;
3253
3254 if (er->width() == width && er->capLength() == cap &&
3255 er->color() == c && er->plusSide() == plus &&
3256 er->minusSide() == minus && er->throughSymbol() == through &&
3257 er->xErrors() == xErr)
3258 return;
3259
3260 er->setWidth(width);
3261 er->setCapLength(cap);
3262 er->setColor(c);
3263 er->setXErrors(xErr);
3264 er->drawThroughSymbol(through);
3265 er->drawPlusSide(plus);
3266 er->drawMinusSide(minus);
3267
3268 replot();
3269 emit modifiedGraph();
3270 }
3271
addErrorBars(const QString & yColName,Table * errTable,const QString & errColName,int type,double width,int cap,const QColor & color,bool through,bool minus,bool plus)3272 ErrorBarsCurve* Graph::addErrorBars(const QString& yColName, Table *errTable, const QString& errColName,
3273 int type, double width, int cap, const QColor& color, bool through, bool minus, bool plus)
3274 {
3275 foreach(QwtPlotItem *it, d_curves){
3276 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
3277 continue;
3278 if (((PlotCurve *)it)->type() == ErrorBars || ((PlotCurve *)it)->type() == Function)
3279 continue;
3280
3281 if (it->title().text() == yColName)
3282 return addErrorBars((DataCurve*)it, errTable, errColName, type, width, cap, color, through, minus, plus);
3283 }
3284 return NULL;
3285 }
3286
addErrorBars(const QString & xColName,const QString & yColName,Table * errTable,const QString & errColName,int type,double width,int cap,const QColor & color,bool through,bool minus,bool plus)3287 ErrorBarsCurve* Graph::addErrorBars(const QString& xColName, const QString& yColName,
3288 Table *errTable, const QString& errColName, int type, double width, int cap,
3289 const QColor& color, bool through, bool minus, bool plus)
3290 {
3291 return addErrorBars(masterCurve(xColName, yColName), errTable, errColName, type, width, cap, color, through, minus, plus);
3292 }
3293
addErrorBars(DataCurve * c,Table * errTable,const QString & errColName,int type,double width,int cap,const QColor & color,bool through,bool minus,bool plus)3294 ErrorBarsCurve* Graph::addErrorBars(DataCurve *c, Table *errTable, const QString& errColName,
3295 int type, double width, int cap, const QColor& color, bool through, bool minus, bool plus)
3296 {
3297 ErrorBarsCurve *er = new ErrorBarsCurve(type, errTable, errColName);
3298 insertCurve(er);
3299
3300 er->setMasterCurve(c);
3301 er->setCapLength(cap);
3302 er->setColor(color);
3303 er->setWidth(width);
3304 er->drawPlusSide(plus);
3305 er->drawMinusSide(minus);
3306 er->drawThroughSymbol(through);
3307
3308 if (c)
3309 updatePlot();
3310 return er;
3311 }
3312
loadErrorBars(QList<ErrorBarsCurve * > errBars,QList<int> mcIndexes)3313 void Graph::loadErrorBars(QList<ErrorBarsCurve *> errBars, QList<int> mcIndexes)
3314 {
3315 for (int i = 0; i < errBars.size() && i < mcIndexes.size(); i++){
3316 ErrorBarsCurve *er = errBars[i];
3317 if (er)
3318 er->setMasterCurve(dataCurve(mcIndexes[i]));
3319 }
3320 }
3321
isPiePlot()3322 bool Graph::isPiePlot()
3323 {
3324 if (d_curves.size() != 1)
3325 return false;
3326
3327 QwtPlotItem *it = d_curves.first();
3328 if (it->rtti() != QwtPlotItem::Rtti_PlotCurve)
3329 return false;
3330
3331 if (((PlotCurve *)it)->type() == Pie)
3332 return true;
3333
3334 return false;
3335 }
3336
plotPie(Table * w,const QString & name,const QPen & pen,int brush,int size,int firstColor,int startRow,int endRow,bool visible,double d_start_azimuth,double d_view_angle,double d_thickness,double d_horizontal_offset,double d_edge_dist,bool d_counter_clockwise,bool d_auto_labeling,bool d_values,bool d_percentages,bool d_categories,bool d_fixed_labels_pos)3337 PieCurve* Graph::plotPie(Table* w, const QString& name, const QPen& pen, int brush,
3338 int size, int firstColor, int startRow, int endRow, bool visible,
3339 double d_start_azimuth, double d_view_angle, double d_thickness,
3340 double d_horizontal_offset, double d_edge_dist, bool d_counter_clockwise,
3341 bool d_auto_labeling, bool d_values, bool d_percentages,
3342 bool d_categories, bool d_fixed_labels_pos)
3343 {
3344 if (endRow < 0)
3345 endRow = w->numRows() - 1;
3346
3347 PieCurve *pie = new PieCurve(w, name, startRow, endRow);
3348 insertCurve(pie);
3349
3350 pie->loadData();
3351 pie->initLabels();
3352
3353 pie->setPen(pen);
3354 pie->setRadius(size);
3355 pie->setFirstColor(firstColor);
3356 pie->setBrushStyle(PatternBox::brushStyle(brush));
3357 pie->setVisible(visible);
3358
3359 pie->setStartAzimuth(d_start_azimuth);
3360 pie->setViewAngle(d_view_angle);
3361 pie->setThickness(d_thickness);
3362 pie->setHorizontalOffset(d_horizontal_offset);
3363 pie->setLabelsEdgeDistance(d_edge_dist);
3364 pie->setCounterClockwise(d_counter_clockwise);
3365 pie->setLabelsAutoFormat(d_auto_labeling);
3366 pie->setLabelValuesFormat(d_values);
3367 pie->setLabelPercentagesFormat(d_percentages);
3368 pie->setLabelCategories(d_categories);
3369 pie->setFixedLabelsPosition(d_fixed_labels_pos);
3370 return pie;
3371 }
3372
plotPie(Table * w,const QString & name,int startRow,int endRow)3373 PieCurve* Graph::plotPie(Table* w, const QString& name, int startRow, int endRow)
3374 {
3375 for (int i=0; i<QwtPlot::axisCnt; i++)
3376 enableAxis(i, false);
3377 scalePicker->refresh();
3378
3379 setTitle(QString::null);
3380
3381 QwtPlotCanvas* canvas = (QwtPlotCanvas*)this->canvas();
3382 canvas->setLineWidth(0);
3383 setFrame(1, Qt::black);
3384
3385 PieCurve *pie = new PieCurve(w, name, startRow, endRow);
3386 insertCurve(pie);
3387 pie->loadData();
3388 pie->initLabels();
3389
3390 replot();
3391 return pie;
3392 }
3393
insertPlotItem(QwtPlotItem * i,int type)3394 void Graph::insertPlotItem(QwtPlotItem *i, int type)
3395 {
3396 insertCurve(i);
3397
3398 if (i->rtti() != QwtPlotItem::Rtti_PlotSpectrogram){
3399 ((PlotCurve *)i)->setPlotStyle(type);
3400 addLegendItem();
3401 }
3402 }
3403
addCurves(Table * w,const QStringList & names,int style,double lWidth,int sSize,int startRow,int endRow)3404 bool Graph::addCurves(Table* w, const QStringList& names, int style, double lWidth, int sSize, int startRow, int endRow)
3405 {
3406 if (!w)
3407 return false;
3408
3409 if (style == Pie)
3410 plotPie(w, names[0], startRow, endRow);
3411 else if (style == Box)
3412 plotBox(w, names, startRow, endRow);
3413 else if (style == VectXYXY || style == VectXYAM)
3414 plotVectors(w, names, style, startRow, endRow);
3415 else if (style == Histogram){
3416 int curves = names.count();
3417 for (int i=0; i<curves; i++){
3418 QwtHistogram *h = new QwtHistogram(w, names[i], startRow, endRow);
3419 if (h){
3420 insertCurve(h);
3421 h->loadData();
3422 CurveLayout cl = initCurveLayout(style, curves);
3423 cl.lWidth = lWidth;
3424 updateCurveLayout(h, &cl);
3425 addLegendItem();
3426 }
3427 }
3428 } else {
3429 int curves = names.count();
3430 int errCurves = 0;
3431 QStringList lst = QStringList(), masterCurvesLst = QStringList();
3432 for (int i=0; i<curves; i++){//We rearrange the list so that the error bars are placed at the end
3433 QString colName = names[i];
3434 int j = w->colIndex(colName);
3435 if (w->colPlotDesignation(j) == Table::xErr || w->colPlotDesignation(j) == Table::yErr ||
3436 w->colPlotDesignation(j) == Table::Label){
3437 errCurves++;
3438 lst << colName;
3439 } else {
3440 lst.prepend(colName);
3441 masterCurvesLst << colName;
3442 }
3443 }
3444
3445 for (int i = 0; i < curves; i++){
3446 int j = w->colIndex(lst[i]);
3447 PlotCurve *c = NULL;
3448 if (w->colPlotDesignation(j) == Table::xErr || w->colPlotDesignation(j) == Table::yErr){
3449 int xcol = w->colX(j);
3450 int ycol = w->colY(j, xcol, masterCurvesLst);
3451 if (xcol < 0 || ycol < 0)
3452 return false;
3453
3454 ErrorBarsCurve *er = NULL;
3455 if (w->colPlotDesignation(j) == Table::xErr)
3456 er = addErrorBars(w->colName(xcol), w->colName(ycol), w, lst[i], (int)ErrorBarsCurve::Horizontal);
3457 else
3458 er = addErrorBars(w->colName(xcol), w->colName(ycol), w, lst[i]);
3459
3460 if (!er)
3461 continue;
3462
3463 DataCurve *mc = er->masterCurve();
3464 if (mc)
3465 er->setColor(mc->pen().color());
3466 } else if (w->colPlotDesignation(j) == Table::Label){
3467 QString labelsCol = names[i];
3468 int xcol = w->colX(w->colIndex(labelsCol));
3469 int ycol = w->colY(w->colIndex(labelsCol), xcol);
3470 if (xcol < 0 || ycol < 0)
3471 return false;
3472
3473 DataCurve* mc = masterCurve(w->colName(xcol), w->colName(ycol));
3474 if (mc){
3475 replot();
3476 mc->setLabelsColumnName(labelsCol);
3477 } else
3478 return false;
3479 } else
3480 c = (PlotCurve *)insertCurve(w, lst[i], style, startRow, endRow);
3481
3482 if (c && c->type() != ErrorBars){
3483 CurveLayout cl = initCurveLayout(style, curves - errCurves);
3484 cl.sSize = sSize;
3485 cl.lWidth = lWidth;
3486 updateCurveLayout(c, &cl);
3487 }
3488 }
3489 }
3490
3491 replot();
3492
3493 updateSecondaryAxis(QwtPlot::xTop, true);
3494 updateSecondaryAxis(QwtPlot::yRight, true);
3495 updateAxesTitles();
3496
3497 replot();
3498
3499 d_zoomer[0]->setZoomBase();
3500 d_zoomer[1]->setZoomBase();
3501
3502 if (!d_auto_scale){
3503 for (int i = 0; i < QwtPlot::axisCnt; i++)
3504 setAxisScaleDiv(i, *axisScaleDiv(i));
3505 }
3506
3507 return true;
3508 }
3509
insertCurve(Table * w,const QString & name,int style,int startRow,int endRow)3510 DataCurve* Graph::insertCurve(Table* w, const QString& name, int style, int startRow, int endRow)
3511 {//provided for convenience
3512 int ycol = w->colIndex(name);
3513 int xcol = w->colX(ycol);
3514
3515 DataCurve* c = insertCurve(w, w->colName(xcol), w->colName(ycol), style, startRow, endRow);
3516 if (c)
3517 emit modifiedGraph();
3518 return c;
3519 }
3520
insertCurve(Table * w,int xcol,const QString & name,int style)3521 DataCurve* Graph::insertCurve(Table* w, int xcol, const QString& name, int style)
3522 {
3523 return insertCurve(w, w->colName(xcol), w->colName(w->colIndex(name)), style);
3524 }
3525
insertCurve(Table * w,const QString & xColName,const QString & yColName,int style,int startRow,int endRow)3526 DataCurve* Graph::insertCurve(Table* w, const QString& xColName, const QString& yColName, int style, int startRow, int endRow)
3527 {
3528 if (style == Histogram){
3529 DataCurve *c = new QwtHistogram(w, yColName, startRow, endRow);
3530 insertCurve(c);
3531 return c;
3532 }
3533
3534 int xcol = w->colIndex(xColName);
3535 int ycol = w->colIndex(yColName);
3536 if (xcol < 0 || ycol < 0)
3537 return NULL;
3538
3539 if (endRow < 0)
3540 endRow = w->numRows() - 1;
3541
3542 int xAxis = QwtPlot::xBottom;
3543 if (style == HorizontalBars)
3544 xAxis = QwtPlot::yLeft;
3545
3546 int size = 0;
3547 for (int i = startRow; i <= endRow; i++ ){
3548 if (!w->text(i, xcol).isEmpty() && !w->text(i, ycol).isEmpty()){
3549 size++;
3550 break;
3551 }
3552 }
3553 if (!size)
3554 return NULL;
3555
3556 DataCurve *c = 0;
3557 if (style == VerticalBars || style == StackColumn){
3558 c = new QwtBarCurve(QwtBarCurve::Vertical, w, xColName, yColName, startRow, endRow);
3559 if (style == StackColumn){
3560 style = VerticalBars;
3561 ((QwtBarCurve*)c)->setStacked();
3562 }
3563 } else if (style == HorizontalBars || style == StackBar){
3564 c = new QwtBarCurve(QwtBarCurve::Horizontal, w, xColName, yColName, startRow, endRow);
3565 if (style == StackBar){
3566 style = HorizontalBars;
3567 ((QwtBarCurve*)c)->setStacked();
3568 }
3569 } else
3570 c = new DataCurve(w, xColName, yColName, startRow, endRow);
3571
3572 insertCurve(c);
3573 c->setPlotStyle(style);
3574
3575 CurveLayout cl = initCurveLayout(style, 0, false);
3576 updateCurveLayout(c, &cl);
3577
3578 c->loadData();
3579 c->enableSpeedMode();
3580
3581 int xColType = w->columnType(xcol);
3582 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(xAxis);
3583 if (xColType == Table::Time && sd && sd->scaleType() != ScaleDraw::Time)
3584 setLabelsDateTimeFormat(xAxis, ScaleDraw::Time, w->columnFormat(xcol));
3585 else if (xColType == Table::Date && sd && sd->scaleType() != ScaleDraw::Date)
3586 setLabelsDateTimeFormat(xAxis, ScaleDraw::Date, w->columnFormat(xcol));
3587
3588 addLegendItem();
3589 return c;
3590 }
3591
insertCurve(Table * xt,const QString & xColName,Table * yt,const QString & yColName,int style,int startRow,int endRow)3592 DataCurve* Graph::insertCurve(Table* xt, const QString& xColName, Table* yt, const QString& yColName, int style, int startRow, int endRow)
3593 {
3594 if (!xt || !yt)
3595 return NULL;
3596
3597 int xcol = xt->colIndex(xColName);
3598 int ycol = yt->colIndex(yColName);
3599 if (xcol < 0 || ycol < 0)
3600 return NULL;
3601
3602 if (endRow < 0)
3603 endRow = yt->numRows() - 1;
3604
3605 int xAxis = QwtPlot::xBottom;
3606 if (style == HorizontalBars)
3607 xAxis = QwtPlot::yLeft;
3608
3609 int size = 0;
3610 for (int i = startRow; i <= endRow; i++ ){
3611 if (!xt->text(i, xcol).isEmpty() && !yt->text(i, ycol).isEmpty()){
3612 size++;
3613 break;
3614 }
3615 }
3616 if (!size)
3617 return NULL;
3618
3619 DataCurve *c = new DataCurve(xt, xColName, yt, yColName, startRow, endRow);
3620 insertCurve(c);
3621 c->setPlotStyle(style);
3622
3623 CurveLayout cl = initCurveLayout(style, 0, false);
3624 updateCurveLayout(c, &cl);
3625
3626 c->loadData();
3627 c->enableSpeedMode();
3628
3629 int xColType = xt->columnType(xcol);
3630 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(xAxis);
3631 if (xColType == Table::Time && sd && sd->scaleType() != ScaleDraw::Time)
3632 setLabelsDateTimeFormat(xAxis, ScaleDraw::Time, xt->columnFormat(xcol));
3633 else if (xColType == Table::Date && sd && sd->scaleType() != ScaleDraw::Date)
3634 setLabelsDateTimeFormat(xAxis, ScaleDraw::Date, xt->columnFormat(xcol));
3635
3636 addLegendItem();
3637 return c;
3638 }
3639
addHistogram(Matrix * m)3640 QwtHistogram* Graph::addHistogram(Matrix *m)
3641 {
3642 if (!m)
3643 return NULL;
3644
3645 QwtHistogram *c = new QwtHistogram(m);
3646 c->setStyle(QwtPlotCurve::UserCurve);
3647 c->setPen(QPen(Qt::black, 1.0));
3648 c->setBrush(QBrush(Qt::black));
3649 c->loadData();
3650 insertCurve(c);
3651
3652 addLegendItem();
3653 updatePlot();
3654 return c;
3655 }
3656
restoreHistogram(Matrix * m,const QStringList & l)3657 QwtHistogram* Graph::restoreHistogram(Matrix *m, const QStringList& l)
3658 {
3659 if (!m)
3660 return NULL;
3661
3662 QwtHistogram *h = new QwtHistogram(m);
3663 h->setBinning(l[17].toInt(), l[18].toDouble(), l[19].toDouble(), l[20].toDouble());
3664 h->setGap(l[15].toInt());
3665 h->setOffset(l[16].toInt());
3666 h->loadData();
3667 h->setAxis(l[l.count()-5].toInt(), l[l.count()-4].toInt());
3668 h->setVisible(l.last().toInt());
3669
3670 insertCurve(h);
3671 return h;
3672 }
3673
plotVectors(Table * w,const QStringList & colList,int style,int startRow,int endRow)3674 VectorCurve* Graph::plotVectors(Table* w, const QStringList& colList, int style, int startRow, int endRow)
3675 {
3676 if (colList.count() != 4)
3677 return NULL;
3678
3679 if (endRow < 0)
3680 endRow = w->numRows() - 1;
3681
3682 VectorCurve *v = 0;
3683 if (style == VectXYAM)
3684 v = new VectorCurve(VectorCurve::XYAM, w, colList[0], colList[1], colList[2], colList[3], startRow, endRow);
3685 else
3686 v = new VectorCurve(VectorCurve::XYXY, w, colList[0], colList[1], colList[2], colList[3], startRow, endRow);
3687
3688 if (!v)
3689 return NULL;
3690
3691 insertCurve(v);
3692 v->setPlotStyle(style);
3693 v->loadData();
3694 v->setStyle(QwtPlotCurve::NoCurve);
3695
3696 addLegendItem();
3697 updatePlot();
3698 return v;
3699 }
3700
updateVectorsLayout(int curve,const QColor & color,double width,int arrowLength,int arrowAngle,bool filled,int position,const QString & xEndColName,const QString & yEndColName)3701 void Graph::updateVectorsLayout(int curve, const QColor& color, double width,
3702 int arrowLength, int arrowAngle, bool filled, int position,
3703 const QString& xEndColName, const QString& yEndColName)
3704 {
3705 VectorCurve *vect = (VectorCurve *)this->curve(curve);
3706 if (!vect)
3707 return;
3708
3709 vect->setColor(color);
3710 vect->setWidth(width);
3711 vect->setHeadLength(arrowLength);
3712 vect->setHeadAngle(arrowAngle);
3713 vect->fillArrowHead(filled);
3714 vect->setPosition(position);
3715
3716 if (!xEndColName.isEmpty() && !yEndColName.isEmpty())
3717 vect->setVectorEnd(xEndColName, yEndColName);
3718
3719 replot();
3720 emit modifiedGraph();
3721 }
3722
setAutoScale()3723 void Graph::setAutoScale()
3724 {
3725 for (int i = 0; i < QwtPlot::axisCnt; i++){
3726 setAxisAutoScale(i);
3727 d_user_step[i] = 0.0;
3728 }
3729
3730 replot();
3731
3732 updateScale();
3733 emit modifiedGraph();
3734 }
3735
updateAxesTitles()3736 void Graph::updateAxesTitles()
3737 {
3738 for (int i = 0; i < QwtPlot::axisCnt; i++)
3739 ((QwtPlot *)this)->setAxisTitle(i, parseAxisTitle(i));
3740 }
3741
updateAxisTitle(int axis)3742 void Graph::updateAxisTitle(int axis)
3743 {
3744 if (axis < 0 || axis >= QwtPlot::axisCnt)
3745 return;
3746
3747 ((QwtPlot *)this)->setAxisTitle(axis, parseAxisTitle(axis));
3748 }
3749
updatePlot()3750 void Graph::updatePlot()
3751 {
3752 if (d_auto_scale && !zoomOn() && d_active_tool == NULL){
3753 for (int i = 0; i < QwtPlot::axisCnt; i++){
3754 setAxisAutoScale(i);
3755 d_user_step[i] = 0.0;
3756 }
3757 }
3758 replot();
3759 updateScale();
3760 }
3761
updateScale()3762 void Graph::updateScale()
3763 {
3764 if (!d_auto_scale){
3765 //We need this hack due to the fact that in Qwt 5.0 we can't
3766 //disable autoscaling in an easier way, like for example: setAxisAutoScale(axisId, false)
3767 for (int i = 0; i < QwtPlot::axisCnt; i++)
3768 setAxisScaleDiv(i, *axisScaleDiv(i));
3769 }
3770
3771 replot();
3772
3773 updateMarkersBoundingRect();
3774
3775 if (d_synchronize_scales){
3776 updateSecondaryAxis(QwtPlot::xTop);
3777 updateSecondaryAxis(QwtPlot::yRight);
3778 }
3779
3780 replot();//TODO: avoid 2nd replot!
3781 d_zoomer[0]->setZoomBase();
3782 d_zoomer[1]->setZoomBase();
3783 }
3784
setBarsGap(int curve,int gapPercent,int offset)3785 void Graph::setBarsGap(int curve, int gapPercent, int offset)
3786 {
3787 QwtBarCurve *bars = (QwtBarCurve *)this->curve(curve);
3788 if (!bars)
3789 return;
3790
3791 if (bars->gap() == gapPercent && bars->offset() == offset)
3792 return;
3793
3794 bars->setGap(gapPercent);
3795 bars->setOffset(offset);
3796 }
3797
removePie()3798 void Graph::removePie()
3799 {
3800 QList <PieLabel *> labels = ((PieCurve *)curve(0))->labelsList();
3801 foreach(PieLabel *l, labels)
3802 l->setPieCurve(0);
3803
3804 removeCurve(0);
3805 replot();
3806
3807 emit modifiedGraph();
3808 }
3809
removeCurves(const QString & s)3810 void Graph::removeCurves(const QString& s)
3811 {
3812 foreach(QwtPlotItem *it, d_curves){
3813 if (it->title().text() == s){
3814 removeCurve(d_curves.indexOf(it));
3815 continue;
3816 }
3817
3818 if (it->rtti() != QwtPlotItem::Rtti_PlotCurve)
3819 continue;
3820 if (((PlotCurve *)it)->type() == Function)
3821 continue;
3822
3823 if(((DataCurve *)it)->plotAssociation().join(",").contains(s))
3824 removeCurve(d_curves.indexOf(it));
3825 }
3826 replot();
3827 }
3828
removeCurve(const QString & s)3829 void Graph::removeCurve(const QString& s)
3830 {
3831 removeCurve(curveIndex(s));
3832 }
3833
removeCurve(int index)3834 void Graph::removeCurve(int index)
3835 {
3836 if (index < 0 || index >= d_curves.size())
3837 return;
3838
3839 removeCurve(d_curves.at(index));
3840 }
3841
removeCurve(QwtPlotItem * it)3842 void Graph::removeCurve(QwtPlotItem *it)
3843 {
3844 if (!it)
3845 return;
3846
3847 int index = d_curves.indexOf(it);
3848 removeLegendItem(index);
3849
3850 if (it->rtti() != QwtPlotItem::Rtti_PlotSpectrogram){
3851 int curveType = ((PlotCurve *)it)->type();
3852 if (curveType == ErrorBars)
3853 ((ErrorBarsCurve *)it)->detachFromMasterCurve();
3854 else if (curveType != Function){
3855 ((DataCurve *)it)->clearErrorBars();
3856 ((DataCurve *)it)->clearLabels();
3857 }
3858 if (d_fit_curves.contains((QwtPlotCurve *)it)){
3859 int i = d_fit_curves.indexOf((QwtPlotCurve *)it);
3860 if (i >= 0 && i < d_fit_curves.size())
3861 d_fit_curves.removeAt(i);
3862 }
3863 } else {
3864 ((Spectrogram *)it)->clearLabels();
3865 QwtScaleWidget *colorAxis = axisWidget(((Spectrogram *)it)->colorScaleAxis());
3866 if (colorAxis)
3867 colorAxis->setColorBarEnabled(false);
3868 }
3869
3870 if (d_range_selector && d_range_selector->isVisible() &&
3871 curve(index) == d_range_selector->selectedCurve()){
3872 int curves = d_curves.size();
3873 if (curves > 1 && (index - 1) >= 0)
3874 d_range_selector->setSelectedCurve(curve(index - 1));
3875 else if (curves > 1 && index + 1 < curves)
3876 d_range_selector->setSelectedCurve(curve(index + 1));
3877 else
3878 disableTools();
3879 }
3880
3881 it->detach();
3882 d_curves.removeAll(it);
3883 emit modifiedGraph();
3884 }
3885
removeLegendItem(int index)3886 void Graph::removeLegendItem(int index)
3887 {
3888 if (index < 0 || index >= d_curves.size())
3889 return;
3890
3891 QwtPlotItem *it = d_curves.at(index);
3892 if (!it || it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
3893 return;
3894
3895 if (((PlotCurve *)it)->type() == ErrorBars)
3896 return;
3897
3898 foreach(FrameWidget *fw, d_enrichments){
3899 LegendWidget *l = qobject_cast<LegendWidget *>(fw);
3900 if (l && l->isAutoUpdateEnabled()){
3901 QString text = l->text();
3902 QStringList items = text.split( "\n", QString::SkipEmptyParts);
3903
3904 if (index >= (int) items.count())
3905 continue;
3906
3907 QStringList lst = items.grep( "\\l(" + QString::number(index + 1) + ")" );
3908 if (lst.isEmpty())
3909 continue;
3910
3911 items.remove(lst[0]);//remove the corresponding legend string
3912
3913 for (int i=0; i<items.count(); i++){//set new curves indexes in legend text
3914 QString item = items[i];
3915 int pos1 = item.indexOf("\\l(");
3916 int pos2 = item.indexOf(")", pos1);
3917 int pos = pos1 + 3;
3918 int n = pos2 - pos;
3919 int cv = item.mid(pos, n).toInt();
3920 if (cv > index){
3921 int id = cv - 1;
3922 if (!id)
3923 id = 1;
3924 item.replace(pos, n, QString::number(id));
3925 }
3926 pos1 = item.indexOf("%(", pos2);
3927 if (item.contains(","))
3928 pos2 = item.indexOf(",", pos1);
3929 else
3930 pos2 = item.indexOf(")", pos1);
3931 pos = pos1 + 2;
3932 n = pos2 - pos;
3933 cv = item.mid(pos, n).toInt();
3934 if (cv > index){
3935 int id = cv - 1;
3936 if (!id)
3937 id = 1;
3938 item.replace(pos, n, QString::number(id));
3939 }
3940 items[i] = item;
3941 }
3942 text = items.join ( "\n" );
3943 l->setText(text);
3944 }
3945 }
3946 }
3947
addLegendItem()3948 void Graph::addLegendItem()
3949 {
3950 foreach(FrameWidget *fw, d_enrichments){
3951 LegendWidget *l = qobject_cast<LegendWidget *>(fw);
3952 if (l && l->isAutoUpdateEnabled()){
3953 QString text = l->text();
3954 if (text.endsWith("\n") || text.isEmpty())
3955 text.append(legendText(false, d_curves.size() - 1));
3956 else
3957 text.append("\n" + legendText(false, d_curves.size() - 1));
3958 l->setText(text);
3959 l->repaint();
3960 }
3961 }
3962 }
3963
contextMenuEvent(QContextMenuEvent * e)3964 void Graph::contextMenuEvent(QContextMenuEvent *e)
3965 {
3966 if (d_selected_arrow){
3967 emit showMarkerPopupMenu();
3968 return;
3969 }
3970
3971 if (!canvas()->geometry().contains(mapFromGlobal(e->globalPos())))
3972 return;
3973
3974 QPoint pos = canvas()->mapFromParent(e->pos());
3975 int dist, point;
3976 QwtPlotItem *item = closestCurve(pos.x(), pos.y(), dist, point);
3977 if (item && dist < 10)//10 pixels tolerance
3978 emit showCurveContextMenu(item);
3979 else
3980 emit showContextMenu();
3981
3982 e->accept();
3983 }
3984
closeEvent(QCloseEvent * e)3985 void Graph::closeEvent(QCloseEvent *e)
3986 {
3987 emit closedGraph();
3988 e->accept();
3989 }
3990
zoomOn()3991 bool Graph::zoomOn()
3992 {
3993 return (d_zoomer[0]->isEnabled() || d_zoomer[1]->isEnabled());
3994 }
3995
zoomed(const QwtDoubleRect &)3996 void Graph::zoomed (const QwtDoubleRect &)
3997 {
3998 updateMarkersBoundingRect();
3999 emit modifiedGraph();
4000
4001 for (int i = 0; i < QwtPlot::axisCnt; i++)
4002 axisDivChanged(this, i);
4003 }
4004
zoom(bool on)4005 void Graph::zoom(bool on)
4006 {
4007 d_zoomer[0]->setEnabled(on);
4008 d_zoomer[1]->setEnabled(on);
4009 foreach(QwtPlotItem *it, d_curves){
4010 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram && ((Spectrogram *)it)->hasColorScale()){
4011 if (((Spectrogram *)it)->colorScaleAxis() == QwtPlot::xBottom ||
4012 ((Spectrogram *)it)->colorScaleAxis() == QwtPlot::yLeft)
4013 d_zoomer[0]->setEnabled(false);
4014 else
4015 d_zoomer[1]->setEnabled(false);
4016 }
4017 }
4018
4019 if (on)
4020 canvas()->setCursor(QCursor(QPixmap(":/lens.png"), -1, -1));
4021 else
4022 canvas()->setCursor(Qt::arrowCursor);
4023 }
4024
zoomOut()4025 void Graph::zoomOut()
4026 {
4027 d_zoomer[0]->zoom(-1);
4028 d_zoomer[1]->zoom(-1);
4029
4030 if (d_synchronize_scales){
4031 updateSecondaryAxis(QwtPlot::xTop);
4032 updateSecondaryAxis(QwtPlot::yRight);
4033 }
4034 }
4035
enablePanningMagnifier(bool on,int mode)4036 void Graph::enablePanningMagnifier(bool on, int mode)
4037 {
4038 if (d_magnifier)
4039 delete d_magnifier;
4040 if (d_panner)
4041 delete d_panner;
4042
4043 QwtPlotCanvas *cnvs = canvas();
4044 if (on){
4045 cnvs->setCursor(Qt::pointingHandCursor);
4046 d_magnifier = new QwtPlotMagnifier(cnvs);
4047 d_magnifier->setZoomInKey(Qt::Key_Plus, Qt::ShiftModifier);
4048
4049 for (int i = 0; i < QwtPlot::axisCnt; i++){
4050 QwtScaleWidget *scale = axisWidget(i);
4051 if (scale)
4052 connect(scale, SIGNAL(scaleDivChanged()), this, SLOT(updateMarkersBoundingRect()));
4053 }
4054
4055 d_panner = new QwtPlotPanner(cnvs);
4056 connect(d_panner, SIGNAL(panned(int, int)), multiLayer(), SLOT(notifyChanges()));
4057
4058 foreach (QwtPlotItem *it, d_curves){
4059 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram){
4060 Spectrogram *sp = (Spectrogram *)it;
4061 int axis = sp->colorScaleAxis();
4062 d_magnifier->setAxisEnabled (axis, false);
4063 d_panner->setAxisEnabled (axis, false);
4064 }
4065 }
4066
4067 if (mode == 1){
4068 cnvs->setCursor(Qt::SizeVerCursor);
4069 d_magnifier->setAxisEnabled (QwtPlot::xBottom, false);
4070 d_magnifier->setAxisEnabled (QwtPlot::xTop, false);
4071 d_panner->setAxisEnabled (QwtPlot::xBottom, false);
4072 d_panner->setAxisEnabled (QwtPlot::xTop, false);
4073 } else if (mode == 2){
4074 cnvs->setCursor(Qt::SizeHorCursor);
4075 d_magnifier->setAxisEnabled (QwtPlot::yLeft, false);
4076 d_magnifier->setAxisEnabled (QwtPlot::yRight, false);
4077 d_panner->setAxisEnabled (QwtPlot::yLeft, false);
4078 d_panner->setAxisEnabled (QwtPlot::yRight, false);
4079 }
4080 } else {
4081 for (int i = 0; i < QwtPlot::axisCnt; i++){
4082 QwtScaleWidget *scale = axisWidget(i);
4083 if (scale)
4084 disconnect(scale, SIGNAL(scaleDivChanged()), this, SLOT(updateMarkersBoundingRect()));
4085 }
4086
4087 cnvs->setCursor(Qt::arrowCursor);
4088 d_magnifier = NULL;
4089 d_panner = NULL;
4090 }
4091 }
4092
addImage(ImageWidget * i)4093 ImageWidget* Graph::addImage(ImageWidget* i)
4094 {
4095 if (!i)
4096 return 0;
4097
4098 ImageWidget* i2 = new ImageWidget(this, i->fileName());
4099 if (i2){
4100 d_enrichments << i2;
4101 i2->setCoordinates(i->xValue(), i->yValue(), i->right(), i->bottom());
4102 }
4103 return i2;
4104 }
4105
addImage(const QString & fileName)4106 ImageWidget* Graph::addImage(const QString& fileName)
4107 {
4108 if (fileName.isEmpty() || !QFile::exists(fileName))
4109 return 0;
4110
4111 ImageWidget* i = new ImageWidget(this, fileName);
4112 if (i){
4113 d_enrichments << i;
4114 emit modifiedGraph();
4115 }
4116 return i;
4117 }
4118
addImage(const QImage & image)4119 ImageWidget* Graph::addImage(const QImage& image)
4120 {
4121 ImageWidget* i = new ImageWidget(this, image);
4122 if (i){
4123 d_enrichments << i;
4124 emit modifiedGraph();
4125 }
4126 return i;
4127 }
4128
insertImageMarker(const QStringList & lst,int fileVersion)4129 void Graph::insertImageMarker(const QStringList& lst, int fileVersion)
4130 {
4131 QString fn = lst[1];
4132 if (!QFile::exists(fn)){
4133 QMessageBox::warning(0, tr("QtiPlot - File open error"),
4134 tr("Image file: <p><b> %1 </b><p>does not exist anymore!").arg(fn));
4135 } else {
4136 ImageWidget* mrk = new ImageWidget(this, fn);
4137 if (!mrk)
4138 return;
4139
4140 d_enrichments << mrk;
4141
4142 if (fileVersion < 86){
4143 mrk->setOrigin(lst[2].toInt(), lst[3].toInt());
4144 mrk->resize(QSize(lst[4].toInt(), lst[5].toInt()));
4145 } else if (fileVersion < 90) {
4146 double left = lst[2].toDouble();
4147 double right = left + lst[4].toDouble();
4148 double top = lst[3].toDouble();
4149 double bottom = top - lst[5].toDouble();
4150 mrk->setCoordinates(left, top, right, bottom);
4151 } else
4152 mrk->setCoordinates(lst[2].toDouble(), lst[3].toDouble(), lst[4].toDouble(), lst[5].toDouble());
4153 }
4154 }
4155
drawLine(bool on,bool arrow)4156 void Graph::drawLine(bool on, bool arrow)
4157 {
4158 drawLineOn = on;
4159 drawArrowOn = arrow;
4160 if (!on)
4161 emit drawLineEnded(true);
4162 }
4163
modifyFunctionCurve(int curve,int type,const QStringList & formulas,const QString & var,double start,double end,int points,const QMap<QString,double> & constants)4164 void Graph::modifyFunctionCurve(int curve, int type, const QStringList &formulas,
4165 const QString& var, double start, double end, int points, const QMap<QString, double>& constants)
4166 {
4167 FunctionCurve *c = (FunctionCurve *)this->curve(curve);
4168 if (!c)
4169 return;
4170
4171 QString oldVar = c->variable();
4172 QStringList oldFormulas = c->formulas();
4173 const QMap<QString, double> oldConstants = c->constants();
4174 double oldStartRange = c->startRange();
4175 double oldEndRange = c->endRange();
4176 int oldPoints = c->dataSize();
4177 int oldType = c->functionType();
4178 if (oldType == type &&
4179 oldVar == var &&
4180 oldFormulas == formulas &&
4181 oldStartRange == start &&
4182 oldEndRange == end &&
4183 oldPoints == points &&
4184 oldConstants == constants)
4185 return;
4186
4187 QString oldLegend = c->legend();
4188
4189 c->setFunctionType((FunctionCurve::FunctionType)type);
4190 c->setRange(start, end);
4191 c->setFormulas(formulas);
4192 c->setVariable(var);
4193 c->setConstants(constants);
4194 if (!c->loadData(points)){
4195 c->setFunctionType((FunctionCurve::FunctionType)oldType);
4196 c->setRange(oldStartRange, oldEndRange);
4197 c->setFormulas(oldFormulas);
4198 c->setVariable(oldVar);
4199 c->setConstants(oldConstants);
4200 return;
4201 }
4202
4203 foreach(FrameWidget *fw, d_enrichments){
4204 LegendWidget *l = qobject_cast<LegendWidget *>(fw);
4205 if (l && l->isAutoUpdateEnabled()){//update legends
4206 QString text = (l->text()).replace(oldLegend, c->legend());
4207 l->setText(text);
4208 }
4209 }
4210 updatePlot();
4211 emit modifiedGraph();
4212 }
4213
generateFunctionName(const QString & name)4214 QString Graph::generateFunctionName(const QString& name)
4215 {
4216 int index = 1;
4217 QString newName = name + QString::number(index);
4218
4219 QStringList lst;
4220 foreach(QwtPlotItem *it, d_curves){
4221 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
4222 continue;
4223
4224 PlotCurve *c = (PlotCurve*)it;
4225 if (c->type() == Function)
4226 lst << c->title().text();
4227 }
4228
4229 while(lst.contains(newName))
4230 newName = name + QString::number(++index);
4231 return newName;
4232 }
4233
addFunction(const QStringList & formulas,double start,double end,int points,const QString & var,int type,const QString & title)4234 FunctionCurve* Graph::addFunction(const QStringList &formulas, double start, double end, int points, const QString &var, int type, const QString& title)
4235 {
4236 QString name;
4237 if (!title.isEmpty())
4238 name = title;
4239 else
4240 name = generateFunctionName();
4241
4242 FunctionCurve *c = new FunctionCurve((const FunctionCurve::FunctionType)type, name);
4243 c->setRange(start, end);
4244 c->setFormulas(formulas);
4245 c->setVariable(var);
4246 c->loadData(points);
4247
4248 insertCurve(c);
4249
4250 int colorIndex = 0, symbolIndex;
4251 guessUniqueCurveLayout(colorIndex, symbolIndex);
4252 c->setPen(QPen(ColorBox::defaultColor(colorIndex), 1.0));
4253
4254 addLegendItem();
4255 updatePlot();
4256
4257 emit modifiedGraph();
4258 return c;
4259 }
4260
insertFunctionCurve(const QString & formula,int points,int fileVersion)4261 FunctionCurve* Graph::insertFunctionCurve(const QString& formula, int points, int fileVersion)
4262 {
4263 int type = 0;
4264 QStringList formulas;
4265 QString var, name = QString::null;
4266 double start = 0.0, end = 0.0;
4267
4268 QStringList curve = formula.split(",");
4269 if (fileVersion < 87) {
4270 if (curve[0][0]=='f') {
4271 type = FunctionCurve::Normal;
4272 formulas += curve[0].section('=',1,1);
4273 var = curve[1];
4274 start = curve[2].toDouble();
4275 end = curve[3].toDouble();
4276 } else if (curve[0][0]=='X') {
4277 type = FunctionCurve::Parametric;
4278 formulas += curve[0].section('=',1,1);
4279 formulas += curve[1].section('=',1,1);
4280 var = curve[2];
4281 start = curve[3].toDouble();
4282 end = curve[4].toDouble();
4283 } else if (curve[0][0]=='R') {
4284 type = FunctionCurve::Polar;
4285 formulas += curve[0].section('=',1,1);
4286 formulas += curve[1].section('=',1,1);
4287 var = curve[2];
4288 start = curve[3].toDouble();
4289 end = curve[4].toDouble();
4290 }
4291 } else {
4292 type = curve[0].toInt();
4293 name = curve[1];
4294
4295 if (type == FunctionCurve::Normal) {
4296 formulas << curve[2];
4297 var = curve[3];
4298 start = curve[4].toDouble();
4299 end = curve[5].toDouble();
4300 } else if (type == FunctionCurve::Polar || type == FunctionCurve::Parametric) {
4301 formulas << curve[2];
4302 formulas << curve[3];
4303 var = curve[4];
4304 start = curve[5].toDouble();
4305 end = curve[6].toDouble();
4306 }
4307 }
4308 return addFunction(formulas, start, end, points, var, type, name);
4309 }
4310
createTable(const QString & curveName)4311 void Graph::createTable(const QString& curveName)
4312 {
4313 if (curveName.isEmpty())
4314 return;
4315
4316 const QwtPlotCurve* cv = curve(curveName);
4317 if (!cv)
4318 return;
4319
4320 createTable(cv);
4321 }
4322
createTable(const QwtPlotCurve * curve)4323 void Graph::createTable(const QwtPlotCurve* curve)
4324 {
4325 if (!curve)
4326 return;
4327
4328 MultiLayer *plot = multiLayer();
4329 if (!plot)
4330 return;
4331
4332 ApplicationWindow *app = plot->applicationWindow();
4333 if (!app)
4334 return;
4335
4336 int size = curve->dataSize();
4337 Table *t = app->newTable(size, 2, QString::null, tr("Data set generated from curve") + ": " + curve->title().text());
4338 for (int i = 0; i < size; i++){
4339 t->setCell(i, 0, curve->x(i));
4340 t->setCell(i, 1, curve->y(i));
4341 }
4342 t->showNormal();
4343 }
4344
saveToString(bool saveAsTemplate)4345 QString Graph::saveToString(bool saveAsTemplate)
4346 {
4347 QString s="<graph>\n";
4348 s+="ggeometry\t";
4349 s+=QString::number(pos().x())+"\t";
4350 s+=QString::number(pos().y())+"\t";
4351 s+=QString::number(geometry().width())+"\t";
4352 s+=QString::number(geometry().height())+"\n";
4353
4354 MultiLayer *ml = multiLayer();
4355 if (ml){
4356 s += "<PageGeometry>";
4357 s += QString::number((double)pos().x()/(double)ml->canvas()->width()) + "\t";
4358 s += QString::number((double)pos().y()/(double)ml->canvas()->height()) + "\t";
4359 s += QString::number((double)geometry().width()/(double)ml->canvas()->width()) + "\t";
4360 s += QString::number((double)geometry().height()/(double)ml->canvas()->height());
4361 s += "</PageGeometry>\n";
4362 }
4363
4364 s+=saveTitle();
4365 s+="<Antialiasing>" + QString::number(d_antialiasing) + "</Antialiasing>\n";
4366 s+="<Autoscaling>" + QString::number(d_auto_scale) + "</Autoscaling>\n";
4367 s+="<ScaleFonts>" + QString::number(autoScaleFonts) + "</ScaleFonts>\n";
4368 s+="<GridOnTop>" + QString::number(d_grid_on_top) + "</GridOnTop>\n";
4369 s+="<MissingDataGap>" + QString::number(d_missing_data_gap) + "</MissingDataGap>\n";
4370 s+="Background\t" + paletteBackgroundColor().name() + "\t";
4371 s+=QString::number(paletteBackgroundColor().alpha()) + "\n";
4372 s+=saveBackgroundImage();
4373 s+="Margin\t"+QString::number(margin())+"\n";
4374 s+="Border\t"+QString::number(lineWidth())+"\t"+frameColor().name()+"\n";
4375 s+=grid()->saveToString();
4376 s+=saveEnabledAxes();
4377 s+="AxesTitles\t"+saveScaleTitles();
4378 s+=saveAxesTitleColors();
4379 s+=saveAxesTitleAlignement();
4380 s+=saveFonts();
4381 s+=saveAxesColors();
4382 s+=saveAxesBaseline();
4383 s+=saveCanvas();
4384
4385 if (!saveAsTemplate)
4386 s+=saveCurves();
4387
4388 s+=saveScale();
4389 s+=saveAxesFormulas();
4390 s+=saveLabelsFormat();
4391 s+=saveAxesLabelsType();
4392 s+=saveTicksType();
4393 s+="TicksLength\t"+QString::number(minorTickLength())+"\t"+QString::number(majorTickLength())+"\n";
4394 s+=saveAxesBackbones();
4395 s+="AxesLineWidth\t"+QString::number(axesLinewidth())+"\n";
4396 s+=saveLabelsRotation();
4397 s+=saveLabelsPrefixAndSuffix();
4398 s+=saveTickLabelsSpace();
4399 s+=saveEnabledTickLabels();
4400 s+=saveMarkers();
4401 if (d_Douglas_Peuker_tolerance > 0.0){
4402 s += "<SpeedMode>" + QString::number(d_Douglas_Peuker_tolerance) + "\t";
4403 s += QString::number(d_speed_mode_points) + "</SpeedMode>\n";
4404 }
4405
4406 if (d_image_profiles_tool){
4407 s += "<ImageProfileTool>" + d_image_profiles_tool->matrix()->objectName();
4408 if (!d_image_profiles_tool->horizontalTable().isNull())
4409 s += "\t" + d_image_profiles_tool->horizontalTable()->objectName();
4410 if (!d_image_profiles_tool->verticalTable().isNull())
4411 s += "\t" + d_image_profiles_tool->verticalTable()->objectName();
4412 s += "</ImageProfileTool>\n";
4413 s += "<ImageProfileValues>";
4414 s += QString::number(d_image_profiles_tool->xValue()) + "\t" + QString::number(d_image_profiles_tool->yValue());
4415 int pixels = d_image_profiles_tool->averagePixels();
4416 if (pixels > 1)
4417 s += "\t" + QString::number(pixels);
4418 s += "</ImageProfileValues>\n";
4419 }
4420
4421 if (isWaterfallPlot()){
4422 s += "<waterfall>" + QString::number(d_waterfall_offset_x) + ",";
4423 s += QString::number(d_waterfall_offset_y) + ",";
4424 bool sideLines = d_curves.size() > 0 && curve(0)->sideLinesEnabled();
4425 s += QString::number(sideLines) + "</waterfall>\n";
4426 }
4427
4428 s += "</graph>\n";
4429 return s;
4430 }
4431
saveBackgroundImage()4432 QString Graph::saveBackgroundImage()
4433 {
4434 if (d_canvas_bkg_path.isEmpty())
4435 return QString();
4436
4437 QString s = "<BackgroundImage>\n";
4438 s += "<path>" + d_canvas_bkg_path + "</path>\n";
4439 s += "<xpm>\n";
4440 QByteArray bytes;
4441 QBuffer buffer(&bytes);
4442 buffer.open(QIODevice::WriteOnly);
4443 d_canvas_bkg_pix.save(&buffer, "XPM");
4444 s += QString(bytes);
4445 s += "</xpm>\n";
4446
4447 return s + "</BackgroundImage>\n";
4448 }
4449
restoreBackgroundImage(const QStringList & lst)4450 void Graph::restoreBackgroundImage(const QStringList& lst)
4451 {
4452 QStringList::const_iterator line;
4453 for (line = lst.begin(); line != lst.end(); line++){
4454 QString s = *line;
4455 if (s.contains("<path>"))
4456 d_canvas_bkg_path = s.remove("<path>").remove("</path>");
4457 else if (s.contains("<xpm>")){
4458 QString xpm;
4459 while ( s != "</xpm>" ){
4460 s = *(++line);
4461 xpm += s + "\n";
4462 }
4463 d_canvas_bkg_pix.loadFromData(xpm.toAscii());
4464 }
4465 }
4466 }
4467
updateMarkersBoundingRect(bool rescaleEvent)4468 void Graph::updateMarkersBoundingRect(bool rescaleEvent)
4469 {
4470 foreach(FrameWidget *f, d_enrichments){
4471 if (!rescaleEvent && qobject_cast<LegendWidget *>(f)){
4472 f->resetOrigin();
4473 continue;
4474 }
4475
4476 if (f->attachPolicy() == FrameWidget::Scales)
4477 f->resetCoordinates();
4478 else if (rescaleEvent)
4479 f->updateCoordinates();
4480 }
4481 replot();
4482
4483 if (!d_lines.size())
4484 return;
4485
4486 foreach (QwtPlotMarker *i, d_lines)
4487 ((ArrowMarker*)i)->updateBoundingRect();
4488
4489 replot();
4490 }
4491
resizeEvent(QResizeEvent * e)4492 void Graph::resizeEvent ( QResizeEvent *e )
4493 {
4494 QSize size = e->size();
4495 if (size.height() <= 0)
4496 size.setHeight(e->oldSize().height());
4497
4498 resize(size);
4499 updateLayout();
4500 updateCurveLabels();
4501
4502 bool layerSelected = multiLayer()->hasSelectedLayers();
4503 foreach(FrameWidget *f, d_enrichments){
4504 if (layerSelected && f->attachPolicy() == FrameWidget::Page)
4505 f->updateCoordinates();
4506 else {
4507 TexWidget *tw = qobject_cast<TexWidget *>(f);
4508 LegendWidget *l = qobject_cast<LegendWidget *>(f);
4509 if (tw || l)
4510 f->resetOrigin();
4511 else
4512 f->resetCoordinates();
4513 }
4514 }
4515 }
4516
scaleFonts(double factor)4517 void Graph::scaleFonts(double factor)
4518 {
4519 if (factor == 1.0 || factor <= 0.0)
4520 return;
4521
4522 for (int i = 0; i<QwtPlot::axisCnt; i++){
4523 QFont font = axisFont(i);
4524 font.setPointSizeFloat(factor*font.pointSizeF());
4525 setAxisFont(i, font);
4526
4527 QwtText title = axisTitle(i);
4528 font = title.font();
4529 font.setPointSizeF(factor*font.pointSizeF());
4530 title.setFont(font);
4531 ((QwtPlot *)this)->setAxisTitle(i, title);
4532 }
4533
4534 QwtText t = this->title();
4535 QFont font = t.font();
4536 font.setPointSizeF(factor*font.pointSizeF());
4537 t.setFont(font);
4538 setTitle(t);
4539
4540 QList<QwtPlotItem *> curves = curvesList();
4541 foreach(QwtPlotItem *i, curves){
4542 if(i->rtti() != QwtPlotItem::Rtti_PlotSpectrogram &&
4543 ((PlotCurve *)i)->type() != Graph::Function &&
4544 ((DataCurve *)i)->hasLabels()){
4545 QFont font = ((DataCurve *)i)->labelsFont();
4546 font.setPointSizeF(factor*font.pointSizeF());
4547 ((DataCurve *)i)->setLabelsFont(font);
4548 if (((DataCurve *)i)->hasSelectedLabels())
4549 notifyFontChange(font);
4550 }
4551 }
4552
4553 foreach(FrameWidget *f, d_enrichments){
4554 LegendWidget *l = qobject_cast<LegendWidget *>(f);
4555 if (!l)
4556 continue;
4557 QFont font = l->font();
4558 font.setPointSizeF(factor*font.pointSizeF());
4559 l->setFont(font);
4560 l->resetOrigin();
4561 }
4562 }
4563
setFrame(int width,const QColor & color)4564 void Graph::setFrame (int width, const QColor& color)
4565 {
4566 if (frameColor() == color && width == lineWidth())
4567 return;
4568
4569 QPalette pal = palette();
4570 pal.setColor(QColorGroup::Foreground, color);
4571 setPalette(pal);
4572
4573 setLineWidth(width);
4574 }
4575
setBackgroundColor(const QColor & color)4576 void Graph::setBackgroundColor(const QColor& color)
4577 {
4578 QColorGroup cg;
4579 QPalette p = palette();
4580 p.setColor(QColorGroup::Window, color);
4581 setPalette(p);
4582
4583 setAutoFillBackground(true);
4584 emit modifiedGraph();
4585 }
4586
penStyleName(Qt::PenStyle style)4587 QString Graph::penStyleName(Qt::PenStyle style)
4588 {
4589 if (style==Qt::SolidLine)
4590 return "SolidLine";
4591 else if (style==Qt::DashLine)
4592 return "DashLine";
4593 else if (style==Qt::DotLine)
4594 return "DotLine";
4595 else if (style==Qt::DashDotLine)
4596 return "DashDotLine";
4597 else if (style==Qt::DashDotDotLine)
4598 return "DashDotDotLine";
4599 else
4600 return "SolidLine";
4601 }
4602
getPenStyle(int style)4603 Qt::PenStyle Graph::getPenStyle(int style)
4604 {
4605 Qt::PenStyle linePen = Qt::SolidLine;
4606 switch (style)
4607 {
4608 case 0:
4609 break;
4610 case 1:
4611 linePen=Qt::DashLine;
4612 break;
4613 case 2:
4614 linePen=Qt::DotLine;
4615 break;
4616 case 3:
4617 linePen=Qt::DashDotLine;
4618 break;
4619 case 4:
4620 linePen=Qt::DashDotDotLine;
4621 break;
4622 }
4623 return linePen;
4624 }
4625
getPenStyle(const QString & s)4626 Qt::PenStyle Graph::getPenStyle(const QString& s)
4627 {
4628 Qt::PenStyle style = Qt::SolidLine;
4629 if (s == "DashLine")
4630 style=Qt::DashLine;
4631 else if (s == "DotLine")
4632 style=Qt::DotLine;
4633 else if (s == "DashDotLine")
4634 style=Qt::DashDotLine;
4635 else if (s == "DashDotDotLine")
4636 style=Qt::DashDotDotLine;
4637 return style;
4638 }
4639
obsoleteSymbolStyle(int type)4640 int Graph::obsoleteSymbolStyle(int type)
4641 {
4642 if (type <= 4)
4643 return type + 1;
4644 else
4645 return type + 2;
4646 }
4647
showPlotErrorMessage(QWidget * parent,const QStringList & emptyColumns)4648 void Graph::showPlotErrorMessage(QWidget *parent, const QStringList& emptyColumns)
4649 {
4650 QApplication::restoreOverrideCursor();
4651
4652 int n = (int)emptyColumns.count();
4653 if (n > 1)
4654 {
4655 QString columns;
4656 for (int i = 0; i < n; i++)
4657 columns += "<p><b>" + emptyColumns[i] + "</b></p>";
4658
4659 QMessageBox::warning(parent, tr("QtiPlot - Warning"),
4660 tr("The columns") + ": " + columns + tr("are empty and will not be added to the plot!"));
4661 }
4662 else if (n == 1)
4663 QMessageBox::warning(parent, tr("QtiPlot - Warning"),
4664 tr("The column") + " <b>" + emptyColumns[0] + "</b> " + tr("is empty and will not be added to the plot!"));
4665 }
4666
showTitleContextMenu()4667 void Graph::showTitleContextMenu()
4668 {
4669 QMenu titleMenu(this);
4670 titleMenu.insertItem(QPixmap(":/cut.png"), tr("Cu&t"),this, SLOT(cutTitle()));
4671 titleMenu.insertItem(QPixmap(":/copy.png"), tr("&Copy"),this, SLOT(copyTitle()));
4672 titleMenu.insertItem(tr("C&lear"),this, SLOT(clearTitle()));
4673 titleMenu.insertItem(QPixmap(":/delete.png"), tr("&Delete"),this, SLOT(removeTitle()));
4674 titleMenu.insertSeparator();
4675 titleMenu.insertItem(tr("&Properties..."), this, SIGNAL(viewTitleDialog()));
4676 titleMenu.exec(QCursor::pos());
4677 }
4678
cutTitle()4679 void Graph::cutTitle()
4680 {
4681 QApplication::clipboard()->setText(title().text(), QClipboard::Clipboard);
4682 removeTitle();
4683 }
4684
copyTitle()4685 void Graph::copyTitle()
4686 {
4687 QApplication::clipboard()->setText(title().text(), QClipboard::Clipboard);
4688 }
4689
removeAxisTitle()4690 void Graph::removeAxisTitle()
4691 {
4692 int selectedAxis = scalePicker->currentAxis()->alignment();
4693 int axis = (selectedAxis + 2)%4;//unconsistent notation in Qwt enumerations between
4694 //QwtScaleDraw::alignment and QwtPlot::Axis
4695 setAxisTitle(axis, "");//due to the plot layout updates, we must always have a non empty title
4696 }
4697
clearAxisTitle()4698 void Graph::clearAxisTitle()
4699 {
4700 int selectedAxis = scalePicker->currentAxis()->alignment();
4701 int axis = (selectedAxis + 2)%4;//unconsistent notation in Qwt enumerations between
4702 //QwtScaleDraw::alignment and QwtPlot::Axis
4703 setAxisTitle(axis, " ");//due to the plot layout updates, we must always have a non empty title
4704 }
4705
cutAxisTitle()4706 void Graph::cutAxisTitle()
4707 {
4708 copyAxisTitle();
4709 removeAxisTitle();
4710 }
4711
copyAxisTitle()4712 void Graph::copyAxisTitle()
4713 {
4714 int selectedAxis = scalePicker->currentAxis()->alignment();
4715 int axis = (selectedAxis + 2)%4;//unconsistent notation in Qwt enumerations between
4716 //QwtScaleDraw::alignment and QwtPlot::Axis
4717 QApplication::clipboard()->setText(axisTitle(axis).text(), QClipboard::Clipboard);
4718 }
4719
showAxisTitleMenu()4720 void Graph::showAxisTitleMenu()
4721 {
4722 QMenu titleMenu(this);
4723 titleMenu.insertItem(QPixmap(":/cut.png"), tr("Cu&t"), this, SLOT(cutAxisTitle()));
4724 titleMenu.insertItem(QPixmap(":/copy.png"), tr("&Copy"), this, SLOT(copyAxisTitle()));
4725 titleMenu.insertItem(tr("C&lear"),this, SLOT(clearAxisTitle()));
4726 titleMenu.insertItem(QPixmap(":/delete.png"), tr("&Delete"),this, SLOT(removeAxisTitle()));
4727 titleMenu.insertSeparator();
4728 titleMenu.insertItem(tr("&Properties..."), this, SIGNAL(showAxisTitleDialog()));
4729 titleMenu.exec(QCursor::pos());
4730 }
4731
showAxisContextMenu(int axis)4732 void Graph::showAxisContextMenu(int axis)
4733 {
4734 QMenu menu(this);
4735 menu.setCheckable(true);
4736 menu.insertItem(QPixmap(":/unzoom.png"), tr("&Rescale to show all"), this, SLOT(setAutoScale()), tr("Ctrl+Shift+R"));
4737 menu.insertSeparator();
4738 menu.insertItem(tr("&Hide axis"), this, SLOT(hideSelectedAxis()));
4739
4740 int gridsID = menu.insertItem(tr("&Show grids"), this, SLOT(showGrids()));
4741 if (axis == QwtScaleDraw::LeftScale || axis == QwtScaleDraw::RightScale){
4742 if (grid()->yEnabled())
4743 menu.setItemChecked(gridsID, true);
4744 } else {
4745 if (grid()->xEnabled())
4746 menu.setItemChecked(gridsID, true);
4747 }
4748
4749 menu.insertSeparator();
4750 menu.insertItem(tr("&Scale..."), this, SLOT(showScaleDialog()));
4751 menu.insertItem(tr("&Properties..."), this, SLOT(showAxisDialog()));
4752 menu.exec(QCursor::pos());
4753 }
4754
showAxisDialog()4755 void Graph::showAxisDialog()
4756 {
4757 QwtScaleWidget *scale = scalePicker->currentAxis();
4758 if (scale)
4759 emit showAxisDialog(scale->alignment());
4760 }
4761
showScaleDialog()4762 void Graph::showScaleDialog()
4763 {
4764 emit axisDblClicked(scalePicker->currentAxis()->alignment());
4765 }
4766
hideSelectedAxis()4767 void Graph::hideSelectedAxis()
4768 {
4769 int axis = -1;
4770 int selectedAxis = scalePicker->currentAxis()->alignment();
4771 if (selectedAxis == QwtScaleDraw::LeftScale || selectedAxis == QwtScaleDraw::RightScale)
4772 axis = selectedAxis - 2;
4773 else
4774 axis = selectedAxis + 2;
4775
4776 enableAxis(axis, false);
4777 scalePicker->refresh();
4778 emit modifiedGraph();
4779 }
4780
showGrids()4781 void Graph::showGrids()
4782 {
4783 showGrid (scalePicker->currentAxis()->alignment());
4784 }
4785
showGrid()4786 void Graph::showGrid()
4787 {
4788 showGrid(QwtScaleDraw::LeftScale);
4789 showGrid(QwtScaleDraw::BottomScale);
4790 }
4791
showGrid(int axis)4792 void Graph::showGrid(int axis)
4793 {
4794 if (!d_grid)
4795 return;
4796
4797 if (axis == QwtScaleDraw::LeftScale || axis == QwtScaleDraw::RightScale){
4798 d_grid->enableY(!d_grid->yEnabled());
4799 d_grid->enableYMin(!d_grid->yMinEnabled());
4800 } else if (axis == QwtScaleDraw::BottomScale || axis == QwtScaleDraw::TopScale){
4801 d_grid->enableX(!d_grid->xEnabled());
4802 d_grid->enableXMin(!d_grid->xMinEnabled());
4803 } else
4804 return;
4805
4806 replot();
4807 emit modifiedGraph();
4808 }
4809
copyScaleWidget(Graph * g,int i)4810 void Graph::copyScaleWidget(Graph* g, int i)
4811 {
4812 if (g->axisEnabled (i)){
4813 enableAxis(i);
4814 QwtScaleWidget *scale = (QwtScaleWidget *)axisWidget(i);
4815 if (scale){
4816 scale->setSpacing(g->axisWidget(i)->spacing());
4817 scale->setMargin(g->axisWidget(i)->margin());
4818 QPalette pal = scale->palette();
4819 pal.setColor(QColorGroup::Foreground, g->axisColor(i));
4820 pal.setColor(QColorGroup::Text, g->axisLabelsColor(i));
4821 scale->setPalette(pal);
4822 setAxisFont (i, g->axisFont(i));
4823
4824 d_axis_titles[i] = g->axisTitleString(i);
4825 scale->setTitle(g->axisTitle(i));
4826 scale->setLayoutFlag(QwtScaleWidget::TitleInverted, g->axisWidget(i)->testLayoutFlag(QwtScaleWidget::TitleInverted));
4827 }
4828 }
4829 }
4830
copyScaleDraw(Graph * g,int i)4831 void Graph::copyScaleDraw(Graph* g, int i)
4832 {
4833 ScaleDraw *sdg = (ScaleDraw *)g->axisScaleDraw (i);
4834 if (sdg->hasComponent(QwtAbstractScaleDraw::Labels)){
4835 ScaleDraw::ScaleType type = sdg->scaleType();
4836 if (type == ScaleDraw::Numeric)
4837 setLabelsNumericFormat(i, g->axisLabelFormat(i), g->axisLabelPrecision(i), sdg->formula());
4838 else if (type == ScaleDraw::Day)
4839 setLabelsDayFormat(i, sdg->nameFormat());
4840 else if (type == ScaleDraw::Month)
4841 setLabelsMonthFormat(i, sdg->nameFormat());
4842 else if (type == ScaleDraw::Time || type == ScaleDraw::Date)
4843 setLabelsDateTimeFormat(i, type, sdg->formatString());
4844 else
4845 setAxisScaleDraw(i, new ScaleDraw(this, sdg->labelsList(), sdg->formatString(), sdg->scaleType()));
4846 } else
4847 axisScaleDraw (i)->enableComponent(QwtAbstractScaleDraw::Labels, false);
4848
4849 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(i);
4850 sd->enableComponent (QwtAbstractScaleDraw::Backbone, sdg->hasComponent(QwtAbstractScaleDraw::Backbone));
4851 sd->setSpacing(sdg->spacing());
4852 sd->setShowTicksPolicy(sdg->showTicksPolicy());
4853 sd->setPrefix(sdg->prefix());
4854 sd->setSuffix(sdg->suffix());
4855
4856 setAxisTicksLength(i, sdg->majorTicksStyle(), sdg->minorTicksStyle(), g->minorTickLength(), g->majorTickLength());
4857
4858 const ScaleEngine *se = (ScaleEngine *)g->axisScaleEngine(i);
4859 if (!se)
4860 return;
4861
4862 const QwtScaleDiv *div = g->axisScaleDiv(i);
4863 //set same scale
4864 setScale(i, div->lowerBound(), div->upperBound(), fabs(g->axisStep(i)), div->ticks(QwtScaleDiv::MajorTick).size(), g->axisMaxMinor(i),
4865 se->type(), se->testAttribute(QwtScaleEngine::Inverted), se->axisBreakLeft(), se->axisBreakRight(),
4866 se->breakPosition(), se->stepBeforeBreak(), se->stepAfterBreak(), se->minTicksBeforeBreak(),
4867 se->minTicksAfterBreak(), se->log10ScaleAfterBreak(), se->breakWidth(), se->hasBreakDecoration());
4868 }
4869
copyEnrichments(Graph * g)4870 void Graph::copyEnrichments(Graph* g)
4871 {
4872 if (!g)
4873 return;
4874
4875 QList<FrameWidget *> enrichements = g->enrichmentsList();
4876 foreach (FrameWidget *e, enrichements){
4877 PieLabel *l = qobject_cast<PieLabel *>(e);
4878 if (l)
4879 continue;
4880 add(e);
4881 }
4882
4883 QList<ArrowMarker *> lines = g->arrowsList();
4884 foreach (ArrowMarker *a, lines)
4885 addArrow(a);
4886 }
4887
copy(Graph * g)4888 void Graph::copy(Graph* g)
4889 {
4890 d_waterfall_offset_x = g->waterfallXOffset();
4891 d_waterfall_offset_y = g->waterfallYOffset();
4892
4893 setMargin(g->margin());
4894 setBackgroundColor(g->paletteBackgroundColor());
4895 setFrame(g->lineWidth(), g->frameColor());
4896 setCanvasBackground(g->canvasBackground());
4897 setCanvasBackgroundImage(g->canvasBackgroundFileName(), false);
4898 setAxisTitlePolicy(g->axisTitlePolicy());
4899
4900 for (int i = 0; i < QwtPlot::axisCnt; i++){
4901 enableAxis(i, g->axisEnabled(i));
4902 copyScaleWidget(g, i);
4903 }
4904
4905 grid()->copy(g->grid());
4906 d_grid_on_top = g->hasGridOnTop();
4907 d_missing_data_gap = g->isMissingDataGapEnabled();
4908 setTitle(g->title());
4909 setCanvasFrame(g->canvasFrameWidth(), g->canvasFrameColor());
4910 setAxesLinewidth(g->axesLinewidth());
4911
4912 d_Douglas_Peuker_tolerance = g->getDouglasPeukerTolerance();
4913
4914 copyCurves(g);
4915
4916 for (int i = 0; i < QwtPlot::axisCnt; i++){
4917 copyScaleDraw(g, i);
4918 setAxisLabelRotation(i, g->labelsRotation(i));
4919 }
4920
4921 updateAxesTitles();
4922 updateLayout();
4923 d_auto_scale = g->isAutoscalingEnabled();
4924
4925 d_zoomer[0]->setZoomBase();
4926 d_zoomer[1]->setZoomBase();
4927
4928 d_disable_curve_antialiasing = g->isCurveAntialiasingDisabled();
4929 d_max_antialising_size = g->maxAntialisingSize();
4930 setAntialiasing(g->antialiasing(), false);
4931
4932 copyEnrichments(g);
4933
4934 autoScaleFonts = g->autoscaleFonts();
4935 d_synchronize_scales = g->hasSynchronizedScaleDivisions();
4936 }
4937
copyCurves(Graph * g)4938 void Graph::copyCurves(Graph* g)
4939 {
4940 if (!g)
4941 return;
4942
4943 QList<QwtPlotItem *> curvesList = g->curvesList();
4944 foreach (QwtPlotItem *it, curvesList){
4945 if (it->rtti() == QwtPlotItem::Rtti_PlotCurve){
4946 DataCurve *cv = (DataCurve *)it;
4947 int n = cv->dataSize();
4948 int style = ((PlotCurve *)it)->type();
4949 Table *t = cv->table();
4950
4951 PlotCurve *c = 0;
4952 if (style == Pie){
4953 c = new PieCurve(t, cv->title().text(), cv->startRow(), cv->endRow());
4954 insertCurve(c);
4955 } else if (style == Function) {
4956 c = new FunctionCurve(cv->title().text());
4957 insertCurve(c);
4958 ((FunctionCurve*)c)->copy((FunctionCurve*)cv);
4959 ((FunctionCurve*)c)->loadData(n);
4960 } else if (style == VerticalBars || style == HorizontalBars){
4961 c = new QwtBarCurve(((QwtBarCurve*)cv)->orientation(), t, cv->xColumnName(),
4962 cv->title().text(), cv->startRow(), cv->endRow());
4963 insertCurve(c);
4964 ((QwtBarCurve*)c)->copy((QwtBarCurve*)cv);
4965 } else if (style == ErrorBars){
4966 ErrorBarsCurve *er = (ErrorBarsCurve*)cv;
4967 DataCurve *master_curve = masterCurve(er);
4968 if (master_curve){
4969 c = new ErrorBarsCurve(t, cv->title().text());
4970 insertCurve(c);
4971 ((ErrorBarsCurve*)c)->copy(er);
4972 ((ErrorBarsCurve*)c)->setMasterCurve(master_curve);
4973 }
4974 } else if (style == Histogram){
4975 QwtHistogram *h = (QwtHistogram*)cv;
4976 if (h->matrix())
4977 c = new QwtHistogram(h->matrix());
4978 else
4979 c = new QwtHistogram(t, cv->title().text(), cv->startRow(), cv->endRow());
4980 insertCurve(c);
4981 ((QwtHistogram *)c)->copy(h);
4982 } else if (style == VectXYXY || style == VectXYAM){
4983 VectorCurve::VectorStyle vs = VectorCurve::XYXY;
4984 if (style == VectXYAM)
4985 vs = VectorCurve::XYAM;
4986 c = new VectorCurve(vs, t, cv->xColumnName(), cv->title().text(),
4987 ((VectorCurve *)cv)->vectorEndXAColName(),
4988 ((VectorCurve *)cv)->vectorEndYMColName(),
4989 cv->startRow(), cv->endRow());
4990 insertCurve(c);
4991 ((VectorCurve *)c)->copy((const VectorCurve *)cv);
4992 } else if (style == Box){
4993 c = new BoxCurve(t, cv->title().text(), cv->startRow(), cv->endRow());
4994 insertCurve(c);
4995
4996 QVector<double> y(n);
4997 for (int j = 0; j < n; j++)
4998 y[j] = cv->y(j);
4999 QwtSingleArrayData dat(cv->x(0), y, n);
5000 c->setData(dat);
5001 ((BoxCurve*)c)->copy((BoxCurve *)cv);
5002 } else {
5003 if (t != cv->xTable())
5004 c = new DataCurve(cv->xTable(), cv->xColumnName(), t, cv->title().text(), cv->startRow(), cv->endRow());
5005 else
5006 c = new DataCurve(t, cv->xColumnName(), cv->title().text(), cv->startRow(), cv->endRow());
5007 insertCurve(c);
5008 }
5009 if (c->type() != Box && c->type() != ErrorBars && c->type() != Function){
5010 ((DataCurve *)c)->loadData();
5011 c->enableSideLines(cv->sideLinesEnabled());
5012
5013 if (c->type() == Pie)
5014 ((PieCurve*)c)->clone((PieCurve*)cv);
5015 else
5016 ((DataCurve *)c)->clone(cv);
5017 }
5018
5019 c->setPen(cv->pen());
5020 c->setBrush(cv->brush());
5021 c->setStyle(cv->style());
5022 c->setSymbol(cv->symbol());
5023
5024 if (cv->testCurveAttribute (QwtPlotCurve::Fitted)){
5025 c->setCurveAttribute(QwtPlotCurve::Fitted, true);
5026 if (d_Douglas_Peuker_tolerance > 0.0 && c->dataSize() >= d_speed_mode_points){
5027 QwtWeedingCurveFitter *fitter = new QwtWeedingCurveFitter(d_Douglas_Peuker_tolerance);
5028 c->setCurveFitter(fitter);
5029 }
5030 } else if (cv->testCurveAttribute (QwtPlotCurve::Inverted))
5031 c->setCurveAttribute(QwtPlotCurve::Inverted, true);
5032
5033 c->setRenderHint(QwtPlotItem::RenderAntialiased, cv->testRenderHint(QwtPlotItem::RenderAntialiased));
5034 c->setAxis(cv->xAxis(), cv->yAxis());
5035 c->setVisible(cv->isVisible());
5036 c->setPlotStyle(((PlotCurve *)it)->plotStyle());
5037
5038 QList<QwtPlotCurve *>lst = g->fitCurvesList();
5039 if (lst.contains((QwtPlotCurve *)it))
5040 d_fit_curves << c;
5041 } else if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram){
5042 Spectrogram *sp = ((Spectrogram *)it)->copy(this);
5043 insertCurve(sp);
5044
5045 sp->setRenderHint(QwtPlotItem::RenderAntialiased, it->testRenderHint(QwtPlotItem::RenderAntialiased));
5046 sp->showColorScale(((Spectrogram *)it)->colorScaleAxis(), ((Spectrogram *)it)->hasColorScale());
5047 sp->setColorBarWidth(((Spectrogram *)it)->colorBarWidth());
5048 sp->setAxis(it->xAxis(), it->yAxis());
5049 sp->setVisible(it->isVisible());
5050 }
5051 }
5052 }
5053
5054
plotBox(Table * w,const QStringList & names,int startRow,int endRow)5055 void Graph::plotBox(Table *w, const QStringList& names, int startRow, int endRow)
5056 {
5057 if (endRow < 0)
5058 endRow = w->numRows() - 1;
5059
5060 QList<QColor> indexedColors = ColorBox::defaultColors();
5061 MultiLayer *ml = multiLayer();
5062 if (ml){
5063 ApplicationWindow *app = ml->applicationWindow();
5064 if (app)
5065 indexedColors = app->indexedColors();
5066 }
5067
5068 QColor color = Qt::black;
5069 for (int j = 0; j < names.count(); j++){
5070 BoxCurve *c = new BoxCurve(w, names[j], startRow, endRow);
5071 insertCurve(c);
5072
5073 if (j < indexedColors.size())
5074 color = indexedColors[j];
5075 c->setData(QwtSingleArrayData(double(j+1), QwtArray<double>(), 0));
5076 c->loadData();
5077 c->setPen(QPen(color, 1));
5078 c->setSymbol(QwtSymbol(QwtSymbol::NoSymbol, QBrush(), QPen(color, 1), QSize(7, 7)));
5079 }
5080
5081 foreach(FrameWidget *fw, d_enrichments){
5082 LegendWidget *l = qobject_cast<LegendWidget *>(fw);
5083 if (l && l->isAutoUpdateEnabled())
5084 l->setText(legendText());
5085 }
5086
5087 ScaleDraw *sd = new ScaleDraw(this, w->selectedYLabels(), w->objectName(), ScaleDraw::ColHeader);
5088 sd->setShowTicksPolicy(ScaleDraw::HideBeginEnd);
5089 setAxisScaleDraw (QwtPlot::xBottom, sd);
5090 setAxisMaxMajor(QwtPlot::xBottom, names.count() + 1);
5091 setAxisMaxMinor(QwtPlot::xBottom, 0);
5092
5093 setAxisScaleDraw (QwtPlot::xTop, new ScaleDraw(this, w->selectedYLabels(), w->objectName(), ScaleDraw::ColHeader));
5094 setAxisMaxMajor(QwtPlot::xTop, names.count() + 1);
5095 setAxisMaxMinor(QwtPlot::xTop, 0);
5096 }
5097
setCurveStyle(int index,int s)5098 void Graph::setCurveStyle(int index, int s)
5099 {
5100 PlotCurve *c = (PlotCurve *)curve(index);
5101 if (!c)
5102 return;
5103
5104 int curve_type = c->plotStyle();
5105 if (curve_type == VerticalBars || curve_type == HorizontalBars || curve_type == Histogram ||
5106 curve_type == Pie || curve_type == Box || curve_type == ErrorBars ||
5107 curve_type == VectXYXY || curve_type == VectXYAM)
5108 return;//these are not line styles, but distinct curve types and this function must not change the curve type
5109
5110 c->setCurveAttribute(QwtPlotCurve::Fitted, false);
5111 c->setCurveAttribute(QwtPlotCurve::Inverted, false);
5112
5113 if (s == 5){//ancient spline style in Qwt 4.2.0
5114 s = QwtPlotCurve::Lines;
5115 c->setCurveAttribute(QwtPlotCurve::Fitted, true);
5116 c->setPlotStyle(Spline);
5117 } else if (s == 6){// Vertical Steps
5118 s = QwtPlotCurve::Steps;
5119 c->setCurveAttribute(QwtPlotCurve::Inverted, false);
5120 c->setPlotStyle(VerticalSteps);
5121 } else if (s == QwtPlotCurve::Steps){// Horizontal Steps
5122 c->setPlotStyle(HorizontalSteps);
5123 c->setCurveAttribute(QwtPlotCurve::Inverted, true);
5124 } else if (s == QwtPlotCurve::Sticks)
5125 c->setPlotStyle(VerticalDropLines);
5126 else {//QwtPlotCurve::Lines || QwtPlotCurve::Dots
5127 if (c->symbol().style() == QwtSymbol::NoSymbol)
5128 c->setPlotStyle(Line);
5129 else if (c->symbol().style() != QwtSymbol::NoSymbol && (QwtPlotCurve::CurveStyle)s == QwtPlotCurve::NoCurve)
5130 c->setPlotStyle(Scatter);
5131 else
5132 c->setPlotStyle(LineSymbols);
5133 }
5134
5135 c->setStyle((QwtPlotCurve::CurveStyle)s);
5136 if (curve_type != Function)
5137 ((DataCurve *)c)->enableSpeedMode();
5138 }
5139
openBoxDiagram(Table * w,const QStringList & l,int fileVersion)5140 BoxCurve* Graph::openBoxDiagram(Table *w, const QStringList& l, int fileVersion)
5141 {
5142 if (!w)
5143 return NULL;
5144
5145 int startRow = 0;
5146 int endRow = w->numRows()-1;
5147 if (fileVersion >= 90) {
5148 startRow = l[l.count()-3].toInt();
5149 endRow = l[l.count()-2].toInt();
5150 }
5151
5152 BoxCurve *c = new BoxCurve(w, l[2], startRow, endRow);
5153 insertCurve(c);
5154
5155 c->setData(QwtSingleArrayData(l[1].toDouble(), QwtArray<double>(), 0));
5156 c->setData(QwtSingleArrayData(l[1].toDouble(), QwtArray<double>(), 0));
5157 c->loadData();
5158
5159 c->setMaxStyle(SymbolBox::style(l[16].toInt()));
5160 c->setP99Style(SymbolBox::style(l[17].toInt()));
5161 c->setMeanStyle(SymbolBox::style(l[18].toInt()));
5162 c->setP1Style(SymbolBox::style(l[19].toInt()));
5163 c->setMinStyle(SymbolBox::style(l[20].toInt()));
5164
5165 c->setBoxStyle(l[21].toInt());
5166 c->setBoxWidth(l[22].toInt());
5167 c->setBoxRange(l[23].toInt(), l[24].toDouble());
5168 c->setWhiskersRange(l[25].toInt(), l[26].toDouble());
5169 return c;
5170 }
5171
setActiveTool(PlotToolInterface * tool)5172 void Graph::setActiveTool(PlotToolInterface *tool)
5173 {
5174 if (!tool && d_peak_fit_tool){
5175 delete d_peak_fit_tool;
5176 d_peak_fit_tool = NULL;
5177 return;
5178 }
5179
5180 if (tool && tool->rtti() == PlotToolInterface::Rtti_MultiPeakFitTool){
5181 d_peak_fit_tool = tool;
5182
5183 if (d_range_selector)
5184 d_range_selector->setEnabled(false);
5185 return;
5186 }
5187
5188 if (tool && tool->rtti() == PlotToolInterface::Rtti_ImageProfilesTool){
5189 d_image_profiles_tool = (ImageProfilesTool*)tool;
5190 return;
5191 }
5192
5193 if(d_active_tool)
5194 delete d_active_tool;
5195
5196 d_active_tool = tool;
5197 }
5198
disableTools()5199 void Graph::disableTools()
5200 {
5201 if (zoomOn())
5202 zoom(false);
5203
5204 enablePanningMagnifier(false);
5205
5206 if (drawLineActive())
5207 drawLine(false);
5208
5209 if(d_active_tool)
5210 delete d_active_tool;
5211 d_active_tool = NULL;
5212
5213 if (d_peak_fit_tool)
5214 delete d_peak_fit_tool;
5215 d_peak_fit_tool = NULL;
5216
5217 if (d_range_selector)
5218 d_range_selector->setVisible(false);
5219 }
5220
disableImageProfilesTool()5221 void Graph::disableImageProfilesTool()
5222 {
5223 if (d_image_profiles_tool)
5224 delete d_image_profiles_tool;
5225 }
5226
hasActiveTool()5227 bool Graph::hasActiveTool()
5228 {
5229 if (zoomOn() || drawLineActive() || d_active_tool || d_peak_fit_tool ||
5230 d_magnifier || d_panner || (d_range_selector && d_range_selector->isVisible()))
5231 return true;
5232
5233 return false;
5234 }
5235
enableRangeSelectors(const QObject * status_target,const char * status_slot)5236 bool Graph::enableRangeSelectors(const QObject *status_target, const char *status_slot)
5237 {
5238 if (!d_range_selector){
5239 d_range_selector = new RangeSelectorTool(this, status_target, status_slot);
5240 //setActiveTool(d_range_selector);
5241 connect(d_range_selector, SIGNAL(changed()), this, SIGNAL(dataRangeChanged()));
5242 }
5243
5244 d_range_selector->setVisible(true);
5245 d_range_selector->setEnabled(true);
5246 return true;
5247 }
5248
guessUniqueCurveLayout(int & colorIndex,int & symbolIndex)5249 void Graph::guessUniqueCurveLayout(int& colorIndex, int& symbolIndex)
5250 {
5251 colorIndex = 0;
5252 symbolIndex = 0;
5253
5254 QList<QColor> indexedColors = ColorBox::defaultColors();
5255 QList<int> indexedSymbols = SymbolBox::defaultSymbols();
5256 MultiLayer *ml = multiLayer();
5257 if (ml){
5258 ApplicationWindow *app = ml->applicationWindow();
5259 if (app){
5260 indexedColors = app->indexedColors();
5261 indexedSymbols = app->indexedSymbols();
5262 }
5263 }
5264
5265 int curve_index = d_curves.size() - 1;
5266 if (curve_index >= 0){// find out the pen color of the master curve
5267 PlotCurve *c = (PlotCurve *)curve(curve_index);
5268 if (c && c->type() == ErrorBars){
5269 ErrorBarsCurve *er = (ErrorBarsCurve *)c;
5270 DataCurve *master_curve = er->masterCurve();
5271 if (master_curve){
5272 colorIndex = indexedColors.indexOf(master_curve->pen().color());
5273 return;
5274 }
5275 }
5276 }
5277
5278 foreach (QwtPlotItem *it, d_curves){
5279 if (it->rtti() == QwtPlotItem::Rtti_PlotCurve){
5280 const QwtPlotCurve *c = (QwtPlotCurve *)it;
5281 int index = indexedColors.indexOf(c->pen().color());
5282 if (index > colorIndex)
5283 colorIndex = index;
5284
5285 QwtSymbol symb = c->symbol();
5286 index = indexedSymbols.indexOf(int(symb.style()));
5287 if (index < 0)
5288 symbolIndex = 0;
5289 else if (index > symbolIndex)
5290 symbolIndex = index;
5291 }
5292 }
5293 if (d_curves.size() > 1){
5294 colorIndex = (++colorIndex)%16;
5295 symbolIndex = (++symbolIndex)%15;
5296 } else
5297 symbolIndex = 0;
5298
5299 if (colorIndex == 13) //avoid white invisible curves
5300 colorIndex = 0;
5301 }
5302
addFitCurve(QwtPlotCurve * c)5303 void Graph::addFitCurve(QwtPlotCurve *c)
5304 {
5305 if (c)
5306 d_fit_curves << c;
5307 }
5308
deleteFitCurves()5309 void Graph::deleteFitCurves()
5310 {
5311 foreach(QwtPlotCurve *c, d_fit_curves)
5312 removeCurve(c);
5313
5314 replot();
5315 }
5316
5317 //! Returns a pointer to the spectrogram which data source is matrix m (the pointer can be NULL)
spectrogram(Matrix * m)5318 Spectrogram* Graph::spectrogram(Matrix *m)
5319 {
5320 if (!m)
5321 return NULL;
5322
5323 foreach (QwtPlotItem *item, d_curves){
5324 if(item && item->rtti() == QwtPlotItem::Rtti_PlotSpectrogram){
5325 Spectrogram *s = (Spectrogram *)item;
5326 if (s && s->matrix() == m)
5327 return s;
5328 }
5329 }
5330 return NULL;
5331 }
5332
plotSpectrogram(Matrix * m,CurveType type)5333 Spectrogram* Graph::plotSpectrogram(Matrix *m, CurveType type)
5334 {
5335 if (!m || (type != GrayScale && type != ColorMap && type != Contour))
5336 return 0;
5337
5338 if (plotItemsList().contains(m->objectName()))
5339 return spectrogram(m);
5340
5341 Spectrogram *d_spectrogram = new Spectrogram(this, m);
5342 insertCurve(d_spectrogram);
5343
5344 if (type == GrayScale){
5345 d_spectrogram->setGrayScale();
5346 d_spectrogram->clearLabels();
5347 } else if (type == Contour){
5348 d_spectrogram->setDisplayMode(QwtPlotSpectrogram::ImageMode, false);
5349 d_spectrogram->setDisplayMode(QwtPlotSpectrogram::ContourMode, true);
5350 } else if (type == ColorMap){
5351 d_spectrogram->setDefaultColorMap();
5352 d_spectrogram->setDisplayMode(QwtPlotSpectrogram::ContourMode, true);
5353 }
5354
5355 QwtScaleWidget *rightAxis = axisWidget(QwtPlot::yRight);
5356 rightAxis->setColorBarEnabled(type != Contour);
5357 rightAxis->setColorMap(d_spectrogram->data().range(), d_spectrogram->colorMap());
5358
5359 if (type != Contour)
5360 setAxisScale(QwtPlot::yRight,
5361 d_spectrogram->data().range().minValue(),
5362 d_spectrogram->data().range().maxValue());
5363
5364 replot();
5365
5366 updateSecondaryAxis(QwtPlot::xTop);
5367 if (type == Contour){
5368 d_spectrogram->setColorScaleAxis(QwtPlot::xTop);
5369 updateSecondaryAxis(QwtPlot::yRight);
5370 }
5371
5372 d_zoomer[0]->setZoomBase();
5373 d_zoomer[1]->setZoomBase();
5374
5375 return d_spectrogram;
5376 }
5377
restoreSpectrogram(ApplicationWindow * app,const QStringList & lst)5378 void Graph::restoreSpectrogram(ApplicationWindow *app, const QStringList& lst)
5379 {
5380 QStringList::const_iterator line = lst.begin();
5381 QString s = (*line).stripWhiteSpace();
5382 QString matrixName = s.remove("<matrix>").remove("</matrix>");
5383 Matrix *m = app->matrix(matrixName);
5384 if (!m)
5385 return;
5386
5387 Spectrogram *sp = new Spectrogram(this, m);
5388 insertCurve(sp);
5389
5390 for (line++; line != lst.end(); line++){
5391 QString s = *line;
5392 if (s.contains("<useMatrixFormula>") && (s.trimmed().remove("<useMatrixFormula>").remove("</useMatrixFormula>")).toInt())
5393 sp->setUseMatrixFormula(true);
5394 else if (s.contains("<xAxis>")){
5395 sp->setXAxis(s.trimmed().remove("<xAxis>").remove("</xAxis>").toInt());
5396 } else if (s.contains("<yAxis>")){
5397 sp->setYAxis(s.trimmed().remove("<yAxis>").remove("</yAxis>").toInt());
5398 } else if (s.contains("<ColorPolicy>")){
5399 int color_policy = s.remove("<ColorPolicy>").remove("</ColorPolicy>").stripWhiteSpace().toInt();
5400 if (color_policy == Spectrogram::GrayScale)
5401 sp->setGrayScale();
5402 else if (color_policy == Spectrogram::Default)
5403 sp->setDefaultColorMap();
5404 } else if (s.contains("<ColorMap>")){
5405 QStringList lst;
5406 while ((*line).trimmed() != "</ColorMap>" )
5407 lst << *(++line);
5408 lst.pop_back();
5409 sp->setCustomColorMap(LinearColorMap::fromXmlStringList(lst));
5410 } else if (s.contains("<Image>")){
5411 int mode = s.remove("<Image>").remove("</Image>").stripWhiteSpace().toInt();
5412 sp->setDisplayMode(QwtPlotSpectrogram::ImageMode, mode);
5413 } else if (s.contains("<ContourLines>")){
5414 int contours = s.remove("<ContourLines>").remove("</ContourLines>").stripWhiteSpace().toInt();
5415 sp->setDisplayMode(QwtPlotSpectrogram::ContourMode, contours);
5416 if (contours){
5417 s = (*(++line)).stripWhiteSpace();
5418 int levels = s.remove("<Levels>").remove("</Levels>").toInt();
5419 QwtValueList levelsLst;
5420 for (int i = 0; i < levels; i++){
5421 s = (*(++line)).stripWhiteSpace();
5422 if (s.contains("</z>"))
5423 levelsLst += s.remove("<z>").remove("</z>").toDouble();
5424 }
5425 if (levelsLst.size() > 0)
5426 sp->setContourLevels(levelsLst);
5427 else
5428 sp->setLevelsNumber(levels);
5429
5430 s = (*(++line)).stripWhiteSpace();
5431 int defaultPen = s.remove("<DefaultPen>").remove("</DefaultPen>").toInt();
5432 if (!defaultPen)
5433 sp->setColorMapPen();
5434 else {
5435 s = (*(++line)).stripWhiteSpace();
5436 QColor c = QColor(s.remove("<PenColor>").remove("</PenColor>"));
5437 s = (*(++line)).stripWhiteSpace();
5438 double width = s.remove("<PenWidth>").remove("</PenWidth>").toDouble();
5439 s = (*(++line)).stripWhiteSpace();
5440 int style = s.remove("<PenStyle>").remove("</PenStyle>").toInt();
5441 QPen pen = QPen(c, width, Graph::getPenStyle(style));
5442 pen.setCosmetic(true);
5443 sp->setDefaultContourPen(pen);
5444 }
5445 sp->showContourLineLabels(false);
5446 } else
5447 sp->clearLabels();
5448 } else if (s.contains("<PenList>")){
5449 int levels = sp->contourLevels().size();
5450 QList <QPen> penLst;
5451 for (int i = 0; i < levels; i++){
5452 s = (*(++line)).stripWhiteSpace();
5453 if (s.contains("</pen>")){
5454 QStringList lst = s.remove("<pen>").remove("</pen>").split(",");
5455 if (lst.size() == 3)
5456 penLst << QPen(QColor(lst[0]), lst[1].toDouble(), PenStyleBox::penStyle(lst[2].toInt()));
5457 }
5458 }
5459 if (!penLst.isEmpty())
5460 sp->setContourPenList(penLst);
5461 } else if (s.contains("<Labels>")){
5462 sp->showContourLineLabels(true);
5463 s = (*(++line)).stripWhiteSpace();
5464 sp->setLabelsColor(QColor(s.remove("<Color>").remove("</Color>")));
5465 s = (*(++line)).stripWhiteSpace();
5466 sp->setLabelsWhiteOut(s.remove("<WhiteOut>").remove("</WhiteOut>").toInt());
5467 s = (*(++line)).stripWhiteSpace();
5468 sp->setLabelsRotation(s.remove("<Angle>").remove("</Angle>").toDouble());
5469 s = (*(++line)).stripWhiteSpace();
5470 double xOffset = s.remove("<xOffset>").remove("</xOffset>").toDouble();
5471 s = (*(++line)).stripWhiteSpace();
5472 double yOffset = s.remove("<yOffset>").remove("</yOffset>").toDouble();
5473 sp->setLabelsOffset(xOffset, yOffset);
5474 s = (*(++line)).stripWhiteSpace().remove("<Font>").remove("</Font>");
5475 QFont fnt;
5476 fnt.fromString(s);
5477 sp->setLabelsFont(fnt);
5478 } else if (s.contains("<offset>")){
5479 QStringList lst = s.remove("<offset>").remove("</offset>").split(",");
5480 if (lst.size() == 3)
5481 sp->setLabelOffset(lst[0].toInt(), lst[1].toDouble(), lst[2].toDouble());
5482 } else if (s.contains("<ColorBar>")){
5483 s = *(++line);
5484 int color_axis = s.remove("<axis>").remove("</axis>").stripWhiteSpace().toInt();
5485 s = *(++line);
5486 int width = s.remove("<width>").remove("</width>").stripWhiteSpace().toInt();
5487
5488 QwtScaleWidget *colorAxis = axisWidget(color_axis);
5489 if (colorAxis){
5490 colorAxis->setColorBarWidth(width);
5491 colorAxis->setColorBarEnabled(true);
5492 }
5493 line++;
5494 } else if (s.contains("<Visible>")){
5495 int on = s.remove("<Visible>").remove("</Visible>").stripWhiteSpace().toInt();
5496 sp->setVisible(on);
5497 }
5498 }
5499 }
5500
restoreCurveLabels(int curveID,const QStringList & lst)5501 void Graph::restoreCurveLabels(int curveID, const QStringList& lst)
5502 {
5503 DataCurve *c = (DataCurve *)curve(curveID);
5504 if (!c)
5505 return;
5506
5507 c->restoreLabels(lst);
5508 }
5509
validCurvesDataSize()5510 bool Graph::validCurvesDataSize()
5511 {
5512 if (d_curves.size() == 0){
5513 QMessageBox::warning(this, tr("QtiPlot - Warning"), tr("There are no curves available on this plot!"));
5514 return false;
5515 } else {
5516 foreach (QwtPlotItem *item, d_curves){
5517 if(item && item->rtti() != QwtPlotItem::Rtti_PlotSpectrogram){
5518 QwtPlotCurve *c = (QwtPlotCurve *)item;
5519 if (c->dataSize() >= 2)
5520 return true;
5521 }
5522 }
5523 QMessageBox::warning(this, tr("QtiPlot - Error"),
5524 tr("There are no curves with more than two points on this plot. Operation aborted!"));
5525 return false;
5526 }
5527 }
5528
~Graph()5529 Graph::~Graph()
5530 {
5531 if(d_markers_selector)
5532 delete d_markers_selector;
5533 if(d_peak_fit_tool)
5534 delete d_peak_fit_tool;
5535 if(d_active_tool)
5536 delete d_active_tool;
5537 if (d_range_selector)
5538 delete d_range_selector;
5539 delete titlePicker;
5540 delete scalePicker;
5541 delete cp;
5542
5543 if (d_magnifier)
5544 delete d_magnifier;
5545 if (d_panner)
5546 delete d_panner;
5547
5548 disableImageProfilesTool();
5549
5550 foreach(FrameWidget *fw, d_enrichments)
5551 fw->close();
5552 }
5553
setAntialiasing(bool on,bool update)5554 void Graph::setAntialiasing(bool on, bool update)
5555 {
5556 if (d_antialiasing == on && !update)
5557 return;
5558
5559 d_antialiasing = on;
5560
5561 if (update){
5562 foreach(QwtPlotItem *it, d_curves)
5563 it->setRenderHint(QwtPlotItem::RenderAntialiased, isCurveAntialiasingEnabled(it));
5564 foreach (QwtPlotMarker *i, d_lines)
5565 i->setRenderHint(QwtPlotItem::RenderAntialiased, d_antialiasing);
5566 replot();
5567 }
5568 }
5569
isCurveAntialiasingEnabled(QwtPlotItem * it)5570 bool Graph::isCurveAntialiasingEnabled(QwtPlotItem *it)
5571 {
5572 if (!d_antialiasing || !it)
5573 return false;
5574
5575 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
5576 return true;
5577
5578 if (d_disable_curve_antialiasing && ((PlotCurve *)it)->dataSize() > d_max_antialising_size)
5579 return false;
5580
5581 return true;
5582 }
5583
disableCurveAntialiasing(bool disable,int maxPoints)5584 void Graph::disableCurveAntialiasing(bool disable, int maxPoints)
5585 {
5586 if (!d_antialiasing)
5587 return;
5588
5589 if (d_disable_curve_antialiasing == disable && d_max_antialising_size == maxPoints)
5590 return;
5591
5592 d_disable_curve_antialiasing = disable;
5593 d_max_antialising_size = maxPoints;
5594
5595 if (d_curves.isEmpty())
5596 return;
5597
5598 foreach(QwtPlotItem *it, d_curves)
5599 it->setRenderHint(QwtPlotItem::RenderAntialiased, isCurveAntialiasingEnabled(it));
5600 replot();
5601 }
5602
focusNextPrevChild(bool)5603 bool Graph::focusNextPrevChild ( bool )
5604 {
5605 /*int markers = d_lines.size();
5606 int enrichments = d_enrichments.size();
5607 if (markers < 1 && enrichments < 1)
5608 return false;
5609
5610 if (d_selected_arrow){
5611 int next = d_lines.indexOf(d_selected_arrow) + 1;
5612 if (next >= 0 && next < markers){//select next arrow
5613 cp->disableEditing();
5614 deselectMarker();
5615 setSelectedMarker(d_lines.at(next));
5616 return true;
5617 } else if (enrichments){ //select first enrichment
5618 cp->disableEditing();
5619 deselectMarker();
5620 select(d_enrichments[0]);
5621 return true;
5622 }
5623 }
5624
5625 if (d_active_enrichment){
5626 int next = d_enrichments.indexOf(d_active_enrichment) + 1;
5627 if (next >= 0 && next < enrichments){//select next enrichment
5628 cp->disableEditing();
5629 deselectMarker();
5630 select(d_enrichments[next]);
5631 return true;
5632 } else if (markers){//select first arrow
5633 deselectMarker();
5634 setSelectedMarker(d_lines.at(0));
5635 return true;
5636 }
5637 }
5638
5639 if (enrichments) { //select first enrichment
5640 select(d_enrichments[0]);
5641 return true;
5642 }
5643
5644 if (markers){//select first arrow
5645 deselectMarker();
5646 setSelectedMarker(d_lines.at(0));
5647 return true;
5648 }*/
5649
5650 return false;
5651 }
5652
axisFormatInfo(int axis)5653 QString Graph::axisFormatInfo(int axis)
5654 {
5655 if (axis < 0 || axis > QwtPlot::axisCnt)
5656 return QString();
5657
5658 return ((ScaleDraw *)axisScaleDraw(axis))->formatString();
5659 }
5660
updateCurveNames(const QString & oldName,const QString & newName,bool updateTableName)5661 void Graph::updateCurveNames(const QString& oldName, const QString& newName, bool updateTableName)
5662 {
5663 //update plotted curves list
5664 foreach(QwtPlotItem *it, d_curves){
5665 if (it->rtti() != QwtPlotItem::Rtti_PlotCurve)
5666 continue;
5667
5668 DataCurve *c = (DataCurve *)it;
5669 if (c->type() != Function && c->plotAssociation().join(",").contains(oldName))
5670 c->updateColumnNames(oldName, newName, updateTableName);
5671 }
5672
5673 updateAxesTitles();
5674 replot();
5675 }
5676
setCurveFullRange(int curveIndex)5677 void Graph::setCurveFullRange(int curveIndex)
5678 {
5679 DataCurve *c = (DataCurve *)curve(curveIndex);
5680 if (c){
5681 c->setFullRange();
5682 updatePlot();
5683 emit modifiedGraph();
5684 }
5685 }
5686
setCurveLineColor(int curveIndex,int colorIndex)5687 void Graph::setCurveLineColor(int curveIndex, int colorIndex)
5688 {
5689 QwtPlotCurve *c = curve(curveIndex);
5690 if (c){
5691 QPen pen = c->pen();
5692 pen.setColor(ColorBox::defaultColor(colorIndex));
5693 c->setPen(pen);
5694 replot();
5695 emit modifiedGraph();
5696 }
5697 }
5698
setCurveLineColor(int curveIndex,QColor qColor)5699 void Graph::setCurveLineColor(int curveIndex, QColor qColor)
5700 {
5701 QwtPlotCurve *c = curve(curveIndex);
5702 if (c){
5703 QPen pen = c->pen();
5704 pen.setColor(qColor);
5705 c->setPen(pen);
5706 replot();
5707 emit modifiedGraph();
5708 }
5709 }
5710
setCurveLineStyle(int curveIndex,Qt::PenStyle style)5711 void Graph::setCurveLineStyle(int curveIndex, Qt::PenStyle style)
5712 {
5713 QwtPlotCurve *c = curve(curveIndex);
5714 if (c){
5715 QPen pen = c->pen();
5716 pen.setStyle(style);
5717 c->setPen(pen);
5718 replot();
5719 emit modifiedGraph();
5720 }
5721 }
5722
setCurveLineWidth(int curveIndex,double width)5723 void Graph::setCurveLineWidth(int curveIndex, double width)
5724 {
5725 QwtPlotCurve *c = curve(curveIndex);
5726 if (c){
5727 QPen pen = c->pen();
5728 pen.setWidthF(width);
5729 c->setPen(pen);
5730 replot();
5731 emit modifiedGraph();
5732 }
5733 }
5734
setGrayScale()5735 void Graph::setGrayScale()
5736 {
5737 if (isPiePlot())
5738 return;
5739
5740 int curves = d_curves.size();
5741 int dv = int(255/double(curves));
5742 int i = 0;
5743 QColor color = Qt::black;
5744 int hue = color.hue();
5745 foreach (QwtPlotItem *it, d_curves){
5746 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram){
5747 ((Spectrogram *)it)->setGrayScale();
5748 continue;
5749 }
5750
5751 PlotCurve *c = (PlotCurve *)it;
5752 if (c->type() == ErrorBars)
5753 continue;
5754
5755 QPen pen = c->pen();
5756 if (i){
5757 int v = i*dv;
5758 if (v > 255)
5759 v = 0;
5760 color = QColor::fromHsv(hue, 0, v);
5761 }
5762 pen.setColor(color);
5763 c->setPen(pen);
5764
5765 QBrush brush = c->brush();
5766 if (brush.style() != Qt::NoBrush){
5767 brush.setColor(color);
5768 c->setBrush(brush);
5769 }
5770
5771 QwtSymbol symbol = c->symbol();
5772 pen = symbol.pen();
5773 pen.setColor(color);
5774 symbol.setPen(pen);
5775 if (symbol.brush().style() != Qt::NoBrush)
5776 symbol.setBrush(QBrush(color));
5777 c->setSymbol(symbol);
5778 i++;
5779 }
5780
5781 foreach (QwtPlotItem *it, d_curves){
5782 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
5783 continue;
5784
5785 PlotCurve *c = (PlotCurve *)it;
5786 if (c->type() == ErrorBars){
5787 ErrorBarsCurve *er = (ErrorBarsCurve *)it;
5788 DataCurve* mc = er->masterCurve();
5789 if (mc)
5790 er->setColor(mc->pen().color());
5791 }
5792 }
5793
5794 replot();
5795 emit modifiedGraph();
5796 }
5797
setIndexedColors()5798 void Graph::setIndexedColors()
5799 {
5800 QList<QColor> colors;
5801 MultiLayer *ml = multiLayer();
5802 if (ml && ml->applicationWindow())
5803 colors = ml->applicationWindow()->indexedColors();
5804 else
5805 colors = ColorBox::defaultColors();
5806
5807 int i = 0;
5808 foreach (QwtPlotItem *it, d_curves){
5809 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
5810 continue;
5811
5812 PlotCurve *c = (PlotCurve *)it;
5813 if (c->type() == ErrorBars)
5814 continue;
5815
5816 QPen pen = c->pen();
5817 QColor color = colors[i];
5818 pen.setColor(color);
5819 c->setPen(pen);
5820
5821 QBrush brush = c->brush();
5822 if (brush.style() != Qt::NoBrush){
5823 brush.setColor(color);
5824 c->setBrush(brush);
5825 }
5826
5827 QwtSymbol symbol = c->symbol();
5828 pen = symbol.pen();
5829 pen.setColor(color);
5830 symbol.setPen(pen);
5831 if (symbol.brush().style() != Qt::NoBrush)
5832 symbol.setBrush(QBrush(color));
5833 c->setSymbol(symbol);
5834 i++;
5835 }
5836
5837 foreach (QwtPlotItem *it, d_curves){
5838 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
5839 continue;
5840
5841 PlotCurve *c = (PlotCurve *)it;
5842 if (c->type() == ErrorBars){
5843 ErrorBarsCurve *er = (ErrorBarsCurve *)it;
5844 DataCurve* mc = er->masterCurve();
5845 if (mc)
5846 er->setColor(mc->pen().color());
5847 }
5848 }
5849
5850 replot();
5851 emit modifiedGraph();
5852 }
5853
masterCurve(ErrorBarsCurve * er)5854 DataCurve* Graph::masterCurve(ErrorBarsCurve *er)
5855 {
5856 foreach(QwtPlotItem *it, d_curves){
5857 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
5858 continue;
5859 if (((PlotCurve *)it)->type() == Function)
5860 continue;
5861
5862 DataCurve *c = (DataCurve *)it;
5863 DataCurve *mc = er->masterCurve();
5864 if (c && mc && c->plotAssociation() == mc->plotAssociation() &&
5865 c->startRow() == mc->startRow() && c->endRow() == mc->endRow())
5866 return c;
5867 }
5868 return 0;
5869 }
5870
masterCurve(const QString & xColName,const QString & yColName)5871 DataCurve* Graph::masterCurve(const QString& xColName, const QString& yColName)
5872 {
5873 QString master_curve = xColName + "(X)," + yColName + "(Y)";
5874 foreach(QwtPlotItem *it, d_curves){
5875 if (it->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
5876 continue;
5877 if (((PlotCurve *)it)->type() == Function)
5878 continue;
5879
5880 if (((DataCurve *)it)->xColumnName() == xColName && it->title().text() == yColName)
5881 return (DataCurve *)it;
5882 }
5883 return NULL;
5884 }
5885
showCurve(int index,bool visible)5886 void Graph::showCurve(int index, bool visible)
5887 {
5888 QwtPlotItem *it = plotItem(index);
5889 if (it)
5890 it->setVisible(visible);
5891
5892 emit modifiedGraph();
5893 }
5894
visibleCurves()5895 int Graph::visibleCurves()
5896 {
5897 int c = 0;
5898 foreach(QwtPlotItem *it, d_curves){
5899 if (it->isVisible())
5900 c++;
5901 }
5902 return c;
5903 }
5904
selectedScale()5905 QwtScaleWidget* Graph::selectedScale()
5906 {
5907 return scalePicker->selectedAxis();
5908 }
5909
axisTitleSelected()5910 bool Graph::axisTitleSelected()
5911 {
5912 return scalePicker->titleSelected();
5913 }
5914
currentScale()5915 QwtScaleWidget* Graph::currentScale()
5916 {
5917 return scalePicker->currentAxis();
5918 }
5919
axisTitleRect(const QwtScaleWidget * scale)5920 QRect Graph::axisTitleRect(const QwtScaleWidget *scale)
5921 {
5922 if (!scale)
5923 return QRect();
5924
5925 return scalePicker->titleRect(scale);
5926 }
5927
setCurrentFont(const QFont & f)5928 void Graph::setCurrentFont(const QFont& f)
5929 {
5930 QwtScaleWidget *axis = scalePicker->selectedAxis();
5931 if (axis){
5932 if (scalePicker->titleSelected()){
5933 QwtText title = axis->title();
5934 title.setFont(f);
5935 axis->setTitle(title);
5936 } else if (scalePicker->labelsSelected())
5937 axis->setFont(f);
5938 emit modifiedGraph();
5939 } else if (d_active_enrichment){
5940 LegendWidget *l = qobject_cast<LegendWidget *>(d_active_enrichment);
5941 if (l){
5942 l->setFont(f);
5943 l->repaint();
5944 emit modifiedGraph();
5945 }
5946 } else if (titlePicker->selected()){
5947 setTitleFont(f);
5948 updateMarkersBoundingRect();
5949 } else {
5950 QList<QwtPlotItem *> curves = curvesList();
5951 foreach(QwtPlotItem *i, curves){
5952 if(i->rtti() != QwtPlotItem::Rtti_PlotSpectrogram &&
5953 ((PlotCurve *)i)->type() != Graph::Function){
5954 if(((DataCurve *)i)->hasSelectedLabels()){
5955 ((DataCurve *)i)->setLabelsFont(f);
5956 replot();
5957 emit modifiedGraph();
5958 return;
5959 }
5960 }
5961 }
5962 }
5963 }
5964
setCurrentColor(const QColor & c)5965 void Graph::setCurrentColor(const QColor& c)
5966 {
5967 QwtScaleWidget *axis = scalePicker->selectedAxis();
5968 if (axis){
5969 if (scalePicker->titleSelected()){
5970 QwtText title = axis->title();
5971 title.setColor(c);
5972 axis->setTitle(title);
5973 } else if (scalePicker->labelsSelected()){
5974 QPalette pal = axis->palette();
5975 pal.setColor(QColorGroup::Text, c);
5976 axis->setPalette(pal);
5977 }
5978 emit modifiedGraph();
5979 } else if (d_active_enrichment){
5980 LegendWidget *l = qobject_cast<LegendWidget *>(d_active_enrichment);
5981 if (l){
5982 l->setTextColor(c);
5983 l->repaint();
5984 emit modifiedGraph();
5985 }
5986 } else if (titlePicker->selected()){
5987 QwtText t = title();
5988 t.setColor(c);
5989 setTitle(t);
5990 emit modifiedGraph();
5991 } else {
5992 QList<QwtPlotItem *> curves = curvesList();
5993 foreach(QwtPlotItem *i, curves){
5994 if(i->rtti() != QwtPlotItem::Rtti_PlotSpectrogram &&
5995 ((PlotCurve *)i)->type() != Graph::Function){
5996 if(((DataCurve *)i)->hasSelectedLabels()){
5997 ((DataCurve *)i)->setLabelsColor(c);
5998 replot();
5999 emit modifiedGraph();
6000 return;
6001 }
6002 }
6003 }
6004 }
6005 }
6006
axisFormula(int axis)6007 QString Graph::axisFormula(int axis)
6008 {
6009 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(axis);
6010 if (sd)
6011 return sd->formula();
6012
6013 return QString();
6014 }
6015
setAxisFormula(int axis,const QString & formula)6016 void Graph::setAxisFormula(int axis, const QString &formula)
6017 {
6018 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw(axis);
6019 if (sd)
6020 sd->setFormula(formula);
6021 }
6022
frameColor()6023 QColor Graph::frameColor()
6024 {
6025 return palette().color(QPalette::Active, QPalette::Foreground);
6026 }
6027
printFrame(QPainter * painter,const QRect & rect) const6028 void Graph::printFrame(QPainter *painter, const QRect &rect) const
6029 {
6030 painter->save();
6031
6032 int lw = qRound((double)painter->device()->logicalDpiX()/(double)logicalDpiX()*lineWidth());
6033 if (lw){
6034 QColor color = palette().color(QPalette::Active, QPalette::Foreground);
6035 painter->setPen (QPen(color, lw, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
6036 } else
6037 painter->setPen(QPen(Qt::NoPen));
6038
6039 int lw2 = lw/2;
6040 QRect r = rect;
6041 if (lw % 2)
6042 r.adjust(lw2, lw2, -(lw2 + 1), -(lw2 + 1));
6043 else
6044 r.adjust(lw2, lw2, -lw2, -lw2);
6045
6046 QwtPainter::fillRect(painter, r, paletteBackgroundColor());
6047 painter->drawRect(r);
6048 painter->restore();
6049 }
6050
setCanvasBackgroundImage(const QString & fn,bool update)6051 void Graph::setCanvasBackgroundImage(const QString & fn, bool update)
6052 {
6053 if (fn == d_canvas_bkg_path)
6054 return;
6055
6056 if (fn.isEmpty()){
6057 d_canvas_bkg_path = QString();
6058 d_canvas_bkg_pix = QPixmap();
6059 replot();
6060 return;
6061 }
6062
6063 QFileInfo fi(fn);
6064 if (!fi.exists ()|| !fi.isReadable())
6065 return;
6066
6067 QList<QByteArray> lst = QImageReader::supportedImageFormats() << "JPG";
6068 for (int i = 0; i<(int)lst.count(); i++){
6069 if (fn.contains("." + lst[i])){
6070 d_canvas_bkg_pix.load(fn, lst[i], QPixmap::Auto);
6071 d_canvas_bkg_path = fn;
6072
6073 if (update)
6074 replot();
6075
6076 return;
6077 }
6078 }
6079 }
6080
printCanvas(QPainter * painter,const QRect & canvasRect,const QwtScaleMap map[axisCnt],const QwtPlotPrintFilter & pfilter) const6081 void Graph::printCanvas(QPainter *painter, const QRect &canvasRect,
6082 const QwtScaleMap map[axisCnt], const QwtPlotPrintFilter &pfilter) const
6083 {
6084 painter->save();
6085
6086 const QwtPlotCanvas* plotCanvas = canvas();
6087 int lw = qRound((double)painter->device()->logicalDpiX()/(double)logicalDpiX()*plotCanvas->lineWidth());
6088
6089 QRect fillRect = canvasRect.adjusted(0, 0, -1, -1);
6090 QwtPainter::fillRect(painter, fillRect, canvasBackground());
6091
6092 painter->setClipping(true);
6093 painter->setClipRect(fillRect);
6094 drawItems(painter, fillRect, map, pfilter);
6095 painter->restore();
6096
6097 if(lw > 0){
6098 painter->save();
6099 QColor color = plotCanvas->palette().color(QPalette::Active, QColorGroup::Foreground);
6100 painter->setPen (QPen(color, lw, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin));
6101 painter->drawRect(fillRect);
6102 painter->restore();
6103 }
6104 }
6105
drawItems(QPainter * painter,const QRect & rect,const QwtScaleMap map[axisCnt],const QwtPlotPrintFilter & pfilter) const6106 void Graph::drawItems (QPainter *painter, const QRect &rect,
6107 const QwtScaleMap map[axisCnt], const QwtPlotPrintFilter &pfilter) const
6108 {
6109 for (int i = 0; i < QwtPlot::axisCnt; i++){
6110 if (!axisEnabled(i) || d_is_printing)
6111 continue;
6112 drawBreak(painter, rect, map[i], i);
6113 }
6114
6115 for (int i = 0; i < QwtPlot::axisCnt; i++){
6116 ScaleEngine *sc_engine = (ScaleEngine *)axisScaleEngine(i);
6117 if (!sc_engine->hasBreak())
6118 continue;
6119
6120 QwtScaleMap m = map[i];
6121 int lb = m.transform(sc_engine->axisBreakLeft());
6122 int rb = m.transform(sc_engine->axisBreakRight());
6123
6124 if (d_is_printing && painter->paintEngine()->type() != QPaintEngine::Raster){
6125 if (i == QwtPlot::yLeft || i == QwtPlot::yRight){
6126 double yfactor = (double)painter->device()->logicalDpiY()/(double)this->logicalDpiY();
6127 int dy = qRound(abs(lb - rb)*yfactor*0.5);
6128 rb -= dy;
6129 lb += dy;
6130 } else {
6131 double xfactor = (double)painter->device()->logicalDpiX()/(double)this->logicalDpiX();
6132 int dx = qRound(abs(lb - rb)*xfactor*0.5);
6133 lb -= dx;
6134 rb += dx;
6135 }
6136 }
6137
6138 int start = lb, end = rb;
6139 if (sc_engine->testAttribute(QwtScaleEngine::Inverted)){
6140 end = lb;
6141 start = rb;
6142 }
6143 QRegion cr(rect);
6144 if (i == QwtPlot::xBottom || i == QwtPlot::xTop)
6145 painter->setClipRegion(cr.subtracted(QRegion(start, rect.y(), abs(end - start + 1), rect.height())), Qt::IntersectClip);
6146 else if (i == QwtPlot::yLeft || i == QwtPlot::yRight)
6147 painter->setClipRegion(cr.subtracted(QRegion(rect.x(), end, rect.width(), abs(end - start + 1))), Qt::IntersectClip);
6148 }
6149
6150 painter->setRenderHint(QPainter::TextAntialiasing);
6151
6152 if (!d_canvas_bkg_pix.isNull())
6153 painter->drawPixmap(rect, d_canvas_bkg_pix);
6154
6155 QwtPlot::drawItems(painter, rect, map, pfilter);
6156
6157 if (d_is_printing)
6158 return;
6159
6160 for (int i = 0; i<QwtPlot::axisCnt; i++){
6161 if (!axisEnabled(i))
6162 continue;
6163
6164 drawBreak(painter, rect, map[i], i);
6165
6166 ScaleDraw *sd = (ScaleDraw *) axisScaleDraw (i);
6167 int majorTicksType = sd->majorTicksStyle();
6168 int minorTicksType = sd->minorTicksStyle();
6169 bool min = (minorTicksType == ScaleDraw::In || minorTicksType == ScaleDraw::Both);
6170 bool maj = (majorTicksType == ScaleDraw::In || majorTicksType == ScaleDraw::Both);
6171 if (min || maj)
6172 drawInwardTicks(painter, rect, map[i], i, min, maj);
6173 }
6174 }
6175
drawInwardTicks(QPainter * painter,const QRect & rect,const QwtScaleMap & map,int axis,bool min,bool maj) const6176 void Graph::drawInwardTicks(QPainter *painter, const QRect &rect,
6177 const QwtScaleMap &map, int axis, bool min, bool maj) const
6178 {
6179 const QwtScaleWidget *scale = axisWidget(axis);
6180 if (!scale)
6181 return;
6182
6183 int x1 = rect.left();
6184 int x2 = rect.right();
6185 int y1 = rect.top();
6186 int y2 = rect.bottom();
6187
6188 QPalette pal = scale->palette();
6189 QColor color = pal.color(QPalette::Active, QColorGroup::Foreground);
6190
6191 painter->save();
6192 painter->setPen(QPen(color, scale->penWidth(), Qt::SolidLine));
6193
6194 QwtScaleDiv *scDiv = (QwtScaleDiv *)axisScaleDiv(axis);
6195 const QwtValueList minTickList = scDiv->ticks(QwtScaleDiv::MinorTick);
6196 int minTicks = (int)minTickList.count();
6197
6198 const QwtValueList medTickList = scDiv->ticks(QwtScaleDiv::MediumTick);
6199 int medTicks = (int)medTickList.count();
6200
6201 QwtValueList majTickList = scDiv->ticks(QwtScaleDiv::MajorTick);
6202
6203 ScaleEngine *sc_engine = (ScaleEngine *)axisScaleEngine(axis);
6204 if (sc_engine->hasBreak()){
6205 majTickList.removeAll(sc_engine->axisBreakLeft());
6206 majTickList.removeAll(sc_engine->axisBreakRight());
6207 }
6208 int majTicks = (int)majTickList.count();
6209
6210 int j, x, y, low,high;
6211 int clw = canvas()->lineWidth();
6212 switch (axis)
6213 {
6214 case QwtPlot::yLeft:
6215 x = x1;
6216 low = y1 + d_maj_tick_length;
6217 high = y2 - d_maj_tick_length;
6218 if (min && d_min_tick_length){
6219 for (j = 0; j < minTicks; j++){
6220 y = map.transform(minTickList[j]);
6221 if (y > low && y < high)
6222 QwtPainter::drawLine(painter, x, y, x + d_min_tick_length, y);
6223 }
6224 for (j = 0; j < medTicks; j++){
6225 y = map.transform(medTickList[j]);
6226 if (y > low && y < high)
6227 QwtPainter::drawLine(painter, x, y, x + d_min_tick_length, y);
6228 }
6229 }
6230
6231 if (maj && d_maj_tick_length){
6232 for (j = 0; j < majTicks; j++){
6233 y = map.transform(majTickList[j]);
6234 if ((y > low && y < high) ||
6235 (y > high && !axisEnabled (QwtPlot::xBottom) && !clw) ||
6236 (y < low && !axisEnabled(QwtPlot::xTop) && !clw))
6237 QwtPainter::drawLine(painter, x, y, x + d_maj_tick_length, y);
6238 }
6239 }
6240 break;
6241
6242 case QwtPlot::yRight:
6243 {
6244 x = x2;
6245 low = y1 + d_maj_tick_length;
6246 high = y2 - d_maj_tick_length;
6247 if (min && d_min_tick_length){
6248 for (j = 0; j < minTicks; j++){
6249 y = map.transform(minTickList[j]);
6250 if (y > low && y < high)
6251 QwtPainter::drawLine(painter, x, y, x - d_min_tick_length, y);
6252 }
6253 for (j = 0; j < medTicks; j++){
6254 y = map.transform(medTickList[j]);
6255 if (y > low && y < high)
6256 QwtPainter::drawLine(painter, x, y, x - d_min_tick_length, y);
6257 }
6258 }
6259
6260 if (maj && d_maj_tick_length){
6261 for (j = 0; j <majTicks; j++){
6262 y = map.transform(majTickList[j]);
6263 if ((y > low && y < high) ||
6264 (y > high && !axisEnabled (QwtPlot::xBottom) && !clw) ||
6265 (y < low && !axisEnabled(QwtPlot::xTop) && !clw))
6266 QwtPainter::drawLine(painter, x, y, x - d_maj_tick_length, y);
6267 }
6268 }
6269 }
6270 break;
6271
6272 case QwtPlot::xBottom:
6273 y = y2;
6274 low = x1 + d_maj_tick_length;
6275 high = x2 - d_maj_tick_length;
6276 if (min && d_min_tick_length){
6277 for (j = 0; j < minTicks; j++){
6278 x = map.transform(minTickList[j]);
6279 if (x > low && x < high)
6280 QwtPainter::drawLine(painter, x, y, x, y - d_min_tick_length);
6281 }
6282 for (j = 0; j < medTicks; j++){
6283 x = map.transform(medTickList[j]);
6284 if (x > low && x < high)
6285 QwtPainter::drawLine(painter, x, y, x, y - d_min_tick_length);
6286 }
6287 }
6288
6289 if (maj && d_maj_tick_length){
6290 for (j = 0; j < majTicks; j++){
6291 x = map.transform(majTickList[j]);
6292 if ((x > low && x < high) ||
6293 (x > high && !axisEnabled(QwtPlot::yRight) && !clw) ||
6294 (x < low && !axisEnabled(QwtPlot::yLeft) && !clw))
6295 QwtPainter::drawLine(painter, x, y, x, y - d_maj_tick_length);
6296 }
6297 }
6298 break;
6299
6300 case QwtPlot::xTop:
6301 y = y1;
6302 low = x1 + d_maj_tick_length;
6303 high = x2 - d_maj_tick_length;
6304
6305 if (min && d_min_tick_length){
6306 for (j = 0; j < minTicks; j++){
6307 x = map.transform(minTickList[j]);
6308 if (x > low && x < high)
6309 QwtPainter::drawLine(painter, x, y, x, y + d_min_tick_length);
6310 }
6311 for (j = 0; j < medTicks; j++){
6312 x = map.transform(medTickList[j]);
6313 if (x > low && x < high)
6314 QwtPainter::drawLine(painter, x, y, x, y + d_min_tick_length);
6315 }
6316 }
6317
6318 if (maj && d_maj_tick_length){
6319 for (j = 0; j < majTicks; j++){
6320 x = map.transform(majTickList[j]);
6321 if ((x > low && x < high) ||
6322 (x > high && !axisEnabled(QwtPlot::yRight) && !clw) ||
6323 (x < low && !axisEnabled(QwtPlot::yLeft) && !clw))
6324 QwtPainter::drawLine(painter, x, y, x, y + d_maj_tick_length);
6325 }
6326 }
6327 break;
6328 }
6329 painter->restore();
6330 }
6331
drawBreak(QPainter * painter,const QRect & rect,const QwtScaleMap & map,int axis) const6332 void Graph::drawBreak(QPainter *painter, const QRect &rect, const QwtScaleMap &map, int axis) const
6333 {
6334 ScaleEngine *sc_engine = (ScaleEngine *)axisScaleEngine(axis);
6335 if (!sc_engine->hasBreak() || !sc_engine->hasBreakDecoration())
6336 return;
6337
6338 painter->save();
6339 painter->setRenderHint(QPainter::Antialiasing);
6340
6341 QColor color = axisWidget(axis)->palette().color(QPalette::Active, QColorGroup::Foreground);
6342 painter->setPen(QPen(color, axesLinewidth(), Qt::SolidLine));
6343
6344 int left = map.transform(sc_engine->axisBreakLeft());
6345 int right = map.transform(sc_engine->axisBreakRight());
6346 int x, y;
6347 int len = d_maj_tick_length;
6348 switch (axis){
6349 case QwtPlot::yLeft:
6350 x = rect.left() - 1;
6351 QwtPainter::drawLine(painter, x, left, x + len, left - len);
6352 QwtPainter::drawLine(painter, x, right, x + len, right - len);
6353 break;
6354
6355 case QwtPlot::yRight:
6356 x = rect.right() + 1;
6357 QwtPainter::drawLine(painter, x - len, left + len, x, left);
6358 QwtPainter::drawLine(painter, x - len, right + len, x, right);
6359 break;
6360
6361 case QwtPlot::xBottom:
6362 y = rect.bottom() + 1;
6363 QwtPainter::drawLine(painter, left, y, left + len, y - len);
6364 QwtPainter::drawLine(painter, right, y, right + len, y - len);
6365 break;
6366
6367 case QwtPlot::xTop:
6368 y = rect.top() - 1;
6369 QwtPainter::drawLine(painter, left - len, y + len, left, y);
6370 QwtPainter::drawLine(painter, right - len, y + len, right, y);
6371 break;
6372 }
6373 painter->restore();
6374 }
6375
axesLinewidth() const6376 int Graph::axesLinewidth() const
6377 {
6378 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) {
6379 const QwtScaleWidget *scale = this->axisWidget(axis);
6380 if (scale)
6381 return scale->penWidth();
6382 }
6383 return 0;
6384 }
6385
minorTickLength() const6386 int Graph::minorTickLength() const
6387 {
6388 return d_min_tick_length;
6389 }
6390
majorTickLength() const6391 int Graph::majorTickLength() const
6392 {
6393 return d_maj_tick_length;
6394 }
6395
setTickLength(int minLength,int majLength)6396 void Graph::setTickLength (int minLength, int majLength)
6397 {
6398 if (d_maj_tick_length == majLength && d_min_tick_length == minLength)
6399 return;
6400
6401 d_maj_tick_length = majLength;
6402 d_min_tick_length = minLength;
6403 }
6404
closestCurve(int xpos,int ypos,int & dist,int & point)6405 QwtPlotItem* Graph::closestCurve(int xpos, int ypos, int &dist, int &point)
6406 {
6407 double dmin = DBL_MAX;
6408 QPoint p = QPoint(xpos, ypos);
6409 QwtPlotItem *curve = NULL;
6410 foreach (QwtPlotItem *item, d_curves){
6411 if(item->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
6412 continue;
6413
6414 PlotCurve *c = (PlotCurve *)item;
6415 if (c->type() == Graph::ErrorBars)
6416 continue;
6417
6418 if (c->type() != Graph::Function){
6419 DataCurve *dc = (DataCurve *)c;
6420 if (dc->hasLabels() && dc->selectedLabels(p)){
6421 dist = 0;
6422 return item;
6423 }
6424 }
6425
6426 double d = 0;
6427 int pnt = c->closestPoint(p, &d);
6428 if (pnt >= 0 && d < dmin){
6429 dmin = d;
6430 curve = c;
6431 point = pnt;
6432 }
6433 }
6434
6435 if (curve){
6436 if (dmin <= 10){
6437 dist = qRound(dmin);
6438 return curve;
6439 }
6440 }
6441
6442 QwtScaleMap map[QwtPlot::axisCnt];
6443 for (int axis = 0; axis < QwtPlot::axisCnt; axis++)
6444 map[axis] = canvasMap(axis);
6445
6446 foreach (QwtPlotItem *item, d_curves){
6447 if(item->rtti() != QwtPlotItem::Rtti_PlotSpectrogram)
6448 continue;
6449
6450 Spectrogram *c = (Spectrogram *)item;
6451 if (c->selectedLabels(p)){
6452 dist = 0;
6453 return item;
6454 } else {
6455 c->selectLabel(false);
6456 if (c->transform(map[c->xAxis()], map[c->yAxis()], c->boundingRect()).contains(p)){
6457 dist = 0;
6458 return item;
6459 }
6460 }
6461 }
6462 return NULL;
6463 }
6464
insertMarker(QwtPlotMarker * m)6465 void Graph::insertMarker(QwtPlotMarker *m)
6466 {
6467 m->setRenderHint(QwtPlotItem::RenderAntialiased, d_antialiasing);
6468 m->attach(((QwtPlot *)this));
6469 }
6470
insertCurve(QwtPlotItem * c)6471 void Graph::insertCurve(QwtPlotItem *c)
6472 {
6473 if (!c)
6474 return;
6475
6476 if (!d_curves.contains(c))
6477 d_curves.append(c);
6478
6479 c->setRenderHint(QwtPlotItem::RenderAntialiased, d_antialiasing);
6480 c->attach(this);
6481 }
6482
getMajorTicksType()6483 QList<int> Graph::getMajorTicksType()
6484 {
6485 QList<int> majorTicksType;
6486 for (int axis=0; axis<QwtPlot::axisCnt; axis++){
6487 if (axisEnabled(axis)){
6488 ScaleDraw *sd = (ScaleDraw *) axisScaleDraw (axis);
6489 majorTicksType << sd->majorTicksStyle();
6490 } else
6491 majorTicksType << ScaleDraw::Out;
6492 }
6493 return majorTicksType;
6494 }
6495
setMajorTicksType(int axis,int type)6496 void Graph::setMajorTicksType(int axis, int type)
6497 {
6498 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
6499 if (sd)
6500 sd->setMajorTicksStyle ((ScaleDraw::TicksStyle)type);
6501 }
6502
getMinorTicksType()6503 QList<int> Graph::getMinorTicksType()
6504 {
6505 QList<int> minorTicksType;
6506 for (int axis=0; axis<QwtPlot::axisCnt; axis++)
6507 {
6508 if (axisEnabled(axis))
6509 {
6510 ScaleDraw *sd = (ScaleDraw *) axisScaleDraw (axis);
6511 minorTicksType << sd->minorTicksStyle();
6512 }
6513 else
6514 minorTicksType << ScaleDraw::Out;
6515 }
6516 return minorTicksType;
6517 }
6518
setMinorTicksType(int axis,int type)6519 void Graph::setMinorTicksType(int axis, int type)
6520 {
6521 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
6522 if (sd)
6523 sd->setMinorTicksStyle((ScaleDraw::TicksStyle)type);
6524 }
6525
axisLabelFormat(int axis)6526 int Graph::axisLabelFormat(int axis)
6527 {
6528 if (axisValid(axis)){
6529 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
6530 return sd->labelNumericFormat();
6531 }
6532 return 0;
6533 }
6534
axisLabelPrecision(int axis)6535 int Graph::axisLabelPrecision(int axis)
6536 {
6537 if (axisValid(axis))
6538 {
6539 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
6540 return sd->labelNumericPrecision();
6541 }
6542
6543 //for a bad call we return the default values
6544 return 4;
6545 }
6546
6547 /*!
6548 \return the number format for the major scale labels of a specified axis
6549 \param axis axis index
6550 \retval f format character
6551 \retval prec precision
6552 */
axisLabelFormat(int axis,char & f,int & prec) const6553 void Graph::axisLabelFormat(int axis, char &f, int &prec) const
6554 {
6555 if (axisValid(axis)){
6556 ScaleDraw *sd = (ScaleDraw *)axisScaleDraw (axis);
6557 sd->labelFormat(f, prec);
6558 } else {//for a bad call we return the default values
6559 f = 'g';
6560 prec = 4;
6561 }
6562 }
6563
6564 /*!
6565 \brief Adjust plot content to its current size.
6566 Must be reimplemented because the base implementation adds a mask causing an ugly drawing artefact.
6567 */
updateLayout()6568 void Graph::updateLayout()
6569 {
6570 plotLayout()->activate(this, contentsRect());
6571 // resize and show the visible widgets
6572
6573 if (!titleLabel()->text().isEmpty()){
6574 titleLabel()->setGeometry(plotLayout()->titleRect());
6575 if (!titleLabel()->isVisible())
6576 titleLabel()->show();
6577 } else
6578 titleLabel()->hide();
6579
6580 for (int axisId = 0; axisId < axisCnt; axisId++){
6581 if (axisEnabled(axisId) ){
6582 axisWidget(axisId)->setGeometry(plotLayout()->scaleRect(axisId));
6583 if (!axisWidget(axisId)->isVisible())
6584 axisWidget(axisId)->show();
6585 } else
6586 axisWidget(axisId)->hide();
6587 }
6588
6589 canvas()->setUpdatesEnabled(false);
6590 canvas()->setGeometry(plotLayout()->canvasRect());
6591 canvas()->setUpdatesEnabled(true);
6592
6593 updatedLayout(this);
6594 }
6595
6596 /*!
6597 \brief Adjust plot content to its canvas size.
6598 \param cr The new geometry of the canvas.
6599 */
setCanvasGeometry(const QRect & cr)6600 void Graph::setCanvasGeometry(const QRect &cr)
6601 {
6602 bool scaleFonts = autoScaleFonts;
6603 autoScaleFonts = false;
6604
6605 QRect ocr = plotLayout()->canvasRect().translated(pos());//old canvas geometry
6606
6607 QRect rect = geometry();
6608 rect.adjust(cr.x() - ocr.x(), cr.y() - ocr.y(), cr.right() - ocr.right(), cr.bottom() - ocr.bottom());
6609 setGeometry(rect);
6610
6611 updateMarkersBoundingRect(false);
6612 autoScaleFonts = scaleFonts;
6613 }
6614
6615 /*!
6616 \brief Adjust plot content to its canvas size.
6617 \param cr The new size of the canvas.
6618 */
setCanvasSize(const QSize & size)6619 void Graph::setCanvasSize(const QSize &size)
6620 {
6621 bool scaleFonts = autoScaleFonts;
6622 autoScaleFonts = false;
6623
6624 QRect ocr = plotLayout()->canvasRect().translated(pos());//old canvas geometry
6625
6626 QRect rect = geometry();
6627 rect.adjust(0, 0, size.width() - ocr.width(), size.height() - ocr.height());
6628 setGeometry(rect);
6629
6630 updateMarkersBoundingRect(false);
6631 autoScaleFonts = scaleFonts;
6632 }
6633
paletteBackgroundColor() const6634 const QColor & Graph::paletteBackgroundColor() const
6635 {
6636 return palette().color(QPalette::Window);
6637 }
6638
updateCurveLabels()6639 void Graph::updateCurveLabels()
6640 {
6641 QList<QwtPlotItem *> curves = curvesList();
6642 foreach(QwtPlotItem *i, curves){
6643 if(i->rtti() != QwtPlotItem::Rtti_PlotSpectrogram &&
6644 ((PlotCurve *)i)->type() != Graph::Function &&
6645 ((DataCurve *)i)->hasLabels())
6646 ((DataCurve *)i)->updateLabelsPosition();
6647 }
6648 }
6649
showEvent(QShowEvent * event)6650 void Graph::showEvent (QShowEvent * event)
6651 {
6652 event->accept();
6653 updateCurveLabels();
6654 }
6655
6656 /*!
6657 \brief Paint the plot into a given rectangle.
6658 Paint the contents of a QwtPlot instance into a given rectangle (Qwt modified code).
6659
6660 \param painter Painter
6661 \param plotRect Bounding rectangle
6662 \param pfilter Print filter
6663 */
print(QPainter * painter,const QRect & plotRect,const QwtPlotPrintFilter & pfilter)6664 void Graph::print(QPainter *painter, const QRect &plotRect, const QwtPlotPrintFilter &pfilter)
6665 {
6666 if (painter == 0 || !painter->isActive() || !plotRect.isValid() || size().isNull())
6667 return;
6668
6669 deselect();
6670
6671 d_is_printing = true;
6672
6673 printFrame(painter, plotRect);
6674
6675 painter->save();
6676
6677 // All paint operations need to be scaled according to
6678 // the paint device metrics.
6679
6680 QwtPainter::setMetricsMap(this, painter->device());
6681 const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();
6682
6683 // It is almost impossible to integrate into the Qt layout
6684 // framework, when using different fonts for printing
6685 // and screen. To avoid writing different and Qt unconform
6686 // layout engines we change the widget attributes, print and
6687 // reset the widget attributes again. This way we produce a lot of
6688 // useless layout events ...
6689
6690 pfilter.apply((QwtPlot *)this);
6691
6692 int axisId;
6693 int baseLineDists[QwtPlot::axisCnt];
6694 if (pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales){
6695 // In case of no background we set the backbone of
6696 // the scale on the frame of the canvas.
6697
6698 for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ){
6699 QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
6700 if ( scaleWidget ){
6701 baseLineDists[axisId] = scaleWidget->margin();
6702 scaleWidget->setMargin(0);
6703 }
6704 }
6705 }
6706
6707 // Calculate the layout for the print.
6708
6709 int layoutOptions = QwtPlotLayout::IgnoreScrollbars;
6710 if ( !(pfilter.options() & QwtPlotPrintFilter::PrintMargin) )
6711 layoutOptions |= QwtPlotLayout::IgnoreMargin;
6712 if ( !(pfilter.options() & QwtPlotPrintFilter::PrintLegend) )
6713 layoutOptions |= QwtPlotLayout::IgnoreLegend;
6714
6715 int bw = lineWidth();
6716 plotLayout()->activate(this,
6717 QwtPainter::metricsMap().deviceToLayout(plotRect.adjusted(bw, bw, -bw, -bw)), layoutOptions);
6718
6719 QRect canvasRect = plotLayout()->canvasRect();
6720
6721 // The border of the bounding rect needs to be scaled to
6722 // layout coordinates, so that it is aligned to the axes
6723
6724 QRect boundingRect( canvasRect.left() - 1, canvasRect.top() - 1,
6725 canvasRect.width() + 2, canvasRect.height() + 2);
6726 boundingRect = metricsMap.layoutToDevice(boundingRect);
6727 boundingRect.setWidth(boundingRect.width() - 1);
6728 boundingRect.setHeight(boundingRect.height() - 1);
6729
6730 canvasRect = metricsMap.layoutToDevice(canvasRect);
6731
6732 // When using QwtPainter all sizes where computed in pixel
6733 // coordinates and scaled by QwtPainter later. This limits
6734 // the precision to screen resolution. A much better solution
6735 // is to scale the maps and print in unlimited resolution.
6736
6737 QwtScaleMap map[axisCnt];
6738 for (axisId = 0; axisId < axisCnt; axisId++){
6739 map[axisId].setTransformation(axisScaleEngine(axisId)->transformation());
6740
6741 const QwtScaleDiv &scaleDiv = *axisScaleDiv(axisId);
6742 map[axisId].setScaleInterval(scaleDiv.lowerBound(), scaleDiv.upperBound());
6743
6744 double from, to;
6745 if ( axisEnabled(axisId) ){
6746 const int sDist = axisWidget(axisId)->startBorderDist();
6747 const int eDist = axisWidget(axisId)->endBorderDist();
6748 const QRect &scaleRect = plotLayout()->scaleRect(axisId);
6749
6750 if ( axisId == xTop || axisId == xBottom ){
6751 from = metricsMap.layoutToDeviceX(scaleRect.left() + sDist);
6752 to = metricsMap.layoutToDeviceX(scaleRect.right() + 1 - eDist);
6753 } else {
6754 from = metricsMap.layoutToDeviceY(scaleRect.bottom() + 1 - eDist );
6755 to = metricsMap.layoutToDeviceY(scaleRect.top() + sDist);
6756 }
6757 } else {
6758 int margin = plotLayout()->canvasMargin(axisId);
6759 if ( axisId == yLeft || axisId == yRight ){
6760 margin = metricsMap.layoutToDeviceY(margin);
6761 from = canvasRect.bottom() - margin;
6762 to = canvasRect.top() + margin;
6763 } else {
6764 margin = metricsMap.layoutToDeviceX(margin);
6765 from = canvasRect.left() + margin;
6766 to = canvasRect.right() - margin;
6767 }
6768 }
6769 map[axisId].setPaintXInterval(from, to);
6770 }
6771
6772 if (!metricsMap.isIdentity()){//we set non-cosmetic pens in order to scale pen width
6773 foreach (QwtPlotItem *item, d_curves){
6774 if(item->rtti() == QwtPlotItem::Rtti_PlotSpectrogram){
6775 Spectrogram *sp = (Spectrogram *)item;
6776 QPen pen = sp->defaultContourPen();
6777 pen.setCosmetic(false);
6778 sp->setDefaultContourPen(pen);
6779 } else {
6780 PlotCurve *c = (PlotCurve *)item;
6781 QPen pen = c->pen();
6782 pen.setCosmetic(false);
6783 c->setPen(pen);
6784 if (c->type() == Graph::VectXYXY || c->type() == Graph::VectXYAM){
6785 VectorCurve *v = (VectorCurve *)item;
6786 pen = v->vectorPen();
6787 pen.setCosmetic(false);
6788 v->setVectorPen(pen);
6789 }
6790 QwtSymbol symbol = c->symbol();
6791 pen = symbol.pen();
6792 if (pen.style() != Qt::NoPen){
6793 pen.setCosmetic(false);
6794 symbol.setPen(pen);
6795 c->setSymbol(symbol);
6796 }
6797 }
6798 }
6799 }
6800
6801 // The canvas maps are already scaled.
6802 QwtPainter::setMetricsMap(painter->device(), painter->device());
6803
6804 double fontFactor = ((ScaledFontsPrintFilter *)(&pfilter))->scaleFontsFactor();
6805 QList<FrameWidget*> enrichments = stackingOrderEnrichmentsList();
6806 foreach(FrameWidget *f, enrichments){
6807 if (!f->isVisible() || f->isOnTop())
6808 continue;
6809
6810 QFont fnt;
6811 LegendWidget *lw = qobject_cast<LegendWidget *>(f);
6812 if (lw){
6813 fnt = lw->font();
6814 QFont font(fnt);
6815 font.setPointSizeF(fontFactor*font.pointSizeF());
6816 lw->setFont(font);
6817 }
6818
6819 f->print(painter, map);
6820
6821 if (lw)//restore original font
6822 lw->setFont(fnt);
6823 }
6824 printCanvas(painter, canvasRect, map, pfilter);
6825 QwtPainter::resetMetricsMap();
6826
6827 foreach (QwtPlotItem *item, d_curves){
6828 if(item->rtti() == QwtPlotItem::Rtti_PlotSpectrogram){
6829 Spectrogram *sp = (Spectrogram *)item;
6830 QPen pen = sp->defaultContourPen();
6831 pen.setCosmetic(true);
6832 sp->setDefaultContourPen(pen);
6833 } else {
6834 PlotCurve *c = (PlotCurve *)item;
6835 QPen pen = c->pen();
6836 pen.setCosmetic(true);
6837 c->setPen(pen);
6838 if (c->type() == Graph::VectXYXY || c->type() == Graph::VectXYAM){
6839 VectorCurve *v = (VectorCurve *)item;
6840 pen = v->vectorPen();
6841 pen.setCosmetic(true);
6842 v->setVectorPen(pen);
6843 }
6844
6845 QwtSymbol symbol = c->symbol();
6846 pen = symbol.pen();
6847 if (pen.style() != Qt::NoPen){
6848 pen.setCosmetic(true);
6849 symbol.setPen(pen);
6850 c->setSymbol(symbol);
6851 }
6852 }
6853 }
6854
6855 QwtPainter::setMetricsMap(this, painter->device());
6856
6857 if ((pfilter.options() & QwtPlotPrintFilter::PrintTitle) && (!titleLabel()->text().isEmpty())){
6858 QwtTextLabel *title = titleLabel();
6859 QString old_title = title->text().text();
6860 #ifdef TEX_OUTPUT
6861 if (d_is_exporting_tex){
6862 QString s = old_title;
6863 if (d_tex_escape_strings)
6864 s = escapeTeXSpecialCharacters(s);
6865 s = texSuperscripts(s);
6866 title->setText(s);
6867
6868 int flags = title->text().renderFlags();
6869 if (flags & Qt::AlignLeft)
6870 ((QTeXPaintDevice *)painter->device())->setTextHorizontalAlignment(Qt::AlignLeft);
6871 else if (flags & Qt::AlignRight)
6872 ((QTeXPaintDevice *)painter->device())->setTextHorizontalAlignment(Qt::AlignRight);
6873 }
6874 #endif
6875
6876 printTitle(painter, plotLayout()->titleRect());
6877
6878 #ifdef TEX_OUTPUT
6879 if (d_is_exporting_tex){
6880 title->setText(old_title);
6881 ((QTeXPaintDevice *)painter->device())->setTextHorizontalAlignment(Qt::AlignHCenter);
6882 }
6883 #endif
6884 }
6885
6886 canvasRect = plotLayout()->canvasRect();
6887
6888 for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ){
6889 QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
6890 if (scaleWidget){
6891 int baseDist = scaleWidget->margin();
6892
6893 int startDist, endDist;
6894 scaleWidget->getBorderDistHint(startDist, endDist);
6895
6896 QRect scaleRect = plotLayout()->scaleRect(axisId);
6897 if (!scaleWidget->margin()){
6898 switch(axisId){
6899 case xBottom:
6900 scaleRect.setTop(canvasRect.bottom());
6901 break;
6902 case xTop:
6903 scaleRect.setBottom(canvasRect.top());
6904 break;
6905 case yLeft:
6906 scaleRect.setRight(canvasRect.left());
6907 break;
6908 case yRight:
6909 scaleRect.setLeft(canvasRect.right());
6910 break;
6911 }
6912 }
6913 printScale(painter, axisId, startDist, endDist, baseDist, scaleRect);
6914 }
6915 }
6916 QwtPainter::resetMetricsMap();
6917
6918 plotLayout()->invalidate();
6919
6920 // reset all widgets with their original attributes.
6921 if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales ){
6922 // restore the previous base line dists
6923 for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ){
6924 QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
6925 if ( scaleWidget )
6926 scaleWidget->setMargin(baseLineDists[axisId]);
6927 }
6928 }
6929
6930 QwtPainter::setMetricsMap(painter->device(), painter->device());
6931 foreach(FrameWidget *f, enrichments){
6932 if (!f->isVisible() || !f->isOnTop())
6933 continue;
6934 QFont fnt;
6935 LegendWidget *lw = qobject_cast<LegendWidget *>(f);
6936 if (lw){
6937 fnt = lw->font();
6938 QFont font(fnt);
6939 font.setPointSizeF(fontFactor*font.pointSizeF());
6940 lw->setFont(font);
6941 }
6942
6943 f->print(painter, map);
6944
6945 if (lw)//restore original font
6946 lw->setFont(fnt);
6947 }
6948 QwtPainter::resetMetricsMap();
6949
6950 pfilter.reset((QwtPlot *)this);
6951
6952 plotLayout()->activate(this, contentsRect());
6953
6954 painter->restore();
6955
6956 d_is_printing = false;
6957 }
6958
addTexFormula(const QString & s,const QPixmap & pix)6959 TexWidget* Graph::addTexFormula(const QString& s, const QPixmap& pix)
6960 {
6961 TexWidget *t = new TexWidget(this, s, pix);
6962 d_enrichments << t;
6963 emit modifiedGraph();
6964 return t;
6965 }
6966
add(FrameWidget * fw,bool copy)6967 FrameWidget* Graph::add(FrameWidget* fw, bool copy)
6968 {
6969 if (!fw)
6970 return NULL;
6971
6972 if (!copy){
6973 d_enrichments << fw;
6974 d_active_enrichment = fw;
6975 return fw;
6976 }
6977
6978 FrameWidget *aux = NULL;
6979 LegendWidget *l = qobject_cast<LegendWidget *>(fw);
6980 if (l){
6981 aux = new LegendWidget(this);
6982 ((LegendWidget *)aux)->clone(l);
6983 }
6984
6985 TexWidget *t = qobject_cast<TexWidget *>(fw);
6986 if (t){
6987 aux = new TexWidget(this);
6988 ((TexWidget *)aux)->clone(t);
6989 }
6990
6991 ImageWidget *i = qobject_cast<ImageWidget *>(fw);
6992 if (i){
6993 aux = new ImageWidget(this);
6994 ((ImageWidget *)aux)->clone(i);
6995 }
6996
6997 RectangleWidget *r = qobject_cast<RectangleWidget *>(fw);
6998 if (r){
6999 aux = new RectangleWidget(this);
7000 ((RectangleWidget *)aux)->clone(r);
7001 }
7002
7003 EllipseWidget *e = qobject_cast<EllipseWidget *>(fw);
7004 if (e){
7005 aux = new EllipseWidget(this);
7006 ((EllipseWidget *)aux)->clone(e);
7007 }
7008
7009 aux->setAttachPolicy(fw->attachPolicy());
7010 aux->setOnTop(fw->isOnTop());
7011 aux->setVisible(fw->isVisible());
7012
7013 d_enrichments << aux;
7014 d_active_enrichment = aux;
7015 return aux;
7016 }
7017
activeText()7018 LegendWidget* Graph::activeText()
7019 {
7020 return qobject_cast<LegendWidget *>(d_active_enrichment);
7021 }
7022
raiseEnrichements()7023 void Graph::raiseEnrichements()
7024 {
7025 QList<Graph *> lst = multiLayer()->layersList();
7026 foreach(Graph *g, lst){
7027 if (g == this)
7028 continue;
7029
7030 QList<FrameWidget *> eLst = g->enrichmentsList();
7031 foreach(FrameWidget *fw, eLst){
7032 if (fw->isOnTop())
7033 fw->raise();
7034 else
7035 fw->lower();
7036 }
7037 }
7038
7039 foreach(FrameWidget *fw, d_enrichments){
7040 if (fw->isOnTop())
7041 fw->raise();
7042 else
7043 fw->lower();
7044 }
7045 }
7046
boundingRect()7047 QRect Graph::boundingRect()
7048 {
7049 QRect r = rect();
7050
7051 foreach(FrameWidget *fw, d_enrichments){
7052 if (fw->isHidden() || fw->visibleRegion().isEmpty())//pie labels can be hidden
7053 continue;
7054
7055 r = r.united(fw->geometry());
7056 }
7057 return r;
7058 }
7059
customPrintSize(const QSizeF & customSize,int unit,int dpi)7060 QSize Graph::customPrintSize(const QSizeF& customSize, int unit, int dpi)
7061 {
7062 if (!customSize.isValid())
7063 return QSize();
7064
7065 QSize size = QSize();
7066 switch(unit){
7067 case FrameWidget::Pixel:
7068 size = customSize.toSize();
7069 break;
7070 case FrameWidget::Inch:
7071 size = QSize(qRound(customSize.width()*dpi), qRound(customSize.height()*dpi));
7072 break;
7073 case FrameWidget::Millimeter:
7074 size = QSize(qRound(customSize.width()*dpi/25.4), qRound(customSize.height()*dpi/25.4));
7075 break;
7076 case FrameWidget::Centimeter:
7077 size = QSize(qRound(customSize.width()*dpi/2.54), qRound(customSize.height()*dpi/2.54));
7078 break;
7079 case FrameWidget::Point:
7080 size = QSize(qRound(customSize.width()*dpi/72.0), qRound(customSize.height()*dpi/72.0));
7081 break;
7082 }
7083 return size;
7084 }
7085
rangeSelectorsEnabled()7086 bool Graph::rangeSelectorsEnabled()
7087 {
7088 if (d_range_selector && d_range_selector->isVisible())
7089 return true;
7090 return false;
7091 }
7092
7093 /*!
7094 \brief Paint a scale into a given rectangle.
7095 Paint the scale into a given rectangle (modified code from Qwt).
7096
7097 \param painter Painter
7098 \param axisId Axis
7099 \param startDist Start border distance
7100 \param endDist End border distance
7101 \param baseDist Base distance
7102 \param rect Bounding rectangle
7103 */
7104
printScale(QPainter * painter,int axisId,int startDist,int endDist,int baseDist,const QRect & rect) const7105 void Graph::printScale(QPainter *painter,
7106 int axisId, int startDist, int endDist, int baseDist,
7107 const QRect &rect) const
7108 {
7109 if (!axisEnabled(axisId))
7110 return;
7111
7112 QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
7113 if ( scaleWidget->isColorBarEnabled()
7114 && scaleWidget->colorBarWidth() > 0)
7115 {
7116 const QwtMetricsMap map = QwtPainter::metricsMap();
7117
7118 QRect r = map.layoutToScreen(rect);
7119 r.setWidth(r.width() - 1);
7120 r.setHeight(r.height() - 1);
7121
7122 scaleWidget->drawColorBar(painter, scaleWidget->colorBarRect(r));
7123
7124 const int off = scaleWidget->colorBarWidth() + scaleWidget->spacing();
7125 if ( scaleWidget->scaleDraw()->orientation() == Qt::Horizontal )
7126 baseDist += map.screenToLayoutY(off);
7127 else
7128 baseDist += map.screenToLayoutX(off);
7129 }
7130
7131 QwtScaleDraw::Alignment align;
7132 int x, y, w;
7133
7134 switch(axisId)
7135 {
7136 case yLeft:
7137 {
7138 x = rect.right() - baseDist;
7139 y = rect.y() + startDist;
7140 w = rect.height() - startDist - endDist;
7141 align = QwtScaleDraw::LeftScale;
7142 break;
7143 }
7144 case yRight:
7145 {
7146 x = rect.left() + baseDist;
7147 y = rect.y() + startDist;
7148 w = rect.height() - startDist - endDist;
7149 align = QwtScaleDraw::RightScale;
7150 break;
7151 }
7152 case xTop:
7153 {
7154 x = rect.left() + startDist;
7155 y = rect.bottom() - baseDist;
7156 w = rect.width() - startDist - endDist;
7157 align = QwtScaleDraw::TopScale;
7158 break;
7159 }
7160 case xBottom:
7161 {
7162 x = rect.left() + startDist;
7163 y = rect.top() + baseDist;
7164 w = rect.width() - startDist - endDist;
7165 align = QwtScaleDraw::BottomScale;
7166 break;
7167 }
7168 default:
7169 return;
7170 }
7171
7172 QwtText title = scaleWidget->title();
7173 QString old_title = title.text();
7174 #ifdef TEX_OUTPUT
7175 if (d_is_exporting_tex){
7176 QString s = old_title;
7177 if (d_tex_escape_strings)
7178 s = escapeTeXSpecialCharacters(s);
7179 s = texSuperscripts(s);
7180 title.setText(s);
7181
7182 int flags = title.renderFlags();
7183 if (flags & Qt::AlignLeft)
7184 ((QTeXPaintDevice *)painter->device())->setTextHorizontalAlignment(Qt::AlignLeft);
7185 else if (flags & Qt::AlignRight)
7186 ((QTeXPaintDevice *)painter->device())->setTextHorizontalAlignment(Qt::AlignRight);
7187
7188 scaleWidget->setTitle(title);
7189 }
7190 #endif
7191
7192 scaleWidget->drawTitle(painter, align, rect);
7193
7194 #ifdef TEX_OUTPUT
7195 if (d_is_exporting_tex){
7196 title.setText(old_title);
7197 scaleWidget->setTitle(title);
7198 ((QTeXPaintDevice *)painter->device())->setTextHorizontalAlignment(Qt::AlignHCenter);
7199 }
7200 #endif
7201
7202 painter->save();
7203 painter->setFont(scaleWidget->font());
7204
7205 QPen pen = painter->pen();
7206 int lw = scaleWidget->penWidth();
7207 if (!lw)
7208 lw = 1;
7209 pen.setWidthF(lw*(double)painter->device()->logicalDpiX()/(double)logicalDpiX());
7210 painter->setPen(pen);
7211
7212 QwtScaleDraw *sd = (QwtScaleDraw *)scaleWidget->scaleDraw();
7213 const QPoint sdPos = sd->pos();
7214 const int sdLength = sd->length();
7215
7216 sd->move(x, y);
7217 sd->setLength(w);
7218
7219 QPalette palette = scaleWidget->palette();
7220 palette.setCurrentColorGroup(QPalette::Active);
7221
7222 sd->draw(painter, palette);
7223
7224 // reset previous values
7225 sd->move(sdPos);
7226 sd->setLength(sdLength);
7227
7228 painter->restore();
7229 }
7230
7231 #ifdef TEX_OUTPUT
escapeTeXSpecialCharacters(const QString & s)7232 QString Graph::escapeTeXSpecialCharacters(const QString &s)
7233 {
7234 QString text = s;
7235 text.replace("$", "\\$");
7236 text.replace("_", "\\_");
7237 text.replace("{", "\\{");
7238 text.replace("}", "\\}");
7239 text.replace("^", "\\^");
7240 text.replace("&", "\\&");
7241 text.replace("%", "\\%");
7242 text.replace("#", "\\#");
7243 return text;
7244 }
7245
texSuperscripts(const QString & text)7246 QString Graph::texSuperscripts(const QString &text)
7247 {
7248 QString s = text;
7249 s.replace("<sub>", "$_{");
7250 s.replace("<sup>", "$^{");
7251 s.replace("</sub>", "}$");
7252 s.replace("</sup>", "}$");
7253 return s;
7254 }
7255 #endif
7256
changeCurveIndex(int fromIndex,int toIndex)7257 void Graph::changeCurveIndex(int fromIndex, int toIndex)
7258 {
7259 if (d_curves.isEmpty())
7260 return;
7261
7262 if (fromIndex < 0 || fromIndex >= d_curves.size() ||
7263 toIndex < 0 || toIndex >= d_curves.size()) return;
7264
7265 d_curves.move ( fromIndex, toIndex );
7266
7267 int z = 0;
7268 foreach(QwtPlotItem *c, d_curves){
7269 c->setZ(z);
7270 z++;
7271 }
7272 replot();
7273 modifiedGraph();
7274 }
7275
dragEnterEvent(QDragEnterEvent * e)7276 void Graph::dragEnterEvent( QDragEnterEvent* e )
7277 {
7278 Graph *g = qobject_cast<Graph*>(e->source());
7279 if (g && g->multiLayer() == this->multiLayer())
7280 return;
7281
7282 if (e->mimeData()->hasFormat("text/plain"))
7283 e->acceptProposedAction();
7284 }
7285
dropEvent(QDropEvent * event)7286 void Graph::dropEvent(QDropEvent* event)
7287 {
7288 MultiLayer *ml = multiLayer();
7289 if (!ml)
7290 return;
7291
7292 ApplicationWindow *app = ml->applicationWindow();
7293 Table *t = qobject_cast<Table*>(event->source());
7294 if (t){
7295 QStringList columns = event->mimeData()->text().split("\n");
7296 if (columns.isEmpty())
7297 return;
7298
7299 addCurves(t, columns, app->defaultCurveStyle, app->defaultCurveLineWidth, app->defaultSymbolSize);
7300 return;
7301 }
7302
7303 Matrix *m = qobject_cast<Matrix*>(event->source());
7304 if (m){
7305 plotSpectrogram(m, ColorMap);
7306 return;
7307 }
7308
7309 Graph *g = qobject_cast<Graph*>(event->source());
7310 if (!g || g->multiLayer() == this->multiLayer())
7311 return;
7312
7313 QStringList lst = event->mimeData()->text().split(";");
7314
7315 QPoint pos = multiLayer()->canvas()->mapFromGlobal(QCursor::pos());
7316 pos = QPoint(pos.x() - lst[0].toInt(), pos.y() - lst[1].toInt());
7317 Graph *clone = multiLayer()->addLayer(pos.x(), pos.y(), g->width(), g->height());
7318 if (clone)
7319 clone->copy(g);
7320 }
7321
enableDouglasPeukerSpeedMode(double tolerance,int maxPoints)7322 void Graph::enableDouglasPeukerSpeedMode(double tolerance, int maxPoints)
7323 {
7324 if (d_speed_mode_points == maxPoints &&
7325 d_Douglas_Peuker_tolerance == tolerance)
7326 return;
7327
7328 d_speed_mode_points = maxPoints;
7329 d_Douglas_Peuker_tolerance = tolerance;
7330
7331 foreach (QwtPlotItem *item, d_curves){
7332 if(item->rtti() == QwtPlotItem::Rtti_PlotSpectrogram)
7333 continue;
7334
7335 PlotCurve *c = (PlotCurve *)item;
7336 if (!c || c->type() == Function)
7337 continue;
7338
7339 if (tolerance == 0.0 || c->dataSize() < d_speed_mode_points){
7340 c->setCurveAttribute(QwtPlotCurve::Fitted, false);
7341 continue;
7342 }
7343
7344 c->setCurveAttribute(QwtPlotCurve::Fitted);
7345
7346 QwtWeedingCurveFitter *fitter = new QwtWeedingCurveFitter(tolerance);
7347 c->setCurveFitter(fitter);
7348 }
7349 replot();
7350 }
7351
stackingOrderEnrichmentsList() const7352 QList<FrameWidget*> Graph::stackingOrderEnrichmentsList() const
7353 {
7354 MultiLayer *ml = multiLayer();
7355 if (!ml)
7356 return d_enrichments;
7357
7358 QList<FrameWidget*> enrichements;
7359 QObjectList lst = ml->canvas()->children();
7360 foreach(QObject *o, lst){
7361 FrameWidget *fw = qobject_cast<FrameWidget *>(o);
7362 if (fw && fw->plot() == this)
7363 enrichements << fw;
7364 }
7365 return enrichements;
7366 }
7367
mousePressed(QEvent * e)7368 bool Graph::mousePressed(QEvent *e)
7369 {
7370 const QMouseEvent *me = (const QMouseEvent *)e;
7371
7372 QList<FrameWidget*> lst = stackingOrderEnrichmentsList();
7373 foreach(FrameWidget *o, lst){
7374 QPoint pos = o->mapFromGlobal(me->globalPos());
7375 if (o->rect().contains(pos))
7376 return QCoreApplication::sendEvent(o, e);
7377 }
7378
7379 QPoint pos = mapFromGlobal(me->globalPos());
7380 if (plotLayout()->titleRect().contains(pos))
7381 return QCoreApplication::sendEvent(titleLabel(), e);
7382
7383 for (int i = 0; i < QwtPlot::axisCnt; i++ ){
7384 QwtScaleWidget *sw = axisWidget(i);
7385 if (!sw)
7386 continue;
7387
7388 QRect r = plotLayout()->scaleRect(i);
7389 if (r.contains(pos)){
7390 if (scalePicker->scaleRect(sw).translated(r.topLeft()).contains(pos))
7391 scalePicker->selectLabels(sw);
7392 else
7393 scalePicker->selectTitle(sw);
7394 return true;
7395 }
7396 }
7397
7398 return false;
7399 }
7400
setWaterfallXOffset(int offset)7401 void Graph::setWaterfallXOffset(int offset)
7402 {
7403 if (offset == d_waterfall_offset_x)
7404 return;
7405
7406 d_waterfall_offset_x = offset;
7407 updateDataCurves();
7408 emit modifiedGraph();
7409 }
7410
setWaterfallYOffset(int offset)7411 void Graph::setWaterfallYOffset(int offset)
7412 {
7413 if (offset == d_waterfall_offset_y)
7414 return;
7415
7416 d_waterfall_offset_y = offset;
7417 updateDataCurves();
7418 emit modifiedGraph();
7419 }
7420
setWaterfallOffset(int x,int y,bool update)7421 void Graph::setWaterfallOffset(int x, int y, bool update)
7422 {
7423 d_waterfall_offset_x = x;
7424 d_waterfall_offset_y = y;
7425
7426 if (update){
7427 updateDataCurves();
7428 emit modifiedGraph();
7429 }
7430 }
7431
updateWaterfallFill(bool on)7432 void Graph::updateWaterfallFill(bool on)
7433 {
7434 int n = d_curves.size();
7435 if (!n)
7436 return;
7437
7438 for (int i = 0; i < n; i++){
7439 PlotCurve *cv = (PlotCurve *)curve(i);
7440 if (!cv)
7441 continue;
7442
7443 if (on && multiLayer())
7444 cv->setBrush(QBrush(multiLayer()->waterfallFillColor()));
7445 else
7446 cv->setBrush(QBrush());
7447 }
7448 replot();
7449 emit modifiedGraph();
7450 }
7451
setWaterfallSideLines(bool on)7452 void Graph::setWaterfallSideLines(bool on)
7453 {
7454 int n = d_curves.size();
7455 if (!n)
7456 return;
7457
7458 if (curve(0)->sideLinesEnabled() == on)
7459 return;
7460
7461 for (int i = 0; i < n; i++){
7462 PlotCurve *cv = (PlotCurve *)curve(i);
7463 if (cv)
7464 cv->enableSideLines(on);
7465 }
7466 replot();
7467 emit modifiedGraph();
7468 }
7469
setWaterfallFillColor(const QColor & c)7470 void Graph::setWaterfallFillColor(const QColor& c)
7471 {
7472 int n = d_curves.size();
7473 if (!n)
7474 return;
7475
7476 for (int i = 0; i < n; i++){
7477 PlotCurve *cv = (PlotCurve *)curve(i);
7478 if (cv)
7479 cv->setBrush(QBrush(c));
7480 }
7481 replot();
7482 emit modifiedGraph();
7483 }
7484
reverseCurveOrder()7485 void Graph::reverseCurveOrder()
7486 {
7487 if (d_curves.isEmpty())
7488 return;
7489
7490 QList<QwtPlotItem *> lst;
7491 int n = d_curves.size();
7492 for (int i = 0; i < n; i++)
7493 lst << d_curves[n - i - 1];
7494
7495 setCurvesList(lst);
7496 emit modifiedGraph();
7497 }
7498
updateDataCurves()7499 void Graph::updateDataCurves()
7500 {
7501 int n = d_curves.size();
7502 if (!n)
7503 return;
7504
7505 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
7506 for (int i = 0; i < n; i++){
7507 DataCurve *c = dataCurve(i);
7508 if (c)
7509 c->loadData();
7510 }
7511 replot();
7512 QApplication::restoreOverrideCursor();
7513 }
7514
setGridOnTop(bool on,bool update)7515 void Graph::setGridOnTop(bool on, bool update)
7516 {
7517 if (d_grid_on_top == on)
7518 return;
7519
7520 d_grid_on_top = on;
7521
7522 on ? d_grid->setZ(INT_MAX) : d_grid->setZ(INT_MIN);
7523
7524 if (update){
7525 replot();
7526 modifiedGraph();
7527 }
7528 }
7529
showMissingDataGap(bool on,bool update)7530 void Graph::showMissingDataGap(bool on, bool update)
7531 {
7532 if (d_missing_data_gap == on)
7533 return;
7534
7535 d_missing_data_gap = on;
7536
7537 if (update){
7538 replot();
7539 modifiedGraph();
7540 }
7541 }
7542