00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <qmetaobject.h>
00020 #include <ktempfile.h>
00021 #include <kmimetype.h>
00022 #include <koFilterChain.h>
00023 #include <koQueryTrader.h>
00024 #include <koFilterManager.h>
00025 #include <koDocument.h>
00026 #include <kdebug.h>
00027
00028 #include <priorityqueue.h>
00029
00030 #include <limits.h>
00031
00032
00033
00034 namespace {
00035 const char* const SIGNAL_PREFIX = "commSignal";
00036 const int SIGNAL_PREFIX_LEN = 10;
00037 const char* const SLOT_PREFIX = "commSlot";
00038 const int SLOT_PREFIX_LEN = 8;
00039 }
00040
00041
00042 KoFilterChain::ChainLink::ChainLink( KoFilterChain* chain, KoFilterEntry::Ptr filterEntry,
00043 const QCString& from, const QCString& to ) :
00044 m_chain( chain ), m_filterEntry( filterEntry ), m_from( from ), m_to( to ),
00045 m_filter( 0 ), d( 0 )
00046 {
00047 }
00048
00049 KoFilter::ConversionStatus KoFilterChain::ChainLink::invokeFilter( const ChainLink* const parentChainLink )
00050 {
00051 if ( !m_filterEntry ) {
00052 kdError( 30500 ) << "This filter entry is null. Strange stuff going on." << endl;
00053 return KoFilter::CreationError;
00054 }
00055
00056 m_filter = m_filterEntry->createFilter( m_chain, 0, 0 );
00057
00058 if ( !m_filter ) {
00059 kdError( 30500 ) << "Couldn't create the filter." << endl;
00060 return KoFilter::CreationError;
00061 }
00062
00063 if ( parentChainLink )
00064 setupCommunication( parentChainLink->m_filter );
00065
00066 KoFilter::ConversionStatus status = m_filter->convert( m_from, m_to );
00067 delete m_filter;
00068 m_filter=0;
00069 return status;
00070 }
00071
00072 void KoFilterChain::ChainLink::dump() const
00073 {
00074 kdDebug( 30500 ) << " Link: " << m_filterEntry->service()->name() << endl;
00075 }
00076
00077 int KoFilterChain::ChainLink::lruPartIndex() const
00078 {
00079 if ( m_filter && m_filter->inherits( "KoEmbeddingFilter" ) )
00080 return static_cast<KoEmbeddingFilter*>( m_filter )->lruPartIndex();
00081 return -1;
00082 }
00083
00084 void KoFilterChain::ChainLink::setupCommunication( const KoFilter* const parentFilter ) const
00085 {
00086
00087 QObject::connect( m_filter, SIGNAL( sigProgress( int ) ),
00088 m_chain->manager(), SIGNAL( sigProgress( int ) ) );
00089
00090 if ( !parentFilter )
00091 return;
00092
00093 const QMetaObject* const parent = parentFilter->metaObject();
00094 const QMetaObject* const child = m_filter->metaObject();
00095 if ( !parent || !child )
00096 return;
00097
00098 setupConnections( parentFilter, parent->signalNames(), m_filter, child->slotNames() );
00099 setupConnections( m_filter, child->signalNames(), parentFilter, parent->slotNames() );
00100 }
00101
00102 void KoFilterChain::ChainLink::setupConnections( const KoFilter* sender, const QStrList& sigs,
00103 const KoFilter* receiver, const QStrList& sl0ts ) const
00104 {
00105 QStrListIterator signalIt( sigs );
00106 for ( ; signalIt.current(); ++signalIt ) {
00107 if ( strncmp( signalIt.current(), SIGNAL_PREFIX, SIGNAL_PREFIX_LEN ) == 0 ) {
00108 QStrListIterator slotIt( sl0ts );
00109 for ( ; slotIt.current(); ++slotIt ) {
00110 if ( strncmp( slotIt.current(), SLOT_PREFIX, SLOT_PREFIX_LEN ) == 0 ) {
00111 if ( strcmp( signalIt.current() + SIGNAL_PREFIX_LEN, slotIt.current() + SLOT_PREFIX_LEN ) == 0 ) {
00112 QCString signalString;
00113 signalString.setNum( QSIGNAL_CODE );
00114 signalString += signalIt.current();
00115 QCString slotString;
00116 slotString.setNum( QSLOT_CODE );
00117 slotString += slotIt.current();
00118 QObject::connect( sender, signalString, receiver, slotString );
00119 }
00120 }
00121 }
00122 }
00123 }
00124 }
00125
00126
00127 KoFilterChain::~KoFilterChain()
00128 {
00129 if ( filterManagerParentChain() && filterManagerParentChain()->m_outputStorage )
00130 filterManagerParentChain()->m_outputStorage->leaveDirectory();
00131 manageIO();
00132 }
00133
00134 KoFilter::ConversionStatus KoFilterChain::invokeChain()
00135 {
00136 KoFilter::ConversionStatus status = KoFilter::OK;
00137
00138 m_state = Beginning;
00139 int count = m_chainLinks.count();
00140
00141
00142 const ChainLink* parentChainLink = 0;
00143 if ( filterManagerParentChain() )
00144 parentChainLink = filterManagerParentChain()->m_chainLinks.current();
00145
00146
00147 m_chainLinks.first();
00148 for ( ; count > 1 && m_chainLinks.current() && status == KoFilter::OK;
00149 m_chainLinks.next(), --count ) {
00150 status = m_chainLinks.current()->invokeFilter( parentChainLink );
00151 m_state = Middle;
00152 manageIO();
00153 }
00154
00155 if ( !m_chainLinks.current() ) {
00156 kdWarning( 30500 ) << "Huh?? Found a null pointer in the chain" << endl;
00157 return KoFilter::StupidError;
00158 }
00159
00160 if ( status == KoFilter::OK ) {
00161 if ( m_state & Beginning )
00162 m_state |= End;
00163 else
00164 m_state = End;
00165 status = m_chainLinks.current()->invokeFilter( parentChainLink );
00166 manageIO();
00167 }
00168
00169 m_state = Done;
00170 finalizeIO();
00171 return status;
00172 }
00173
00174 QString KoFilterChain::chainOutput() const
00175 {
00176 if ( m_state == Done )
00177 return m_inputFile;
00178 return QString::null;
00179 }
00180
00181 QString KoFilterChain::inputFile()
00182 {
00183 if ( m_inputQueried == File )
00184 return m_inputFile;
00185 else if ( m_inputQueried != Nil ) {
00186 kdWarning( 30500 ) << "You already asked for some different source." << endl;
00187 return QString::null;
00188 }
00189 m_inputQueried = File;
00190
00191 if ( m_state & Beginning ) {
00192 if ( static_cast<KoFilterManager::Direction>( filterManagerDirection() ) ==
00193 KoFilterManager::Import )
00194 m_inputFile = filterManagerImportFile();
00195 else
00196 inputFileHelper( filterManagerKoDocument(), filterManagerImportFile() );
00197 }
00198 else
00199 if ( m_inputFile.isEmpty() )
00200 inputFileHelper( m_inputDocument, QString::null );
00201
00202 return m_inputFile;
00203 }
00204
00205 QString KoFilterChain::outputFile()
00206 {
00207
00208
00209 if ( filterManagerParentChain() )
00210 kdWarning( 30500 )<< "An embedded filter has to use storageFile()!" << endl;
00211
00212 if ( m_outputQueried == File )
00213 return m_outputFile;
00214 else if ( m_outputQueried != Nil ) {
00215 kdWarning( 30500 ) << "You already asked for some different destination." << endl;
00216 return QString::null;
00217 }
00218 m_outputQueried = File;
00219
00220 if ( m_state & End ) {
00221 if ( static_cast<KoFilterManager::Direction>( filterManagerDirection() ) ==
00222 KoFilterManager::Import )
00223 outputFileHelper( false );
00224 else
00225 m_outputFile = filterManagerExportFile();
00226 }
00227 else
00228 outputFileHelper( true );
00229
00230 return m_outputFile;
00231 }
00232
00233 KoStoreDevice* KoFilterChain::storageFile( const QString& name, KoStore::Mode mode )
00234 {
00235
00236
00237 if ( m_outputQueried == Nil && mode == KoStore::Write && filterManagerParentChain() )
00238 return storageInitEmbedding( name );
00239
00240
00241 if ( m_inputQueried == Storage && mode == KoStore::Read &&
00242 m_inputStorage && m_inputStorage->mode() == KoStore::Read )
00243 return storageNewStreamHelper( &m_inputStorage, &m_inputStorageDevice, name );
00244 else if ( m_outputQueried == Storage && mode == KoStore::Write &&
00245 m_outputStorage && m_outputStorage->mode() == KoStore::Write )
00246 return storageNewStreamHelper( &m_outputStorage, &m_outputStorageDevice, name );
00247 else if ( m_inputQueried == Nil && mode == KoStore::Read )
00248 return storageHelper( inputFile(), name, KoStore::Read,
00249 &m_inputStorage, &m_inputStorageDevice );
00250 else if ( m_outputQueried == Nil && mode == KoStore::Write )
00251 return storageHelper( outputFile(), name, KoStore::Write,
00252 &m_outputStorage, &m_outputStorageDevice );
00253 else {
00254 kdWarning( 30500 ) << "Oooops, how did we get here? You already asked for a"
00255 << " different source/destination?" << endl;
00256 return 0;
00257 }
00258 }
00259
00260 KoDocument* KoFilterChain::inputDocument()
00261 {
00262 if ( m_inputQueried == Document )
00263 return m_inputDocument;
00264 else if ( m_inputQueried != Nil ) {
00265 kdWarning( 30500 ) << "You already asked for some different source." << endl;
00266 return 0;
00267 }
00268
00269 if ( ( m_state & Beginning ) &&
00270 static_cast<KoFilterManager::Direction>( filterManagerDirection() ) == KoFilterManager::Export &&
00271 filterManagerKoDocument() )
00272 m_inputDocument = filterManagerKoDocument();
00273 else if ( !m_inputDocument )
00274 m_inputDocument = createDocument( inputFile() );
00275
00276 m_inputQueried = Document;
00277 return m_inputDocument;
00278 }
00279
00280 KoDocument* KoFilterChain::outputDocument()
00281 {
00282
00283
00284 if ( filterManagerParentChain() ) {
00285 kdWarning( 30500 )<< "An embedded filter has to use storageFile()!" << endl;
00286 return 0;
00287 }
00288
00289 if ( m_outputQueried == Document )
00290 return m_outputDocument;
00291 else if ( m_outputQueried != Nil ) {
00292 kdWarning( 30500 ) << "You already asked for some different destination." << endl;
00293 return 0;
00294 }
00295
00296 if ( ( m_state & End ) &&
00297 static_cast<KoFilterManager::Direction>( filterManagerDirection() ) == KoFilterManager::Import &&
00298 filterManagerKoDocument() )
00299 m_outputDocument = filterManagerKoDocument();
00300 else
00301 m_outputDocument = createDocument( m_chainLinks.current()->to() );
00302
00303 m_outputQueried = Document;
00304 return m_outputDocument;
00305 }
00306
00307 void KoFilterChain::dump() const
00308 {
00309 kdDebug( 30500 ) << "########## KoFilterChain with " << m_chainLinks.count() << " members:" << endl;
00310 QPtrListIterator<ChainLink> it( m_chainLinks );
00311 for ( ; it.current(); ++it )
00312 it.current()->dump();
00313 kdDebug( 30500 ) << "########## KoFilterChain (done) ##########" << endl;
00314 }
00315
00316 KoFilterChain::KoFilterChain( const KoFilterManager* manager ) :
00317 m_manager( manager ), m_state( Beginning ), m_inputStorage( 0 ),
00318 m_inputStorageDevice( 0 ), m_outputStorage( 0 ), m_outputStorageDevice( 0 ),
00319 m_inputDocument( 0 ), m_outputDocument( 0 ), m_inputTempFile( 0 ),
00320 m_outputTempFile( 0 ), m_inputQueried( Nil ), m_outputQueried( Nil ), d( 0 )
00321 {
00322
00323 m_chainLinks.setAutoDelete( true );
00324 }
00325
00326 void KoFilterChain::appendChainLink( KoFilterEntry::Ptr filterEntry, const QCString& from, const QCString& to )
00327 {
00328 m_chainLinks.append( new ChainLink( this, filterEntry, from, to ) );
00329 }
00330
00331 void KoFilterChain::prependChainLink( KoFilterEntry::Ptr filterEntry, const QCString& from, const QCString& to )
00332 {
00333 m_chainLinks.prepend( new ChainLink( this, filterEntry, from, to ) );
00334 }
00335
00336 void KoFilterChain::enterDirectory( const QString& directory )
00337 {
00338
00339
00340 if ( m_outputStorage )
00341 m_outputStorage->enterDirectory( directory );
00342 m_internalEmbeddingDirectories.append( directory );
00343 }
00344
00345 void KoFilterChain::leaveDirectory()
00346 {
00347 if ( m_outputStorage )
00348 m_outputStorage->leaveDirectory();
00349 if ( !m_internalEmbeddingDirectories.isEmpty() )
00350 m_internalEmbeddingDirectories.pop_back();
00351 }
00352
00353 QString KoFilterChain::filterManagerImportFile() const
00354 {
00355 return m_manager->importFile();
00356 }
00357
00358 QString KoFilterChain::filterManagerExportFile() const
00359 {
00360 return m_manager->exportFile();
00361 }
00362
00363 KoDocument* KoFilterChain::filterManagerKoDocument() const
00364 {
00365 return m_manager->document();
00366 }
00367
00368 int KoFilterChain::filterManagerDirection() const
00369 {
00370 return m_manager->direction();
00371 }
00372
00373 KoFilterChain* const KoFilterChain::filterManagerParentChain() const
00374 {
00375 return m_manager->parentChain();
00376 }
00377
00378 void KoFilterChain::manageIO()
00379 {
00380 m_inputQueried = Nil;
00381 m_outputQueried = Nil;
00382
00383 delete m_inputStorageDevice;
00384 m_inputStorageDevice = 0;
00385 if ( m_inputStorage ) {
00386 m_inputStorage->close();
00387 delete m_inputStorage;
00388 m_inputStorage = 0;
00389 }
00390 if ( m_inputTempFile ) {
00391 m_inputTempFile->close();
00392 delete m_inputTempFile;
00393 m_inputTempFile = 0;
00394 }
00395 m_inputFile = QString::null;
00396
00397 if ( !m_outputFile.isEmpty() ) {
00398 m_inputFile = m_outputFile;
00399 m_outputFile = QString::null;
00400 m_inputTempFile = m_outputTempFile;
00401 m_outputTempFile = 0;
00402
00403 delete m_outputStorageDevice;
00404 m_outputStorageDevice = 0;
00405 if ( m_outputStorage ) {
00406 m_outputStorage->close();
00407
00408
00409 if ( !filterManagerParentChain() || m_outputStorage->mode() != KoStore::Write )
00410 delete m_outputStorage;
00411 m_outputStorage = 0;
00412 }
00413 }
00414
00415 if ( m_inputDocument != filterManagerKoDocument() )
00416 delete m_inputDocument;
00417 m_inputDocument = m_outputDocument;
00418 m_outputDocument = 0;
00419 }
00420
00421 void KoFilterChain::finalizeIO()
00422 {
00423
00424
00425
00426
00427 if ( m_inputDocument &&
00428 static_cast<KoFilterManager::Direction>( filterManagerDirection() ) == KoFilterManager::Export ) {
00429 kdDebug( 30500 ) << "Saving the output document to the export file" << endl;
00430 m_inputDocument->saveNativeFormat( filterManagerExportFile() );
00431 m_inputFile = filterManagerExportFile();
00432 }
00433 }
00434
00435 bool KoFilterChain::createTempFile( KTempFile** tempFile, bool autoDelete )
00436 {
00437 if ( *tempFile ) {
00438 kdError( 30500 ) << "Ooops, why is there already a temp file???" << endl;
00439 return false;
00440 }
00441 *tempFile = new KTempFile();
00442 ( *tempFile )->setAutoDelete( autoDelete );
00443 return ( *tempFile )->status() == 0;
00444 }
00445
00446 void KoFilterChain::inputFileHelper( KoDocument* document, const QString& alternativeFile )
00447 {
00448 if ( document ) {
00449 if ( !createTempFile( &m_inputTempFile ) ) {
00450 delete m_inputTempFile;
00451 m_inputTempFile = 0;
00452 m_inputFile = QString::null;
00453 return;
00454 }
00455 if ( !document->saveNativeFormat( m_inputTempFile->name() ) ) {
00456 delete m_inputTempFile;
00457 m_inputTempFile = 0;
00458 m_inputFile = QString::null;
00459 return;
00460 }
00461 m_inputFile = m_inputTempFile->name();
00462 }
00463 else
00464 m_inputFile = alternativeFile;
00465 }
00466
00467 void KoFilterChain::outputFileHelper( bool autoDelete )
00468 {
00469 if ( !createTempFile( &m_outputTempFile, autoDelete ) ) {
00470 delete m_outputTempFile;
00471 m_outputTempFile = 0;
00472 m_outputFile = QString::null;
00473 }
00474 else
00475 m_outputFile = m_outputTempFile->name();
00476 }
00477
00478 KoStoreDevice* KoFilterChain::storageNewStreamHelper( KoStore** storage, KoStoreDevice** device,
00479 const QString& name )
00480 {
00481 delete *device;
00482 *device = 0;
00483 if ( ( *storage )->isOpen() )
00484 ( *storage )->close();
00485 if ( ( *storage )->bad() )
00486 return storageCleanupHelper( storage );
00487 if ( !( *storage )->open( name ) )
00488 return 0;
00489
00490 *device = new KoStoreDevice( *storage );
00491 return *device;
00492 }
00493
00494 KoStoreDevice* KoFilterChain::storageHelper( const QString& file, const QString& streamName,
00495 KoStore::Mode mode, KoStore** storage,
00496 KoStoreDevice** device )
00497 {
00498 if ( file.isEmpty() )
00499 return 0;
00500 if ( *storage ) {
00501 kdDebug( 30500 ) << "Uh-oh, we forgot to clean up..." << endl;
00502 return 0;
00503 }
00504
00505 storageInit( file, mode, storage );
00506
00507 if ( ( *storage )->bad() )
00508 return storageCleanupHelper( storage );
00509
00510
00511
00512
00513 if ( mode == KoStore::Read )
00514 m_inputQueried = Storage;
00515 else
00516 m_outputQueried = Storage;
00517
00518 return storageCreateFirstStream( streamName, storage, device );
00519 }
00520
00521 void KoFilterChain::storageInit( const QString& file, KoStore::Mode mode, KoStore** storage )
00522 {
00523 QCString appIdentification( "" );
00524 if ( mode == KoStore::Write ) {
00525
00526
00527
00528
00529
00530
00531 appIdentification = m_chainLinks.current()->to();
00532 }
00533 *storage = KoStore::createStore( file, mode, appIdentification );
00534 }
00535
00536 KoStoreDevice* KoFilterChain::storageInitEmbedding( const QString& name )
00537 {
00538 if ( m_outputStorage ) {
00539 kdWarning( 30500 ) << "Ooops! Something's really screwed here." << endl;
00540 return 0;
00541 }
00542
00543 m_outputStorage = filterManagerParentChain()->m_outputStorage;
00544
00545 if ( !m_outputStorage ) {
00546
00547
00548 storageInit( filterManagerParentChain()->outputFile(), KoStore::Write, &m_outputStorage );
00549
00550
00551 filterManagerParentChain()->m_outputStorage = m_outputStorage;
00552 filterManagerParentChain()->m_outputQueried = Storage;
00553 }
00554
00555 if ( m_outputStorage->isOpen() )
00556 m_outputStorage->close();
00557 if ( m_outputStorage->bad() )
00558 return storageCleanupHelper( &m_outputStorage );
00559
00560 m_outputQueried = Storage;
00561
00562
00563
00564 const int lruPartIndex = filterManagerParentChain()->m_chainLinks.current()->lruPartIndex();
00565 if ( lruPartIndex == -1 ) {
00566 kdError( 30500 ) << "Huh! You want to use embedding features w/o inheriting KoEmbeddingFilter?" << endl;
00567 return storageCleanupHelper( &m_outputStorage );
00568 }
00569
00570 if ( !m_outputStorage->enterDirectory( QString( "part%1" ).arg( lruPartIndex ) ) )
00571 return storageCleanupHelper( &m_outputStorage );
00572
00573 return storageCreateFirstStream( name, &m_outputStorage, &m_outputStorageDevice );
00574 }
00575
00576 KoStoreDevice* KoFilterChain::storageCreateFirstStream( const QString& streamName, KoStore** storage,
00577 KoStoreDevice** device )
00578 {
00579
00580
00581
00582 if ( !m_internalEmbeddingDirectories.isEmpty() ) {
00583 QStringList::ConstIterator it = m_internalEmbeddingDirectories.begin();
00584 QStringList::ConstIterator end = m_internalEmbeddingDirectories.end();
00585 for ( ; it != end && ( *storage )->enterDirectory( *it ); ++it );
00586 }
00587
00588 if ( !( *storage )->open( streamName ) )
00589 return 0;
00590
00591 if ( *device ) {
00592 kdDebug( 30500 ) << "Uh-oh, we forgot to clean up the storage device!" << endl;
00593 ( *storage )->close();
00594 return storageCleanupHelper( storage );
00595 }
00596 *device = new KoStoreDevice( *storage );
00597 return *device;
00598 }
00599
00600 KoStoreDevice* KoFilterChain::storageCleanupHelper( KoStore** storage )
00601 {
00602
00603 if ( *storage != m_outputStorage || !filterManagerParentChain() ||
00604 ( *storage )->mode() != KoStore::Write )
00605 delete *storage;
00606 *storage = 0;
00607 return 0;
00608 }
00609
00610 KoDocument* KoFilterChain::createDocument( const QString& file )
00611 {
00612 KURL url;
00613 url.setPath( file );
00614 KMimeType::Ptr t = KMimeType::findByURL( url, 0, true );
00615 if ( t->name() == KMimeType::defaultMimeType() ) {
00616 kdError( 30500 ) << "No mimetype found for " << file << endl;
00617 return 0;
00618 }
00619
00620 KoDocument *doc = createDocument( QCString( t->name().latin1() ) );
00621
00622 if ( !doc || !doc->loadNativeFormat( file ) ) {
00623 kdError( 30500 ) << "Couldn't load from the file" << endl;
00624 delete doc;
00625 return 0;
00626 }
00627 return doc;
00628 }
00629
00630 KoDocument* KoFilterChain::createDocument( const QCString& mimeType )
00631 {
00632 const QString constraint( QString::fromLatin1( "[X-KDE-NativeMimeType] == '%1'" ).arg( mimeType ) );
00633 QValueList<KoDocumentEntry> entries = KoDocumentEntry::query( constraint );
00634 if ( entries.isEmpty() ) {
00635 kdError( 30500 ) << "Couldn't find a KOffice document entry for " << mimeType << endl;
00636 return 0;
00637 }
00638
00639 if ( entries.count() != 1 )
00640 kdWarning( 30500 ) << "Huh?? Two document entries for the same mimetype?"
00641 << " Will take the first one." << endl;
00642
00643 KoDocument* doc = entries.first().createDoc();
00644 if ( !doc ) {
00645 kdError( 30500 ) << "Couldn't create the document" << endl;
00646 return 0;
00647 }
00648 return doc;
00649 }
00650
00651
00652 namespace KOffice {
00653
00654 Edge::Edge( Vertex* vertex, KoFilterEntry::Ptr filterEntry ) :
00655 m_vertex( vertex ), m_filterEntry( filterEntry ), d( 0 )
00656 {
00657 }
00658
00659 void Edge::relax( const Vertex* predecessor, PriorityQueue<Vertex>& queue )
00660 {
00661 if ( !m_vertex || !predecessor || !m_filterEntry )
00662 return;
00663 if ( m_vertex->setKey( predecessor->key() + m_filterEntry->weight ) ) {
00664 queue.keyDecreased( m_vertex );
00665 m_vertex->setPredecessor( predecessor );
00666 }
00667 }
00668
00669 void Edge::dump( const QCString& indent ) const
00670 {
00671 if ( m_vertex )
00672 kdDebug( 30500 ) << indent << "Edge -> '" << m_vertex->mimeType()
00673 << "' (" << m_filterEntry->weight << ")" << endl;
00674 else
00675 kdDebug( 30500 ) << indent << "Edge -> '(null)' ("
00676 << m_filterEntry->weight << ")" << endl;
00677 }
00678
00679
00680 Vertex::Vertex( const QCString& mimeType ) : m_predecessor( 0 ), m_mimeType( mimeType ),
00681 m_weight( UINT_MAX ), m_index( -1 ), d( 0 )
00682 {
00683 m_edges.setAutoDelete( true );
00684 }
00685
00686 bool Vertex::setKey( unsigned int key )
00687 {
00688 if ( m_weight > key ) {
00689 m_weight = key;
00690 return true;
00691 }
00692 return false;
00693 }
00694
00695 void Vertex::reset()
00696 {
00697 m_weight = UINT_MAX;
00698 m_predecessor = 0;
00699 }
00700
00701 void Vertex::addEdge( const Edge* edge )
00702 {
00703 if ( !edge || edge->weight() == 0 )
00704 return;
00705 m_edges.append( edge );
00706 }
00707
00708 const Edge* Vertex::findEdge( const Vertex* vertex ) const
00709 {
00710 if ( !vertex )
00711 return 0;
00712 const Edge* edge = 0;
00713 QPtrListIterator<Edge> it( m_edges );
00714
00715 for ( ; it.current(); ++it ) {
00716 if ( it.current()->vertex() == vertex &&
00717 ( !edge || it.current()->weight() < edge->weight() ) )
00718 edge = it.current();
00719 }
00720 return edge;
00721 }
00722
00723 void Vertex::relaxVertices( PriorityQueue<Vertex>& queue )
00724 {
00725 for ( Edge *e = m_edges.first(); e; e = m_edges.next() )
00726 e->relax( this, queue );
00727 }
00728
00729 void Vertex::dump( const QCString& indent ) const
00730 {
00731 kdDebug( 30500 ) << indent << "Vertex: " << m_mimeType << " (" << m_weight << "):" << endl;
00732 const QCString i( indent + " " );
00733 QPtrListIterator<Edge> it( m_edges );
00734 for ( ; it.current(); ++it )
00735 it.current()->dump( i );
00736 }
00737
00738
00739 Graph::Graph( const QCString& from ) : m_vertices( 47 ), m_from( from ),
00740 m_graphValid( false ), d( 0 )
00741 {
00742 m_vertices.setAutoDelete( true );
00743 buildGraph();
00744 shortestPaths();
00745 }
00746
00747 void Graph::setSourceMimeType( const QCString& from )
00748 {
00749 if ( from == m_from )
00750 return;
00751 m_from = from;
00752 m_graphValid = false;
00753
00754
00755 QAsciiDictIterator<Vertex> it( m_vertices );
00756 for ( ; it.current(); ++it )
00757 it.current()->reset();
00758
00759
00760 shortestPaths();
00761 }
00762
00763 KoFilterChain::Ptr Graph::chain( const KoFilterManager* manager, QCString& to ) const
00764 {
00765 if ( !isValid() || !manager )
00766 return 0;
00767
00768 if ( to.isEmpty() ) {
00769 to = findKOfficePart();
00770 if ( to.isEmpty() )
00771 return 0;
00772 }
00773
00774 const Vertex* vertex = m_vertices[ to ];
00775 if ( !vertex || vertex->key() == UINT_MAX )
00776 return 0;
00777
00778 KoFilterChain::Ptr ret = new KoFilterChain( manager );
00779
00780
00781 const Vertex* tmp = vertex->predecessor();
00782 while ( tmp ) {
00783 const Edge* const edge = tmp->findEdge( vertex );
00784 Q_ASSERT( edge );
00785 ret->prependChainLink( edge->filterEntry(), tmp->mimeType(), vertex->mimeType() );
00786 vertex = tmp;
00787 tmp = tmp->predecessor();
00788 }
00789 return ret;
00790 }
00791
00792 void Graph::dump() const
00793 {
00794 kdDebug( 30500 ) << "+++++++++ Graph::dump +++++++++" << endl;
00795 kdDebug( 30500 ) << "From: " << m_from << endl;
00796 QAsciiDictIterator<Vertex> it( m_vertices );
00797 for ( ; it.current(); ++it )
00798 it.current()->dump( " " );
00799 kdDebug( 30500 ) << "+++++++++ Graph::dump (done) +++++++++" << endl;
00800 }
00801
00802
00803
00804 void Graph::buildGraph()
00805 {
00806
00807 QValueList<KoDocumentEntry> parts( KoDocumentEntry::query() );
00808 QValueList<KoDocumentEntry>::ConstIterator partIt( parts.begin() );
00809 QValueList<KoDocumentEntry>::ConstIterator partEnd( parts.end() );
00810
00811 while ( partIt != partEnd ) {
00812 const QCString key( ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString().latin1() );
00813 if ( !key.isEmpty() )
00814 m_vertices.insert( key, new Vertex( key ) );
00815 ++partIt;
00816 }
00817
00818 QValueList<KoFilterEntry::Ptr> filters( KoFilterEntry::query() );
00819 QValueList<KoFilterEntry::Ptr>::ConstIterator it = filters.begin();
00820 QValueList<KoFilterEntry::Ptr>::ConstIterator end = filters.end();
00821
00822 for ( ; it != end; ++it ) {
00823
00824 QStringList::ConstIterator importIt = ( *it )->import.begin();
00825 QStringList::ConstIterator importEnd = ( *it )->import.end();
00826 for ( ; importIt != importEnd; ++importIt ) {
00827 const QCString key = ( *importIt ).latin1();
00828
00829 if ( !m_vertices[ key ] )
00830 m_vertices.insert( key, new Vertex( key ) );
00831 }
00832
00833
00834 if ( KoFilterManager::filterAvailable( *it ) ) {
00835 QStringList::ConstIterator exportIt = ( *it )->export_.begin();
00836 QStringList::ConstIterator exportEnd = ( *it )->export_.end();
00837
00838 for ( ; exportIt != exportEnd; ++exportIt ) {
00839
00840 const QCString key = ( *exportIt ).latin1();
00841 Vertex* exp = m_vertices[ key ];
00842 if ( !exp ) {
00843 exp = new Vertex( key );
00844 m_vertices.insert( key, exp );
00845 }
00846
00847 importIt = ( *it )->import.begin();
00848 for ( ; importIt != importEnd; ++importIt )
00849 m_vertices[ ( *importIt ).latin1() ]->addEdge( new Edge( exp, *it ) );
00850 }
00851 }
00852 else
00853 kdDebug( 30500 ) << "Filter: " << ( *it )->service()->name() << " doesn't apply." << endl;
00854 }
00855 }
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865 void Graph::shortestPaths()
00866 {
00867
00868 Vertex* from = m_vertices[ m_from ];
00869 if ( !from )
00870 return;
00871
00872
00873 from->setKey( 0 );
00874
00875
00876 PriorityQueue<Vertex> queue( m_vertices );
00877
00878 while ( !queue.isEmpty() ) {
00879 Vertex *min = queue.extractMinimum();
00880
00881 if ( min->key() == UINT_MAX )
00882 break;
00883 min->relaxVertices( queue );
00884 }
00885 m_graphValid = true;
00886 }
00887
00888 QCString Graph::findKOfficePart() const
00889 {
00890
00891 QValueList<KoDocumentEntry> parts( KoDocumentEntry::query() );
00892 QValueList<KoDocumentEntry>::ConstIterator partIt( parts.begin() );
00893 QValueList<KoDocumentEntry>::ConstIterator partEnd( parts.end() );
00894
00895 const Vertex *v = 0;
00896
00897
00898 while ( !v && partIt != partEnd ) {
00899 QString key( ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString() );
00900 if ( !key.isEmpty() )
00901 v = m_vertices[ key.latin1() ];
00902 ++partIt;
00903 }
00904 if ( !v )
00905 return "";
00906
00907
00908 while ( partIt != partEnd ) {
00909 QString key( ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString() );
00910 Vertex* tmp = 0;
00911 if ( !key.isEmpty() )
00912 tmp = m_vertices[ key.latin1() ];
00913
00914 if ( tmp && tmp->key() < v->key() )
00915 v = tmp;
00916 ++partIt;
00917 }
00918
00919
00920 if ( v->key() == 0 )
00921 return "";
00922
00923 return v->mimeType();
00924 }
00925
00926 }