ScriptEngine *loadEngine(const QString &language, Types::ComponentType type, QObject *parent,
    const QVariantList &args = QVariantList())
{
    ScriptEngine *engine = 0;

    auto filter = [&language](const KPluginMetaData &md) -> bool
    {
        return md.value(QStringLiteral("X-Plasma-API")) == language;
    };
    QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("plasma/scriptengines"), filter);

    if (plugins.count()) {
        const QString componentTypes = plugins.first().value(QStringLiteral("X-Plasma-ComponentTypes"));
        if (((type & Types::AppletComponent)     && componentTypes != QLatin1String("Applet"))
         || ((type & Types::DataEngineComponent) && componentTypes != QLatin1String("DataEngine"))) {
            return 0;
        }
        KPluginInfo::List lst = KPluginInfo::fromMetaData(plugins);
        KPluginLoader loader(lst.first().libraryPath());
        KPluginFactory *factory = loader.factory();
        if (factory) {
            engine = factory->create<Plasma::ScriptEngine>(0, args);
        }
    }

    return engine;
}
ScriptEngine *loadEngine(const QString &language, Types::ComponentType type, QObject *parent,
    const QVariantList &args = QVariantList())
{
    ScriptEngine *engine = 0;

    auto filter = [&language](const KPluginMetaData &md) -> bool
    {
        return md.value(QStringLiteral("X-Plasma-API")) == language;
    };
    QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("plasma/scriptengines"), filter);

    if (plugins.count()) {
        const QStringList componentTypes = KPluginMetaData::readStringList(plugins.first().rawData(), QStringLiteral("X-Plasma-ComponentTypes"));
        if (((type & Types::AppletComponent)     && !componentTypes.contains(QLatin1String("Applet")))
         || ((type & Types::DataEngineComponent) && !componentTypes.contains(QLatin1String("DataEngine")))) {

            qCWarning(LOG_PLASMA) << "ScriptEngine" << plugins.first().name() << "does not provide Applet or DataEngine components, returning empty.";
            return 0;
        }
        KPluginInfo::List lst = KPluginInfo::fromMetaData(plugins);
        KPluginLoader loader(lst.first().libraryPath());
        KPluginFactory *factory = loader.factory();
        if (factory) {
            engine = factory->create<Plasma::ScriptEngine>(0, args);
        } else {
            qCWarning(LOG_PLASMA) << "Unable to load" << plugins.first().name() << "ScriptEngine";
        }
    }

    return engine;
}
Service *PluginLoader::loadService(const QString &name, const QVariantList &args, QObject *parent)
{
    Service *service = d->isDefaultLoader ? 0 : internalLoadService(name, args, parent);
    if (service) {
        return service;
    }

    //TODO: scripting API support
    if (name.isEmpty()) {
        return new NullService(QString(), parent);
    } else if (name == QLatin1String("org.kde.servicestorage")) {
        return new Storage(parent);
    }


    // Look for C++ plugins first
    auto filter = [&name](const KPluginMetaData &md) -> bool
    {
        return md.pluginId() == name;
    };
    QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_servicesPluginDir, filter);

    if (plugins.count()) {
        KPluginInfo::List lst = KPluginInfo::fromMetaData(plugins);
        KPluginLoader loader(lst.first().libraryPath());
        if (!Plasma::isPluginVersionCompatible(loader.pluginVersion())) {
            return 0;
        }
        KPluginFactory *factory = loader.factory();
        if (factory) {
            service = factory->create<Plasma::Service>(0, args);
        }
    }

    if (service) {
        if (service->name().isEmpty()) {
            service->setName(name);
        }
        return service;
    } else {
        return new NullService(name, parent);
    }
}
ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, const QString &name, const QVariantList &args)
{
    if (name.isEmpty()) {
        return 0;
    }

    ContainmentActions *actions = d->isDefaultLoader ? 0 : internalLoadContainmentActions(parent, name, args);
    if (actions) {
        return actions;
    }


    // Look for C++ plugins first
    auto filter = [&name](const KPluginMetaData &md) -> bool
    {
        return md.pluginId() == name;
    };
    QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_containmentActionsPluginDir, filter);

    if (plugins.count()) {
        KPluginInfo::List lst = KPluginInfo::fromMetaData(plugins);
        KPluginLoader loader(lst.first().libraryPath());
        const QVariantList argsWithMetaData = QVariantList() << loader.metaData().toVariantMap();
        KPluginFactory *factory = loader.factory();
        if (factory) {
            actions = factory->create<Plasma::ContainmentActions>(0, argsWithMetaData);
        }
    }
    if (actions) {
        return actions;
    }

    //FIXME: this is only for backwards compatibility, but probably will have to stay
    //for the time being
    QString constraint = QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
    KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("Plasma/ContainmentActions"), constraint);

    if (offers.isEmpty()) {
#ifndef NDEBUG
        qCDebug(LOG_PLASMA) << "offers is empty for " << name;
#endif
        return 0;
    }

    KService::Ptr offer = offers.first();
    KPluginLoader plugin(*offer);

    if (!Plasma::isPluginVersionCompatible(plugin.pluginVersion())) {
        return 0;
    }

    QVariantList allArgs;
    allArgs << offer->storageId() << args;
    QString error;
    actions = offer->createInstance<Plasma::ContainmentActions>(parent, allArgs, &error);

    if (!actions) {
#ifndef NDEBUG
        // qCDebug(LOG_PLASMA) << "Couldn't load containmentActions \"" << name << "\"! reason given: " << error;
#endif
    }

    return actions;
}
MousePluginWidget::MousePluginWidget(const QString &pluginName, const QString &trigger, QGridLayout *layoutHack, QWidget *parent)
    : QObject(parent),
      m_configDlg(0),
      m_containment(0),
      m_lastConfigLocation(trigger),
      m_tempConfigParent(QString(), KConfig::SimpleConfig)
{
    KPluginInfo::List plugins = Plasma::ContainmentActions::listContainmentActionsInfo();
    if (plugins.isEmpty()) {
        //panic!!
        QLabel *fail = new QLabel(i18n("No plugins found, check your installation."), parent);
        layoutHack->addWidget(fail, 0, 0);
        return;
    }

    //make us some widgets
    m_pluginList = new QComboBox(parent);
    m_aboutButton = new QToolButton(parent);
    m_clearButton = new QToolButton(parent);
    m_triggerButton = new MouseInputButton(parent);
    m_configButton = new QToolButton(parent);
    //m_ui.description->setText(plugin.comment());

    //plugin list
    //FIXME is there some way to share this across all the entries?
    foreach (const KPluginInfo& plugin, plugins) {
        if (plugin.property("NoDisplay").toBool()) {
            continue;
        }

        m_pluginList->addItem(KIcon(plugin.icon()), plugin.name(), QVariant::fromValue(plugin));
        if (plugin.pluginName() == pluginName) {
            m_pluginList->setCurrentIndex(m_pluginList->count() - 1);
            m_plugin = plugin;
        }
    }

    if (! m_plugin.isValid()) {
        //probably an empty string; pick the first one
        m_pluginList->setCurrentIndex(0);
        m_plugin = plugins.first();
    }

    //I can haz config?
    m_tempConfig = KConfigGroup(&m_tempConfigParent, "test");
    if (!m_plugin.property("X-Plasma-HasConfigurationInterface").toBool()) {
        m_configButton->setVisible(false);
    }

    setTrigger(trigger);

    //pretty icons for the buttons
    m_aboutButton->setIcon(KIcon("dialog-information"));
    m_aboutButton->setToolTip(i18nc("About mouse action", "About"));
    m_triggerButton->setIcon(KIcon("input-mouse"));
    m_configButton->setIcon(KIcon("configure"));
    m_configButton->setToolTip(i18nc("Configure mouse action", "Configure"));
    m_clearButton->setIcon(KIcon("list-remove"));
    m_clearButton->setToolTip(i18nc("Remove mouse action", "Remove"));

    //HACK
    //FIXME what's the Right Way to do this?
    int row = layoutHack->rowCount();
    layoutHack->addWidget(m_triggerButton, row, 0);
    layoutHack->addWidget(m_pluginList, row, 1);
    layoutHack->addWidget(m_configButton, row, 2);
    layoutHack->addWidget(m_aboutButton, row, 3);
    layoutHack->addWidget(m_clearButton, row, 4);

    //connect
    connect(m_pluginList, SIGNAL(currentIndexChanged(int)), this, SLOT(setPlugin(int)));
    connect(m_triggerButton, SIGNAL(triggerChanged(QString,QString)), this, SLOT(changeTrigger(QString,QString)));
    connect(m_configButton, SIGNAL(clicked()), this, SLOT(configure()));
    connect(m_clearButton, SIGNAL(clicked()), this, SLOT(clearTrigger()));
    connect(m_aboutButton, SIGNAL(clicked()), this, SLOT(showAbout()));
}