Warning, file /office/calligra/filters/sheets/applixspread/applixspreadimport.cc was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2001 Enno Bartels <ebartels@nwn.de>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "applixspreadimport.h"
0008 
0009 #include <QFile>
0010 #include <QMessageBox>
0011 #include <QDebug>
0012 #include <math.h>
0013 #include <KoFilterChain.h>
0014 #include <kpluginfactory.h>
0015 #include <sheets/engine/Util.h>
0016 
0017 K_PLUGIN_FACTORY_WITH_JSON(APPLIXSPREADImportFactory, "calligra_filter_applixspread2kspread.json",
0018                            registerPlugin<APPLIXSPREADImport>();)
0019 
0020 
0021 APPLIXSPREADImport::APPLIXSPREADImport(QObject *parent, const QVariantList&)
0022         : KoFilter(parent)
0023 {
0024 }
0025 
0026 QString APPLIXSPREADImport::nextLine(QTextStream & stream)
0027 {
0028     if (!m_nextPendingLine.isNull()) {
0029         const QString s = m_nextPendingLine;
0030         m_nextPendingLine.clear();
0031         return s;
0032     }
0033 
0034     QString s = stream.readLine();
0035     m_instep += s.length();
0036     if (m_instep > m_stepsize) {
0037         m_instep = 0;
0038         m_progress += 2;
0039         emit sigProgress(m_progress);
0040     }
0041     return s;
0042 }
0043 
0044 struct t_mycolor {
0045     int r;
0046     int g;
0047     int b;
0048 
0049     int c;
0050     int m;
0051     int y;
0052     int k;
0053 };
0054 
0055 struct t_rc {
0056     QStringList tabname;
0057     QStringList rc;
0058 };
0059 
0060 // Store shared formula definitions
0061 struct t_sharedFormula {
0062     int origRow;
0063     int origColumn;
0064     QString formula;
0065 };
0066 
0067 KoFilter::ConversionStatus APPLIXSPREADImport::convert(const QByteArray& from, const QByteArray& to)
0068 {
0069 
0070     if (to != "application/x-kspread" || from != "application/x-applix-spreadsheet")
0071         return KoFilter::NotImplemented;
0072 
0073     QFile in(m_chain->inputFile());
0074     if (!in.open(QIODevice::ReadOnly)) {
0075         qWarning() << "Unable to open input file!";
0076         in.close();
0077         return KoFilter::FileNotFound;
0078     }
0079 
0080     QString str;
0081     QList<t_mycolor*> mcol;
0082 
0083     str += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
0084            "<!DOCTYPE spreadsheet>\n"
0085            "<spreadsheet mime=\"application/x-kspread\" editor=\"KSpread\" >\n"
0086            " <paper format=\"A4\" orientation=\"Portrait\" >\n"
0087            "  <borders right=\"20\" left=\"20\" bottom=\"20\" top=\"20\" />\n"
0088            "  <head/>\n"
0089            "  <foot/>\n"
0090            " </paper>\n"
0091 //    str += " <locale positivePrefixCurrencySymbol=\"True\" negativeMonetarySignPosition=\"1\" negativePrefixCurrencySymbol=\"True\" fracDigits=\"2\" thousandsSeparator=\" \" dateFormat=\"%A, %e. %B %Y\" timeFormat=\"%H:%M:%S\" monetaryDecimalSymbol=\",\" weekStartsMonday=\"True\" currencySymbol=\"DM\" negativeSign=\"-\" positiveSign=\"\" positiveMonetarySignPosition=\"1\" decimalSymbol=\",\" monetaryThousandsSeparator=\" \" dateFormatShort=\"%d.%m.%Y\" />\n";
0092            " <map markerColumn=\"1\" activeTable=\"Table1\" markerRow=\"1\" >\n";
0093 //      str += "  <table columnnumber=\"0\" borders=\"0\" hide=\"0\" hidezero=\"0\" firstletterupper=\"0\" grid=\"1\" formular=\"0\" lcmode=\"0\" name=\"Tabelle1\" >\n";
0094 
0095 
0096     // QTextStream
0097     QTextStream stream(&in);
0098     m_stepsize = in.size() / 50;
0099     m_instep   = 0;
0100     m_progress = 0;
0101     int  pos;
0102     QString  tabctr ;  // Tab control (current tab name)
0103     QStringList typefacetab;
0104     QHash<QString, t_sharedFormula> sharedFormulas;
0105 
0106     t_rc my_rc;
0107 
0108 
0109 
0110     /**************************************************************************
0111      * Read header                                                            *
0112      **************************************************************************/
0113     if (! readHeader(stream)) return KoFilter::StupidError;
0114 
0115     while (!stream.atEnd()) {
0116         // Read one line
0117         QString mystr = nextLine(stream);
0118 
0119         qDebug() << "INPUT :" << mystr;
0120 
0121 
0122         /**********************************************************************
0123          *  Looking for the colormap                                          *
0124          **********************************************************************/
0125         if (mystr.startsWith("COLORMAP")) {
0126             readColormap(stream, mcol);
0127         }
0128 
0129         /**********************************************************************
0130          *  Looking for the typeface table                                    *
0131          **********************************************************************/
0132         else if (mystr.startsWith("TYPEFACE TABLE")) {
0133             readTypefaceTable(stream, typefacetab);
0134         }
0135 
0136         /**********************************************************************
0137          *  Looking for some View-Information                                 *
0138          **********************************************************************/
0139         else if (mystr.startsWith("View Start, Name:")) {
0140             readView(stream, mystr, my_rc);
0141         }
0142 
0143 
0144         /**********************************************************************
0145          *   Detect ( at the first place of the Line                          *
0146          **********************************************************************/
0147         else if (mystr[0] == '(') {
0148 
0149             // Delete  '('
0150             mystr.remove(0, 1);
0151 
0152             // Remember length of the string
0153             if (mystr.length() >= 80 - 1) {
0154                 //qDebug() << " Line >= 80 chars";
0155                 bool ok = true;
0156                 do {
0157                     QString mystrn = nextLine(stream);
0158                     if (mystrn[0] == ' ') {
0159                         mystrn.remove(0, 1);
0160                         mystr += mystrn;
0161                     } else {
0162                         m_nextPendingLine = mystrn;
0163                         ok = false;
0164                     }
0165                 } while (ok);
0166                 qDebug() << " Long line -> new input line:" << mystr;
0167             }
0168 
0169             // Search for ')'
0170             pos = mystr.indexOf(')');
0171             QString typestr = mystr.left(pos);
0172 
0173             // Delete typeformat info incl. Space
0174             mystr.remove(0, pos + 1);
0175 
0176             // At this point mystr looks like " A!E15: 10"
0177             Q_ASSERT(mystr.startsWith(' '));
0178 
0179             // Extract table number/name
0180             pos = mystr.indexOf('!');
0181 
0182             // Copy tabnumber information
0183             QString tabnostr = mystr.left(pos).mid(1);
0184 
0185             // Delete tabnumber information
0186             mystr.remove(0, pos + 1);
0187 
0188             // At this point mystr looks like "E15: 10"
0189             pos = 0;
0190             while (mystr[pos].isLetter()) {
0191                 ++pos;
0192             }
0193             const QString cellcolstr = mystr.mid(0, pos);
0194             // Transform ascii column to int column
0195             const int icol = translateColumnNumber(cellcolstr);
0196 
0197             int endPos = pos;
0198             while (mystr[endPos].isDigit()) {
0199                 ++endPos;
0200             }
0201 
0202             const QString rowstr = mystr.mid(pos, endPos - pos);
0203             bool ok;
0204             const int irow = rowstr.toInt(&ok);
0205             Q_ASSERT(ok);
0206 
0207             // OK, what do we have now?
0208             const QChar contentType = mystr.at(endPos);
0209 
0210             // Delete cellnumber information
0211             mystr.remove(0, endPos + 1);
0212             if (mystr.startsWith(' ')) {
0213                 mystr.remove(0, 1);
0214             }
0215 
0216             // ';' // first instance (definition) of a shared formula
0217             // '.' // instance (usage) of a shared formula
0218             // ':' // simple value
0219 
0220             if (contentType == ';' || contentType == '.') {
0221                 // Skip the value
0222                 int pos = 0;
0223                 while (!mystr.at(pos).isSpace()) {
0224                     ++pos;
0225                 }
0226                 while (mystr.at(pos).isSpace()) {
0227                     ++pos;
0228                 }
0229                 qDebug() << "Skipping value" << mystr.mid(0, pos);
0230                 mystr.remove(0, pos);
0231 
0232                 if (contentType == ';') {
0233                     if (mystr.at(0) == '+')
0234                         mystr[0] = '=';
0235                     Q_ASSERT(mystr.at(0) == '=');
0236                 }
0237             }
0238 
0239             // Replace part for this characters: <, >, &
0240             mystr.replace(QRegExp("&"), "&amp;");
0241             mystr.replace(QRegExp("<"), "&lt;");
0242             mystr.replace(QRegExp(">"), "&gt;");
0243 
0244 
0245             // Replace part for Applix Characters
0246             bool foundSpecialCharakter;
0247 
0248             do {
0249                 // initialize
0250                 foundSpecialCharakter = false;
0251 
0252                 pos = mystr.indexOf('^');
0253 
0254                 // is there a special character ?
0255                 if (pos > -1) {
0256                     // i have found a special character !
0257                     foundSpecialCharakter = true;
0258 
0259                     // translate the applix special character
0260                     const QChar newchar = specCharfind(mystr[pos+1], mystr[pos+2]);
0261 
0262                     // replace the character
0263                     mystr.replace(pos, 3, newchar);
0264                 }
0265 
0266             } while (foundSpecialCharakter == true);
0267 
0268 
0269             // examine the typestring
0270             // split typestring in 3 parts by an |
0271 
0272             const int pos1 = typestr.indexOf('|');
0273             const int pos2 = typestr.lastIndexOf('|');
0274             const QString typeFormStr = typestr.left(pos1);
0275             const QString typeCharStr = typestr.mid(pos1 + 1,  pos2 - pos1 - 1);
0276             const QString typeCellStr = typestr.right(typestr.length() - pos2 - 1);
0277 
0278             // Is it a new table
0279             if (tabctr != tabnostr) {
0280                 // is it not the first table
0281                 if (!(tabctr.isNull()))  str += "  </table>\n";
0282 
0283                 str += "  <table columnnumber=\"0\" borders=\"0\" hide=\"0\" hidezero=\"0\" firstletterupper=\"0\" grid=\"1\" formular=\"0\" lcmode=\"0\" name=\"" +
0284                        tabnostr +
0285                        "\" >\n";
0286 
0287                 tabctr = tabnostr;
0288 
0289                 // Searching for the rowcol part and adding to the hole string
0290                 pos = my_rc.tabname.indexOf(tabnostr);
0291                 if (pos > -1) str += my_rc.rc[pos];
0292             }
0293 
0294             //qDebug()<<" Data : Text :"<<mystr<<" tab :"<<tabnostr<<""<< cellnostr <<"" <<ccol<<"" << irow<<""<< typeFormStr<<"" <<typeCharStr<<"" <<typeCellStr;
0295 
0296             /********************************************************************
0297              * Support for shared formulas                                      *
0298              ********************************************************************/
0299 
0300             if (contentType == ';') {
0301 
0302                 mystr = convertFormula(mystr);
0303 
0304                 const QString formulaRefLine = nextLine(stream); // "Formula: 358"
0305                 qDebug() << "shared formula: next line is" << formulaRefLine;
0306                 if (!formulaRefLine.startsWith("Formula: ")) {
0307                     qWarning() << "Missing formula ID after" << mystr;
0308                 } else {
0309                     const QString key = formulaRefLine.mid(9);
0310                     t_sharedFormula sf;
0311                     sf.origColumn = icol;
0312                     sf.origRow = irow;
0313                     sf.formula = mystr;
0314                     sharedFormulas.insert(key, sf);
0315                 }
0316             } else if (contentType == '.') {
0317                 const QString key = mystr;
0318                 const t_sharedFormula sf = sharedFormulas.value(key);
0319 
0320                 // adjust the formula: if it came from C1, with =A1+B1,
0321                 // and we're now in C3, then it needs to become =A3+B3, just like copy/paste would do.
0322                 mystr = Calligra::Sheets::Util::adjustFormulaReference(sf.formula, sf.origRow, sf.origColumn, irow, icol);
0323             }
0324 
0325             /********************************************************************
0326              * examine character format String, split it up in basic parts      *
0327              ********************************************************************/
0328             int bold = 0, italic = 0, underline = 0, fontsize = 12, fontnr = -1;
0329             int fg = -1; // fg = foregound
0330 
0331             const QStringList typeCharList = typeCharStr.split(',', QString::SkipEmptyParts);
0332             Q_FOREACH(const QString& typeChar, typeCharList) {
0333                 // Output
0334                 qDebug() << "typeChar: " << typeChar;
0335 
0336                 if (typeChar == "B") {
0337                     qDebug() << " bold";
0338                     bold  = 1;
0339                 } else if (typeChar == "I") {
0340                     qDebug() << "   = italic";
0341                     italic = 1;
0342                 } else if (typeChar == "U") {
0343                     qDebug() << "   = underline";
0344                     underline = 1;
0345                 } else if (typeChar.startsWith("FG")) {
0346                     fg = typeChar.midRef(2).toInt();
0347                     qDebug() << "  = Colornr" << fg;
0348                 } else if (typeChar.startsWith("TF")) {
0349                     fontnr = typeChar.midRef(2).toInt();
0350                     qDebug() << " = Font :" << fontnr << "" << typefacetab[fontnr];
0351                 } else if (typeChar.startsWith('P')) {
0352                     fontsize = typeChar.midRef(1).toInt();
0353                     qDebug() << "   = Fontsize" << fontsize;
0354                 } else {
0355                     qDebug() << "   = ??? Unknown typeChar:" << typeChar;
0356                 }
0357             }
0358             qDebug();
0359 
0360 
0361             /********************************************************************
0362              * examine pos format String, split it up in basic parts           *
0363              ********************************************************************/
0364             int align = 0, valign = 0;
0365 
0366             const QStringList typeFormList = typeFormStr.split(',', QString::SkipEmptyParts);
0367             Q_FOREACH(const QString& typeFormat, typeFormList) {
0368                 // Grep horizontal alignment
0369                 if (typeFormat == "1") {
0370                     qDebug() << " = left align";
0371                     align = 1; // left
0372                 } else if (typeFormat == "2") {
0373                     qDebug() << " = right align";
0374                     align = 3; // right
0375                 } else if (typeFormat == "3") {
0376                     qDebug() << " = center align";
0377                     align = 2; // center
0378                 }
0379 
0380                 // Grep vertical alignment
0381                 else if (typeFormat == "VT") {
0382                     qDebug() << " = top valign";
0383                     valign =  1; // top
0384                 } else if (typeFormat == "VC") {
0385                     qDebug() << " = center valign";
0386                     valign =  0; // center - default (2)
0387                 } else if (typeFormat == "VB") {
0388                     qDebug() << " = bottom valign";
0389                     valign =  3; // bottom
0390                 } else {
0391                     qDebug() << "   = ??? unknown typeFormat" << typeFormat;
0392                 }
0393             }
0394 
0395 
0396             /********************************************************************
0397              * examine cell format String, split it up in basic parts           *
0398              ********************************************************************/
0399             int topPenWidth = 0, bottomPenWidth = 0, leftPenWidth = 0, rightPenWidth = 0, fg_bg = -1;
0400             int topPenStyle = 0, bottomPenStyle = 0, leftPenStyle = 0, rightPenStyle = 0;
0401             int brushstyle = 0,     brushcolor = 1;
0402             int topbrushstyle = 0,  topbrushcolor = 1, topfg_bg = 1;
0403             int leftbrushstyle = 0, leftbrushcolor = 1, leftfg_bg = 1;
0404             int rightbrushstyle = 0, rightbrushcolor = 1, rightfg_bg = 1;
0405             int bottombrushstyle = 0, bottombrushcolor = 1, bottomfg_bg = 1;
0406 
0407             const QStringList typeCellList = typeCellStr.split(',', QString::SkipEmptyParts);
0408             Q_FOREACH(/*can't use const QString&*/ QString typeCell, typeCellList) {
0409 
0410                 if (typeCell[0] == 'T') {
0411                     qDebug() << " = top";
0412                     transPenFormat(typeCell, &topPenWidth, &topPenStyle);
0413 
0414                     if (typeCell.length() > 2) {
0415                         typeCell.remove(0, 2);
0416                         filterSHFGBG(typeCell, &topbrushstyle, &topbrushcolor, &topfg_bg);
0417                     }
0418 
0419                 }
0420 
0421                 else if (typeCell[0] == 'B') {
0422                     qDebug() << " = bottom";
0423                     transPenFormat(typeCell, &bottomPenWidth, &bottomPenStyle);
0424 
0425                     if (typeCell.length() > 2) {
0426                         typeCell.remove(0, 2);
0427                         filterSHFGBG(typeCell, &bottombrushstyle, &bottombrushcolor, &bottomfg_bg);
0428                     }
0429                 }
0430 
0431                 else if (typeCell[0] == 'L') {
0432                     qDebug() << " = left";
0433                     transPenFormat(typeCell, &leftPenWidth, &leftPenStyle);
0434 
0435                     if (typeCell.length() > 2) {
0436                         typeCell.remove(0, 2);
0437                         filterSHFGBG(typeCell, &leftbrushstyle, &leftbrushcolor, &leftfg_bg);
0438                     }
0439                 }
0440 
0441                 else if (typeCell[0] == 'R') {
0442                     qDebug() << " = right";
0443                     transPenFormat(typeCell, &rightPenWidth, &rightPenStyle);
0444 
0445                     if (typeCell.length() > 2) {
0446                         typeCell.remove(0, 2);
0447                         filterSHFGBG(typeCell, &rightbrushstyle, &rightbrushcolor, &rightfg_bg);
0448                     }
0449                 }
0450 
0451                 else if ((typeCell.startsWith("SH")) || (typeCell.startsWith("FG")) ||
0452                          (typeCell.startsWith("BG"))) {
0453                     qDebug() << " =";
0454                     filterSHFGBG(typeCell, &brushstyle, &fg_bg, &brushcolor);
0455                 }
0456 
0457                 else {
0458                     qDebug() << "   = ??? unknown typeCell" << typeCell;
0459                 }
0460 
0461             }
0462 
0463 
0464 
0465 
0466 
0467             QString col;
0468 
0469             // create kspread fileformat output
0470             str += "   <cell row=\"" + QString::number(irow) + "\""
0471                    " column=\""      + QString::number(icol) + "\">\n";
0472             if (bold == 1  || italic == 1 || underline == 1 ||
0473                     align != 0 || valign != 0 ||
0474                     topPenStyle  != 0  || bottomPenStyle != 0 ||
0475                     leftPenStyle != 0  || rightPenStyle  != 0 || fg != -1 || fg_bg != -1 ||
0476                     fontsize != 12 || brushstyle != 0 || fontnr != -1) {
0477                 str += "    <format";
0478                 if (brushstyle != 0) {
0479                     str += " brushstyle=\""  + QString::number(brushstyle) + "\" "
0480                            " brushcolor=\"" +
0481                            writeColor(mcol.at(brushcolor)) +
0482                            "\"";
0483                 }
0484 
0485                 if (align   != 0)  str += " align=\""  + QString::number(align) + "\" ";
0486                 if (valign  != 0)  str += " alignY=\"" + QString::number(valign) + "\" ";
0487                 if (fg_bg != -1) {
0488                     str += " bgcolor=\"" +
0489                            writeColor(mcol.at(fg_bg)) +
0490                            "\" ";
0491                 }
0492                 str += ">\n";
0493 
0494                 // Font color
0495                 if (fg != -1) {
0496                     str += "    <pen width=\"0\" style=\"1\" color=\"" +
0497                            writeColor(mcol.at(fg)) +
0498                            "\" />\n";
0499                 }
0500 
0501                 // Left border
0502                 if (leftPenWidth > 0) {
0503                     str += "    <left-border>\n";
0504                     col = writeColor(mcol.at(leftfg_bg));
0505                     writePen(str, leftPenWidth, leftPenStyle, col);
0506                     str += "    </left-border>\n";
0507                 }
0508 
0509                 // Right border
0510                 if (rightPenWidth > 0) {
0511                     str += "    <right-border>\n";
0512                     col = writeColor(mcol.at(rightfg_bg));
0513                     writePen(str, rightPenWidth, rightPenStyle, col);
0514                     str += "    </right-border>\n";
0515                 }
0516 
0517                 // Bottom border
0518                 if (bottomPenWidth > 0) {
0519                     str += "    <bottom-border>\n";
0520                     col = writeColor(mcol.at(bottomfg_bg));
0521                     writePen(str, bottomPenWidth, bottomPenStyle, col);
0522                     str += "    </bottom-border>\n";
0523                 }
0524 
0525                 // Top border
0526                 if (topPenWidth > 0) {
0527                     str += "    <top-border>\n";
0528                     col = writeColor(mcol.at(topfg_bg));
0529                     writePen(str, topPenWidth, topPenStyle, col);
0530                     str += "    </top-border>\n";
0531                 }
0532 
0533                 // Font (size and family)
0534                 if ((fontsize != 12) || (fontnr != -1)) {
0535                     str += "     <font ";
0536                     // Fontsize
0537                     if (fontsize != 12) {
0538                         str += "size=\"" +
0539                                QString::number(fontsize) +
0540                                "\" ";
0541                     }
0542                     // Fontfamily
0543                     if (fontnr != -1) {
0544                         str += "family=\"" +
0545                                typefacetab[fontnr].toLatin1() +
0546                                "\" ";
0547                     }
0548                     str += "weight=\"0\"";
0549 
0550                     if (italic    == 1) str += " italic=\"yes\"";
0551                     if (bold      == 1) str += " bold=\"yes\"";
0552                     if (underline == 1) str += " underline=\"yes\"";
0553 
0554                     str += " />\n";
0555                 }
0556                 str += "    </format>\n";
0557             }
0558             str += "    <text>" + mystr + "</text>\n"
0559                    "   </cell>\n";
0560         }
0561 
0562     }
0563     emit sigProgress(100);
0564 
0565     str += "  </table>\n"
0566            " </map>\n"
0567            "</spreadsheet>\n";
0568 //  str += "</DOC>\n";
0569 
0570     qDebug() << "Text" << str;
0571 
0572     KoStoreDevice* out = m_chain->storageFile("root", KoStore::Write);
0573 
0574     if (!out) {
0575         qWarning() << "Unable to open output file!";
0576         in.close();
0577         return KoFilter::StorageCreationError;
0578     }
0579 
0580     QByteArray cstring = str.toUtf8();
0581     out->write(cstring, cstring.length());
0582 
0583     in.close();
0584     return KoFilter::OK;
0585 }
0586 
0587 
0588 
0589 
0590 /******************************************************************************
0591  *  function: specCharfind                                                    *
0592  ******************************************************************************/
0593 QChar
0594 APPLIXSPREADImport::specCharfind(QChar a, QChar b)
0595 {
0596     QChar chr;
0597 
0598     if ((a == 'n') && (b == 'p'))  chr = 0x00DF; // 'ß';
0599 
0600 
0601     else if ((a == 'n') && (b == 'c'))  chr = 0x00D2; // 'Ò';
0602     else if ((a == 'p') && (b == 'c'))  chr = 0x00F2; // 'ò';
0603 
0604     else if ((a == 'n') && (b == 'd'))  chr = 0x00D3; // 'Ó';
0605     else if ((a == 'p') && (b == 'd'))  chr = 0x00F3; // 'ó';
0606 
0607     else if ((a == 'n') && (b == 'e'))  chr = 0x00D4; // 'Ô';
0608     else if ((a == 'p') && (b == 'e'))  chr = 0x00F4; // 'ô';
0609 
0610     else if ((a == 'n') && (b == 'f'))  chr = 0x00D5; // 'Õ';
0611     else if ((a == 'p') && (b == 'f'))  chr = 0x00F5; // 'õ';
0612 
0613     else if ((a == 'n') && (b == 'g'))  chr = 0x00D6; // 'Ö';
0614     else if ((a == 'p') && (b == 'g'))  chr = 0x00F6; // 'ö';
0615 
0616 
0617 
0618     else if ((a == 'n') && (b == 'j'))  chr = 0x00D9; // 'Ù';
0619     else if ((a == 'p') && (b == 'j'))  chr = 0x00F9; // 'ù';
0620 
0621     else if ((a == 'n') && (b == 'k'))  chr = 0x00DA; // 'Ú';
0622     else if ((a == 'p') && (b == 'k'))  chr = 0x00FA; // 'ú';
0623 
0624     else if ((a == 'n') && (b == 'l'))  chr = 0x00DB; // 'Û';
0625     else if ((a == 'p') && (b == 'l'))  chr = 0x00FB; // 'û';
0626 
0627     else if ((a == 'n') && (b == 'm'))  chr = 0x00DC; // 'Ü';
0628     else if ((a == 'p') && (b == 'm'))  chr = 0x00FC; // 'ü';
0629 
0630 
0631 
0632     else if ((a == 'm') && (b == 'a'))  chr = 0x00C0; // 'À';
0633     else if ((a == 'o') && (b == 'a'))  chr = 0x00E0; // 'à';
0634 
0635     else if ((a == 'm') && (b == 'b'))  chr = 0x00C1; // 'Á';
0636     else if ((a == 'o') && (b == 'b'))  chr = 0x00E1; // 'á';
0637 
0638     else if ((a == 'm') && (b == 'c'))  chr = 0x00C2; // 'Â';
0639     else if ((a == 'o') && (b == 'c'))  chr = 0x00E2; // 'â';
0640 
0641     else if ((a == 'm') && (b == 'd'))  chr = 0x00C3; // 'Ã';
0642     else if ((a == 'o') && (b == 'd'))  chr = 0x00E3; // 'ã';
0643 
0644     else if ((a == 'm') && (b == 'e'))  chr = 0x00C4; // 'Ä';
0645     else if ((a == 'o') && (b == 'e'))  chr = 0x00E4; // 'ä';
0646 
0647     else if ((a == 'm') && (b == 'f'))  chr = 0x00C5; // 'Å';
0648     else if ((a == 'o') && (b == 'f'))  chr = 0x00E5; // 'å';
0649 
0650     else if ((a == 'm') && (b == 'g'))  chr = 0x00C6; // 'Æ';
0651     else if ((a == 'o') && (b == 'g'))  chr = 0x00E6; // 'æ';
0652 
0653 
0654 
0655     else if ((a == 'm') && (b == 'i'))  chr = 0x00C8; // 'È';
0656     else if ((a == 'o') && (b == 'i'))  chr = 0x00E8; // 'è';
0657 
0658     else if ((a == 'm') && (b == 'j'))  chr = 0x00C9; // 'É';
0659     else if ((a == 'o') && (b == 'j'))  chr = 0x00E9; // 'é';
0660 
0661     else if ((a == 'm') && (b == 'k'))  chr = 0x00CA; // 'Ê';
0662     else if ((a == 'o') && (b == 'k'))  chr = 0x00EA; // 'ê';
0663 
0664     else if ((a == 'm') && (b == 'l'))  chr = 0x00CB; // 'Ë';
0665     else if ((a == 'o') && (b == 'l'))  chr = 0x00EB; // 'ë';
0666 
0667 
0668 
0669     else if ((a == 'm') && (b == 'm'))  chr = 0x00CC; // 'Ì';
0670     else if ((a == 'o') && (b == 'm'))  chr = 0x00EC; // 'ì';
0671 
0672     else if ((a == 'm') && (b == 'n'))  chr = 0x00CD; // 'Í';
0673     else if ((a == 'o') && (b == 'n'))  chr = 0x00ED; // 'í';
0674 
0675     else if ((a == 'm') && (b == 'o'))  chr = 0x00CE; // 'Î';
0676     else if ((a == 'o') && (b == 'o'))  chr = 0x00EE; // 'î';
0677 
0678     else if ((a == 'm') && (b == 'p'))  chr = 0x00CF; // 'Ï';
0679     else if ((a == 'o') && (b == 'p'))  chr = 0x00EF; // 'ï';
0680 
0681 
0682     else if ((a == 'n') && (b == 'b'))  chr = 0x00D1; // 'Ñ';
0683     else if ((a == 'p') && (b == 'b'))  chr = 0x00F1; // 'ñ';
0684 
0685 
0686     else if ((a == 'k') && (b == 'c'))  chr = 0x00A2; // '¢';
0687     else if ((a == 'k') && (b == 'j'))  chr = 0x00A9; // '©';
0688     else if ((a == 'l') && (b == 'f'))  chr = 0x00B5; // 'µ';
0689     else if ((a == 'n') && (b == 'i'))  chr = 0x00D8; // 'Ø';
0690     else if ((a == 'p') && (b == 'i'))  chr = 0x00F8; // 'ø';
0691 
0692     else if ((a == 'l') && (b == 'j'))  chr = 0x00B9; // '¹';
0693     else if ((a == 'l') && (b == 'c'))  chr = 0x00B2; // '²';
0694     else if ((a == 'l') && (b == 'd'))  chr = 0x00B3; // '³';
0695 
0696     else if ((a == 'l') && (b == 'm'))  chr = 0x0152; // 'Œ';
0697     else if ((a == 'l') && (b == 'n'))  chr = 0x0153; // 'œ';
0698     else if ((a == 'l') && (b == 'o'))  chr = 0x0178; // 'Ÿ';
0699 
0700     else if ((a == 'l') && (b == 'a'))  chr = 0x00B0; // '°';
0701 
0702     else if ((a == 'k') && (b == 'o'))  chr = 0x00AE; // '®';
0703     else if ((a == 'k') && (b == 'h'))  chr = 0x00A7; // '§';
0704     else if ((a == 'k') && (b == 'd'))  chr = 0x00A3; // '£';
0705 
0706     else if ((a == 'p') && (b == 'a'))  chr = 0x00F0; // 'ð';
0707     else if ((a == 'n') && (b == 'a'))  chr = 0x00D0; // 'Ð';
0708 
0709     else if ((a == 'l') && (b == 'l'))  chr = 0x00BB; // '»';
0710     else if ((a == 'k') && (b == 'l'))  chr = 0x00AB; // '«';
0711 
0712     else if ((a == 'l') && (b == 'k'))  chr = 0x00BA; // 'º';
0713 
0714     else if ((a == 'l') && (b == 'h'))  chr = 0x00B7; // '·';
0715 
0716     else if ((a == 'k') && (b == 'b'))  chr = 0x00A1; // '¡';
0717 
0718     else if ((a == 'k') && (b == 'e'))  chr = 0x20AC; // '€';
0719 
0720     else if ((a == 'l') && (b == 'b'))  chr = 0x00B1; // '±';
0721 
0722     else if ((a == 'l') && (b == 'p'))  chr = 0x00BF; // '¿';
0723 
0724     else if ((a == 'k') && (b == 'f'))  chr = 0x00A5; // '¥';
0725 
0726     else if ((a == 'p') && (b == 'o'))  chr = 0x00FE; // 'þ';
0727     else if ((a == 'n') && (b == 'o'))  chr = 0x00DE; // 'Þ';
0728 
0729     else if ((a == 'n') && (b == 'n'))  chr = 0x00DD; // 'Ý';
0730     else if ((a == 'p') && (b == 'n'))  chr = 0x00FD; // 'ý';
0731     else if ((a == 'p') && (b == 'p'))  chr = 0x00FF; // 'ÿ';
0732 
0733     else if ((a == 'k') && (b == 'k'))  chr = 0x00AA; // 'ª';
0734 
0735     else if ((a == 'k') && (b == 'm'))  chr = 0x00AC; // '¬';
0736     else if ((a == 'p') && (b == 'h'))  chr = 0x00F7; // '÷';
0737 
0738     else if ((a == 'k') && (b == 'g'))  chr = 0x007C; // '|';
0739 
0740     else if ((a == 'l') && (b == 'e'))  chr = 0x0027; // '\'';
0741 
0742     else if ((a == 'k') && (b == 'i'))  chr = 0x0161; // 'š';
0743 
0744     else if ((a == 'k') && (b == 'n'))  chr = 0x00AD; // '­';
0745 
0746     else if ((a == 'k') && (b == 'p'))  chr = 0x00AF; // '¯';
0747 
0748     else if ((a == 'l') && (b == 'g'))  chr = 0x00B6; // '¶';
0749 
0750     else if ((a == 'l') && (b == 'i'))  chr = 0x017E; // 'ž';
0751 
0752     else if ((a == 'm') && (b == 'h'))  chr = 0x00C7; // 'Ç';
0753     else if ((a == 'o') && (b == 'h'))  chr = 0x00E7; // 'ç';
0754 
0755     else if ((a == 'n') && (b == 'h'))  chr = 0x00D7; // '×';
0756 
0757     else if ((a == 'k') && (b == 'a'))  chr = 0x0020; // ' ';
0758 
0759     else if ((a == 'a') && (b == 'j'))  chr = 0x0021; // '!';
0760 
0761     else  chr = 0x0023; // '#';
0762 
0763     return chr;
0764 }
0765 
0766 
0767 
0768 /******************************************************************************
0769  *  function:   writePen                                                      *
0770  ******************************************************************************/
0771 void
0772 APPLIXSPREADImport::writePen(QString &str, int penwidth, int penstyle, const QString &framecolor)
0773 {
0774     str += "     <pen width=\"" +
0775 
0776     // width of the pen
0777            QString::number(penwidth) +
0778            "\" style=\"" +
0779 
0780     // style of the pen
0781            QString::number(penstyle) +
0782            "\" color=\"" +
0783 
0784     // color of the pen
0785            framecolor +
0786            "\" />\n";
0787 
0788 }
0789 
0790 
0791 
0792 /******************************************************************************
0793  *  function:   writeColor                                                    *
0794  ******************************************************************************/
0795 QString
0796 APPLIXSPREADImport::writeColor(t_mycolor *mc)
0797 {
0798     char rgb[20];
0799 
0800 //    printf ("                 WriteColor: <%d>-<%d>-<%d>   <%d>-<%d>-<%d>-<%d>\n",
0801 //            mc->r, mc->g, mc->b,
0802 //            mc->c, mc->m, mc->y, mc->k);
0803 
0804     sprintf(rgb, "#%02X%02X%02X", mc->r, mc->g, mc->b);
0805     QString bla = rgb;
0806 
0807 
0808     return bla;
0809 }
0810 
0811 
0812 
0813 
0814 /******************************************************************************
0815  *  function:   readTypefaceTable                                             *
0816  ******************************************************************************/
0817 void
0818 APPLIXSPREADImport::readTypefaceTable(QTextStream &stream, QStringList &typefacetab)
0819 {
0820     int tftabCounter = 0;
0821     QString mystr;
0822 
0823     // Read the colormap
0824     qDebug() << "Reading typeface table:";
0825 
0826     bool ok = true;
0827     do {
0828         mystr = nextLine(stream);
0829         // FIXME: What happens if the magic words are not present in the stream?
0830         if (mystr == "END TYPEFACE TABLE") ok = false;
0831         else {
0832             //printf ("  %2d: <%s>\n", tftabCounter, mystr.toLatin1());
0833             typefacetab.append(mystr);
0834             tftabCounter++;
0835         }
0836     } while (ok == true);
0837 
0838     qDebug() << "... done";
0839 }
0840 
0841 
0842 
0843 /******************************************************************************
0844  *  function:   readColormap                                                  *
0845  ******************************************************************************/
0846 void
0847 APPLIXSPREADImport::readColormap(QTextStream &stream,  QList<t_mycolor*> &mcol)
0848 {
0849     int contcount, pos;
0850 
0851     QString colstr, mystr;
0852     qDebug() << "Reading colormap:";
0853 
0854     bool ok = true;
0855 
0856     do {
0857 
0858         mystr = nextLine(stream).trimmed();
0859 
0860         if (mystr == "END COLORMAP") ok = false;
0861         else {
0862             qDebug() << "  ->" << mystr;
0863 
0864             // Count the number of  whitespaces
0865             contcount = mystr.count(' ');
0866             qDebug() << "contcount:" << contcount;
0867             contcount -= 5;
0868 
0869             // Begin off interest
0870             pos = mystr.indexOf(" 0 ");
0871 
0872             // get colorname
0873             colstr = mystr.left(pos);
0874             mystr.remove(0, pos + 1);
0875             mystr = mystr.trimmed();
0876 
0877             t_mycolor *tmc = new t_mycolor;
0878 
0879             // get sub colors
0880             pos = sscanf(mystr.toLatin1(), "0 %d %d %d %d 0",
0881                          &tmc->c, &tmc->m, &tmc->y, &tmc->k);
0882 
0883             printf("  - <%-20s> <%-15s> <%3d> <%3d> <%3d> <%3d>  pos: %d\n",
0884                    mystr.toLatin1().data(),
0885                    colstr.toLatin1().data(),
0886                    tmc->c, tmc->m, tmc->y, tmc->k, pos);
0887 
0888             // Color transformation cmyk -> rgb
0889             tmc->r = 255 - (tmc->c + tmc->k);
0890             if (tmc->r < 0) tmc->r = 0;
0891 
0892             tmc->g = 255 - (tmc->m + tmc->k);
0893             if (tmc->g < 0) tmc->g = 0;
0894 
0895             tmc->b = 255 - (tmc->y + tmc->k);
0896             if (tmc->b < 0) tmc->b = 0;
0897 
0898             mcol.append(tmc);
0899         }
0900 
0901     } while (ok == true);
0902 
0903     qDebug() << "... done" << mcol.count();
0904 
0905     foreach(t_mycolor* emp, mcol) {
0906         printf(" c:%3d m:%3d y:%3d k:%3d   r:%3d g:%3d b:%3d\n",
0907                emp->c, emp->m, emp->y, emp->k, emp->r, emp->g, emp->b);
0908     }
0909 }
0910 
0911 
0912 
0913 
0914 /******************************************************************************
0915  *  function:   readColormap                                                  *
0916  ******************************************************************************/
0917 void
0918 APPLIXSPREADImport::readView(QTextStream &stream, const QString &instr, t_rc &rc)
0919 {
0920     QString rowcolstr;
0921     QString mystr, tabname;
0922 
0923     qDebug() << "Reading View";
0924 
0925     tabname = instr;
0926 
0927     tabname.remove(0, 19);
0928     tabname.remove(tabname.length() - 2, 2);
0929     qDebug() << "  - Table name:" << tabname;
0930 
0931     bool ok = true;
0932     do {
0933         mystr = nextLine(stream);
0934 
0935         qDebug() << "" << mystr;
0936         if (mystr.startsWith("View End, Name:")) ok = false;
0937         else {
0938             // COLUMN Widths
0939             if (mystr.startsWith("View Column Widths")) {
0940                 qDebug() << "   - Column Widths";
0941                 mystr.remove(0, 20);
0942                 qDebug() << "" << mystr;
0943 
0944                 int  colwidth, icolumn;
0945                 char ccolumn;
0946 
0947                 // loop
0948                 QStringList ColumnList;
0949                 ColumnList = mystr.split(' ');
0950 
0951                 for (QStringList::Iterator it = ColumnList.begin(); it != ColumnList.end(); ++it) {
0952 
0953                     sscanf((*it).toLatin1(), "%c:%d", &ccolumn, &colwidth);
0954                     int len = (*it).length();
0955                     int pos = (*it).indexOf(':');
0956                     (*it).remove(pos, len - pos);
0957 
0958                     printf("     >%s<- -<%c><%d>  \n", (*it).toLatin1().data(), ccolumn, colwidth);
0959 
0960                     // Transformat ascii column to int column
0961                     icolumn = translateColumnNumber(*it);
0962 
0963                     //icolumn = ccolumn - 64;
0964                     // Translate the column width right from applix to kspread
0965                     icolumn = icolumn * 5;
0966 
0967 
0968                     rowcolstr += "  <column width=\"" +
0969                                  QString::number(colwidth) +
0970                                  "\" column=\"" +
0971                                  QString::number(icolumn) +
0972                                  "\" >\n"
0973                                  "   <format/>\n"
0974                                  "  </column>\n";
0975                 }
0976             }
0977 
0978             // ROW Heights
0979             else if (mystr.startsWith("View Row Heights")) {
0980                 qDebug() << "   - Row Heights";
0981                 mystr.remove(0, 17);
0982                 qDebug() << "" << mystr;
0983 
0984                 int irow, rowheight;
0985 
0986                 // loop
0987                 QStringList RowList;
0988                 RowList = mystr.split(' ');
0989 
0990                 for (QStringList::Iterator it = RowList.begin(); it != RowList.end(); ++it) {
0991                     sscanf((*it).toLatin1(), " %d:%d",
0992                            &irow, &rowheight);
0993                     printf("   row: %2d   height: %2d\n", irow, rowheight);
0994                     if (rowheight > 32768) rowheight -= 32768;
0995                     printf("              height: %2d\n", rowheight);
0996                     rowcolstr += "  <row row=\"" +
0997                                  QString::number(irow) +
0998                                  "\" height=\"" +
0999                                  QString::number(rowheight) +
1000                                  "\" >\n"
1001                                  "   <format/>\n"
1002                                  "  </row>\n";
1003                 }
1004 
1005 
1006             }
1007         } // else != END COLORMAP
1008     } while (ok == true);
1009 
1010     // tabname append to my list
1011     // tabname append to my list
1012     rc.tabname.append(tabname);
1013     rc.rc.append(rowcolstr);
1014 
1015     printf("%s %s\n", tabname.toLatin1().data(),
1016            rowcolstr.toLatin1().data());
1017 
1018     printf("...done \n\n");
1019 }
1020 
1021 
1022 
1023 
1024 
1025 /******************************************************************************
1026  *  function:   filterSHFGBG                                                  *
1027  ******************************************************************************/
1028 void
1029 APPLIXSPREADImport::filterSHFGBG(const QString &it, int *style, int *bgcolor,
1030                                  int *fgcolor)
1031 {
1032     QString tmpstr;
1033     int     pos;
1034     int     m2 = 0, m3 = 0;
1035 
1036     // filter SH = Brushstyle Background
1037     pos = it.indexOf("SH");
1038     if (pos > -1) {
1039         tmpstr = it;
1040         if (pos > 0)   tmpstr.remove(0, pos);
1041         pos = sscanf(tmpstr.toLatin1(), "SH%d",
1042                      style);
1043 
1044         printf("style: %d(%d)  ",
1045                *style, pos);
1046     }
1047 
1048 
1049     // filter FG = FGCOLOR
1050     pos = it.indexOf("FG");
1051     if (pos > -1) {
1052         tmpstr = it;
1053         if (pos > 0)   tmpstr.remove(0, pos);
1054         pos = sscanf(tmpstr.toLatin1(), "FG%d",
1055                      fgcolor);
1056         printf("fg: %d(%d)  ",
1057                *fgcolor, pos);
1058         m2 = 1;
1059     }
1060 
1061 
1062     // filter BG = BGCOLOR
1063     pos = it.indexOf("BG");
1064     if (pos > -1) {
1065         tmpstr = it;
1066         if (pos > 0)   tmpstr.remove(0, pos);
1067         pos = sscanf(tmpstr.toLatin1(), "BG%d",
1068                      bgcolor);
1069         printf("bgcolor: %d(%d)  ",
1070                *bgcolor, pos);
1071         m3 = 1;
1072     }
1073 
1074 
1075     printf("\n");
1076 
1077 
1078     // correct the bgcolor to the fgcolor if the background is plain
1079     if ((*style == 8) && (m2 == 1) && (m3 == 0)) {
1080         *bgcolor = *fgcolor;
1081     }
1082 
1083 
1084     // Translate brushstyle to kspread brushstyle
1085     if (*style != 0) {
1086         if (*style ==  1) *style =  0;
1087         else if (*style ==  2) *style =  7;
1088         else if (*style ==  3) *style =  0;
1089         else if (*style ==  4) *style =  4;
1090         else if (*style ==  5) *style =  3;
1091         else if (*style ==  6) *style =  2;
1092         else if (*style ==  7) *style =  0;
1093         else if (*style ==  8) *style =  0;
1094         else if (*style ==  9) *style = 10;
1095         else if (*style == 10) *style =  9;
1096         else if (*style == 11) *style = 11;
1097         else if (*style == 12) *style = 12;
1098         else if (*style == 13) *style = 13;
1099         else if (*style == 14) *style = 14;
1100         else if (*style == 15) *style =  0;
1101         else if (*style == 16) *style =  0;
1102         else if (*style == 17) *style =  0;
1103         else if (*style == 18) *style =  0;
1104         else if (*style == 19) *style =  0;
1105     }
1106 }
1107 
1108 
1109 
1110 /******************************************************************************
1111  *  function:   filterSHFGBG                                                  *
1112  ******************************************************************************/
1113 void
1114 APPLIXSPREADImport::transPenFormat(const QString &it, int *PenWidth, int *PenStyle)
1115 {
1116 
1117     if (it[1] == '1') {
1118         *PenWidth = 1;
1119         *PenStyle = 1;
1120     }
1121 
1122     else if (it[1] == '2') {
1123         *PenWidth = 2;
1124         *PenStyle = 1;
1125     }
1126 
1127     else if (it[1] == '3') {
1128         *PenWidth = 3;
1129         *PenStyle = 1;
1130     }
1131 
1132     else if (it[1] == '4') {
1133         *PenWidth = 1;
1134         *PenStyle = 3;
1135     }
1136 
1137     else if (it[1] == '5') {
1138         *PenWidth = 5;
1139         *PenStyle = 1;
1140     }
1141 
1142     printf("frame (w:%d - s:%d) \n", *PenWidth, *PenStyle);
1143 }
1144 
1145 
1146 
1147 
1148 /******************************************************************************
1149  *  function: readHeader                                                       *
1150  ******************************************************************************/
1151 int
1152 APPLIXSPREADImport::readHeader(QTextStream &stream)
1153 {
1154     QString mystr;
1155     int     vers[3] = { 0, 0, 0 };
1156     int     rueck;
1157 
1158 
1159     // Read Headline
1160     mystr = nextLine(stream);
1161     rueck = sscanf(mystr.toLatin1(),
1162                    "*BEGIN SPREADSHEETS VERSION=%d/%d ENCODING=%dBIT",
1163                    &vers[0], &vers[1], &vers[2]);
1164     printf("Versions info: %d %d %d\n", vers[0], vers[1], vers[2]);
1165 
1166     // Check the headline
1167     if (rueck <= 0) {
1168         printf("Header not correct - May be it is not an applixspreadsheet file\n");
1169         printf("Headerline: <%s>\n", mystr.toLatin1().data());
1170 
1171         QMessageBox::critical(0L, "Applix spreadsheet header problem",
1172                               QString("The Applix Spreadsheet header is not correct. "
1173                                       "May be it is not an applix spreadsheet file! <BR>"
1174                                       "This is the header line I did read:<BR><B>%1</B>").arg(mystr),
1175                               "Okay");
1176 
1177 
1178         return false;
1179     } else {
1180         return true;
1181     }
1182 }
1183 
1184 
1185 /******************************************************************************
1186  *  function: translateColumnNumber                                           *
1187  ******************************************************************************/
1188 int
1189 APPLIXSPREADImport::translateColumnNumber(const QString& colstr)
1190 {
1191     int icol = 0;
1192     const int len = colstr.length();
1193     int p = len - 1;
1194     int x = 1;
1195 
1196     //qDebug() << "len=" << len;
1197     while (p >= 0) {
1198         //qDebug() << "x=" << x << "p=" << p << "char=" << colstr[p].toLatin1();
1199         const char c = colstr[p].toLatin1();
1200         // Upper chars
1201         if ((c >= 'A') && (c <= 'Z')) {
1202             //qDebug() << " UPPER";
1203             icol += ((int)pow((double)x, 26) * (c - 'A' + 1));
1204             ++x;
1205         }
1206         // lower chars
1207         else if ((c >= 'a') && (c <= 'z')) {
1208             //qDebug() << " lower";
1209             icol += ((int)pow((double)x, 26) * (c - 'a' + 1));
1210             ++x;
1211         }
1212         p--;
1213     }
1214 
1215     qDebug() << colstr << "->" << icol;
1216     return icol;
1217 }
1218 
1219 // Converts =SUM(F1,4) into =SUM(F1;4) -- well, plus possible nesting
1220 QString APPLIXSPREADImport::convertFormula(const QString& input) const
1221 {
1222     // Let me be stupid for now
1223     QString ret = input;
1224     ret.replace(',', ';');
1225     return ret;
1226 }
1227 
1228 #include "applixspreadimport.moc"