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 }