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