You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/kdeprint/kmfactory.cpp

454 lines
12 KiB

/*
* This file is part of the KDE libraries
* Copyright (c) 2001 Michael Goffioul <kdeprint@swing.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
**/
#include "kmfactory.h"
#include "kmmanager.h"
#include "kmjobmanager.h"
#include "kmuimanager.h"
#include "kprinterimpl.h"
#include "kprinter.h"
#include "kpreloadobject.h"
#include "kdeprintcheck.h"
#include "kxmlcommand.h"
#include <tqdir.h>
#include <tqfile.h>
#include <tqsettings.h>
#include <klibloader.h>
#include <kconfig.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <ksimpleconfig.h>
#include <kstaticdeleter.h>
#include <kapplication.h>
#include <dcopclient.h>
#include <dcopref.h>
#include <kio/authinfo.h>
#include <unistd.h>
#define UNLOAD_OBJECT(x) if (x != 0) { delete x; x = 0; }
#ifdef Q_WS_X11
extern void qt_generate_epsf( bool b );
#endif
KMFactory* KMFactory::m_self = 0;
static KStaticDeleter<KMFactory> s_kmfactorysd;
KMFactory* KMFactory::self()
{
if (!m_self)
m_self = s_kmfactorysd.setObject(m_self, new KMFactory());
return m_self;
}
bool KMFactory::exists()
{
return m_self != 0L;
}
void KMFactory::release()
{
if (m_self)
{
KMFactory* p = m_self;
m_self = 0; // so that exists() says false
delete p;
}
}
KMFactory::KMFactory()
: TQObject(NULL, "Factory")
{
m_settings = new Settings;
m_settings->application = KPrinter::Dialog;
m_settings->pageSelection = KPrinter::SystemSide;
m_settings->standardDialogPages = KPrinter::CopiesPage;
m_settings->pageSize = -1;
m_settings->orientation = -1;
m_objects.setAutoDelete(false);
m_manager = 0;
m_jobmanager = 0;
m_uimanager = 0;
m_implementation = 0;
m_factory = 0;
m_printconfig = 0;
#if QT_VERSION >= 230
// Qt's default behavior, to generate EPS in some cases and not in others, sucks.
// This is fixed in Qt 3.0, but for Qt 2.x we need to disable it explicitly.
// If this is a problem for anyone, we can add a public method to set this flag.
// (David Faure, doing as advised by Lars Knoll)
#ifdef Q_WS_X11
qt_generate_epsf( false );
#endif
#endif
// By default, embed PS fonts
bool ok = false;
TQSettings settings;
settings.readBoolEntry( "/qt/embedFonts", true, &ok );
if ( !ok )
settings.writeEntry( "/qt/embedFonts", true );
KGlobal::iconLoader()->addAppDir("kdeprint");
KGlobal::locale()->insertCatalogue("kdeprint");
// create DCOP signal connection
connectDCOPSignal(0, 0, "pluginChanged(pid_t)", "slot_pluginChanged(pid_t)", false);
connectDCOPSignal(0, 0, "configChanged()", "slot_configChanged()", false);
}
KMFactory::~KMFactory()
{
delete m_settings;
// The only object to be destroyed is m_printconfig. All other objects have been
// created with "this" as parent, so we don't need to care about their destruction
UNLOAD_OBJECT(m_printconfig);
m_self = 0;
}
KMManager* KMFactory::manager()
{
if (!m_manager)
createManager();
Q_CHECK_PTR(m_manager);
return m_manager;
}
KMJobManager* KMFactory::jobManager()
{
if (!m_jobmanager)
createJobManager();
Q_CHECK_PTR(m_jobmanager);
return m_jobmanager;
}
KMUiManager* KMFactory::uiManager()
{
if (!m_uimanager)
createUiManager();
Q_CHECK_PTR(m_uimanager);
return m_uimanager;
}
KPrinterImpl* KMFactory::printerImplementation()
{
if (!m_implementation)
createPrinterImpl();
Q_CHECK_PTR(m_implementation);
return m_implementation;
}
KMVirtualManager* KMFactory::virtualManager()
{
return manager()->m_virtualmgr;
}
KMSpecialManager* KMFactory::specialManager()
{
return manager()->m_specialmgr;
}
KXmlCommandManager* KMFactory::commandManager()
{
return KXmlCommandManager::self();
}
void KMFactory::createManager()
{
loadFactory();
if (m_factory) m_manager = (KMManager*)m_factory->create(this,"Manager","KMManager");
if (!m_manager) m_manager = new KMManager(this,"Manager");
}
void KMFactory::createJobManager()
{
loadFactory();
if (m_factory) m_jobmanager = (KMJobManager*)m_factory->create(this,"JobManager","KMJobManager");
if (!m_jobmanager) m_jobmanager = new KMJobManager(this,"JobManager");
}
void KMFactory::createUiManager()
{
loadFactory();
if (m_factory) m_uimanager = (KMUiManager*)m_factory->create(this,"UiManager","KMUiManager");
if (!m_uimanager) m_uimanager = new KMUiManager(this,"UiManager");
}
void KMFactory::createPrinterImpl()
{
loadFactory();
if (m_factory) m_implementation = (KPrinterImpl*)m_factory->create(this,"PrinterImpl","KPrinterImpl");
if (!m_implementation) m_implementation = new KPrinterImpl(this,"PrinterImpl");
}
void KMFactory::loadFactory(const TQString& syst)
{
if (!m_factory)
{
TQString sys(syst);
if (sys.isEmpty())
// load default configured print plugin
sys = printSystem();
TQString libname = TQString::tqfromLatin1("kdeprint_%1").arg(sys);
m_factory = KLibLoader::self()->factory(TQFile::encodeName(libname));
if (!m_factory)
{
KMessageBox::error(0,
i18n("<qt>There was an error loading %1. The diagnostic is:<p>%2</p></qt>")
.arg(libname).arg(KLibLoader::self()->lastErrorMessage()));
}
}
}
KConfig* KMFactory::printConfig(const TQString& group)
{
if (!m_printconfig)
{
m_printconfig = new KConfig("kdeprintrc");
Q_CHECK_PTR(m_printconfig);
}
if (!group.isEmpty())
m_printconfig->setGroup(group);
return m_printconfig;
}
TQString KMFactory::printSystem()
{
KConfig *conf = printConfig();
conf->setGroup("General");
TQString sys = conf->readEntry("PrintSystem");
if (sys.isEmpty())
{
// perform auto-detection (will at least return "lpdunix")
sys = autoDetect();
// save the result
conf->writeEntry("PrintSystem", sys);
conf->sync();
}
else if ( sys.length()==1 && sys[0].isDigit() ) // discard old-style settings
sys = "lpdunix";
return sys;
}
void KMFactory::unload()
{
UNLOAD_OBJECT(m_manager);
UNLOAD_OBJECT(m_jobmanager);
UNLOAD_OBJECT(m_uimanager);
UNLOAD_OBJECT(m_implementation);
// factory will be automatically unloaded by KLibLoader as all object have been deleted.
// But to have loadFactory() to work, we need to set m_factory to NULL.
m_factory = 0;
}
void KMFactory::reload(const TQString& syst, bool saveSyst)
{
// notify all registered objects about the coming reload
TQPtrListIterator<KPReloadObject> it(m_objects);
for (;it.current();++it)
it.current()->aboutToReload();
// unload all objects from the plugin
unload();
if (saveSyst)
{
KConfig *conf = printConfig();
conf->setGroup("General");
conf->writeEntry("PrintSystem", syst);
conf->sync();
// notify all other apps using DCOP signal
emit pluginChanged(getpid());
}
// reload the factory
loadFactory(syst);
// notify all registered objects
for (it.toFirst();it.current();++it)
it.current()->reload();
}
TQValueList<KMFactory::PluginInfo> KMFactory::pluginList()
{
TQDir d(locate("data", "kdeprint/plugins/"), "*.print", TQDir::Name, TQDir::Files);
TQValueList<PluginInfo> list;
for (uint i=0; i<d.count(); i++)
{
PluginInfo info(pluginInfo(d.absFilePath(d[i])));
if (info.name.isEmpty())
continue;
list.append(info);
}
return list;
}
KMFactory::PluginInfo KMFactory::pluginInfo(const TQString& name)
{
TQString path(name);
if (path[0] != '/')
path = locate("data", TQString::tqfromLatin1("kdeprint/plugins/%1.print").arg(name));
KSimpleConfig conf(path);
PluginInfo info;
conf.setGroup("KDE Print Entry");
info.name = conf.readEntry("PrintSystem");
info.comment = conf.readEntry("Comment");
if (info.comment.isEmpty())
info.comment = info.name;
info.detectUris = conf.readListEntry("DetectUris");
info.detectPrecedence = conf.readNumEntry("DetectPrecedence", 0);
info.mimeTypes = conf.readListEntry("MimeTypes");
if (info.mimeTypes.isEmpty())
info.mimeTypes << "application/postscript";
info.primaryMimeType = conf.readEntry("PrimaryMimeType", info.mimeTypes[0]);
return info;
}
void KMFactory::registerObject(KPReloadObject *obj, bool priority)
{
// check if object already registered, then add it
if (m_objects.findRef(obj) == -1)
{
if (priority)
m_objects.prepend(obj);
else
m_objects.append(obj);
kdDebug(500) << "kdeprint: registering " << (void*)obj << ", number of objects = " << m_objects.count() << endl;
}
}
void KMFactory::unregisterObject(KPReloadObject *obj)
{
// remove object from list (not deleted as autoDelete is false)
m_objects.removeRef(obj);
kdDebug(500) << "kdeprint: unregistering " << (void*)obj << ", number of objects = " << m_objects.count() << endl;
}
TQString KMFactory::autoDetect()
{
TQValueList<PluginInfo> plugins = pluginList();
int pluginIndex(-1), currentPrecedence(0);
for (uint i=0;i<plugins.count();i++)
{
if (plugins[i].detectUris.count() > 0 && KdeprintChecker::check(plugins[i].detectUris)
&& (pluginIndex == -1 || plugins[i].detectPrecedence >= currentPrecedence))
{
pluginIndex = i;
currentPrecedence = plugins[i].detectPrecedence;
}
}
return (pluginIndex == -1 ? TQString::tqfromLatin1("lpdunix") : plugins[pluginIndex].name);
}
void KMFactory::slot_pluginChanged(pid_t pid)
{
// only do something if the notification comes from another process
if (pid != getpid())
{
// Unload config object (avoid saving it)
printConfig()->rollback();
UNLOAD_OBJECT(m_printconfig);
// Then reload everything and notified registered objects.
// Do NOT re-save the new print system.
TQString syst = printSystem();
reload(syst, false);
}
}
void KMFactory::slot_configChanged()
{
kdDebug(500) << "KMFactory (" << getpid() << ") receiving DCOP signal configChanged()" << endl;
// unload/reload config object (make it non dirty to
// avoid saving it and overwriting the newly saved options
// in the other application)
printConfig()->rollback();
UNLOAD_OBJECT(m_printconfig);
printConfig();
// notify all registered objects about the coming reload
TQPtrListIterator<KPReloadObject> it(m_objects);
/*for (;it.current();++it)
it.current()->aboutToReload();*/
// notify all object about the change
for (it.toFirst(); it.current();++it)
it.current()->configChanged();
}
void KMFactory::saveConfig()
{
KConfig *conf = printConfig();
conf->sync();
kdDebug(500) << "KMFactory (" << getpid() << ") emitting DCOP signal configChanged()" << endl;
emit configChanged();
// normally, the self application should also receive the signal,
// anyway the config object has been updated "locally", so ne real
// need to reload the config file.
}
TQPair<TQString,TQString> KMFactory::requestPassword( int& seqNbr, const TQString& user, const TQString& host, int port )
{
DCOPRef kdeprintd( "kded", "kdeprintd" );
/**
* We do not use an internal event loop for 2 potential problems:
* - the MessageWindow modality (appearing afterwards, it pops up on top
* of the password dialog)
* - KMTimer should be stopped, but it's unavailable from this object
*/
DCOPReply reply = kdeprintd.call( "requestPassword", user, host, port, seqNbr );
if ( reply.isValid() )
{
TQString replyString = reply;
if ( replyString != "::" )
{
TQStringList l = TQStringList::split( ':', replyString, true );
if ( l.count() == 3 )
{
seqNbr = l[ 2 ].toInt();
return TQPair<TQString,TQString>( l[ 0 ], l[ 1 ] );
}
}
}
return TQPair<TQString,TQString>( TQString::null, TQString::null );
}
void KMFactory::initPassword( const TQString& user, const TQString& password, const TQString& host, int port )
{
DCOPRef kdeprintd( "kded", "kdeprintd" );
/**
* We do not use an internal event loop for 2 potential problems:
* - the MessageWindow modality (appearing afterwards, it pops up on top
* of the password dialog)
* - KMTimer should be stopped, but it's unavailable from this object
*/
kdeprintd.call( "initPassword", user, password, host, port );
}
#include "kmfactory.moc"