00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <qpainter.h>
00038 #include <qworkspace.h>
00039 #include <qlineedit.h>
00040 #include <qcheckbox.h>
00041 #include <qspinbox.h>
00042 #include <qvalidator.h>
00043 #include <qprinter.h>
00044 #include <qpaintdevicemetrics.h>
00045 #include <qpopupmenu.h>
00046
00047 #include "tolinechart.h"
00048
00049
00050
00051
00052 #include "tolinechartsetupui.h"
00053
00054
00055 #ifdef TO_HAS_KPRINT
00056 #include <kprinter.h>
00057 #endif
00058
00059
00060
00061
00062 #include "print.xpm"
00063
00064 static QColor ChartColors[]={
00065 Qt::red,
00066 Qt::green,
00067 Qt::blue,
00068 Qt::cyan,
00069 Qt::magenta,
00070 Qt::yellow,
00071 Qt::darkRed,
00072 Qt::darkGreen,
00073 Qt::darkBlue,
00074 Qt::darkCyan,
00075 Qt::darkMagenta,
00076 Qt::darkYellow
00077 };
00078
00079 QColor toChartColor(int index)
00080 {
00081 return ChartColors[index%(sizeof(ChartColors)/sizeof(QColor))];
00082 }
00083
00084
00085 double toLineChart::round(double round,bool up)
00086 {
00087 double base=1.0E-5;
00088 double mult=1;
00089 if (round<0) {
00090 mult=-1;
00091 round=-round;
00092 up=!up;
00093 }
00094 for(;;base*=10) {
00095 if (up) {
00096 if (base>=round)
00097 return mult*base;
00098 else if (base*2.5>=round)
00099 return mult*base*2.5;
00100 else if (base*5>=round)
00101 return mult*base*5;
00102 } else if (base>round) {
00103 if (base/2<=round)
00104 return mult*base/2;
00105 else if (base/4<=round)
00106 return mult*base/4;
00107 else if (base/10<=round)
00108 return mult*base/10;
00109 else
00110 return 0;
00111 }
00112 }
00113 }
00114
00115 void toLineChart::setSamples(int samples)
00116 {
00117 Samples=samples;
00118
00119 if (Samples>0) {
00120 while (int(XValues.size())>Samples)
00121 XValues.erase(XValues.begin());
00122
00123 for(std::list<std::list<double> >::iterator i=Values.begin();i!=Values.end();i++)
00124 while (int((*i).size())>Samples)
00125 (*i).erase((*i).begin());
00126 }
00127 update();
00128 }
00129
00130 toLineChart::toLineChart(QWidget *parent,const char *name,WFlags f)
00131 : QWidget(parent,name,f)
00132 {
00133 Menu=NULL;
00134 MinAuto=MaxAuto=true;
00135 MinValue=MaxValue=0;
00136 Legend=true;
00137 Last=false;
00138 Grid=5;
00139 AxisText=true;
00140 MousePoint[0]=MousePoint[1]=QPoint(-1,-1);
00141
00142 clearZoom();
00143
00144
00145 setSamples(1);
00146
00147 setMinimumSize(80,50);
00148
00149
00150
00151 QString str="";
00152 if (!str.isEmpty()) {
00153
00154 QFont font("Verdana");
00155 setFont(font);
00156 }
00157 }
00158
00159 void toLineChart::addValues(std::list<double> &value,const QString &xValue)
00160 {
00161 if (int(XValues.size())==Samples&&Samples>0)
00162 XValues.erase(XValues.begin());
00163 XValues.insert(XValues.end(),xValue);
00164
00165 if (Samples>0)
00166 for(std::list<std::list<double> >::iterator i=Values.begin();i!=Values.end();i++)
00167 if (int((*i).size())==Samples)
00168 (*i).erase((*i).begin());
00169
00170 std::list<double>::iterator j=value.begin();
00171 for(std::list<std::list<double> >::iterator i=Values.begin();i!=Values.end()&&j!=value.end();i++) {
00172 (*i).insert((*i).end(),*j);
00173 j++;
00174 }
00175 while(j!=value.end()) {
00176 std::list<double> t;
00177 t.insert(t.end(),*j);
00178 Values.insert(Values.end(),t);
00179 j++;
00180 }
00181 update();
00182 }
00183
00184 QRect toLineChart::fixRect(QPoint p1,QPoint p2)
00185 {
00186 if (p1.x()<Chart.x())
00187 p1.setX(Chart.x());
00188 if (p2.x()<Chart.x())
00189 p2.setX(Chart.x());
00190 if (p1.x()>Chart.x()+Chart.width())
00191 p1.setX(Chart.x()+Chart.width());
00192 if (p2.x()>Chart.x()+Chart.width())
00193 p2.setX(Chart.x()+Chart.width());
00194
00195 if (p1.y()<Chart.y())
00196 p1.setY(Chart.y());
00197 if (p2.y()<Chart.y())
00198 p2.setY(Chart.y());
00199 if (p1.y()>Chart.y()+Chart.height())
00200 p1.setY(Chart.y()+Chart.height());
00201 if (p2.y()>Chart.y()+Chart.height())
00202 p2.setY(Chart.y()+Chart.height());
00203
00204 return QRect(min(p1.x(),p2.x()),
00205 min(p1.y(),p2.y()),
00206 abs(p1.x()-p2.x()),
00207 abs(p1.y()-p2.y()));
00208 }
00209
00210 #define FONT_ALIGN AlignLeft|AlignTop|ExpandTabs
00211
00212 void toLineChart::paintTitle(QPainter *p,QRect &rect)
00213 {
00214 if (!Title.isEmpty()) {
00215 p->save();
00216 QFont f=p->font();
00217 f.setBold(true);
00218 p->setFont(f);
00219 QFontMetrics fm=p->fontMetrics();
00220 QRect bounds=fm.boundingRect(0,0,rect.width(),rect.width(),FONT_ALIGN,Title);
00221 p->drawText(0,2,rect.width(),bounds.height(),AlignHCenter|AlignTop|ExpandTabs,Title);
00222 p->restore();
00223 p->translate(0,bounds.height()+2);
00224 rect.setTop(rect.top()+bounds.height()+2);
00225 }
00226 if (Last) {
00227 QString str;
00228 for(std::list<std::list<double> >::iterator i=Values.begin();i!=Values.end();i++) {
00229 if ((*i).begin()!=(*i).end()) {
00230 if (!str.isEmpty())
00231 str+="\n";
00232 str+=QString::number(*(*i).rbegin());
00233 str+=YPostfix;
00234 }
00235 }
00236 if (!str.isEmpty()) {
00237 QFontMetrics fm=p->fontMetrics();
00238 QRect bounds=fm.boundingRect(0,0,rect.width(),rect.height(),FONT_ALIGN,str);
00239 p->drawText(0,2,rect.width(),bounds.height(),AlignHCenter|AlignTop|ExpandTabs,str);
00240 p->translate(0,bounds.height());
00241 rect.setTop(rect.top()+bounds.height());
00242 }
00243 }
00244 }
00245
00246 void toLineChart::paintLegend(QPainter *p,QRect &rect)
00247 {
00248 QFontMetrics fm=p->fontMetrics();
00249 if (Legend) {
00250 int lwidth=0;
00251 int lheight=0;
00252 {
00253 for(std::list<QString>::iterator i=Labels.begin();i!=Labels.end();i++) {
00254 if (!(*i).isEmpty()&&*i!=" ") {
00255 QRect bounds=fm.boundingRect(0,0,10000,10000,FONT_ALIGN,*i);
00256 if (lwidth<bounds.width())
00257 lwidth=bounds.width();
00258 lheight+=bounds.height();
00259 }
00260 }
00261 }
00262 if (lheight>0) {
00263 lheight+=4;
00264 lwidth+=14;
00265 }
00266 int lx=rect.width()-lwidth-2;
00267 int ly=2;
00268 if (lx<50)
00269 lx=50;
00270 p->save();
00271 p->setBrush(white);
00272 p->drawRect(lx,ly,lwidth,lheight);
00273 p->restore();
00274 rect.setRight(lx-2);
00275 lx+=12;
00276 ly+=2;
00277 int cp=0;
00278 for(std::list<QString>::iterator i=Labels.begin();i!=Labels.end();i++) {
00279 QRect bounds=fm.boundingRect(lx,ly,100000,100000,FONT_ALIGN,*i);
00280 if (!(*i).isEmpty()&&*i!=" ") {
00281 p->drawText(bounds,FONT_ALIGN,*i);
00282 p->save();
00283 p->setBrush(toChartColor(cp));
00284 p->drawRect(lx-10,ly+bounds.height()/2-fm.ascent()/2,8,fm.ascent());
00285 p->restore();
00286 ly+=bounds.height();
00287 }
00288 cp++;
00289 }
00290 }
00291 }
00292
00293 void toLineChart::paintAxis(QPainter *p,QRect &rect)
00294 {
00295 QFontMetrics fm=p->fontMetrics();
00296
00297 bool leftAxis=true;
00298 if ((zMaxValue==0||zMaxValue==round(0,true))&&zMinValue==0)
00299 leftAxis=false;
00300
00301 if (AxisText) {
00302 int yoffset=0;
00303 QString minstr;
00304 QString maxstr;
00305 QRect ybounds;
00306 if (leftAxis) {
00307 minstr=QString::number(zMinValue);
00308 maxstr=QString::number(zMaxValue);
00309 #if 0
00310 minstr+=YPostfix;
00311 #endif
00312 maxstr+=YPostfix;
00313 QRect bounds=fm.boundingRect(0,0,100000,100000,FONT_ALIGN,minstr);
00314 yoffset=bounds.height();
00315 ybounds=fm.boundingRect(0,0,100000,100000,FONT_ALIGN,maxstr);
00316 if (yoffset<ybounds.height())
00317 yoffset=ybounds.height();
00318 }
00319
00320 QString maxXstr;
00321 QString minXstr;
00322 int xoffset=0;
00323 if (XValues.size()>1) {
00324 minXstr=*(XValues.begin());
00325 maxXstr=*(XValues.rbegin());
00326
00327 if (Zooming) {
00328 int count=0;
00329 for(std::list<QString>::reverse_iterator i=XValues.rbegin();i!=XValues.rend();i++) {
00330 if (count==SkipSamples)
00331 maxXstr=*i;
00332 else if (count==SkipSamples+UseSamples-1) {
00333 minXstr=*i;
00334 break;
00335 }
00336 count++;
00337 }
00338 }
00339
00340 QRect bounds=fm.boundingRect(0,0,100000,100000,FONT_ALIGN,minXstr);
00341 xoffset=bounds.height();
00342 bounds=fm.boundingRect(0,0,100000,100000,FONT_ALIGN,maxXstr);
00343 if (xoffset<bounds.height())
00344 xoffset=bounds.height();
00345
00346 if (zMinValue!=0||zMaxValue!=0) {
00347 p->save();
00348 p->rotate(-90);
00349 #if 0
00350 p->drawText(xoffset-bottom+2,0,bottom-4-xoffset,yoffset,
00351 AlignLeft|AlignBottom|ExpandTabs,minstr);
00352 p->drawText(xoffset-bottom+2,0,bottom-4-xoffset,yoffset,
00353 AlignRight|AlignBottom|ExpandTabs,maxstr);
00354 #else
00355
00356 p->drawText(xoffset-rect.height()+2,fm.ascent()+1,minstr);
00357 p->drawText(-2-ybounds.width(),fm.ascent()+1,maxstr);
00358 #endif
00359 p->restore();
00360 } else
00361 yoffset=0;
00362 p->drawText(yoffset+2,rect.height()-xoffset-2,rect.width()-4-yoffset,xoffset,
00363 AlignLeft|AlignTop|ExpandTabs,minXstr);
00364 p->drawText(yoffset+2,rect.height()-xoffset-2,rect.width()-4-yoffset,xoffset,
00365 AlignRight|AlignTop|ExpandTabs,maxXstr);
00366 p->translate(yoffset,0);
00367 rect.setLeft(yoffset);
00368 rect.setBottom(rect.bottom()-xoffset);
00369 }
00370 }
00371
00372 p->save();
00373 p->setBrush(white);
00374 Chart=QRect(rect.left()+2,rect.top()+2,rect.width()-3,rect.height()-3);
00375 p->drawRect(2,2,rect.width()-3,rect.height()-3);
00376 p->restore();
00377 if (Grid>1) {
00378 p->save();
00379 p->setPen(gray);
00380 for (int i=1;i<Grid;i++) {
00381 int ypos=(rect.height()-4)*i/Grid+2;
00382 int xpos=(rect.width()-4)*i/Grid+2;
00383 p->drawLine(3,ypos,rect.width()-3,ypos);
00384 p->drawLine(xpos,3,xpos,rect.height()-3);
00385 }
00386 p->restore();
00387 }
00388 }
00389
00390 void toLineChart::paintChart(QPainter *p,QRect &rect)
00391 {
00392 if (!Zooming) {
00393 if (MinAuto||MaxAuto) {
00394 bool first=true;
00395 for(std::list<std::list<double> >::iterator i=Values.begin();i!=Values.end();i++) {
00396 for(std::list<double>::iterator j=(*i).begin();j!=(*i).end();j++) {
00397 if (first) {
00398 zMinValue=*j;
00399 zMaxValue=*j;
00400 first=false;
00401 } else if (zMaxValue<*j)
00402 zMaxValue=*j;
00403 else if (zMinValue>*j)
00404 zMinValue=*j;
00405 }
00406 }
00407 zMaxValue=round(zMaxValue,true);
00408 zMinValue=round(zMinValue,false);
00409 }
00410 if(!MinAuto)
00411 zMinValue=MinValue;
00412 else
00413 zMinValue=round(zMinValue,false);
00414 if(!MaxAuto)
00415 zMaxValue=MaxValue;
00416 else
00417 zMaxValue=round(zMaxValue,true);
00418 }
00419
00420 paintTitle(p,rect);
00421 paintLegend(p,rect);
00422 paintAxis(p,rect);
00423
00424 int cp=0;
00425 int samples=countSamples();
00426 if (samples>1) {
00427 const QWMatrix &mtx=p->worldMatrix();
00428 p->setClipRect(int(mtx.dx()+2),int(mtx.dy()+2),rect.width()-3,rect.height()-3);
00429 if (Zooming)
00430 p->drawText(2,2,rect.width()-4,rect.height()-4,
00431 AlignLeft|AlignTop,"Zoom");
00432 for(std::list<std::list<double> >::iterator i=Values.begin();i!=Values.end();i++) {
00433 p->save();
00434 p->setPen(toChartColor(cp++));
00435 std::list<double> &val=*i;
00436 int count=0;
00437 bool first=true;
00438 int lval=0;
00439 int lx=rect.width()-2;
00440 int skip=SkipSamples;
00441 for(std::list<double>::reverse_iterator j=val.rbegin();j!=val.rend()&&lx>=2;j++) {
00442 if (skip>0)
00443 skip--;
00444 else {
00445 int val=int(rect.height()-2-((*j-zMinValue)/(zMaxValue-zMinValue)*(rect.height()-4)));
00446 if (!first) {
00447 int x=lx;
00448 x=rect.width()-2-(count+1)*(rect.width()-4)/samples;
00449 p->drawLine(x,val,lx,lval);
00450 lx=x;
00451 } else
00452 first=false;
00453 lval=val;
00454 count++;
00455 if (count>=samples)
00456 break;
00457 }
00458 }
00459 p->restore();
00460 }
00461 }
00462 }
00463
00464 void toLineChart::paintEvent(QPaintEvent *e)
00465 {
00466 QPainter p(this);
00467 p.setFont(font());
00468 QRect rect(0,0,width(),height());
00469 paintChart(&p,rect);
00470 MousePoint[1]=QPoint(-1,-1);
00471 }
00472
00473 void toLineChart::mouseReleaseEvent(QMouseEvent *e)
00474 {
00475 if (e->button()==LeftButton&&MousePoint[0]!=QPoint(-1,-1)) {
00476 if (MousePoint[1]!=QPoint(-1,-1)) {
00477 QRect rect=fixRect(MousePoint[0],MousePoint[1]);
00478 QPainter p(this);
00479 p.setRasterOp(NotROP);
00480 p.drawRect(rect);
00481 }
00482 if (MousePoint[0].x()!=e->x()&&
00483 MousePoint[0].y()!=e->y()) {
00484 QRect rect=fixRect(MousePoint[0],e->pos());
00485 int samples=countSamples();
00486 UseSamples=samples*rect.width()/Chart.width()+1;
00487 if (UseSamples<2)
00488 UseSamples=2;
00489 SkipSamples+=samples*(Chart.width()+Chart.x()-rect.x()-rect.width())/Chart.width();
00490 Zooming=true;
00491
00492 double t=(zMaxValue-zMinValue)*(Chart.y()+Chart.height()-rect.y()-rect.height())/Chart.height()+zMinValue;
00493 zMaxValue=(zMaxValue-zMinValue)*(Chart.y()+Chart.height()-rect.y())/Chart.height()+zMinValue;
00494 zMinValue=t;
00495 update();
00496 }
00497 MousePoint[1]=MousePoint[0]=QPoint(-1,-1);
00498 } else if (e->button()==RightButton) {
00499 if (Chart.contains(e->pos())) {
00500 clearZoom();
00501 update();
00502 }
00503 }
00504 }
00505
00506 int toLineChart::countSamples(void)
00507 {
00508 int samples=Samples;
00509 if (Samples<=0)
00510 for(std::list<std::list<double> >::reverse_iterator i=Values.rbegin();i!=Values.rend();i++)
00511 samples=max(samples,int((*i).size()));
00512 if (UseSamples>1&&UseSamples<samples)
00513 samples=UseSamples;
00514 return samples;
00515 }
00516
00517 void toLineChart::mousePressEvent(QMouseEvent *e)
00518 {
00519 if (e->button()==LeftButton)
00520 MousePoint[0]=e->pos();
00521 else if (e->button()==RightButton) {
00522 if (!Chart.contains(e->pos())||!Zooming) {
00523 if (!Menu) {
00524 Menu=new QPopupMenu(this);
00525 Menu->insertItem(QPixmap((const char *)print_xpm),"&Print",this,SLOT(editPrint()));
00526 Menu->insertItem("&Open in new window",this,SLOT(openCopy()));
00527 Menu->insertSeparator();
00528 Menu->insertItem("&Properties",this,SLOT(setup()));
00529 }
00530 Menu->popup(e->globalPos());
00531 }
00532 }
00533 }
00534
00535 void toLineChart::setup(void)
00536 {
00537 toLineChartSetupUI setup(this,NULL,true);
00538 setup.MinValue->setText(QString::number(MinValue));
00539 setup.MaxValue->setText(QString::number(MaxValue));
00540 setup.AutoMax->setChecked(MaxAuto);
00541 setup.AutoMin->setChecked(MinAuto);
00542 setup.ShowAxis->setChecked(AxisText);
00543 setup.ShowLast->setChecked(Last);
00544 setup.ShowLegend->setChecked(Legend);
00545 setup.Grids->setValue(Grid);
00546
00547 setup.MaxValue->setValidator(new QDoubleValidator(setup.MaxValue));
00548 setup.MinValue->setValidator(new QDoubleValidator(setup.MinValue));
00549
00550 if (setup.exec()) {
00551 MinValue=setup.MinValue->text().toDouble();
00552 MaxValue=setup.MaxValue->text().toDouble();
00553 MaxAuto=setup.AutoMax->isChecked();
00554 MinAuto=setup.AutoMin->isChecked();
00555 AxisText=setup.ShowAxis->isChecked();
00556 Last=setup.ShowLast->isChecked();
00557 Legend=setup.ShowLegend->isChecked();
00558
00559 Grid=setup.Grids->value();
00560 update();
00561 }
00562 }
00563
00564 void toLineChart::editPrint(void)
00565
00566 {
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 }
00579
00580 void toLineChart::clearZoom(void)
00581 {
00582 Zooming=false;
00583 SkipSamples=0;
00584 UseSamples=-1;
00585 zMinValue=-1;
00586 zMaxValue=-1;
00587 }
00588
00589 void toLineChart::mouseMoveEvent(QMouseEvent *e)
00590 {
00591 if (MousePoint[0]!=QPoint(-1,-1)) {
00592 QPainter p(this);
00593 p.setRasterOp(NotROP);
00594 if (MousePoint[1]!=QPoint(-1,-1))
00595 p.drawRect(fixRect(MousePoint[0],MousePoint[1]));
00596 MousePoint[1]=e->pos();
00597 p.drawRect(fixRect(MousePoint[0],MousePoint[1]));
00598 }
00599 }
00600
00601
00602 void toLineChart::mouseDoubleClickEvent(QMouseEvent *e)
00603 {
00604 if (e->button()==LeftButton)
00605 openCopy();
00606 }
00607
00608 void toLineChart::openCopy(void)
00609 {
00610 QWidget *newWin=new toLineChart(this,0,NULL,WDestructiveClose);
00611 newWin->show();
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633 }
00634
00635 toLineChart::toLineChart (toLineChart *chart,QWidget *parent,const char *name,WFlags f)
00636 : QWidget(parent,name,f)
00637 {
00638 Menu=NULL;
00639 Values=chart->Values;
00640 XValues=chart->XValues;
00641 Labels=chart->Labels;
00642 Legend=chart->Legend;
00643 Last=false;
00644 Grid=5;
00645 AxisText=true;
00646 MinValue=chart->MinValue;
00647 MinAuto=chart->MinAuto;
00648 MaxValue=chart->MaxValue;
00649 MaxAuto=chart->MaxAuto;
00650 Samples=chart->Samples;
00651 Title=chart->Title;
00652 YPostfix=chart->YPostfix;
00653
00654 setCaption(Title);
00655
00656 clearZoom();
00657
00658 setMinimumSize(80,50);
00659
00660
00661
00662 QString str="mola";
00663 if (!str.isEmpty()) {
00664 QFont font("Verdana");
00665 setFont(font);
00666 }
00667 }
00668
00669