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 if (status == KoFilter::OK)
00171 finalizeIO();
00172 return status;
00173 }
00174
00175 QString KoFilterChain::chainOutput() const
00176 {
00177 if ( m_state == Done )
00178 return m_inputFile;
00179 return QString::null;
00180 }
00181
00182 QString KoFilterChain::inputFile()
00183 {
00184 if ( m_inputQueried == File )
00185 return m_inputFile;
00186 else if ( m_inputQueried != Nil ) {
00187 kdWarning( 30500 ) << "You already asked for some different source." << endl;
00188 return QString::null;
00189 }
00190 m_inputQueried = File;
00191
00192 if ( m_state & Beginning ) {
00193 if ( static_cast<KoFilterManager::Direction>( filterManagerDirection() ) ==
00194 KoFilterManager::Import )
00195 m_inputFile = filterManagerImportFile();
00196 else
00197 inputFileHelper( filterManagerKoDocument(), filterManagerImportFile() );
00198 }
00199 else
00200 if ( m_inputFile.isEmpty() )
00201 inputFileHelper( m_inputDocument, QString::null );
00202
00203 return m_inputFile;
00204 }
00205
00206 QString KoFilterChain::outputFile()
00207 {
00208
00209
00210 if ( filterManagerParentChain() )
00211 kdWarning( 30500 )<< "An embedded filter has to use storageFile()!" << endl;
00212
00213 if ( m_outputQueried == File )
00214 return m_outputFile;
00215 else if ( m_outputQueried != Nil ) {
00216 kdWarning( 30500 ) << "You already asked for some different destination." << endl;
00217 return QString::null;
00218 }
00219 m_outputQueried = File;
00220
00221 if ( m_state & End ) {
00222 if ( static_cast<KoFilterManager::Direction>( filterManagerDirection() ) ==
00223 KoFilterManager::Import )
00224 outputFileHelper( false );
00225 else
00226 m_outputFile = filterManagerExportFile();
00227 }
00228 else
00229 outputFileHelper( true );
00230
00231 return m_outputFile;
00232 }
00233
00234 KoStoreDevice* KoFilterChain::storageFile( const QString& name, KoStore::Mode mode )
00235 {
00236
00237
00238 if ( m_outputQueried == Nil && mode == KoStore::Write && filterManagerParentChain() )
00239 return storageInitEmbedding( name );
00240
00241
00242 if ( m_inputQueried == Storage && mode == KoStore::Read &&
00243 m_inputStorage && m_inputStorage->mode() == KoStore::Read )
00244 return storageNewStreamHelper( &m_inputStorage, &m_inputStorageDevice, name );
00245 else if ( m_outputQueried == Storage && mode == KoStore::Write &&
00246 m_outputStorage && m_outputStorage->mode() == KoStore::Write )
00247 return storageNewStreamHelper( &m_outputStorage, &m_outputStorageDevice, name );
00248 else if ( m_inputQueried == Nil && mode == KoStore::Read )
00249 return storageHelper( inputFile(), name, KoStore::Read,
00250 &m_inputStorage, &m_inputStorageDevice );
00251 else if ( m_outputQueried == Nil && mode == KoStore::Write )
00252 return storageHelper( outputFile(), name, KoStore::Write,
00253 &m_outputStorage, &m_outputStorageDevice );
00254 else {
00255 kdWarning( 30500 ) << "Oooops, how did we get here? You already asked for a"
00256 << " different source/destination?" << endl;
00257 return 0;
00258 }
00259 }
00260
00261 KoDocument* KoFilterChain::inputDocument()
00262 {
00263 if ( m_inputQueried == Document )
00264 return m_inputDocument;
00265 else if ( m_inputQueried != Nil ) {
00266 kdWarning( 30500 ) << "You already asked for some different source." << endl;
00267 return 0;
00268 }
00269
00270 if ( ( m_state & Beginning ) &&
00271 static_cast<KoFilterManager::Direction>( filterManagerDirection() ) == KoFilterManager::Export &&
00272 filterManagerKoDocument() )
00273 m_inputDocument = filterManagerKoDocument();
00274 else if ( !m_inputDocument )
00275 m_inputDocument = createDocument( inputFile() );
00276
00277 m_inputQueried = Document;
00278 return m_inputDocument;
00279 }
00280
00281 KoDocument* KoFilterChain::outputDocument()
00282 {
00283
00284
00285 if ( filterManagerParentChain() ) {
00286 kdWarning( 30500 )<< "An embedded filter has to use storageFile()!" << endl;
00287 return 0;
00288 }
00289
00290 if ( m_outputQueried == Document )
00291 return m_outputDocument;
00292 else if ( m_outputQueried != Nil ) {
00293 kdWarning( 30500 ) << "You already asked for some different destination." << endl;
00294 return 0;
00295 }
00296
00297 if ( ( m_state & End ) &&
00298 static_cast<KoFilterManager::Direction>( filterManagerDirection() ) == KoFilterManager::Import &&
00299 filterManagerKoDocument() )
00300 m_outputDocument = filterManagerKoDocument();
00301 else
00302 m_outputDocument = createDocument( m_chainLinks.current()->to() );
00303
00304 m_outputQueried = Document;
00305 return m_outputDocument;
00306 }
00307
00308 void KoFilterChain::dump() const
00309 {
00310 kdDebug( 30500 ) << "########## KoFilterChain with " << m_chainLinks.count() << " members:" << endl;
00311 QPtrListIterator<ChainLink> it( m_chainLinks );
00312 for ( ; it.current(); ++it )
00313 it.current()->dump();
00314 kdDebug( 30500 ) << "########## KoFilterChain (done) ##########" << endl;
00315 }
00316
00317 KoFilterChain::KoFilterChain( const KoFilterManager* manager ) :
00318 m_manager( manager ), m_state( Beginning ), m_inputStorage( 0 ),
00319 m_inputStorageDevice( 0 ), m_outputStorage( 0 ), m_outputStorageDevice( 0 ),
00320 m_inputDocument( 0 ), m_outputDocument( 0 ), m_inputTempFile( 0 ),
00321 m_outputTempFile( 0 ), m_inputQueried( Nil ), m_outputQueried( Nil ), d( 0 )
00322 {
00323
00324 m_chainLinks.setAutoDelete( true );
00325 }
00326
00327 void KoFilterChain::appendChainLink( KoFilterEntry::Ptr filterEntry, const QCString& from, const QCString& to )
00328 {
00329 m_chainLinks.append( new ChainLink( this, filterEntry, from, to ) );
00330 }
00331
00332 void KoFilterChain::prependChainLink( KoFilterEntry::Ptr filterEntry, const QCString& from, const QCString& to )
00333 {
00334 m_chainLinks.prepend( new ChainLink( this, filterEntry, from, to ) );
00335 }
00336
00337 void KoFilterChain::enterDirectory( const QString& directory )
00338 {
00339
00340
00341 if ( m_outputStorage )
00342 m_outputStorage->enterDirectory( directory );
00343 m_internalEmbeddingDirectories.append( directory );
00344 }
00345
00346 void KoFilterChain::leaveDirectory()
00347 {
00348 if ( m_outputStorage )
00349 m_outputStorage->leaveDirectory();
00350 if ( !m_internalEmbeddingDirectories.isEmpty() )
00351 m_internalEmbeddingDirectories.pop_back();
00352 }
00353
00354 QString KoFilterChain::filterManagerImportFile() const
00355 {
00356 return m_manager->importFile();
00357 }
00358
00359 QString KoFilterChain::filterManagerExportFile() const
00360 {
00361 return m_manager->exportFile();
00362 }
00363
00364 KoDocument* KoFilterChain::filterManagerKoDocument() const
00365 {
00366 return m_manager->document();
00367 }
00368
00369 int KoFilterChain::filterManagerDirection() const
00370 {
00371 return m_manager->direction();
00372 }
00373
00374 KoFilterChain* const KoFilterChain::filterManagerParentChain() const
00375 {
00376 return m_manager->parentChain();
00377 }
00378
00379 void KoFilterChain::manageIO()
00380 {
00381 m_inputQueried = Nil;
00382 m_outputQueried = Nil;
00383
00384 delete m_inputStorageDevice;
00385 m_inputStorageDevice = 0;
00386 if ( m_inputStorage ) {
00387 m_inputStorage->close();
00388 delete m_inputStorage;
00389 m_inputStorage = 0;
00390 }
00391 if ( m_inputTempFile ) {
00392 m_inputTempFile->close();
00393 delete m_inputTempFile;
00394 m_inputTempFile = 0;
00395 }
00396 m_inputFile = QString::null;
00397
00398 if ( !m_outputFile.isEmpty() ) {
00399 m_inputFile = m_outputFile;
00400 m_outputFile = QString::null;
00401 m_inputTempFile = m_outputTempFile;
00402 m_outputTempFile = 0;
00403
00404 delete m_outputStorageDevice;
00405 m_outputStorageDevice = 0;
00406 if ( m_outputStorage ) {
00407 m_outputStorage->close();
00408
00409
00410 if ( !filterManagerParentChain() || m_outputStorage->mode() != KoStore::Write )
00411 delete m_outputStorage;
00412 m_outputStorage = 0;
00413 }
00414 }
00415
00416 if ( m_inputDocument != filterManagerKoDocument() )
00417 delete m_inputDocument;
00418 m_inputDocument = m_outputDocument;
00419 m_outputDocument = 0;
00420 }
00421
00422 void KoFilterChain::finalizeIO()
00423 {
00424
00425
00426
00427
00428 if ( m_inputDocument &&
00429 static_cast<KoFilterManager::Direction>( filterManagerDirection() ) == KoFilterManager::Export ) {
00430 kdDebug( 30500 ) << "Saving the output document to the export file" << endl;
00431 m_inputDocument->saveNativeFormat( filterManagerExportFile() );
00432 m_inputFile = filterManagerExportFile();
00433 }
00434 }
00435
00436 bool KoFilterChain::createTempFile( KTempFile** tempFile, bool autoDelete )
00437 {
00438 if ( *tempFile ) {
00439 kdError( 30500 ) << "Ooops, why is there already a temp file???" << endl;
00440 return false;
00441 }
00442 *tempFile = new KTempFile();
00443 ( *tempFile )->setAutoDelete( autoDelete );
00444 return ( *tempFile )->status() == 0;
00445 }
00446
00447 void KoFilterChain::inputFileHelper( KoDocument* document, const QString& alternativeFile )
00448 {
00449 if ( document ) {
00450 if ( !createTempFile( &m_inputTempFile ) ) {
00451 delete m_inputTempFile;
00452 m_inputTempFile = 0;
00453 m_inputFile = QString::null;
00454 return;
00455 }
00456 if ( !document->saveNativeFormat( m_inputTempFile->name() ) ) {
00457 delete m_inputTempFile;
00458 m_inputTempFile = 0;
00459 m_inputFile = QString::null;
00460 return;
00461 }
00462 m_inputFile = m_inputTempFile->name();
00463 }
00464 else
00465 m_inputFile = alternativeFile;
00466 }
00467
00468 void KoFilterChain::outputFileHelper( bool autoDelete )
00469 {
00470 if ( !createTempFile( &m_outputTempFile, autoDelete ) ) {
00471 delete m_outputTempFile;
00472 m_outputTempFile = 0;
00473 m_outputFile = QString::null;
00474 }
00475 else
00476 m_outputFile = m_outputTempFile->name();
00477 }
00478
00479 KoStoreDevice* KoFilterChain::storageNewStreamHelper( KoStore** storage, KoStoreDevice** device,
00480 const QString& name )
00481 {
00482 delete *device;
00483 *device = 0;
00484 if ( ( *storage )->isOpen() )
00485 ( *storage )->close();
00486 if ( ( *storage )->bad() )
00487 return storageCleanupHelper( storage );
00488 if ( !( *storage )->open( name ) )
00489 return 0;
00490
00491 *device = new KoStoreDevice( *storage );
00492 return *device;
00493 }
00494
00495 KoStoreDevice* KoFilterChain::storageHelper( const QString& file, const QString& streamName,
00496 KoStore::Mode mode, KoStore** storage,
00497 KoStoreDevice** device )
00498 {
00499 if ( file.isEmpty() )
00500 return 0;
00501 if ( *storage ) {
00502 kdDebug( 30500 ) << "Uh-oh, we forgot to clean up..." << endl;
00503 return 0;
00504 }
00505
00506 storageInit( file, mode, storage );
00507
00508 if ( ( *storage )->bad() )
00509 return storageCleanupHelper( storage );
00510
00511
00512
00513
00514 if ( mode == KoStore::Read )
00515 m_inputQueried = Storage;
00516 else
00517 m_outputQueried = Storage;
00518
00519 return storageCreateFirstStream( streamName, storage, device );
00520 }
00521
00522 void KoFilterChain::storageInit( const QString& file, KoStore::Mode mode, KoStore** storage )
00523 {
00524 QCString appIdentification( "" );
00525 if ( mode == KoStore::Write ) {
00526
00527
00528
00529
00530
00531
00532 appIdentification = m_chainLinks.current()->to();
00533 }
00534 *storage = KoStore::createStore( file, mode, appIdentification );
00535 }
00536
00537 KoStoreDevice* KoFilterChain::storageInitEmbedding( const QString& name )
00538 {
00539 if ( m_outputStorage ) {
00540 kdWarning( 30500 ) << "Ooops! Something's really screwed here." << endl;
00541 return 0;
00542 }
00543
00544 m_outputStorage = filterManagerParentChain()->m_outputStorage;
00545
00546 if ( !m_outputStorage ) {
00547
00548
00549 storageInit( filterManagerParentChain()->outputFile(), KoStore::Write, &m_outputStorage );
00550
00551
00552 filterManagerParentChain()->m_outputStorage = m_outputStorage;
00553 filterManagerParentChain()->m_outputQueried = Storage;
00554 }
00555
00556 if ( m_outputStorage->isOpen() )
00557 m_outputStorage->close();
00558 if ( m_outputStorage->bad() )
00559 return storageCleanupHelper( &m_outputStorage );
00560
00561 m_outputQueried = Storage;
00562
00563
00564
00565 const int lruPartIndex = filterManagerParentChain()->m_chainLinks.current()->lruPartIndex();
00566 if ( lruPartIndex == -1 ) {
00567 kdError( 30500 ) << "Huh! You want to use embedding features w/o inheriting KoEmbeddingFilter?" << endl;
00568 return storageCleanupHelper( &m_outputStorage );
00569 }
00570
00571 if ( !m_outputStorage->enterDirectory( QString( "part%1" ).arg( lruPartIndex ) ) )
00572 return storageCleanupHelper( &m_outputStorage );
00573
00574 return storageCreateFirstStream( name, &m_outputStorage, &m_outputStorageDevice );
00575 }
00576
00577 KoStoreDevice* KoFilterChain::storageCreateFirstStream( const QString& streamName, KoStore** storage,
00578 KoStoreDevice** device )
00579 {
00580
00581
00582
00583 if ( !m_internalEmbeddingDirectories.isEmpty() ) {
00584 QStringList::ConstIterator it = m_internalEmbeddingDirectories.begin();
00585 QStringList::ConstIterator end = m_internalEmbeddingDirectories.end();
00586 for ( ; it != end && ( *storage )->enterDirectory( *it ); ++it );
00587 }
00588
00589 if ( !( *storage )->open( streamName ) )
00590 return 0;
00591
00592 if ( *device ) {
00593 kdDebug( 30500 ) << "Uh-oh, we forgot to clean up the storage device!" << endl;
00594 ( *storage )->close();
00595 return storageCleanupHelper( storage );
00596 }
00597 *device = new KoStoreDevice( *storage );
00598 return *device;
00599 }
00600
00601 KoStoreDevice* KoFilterChain::storageCleanupHelper( KoStore** storage )
00602 {
00603
00604 if ( *storage != m_outputStorage || !filterManagerParentChain() ||
00605 ( *storage )->mode() != KoStore::Write )
00606 delete *storage;
00607 *storage = 0;
00608 return 0;
00609 }
00610
00611 KoDocument* KoFilterChain::createDocument( const QString& file )
00612 {
00613 KURL url;
00614 url.setPath( file );
00615 KMimeType::Ptr t = KMimeType::findByURL( url, 0, true );
00616 if ( t->name() == KMimeType::defaultMimeType() ) {
00617 kdError( 30500 ) << "No mimetype found for " << file << endl;
00618 return 0;
00619 }
00620
00621 KoDocument *doc = createDocument( QCString( t->name().latin1() ) );
00622
00623 if ( !doc || !doc->loadNativeFormat( file ) ) {
00624 kdError( 30500 ) << "Couldn't load from the file" << endl;
00625 delete doc;
00626 return 0;
00627 }
00628 return doc;
00629 }
00630
00631 KoDocument* KoFilterChain::createDocument( const QCString& mimeType )
00632 {
00633 KoDocumentEntry entry = KoDocumentEntry::queryByMimeType(mimeType);
00634
00635 if (entry.isEmpty())
00636 {
00637 kdError( 30500 ) << "Couldn't find a part that can handle mimetype " << mimeType << endl;
00638 }
00639
00640 KoDocument* doc = entry.createDoc();
00641 if ( !doc ) {
00642 kdError( 30500 ) << "Couldn't create the document" << endl;
00643 return 0;
00644 }
00645 return doc;
00646 }
00647
00648
00649 namespace KOffice {
00650
00651 Edge::Edge( Vertex* vertex, KoFilterEntry::Ptr filterEntry ) :
00652 m_vertex( vertex ), m_filterEntry( filterEntry ), d( 0 )
00653 {
00654 }
00655
00656 void Edge::relax( const Vertex* predecessor, PriorityQueue<Vertex>& queue )
00657 {
00658 if ( !m_vertex || !predecessor || !m_filterEntry )
00659 return;
00660 if ( m_vertex->setKey( predecessor->key() + m_filterEntry->weight ) ) {
00661 queue.keyDecreased( m_vertex );
00662 m_vertex->setPredecessor( predecessor );
00663 }
00664 }
00665
00666 void Edge::dump( const QCString& indent ) const
00667 {
00668 if ( m_vertex )
00669 kdDebug( 30500 ) << indent << "Edge -> '" << m_vertex->mimeType()
00670 << "' (" << m_filterEntry->weight << ")" << endl;
00671 else
00672 kdDebug( 30500 ) << indent << "Edge -> '(null)' ("
00673 << m_filterEntry->weight << ")" << endl;
00674 }
00675
00676
00677 Vertex::Vertex( const QCString& mimeType ) : m_predecessor( 0 ), m_mimeType( mimeType ),
00678 m_weight( UINT_MAX ), m_index( -1 ), d( 0 )
00679 {
00680 m_edges.setAutoDelete( true );
00681 }
00682
00683 bool Vertex::setKey( unsigned int key )
00684 {
00685 if ( m_weight > key ) {
00686 m_weight = key;
00687 return true;
00688 }
00689 return false;
00690 }
00691
00692 void Vertex::reset()
00693 {
00694 m_weight = UINT_MAX;
00695 m_predecessor = 0;
00696 }
00697
00698 void Vertex::addEdge( const Edge* edge )
00699 {
00700 if ( !edge || edge->weight() == 0 )
00701 return;
00702 m_edges.append( edge );
00703 }
00704
00705 const Edge* Vertex::findEdge( const Vertex* vertex ) const
00706 {
00707 if ( !vertex )
00708 return 0;
00709 const Edge* edge = 0;
00710 QPtrListIterator<Edge> it( m_edges );
00711
00712 for ( ; it.current(); ++it ) {
00713 if ( it.current()->vertex() == vertex &&
00714 ( !edge || it.current()->weight() < edge->weight() ) )
00715 edge = it.current();
00716 }
00717 return edge;
00718 }
00719
00720 void Vertex::relaxVertices( PriorityQueue<Vertex>& queue )
00721 {
00722 for ( Edge *e = m_edges.first(); e; e = m_edges.next() )
00723 e->relax( this, queue );
00724 }
00725
00726 void Vertex::dump( const QCString& indent ) const
00727 {
00728 kdDebug( 30500 ) << indent << "Vertex: " << m_mimeType << " (" << m_weight << "):" << endl;
00729 const QCString i( indent + " " );
00730 QPtrListIterator<Edge> it( m_edges );
00731 for ( ; it.current(); ++it )
00732 it.current()->dump( i );
00733 }
00734
00735
00736 Graph::Graph( const QCString& from ) : m_vertices( 47 ), m_from( from ),
00737 m_graphValid( false ), d( 0 )
00738 {
00739 m_vertices.setAutoDelete( true );
00740 buildGraph();
00741 shortestPaths();
00742 }
00743
00744 void Graph::setSourceMimeType( const QCString& from )
00745 {
00746 if ( from == m_from )
00747 return;
00748 m_from = from;
00749 m_graphValid = false;
00750
00751
00752 QAsciiDictIterator<Vertex> it( m_vertices );
00753 for ( ; it.current(); ++it )
00754 it.current()->reset();
00755
00756
00757 shortestPaths();
00758 }
00759
00760 KoFilterChain::Ptr Graph::chain( const KoFilterManager* manager, QCString& to ) const
00761 {
00762 if ( !isValid() || !manager )
00763 return 0;
00764
00765 if ( to.isEmpty() ) {
00766 to = findKOfficePart();
00767 if ( to.isEmpty() )
00768 return 0;
00769 }
00770
00771 const Vertex* vertex = m_vertices[ to ];
00772 if ( !vertex || vertex->key() == UINT_MAX )
00773 return 0;
00774
00775 KoFilterChain::Ptr ret = new KoFilterChain( manager );
00776
00777
00778 const Vertex* tmp = vertex->predecessor();
00779 while ( tmp ) {
00780 const Edge* const edge = tmp->findEdge( vertex );
00781 Q_ASSERT( edge );
00782 ret->prependChainLink( edge->filterEntry(), tmp->mimeType(), vertex->mimeType() );
00783 vertex = tmp;
00784 tmp = tmp->predecessor();
00785 }
00786 return ret;
00787 }
00788
00789 void Graph::dump() const
00790 {
00791 kdDebug( 30500 ) << "+++++++++ Graph::dump +++++++++" << endl;
00792 kdDebug( 30500 ) << "From: " << m_from << endl;
00793 QAsciiDictIterator<Vertex> it( m_vertices );
00794 for ( ; it.current(); ++it )
00795 it.current()->dump( " " );
00796 kdDebug( 30500 ) << "+++++++++ Graph::dump (done) +++++++++" << endl;
00797 }
00798
00799
00800
00801 void Graph::buildGraph()
00802 {
00803
00804 QValueList<KoDocumentEntry> parts( KoDocumentEntry::query() );
00805 QValueList<KoDocumentEntry>::ConstIterator partIt( parts.begin() );
00806 QValueList<KoDocumentEntry>::ConstIterator partEnd( parts.end() );
00807
00808 while ( partIt != partEnd ) {
00809 QStringList nativeMimeTypes = ( *partIt ).service()->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
00810 nativeMimeTypes += ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString();
00811 QStringList::ConstIterator it = nativeMimeTypes.begin();
00812 QStringList::ConstIterator end = nativeMimeTypes.end();
00813 for ( ; it != end; ++it )
00814 if ( !(*it).isEmpty() )
00815 m_vertices.insert( (*it).latin1(), new Vertex( (*it).latin1() ) );
00816 ++partIt;
00817 }
00818
00819 QValueList<KoFilterEntry::Ptr> filters( KoFilterEntry::query() );
00820 QValueList<KoFilterEntry::Ptr>::ConstIterator it = filters.begin();
00821 QValueList<KoFilterEntry::Ptr>::ConstIterator end = filters.end();
00822
00823 for ( ; it != end; ++it ) {
00824
00825 QStringList::ConstIterator importIt = ( *it )->import.begin();
00826 QStringList::ConstIterator importEnd = ( *it )->import.end();
00827 for ( ; importIt != importEnd; ++importIt ) {
00828 const QCString key = ( *importIt ).latin1();
00829
00830 if ( !m_vertices[ key ] )
00831 m_vertices.insert( key, new Vertex( key ) );
00832 }
00833
00834
00835 if ( KoFilterManager::filterAvailable( *it ) ) {
00836 QStringList::ConstIterator exportIt = ( *it )->export_.begin();
00837 QStringList::ConstIterator exportEnd = ( *it )->export_.end();
00838
00839 for ( ; exportIt != exportEnd; ++exportIt ) {
00840
00841 const QCString key = ( *exportIt ).latin1();
00842 Vertex* exp = m_vertices[ key ];
00843 if ( !exp ) {
00844 exp = new Vertex( key );
00845 m_vertices.insert( key, exp );
00846 }
00847
00848 importIt = ( *it )->import.begin();
00849 for ( ; importIt != importEnd; ++importIt )
00850 m_vertices[ ( *importIt ).latin1() ]->addEdge( new Edge( exp, *it ) );
00851 }
00852 }
00853 else
00854 kdDebug( 30500 ) << "Filter: " << ( *it )->service()->name() << " doesn't apply." << endl;
00855 }
00856 }
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866 void Graph::shortestPaths()
00867 {
00868
00869 Vertex* from = m_vertices[ m_from ];
00870 if ( !from )
00871 return;
00872
00873
00874 from->setKey( 0 );
00875
00876
00877 PriorityQueue<Vertex> queue( m_vertices );
00878
00879 while ( !queue.isEmpty() ) {
00880 Vertex *min = queue.extractMinimum();
00881
00882 if ( min->key() == UINT_MAX )
00883 break;
00884 min->relaxVertices( queue );
00885 }
00886 m_graphValid = true;
00887 }
00888
00889 QCString Graph::findKOfficePart() const
00890 {
00891
00892 QValueList<KoDocumentEntry> parts( KoDocumentEntry::query() );
00893 QValueList<KoDocumentEntry>::ConstIterator partIt( parts.begin() );
00894 QValueList<KoDocumentEntry>::ConstIterator partEnd( parts.end() );
00895
00896 const Vertex *v = 0;
00897
00898
00899 while ( !v && partIt != partEnd ) {
00900 QStringList nativeMimeTypes = ( *partIt ).service()->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
00901 nativeMimeTypes += ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString();
00902 QStringList::ConstIterator it = nativeMimeTypes.begin();
00903 QStringList::ConstIterator end = nativeMimeTypes.end();
00904 for ( ; !v && it != end; ++it )
00905 if ( !(*it).isEmpty() )
00906 v = m_vertices[ ( *it ).latin1() ];
00907 ++partIt;
00908 }
00909 if ( !v )
00910 return "";
00911
00912
00913 while ( partIt != partEnd ) {
00914 QStringList nativeMimeTypes = ( *partIt ).service()->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
00915 nativeMimeTypes += ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString();
00916 QStringList::ConstIterator it = nativeMimeTypes.begin();
00917 QStringList::ConstIterator end = nativeMimeTypes.end();
00918 for ( ; !v && it != end; ++it ) {
00919 QString key = *it;
00920 if ( !key.isEmpty() ) {
00921 Vertex* tmp = m_vertices[ key.latin1() ];
00922 if ( tmp && tmp->key() < v->key() )
00923 v = tmp;
00924 }
00925 }
00926 ++partIt;
00927 }
00928
00929
00930 if ( v->key() == 0 )
00931 return "";
00932
00933 return v->mimeType();
00934 }
00935
00936 }