1 // xlsxformat.cpp
2
3 #include <QtGlobal>
4 #include <QDataStream>
5 #include <QDebug>
6
7 #include "xlsxformat.h"
8 #include "xlsxformat_p.h"
9 #include "xlsxcolor_p.h"
10 #include "xlsxnumformatparser_p.h"
11
12 QT_BEGIN_NAMESPACE_XLSX
13
FormatPrivate()14 FormatPrivate::FormatPrivate()
15 : dirty(true)
16 , font_dirty(true), font_index_valid(false), font_index(0)
17 , fill_dirty(true), fill_index_valid(false), fill_index(0)
18 , border_dirty(true), border_index_valid(false), border_index(0)
19 , xf_index(-1), xf_indexValid(false)
20 , is_dxf_fomat(false), dxf_index(-1), dxf_indexValid(false)
21 , theme(0)
22 {
23 }
24
FormatPrivate(const FormatPrivate & other)25 FormatPrivate::FormatPrivate(const FormatPrivate &other)
26 : QSharedData(other)
27 , dirty(other.dirty), formatKey(other.formatKey)
28 , font_dirty(other.font_dirty), font_index_valid(other.font_index_valid), font_key(other.font_key), font_index(other.font_index)
29 , fill_dirty(other.fill_dirty), fill_index_valid(other.fill_index_valid), fill_key(other.fill_key), fill_index(other.fill_index)
30 , border_dirty(other.border_dirty), border_index_valid(other.border_index_valid), border_key(other.border_key), border_index(other.border_index)
31 , xf_index(other.xf_index), xf_indexValid(other.xf_indexValid)
32 , is_dxf_fomat(other.is_dxf_fomat), dxf_index(other.dxf_index), dxf_indexValid(other.dxf_indexValid)
33 , theme(other.theme)
34 , properties(other.properties)
35 {
36
37 }
38
~FormatPrivate()39 FormatPrivate::~FormatPrivate()
40 {
41
42 }
43
44 /*!
45 * \class Format
46 * \inmodule QtXlsx
47 * \brief Providing the methods and properties that are available for formatting cells in Excel.
48 */
49
50 /*!
51 * \enum Format::FontScript
52 *
53 * The enum type defines the type of font script.
54 *
55 * \value FontScriptNormal normal
56 * \value FontScriptSuper super script
57 * \value FontScriptSub sub script
58 */
59
60
61 /*!
62 * \enum Format::FontUnderline
63 *
64 * The enum type defines the type of font underline.
65 *
66 * \value FontUnderlineNone
67 * \value FontUnderlineSingle
68 * \value FontUnderlineDouble
69 * \value FontUnderlineSingleAccounting
70 * \value FontUnderlineDoubleAccounting
71 */
72
73 /*!
74 * \enum Format::HorizontalAlignment
75 *
76 * The enum type defines the type of horizontal alignment.
77 *
78 * \value AlignHGeneral
79 * \value AlignLeft
80 * \value AlignHCenter
81 * \value AlignRight
82 * \value AlignHFill
83 * \value AlignHJustify
84 * \value AlignHMerge
85 * \value AlignHDistributed
86 */
87
88 /*!
89 * \enum Format::VerticalAlignment
90 *
91 * The enum type defines the type of vertical alignment.
92 *
93 * \value AlignTop,
94 * \value AlignVCenter,
95 * \value AlignBottom,
96 * \value AlignVJustify,
97 * \value AlignVDistributed
98 */
99
100 /*!
101 * \enum Format::BorderStyle
102 *
103 * The enum type defines the type of font underline.
104 *
105 * \value BorderNone
106 * \value BorderThin
107 * \value BorderMedium
108 * \value BorderDashed
109 * \value BorderDotted
110 * \value BorderThick
111 * \value BorderDouble
112 * \value BorderHair
113 * \value BorderMediumDashed
114 * \value BorderDashDot
115 * \value BorderMediumDashDot
116 * \value BorderDashDotDot
117 * \value BorderMediumDashDotDot
118 * \value BorderSlantDashDot
119 */
120
121 /*!
122 * \enum Format::DiagonalBorderType
123 *
124 * The enum type defines the type of diagonal border.
125 *
126 * \value DiagonalBorderNone
127 * \value DiagonalBorderDown
128 * \value DiagonalBorderUp
129 * \value DiagnoalBorderBoth
130 */
131
132 /*!
133 * \enum Format::FillPattern
134 *
135 * The enum type defines the type of fill.
136 *
137 * \value PatternNone
138 * \value PatternSolid
139 * \value PatternMediumGray
140 * \value PatternDarkGray
141 * \value PatternLightGray
142 * \value PatternDarkHorizontal
143 * \value PatternDarkVertical
144 * \value PatternDarkDown
145 * \value PatternDarkUp
146 * \value PatternDarkGrid
147 * \value PatternDarkTrellis
148 * \value PatternLightHorizontal
149 * \value PatternLightVertical
150 * \value PatternLightDown
151 * \value PatternLightUp
152 * \value PatternLightTrellis
153 * \value PatternGray125
154 * \value PatternGray0625
155 * \value PatternLightGrid
156 */
157
158 /*!
159 * Creates a new invalid format.
160 */
Format()161 Format::Format()
162 {
163 //The d pointer is initialized with a null pointer
164 }
165
166 /*!
167 Creates a new format with the same attributes as the \a other format.
168 */
Format(const Format & other)169 Format::Format(const Format &other)
170 :d(other.d)
171 {
172
173 }
174
175 /*!
176 Assigns the \a other format to this format, and returns a
177 reference to this format.
178 */
operator =(const Format & other)179 Format &Format::operator =(const Format &other)
180 {
181 d = other.d;
182 return *this;
183 }
184
185 /*!
186 * Destroys this format.
187 */
~Format()188 Format::~Format()
189 {
190 }
191
192 /*!
193 * Returns the number format identifier.
194 */
numberFormatIndex() const195 int Format::numberFormatIndex() const
196 {
197 return intProperty(FormatPrivate::P_NumFmt_Id, 0);
198 }
199
200 /*!
201 * Set the number format identifier. The \a format
202 * must be a valid built-in number format identifier
203 * or the identifier of a custom number format.
204 */
setNumberFormatIndex(int format)205 void Format::setNumberFormatIndex(int format)
206 {
207 setProperty(FormatPrivate::P_NumFmt_Id, format);
208 clearProperty(FormatPrivate::P_NumFmt_FormatCode);
209 }
210
211 /*!
212 * Returns the number format string.
213 * \note for built-in number formats, this may
214 * return an empty string.
215 */
numberFormat() const216 QString Format::numberFormat() const
217 {
218 return stringProperty(FormatPrivate::P_NumFmt_FormatCode);
219 }
220
221 /*!
222 * Set number \a format.
223 * http://office.microsoft.com/en-001/excel-help/create-a-custom-number-format-HP010342372.aspx
224 */
setNumberFormat(const QString & format)225 void Format::setNumberFormat(const QString &format)
226 {
227 if (format.isEmpty())
228 return;
229 setProperty(FormatPrivate::P_NumFmt_FormatCode, format);
230 clearProperty(FormatPrivate::P_NumFmt_Id); //numFmt id must be re-generated.
231 }
232
233 /*!
234 * Returns whether the number format is probably a dateTime or not
235 */
isDateTimeFormat() const236 bool Format::isDateTimeFormat() const
237 {
238 //NOTICE:
239
240 if (hasProperty(FormatPrivate::P_NumFmt_FormatCode))
241 {
242 //Custom numFmt, so
243 //Gauss from the number string
244 return NumFormatParser::isDateTime(numberFormat());
245 }
246 else if (hasProperty(FormatPrivate::P_NumFmt_Id))
247 {
248 //Non-custom numFmt
249 int idx = numberFormatIndex();
250
251 //Is built-in date time number id?
252 if ((idx >= 14 && idx <= 22) || (idx >= 45 && idx <= 47))
253 return true;
254
255 if ((idx >= 27 && idx <= 36) || (idx >= 50 && idx <= 58)) //Used in CHS\CHT\JPN\KOR
256 return true;
257 }
258
259 return false;
260 }
261
262 /*!
263 \internal
264 Set a custom num \a format with the given \a id.
265 */
setNumberFormat(int id,const QString & format)266 void Format::setNumberFormat(int id, const QString &format)
267 {
268 setProperty(FormatPrivate::P_NumFmt_Id, id);
269 setProperty(FormatPrivate::P_NumFmt_FormatCode, format);
270 }
271
272 /*!
273 \internal
274 Called by styles to fix the numFmt
275 */
fixNumberFormat(int id,const QString & format)276 void Format::fixNumberFormat(int id, const QString &format)
277 {
278 setProperty(FormatPrivate::P_NumFmt_Id, id, 0, false);
279 setProperty(FormatPrivate::P_NumFmt_FormatCode, format, QString(), false);
280 }
281
282 /*!
283 \internal
284 Return true if the format has number format.
285 */
hasNumFmtData() const286 bool Format::hasNumFmtData() const
287 {
288 if (!d)
289 return false;
290
291 if ( hasProperty(FormatPrivate::P_NumFmt_Id) ||
292 hasProperty(FormatPrivate::P_NumFmt_FormatCode) )
293 {
294 return true;
295 }
296 return false;
297 }
298
299 /*!
300 * Return the size of the font in points.
301 */
fontSize() const302 int Format::fontSize() const
303 {
304 return intProperty(FormatPrivate::P_Font_Size);
305 }
306
307 /*!
308 * Set the \a size of the font in points.
309 */
setFontSize(int size)310 void Format::setFontSize(int size)
311 {
312 setProperty(FormatPrivate::P_Font_Size, size, 0);
313 }
314
315 /*!
316 * Return whether the font is italic.
317 */
fontItalic() const318 bool Format::fontItalic() const
319 {
320 return boolProperty(FormatPrivate::P_Font_Italic);
321 }
322
323 /*!
324 * Turn on/off the italic font based on \a italic.
325 */
setFontItalic(bool italic)326 void Format::setFontItalic(bool italic)
327 {
328 setProperty(FormatPrivate::P_Font_Italic, italic, false);
329 }
330
331 /*!
332 * Return whether the font is strikeout.
333 */
fontStrikeOut() const334 bool Format::fontStrikeOut() const
335 {
336 return boolProperty(FormatPrivate::P_Font_StrikeOut);
337 }
338
339 /*!
340 * Turn on/off the strikeOut font based on \a strikeOut.
341 */
setFontStrikeOut(bool strikeOut)342 void Format::setFontStrikeOut(bool strikeOut)
343 {
344 setProperty(FormatPrivate::P_Font_StrikeOut, strikeOut, false);
345 }
346
347 /*!
348 * Return the color of the font.
349 */
fontColor() const350 QColor Format::fontColor() const
351 {
352 if (hasProperty(FormatPrivate::P_Font_Color))
353 return colorProperty(FormatPrivate::P_Font_Color);
354 return QColor();
355 }
356
357 /*!
358 * Set the \a color of the font.
359 */
setFontColor(const QColor & color)360 void Format::setFontColor(const QColor &color)
361 {
362 setProperty(FormatPrivate::P_Font_Color, XlsxColor(color), XlsxColor());
363 }
364
365 /*!
366 * Return whether the font is bold.
367 */
fontBold() const368 bool Format::fontBold() const
369 {
370 return boolProperty(FormatPrivate::P_Font_Bold);
371 }
372
373 /*!
374 * Turn on/off the bold font based on the given \a bold.
375 */
setFontBold(bool bold)376 void Format::setFontBold(bool bold)
377 {
378 setProperty(FormatPrivate::P_Font_Bold, bold, false);
379 }
380
381 /*!
382 * Return the script style of the font.
383 */
fontScript() const384 Format::FontScript Format::fontScript() const
385 {
386 return static_cast<Format::FontScript>(intProperty(FormatPrivate::P_Font_Script));
387 }
388
389 /*!
390 * Set the script style of the font to \a script.
391 */
setFontScript(FontScript script)392 void Format::setFontScript(FontScript script)
393 {
394 setProperty(FormatPrivate::P_Font_Script, script, FontScriptNormal);
395 }
396
397 /*!
398 * Return the underline style of the font.
399 */
fontUnderline() const400 Format::FontUnderline Format::fontUnderline() const
401 {
402 return static_cast<Format::FontUnderline>(intProperty(FormatPrivate::P_Font_Underline));
403 }
404
405 /*!
406 * Set the underline style of the font to \a underline.
407 */
setFontUnderline(FontUnderline underline)408 void Format::setFontUnderline(FontUnderline underline)
409 {
410 setProperty(FormatPrivate::P_Font_Underline, underline, FontUnderlineNone);
411 }
412
413 /*!
414 * Return whether the font is outline.
415 */
fontOutline() const416 bool Format::fontOutline() const
417 {
418 return boolProperty(FormatPrivate::P_Font_Outline);
419 }
420
421 /*!
422 * Turn on/off the outline font based on \a outline.
423 */
setFontOutline(bool outline)424 void Format::setFontOutline(bool outline)
425 {
426 setProperty(FormatPrivate::P_Font_Outline, outline, false);
427 }
428
429 /*!
430 * Return the name of the font.
431 */
fontName() const432 QString Format::fontName() const
433 {
434 return stringProperty(FormatPrivate::P_Font_Name, QStringLiteral("Calibri"));
435 }
436
437 /*!
438 * Set the name of the font to \a name.
439 */
setFontName(const QString & name)440 void Format::setFontName(const QString &name)
441 {
442 setProperty(FormatPrivate::P_Font_Name, name, QStringLiteral("Calibri"));
443 }
444
445 /*!
446 * Returns a QFont object based on font data contained in the format.
447 */
font() const448 QFont Format::font() const
449 {
450 QFont font;
451 font.setFamily(fontName());
452 if (fontSize() > 0)
453 font.setPointSize(fontSize());
454 font.setBold(fontBold());
455 font.setItalic(fontItalic());
456 font.setUnderline(fontUnderline()!=FontUnderlineNone);
457 font.setStrikeOut(fontStrikeOut());
458 return font;
459 }
460
461 /*!
462 * Set the format properties from the given \a font.
463 */
setFont(const QFont & font)464 void Format::setFont(const QFont &font)
465 {
466 setFontName(font.family());
467 if (font.pointSize() > 0)
468 setFontSize(font.pointSize());
469 setFontBold(font.bold());
470 setFontItalic(font.italic());
471 setFontUnderline(font.underline() ? FontUnderlineSingle : FontUnderlineNone);
472 setFontStrikeOut(font.strikeOut());
473 }
474
475 /*!
476 * \internal
477 * When the format has font data, when need to assign a valid index for it.
478 * The index value is depend on the order <fonts > in styles.xml
479 */
fontIndexValid() const480 bool Format::fontIndexValid() const
481 {
482 if (!hasFontData())
483 return false;
484 return d->font_index_valid;
485 }
486
487 /*!
488 * \internal
489 */
fontIndex() const490 int Format::fontIndex() const
491 {
492 if (fontIndexValid())
493 return d->font_index;
494
495 return 0;
496 }
497
498 /*!
499 * \internal
500 */
setFontIndex(int index)501 void Format::setFontIndex(int index)
502 {
503 d->font_index = index;
504 d->font_index_valid = true;
505 }
506
507 /*!
508 * \internal
509 */
fontKey() const510 QByteArray Format::fontKey() const
511 {
512 if (isEmpty())
513 return QByteArray();
514
515 if (d->font_dirty) {
516 QByteArray key;
517 QDataStream stream(&key, QIODevice::WriteOnly);
518 for (int i=FormatPrivate::P_Font_STARTID; i<FormatPrivate::P_Font_ENDID; ++i) {
519 auto it = d->properties.constFind(i);
520 if (it != d->properties.constEnd())
521 stream << i << it.value();
522 };
523
524 const_cast<Format*>(this)->d->font_key = key;
525 const_cast<Format*>(this)->d->font_dirty = false;
526 }
527
528 return d->font_key;
529 }
530
531 /*!
532 \internal
533 Return true if the format has font format, otherwise return false.
534 */
hasFontData() const535 bool Format::hasFontData() const
536 {
537 if (!d)
538 return false;
539
540 for (int i=FormatPrivate::P_Font_STARTID; i<FormatPrivate::P_Font_ENDID; ++i) {
541 if (hasProperty(i))
542 return true;
543 }
544 return false;
545 }
546
547 /*!
548 * Return the horizontal alignment.
549 */
horizontalAlignment() const550 Format::HorizontalAlignment Format::horizontalAlignment() const
551 {
552 return static_cast<Format::HorizontalAlignment>(intProperty(FormatPrivate::P_Alignment_AlignH, AlignHGeneral));
553 }
554
555 /*!
556 * Set the horizontal alignment with the given \a align.
557 */
setHorizontalAlignment(HorizontalAlignment align)558 void Format::setHorizontalAlignment(HorizontalAlignment align)
559 {
560 if (hasProperty(FormatPrivate::P_Alignment_Indent)
561 &&(align != AlignHGeneral && align != AlignLeft && align != AlignRight && align != AlignHDistributed)) {
562 clearProperty(FormatPrivate::P_Alignment_Indent);
563 }
564
565 if (hasProperty(FormatPrivate::P_Alignment_ShinkToFit)
566 && (align == AlignHFill || align == AlignHJustify || align == AlignHDistributed)) {
567 clearProperty(FormatPrivate::P_Alignment_ShinkToFit);
568 }
569
570 setProperty(FormatPrivate::P_Alignment_AlignH, align, AlignHGeneral);
571 }
572
573 /*!
574 * Return the vertical alignment.
575 */
verticalAlignment() const576 Format::VerticalAlignment Format::verticalAlignment() const
577 {
578 return static_cast<Format::VerticalAlignment>(intProperty(FormatPrivate::P_Alignment_AlignV, AlignBottom));
579 }
580
581 /*!
582 * Set the vertical alignment with the given \a align.
583 */
setVerticalAlignment(VerticalAlignment align)584 void Format::setVerticalAlignment(VerticalAlignment align)
585 {
586 setProperty(FormatPrivate::P_Alignment_AlignV, align, AlignBottom);
587 }
588
589 /*!
590 * Return whether the cell text is wrapped.
591 */
textWrap() const592 bool Format::textWrap() const
593 {
594 return boolProperty(FormatPrivate::P_Alignment_Wrap);
595 }
596
597 /*!
598 * Enable the text wrap if \a wrap is true.
599 */
setTextWrap(bool wrap)600 void Format::setTextWrap(bool wrap)
601 {
602 if (wrap && hasProperty(FormatPrivate::P_Alignment_ShinkToFit))
603 clearProperty(FormatPrivate::P_Alignment_ShinkToFit);
604
605 setProperty(FormatPrivate::P_Alignment_Wrap, wrap, false);
606 }
607
608 /*!
609 * Return the text rotation.
610 */
rotation() const611 int Format::rotation() const
612 {
613 return intProperty(FormatPrivate::P_Alignment_Rotation);
614 }
615
616 /*!
617 * Set the text roation with the given \a rotation. Must be in the range [0, 180] or 255.
618 */
setRotation(int rotation)619 void Format::setRotation(int rotation)
620 {
621 setProperty(FormatPrivate::P_Alignment_Rotation, rotation, 0);
622 }
623
624 /*!
625 * Return the text indentation level.
626 */
indent() const627 int Format::indent() const
628 {
629 return intProperty(FormatPrivate::P_Alignment_Indent);
630 }
631
632 /*!
633 * Set the text indentation level with the given \a indent. Must be less than or equal to 15.
634 */
setIndent(int indent)635 void Format::setIndent(int indent)
636 {
637 if (indent && hasProperty(FormatPrivate::P_Alignment_AlignH)) {
638 HorizontalAlignment hl = horizontalAlignment();
639
640 if (hl != AlignHGeneral && hl != AlignLeft && hl!= AlignRight && hl!= AlignHJustify) {
641 setHorizontalAlignment(AlignLeft);
642 }
643 }
644
645 setProperty(FormatPrivate::P_Alignment_Indent, indent, 0);
646 }
647
648 /*!
649 * Return whether the cell is shrink to fit.
650 */
shrinkToFit() const651 bool Format::shrinkToFit() const
652 {
653 return boolProperty(FormatPrivate::P_Alignment_ShinkToFit);
654 }
655
656 /*!
657 * Turn on/off shrink to fit base on \a shink.
658 */
setShrinkToFit(bool shink)659 void Format::setShrinkToFit(bool shink)
660 {
661 if (shink && hasProperty(FormatPrivate::P_Alignment_Wrap))
662 clearProperty(FormatPrivate::P_Alignment_Wrap);
663
664 if (shink && hasProperty(FormatPrivate::P_Alignment_AlignH)) {
665 HorizontalAlignment hl = horizontalAlignment();
666 if (hl == AlignHFill || hl == AlignHJustify || hl == AlignHDistributed)
667 setHorizontalAlignment(AlignLeft);
668 }
669
670 setProperty(FormatPrivate::P_Alignment_ShinkToFit, shink, false);
671 }
672
673 /*!
674 * \internal
675 */
hasAlignmentData() const676 bool Format::hasAlignmentData() const
677 {
678 if (!d)
679 return false;
680
681 for (int i=FormatPrivate::P_Alignment_STARTID; i<FormatPrivate::P_Alignment_ENDID; ++i) {
682 if (hasProperty(i))
683 return true;
684 }
685 return false;
686 }
687
688 /*!
689 * Set the border style with the given \a style.
690 */
setBorderStyle(BorderStyle style)691 void Format::setBorderStyle(BorderStyle style)
692 {
693 setLeftBorderStyle(style);
694 setRightBorderStyle(style);
695 setBottomBorderStyle(style);
696 setTopBorderStyle(style);
697 }
698
699 /*!
700 * Sets the border color with the given \a color.
701 */
setBorderColor(const QColor & color)702 void Format::setBorderColor(const QColor &color)
703 {
704 setLeftBorderColor(color);
705 setRightBorderColor(color);
706 setTopBorderColor(color);
707 setBottomBorderColor(color);
708 }
709
710 /*!
711 * Returns the left border style
712 */
leftBorderStyle() const713 Format::BorderStyle Format::leftBorderStyle() const
714 {
715 return static_cast<BorderStyle>(intProperty(FormatPrivate::P_Border_LeftStyle));
716 }
717
718 /*!
719 * Sets the left border style to \a style
720 */
setLeftBorderStyle(BorderStyle style)721 void Format::setLeftBorderStyle(BorderStyle style)
722 {
723 setProperty(FormatPrivate::P_Border_LeftStyle, style, BorderNone);
724 }
725
726 /*!
727 * Returns the left border color
728 */
leftBorderColor() const729 QColor Format::leftBorderColor() const
730 {
731 return colorProperty(FormatPrivate::P_Border_LeftColor);
732 }
733
734 /*!
735 Sets the left border color to the given \a color
736 */
setLeftBorderColor(const QColor & color)737 void Format::setLeftBorderColor(const QColor &color)
738 {
739 setProperty(FormatPrivate::P_Border_LeftColor, XlsxColor(color), XlsxColor());
740 }
741
742 /*!
743 Returns the right border style.
744 */
rightBorderStyle() const745 Format::BorderStyle Format::rightBorderStyle() const
746 {
747 return static_cast<BorderStyle>(intProperty(FormatPrivate::P_Border_RightStyle));
748 }
749
750 /*!
751 Sets the right border style to the given \a style.
752 */
setRightBorderStyle(BorderStyle style)753 void Format::setRightBorderStyle(BorderStyle style)
754 {
755 setProperty(FormatPrivate::P_Border_RightStyle, style, BorderNone);
756 }
757
758 /*!
759 Returns the right border color.
760 */
rightBorderColor() const761 QColor Format::rightBorderColor() const
762 {
763 return colorProperty(FormatPrivate::P_Border_RightColor);
764 }
765
766 /*!
767 Sets the right border color to the given \a color
768 */
setRightBorderColor(const QColor & color)769 void Format::setRightBorderColor(const QColor &color)
770 {
771 setProperty(FormatPrivate::P_Border_RightColor, XlsxColor(color), XlsxColor());
772 }
773
774 /*!
775 Returns the top border style.
776 */
topBorderStyle() const777 Format::BorderStyle Format::topBorderStyle() const
778 {
779 return static_cast<BorderStyle>(intProperty(FormatPrivate::P_Border_TopStyle));
780 }
781
782 /*!
783 Sets the top border style to the given \a style.
784 */
setTopBorderStyle(BorderStyle style)785 void Format::setTopBorderStyle(BorderStyle style)
786 {
787 setProperty(FormatPrivate::P_Border_TopStyle, style, BorderNone);
788 }
789
790 /*!
791 Returns the top border color.
792 */
topBorderColor() const793 QColor Format::topBorderColor() const
794 {
795 return colorProperty(FormatPrivate::P_Border_TopColor);
796 }
797
798 /*!
799 Sets the top border color to the given \a color.
800 */
setTopBorderColor(const QColor & color)801 void Format::setTopBorderColor(const QColor &color)
802 {
803 setProperty(FormatPrivate::P_Border_TopColor, XlsxColor(color), XlsxColor());
804 }
805
806 /*!
807 Returns the bottom border style.
808 */
bottomBorderStyle() const809 Format::BorderStyle Format::bottomBorderStyle() const
810 {
811 return static_cast<BorderStyle>(intProperty(FormatPrivate::P_Border_BottomStyle));
812 }
813
814 /*!
815 Sets the bottom border style to the given \a style.
816 */
setBottomBorderStyle(BorderStyle style)817 void Format::setBottomBorderStyle(BorderStyle style)
818 {
819 setProperty(FormatPrivate::P_Border_BottomStyle, style, BorderNone);
820 }
821
822 /*!
823 Returns the bottom border color.
824 */
bottomBorderColor() const825 QColor Format::bottomBorderColor() const
826 {
827 return colorProperty(FormatPrivate::P_Border_BottomColor);
828 }
829
830 /*!
831 Sets the bottom border color to the given \a color.
832 */
setBottomBorderColor(const QColor & color)833 void Format::setBottomBorderColor(const QColor &color)
834 {
835 setProperty(FormatPrivate::P_Border_BottomColor, XlsxColor(color), XlsxColor());
836 }
837
838 /*!
839 Return the diagonla border style.
840 */
diagonalBorderStyle() const841 Format::BorderStyle Format::diagonalBorderStyle() const
842 {
843 return static_cast<BorderStyle>(intProperty(FormatPrivate::P_Border_DiagonalStyle));
844 }
845
846 /*!
847 Sets the diagonal border style to the given \a style.
848 */
setDiagonalBorderStyle(BorderStyle style)849 void Format::setDiagonalBorderStyle(BorderStyle style)
850 {
851 setProperty(FormatPrivate::P_Border_DiagonalStyle, style, BorderNone);
852 }
853
854 /*!
855 Returns the diagonal border type.
856 */
diagonalBorderType() const857 Format::DiagonalBorderType Format::diagonalBorderType() const
858 {
859 return static_cast<DiagonalBorderType>(intProperty(FormatPrivate::P_Border_DiagonalType));
860 }
861
862 /*!
863 Sets the diagonal border type to the given \a style
864 */
setDiagonalBorderType(DiagonalBorderType style)865 void Format::setDiagonalBorderType(DiagonalBorderType style)
866 {
867 setProperty(FormatPrivate::P_Border_DiagonalType, style, DiagonalBorderNone);
868 }
869
870 /*!
871 Returns the diagonal border color.
872 */
diagonalBorderColor() const873 QColor Format::diagonalBorderColor() const
874 {
875 return colorProperty(FormatPrivate::P_Border_DiagonalColor);
876 }
877
878 /*!
879 Sets the diagonal border color to the given \a color
880 */
setDiagonalBorderColor(const QColor & color)881 void Format::setDiagonalBorderColor(const QColor &color)
882 {
883 setProperty(FormatPrivate::P_Border_DiagonalColor, XlsxColor(color), XlsxColor());
884 }
885
886 /*!
887 \internal
888 Returns whether this format has been set valid border index.
889 */
borderIndexValid() const890 bool Format::borderIndexValid() const
891 {
892 if (!hasBorderData())
893 return false;
894 return d->border_index_valid;
895 }
896
897 /*!
898 \internal
899 Returns the border index.
900 */
borderIndex() const901 int Format::borderIndex() const
902 {
903 if (borderIndexValid())
904 return d->border_index;
905 return 0;
906 }
907
908 /*!
909 * \internal
910 */
setBorderIndex(int index)911 void Format::setBorderIndex(int index)
912 {
913 d->border_index = index;
914 d->border_index_valid = true;
915 }
916
917 /*! \internal
918 */
borderKey() const919 QByteArray Format::borderKey() const
920 {
921 if (isEmpty())
922 return QByteArray();
923
924 if (d->border_dirty) {
925 QByteArray key;
926 QDataStream stream(&key, QIODevice::WriteOnly);
927 for (int i=FormatPrivate::P_Border_STARTID; i<FormatPrivate::P_Border_ENDID; ++i) {
928 auto it = d->properties.constFind(i);
929 if (it != d->properties.constEnd())
930 stream << i << it.value();
931 };
932
933 const_cast<Format*>(this)->d->border_key = key;
934 const_cast<Format*>(this)->d->border_dirty = false;
935 }
936
937 return d->border_key;
938 }
939
940 /*!
941 \internal
942 Return true if the format has border format, otherwise return false.
943 */
hasBorderData() const944 bool Format::hasBorderData() const
945 {
946 if (!d)
947 return false;
948
949 for (int i=FormatPrivate::P_Border_STARTID; i<FormatPrivate::P_Border_ENDID; ++i) {
950 if (hasProperty(i))
951 return true;
952 }
953 return false;
954 }
955
956 /*!
957 Return the fill pattern.
958 */
fillPattern() const959 Format::FillPattern Format::fillPattern() const
960 {
961 return static_cast<FillPattern>(intProperty(FormatPrivate::P_Fill_Pattern, PatternNone));
962 }
963
964 /*!
965 Sets the fill pattern to the given \a pattern.
966 */
setFillPattern(FillPattern pattern)967 void Format::setFillPattern(FillPattern pattern)
968 {
969 setProperty(FormatPrivate::P_Fill_Pattern, pattern, PatternNone);
970 }
971
972 /*!
973 Returns the foreground color of the pattern.
974 */
patternForegroundColor() const975 QColor Format::patternForegroundColor() const
976 {
977 return colorProperty(FormatPrivate::P_Fill_FgColor);
978 }
979
980 /*!
981 Sets the foreground color of the pattern with the given \a color.
982 */
setPatternForegroundColor(const QColor & color)983 void Format::setPatternForegroundColor(const QColor &color)
984 {
985 if (color.isValid() && !hasProperty(FormatPrivate::P_Fill_Pattern))
986 setFillPattern(PatternSolid);
987 setProperty(FormatPrivate::P_Fill_FgColor, XlsxColor(color), XlsxColor());
988 }
989
990 /*!
991 Returns the background color of the pattern.
992 */
patternBackgroundColor() const993 QColor Format::patternBackgroundColor() const
994 {
995 return colorProperty(FormatPrivate::P_Fill_BgColor);
996 }
997
998 /*!
999 Sets the background color of the pattern with the given \a color.
1000 */
setPatternBackgroundColor(const QColor & color)1001 void Format::setPatternBackgroundColor(const QColor &color)
1002 {
1003 if (color.isValid() && !hasProperty(FormatPrivate::P_Fill_Pattern))
1004 setFillPattern(PatternSolid);
1005 setProperty(FormatPrivate::P_Fill_BgColor, XlsxColor(color), XlsxColor());
1006 }
1007
1008 /*!
1009 * \internal
1010 */
fillIndexValid() const1011 bool Format::fillIndexValid() const
1012 {
1013 if (!hasFillData())
1014 return false;
1015 return d->fill_index_valid;
1016 }
1017
1018 /*!
1019 * \internal
1020 */
fillIndex() const1021 int Format::fillIndex() const
1022 {
1023 if (fillIndexValid())
1024 return d->fill_index;
1025 return 0;
1026 }
1027
1028 /*!
1029 * \internal
1030 */
setFillIndex(int index)1031 void Format::setFillIndex(int index)
1032 {
1033 d->fill_index = index;
1034 d->fill_index_valid = true;
1035 }
1036
1037 /*!
1038 * \internal
1039 */
fillKey() const1040 QByteArray Format::fillKey() const
1041 {
1042 if (isEmpty())
1043 return QByteArray();
1044
1045 if (d->fill_dirty) {
1046 QByteArray key;
1047 QDataStream stream(&key, QIODevice::WriteOnly);
1048 for (int i=FormatPrivate::P_Fill_STARTID; i<FormatPrivate::P_Fill_ENDID; ++i) {
1049 auto it = d->properties.constFind(i);
1050 if (it != d->properties.constEnd())
1051 stream << i << it.value();
1052 };
1053
1054 const_cast<Format*>(this)->d->fill_key = key;
1055 const_cast<Format*>(this)->d->fill_dirty = false;
1056 }
1057
1058 return d->fill_key;
1059 }
1060
1061 /*!
1062 \internal
1063 Return true if the format has fill format, otherwise return false.
1064 */
hasFillData() const1065 bool Format::hasFillData() const
1066 {
1067 if (!d)
1068 return false;
1069
1070 for (int i=FormatPrivate::P_Fill_STARTID; i<FormatPrivate::P_Fill_ENDID; ++i) {
1071 if (hasProperty(i))
1072 return true;
1073 }
1074 return false;
1075 }
1076
1077 /*!
1078 Returns whether the hidden protection property is set to true.
1079 */
hidden() const1080 bool Format::hidden() const
1081 {
1082 return boolProperty(FormatPrivate::P_Protection_Hidden);
1083 }
1084
1085 /*!
1086 Sets the hidden protection property with the given \a hidden.
1087 */
setHidden(bool hidden)1088 void Format::setHidden(bool hidden)
1089 {
1090 setProperty(FormatPrivate::P_Protection_Hidden, hidden);
1091 }
1092
1093 /*!
1094 Returns whether the locked protection property is set to true.
1095 */
locked() const1096 bool Format::locked() const
1097 {
1098 return boolProperty(FormatPrivate::P_Protection_Locked);
1099 }
1100
1101 /*!
1102 Sets the locked protection property with the given \a locked.
1103 */
setLocked(bool locked)1104 void Format::setLocked(bool locked)
1105 {
1106 setProperty(FormatPrivate::P_Protection_Locked, locked);
1107 }
1108
1109 /*!
1110 \internal
1111 Return true if the format has protection data, otherwise return false.
1112 */
hasProtectionData() const1113 bool Format::hasProtectionData() const
1114 {
1115 if (!d)
1116 return false;
1117
1118 if (hasProperty(FormatPrivate::P_Protection_Hidden)
1119 || hasProperty(FormatPrivate::P_Protection_Locked)) {
1120 return true;
1121 }
1122 return false;
1123 }
1124
1125 /*!
1126 Merges the current format with the properties described by format \a modifier.
1127 */
mergeFormat(const Format & modifier)1128 void Format::mergeFormat(const Format &modifier)
1129 {
1130 if (!modifier.isValid())
1131 return;
1132
1133 if (!isValid()) {
1134 d = modifier.d;
1135 return;
1136 }
1137
1138 QMapIterator<int, QVariant> it(modifier.d->properties);
1139 while(it.hasNext()) {
1140 it.next();
1141 setProperty(it.key(), it.value());
1142 }
1143 }
1144
1145 /*!
1146 Returns true if the format is valid; otherwise returns false.
1147 */
isValid() const1148 bool Format::isValid() const
1149 {
1150 if (d)
1151 return true;
1152 return false;
1153 }
1154
1155 /*!
1156 Returns true if the format is empty; otherwise returns false.
1157 */
isEmpty() const1158 bool Format::isEmpty() const
1159 {
1160 if (!d)
1161 return true;
1162 return d->properties.isEmpty();
1163 }
1164
1165 /*!
1166 * \internal
1167 */
formatKey() const1168 QByteArray Format::formatKey() const
1169 {
1170 if (isEmpty())
1171 return QByteArray();
1172
1173 if (d->dirty) {
1174 QByteArray key;
1175 QDataStream stream(&key, QIODevice::WriteOnly);
1176
1177 QMapIterator<int, QVariant> i(d->properties);
1178 while (i.hasNext()) {
1179 i.next();
1180 stream<<i.key()<<i.value();
1181 }
1182
1183 d->formatKey = key;
1184 d->dirty = false;
1185 }
1186
1187 return d->formatKey;
1188 }
1189
1190 /*!
1191 * \internal
1192 * Called by QXlsx::Styles or some unittests.
1193 */
setXfIndex(int index)1194 void Format::setXfIndex(int index)
1195 {
1196 if (!d)
1197 d = new FormatPrivate;
1198 d->xf_index = index;
1199 d->xf_indexValid = true;
1200 }
1201
1202 /*!
1203 * \internal
1204 */
xfIndex() const1205 int Format::xfIndex() const
1206 {
1207 if (!d)
1208 return -1;
1209 return d->xf_index;
1210 }
1211
1212 /*!
1213 * \internal
1214 */
xfIndexValid() const1215 bool Format::xfIndexValid() const
1216 {
1217 if (!d)
1218 return false;
1219 return d->xf_indexValid;
1220 }
1221
1222 /*!
1223 * \internal
1224 * Called by QXlsx::Styles or some unittests.
1225 */
setDxfIndex(int index)1226 void Format::setDxfIndex(int index)
1227 {
1228 if (!d)
1229 d = new FormatPrivate;
1230 d->dxf_index = index;
1231 d->dxf_indexValid = true;
1232 }
1233
1234 /*!
1235 * \internal
1236 * Returns the index in the styles dxfs.
1237 */
dxfIndex() const1238 int Format::dxfIndex() const
1239 {
1240 if (!d)
1241 return -1;
1242 return d->dxf_index;
1243 }
1244
1245 /*!
1246 * \internal
1247 * Returns whether the dxf index is valid or not.
1248 */
dxfIndexValid() const1249 bool Format::dxfIndexValid() const
1250 {
1251 if (!d)
1252 return false;
1253 return d->dxf_indexValid;
1254 }
1255
1256 /*!
1257 Returns ture if the \a format is equal to this format.
1258 */
operator ==(const Format & format) const1259 bool Format::operator ==(const Format &format) const
1260 {
1261 return this->formatKey() == format.formatKey();
1262 }
1263
1264 /*!
1265 Returns ture if the \a format is not equal to this format.
1266 */
operator !=(const Format & format) const1267 bool Format::operator !=(const Format &format) const
1268 {
1269 return this->formatKey() != format.formatKey();
1270 }
1271
theme() const1272 int Format::theme() const
1273 {
1274 return d->theme;
1275 }
1276
1277 /*!
1278 * \internal
1279 */
property(int propertyId,const QVariant & defaultValue) const1280 QVariant Format::property(int propertyId, const QVariant &defaultValue) const
1281 {
1282 if (d) {
1283 auto it = d->properties.constFind(propertyId);
1284 if (it != d->properties.constEnd())
1285 return it.value();
1286 }
1287 return defaultValue;
1288 }
1289
1290 /*!
1291 * \internal
1292 */
setProperty(int propertyId,const QVariant & value,const QVariant & clearValue,bool detach)1293 void Format::setProperty(int propertyId, const QVariant &value, const QVariant &clearValue, bool detach)
1294 {
1295 if (!d)
1296 d = new FormatPrivate;
1297
1298 if (value != clearValue)
1299 {
1300 auto it = d->properties.constFind(propertyId);
1301 if (it != d->properties.constEnd() && it.value() == value)
1302 return;
1303
1304 if (detach)
1305 d.detach();
1306
1307 d->properties[propertyId] = value;
1308 }
1309 else
1310 {
1311 if (!d->properties.contains(propertyId))
1312 return;
1313
1314 if (detach)
1315 d.detach();
1316
1317 d->properties.remove(propertyId);
1318 }
1319
1320 d->dirty = true;
1321 d->xf_indexValid = false;
1322 d->dxf_indexValid = false;
1323
1324 if (propertyId >= FormatPrivate::P_Font_STARTID && propertyId < FormatPrivate::P_Font_ENDID)
1325 {
1326 d->font_dirty = true;
1327 d->font_index_valid = false;
1328 }
1329 else if (propertyId >= FormatPrivate::P_Border_STARTID && propertyId < FormatPrivate::P_Border_ENDID)
1330 {
1331 d->border_dirty = true;
1332 d->border_index_valid = false;
1333 }
1334 else if (propertyId >= FormatPrivate::P_Fill_STARTID && propertyId < FormatPrivate::P_Fill_ENDID)
1335 {
1336 d->fill_dirty = true;
1337 d->fill_index_valid = false;
1338 }
1339 }
1340
1341 /*!
1342 * \internal
1343 */
clearProperty(int propertyId)1344 void Format::clearProperty(int propertyId)
1345 {
1346 setProperty(propertyId, QVariant());
1347 }
1348
1349 /*!
1350 * \internal
1351 */
hasProperty(int propertyId) const1352 bool Format::hasProperty(int propertyId) const
1353 {
1354 if (!d)
1355 return false;
1356 return d->properties.contains(propertyId);
1357 }
1358
1359 /*!
1360 * \internal
1361 */
boolProperty(int propertyId,bool defaultValue) const1362 bool Format::boolProperty(int propertyId, bool defaultValue) const
1363 {
1364 if (!hasProperty(propertyId))
1365 return defaultValue;
1366
1367 const QVariant prop = d->properties[propertyId];
1368 if (prop.userType() != QMetaType::Bool)
1369 return defaultValue;
1370 return prop.toBool();
1371 }
1372
1373 /*!
1374 * \internal
1375 */
intProperty(int propertyId,int defaultValue) const1376 int Format::intProperty(int propertyId, int defaultValue) const
1377 {
1378 if (!hasProperty(propertyId))
1379 return defaultValue;
1380
1381 const QVariant prop = d->properties[propertyId];
1382 if (prop.userType() != QMetaType::Int)
1383 return defaultValue;
1384 return prop.toInt();
1385 }
1386
1387 /*!
1388 * \internal
1389 */
doubleProperty(int propertyId,double defaultValue) const1390 double Format::doubleProperty(int propertyId, double defaultValue) const
1391 {
1392 if (!hasProperty(propertyId))
1393 return defaultValue;
1394
1395 const QVariant prop = d->properties[propertyId];
1396 if (prop.userType() != QMetaType::Double && prop.userType() != QMetaType::Float)
1397 return defaultValue;
1398 return prop.toDouble();
1399 }
1400
1401 /*!
1402 * \internal
1403 */
stringProperty(int propertyId,const QString & defaultValue) const1404 QString Format::stringProperty(int propertyId, const QString &defaultValue) const
1405 {
1406 if (!hasProperty(propertyId))
1407 return defaultValue;
1408
1409 const QVariant prop = d->properties[propertyId];
1410 if (prop.userType() != QMetaType::QString)
1411 return defaultValue;
1412 return prop.toString();
1413 }
1414
1415 /*!
1416 * \internal
1417 */
colorProperty(int propertyId,const QColor & defaultValue) const1418 QColor Format::colorProperty(int propertyId, const QColor &defaultValue) const
1419 {
1420 if (!hasProperty(propertyId))
1421 return defaultValue;
1422
1423 const QVariant prop = d->properties[propertyId];
1424 if (prop.userType() != qMetaTypeId<XlsxColor>())
1425 return defaultValue;
1426 return qvariant_cast<XlsxColor>(prop).rgbColor();
1427 }
1428
1429 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug dbg,const Format & f)1430 QDebug operator<<(QDebug dbg, const Format &f)
1431 {
1432 dbg.nospace() << "QXlsx::Format(" << f.d->properties << ")";
1433 return dbg.space();
1434 }
1435 #endif
1436
1437 QT_END_NAMESPACE_XLSX
1438