75
82
// Add needed attribute to paragraph style.
77
// Note: This logic breaks down if this isn't the first string
78
// in the paragraph, or there are other strings with
79
// another colBreak later in the same paragraph.
84
// NOTE: This logic breaks down if this isn't the first string in the
85
// paragraph, or there are other strings with another colBreak
86
// later in the same paragraph.
80
87
m_odfParagraphStyle->addProperty("fo:break-before", "column", KoGenStyle::ParagraphType);
81
88
// Remove character that signaled a column break
82
89
text.remove(QChar(0xE));
85
// if it's inner paragraph, push back true
86
// this is an m_textStyles.push_back(NULL) complement if we still need the style applied
92
// if it's inner paragraph, push back true this is an
93
// m_textStyles.push_back(NULL) complement if we still need the style
87
95
m_addCompleteElement.push_back(addCompleteElement);
89
97
// Add text string to list.
90
m_textStrings.push_back(QString(text));
98
//m_textStrings.push_back(QString(text));
99
m_textStrings.append(QString(text));
92
101
// Now find out what style to associate with the string.
101
110
const wvWare::Style* msTextStyle = styles.styleByIndex(chp->istd);
102
111
Q_ASSERT(msTextStyle);
103
112
QString msTextStyleName = Conversion::styleNameString(msTextStyle->name());
104
kDebug(30513) << "text has characterstyle " << msTextStyleName;
113
kDebug(30513) << "text based on characterstyle " << msTextStyleName;
106
KoGenStyle *textStyle = m_mainStyles->styleForModification(msTextStyleName);
108
kWarning() << "Couldn't retrieve style for modification!";
115
KoGenStyle *textStyle;
111
117
bool suppresFontSize = false;
112
118
if (m_textStyles.size() == 0 && m_paragraphProperties->pap().dcs.lines > 1) {
113
119
suppresFontSize = true;
116
// Modify the character style if we detect any diff between the
117
// chp of the paragraph and the summed chp.
118
const wvWare::Style* parentStyle = styles.styleByIndex(msTextStyle->m_std->istdBase);
120
applyCharacterProperties(chp, textStyle, m_paragraphStyle, suppresFontSize);
122
// Apply any extra properties to our auto style
123
// those extra properties is the diff beteween the referenceChp and the summed chp.
124
// ReferenceCHP can be either the paragraph or a named style
125
if (msTextStyle->sti() != 65) {
126
// this is not default paragraph font
127
textStyle = new KoGenStyle(KoGenStyle::TextAutoStyle, "text");
128
if (m_inStylesDotXml) {
129
textStyle->setAutoStyleInStylesDotXml(true);
131
textStyle->setParentName(msTextStyleName);
132
//if we have a new font, process that
133
const wvWare::Word97::CHP* refChp = &msTextStyle->chp();
134
if (!refChp || refChp->ftcAscii != chp->ftcAscii) {
135
if (!fontName.isEmpty()) {
136
textStyle->addProperty(QString("style:font-name"), fontName, KoGenStyle::TextType);
138
applyCharacterProperties(chp, textStyle, msTextStyle, m_bgColor, suppresFontSize, m_combinedCharacters);
141
// Default Paragraph Font, which is handled differently
142
// Meaning we should really compare against the CHP of the paragraph
143
textStyle = new KoGenStyle(KoGenStyle::TextAutoStyle, "text");
144
if (m_inStylesDotXml) {
145
textStyle->setAutoStyleInStylesDotXml(true);
121
147
//if we have a new font, process that
122
148
const wvWare::Word97::CHP* refChp = &m_paragraphStyle->chp();
123
149
if (!refChp || refChp->ftcAscii != chp->ftcAscii) {
147
165
// Set up the paragraph style.
148
applyParagraphProperties(*m_paragraphProperties, m_odfParagraphStyle, m_paragraphStyle, m_inHeaderFooter && m_containsPageNumberField);
166
applyParagraphProperties(*m_paragraphProperties, m_odfParagraphStyle, m_paragraphStyle,
167
m_inHeaderFooter && m_containsPageNumberField, this);
169
// MS Word puts dropcap characters in its own paragraph with the
170
// rest of the text in the subsequent paragraph. On the other
171
// hand, ODF wants the whole paragraph to be one unit.
173
// So if this paragraph is only one string and we have a dropcap,
174
// then we should combine this paragraph with the next, and write
175
// them together. That means we should just return here now so
176
// that the next call to writeToFile() they will be in the same
178
if (m_dropCapStatus == IsDropCapPara) {
179
kDebug(30513) << "returning with drop cap paragraph";
180
if (m_textStrings.size()) {
181
if (m_textStyles[0] != 0) {
182
m_dropCapStyleName= m_textStyles[0]->parentName();
188
// If there is a dropcap defined, then write it to the style.
189
if (m_dropCapStatus == HasDropCapIntegrated) {
190
kDebug(30513) << "Creating drop cap style";
193
buf.open(QIODevice::WriteOnly);
194
KoXmlWriter tmpWriter(&buf, 3);
195
tmpWriter.startElement("style:drop-cap");
196
tmpWriter.addAttribute("style:lines", m_dcs_lines);
197
tmpWriter.addAttributePt("style:distance", m_dropCapDistance);
198
// We have only support for fdct=1, i.e. regular dropcaps.
199
// There is no support for fdct=2, i.e. dropcaps in the margin (ODF doesn't support this).
200
tmpWriter.addAttribute("style:length", m_dcs_fdct > 0 ? 1 : 0);
201
if (!m_dropCapStyleName.isEmpty()) {
202
tmpWriter.addAttribute("style:style-name", m_dropCapStyleName.toUtf8());
204
tmpWriter.endElement(); //style:drop-cap
207
QString contents = QString::fromUtf8(buf.buffer(), buf.buffer().size());
208
m_odfParagraphStyle->addChildElement("style:drop-cap", contents);
210
m_dropCapStatus = NoDropCap;
213
QString textStyleName;
214
//add paragraph style to the collection and its name to the content
215
kDebug(30513) << "adding paragraphStyle";
216
//add the attribute for our style in <text:p>
218
textStyleName = m_mainStyles->insert(*m_odfParagraphStyle, textStyleName);
220
//check if the paragraph is inside of an absolutely positioned frame
221
if ( !m_paragraphProperties->pap().fInTable &&
222
(m_paragraphProperties->pap().dxaAbs != 0 || m_paragraphProperties->pap().dyaAbs) )
224
KoGenStyle userStyle(KoGenStyle::GraphicAutoStyle, "graphic");
225
QString drawStyleName;
227
writer->startElement("text:p", false);
228
writer->addAttribute("text:style-name", textStyleName.toUtf8());
232
const wvWare::Word97::PAP& pap = m_paragraphProperties->pap();
234
//MS-DOC - sprmPDxaAbs - relative horizontal position to anchor
235
// (-4) - center, (-8) - right, (-12) - inside, (-16) - outside
236
if (pap.dxaAbs == -4) {
237
userStyle.addProperty("style:horizontal-pos","center");
239
else if (pap.dxaAbs == -8) {
240
userStyle.addProperty("style:horizontal-pos","right");
242
else if (pap.dxaAbs == -12) {
243
userStyle.addProperty("style:horizontal-pos","inside");
245
else if (pap.dxaAbs == -16) {
246
userStyle.addProperty("style:horizontal-pos","outside");
250
userStyle.addProperty("style:horizontal-pos","from-left");
252
//MS-DOC - sprmPDyaAbs - relative vertical position to anchor
253
// (-4) - top, (-8) - middle, (-12) - bottom, (-16) - inside,
255
if (pap.dyaAbs == -4) {
256
userStyle.addProperty("style:vertical-pos","top");
258
else if (pap.dyaAbs == -8) {
259
userStyle.addProperty("style:vertical-pos","middle");
261
else if (pap.dyaAbs == -12) {
262
userStyle.addProperty("style:vertical-pos","bottom");
264
else if (pap.dyaAbs == -16) {
265
userStyle.addProperty("style:vertical-pos","inline");
267
else if (pap.dyaAbs == -20) {
268
userStyle.addProperty("style:vertical-pos","inline");
272
userStyle.addProperty("style:vertical-pos","from-top");
274
//MS-DOC - PositionCodeOperand - anchor vertical position
275
// 0 - margin, 1 - page, 2 - paragraph
276
if (pap.pcVert == 0) {
277
userStyle.addProperty("style:vertical-rel","page-content");
279
else if (pap.pcVert == 1) {
280
userStyle.addProperty("style:vertical-rel","page");
282
else if (pap.pcVert == 2) {
283
userStyle.addProperty("style:vertical-rel","paragraph");
285
//MS-DOC - PositionCodeOperand - anchor horizontal position
286
// 0 - current column, 1 - margin, 2 - page
287
if (pap.pcHorz == 0) {
288
userStyle.addProperty("style:horizontal-rel","paragraph");
290
else if (pap.pcHorz == 1) {
291
userStyle.addProperty("style:horizontal-rel","page-content");
293
else if (pap.pcHorz == 2) {
294
userStyle.addProperty("style:horizontal-rel","page");
297
drawStyleName = "fr";
298
drawStyleName = m_mainStyles->insert(userStyle, drawStyleName);
299
writer->startElement("draw:frame");
300
writer->addAttribute("draw:style-name", drawStyleName.toUtf8());
301
writer->addAttribute("text:anchor-type", "paragraph");
303
if (pap.dxaWidth != 0) {
304
writer->addAttributePt("svg:width", (double)pap.dxaWidth/20);
306
if (pap.dyaHeight != 0) {
307
writer->addAttributePt("svg:height", (double)pap.dyaHeight/20);
309
writer->addAttributePt("svg:x", (double)dxaAbs/20);
310
writer->addAttributePt("svg:y", (double)dyaAbs/20);
311
writer->startElement("draw:text-box");
150
314
// Open paragraph or heading tag.
151
315
if (m_isHeading) {
155
319
writer->startElement("text:p", false);
158
//add paragraph style to the collection and its name to the content
159
kDebug(30513) << "adding paragraphStyle";
160
//add the attribute for our style in <text:p>
161
QString styleName("P");
162
styleName = m_mainStyles->insert(*m_odfParagraphStyle, styleName);
163
writer->addAttribute("text:style-name", styleName.toUtf8());
165
//just close the paragraph if there's no content
166
if (m_textStrings.empty()) {
167
writer->endElement(); //text:p
171
//loop through each text strings and styles (equal # of both)
172
kDebug(30513) << "writing text spans now";
173
QString oldStyleName;
174
bool startedSpan = false;
175
for (int i = 0; i < m_textStrings.size(); i++) {
176
if (m_textStyles[i] == 0) {
177
//if style is null, we have an inner paragraph and add the
178
// complete paragraph element to writer
179
//need to get const char* from the QString
180
kDebug(30513) << "complete element: " <<
181
m_textStrings[i].toLocal8Bit().constData();
182
writer->addCompleteElement(m_textStrings[i].toLocal8Bit().constData());
184
//add text style to collection
185
//put style into m_mainStyles & get its name
186
//kDebug(30513) << m_textStyles[i]->type();
188
styleName = m_mainStyles->insert(*m_textStyles[i], styleName);
190
if (oldStyleName != styleName) {
322
writer->addAttribute("text:style-name", textStyleName.toUtf8());
324
//if there's any paragraph content
325
if (!m_textStrings.isEmpty()) {
326
//Loop through each text strings and styles (equal # of both) and write
328
kDebug(30513) << "writing text spans now";
329
QString oldStyleName;
330
bool startedSpan = false;
331
for (int i = 0; i < m_textStrings.size(); i++) {
332
if (m_textStyles[i] == 0) {
191
333
if (startedSpan) {
192
334
writer->endElement(); //text:span
193
335
startedSpan = false;
195
if (styleName != "DefaultParagraphFont") {
196
writer->startElement("text:span");
197
writer->addAttribute("text:style-name", styleName.toUtf8());
200
oldStyleName = styleName;
202
//write text string to writer
203
//now I just need to write the text:span to the header tag
204
kDebug(30513) << "Writing \"" << m_textStrings[i] << "\"";
205
if (m_addCompleteElement[i] == false) {
206
writer->addTextSpan(m_textStrings[i]);
207
} else { // special case we need style applied and complete element added
338
//if style is null, we have an inner paragraph and add the
339
//complete paragraph element to writer need to get const char*
341
kDebug(30513) << "complete element: " <<
342
m_textStrings[i].toLocal8Bit().constData();
208
343
writer->addCompleteElement(m_textStrings[i].toLocal8Bit().constData());
345
//put style into m_mainStyles & get its name
347
textStyleName = m_mainStyles->insert(*m_textStyles[i], textStyleName);
348
//kDebug(30513) << m_textStyles[i]->type();
350
if (oldStyleName != textStyleName) {
352
writer->endElement(); //text:span
355
if (textStyleName != "DefaultParagraphFont") {
356
writer->startElement("text:span");
357
writer->addAttribute("text:style-name", textStyleName.toUtf8());
360
oldStyleName = textStyleName;
362
//Write text string to writer. Now I just need to write the
363
//text:span to the header tag.
364
kDebug(30513) << "Writing \"" << m_textStrings[i] << "\"";
365
if (m_addCompleteElement[i] == false) {
366
writer->addTextSpan(m_textStrings[i]);
368
//special case we need style applied and complete element added
370
writer->addCompleteElement(m_textStrings[i].toLocal8Bit().constData());
373
//delete m_textStyles[i];
212
//delete m_textStyles[i];
377
// If we have an unfinished text:span, finish it now.
379
writer->endElement(); //text:span
216
if (startedSpan) // we wrote a span of text so make sure we close the span tag
217
writer->endElement(); //text:span
219
383
//close the <text:p> or <text:h> tag we opened
220
384
writer->endElement();
386
//check if the paragraph is inside of an absolutely positioned frame
387
if ( !m_paragraphProperties->pap().fInTable &&
388
(m_paragraphProperties->pap().dxaAbs != 0 || m_paragraphProperties->pap().dyaAbs) )
390
writer->endElement(); //draw:text-box
391
writer->endElement(); //draw:frame
392
writer->endElement(); //close the <text:p>
223
396
void Paragraph::setParagraphStyle(const wvWare::Style* paragraphStyle)
330
504
style->addProperty("style:writing-mode", "lr-tb", KoGenStyle::ParagraphType);
333
if (!refPap || refPap->shd.cvBack != pap.shd.cvBack) {
334
if (pap.shd.cvBack != 0xff000000)
335
style->addProperty(QString("fo:background-color"), '#' + QString::number(pap.shd.cvBack | 0xff000000, 16).right(6).toUpper());
337
style->addProperty("fo:background-color", "transparent", KoGenStyle::ParagraphType);
507
// if there is no parent style OR the parent and child background color
508
// don't match OR parent color was invalid, childs color is valid
509
if (!refPap || refPap->shd.cvBack != pap.shd.cvBack ||
510
(refPap->shd.shdAutoOrNill && !pap.shd.shdAutoOrNill) )
513
// is the color valid? (don't compare to black - 0xff000000 !!!)
514
if (!pap.shd.shdAutoOrNill) {
515
color = '#' + QString::number(pap.shd.cvBack | 0xff000000, 16).right(6).toUpper();
516
//update the background-color information
519
color = "transparent";
521
style->addProperty("fo:background-color", color, KoGenStyle::ParagraphType);
340
524
//dxaLeft1 = first-line indent from left margin (signed, relative to dxaLeft)
444
628
style->addProperty("fo:border-right", Conversion::setBorderAttributes(pap.brcRight), KoGenStyle::ParagraphType);
631
// Drop Cap Style (DCS)
447
632
if (!refPap || refPap->dcs.fdct != pap.dcs.fdct || refPap->dcs.lines != pap.dcs.lines) {
634
kDebug(30513) << "Processing drop cap";
635
if (paragraph->m_textStrings.size() > 0)
636
kDebug(30513) << "String = """ << paragraph->m_textStrings[0] << """";
638
kDebug(30513) << "No drop cap string";
640
paragraph->m_dropCapStatus = IsDropCapPara;
641
paragraph->m_dcs_fdct = pap.dcs.fdct;
642
paragraph->m_dcs_lines = pap.dcs.lines;
643
paragraph->m_dropCapDistance = (qreal)pap.dxaFromText / (qreal)20.0;
449
647
buf.open(QIODevice::WriteOnly);
450
648
KoXmlWriter tmpWriter(&buf, 3);
451
tmpWriter.startElement("style:drop-cap");
649
tmpWriter.startElement("style:drop-cap");
452
650
tmpWriter.addAttribute("style:lines", pap.dcs.lines);
453
651
tmpWriter.addAttributePt("style:distance", (qreal)pap.dxaFromText / (qreal)20.0);
454
652
tmpWriter.addAttribute("style:length", pap.dcs.fdct > 0 ? 1 : 0);
455
653
tmpWriter.endElement();//style:drop-cap
457
656
QString contents = QString::fromUtf8(buf.buffer(), buf.buffer().size());
458
657
style->addChildElement("style:drop-cap", contents);
461
661
//TODO introduce diff for tabs too like in: if(!refPap || refPap->fKeep != pap
890
void Paragraph::setCombinedCharacters(bool isCombined)
892
m_combinedCharacters = isCombined;
895
Paragraph::DropCapStatus Paragraph::dropCapStatus() const
897
return m_dropCapStatus;
900
void Paragraph::getDropCapData(QString *string, int *type, int *lines, qreal *distance, QString *style) const
902
// As far as I can see there is only ever a single character as drop cap.
903
*string = m_textStrings.isEmpty() ? QString() : m_textStrings[0];
905
*lines = m_dcs_lines;
906
*distance = m_dropCapDistance;
907
*style = m_dropCapStyleName;
911
void Paragraph::addDropCap(QString &string, int type, int lines, qreal distance, QString style)
913
kDebug(30513) << "combining drop cap paragraph: " << string;
914
if (m_dropCapStatus == IsDropCapPara)
915
kDebug(30513) << "This paragraph already has a dropcap set!";
917
m_dropCapStatus = HasDropCapIntegrated;
919
// Get the drop cap data.
922
m_dropCapDistance = distance;
923
m_dropCapStyleName = style;
925
// Add the actual text.
926
// Here we assume that there will only be one text snippet for the drop cap.
930
kDebug(30513) << "size: " << m_textStrings.size();
931
if (m_textStrings.isEmpty()) {
932
m_textStrings.append(string);
933
KoGenStyle* style = 0;
934
m_textStyles.insert(m_textStyles.begin(), style);
936
m_textStrings[0].prepend(string);
939
m_textStrings.prepend(string);
940
KoGenStyle* style = 0;
941
m_textStyles.insert(m_textStyles.begin(), style);
945
std::vector<QString> tempStrings;
946
std::vector<const KoGenStyle*> tempStyles;
947
tempStrings.push_back(dropCapParagraph->m_textStrings[0]);
948
KoGenStyle* style = 0;
949
tempStyles.push_back(style);
951
if (dropCapParagraph->m_textStrings.size() > 0) {
952
for (uint i = 0; i < m_textStrings.size(); ++i) {
953
tempStrings.push_back(m_textStrings.[i]);
954
tempStyles.push_back(m_textStyles.[i]);
958
m_textStrings = tempStrings;
959
m_textStyles = tempStyles;
964
int Paragraph::strings() const
966
return m_textStrings.size();
969
QString Paragraph::string(int index) const
971
return m_textStrings[index];
974
QString Paragraph::createTextStyle(wvWare::SharedPtr<const wvWare::Word97::CHP> chp, const wvWare::StyleSheet& styles)
976
const wvWare::Style* msTextStyle = styles.styleByIndex(chp->istd);
977
Q_ASSERT(msTextStyle);
978
QString msTextStyleName = Conversion::styleNameString(msTextStyle->name());
979
kDebug(30513) << "text based on characterstyle " << msTextStyleName;
981
KoGenStyle *textStyle;
982
textStyle = new KoGenStyle(KoGenStyle::TextAutoStyle, "text");
983
if (m_inStylesDotXml) {
984
textStyle->setAutoStyleInStylesDotXml(true);
987
bool suppresFontSize = false;
988
if (m_paragraphProperties->pap().dcs.lines > 1) {
989
suppresFontSize = true;
991
applyCharacterProperties(chp, textStyle, m_paragraphStyle, m_bgColor, suppresFontSize, m_combinedCharacters);
993
QString textStyleName('T');
994
textStyleName = m_mainStyles->insert(*textStyle, textStyleName);
996
return textStyleName;
1000
QString Paragraph::contrastFontColor(QString name)
1005
// counting the perceptive luminance - human eye favors green color...
1006
double a = 1 - (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255;
1009
d = 0; // bright colors - black font
1011
d = 255; // dark colors - white font
1013
return QColor(d, d, d).name();