msword/conversion.cpp
1/* This file is part of the KOffice project
2 Copyright (C) 2002 Werner Trobin <trobin@kde.org>
3 Copyright (C) 2002 David Faure <faure@kde.org>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "conversion.h"
21
22#include <wv2/word97_generated.h>
23#include <wv2/functordata.h>
24#include <wv2/fields.h>
25
26#include <kdebug.h>
27#include <tqregexp.h>
28#include <tqdom.h>
29#include <tdelocale.h>
30
31TQColor Conversion::color(int number, int defaultcolor, bool defaultWhite)
32{
33 switch(number)
34 {
35 case 0:
36 if(defaultWhite)
37 return TQt::white;
38 case 1:
39 return TQt::black;
40 case 2:
41 return TQt::blue;
42 case 3:
43 return TQt::cyan;
44 case 4:
45 return TQt::green;
46 case 5:
47 return TQt::magenta;
48 case 6:
49 return TQt::red;
50 case 7:
51 return TQt::yellow;
52 case 8:
53 return TQt::white;
54 case 9:
55 return TQt::darkBlue;
56 case 10:
57 return TQt::darkCyan;
58 case 11:
59 return TQt::darkGreen;
60 case 12:
61 return TQt::darkMagenta;
62 case 13:
63 return TQt::darkRed;
64 case 14:
65 return TQt::darkYellow;
66 case 15:
67 return TQt::darkGray;
68 case 16:
69 return TQt::lightGray;
70
71 default:
72 kdDebug(30513) << "Conversion::color: unknown color: " << number << endl;
73 if(defaultcolor == -1)
74 return TQColor("black");
75 else
76 return color(defaultcolor, -1);
77 }
78}
79
80int Conversion::fillPatternStyle( int ipat )
81{
82 // See $TQTDIR/doc/html/qbrush.html#setStyle
83 switch( ipat ) {
84 case 0: // Automatic (Apparently it means Solid from background color instead of foreground)
85 case 1: // Solid
86 return TQt::SolidPattern;
87 case 2: // 5%
88 case 35: // 2.5 Percent
89 case 36: // 7.5 Percent
90 return TQt::Dense7Pattern;
91 case 3: // 10%
92 case 37: // 12.5 Percent
93 case 38: // 15 Percent
94 case 39: // 17.5 Percent
95 case 4: // 20%
96 return TQt::Dense6Pattern;
97 case 40: // 22.5 Percent
98 case 5: // 25%
99 case 41: // 27.5 Percent
100 case 6: // 30%
101 case 42: // 32.5 Percent
102 case 43: // 35 Percent
103 case 44: // 37.5 Percent
104 case 7: // 40%
105 return TQt::Dense5Pattern;
106 case 45: // 42.5 Percent
107 case 46: // 45 Percent
108 case 47: // 47.5 Percent
109 case 8: // 50%
110 case 48: // 52.5 Percent
111 case 49: // 55 Percent
112 return TQt::Dense4Pattern;
113 case 50: // 57.5 Percent
114 case 9: // 60%
115 case 51: // 62.5 Percent
116 case 52: // 65 Percent
117 case 53: // 67.5 Percent
118 case 10: // 70%
119 case 54: // 72.5 Percent
120 return TQt::Dense3Pattern;
121 case 11: // 75%
122 case 55: // 77.5 Percent
123 case 12: // 80%
124 case 56: // 82.5 Percent
125 case 57: // 85 Percent
126 case 58: // 87.5 Percent
127 case 13: // 90%
128 return TQt::Dense2Pattern;
129 case 59: // 92.5 Percent
130 case 60: // 95 Percent
131 case 61: // 97.5 Percent
132 case 62: // 97 Percent
133 return TQt::Dense1Pattern;
134 case 14: // Dark Horizontal
135 case 20: // Horizontal
136 return TQt::HorPattern;
137 case 15: // Dark Vertical
138 case 21: // Vertical
139 return TQt::VerPattern;
140 case 16: // Dark Forward Diagonal
141 case 22: // Forward Diagonal
142 return TQt::FDiagPattern;
143 case 17: // Dark Backward Diagonal
144 case 23: // Backward Diagonal
145 return TQt::BDiagPattern;
146 case 18: // Dark Cross
147 case 24: // Cross
148 return TQt::CrossPattern;
149 case 19: // Dark Diagonal Cross
150 case 25: // Diagonal Cross
151 return TQt::DiagCrossPattern;
152 default:
153 kdWarning(30513) << "Unhandled undocumented SHD ipat value: " << ipat << endl;
154 return TQt::NoBrush;
155 }
156}
157
158
159int Conversion::ditheringToGray( int ipat, bool* ok )
160{
161 *ok = true; // optimistic ;)
162 switch( ipat ) {
163 case 2: // 5%
164 return 255 - tqRound(0.05 * 255);
165 case 35: // 2.5 Percent
166 return 255 - tqRound(0.025 * 255);
167 case 36: // 7.5 Percent
168 return 255 - tqRound(0.075 * 255);
169 case 3: // 10%
170 return 255 - tqRound(0.1 * 255);
171 case 37: // 12.5 Percent
172 return 255 - tqRound(0.125 * 255);
173 case 38: // 15 Percent
174 return 255 - tqRound(0.15 * 255);
175 case 39: // 17.5 Percent
176 return 255 - tqRound(0.175 * 255);
177 case 4: // 20%
178 return 255 - tqRound(0.2 * 255);
179 case 40: // 22.5 Percent
180 return 255 - tqRound(0.225 * 255);
181 case 5: // 25%
182 return 255 - tqRound(0.25 * 255);
183 case 41: // 27.5 Percent
184 return 255 - tqRound(0.275 * 255);
185 case 6: // 30%
186 return 255 - tqRound(0.3 * 255);
187 case 42: // 32.5 Percent
188 return 255 - tqRound(0.325 * 255);
189 case 43: // 35 Percent
190 return 255 - tqRound(0.35 * 255);
191 case 44: // 37.5 Percent
192 return 255 - tqRound(0.375 * 255);
193 case 7: // 40%
194 return 255 - tqRound(0.4 * 255);
195 case 45: // 42.5 Percent
196 return 255 - tqRound(0.425 * 255);
197 case 46: // 45 Percent
198 return 255 - tqRound(0.45 * 255);
199 case 47: // 47.5 Percent
200 return 255 - tqRound(0.475 * 255);
201 case 8: // 50%
202 return 255 - tqRound(0.5 * 255);
203 case 48: // 52.5 Percent
204 return 255 - tqRound(0.525 * 255);
205 case 49: // 55 Percent
206 return 255 - tqRound(0.55 * 255);
207 case 50: // 57.5 Percent
208 return 255 - tqRound(0.575 * 255);
209 case 9: // 60%
210 return 255 - tqRound(0.6 * 255);
211 case 51: // 62.5 Percent
212 return 255 - tqRound(0.625 * 255);
213 case 52: // 65 Percent
214 return 255 - tqRound(0.65 * 255);
215 case 53: // 67.5 Percent
216 return 255 - tqRound(0.675 * 255);
217 case 10: // 70%
218 return 255 - tqRound(0.7 * 255);
219 case 54: // 72.5 Percent
220 return 255 - tqRound(0.725 * 255);
221 case 11: // 75%
222 return 255 - tqRound(0.75 * 255);
223 case 55: // 77.5 Percent
224 return 255 - tqRound(0.775 * 255);
225 case 12: // 80%
226 return 255 - tqRound(0.8 * 255);
227 case 56: // 82.5 Percent
228 return 255 - tqRound(0.825 * 255);
229 case 57: // 85 Percent
230 return 255 - tqRound(0.85 * 255);
231 case 58: // 87.5 Percent
232 return 255 - tqRound(0.875 * 255);
233 case 13: // 90%
234 return 255 - tqRound(0.9 * 255);
235 case 59: // 92.5 Percent
236 return 255 - tqRound(0.925 * 255);
237 case 60: // 95 Percent
238 return 255 - tqRound(0.95 * 255);
239 case 61: // 97.5 Percent
240 return 255 - tqRound(0.975 * 255);
241 case 62: // 97 Percent
242 return 255 - tqRound(0.97 * 255);
243 default:
244 *ok = false;
245 return 0;
246 }
247}
248
249TQString Conversion::alignment( int jc ) {
250 TQString value( "left" );
251 if ( jc == 1 )
252 value = "center";
253 else if ( jc == 2 )
254 value = "right";
255 else if ( jc == 3 )
256 value = "justify";
257 return value;
258}
259
260TQString Conversion::lineSpacing( const wvWare::Word97::LSPD& lspd )
261{
262 TQString value( "0" );
263 if ( lspd.fMultLinespace == 1 )
264 {
265 // This will be e.g. 1.5 for a 1.5 linespacing.
266 float proportionalLineSpacing = (float)lspd.dyaLine / 240.0;
267 if ( TQABS(proportionalLineSpacing - 1.5) <= 0.25 ) // close to 1.5?
268 value = "oneandhalf";
269 else if ( proportionalLineSpacing > 1.75) // close to 2.0, or more?
270 value = "double";
271 }
272 else if ( lspd.fMultLinespace == 0 )
273 {
274 // see sprmPDyaLine in generator_wword8.htm
275 //float value = TQABS((float)lspd.dyaLine / 20.0); // twip -> pt
276 // lspd.dyaLine > 0 means "at least", < 0 means "exactly"
277 // "at least" is now possible in kword, but here it's the size of the whole
278 // line, not the spacing between the line (!)
279 // To convert between the two, we'd need to find out the height of the
280 // highest character in the line, and substract it from the value..... Ouch.
281 // Better implement line-height-at-least like OOo has.
282 }
283 else
284 kdWarning(30513) << "Unhandled LSPD::fMultLinespace value: " << lspd.fMultLinespace << endl;
285 return value;
286}
287
288void Conversion::setColorAttributes( TQDomElement& element, int ico, const TQString& prefix, bool defaultWhite )
289{
290 TQColor color = Conversion::color( ico, -1, defaultWhite );
291 element.setAttribute( prefix.isNull() ? "red" : prefix+"Red", color.red() );
292 element.setAttribute( prefix.isNull() ? "blue" : prefix+"Blue", color.blue() );
293 element.setAttribute( prefix.isNull() ? "green" : prefix+"Green", color.green() );
294}
295
296void Conversion::setBorderAttributes( TQDomElement& borderElement, const wvWare::Word97::BRC& brc, const TQString& prefix )
297{
298 setColorAttributes( borderElement, brc.cv, prefix, false );
299
300 borderElement.setAttribute( prefix.isNull() ? "width" : prefix+"Width",
301 (double)brc.dptLineWidth / 8.0 );
302
303 TQString style = "0"; // KWord: solid
304 switch ( brc.brcType ) {
305 case 0: // none
306 Q_ASSERT( brc.dptLineWidth == 0 ); // otherwise kword will show a border!
307 break;
308 case 7: // dash large gap
309 case 22: // dash small gap
310 style = "1"; // KWord: dashes
311 break;
312 case 6: // dot
313 style = "2";
314 break;
315 case 8: // dot dash
316 style = "3";
317 break;
318 case 9: // dot dot dash
319 style = "4";
320 break;
321 case 3: // double
322 style = "5";
323 break;
324 case 1: // single
325 default:
326 // if a fancy unsupported border is specified -> better a normal border than none
327 // (so we keep the default value, "0", for "solid single line".
328 break;
329 }
330 borderElement.setAttribute( prefix.isNull() ? "style" : prefix+"Style", style );
331 // We ignore brc.dptSpace (spacing), brc.fShadow (shadow), and brc.fFrame (?)
332}
333
334int Conversion::numberFormatCode( int nfc )
335{
336 switch ( nfc )
337 {
338 case 1: // upper case roman
339 return 5;
340 case 2: // lower case roman
341 return 4;
342 case 3: // upper case letter
343 return 3;
344 case 4: // lower case letter
345 return 2;
346 case 5: // arabic with a trailing dot (added by writeCounter)
347 case 6: // numbered (one, two, three) - not supported by KWord
348 case 7: // ordinal (first, second, third) - not supported by KWord
349 case 22: // leading zero (01-09, 10-99, 100-...) - not supported by KWord
350 case 0: // arabic
351 return 1;
352 }
353 kdWarning(30513) << k_funcinfo << "Unknown NFC: " << nfc << endl;
354 return 1;
355}
356
357int Conversion::headerTypeToFrameInfo( unsigned char type )
358{
359 switch (type) {
360 case wvWare::HeaderData::HeaderEven:
361 return 2;
362 case wvWare::HeaderData::HeaderOdd:
363 return 3;
364 case wvWare::HeaderData::FooterEven:
365 return 5;
366 case wvWare::HeaderData::FooterOdd:
367 return 6;
368 case wvWare::HeaderData::HeaderFirst:
369 return 1;
370 case wvWare::HeaderData::FooterFirst:
371 return 4;
372 }
373 return 0;
374}
375
376TQString Conversion::headerTypeToFramesetName( unsigned char type )
377{
378 switch (type) {
379 case wvWare::HeaderData::HeaderEven:
380 return i18n("Even Pages Header");
381 case wvWare::HeaderData::HeaderOdd:
382 return i18n("Odd Pages Header");
383 case wvWare::HeaderData::FooterEven:
384 return i18n("Even Pages Footer");
385 case wvWare::HeaderData::FooterOdd:
386 return i18n("Odd Pages Footer");
387 case wvWare::HeaderData::HeaderFirst:
388 return i18n("First Page Header");
389 case wvWare::HeaderData::FooterFirst:
390 return i18n("First Page Footer");
391 }
392 return TQString();
393}
394
395bool Conversion::isHeader( unsigned char type )
396{
397 switch (type) {
398 case wvWare::HeaderData::HeaderEven:
399 case wvWare::HeaderData::HeaderOdd:
400 case wvWare::HeaderData::HeaderFirst:
401 return true;
402 }
403 return false;
404}
405
406int Conversion::headerMaskToHType( unsigned char mask )
407{
408 bool hasFirst = ( mask & wvWare::HeaderData::HeaderFirst );
409 // Odd is always there. We have even!=odd only if Even is there too.
410 bool hasEvenOdd = ( mask & wvWare::HeaderData::HeaderEven );
411 //kdDebug(30513) << k_funcinfo << " hasEvenOdd=" << hasEvenOdd << endl;
412 if ( hasFirst )
413 return hasEvenOdd ? 1 : 2;
414 return hasEvenOdd ? 3 : 0;
415}
416
417int Conversion::headerMaskToFType( unsigned char mask )
418{
419 bool hasFirst = ( mask & wvWare::HeaderData::FooterFirst );
420 bool hasEvenOdd = ( mask & wvWare::HeaderData::FooterEven );
421 // Odd is always there. We have even!=odd only if Even is there too.
422 kdDebug(30513) << k_funcinfo << " hasEvenOdd=" << hasEvenOdd << endl;
423 if ( hasFirst )
424 return hasEvenOdd ? 1 : 2;
425 return hasEvenOdd ? 3 : 0;
426}
427
428int Conversion::fldToFieldType( const wvWare::FLD* fld )
429{
430 // assume unhandled
431 int m_fieldType = -1;
432
433 // sanity check
434 if( !fld ) return -1;
435
436 switch( fld->flt )
437 {
438 case 15: m_fieldType = 10; break; // title
439 case 17: m_fieldType = 2; break; // author
440 case 18: m_fieldType = -1; break; // keywords (unhandled)
441 case 19: m_fieldType = 11; break; // comments (unhandled)
442 case 21: m_fieldType = -1; break; // createdate (unhandled)
443 case 22: m_fieldType = -1; break; // savedate (unhandled)
444 case 23: m_fieldType = -1; break; // printdate (unhandled)
445 case 25: m_fieldType = -1; break; // edittime (unhandled)
446 case 29: m_fieldType = 0; break; // filename (unhandled)
447 case 32: m_fieldType = -1; break; // time (unhandled)
448 case 60: m_fieldType = 2; break; // username <-> KWord's author name
449 case 61: m_fieldType = 16; break; // userinitials <-> KWord's author initial)
450 case 62: m_fieldType = -1; break; // useraddress (unhandled)
451 default: m_fieldType = -1; break;
452 }
453
454 if( m_fieldType < 0 )
455 kdDebug(30513) << "unhandled field: fld.ftl: " << (int)fld->flt << endl;
456
457 return m_fieldType;
458}