File indexing completed on 2025-07-13 10:51:48

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2003 Norbert Andres <nandres@web.de>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <opencalcstyleexport.h>
0008 
0009 #include <sheets/core/Cell.h>
0010 #include <sheets/core/Map.h>
0011 #include <sheets/core/Sheet.h>
0012 #include <sheets/core/Style.h>
0013 #include <sheets/core/StyleManager.h>
0014 
0015 #include <QDomDocument>
0016 
0017 using namespace Calligra::Sheets;
0018 
0019 OpenCalcStyles::OpenCalcStyles()
0020 {
0021 }
0022 
0023 OpenCalcStyles::~OpenCalcStyles()
0024 {
0025     while (!m_cellStyles.isEmpty()) delete m_cellStyles.takeFirst();
0026     while (!m_columnStyles.isEmpty()) delete m_columnStyles.takeFirst();
0027     while (!m_numberStyles.isEmpty()) delete m_numberStyles.takeFirst();
0028     while (!m_rowStyles.isEmpty()) delete m_rowStyles.takeFirst();
0029     while (!m_sheetStyles.isEmpty()) delete m_sheetStyles.takeFirst();
0030     while (!m_fontList.isEmpty()) delete m_fontList.takeFirst();
0031 }
0032 
0033 void OpenCalcStyles::writeStyles(QDomDocument & doc, QDomElement & autoStyles)
0034 {
0035     addColumnStyles(doc, autoStyles);
0036     addRowStyles(doc, autoStyles);
0037     addSheetStyles(doc, autoStyles);
0038     addNumberStyles(doc, autoStyles);
0039     addCellStyles(doc, autoStyles);
0040 }
0041 
0042 void OpenCalcStyles::writeFontDecl(QDomDocument & doc, QDomElement & fontDecls)
0043 {
0044     foreach(QFont * f, m_fontList) {
0045         QDomElement fontDecl = doc.createElement("style:font-decl");
0046 
0047         fontDecl.setAttribute("style:name", f->family());
0048         fontDecl.setAttribute("fo:font-family", f->family());
0049         fontDecl.setAttribute("style:font-pitch", (f->fixedPitch() ? "fixed" : "variable"));
0050 
0051         // missing:
0052         // style:font-charset="x-symbol" style:font-family-generic="swiss"
0053         // style:font-style-name= "Bold/Standard/Regular"
0054 
0055         fontDecls.appendChild(fontDecl);
0056     }
0057 }
0058 
0059 void OpenCalcStyles::addFont(QFont const & font, bool def)
0060 {
0061     if (def)
0062         m_defaultFont = font;
0063 
0064     foreach(QFont * f, m_fontList) {
0065         if (f->family() == font.family())
0066             return;
0067 
0068     }
0069 
0070     QFont * f = new QFont(font);
0071     m_fontList.append(f);
0072 }
0073 
0074 QString OpenCalcStyles::cellStyle(CellStyle const & cs)
0075 {
0076     CellStyle * t = 0;
0077     foreach(t, m_cellStyles) {
0078         if (CellStyle::isEqual(t, cs))
0079             return t->name;
0080     }
0081 
0082     t = new CellStyle();
0083     t->copyData(cs);
0084 
0085     m_cellStyles.append(t);
0086 
0087     t->name = QString("ce%1").arg(m_cellStyles.count());
0088 
0089     return t->name;
0090 }
0091 
0092 QString OpenCalcStyles::columnStyle(ColumnStyle const & cs)
0093 {
0094     ColumnStyle * t = 0;
0095     foreach(t, m_columnStyles) {
0096         if (ColumnStyle::isEqual(t, cs))
0097             return t->name;
0098     }
0099 
0100     t = new ColumnStyle();
0101     t->copyData(cs);
0102 
0103     m_columnStyles.append(t);
0104 
0105     t->name = QString("co%1").arg(m_columnStyles.count());
0106 
0107     return t->name;
0108 }
0109 
0110 QString OpenCalcStyles::numberStyle(NumberStyle const &)
0111 {
0112     return "";
0113 }
0114 
0115 QString OpenCalcStyles::rowStyle(RowStyle const & rs)
0116 {
0117     RowStyle * t = 0;
0118     foreach(t, m_rowStyles) {
0119         if (RowStyle::isEqual(t, rs))
0120             return t->name;
0121     }
0122 
0123     t = new RowStyle();
0124     t->copyData(rs);
0125 
0126     m_rowStyles.append(t);
0127 
0128     t->name = QString("ro%1").arg(m_rowStyles.count());
0129 
0130     return t->name;
0131 }
0132 
0133 QString OpenCalcStyles::sheetStyle(SheetStyle const & ts)
0134 {
0135     SheetStyle * t = 0;
0136     foreach(t, m_sheetStyles) {
0137         if (SheetStyle::isEqual(t, ts))
0138             return t->name;
0139     }
0140 
0141     t = new SheetStyle();
0142     t->copyData(ts);
0143 
0144     m_sheetStyles.append(t);
0145 
0146     t->name = QString("ta%1").arg(m_sheetStyles.count());
0147 
0148     return t->name;
0149 }
0150 
0151 QString convertPenToString(QPen const & pen)
0152 {
0153     QString s(QString("%1cm solid ").arg(pen.width() * 0.035));
0154     s += pen.color().name();
0155 
0156     return s;
0157 }
0158 
0159 void OpenCalcStyles::addCellStyles(QDomDocument & doc, QDomElement & autoStyles)
0160 {
0161 
0162     CellStyle * t = 0;
0163     foreach(t, m_cellStyles) {
0164         QDomElement ts = doc.createElement("style:style");
0165         ts.setAttribute("style:name", t->name);
0166         ts.setAttribute("style:family", "table-cell");
0167         ts.setAttribute("style:parent-style-name", "Default");
0168         if (t->numberStyle.length() > 0)
0169             ts.setAttribute("style:data-style-name", t->numberStyle);
0170 
0171         QDomElement prop = doc.createElement("style:properties");
0172 
0173         if (t->font.family() != m_defaultFont.family())
0174             prop.setAttribute("style:font-name", t->font.family());
0175 
0176         if (t->font.bold() != m_defaultFont.bold())
0177             prop.setAttribute("fo:font-weight", (t->font.bold() ? "bold" : "light"));
0178 
0179         prop.setAttribute("fo:font-size", QString("%1pt").arg(t->font.pointSize()));
0180 
0181         if (t->font.underline() != m_defaultFont.underline()) {
0182             prop.setAttribute("style:text-underline", (t->font.underline() ? "single" : "none"));
0183             if (t->font.underline())
0184                 prop.setAttribute("style:text-underline-color", "font-color");
0185         }
0186 
0187         if (t->font.italic() != m_defaultFont.italic())
0188             prop.setAttribute("fo:font-style", (t->font.italic() ? "italic" : "none"));
0189 
0190         if (t->font.strikeOut() != m_defaultFont.strikeOut())
0191             prop.setAttribute("style:text-crossing-out", (t->font.strikeOut() ? "single-line" : "none"));
0192 
0193         if (t->color.name() != "#000000")
0194             prop.setAttribute("fo:color", t->color.name());
0195 
0196         if (t->bgColor.name() != "#ffffff")
0197             prop.setAttribute("fo:background-color", t->bgColor.name());
0198 
0199         if (t->alignX != Calligra::Sheets::Style::HAlignUndefined) {
0200             QString value;
0201             if (t->alignX == Calligra::Sheets::Style::Center)
0202                 value = "center";
0203             else if (t->alignX == Calligra::Sheets::Style::Right)
0204                 value = "end";
0205             else if (t->alignX == Calligra::Sheets::Style::Left)
0206                 value = "start";
0207             prop.setAttribute("fo:text-align", value);
0208         }
0209 
0210         if (t->alignY != Calligra::Sheets::Style::Bottom)   // default in OpenCalc
0211             prop.setAttribute("fo:vertical-align", (t->alignY == Calligra::Sheets::Style::Middle ? "middle" : "top"));
0212 
0213         if (t->indent > 0.0) {
0214             prop.setAttribute("fo:margin-left", QString("%1pt").arg(t->indent));
0215             if (t->alignX == Calligra::Sheets::Style::HAlignUndefined)
0216                 prop.setAttribute("fo:text-align", "start");
0217         }
0218 
0219         if (t->wrap)
0220             prop.setAttribute("fo:wrap-option", "wrap");
0221 
0222         if (t->vertical) {
0223             prop.setAttribute("fo:direction", "ttb");
0224             prop.setAttribute("style:rotation-angle", "0");
0225         }
0226 
0227         if (t->angle != 0)
0228             prop.setAttribute("style:rotation-angle", QString::number(t->angle));
0229 
0230         if (!t->print)
0231             prop.setAttribute("style:print-content", "false");
0232 
0233         if (t->hideAll)
0234             prop.setAttribute("style:cell-protect", "hidden-and-protected");
0235         else if (t->notProtected && !t->hideFormula)
0236             prop.setAttribute("style:cell-protect", "none");
0237         else if (t->notProtected && t->hideFormula)
0238             prop.setAttribute("style:cell-protect", "formula-hidden");
0239         else if (t->hideFormula)
0240             prop.setAttribute("style:cell-protect", "protected formula-hidden");
0241         else if (!t->notProtected)
0242             prop.setAttribute("style:cell-protect", "protected");
0243 
0244 
0245         if ((t->left == t->right) && (t->left == t->top) && (t->left == t->bottom)) {
0246             if ((t->left.width() != 0) && (t->left.style() != Qt::NoPen))
0247                 prop.setAttribute("fo:border", convertPenToString(t->left));
0248         } else {
0249             if ((t->left.width() != 0) && (t->left.style() != Qt::NoPen))
0250                 prop.setAttribute("fo:border-left", convertPenToString(t->left));
0251 
0252             if ((t->right.width() != 0) && (t->right.style() != Qt::NoPen))
0253                 prop.setAttribute("fo:border-right", convertPenToString(t->right));
0254 
0255             if ((t->top.width() != 0) && (t->top.style() != Qt::NoPen))
0256                 prop.setAttribute("fo:border-top", convertPenToString(t->top));
0257 
0258             if ((t->bottom.width() != 0) && (t->bottom.style() != Qt::NoPen))
0259                 prop.setAttribute("fo:border-bottom", convertPenToString(t->bottom));
0260         }
0261 
0262         ts.appendChild(prop);
0263         autoStyles.appendChild(ts);
0264     }
0265 }
0266 
0267 void OpenCalcStyles::addColumnStyles(QDomDocument & doc, QDomElement & autoStyles)
0268 {
0269     ColumnStyle * t = 0;
0270     foreach(t, m_columnStyles) {
0271         QDomElement ts = doc.createElement("style:style");
0272         ts.setAttribute("style:name", t->name);
0273         ts.setAttribute("style:family", "table-column");
0274 
0275         QDomElement prop = doc.createElement("style:properties");
0276         if (t->breakB != ::Style::none)
0277             prop.setAttribute("fo:break-before", (t->breakB == ::Style::automatic ? "auto" : "page"));
0278         prop.setAttribute("style:column-width", QString("%1cm").arg(t->size));
0279 
0280         ts.appendChild(prop);
0281         autoStyles.appendChild(ts);
0282     }
0283 }
0284 
0285 void OpenCalcStyles::addNumberStyles(QDomDocument & /*doc*/, QDomElement & /*autoStyles*/)
0286 {
0287 }
0288 
0289 void OpenCalcStyles::addRowStyles(QDomDocument & doc, QDomElement & autoStyles)
0290 {
0291     RowStyle * t = 0;
0292     foreach(t, m_rowStyles) {
0293         QDomElement ts = doc.createElement("style:style");
0294         ts.setAttribute("style:name", t->name);
0295         ts.setAttribute("style:family", "table-row");
0296 
0297         QDomElement prop = doc.createElement("style:properties");
0298         prop.setAttribute("style:row-height", QString("%1cm").arg(t->size));
0299         if (t->breakB != ::Style::none)
0300             prop.setAttribute("fo:break-before", (t->breakB == ::Style::automatic ? "auto" : "page"));
0301 
0302         ts.appendChild(prop);
0303         autoStyles.appendChild(ts);
0304 
0305     }
0306 }
0307 
0308 void OpenCalcStyles::addSheetStyles(QDomDocument & doc, QDomElement & autoStyles)
0309 {
0310     SheetStyle * t = 0;
0311     foreach(t, m_sheetStyles) {
0312         QDomElement ts = doc.createElement("style:style");
0313         ts.setAttribute("style:name", t->name);
0314         ts.setAttribute("style:family", "table");
0315         ts.setAttribute("style:master-page-name", "Default");
0316 
0317         QDomElement prop = doc.createElement("style:properties");
0318         prop.setAttribute("table:display", (t->visible ? "true" : "false"));
0319 
0320         ts.appendChild(prop);
0321         autoStyles.appendChild(ts);
0322     }
0323 }
0324 
0325 bool SheetStyle::isEqual(SheetStyle const * const t1, SheetStyle const & t2)
0326 {
0327     if (t1->visible == t2.visible)
0328         return true;
0329 
0330     return false;
0331 }
0332 
0333 CellStyle::CellStyle()
0334         : color(Qt::black),
0335         bgColor(Qt::white),
0336         indent(-1.0),
0337         wrap(false),
0338         vertical(false),
0339         angle(0),
0340         print(true),
0341         left(Qt::black, 0, Qt::NoPen),
0342         right(Qt::black, 0, Qt::NoPen),
0343         top(Qt::black, 0, Qt::NoPen),
0344         bottom(Qt::black, 0, Qt::NoPen),
0345         hideAll(false),
0346         hideFormula(false),
0347         notProtected(false),
0348         alignX(Calligra::Sheets::Style::HAlignUndefined),
0349         alignY(Calligra::Sheets::Style::Middle)
0350 {
0351 }
0352 
0353 void CellStyle::copyData(CellStyle const & ts)
0354 {
0355     font          = ts.font;
0356     numberStyle   = ts.numberStyle;
0357     color         = ts.color;
0358     bgColor       = ts.bgColor;
0359     indent        = ts.indent;
0360     wrap          = ts.wrap;
0361     vertical      = ts.vertical;
0362     angle         = ts.angle;
0363     print         = ts.print;
0364     left          = ts.left;
0365     right         = ts.right;
0366     top           = ts.top;
0367     bottom        = ts.bottom;
0368     hideAll       = ts.hideAll;
0369     hideFormula   = ts.hideFormula;
0370     notProtected  = ts.notProtected;
0371     alignX        = ts.alignX;
0372     alignY        = ts.alignY;
0373 }
0374 
0375 bool CellStyle::isEqual(CellStyle const * const t1, CellStyle const & t2)
0376 {
0377     if ((t1->font == t2.font) && (t1->numberStyle == t2.numberStyle)
0378             && (t1->color == t2.color) && (t1->bgColor == t2.bgColor)
0379             && (t1->alignX == t2.alignX) && (t1->alignY == t2.alignY)
0380             && (t1->indent == t2.indent) && (t1->wrap == t2.wrap)
0381             && (t1->vertical == t2.vertical) && (t1->angle == t2.angle)
0382             && (t1->print == t2.print) && (t1->left == t2.left)
0383             && (t1->right == t2.right) && (t1->top == t2.top)
0384             && (t1->bottom == t2.bottom) && (t1->hideAll == t2.hideAll)
0385             && (t1->hideFormula == t2.hideFormula) && (t1->notProtected == t2.notProtected)
0386        )
0387         return true;
0388 
0389     return false;
0390 }
0391 
0392 // all except the number style
0393 void CellStyle::loadData(CellStyle & cs, const Cell& cell)
0394 {
0395     const Calligra::Sheets::Style style = cell.style();
0396     const Calligra::Sheets::Style* defaultStyle = cell.fullSheet()->fullMap()->styleManager()->defaultStyle();
0397 
0398     QFont font = style.font();
0399     if (font != defaultStyle->font())
0400         cs.font = font;
0401 
0402     QColor color = style.fontColor();
0403     if (color != defaultStyle->fontColor())
0404         cs.color   = color;
0405 
0406     QColor bgColor = style.backgroundColor();
0407     if (bgColor != defaultStyle->backgroundColor())
0408         cs.bgColor = bgColor;
0409 
0410     if (style.hasAttribute(Calligra::Sheets::Style::HorizontalAlignment))
0411         cs.alignX = style.halign();
0412 
0413     if (style.hasAttribute(Calligra::Sheets::Style::VerticalAlignment))
0414         cs.alignY = style.valign();
0415 
0416     if (style.hasAttribute(Calligra::Sheets::Style::Indentation))
0417         cs.indent = style.indentation();
0418 
0419     if (style.hasAttribute(Calligra::Sheets::Style::Angle))
0420         cs.angle  = -style.angle();
0421 
0422     if (style.hasAttribute(Calligra::Sheets::Style::MultiRow))
0423         cs.wrap   = style.wrapText();
0424 
0425     if (style.hasAttribute(Calligra::Sheets::Style::VerticalText))
0426         cs.vertical = style.verticalText();
0427 
0428     if (style.hasAttribute(Calligra::Sheets::Style::DontPrintText))
0429         cs.print = style.printText();
0430 
0431     if (style.hasAttribute(Calligra::Sheets::Style::LeftPen))
0432         cs.left  = style.leftBorderPen();
0433 
0434     if (style.hasAttribute(Calligra::Sheets::Style::RightPen))
0435         cs.right = style.rightBorderPen();
0436 
0437     if (style.hasAttribute(Calligra::Sheets::Style::TopPen))
0438         cs.top  = style.topBorderPen();
0439 
0440     if (style.hasAttribute(Calligra::Sheets::Style::BottomPen))
0441         cs.bottom  = style.bottomBorderPen();
0442 
0443     if (style.hasAttribute(Calligra::Sheets::Style::NotProtected))
0444         cs.notProtected = style.notProtected();
0445 
0446     if (style.hasAttribute(Calligra::Sheets::Style::HideAll))
0447         cs.hideAll = style.hideAll();
0448 
0449     if (style.hasAttribute(Calligra::Sheets::Style::HideFormula))
0450         cs.hideFormula = style.hideFormula();
0451 }
0452 
0453 bool NumberStyle::isEqual(NumberStyle const * const t1, NumberStyle const & t2)
0454 {
0455     if ((t1->type == t2.type) && (t1->pattern == t2.pattern))
0456         return true;
0457 
0458     return false;
0459 }
0460 
0461 void ColumnStyle::copyData(ColumnStyle const & cs)
0462 {
0463     breakB = cs.breakB;
0464     size   = cs.size;
0465 }
0466 
0467 bool ColumnStyle::isEqual(ColumnStyle const * const c1, ColumnStyle const & c2)
0468 {
0469     if ((c1->breakB == c2.breakB) && (c1->size == c2.size))
0470         return true;
0471 
0472     return false;
0473 }
0474 
0475 void RowStyle::copyData(RowStyle const & cs)
0476 {
0477     breakB = cs.breakB;
0478     size   = cs.size;
0479 }
0480 
0481 bool RowStyle::isEqual(RowStyle const * const c1, RowStyle const & c2)
0482 {
0483     if ((c1->breakB == c2.breakB) && (c1->size == c2.size))
0484         return true;
0485 
0486     return false;
0487 }