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 if ( t->name() == KMimeType::defaultMimeType() ) {
00148 kdError(s_area) << "No mimetype found for " << url << endl;
00149 status = KoFilter::BadMimeType;
00150 return QString::null;
00151 }
00152
00153 m_graph.setSourceMimeType( t->name().latin1() );
00154 if ( !m_graph.isValid() ) {
00155 bool userCancelled = false;
00156
00157 kdWarning(s_area) << "Can't open " << t->name () << ", trying filter chooser" << endl;
00158 if ( m_document )
00159 {
00160 if ( !m_document->isAutoErrorHandlingEnabled() )
00161 {
00162 status = KoFilter::BadConversionGraph;
00163 return QString::null;
00164 }
00165 QCString nativeFormat = m_document->nativeFormatMimeType ();
00166
00167 QApplication::setOverrideCursor( arrowCursor );
00168 KoFilterChooser chooser(0,
00169 KoFilterManager::mimeFilter (nativeFormat, KoFilterManager::Import, m_document->extraNativeMimeTypes()),
00170 nativeFormat);
00171 if (chooser.exec ())
00172 {
00173 QCString f = chooser.filterSelected ().latin1();
00174
00175 if (f == nativeFormat)
00176 {
00177 status = KoFilter::OK;
00178 QApplication::restoreOverrideCursor();
00179 return url;
00180 }
00181
00182 m_graph.setSourceMimeType (f);
00183 }
00184 else
00185 userCancelled = true;
00186 QApplication::restoreOverrideCursor();
00187 }
00188
00189 if (!m_graph.isValid())
00190 {
00191 kdError(s_area) << "Couldn't create a valid graph for this source mimetype: "
00192 << t->name() << endl;
00193 importErrorHelper( t->name(), userCancelled );
00194 status = KoFilter::BadConversionGraph;
00195 return QString::null;
00196 }
00197 }
00198
00199 KoFilterChain::Ptr chain( 0 );
00200
00201 if ( m_document ) {
00202 QCString mimeType = m_document->nativeFormatMimeType();
00203 QStringList extraMimes = m_document->extraNativeMimeTypes();
00204 int i=0, n = extraMimes.count();
00205 chain = m_graph.chain( this, mimeType );
00206 while( !chain && i<n) {
00207 mimeType = extraMimes[i].utf8();
00208 chain = m_graph.chain( this, mimeType );
00209 ++i;
00210 }
00211 }
00212 else {
00213 kdError(s_area) << "You aren't supposed to use import() from a filter!" << endl;
00214 status = KoFilter::UsageError;
00215 return QString::null;
00216 }
00217
00218 if ( !chain ) {
00219 kdError(s_area) << "Couldn't create a valid filter chain!" << endl;
00220 importErrorHelper( t->name() );
00221 status = KoFilter::BadConversionGraph;
00222 return QString::null;
00223 }
00224
00225
00226 m_direction = Import;
00227 m_importUrl = url;
00228 m_exportUrl = QString::null;
00229
00230 status = chain->invokeChain();
00231
00232 m_importUrl = QString::null;
00233
00234 if ( status == KoFilter::OK )
00235 return chain->chainOutput();
00236 return QString::null;
00237 }
00238
00239 KoFilter::ConversionStatus KoFilterManager::exp0rt( const QString& url, QCString& mimeType )
00240 {
00241 bool userCancelled = false;
00242
00243
00244
00245 m_direction = Export;
00246 m_exportUrl = url;
00247
00248 KoFilterChain::Ptr chain = 0;
00249 if ( m_document ) {
00250
00251 QStringList nativeMimeTypes;
00252 nativeMimeTypes.append( m_document->nativeFormatMimeType() );
00253 nativeMimeTypes += m_document->extraNativeMimeTypes();
00254 QStringList::ConstIterator it = nativeMimeTypes.begin();
00255 const QStringList::ConstIterator end = nativeMimeTypes.end();
00256 for ( ; !chain && it != end; ++it )
00257 {
00258 m_graph.setSourceMimeType( (*it).latin1() );
00259 if ( m_graph.isValid() )
00260 chain = m_graph.chain( this, mimeType );
00261 }
00262 }
00263 else if ( !m_importUrlMimetypeHint.isEmpty() ) {
00264 kdDebug(s_area) << "Using the mimetype hint: '" << m_importUrlMimetypeHint << "'" << endl;
00265 m_graph.setSourceMimeType( m_importUrlMimetypeHint );
00266 }
00267 else {
00268 KURL u;
00269 u.setPath( m_importUrl );
00270 KMimeType::Ptr t = KMimeType::findByURL( u, 0, true );
00271 if ( t->name() == KMimeType::defaultMimeType() ) {
00272 kdError(s_area) << "No mimetype found for " << m_importUrl << endl;
00273 return KoFilter::BadMimeType;
00274 }
00275 m_graph.setSourceMimeType( t->name().latin1() );
00276
00277 if ( !m_graph.isValid() ) {
00278 kdWarning(s_area) << "Can't open " << t->name () << ", trying filter chooser" << endl;
00279
00280 QApplication::setOverrideCursor( arrowCursor );
00281 KoFilterChooser chooser(0, KoFilterManager::mimeFilter ());
00282 if (chooser.exec ())
00283 m_graph.setSourceMimeType (chooser.filterSelected ().latin1 ());
00284 else
00285 userCancelled = true;
00286
00287 QApplication::restoreOverrideCursor();
00288 }
00289 }
00290
00291 if (!m_graph.isValid ())
00292 {
00293 kdError(s_area) << "Couldn't create a valid graph for this source mimetype." << endl;
00294 if (!userCancelled) KMessageBox::error( 0L, i18n("Could not export file."), i18n("Missing Export Filter") );
00295 return KoFilter::BadConversionGraph;
00296 }
00297
00298 if ( !chain )
00299 chain = m_graph.chain( this, mimeType );
00300
00301 if ( !chain ) {
00302 kdError(s_area) << "Couldn't create a valid filter chain to " << mimeType << " !" << endl;
00303 KMessageBox::error( 0L, i18n("Could not export file."), i18n("Missing Export Filter") );
00304 return KoFilter::BadConversionGraph;
00305 }
00306
00307 return chain->invokeChain();
00308 }
00309
00310 namespace
00311 {
00312
00313 class Vertex
00314 {
00315 public:
00316 Vertex( const QCString& mimeType ) : m_color( White ), m_mimeType( mimeType ) {}
00317
00318 enum Color { White, Gray, Black };
00319 Color color() const { return m_color; }
00320 void setColor( Color color ) { m_color = color; }
00321
00322 QCString mimeType() const { return m_mimeType; }
00323
00324 void addEdge( Vertex* vertex ) { if ( vertex ) m_edges.append( vertex ); }
00325 QPtrList<Vertex> edges() const { return m_edges; }
00326
00327 private:
00328 Color m_color;
00329 QCString m_mimeType;
00330 QPtrList<Vertex> m_edges;
00331 };
00332
00333
00334
00335 void buildGraph( QAsciiDict<Vertex>& vertices, KoFilterManager::Direction direction )
00336 {
00337 QStringList stopList;
00338 stopList << "text/plain";
00339 stopList << "text/csv";
00340 stopList << "text/x-tex";
00341 stopList << "text/html";
00342
00343 vertices.setAutoDelete( true );
00344
00345
00346
00347 QValueList<KoDocumentEntry> parts( KoDocumentEntry::query(false, QString::null) );
00348 QValueList<KoDocumentEntry>::ConstIterator partIt( parts.begin() );
00349 QValueList<KoDocumentEntry>::ConstIterator partEnd( parts.end() );
00350
00351 while ( partIt != partEnd ) {
00352 QStringList nativeMimeTypes = ( *partIt ).service()->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
00353 nativeMimeTypes += ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString();
00354 QStringList::ConstIterator it = nativeMimeTypes.begin();
00355 const QStringList::ConstIterator end = nativeMimeTypes.end();
00356 for ( ; it != end; ++it )
00357 if ( !(*it).isEmpty() )
00358 vertices.insert( (*it).latin1(), new Vertex( (*it).latin1() ) );
00359 ++partIt;
00360 }
00361
00362 QValueList<KoFilterEntry::Ptr> filters = KoFilterEntry::query();
00363 QValueList<KoFilterEntry::Ptr>::ConstIterator it = filters.begin();
00364 const QValueList<KoFilterEntry::Ptr>::ConstIterator end = filters.end();
00365
00366 for ( ; it != end; ++it ) {
00367
00368 QStringList impList;
00369 QStringList expList;
00370
00371 const QStringList::Iterator stopEnd = stopList.end();
00372
00373 if ( direction == KoFilterManager::Import ) {
00374
00375 QStringList::ConstIterator testIt = ( *it )->export_.begin();
00376 QStringList::ConstIterator testEnd = ( *it )->export_.end();
00377 for ( ; testIt != testEnd ; ++testIt ) {
00378 if ( stopList.find( *testIt ) == stopEnd ) {
00379 expList.append( *testIt );
00380 }
00381 }
00382 impList = ( *it )->import;
00383 }
00384 else {
00385
00386 QStringList::ConstIterator testIt = ( *it )->import.begin();
00387 const QStringList::ConstIterator testEnd = ( *it )->import.end();
00388 for ( ; testIt != testEnd ; ++testIt ) {
00389 if ( stopList.find( *testIt ) == stopEnd ) {
00390 impList.append( *testIt );
00391 }
00392 }
00393 expList = ( *it )->export_;
00394 }
00395
00396 if ( impList.empty() || expList.empty() )
00397 {
00398
00399 kdDebug( 30500 ) << "Filter: " << ( *it )->service()->name() << " ruled out" << endl;
00400 continue;
00401 }
00402
00403
00404 QStringList::ConstIterator importIt = impList.begin();
00405 const QStringList::ConstIterator importEnd = impList.end();
00406 for ( ; importIt != importEnd; ++importIt ) {
00407 const QCString key = ( *importIt ).latin1();
00408
00409 if ( !vertices[ key ] )
00410 vertices.insert( key, new Vertex( key ) );
00411 }
00412
00413
00414 if ( KoFilterManager::filterAvailable( *it ) ) {
00415 QStringList::ConstIterator exportIt = expList.begin();
00416 const QStringList::ConstIterator exportEnd = expList.end();
00417
00418 for ( ; exportIt != exportEnd; ++exportIt ) {
00419
00420 const QCString key = ( *exportIt ).latin1();
00421 Vertex* exp = vertices[ key ];
00422 if ( !exp ) {
00423 exp = new Vertex( key );
00424 vertices.insert( key, exp );
00425 }
00426
00427
00428
00429
00430 importIt = impList.begin();
00431 if ( direction == KoFilterManager::Import ) {
00432 for ( ; importIt != importEnd; ++importIt )
00433 exp->addEdge( vertices[ ( *importIt ).latin1() ] );
00434 } else {
00435 for ( ; importIt != importEnd; ++importIt )
00436 vertices[ ( *importIt ).latin1() ]->addEdge( exp );
00437 }
00438 }
00439 }
00440 else
00441 kdDebug( 30500 ) << "Filter: " << ( *it )->service()->name() << " does not apply." << endl;
00442 }
00443 }
00444
00445
00446
00447
00448 QStringList connected( const QAsciiDict<Vertex>& vertices, const QCString& mimetype )
00449 {
00450 if ( mimetype.isEmpty() )
00451 return QStringList();
00452 Vertex *v = vertices[ mimetype ];
00453 if ( !v )
00454 return QStringList();
00455
00456 v->setColor( Vertex::Gray );
00457 std::queue<Vertex*> queue;
00458 queue.push( v );
00459 QStringList connected;
00460
00461 while ( !queue.empty() ) {
00462 v = queue.front();
00463 queue.pop();
00464 QPtrList<Vertex> edges = v->edges();
00465 QPtrListIterator<Vertex> it( edges );
00466 for ( ; it.current(); ++it ) {
00467 if ( it.current()->color() == Vertex::White ) {
00468 it.current()->setColor( Vertex::Gray );
00469 queue.push( it.current() );
00470 }
00471 }
00472 v->setColor( Vertex::Black );
00473 connected.append( v->mimeType() );
00474 }
00475 return connected;
00476 }
00477 }
00478
00479
00480
00481 QStringList KoFilterManager::mimeFilter( const QCString& mimetype, Direction direction, const QStringList& extraNativeMimeTypes )
00482 {
00483
00484 QAsciiDict<Vertex> vertices;
00485 buildGraph( vertices, direction );
00486
00487
00488
00489 QStringList nativeMimeTypes;
00490 nativeMimeTypes.append( QString::fromLatin1( mimetype ) );
00491 nativeMimeTypes += extraNativeMimeTypes;
00492
00493
00494 QStringList lst = nativeMimeTypes;
00495
00496
00497 for( QStringList::ConstIterator natit = nativeMimeTypes.begin(); natit != nativeMimeTypes.end(); ++natit ) {
00498 const QStringList outMimes = connected( vertices, (*natit).latin1() );
00499
00500 for ( QStringList::ConstIterator mit = outMimes.begin(); mit != outMimes.end(); ++mit )
00501 if ( lst.find( *mit ) == lst.end() )
00502 lst.append( *mit );
00503 }
00504 return lst;
00505 }
00506
00507 QStringList KoFilterManager::mimeFilter()
00508 {
00509 QAsciiDict<Vertex> vertices;
00510 buildGraph( vertices, KoFilterManager::Import );
00511
00512 QValueList<KoDocumentEntry> parts( KoDocumentEntry::query(false, QString::null) );
00513 QValueList<KoDocumentEntry>::ConstIterator partIt( parts.begin() );
00514 QValueList<KoDocumentEntry>::ConstIterator partEnd( parts.end() );
00515
00516 if ( partIt == partEnd )
00517 return QStringList();
00518
00519
00520
00521
00522
00523
00524 Vertex *v = new Vertex( "supercalifragilistic/x-pialadocious" );
00525 vertices.insert( "supercalifragilistic/x-pialadocious", v );
00526 while ( partIt != partEnd ) {
00527 QStringList nativeMimeTypes = ( *partIt ).service()->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
00528 nativeMimeTypes += ( *partIt ).service()->property( "X-KDE-NativeMimeType" ).toString();
00529 QStringList::ConstIterator it = nativeMimeTypes.begin();
00530 const QStringList::ConstIterator end = nativeMimeTypes.end();
00531 for ( ; it != end; ++it )
00532 if ( !(*it).isEmpty() )
00533 v->addEdge( vertices[ (*it).latin1() ] );
00534 ++partIt;
00535 }
00536 QStringList result = connected( vertices, "supercalifragilistic/x-pialadocious" );
00537
00538
00539 result.remove( "supercalifragilistic/x-pialadocious" );
00540 return result;
00541 }
00542
00543
00544
00545 bool KoFilterManager::filterAvailable( KoFilterEntry::Ptr entry )
00546 {
00547 if ( !entry )
00548 return false;
00549 if ( entry->available != "check" )
00550 return true;
00551
00552
00553
00554 QString key( entry->service()->name() );
00555 key += " - ";
00556 key += entry->service()->library();
00557
00558 if ( !m_filterAvailable.contains( key ) ) {
00559
00560
00561 KLibrary* library = KLibLoader::self()->library( QFile::encodeName( entry->service()->library() ) );
00562 if ( !library ) {
00563 kdWarning( 30500 ) << "Huh?? Couldn't load the lib: "
00564 << KLibLoader::self()->lastErrorMessage() << endl;
00565 m_filterAvailable[ key ] = false;
00566 return false;
00567 }
00568
00569
00570 QCString symname;
00571 symname.sprintf("check_%s", library->name().latin1() );
00572 void* sym = library->symbol( symname );
00573 if ( !sym )
00574 {
00575 kdWarning( 30500 ) << "The library " << library->name()
00576 << " does not offer a check_" << library->name()
00577 << " function." << endl;
00578 m_filterAvailable[ key ] = false;
00579 }
00580 else {
00581 typedef int (*t_func)();
00582 t_func check = (t_func)sym;
00583 m_filterAvailable[ key ] = check() == 1;
00584 }
00585 }
00586 return m_filterAvailable[ key ];
00587 }
00588
00589 void KoFilterManager::importErrorHelper( const QString& mimeType, const bool suppressDialog )
00590 {
00591 QString tmp = i18n("Could not import file of type\n%1").arg( mimeType );
00592
00593 if (!suppressDialog) KMessageBox::error( 0L, tmp, i18n("Missing Import Filter") );
00594 }
00595
00596 void KoFilterManager::setBatchMode( const bool batch )
00597 {
00598 d->m_batch = batch;
00599 }
00600
00601 bool KoFilterManager::getBatchMode( void ) const
00602 {
00603 return d->m_batch;
00604 }
00605
00606 #include <KoFilterManager.moc>
00607 #include <KoFilterManager_p.moc>