File indexing completed on 2025-01-19 13:27:13

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