00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <KoFilterManager.h>
00024 #include <KoFilterManager_p.h>
00025
00026 #include <qfile.h>
00027 #include <qlabel.h>
00028 #include <qlayout.h>
00029 #include <qptrlist.h>
00030 #include <qapplication.h>
00031
00032 #include <klocale.h>
00033 #include <kmessagebox.h>
00034 #include <KoDocument.h>
00035 #include <klibloader.h>
00036 #include <klistbox.h>
00037 #include <kmimetype.h>
00038 #include <kdebug.h>
00039
00040 #include <queue>
00041
00042 #include <unistd.h>
00043
00044 class KoFilterManager::Private
00045 {
00046 public:
00047 bool m_batch;
00048 };
00049
00050
00051 KoFilterChooser::KoFilterChooser (QWidget *parent, const QStringList &mimeTypes, const QString &nativeFormat)
00052 : KDialogBase (parent, "kofilterchooser", true, i18n ("Choose Filter"),
00053 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, true),
00054 m_mimeTypes (mimeTypes)
00055 {
00056 setInitialSize (QSize (300, 350));
00057
00058 QWidget *page = new QWidget (this);
00059 setMainWidget (page);
00060
00061
00062 QVBoxLayout *layout = new QVBoxLayout (page, marginHint (), spacingHint () * 2);
00063
00064 QLabel *filterLabel = new QLabel (i18n ("Select a filter:"), page, "filterlabel");
00065 layout->addWidget (filterLabel);
00066
00067 m_filterList = new KListBox (page, "filterlist");
00068 layout->addWidget (m_filterList);
00069
00070 Q_ASSERT (!m_mimeTypes.isEmpty ());
00071 for (QStringList::ConstIterator it = m_mimeTypes.begin ();
00072 it != m_mimeTypes.end ();
00073 it++)
00074 {
00075 KMimeType::Ptr mime = KMimeType::mimeType (*it);
00076 m_filterList->insertItem (mime->comment ());
00077 }
00078
00079 if (nativeFormat == "application/x-kword")
00080 {
00081 const int index = m_mimeTypes.findIndex ("text/plain");
00082 if (index > -1)
00083 m_filterList->setCurrentItem (index);
00084 }
00085
00086 if (m_filterList->currentItem () == -1)
00087 m_filterList->setCurrentItem (0);
00088
00089 m_filterList->centerCurrentItem ();
00090 m_filterList->setFocus ();
00091
00092 connect (m_filterList, SIGNAL (selected (int)), this, SLOT (slotOk ()));
00093 }
00094
00095 KoFilterChooser::~KoFilterChooser ()
00096 {
00097 }
00098
00099 QString KoFilterChooser::filterSelected ()
00100 {
00101 const int item = m_filterList->currentItem ();
00102
00103 if (item > -1)
00104 return m_mimeTypes [item];
00105 else
00106 return QString::null;
00107 }
00108
00109
00110
00111 QMap<QString, bool> KoFilterManager::m_filterAvailable;
00112
00113 const int KoFilterManager::s_area = 30500;
00114
00115
00116 KoFilterManager::KoFilterManager( KoDocument* document ) :
00117 m_document( document ), m_parentChain( 0 ), m_graph( "" ), d( 0 )
00118 {
00119 d = new KoFilterManager::Private;
00120 d -> m_batch = false;
00121 if ( document )
00122 QObject::connect( this, SIGNAL( sigProgress( int ) ),
00123 document, SIGNAL( sigProgress( int ) ) );
00124 }
00125
00126
00127 KoFilterManager::KoFilterManager( const QString& url, const QCString& mimetypeHint,
00128 KoFilterChain* const parentChain ) :
00129 m_document( 0 ), m_parentChain( parentChain ), m_importUrl( url ), m_importUrlMimetypeHint( mimetypeHint ),
00130 m_graph( "" ), d( 0 )
00131 {
00132 d = new KoFilterManager::Private;
00133 d -> m_batch = false;
00134 }
00135
00136 KoFilterManager::~KoFilterManager()
00137 {
00138 delete d;
00139 }
00140
00141 QString KoFilterManager::import( const QString& url, KoFilter::ConversionStatus& status )
00142 {
00143
00144 KURL u;
00145 u.setPath( url );
00146 KMimeType::Ptr t = KMimeType::findByURL( u, 0, true );
00147
00148 m_graph.setSourceMimeType( t->name().latin1() );
00149 if ( !m_graph.isValid() ) {
00150 bool userCancelled = false;
00151
00152 kdWarning(s_area) << "Can't open " << t->name () << ", trying filter chooser" << endl;
00153 if ( m_document )
00154 {
00155 if ( !m_document->isAutoErrorHandlingEnabled() )
00156 {
00157 status = KoFilter::BadConversionGraph;
00158 return QString::null;
00159 }
00160 QCString nativeFormat = m_document->nativeFormatMimeType ();
00161
00162 QApplication::setOverrideCursor( arrowCursor );
00163 KoFilterChooser chooser(0,
00164 KoFilterManager::mimeFilter (nativeFormat, KoFilterManager::Import, m_document->extraNativeMimeTypes()),
00165 nativeFormat);
00166 if (chooser.exec ())
00167 {
00168 QCString f = chooser.filterSelected ().latin1();
00169
00170 if (f == nativeFormat)
00171 {
00172 status = KoFilter::OK;
00173 QApplication::restoreOverrideCursor();
00174 return url;
00175 }
00176
00177 m_graph.setSourceMimeType (f);
00178 }
00179 else
00180 userCancelled = true;
00181 QApplication::restoreOverrideCursor();
00182 }
00183
00184 if (!m_graph.isValid())
00185 {
00186 kdError(s_area) << "Couldn't create a valid graph for this source mimetype: "
00187 << t->name() << endl;
00188 importErrorHelper( t->name(), userCancelled );
00189 status = KoFilter::BadConversionGraph;
00190 return QString::null;
00191 }
00192 }
00193
00194 KoFilterChain::Ptr chain( 0 );
00195
00196 if ( m_document ) {
00197 QCString mimeType = m_document->nativeFormatMimeType();
00198 QStringList extraMimes = m_document->extraNativeMimeTypes();
00199 int i=0, n = extraMimes.count();
00200 chain = m_graph.chain( this, mimeType );
00201 while( !chain && i<n) {
00202 mimeType = extraMimes[i].utf8();
00203 chain = m_graph.chain( this, mimeType );
00204 ++i;
00205 }
00206 }
00207 else {
00208 kdError(s_area) << "You aren't supposed to use import() from a filter!" << endl;
00209 status = KoFilter::UsageError;
00210 return QString::null;
00211 }
00212
00213 if ( !chain ) {
00214 kdError(s_area) << "Couldn't create a valid filter chain!" << endl;
00215 importErrorHelper( t->name() );
00216 status = KoFilter::BadConversionGraph;
00217 return QString::null;
00218 }
00219
00220
00221 m_direction = Import;
00222 m_importUrl = url;
00223 m_exportUrl = QString::null;
00224
00225 status = chain->invokeChain();
00226
00227 m_importUrl = QString::null;
00228
00229 if ( status == KoFilter::OK )
00230 return chain->chainOutput();
00231 return QString::null;
00232 }
00233
00234 KoFilter::ConversionStatus KoFilterManager::exp0rt( const QString& url, QCString& mimeType )
00235 {
00236 bool userCancelled = false;
00237
00238
00239
00240 m_direction = Export;
00241 m_exportUrl = url;
00242
00243 KoFilterChain::Ptr chain = 0;
00244 if ( m_document ) {
00245
00246 QStringList nativeMimeTypes;
00247 nativeMimeTypes.append( m_document->nativeFormatMimeType() );
00248 nativeMimeTypes += m_document->extraNativeMimeTypes();
00249 QStringList::ConstIterator it = nativeMimeTypes.begin();
00250 const QStringList::ConstIterator end = nativeMimeTypes.end();
00251 for ( ; !chain && it != end; ++it )
00252 {
00253 m_graph.setSourceMimeType( (*it).latin1() );
00254 if ( m_graph.isValid() )
00255 chain = m_graph.chain( this, mimeType );
00256 }
00257 }
00258 else if ( !m_importUrlMimetypeHint.isEmpty() ) {
00259 kdDebug(s_area) << "Using the mimetype hint: '" << m_importUrlMimetypeHint << "'" << endl;
00260 m_graph.setSourceMimeType( m_importUrlMimetypeHint );
00261 }
00262 else {
00263 KURL u;
00264 u.setPath( m_importUrl );
00265 KMimeType::Ptr t = KMimeType::findByURL( u, 0, true );
00266 if ( t->name() == KMimeType::defaultMimeType() ) {
00267 kdError(s_area) << "No mimetype found for " << m_importUrl << endl;
00268 return KoFilter::BadMimeType;
00269 }
00270 m_graph.setSourceMimeType( t->name().latin1() );
00271
00272 if ( !m_graph.isValid() ) {
00273 kdWarning(s_area) << "Can't open " << t->name () << ", trying filter chooser" << endl;
00274
00275 QApplication::setOverrideCursor( arrowCursor );
00276 KoFilterChooser chooser(0, KoFilterManager::mimeFilter ());
00277 if (chooser.exec ())
00278 m_graph.setSourceMimeType (chooser.filterSelected ().latin1 ());
00279 else
00280 userCancelled = true;
00281
00282 QApplication::restoreOverrideCursor();
00283 }
00284 }
00285
00286 if (!m_graph.isValid ())
00287 {
00288 kdError(s_area) << "Couldn't create a valid graph for this source mimetype." << endl;
00289 if (!userCancelled) KMessageBox::error( 0L, i18n("Could not export file."), i18n("Missing Export Filter") );
00290 return KoFilter::BadConversionGraph;
00291 }
00292
00293 if ( !chain )
00294 chain = m_graph.chain( this, mimeType );
00295
00296 if ( !chain ) {
00297 kdError(s_area) << "Couldn't create a valid filter chain to " << mimeType << " !" << endl;
00298 KMessageBox::error( 0L, i18n("Could not export file."), i18n("Missing Export Filter") );
00299 return KoFilter::BadConversionGraph;
00300 }
00301
00302 return chain->invokeChain();
00303 }
00304
00305 namespace
00306 {
00307
00308 class Vertex
00309 {
00310 public:
00311 Vertex( const QCString& mimeType ) : m_color( White ), m_mimeType( mimeType ) {}
00312
00313 enum Color { White, Gray, Black };
00314 Color color() const { return m_color; }
00315 void setColor( Color color ) { m_color = color; }
00316
00317 QCString mimeType() const { return m_mimeType; }
00318
00319 void addEdge( Vertex* vertex ) { if ( vertex ) m_edges.append( vertex ); }
00320 QPtrList<Vertex> edges() const { return m_edges; }
00321
00322 private:
00323 Color m_color;
00324 QCString m_mimeType;
00325 QPtrList<Vertex> m_edges;
00326 };
00327
00328
00329
00330 void buildGraph( QAsciiDict<Vertex>& vertices, KoFilterManager::Direction direction )
00331 {
00332 QStringList stopList;
00333 stopList << "text/plain";
00334 stopList << "text/csv";
00335 stopList << "text/x-tex";
00336 stopList << "text/html";
00337
00338 vertices.setAutoDelete( true );
00339
00340
00341
00342 QValueList<KoDocumentEntry> parts( KoDocumentEntry::query(false, QString::null) );
00343 QValueList<KoDocumentEntry>::ConstIterator partIt( parts.begin() );
00344 QValueList<KoDocumentEntry>::ConstIterator partEnd( parts.end() );
00345
00346 while ( partIt != partEnd ) {
00347 QStringList nativeMimeTypes = ( *partIt ).service()->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
00348 nativeMimeTypes += ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString();
00349 QStringList::ConstIterator it = nativeMimeTypes.begin();
00350 const QStringList::ConstIterator end = nativeMimeTypes.end();
00351 for ( ; it != end; ++it )
00352 if ( !(*it).isEmpty() )
00353 vertices.insert( (*it).latin1(), new Vertex( (*it).latin1() ) );
00354 ++partIt;
00355 }
00356
00357 QValueList<KoFilterEntry::Ptr> filters = KoFilterEntry::query();
00358 QValueList<KoFilterEntry::Ptr>::ConstIterator it = filters.begin();
00359 const QValueList<KoFilterEntry::Ptr>::ConstIterator end = filters.end();
00360
00361 for ( ; it != end; ++it ) {
00362
00363 QStringList impList;
00364 QStringList expList;
00365
00366 const QStringList::Iterator stopEnd = stopList.end();
00367
00368 if ( direction == KoFilterManager::Import ) {
00369
00370 QStringList::ConstIterator testIt = ( *it )->export_.begin();
00371 QStringList::ConstIterator testEnd = ( *it )->export_.end();
00372 for ( ; testIt != testEnd ; ++testIt ) {
00373 if ( stopList.find( *testIt ) == stopEnd ) {
00374 expList.append( *testIt );
00375 }
00376 }
00377 impList = ( *it )->import;
00378 }
00379 else {
00380
00381 QStringList::ConstIterator testIt = ( *it )->import.begin();
00382 const QStringList::ConstIterator testEnd = ( *it )->import.end();
00383 for ( ; testIt != testEnd ; ++testIt ) {
00384 if ( stopList.find( *testIt ) == stopEnd ) {
00385 impList.append( *testIt );
00386 }
00387 }
00388 expList = ( *it )->export_;
00389 }
00390
00391 if ( impList.empty() || expList.empty() )
00392 {
00393
00394 kdDebug( 30500 ) << "Filter: " << ( *it )->service()->name() << " ruled out" << endl;
00395 continue;
00396 }
00397
00398
00399 QStringList::ConstIterator importIt = impList.begin();
00400 const QStringList::ConstIterator importEnd = impList.end();
00401 for ( ; importIt != importEnd; ++importIt ) {
00402 const QCString key = ( *importIt ).latin1();
00403
00404 if ( !vertices[ key ] )
00405 vertices.insert( key, new Vertex( key ) );
00406 }
00407
00408
00409 if ( KoFilterManager::filterAvailable( *it ) ) {
00410 QStringList::ConstIterator exportIt = expList.begin();
00411 const QStringList::ConstIterator exportEnd = expList.end();
00412
00413 for ( ; exportIt != exportEnd; ++exportIt ) {
00414
00415 const QCString key = ( *exportIt ).latin1();
00416 Vertex* exp = vertices[ key ];
00417 if ( !exp ) {
00418 exp = new Vertex( key );
00419 vertices.insert( key, exp );
00420 }
00421
00422
00423
00424
00425 importIt = impList.begin();
00426 if ( direction == KoFilterManager::Import ) {
00427 for ( ; importIt != importEnd; ++importIt )
00428 exp->addEdge( vertices[ ( *importIt ).latin1() ] );
00429 } else {
00430 for ( ; importIt != importEnd; ++importIt )
00431 vertices[ ( *importIt ).latin1() ]->addEdge( exp );
00432 }
00433 }
00434 }
00435 else
00436 kdDebug( 30500 ) << "Filter: " << ( *it )->service()->name() << " does not apply." << endl;
00437 }
00438 }
00439
00440
00441
00442
00443 QStringList connected( const QAsciiDict<Vertex>& vertices, const QCString& mimetype )
00444 {
00445 if ( mimetype.isEmpty() )
00446 return QStringList();
00447 Vertex *v = vertices[ mimetype ];
00448 if ( !v )
00449 return QStringList();
00450
00451 v->setColor( Vertex::Gray );
00452 std::queue<Vertex*> queue;
00453 queue.push( v );
00454 QStringList connected;
00455
00456 while ( !queue.empty() ) {
00457 v = queue.front();
00458 queue.pop();
00459 QPtrList<Vertex> edges = v->edges();
00460 QPtrListIterator<Vertex> it( edges );
00461 for ( ; it.current(); ++it ) {
00462 if ( it.current()->color() == Vertex::White ) {
00463 it.current()->setColor( Vertex::Gray );
00464 queue.push( it.current() );
00465 }
00466 }
00467 v->setColor( Vertex::Black );
00468 connected.append( v->mimeType() );
00469 }
00470 return connected;
00471 }
00472 }
00473
00474
00475
00476 QStringList KoFilterManager::mimeFilter( const QCString& mimetype, Direction direction, const QStringList& extraNativeMimeTypes )
00477 {
00478
00479 QAsciiDict<Vertex> vertices;
00480 buildGraph( vertices, direction );
00481
00482
00483
00484 QStringList nativeMimeTypes;
00485 nativeMimeTypes.append( QString::fromLatin1( mimetype ) );
00486 nativeMimeTypes += extraNativeMimeTypes;
00487
00488
00489 QStringList lst = nativeMimeTypes;
00490
00491
00492 for( QStringList::ConstIterator natit = nativeMimeTypes.begin(); natit != nativeMimeTypes.end(); ++natit ) {
00493 const QStringList outMimes = connected( vertices, (*natit).latin1() );
00494
00495 for ( QStringList::ConstIterator mit = outMimes.begin(); mit != outMimes.end(); ++mit )
00496 if ( lst.find( *mit ) == lst.end() )
00497 lst.append( *mit );
00498 }
00499 return lst;
00500 }
00501
00502 QStringList KoFilterManager::mimeFilter()
00503 {
00504 QAsciiDict<Vertex> vertices;
00505 buildGraph( vertices, KoFilterManager::Import );
00506
00507 QValueList<KoDocumentEntry> parts( KoDocumentEntry::query(false, QString::null) );
00508 QValueList<KoDocumentEntry>::ConstIterator partIt( parts.begin() );
00509 QValueList<KoDocumentEntry>::ConstIterator partEnd( parts.end() );
00510
00511 if ( partIt == partEnd )
00512 return QStringList();
00513
00514
00515
00516
00517
00518
00519 Vertex *v = new Vertex( "supercalifragilistic/x-pialadocious" );
00520 vertices.insert( "supercalifragilistic/x-pialadocious", v );
00521 while ( partIt != partEnd ) {
00522 QStringList nativeMimeTypes = ( *partIt ).service()->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
00523 nativeMimeTypes += ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString();
00524 QStringList::ConstIterator it = nativeMimeTypes.begin();
00525 const QStringList::ConstIterator end = nativeMimeTypes.end();
00526 for ( ; it != end; ++it )
00527 if ( !(*it).isEmpty() )
00528 v->addEdge( vertices[ (*it).latin1() ] );
00529 ++partIt;
00530 }
00531 QStringList result = connected( vertices, "supercalifragilistic/x-pialadocious" );
00532
00533
00534 result.remove( "supercalifragilistic/x-pialadocious" );
00535 return result;
00536 }
00537
00538
00539
00540 bool KoFilterManager::filterAvailable( KoFilterEntry::Ptr entry )
00541 {
00542 if ( !entry )
00543 return false;
00544 if ( entry->available != "check" )
00545 return true;
00546
00547
00548
00549 QString key( entry->service()->name() );
00550 key += " - ";
00551 key += entry->service()->library();
00552
00553 if ( !m_filterAvailable.contains( key ) ) {
00554
00555
00556 KLibrary* library = KLibLoader::self()->library( QFile::encodeName( entry->service()->library() ) );
00557 if ( !library ) {
00558 kdWarning( 30500 ) << "Huh?? Couldn't load the lib: "
00559 << KLibLoader::self()->lastErrorMessage() << endl;
00560 m_filterAvailable[ key ] = false;
00561 return false;
00562 }
00563
00564
00565 QCString symname;
00566 symname.sprintf("check_%s", library->name().latin1() );
00567 void* sym = library->symbol( symname );
00568 if ( !sym )
00569 {
00570 kdWarning( 30500 ) << "The library " << library->name()
00571 << " does not offer a check_" << library->name()
00572 << " function." << endl;
00573 m_filterAvailable[ key ] = false;
00574 }
00575 else {
00576 typedef int (*t_func)();
00577 t_func check = (t_func)sym;
00578 m_filterAvailable[ key ] = check() == 1;
00579 }
00580 }
00581 return m_filterAvailable[ key ];
00582 }
00583
00584 void KoFilterManager::importErrorHelper( const QString& mimeType, const bool suppressDialog )
00585 {
00586 QString tmp = i18n("Could not import file of type\n%1").arg( mimeType );
00587
00588 if (!suppressDialog) KMessageBox::error( 0L, tmp, i18n("Missing Import Filter") );
00589 }
00590
00591 void KoFilterManager::setBatchMode( const bool batch )
00592 {
00593 d->m_batch = batch;
00594 }
00595
00596 bool KoFilterManager::getBatchMode( void ) const
00597 {
00598 return d->m_batch;
00599 }
00600
00601 #include <KoFilterManager.moc>
00602 #include <KoFilterManager_p.moc>