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