kmfactory.cpp

00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (c) 2001 Michael Goffioul <kdeprint@swing.be>
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License version 2 as published by the Free Software Foundation.
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 
00020 #include "kmfactory.h"
00021 #include "kmmanager.h"
00022 #include "kmjobmanager.h"
00023 #include "kmuimanager.h"
00024 #include "kprinterimpl.h"
00025 #include "kprinter.h"
00026 #include "kpreloadobject.h"
00027 #include "kdeprintcheck.h"
00028 #include "kxmlcommand.h"
00029 
00030 #include <qdir.h>
00031 #include <qfile.h>
00032 #include <qsettings.h>
00033 
00034 #include <klibloader.h>
00035 #include <kconfig.h>
00036 #include <kstandarddirs.h>
00037 #include <kiconloader.h>
00038 #include <kdebug.h>
00039 #include <kmessagebox.h>
00040 #include <klocale.h>
00041 #include <ksimpleconfig.h>
00042 #include <kstaticdeleter.h>
00043 #include <kapplication.h>
00044 #include <dcopclient.h>
00045 #include <dcopref.h>
00046 #include <kio/authinfo.h>
00047 
00048 #include <unistd.h>
00049 
00050 #define UNLOAD_OBJECT(x) if (x != 0) { delete x; x = 0; }
00051 
00052 #ifdef Q_WS_X11
00053 extern void qt_generate_epsf( bool b );
00054 #endif
00055 
00056 KMFactory* KMFactory::m_self = 0;
00057 static KStaticDeleter<KMFactory> s_kmfactorysd;
00058 
00059 KMFactory* KMFactory::self()
00060 {
00061     if (!m_self)
00062         m_self = s_kmfactorysd.setObject(m_self, new KMFactory());
00063     return m_self;
00064 }
00065 
00066 bool KMFactory::exists()
00067 {
00068     return m_self != 0L;
00069 }
00070 
00071 void KMFactory::release()
00072 {
00073     if (m_self)
00074     {
00075         KMFactory* p = m_self;
00076         m_self = 0; // so that exists() says false
00077         delete p;
00078     }
00079 }
00080 
00081 KMFactory::KMFactory()
00082     : QObject(NULL, "Factory")
00083 {
00084     m_settings = new Settings;
00085     m_settings->application = KPrinter::Dialog;
00086     m_settings->pageSelection = KPrinter::SystemSide;
00087     m_settings->standardDialogPages = KPrinter::CopiesPage;
00088     m_settings->pageSize = -1;
00089     m_settings->orientation = -1;
00090 
00091     m_objects.setAutoDelete(false);
00092 
00093     m_manager = 0;
00094     m_jobmanager = 0;
00095     m_uimanager = 0;
00096     m_implementation = 0;
00097     m_factory = 0;
00098     m_printconfig = 0;
00099 #if QT_VERSION >= 230
00100     // Qt's default behavior, to generate EPS in some cases and not in others, sucks.
00101     // This is fixed in Qt 3.0, but for Qt 2.x we need to disable it explicitly.
00102     // If this is a problem for anyone, we can add a public method to set this flag.
00103     // (David Faure, doing as advised by Lars Knoll)
00104 #ifdef Q_WS_X11
00105     qt_generate_epsf( false );
00106 #endif
00107 #endif
00108 
00109     // By default, embed PS fonts
00110     bool ok = false;
00111     QSettings settings;
00112     settings.readBoolEntry( "/qt/embedFonts", true, &ok );
00113     if ( !ok )
00114         settings.writeEntry( "/qt/embedFonts", true );
00115 
00116     KGlobal::iconLoader()->addAppDir("kdeprint");
00117         KGlobal::locale()->insertCatalogue("kdeprint");
00118 
00119     // create DCOP signal connection
00120     connectDCOPSignal(0, 0, "pluginChanged(pid_t)", "slot_pluginChanged(pid_t)", false);
00121     connectDCOPSignal(0, 0, "configChanged()", "slot_configChanged()", false);
00122 }
00123 
00124 KMFactory::~KMFactory()
00125 {
00126     delete m_settings;
00127     // The only object to be destroyed is m_printconfig. All other objects have been
00128     // created with "this" as parent, so we don't need to care about their destruction
00129     UNLOAD_OBJECT(m_printconfig);
00130     m_self = 0;
00131 }
00132 
00133 KMManager* KMFactory::manager()
00134 {
00135     if (!m_manager)
00136         createManager();
00137     Q_CHECK_PTR(m_manager);
00138     return m_manager;
00139 }
00140 
00141 KMJobManager* KMFactory::jobManager()
00142 {
00143     if (!m_jobmanager)
00144         createJobManager();
00145     Q_CHECK_PTR(m_jobmanager);
00146     return m_jobmanager;
00147 }
00148 
00149 KMUiManager* KMFactory::uiManager()
00150 {
00151     if (!m_uimanager)
00152         createUiManager();
00153     Q_CHECK_PTR(m_uimanager);
00154     return m_uimanager;
00155 }
00156 
00157 KPrinterImpl* KMFactory::printerImplementation()
00158 {
00159     if (!m_implementation)
00160         createPrinterImpl();
00161     Q_CHECK_PTR(m_implementation);
00162     return m_implementation;
00163 }
00164 
00165 KMVirtualManager* KMFactory::virtualManager()
00166 {
00167     return manager()->m_virtualmgr;
00168 }
00169 
00170 KMSpecialManager* KMFactory::specialManager()
00171 {
00172     return manager()->m_specialmgr;
00173 }
00174 
00175 KXmlCommandManager* KMFactory::commandManager()
00176 {
00177     return KXmlCommandManager::self();
00178 }
00179 
00180 void KMFactory::createManager()
00181 {
00182     loadFactory();
00183     if (m_factory) m_manager = (KMManager*)m_factory->create(this,"Manager","KMManager");
00184     if (!m_manager) m_manager = new KMManager(this,"Manager");
00185 }
00186 
00187 void KMFactory::createJobManager()
00188 {
00189     loadFactory();
00190     if (m_factory) m_jobmanager = (KMJobManager*)m_factory->create(this,"JobManager","KMJobManager");
00191     if (!m_jobmanager) m_jobmanager = new KMJobManager(this,"JobManager");
00192 }
00193 
00194 void KMFactory::createUiManager()
00195 {
00196     loadFactory();
00197     if (m_factory) m_uimanager = (KMUiManager*)m_factory->create(this,"UiManager","KMUiManager");
00198     if (!m_uimanager) m_uimanager = new KMUiManager(this,"UiManager");
00199 }
00200 
00201 void KMFactory::createPrinterImpl()
00202 {
00203     loadFactory();
00204     if (m_factory) m_implementation = (KPrinterImpl*)m_factory->create(this,"PrinterImpl","KPrinterImpl");
00205     if (!m_implementation) m_implementation = new KPrinterImpl(this,"PrinterImpl");
00206 }
00207 
00208 void KMFactory::loadFactory(const QString& syst)
00209 {
00210     if (!m_factory)
00211     {
00212         QString sys(syst);
00213         if (sys.isEmpty())
00214             // load default configured print plugin
00215             sys = printSystem();
00216         QString libname = QString::fromLatin1("kdeprint_%1").arg(sys);
00217         m_factory = KLibLoader::self()->factory(QFile::encodeName(libname));
00218                 if (!m_factory)
00219                 {
00220                         KMessageBox::error(0,
00221                             i18n("<qt>There was an error loading %1. The diagnostic is:<p>%2</p></qt>")
00222                             .arg(libname).arg(KLibLoader::self()->lastErrorMessage()));
00223                 }
00224     }
00225 }
00226 
00227 KConfig* KMFactory::printConfig(const QString& group)
00228 {
00229     //exit(0);
00230     if (!m_printconfig)
00231     {
00232         m_printconfig = new KConfig("kdeprintrc");
00233         Q_CHECK_PTR(m_printconfig);
00234     }
00235     if (!group.isEmpty())
00236         m_printconfig->setGroup(group);
00237     return m_printconfig;
00238 }
00239 
00240 QString KMFactory::printSystem()
00241 {
00242     KConfig *conf = printConfig();
00243     conf->setGroup("General");
00244     QString sys = conf->readEntry("PrintSystem");
00245     if (sys.isEmpty())
00246     {
00247         // perform auto-detection (will at least return "lpdunix")
00248         sys = autoDetect();
00249         // save the result
00250         conf->writeEntry("PrintSystem", sys);
00251         conf->sync();
00252     }
00253     else if ( sys.length()==1 && sys[0].isDigit() ) // discard old-style settings
00254             sys = "lpdunix";
00255     else{
00256         //Always Autodetect
00257         //it will not try autodetect if user changes any option
00258         //when user force some option, AlwaysSearch will be "no" and then
00259         //kprinter will not to try autodetect again.
00260         if(conf->readEntry("AlwaysSearch") != "no" ){
00261             sys = autoDetect();
00262             conf->writeEntry("PrintSystem",sys);
00263             conf->writeEntry("AlwaysSearch","yes");
00264             conf->sync();
00265         }
00266 
00267     }
00268     return sys;
00269 }
00270 
00271 void KMFactory::unload()
00272 {
00273     UNLOAD_OBJECT(m_manager);
00274     UNLOAD_OBJECT(m_jobmanager);
00275     UNLOAD_OBJECT(m_uimanager);
00276     UNLOAD_OBJECT(m_implementation);
00277     // factory will be automatically unloaded by KLibLoader as all object have been deleted.
00278     // But to have loadFactory() to work, we need to set m_factory to NULL.
00279     m_factory = 0;
00280 }
00281 
00282 void KMFactory::reload(const QString& syst, bool saveSyst)
00283 {
00284     // notify all registered objects about the coming reload
00285     QPtrListIterator<KPReloadObject>    it(m_objects);
00286     for (;it.current();++it)
00287         it.current()->aboutToReload();
00288 
00289     // unload all objects from the plugin
00290     unload();
00291     if (saveSyst)
00292     {
00293         KConfig *conf = printConfig();  
00294         conf->setGroup("General");
00295 
00296         conf->writeEntry("AlwaysSearch","no");
00297         conf->writeEntry("PrintSystem", syst);
00298         conf->sync();
00299 
00300         // notify all other apps using DCOP signal
00301         emit pluginChanged(getpid());
00302     }
00303 
00304     // reload the factory
00305     loadFactory(syst);
00306 
00307     // notify all registered objects
00308     for (it.toFirst();it.current();++it)
00309         it.current()->reload();
00310 }
00311 
00312 QValueList<KMFactory::PluginInfo> KMFactory::pluginList()
00313 {
00314     QDir    d(locate("data", "kdeprint/plugins/"), "*.print", QDir::Name, QDir::Files);
00315     QValueList<PluginInfo>  list;
00316     for (uint i=0; i<d.count(); i++)
00317     {
00318         PluginInfo  info(pluginInfo(d.absFilePath(d[i])));
00319         if (info.name.isEmpty())
00320             continue;
00321         list.append(info);
00322     }
00323     return list;
00324 }
00325 
00326 KMFactory::PluginInfo KMFactory::pluginInfo(const QString& name)
00327 {
00328     QString path(name);
00329     if (path[0] != '/')
00330         path = locate("data", QString::fromLatin1("kdeprint/plugins/%1.print").arg(name));
00331     KSimpleConfig   conf(path);
00332     PluginInfo  info;
00333 
00334     conf.setGroup("KDE Print Entry");
00335     info.name = conf.readEntry("PrintSystem");
00336     info.comment = conf.readEntry("Comment");
00337     if (info.comment.isEmpty())
00338         info.comment = info.name;
00339     info.detectUris = conf.readListEntry("DetectUris");
00340     info.detectPrecedence = conf.readNumEntry("DetectPrecedence", 0);
00341     info.mimeTypes = conf.readListEntry("MimeTypes");
00342     if (info.mimeTypes.isEmpty())
00343         info.mimeTypes << "application/postscript";
00344     info.primaryMimeType = conf.readEntry("PrimaryMimeType", info.mimeTypes[0]);
00345 
00346     return info;
00347 }
00348 
00349 void KMFactory::registerObject(KPReloadObject *obj, bool priority)
00350 {
00351     // check if object already registered, then add it
00352     if (m_objects.findRef(obj) == -1)
00353     {
00354         if (priority)
00355             m_objects.prepend(obj);
00356         else
00357             m_objects.append(obj);
00358         kdDebug(500) << "kdeprint: registering " << (void*)obj << ", number of objects = " << m_objects.count() << endl;
00359     }
00360 }
00361 
00362 void KMFactory::unregisterObject(KPReloadObject *obj)
00363 {
00364     // remove object from list (not deleted as autoDelete is false)
00365     m_objects.removeRef(obj);
00366     kdDebug(500) << "kdeprint: unregistering " << (void*)obj << ", number of objects = " << m_objects.count() << endl;
00367 }
00368 
00369 QString KMFactory::autoDetect()
00370 {
00371     QValueList<PluginInfo>  plugins = pluginList();
00372     int pluginIndex(-1), currentPrecedence(0);
00373     for (uint i=0;i<plugins.count();i++)
00374     {
00375         if (plugins[i].detectUris.count() > 0 && KdeprintChecker::check(plugins[i].detectUris)
00376             && (pluginIndex == -1 || plugins[i].detectPrecedence >= currentPrecedence))
00377         {
00378             pluginIndex = i;
00379             currentPrecedence = plugins[i].detectPrecedence;
00380         }
00381     }
00382     return (pluginIndex == -1 ? QString::fromLatin1("lpdunix") : plugins[pluginIndex].name);
00383 }
00384 
00385 void KMFactory::slot_pluginChanged(pid_t pid)
00386 {
00387     // only do something if the notification comes from another process
00388     if (pid != getpid())
00389     {
00390         // Unload config object (avoid saving it)
00391         printConfig()->rollback();
00392         UNLOAD_OBJECT(m_printconfig);
00393         // Then reload everything and notified registered objects.
00394         // Do NOT re-save the new print system.
00395         QString syst = printSystem();
00396         reload(syst, false);
00397     }
00398 }
00399 
00400 void KMFactory::slot_configChanged()
00401 {
00402     kdDebug(500) << "KMFactory (" << getpid() << ") receiving DCOP signal configChanged()" << endl;
00403     // unload/reload config object (make it non dirty to
00404     // avoid saving it and overwriting the newly saved options
00405     // in the other application)
00406     printConfig()->rollback();
00407     UNLOAD_OBJECT(m_printconfig);
00408     printConfig();
00409 
00410     // notify all registered objects about the coming reload
00411     QPtrListIterator<KPReloadObject>    it(m_objects);
00412     /*for (;it.current();++it)
00413         it.current()->aboutToReload();*/
00414 
00415     // notify all object about the change
00416     for (it.toFirst(); it.current();++it)
00417         it.current()->configChanged();
00418 }
00419 
00420 void KMFactory::saveConfig()
00421 {
00422     KConfig *conf = printConfig();
00423     conf->sync();
00424     kdDebug(500) << "KMFactory (" << getpid() << ") emitting DCOP signal configChanged()" << endl;
00425     emit configChanged();
00426     // normally, the self application should also receive the signal,
00427     // anyway the config object has been updated "locally", so ne real
00428     // need to reload the config file.
00429 }
00430 
00431 QPair<QString,QString> KMFactory::requestPassword( int& seqNbr, const QString& user, const QString& host, int port )
00432 {
00433     DCOPRef kdeprintd( "kded", "kdeprintd" );
00440     DCOPReply reply = kdeprintd.call( "requestPassword", user, host, port, seqNbr );
00441     if ( reply.isValid() )
00442     {
00443         QString replyString = reply;
00444         if ( replyString != "::" )
00445         {
00446             QStringList l = QStringList::split( ':', replyString, true );
00447             if ( l.count() == 3 )
00448             {
00449                 seqNbr = l[ 2 ].toInt();
00450                 return QPair<QString,QString>( l[ 0 ], l[ 1 ] );
00451             }
00452         }
00453     }
00454     return QPair<QString,QString>( QString::null, QString::null );
00455 }
00456 
00457 void KMFactory::initPassword( const QString& user, const QString& password, const QString& host, int port )
00458 {
00459     DCOPRef kdeprintd( "kded", "kdeprintd" );
00466     kdeprintd.call( "initPassword", user, password, host, port );
00467 }
00468 
00469 #include "kmfactory.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys