1
/***************************************************************************
4
--------------------------------------------------------------------
5
Copyright : (C) 2006-2007 by Ion Vasilief, Alex Kargovsky, Tilman Benkert
6
Email (use @ for *) : ion_vasilief*yahoo.fr, kargovsky*yumr.phys.msu.su, thzs*gmx.net
7
Description : Origin project import class
9
***************************************************************************/
11
/***************************************************************************
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. *
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. *
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 *
28
***************************************************************************/
29
#include "importOPJ.h"
33
#include <QMessageBox>
34
#include <QDockWidget>
39
#include "MultiLayer.h"
41
#include "QwtHistogram.h"
44
#define OBJECTXOFFSET 200
46
QString strreverse(const QString &str) //QString reversing
49
for(int i=str.length()-1; i>=0; --i)
56
ImportOPJ::ImportOPJ(ApplicationWindow *app, const QString& filename) :
60
OPJFile opj((const char *)filename.latin1());
61
parse_error = opj.Parse();
65
mw->showResults(opj.resultsLogString(),mw->logWindow->isVisible());
68
int ImportOPJ::translateOrigin2ScidavisLineStyle(int linestyle) {
76
case OPJFile::ShortDash:
80
case OPJFile::ShortDot:
83
case OPJFile::DashDot:
84
case OPJFile::ShortDashDot:
87
case OPJFile::DashDotDot:
94
bool ImportOPJ::importTables(OPJFile opj)
97
int SciDAVis_scaling_factor=10; //in Origin width is measured in characters while in SciDAVis - pixels --- need to be accurate
98
for (int s=0; s<opj.numSpreads(); s++)
100
int nr_cols = opj.numCols(s);
101
int maxrows = opj.maxRows(s);
103
Table *table = (opj.spreadHidden(s)||opj.spreadLoose(s))&&opj.Version()==7.5 ? mw->newHiddenTable(opj.spreadName(s), opj.spreadLabel(s), maxrows, nr_cols)
104
: mw->newTable(opj.spreadName(s), maxrows, nr_cols);
108
table->setWindowLabel(opj.spreadLabel(s));
109
for (int j=0; j<nr_cols; j++)
111
QString name(opj.colName(s,j));
112
table->setColName(j, name.replace(QRegExp(".*_"),""));
113
table->setCommand(j, QString(opj.colCommand(s,j)));
114
table->setColComment(j, QString(opj.colComment(s,j)));
115
table->changeColWidth(opj.colWidth(s,j)*SciDAVis_scaling_factor, j);
117
if (QString(opj.colType(s,j)) == "X")
118
table->setColPlotDesignation(j, SciDAVis::X);
119
else if (QString(opj.colType(s,j)) == "Y")
120
table->setColPlotDesignation(j, SciDAVis::Y);
121
else if (QString(opj.colType(s,j)) == "Z")
122
table->setColPlotDesignation(j, SciDAVis::Z);
123
else if (QString(opj.colType(s,j)) == "DX")
124
table->setColPlotDesignation(j, SciDAVis::xErr);
125
else if (QString(opj.colType(s,j)) == "DY")
126
table->setColPlotDesignation(j, SciDAVis::yErr);
128
table->setColPlotDesignation(j, SciDAVis::noDesignation);
130
table->setHeaderColType();//update header
132
double **d_cells = new double* [nr_cols];
133
for ( int i = 0; i < nr_cols; ++i)
134
d_cells[i] = new double [table->numRows()];
136
for (int i=0; i<opj.numRows(s,j); i++){
137
if(strcmp(opj.colType(s,j),"LABEL")&&opj.colValueType(s,j)!=1){// number
138
double* val = (double*)opj.oData(s,j,i,true);
139
if(fabs(*val)>0 && fabs(*val)<2.0e-300)// empty entry
142
table->setText(i, j, QLocale().toString(*val, 'g', 14));
143
d_cells[j][i] = *val;
145
else// label? doesn't seem to work
146
table->setText(i, j, QString((char*)opj.oData(s,j,i)));
148
table->saveToMemory(d_cells);
151
switch(opj.colValueType(s,j))
154
case 6: //Text&Numeric
156
if(opj.colNumDisplayType(s,j)==0)
159
switch(opj.colValueTypeSpec(s,j))
161
case 0: //Decimal 1000
167
case 2: //Engeneering
168
case 3: //Decimal 1,000
172
table->setColNumericFormat(f, opj.colDecPlaces(s,j), j);
175
table->setTextFormat(j);
178
switch(opj.colValueTypeSpec(s,j))
184
format="dd/MM/yyyy HH:mm";
187
format="dd/MM/yyyy HH:mm:ss";
230
table->setDateFormat(format, j);
233
switch(opj.colValueTypeSpec(s,j)+128)
245
format="hh:mm:ss.zzz";
266
format="hh:mm:ss.zzz";
269
table->setTimeFormat(format, j);
272
switch(opj.colValueTypeSpec(s,j)){
283
table->setMonthFormat(format, j);
286
switch(opj.colValueTypeSpec(s,j)){
297
table->setDayFormat(format, j);
302
/*for (int i=0; i<opj.numRows(s,j); i++)
304
if(strcmp(opj.colType(s,j),"LABEL")&&opj.colValueType(s,j)!=1)
306
double* val = (double*)opj.oData(s,j,i,true);
307
if(fabs(*val)>0 && fabs(*val)<2.0e-300)// empty entry
310
//if (table->columnType(j) == Table::Date)
311
//QMessageBox::about(0, "", QDate::fromJulianDay(int(*val)+1).toString("dd/MM/yyyy"));
313
table->setText(i, j, QLocale().toString(*val));
315
else// label? doesn't seem to work
316
table->setText(i, j, QString((char*)opj.oData(s,j,i)));
321
if(!(opj.spreadHidden(s)||opj.spreadLoose(s))||opj.Version()!=7.5)
326
int dx=table->verticalHeaderWidth();
327
int dy=table->parentWidget()->frameGeometry().height() - table->height();
328
table->parentWidget()->move(QPoint(visible_count*dx+xoffset*OBJECTXOFFSET,visible_count*dy));
334
for (int s=0; s<opj.numMatrices(); s++)
336
int nr_cols = opj.numMartixCols(s);
337
int nr_rows = opj.numMartixRows(s);
339
Matrix* matrix = mw->newMatrix(opj.matrixName(s), nr_rows, nr_cols);
343
matrix->setWindowLabel(opj.matrixLabel(s));
344
matrix->setFormula(opj.matrixFormula(s));
345
matrix->setColumnsWidth(opj.matrixWidth(s)*SciDAVis_scaling_factor);
348
matrix->table()->blockSignals(true);
350
for (int j=0; j<nr_cols; j++)
352
for (int i=0; i<nr_rows; i++)
354
double val = opj.matrixData(s,j,i);
355
if(fabs(val)>0 && fabs(val)<2.0e-300)// empty entry
358
matrix->setCell(i, j, val);
362
matrix->saveCellsToMemory();
365
switch(opj.matrixValueTypeSpec(s))
367
case 0: //Decimal 1000
373
case 2: //Engeneering
374
case 3: //Decimal 1,000
378
matrix->setNumericFormat(f, opj.matrixSignificantDigits(s));
381
matrix->table()->blockSignals(false);
383
matrix->showNormal();
385
//cascade the matrices
387
int dx=matrix->verticalHeaderWidth();
388
int dy=matrix->parentWidget()->frameGeometry().height() - matrix->height();
393
matrix->parentWidget()->move(QPoint(visible_count*dx+xoffset*OBJECTXOFFSET,visible_count*dy));
403
bool ImportOPJ::importNotes(OPJFile opj)
406
for (int n=0; n<opj.numNotes(); n++)
408
QString name=opj.noteName(n);
409
QRegExp rx("^@(\\S+)$");
410
if(rx.indexIn(name)==0)
412
name=name.mid(2,name.length()-3);
414
Note *note = mw->newNote(name);
417
note->setWindowLabel(opj.noteLabel(n));
418
note->setText(opj.noteText(n));
422
int dy=note->parentWidget()->frameGeometry().height() - note->height();
423
note->parentWidget()->move(QPoint(visible_count*dx+xoffset*OBJECTXOFFSET,visible_count*dy));
431
bool ImportOPJ::importGraphs(OPJFile opj)
433
double pi=3.141592653589793;
435
int tickTypeMap[]={0,3,1,2};
436
for (int g=0; g<opj.numGraphs(); g++)
438
MultiLayer *ml = mw->multilayerPlot(opj.graphName(g));
442
ml->hide();//!hack used in order to avoid resize and repaint events
443
ml->setWindowLabel(opj.graphLabel(g));
444
for(int l=0; l<opj.numLayers(g); l++)
446
Graph *graph=ml->addLayer();
450
graph->setXAxisTitle(parseOriginText(QString::fromLocal8Bit(opj.layerXAxisTitle(g,l))));
451
graph->setYAxisTitle(parseOriginText(QString::fromLocal8Bit(opj.layerYAxisTitle(g,l))));
452
if(strlen(opj.layerLegend(g,l))>0)
453
graph->newLegend(parseOriginText(QString::fromLocal8Bit(opj.layerLegend(g,l))));
457
for(int c=0; c<opj.numCurves(g,l); c++)
459
QString data(opj.curveDataName(g,l,c));
461
switch(opj.curveType(g,l,c))
466
case OPJFile::Scatter:
467
style=Graph::Scatter;
469
case OPJFile::LineSymbol:
470
style=Graph::LineSymbols;
472
case OPJFile::ErrorBar:
473
case OPJFile::XErrorBar:
474
style=Graph::ErrorBars;
476
case OPJFile::Column:
477
style=Graph::VerticalBars;
480
style=Graph::HorizontalBars;
482
case OPJFile::Histogram:
483
style=Graph::Histogram;
489
switch(data[0].toAscii())
492
tableName = data.right(data.length()-2);
493
if(style==Graph::ErrorBars)
495
int flags=opj.curveSymbolType(g,l,c);
496
graph->addErrorBars(tableName + "_" + opj.curveXColName(g,l,c), mw->table(tableName), tableName + "_" + opj.curveYColName(g,l,c),
497
((flags&0x10)==0x10?0:1), ceil(opj.curveLineWidth(g,l,c)), ceil(opj.curveSymbolSize(g,l,c)), QColor(Qt::black),
498
(flags&0x40)==0x40, (flags&2)==2, (flags&1)==1);
500
else if(style==Graph::Histogram)
501
graph->insertCurve(mw->table(tableName), tableName + "_" + opj.curveYColName(g,l,c), style);
503
graph->insertCurve(mw->table(tableName), tableName + "_" + opj.curveXColName(g,l,c), tableName + "_" + opj.curveYColName(g,l,c), style);
506
QStringList formulas;
507
QList<double> ranges;
508
int s=opj.functionIndex(data.right(data.length()-2).toStdString().c_str());
510
if(opj.functionType(s)==1)//Polar
513
formulas << opj.functionFormula(s) << "x";
514
ranges << pi/180*opj.functionBegin(s) << pi/180*opj.functionEnd(s);
519
formulas << opj.functionFormula(s);
520
ranges << opj.functionBegin(s) << opj.functionEnd(s);
522
graph->addFunctionCurve(mw, type, formulas, "x", ranges, opj.functionPoints(s), opj.functionName(s));
524
mw->updateFunctionLists(type, formulas);
528
CurveLayout cl = graph->initCurveLayout(style, opj.numCurves(g,l));
529
cl.sSize = ceil(opj.curveSymbolSize(g,l,c));
530
cl.penWidth=opj.curveSymbolThickness(g,l,c);
531
color=opj.curveSymbolColor(g,l,c);
532
if((style==Graph::Scatter||style==Graph::LineSymbols)&&color==0xF7)//0xF7 -Automatic color
535
switch(opj.curveSymbolType(g,l,c)&0xFF)
565
case 9: //Horizontal -
568
case 10: //Vertical |
588
switch(opj.curveSymbolType(g,l,c)>>8)
599
color=opj.curveSymbolFillColor(g,l,c);
600
if((style==Graph::Scatter||style==Graph::LineSymbols)&&color==0xF7)//0xF7 -Automatic color
601
color=17;// depend on Origin settings - not stored in file
608
cl.lWidth = ceil(opj.curveLineWidth(g,l,c));
609
color=opj.curveLineColor(g,l,c);
610
cl.lCol=(color==0xF7?0:color); //0xF7 -Automatic color
611
int linestyle=opj.curveLineStyle(g,l,c);
612
cl.filledArea=(opj.curveIsFilledArea(g,l,c)||style==Graph::VerticalBars||style==Graph::HorizontalBars||style==Graph::Histogram)?1:0;
615
switch(opj.curveFillPattern(g,l,c))
651
color=(cl.aStyle==0 ? opj.curveFillAreaColor(g,l,c) : opj.curveFillPatternColor(g,l,c));
652
cl.aCol=(color==0xF7?0:color); //0xF7 -Automatic color
653
if (style == Graph::VerticalBars || style == Graph::HorizontalBars || style == Graph::Histogram)
655
color=opj.curveFillPatternBorderColor(g,l,c);
656
cl.lCol = (color==0xF7?0:color); //0xF7 -Automatic color
657
color=(cl.aStyle==0 ? opj.curveFillAreaColor(g,l,c) : opj.curveFillPatternColor(g,l,c));
658
cl.aCol=(color==0xF7?cl.lCol:color); //0xF7 -Automatic color
659
cl.lWidth = ceil(opj.curveFillPatternBorderWidth(g,l,c));
660
linestyle=opj.curveFillPatternBorderStyle(g,l,c);
669
case OPJFile::ShortDash:
673
case OPJFile::ShortDot:
676
case OPJFile::DashDot:
677
case OPJFile::ShortDashDot:
680
case OPJFile::DashDotDot:
685
graph->updateCurveLayout(c, &cl);
686
if (style == Graph::VerticalBars || style == Graph::HorizontalBars)
688
QwtBarCurve *b = (QwtBarCurve*)graph->curve(c);
690
b->setGap(qRound(100-opj.curveSymbolSize(g,l,c)*10));
692
else if(style == Graph::Histogram)
694
QwtHistogram *h = (QwtHistogram*)graph->curve(c);
697
vector<double> bin=opj.layerHistogram(g,l);
699
h->setBinning(false, bin[0], bin[1], bin[2]);
703
switch(opj.curveLineConnect(g,l,c))
705
case OPJFile::NoLine:
706
graph->setCurveStyle(c, QwtPlotCurve::NoCurve);
708
case OPJFile::Straight:
709
graph->setCurveStyle(c, QwtPlotCurve::Lines);
711
case OPJFile::BSpline:
712
case OPJFile::Bezier:
713
case OPJFile::Spline:
714
graph->setCurveStyle(c, 5);
716
case OPJFile::StepHorizontal:
717
case OPJFile::StepHCenter:
718
graph->setCurveStyle(c, QwtPlotCurve::Steps);
720
case OPJFile::StepVertical:
721
case OPJFile::StepVCenter:
722
graph->setCurveStyle(c, 6);
727
vector<double> rangeX=opj.layerXRange(g,l);
728
vector<int> ticksX=opj.layerXTicks(g,l);
729
vector<double> rangeY=opj.layerYRange(g,l);
730
vector<int> ticksY=opj.layerYTicks(g,l);
731
if(style==Graph::HorizontalBars)
733
graph->setScale(0,rangeX[0],rangeX[1],rangeX[2],ticksX[0],ticksX[1],opj.layerXScale(g,l));
734
graph->setScale(2,rangeY[0],rangeY[1],rangeY[2],ticksY[0],ticksY[1],opj.layerYScale(g,l));
738
graph->setScale(2,rangeX[0],rangeX[1],rangeX[2],ticksX[0],ticksX[1],opj.layerXScale(g,l));
739
graph->setScale(0,rangeY[0],rangeY[1],rangeY[2],ticksY[0],ticksY[1],opj.layerYScale(g,l));
743
vector<graphGrid> grids=opj.layerGrid(g,l);
744
Grid *grid = graph->grid();
745
grid->enableX(grids[0].hidden?0:1);
746
grid->enableXMin(grids[1].hidden?0:1);
747
grid->enableY(grids[2].hidden?0:1);
748
grid->enableYMin(grids[3].hidden?0:1);
750
grid->setMajPenX(QPen(ColorBox::color(grids[0].color), ceil(grids[0].width),
751
Graph::getPenStyle(translateOrigin2ScidavisLineStyle(grids[0].style))));
752
grid->setMinPenX(QPen(ColorBox::color(grids[1].color), ceil(grids[1].width),
753
Graph::getPenStyle(translateOrigin2ScidavisLineStyle(grids[1].style))));
754
grid->setMajPenY(QPen(ColorBox::color(grids[2].color), ceil(grids[2].width),
755
Graph::getPenStyle(translateOrigin2ScidavisLineStyle(grids[2].style))));
756
grid->setMinPenY(QPen(ColorBox::color(grids[3].color), ceil(grids[3].width),
757
Graph::getPenStyle(translateOrigin2ScidavisLineStyle(grids[3].style))));
760
grid->enableZeroLineX(0);
761
grid->enableZeroLineY(0);
763
vector<graphAxisFormat> formats=opj.layerAxisFormat(g,l);
764
vector<graphAxisTick> ticks=opj.layerAxisTickLabels(g,l);
765
for(int i=0; i<4; ++i)
767
QString data(ticks[i].dataName.c_str());
768
QString tableName=data.right(data.length()-2) + "_" + ticks[i].colName.c_str();
773
int prec=ticks[i].decimal_places;
774
switch(ticks[i].value_type)
776
case OPJFile::Numeric:
778
switch(ticks[i].value_type_specification)
780
case 0: //Decimal 1000
786
case 2: //Engeneering
787
case 3: //Decimal 1,000
794
case OPJFile::Text: //Text
803
case OPJFile::Month: // Month
805
format=ticks[i].value_type_specification;
807
case OPJFile::Day: // Day
809
format=ticks[i].value_type_specification;
811
case OPJFile::ColumnHeading:
812
type=Graph::ColHeader;
813
switch(ticks[i].value_type_specification)
815
case 0: //Decimal 1000
821
case 2: //Engeneering
822
case 3: //Decimal 1,000
834
graph->showAxis(i, type, tableName, mw->table(tableName), !(formats[i].hidden),
835
tickTypeMap[formats[i].majorTicksType], tickTypeMap[formats[i].minorTicksType],
836
!(ticks[i].hidden), ColorBox::color(formats[i].color), format, prec,
837
ticks[i].rotation, 0, "", (ticks[i].color==0xF7 ? ColorBox::color(formats[i].color) : ColorBox::color(ticks[i].color)));
841
graph->setAutoscaleFonts(mw->autoScaleFonts);//restore user defined fonts behaviour
842
graph->setIgnoreResizeEvents(!mw->autoResizeLayers);
845
if(!opj.graphHidden(g))
848
int dy=ml->parentWidget()->frameGeometry().height() - ml->height();
849
ml->parentWidget()->move(QPoint(visible_count*dx+xoffset*OBJECTXOFFSET,visible_count*dy));
852
ml->arrangeLayers(true,true);
857
ml->arrangeLayers(true,true);
866
QString ImportOPJ::parseOriginText(const QString &str)
868
QStringList lines=str.split("\n");
870
for(int i=0; i<lines.size(); ++i)
874
text.append(parseOriginTags(lines[i]));
879
QString ImportOPJ::parseOriginTags(const QString &str)
882
//replace \l(...) and %(...) tags
883
QRegExp rxline("\\\\\\s*l\\s*\\(\\s*\\d+\\s*\\)");
884
QRegExp rxcol("\\%\\(\\d+\\)");
885
int pos = rxline.indexIn(line);
887
QString value = rxline.cap(0);
888
int len=value.length();
889
value.replace(QRegExp(" "),"");
890
value="\\c{"+value.mid(3,value.length()-4)+"}";
891
line.replace(pos, len, value);
892
pos = rxline.indexIn(line);
894
//Lookbehind conditions are not supported - so need to reverse string
895
QRegExp rx("\\)[^\\)\\(]*\\((?!\\s*[buig\\+\\-]\\s*\\\\)");
896
QRegExp rxfont("\\)[^\\)\\(]*\\((?![^\\:]*\\:f\\s*\\\\)");
897
QString linerev = strreverse(line);
898
QString lBracket=strreverse("&lbracket;");
899
QString rBracket=strreverse("&rbracket;");
900
QString ltagBracket=strreverse("<agbracket;");
901
QString rtagBracket=strreverse("&rtagbracket;");
902
int pos1=rx.indexIn(linerev);
903
int pos2=rxfont.indexIn(linerev);
905
while (pos1>-1 || pos2>-1) {
908
QString value = rx.cap(0);
909
int len=value.length();
910
value=rBracket+value.mid(1,len-2)+lBracket;
911
linerev.replace(pos1, len, value);
913
else if ((pos1>pos2&&pos2!=-1)||pos1==-1)
915
QString value = rxfont.cap(0);
916
int len=value.length();
917
value=rtagBracket+value.mid(1,len-2)+ltagBracket;
918
linerev.replace(pos2, len, value);
920
else if ((pos2>pos1&&pos1!=-1)||pos2==-1)
922
QString value = rx.cap(0);
923
int len=value.length();
924
value=rtagBracket+value.mid(1,len-2)+ltagBracket;
925
linerev.replace(pos1, len, value);
928
pos1=rx.indexIn(linerev);
929
pos2=rxfont.indexIn(linerev);
931
linerev.replace(ltagBracket, "(");
932
linerev.replace(rtagBracket, ")");
934
line = strreverse(linerev);
936
//replace \b(...), \i(...), \u(...), \g(...), \+(...), \-(...), \f:font(...) tags
942
"\\\\\\s*\\+\\s*\\(",
943
"\\\\\\s*\\-\\s*\\(",
944
"\\\\\\s*f\\:[^\\(]*\\("};
945
int postag[]={0,0,0,0,0,0,0};
946
QString ltag[]={"<b>","<i>","<u>","<font face=Symbol>","<sup>","<sub>","<font face=%1>"};
947
QString rtag[]={"</b>","</i>","</u>","</font>","</sup>","</sub>","</font>"};
949
for(int i=0; i<7; ++i)
950
rxtags[i].setPattern(rxstr[i]+"[^\\(\\)]*\\)");
954
for(int i=0; i<7; ++i)
956
postag[i] = rxtags[i].indexIn(line);
957
while (postag[i] > -1) {
958
QString value = rxtags[i].cap(0);
959
int len=value.length();
960
int pos2=value.indexOf("(");
962
value=ltag[i]+value.mid(pos2+1,len-pos2-2)+rtag[i];
965
int posfont=value.indexOf("f:");
966
value=ltag[i].arg(value.mid(posfont+2,pos2-posfont-2))+value.mid(pos2+1,len-pos2-2)+rtag[i];
968
line.replace(postag[i], len, value);
969
postag[i] = rxtags[i].indexIn(line);
973
for(int i=0; i<7; ++i)
975
if(rxtags[i].indexIn(line)>-1)
983
//replace unclosed tags
984
for(int i=0; i<6; ++i)
985
line.replace(QRegExp(rxstr[i]), ltag[i]);
986
rxfont.setPattern(rxstr[6]);
987
pos = rxfont.indexIn(line);
989
QString value = rxfont.cap(0);
990
int len=value.length();
991
int posfont=value.indexOf("f:");
992
value=ltag[6].arg(value.mid(posfont+2,len-posfont-3));
993
line.replace(pos, len, value);
994
pos = rxfont.indexIn(line);
997
line.replace("&lbracket;", "(");
998
line.replace("&rbracket;", ")");
1003
//TODO: bug in grid dialog
1004
// scale/minor ticks checkbox
1005
// histogram: autobin export
1006
// if prec not setted - automac+4digits