2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2014-01-07 13:27:11 +01:00
|
|
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
2012-10-02 09:12:39 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
|
**
|
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 14:09:21 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "pluginmanager.h"
|
|
|
|
|
#include "pluginmanager_p.h"
|
|
|
|
|
#include "pluginspec.h"
|
|
|
|
|
#include "pluginspec_p.h"
|
|
|
|
|
#include "optionsparser.h"
|
|
|
|
|
#include "iplugin.h"
|
2010-03-12 16:02:23 +01:00
|
|
|
#include "plugincollection.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QEventLoop>
|
|
|
|
|
#include <QDateTime>
|
|
|
|
|
#include <QDir>
|
2013-08-28 16:29:08 +02:00
|
|
|
#include <QFile>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QMetaProperty>
|
|
|
|
|
#include <QSettings>
|
|
|
|
|
#include <QTextStream>
|
|
|
|
|
#include <QTime>
|
|
|
|
|
#include <QWriteLocker>
|
2012-08-06 13:42:46 +02:00
|
|
|
#include <QDebug>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QTimer>
|
2013-08-28 16:29:08 +02:00
|
|
|
#include <QSysInfo>
|
2011-01-05 18:35:08 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#ifdef WITH_TESTS
|
|
|
|
|
#include <QTest>
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-09-26 13:01:29 +02:00
|
|
|
const char C_IGNORED_PLUGINS[] = "Plugins/Ignored";
|
|
|
|
|
const char C_FORCEENABLED_PLUGINS[] = "Plugins/ForceEnabled";
|
|
|
|
|
const int DELAYED_INITIALIZE_INTERVAL = 20; // ms
|
2010-03-12 16:02:23 +01:00
|
|
|
|
2008-12-11 11:26:42 +01:00
|
|
|
typedef QList<ExtensionSystem::PluginSpec *> PluginSpecSet;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
enum { debugLeaks = 0 };
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\namespace ExtensionSystem
|
2011-01-05 18:35:08 +01:00
|
|
|
\brief The ExtensionSystem namespace provides classes that belong to the
|
|
|
|
|
core plugin system.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-01-05 18:35:08 +01:00
|
|
|
The basic extension system contains the plugin manager and its supporting classes,
|
2008-12-02 12:01:29 +01:00
|
|
|
and the IPlugin interface that must be implemented by plugin providers.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\namespace ExtensionSystem::Internal
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class ExtensionSystem::PluginManager
|
|
|
|
|
\mainclass
|
|
|
|
|
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The PluginManager class implements the core plugin system that
|
|
|
|
|
manages the plugins, their life cycle, and their registered objects.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
The plugin manager is used for the following tasks:
|
|
|
|
|
\list
|
2013-02-06 08:50:23 +01:00
|
|
|
\li Manage plugins and their state
|
|
|
|
|
\li Manipulate a 'common object pool'
|
2008-12-02 12:01:29 +01:00
|
|
|
\endlist
|
|
|
|
|
|
|
|
|
|
\section1 Plugins
|
2013-09-06 11:46:55 +02:00
|
|
|
Plugins consist of an XML descriptor file, and of a library that contains a Qt plugin
|
2008-12-02 12:01:29 +01:00
|
|
|
(declared via Q_EXPORT_PLUGIN) that must derive from the IPlugin class.
|
|
|
|
|
The plugin manager is used to set a list of file system directories to search for
|
|
|
|
|
plugins, retrieve information about the state of these plugins, and to load them.
|
|
|
|
|
|
2013-09-06 11:46:55 +02:00
|
|
|
Usually, the application creates a PluginManager instance and initiates the
|
|
|
|
|
loading.
|
2008-12-02 12:01:29 +01:00
|
|
|
\code
|
2013-08-30 12:30:04 +02:00
|
|
|
// 'plugins' and subdirs will be searched for plugins
|
|
|
|
|
ExtensionSystem::PluginManager::setPluginPaths(QStringList() << "plugins");
|
|
|
|
|
ExtensionSystem::PluginManager::loadPlugins(); // try to load all the plugins
|
2008-12-02 12:01:29 +01:00
|
|
|
\endcode
|
2013-09-06 11:46:55 +02:00
|
|
|
Additionally, it is possible to directly access the plugin specifications
|
|
|
|
|
(the information in the descriptor file), the plugin instances (via PluginSpec),
|
2008-12-02 12:01:29 +01:00
|
|
|
and their state.
|
|
|
|
|
|
|
|
|
|
\section1 Object Pool
|
|
|
|
|
Plugins (and everybody else) can add objects to a common 'pool' that is located in
|
|
|
|
|
the plugin manager. Objects in the pool must derive from QObject, there are no other
|
|
|
|
|
prerequisites. All objects of a specified type can be retrieved from the object pool
|
2014-05-06 17:56:30 +02:00
|
|
|
via the getObjects() and getObject() functions.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
Whenever the state of the object pool changes a corresponding signal is emitted by the plugin manager.
|
|
|
|
|
|
|
|
|
|
A common usecase for the object pool is that a plugin (or the application) provides
|
|
|
|
|
an "extension point" for other plugins, which is a class / interface that can
|
|
|
|
|
be implemented and added to the object pool. The plugin that provides the
|
|
|
|
|
extension point looks for implementations of the class / interface in the object pool.
|
|
|
|
|
\code
|
2011-01-05 18:35:08 +01:00
|
|
|
// Plugin A provides a "MimeTypeHandler" extension point
|
2008-12-02 12:01:29 +01:00
|
|
|
// in plugin B:
|
|
|
|
|
MyMimeTypeHandler *handler = new MyMimeTypeHandler();
|
|
|
|
|
ExtensionSystem::PluginManager::instance()->addObject(handler);
|
2011-01-05 18:35:08 +01:00
|
|
|
// In plugin A:
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<MimeTypeHandler *> mimeHandlers =
|
2013-08-30 12:30:04 +02:00
|
|
|
ExtensionSystem::PluginManager::getObjects<MimeTypeHandler>();
|
2008-12-02 12:01:29 +01:00
|
|
|
\endcode
|
|
|
|
|
|
2011-01-05 18:35:08 +01:00
|
|
|
|
|
|
|
|
The \c{ExtensionSystem::Invoker} class template provides "syntactic sugar"
|
|
|
|
|
for using "soft" extension points that may or may not be provided by an
|
|
|
|
|
object in the pool. This approach does neither require the "user" plugin being
|
|
|
|
|
linked against the "provider" plugin nor a common shared
|
|
|
|
|
header file. The exposed interface is implicitly given by the
|
2013-10-07 13:34:40 +02:00
|
|
|
invokable functions of the "provider" object in the object pool.
|
2011-01-05 18:35:08 +01:00
|
|
|
|
|
|
|
|
The \c{ExtensionSystem::invoke} function template encapsulates
|
2012-11-28 20:28:42 +02:00
|
|
|
{ExtensionSystem::Invoker} construction for the common case where
|
2011-01-05 18:35:08 +01:00
|
|
|
the success of the call is not checked.
|
|
|
|
|
|
|
|
|
|
\code
|
|
|
|
|
// In the "provide" plugin A:
|
|
|
|
|
namespace PluginA {
|
|
|
|
|
class SomeProvider : public QObject
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Q_INVOKABLE QString doit(const QString &msg, int n) {
|
|
|
|
|
{
|
|
|
|
|
qDebug() << "I AM DOING IT " << msg;
|
|
|
|
|
return QString::number(n);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
} // namespace PluginA
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// In the "user" plugin B:
|
|
|
|
|
int someFuntionUsingPluginA()
|
|
|
|
|
{
|
|
|
|
|
using namespace ExtensionSystem;
|
|
|
|
|
|
2013-08-30 12:30:04 +02:00
|
|
|
QObject *target = PluginManager::getObjectByClassName("PluginA::SomeProvider");
|
2011-01-05 18:35:08 +01:00
|
|
|
|
|
|
|
|
if (target) {
|
|
|
|
|
// Some random argument.
|
|
|
|
|
QString msg = "REALLY.";
|
|
|
|
|
|
|
|
|
|
// Plain function call, no return value.
|
|
|
|
|
invoke<void>(target, "doit", msg, 2);
|
|
|
|
|
|
|
|
|
|
// Plain function with no return value.
|
|
|
|
|
qDebug() << "Result: " << invoke<QString>(target, "doit", msg, 21);
|
|
|
|
|
|
|
|
|
|
// Record success of function call with return value.
|
|
|
|
|
Invoker<QString> in1(target, "doit", msg, 21);
|
|
|
|
|
qDebug() << "Success: (expected)" << in1.wasSuccessful();
|
|
|
|
|
|
|
|
|
|
// Try to invoke a non-existing function.
|
|
|
|
|
Invoker<QString> in2(target, "doitWrong", msg, 22);
|
|
|
|
|
qDebug() << "Success (not expected):" << in2.wasSuccessful();
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
// We have to cope with plugin A's absence.
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
\endcode
|
|
|
|
|
|
2013-02-06 08:50:23 +01:00
|
|
|
\note The type of the parameters passed to the \c{invoke()} calls
|
2011-01-05 18:35:08 +01:00
|
|
|
is deduced from the parameters themselves and must match the type of
|
|
|
|
|
the arguments of the called functions \e{exactly}. No conversion or even
|
|
|
|
|
integer promotions are applicable, so to invoke a function with a \c{long}
|
|
|
|
|
parameter explicitly use \c{long(43)} or such.
|
|
|
|
|
|
2013-02-06 08:50:23 +01:00
|
|
|
\note The object pool manipulating functions are thread-safe.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn void PluginManager::objectAdded(QObject *obj)
|
2013-09-06 11:46:55 +02:00
|
|
|
Signals that \a obj has been added to the object pool.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn void PluginManager::aboutToRemoveObject(QObject *obj)
|
2013-09-06 11:46:55 +02:00
|
|
|
Signals that \a obj will be removed from the object pool.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn void PluginManager::pluginsChanged()
|
2013-09-06 11:46:55 +02:00
|
|
|
Signals that the list of available plugins has changed.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
\sa plugins()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-05-23 16:13:55 +02:00
|
|
|
\fn T *PluginManager::getObject()
|
|
|
|
|
|
2013-09-06 11:46:55 +02:00
|
|
|
Retrieves the object of a given type from the object pool.
|
|
|
|
|
|
2014-05-06 17:56:30 +02:00
|
|
|
This function uses \c qobject_cast to determine the type of an object.
|
2008-12-02 12:01:29 +01:00
|
|
|
If there are more than one object of the given type in
|
2014-05-06 18:33:10 +02:00
|
|
|
the object pool, this function will arbitrarily choose one of them.
|
|
|
|
|
|
|
|
|
|
\sa addObject()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn T *PluginManager::getObject(Predicate predicate)
|
|
|
|
|
|
|
|
|
|
Retrieves the object of a given type from the object pool that matches
|
|
|
|
|
the \a predicate.
|
|
|
|
|
|
|
|
|
|
This function uses \c qobject_cast to determine the type of an object.
|
|
|
|
|
The predicate must be a function taking T * and returning a bool.
|
|
|
|
|
If there is more than one object matching the type and predicate,
|
|
|
|
|
this function will arbitrarily choose one of them.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
\sa addObject()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-05-23 16:13:55 +02:00
|
|
|
\fn QList<T *> PluginManager::getObjects()
|
2013-09-06 11:46:55 +02:00
|
|
|
|
|
|
|
|
Retrieves all objects of a given type from the object pool.
|
|
|
|
|
|
2014-05-06 17:56:30 +02:00
|
|
|
This function uses \c qobject_cast to determine the type of an object.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
\sa addObject()
|
|
|
|
|
*/
|
|
|
|
|
|
2014-05-06 18:33:10 +02:00
|
|
|
/*!
|
|
|
|
|
\fn QList<T *> PluginManager::getObjects(Predicate predicate)
|
|
|
|
|
|
|
|
|
|
Retrieves all objects of a given type from the object pool that
|
|
|
|
|
match the \a predicate.
|
|
|
|
|
|
|
|
|
|
This function uses \c qobject_cast to determine the type of an object.
|
|
|
|
|
The predicate should be a unary function taking a T* parameter and
|
|
|
|
|
returning a bool.
|
|
|
|
|
|
|
|
|
|
\sa addObject()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
using namespace ExtensionSystem;
|
|
|
|
|
using namespace ExtensionSystem::Internal;
|
|
|
|
|
|
2013-08-29 15:00:46 +02:00
|
|
|
static Internal::PluginManagerPrivate *d = 0;
|
|
|
|
|
static PluginManager *m_instance = 0;
|
|
|
|
|
|
2008-12-11 11:26:42 +01:00
|
|
|
static bool lessThanByPluginName(const PluginSpec *one, const PluginSpec *two)
|
|
|
|
|
{
|
|
|
|
|
return one->name() < two->name();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Gets the unique plugin manager instance.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
PluginManager *PluginManager::instance()
|
|
|
|
|
{
|
|
|
|
|
return m_instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Creates a plugin manager. Should be done only once per application.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
PluginManager::PluginManager()
|
|
|
|
|
{
|
|
|
|
|
m_instance = this;
|
2013-08-29 15:00:46 +02:00
|
|
|
d = new PluginManagerPrivate(this);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
PluginManager::~PluginManager()
|
|
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
d = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Adds the object \a obj to the object pool, so it can be retrieved
|
|
|
|
|
again from the pool by type.
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
The plugin manager does not do any memory management - added objects
|
|
|
|
|
must be removed from the pool and deleted manually by whoever is responsible for the object.
|
|
|
|
|
|
|
|
|
|
Emits the objectAdded() signal.
|
|
|
|
|
|
|
|
|
|
\sa PluginManager::removeObject()
|
|
|
|
|
\sa PluginManager::getObject()
|
|
|
|
|
\sa PluginManager::getObjects()
|
|
|
|
|
*/
|
|
|
|
|
void PluginManager::addObject(QObject *obj)
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
d->addObject(obj);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Emits aboutToRemoveObject() and removes the object \a obj from the object pool.
|
|
|
|
|
\sa PluginManager::addObject()
|
|
|
|
|
*/
|
|
|
|
|
void PluginManager::removeObject(QObject *obj)
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
d->removeObject(obj);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Retrieves the list of all objects in the pool, unfiltered.
|
|
|
|
|
|
|
|
|
|
Usually, clients do not need to call this function.
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
\sa PluginManager::getObject()
|
|
|
|
|
\sa PluginManager::getObjects()
|
|
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
QList<QObject *> PluginManager::allObjects()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->allObjects;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QReadWriteLock *PluginManager::listLock()
|
|
|
|
|
{
|
|
|
|
|
return &d->m_lock;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Tries to load all the plugins that were previously found when
|
|
|
|
|
setting the plugin search paths. The plugin specs of the plugins
|
|
|
|
|
can be used to retrieve error and state information about individual plugins.
|
|
|
|
|
|
|
|
|
|
\sa setPluginPaths()
|
|
|
|
|
\sa plugins()
|
|
|
|
|
*/
|
|
|
|
|
void PluginManager::loadPlugins()
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->loadPlugins();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-29 15:59:31 +02:00
|
|
|
/*!
|
|
|
|
|
Returns true if any plugin has errors even though it is enabled.
|
|
|
|
|
Most useful to call after loadPlugins().
|
|
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
bool PluginManager::hasError()
|
2011-08-29 15:59:31 +02:00
|
|
|
{
|
|
|
|
|
foreach (PluginSpec *spec, plugins()) {
|
|
|
|
|
// only show errors on startup if plugin is enabled.
|
2013-02-12 13:15:05 +01:00
|
|
|
if (spec->hasError() && spec->isEnabledInSettings() && !spec->isDisabledIndirectly())
|
2011-08-29 15:59:31 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-13 13:36:47 +02:00
|
|
|
/*!
|
|
|
|
|
Shuts down and deletes all plugins.
|
|
|
|
|
*/
|
|
|
|
|
void PluginManager::shutdown()
|
|
|
|
|
{
|
|
|
|
|
d->shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
The list of paths were the plugin manager searches for plugins.
|
|
|
|
|
|
|
|
|
|
\sa setPluginPaths()
|
|
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
QStringList PluginManager::pluginPaths()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->pluginPaths;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Sets the plugin search paths, i.e. the file system paths where the plugin manager
|
|
|
|
|
looks for plugin descriptions. All given \a paths and their sub directory trees
|
|
|
|
|
are searched for plugin xml description files.
|
|
|
|
|
|
|
|
|
|
\sa pluginPaths()
|
|
|
|
|
\sa loadPlugins()
|
|
|
|
|
*/
|
|
|
|
|
void PluginManager::setPluginPaths(const QStringList &paths)
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
d->setPluginPaths(paths);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
The file extension of plugin description files.
|
|
|
|
|
The default is "xml".
|
|
|
|
|
|
|
|
|
|
\sa setFileExtension()
|
|
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
QString PluginManager::fileExtension()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->extension;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Sets the file extension of plugin description files.
|
|
|
|
|
The default is "xml".
|
|
|
|
|
At the moment this must be called before setPluginPaths() is called.
|
|
|
|
|
// ### TODO let this + setPluginPaths read the plugin specs lazyly whenever loadPlugins() or plugins() is called.
|
|
|
|
|
*/
|
|
|
|
|
void PluginManager::setFileExtension(const QString &extension)
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
d->extension = extension;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-10-26 14:46:29 +02:00
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Defines the user specific settings to use for information about enabled and
|
|
|
|
|
disabled plugins.
|
2011-10-26 14:46:29 +02:00
|
|
|
Needs to be set before the plugin search path is set with setPluginPaths().
|
|
|
|
|
*/
|
2010-10-25 16:57:58 +02:00
|
|
|
void PluginManager::setSettings(QSettings *settings)
|
2010-03-12 16:02:23 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
d->setSettings(settings);
|
2010-10-25 16:57:58 +02:00
|
|
|
}
|
|
|
|
|
|
2011-10-26 14:46:29 +02:00
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Defines the global (user-independent) settings to use for information about
|
|
|
|
|
default disabled plugins.
|
2011-10-26 14:46:29 +02:00
|
|
|
Needs to be set before the plugin search path is set with setPluginPaths().
|
|
|
|
|
*/
|
|
|
|
|
void PluginManager::setGlobalSettings(QSettings *settings)
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
d->setGlobalSettings(settings);
|
2011-10-26 14:46:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Returns the user specific settings used for information about enabled and
|
|
|
|
|
disabled plugins.
|
2011-10-26 14:46:29 +02:00
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
QSettings *PluginManager::settings()
|
2010-10-25 16:57:58 +02:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->settings;
|
2010-10-25 16:57:58 +02:00
|
|
|
}
|
|
|
|
|
|
2011-10-26 14:46:29 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the global (user-independent) settings used for information about default disabled plugins.
|
|
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
QSettings *PluginManager::globalSettings()
|
2010-10-25 16:57:58 +02:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->globalSettings;
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PluginManager::writeSettings()
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
d->writeSettings();
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
The arguments left over after parsing (that were neither startup nor plugin
|
2008-12-02 12:01:29 +01:00
|
|
|
arguments). Typically, this will be the list of files to open.
|
|
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
QStringList PluginManager::arguments()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->arguments;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
List of all plugin specifications that have been found in the plugin search paths.
|
|
|
|
|
This list is valid directly after the setPluginPaths() call.
|
|
|
|
|
The plugin specifications contain the information from the plugins' xml description files
|
|
|
|
|
and the current state of the plugins. If a plugin's library has been already successfully loaded,
|
|
|
|
|
the plugin specification has a reference to the created plugin instance as well.
|
|
|
|
|
|
|
|
|
|
\sa setPluginPaths()
|
|
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
QList<PluginSpec *> PluginManager::plugins()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->pluginSpecs;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-06-18 11:34:15 +02:00
|
|
|
QHash<QString, PluginCollection *> PluginManager::pluginCollections()
|
2010-03-12 16:02:23 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->pluginCategories;
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-05 08:43:52 +03:00
|
|
|
static const char argumentKeywordC[] = ":arguments";
|
2009-12-14 18:01:39 +01:00
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Serializes plugin options and arguments for sending in a single string
|
2009-12-14 18:01:39 +01:00
|
|
|
via QtSingleApplication:
|
|
|
|
|
":myplugin|-option1|-option2|:arguments|argument1|argument2",
|
|
|
|
|
as a list of lists started by a keyword with a colon. Arguments are last.
|
|
|
|
|
|
|
|
|
|
\sa setPluginPaths()
|
|
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
QString PluginManager::serializedArguments()
|
2009-12-14 18:01:39 +01:00
|
|
|
{
|
|
|
|
|
const QChar separator = QLatin1Char('|');
|
|
|
|
|
QString rc;
|
|
|
|
|
foreach (const PluginSpec *ps, plugins()) {
|
|
|
|
|
if (!ps->arguments().isEmpty()) {
|
|
|
|
|
if (!rc.isEmpty())
|
|
|
|
|
rc += separator;
|
|
|
|
|
rc += QLatin1Char(':');
|
|
|
|
|
rc += ps->name();
|
|
|
|
|
rc += separator;
|
|
|
|
|
rc += ps->arguments().join(QString(separator));
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-08-29 15:00:46 +02:00
|
|
|
if (!d->arguments.isEmpty()) {
|
2009-12-14 18:01:39 +01:00
|
|
|
if (!rc.isEmpty())
|
|
|
|
|
rc += separator;
|
|
|
|
|
rc += QLatin1String(argumentKeywordC);
|
|
|
|
|
// If the argument appears to be a file, make it absolute
|
|
|
|
|
// when sending to another instance.
|
2013-08-29 15:00:46 +02:00
|
|
|
foreach (const QString &argument, d->arguments) {
|
2009-12-14 18:01:39 +01:00
|
|
|
rc += separator;
|
|
|
|
|
const QFileInfo fi(argument);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (fi.exists() && fi.isRelative())
|
2009-12-14 18:01:39 +01:00
|
|
|
rc += fi.absoluteFilePath();
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else
|
2009-12-14 18:01:39 +01:00
|
|
|
rc += argument;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Extract a sublist from the serialized arguments
|
|
|
|
|
* indicated by a keyword starting with a colon indicator:
|
|
|
|
|
* ":a,i1,i2,:b:i3,i4" with ":a" -> "i1,i2"
|
|
|
|
|
*/
|
|
|
|
|
static QStringList subList(const QStringList &in, const QString &key)
|
|
|
|
|
{
|
|
|
|
|
QStringList rc;
|
|
|
|
|
// Find keyword and copy arguments until end or next keyword
|
|
|
|
|
const QStringList::const_iterator inEnd = in.constEnd();
|
|
|
|
|
QStringList::const_iterator it = qFind(in.constBegin(), inEnd, key);
|
|
|
|
|
if (it != inEnd) {
|
|
|
|
|
const QChar nextIndicator = QLatin1Char(':');
|
|
|
|
|
for (++it; it != inEnd && !it->startsWith(nextIndicator); ++it)
|
|
|
|
|
rc.append(*it);
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Parses the options encoded by serializedArguments() const
|
|
|
|
|
and passes them on to the respective plugins along with the arguments.
|
2013-03-11 18:15:49 +02:00
|
|
|
|
|
|
|
|
\a socket is passed for disconnecting the peer when the operation is done (for example,
|
|
|
|
|
document is closed) for supporting the -block flag.
|
2009-12-14 18:01:39 +01:00
|
|
|
*/
|
|
|
|
|
|
2013-03-11 18:15:49 +02:00
|
|
|
void PluginManager::remoteArguments(const QString &serializedArgument, QObject *socket)
|
2009-12-14 18:01:39 +01:00
|
|
|
{
|
|
|
|
|
if (serializedArgument.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
QStringList serializedArguments = serializedArgument.split(QLatin1Char('|'));
|
|
|
|
|
const QStringList arguments = subList(serializedArguments, QLatin1String(argumentKeywordC));
|
|
|
|
|
foreach (const PluginSpec *ps, plugins()) {
|
|
|
|
|
if (ps->state() == PluginSpec::Running) {
|
|
|
|
|
const QStringList pluginOptions = subList(serializedArguments, QLatin1Char(':') + ps->name());
|
2013-03-11 18:15:49 +02:00
|
|
|
QObject *socketParent = ps->plugin()->remoteCommand(pluginOptions, arguments);
|
|
|
|
|
if (socketParent && socket) {
|
|
|
|
|
socket->setParent(socketParent);
|
|
|
|
|
socket = 0;
|
|
|
|
|
}
|
2009-12-14 18:01:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
2013-03-11 18:15:49 +02:00
|
|
|
if (socket)
|
|
|
|
|
delete socket;
|
2009-12-14 18:01:39 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
Takes the list of command line options in \a args and parses them.
|
|
|
|
|
The plugin manager itself might process some options itself directly (-noload <plugin>), and
|
|
|
|
|
adds options that are registered by plugins to their plugin specs.
|
|
|
|
|
The caller (the application) may register itself for options via the \a appOptions list, containing pairs
|
|
|
|
|
of "option string" and a bool that indicates if the option requires an argument.
|
|
|
|
|
Application options always override any plugin's options.
|
2010-01-29 21:33:57 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
\a foundAppOptions is set to pairs of ("option string", "argument") for any application options that were found.
|
2013-10-07 13:34:40 +02:00
|
|
|
The command line options that were not processed can be retrieved via the arguments() function.
|
2008-12-02 12:01:29 +01:00
|
|
|
If an error occurred (like missing argument for an option that requires one), \a errorString contains
|
|
|
|
|
a descriptive message of the error.
|
2010-01-29 21:33:57 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
Returns if there was an error.
|
|
|
|
|
*/
|
|
|
|
|
bool PluginManager::parseOptions(const QStringList &args,
|
|
|
|
|
const QMap<QString, bool> &appOptions,
|
|
|
|
|
QMap<QString, QString> *foundAppOptions,
|
|
|
|
|
QString *errorString)
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
OptionsParser options(args, appOptions, foundAppOptions, errorString, d);
|
2008-12-02 12:01:29 +01:00
|
|
|
return options.parse();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline void indent(QTextStream &str, int indent)
|
|
|
|
|
{
|
|
|
|
|
const QChar blank = QLatin1Char(' ');
|
|
|
|
|
for (int i = 0 ; i < indent; i++)
|
|
|
|
|
str << blank;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void formatOption(QTextStream &str,
|
|
|
|
|
const QString &opt, const QString &parm, const QString &description,
|
|
|
|
|
int optionIndentation, int descriptionIndentation)
|
|
|
|
|
{
|
|
|
|
|
int remainingIndent = descriptionIndentation - optionIndentation - opt.size();
|
|
|
|
|
indent(str, optionIndentation);
|
|
|
|
|
str << opt;
|
|
|
|
|
if (!parm.isEmpty()) {
|
|
|
|
|
str << " <" << parm << '>';
|
|
|
|
|
remainingIndent -= 3 + parm.size();
|
|
|
|
|
}
|
2010-03-23 15:56:11 +01:00
|
|
|
indent(str, qMax(1, remainingIndent));
|
2008-12-02 12:01:29 +01:00
|
|
|
str << description << '\n';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Formats the startup options of the plugin manager for command line help.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation)
|
|
|
|
|
{
|
2013-02-12 13:19:15 +01:00
|
|
|
formatOption(str, QLatin1String(OptionsParser::LOAD_OPTION),
|
|
|
|
|
QLatin1String("plugin"), QLatin1String("Load <plugin>"),
|
|
|
|
|
optionIndentation, descriptionIndentation);
|
2008-12-02 12:01:29 +01:00
|
|
|
formatOption(str, QLatin1String(OptionsParser::NO_LOAD_OPTION),
|
|
|
|
|
QLatin1String("plugin"), QLatin1String("Do not load <plugin>"),
|
|
|
|
|
optionIndentation, descriptionIndentation);
|
2010-03-02 12:33:51 +01:00
|
|
|
formatOption(str, QLatin1String(OptionsParser::PROFILE_OPTION),
|
|
|
|
|
QString(), QLatin1String("Profile plugin loading"),
|
|
|
|
|
optionIndentation, descriptionIndentation);
|
2011-10-13 09:22:28 +02:00
|
|
|
#ifdef WITH_TESTS
|
2013-01-22 12:54:22 +01:00
|
|
|
formatOption(str, QString::fromLatin1(OptionsParser::TEST_OPTION)
|
2013-03-20 16:31:14 +01:00
|
|
|
+ QLatin1String(" <plugin>[,testfunction[:testdata]]..."), QString(),
|
2013-09-03 15:17:24 +02:00
|
|
|
QLatin1String("Run plugin's tests (by default a separate settings path is used)"),
|
|
|
|
|
optionIndentation, descriptionIndentation);
|
2013-01-22 12:54:22 +01:00
|
|
|
formatOption(str, QString::fromLatin1(OptionsParser::TEST_OPTION) + QLatin1String(" all"),
|
|
|
|
|
QString(), QLatin1String("Run tests from all plugins"),
|
2011-10-13 09:22:28 +02:00
|
|
|
optionIndentation, descriptionIndentation);
|
|
|
|
|
#endif
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Formats the plugin options of the plugin specs for command line help.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
|
2012-06-18 11:34:15 +02:00
|
|
|
void PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions;
|
|
|
|
|
// Check plugins for options
|
2013-08-29 15:00:46 +02:00
|
|
|
const PluginSpecSet::const_iterator pcend = d->pluginSpecs.constEnd();
|
|
|
|
|
for (PluginSpecSet::const_iterator pit = d->pluginSpecs.constBegin(); pit != pcend; ++pit) {
|
2008-12-02 12:01:29 +01:00
|
|
|
const PluginArgumentDescriptions pargs = (*pit)->argumentDescriptions();
|
|
|
|
|
if (!pargs.empty()) {
|
|
|
|
|
str << "\nPlugin: " << (*pit)->name() << '\n';
|
|
|
|
|
const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd();
|
|
|
|
|
for (PluginArgumentDescriptions::const_iterator ait =pargs.constBegin(); ait != acend; ++ait)
|
|
|
|
|
formatOption(str, ait->name, ait->parameter, ait->description, optionIndentation, descriptionIndentation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Formats the version of the plugin specs for command line help.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
void PluginManager::formatPluginVersions(QTextStream &str)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
const PluginSpecSet::const_iterator cend = d->pluginSpecs.constEnd();
|
|
|
|
|
for (PluginSpecSet::const_iterator it = d->pluginSpecs.constBegin(); it != cend; ++it) {
|
2008-12-02 12:01:29 +01:00
|
|
|
const PluginSpec *ps = *it;
|
|
|
|
|
str << " " << ps->name() << ' ' << ps->version() << ' ' << ps->description() << '\n';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PluginManager::startTests()
|
|
|
|
|
{
|
|
|
|
|
#ifdef WITH_TESTS
|
2013-01-22 12:54:22 +01:00
|
|
|
foreach (const PluginManagerPrivate::TestSpec &testSpec, d->testSpecs) {
|
|
|
|
|
const PluginSpec * const pluginSpec = testSpec.pluginSpec;
|
2011-11-14 15:28:39 +01:00
|
|
|
if (!pluginSpec->plugin())
|
|
|
|
|
continue;
|
2013-01-22 12:54:22 +01:00
|
|
|
|
2013-10-07 13:34:40 +02:00
|
|
|
// Collect all test functions of the plugin.
|
2013-01-22 12:54:22 +01:00
|
|
|
QStringList allTestFunctions;
|
2013-01-24 08:22:30 +01:00
|
|
|
const QMetaObject *metaObject = pluginSpec->plugin()->metaObject();
|
2013-01-22 12:54:22 +01:00
|
|
|
|
2013-01-24 08:22:30 +01:00
|
|
|
for (int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i) {
|
2012-04-18 13:54:50 +02:00
|
|
|
#if QT_VERSION >= 0x050000
|
2013-01-24 08:22:30 +01:00
|
|
|
const QByteArray signature = metaObject->method(i).methodSignature();
|
2012-04-18 13:54:50 +02:00
|
|
|
#else
|
2013-01-24 08:22:30 +01:00
|
|
|
const QByteArray signature = metaObject->method(i).signature();
|
2012-04-18 13:54:50 +02:00
|
|
|
#endif
|
|
|
|
|
if (signature.startsWith("test") && !signature.endsWith("_data()")) {
|
|
|
|
|
const QString method = QString::fromLatin1(signature);
|
2013-01-24 08:22:30 +01:00
|
|
|
const QString methodName = method.left(method.size() - 2);
|
|
|
|
|
allTestFunctions.append(methodName);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2013-01-22 12:54:22 +01:00
|
|
|
|
|
|
|
|
QStringList testFunctionsToExecute;
|
|
|
|
|
|
|
|
|
|
// User did not specify any test functions, so add every test function.
|
|
|
|
|
if (testSpec.testFunctions.isEmpty()) {
|
|
|
|
|
testFunctionsToExecute = allTestFunctions;
|
|
|
|
|
|
|
|
|
|
// User specified test functions. Add them if they are valid.
|
|
|
|
|
} else {
|
|
|
|
|
foreach (const QString &userTestFunction, testSpec.testFunctions) {
|
|
|
|
|
// There might be a test data suffix like in "testfunction:testdata1".
|
|
|
|
|
QString testFunctionName = userTestFunction;
|
2013-08-26 15:50:32 +02:00
|
|
|
QString testDataSuffix;
|
2013-01-22 12:54:22 +01:00
|
|
|
const int index = testFunctionName.indexOf(QLatin1Char(':'));
|
2013-08-26 15:50:32 +02:00
|
|
|
if (index != -1) {
|
|
|
|
|
testDataSuffix = testFunctionName.mid(index);
|
2013-01-22 12:54:22 +01:00
|
|
|
testFunctionName = testFunctionName.left(index);
|
2013-08-26 15:50:32 +02:00
|
|
|
}
|
2013-01-22 12:54:22 +01:00
|
|
|
|
2013-08-26 15:50:32 +02:00
|
|
|
const QRegExp regExp(testFunctionName, Qt::CaseSensitive, QRegExp::Wildcard);
|
|
|
|
|
QStringList matchingFunctions;
|
|
|
|
|
foreach (const QString &testFunction, allTestFunctions) {
|
|
|
|
|
if (regExp.exactMatch(testFunction))
|
|
|
|
|
matchingFunctions.append(testFunction);
|
|
|
|
|
}
|
|
|
|
|
if (!matchingFunctions.isEmpty()) {
|
2013-01-22 12:54:22 +01:00
|
|
|
// If the specified test data is invalid, the QTest framework will
|
|
|
|
|
// print a reasonable error message for us.
|
2013-08-26 15:50:32 +02:00
|
|
|
foreach (const QString &matchingFunction, matchingFunctions)
|
|
|
|
|
testFunctionsToExecute.append(matchingFunction + testDataSuffix);
|
2013-01-22 12:54:22 +01:00
|
|
|
} else {
|
|
|
|
|
QTextStream out(stdout);
|
2013-08-26 15:50:32 +02:00
|
|
|
out << "No test function matches \"" << testFunctionName
|
2013-01-22 12:54:22 +01:00
|
|
|
<< "\" for plugin \"" << pluginSpec->name() << "\"." << endl
|
|
|
|
|
<< " Available test functions for plugin \"" << pluginSpec->name()
|
|
|
|
|
<< "\" are:" << endl;
|
|
|
|
|
foreach (const QString &testFunction, allTestFunctions)
|
|
|
|
|
out << " " << testFunction << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-15 11:15:33 +01:00
|
|
|
// Don't run QTest::qExec without any test functions, that'd run
|
2011-11-14 15:28:39 +01:00
|
|
|
// *all* slots as tests.
|
2013-03-15 11:15:33 +01:00
|
|
|
if (!testFunctionsToExecute.isEmpty()) {
|
|
|
|
|
// QTest::qExec() expects basically QCoreApplication::arguments(),
|
|
|
|
|
QStringList qExecArguments = QStringList()
|
|
|
|
|
<< QLatin1String("arg0") // fake application name
|
|
|
|
|
<< QLatin1String("-maxwarnings") << QLatin1String("0"); // unlimit output
|
|
|
|
|
qExecArguments << testFunctionsToExecute;
|
|
|
|
|
QTest::qExec(pluginSpec->plugin(), qExecArguments);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2011-09-19 10:02:45 +02:00
|
|
|
if (!d->testSpecs.isEmpty())
|
2011-02-17 11:37:34 +01:00
|
|
|
QTimer::singleShot(1, QCoreApplication::instance(), SLOT(quit()));
|
2008-12-02 12:01:29 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-05 18:04:24 +01:00
|
|
|
/*!
|
|
|
|
|
* \internal
|
|
|
|
|
*/
|
2013-04-04 14:30:17 +02:00
|
|
|
bool PluginManager::testRunRequested()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return !d->testSpecs.isEmpty();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-01-05 18:04:24 +01:00
|
|
|
/*!
|
|
|
|
|
* \internal
|
|
|
|
|
*/
|
2012-06-18 11:34:15 +02:00
|
|
|
QString PluginManager::testDataDirectory()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-09-29 11:42:07 +02:00
|
|
|
QByteArray ba = qgetenv("QTCREATOR_TEST_DIR");
|
2009-02-19 12:02:47 +01:00
|
|
|
QString s = QString::fromLocal8Bit(ba.constData(), ba.size());
|
2008-12-02 12:01:29 +01:00
|
|
|
if (s.isEmpty()) {
|
2012-11-27 22:23:17 +02:00
|
|
|
s = QLatin1String(IDE_TEST_DIR);
|
|
|
|
|
s.append(QLatin1String("/tests"));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
s = QDir::cleanPath(s);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-12 11:12:54 +02:00
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Creates a profiling entry showing the elapsed time if profiling is
|
|
|
|
|
activated.
|
2010-05-12 11:12:54 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void PluginManager::profilingReport(const char *what, const PluginSpec *spec)
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
d->profilingReport(what, spec);
|
2010-05-12 11:12:54 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-19 16:29:47 +02:00
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Returns a list of plugins in load order.
|
|
|
|
|
*/
|
|
|
|
|
QList<PluginSpec *> PluginManager::loadQueue()
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
return d->loadQueue();
|
2010-05-19 16:29:47 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
//============PluginManagerPrivate===========
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
PluginSpec *PluginManagerPrivate::createSpec()
|
|
|
|
|
{
|
|
|
|
|
return new PluginSpec();
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-25 16:57:58 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::setSettings(QSettings *s)
|
|
|
|
|
{
|
|
|
|
|
if (settings)
|
|
|
|
|
delete settings;
|
|
|
|
|
settings = s;
|
|
|
|
|
if (settings)
|
|
|
|
|
settings->setParent(this);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-26 14:46:29 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::setGlobalSettings(QSettings *s)
|
|
|
|
|
{
|
|
|
|
|
if (globalSettings)
|
|
|
|
|
delete globalSettings;
|
|
|
|
|
globalSettings = s;
|
|
|
|
|
if (globalSettings)
|
|
|
|
|
globalSettings->setParent(this);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec)
|
|
|
|
|
{
|
|
|
|
|
return spec->d;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-02 10:47:33 +01:00
|
|
|
void PluginManagerPrivate::nextDelayedInitialize()
|
|
|
|
|
{
|
|
|
|
|
while (!delayedInitializeQueue.isEmpty()) {
|
|
|
|
|
PluginSpec *spec = delayedInitializeQueue.takeFirst();
|
|
|
|
|
profilingReport(">delayedInitialize", spec);
|
|
|
|
|
bool delay = spec->d->delayedInitialize();
|
|
|
|
|
profilingReport("<delayedInitialize", spec);
|
|
|
|
|
if (delay)
|
|
|
|
|
break; // do next delayedInitialize after a delay
|
|
|
|
|
}
|
|
|
|
|
if (delayedInitializeQueue.isEmpty()) {
|
|
|
|
|
delete delayedInitializeTimer;
|
|
|
|
|
delayedInitializeTimer = 0;
|
2013-02-06 13:53:51 +01:00
|
|
|
profilingSummary();
|
2012-08-17 09:09:15 +02:00
|
|
|
emit q->initializationDone();
|
2013-07-24 11:17:31 +02:00
|
|
|
#ifdef WITH_TESTS
|
|
|
|
|
if (q->testRunRequested())
|
|
|
|
|
q->startTests();
|
|
|
|
|
#endif
|
2012-02-02 10:47:33 +01:00
|
|
|
} else {
|
|
|
|
|
delayedInitializeTimer->start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2010-03-02 12:33:51 +01:00
|
|
|
PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) :
|
|
|
|
|
extension(QLatin1String("xml")),
|
2012-02-02 10:47:33 +01:00
|
|
|
delayedInitializeTimer(0),
|
|
|
|
|
shutdownEventLoop(0),
|
2010-03-02 12:33:51 +01:00
|
|
|
m_profileElapsedMS(0),
|
2010-05-12 11:12:54 +02:00
|
|
|
m_profilingVerbosity(0),
|
2010-10-25 16:57:58 +02:00
|
|
|
settings(0),
|
2011-10-26 14:46:29 +02:00
|
|
|
globalSettings(0),
|
2010-03-02 12:33:51 +01:00
|
|
|
q(pluginManager)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-13 13:36:47 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
PluginManagerPrivate::~PluginManagerPrivate()
|
|
|
|
|
{
|
|
|
|
|
qDeleteAll(pluginSpecs);
|
2010-03-12 16:02:23 +01:00
|
|
|
qDeleteAll(pluginCategories);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-13 13:36:47 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2010-03-12 16:02:23 +01:00
|
|
|
void PluginManagerPrivate::writeSettings()
|
|
|
|
|
{
|
2010-10-25 16:57:58 +02:00
|
|
|
if (!settings)
|
|
|
|
|
return;
|
2010-03-30 14:18:15 +02:00
|
|
|
QStringList tempDisabledPlugins;
|
2010-03-30 16:54:29 +02:00
|
|
|
QStringList tempForceEnabledPlugins;
|
2012-11-28 20:44:03 +02:00
|
|
|
foreach (PluginSpec *spec, pluginSpecs) {
|
2013-02-12 13:15:05 +01:00
|
|
|
if (!spec->isDisabledByDefault() && !spec->isEnabledInSettings())
|
2010-03-30 14:18:15 +02:00
|
|
|
tempDisabledPlugins.append(spec->name());
|
2013-02-12 13:15:05 +01:00
|
|
|
if (spec->isDisabledByDefault() && spec->isEnabledInSettings())
|
2010-03-30 16:54:29 +02:00
|
|
|
tempForceEnabledPlugins.append(spec->name());
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
2010-10-25 16:57:58 +02:00
|
|
|
settings->setValue(QLatin1String(C_IGNORED_PLUGINS), tempDisabledPlugins);
|
|
|
|
|
settings->setValue(QLatin1String(C_FORCEENABLED_PLUGINS), tempForceEnabledPlugins);
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-13 13:36:47 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2010-10-25 16:57:58 +02:00
|
|
|
void PluginManagerPrivate::readSettings()
|
2010-03-12 16:02:23 +01:00
|
|
|
{
|
2013-11-14 15:57:37 +01:00
|
|
|
if (globalSettings) {
|
2011-10-26 14:46:29 +02:00
|
|
|
defaultDisabledPlugins = globalSettings->value(QLatin1String(C_IGNORED_PLUGINS)).toStringList();
|
2013-11-14 15:57:37 +01:00
|
|
|
defaultEnabledPlugins = globalSettings->value(QLatin1String(C_FORCEENABLED_PLUGINS)).toStringList();
|
|
|
|
|
}
|
2011-10-26 14:46:29 +02:00
|
|
|
if (settings) {
|
|
|
|
|
disabledPlugins = settings->value(QLatin1String(C_IGNORED_PLUGINS)).toStringList();
|
|
|
|
|
forceEnabledPlugins = settings->value(QLatin1String(C_FORCEENABLED_PLUGINS)).toStringList();
|
|
|
|
|
}
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-13 13:36:47 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2008-12-02 12:01:29 +01:00
|
|
|
void PluginManagerPrivate::stopAll()
|
|
|
|
|
{
|
2012-02-02 10:47:33 +01:00
|
|
|
if (delayedInitializeTimer && delayedInitializeTimer->isActive()) {
|
|
|
|
|
delayedInitializeTimer->stop();
|
|
|
|
|
delete delayedInitializeTimer;
|
|
|
|
|
delayedInitializeTimer = 0;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<PluginSpec *> queue = loadQueue();
|
|
|
|
|
foreach (PluginSpec *spec, queue) {
|
|
|
|
|
loadPlugin(spec, PluginSpec::Stopped);
|
|
|
|
|
}
|
2010-07-13 13:36:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::deleteAll()
|
|
|
|
|
{
|
|
|
|
|
QList<PluginSpec *> queue = loadQueue();
|
2008-12-02 12:01:29 +01:00
|
|
|
QListIterator<PluginSpec *> it(queue);
|
|
|
|
|
it.toBack();
|
|
|
|
|
while (it.hasPrevious()) {
|
|
|
|
|
loadPlugin(it.previous(), PluginSpec::Deleted);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::addObject(QObject *obj)
|
|
|
|
|
{
|
|
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
QWriteLocker lock(&m_lock);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (obj == 0) {
|
|
|
|
|
qWarning() << "PluginManagerPrivate::addObject(): trying to add null object";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (allObjects.contains(obj)) {
|
|
|
|
|
qWarning() << "PluginManagerPrivate::addObject(): trying to add duplicate object";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (debugLeaks)
|
|
|
|
|
qDebug() << "PluginManagerPrivate::addObject" << obj << obj->objectName();
|
|
|
|
|
|
2010-05-12 11:12:54 +02:00
|
|
|
if (m_profilingVerbosity && !m_profileTimer.isNull()) {
|
|
|
|
|
// Report a timestamp when adding an object. Useful for profiling
|
|
|
|
|
// its initialization time.
|
|
|
|
|
const int absoluteElapsedMS = m_profileTimer->elapsed();
|
|
|
|
|
qDebug(" %-43s %8dms", obj->metaObject()->className(), absoluteElapsedMS);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
allObjects.append(obj);
|
|
|
|
|
}
|
|
|
|
|
emit q->objectAdded(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::removeObject(QObject *obj)
|
|
|
|
|
{
|
|
|
|
|
if (obj == 0) {
|
|
|
|
|
qWarning() << "PluginManagerPrivate::removeObject(): trying to remove null object";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!allObjects.contains(obj)) {
|
|
|
|
|
qWarning() << "PluginManagerPrivate::removeObject(): object not in list:"
|
|
|
|
|
<< obj << obj->objectName();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (debugLeaks)
|
|
|
|
|
qDebug() << "PluginManagerPrivate::removeObject" << obj << obj->objectName();
|
|
|
|
|
|
|
|
|
|
emit q->aboutToRemoveObject(obj);
|
2013-08-29 15:00:46 +02:00
|
|
|
QWriteLocker lock(&m_lock);
|
2008-12-02 12:01:29 +01:00
|
|
|
allObjects.removeAll(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::loadPlugins()
|
|
|
|
|
{
|
|
|
|
|
QList<PluginSpec *> queue = loadQueue();
|
|
|
|
|
foreach (PluginSpec *spec, queue) {
|
|
|
|
|
loadPlugin(spec, PluginSpec::Loaded);
|
|
|
|
|
}
|
|
|
|
|
foreach (PluginSpec *spec, queue) {
|
|
|
|
|
loadPlugin(spec, PluginSpec::Initialized);
|
|
|
|
|
}
|
|
|
|
|
QListIterator<PluginSpec *> it(queue);
|
|
|
|
|
it.toBack();
|
|
|
|
|
while (it.hasPrevious()) {
|
2012-02-02 10:47:33 +01:00
|
|
|
PluginSpec *spec = it.previous();
|
|
|
|
|
loadPlugin(spec, PluginSpec::Running);
|
|
|
|
|
if (spec->state() == PluginSpec::Running)
|
|
|
|
|
delayedInitializeQueue.append(spec);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
emit q->pluginsChanged();
|
2012-02-02 10:47:33 +01:00
|
|
|
|
|
|
|
|
delayedInitializeTimer = new QTimer;
|
|
|
|
|
delayedInitializeTimer->setInterval(DELAYED_INITIALIZE_INTERVAL);
|
|
|
|
|
delayedInitializeTimer->setSingleShot(true);
|
|
|
|
|
connect(delayedInitializeTimer, SIGNAL(timeout()),
|
|
|
|
|
this, SLOT(nextDelayedInitialize()));
|
|
|
|
|
delayedInitializeTimer->start();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-13 13:36:47 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::shutdown()
|
|
|
|
|
{
|
|
|
|
|
stopAll();
|
|
|
|
|
if (!asynchronousPlugins.isEmpty()) {
|
|
|
|
|
shutdownEventLoop = new QEventLoop;
|
|
|
|
|
shutdownEventLoop->exec();
|
|
|
|
|
}
|
|
|
|
|
deleteAll();
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (!allObjects.isEmpty())
|
2010-07-13 13:36:47 +02:00
|
|
|
qDebug() << "There are" << allObjects.size() << "objects left in the plugin manager pool: " << allObjects;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::asyncShutdownFinished()
|
|
|
|
|
{
|
|
|
|
|
IPlugin *plugin = qobject_cast<IPlugin *>(sender());
|
|
|
|
|
Q_ASSERT(plugin);
|
|
|
|
|
asynchronousPlugins.removeAll(plugin->pluginSpec());
|
|
|
|
|
if (asynchronousPlugins.isEmpty())
|
|
|
|
|
shutdownEventLoop->exit();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
QList<PluginSpec *> PluginManagerPrivate::loadQueue()
|
|
|
|
|
{
|
|
|
|
|
QList<PluginSpec *> queue;
|
|
|
|
|
foreach (PluginSpec *spec, pluginSpecs) {
|
|
|
|
|
QList<PluginSpec *> circularityCheckQueue;
|
|
|
|
|
loadQueue(spec, queue, circularityCheckQueue);
|
|
|
|
|
}
|
|
|
|
|
return queue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queue,
|
|
|
|
|
QList<PluginSpec *> &circularityCheckQueue)
|
|
|
|
|
{
|
|
|
|
|
if (queue.contains(spec))
|
|
|
|
|
return true;
|
|
|
|
|
// check for circular dependencies
|
|
|
|
|
if (circularityCheckQueue.contains(spec)) {
|
|
|
|
|
spec->d->hasError = true;
|
2013-10-17 13:48:04 +02:00
|
|
|
spec->d->errorString = PluginManager::tr("Circular dependency detected:");
|
|
|
|
|
spec->d->errorString += QLatin1Char('\n');
|
2008-12-02 12:01:29 +01:00
|
|
|
int index = circularityCheckQueue.indexOf(spec);
|
|
|
|
|
for (int i = index; i < circularityCheckQueue.size(); ++i) {
|
2013-10-17 13:48:04 +02:00
|
|
|
spec->d->errorString.append(PluginManager::tr("%1(%2) depends on")
|
2008-12-02 12:01:29 +01:00
|
|
|
.arg(circularityCheckQueue.at(i)->name()).arg(circularityCheckQueue.at(i)->version()));
|
2013-10-17 13:48:04 +02:00
|
|
|
spec->d->errorString += QLatin1Char('\n');
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-02-27 20:06:08 +01:00
|
|
|
spec->d->errorString.append(PluginManager::tr("%1(%2)").arg(spec->name()).arg(spec->version()));
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
circularityCheckQueue.append(spec);
|
|
|
|
|
// check if we have the dependencies
|
|
|
|
|
if (spec->state() == PluginSpec::Invalid || spec->state() == PluginSpec::Read) {
|
2010-05-19 16:29:47 +02:00
|
|
|
queue.append(spec);
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
2010-05-19 16:29:47 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
// add dependencies
|
|
|
|
|
foreach (PluginSpec *depSpec, spec->dependencySpecs()) {
|
|
|
|
|
if (!loadQueue(depSpec, queue, circularityCheckQueue)) {
|
|
|
|
|
spec->d->hasError = true;
|
|
|
|
|
spec->d->errorString =
|
2009-02-27 20:06:08 +01:00
|
|
|
PluginManager::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
|
2008-12-02 12:01:29 +01:00
|
|
|
.arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// add self
|
|
|
|
|
queue.append(spec);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState)
|
|
|
|
|
{
|
2010-05-19 16:29:47 +02:00
|
|
|
if (spec->hasError() || spec->state() != destState-1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// don't load disabled plugins.
|
2013-02-12 13:19:15 +01:00
|
|
|
if (!spec->isEffectivelyEnabled() && destState == PluginSpec::Loaded)
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
2010-03-12 16:02:23 +01:00
|
|
|
|
2010-03-02 12:33:51 +01:00
|
|
|
switch (destState) {
|
|
|
|
|
case PluginSpec::Running:
|
|
|
|
|
profilingReport(">initializeExtensions", spec);
|
2008-12-02 12:01:29 +01:00
|
|
|
spec->d->initializeExtensions();
|
2010-03-02 12:33:51 +01:00
|
|
|
profilingReport("<initializeExtensions", spec);
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
2010-03-02 12:33:51 +01:00
|
|
|
case PluginSpec::Deleted:
|
2010-07-13 13:36:47 +02:00
|
|
|
profilingReport(">delete", spec);
|
2008-12-02 12:01:29 +01:00
|
|
|
spec->d->kill();
|
2010-07-13 13:36:47 +02:00
|
|
|
profilingReport("<delete", spec);
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
2010-03-02 12:33:51 +01:00
|
|
|
default:
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2011-01-11 14:01:08 +01:00
|
|
|
// check if dependencies have loaded without error
|
|
|
|
|
QHashIterator<PluginDependency, PluginSpec *> it(spec->dependencySpecs());
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
if (it.key().type == PluginDependency::Optional)
|
|
|
|
|
continue;
|
|
|
|
|
PluginSpec *depSpec = it.value();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (depSpec->state() != destState) {
|
|
|
|
|
spec->d->hasError = true;
|
|
|
|
|
spec->d->errorString =
|
2009-02-27 20:06:08 +01:00
|
|
|
PluginManager::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
|
2008-12-02 12:01:29 +01:00
|
|
|
.arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-03-02 12:33:51 +01:00
|
|
|
switch (destState) {
|
|
|
|
|
case PluginSpec::Loaded:
|
|
|
|
|
profilingReport(">loadLibrary", spec);
|
2008-12-02 12:01:29 +01:00
|
|
|
spec->d->loadLibrary();
|
2010-03-02 12:33:51 +01:00
|
|
|
profilingReport("<loadLibrary", spec);
|
|
|
|
|
break;
|
|
|
|
|
case PluginSpec::Initialized:
|
|
|
|
|
profilingReport(">initializePlugin", spec);
|
2008-12-02 12:01:29 +01:00
|
|
|
spec->d->initializePlugin();
|
2010-03-02 12:33:51 +01:00
|
|
|
profilingReport("<initializePlugin", spec);
|
|
|
|
|
break;
|
|
|
|
|
case PluginSpec::Stopped:
|
|
|
|
|
profilingReport(">stop", spec);
|
2010-07-13 13:36:47 +02:00
|
|
|
if (spec->d->stop() == IPlugin::AsynchronousShutdown) {
|
|
|
|
|
asynchronousPlugins << spec;
|
|
|
|
|
connect(spec->plugin(), SIGNAL(asynchronousShutdownFinished()),
|
|
|
|
|
this, SLOT(asyncShutdownFinished()));
|
|
|
|
|
}
|
2010-03-02 12:33:51 +01:00
|
|
|
profilingReport("<stop", spec);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::setPluginPaths(const QStringList &paths)
|
|
|
|
|
{
|
|
|
|
|
pluginPaths = paths;
|
2010-10-25 16:57:58 +02:00
|
|
|
readSettings();
|
2008-12-02 12:01:29 +01:00
|
|
|
readPluginPaths();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginManagerPrivate::readPluginPaths()
|
|
|
|
|
{
|
2010-03-12 16:02:23 +01:00
|
|
|
qDeleteAll(pluginCategories);
|
2008-12-02 12:01:29 +01:00
|
|
|
qDeleteAll(pluginSpecs);
|
|
|
|
|
pluginSpecs.clear();
|
2010-03-12 16:02:23 +01:00
|
|
|
pluginCategories.clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
QStringList specFiles;
|
|
|
|
|
QStringList searchPaths = pluginPaths;
|
|
|
|
|
while (!searchPaths.isEmpty()) {
|
|
|
|
|
const QDir dir(searchPaths.takeFirst());
|
2010-03-02 12:33:51 +01:00
|
|
|
const QString pattern = QLatin1String("*.") + extension;
|
|
|
|
|
const QFileInfoList files = dir.entryInfoList(QStringList(pattern), QDir::Files);
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QFileInfo &file, files)
|
|
|
|
|
specFiles << file.absoluteFilePath();
|
|
|
|
|
const QFileInfoList dirs = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
|
|
|
|
|
foreach (const QFileInfo &subdir, dirs)
|
|
|
|
|
searchPaths << subdir.absoluteFilePath();
|
|
|
|
|
}
|
2010-03-12 16:02:23 +01:00
|
|
|
defaultCollection = new PluginCollection(QString());
|
2012-11-27 22:23:17 +02:00
|
|
|
pluginCategories.insert(QString(), defaultCollection);
|
2010-03-12 16:02:23 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &specFile, specFiles) {
|
|
|
|
|
PluginSpec *spec = new PluginSpec;
|
|
|
|
|
spec->d->read(specFile);
|
2010-03-12 16:02:23 +01:00
|
|
|
|
|
|
|
|
PluginCollection *collection = 0;
|
|
|
|
|
// find correct plugin collection or create a new one
|
2013-07-17 00:01:45 +03:00
|
|
|
if (pluginCategories.contains(spec->category())) {
|
2010-03-12 16:02:23 +01:00
|
|
|
collection = pluginCategories.value(spec->category());
|
2013-07-17 00:01:45 +03:00
|
|
|
} else {
|
2010-03-12 16:02:23 +01:00
|
|
|
collection = new PluginCollection(spec->category());
|
|
|
|
|
pluginCategories.insert(spec->category(), collection);
|
|
|
|
|
}
|
2013-11-14 15:57:37 +01:00
|
|
|
// defaultDisabledPlugins and defaultEnabledPlugins from install settings
|
|
|
|
|
// is used to override the defaults read from the plugin spec
|
|
|
|
|
if (!spec->isDisabledByDefault() && defaultDisabledPlugins.contains(spec->name())) {
|
2011-10-26 14:46:29 +02:00
|
|
|
spec->setDisabledByDefault(true);
|
|
|
|
|
spec->setEnabled(false);
|
2013-11-14 15:57:37 +01:00
|
|
|
} else if (spec->isDisabledByDefault() && defaultEnabledPlugins.contains(spec->name())) {
|
|
|
|
|
spec->setDisabledByDefault(false);
|
|
|
|
|
spec->setEnabled(true);
|
2011-10-26 14:46:29 +02:00
|
|
|
}
|
|
|
|
|
if (spec->isDisabledByDefault() && forceEnabledPlugins.contains(spec->name()))
|
2010-03-30 16:54:29 +02:00
|
|
|
spec->setEnabled(true);
|
2011-10-26 14:46:29 +02:00
|
|
|
if (!spec->isDisabledByDefault() && disabledPlugins.contains(spec->name()))
|
2010-03-30 14:18:15 +02:00
|
|
|
spec->setEnabled(false);
|
2010-03-12 16:02:23 +01:00
|
|
|
|
|
|
|
|
collection->addPlugin(spec);
|
2008-12-11 11:26:42 +01:00
|
|
|
pluginSpecs.append(spec);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
resolveDependencies();
|
2008-12-11 11:26:42 +01:00
|
|
|
// ensure deterministic plugin load order by sorting
|
|
|
|
|
qSort(pluginSpecs.begin(), pluginSpecs.end(), lessThanByPluginName);
|
2008-12-02 12:01:29 +01:00
|
|
|
emit q->pluginsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PluginManagerPrivate::resolveDependencies()
|
|
|
|
|
{
|
|
|
|
|
foreach (PluginSpec *spec, pluginSpecs) {
|
|
|
|
|
spec->d->resolveDependencies(pluginSpecs);
|
|
|
|
|
}
|
2013-02-12 13:19:15 +01:00
|
|
|
|
|
|
|
|
// Reset disabledIndirectly flag
|
|
|
|
|
foreach (PluginSpec *spec, loadQueue())
|
|
|
|
|
spec->d->disabledIndirectly = false;
|
|
|
|
|
|
2010-05-19 16:29:47 +02:00
|
|
|
foreach (PluginSpec *spec, loadQueue()) {
|
|
|
|
|
spec->d->disableIndirectlyIfDependencyDisabled();
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Look in argument descriptions of the specs for the option.
|
|
|
|
|
PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *requiresArgument) const
|
|
|
|
|
{
|
|
|
|
|
// Look in the plugins for an option
|
|
|
|
|
typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions;
|
|
|
|
|
|
|
|
|
|
*requiresArgument = false;
|
|
|
|
|
const PluginSpecSet::const_iterator pcend = pluginSpecs.constEnd();
|
|
|
|
|
for (PluginSpecSet::const_iterator pit = pluginSpecs.constBegin(); pit != pcend; ++pit) {
|
|
|
|
|
PluginSpec *ps = *pit;
|
|
|
|
|
const PluginArgumentDescriptions pargs = ps->argumentDescriptions();
|
|
|
|
|
if (!pargs.empty()) {
|
|
|
|
|
const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd();
|
|
|
|
|
for (PluginArgumentDescriptions::const_iterator ait = pargs.constBegin(); ait != acend; ++ait) {
|
|
|
|
|
if (ait->name == option) {
|
|
|
|
|
*requiresArgument = !ait->parameter.isEmpty();
|
|
|
|
|
return ps;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-12 14:34:36 +02:00
|
|
|
void PluginManagerPrivate::disablePluginIndirectly(PluginSpec *spec)
|
2010-03-12 16:02:23 +01:00
|
|
|
{
|
2010-05-12 14:34:36 +02:00
|
|
|
spec->d->disabledIndirectly = true;
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
PluginSpec *PluginManagerPrivate::pluginByName(const QString &name) const
|
|
|
|
|
{
|
|
|
|
|
foreach (PluginSpec *spec, pluginSpecs)
|
|
|
|
|
if (spec->name() == name)
|
|
|
|
|
return spec;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-02 12:33:51 +01:00
|
|
|
void PluginManagerPrivate::initProfiling()
|
|
|
|
|
{
|
|
|
|
|
if (m_profileTimer.isNull()) {
|
|
|
|
|
m_profileTimer.reset(new QTime);
|
|
|
|
|
m_profileTimer->start();
|
|
|
|
|
m_profileElapsedMS = 0;
|
|
|
|
|
qDebug("Profiling started");
|
2010-05-12 11:12:54 +02:00
|
|
|
} else {
|
|
|
|
|
m_profilingVerbosity++;
|
2010-03-02 12:33:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PluginManagerPrivate::profilingReport(const char *what, const PluginSpec *spec /* = 0 */)
|
|
|
|
|
{
|
|
|
|
|
if (!m_profileTimer.isNull()) {
|
|
|
|
|
const int absoluteElapsedMS = m_profileTimer->elapsed();
|
|
|
|
|
const int elapsedMS = absoluteElapsedMS - m_profileElapsedMS;
|
|
|
|
|
m_profileElapsedMS = absoluteElapsedMS;
|
2013-02-07 12:48:16 +01:00
|
|
|
if (spec)
|
|
|
|
|
m_profileTotal[spec] += elapsedMS;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (spec)
|
2010-03-02 12:33:51 +01:00
|
|
|
qDebug("%-22s %-22s %8dms (%8dms)", what, qPrintable(spec->name()), absoluteElapsedMS, elapsedMS);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else
|
2010-05-12 11:12:54 +02:00
|
|
|
qDebug("%-45s %8dms (%8dms)", what, absoluteElapsedMS, elapsedMS);
|
2010-03-02 12:33:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
2011-01-05 18:35:08 +01:00
|
|
|
|
2013-02-06 13:53:51 +01:00
|
|
|
void PluginManagerPrivate::profilingSummary() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_profileTimer.isNull()) {
|
|
|
|
|
typedef QMultiMap<int, const PluginSpec *> Sorter;
|
|
|
|
|
Sorter sorter;
|
2013-02-12 16:43:02 +01:00
|
|
|
int total = 0;
|
2013-02-06 13:53:51 +01:00
|
|
|
|
|
|
|
|
QHash<const PluginSpec *, int>::ConstIterator it1 = m_profileTotal.constBegin();
|
|
|
|
|
QHash<const PluginSpec *, int>::ConstIterator et1 = m_profileTotal.constEnd();
|
2013-02-12 16:43:02 +01:00
|
|
|
for (; it1 != et1; ++it1) {
|
2013-02-06 13:53:51 +01:00
|
|
|
sorter.insert(it1.value(), it1.key());
|
2013-02-12 16:43:02 +01:00
|
|
|
total += it1.value();
|
|
|
|
|
}
|
2013-02-06 13:53:51 +01:00
|
|
|
|
|
|
|
|
Sorter::ConstIterator it2 = sorter.begin();
|
|
|
|
|
Sorter::ConstIterator et2 = sorter.end();
|
|
|
|
|
for (; it2 != et2; ++it2)
|
2013-02-12 16:43:02 +01:00
|
|
|
qDebug("%-22s %8dms ( %5.2f%% )", qPrintable(it2.value()->name()),
|
|
|
|
|
it2.key(), 100.0 * it2.key() / total);
|
|
|
|
|
qDebug("Total: %8dms", total);
|
2013-02-06 13:53:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-28 16:29:08 +02:00
|
|
|
static inline QString getPlatformName()
|
|
|
|
|
{
|
|
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
|
QString result = QLatin1String("Mac OS");
|
|
|
|
|
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_0)
|
|
|
|
|
result += QLatin1String(" 10.") + QString::number(QSysInfo::MacintoshVersion - QSysInfo::MV_10_0);
|
|
|
|
|
return result;
|
|
|
|
|
#elif defined(Q_OS_UNIX)
|
|
|
|
|
QFile osReleaseFile(QLatin1String("/etc/os-release")); // Newer Linuxes
|
|
|
|
|
if (osReleaseFile.open(QIODevice::ReadOnly)) {
|
|
|
|
|
QString name;
|
|
|
|
|
QString version;
|
|
|
|
|
forever {
|
|
|
|
|
const QByteArray line = osReleaseFile.readLine();
|
|
|
|
|
if (line.isEmpty())
|
|
|
|
|
break;
|
|
|
|
|
if (line.startsWith("NAME=\""))
|
|
|
|
|
name = QString::fromLatin1(line.mid(6, line.size() - 8)).trimmed();
|
|
|
|
|
if (line.startsWith("VERSION_ID=\""))
|
|
|
|
|
version = QString::fromLatin1(line.mid(12, line.size() - 14)).trimmed();
|
|
|
|
|
}
|
|
|
|
|
if (!name.isEmpty()) {
|
|
|
|
|
if (!version.isEmpty())
|
|
|
|
|
name += QLatin1Char(' ') + version;
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QFile issueFile(QLatin1String("/etc/issue")); // Older Linuxes
|
|
|
|
|
if (issueFile.open(QIODevice::ReadOnly)) {
|
|
|
|
|
QByteArray issue = issueFile.readAll();
|
|
|
|
|
const int end = issue.lastIndexOf(" \\n");
|
|
|
|
|
if (end >= 0)
|
|
|
|
|
issue.truncate(end);
|
|
|
|
|
return QString::fromLatin1(issue).trimmed();
|
|
|
|
|
}
|
|
|
|
|
# ifdef Q_OS_LINUX
|
|
|
|
|
return QLatin1String("Linux");
|
|
|
|
|
# else
|
|
|
|
|
return QLatin1String("Unix");
|
|
|
|
|
# endif // Q_OS_LINUX
|
|
|
|
|
#elif defined(Q_OS_WIN)
|
|
|
|
|
QString result = QLatin1String("Windows");
|
|
|
|
|
switch (QSysInfo::WindowsVersion) {
|
|
|
|
|
case QSysInfo::WV_XP:
|
|
|
|
|
result += QLatin1String(" XP");
|
|
|
|
|
break;
|
|
|
|
|
case QSysInfo::WV_2003:
|
|
|
|
|
result += QLatin1String(" 2003");
|
|
|
|
|
break;
|
|
|
|
|
case QSysInfo::WV_VISTA:
|
|
|
|
|
result += QLatin1String(" Vista");
|
|
|
|
|
break;
|
|
|
|
|
case QSysInfo::WV_WINDOWS7:
|
|
|
|
|
result += QLatin1String(" 7");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8)
|
|
|
|
|
result += QLatin1String(" 8");
|
|
|
|
|
return result;
|
|
|
|
|
#endif // Q_OS_WIN
|
|
|
|
|
return QLatin1String("Unknown");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString PluginManager::platformName()
|
|
|
|
|
{
|
|
|
|
|
static const QString result = getPlatformName();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-05 18:35:08 +01:00
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Retrieves one object with \a name from the object pool.
|
2011-01-05 18:35:08 +01:00
|
|
|
\sa addObject()
|
|
|
|
|
*/
|
|
|
|
|
|
2012-06-18 11:34:15 +02:00
|
|
|
QObject *PluginManager::getObjectByName(const QString &name)
|
2011-01-05 18:35:08 +01:00
|
|
|
{
|
2013-08-29 15:00:46 +02:00
|
|
|
QReadLocker lock(&d->m_lock);
|
2011-01-05 18:35:08 +01:00
|
|
|
QList<QObject *> all = allObjects();
|
|
|
|
|
foreach (QObject *obj, all) {
|
|
|
|
|
if (obj->objectName() == name)
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-06 11:46:55 +02:00
|
|
|
Retrieves one object inheriting a class with \a className from the object
|
|
|
|
|
pool.
|
2011-01-05 18:35:08 +01:00
|
|
|
\sa addObject()
|
|
|
|
|
*/
|
|
|
|
|
|
2012-06-18 11:34:15 +02:00
|
|
|
QObject *PluginManager::getObjectByClassName(const QString &className)
|
2011-01-05 18:35:08 +01:00
|
|
|
{
|
|
|
|
|
const QByteArray ba = className.toUtf8();
|
2013-08-29 15:00:46 +02:00
|
|
|
QReadLocker lock(&d->m_lock);
|
2011-01-05 18:35:08 +01:00
|
|
|
QList<QObject *> all = allObjects();
|
|
|
|
|
foreach (QObject *obj, all) {
|
|
|
|
|
if (obj->inherits(ba.constData()))
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|