00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <htmlexport.h>
00023 #include <exportdialog.h>
00024
00025 #include <qfile.h>
00026 #include <qtextcodec.h>
00027
00028 #include <kdebug.h>
00029 #include <kgenericfactory.h>
00030 #include <KoFilterChain.h>
00031 #include <KoDocumentInfo.h>
00032 #include <kofficeversion.h>
00033
00034 #include <kspread_map.h>
00035 #include <kspread_sheet.h>
00036 #include <kspread_doc.h>
00037 #include <kspread_util.h>
00038
00039 using namespace KSpread;
00040
00041 typedef KGenericFactory<HTMLExport, KoFilter> HTMLExportFactory;
00042 K_EXPORT_COMPONENT_FACTORY( libkspreadhtmlexport, HTMLExportFactory( "kofficefilters" ) )
00043
00044 const QString html_table_tag = "table";
00045 const QString html_table_options = QString(" border=\"%1\" cellspacing=\"%2\"");
00046 const QString html_row_tag = "tr";
00047 const QString html_row_options = "";
00048 const QString html_cell_tag = "td";
00049 const QString html_cell_options = "";
00050 const QString html_bold = "b";
00051 const QString html_italic = "i";
00052 const QString html_underline = "u";
00053 const QString html_right= "right";
00054 const QString html_left= "left";
00055 const QString html_center= "center";
00056 const QString html_top="top";
00057 const QString html_bottom="bottom";
00058 const QString html_middle="middle";
00059 const QString html_h1="h1";
00060
00061 HTMLExport::HTMLExport(KoFilter *, const char *, const QStringList&) :
00062 KoFilter(), m_dialog( new ExportDialog() )
00063 {
00064 }
00065
00066 HTMLExport::~HTMLExport()
00067 {
00068 delete m_dialog;
00069 }
00070
00071
00072 const QString strAmp ("&");
00073 const QString nbsp (" ");
00074 const QString strLt ("<");
00075 const QString strGt (">");
00076
00077
00078
00079 KoFilter::ConversionStatus HTMLExport::convert( const QCString& from, const QCString& to )
00080 {
00081 if(to!="text/html" || from!="application/x-kspread")
00082 {
00083 kdWarning(30501) << "Invalid mimetypes " << to << " " << from << endl;
00084 return KoFilter::NotImplemented;
00085 }
00086
00087 KoDocument* document = m_chain->inputDocument();
00088
00089 if ( !document )
00090 return KoFilter::StupidError;
00091
00092 if( !::qt_cast<const KSpread::Doc *>( document ) )
00093 {
00094 kdWarning(30501) << "document isn't a KSpread::Doc but a " << document->className() << endl;
00095 return KoFilter::NotImplemented;
00096 }
00097
00098 const Doc * ksdoc=static_cast<const Doc *>(document);
00099
00100 if( ksdoc->mimeType() != "application/x-kspread" )
00101 {
00102 kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
00103 return KoFilter::NotImplemented;
00104 }
00105
00106 Sheet *sheet = ksdoc->map()->firstSheet();
00107 QString filenameBase = m_chain->outputFile();
00108 filenameBase = filenameBase.left( filenameBase.findRev( '.' ) );
00109
00110 QStringList sheets;
00111 while( sheet != 0 )
00112 {
00113 int rows = 0;
00114 int columns = 0;
00115 detectFilledCells( sheet, rows, columns );
00116 m_rowmap[ sheet->sheetName() ] = rows;
00117 m_columnmap[ sheet->sheetName() ] = columns;
00118
00119 if( rows > 0 && columns > 0 )
00120 {
00121 sheets.append( sheet->sheetName() );
00122 }
00123 sheet = ksdoc->map()->nextSheet();
00124 }
00125 m_dialog->setSheets( sheets );
00126
00127 if( m_dialog->exec() == QDialog::Rejected )
00128 return KoFilter::UserCancelled;
00129
00130 sheets = m_dialog->sheets();
00131 QString str;
00132 for( uint i = 0; i < sheets.count() ; ++i )
00133 {
00134 sheet = ksdoc->map()->findSheet( sheets[i] );
00135
00136 QString file = fileName( filenameBase, sheet->sheetName(), sheets.count() > 1 );
00137
00138 if( m_dialog->separateFiles() || sheets[i] == sheets.first() )
00139 {
00140 str = QString::null;
00141 openPage( sheet, document, str );
00142 writeTOC( sheets, filenameBase, str );
00143 }
00144
00145 convertSheet( sheet, str, m_rowmap[ sheet->sheetName() ], m_columnmap[ sheet->sheetName() ] );
00146
00147 if( m_dialog->separateFiles() || sheets[i] == sheets.last() )
00148 {
00149 closePage( str );
00150 QFile out(file);
00151 if(!out.open(IO_WriteOnly)) {
00152 kdError(30501) << "Unable to open output file!" << endl;
00153 out.close();
00154 return KoFilter::FileNotFound;
00155 }
00156 QTextStream streamOut(&out);
00157 streamOut.setCodec( m_dialog->encoding() );
00158 streamOut << str << endl;
00159 out.close();
00160 }
00161
00162 if( !m_dialog->separateFiles() )
00163 {
00164 createSheetSeparator( str );
00165 }
00166
00167 }
00168
00169 emit sigProgress(100);
00170 return KoFilter::OK;
00171 }
00172
00173 void HTMLExport::openPage( Sheet *sheet, KoDocument *document, QString &str )
00174 {
00175 QString title;
00176 KoDocumentInfo *info = document->documentInfo();
00177 KoDocumentInfoAbout *aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
00178 if ( aboutPage && !aboutPage->title().isEmpty() )
00179 title = aboutPage->title() + " - ";
00180
00181 title += sheet->sheetName();
00182
00183
00184 str = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" ";
00185 str += " \"http://www.w3.org/TR/html4/loose.dtd\"> \n";
00186 str += "<html>\n";
00187 str += "<head>\n";
00188 str += "<meta http-equiv=\"Content-Type\" ";
00189 str += QString("content=\"text/html; charset=%1\">\n").arg( m_dialog->encoding()->mimeName() );
00190 str += "<meta name=\"Generator\" ";
00191 str += "content=\"KSpread HTML Export Filter Version = ";
00192 str += KOFFICE_VERSION_STRING;
00193 str += "\">\n";
00194
00195
00196 if( !m_dialog->customStyleURL().isEmpty() )
00197 {
00198 str += "<link ref=\"stylesheet\" type=\"text/css\" href=\"";
00199 str += m_dialog->customStyleURL();
00200 str += "\" title=\"Style\" >\n";
00201 }
00202
00203 str += "<title>" + title + "</title>\n";
00204 str += "</head>\n";
00205 str += QString("<body bgcolor=\"#FFFFFF\" dir=\"%1\">\n").arg(
00206 sheet->isRightToLeft()?"rtl":"ltr");
00207
00208 str += "<a name=\"__top\">\n";
00209 }
00210
00211 void HTMLExport::closePage( QString &str )
00212 {
00213 str += "<p align=\"" + html_center + "\"><a href=\"#__top\">" + i18n("Top") + "</a></p>\n";
00214 str += "</body>\n";
00215 str += "</html>\n\n";
00216 }
00217
00218 void HTMLExport::convertSheet( Sheet *sheet, QString &str, int iMaxUsedRow, int iMaxUsedColumn )
00219 {
00220 QString emptyLines;
00221
00222
00223
00224 int iMaxRow = sheet->maxRow();
00225
00226 if( !m_dialog->separateFiles() )
00227 str += "<a name=\"" + sheet->sheetName().lower().stripWhiteSpace() + "\">\n";
00228
00229 str += ("<h1>" + sheet->sheetName() + "</h1><br>\n");
00230
00231
00232
00233 int value=0;
00234 int step=iMaxRow > 50 ? iMaxRow/50 : 1;
00235 int i=1;
00236
00237 str += "<" + html_table_tag + html_table_options.arg( m_dialog->useBorders() ? "1" : "0" ).arg( m_dialog->pixelsBetweenCells() ) +
00238 QString("dir=\"%1\">\n").arg(sheet->isRightToLeft()?"rtl":"ltr");
00239
00240 unsigned int nonempty_cells_prev=0;
00241
00242 for ( int currentrow = 1 ; currentrow <= iMaxUsedRow ; ++currentrow, ++i )
00243 {
00244 if(i>step) {
00245 value+=2;
00246 emit sigProgress(value);
00247 i=0;
00248 }
00249
00250 QString separators;
00251 QString line;
00252 unsigned int nonempty_cells=0;
00253 unsigned int colspan_cells=0;
00254
00255 for ( int currentcolumn = 1 ; currentcolumn <= iMaxUsedColumn ; currentcolumn++ )
00256 {
00257 Cell * cell = sheet->cellAt( currentcolumn, currentrow, false );
00258 colspan_cells=cell->extraXCells();
00259 if (cell->needsPrinting())
00260 nonempty_cells++;
00261 QString text;
00262 QColor bgcolor = cell->bgColor(currentcolumn,currentrow);
00263
00264
00265 bool link = false;
00266
00267 if ( !cell->link().isEmpty() )
00268 {
00269 if ( localReferenceAnchor(cell->link()) )
00270 {
00271 text = cell->text();
00272 }
00273 else
00274 {
00275 text = " <A href=\"" + cell->link() + "\">" + cell->text() + "</A>";
00276 link = true;
00277 }
00278 }
00279 else
00280 text=cell->strOutText();
00281 #if 0
00282 switch( cell->content() ) {
00283 case Cell::Text:
00284 text = cell->text();
00285 break;
00286 case Cell::RichText:
00287 case Cell::VisualFormula:
00288 text = cell->text();
00289 break;
00290 case Cell::Formula:
00291 cell->calc( TRUE );
00292 text = cell->valueString();
00293 break;
00294 }
00295 text = cell->prefix(currentrow, currentcolumn) + " " + text + " "
00296 + cell->postfix(currentrow, currentcolumn);
00297 #endif
00298 line += " <" + html_cell_tag + html_cell_options;
00299 if (text.isRightToLeft() != sheet->isRightToLeft())
00300 line += QString(" dir=\"%1\" ").arg(text.isRightToLeft()?"rtl":"ltr");
00301 if (bgcolor.isValid() && bgcolor.name()!="#ffffff")
00302 line += " bgcolor=\"" + bgcolor.name() + "\"";
00303
00304 switch((Format::Align)cell->defineAlignX())
00305 {
00306 case Format::Left:
00307 line+=" align=\"" + html_left +"\"";
00308 break;
00309 case Format::Right:
00310 line+=" align=\"" + html_right +"\"";
00311 break;
00312 case Format::Center:
00313 line+=" align=\"" + html_center +"\"";
00314 break;
00315 case Format::Undefined:
00316 break;
00317 }
00318 switch((Format::AlignY)cell-> format()->alignY(currentrow, currentcolumn))
00319 {
00320 case Format::Top:
00321 line+=" valign=\"" + html_top +"\"";
00322 break;
00323 case Format::Middle:
00324 line+=" valign=\"" + html_middle +"\"";
00325 break;
00326 case Format::Bottom:
00327 line+=" valign=\"" + html_bottom +"\"";
00328 break;
00329 case Format::UndefinedY:
00330 break;
00331 }
00332 line+=" width=\""+QString::number(cell->width())+"\"";
00333 line+=" height=\""+QString::number(cell->height())+"\"";
00334
00335 if (cell->extraXCells()>0)
00336 {
00337 QString tmp;
00338 int extra_cells=cell->extraXCells();
00339 line += " colspan=\"" + tmp.setNum(extra_cells+1) + "\"";
00340 currentcolumn += extra_cells;
00341 }
00342 text = text.stripWhiteSpace();
00343 if( text.at(0) == '!' ) {
00344
00345 text = text.right(text.length()-1);
00346 } else if ( !link ) {
00347
00348 text.replace ('&' , strAmp)
00349 .replace ('<' , strLt)
00350 .replace ('>' , strGt)
00351 .replace (' ' , nbsp);
00352 }
00353 line += ">\n";
00354
00355 if (cell->format()->textFontBold(currentcolumn,currentrow))
00356 {
00357 text.insert(0, "<" + html_bold + ">");
00358 text.append("</" + html_bold + ">");
00359 }
00360 if (cell->format()->textFontItalic(currentcolumn,currentrow))
00361 {
00362 text.insert(0, "<" + html_italic + ">");
00363 text.append("</" + html_italic + ">");
00364 }
00365 if (cell->format()->textFontUnderline(currentcolumn,currentrow))
00366 {
00367 text.insert(0, "<" + html_underline + ">");
00368 text.append("</" + html_underline + ">");
00369 }
00370 QColor textColor = cell->format()->textColor(currentcolumn,currentrow);
00371 if (textColor.isValid() && textColor.name()!="#000000")
00372 {
00373 text.insert(0, "<font color=\"" + textColor.name() + "\">");
00374 text.append("</font>");
00375 }
00376 line += " " + text;
00377 line += "\n </" + html_cell_tag + ">\n";
00378 }
00379
00380 if (nonempty_cells == 0 && nonempty_cells_prev == 0) {
00381 nonempty_cells_prev = nonempty_cells;
00382
00383 continue;
00384 } else {
00385 nonempty_cells_prev = nonempty_cells;
00386 str += emptyLines;
00387 str += "<" + html_row_tag + html_row_options + ">\n";
00388 str += line;
00389 str += "</" + html_row_tag + ">";
00390 emptyLines = QString::null;
00391
00392
00393 emptyLines += "\n";
00394 }
00395 }
00396 str += "\n</" + html_table_tag + ">\n<br>\n";
00397 }
00398
00399 void HTMLExport::createSheetSeparator( QString &str )
00400 {
00401 str += ("<p align=\"" + html_center + "\"><a href=\"#__top\">" + i18n("Top") + "</a></p>\n" );
00402 str += "<hr width=\"80%\">\n";
00403 }
00404
00405 void HTMLExport::writeTOC( const QStringList &sheets, const QString &base, QString &str )
00406 {
00407
00408 if( sheets.count() == 1 )
00409 return;
00410
00411 str += "<p align=\"" + html_center + "\">\n";
00412
00413 for( uint i = 0 ; i < sheets.count() ; ++i )
00414 {
00415 str += "<a href=\"";
00416
00417 if( m_dialog->separateFiles() )
00418 {
00419 str += fileName( base, sheets[i], sheets.count() > 1 );
00420 }
00421 else
00422 {
00423 str += "#" + sheets[i].lower().stripWhiteSpace();
00424 }
00425
00426 str += "\">" + sheets[i] + "</a>\n";
00427 if( i != sheets.count() -1 )
00428 str += " - ";
00429 }
00430
00431 str += "</p><hr width=\"80%\">\n";
00432 }
00433
00434 QString HTMLExport::fileName( const QString &base, const QString &sheetName, bool multipleFiles )
00435 {
00436 QString fileName = base;
00437 if( m_dialog->separateFiles() && multipleFiles )
00438 {
00439 fileName += "-" + sheetName;
00440 }
00441 fileName += ".html";
00442
00443 return fileName;
00444 }
00445
00446 void HTMLExport::detectFilledCells( Sheet *sheet, int &rows, int &columns )
00447 {
00448 int iMaxColumn = sheet->maxColumn();
00449 int iMaxRow = sheet->maxRow();
00450 rows = 0;
00451 columns = 0;
00452
00453 for ( int currentrow = 1 ; currentrow <= iMaxRow ; ++currentrow)
00454 {
00455 Cell * cell = 0L;
00456 int iUsedColumn=0;
00457 for ( int currentcolumn = 1 ; currentcolumn <= iMaxColumn ; currentcolumn++ )
00458 {
00459 cell = sheet->cellAt( currentcolumn, currentrow, false );
00460 QString text;
00461 if ( !cell->isDefault() && !cell->isEmpty() )
00462 {
00463 iUsedColumn = currentcolumn;
00464 }
00465 }
00466 if (cell)
00467 iUsedColumn += cell->extraXCells();
00468 if (iUsedColumn > columns)
00469 columns = iUsedColumn;
00470 if ( iUsedColumn > 0 )
00471 rows = currentrow;
00472 }
00473 }
00474
00475 #include <htmlexport.moc>