1 /* This file is part of the KDE project
2 Copyright (C) 2001 Enno Bartels <ebartels@nwn.de>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library 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 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. 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 "applixspreadimport.h"
21
22 #include <QMessageBox>
23 #include <QStringList>
24 #include <QRegExp>
25 #include <QList>
26 #include <QTextStream>
27 #include <QByteArray>
28 #include <kdebug.h>
29 #include <math.h>
30 #include <KoFilterChain.h>
31 #include <kpluginfactory.h>
32 #include <sheets/Util.h>
33
34 K_PLUGIN_FACTORY_WITH_JSON(APPLIXSPREADImportFactory, "calligra_filter_applixspread2kspread.json",
35 registerPlugin<APPLIXSPREADImport>();)
36
37
APPLIXSPREADImport(QObject * parent,const QVariantList &)38 APPLIXSPREADImport::APPLIXSPREADImport(QObject *parent, const QVariantList&)
39 : KoFilter(parent)
40 {
41 }
42
nextLine(QTextStream & stream)43 QString APPLIXSPREADImport::nextLine(QTextStream & stream)
44 {
45 if (!m_nextPendingLine.isNull()) {
46 const QString s = m_nextPendingLine;
47 m_nextPendingLine.clear();
48 return s;
49 }
50
51 QString s = stream.readLine();
52 m_instep += s.length();
53 if (m_instep > m_stepsize) {
54 m_instep = 0;
55 m_progress += 2;
56 emit sigProgress(m_progress);
57 }
58 return s;
59 }
60
61 struct t_mycolor {
62 int r;
63 int g;
64 int b;
65
66 int c;
67 int m;
68 int y;
69 int k;
70 };
71
72 struct t_rc {
73 QStringList tabname;
74 QStringList rc;
75 };
76
77 // Store shared formula definitions
78 struct t_sharedFormula {
79 int origRow;
80 int origColumn;
81 QString formula;
82 };
83
convert(const QByteArray & from,const QByteArray & to)84 KoFilter::ConversionStatus APPLIXSPREADImport::convert(const QByteArray& from, const QByteArray& to)
85 {
86
87 if (to != "application/x-kspread" || from != "application/x-applix-spreadsheet")
88 return KoFilter::NotImplemented;
89
90 QFile in(m_chain->inputFile());
91 if (!in.open(QIODevice::ReadOnly)) {
92 kError(30502) << "Unable to open input file!" << endl;
93 in.close();
94 return KoFilter::FileNotFound;
95 }
96
97 QString str;
98 QList<t_mycolor*> mcol;
99
100 str += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
101 "<!DOCTYPE spreadsheet>\n"
102 "<spreadsheet mime=\"application/x-kspread\" editor=\"KSpread\" >\n"
103 " <paper format=\"A4\" orientation=\"Portrait\" >\n"
104 " <borders right=\"20\" left=\"20\" bottom=\"20\" top=\"20\" />\n"
105 " <head/>\n"
106 " <foot/>\n"
107 " </paper>\n"
108 // str += " <locale positivePrefixCurrencySymbol=\"True\" negativeMonetarySignPosition=\"1\" negativePrefixCurrencySymbol=\"True\" fracDigits=\"2\" thousandsSeparator=\" \" dateFormat=\"%A, %e. %B %Y\" timeFormat=\"%H:%M:%S\" monetaryDecimalSymbol=\",\" weekStartsMonday=\"True\" currencySymbol=\"DM\" negativeSign=\"-\" positiveSign=\"\" positiveMonetarySignPosition=\"1\" decimalSymbol=\",\" monetaryThousandsSeparator=\" \" dateFormatShort=\"%d.%m.%Y\" />\n";
109 " <map markerColumn=\"1\" activeTable=\"Table1\" markerRow=\"1\" >\n";
110 // str += " <table columnnumber=\"0\" borders=\"0\" hide=\"0\" hidezero=\"0\" firstletterupper=\"0\" grid=\"1\" formular=\"0\" lcmode=\"0\" name=\"Tabelle1\" >\n";
111
112
113 // QTextStream
114 QTextStream stream(&in);
115 m_stepsize = in.size() / 50;
116 m_instep = 0;
117 m_progress = 0;
118 int pos;
119 QString tabctr ; // Tab control (current tab name)
120 QStringList typefacetab;
121 QHash<QString, t_sharedFormula> sharedFormulas;
122
123 t_rc my_rc;
124
125
126
127 /**************************************************************************
128 * Read header *
129 **************************************************************************/
130 if (! readHeader(stream)) return KoFilter::StupidError;
131
132 while (!stream.atEnd()) {
133 // Read one line
134 QString mystr = nextLine(stream);
135
136 kDebug() << "INPUT :" << mystr;
137
138
139 /**********************************************************************
140 * Looking for the colormap *
141 **********************************************************************/
142 if (mystr.startsWith("COLORMAP")) {
143 readColormap(stream, mcol);
144 }
145
146 /**********************************************************************
147 * Looking for the typeface table *
148 **********************************************************************/
149 else if (mystr.startsWith("TYPEFACE TABLE")) {
150 readTypefaceTable(stream, typefacetab);
151 }
152
153 /**********************************************************************
154 * Looking for some View-Information *
155 **********************************************************************/
156 else if (mystr.startsWith("View Start, Name:")) {
157 readView(stream, mystr, my_rc);
158 }
159
160
161 /**********************************************************************
162 * Detect ( at the first place of the Line *
163 **********************************************************************/
164 else if (mystr[0] == '(') {
165
166 // Delete '('
167 mystr.remove(0, 1);
168
169 // Remember length of the string
170 if (mystr.length() >= 80 - 1) {
171 //kDebug() << " Line >= 80 chars";
172 bool ok = true;
173 do {
174 QString mystrn = nextLine(stream);
175 if (mystrn[0] == ' ') {
176 mystrn.remove(0, 1);
177 mystr += mystrn;
178 } else {
179 m_nextPendingLine = mystrn;
180 ok = false;
181 }
182 } while (ok);
183 kDebug() << " Long line -> new input line:" << mystr;
184 }
185
186 // Search for ')'
187 pos = mystr.indexOf(')');
188 QString typestr = mystr.left(pos);
189
190 // Delete typeformat info incl. Space
191 mystr.remove(0, pos + 1);
192
193 // At this point mystr looks like " A!E15: 10"
194 Q_ASSERT(mystr.startsWith(' '));
195
196 // Extract table number/name
197 pos = mystr.indexOf('!');
198
199 // Copy tabnumber information
200 QString tabnostr = mystr.left(pos).mid(1);
201
202 // Delete tabnumber information
203 mystr.remove(0, pos + 1);
204
205 // At this point mystr looks like "E15: 10"
206 pos = 0;
207 while (mystr[pos].isLetter()) {
208 ++pos;
209 }
210 const QString cellcolstr = mystr.mid(0, pos);
211 // Transform ascii column to int column
212 const int icol = translateColumnNumber(cellcolstr);
213
214 int endPos = pos;
215 while (mystr[endPos].isDigit()) {
216 ++endPos;
217 }
218
219 const QString rowstr = mystr.mid(pos, endPos - pos);
220 bool ok;
221 const int irow = rowstr.toInt(&ok);
222 Q_ASSERT(ok);
223
224 // OK, what do we have now?
225 const QChar contentType = mystr.at(endPos);
226
227 // Delete cellnumber information
228 mystr.remove(0, endPos + 1);
229 if (mystr.startsWith(' ')) {
230 mystr.remove(0, 1);
231 }
232
233 // ';' // first instance (definition) of a shared formula
234 // '.' // instance (usage) of a shared formula
235 // ':' // simple value
236
237 if (contentType == ';' || contentType == '.') {
238 // Skip the value
239 int pos = 0;
240 while (!mystr.at(pos).isSpace()) {
241 ++pos;
242 }
243 while (mystr.at(pos).isSpace()) {
244 ++pos;
245 }
246 kDebug() << "Skipping value" << mystr.mid(0, pos);
247 mystr.remove(0, pos);
248
249 if (contentType == ';') {
250 if (mystr.at(0) == '+')
251 mystr[0] = '=';
252 Q_ASSERT(mystr.at(0) == '=');
253 }
254 }
255
256 // Replace part for this characters: <, >, &
257 mystr.replace(QRegExp("&"), "&");
258 mystr.replace(QRegExp("<"), "<");
259 mystr.replace(QRegExp(">"), ">");
260
261
262 // Replace part for Applix Characters
263 bool foundSpecialCharakter;
264
265 do {
266 // initialize
267 foundSpecialCharakter = false;
268
269 pos = mystr.indexOf('^');
270
271 // is there a special character ?
272 if (pos > -1) {
273 // i have found a special character !
274 foundSpecialCharakter = true;
275
276 // translate the applix special character
277 const QChar newchar = specCharfind(mystr[pos+1], mystr[pos+2]);
278
279 // replace the character
280 mystr.replace(pos, 3, newchar);
281 }
282
283 } while (foundSpecialCharakter == true);
284
285
286 // examine the typestring
287 // split typestring in 3 parts by an |
288
289 const int pos1 = typestr.indexOf('|');
290 const int pos2 = typestr.lastIndexOf('|');
291 const QString typeFormStr = typestr.left(pos1);
292 const QString typeCharStr = typestr.mid(pos1 + 1, pos2 - pos1 - 1);
293 const QString typeCellStr = typestr.right(typestr.length() - pos2 - 1);
294
295 // Is it a new table
296 if (tabctr != tabnostr) {
297 // is it not the first table
298 if (!(tabctr.isNull())) str += " </table>\n";
299
300 str += " <table columnnumber=\"0\" borders=\"0\" hide=\"0\" hidezero=\"0\" firstletterupper=\"0\" grid=\"1\" formular=\"0\" lcmode=\"0\" name=\"" +
301 tabnostr +
302 "\" >\n";
303
304 tabctr = tabnostr;
305
306 // Searching for the rowcol part and adding to the hole string
307 pos = my_rc.tabname.indexOf(tabnostr);
308 if (pos > -1) str += my_rc.rc[pos];
309 }
310
311 //kDebug()<<" Data : Text :"<<mystr<<" tab :"<<tabnostr<<""<< cellnostr <<"" <<ccol<<"" << irow<<""<< typeFormStr<<"" <<typeCharStr<<"" <<typeCellStr;
312
313 /********************************************************************
314 * Support for shared formulas *
315 ********************************************************************/
316
317 if (contentType == ';') {
318
319 mystr = convertFormula(mystr);
320
321 const QString formulaRefLine = nextLine(stream); // "Formula: 358"
322 kDebug() << "shared formula: next line is" << formulaRefLine;
323 if (!formulaRefLine.startsWith("Formula: ")) {
324 kError() << "Missing formula ID after" << mystr;
325 } else {
326 const QString key = formulaRefLine.mid(9);
327 t_sharedFormula sf;
328 sf.origColumn = icol;
329 sf.origRow = irow;
330 sf.formula = mystr;
331 sharedFormulas.insert(key, sf);
332 }
333 } else if (contentType == '.') {
334 const QString key = mystr;
335 const t_sharedFormula sf = sharedFormulas.value(key);
336
337 // adjust the formula: if it came from C1, with =A1+B1,
338 // and we're now in C3, then it needs to become =A3+B3, just like copy/paste would do.
339 mystr = Calligra::Sheets::Util::adjustFormulaReference(sf.formula, sf.origRow, sf.origColumn, irow, icol);
340 }
341
342 /********************************************************************
343 * examine character format String, split it up in basic parts *
344 ********************************************************************/
345 int bold = 0, italic = 0, underline = 0, fontsize = 12, fontnr = -1;
346 int fg = -1; // fg = foregound
347
348 const QStringList typeCharList = typeCharStr.split(',', QString::SkipEmptyParts);
349 Q_FOREACH(const QString& typeChar, typeCharList) {
350 // Output
351 kDebug() << "typeChar: " << typeChar;
352
353 if (typeChar == "B") {
354 kDebug() << " bold";
355 bold = 1;
356 } else if (typeChar == "I") {
357 kDebug() << " = italic";
358 italic = 1;
359 } else if (typeChar == "U") {
360 kDebug() << " = underline";
361 underline = 1;
362 } else if (typeChar.startsWith("FG")) {
363 fg = typeChar.mid(2).toInt();
364 kDebug() << " = Colornr" << fg;
365 } else if (typeChar.startsWith("TF")) {
366 fontnr = typeChar.mid(2).toInt();
367 kDebug() << " = Font :" << fontnr << "" << typefacetab[fontnr];
368 } else if (typeChar.startsWith('P')) {
369 fontsize = typeChar.mid(1).toInt();
370 kDebug() << " = Fontsize" << fontsize;
371 } else {
372 kDebug() << " = ??? Unknown typeChar:" << typeChar;
373 }
374 }
375 kDebug();
376
377
378 /********************************************************************
379 * examine pos format String, split it up in basic parts *
380 ********************************************************************/
381 int align = 0, valign = 0;
382
383 const QStringList typeFormList = typeFormStr.split(',', QString::SkipEmptyParts);
384 Q_FOREACH(const QString& typeFormat, typeFormList) {
385 // Grep horizontal alignment
386 if (typeFormat == "1") {
387 kDebug() << " = left align";
388 align = 1; // left
389 } else if (typeFormat == "2") {
390 kDebug() << " = right align";
391 align = 3; // right
392 } else if (typeFormat == "3") {
393 kDebug() << " = center align";
394 align = 2; // center
395 }
396
397 // Grep vertical alignment
398 else if (typeFormat == "VT") {
399 kDebug() << " = top valign";
400 valign = 1; // top
401 } else if (typeFormat == "VC") {
402 kDebug() << " = center valign";
403 valign = 0; // center - default (2)
404 } else if (typeFormat == "VB") {
405 kDebug() << " = bottom valign";
406 valign = 3; // bottom
407 } else {
408 kDebug() << " = ??? unknown typeFormat" << typeFormat;
409 }
410 }
411
412
413 /********************************************************************
414 * examine cell format String, split it up in basic parts *
415 ********************************************************************/
416 int topPenWidth = 0, bottomPenWidth = 0, leftPenWidth = 0, rightPenWidth = 0, fg_bg = -1;
417 int topPenStyle = 0, bottomPenStyle = 0, leftPenStyle = 0, rightPenStyle = 0;
418 int brushstyle = 0, brushcolor = 1;
419 int topbrushstyle = 0, topbrushcolor = 1, topfg_bg = 1;
420 int leftbrushstyle = 0, leftbrushcolor = 1, leftfg_bg = 1;
421 int rightbrushstyle = 0, rightbrushcolor = 1, rightfg_bg = 1;
422 int bottombrushstyle = 0, bottombrushcolor = 1, bottomfg_bg = 1;
423
424 const QStringList typeCellList = typeCellStr.split(',', QString::SkipEmptyParts);
425 Q_FOREACH(/*can't use const QString&*/ QString typeCell, typeCellList) {
426
427 if (typeCell[0] == 'T') {
428 kDebug() << " = top";
429 transPenFormat(typeCell, &topPenWidth, &topPenStyle);
430
431 if (typeCell.length() > 2) {
432 typeCell.remove(0, 2);
433 filterSHFGBG(typeCell, &topbrushstyle, &topbrushcolor, &topfg_bg);
434 }
435
436 }
437
438 else if (typeCell[0] == 'B') {
439 kDebug() << " = bottom";
440 transPenFormat(typeCell, &bottomPenWidth, &bottomPenStyle);
441
442 if (typeCell.length() > 2) {
443 typeCell.remove(0, 2);
444 filterSHFGBG(typeCell, &bottombrushstyle, &bottombrushcolor, &bottomfg_bg);
445 }
446 }
447
448 else if (typeCell[0] == 'L') {
449 kDebug() << " = left";
450 transPenFormat(typeCell, &leftPenWidth, &leftPenStyle);
451
452 if (typeCell.length() > 2) {
453 typeCell.remove(0, 2);
454 filterSHFGBG(typeCell, &leftbrushstyle, &leftbrushcolor, &leftfg_bg);
455 }
456 }
457
458 else if (typeCell[0] == 'R') {
459 kDebug() << " = right";
460 transPenFormat(typeCell, &rightPenWidth, &rightPenStyle);
461
462 if (typeCell.length() > 2) {
463 typeCell.remove(0, 2);
464 filterSHFGBG(typeCell, &rightbrushstyle, &rightbrushcolor, &rightfg_bg);
465 }
466 }
467
468 else if ((typeCell.startsWith("SH")) || (typeCell.startsWith("FG")) ||
469 (typeCell.startsWith("BG"))) {
470 kDebug() << " =";
471 filterSHFGBG(typeCell, &brushstyle, &fg_bg, &brushcolor);
472 }
473
474 else {
475 kDebug() << " = ??? unknown typeCell" << typeCell;
476 }
477
478 }
479
480
481
482
483
484 QString col;
485
486 // create kspread fileformat output
487 str += " <cell row=\"" + QString::number(irow) + "\""
488 " column=\"" + QString::number(icol) + "\">\n";
489 if (bold == 1 || italic == 1 || underline == 1 ||
490 align != 0 || valign != 0 ||
491 topPenStyle != 0 || bottomPenStyle != 0 ||
492 leftPenStyle != 0 || rightPenStyle != 0 || fg != -1 || fg_bg != -1 ||
493 fontsize != 12 || brushstyle != 0 || fontnr != -1) {
494 str += " <format";
495 if (brushstyle != 0) {
496 str += " brushstyle=\"" + QString::number(brushstyle) + "\" "
497 " brushcolor=\"" +
498 writeColor(mcol.at(brushcolor)) +
499 "\"";
500 }
501
502 if (align != 0) str += " align=\"" + QString::number(align) + "\" ";
503 if (valign != 0) str += " alignY=\"" + QString::number(valign) + "\" ";
504 if (fg_bg != -1) {
505 str += " bgcolor=\"" +
506 writeColor(mcol.at(fg_bg)) +
507 "\" ";
508 }
509 str += ">\n";
510
511 // Font color
512 if (fg != -1) {
513 str += " <pen width=\"0\" style=\"1\" color=\"" +
514 writeColor(mcol.at(fg)) +
515 "\" />\n";
516 }
517
518 // Left border
519 if (leftPenWidth > 0) {
520 str += " <left-border>\n";
521 col = writeColor(mcol.at(leftfg_bg));
522 writePen(str, leftPenWidth, leftPenStyle, col);
523 str += " </left-border>\n";
524 }
525
526 // Right border
527 if (rightPenWidth > 0) {
528 str += " <right-border>\n";
529 col = writeColor(mcol.at(rightfg_bg));
530 writePen(str, rightPenWidth, rightPenStyle, col);
531 str += " </right-border>\n";
532 }
533
534 // Bottom border
535 if (bottomPenWidth > 0) {
536 str += " <bottom-border>\n";
537 col = writeColor(mcol.at(bottomfg_bg));
538 writePen(str, bottomPenWidth, bottomPenStyle, col);
539 str += " </bottom-border>\n";
540 }
541
542 // Top border
543 if (topPenWidth > 0) {
544 str += " <top-border>\n";
545 col = writeColor(mcol.at(topfg_bg));
546 writePen(str, topPenWidth, topPenStyle, col);
547 str += " </top-border>\n";
548 }
549
550 // Font (size and family)
551 if ((fontsize != 12) || (fontnr != -1)) {
552 str += " <font ";
553 // Fontsize
554 if (fontsize != 12) {
555 str += "size=\"" +
556 QString::number(fontsize) +
557 "\" ";
558 }
559 // Fontfamily
560 if (fontnr != -1) {
561 str += "family=\"" +
562 typefacetab[fontnr].toLatin1() +
563 "\" ";
564 }
565 str += "weight=\"0\"";
566
567 if (italic == 1) str += " italic=\"yes\"";
568 if (bold == 1) str += " bold=\"yes\"";
569 if (underline == 1) str += " underline=\"yes\"";
570
571 str += " />\n";
572 }
573 str += " </format>\n";
574 }
575 str += " <text>" + mystr + "</text>\n"
576 " </cell>\n";
577 }
578
579 }
580 emit sigProgress(100);
581
582 str += " </table>\n"
583 " </map>\n"
584 "</spreadsheet>\n";
585 // str += "</DOC>\n";
586
587 kDebug() << "Text" << str;
588
589 KoStoreDevice* out = m_chain->storageFile("root", KoStore::Write);
590
591 if (!out) {
592 kError(38000/*30502*/) << "Unable to open output file!" << endl;
593 in.close();
594 return KoFilter::StorageCreationError;
595 }
596
597 QByteArray cstring = str.toUtf8();
598 out->write(cstring, cstring.length());
599
600 in.close();
601 return KoFilter::OK;
602 }
603
604
605
606
607 /******************************************************************************
608 * function: specCharfind *
609 ******************************************************************************/
610 QChar
specCharfind(QChar a,QChar b)611 APPLIXSPREADImport::specCharfind(QChar a, QChar b)
612 {
613 QChar chr;
614
615 if ((a == 'n') && (b == 'p')) chr = 0x00DF; // 'ß';
616
617
618 else if ((a == 'n') && (b == 'c')) chr = 0x00D2; // 'Ò';
619 else if ((a == 'p') && (b == 'c')) chr = 0x00F2; // 'ò';
620
621 else if ((a == 'n') && (b == 'd')) chr = 0x00D3; // 'Ó';
622 else if ((a == 'p') && (b == 'd')) chr = 0x00F3; // 'ó';
623
624 else if ((a == 'n') && (b == 'e')) chr = 0x00D4; // 'Ô';
625 else if ((a == 'p') && (b == 'e')) chr = 0x00F4; // 'ô';
626
627 else if ((a == 'n') && (b == 'f')) chr = 0x00D5; // 'Õ';
628 else if ((a == 'p') && (b == 'f')) chr = 0x00F5; // 'õ';
629
630 else if ((a == 'n') && (b == 'g')) chr = 0x00D6; // 'Ö';
631 else if ((a == 'p') && (b == 'g')) chr = 0x00F6; // 'ö';
632
633
634
635 else if ((a == 'n') && (b == 'j')) chr = 0x00D9; // 'Ù';
636 else if ((a == 'p') && (b == 'j')) chr = 0x00F9; // 'ù';
637
638 else if ((a == 'n') && (b == 'k')) chr = 0x00DA; // 'Ú';
639 else if ((a == 'p') && (b == 'k')) chr = 0x00FA; // 'ú';
640
641 else if ((a == 'n') && (b == 'l')) chr = 0x00DB; // 'Û';
642 else if ((a == 'p') && (b == 'l')) chr = 0x00FB; // 'û';
643
644 else if ((a == 'n') && (b == 'm')) chr = 0x00DC; // 'Ü';
645 else if ((a == 'p') && (b == 'm')) chr = 0x00FC; // 'ü';
646
647
648
649 else if ((a == 'm') && (b == 'a')) chr = 0x00C0; // 'À';
650 else if ((a == 'o') && (b == 'a')) chr = 0x00E0; // 'à';
651
652 else if ((a == 'm') && (b == 'b')) chr = 0x00C1; // 'Á';
653 else if ((a == 'o') && (b == 'b')) chr = 0x00E1; // 'á';
654
655 else if ((a == 'm') && (b == 'c')) chr = 0x00C2; // 'Â';
656 else if ((a == 'o') && (b == 'c')) chr = 0x00E2; // 'â';
657
658 else if ((a == 'm') && (b == 'd')) chr = 0x00C3; // 'Ã';
659 else if ((a == 'o') && (b == 'd')) chr = 0x00E3; // 'ã';
660
661 else if ((a == 'm') && (b == 'e')) chr = 0x00C4; // 'Ä';
662 else if ((a == 'o') && (b == 'e')) chr = 0x00E4; // 'ä';
663
664 else if ((a == 'm') && (b == 'f')) chr = 0x00C5; // 'Å';
665 else if ((a == 'o') && (b == 'f')) chr = 0x00E5; // 'å';
666
667 else if ((a == 'm') && (b == 'g')) chr = 0x00C6; // 'Æ';
668 else if ((a == 'o') && (b == 'g')) chr = 0x00E6; // 'æ';
669
670
671
672 else if ((a == 'm') && (b == 'i')) chr = 0x00C8; // 'È';
673 else if ((a == 'o') && (b == 'i')) chr = 0x00E8; // 'è';
674
675 else if ((a == 'm') && (b == 'j')) chr = 0x00C9; // 'É';
676 else if ((a == 'o') && (b == 'j')) chr = 0x00E9; // 'é';
677
678 else if ((a == 'm') && (b == 'k')) chr = 0x00CA; // 'Ê';
679 else if ((a == 'o') && (b == 'k')) chr = 0x00EA; // 'ê';
680
681 else if ((a == 'm') && (b == 'l')) chr = 0x00CB; // 'Ë';
682 else if ((a == 'o') && (b == 'l')) chr = 0x00EB; // 'ë';
683
684
685
686 else if ((a == 'm') && (b == 'm')) chr = 0x00CC; // 'Ì';
687 else if ((a == 'o') && (b == 'm')) chr = 0x00EC; // 'ì';
688
689 else if ((a == 'm') && (b == 'n')) chr = 0x00CD; // 'Í';
690 else if ((a == 'o') && (b == 'n')) chr = 0x00ED; // 'í';
691
692 else if ((a == 'm') && (b == 'o')) chr = 0x00CE; // 'Î';
693 else if ((a == 'o') && (b == 'o')) chr = 0x00EE; // 'î';
694
695 else if ((a == 'm') && (b == 'p')) chr = 0x00CF; // 'Ï';
696 else if ((a == 'o') && (b == 'p')) chr = 0x00EF; // 'ï';
697
698
699 else if ((a == 'n') && (b == 'b')) chr = 0x00D1; // 'Ñ';
700 else if ((a == 'p') && (b == 'b')) chr = 0x00F1; // 'ñ';
701
702
703 else if ((a == 'k') && (b == 'c')) chr = 0x00A2; // '¢';
704 else if ((a == 'k') && (b == 'j')) chr = 0x00A9; // '©';
705 else if ((a == 'l') && (b == 'f')) chr = 0x00B5; // 'µ';
706 else if ((a == 'n') && (b == 'i')) chr = 0x00D8; // 'Ø';
707 else if ((a == 'p') && (b == 'i')) chr = 0x00F8; // 'ø';
708
709 else if ((a == 'l') && (b == 'j')) chr = 0x00B9; // '¹';
710 else if ((a == 'l') && (b == 'c')) chr = 0x00B2; // '²';
711 else if ((a == 'l') && (b == 'd')) chr = 0x00B3; // '³';
712
713 else if ((a == 'l') && (b == 'm')) chr = 0x0152; // 'Œ';
714 else if ((a == 'l') && (b == 'n')) chr = 0x0153; // 'œ';
715 else if ((a == 'l') && (b == 'o')) chr = 0x0178; // 'Ÿ';
716
717 else if ((a == 'l') && (b == 'a')) chr = 0x00B0; // '°';
718
719 else if ((a == 'k') && (b == 'o')) chr = 0x00AE; // '®';
720 else if ((a == 'k') && (b == 'h')) chr = 0x00A7; // '§';
721 else if ((a == 'k') && (b == 'd')) chr = 0x00A3; // '£';
722
723 else if ((a == 'p') && (b == 'a')) chr = 0x00F0; // 'ð';
724 else if ((a == 'n') && (b == 'a')) chr = 0x00D0; // 'Ð';
725
726 else if ((a == 'l') && (b == 'l')) chr = 0x00BB; // '»';
727 else if ((a == 'k') && (b == 'l')) chr = 0x00AB; // '«';
728
729 else if ((a == 'l') && (b == 'k')) chr = 0x00BA; // 'º';
730
731 else if ((a == 'l') && (b == 'h')) chr = 0x00B7; // '·';
732
733 else if ((a == 'k') && (b == 'b')) chr = 0x00A1; // '¡';
734
735 else if ((a == 'k') && (b == 'e')) chr = 0x20AC; // '€';
736
737 else if ((a == 'l') && (b == 'b')) chr = 0x00B1; // '±';
738
739 else if ((a == 'l') && (b == 'p')) chr = 0x00BF; // '¿';
740
741 else if ((a == 'k') && (b == 'f')) chr = 0x00A5; // '¥';
742
743 else if ((a == 'p') && (b == 'o')) chr = 0x00FE; // 'þ';
744 else if ((a == 'n') && (b == 'o')) chr = 0x00DE; // 'Þ';
745
746 else if ((a == 'n') && (b == 'n')) chr = 0x00DD; // 'Ý';
747 else if ((a == 'p') && (b == 'n')) chr = 0x00FD; // 'ý';
748 else if ((a == 'p') && (b == 'p')) chr = 0x00FF; // 'ÿ';
749
750 else if ((a == 'k') && (b == 'k')) chr = 0x00AA; // 'ª';
751
752 else if ((a == 'k') && (b == 'm')) chr = 0x00AC; // '¬';
753 else if ((a == 'p') && (b == 'h')) chr = 0x00F7; // '÷';
754
755 else if ((a == 'k') && (b == 'g')) chr = 0x007C; // '|';
756
757 else if ((a == 'l') && (b == 'e')) chr = 0x0027; // '\'';
758
759 else if ((a == 'k') && (b == 'i')) chr = 0x0161; // 'š';
760
761 else if ((a == 'k') && (b == 'n')) chr = 0x00AD; // '';
762
763 else if ((a == 'k') && (b == 'p')) chr = 0x00AF; // '¯';
764
765 else if ((a == 'l') && (b == 'g')) chr = 0x00B6; // '¶';
766
767 else if ((a == 'l') && (b == 'i')) chr = 0x017E; // 'ž';
768
769 else if ((a == 'm') && (b == 'h')) chr = 0x00C7; // 'Ç';
770 else if ((a == 'o') && (b == 'h')) chr = 0x00E7; // 'ç';
771
772 else if ((a == 'n') && (b == 'h')) chr = 0x00D7; // '×';
773
774 else if ((a == 'k') && (b == 'a')) chr = 0x0020; // ' ';
775
776 else if ((a == 'a') && (b == 'j')) chr = 0x0021; // '!';
777
778 else chr = 0x0023; // '#';
779
780 return chr;
781 }
782
783
784
785 /******************************************************************************
786 * function: writePen *
787 ******************************************************************************/
788 void
writePen(QString & str,int penwidth,int penstyle,const QString & framecolor)789 APPLIXSPREADImport::writePen(QString &str, int penwidth, int penstyle, const QString &framecolor)
790 {
791 str += " <pen width=\"" +
792
793 // width of the pen
794 QString::number(penwidth) +
795 "\" style=\"" +
796
797 // style of the pen
798 QString::number(penstyle) +
799 "\" color=\"" +
800
801 // color of the pen
802 framecolor +
803 "\" />\n";
804
805 }
806
807
808
809 /******************************************************************************
810 * function: writeColor *
811 ******************************************************************************/
812 QString
writeColor(t_mycolor * mc)813 APPLIXSPREADImport::writeColor(t_mycolor *mc)
814 {
815 char rgb[20];
816
817 // printf (" WriteColor: <%d>-<%d>-<%d> <%d>-<%d>-<%d>-<%d>\n",
818 // mc->r, mc->g, mc->b,
819 // mc->c, mc->m, mc->y, mc->k);
820
821 sprintf(rgb, "#%02X%02X%02X", mc->r, mc->g, mc->b);
822 QString bla = rgb;
823
824
825 return bla;
826 }
827
828
829
830
831 /******************************************************************************
832 * function: readTypefaceTable *
833 ******************************************************************************/
834 void
readTypefaceTable(QTextStream & stream,QStringList & typefacetab)835 APPLIXSPREADImport::readTypefaceTable(QTextStream &stream, QStringList &typefacetab)
836 {
837 int tftabCounter = 0;
838 QString mystr;
839
840 // Read the colormap
841 kDebug() << "Reading typeface table:";
842
843 bool ok = true;
844 do {
845 mystr = nextLine(stream);
846 // FIXME: What happens if the magic words are not present in the stream?
847 if (mystr == "END TYPEFACE TABLE") ok = false;
848 else {
849 //printf (" %2d: <%s>\n", tftabCounter, mystr.toLatin1());
850 typefacetab.append(mystr);
851 tftabCounter++;
852 }
853 } while (ok == true);
854
855 kDebug() << "... done";
856 }
857
858
859
860 /******************************************************************************
861 * function: readColormap *
862 ******************************************************************************/
863 void
readColormap(QTextStream & stream,QList<t_mycolor * > & mcol)864 APPLIXSPREADImport::readColormap(QTextStream &stream, QList<t_mycolor*> &mcol)
865 {
866 int contcount, pos;
867
868 QString colstr, mystr;
869 kDebug() << "Reading colormap:";
870
871 bool ok = true;
872
873 do {
874
875 mystr = nextLine(stream).trimmed();
876
877 if (mystr == "END COLORMAP") ok = false;
878 else {
879 kDebug() << " ->" << mystr;
880
881 // Count the number of whitespaces
882 contcount = mystr.count(' ');
883 kDebug() << "contcount:" << contcount;
884 contcount -= 5;
885
886 // Begin off interest
887 pos = mystr.indexOf(" 0 ");
888
889 // get colorname
890 colstr = mystr.left(pos);
891 mystr.remove(0, pos + 1);
892 mystr = mystr.trimmed();
893
894 t_mycolor *tmc = new t_mycolor;
895
896 // get sub colors
897 pos = sscanf(mystr.toLatin1(), "0 %d %d %d %d 0",
898 &tmc->c, &tmc->m, &tmc->y, &tmc->k);
899
900 printf(" - <%-20s> <%-15s> <%3d> <%3d> <%3d> <%3d> pos: %d\n",
901 mystr.toLatin1().data(),
902 colstr.toLatin1().data(),
903 tmc->c, tmc->m, tmc->y, tmc->k, pos);
904
905 // Color transformation cmyk -> rgb
906 tmc->r = 255 - (tmc->c + tmc->k);
907 if (tmc->r < 0) tmc->r = 0;
908
909 tmc->g = 255 - (tmc->m + tmc->k);
910 if (tmc->g < 0) tmc->g = 0;
911
912 tmc->b = 255 - (tmc->y + tmc->k);
913 if (tmc->b < 0) tmc->b = 0;
914
915 mcol.append(tmc);
916 }
917
918 } while (ok == true);
919
920 kDebug() << "... done" << mcol.count();
921
922 foreach(t_mycolor* emp, mcol) {
923 printf(" c:%3d m:%3d y:%3d k:%3d r:%3d g:%3d b:%3d\n",
924 emp->c, emp->m, emp->y, emp->k, emp->r, emp->g, emp->b);
925 }
926 }
927
928
929
930
931 /******************************************************************************
932 * function: readColormap *
933 ******************************************************************************/
934 void
readView(QTextStream & stream,const QString & instr,t_rc & rc)935 APPLIXSPREADImport::readView(QTextStream &stream, const QString &instr, t_rc &rc)
936 {
937 QString rowcolstr;
938 QString mystr, tabname;
939
940 kDebug() << "Reading View";
941
942 tabname = instr;
943
944 tabname.remove(0, 19);
945 tabname.remove(tabname.length() - 2, 2);
946 kDebug() << " - Table name:" << tabname;
947
948 bool ok = true;
949 do {
950 mystr = nextLine(stream);
951
952 kDebug() << "" << mystr;
953 if (mystr.startsWith("View End, Name:")) ok = false;
954 else {
955 // COLUMN Widths
956 if (mystr.startsWith("View Column Widths")) {
957 kDebug() << " - Column Widths";
958 mystr.remove(0, 20);
959 kDebug() << "" << mystr;
960
961 int colwidth, icolumn;
962 char ccolumn;
963
964 // loop
965 QStringList ColumnList;
966 ColumnList = mystr.split(' ');
967
968 for (QStringList::Iterator it = ColumnList.begin(); it != ColumnList.end(); ++it) {
969
970 sscanf((*it).toLatin1(), "%c:%d", &ccolumn, &colwidth);
971 int len = (*it).length();
972 int pos = (*it).indexOf(':');
973 (*it).remove(pos, len - pos);
974
975 printf(" >%s<- -<%c><%d> \n", (*it).toLatin1().data(), ccolumn, colwidth);
976
977 // Transformat ascii column to int column
978 icolumn = translateColumnNumber(*it);
979
980 //icolumn = ccolumn - 64;
981 // Translate the column width right from applix to kspread
982 icolumn = icolumn * 5;
983
984
985 rowcolstr += " <column width=\"" +
986 QString::number(colwidth) +
987 "\" column=\"" +
988 QString::number(icolumn) +
989 "\" >\n"
990 " <format/>\n"
991 " </column>\n";
992 }
993 }
994
995 // ROW Heights
996 else if (mystr.startsWith("View Row Heights")) {
997 kDebug() << " - Row Heights";
998 mystr.remove(0, 17);
999 kDebug() << "" << mystr;
1000
1001 int irow, rowheight;
1002
1003 // loop
1004 QStringList RowList;
1005 RowList = mystr.split(' ');
1006
1007 for (QStringList::Iterator it = RowList.begin(); it != RowList.end(); ++it) {
1008 sscanf((*it).toLatin1(), " %d:%d",
1009 &irow, &rowheight);
1010 printf(" row: %2d height: %2d\n", irow, rowheight);
1011 if (rowheight > 32768) rowheight -= 32768;
1012 printf(" height: %2d\n", rowheight);
1013 rowcolstr += " <row row=\"" +
1014 QString::number(irow) +
1015 "\" height=\"" +
1016 QString::number(rowheight) +
1017 "\" >\n"
1018 " <format/>\n"
1019 " </row>\n";
1020 }
1021
1022
1023 }
1024 } // else != END COLORMAP
1025 } while (ok == true);
1026
1027 // tabname append to my list
1028 // tabname append to my list
1029 rc.tabname.append(tabname);
1030 rc.rc.append(rowcolstr);
1031
1032 printf("%s %s\n", tabname.toLatin1().data(),
1033 rowcolstr.toLatin1().data());
1034
1035 printf("...done \n\n");
1036 }
1037
1038
1039
1040
1041
1042 /******************************************************************************
1043 * function: filterSHFGBG *
1044 ******************************************************************************/
1045 void
filterSHFGBG(const QString & it,int * style,int * bgcolor,int * fgcolor)1046 APPLIXSPREADImport::filterSHFGBG(const QString &it, int *style, int *bgcolor,
1047 int *fgcolor)
1048 {
1049 QString tmpstr;
1050 int pos;
1051 int m2 = 0, m3 = 0;
1052
1053 // filter SH = Brushstyle Background
1054 pos = it.indexOf("SH");
1055 if (pos > -1) {
1056 tmpstr = it;
1057 if (pos > 0) tmpstr.remove(0, pos);
1058 pos = sscanf(tmpstr.toLatin1(), "SH%d",
1059 style);
1060
1061 printf("style: %d(%d) ",
1062 *style, pos);
1063 }
1064
1065
1066 // filter FG = FGCOLOR
1067 pos = it.indexOf("FG");
1068 if (pos > -1) {
1069 tmpstr = it;
1070 if (pos > 0) tmpstr.remove(0, pos);
1071 pos = sscanf(tmpstr.toLatin1(), "FG%d",
1072 fgcolor);
1073 printf("fg: %d(%d) ",
1074 *fgcolor, pos);
1075 m2 = 1;
1076 }
1077
1078
1079 // filter BG = BGCOLOR
1080 pos = it.indexOf("BG");
1081 if (pos > -1) {
1082 tmpstr = it;
1083 if (pos > 0) tmpstr.remove(0, pos);
1084 pos = sscanf(tmpstr.toLatin1(), "BG%d",
1085 bgcolor);
1086 printf("bgcolor: %d(%d) ",
1087 *bgcolor, pos);
1088 m3 = 1;
1089 }
1090
1091
1092 printf("\n");
1093
1094
1095 // correct the bgcolor to the fgcolor if the background is plain
1096 if ((*style == 8) && (m2 == 1) && (m3 == 0)) {
1097 *bgcolor = *fgcolor;
1098 }
1099
1100
1101 // Translate brushstyle to kspread brushstyle
1102 if (*style != 0) {
1103 if (*style == 1) *style = 0;
1104 else if (*style == 2) *style = 7;
1105 else if (*style == 3) *style = 0;
1106 else if (*style == 4) *style = 4;
1107 else if (*style == 5) *style = 3;
1108 else if (*style == 6) *style = 2;
1109 else if (*style == 7) *style = 0;
1110 else if (*style == 8) *style = 0;
1111 else if (*style == 9) *style = 10;
1112 else if (*style == 10) *style = 9;
1113 else if (*style == 11) *style = 11;
1114 else if (*style == 12) *style = 12;
1115 else if (*style == 13) *style = 13;
1116 else if (*style == 14) *style = 14;
1117 else if (*style == 15) *style = 0;
1118 else if (*style == 16) *style = 0;
1119 else if (*style == 17) *style = 0;
1120 else if (*style == 18) *style = 0;
1121 else if (*style == 19) *style = 0;
1122 }
1123 }
1124
1125
1126
1127 /******************************************************************************
1128 * function: filterSHFGBG *
1129 ******************************************************************************/
1130 void
transPenFormat(const QString & it,int * PenWidth,int * PenStyle)1131 APPLIXSPREADImport::transPenFormat(const QString &it, int *PenWidth, int *PenStyle)
1132 {
1133
1134 if (it[1] == '1') {
1135 *PenWidth = 1;
1136 *PenStyle = 1;
1137 }
1138
1139 else if (it[1] == '2') {
1140 *PenWidth = 2;
1141 *PenStyle = 1;
1142 }
1143
1144 else if (it[1] == '3') {
1145 *PenWidth = 3;
1146 *PenStyle = 1;
1147 }
1148
1149 else if (it[1] == '4') {
1150 *PenWidth = 1;
1151 *PenStyle = 3;
1152 }
1153
1154 else if (it[1] == '5') {
1155 *PenWidth = 5;
1156 *PenStyle = 1;
1157 }
1158
1159 printf("frame (w:%d - s:%d) \n", *PenWidth, *PenStyle);
1160 }
1161
1162
1163
1164
1165 /******************************************************************************
1166 * function: readHeader *
1167 ******************************************************************************/
1168 int
readHeader(QTextStream & stream)1169 APPLIXSPREADImport::readHeader(QTextStream &stream)
1170 {
1171 QString mystr;
1172 int vers[3] = { 0, 0, 0 };
1173 int rueck;
1174
1175
1176 // Read Headline
1177 mystr = nextLine(stream);
1178 rueck = sscanf(mystr.toLatin1(),
1179 "*BEGIN SPREADSHEETS VERSION=%d/%d ENCODING=%dBIT",
1180 &vers[0], &vers[1], &vers[2]);
1181 printf("Versions info: %d %d %d\n", vers[0], vers[1], vers[2]);
1182
1183 // Check the headline
1184 if (rueck <= 0) {
1185 printf("Header not correct - May be it is not an applixspreadsheet file\n");
1186 printf("Headerline: <%s>\n", mystr.toLatin1().data());
1187
1188 QMessageBox::critical(0L, "Applix spreadsheet header problem",
1189 QString("The Applix Spreadsheet header is not correct. "
1190 "May be it is not an applix spreadsheet file! <BR>"
1191 "This is the header line I did read:<BR><B>%1</B>").arg(mystr),
1192 "Okay");
1193
1194
1195 return false;
1196 } else {
1197 return true;
1198 }
1199 }
1200
1201
1202 /******************************************************************************
1203 * function: translateColumnNumber *
1204 ******************************************************************************/
1205 int
translateColumnNumber(const QString & colstr)1206 APPLIXSPREADImport::translateColumnNumber(const QString& colstr)
1207 {
1208 int icol = 0;
1209 const int len = colstr.length();
1210 int p = len - 1;
1211 int x = 1;
1212
1213 //kDebug() << "len=" << len;
1214 while (p >= 0) {
1215 //kDebug() << "x=" << x << "p=" << p << "char=" << colstr[p].toLatin1();
1216 const char c = colstr[p].toLatin1();
1217 // Upper chars
1218 if ((c >= 'A') && (c <= 'Z')) {
1219 //kDebug() << " UPPER";
1220 icol += ((int)pow((double)x, 26) * (c - 'A' + 1));
1221 ++x;
1222 }
1223 // lower chars
1224 else if ((c >= 'a') && (c <= 'z')) {
1225 //kDebug() << " lower";
1226 icol += ((int)pow((double)x, 26) * (c - 'a' + 1));
1227 ++x;
1228 }
1229 p--;
1230 }
1231
1232 kDebug() << colstr << "->" << icol;
1233 return icol;
1234 }
1235
1236 // Converts =SUM(F1,4) into =SUM(F1;4) -- well, plus possible nesting
convertFormula(const QString & input) const1237 QString APPLIXSPREADImport::convertFormula(const QString& input) const
1238 {
1239 // Let me be stupid for now
1240 QString ret = input;
1241 ret.replace(',', ';');
1242 return ret;
1243 }
1244
1245 #include "applixspreadimport.moc"
1246