59
84
const QString nbsp (" ");
60
85
const QString strLt ("<");
61
86
const QString strGt (">");
62
const QRegExp regExpAmp ("&");
63
const QRegExp regExpLt ("<");
64
const QRegExp regExpGt (">");
65
const QRegExp regExpSpace(" ");
67
88
// The reason why we use the KoDocument* approach and not the QDomDocument
68
89
// approach is because we don't want to export formulas but values !
69
90
KoFilter::ConversionStatus HTMLExport::convert( const QCString& from, const QCString& to )
92
if(to!="text/html" || from!="application/x-kspread")
94
kdWarning(30501) << "Invalid mimetypes " << to << " " << from << endl;
95
return KoFilter::NotImplemented;
71
98
KoDocument* document = m_chain->inputDocument();
72
QString file( m_chain->outputFile() );
74
return KoFilter::StupidError;
101
return KoFilter::StupidError;
76
103
if(strcmp(document->className(), "KSpreadDoc")!=0) // it's safer that way :)
78
kdWarning(30501) << "document isn't a KSpreadDoc but a " << document->className() << endl;
79
return KoFilter::NotImplemented;
81
if(to!="text/html" || from!="application/x-kspread")
83
kdWarning(30501) << "Invalid mimetypes " << to << " " << from << endl;
84
return KoFilter::NotImplemented;
105
kdWarning(30501) << "document isn't a KSpreadDoc but a " << document->className() << endl;
106
return KoFilter::NotImplemented;
87
109
const KSpreadDoc * ksdoc=static_cast<const KSpreadDoc *>(document);
89
111
if( ksdoc->mimeType() != "application/x-kspread" )
91
kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
92
return KoFilter::NotImplemented;
95
QString html_table_tag = "table";
96
QString html_table_options = " border=\"1\"";
97
QString html_row_tag = "tr";
98
QString html_row_options = "";
99
QString html_cell_tag = "td";
100
QString html_cell_options = "";
101
QString html_bold = "b";
102
QString html_italic = "i";
103
QString html_underline = "u";
104
QString html_right= "right";
105
QString html_left= "left";
106
QString html_center= "center";
107
QString html_top="top";
108
QString html_bottom="bottom";
109
QString html_middle="middle";
111
// Ah ah ah - the document is const, but the map and table aren't. Safety:0.
113
kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
114
return KoFilter::NotImplemented;
117
KSpreadSheet *sheet = ksdoc->map()->firstSheet();
118
QString filenameBase = m_chain->outputFile();
119
filenameBase = filenameBase.left( filenameBase.findRev( '.' ) );
126
detectFilledCells( sheet, rows, columns );
127
m_rowmap[ sheet->sheetName() ] = rows;
128
m_columnmap[ sheet->sheetName() ] = columns;
130
if( rows > 0 && columns > 0 )
132
sheets.append( sheet->sheetName() );
134
sheet = ksdoc->map()->nextSheet();
136
m_dialog->setSheets( sheets );
138
if( m_dialog->exec() == QDialog::Rejected )
139
return KoFilter::UserCancelled;
141
sheets = m_dialog->sheets();
116
KoDocumentInfo *info = document->documentInfo();
117
KoDocumentInfoAbout *aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
118
if ( aboutPage && !aboutPage->title().isEmpty() )
119
title = aboutPage->title();
123
// Now get hold of the table to export
124
// (Hey, this could be part of the dialog too, choosing which table to export....
125
// It's great to have parametrable filters... IIRC even MSOffice doesn't have that)
126
// Ok, for now we'll use the first table - my document has only one table anyway ;-)))
127
KSpreadTable * table = ksdoc->map()->firstTable();
130
str = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" ";
131
str += " \"http://www.w3.org/TR/html4/loose.dtd\"> \n";
134
// TODO: possibility of choosing other encodings
135
str += "<meta http-equiv=\"Content-Type\" ";
136
str += "content=\"text/html; charset=UTF-8\">\n";
137
str += "<meta name=\"Generator\" ";
138
str += "content=\"KSpread HTML Export Filter Version = 0.2\">\n";
139
// I have no idea where to get the document name from :-( table->tableName()
140
str += "<title>" + title + "</title>\n";
142
str += QString("<body bgcolor=\"#FFFFFF\" dir=\"%1\">\n").arg(
143
table->isRightToLeft()?"rtl":"ltr");
143
for( uint i = 0; i < sheets.count() ; ++i )
148
// Either we get hold of KSpreadTable::m_dctCells and apply the old method below (for sorting)
145
sheet = ksdoc->map()->findSheet( sheets[i] );
147
QString file = fileName( filenameBase, sheet->sheetName(), sheets.count() > 1 );
149
if( m_dialog->separateFiles() || sheets[i] == sheets.first() )
152
openPage( sheet, document, str );
153
writeTOC( sheets, filenameBase, str );
156
convertSheet( sheet, str, m_rowmap[ sheet->sheetName() ], m_columnmap[ sheet->sheetName() ] );
158
if( m_dialog->separateFiles() || sheets[i] == sheets.last() )
162
if(!out.open(IO_WriteOnly)) {
163
kdError(30501) << "Unable to open output file!" << endl;
165
return KoFilter::FileNotFound;
167
QTextStream streamOut(&out);
168
streamOut.setCodec( m_dialog->encoding() );
169
streamOut << str << endl;
173
if( !m_dialog->separateFiles() )
175
createSheetSeparator( str );
180
emit sigProgress(100);
184
void HTMLExport::openPage( KSpreadSheet *sheet, KoDocument *document, QString &str )
187
KoDocumentInfo *info = document->documentInfo();
188
KoDocumentInfoAbout *aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
189
if ( aboutPage && !aboutPage->title().isEmpty() )
190
title = aboutPage->title() + " - ";
192
title += sheet->sheetName();
195
str = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" ";
196
str += " \"http://www.w3.org/TR/html4/loose.dtd\"> \n";
199
str += "<meta http-equiv=\"Content-Type\" ";
200
str += QString("content=\"text/html; charset=%1\">\n").arg( m_dialog->encoding()->mimeName() );
201
str += "<meta name=\"Generator\" ";
202
str += "content=\"KSpread HTML Export Filter Version = ";
203
str += KOFFICE_VERSION_STRING;
207
if( !m_dialog->customStyleURL().isEmpty() )
209
str += "<link ref=\"stylesheet\" type=\"text/css\" href=\"";
210
str += m_dialog->customStyleURL();
211
str += "\" title=\"Style\" >\n";
214
str += "<title>" + title + "</title>\n";
216
str += QString("<body bgcolor=\"#FFFFFF\" dir=\"%1\">\n").arg(
217
sheet->isRightToLeft()?"rtl":"ltr");
219
str += "<a name=\"__top\">\n";
222
void HTMLExport::closePage( QString &str )
224
str += "<p align=\"" + html_center + "\"><a href=\"#__top\">" + i18n("Top") + "</a></p>\n";
226
str += "</html>\n\n";
229
void HTMLExport::convertSheet( KSpreadSheet *sheet, QString &str, int iMaxUsedRow, int iMaxUsedColumn )
233
// Either we get hold of KSpreadTable::m_dctCells and apply the old method below (for sorting)
149
234
// or, cleaner and already sorted, we use KSpreadTable's API (slower probably, though)
150
int iMaxColumn = table->maxColumn();
151
int iMaxRow = table->maxRow();
153
// determine max number of used columns to make rect table
155
int iMaxUsedColumn=0;
157
int currentrow, currentcolumn;
159
for ( currentrow = 1 ; currentrow < iMaxRow ; ++currentrow)
161
KSpreadCell * cell = 0L;
163
for ( currentcolumn = 1 ; currentcolumn < iMaxColumn ; currentcolumn++ )
165
cell = table->cellAt( currentcolumn, currentrow, false );
167
if ( !cell->isDefault() && !cell->isEmpty() )
169
iUsedColumn = currentcolumn;
173
iUsedColumn += cell->extraXCells();
174
if (iUsedColumn > iMaxUsedColumn)
175
iMaxUsedColumn = iUsedColumn;
176
if ( iUsedColumn > 0 )
177
iMaxUsedRow = currentrow;
235
int iMaxRow = sheet->maxRow();
237
if( !m_dialog->separateFiles() )
238
str += "<a name=\"" + sheet->sheetName().lower().stripWhiteSpace() + "\">\n";
240
str += ("<h1>" + sheet->sheetName() + "</h1><br>\n");
183
242
// this is just a bad approximation which fails for documents with less than 50 rows, but
184
243
// we don't need any progress stuff there anyway :) (Werner)
186
int step=iMaxRow > 50 ? iMaxRow/50 : 1;
189
str += "<" + html_table_tag + html_table_options +
190
QString("dir=\"%1\">\n").arg(table->isRightToLeft()?"rtl":"ltr");
192
unsigned int nonempty_cells_prev=0;
194
for ( currentrow = 1 ; currentrow < iMaxUsedRow ; ++currentrow, ++i )
198
emit sigProgress(value);
204
unsigned int nonempty_cells=0;
205
unsigned int colspan_cells=0;
207
for ( currentcolumn = 1 ; currentcolumn < iMaxUsedColumn ; currentcolumn++ )
209
KSpreadCell * cell = table->cellAt( currentcolumn, currentrow, false );
210
colspan_cells=cell->extraXCells();
211
if (cell->needsPrinting())
214
QColor bgcolor = cell->bgColor(currentcolumn,currentrow);
245
int step=iMaxRow > 50 ? iMaxRow/50 : 1;
248
str += "<" + html_table_tag + html_table_options.arg( m_dialog->useBorders() ? "1" : "0" ).arg( m_dialog->pixelsBetweenCells() ) +
249
QString("dir=\"%1\">\n").arg(sheet->isRightToLeft()?"rtl":"ltr");
251
unsigned int nonempty_cells_prev=0;
253
for ( int currentrow = 1 ; currentrow <= iMaxUsedRow ; ++currentrow, ++i )
257
emit sigProgress(value);
263
unsigned int nonempty_cells=0;
264
unsigned int colspan_cells=0;
266
for ( int currentcolumn = 1 ; currentcolumn <= iMaxUsedColumn ; currentcolumn++ )
268
KSpreadCell * cell = sheet->cellAt( currentcolumn, currentrow, false );
269
colspan_cells=cell->extraXCells();
270
if (cell->needsPrinting())
273
QColor bgcolor = cell->bgColor(currentcolumn,currentrow);
215
274
// FIXME: some formatting seems to be missing with cell->text(), e.g.
216
275
// "208.00" in KSpread will be "208" in HTML (not always?!)
219
text=cell->strOutText();
278
text=cell->strOutText();
221
280
switch( cell->content() ) {
222
case KSpreadCell::Text:
281
case KSpreadCell::Text:
223
282
text = cell->text();
225
case KSpreadCell::RichText:
226
case KSpreadCell::VisualFormula:
284
case KSpreadCell::RichText:
285
case KSpreadCell::VisualFormula:
227
286
text = cell->text(); // untested
229
case KSpreadCell::Formula:
288
case KSpreadCell::Formula:
230
289
cell->calc( TRUE ); // Incredible, cells are not calculated if the document was just opened
231
290
text = cell->valueString();
234
293
text = cell->prefix(currentrow, currentcolumn) + " " + text + " "
235
294
+ cell->postfix(currentrow, currentcolumn);
237
296
line += " <" + html_cell_tag + html_cell_options;
238
if (text.isRightToLeft() != table->isRightToLeft())
239
line += QString(" dir=\"%1\" ").arg(text.isRightToLeft()?"rtl":"ltr");
240
if (bgcolor.isValid() && bgcolor.name()!="#ffffff") // change color only for non-white cells
241
line += " bgcolor=\"" + bgcolor.name() + "\"";
243
switch((KSpreadCell::Align)cell->defineAlignX())
245
case KSpreadCell::Left:
246
line+=" align=\"" + html_left +"\"";
248
case KSpreadCell::Right:
249
line+=" align=\"" + html_right +"\"";
251
case KSpreadCell::Center:
252
line+=" align=\"" + html_center +"\"";
254
case KSpreadCell::Undefined:
257
switch((KSpreadCell::AlignY)cell-> alignY(currentrow, currentcolumn))
259
case KSpreadCell::Top:
260
line+=" valign=\"" + html_top +"\"";
262
case KSpreadCell::Middle:
263
line+=" valign=\"" + html_middle +"\"";
265
case KSpreadCell::Bottom:
266
line+=" valign=\"" + html_bottom +"\"";
269
line+=" width=\""+QString::number(cell->width())+"\"";
270
line+=" height=\""+QString::number(cell->height())+"\"";
272
if (cell->extraXCells()>0)
275
int extra_cells=cell->extraXCells();
276
line += " colspan=\"" + tmp.setNum(extra_cells+1) + "\"";
277
currentcolumn += extra_cells;
279
text = text.stripWhiteSpace();
280
if( text.at(0) == '!' ) {
297
if (text.isRightToLeft() != sheet->isRightToLeft())
298
line += QString(" dir=\"%1\" ").arg(text.isRightToLeft()?"rtl":"ltr");
299
if (bgcolor.isValid() && bgcolor.name()!="#ffffff") // change color only for non-white cells
300
line += " bgcolor=\"" + bgcolor.name() + "\"";
302
switch((KSpreadCell::Align)cell->defineAlignX())
304
case KSpreadCell::Left:
305
line+=" align=\"" + html_left +"\"";
307
case KSpreadCell::Right:
308
line+=" align=\"" + html_right +"\"";
310
case KSpreadCell::Center:
311
line+=" align=\"" + html_center +"\"";
313
case KSpreadCell::Undefined:
316
switch((KSpreadCell::AlignY)cell-> alignY(currentrow, currentcolumn))
318
case KSpreadCell::Top:
319
line+=" valign=\"" + html_top +"\"";
321
case KSpreadCell::Middle:
322
line+=" valign=\"" + html_middle +"\"";
324
case KSpreadCell::Bottom:
325
line+=" valign=\"" + html_bottom +"\"";
327
case KSpreadCell::UndefinedY:
330
line+=" width=\""+QString::number(cell->width())+"\"";
331
line+=" height=\""+QString::number(cell->height())+"\"";
333
if (cell->extraXCells()>0)
336
int extra_cells=cell->extraXCells();
337
line += " colspan=\"" + tmp.setNum(extra_cells+1) + "\"";
338
currentcolumn += extra_cells;
340
text = text.stripWhiteSpace();
341
if( text.at(0) == '!' ) {
281
342
// this is supposed to be markup, just remove the '!':
282
text = text.right(text.length()-1);
284
// Escape HTML characters. No need to be very efficient IMHO,
286
text.replace (regExpAmp , strAmp)
287
.replace (regExpLt , strLt)
288
.replace (regExpGt , strGt)
289
.replace (regExpSpace, nbsp);
293
if (cell->textFontBold(currentcolumn,currentrow))
295
text.insert(0, "<" + html_bold + ">");
296
text.append("</" + html_bold + ">");
298
if (cell->textFontItalic(currentcolumn,currentrow))
300
text.insert(0, "<" + html_italic + ">");
301
text.append("</" + html_italic + ">");
303
if (cell->textFontUnderline(currentcolumn,currentrow))
305
text.insert(0, "<" + html_underline + ">");
306
text.append("</" + html_underline + ">");
308
QColor textColor = cell->textColor(currentcolumn,currentrow);
309
if (textColor.isValid() && textColor.name()!="#000000") // change color only for non-default text
311
text.insert(0, "<font color=\"" + textColor.name() + "\">");
312
text.append("</font>");
315
line += "\n </" + html_cell_tag + ">\n";
318
if (nonempty_cells == 0 && nonempty_cells_prev == 0) {
319
nonempty_cells_prev = nonempty_cells;
343
text = text.right(text.length()-1);
345
// Escape HTML characters.
346
text.replace ('&' , strAmp)
347
.replace ('<' , strLt)
348
.replace ('>' , strGt)
349
.replace (' ' , nbsp);
353
if (cell->textFontBold(currentcolumn,currentrow))
355
text.insert(0, "<" + html_bold + ">");
356
text.append("</" + html_bold + ">");
358
if (cell->textFontItalic(currentcolumn,currentrow))
360
text.insert(0, "<" + html_italic + ">");
361
text.append("</" + html_italic + ">");
363
if (cell->textFontUnderline(currentcolumn,currentrow))
365
text.insert(0, "<" + html_underline + ">");
366
text.append("</" + html_underline + ">");
368
QColor textColor = cell->textColor(currentcolumn,currentrow);
369
if (textColor.isValid() && textColor.name()!="#000000") // change color only for non-default text
371
text.insert(0, "<font color=\"" + textColor.name() + "\">");
372
text.append("</font>");
375
line += "\n </" + html_cell_tag + ">\n";
378
if (nonempty_cells == 0 && nonempty_cells_prev == 0) {
379
nonempty_cells_prev = nonempty_cells;
320
380
// skip line if there's more than one empty line
323
nonempty_cells_prev = nonempty_cells;
325
str += "<" + html_row_tag + html_row_options + ">\n";
327
str += "</" + html_row_tag + ">";
328
emptyLines = QString::null;
383
nonempty_cells_prev = nonempty_cells;
385
str += "<" + html_row_tag + html_row_options + ">\n";
387
str += "</" + html_row_tag + ">";
388
emptyLines = QString::null;
329
389
// Append a CR, but in a temp string -> if no other real line,
330
390
// then those will be dropped
394
str += "\n</" + html_table_tag + ">\n<br>\n";
397
void HTMLExport::createSheetSeparator( QString &str )
399
str += ("<p align=\"" + html_center + "\"><a href=\"#__top\">" + i18n("Top") + "</a></p>\n" );
400
str += "<hr width=\"80%\">\n";
403
void HTMLExport::writeTOC( const QStringList &sheets, const QString &base, QString &str )
405
// don't create TOC for 1 sheet
406
if( sheets.count() == 1 )
409
str += "<p align=\"" + html_center + "\">\n";
411
for( uint i = 0 ; i < sheets.count() ; ++i )
415
if( m_dialog->separateFiles() )
417
str += fileName( base, sheets[i], sheets.count() > 1 );
421
str += "#" + sheets[i].lower().stripWhiteSpace();
424
str += "\">" + sheets[i] + "</a>\n";
425
if( i != sheets.count() -1 )
429
str += "</p><hr width=\"80%\">\n";
432
QString HTMLExport::fileName( const QString &base, const QString &sheetName, bool multipleFiles )
434
QString fileName = base;
435
if( m_dialog->separateFiles() && multipleFiles )
437
fileName += "-" + sheetName;
444
void HTMLExport::detectFilledCells( KSpreadSheet *sheet, int &rows, int &columns )
446
int iMaxColumn = sheet->maxColumn();
447
int iMaxRow = sheet->maxRow();
451
for ( int currentrow = 1 ; currentrow <= iMaxRow ; ++currentrow)
453
KSpreadCell * cell = 0L;
455
for ( int currentcolumn = 1 ; currentcolumn <= iMaxColumn ; currentcolumn++ )
457
cell = sheet->cellAt( currentcolumn, currentrow, false );
459
if ( !cell->isDefault() && !cell->isEmpty() )
461
iUsedColumn = currentcolumn;
334
str += "\n</" + html_table_tag + ">\n<br>\n";
336
table = ksdoc->map()->nextTable();
341
str += "\n"; // Last CR
342
emit sigProgress(100);
344
// Ok, now write to export file
346
if(!out.open(IO_WriteOnly)) {
347
kdError(30501) << "Unable to open output file!" << endl;
349
return KoFilter::FileNotFound;
351
QTextStream streamOut(&out);
352
streamOut.setEncoding( QTextStream::UnicodeUTF8 ); // TODO: possibility of choosing other encodings
353
streamOut << str << endl;
465
iUsedColumn += cell->extraXCells();
466
if (iUsedColumn > columns)
467
columns = iUsedColumn;
468
if ( iUsedColumn > 0 )
359
473
#include <htmlexport.moc>