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