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