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 if (!m_printconfig) 00230 { 00231 m_printconfig = new KConfig("kdeprintrc"); 00232 Q_CHECK_PTR(m_printconfig); 00233 } 00234 if (!group.isEmpty()) 00235 m_printconfig->setGroup(group); 00236 return m_printconfig; 00237 } 00238 00239 QString KMFactory::printSystem() 00240 { 00241 KConfig *conf = printConfig(); 00242 conf->setGroup("General"); 00243 QString sys = conf->readEntry("PrintSystem"); 00244 if (sys.isEmpty()) 00245 { 00246 // perform auto-detection (will at least return "lpdunix") 00247 sys = autoDetect(); 00248 // save the result 00249 conf->writeEntry("PrintSystem", sys); 00250 conf->sync(); 00251 } 00252 else if ( sys.length()==1 && sys[0].isDigit() ) // discard old-style settings 00253 sys = "lpdunix"; 00254 return sys; 00255 } 00256 00257 void KMFactory::unload() 00258 { 00259 UNLOAD_OBJECT(m_manager); 00260 UNLOAD_OBJECT(m_jobmanager); 00261 UNLOAD_OBJECT(m_uimanager); 00262 UNLOAD_OBJECT(m_implementation); 00263 // factory will be automatically unloaded by KLibLoader as all object have been deleted. 00264 // But to have loadFactory() to work, we need to set m_factory to NULL. 00265 m_factory = 0; 00266 } 00267 00268 void KMFactory::reload(const QString& syst, bool saveSyst) 00269 { 00270 // notify all registered objects about the coming reload 00271 QPtrListIterator<KPReloadObject> it(m_objects); 00272 for (;it.current();++it) 00273 it.current()->aboutToReload(); 00274 00275 // unload all objects from the plugin 00276 unload(); 00277 if (saveSyst) 00278 { 00279 KConfig *conf = printConfig(); 00280 conf->setGroup("General"); 00281 conf->writeEntry("PrintSystem", syst); 00282 conf->sync(); 00283 00284 // notify all other apps using DCOP signal 00285 emit pluginChanged(getpid()); 00286 } 00287 00288 // reload the factory 00289 loadFactory(syst); 00290 00291 // notify all registered objects 00292 for (it.toFirst();it.current();++it) 00293 it.current()->reload(); 00294 } 00295 00296 QValueList<KMFactory::PluginInfo> KMFactory::pluginList() 00297 { 00298 QDir d(locate("data", "kdeprint/plugins/"), "*.print", QDir::Name, QDir::Files); 00299 QValueList<PluginInfo> list; 00300 for (uint i=0; i<d.count(); i++) 00301 { 00302 PluginInfo info(pluginInfo(d.absFilePath(d[i]))); 00303 if (info.name.isEmpty()) 00304 continue; 00305 list.append(info); 00306 } 00307 return list; 00308 } 00309 00310 KMFactory::PluginInfo KMFactory::pluginInfo(const QString& name) 00311 { 00312 QString path(name); 00313 if (path[0] != '/') 00314 path = locate("data", QString::fromLatin1("kdeprint/plugins/%1.print").arg(name)); 00315 KSimpleConfig conf(path); 00316 PluginInfo info; 00317 00318 conf.setGroup("KDE Print Entry"); 00319 info.name = conf.readEntry("PrintSystem"); 00320 info.comment = conf.readEntry("Comment"); 00321 if (info.comment.isEmpty()) 00322 info.comment = info.name; 00323 info.detectUris = conf.readListEntry("DetectUris"); 00324 info.detectPrecedence = conf.readNumEntry("DetectPrecedence", 0); 00325 info.mimeTypes = conf.readListEntry("MimeTypes"); 00326 if (info.mimeTypes.isEmpty()) 00327 info.mimeTypes << "application/postscript"; 00328 info.primaryMimeType = conf.readEntry("PrimaryMimeType", info.mimeTypes[0]); 00329 00330 return info; 00331 } 00332 00333 void KMFactory::registerObject(KPReloadObject *obj, bool priority) 00334 { 00335 // check if object already registered, then add it 00336 if (m_objects.findRef(obj) == -1) 00337 { 00338 if (priority) 00339 m_objects.prepend(obj); 00340 else 00341 m_objects.append(obj); 00342 kdDebug(500) << "kdeprint: registering " << (void*)obj << ", number of objects = " << m_objects.count() << endl; 00343 } 00344 } 00345 00346 void KMFactory::unregisterObject(KPReloadObject *obj) 00347 { 00348 // remove object from list (not deleted as autoDelete is false) 00349 m_objects.removeRef(obj); 00350 kdDebug(500) << "kdeprint: unregistering " << (void*)obj << ", number of objects = " << m_objects.count() << endl; 00351 } 00352 00353 QString KMFactory::autoDetect() 00354 { 00355 QValueList<PluginInfo> plugins = pluginList(); 00356 int pluginIndex(-1), currentPrecedence(0); 00357 for (uint i=0;i<plugins.count();i++) 00358 { 00359 if (plugins[i].detectUris.count() > 0 && KdeprintChecker::check(plugins[i].detectUris) 00360 && (pluginIndex == -1 || plugins[i].detectPrecedence >= currentPrecedence)) 00361 { 00362 pluginIndex = i; 00363 currentPrecedence = plugins[i].detectPrecedence; 00364 } 00365 } 00366 return (pluginIndex == -1 ? QString::fromLatin1("lpdunix") : plugins[pluginIndex].name); 00367 } 00368 00369 void KMFactory::slot_pluginChanged(pid_t pid) 00370 { 00371 // only do something if the notification comes from another process 00372 if (pid != getpid()) 00373 { 00374 // Unload config object (avoid saving it) 00375 printConfig()->rollback(); 00376 UNLOAD_OBJECT(m_printconfig); 00377 // Then reload everything and notified registered objects. 00378 // Do NOT re-save the new print system. 00379 QString syst = printSystem(); 00380 reload(syst, false); 00381 } 00382 } 00383 00384 void KMFactory::slot_configChanged() 00385 { 00386 kdDebug(500) << "KMFactory (" << getpid() << ") receiving DCOP signal configChanged()" << endl; 00387 // unload/reload config object (make it non dirty to 00388 // avoid saving it and overwriting the newly saved options 00389 // in the other application) 00390 printConfig()->rollback(); 00391 UNLOAD_OBJECT(m_printconfig); 00392 printConfig(); 00393 00394 // notify all registered objects about the coming reload 00395 QPtrListIterator<KPReloadObject> it(m_objects); 00396 /*for (;it.current();++it) 00397 it.current()->aboutToReload();*/ 00398 00399 // notify all object about the change 00400 for (it.toFirst(); it.current();++it) 00401 it.current()->configChanged(); 00402 } 00403 00404 void KMFactory::saveConfig() 00405 { 00406 KConfig *conf = printConfig(); 00407 conf->sync(); 00408 kdDebug(500) << "KMFactory (" << getpid() << ") emitting DCOP signal configChanged()" << endl; 00409 emit configChanged(); 00410 // normally, the self application should also receive the signal, 00411 // anyway the config object has been updated "locally", so ne real 00412 // need to reload the config file. 00413 } 00414 00415 QPair<QString,QString> KMFactory::requestPassword( int& seqNbr, const QString& user, const QString& host, int port ) 00416 { 00417 DCOPRef kdeprintd( "kded", "kdeprintd" ); 00424 DCOPReply reply = kdeprintd.call( "requestPassword", user, host, port, seqNbr ); 00425 if ( reply.isValid() ) 00426 { 00427 QString replyString = reply; 00428 if ( replyString != "::" ) 00429 { 00430 QStringList l = QStringList::split( ':', replyString, true ); 00431 if ( l.count() == 3 ) 00432 { 00433 seqNbr = l[ 2 ].toInt(); 00434 return QPair<QString,QString>( l[ 0 ], l[ 1 ] ); 00435 } 00436 } 00437 } 00438 return QPair<QString,QString>( QString::null, QString::null ); 00439 } 00440 00441 void KMFactory::initPassword( const QString& user, const QString& password, const QString& host, int port ) 00442 { 00443 DCOPRef kdeprintd( "kded", "kdeprintd" ); 00450 kdeprintd.call( "initPassword", user, password, host, port ); 00451 } 00452 00453 #include "kmfactory.moc"