00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "document.h"
00021 #include "conversion.h"
00022 #include "texthandler.h"
00023 #include "graphicshandler.h"
00024 #include "versionmagic.h"
00025
00026 #include <KoRect.h>
00027 #include <KoUnit.h>
00028 #include <KoPageLayout.h>
00029 #include <kdebug.h>
00030
00031 #include <wv2/styles.h>
00032 #include <wv2/ustring.h>
00033 #include <wv2/word97_generated.h>
00034 #include <wv2/parser.h>
00035 #include <wv2/parserfactory.h>
00036 #include <wv2/paragraphproperties.h>
00037 #include <wv2/associatedstrings.h>
00038 #include <klocale.h>
00039 #include <KoStore.h>
00040 #include <KoFilterChain.h>
00041
00042
00043 Document::Document( const std::string& fileName, QDomDocument& mainDocument, QDomDocument& documentInfo, QDomElement& framesetsElement, KoFilterChain* chain )
00044 : m_mainDocument( mainDocument ), m_documentInfo ( documentInfo ),
00045 m_framesetsElement( framesetsElement ),
00046 m_replacementHandler( new KWordReplacementHandler ), m_tableHandler( new KWordTableHandler ),
00047 m_pictureHandler( new KWordPictureHandler( this ) ), m_textHandler( 0 ),
00048 m_chain( chain ),
00049 m_parser( wvWare::ParserFactory::createParser( fileName ) ), m_headerFooters( 0 ), m_bodyFound( false ),
00050 m_footNoteNumber( 0 ), m_endNoteNumber( 0 )
00051 {
00052 if ( m_parser )
00053 {
00054 m_textHandler = new KWordTextHandler( m_parser );
00055 connect( m_textHandler, SIGNAL( subDocFound( const wvWare::FunctorBase*, int ) ),
00056 this, SLOT( slotSubDocFound( const wvWare::FunctorBase*, int ) ) );
00057 connect( m_textHandler, SIGNAL( tableFound( const KWord::Table& ) ),
00058 this, SLOT( slotTableFound( const KWord::Table& ) ) );
00059 connect( m_textHandler, SIGNAL( pictureFound( const QString&, const QString&, const wvWare::FunctorBase* ) ),
00060 this, SLOT( slotPictureFound( const QString&, const QString&, const wvWare::FunctorBase* ) ) );
00061 m_parser->setSubDocumentHandler( this );
00062 m_parser->setTextHandler( m_textHandler );
00063 m_parser->setTableHandler( m_tableHandler );
00064 #ifdef IMAGE_IMPORT
00065 m_parser->setPictureHandler( m_pictureHandler );
00066 #endif
00067 m_parser->setInlineReplacementHandler( m_replacementHandler );
00068 processStyles();
00069 processAssociatedStrings();
00070 connect( m_tableHandler, SIGNAL( sigTableCellStart( int, int, int, int, const KoRect&, const QString&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::SHD& ) ),
00071 this, SLOT( slotTableCellStart( int, int, int, int, const KoRect&, const QString&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::BRC&, const wvWare::Word97::SHD& ) ) );
00072 connect( m_tableHandler, SIGNAL( sigTableCellEnd() ),
00073 this, SLOT( slotTableCellEnd() ) );
00074 }
00075 }
00076
00077 Document::~Document()
00078 {
00079 delete m_textHandler;
00080 delete m_pictureHandler;
00081 delete m_tableHandler;
00082 delete m_replacementHandler;
00083 }
00084
00085 void Document::finishDocument()
00086 {
00087 const wvWare::Word97::DOP& dop = m_parser->dop();
00088
00089 QDomElement elementDoc = m_mainDocument.documentElement();
00090
00091 QDomElement element;
00092 element = m_mainDocument.createElement("ATTRIBUTES");
00093 element.setAttribute("processing",0);
00094 char allHeaders = ( wvWare::HeaderData::HeaderEven |
00095 wvWare::HeaderData::HeaderOdd |
00096 wvWare::HeaderData::HeaderFirst );
00097 element.setAttribute("hasHeader", m_headerFooters & allHeaders ? 1 : 0 );
00098 char allFooters = ( wvWare::HeaderData::FooterEven |
00099 wvWare::HeaderData::FooterOdd |
00100 wvWare::HeaderData::FooterFirst );
00101 element.setAttribute("hasFooter", m_headerFooters & allFooters ? 1 : 0 );
00102
00103
00104 element.setAttribute("tabStopValue", (double)dop.dxaTab / 20.0 );
00105 elementDoc.appendChild(element);
00106
00107 element = m_mainDocument.createElement("FOOTNOTESETTING");
00108 elementDoc.appendChild(element);
00109 element.setAttribute( "start", dop.nFtn );
00110 element.setAttribute( "type", Conversion::numberFormatCode( dop.nfcFtnRef2 ) );
00111
00112 element = m_mainDocument.createElement("ENDNOTESETTING");
00113 elementDoc.appendChild(element);
00114 element.setAttribute( "start", dop.nEdn );
00115 element.setAttribute( "type", Conversion::numberFormatCode( dop.nfcEdnRef2 ) );
00116
00117
00118
00119 QDomElement paperElement = elementDoc.namedItem("PAPER").toElement();
00120 Q_ASSERT ( !paperElement.isNull() );
00121 if ( !paperElement.isNull() )
00122 {
00123 kdDebug(30513) << k_funcinfo << "m_headerFooters=" << m_headerFooters << endl;
00124 paperElement.setAttribute("hType", Conversion::headerMaskToHType( m_headerFooters ) );
00125 paperElement.setAttribute("fType", Conversion::headerMaskToFType( m_headerFooters ) );
00126 }
00127
00128
00129 QDomElement picturesElem = m_mainDocument.createElement("PICTURES");
00130 elementDoc.appendChild( picturesElem );
00131 for( QStringList::Iterator it = m_pictureList.begin(); it != m_pictureList.end(); ++it ) {
00132 QDomElement keyElem = m_mainDocument.createElement("KEY");
00133 picturesElem.appendChild( keyElem );
00134 keyElem.setAttribute( "filename", *it );
00135 keyElem.setAttribute( "name", *it );
00136 }
00137 }
00138
00139 void Document::processAssociatedStrings() {
00140 wvWare::AssociatedStrings strings( m_parser->associatedStrings() );
00141
00142 QDomElement infodoc = m_documentInfo.createElement( "document-info" );
00143 QDomElement author = m_documentInfo.createElement( "author" );
00144 QDomElement fullname = m_documentInfo.createElement( "full-name" );
00145 QDomElement title = m_documentInfo.createElement( "title" );
00146 QDomElement about = m_documentInfo.createElement( "about" );
00147
00148 m_documentInfo.appendChild(infodoc);
00149
00150 if ( !strings.author().isNull()) {
00151 fullname.appendChild(
00152 m_documentInfo.createTextNode(
00153 Conversion::string (
00154 strings.author()
00155 ).string()));
00156 author.appendChild(fullname);
00157 infodoc.appendChild(author);
00158 }
00159
00160 if ( !strings.title().isNull()) {
00161 title.appendChild(
00162 m_documentInfo.createTextNode(
00163 Conversion::string (
00164 strings.title()
00165 ).string()));
00166 about.appendChild(title);
00167 infodoc.appendChild(about);
00168 }
00169
00170 }
00171
00172 void Document::processStyles()
00173 {
00174 QDomElement stylesElem = m_mainDocument.createElement( "STYLES" );
00175 m_mainDocument.documentElement().appendChild( stylesElem );
00176
00177 m_textHandler->setFrameSetElement( stylesElem );
00178 const wvWare::StyleSheet& styles = m_parser->styleSheet();
00179 unsigned int count = styles.size();
00180
00181 for ( unsigned int i = 0; i < count ; ++i )
00182 {
00183 const wvWare::Style* style = styles.styleByIndex( i );
00184 Q_ASSERT( style );
00185
00186 if ( style && style->type() == wvWare::Style::sgcPara )
00187 {
00188 QDomElement styleElem = m_mainDocument.createElement("STYLE");
00189 stylesElem.appendChild( styleElem );
00190
00191 QConstString name = Conversion::string( style->name() );
00192 QDomElement element = m_mainDocument.createElement("NAME");
00193 element.setAttribute( "value", name.string() );
00194 styleElem.appendChild( element );
00195
00196 kdDebug(30513) << k_funcinfo << "Style " << i << ": " << name.string() << endl;
00197
00198 const wvWare::Style* followingStyle = styles.styleByID( style->followingStyle() );
00199 if ( followingStyle && followingStyle != style )
00200 {
00201 QConstString followingName = Conversion::string( followingStyle->name() );
00202 element = m_mainDocument.createElement("FOLLOWING");
00203 element.setAttribute( "name", followingName.string() );
00204 styleElem.appendChild( element );
00205 }
00206
00207 m_textHandler->paragLayoutBegin();
00208
00209
00210 m_textHandler->writeFormat( styleElem, &style->chp(), 0L , 0, 0, 1, 0L );
00211
00212 m_textHandler->writeLayout( styleElem, style->paragraphProperties(), style );
00213 }
00214
00215 }
00216 }
00217
00218 bool Document::parse()
00219 {
00220 if ( m_parser )
00221 return m_parser->parse();
00222 return false;
00223 }
00224
00225 void Document::bodyStart()
00226 {
00227 kdDebug(30513) << k_funcinfo << endl;
00228
00229 QDomElement mainFramesetElement = m_mainDocument.createElement("FRAMESET");
00230 mainFramesetElement.setAttribute("frameType",1);
00231 mainFramesetElement.setAttribute("frameInfo",0);
00232
00233 m_framesetsElement.appendChild(mainFramesetElement);
00234
00235
00236 createInitialFrame( mainFramesetElement, 29, 798, 42, 566, false, Reconnect );
00237
00238 m_textHandler->setFrameSetElement( mainFramesetElement );
00239 connect( m_textHandler, SIGNAL( firstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> ) ),
00240 this, SLOT( slotFirstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> ) ) );
00241 m_bodyFound = true;
00242 }
00243
00244 void Document::bodyEnd()
00245 {
00246 kdDebug(30513) << k_funcinfo << endl;
00247 disconnect( m_textHandler, SIGNAL( firstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> ) ),
00248 this, SLOT( slotFirstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> ) ) );
00249 }
00250
00251
00252 void Document::slotFirstSectionFound( wvWare::SharedPtr<const wvWare::Word97::SEP> sep )
00253 {
00254 kdDebug(30513) << k_funcinfo << endl;
00255 QDomElement elementDoc = m_mainDocument.documentElement();
00256
00257 QDomElement elementPaper = m_mainDocument.createElement("PAPER");
00258 bool landscape = (sep->dmOrientPage == 2);
00259 double width = (double)sep->xaPage / 20.0;
00260 double height = (double)sep->yaPage / 20.0;
00261 elementPaper.setAttribute("width", width);
00262 elementPaper.setAttribute("height", height);
00263
00264
00265 width = POINT_TO_MM( width );
00266 height = POINT_TO_MM( height );
00267 KoFormat paperFormat = KoPageFormat::guessFormat( landscape ? height : width, landscape ? width : height );
00268 elementPaper.setAttribute("format",paperFormat);
00269
00270 elementPaper.setAttribute("orientation", landscape ? PG_LANDSCAPE : PG_PORTRAIT );
00271 elementPaper.setAttribute("columns", sep->ccolM1 + 1 );
00272 elementPaper.setAttribute("columnspacing", (double)sep->dxaColumns / 20.0);
00273 elementPaper.setAttribute("spHeadBody", (double)sep->dyaHdrTop / 20.0);
00274 elementPaper.setAttribute("spFootBody", (double)sep->dyaHdrBottom / 20.0);
00275
00276 elementDoc.appendChild(elementPaper);
00277
00278 QDomElement element = m_mainDocument.createElement("PAPERBORDERS");
00279 element.setAttribute("left", (double)sep->dxaLeft / 20.0);
00280 element.setAttribute("top",(double)sep->dyaTop / 20.0);
00281 element.setAttribute("right", (double)sep->dxaRight / 20.0);
00282 element.setAttribute("bottom", (double)sep->dyaBottom / 20.0);
00283 elementPaper.appendChild(element);
00284
00285
00286
00287 }
00288
00289 void Document::headerStart( wvWare::HeaderData::Type type )
00290 {
00291 kdDebug(30513) << "startHeader type=" << type << " (" << Conversion::headerTypeToFramesetName( type ) << ")" << endl;
00292
00293
00294 QDomElement framesetElement = m_mainDocument.createElement("FRAMESET");
00295 framesetElement.setAttribute( "frameType", 1 );
00296 framesetElement.setAttribute( "frameInfo", Conversion::headerTypeToFrameInfo( type ) );
00297 framesetElement.setAttribute( "name", Conversion::headerTypeToFramesetName( type ) );
00298 m_framesetsElement.appendChild(framesetElement);
00299
00300 bool isHeader = Conversion::isHeader( type );
00301
00302 createInitialFrame( framesetElement, 29, 798, isHeader?0:567, isHeader?41:567+41, true, Copy );
00303
00304 m_textHandler->setFrameSetElement( framesetElement );
00305
00306 m_headerFooters |= type;
00307
00308
00309
00310
00311
00312 }
00313
00314 void Document::headerEnd()
00315 {
00316 m_textHandler->setFrameSetElement( QDomElement() );
00317 }
00318
00319 void Document::footnoteStart()
00320 {
00321
00322 SubDocument subdoc( m_subdocQueue.front() );
00323 int type = subdoc.data;
00324
00325
00326 QDomElement framesetElement = m_mainDocument.createElement("FRAMESET");
00327 framesetElement.setAttribute( "frameType", 1 );
00328 framesetElement.setAttribute( "frameInfo", 7 );
00329 if ( type == wvWare::FootnoteData::Endnote )
00330
00331 framesetElement.setAttribute("name", i18n("Endnote %1").arg( ++m_endNoteNumber ) );
00332 else
00333
00334 framesetElement.setAttribute("name", i18n("Footnote %1").arg( ++m_footNoteNumber ) );
00335 m_framesetsElement.appendChild(framesetElement);
00336
00337 createInitialFrame( framesetElement, 29, 798, 567, 567+41, true, NoFollowup );
00338
00339 m_textHandler->setFrameSetElement( framesetElement );
00340 }
00341
00342 void Document::footnoteEnd()
00343 {
00344 kdDebug(30513) << k_funcinfo << endl;
00345 m_textHandler->setFrameSetElement( QDomElement() );
00346 }
00347
00348 void Document::slotTableCellStart( int row, int column, int rowSpan, int columnSpan, const KoRect& cellRect, const QString& tableName, const wvWare::Word97::BRC& brcTop, const wvWare::Word97::BRC& brcBottom, const wvWare::Word97::BRC& brcLeft, const wvWare::Word97::BRC& brcRight, const wvWare::Word97::SHD& shd )
00349 {
00350
00351 QDomElement framesetElement = m_mainDocument.createElement("FRAMESET");
00352 framesetElement.setAttribute( "frameType", 1 );
00353 framesetElement.setAttribute( "frameInfo", 0 );
00354 framesetElement.setAttribute( "grpMgr", tableName );
00355 QString name = i18n("Table_Name Cell row,column", "%1 Cell %2,%3").arg(tableName).arg(row).arg(column);
00356 framesetElement.setAttribute( "name", name );
00357 framesetElement.setAttribute( "row", row );
00358 framesetElement.setAttribute( "col", column );
00359 framesetElement.setAttribute( "rows", rowSpan );
00360 framesetElement.setAttribute( "cols", columnSpan );
00361 m_framesetsElement.appendChild(framesetElement);
00362
00363 QDomElement frameElem = createInitialFrame( framesetElement, cellRect.left(), cellRect.right(), cellRect.top(), cellRect.bottom(), true, NoFollowup );
00364 generateFrameBorder( frameElem, brcTop, brcBottom, brcLeft, brcRight, shd );
00365
00366 m_textHandler->setFrameSetElement( framesetElement );
00367 }
00368
00369 void Document::slotTableCellEnd()
00370 {
00371 m_textHandler->setFrameSetElement( QDomElement() );
00372 }
00373
00374 QDomElement Document::createInitialFrame( QDomElement& parentFramesetElem, double left, double right, double top, double bottom, bool autoExtend, NewFrameBehavior nfb )
00375 {
00376 QDomElement frameElementOut = parentFramesetElem.ownerDocument().createElement("FRAME");
00377 frameElementOut.setAttribute( "left", left );
00378 frameElementOut.setAttribute( "right", right );
00379 frameElementOut.setAttribute( "top", top );
00380 frameElementOut.setAttribute( "bottom", bottom );
00381 frameElementOut.setAttribute( "runaround", 1 );
00382
00383 frameElementOut.setAttribute( "autoCreateNewFrame", autoExtend ? 0 : 1 );
00384 frameElementOut.setAttribute( "newFrameBehavior", nfb );
00385 parentFramesetElem.appendChild( frameElementOut );
00386 return frameElementOut;
00387 }
00388
00389 void Document::generateFrameBorder( QDomElement& frameElementOut, const wvWare::Word97::BRC& brcTop, const wvWare::Word97::BRC& brcBottom, const wvWare::Word97::BRC& brcLeft, const wvWare::Word97::BRC& brcRight, const wvWare::Word97::SHD& shd )
00390 {
00391
00392
00393 if ( brcTop.ico != 255 && brcTop.dptLineWidth != 255 )
00394 Conversion::setBorderAttributes( frameElementOut, brcTop, "t" );
00395 if ( brcBottom.ico != 255 && brcBottom.dptLineWidth != 255 )
00396 Conversion::setBorderAttributes( frameElementOut, brcBottom, "b" );
00397 if ( brcLeft.ico != 255 && brcLeft.dptLineWidth != 255 )
00398 Conversion::setBorderAttributes( frameElementOut, brcLeft, "l" );
00399 if ( brcRight.ico != 255 && brcRight.dptLineWidth != 255 )
00400 Conversion::setBorderAttributes( frameElementOut, brcRight, "r" );
00401
00402
00403 if ( shd.icoFore != 0 || shd.icoBack != 0 )
00404 {
00405
00406
00407
00408
00409 int bkColor = shd.ipat ? shd.icoFore : shd.icoBack;
00410 kdDebug(30513) << "generateFrameBorder: " << " icoFore=" << shd.icoFore << " icoBack=" << shd.icoBack << " ipat=" << shd.ipat << " -> bkColor=" << bkColor << endl;
00411
00412
00413
00414 bool grayHack = ( shd.ipat && shd.icoFore == 1 && shd.icoBack == 8 );
00415 if ( grayHack )
00416 {
00417 bool ok;
00418 int grayLevel = Conversion::ditheringToGray( shd.ipat, &ok );
00419 if ( ok )
00420 {
00421 QColor color( 0, 0, grayLevel, QColor::Hsv );
00422 QString prefix = "bk";
00423 frameElementOut.setAttribute( "bkRed", color.red() );
00424 frameElementOut.setAttribute( "bkBlue", color.blue() );
00425 frameElementOut.setAttribute( "bkGreen", color.green() );
00426 }
00427 else grayHack = false;
00428 }
00429 if ( !grayHack )
00430 {
00431 Conversion::setColorAttributes( frameElementOut, bkColor, "bk", true );
00432
00433 int brushStyle = Conversion::fillPatternStyle( shd.ipat );
00434 frameElementOut.setAttribute( "bkStyle", brushStyle );
00435 }
00436 }
00437 }
00438
00439 void Document::slotSubDocFound( const wvWare::FunctorBase* functor, int data )
00440 {
00441 SubDocument subdoc( functor, data, QString::null, QString::null );
00442 m_subdocQueue.push( subdoc );
00443 }
00444
00445 void Document::slotTableFound( const KWord::Table& table )
00446 {
00447 m_tableQueue.push( table );
00448 }
00449
00450 void Document::slotPictureFound( const QString& frameName, const QString& pictureName,
00451 const wvWare::FunctorBase* pictureFunctor )
00452 {
00453 SubDocument subdoc( pictureFunctor, 0, frameName, pictureName );
00454 m_subdocQueue.push( subdoc );
00455 }
00456
00457 void Document::processSubDocQueue()
00458 {
00459
00460
00461 while ( !m_subdocQueue.empty() || !m_tableQueue.empty() )
00462 {
00463 while ( !m_subdocQueue.empty() )
00464 {
00465 SubDocument subdoc( m_subdocQueue.front() );
00466 Q_ASSERT( subdoc.functorPtr );
00467 (*subdoc.functorPtr)();
00468 delete subdoc.functorPtr;
00469 m_subdocQueue.pop();
00470 }
00471 while ( !m_tableQueue.empty() )
00472 {
00473 KWord::Table& table = m_tableQueue.front();
00474 m_tableHandler->tableStart( &table );
00475 QValueList<KWord::Row> &rows = table.rows;
00476 for( QValueList<KWord::Row>::Iterator it = rows.begin(); it != rows.end(); ++it ) {
00477 KWord::TableRowFunctorPtr f = (*it).functorPtr;
00478 Q_ASSERT( f );
00479 (*f)();
00480 delete f;
00481 }
00482 m_tableHandler->tableEnd();
00483 m_tableQueue.pop();
00484 }
00485 }
00486 }
00487
00488 KoStoreDevice* Document::createPictureFrameSet( const KoSize& size )
00489 {
00490
00491 SubDocument subdoc( m_subdocQueue.front() );
00492
00493 QDomElement framesetElement = m_mainDocument.createElement("FRAMESET");
00494 framesetElement.setAttribute( "frameType", 2 );
00495 framesetElement.setAttribute( "frameInfo", 0 );
00496 framesetElement.setAttribute( "name", subdoc.name );
00497 m_framesetsElement.appendChild(framesetElement);
00498
00499
00500
00501
00502
00503
00504 createInitialFrame( framesetElement, 0, size.width(), 0, size.height(), false, NoFollowup );
00505
00506 QDomElement pictureElem = m_mainDocument.createElement("PICTURE");
00507 framesetElement.appendChild( pictureElem );
00508
00509 QDomElement keyElem = m_mainDocument.createElement("KEY");
00510 pictureElem.appendChild( keyElem );
00511 keyElem.setAttribute( "filename", subdoc.extraName );
00512 m_pictureList.append( subdoc.extraName );
00513
00514 kdDebug(30513) << "Preparing to write picture for '" << subdoc.name << "' into " << subdoc.extraName << endl;
00515 return m_chain->storageFile( subdoc.extraName, KoStore::Write );
00516 }
00517
00518
00519 #include "document.moc"