Warning, file /office/calligra/filters/sheets/gnumeric/gnumericexport.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: 2000 David Faure <faure@kde.org>
0003    SPDX-FileCopyrightText: 2005 Laurent Montel <montel@kde.org>
0004 
0005    SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 /* Gnumeric export filter by Phillip Ezolt (phillipezolt@hotmail.com)
0009    2004 - Some updates by Tim Beaulen (tbscope@gmail.com) */
0010 
0011 #include <gnumericexport.h>
0012 
0013 #include <KCompressionDevice>
0014 #include <kpluginfactory.h>
0015 
0016 // Calligra
0017 #include <KoDocumentInfo.h>
0018 #include <KoFilterChain.h>
0019 #include <KoZoomHandler.h>
0020 #include <KoPart.h>
0021 #include <KoUnit.h>
0022 
0023 // Calligra::Sheets
0024 #include <sheets/engine/CellBaseStorage.h>
0025 #include <sheets/engine/Localization.h>
0026 #include <sheets/engine/NamedAreaManager.h>
0027 #include <sheets/engine/ValueConverter.h>
0028 #include <sheets/engine/Validity.h>
0029 
0030 #include <sheets/core/ApplicationSettings.h>
0031 #include <sheets/core/Cell.h>
0032 #include <sheets/core/ColFormatStorage.h>
0033 #include <sheets/core/DocBase.h>
0034 #include <sheets/core/HeaderFooter.h>
0035 #include <sheets/core/Map.h>
0036 #include <sheets/core/PrintSettings.h>
0037 #include <sheets/core/RowFormatStorage.h>
0038 #include <sheets/core/Sheet.h>
0039 #include <sheets/core/Style.h>
0040 
0041 #include <sheets/part/Canvas.h>
0042 #include <sheets/part/View.h>
0043 
0044 using namespace Calligra::Sheets;
0045 
0046 K_PLUGIN_FACTORY_WITH_JSON(GNUMERICExportFactory, "calligra_filter_sheets2gnumeric.json",
0047                            registerPlugin<GNUMERICExport>();)
0048 
0049 GNUMERICExport::GNUMERICExport(QObject* parent, const QVariantList&)
0050         : KoFilter(parent)
0051 {
0052     isLink = false;
0053     isLinkBold = false;
0054     isLinkItalic = false;
0055 }
0056 
0057 /**
0058  * This function will check if a cell has any type of border.
0059  */
0060 bool GNUMERICExport::hasBorder(const Cell& cell, int currentcolumn, int currentrow)
0061 {
0062     Q_UNUSED(currentcolumn);
0063     Q_UNUSED(currentrow);
0064     const Style style = cell.style();
0065     if (((style.leftBorderPen().width() != 0) &&
0066             (style.leftBorderPen().style() != Qt::NoPen)) ||
0067             ((style.rightBorderPen().width() != 0) &&
0068              (style.rightBorderPen().style() != Qt::NoPen)) ||
0069             ((style.topBorderPen().width() != 0) &&
0070              (style.topBorderPen().style() != Qt::NoPen)) ||
0071             ((style.bottomBorderPen().width() != 0) &&
0072              (style.bottomBorderPen().style() != Qt::NoPen)) ||
0073             ((style.fallDiagonalPen().width() != 0) &&
0074              (style.fallDiagonalPen().style() != Qt::NoPen)) ||
0075             ((style.goUpDiagonalPen().width() != 0) &&
0076              (style.goUpDiagonalPen().style() != Qt::NoPen)))
0077         return true;
0078     else
0079         return false;
0080 }
0081 
0082 const QString GNUMERICExport::ColorToString(int red, int green, int blue)
0083 {
0084     return QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16);
0085 }
0086 
0087 QDomElement GNUMERICExport::GetBorderStyle(QDomDocument gnumeric_doc, const Cell& cell, int currentcolumn, int currentrow)
0088 {
0089     Q_UNUSED(currentcolumn);
0090     Q_UNUSED(currentrow);
0091 
0092     QDomElement border_style;
0093     QDomElement border;
0094 
0095     int red, green, blue;
0096     QColor color;
0097 
0098     border_style = gnumeric_doc.createElement("gmr:StyleBorder");
0099     const Style style = cell.style();
0100 
0101     if ((style.leftBorderPen().width() != 0) &&
0102             (style.leftBorderPen().style() != Qt::NoPen)) {
0103         border = gnumeric_doc.createElement("gmr:Left");
0104         border.setAttribute("Style", "1");
0105 
0106         color =  style.leftBorderPen().color();
0107         red = color.red() << 8;
0108         green = color.green() << 8;
0109         blue = color.blue() << 8;
0110 
0111         border.setAttribute("Color", QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16));
0112     } else {
0113         border = gnumeric_doc.createElement("gmr:Left");
0114         border.setAttribute("Style", "0");
0115     }
0116 
0117     border_style.appendChild(border);
0118 
0119     if ((style.rightBorderPen().width() != 0) &&
0120             (style.rightBorderPen().style() != Qt::NoPen)) {
0121         border = gnumeric_doc.createElement("gmr:Right");
0122         border.setAttribute("Style", "1");
0123 
0124         color =  style.rightBorderPen().color();
0125         red = color.red() << 8;
0126         green = color.green() << 8;
0127         blue = color.blue() << 8;
0128 
0129         border.setAttribute("Color", QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16));
0130     } else {
0131         border = gnumeric_doc.createElement("gmr:Right");
0132         border.setAttribute("Style", "0");
0133     }
0134 
0135     border_style.appendChild(border);
0136 
0137     if ((style.topBorderPen().width() != 0) &&
0138             (style.topBorderPen().style() != Qt::NoPen)) {
0139         border = gnumeric_doc.createElement("gmr:Top");
0140         border.setAttribute("Style", "1");
0141 
0142         color =  style.topBorderPen().color();
0143         red = color.red() << 8;
0144         green = color.green() << 8;
0145         blue = color.blue() << 8;
0146 
0147         border.setAttribute("Color", QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16));
0148     } else {
0149         border = gnumeric_doc.createElement("gmr:Top");
0150         border.setAttribute("Style", "0");
0151     }
0152 
0153     border_style.appendChild(border);
0154 
0155     if ((style.bottomBorderPen().width() != 0) &&
0156             (style.bottomBorderPen().style() != Qt::NoPen)) {
0157         border = gnumeric_doc.createElement("gmr:Bottom");
0158         border.setAttribute("Style", "1");
0159 
0160         color =  style.bottomBorderPen().color();
0161         red = color.red() << 8;
0162         green = color.green() << 8;
0163         blue = color.blue() << 8;
0164 
0165         border.setAttribute("Color", QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16));
0166     } else {
0167         border = gnumeric_doc.createElement("gmr:Bottom");
0168         border.setAttribute("Style", "0");
0169     }
0170 
0171     border_style.appendChild(border);
0172 
0173     if ((style.fallDiagonalPen().width() != 0) &&
0174             (style.fallDiagonalPen().style() != Qt::NoPen)) {
0175         border = gnumeric_doc.createElement("gmr:Diagonal");
0176         border.setAttribute("Style", "1");
0177 
0178         color =  style.fallDiagonalPen().color();
0179         red = color.red() << 8;
0180         green = color.green() << 8;
0181         blue = color.blue() << 8;
0182 
0183         border.setAttribute("Color", QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16));
0184     } else {
0185         border = gnumeric_doc.createElement("gmr:Diagonal");
0186         border.setAttribute("Style", "0");
0187     }
0188 
0189     border_style.appendChild(border);
0190 
0191     if ((style.goUpDiagonalPen().width() != 0) &&
0192             (style.goUpDiagonalPen().style() != Qt::NoPen)) {
0193         border = gnumeric_doc.createElement("gmr:Rev-Diagonal");
0194         border.setAttribute("Style", "1");
0195 
0196         color =  style.goUpDiagonalPen().color();
0197         red = color.red() << 8;
0198         green = color.green() << 8;
0199         blue = color.blue() << 8;
0200 
0201         border.setAttribute("Color", QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16));
0202     } else {
0203         border = gnumeric_doc.createElement("gmr:Rev-Diagonal");
0204         border.setAttribute("Style", "0");
0205     }
0206 
0207     border_style.appendChild(border);
0208 
0209     return border_style;
0210 }
0211 
0212 QDomElement GNUMERICExport::GetValidity(QDomDocument gnumeric_doc, const Cell& cell)
0213 {
0214     ValueConverter *const converter = cell.sheet()->map()->converter();
0215 
0216     //<gmr:Validation Style="1" Type="1" Operator="7" AllowBlank="true" UseDropdown="false" Title="ghhg" Message="ghghhhjfhfghjfghj&#10;fg&#10;hjgf&#10;hj">
0217     //        <gmr:Expression0>45</gmr:Expression0>
0218     //      </gmr:Validation>
0219     Validity kspread_validity = cell.validity();
0220     QDomElement val = gnumeric_doc.createElement("gmr:Validation");
0221     val.setAttribute("Title", kspread_validity.title());
0222     val.setAttribute("Message", kspread_validity.message());
0223     val.setAttribute("AllowBlank", kspread_validity.allowEmptyCell() ? "true" : "false");
0224     if (!kspread_validity.displayMessage()) {
0225         val.setAttribute("Style", "0");
0226     } else {
0227         switch (kspread_validity.action()) {
0228         case Validity::Stop:
0229             val.setAttribute("Style", "1");
0230             break;
0231         case Validity::Warning:
0232             val.setAttribute("Style", "2");
0233             break;
0234         case Validity::Information:
0235             val.setAttribute("Style", "3");
0236             break;
0237         }
0238     }
0239 
0240     switch (kspread_validity.condition()) {
0241     case Validity::None:
0242     case Validity::IsTrueFormula: // FIXME: handle isTrueFormula
0243         //Nothing
0244         break;
0245     case Validity::Equal:
0246         val.setAttribute("Operator", "2");
0247         break;
0248     case Validity::Superior:
0249         val.setAttribute("Operator", "4");
0250         break;
0251     case Validity::Inferior:
0252         val.setAttribute("Operator", "5");
0253         break;
0254     case Validity::SuperiorEqual:
0255         val.setAttribute("Operator", "6");
0256         break;
0257     case Validity::InferiorEqual:
0258         val.setAttribute("Operator", "7");
0259         break;
0260     case Validity::Between:
0261         val.setAttribute("Operator", "0");
0262         break;
0263     case Validity::Different:
0264         val.setAttribute("Operator", "3");
0265         break;
0266     case Validity::DifferentTo:
0267         val.setAttribute("Operator", "1");
0268         break;
0269     }
0270     switch (kspread_validity.restriction()) {
0271     case Validity::NoRestriction:
0272         val.setAttribute("Type", "0");
0273         break;
0274     case Validity::Number: {
0275         val.setAttribute("Type", "2");
0276         switch (kspread_validity.condition()) {
0277         case Validity::None:
0278         case Validity::IsTrueFormula: // FIXME: handle isTrueFormula
0279             //Nothing
0280             break;
0281         case Validity::Equal:
0282         case Validity::Superior:
0283         case Validity::Inferior:
0284         case Validity::SuperiorEqual:
0285         case Validity::InferiorEqual:
0286         case Validity::Different: {
0287             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0288             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0289             val.appendChild(tmp);
0290         }
0291         break;
0292         case Validity::Between:
0293         case Validity::DifferentTo: {
0294             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0295             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0296             val.appendChild(tmp);
0297             tmp = gnumeric_doc.createElement("gmr:Expression1");
0298             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.maximumValue()).asString()));
0299             val.appendChild(tmp);
0300         }
0301         break;
0302         }
0303 
0304         break;
0305     }
0306     case Validity::Text:
0307         //Not supported into gnumeric
0308         //val.setAttribute("Type", "1" );
0309         break;
0310     case Validity::Time:
0311         val.setAttribute("Type", "5");
0312         switch (kspread_validity.condition()) {
0313         case Validity::None:
0314         case Validity::IsTrueFormula: // FIXME: handle isTrueFormula
0315             //Nothing
0316             break;
0317         case Validity::Equal:
0318         case Validity::Superior:
0319         case Validity::Inferior:
0320         case Validity::SuperiorEqual:
0321         case Validity::InferiorEqual:
0322         case Validity::Different: {
0323             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0324             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0325             val.appendChild(tmp);
0326         }
0327         break;
0328         case Validity::Between:
0329         case Validity::DifferentTo: {
0330             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0331             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0332             val.appendChild(tmp);
0333             tmp = gnumeric_doc.createElement("gmr:Expression1");
0334             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.maximumValue()).asString()));
0335             val.appendChild(tmp);
0336         }
0337         break;
0338         }
0339 
0340         break;
0341     case Validity::Date:
0342         val.setAttribute("Type", "4");
0343         switch (kspread_validity.condition()) {
0344         case Validity::None:
0345         case Validity::IsTrueFormula: // FIXME: handle isTrueFormula
0346             //Nothing
0347             break;
0348         case Validity::Equal:
0349         case Validity::Superior:
0350         case Validity::Inferior:
0351         case Validity::SuperiorEqual:
0352         case Validity::InferiorEqual:
0353         case Validity::Different: {
0354             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0355             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0356             val.appendChild(tmp);
0357         }
0358         break;
0359         case Validity::Between:
0360         case Validity::DifferentTo: {
0361             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0362             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0363             val.appendChild(tmp);
0364             tmp = gnumeric_doc.createElement("gmr:Expression1");
0365             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.maximumValue()).asString()));
0366             val.appendChild(tmp);
0367         }
0368         break;
0369         }
0370 
0371         break;
0372     case Validity::Integer:
0373         val.setAttribute("Type", "1");
0374         switch (kspread_validity.condition()) {
0375         case Validity::None:
0376         case Validity::IsTrueFormula: // FIXME: handle isTrueFormula
0377             //Nothing
0378             break;
0379         case Validity::Equal:
0380         case Validity::Superior:
0381         case Validity::Inferior:
0382         case Validity::SuperiorEqual:
0383         case Validity::InferiorEqual:
0384         case Validity::Different: {
0385             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0386             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0387             val.appendChild(tmp);
0388         }
0389         break;
0390         case Validity::Between:
0391         case Validity::DifferentTo: {
0392             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0393             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0394             val.appendChild(tmp);
0395             tmp = gnumeric_doc.createElement("gmr:Expression1");
0396             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.maximumValue()).asString()));
0397             val.appendChild(tmp);
0398         }
0399         break;
0400         }
0401         break;
0402     case Validity::TextLength:
0403         val.setAttribute("Type", "6");
0404         switch (kspread_validity.condition()) {
0405         case Validity::None:
0406         case Validity::IsTrueFormula: // FIXME: handle isTrueFormula
0407             //Nothing
0408             break;
0409         case Validity::Equal:
0410         case Validity::Superior:
0411         case Validity::Inferior:
0412         case Validity::SuperiorEqual:
0413         case Validity::InferiorEqual:
0414         case Validity::Different: {
0415             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0416             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0417             val.appendChild(tmp);
0418         }
0419         break;
0420         case Validity::Between:
0421         case Validity::DifferentTo: {
0422             QDomElement tmp = gnumeric_doc.createElement("gmr:Expression0");
0423             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.minimumValue()).asString()));
0424             val.appendChild(tmp);
0425             tmp = gnumeric_doc.createElement("gmr:Expression1");
0426             tmp.appendChild(gnumeric_doc.createTextNode(converter->asString(kspread_validity.maximumValue()).asString()));
0427             val.appendChild(tmp);
0428         }
0429         break;
0430         }
0431         break;
0432     case Validity::List:
0433         val.setAttribute("Type", "3");
0434         switch (kspread_validity.condition()) {
0435         case Validity::None:
0436         case Validity::IsTrueFormula: // FIXME: handle isTrueFormula
0437             //Nothing
0438             break;
0439         case Validity::Equal:
0440         case Validity::Superior:
0441         case Validity::Inferior:
0442         case Validity::SuperiorEqual:
0443         case Validity::InferiorEqual:
0444         case Validity::Different:
0445             break;
0446         case Validity::Between:
0447         case Validity::DifferentTo:
0448             break;
0449         }
0450         break;
0451     }
0452 
0453     return val;
0454 }
0455 
0456 QDomElement GNUMERICExport::GetFontStyle(QDomDocument gnumeric_doc, const Cell& cell, int currentcolumn, int currentrow)
0457 {
0458     QDomElement font_style;
0459     const Style style = cell.style();
0460     qDebug() << " currentcolumn :" << currentcolumn << " currentrow :" << currentrow;
0461     font_style = gnumeric_doc.createElement("gmr:Font");
0462     font_style.appendChild(gnumeric_doc.createTextNode(style.fontFamily()));
0463 
0464     if (style.italic() || (isLink && isLinkItalic)) {
0465         font_style.setAttribute("Italic", "1");
0466     }
0467     if (style.bold() || (isLink && isLinkBold)) {
0468         font_style.setAttribute("Bold", "1");
0469     }
0470     if (style.underline()) {
0471         font_style.setAttribute("Underline", "1");
0472     }
0473     if (style.strikeOut()) {
0474         font_style.setAttribute("StrikeThrough", "1");
0475     }
0476     if (style.fontSize()) {
0477         font_style.setAttribute("Unit", QString::number(style.fontSize()));
0478     }
0479 
0480     return font_style;
0481 }
0482 
0483 QDomElement GNUMERICExport::GetLinkStyle(QDomDocument gnumeric_doc)
0484 {
0485     QDomElement link_style;
0486 
0487     link_style = gnumeric_doc.createElement("gmr:HyperLink");
0488 
0489     QString path;
0490 
0491     path = linkUrl;
0492 
0493     if (path.section(":", 0, 0).toLower() == "http")
0494         link_style.setAttribute("type", "GnmHLinkURL");
0495     else if (path.section(":", 0, 0).toLower() == "mailto")
0496         link_style.setAttribute("type", "GnmHLinkEMail");
0497     else if (path.section(":", 0, 0).toLower() == "file")
0498         link_style.setAttribute("type", "GnmHLinkExternal");
0499     else if (path.left(5).toLower() == "sheet")
0500         link_style.setAttribute("type", "GnmHLinkCurWB");
0501     else
0502         link_style.setAttribute("type", "");
0503 
0504     link_style.setAttribute("target", path);
0505 
0506     // Calligra Sheets doesn't support link tips.
0507     link_style.setAttribute("tip", "");
0508 
0509     return link_style;
0510 }
0511 
0512 QDomElement GNUMERICExport::GetCellStyle(QDomDocument gnumeric_doc, const Cell& cell, int currentcolumn, int currentrow)
0513 {
0514     QDomElement cell_style;
0515 
0516     cell_style = gnumeric_doc.createElement("gmr:Style");
0517 
0518     int red, green, blue;
0519 
0520     const Style style = cell.style();
0521     QColor bgColor =  style.backgroundColor();
0522     if (bgColor.isValid()) {
0523         red = bgColor.red() << 8;
0524         green = bgColor.green() << 8;
0525         blue = bgColor.blue() << 8;
0526     } else {
0527         // Let's use white default for background
0528         red = 0xffff;
0529         green = 0xffff;
0530         blue = 0xffff;
0531     }
0532 
0533     switch (style.backgroundBrush().style()) {
0534     case Qt::NoBrush:
0535         cell_style.setAttribute("Shade", "0");
0536         break;
0537     case Qt::SolidPattern:
0538         // 100%
0539         cell_style.setAttribute("Shade", "1");
0540         break;
0541     case Qt::Dense1Pattern:
0542         // 87.5%
0543         cell_style.setAttribute("Shade", "25");
0544         break;
0545     case Qt::Dense2Pattern:
0546         // 75%
0547         cell_style.setAttribute("Shade", "2");
0548         break;
0549     case Qt::Dense3Pattern:
0550         // 62.5%
0551         // Not supported by GNumeric
0552         // Fall back to 50%
0553         cell_style.setAttribute("Shade", "3");
0554         break;
0555     case Qt::Dense4Pattern:
0556         // 50%
0557         cell_style.setAttribute("Shade", "3");
0558         break;
0559     case Qt::Dense5Pattern:
0560         // 25%
0561         cell_style.setAttribute("Shade", "4");
0562         break;
0563     case Qt::Dense6Pattern:
0564         // 12.5%
0565         cell_style.setAttribute("Shade", "5");
0566         break;
0567     case Qt::Dense7Pattern:
0568         // 6.25%
0569         cell_style.setAttribute("Shade", "6");
0570         break;
0571     case Qt::HorPattern:
0572         cell_style.setAttribute("Shade", "13");
0573         break;
0574     case Qt::VerPattern:
0575         cell_style.setAttribute("Shade", "14");
0576         break;
0577     case Qt::CrossPattern:
0578         cell_style.setAttribute("Shade", "17");
0579         break;
0580     case Qt::BDiagPattern:
0581         cell_style.setAttribute("Shade", "16");
0582         break;
0583     case Qt::FDiagPattern:
0584         cell_style.setAttribute("Shade", "15");
0585         break;
0586     case Qt::DiagCrossPattern:
0587         cell_style.setAttribute("Shade", "18");
0588         break;
0589     case Qt::TexturePattern:
0590     default:
0591         // Not supported by Gnumeric
0592         cell_style.setAttribute("Shade", "0");
0593         break;
0594     }
0595 
0596     cell_style.setAttribute("Back", QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16));
0597 
0598 
0599     QColor textColor =  style.fontColor();
0600     red = textColor.red() << 8;
0601     green = textColor.green() << 8;
0602     blue = textColor.blue() << 8;
0603 
0604     cell_style.setAttribute("Fore", QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16));
0605 
0606     if (style.halign() ==  Style::HAlignUndefined) {
0607         cell_style.setAttribute("HAlign", "1");
0608     } else if (style.halign() ==  Style::Left) {
0609         cell_style.setAttribute("HAlign", "2");
0610     } else if (style.halign() ==  Style::Right) {
0611         cell_style.setAttribute("HAlign", "4");
0612     } else if (style.halign() ==  Style::Center) {
0613         cell_style.setAttribute("HAlign", "8");
0614     }
0615 
0616     if (style.valign() ==  Style::Top) {
0617         cell_style.setAttribute("VAlign", "1");
0618     } else if (style.valign() ==  Style::Bottom) {
0619         cell_style.setAttribute("VAlign", "2");
0620     } else if (style.valign() ==  Style::Middle) {
0621         cell_style.setAttribute("VAlign", "4");
0622     }
0623 
0624     if (style.wrapText())
0625         cell_style.setAttribute("WrapText", "1");
0626     else
0627         cell_style.setAttribute("WrapText", "0");
0628 
0629     // ShrinkToFit not supported by Calligra Sheets (?)
0630     cell_style.setAttribute("ShrinkToFit", "0");
0631 
0632     // I'm not sure about the rotation values.
0633     // I never got it to work in GNumeric.
0634     cell_style.setAttribute("Rotation", QString::number(-1*style.angle()));
0635 
0636     // The indentation in GNumeric is an integer value. In Calligra Sheets, it's a double.
0637     // Save the double anyway, makes it even better when importing the document back in Calligra Sheets.
0638     // TODO verify if it's correct, in import we "* 10.0"
0639     cell_style.setAttribute("Indent", QString::number(style.indentation()));
0640 
0641     cell_style.setAttribute("Locked", QString::number(!style.notProtected()));
0642 
0643     // A Calligra Sheets cell can have two options to hide: only formula hidden, or everything hidden.
0644     // I only consider a cell with everything hidden as hidden.
0645     // Gnumeric hides everything or nothing.
0646     cell_style.setAttribute("Hidden", QString::number(style.hideAll()));
0647 
0648     QColor patColor =  style.backgroundBrush().color();
0649     red = patColor.red() << 8;
0650     green = patColor.green() << 8;
0651     blue = patColor.blue() << 8;
0652 
0653     cell_style.setAttribute("PatternColor", QString::number(red, 16) + ':' + QString::number(green, 16) + ':' + QString::number(blue, 16));
0654 
0655     if (isLink)
0656         cell_style.appendChild(GetLinkStyle(gnumeric_doc));
0657 
0658     cell_style.appendChild(GetFontStyle(gnumeric_doc, cell, currentcolumn, currentrow));
0659 
0660     if (!cell.validity().isEmpty()) {
0661         cell_style.appendChild(GetValidity(gnumeric_doc, cell));
0662     }
0663 
0664     QString stringFormat;
0665 
0666     Currency currency;
0667 
0668     switch (style.formatType()) {
0669     case Format::Generic:
0670         stringFormat = "General";
0671         break;
0672     case Format::Number:
0673         stringFormat = "0.00";
0674         break;
0675     case Format::Text:
0676         stringFormat = "General";
0677         break;
0678     case Format::Money:
0679 
0680         if (!style.hasAttribute(Style::CurrencyFormat)) {
0681             stringFormat = "0.00";
0682             break;
0683         }
0684         currency = style.currency();
0685 
0686         if (currency.code().isEmpty())
0687             stringFormat = "0.00";
0688         else if (currency.code() == "$")
0689             stringFormat = "$0.00";
0690         else if (currency.code() == QString::fromUtf8("€"))
0691             stringFormat = "[$€-2]0.00";
0692         else if (currency.code() == QString::fromUtf8("£"))
0693             stringFormat = "£0.00";
0694         else if (currency.code() == QString::fromUtf8("Â¥"))
0695             stringFormat = "Â¥0.00";
0696         else
0697             stringFormat = "[$" + currency.code() + "]0.00";
0698 
0699         break;
0700     case Format::Percentage:
0701         stringFormat = "0.00%";
0702         break;
0703     case Format::Scientific:
0704         stringFormat = "0.00E+00";
0705         break;
0706     case Format::fraction_half:
0707         stringFormat = "# ?/2";
0708         break;
0709     case Format::fraction_quarter:
0710         stringFormat = "# ?/4";
0711         break;
0712     case Format::fraction_eighth:
0713         stringFormat = "# ?/8";
0714         break;
0715     case Format::fraction_sixteenth:
0716         stringFormat = "# ?/16";
0717         break;
0718     case Format::fraction_tenth:
0719         stringFormat = "# ?/10";
0720         break;
0721     case Format::fraction_hundredth:
0722         stringFormat = "# ?/100";
0723         break;
0724     case Format::fraction_one_digit:
0725         stringFormat = "# ?/?";
0726         break;
0727     case Format::fraction_two_digits:
0728         stringFormat = "# ?\?/?\?";
0729         break;
0730     case Format::fraction_three_digits:
0731         stringFormat = "# ?\?\?/?\?\?";
0732         break;
0733     case Format::Custom:
0734         stringFormat = style.customFormat();
0735         break;
0736     default:
0737         if (Format::isDate(style.formatType())) {
0738             cell.locale()->dateFormat(style.formatType());
0739         } else if (Format::isTime(style.formatType())) {
0740             cell.locale()->timeFormat(style.formatType());
0741         } else {
0742            // This is a required parameter, so let's write a sane default
0743             qWarning() << "Unhandled Format value, setting 'General' as default: " << style.formatType();
0744             stringFormat = "General";
0745         }
0746         break;
0747     }
0748     cell_style.setAttribute("Format", stringFormat);
0749 
0750     if (hasBorder(cell, currentcolumn, currentrow))
0751         cell_style.appendChild(GetBorderStyle(gnumeric_doc, cell, currentcolumn, currentrow));
0752 
0753     return cell_style;
0754 }
0755 
0756 
0757 void GNUMERICExport::addAttributeItem(QDomDocument gnumeric_doc, QDomElement attributes, const QString& type, const QString& name, bool value)
0758 {
0759     QDomElement gmr_attribute, gmr_type, gmr_name, gmr_value;
0760 
0761     gmr_attribute = gnumeric_doc.createElement("gmr:Attribute");
0762     attributes.appendChild(gmr_attribute);
0763 
0764     gmr_type = gnumeric_doc.createElement("gmr:type");
0765     gmr_type.appendChild(gnumeric_doc.createTextNode(type));
0766     gmr_attribute.appendChild(gmr_type);
0767 
0768     gmr_name = gnumeric_doc.createElement("gmr:name");
0769     gmr_name.appendChild(gnumeric_doc.createTextNode(name));
0770     gmr_attribute.appendChild(gmr_name);
0771 
0772     QString txtValue;
0773     if (value)
0774         txtValue = "true";
0775     else
0776         txtValue = "false";
0777 
0778     gmr_value = gnumeric_doc.createElement("gmr:value");
0779     gmr_value.appendChild(gnumeric_doc.createTextNode(txtValue));
0780     gmr_attribute.appendChild(gmr_value);
0781 }
0782 
0783 void GNUMERICExport::addSummaryItem(QDomDocument gnumeric_doc, QDomElement summary, const QString& name, const QString& value)
0784 {
0785     if (value.isEmpty())
0786         return;
0787     QDomElement gmr_item, gmr_name, gmr_val_string;
0788 
0789     gmr_item = gnumeric_doc.createElement("gmr:Item");
0790     summary.appendChild(gmr_item);
0791 
0792     gmr_name = gnumeric_doc.createElement("gmr:name");
0793     gmr_name.appendChild(gnumeric_doc.createTextNode(name));
0794     gmr_item.appendChild(gmr_name);
0795 
0796     gmr_val_string = gnumeric_doc.createElement("gmr:val-string");
0797     gmr_val_string.appendChild(gnumeric_doc.createTextNode(value));
0798     gmr_item.appendChild(gmr_val_string);
0799 }
0800 
0801 // The reason why we use the KoDocument* approach and not the QDomDocument
0802 // approach is because we don't want to export formulas but values !
0803 KoFilter::ConversionStatus GNUMERICExport::convert(const QByteArray& from, const QByteArray& to)
0804 {
0805     qDebug() << "Exporting GNUmeric";
0806 
0807     QDomDocument gnumeric_doc = QDomDocument();
0808 
0809     KoDocument* document = m_chain->inputDocument();
0810 
0811     if (!document)
0812         return KoFilter::StupidError;
0813 
0814     if (!qobject_cast<const Calligra::Sheets::DocBase *>(document)) {    // it's safer that way :)
0815         qWarning() << "document isn't a Calligra::Sheets::DocBase but a " << document->metaObject()->className();
0816         return KoFilter::NotImplemented;
0817     }
0818     if (to != "application/x-gnumeric" || from != "application/x-kspread") {
0819         qWarning() << "Invalid mimetypes " << to << " " << from;
0820         return KoFilter::NotImplemented;
0821     }
0822 
0823     DocBase* ksdoc = dynamic_cast<DocBase*>(document);
0824 
0825     if (ksdoc->mimeType() != "application/x-kspread") {
0826         qWarning() << "Invalid document mimetype " << ksdoc->mimeType();
0827         return KoFilter::NotImplemented;
0828     }
0829 
0830     /* This could be Made into a function */
0831 
0832     gnumeric_doc.appendChild(gnumeric_doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""));
0833 
0834     QDomElement workbook = gnumeric_doc.createElement("gmr:Workbook");
0835     workbook.setAttribute("xmlns:gmr", "http://www.gnumeric.org/v10.dtd");
0836     workbook.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
0837     workbook.setAttribute("xmlns:schemaLocation", "http://www.gnumeric.org/v8.xsd");
0838     gnumeric_doc.appendChild(workbook);
0839 
0840     /* End Made into a function */
0841 
0842     QDomElement sheets, sheet, tmp, cells, selections, cols, rows, styles, merged, margins, topMargin, leftMargin, bottomMargin, rightMargin, orientation, paper, header, footer, customSize, cellComment, objects, repeatColumns, repeatRows;
0843 
0844     KoDocumentInfo *DocumentInfo = document->documentInfo();
0845 
0846     /*
0847      * Attributes
0848      */
0849     QDomElement attributes = gnumeric_doc.createElement("gmr:Attributes");
0850     workbook.appendChild(attributes);
0851 
0852     Map *map = ksdoc->map();
0853     ApplicationSettings *appsett = map->applicationSettings();
0854     addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::show_horizontal_scrollbar", appsett->showHorizontalScrollBar());
0855     addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::show_vertical_scrollbar", appsett->showVerticalScrollBar());
0856     addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::show_notebook_tabs", appsett->showTabBar());
0857     if (appsett->completionMode() == KCompletion::CompletionAuto)
0858         addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::do_auto_completion", "true");
0859     else
0860         addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::do_auto_completion", "false");
0861     addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::is_protected", map->isProtected());
0862 
0863     /*
0864      * Document summary
0865      */
0866     QDomElement summary =  gnumeric_doc.createElement("gmr:Summary");
0867     workbook.appendChild(summary);
0868 
0869     addSummaryItem(gnumeric_doc, summary, "title", DocumentInfo->aboutInfo("title"));
0870     addSummaryItem(gnumeric_doc, summary, "company", DocumentInfo->authorInfo("company"));
0871     addSummaryItem(gnumeric_doc, summary, "author", DocumentInfo->authorInfo("creator"));
0872     addSummaryItem(gnumeric_doc, summary, "comments", DocumentInfo->aboutInfo("comments"));
0873     addSummaryItem(gnumeric_doc, summary, "keywords", DocumentInfo->aboutInfo("keyword"));
0874 
0875     addSummaryItem(gnumeric_doc, summary, "application", "KSpread");
0876 
0877     /*
0878      * Sheet name index (necessary for the gnumeric xml_sax importer)
0879      */
0880     QDomElement sheetNameIndex = gnumeric_doc.createElement("gmr:SheetNameIndex");
0881     workbook.appendChild(sheetNameIndex);
0882 
0883     for(SheetBase* table : map->sheetList()) {
0884         QDomElement sheetName = gnumeric_doc.createElement("gmr:SheetName");
0885         sheetName.appendChild(gnumeric_doc.createTextNode(table->sheetName()));
0886         sheetNameIndex.appendChild(sheetName);
0887     }
0888 
0889     /*
0890      * Area Names
0891      */
0892     /*
0893     <gmr:Names>
0894     <gmr:Name>
0895       <gmr:name>test</gmr:name>
0896       <gmr:value>Sheet2!$A$2:$D$10</gmr:value>
0897       <gmr:position>A1</gmr:position>
0898     </gmr:Name>
0899     <gmr:Name>
0900       <gmr:name>voiture</gmr:name>
0901       <gmr:value>Sheet2!$A$2:$D$8</gmr:value>
0902       <gmr:position>A1</gmr:position>
0903     </gmr:Name>
0904     </gmr:Names>
0905     */
0906     const QList<QString> namedAreas = map->namedAreaManager()->areaNames();
0907     if (namedAreas.count() > 0) {
0908         SheetBase* sheet = 0;
0909         QRect range;
0910         QDomElement areaNames = gnumeric_doc.createElement("gmr:Names");
0911         for (int i = 0; i < namedAreas.count(); ++i) {
0912             sheet = map->namedAreaManager()->sheet(namedAreas[i]);
0913             if (!sheet)
0914                 continue;
0915             range = map->namedAreaManager()->namedArea(namedAreas[i]).firstRange();
0916             QDomElement areaName = gnumeric_doc.createElement("gmr:Name");
0917             QDomElement areaNameElement = gnumeric_doc.createElement("gmr:name");
0918             areaNameElement.appendChild(gnumeric_doc.createTextNode(namedAreas[i]));
0919             areaName.appendChild(areaNameElement);
0920             QDomElement areaNameValue = gnumeric_doc.createElement("gmr:value");
0921             areaNameValue.appendChild(gnumeric_doc.createTextNode(convertRefToRange(sheet->sheetName(), range)));
0922             areaName.appendChild(areaNameValue);
0923             areaNames.appendChild(areaName);
0924             //TODO <gmr:position>A1</gmr:position> I don't know what is it.
0925         }
0926         workbook.appendChild(areaNames);
0927     }
0928 
0929 
0930     /*
0931      * Sheets
0932      */
0933     sheets = gnumeric_doc.createElement("gmr:Sheets");
0934     workbook.appendChild(sheets);
0935 
0936     QString str;
0937 
0938     View *view = ksdoc->documentPart()->views().isEmpty() ? 0 : static_cast<View*>(ksdoc->documentPart()->views().first());
0939     Canvas * canvas = 0L;
0940     QString activeTableName;
0941     if (view) {
0942         canvas = view->canvasWidget();
0943         activeTableName =  canvas->activeSheet()->sheetName();
0944     }
0945     int i = 0;
0946     int indexActiveTable = 0;
0947     for(SheetBase* btable : map->sheetList()) {
0948         Sheet *table = dynamic_cast<Sheet *>(btable);
0949         if (table->printSettings()->pageLayout().format == KoPageFormat::CustomSize) {
0950             customSize = gnumeric_doc.createElement("gmr:Geometry");
0951             customSize.setAttribute("Width", QString::number(POINT_TO_MM(table->printSettings()->pageLayout().width)));
0952             customSize.setAttribute("Height", QString::number(POINT_TO_MM(table->printSettings()->pageLayout().width)));
0953             sheets.appendChild(customSize);
0954             //<gmr:Geometry Width="768" Height="365"/>
0955         }
0956 
0957         sheet = gnumeric_doc.createElement("gmr:Sheet");
0958         sheets.appendChild(sheet);
0959 
0960         sheet.setAttribute("DisplayFormulas", table->getShowFormula() ? "true" : "false");
0961         sheet.setAttribute("HideZero", table->getHideZero() ? "true" : "false");
0962         sheet.setAttribute("HideGrid", !table->getShowGrid() ? "true" : "false");
0963         sheet.setAttribute("HideColHeader", (!appsett->showColumnHeader() ? "true" : "false"));
0964         sheet.setAttribute("HideRowHeader", (!appsett->showRowHeader() ? "true" : "false"));
0965         /* Not available in Calligra Sheets ?
0966          * sheet.setAttribute("DisplayOutlines", "true");
0967          * sheet.setAttribute("OutlineSymbolsBelow", "true");
0968          * sheet.setAttribute("OutlineSymbolsRight", "true");
0969          * sheet.setAttribute("TabColor", "");
0970          * sheet.setAttribute("TabTextColor", "");
0971          */
0972 
0973         tmp = gnumeric_doc.createElement("gmr:Name");
0974         if (table->sheetName() == activeTableName)
0975             indexActiveTable = i;
0976 
0977         tmp.appendChild(gnumeric_doc.createTextNode(table->sheetName()));
0978 
0979         sheet.appendChild(tmp);
0980 
0981         tmp = gnumeric_doc.createElement("gmr:MaxCol");
0982         tmp.appendChild(gnumeric_doc.createTextNode(QString::number(table->cellStorage()->columns())));
0983         sheet.appendChild(tmp);
0984 
0985         tmp = gnumeric_doc.createElement("gmr:MaxRow");
0986 
0987         tmp.appendChild(gnumeric_doc.createTextNode(QString::number(table->cellStorage()->rows())));
0988         sheet.appendChild(tmp);
0989 
0990         // Zoom value doesn't appear to be correct
0991         // Calligra Sheets 200% gives zoom() = 2.5, this in GNumeric = 250%
0992         tmp = gnumeric_doc.createElement("gmr:Zoom");
0993         if (view)
0994             tmp.appendChild(gnumeric_doc.createTextNode(QString::number(view->zoomHandler()->zoom())));
0995         else
0996             tmp.appendChild(gnumeric_doc.createTextNode("1.0"));
0997         sheet.appendChild(tmp);
0998 
0999         //Print Info
1000         tmp = gnumeric_doc.createElement("gmr:PrintInformation");
1001         margins = gnumeric_doc.createElement("gmr:Margins");
1002 
1003         topMargin = gnumeric_doc.createElement("gmr:top");
1004         topMargin.setAttribute("Points", QString::number(table->printSettings()->pageLayout().topMargin));
1005         topMargin.setAttribute("PrefUnit", "mm");
1006         margins.appendChild(topMargin);
1007 
1008         bottomMargin = gnumeric_doc.createElement("gmr:bottom");
1009         bottomMargin.setAttribute("Points", QString::number(table->printSettings()->pageLayout().bottomMargin));
1010         bottomMargin.setAttribute("PrefUnit", "mm");
1011         margins.appendChild(bottomMargin);
1012 
1013         leftMargin = gnumeric_doc.createElement("gmr:left");
1014         leftMargin.setAttribute("Points", QString::number(table->printSettings()->pageLayout().leftMargin));
1015         leftMargin.setAttribute("PrefUnit", "mm");
1016         margins.appendChild(leftMargin);
1017 
1018         rightMargin = gnumeric_doc.createElement("gmr:right");
1019         rightMargin.setAttribute("Points", QString::number(table->printSettings()->pageLayout().rightMargin));
1020         rightMargin.setAttribute("PrefUnit", "mm");
1021         margins.appendChild(rightMargin);
1022 
1023         tmp.appendChild(margins);
1024         sheet.appendChild(tmp);
1025 
1026         orientation = gnumeric_doc.createElement("gmr:orientation");
1027         QString orientString = table->printSettings()->pageLayout().orientation == KoPageFormat::Landscape ? "landscape" : "portrait";
1028         orientation.appendChild(gnumeric_doc.createTextNode(orientString));
1029         tmp.appendChild(orientation);
1030 
1031         //TODO for future
1032         //<gmr:repeat_top value="A1:IV5"/>
1033         //<gmr:repeat_left value="B1:D65536"/>
1034 
1035         int _tmpRepeatColumnStart = table->printSettings()->repeatedColumns().first;
1036         int _tmpRepeatColumnEnd = table->printSettings()->repeatedColumns().second;
1037         if (_tmpRepeatColumnStart != 0) {
1038             repeatColumns = gnumeric_doc.createElement("gmr:repeat_left");
1039             QString value = Cell::columnName(_tmpRepeatColumnStart) + "1:" + Cell::columnName(_tmpRepeatColumnEnd) + "65536";
1040             repeatColumns.setAttribute("value", value);
1041             tmp.appendChild(repeatColumns);
1042         }
1043         int _tmpRepeatRowStart = table->printSettings()->repeatedRows().first;
1044         int _tmpRepeatRowEnd = table->printSettings()->repeatedRows().second;
1045         if (_tmpRepeatRowStart != 0) {
1046             repeatRows = gnumeric_doc.createElement("gmr:repeat_top");
1047             QString value = 'A' + QString::number(_tmpRepeatRowStart) + ":IV" + QString::number(_tmpRepeatRowEnd);
1048             repeatRows.setAttribute("value", value);
1049             tmp.appendChild(repeatRows);
1050         }
1051 
1052         const HeaderFooter *const headerFooter = table->headerFooter();
1053         header = gnumeric_doc.createElement("gmr:Header");
1054         header.setAttribute("Left", convertVariable(headerFooter->headLeft()));
1055         header.setAttribute("Middle", convertVariable(headerFooter->headMid()));
1056         header.setAttribute("Right", convertVariable(headerFooter->headRight()));
1057         tmp.appendChild(header);
1058 
1059         footer = gnumeric_doc.createElement("gmr:Footer");
1060         footer.setAttribute("Left", convertVariable(headerFooter->footLeft()));
1061         footer.setAttribute("Middle", convertVariable(headerFooter->footMid()));
1062         footer.setAttribute("Right", convertVariable(headerFooter->footRight()));
1063         tmp.appendChild(footer);
1064 
1065         paper = gnumeric_doc.createElement("gmr:paper");
1066         paper.appendChild(gnumeric_doc.createTextNode(table->printSettings()->paperFormatString()));
1067         tmp.appendChild(paper);
1068 
1069         styles = gnumeric_doc.createElement("gmr:Styles");
1070         sheet.appendChild(styles);
1071 
1072         cells = gnumeric_doc.createElement("gmr:Cells");
1073         sheet.appendChild(cells);
1074 
1075         objects = gnumeric_doc.createElement("gmr:Objects");
1076         sheet.appendChild(objects);
1077 
1078         merged = gnumeric_doc.createElement("gmr:MergedRegions");
1079         bool mergedCells = false; // if there are no merged cells in this sheet, don't write an
1080         // empty mergedRegions to the file.
1081         // So, depending on the value of mergedCells,
1082         // the merged dom element is added or not.
1083 
1084         cols = gnumeric_doc.createElement("gmr:Cols");
1085         sheet.appendChild(cols);
1086 
1087         rows = gnumeric_doc.createElement("gmr:Rows");
1088         sheet.appendChild(rows);
1089 
1090         /*
1091           selections = gnumeric_doc.createElement("gmr:Selections");
1092           sheet.appendChild(selections);
1093         */
1094         // Ah ah ah - the document is const, but the map and table aren't. Safety: 0.
1095         // Either we get hold of Sheet::m_dctCells and apply the old method below
1096         // (for sorting) or, cleaner and already sorted, we use Sheet's API
1097         // (slower probably, though)
1098         int iMaxColumn = table->cellStorage()->columns();
1099         int iMaxRow = table->cellStorage()->rows();
1100 
1101         // this is just a bad approximation which fails for documents with less than 50 rows, but
1102         // we don't need any progress stuff there anyway :) (Werner)
1103         int value = 0;
1104         int step = iMaxRow > 50 ? iMaxRow / 50 : 1;
1105         int i = 1;
1106 
1107         /* Save selection info. */
1108 
1109         /* can't save selection anymore -- part of the view, not table */
1110         /*
1111           QDomElement selection = gnumeric_doc.createElement("gmr:Selection");
1112           QRect table_selection(table->selection());
1113 
1114           selections.appendChild(selection);
1115         */
1116         /*  <gmr:Selection startCol="3" startRow="2" endCol="3" endRow="2"/>*/
1117         /*
1118           selection.setAttribute("startCol", QString::number(table_selection.left()-1));
1119           selection.setAttribute("startRow", QString::number(table_selection.top()-1));
1120 
1121           selection.setAttribute("endCol", QString::number(table_selection.right()-1));
1122           selection.setAttribute("endRow", QString::number(table_selection.bottom()-1));
1123         */
1124         /* End selection info. */
1125 
1126 
1127         /* Start COLS */
1128         for (int col = 1; col <= table->columnFormats()->lastNonDefaultCol(); ++col) {
1129             int lastCol;
1130             if (table->columnFormats()->isDefaultCol(col, &lastCol)) {
1131                 col = lastCol;
1132                 continue;
1133             }
1134 
1135             QDomElement colinfo = gnumeric_doc.createElement("gmr:ColInfo");
1136             cols.appendChild(colinfo);
1137             colinfo.setAttribute("No", QString::number(col - 1));
1138             colinfo.setAttribute("Hidden", QString::number(table->columnFormats()->isHidden(col)));
1139             colinfo.setAttribute("Unit", QString::number(table->columnFormats()->colWidth(col)));
1140         }
1141 
1142         /* End COLS */
1143 
1144         //   <gmr:ColInfo No="1" Unit="96.75" MarginA="2" MarginB="2" HardSize="-1" Hidden="0"/>
1145 
1146         /* Start ROWS */
1147         for (int row = 1; row <= table->rowFormats()->lastNonDefaultRow(); ++row) {
1148             int lastRow;
1149             if (table->rowFormats()->isDefaultRow(row, &lastRow)) {
1150                 row = lastRow;
1151                 continue;
1152             }
1153             QDomElement rowinfo = gnumeric_doc.createElement("gmr:RowInfo");
1154             rows.appendChild(rowinfo);
1155             rowinfo.setAttribute("No", QString::number(row - 1));
1156             rowinfo.setAttribute("Hidden", QString::number(table->rowFormats()->isHidden(row)));
1157             rowinfo.setAttribute("Unit", QString::number(table->rowFormats()->rowHeight(row)));
1158         }
1159 
1160         /* End ROWS */
1161 
1162         //rl->setHeight
1163         //  colinfo.info();
1164         /*
1165           <gmr:ColInfo No="1" Unit="96.75" MarginA="2" MarginB="2" HardSize="-1" Hidden="0"/>
1166           <gmr:ColInfo No="3" Unit="113.25" MarginA="2" MarginB="2" HardSize="-1"
1167           Hidden="0"/>
1168         */
1169 
1170         /* End COLS */
1171 
1172         for (int currentrow = 1; currentrow <= iMaxRow; ++currentrow, ++i) {
1173             if (i > step) {
1174                 value += 2;
1175                 emit sigProgress(value);
1176                 i = 0;
1177             }
1178 
1179             for (int currentcolumn = 1; currentcolumn <= iMaxColumn; currentcolumn++) {
1180                 QDomElement cell_contents;
1181                 Cell cell(table, currentcolumn, currentrow);
1182 
1183                 QString text;
1184                 QDomDocument domLink;
1185                 QDomElement domRoot;
1186                 QDomNodeList childNodes;
1187 
1188                 if (!cell.isDefault() && !cell.isEmpty()) {
1189                     if (cell.isFormula()) {
1190                         QString tmp = cell.userInput();
1191                         if (tmp.contains("=="))
1192                             tmp.replace("==", "=");
1193                         text = tmp;
1194                         isLink = false;
1195                     } else if (!cell.link().isEmpty()) {
1196                         isLink = true;
1197                         isLinkBold = false;
1198                         isLinkItalic = false;
1199                         //TODO FIXME
1200                         linkUrl = cell.link();
1201                         linkText = cell.userInput();
1202 
1203                     } else {
1204                         text = cell.userInput();
1205                         isLink = false;
1206                     }
1207 #if 0
1208                     switch (cell.content()) {
1209                     case Cell::Text:
1210                         text = cell.userInput();
1211                         isLink = false;
1212                         break;
1213                     case Cell::RichText:
1214                         // hyperlinks
1215                         // Extract the cell text
1216                         isLink = true;
1217                         isLinkBold = false;
1218                         isLinkItalic = false;
1219                         domLink.setContent(cell.userInput().section("!", 1, 1));
1220 
1221                         domNode = domLink.firstChild();
1222                         domRoot = domNode.toElement();
1223                         text = domNode.toElement().text();
1224 
1225                         while (!domNode.isNull()) {
1226                             QString style;
1227                             style = domNode.toElement().tagName();
1228 
1229                             if (style == "b")
1230                                 isLinkBold = true;
1231 
1232                             if (style == "i")
1233                                 isLinkItalic = true;
1234 
1235                             domNode = domNode.firstChild();
1236                         }
1237 
1238                         //qDebug() <<"---> link, text =" << text;
1239 
1240                         linkUrl = domRoot.attribute("href");
1241                         linkText = text;
1242 
1243                         break;
1244                     case Cell::VisualFormula:
1245                         isLink = false;
1246                         text = cell.userInput(); // untested
1247                         break;
1248                     case Cell::Formula:
1249                         isLink = false;
1250                         QString tmp = cell.userInput();
1251                         if (tmp == "==")
1252                             tmp = replace("==", "=");
1253                         /* cell.calc( true ); // Incredible, cells are not calculated if the document was just opened text = cell.valueString(); */
1254                         text = tmp;
1255                         break;
1256                     }
1257 #endif
1258                 }
1259 
1260                 if (!cell.isDefault()) {
1261 
1262                     // Check if the cell is merged
1263                     // Only cells with content are interesting?
1264                     // Otherwise it can take a while to parse a large sheet
1265 
1266                     if (cell.doesMergeCells()) {
1267                         // The cell is forced to occupy other cells
1268                         QDomElement merge = gnumeric_doc.createElement("gmr:Merge");
1269 
1270                         // Set up the range
1271                         QString fromCol, toCol, fromRow, toRow;
1272                         fromCol = cell.columnName(currentcolumn);
1273                         fromRow = QString::number(currentrow);
1274                         toCol = cell.columnName(currentcolumn + cell.mergedXCells());
1275                         toRow = QString::number(currentrow + cell.mergedYCells());
1276 
1277                         merge.appendChild(gnumeric_doc.createTextNode(fromCol + fromRow + ':' + toCol + toRow));
1278                         mergedCells = true;
1279                         merged.appendChild(merge);
1280                     }
1281                     // ---
1282                     if (!cell.comment().isEmpty()) {
1283                         //<gmr:CellComment Author="" Text="cvbcvbxcvb&#10;cb&#10;xc&#10;vbxcv&#10;" ObjectBound="A1" ObjectOffset="0 0 0 0" ObjectAnchorType="17 16 17 16" Direction="17"/>
1284                         cellComment = gnumeric_doc.createElement("gmr:CellComment");
1285                         cellComment.setAttribute("Text", cell.comment());
1286                         QString sCell = QString("%1%2").arg(Cell::columnName(currentcolumn)).arg(currentrow);
1287 
1288                         cellComment.setAttribute("ObjectBound", sCell);
1289                         objects.appendChild(cellComment);
1290 
1291                     }
1292                     QDomElement gnumeric_cell = gnumeric_doc.createElement("gmr:Cell");
1293                     QDomElement cell_style;
1294 
1295                     QDomElement style_region = gnumeric_doc.createElement("gmr:StyleRegion");
1296 
1297                     cells.appendChild(gnumeric_cell);
1298 
1299                     gnumeric_cell.setAttribute("Col", QString::number(currentcolumn - 1));
1300                     gnumeric_cell.setAttribute("Row", QString::number(currentrow - 1));
1301 
1302                     /* Right now, we create a single region for each cell.. This is inefficient,
1303                      * but the implementation is quicker.. Probably later we will have to
1304                      * consolidate styles into style regions.
1305                      */
1306 
1307                     style_region.setAttribute("startCol", QString::number(currentcolumn - 1));
1308                     style_region.setAttribute("startRow", QString::number(currentrow - 1));
1309                     style_region.setAttribute("endCol", QString::number(currentcolumn - 1));
1310                     style_region.setAttribute("endRow", QString::number(currentrow - 1));
1311 
1312                     cell_style = GetCellStyle(gnumeric_doc, cell, currentcolumn, currentrow);
1313 
1314                     style_region.appendChild(cell_style);
1315 
1316                     styles.appendChild(style_region);
1317 
1318                     //cell_contents = gnumeric_doc.createElement("gmr:Content");
1319                     gnumeric_cell.appendChild(gnumeric_doc.createTextNode(text));
1320                     //gnumeric_cell.appendChild(cell_contents);
1321                 }
1322 
1323                 // Append a delimiter, but in a temp string -> if no other real cell in this line,
1324                 // then those will be dropped
1325             }
1326         }
1327 
1328         if (mergedCells)
1329             sheet.appendChild(merged);
1330     }
1331     QDomElement uidata = gnumeric_doc.createElement("gmr:UIData");
1332     uidata.setAttribute("SelectedTab", QString::number(indexActiveTable));
1333     workbook.appendChild(uidata);
1334 
1335     str = gnumeric_doc.toString();
1336 
1337     emit sigProgress(100);
1338 
1339     // Ok, now write to export file
1340 
1341     QIODevice* out = new KCompressionDevice(m_chain->outputFile(), KCompressionDevice::GZip);
1342 
1343     if (!out) {
1344         qWarning() << "No output file! Aborting!";
1345         return KoFilter::FileNotFound;
1346     }
1347 
1348     if (!out->open(QIODevice::WriteOnly)) {
1349         qWarning() << "Unable to open output file! Aborting!";
1350         delete out;
1351         return KoFilter::FileNotFound;
1352     }
1353 
1354     QTextStream streamOut(out);
1355 
1356     streamOut << str;
1357     streamOut.flush();
1358 
1359     out->close();
1360     delete out;
1361 
1362     return KoFilter::OK;
1363 }
1364 
1365 
1366 QString GNUMERICExport::convertRefToRange(const QString & table, const QRect & rect)
1367 {
1368     QPoint topLeft(rect.topLeft());
1369     QPoint bottomRight(rect.bottomRight());
1370     if (topLeft == bottomRight)
1371         return convertRefToBase(table, rect);
1372     QString s;
1373     s += table;
1374     s += "!$";
1375     s += Cell::columnName(topLeft.x());
1376     s += '$';
1377     s += QString::number(topLeft.y());
1378     s += ":$";
1379     s += Cell::columnName(bottomRight.x());
1380     s += '$';
1381     s += QString::number(bottomRight.y());
1382 
1383     return s;
1384 }
1385 
1386 
1387 QString GNUMERICExport::convertRefToBase(const QString & table, const QRect & rect)
1388 {
1389     QPoint bottomRight(rect.bottomRight());
1390 
1391     QString s;
1392     s = table;
1393     s += "!$";
1394     s += Cell::columnName(bottomRight.x());
1395     s += '$';
1396     s += QString::number(bottomRight.y());
1397 
1398     return s;
1399 }
1400 
1401 QString GNUMERICExport::convertVariable(QString headerFooter)
1402 {
1403     headerFooter.replace("<sheet>", "&[TAB]");
1404     headerFooter.replace("<date>", "&[DATE]");
1405     headerFooter.replace("<page>", "&[PAGE]");
1406     headerFooter.replace("<pages>", "&[PAGES]");
1407     headerFooter.replace("<time>", "&[TIME]");
1408     headerFooter.replace("<file>", "&[FILE]");
1409 
1410     return headerFooter;
1411 }
1412 
1413 #include "gnumericexport.moc"