}
}
- quInfo() << qPrintable(displayName()) << "Storage Backend is ready. Quassel Schema Version:" << installedSchemaVersion();
+ quInfo() << qPrintable(displayName()) << "storage backend is ready. Schema version:" << installedSchemaVersion();
return IsReady;
}
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
-#ifndef ABSTRACTSQLSTORAGE_H
-#define ABSTRACTSQLSTORAGE_H
+#pragma once
#include "storage.h"
+#include <memory>
+
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
AbstractSqlStorage(QObject *parent = 0);
virtual ~AbstractSqlStorage();
- virtual inline AbstractSqlMigrationReader *createMigrationReader() { return 0; }
- virtual inline AbstractSqlMigrationWriter *createMigrationWriter() { return 0; }
+ virtual std::unique_ptr<AbstractSqlMigrationReader> createMigrationReader() { return {}; }
+ virtual std::unique_ptr<AbstractSqlMigrationWriter> createMigrationWriter() { return {}; }
public slots:
virtual State init(const QVariantMap &settings = QVariantMap());
virtual inline bool postProcess() { return true; }
friend class AbstractSqlMigrationReader;
};
-
-
-#endif
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
+// Make moc happy
#include "authenticator.h"
-
-Authenticator::Authenticator(QObject *parent)
- : QObject(parent)
-{
-}
-
+#include "moc_authenticator.cpp"
Q_OBJECT
public:
- Authenticator(QObject *parent = 0);
- virtual ~Authenticator() {};
+ using QObject::QObject;
+ ~Authenticator() override = default;
enum State {
IsReady, // ready to go
/** \return A string that can be displayed by the client to describe the authenticator */
virtual QString description() const = 0;
- //! Returns a list of properties required to use the authenticator backend
- virtual QStringList setupKeys() const = 0;
+ //! Returns data required to configure the authenticator backend
+ /**
+ * A list of flattened triples for each field: {key, translated field name, default value}
+ * The default value's type determines the kind of input widget to be shown
+ * (int -> QSpinBox; QString -> QLineEdit)
+ * \return A list of triples defining the data to be shown in the configuration dialog
+ */
+ virtual QVariantList setupData() const = 0;
//! Checks if the authenticator allows manual password changes from inside quassel.
virtual bool canChangePassword() const = 0;
- //! Returns a map where the keys are are properties to use the authenticator backend
- /* the values are QVariants with default values */
- virtual QVariantMap setupDefaults() const = 0;
-
//! Setup the authenticator provider.
/** This prepares the authenticator provider (e.g. create tables, etc.) for use within Quassel.
* \param settings Hostname, port, username, password, ...
* \return A valid UserId if the password matches the username; 0 else
*/
virtual UserId validateUser(const QString &user, const QString &password) = 0;
-
-private:
-
};
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
+#include <algorithm>
+
#include <QCoreApplication>
#include "core.h"
Core::Core()
- : QObject(),
- _storage(0),
- _authenticator(0)
{
#ifdef HAVE_UMASK
umask(S_IRWXG | S_IRWXO);
# endif
QSettings oldSettings(org, "Quassel Core");
if (oldSettings.allKeys().count()) {
- qWarning() << "\n\n*** IMPORTANT: Config and data file locations have changed. Attempting to auto-migrate your core settings...";
+ quWarning() << "\n\n*** IMPORTANT: Config and data file locations have changed. Attempting to auto-migrate your core settings...";
foreach(QString key, oldSettings.allKeys())
newSettings.setValue(key, oldSettings.value(key));
newSettings.setValue("Config/Version", 1);
- qWarning() << "* Your core settings have been migrated to" << newSettings.fileName();
+ quWarning() << "* Your core settings have been migrated to" << newSettings.fileName();
#ifndef Q_OS_MAC /* we don't need to move the db and cert for mac */
#ifdef Q_OS_WIN
if (oldDb.exists()) {
bool success = oldDb.rename(Quassel::configDirPath() + "quassel-storage.sqlite");
if (success)
- qWarning() << "* Your database has been moved to" << Quassel::configDirPath() + "quassel-storage.sqlite";
+ quWarning() << "* Your database has been moved to" << Quassel::configDirPath() + "quassel-storage.sqlite";
else
- qWarning() << "!!! Moving your database has failed. Please move it manually into" << Quassel::configDirPath();
+ quWarning() << "!!! Moving your database has failed. Please move it manually into" << Quassel::configDirPath();
}
}
// move certificate
QFile cert(quasselDir + "quasselCert.pem");
bool success = cert.rename(Quassel::configDirPath() + "quasselCert.pem");
if (success)
- qWarning() << "* Your certificate has been moved to" << Quassel::configDirPath() + "quasselCert.pem";
+ quWarning() << "* Your certificate has been moved to" << Quassel::configDirPath() + "quasselCert.pem";
else
- qWarning() << "!!! Moving your certificate has failed. Please move it manually into" << Quassel::configDirPath();
+ quWarning() << "!!! Moving your certificate has failed. Please move it manually into" << Quassel::configDirPath();
}
#endif /* !Q_OS_MAC */
- qWarning() << "*** Migration completed.\n\n";
+ quWarning() << "*** Migration completed.\n\n";
}
}
// MIGRATION end
exit(EXIT_FAILURE);
}
+ // Set up storage and authentication backends
registerStorageBackends();
registerAuthenticators();
_configured = initStorage(dbsettings.value("Backend").toString(), dbsettings.value("ConnectionProperties").toMap());
// Not entirely sure what is 'legacy' about the above, but it seems to be the way things work!
- QVariantMap authSettings = cs.authSettings().toMap();
- initAuthenticator(authSettings.value("Authenticator").toString(), authSettings.value("AuthProperties").toMap());
+ if (_configured) {
+ QVariantMap authSettings = cs.authSettings().toMap();
+ initAuthenticator(authSettings.value("Authenticator", "Database").toString(), authSettings.value("AuthProperties").toMap());
+ }
if (Quassel::isOptionSet("select-backend") || Quassel::isOptionSet("select-authenticator")) {
if (Quassel::isOptionSet("select-backend")) {
if (Quassel::isOptionSet("select-authenticator")) {
selectAuthenticator(Quassel::optionValue("select-authenticator"));
}
- exit(0);
+ exit(EXIT_SUCCESS);
}
if (!_configured) {
- if (!_storageBackends.count()) {
- qWarning() << qPrintable(tr("Could not initialize any storage backend! Exiting..."));
- qWarning() << qPrintable(tr("Currently, Quassel supports SQLite3 and PostgreSQL. You need to build your\n"
+ if (_registeredStorageBackends.size() == 0) {
+ quWarning() << qPrintable(tr("Could not initialize any storage backend! Exiting..."));
+ quWarning() << qPrintable(tr("Currently, Quassel supports SQLite3 and PostgreSQL. You need to build your\n"
"Qt library with the sqlite or postgres plugin enabled in order for quasselcore\n"
"to work."));
- exit(1); // TODO make this less brutal (especially for mono client -> popup)
+ exit(EXIT_FAILURE); // TODO make this less brutal (especially for mono client -> popup)
}
-
- qWarning() << "Core is currently not configured! Please connect with a Quassel Client for basic setup.";
+ quWarning() << "Core is currently not configured! Please connect with a Quassel Client for basic setup.";
if (!cs.isWritable()) {
qWarning() << "Cannot write quasselcore configuration; probably a permission problem.";
handler->deleteLater(); // disconnect non authed clients
}
qDeleteAll(_sessions);
- qDeleteAll(_storageBackends);
- qDeleteAll(_authenticators);
}
void Core::restoreState()
{
if (!instance()->_configured) {
- // qWarning() << qPrintable(tr("Cannot restore a state for an unconfigured core!"));
+ // quWarning() << qPrintable(tr("Cannot restore a state for an unconfigured core!"));
return;
}
if (instance()->_sessions.count()) {
- qWarning() << qPrintable(tr("Calling restoreState() even though active sessions exist!"));
+ quWarning() << qPrintable(tr("Calling restoreState() even though active sessions exist!"));
return;
}
CoreSettings s;
/* We don't check, since we are at the first version since switching to Git
uint statever = s.coreState().toMap()["CoreStateVersion"].toUInt();
if(statever < 1) {
- qWarning() << qPrintable(tr("Core state too old, ignoring..."));
+ quWarning() << qPrintable(tr("Core state too old, ignoring..."));
return;
}
*/
QString Core::setupCoreForInternalUsage()
{
- Q_ASSERT(!_storageBackends.isEmpty());
+ Q_ASSERT(!_registeredStorageBackends.empty());
qsrand(QDateTime::currentDateTime().toTime_t());
int pass = 0;
/*** Storage Handling ***/
-void Core::registerStorageBackends()
-{
- // Register storage backends here!
- registerStorageBackend(new SqliteStorage(this));
- registerStorageBackend(new PostgreSqlStorage(this));
-}
-
-bool Core::registerStorageBackend(Storage *backend)
+template<typename Storage>
+void Core::registerStorageBackend()
{
- if (backend->isAvailable()) {
- _storageBackends[backend->displayName()] = backend;
- return true;
- }
- else {
+ auto backend = makeDeferredShared<Storage>(this);
+ if (backend->isAvailable())
+ _registeredStorageBackends.emplace_back(std::move(backend));
+ else
backend->deleteLater();
- return false;
- }
-}
-
-
-void Core::unregisterStorageBackends()
-{
- foreach(Storage *s, _storageBackends.values()) {
- s->deleteLater();
- }
- _storageBackends.clear();
-}
-
-
-void Core::unregisterStorageBackend(Storage *backend)
-{
- _storageBackends.remove(backend->displayName());
- backend->deleteLater();
-}
-
-// Authentication handling, now independent from storage.
-// Register and unregister authenticators.
-
-void Core::registerAuthenticators()
-{
- // Register new authentication backends here!
- registerAuthenticator(new SqlAuthenticator(this));
-#ifdef HAVE_LDAP
- registerAuthenticator(new LdapAuthenticator(this));
-#endif
-}
-
-
-bool Core::registerAuthenticator(Authenticator *authenticator)
-{
- if (authenticator->isAvailable()) {
- _authenticators[authenticator->backendId()] = authenticator;
- return true;
- }
- else {
- authenticator->deleteLater();
- return false;
- }
}
-void Core::unregisterAuthenticators()
+void Core::registerStorageBackends()
{
- foreach(Authenticator* a, _authenticators.values()) {
- a->deleteLater();
+ if (_registeredStorageBackends.empty()) {
+ registerStorageBackend<SqliteStorage>();
+ registerStorageBackend<PostgreSqlStorage>();
}
- _authenticators.clear();
}
-void Core::unregisterAuthenticator(Authenticator *backend)
+DeferredSharedPtr<Storage> Core::storageBackend(const QString &backendId) const
{
- _authenticators.remove(backend->backendId());
- backend->deleteLater();
+ auto it = std::find_if(_registeredStorageBackends.begin(), _registeredStorageBackends.end(),
+ [backendId](const DeferredSharedPtr<Storage> &backend) {
+ return backend->displayName() == backendId;
+ });
+ return it != _registeredStorageBackends.end() ? *it : nullptr;
}
// old db settings:
// "Type" => "sqlite"
bool Core::initStorage(const QString &backend, const QVariantMap &settings, bool setup)
{
- _storage = 0;
-
if (backend.isEmpty()) {
+ quWarning() << "No storage backend selected!";
return false;
}
- Storage *storage = 0;
- if (_storageBackends.contains(backend)) {
- storage = _storageBackends[backend];
- }
- else {
+ auto storage = storageBackend(backend);
+ if (!storage) {
qCritical() << "Selected storage backend is not available:" << backend;
return false;
}
exit(EXIT_FAILURE);
case Storage::IsReady:
// delete all other backends
- _storageBackends.remove(backend);
- unregisterStorageBackends();
- connect(storage, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)), this, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)));
+ _registeredStorageBackends.clear();
+ connect(storage.get(), SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)),
+ this, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)));
+ break;
}
- _storage = storage;
+ _storage = std::move(storage);
return true;
}
+
+void Core::syncStorage()
+{
+ if (_storage)
+ _storage->sync();
+}
+
+
+/*** Storage Access ***/
+bool Core::createNetwork(UserId user, NetworkInfo &info)
+{
+ NetworkId networkId = instance()->_storage->createNetwork(user, info);
+ if (!networkId.isValid())
+ return false;
+
+ info.networkId = networkId;
+ return true;
+}
+
+
+/*** Authenticators ***/
+
+// Authentication handling, now independent from storage.
+template<typename Authenticator>
+void Core::registerAuthenticator()
+{
+ auto authenticator = makeDeferredShared<Authenticator>(this);
+ if (authenticator->isAvailable())
+ _registeredAuthenticators.emplace_back(std::move(authenticator));
+ else
+ authenticator->deleteLater();
+}
+
+
+void Core::registerAuthenticators()
+{
+ if (_registeredAuthenticators.empty()) {
+ registerAuthenticator<SqlAuthenticator>();
+#ifdef HAVE_LDAP
+ registerAuthenticator<LdapAuthenticator>();
+#endif
+ }
+}
+
+
+DeferredSharedPtr<Authenticator> Core::authenticator(const QString &backendId) const
+{
+ auto it = std::find_if(_registeredAuthenticators.begin(), _registeredAuthenticators.end(),
+ [backendId](const DeferredSharedPtr<Authenticator> &authenticator) {
+ return authenticator->backendId() == backendId;
+ });
+ return it != _registeredAuthenticators.end() ? *it : nullptr;
+}
+
+
// FIXME: Apparently, this is the legacy way of initting storage backends?
// If there's a not-legacy way, it should be used here
bool Core::initAuthenticator(const QString &backend, const QVariantMap &settings, bool setup)
{
- _authenticator = 0;
-
if (backend.isEmpty()) {
+ quWarning() << "No authenticator selected!";
return false;
}
- Authenticator *authenticator = 0;
- if (_authenticators.contains(backend)) {
- authenticator = _authenticators[backend];
- }
- else {
+ auto auth = authenticator(backend);
+ if (!auth) {
qCritical() << "Selected auth backend is not available:" << backend;
return false;
}
- Authenticator::State authState = authenticator->init(settings);
+ Authenticator::State authState = auth->init(settings);
switch (authState) {
case Authenticator::NeedsSetup:
if (!setup)
return false; // trigger setup process
- if (authenticator->setup(settings))
+ if (auth->setup(settings))
return initAuthenticator(backend, settings, false);
// if initialization wasn't successful, we quit to keep from coming up unconfigured
case Authenticator::NotAvailable:
exit(EXIT_FAILURE);
case Authenticator::IsReady:
// delete all other backends
- _authenticators.remove(backend);
- unregisterAuthenticators();
+ _registeredAuthenticators.clear();
+ break;
}
- _authenticator = authenticator;
- return true;
-}
-
-
-void Core::syncStorage()
-{
- if (_storage)
- _storage->sync();
-}
-
-
-/*** Storage Access ***/
-bool Core::createNetwork(UserId user, NetworkInfo &info)
-{
- NetworkId networkId = instance()->_storage->createNetwork(user, info);
- if (!networkId.isValid())
- return false;
-
- info.networkId = networkId;
+ _authenticator = std::move(auth);
return true;
}
uid = _storage->internalUser();
}
else {
- qWarning() << "Core::setupInternalClientSession(): You're trying to run monolithic Quassel with an unusable Backend! Go fix it!";
+ quWarning() << "Core::setupInternalClientSession(): You're trying to run monolithic Quassel with an unusable Backend! Go fix it!";
return;
}
void Core::socketError(QAbstractSocket::SocketError err, const QString &errorString)
{
- qWarning() << QString("Socket error %1: %2").arg(err).arg(errorString);
+ quWarning() << QString("Socket error %1: %2").arg(err).arg(errorString);
}
QVariantList Core::backendInfo()
{
- QVariantList backends;
- foreach(const Storage *backend, instance()->_storageBackends.values()) {
+ instance()->registerStorageBackends();
+
+ QVariantList backendInfos;
+ for (auto &&backend : instance()->_registeredStorageBackends) {
QVariantMap v;
+ v["BackendId"] = backend->backendId();
v["DisplayName"] = backend->displayName();
v["Description"] = backend->description();
- v["SetupKeys"] = backend->setupKeys();
- v["SetupDefaults"] = backend->setupDefaults();
- v["IsDefault"] = isStorageBackendDefault(backend);
- backends.append(v);
+ v["SetupData"] = backend->setupData(); // ignored by legacy clients
+
+ // TODO Protocol Break: Remove legacy (cf. authenticatorInfo())
+ const auto &setupData = backend->setupData();
+ QStringList setupKeys;
+ QVariantMap setupDefaults;
+ for (int i = 0; i + 2 < setupData.size(); i += 3) {
+ setupKeys << setupData[i].toString();
+ setupDefaults[setupData[i].toString()] = setupData[i + 2];
+ }
+ v["SetupKeys"] = setupKeys;
+ v["SetupDefaults"] = setupDefaults;
+ // TODO Protocol Break: Remove
+ v["IsDefault"] = (backend->backendId() == "SQLite"); // newer clients will just use the first in the list
+
+ backendInfos << v;
}
- return backends;
+ return backendInfos;
}
QVariantList Core::authenticatorInfo()
{
- QVariantList backends;
- foreach(const Authenticator *backend, instance()->_authenticators.values()) {
+ instance()->registerAuthenticators();
+
+ QVariantList authInfos;
+ for(auto &&backend : instance()->_registeredAuthenticators) {
QVariantMap v;
- v["BackendId"] = backend->backendId();
+ v["BackendId"] = backend->backendId();
v["DisplayName"] = backend->displayName();
v["Description"] = backend->description();
- v["SetupKeys"] = backend->setupKeys();
- v["SetupDefaults"] = backend->setupDefaults();
- backends.append(v);
+ v["SetupData"] = backend->setupData();
+ authInfos << v;
}
- return backends;
+ return authInfos;
}
// migration / backend selection
{
// reregister all storage backends
registerStorageBackends();
- if (!_storageBackends.contains(backend)) {
- qWarning() << qPrintable(QString("Core::selectBackend(): unsupported backend: %1").arg(backend));
- qWarning() << " supported backends are:" << qPrintable(QStringList(_storageBackends.keys()).join(", "));
+ auto storage = storageBackend(backend);
+ if (!storage) {
+ QStringList backends;
+ std::transform(_registeredStorageBackends.begin(), _registeredStorageBackends.end(),
+ std::back_inserter(backends), [](const DeferredSharedPtr<Storage>& backend) {
+ return backend->displayName();
+ });
+ quWarning() << qPrintable(tr("Unsupported storage backend: %1").arg(backend));
+ quWarning() << qPrintable(tr("Supported backends are:")) << qPrintable(backends.join(", "));
return false;
}
- Storage *storage = _storageBackends[backend];
- QVariantMap settings = promptForSettings(storage);
+ QVariantMap settings = promptForSettings(storage.get());
Storage::State storageState = storage->init(settings);
switch (storageState) {
if (!saveBackendSettings(backend, settings)) {
qCritical() << qPrintable(QString("Could not save backend settings, probably a permission problem."));
}
- qWarning() << "Switched backend to:" << qPrintable(backend);
- qWarning() << "Backend already initialized. Skipping Migration";
+ quWarning() << qPrintable(tr("Switched storage backend to: %1").arg(backend));
+ quWarning() << qPrintable(tr("Backend already initialized. Skipping Migration..."));
return true;
case Storage::NotAvailable:
- qCritical() << "Backend is not available:" << qPrintable(backend);
+ qCritical() << qPrintable(tr("Storage backend is not available: %1").arg(backend));
return false;
case Storage::NeedsSetup:
if (!storage->setup(settings)) {
- qWarning() << qPrintable(QString("Core::selectBackend(): unable to setup backend: %1").arg(backend));
+ quWarning() << qPrintable(tr("Unable to setup storage backend: %1").arg(backend));
return false;
}
if (storage->init(settings) != Storage::IsReady) {
- qWarning() << qPrintable(QString("Core::migrateBackend(): unable to initialize backend: %1").arg(backend));
+ quWarning() << qPrintable(tr("Unable to initialize storage backend: %1").arg(backend));
return false;
}
if (!saveBackendSettings(backend, settings)) {
qCritical() << qPrintable(QString("Could not save backend settings, probably a permission problem."));
}
- qWarning() << "Switched backend to:" << qPrintable(backend);
+ quWarning() << qPrintable(tr("Switched storage backend to: %1").arg(backend));
break;
}
// let's see if we have a current storage object we can migrate from
- AbstractSqlMigrationReader *reader = getMigrationReader(_storage);
- AbstractSqlMigrationWriter *writer = getMigrationWriter(storage);
+ auto reader = getMigrationReader(_storage.get());
+ auto writer = getMigrationWriter(storage.get());
if (reader && writer) {
- qDebug() << qPrintable(QString("Migrating Storage backend %1 to %2...").arg(_storage->displayName(), storage->displayName()));
- delete _storage;
- _storage = 0;
- delete storage;
- storage = 0;
+ qDebug() << qPrintable(tr("Migrating storage backend %1 to %2...").arg(_storage->displayName(), storage->displayName()));
+ _storage.reset();
+ storage.reset();
if (reader->migrateTo(writer)) {
qDebug() << "Migration finished!";
+ qDebug() << qPrintable(tr("Migration finished!"));
if (!saveBackendSettings(backend, settings)) {
qCritical() << qPrintable(QString("Could not save backend settings, probably a permission problem."));
return false;
}
return true;
}
+ quWarning() << qPrintable(tr("Unable to migrate storage backend! (No migration writer for %1)").arg(backend));
return false;
- qWarning() << qPrintable(QString("Core::migrateDb(): unable to migrate storage backend! (No migration writer for %1)").arg(backend));
}
// inform the user why we cannot merge
if (!_storage) {
- qWarning() << "No currently active backend. Skipping migration.";
+ quWarning() << qPrintable(tr("No currently active storage backend. Skipping migration..."));
}
else if (!reader) {
- qWarning() << "Currently active backend does not support migration:" << qPrintable(_storage->displayName());
+ quWarning() << qPrintable(tr("Currently active storage backend does not support migration: %1").arg(_storage->displayName()));
}
if (writer) {
- qWarning() << "New backend does not support migration:" << qPrintable(backend);
+ quWarning() << qPrintable(tr("New storage backend does not support migration: %1").arg(backend));
}
// so we were unable to merge, but let's create a user \o/
- _storage = storage;
+ _storage = std::move(storage);
createUser();
return true;
}
{
// Register all authentication backends.
registerAuthenticators();
- if (!_authenticators.contains(backend)) {
- qWarning() << qPrintable(QString("Core::selectAuthenticator(): unsupported backend: %1").arg(backend));
- qWarning() << " supported backends are:" << qPrintable(QStringList(_authenticators.keys()).join(", "));
+ auto auther = authenticator(backend);
+ if (!auther) {
+ QStringList authenticators;
+ std::transform(_registeredAuthenticators.begin(), _registeredAuthenticators.end(),
+ std::back_inserter(authenticators), [](const DeferredSharedPtr<Authenticator>& authenticator) {
+ return authenticator->displayName();
+ });
+ quWarning() << qPrintable(tr("Unsupported authenticator: %1").arg(backend));
+ quWarning() << qPrintable(tr("Supported authenticators are:")) << qPrintable(authenticators.join(", "));
return false;
}
- Authenticator *authenticator = _authenticators[backend];
- QVariantMap settings = promptForSettings(authenticator);
+ QVariantMap settings = promptForSettings(auther.get());
- Authenticator::State state = authenticator->init(settings);
+ Authenticator::State state = auther->init(settings);
switch (state) {
case Authenticator::IsReady:
saveAuthenticatorSettings(backend, settings);
- qWarning() << "Switched auth backend to:" << qPrintable(backend);
-// qWarning() << "Auth backend already initialized. Skipping Migration";
+ quWarning() << qPrintable(tr("Switched authenticator to: %1").arg(backend));
return true;
case Authenticator::NotAvailable:
- qCritical() << "Auth backend is not available:" << qPrintable(backend);
+ qCritical() << qPrintable(tr("Authenticator is not available: %1").arg(backend));
return false;
case Authenticator::NeedsSetup:
- if (!authenticator->setup(settings)) {
- qWarning() << qPrintable(QString("Core::selectAuthenticator(): unable to setup authenticator: %1").arg(backend));
+ if (!auther->setup(settings)) {
+ quWarning() << qPrintable(tr("Unable to setup authenticator: %1").arg(backend));
return false;
}
- if (authenticator->init(settings) != Authenticator::IsReady) {
- qWarning() << qPrintable(QString("Core::migrateBackend(): unable to initialize authenticator: %1").arg(backend));
+ if (auther->init(settings) != Authenticator::IsReady) {
+ quWarning() << qPrintable(tr("Unable to initialize authenticator: %1").arg(backend));
return false;
}
saveAuthenticatorSettings(backend, settings);
- qWarning() << "Switched auth backend to:" << qPrintable(backend);
+ quWarning() << qPrintable(tr("Switched authenticator to: %1").arg(backend));
}
- _authenticator = authenticator;
+ _authenticator = std::move(auther);
return true;
}
enableStdInEcho();
if (password != password2) {
- qWarning() << "Passwords don't match!";
+ quWarning() << "Passwords don't match!";
return false;
}
if (password.isEmpty()) {
- qWarning() << "Password is empty!";
+ quWarning() << "Password is empty!";
return false;
}
return true;
}
else {
- qWarning() << "Unable to add user:" << qPrintable(username);
+ quWarning() << "Unable to add user:" << qPrintable(username);
return false;
}
}
enableStdInEcho();
if (password != password2) {
- qWarning() << "Passwords don't match!";
+ quWarning() << "Passwords don't match!";
return false;
}
if (password.isEmpty()) {
- qWarning() << "Password is empty!";
+ quWarning() << "Password is empty!";
return false;
}
return true;
}
else {
- qWarning() << "Failed to change password!";
+ quWarning() << "Failed to change password!";
return false;
}
}
}
-AbstractSqlMigrationReader *Core::getMigrationReader(Storage *storage)
+std::unique_ptr<AbstractSqlMigrationReader> Core::getMigrationReader(Storage *storage)
{
if (!storage)
- return 0;
+ return nullptr;
AbstractSqlStorage *sqlStorage = qobject_cast<AbstractSqlStorage *>(storage);
if (!sqlStorage) {
qDebug() << "Core::migrateDb(): only SQL based backends can be migrated!";
- return 0;
+ return nullptr;
}
return sqlStorage->createMigrationReader();
}
-AbstractSqlMigrationWriter *Core::getMigrationWriter(Storage *storage)
+std::unique_ptr<AbstractSqlMigrationWriter> Core::getMigrationWriter(Storage *storage)
{
if (!storage)
- return 0;
+ return nullptr;
AbstractSqlStorage *sqlStorage = qobject_cast<AbstractSqlStorage *>(storage);
if (!sqlStorage) {
qDebug() << "Core::migrateDb(): only SQL based backends can be migrated!";
- return 0;
+ return nullptr;
}
return sqlStorage->createMigrationWriter();
// Generic version of promptForSettings that doesn't care what *type* of
// backend it runs over.
-QVariantMap Core::promptForSettings(QStringList keys, QVariantMap defaults)
+template<typename Backend>
+QVariantMap Core::promptForSettings(const Backend *backend)
{
QVariantMap settings;
+ const QVariantList& setupData = backend->setupData();
- if (keys.isEmpty())
+ if (setupData.isEmpty())
return settings;
QTextStream out(stdout);
QTextStream in(stdin);
out << "Default values are in brackets" << endl;
- QString value;
- foreach(QString key, keys) {
- QVariant val;
- if (defaults.contains(key)) {
- val = defaults[key];
- }
- out << key;
- if (!val.toString().isEmpty()) {
- out << " (" << val.toString() << ")";
- }
- out << ": ";
- out.flush();
+ for (int i = 0; i + 2 < setupData.size(); i += 3) {
+ QString key = setupData[i].toString();
+ out << setupData[i+1].toString() << " [" << setupData[i+2].toString() << "]: " << flush;
- bool noEcho = QString("password").toLower().startsWith(key.toLower());
+ bool noEcho = key.toLower().contains("password");
if (noEcho) {
disableStdInEcho();
}
- value = in.readLine().trimmed();
+ QString input = in.readLine().trimmed();
if (noEcho) {
out << endl;
enableStdInEcho();
}
- if (!value.isEmpty()) {
- switch (defaults[key].type()) {
+ QVariant value{setupData[i+2]};
+ if (!input.isEmpty()) {
+ switch (value.type()) {
case QVariant::Int:
- val = QVariant(value.toInt());
+ value = input.toInt();
break;
default:
- val = QVariant(value);
+ value = input;
}
}
- settings[key] = val;
+ settings[key] = value;
}
return settings;
}
-// Since an auth and storage backend work basically the same way,
-// use polymorphism here on this routine.
-QVariantMap Core::promptForSettings(const Storage *storage)
-{
- QStringList keys = storage->setupKeys();
- QVariantMap defaults = storage->setupDefaults();
- return Core::promptForSettings(keys, defaults);
-}
-
-
-QVariantMap Core::promptForSettings(const Authenticator *authenticator)
-{
- QStringList keys = authenticator->setupKeys();
- QVariantMap defaults = authenticator->setupDefaults();
- return Core::promptForSettings(keys, defaults);
-}
-
#ifdef Q_OS_WIN
void Core::stdInEcho(bool on)
SetConsoleMode(hStdin, mode);
}
-
#else
void Core::stdInEcho(bool on)
{
tcsetattr(STDIN_FILENO, TCSANOW, &t);
}
-
#endif /* Q_OS_WIN */
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
-#ifndef CORE_H
-#define CORE_H
+#pragma once
+
+#include <memory>
+#include <vector>
#include <QDateTime>
#include <QString>
#include "authenticator.h"
#include "bufferinfo.h"
+#include "deferredptr.h"
#include "message.h"
#include "oidentdconfiggenerator.h"
#include "sessionthread.h"
static QVariantList backendInfo();
static QVariantList authenticatorInfo();
- /**
- * Checks if a storage backend is the default storage backend. This
- * hardcodes this information into the core (not the client).
- *
- * \param backend The backend to check.
- *
- * @return True if storage backend is default, false otherwise.
- */
- static inline bool isStorageBackendDefault(const Storage *backend)
- {
- return (backend->displayName() == "SQLite") ? true : false;
- }
-
static QString setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authenticator, const QVariantMap &authSetupMap);
static inline QTimer &syncTimer() { return instance()->_storageSyncTimer; }
//void processCoreSetup(QTcpSocket *socket, QVariantMap &msg);
QString setupCoreForInternalUsage();
- void registerStorageBackends();
- bool registerStorageBackend(Storage *);
- void unregisterStorageBackends();
- void unregisterStorageBackend(Storage *);
+ bool createUser();
+ template<typename Storage>
+ void registerStorageBackend();
+
+ template<typename Authenticator>
+ void registerAuthenticator();
+
+ void registerStorageBackends();
void registerAuthenticators();
- bool registerAuthenticator(Authenticator *);
- void unregisterAuthenticators();
- void unregisterAuthenticator(Authenticator *);
+
+ DeferredSharedPtr<Storage> storageBackend(const QString& backendId) const;
+ DeferredSharedPtr<Authenticator> authenticator(const QString& authenticatorId) const;
bool selectBackend(const QString &backend);
bool selectAuthenticator(const QString &backend);
- bool createUser();
bool saveBackendSettings(const QString &backend, const QVariantMap &settings);
void saveAuthenticatorSettings(const QString &backend, const QVariantMap &settings);
- QVariantMap promptForSettings(const Storage *storage);
- QVariantMap promptForSettings(const Authenticator *authenticator);
- QVariantMap promptForSettings(QStringList keys, QVariantMap defaults);
+ template<typename Backend>
+ QVariantMap promptForSettings(const Backend *backend);
private:
QSet<CoreAuthHandler *> _connectingClients;
QHash<UserId, SessionThread *> _sessions;
-
- // Have both a storage backend and an authenticator backend.
- Storage *_storage;
- Authenticator *_authenticator;
+ DeferredSharedPtr<Storage> _storage; ///< Active storage backend
+ DeferredSharedPtr<Authenticator> _authenticator; ///< Active authenticator
QTimer _storageSyncTimer;
#ifdef HAVE_SSL
QTcpServer _server, _v6server;
#endif
- OidentdConfigGenerator *_oidentdConfigGenerator;
+ OidentdConfigGenerator *_oidentdConfigGenerator {nullptr};
- QHash<QString, Storage *> _storageBackends;
- QHash<QString, Authenticator *> _authenticators;
+ std::vector<DeferredSharedPtr<Storage>> _registeredStorageBackends;
+ std::vector<DeferredSharedPtr<Authenticator>> _registeredAuthenticators;
QDateTime _startTime;
bool _configured;
- static AbstractSqlMigrationReader *getMigrationReader(Storage *storage);
- static AbstractSqlMigrationWriter *getMigrationWriter(Storage *storage);
+ static std::unique_ptr<AbstractSqlMigrationReader> getMigrationReader(Storage *storage);
+ static std::unique_ptr<AbstractSqlMigrationWriter> getMigrationWriter(Storage *storage);
static void stdInEcho(bool on);
static inline void enableStdInEcho() { stdInEcho(true); }
static inline void disableStdInEcho() { stdInEcho(false); }
};
-
-
-#endif
return tr("Authenticate users using an LDAP server.");
}
-QStringList LdapAuthenticator::setupKeys() const
-{
- // The parameters needed for LDAP.
- QStringList keys;
- keys << "Hostname"
- << "Port"
- << "Bind DN"
- << "Bind Password"
- << "Base DN"
- << "Filter"
- << "UID Attribute";
- return keys;
-}
-
-QVariantMap LdapAuthenticator::setupDefaults() const
+QVariantList LdapAuthenticator::setupData() const
{
- QVariantMap map;
- map["Hostname"] = QVariant(QString("ldap://localhost"));
- map["Port"] = QVariant(DEFAULT_LDAP_PORT);
- map["UID Attribute"] = QVariant(QString("uid"));
- return map;
+ // The parameters needed for LDAP.
+ QVariantList data;
+ data << "Hostname" << tr("Hostname") << QString{"ldap://localhost"}
+ << "Port" << tr("Port") << DEFAULT_LDAP_PORT
+ << "BindDN" << tr("Bind DN") << QString{}
+ << "BindPassword" << tr("Bind Password") << QString{}
+ << "BaseDN" << tr("Base DN") << QString{}
+ << "Filter" << tr("Filter") << QString{}
+ << "UidAttribute" << tr("UID Attribute") << QString{"uid"}
+ ;
+ return data;
}
{
_hostName = properties["Hostname"].toString();
_port = properties["Port"].toInt();
- _baseDN = properties["Base DN"].toString();
+ _bindDN = properties["BindDN"].toString();
+ _bindPassword = properties["BindPassword"].toString();
+ _baseDN = properties["BaseDN"].toString();
_filter = properties["Filter"].toString();
- _bindDN = properties["Bind DN"].toString();
- _bindPassword = properties["Bind Password"].toString();
- _uidAttribute = properties["UID Attribute"].toString();
+ _uidAttribute = properties["UidAttribute"].toString();
}
// TODO: this code is sufficiently general that in the future, perhaps an abstract
bool status = ldapConnect();
if (!status) {
- quInfo() << qPrintable(backendId()) << "Authenticator cannot connect.";
+ quInfo() << qPrintable(backendId()) << "authenticator cannot connect.";
return NotAvailable;
}
- quInfo() << qPrintable(backendId()) << "Authenticator is ready.";
+ quInfo() << qPrintable(backendId()) << "authenticator is ready.";
return IsReady;
}
//#endif
// Default LDAP server port.
-#define DEFAULT_LDAP_PORT 389
+constexpr int DEFAULT_LDAP_PORT = 389;
class LdapAuthenticator : public Authenticator
{
public:
LdapAuthenticator(QObject *parent = 0);
- virtual ~LdapAuthenticator();
+ ~LdapAuthenticator() override;
public slots:
/* General */
- bool isAvailable() const;
- QString backendId() const;
- QString displayName() const;
- QString description() const;
- virtual QStringList setupKeys() const;
- virtual QVariantMap setupDefaults() const;
+ bool isAvailable() const override;
+ QString backendId() const override;
+ QString displayName() const override;
+ QString description() const override;
+ QVariantList setupData() const override;
- virtual inline bool canChangePassword() const { return false; }
+ bool canChangePassword() const override { return false; }
- bool setup(const QVariantMap &settings = QVariantMap());
- State init(const QVariantMap &settings = QVariantMap());
- UserId validateUser(const QString &user, const QString &password);
+ bool setup(const QVariantMap &settings = {}) override;
+ State init(const QVariantMap &settings = {}) override;
+ UserId validateUser(const QString &user, const QString &password) override;
protected:
- virtual void setAuthProperties(const QVariantMap &properties);
+ void setAuthProperties(const QVariantMap &properties);
bool ldapConnect();
void ldapDisconnect();
bool ldapAuth(const QString &username, const QString &password);
// Protected methods for retrieving info about the LDAP connection.
- inline virtual QString hostName() { return _hostName; }
- inline virtual int port() { return _port; }
- inline virtual QString bindDN() { return _bindDN; }
- inline virtual QString baseDN() { return _baseDN; }
+ QString hostName() const { return _hostName; }
+ int port() const { return _port; }
+ QString bindDN() const { return _bindDN; }
+ QString baseDN() const { return _baseDN; }
private:
QString _hostName;
QString _uidAttribute;
// The actual connection object.
- LDAP *_connection;
-
+ LDAP *_connection {nullptr};
};
}
-AbstractSqlMigrationWriter *PostgreSqlStorage::createMigrationWriter()
+std::unique_ptr<AbstractSqlMigrationWriter> PostgreSqlStorage::createMigrationWriter()
{
- PostgreSqlMigrationWriter *writer = new PostgreSqlMigrationWriter();
+ auto writer = new PostgreSqlMigrationWriter();
QVariantMap properties;
properties["Username"] = _userName;
properties["Password"] = _password;
properties["Port"] = _port;
properties["Database"] = _databaseName;
writer->setConnectionProperties(properties);
- return writer;
+ return std::unique_ptr<AbstractSqlMigrationWriter>{writer};
}
bool PostgreSqlStorage::isAvailable() const
{
- qDebug() << QSqlDatabase::drivers();
- if (!QSqlDatabase::isDriverAvailable("QPSQL")) return false;
+ if (!QSqlDatabase::isDriverAvailable("QPSQL")) {
+ quWarning() << qPrintable(tr("PostgreSQL driver plugin not available for Qt. Installed drivers:"))
+ << qPrintable(QSqlDatabase::drivers().join(", "));
+ return false;
+ }
return true;
}
-QString PostgreSqlStorage::displayName() const
+QString PostgreSqlStorage::backendId() const
{
return QString("PostgreSQL");
}
-QString PostgreSqlStorage::description() const
+QString PostgreSqlStorage::displayName() const
{
- // FIXME: proper description
- return tr("PostgreSQL Turbo Bomber HD!");
+ return backendId(); // Note: Pre-0.13 clients use the displayName property for backend idenfication
}
-QStringList PostgreSqlStorage::setupKeys() const
+QString PostgreSqlStorage::description() const
{
- QStringList keys;
- keys << "Username"
- << "Password"
- << "Hostname"
- << "Port"
- << "Database";
- return keys;
+ // FIXME: proper description
+ return tr("PostgreSQL Turbo Bomber HD!");
}
-QVariantMap PostgreSqlStorage::setupDefaults() const
+QVariantList PostgreSqlStorage::setupData() const
{
- QVariantMap map;
- map["Username"] = QVariant(QString("quassel"));
- map["Hostname"] = QVariant(QString("localhost"));
- map["Port"] = QVariant(5432);
- map["Database"] = QVariant(QString("quassel"));
- return map;
+ QVariantList data;
+ data << "Username" << tr("Username") << QString("quassel")
+ << "Password" << tr("Password") << QString()
+ << "Hostname" << tr("Hostname") << QString("localhost")
+ << "Port" << tr("Port") << 5432
+ << "Database" << tr("Database") << QString("quassel")
+ ;
+ return data;
}
PostgreSqlStorage(QObject *parent = 0);
virtual ~PostgreSqlStorage();
- virtual AbstractSqlMigrationWriter *createMigrationWriter();
+ virtual std::unique_ptr<AbstractSqlMigrationWriter> createMigrationWriter();
public slots:
/* General */
virtual bool isAvailable() const;
+ virtual QString backendId() const;
virtual QString displayName() const;
virtual QString description() const;
- virtual QStringList setupKeys() const;
- virtual QVariantMap setupDefaults() const;
+ virtual QVariantList setupData() const;
// TODO: Add functions for configuring the backlog handling, i.e. defining auto-cleanup settings etc
QString SqlAuthenticator::description() const
{
- return tr("Do not auth against any remote authentication service, but instead save a hashed and salted password "
- "in the selected database.");
+ return tr("Do not authenticate against any remote service, but instead save a hashed and salted password "
+ "in the database selected in the next step.");
}
// TODO: FIXME: this should check if the storage provider is ready, but I don't
// know if there's an exposed way to do that at the moment.
- quInfo() << qPrintable(backendId()) << "Authenticator is ready.";
+ quInfo() << qPrintable(backendId()) << "authenticator is ready.";
return IsReady;
}
QString backendId() const;
QString displayName() const;
QString description() const;
- virtual inline QStringList setupKeys() const { return QStringList(); }
- virtual inline QVariantMap setupDefaults() const { return QVariantMap(); }
+ virtual inline QVariantList setupData() const { return {}; }
virtual inline bool canChangePassword() const { return true; }
/* User handling */
//virtual UserId getUserId(const QString &username);
-
};
}
+QString SqliteStorage::backendId() const
+{
+ return QString("SQLite");
+}
+
+
QString SqliteStorage::displayName() const
{
+ // Note: Pre-0.13 clients use the displayName property for backend idenfication
// We identify the backend to use for the monolithic core by its displayname.
// so only change this string if you _really_ have to and make sure the core
// setup for the mono client still works ;)
- return QString("SQLite");
+ return backendId();
}
SqliteStorage(QObject *parent = 0);
virtual ~SqliteStorage();
- virtual AbstractSqlMigrationReader *createMigrationReader();
+ virtual std::unique_ptr<AbstractSqlMigrationReader> createMigrationReader();
public slots:
/* General */
bool isAvailable() const;
+ QString backendId() const;
QString displayName() const;
- virtual inline QStringList setupKeys() const { return QStringList(); }
- virtual inline QVariantMap setupDefaults() const { return QVariantMap(); }
+ virtual inline QVariantList setupData() const { return {}; }
QString description() const;
// TODO: Add functions for configuring the backlog handling, i.e. defining auto-cleanup settings etc
};
-inline AbstractSqlMigrationReader *SqliteStorage::createMigrationReader()
+inline std::unique_ptr<AbstractSqlMigrationReader> SqliteStorage::createMigrationReader()
{
- return new SqliteMigrationReader();
+ return std::unique_ptr<AbstractSqlMigrationReader>{new SqliteMigrationReader()};
}
Sha1,
Sha2_512,
Latest=Sha2_512
-
+
};
public slots:
*/
virtual bool isAvailable() const = 0;
+ //! Returns the identifier of the authenticator backend
+ /** \return A string that can be used by the client to identify the authenticator backend */
+ virtual QString backendId() const = 0;
+
//! Returns the display name of the storage backend
/** \return A string that can be used by the client to name the storage backend */
virtual QString displayName() const = 0;
/** \return A string that can be displayed by the client to describe the storage backend */
virtual QString description() const = 0;
- //! Returns a list of properties required to use the storage backend
- virtual QStringList setupKeys() const = 0;
-
- //! Returns a map where the keys are are properties to use the storage backend
- /* the values are QVariants with default values */
- virtual QVariantMap setupDefaults() const = 0;
+ //! Returns data required to configure the authenticator backend
+ /**
+ * A list of flattened triples for each field: {key, translated field name, default value}
+ * The default value's type determines the kind of input widget to be shown
+ * (int -> QSpinBox; QString -> QLineEdit)
+ * \return A list of triples defining the data to be shown in the configuration dialog
+ */
+ virtual QVariantList setupData() const = 0;
//! Setup the storage provider.
/** This prepares the storage provider (e.g. create tables, etc.) for use within Quassel.
#include "client.h"
-CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QList<QVariant> &backends, const QList<QVariant> &authenticators, QWidget *parent)
+namespace {
+
+template<typename FieldInfo>
+void createFieldWidgets(QGroupBox *fieldBox, const std::vector<FieldInfo> &fieldInfos)
+{
+ // Create a config UI based on the field types sent from the backend
+ // We make some assumptions here (like integer range and password field names) that may not
+ // hold true for future authenticator types - but the only way around it for now would be to
+ // provide specialized config widgets for those (which may be a good idea anyway, e.g. if we
+ // think about client-side translations...)
+
+ QFormLayout *formLayout = new QFormLayout;
+ for (auto &&fieldInfo : fieldInfos) {
+ QWidget *widget {nullptr};
+ switch (std::get<2>(fieldInfo).type()) {
+ case QVariant::Int:
+ widget = new QSpinBox(fieldBox);
+ // Here we assume that int fields are always in 16 bit range, like ports
+ static_cast<QSpinBox *>(widget)->setMinimum(0);
+ static_cast<QSpinBox *>(widget)->setMaximum(65535);
+ static_cast<QSpinBox *>(widget)->setValue(std::get<2>(fieldInfo).toInt());
+ break;
+ case QVariant::String:
+ widget = new QLineEdit(std::get<2>(fieldInfo).toString(), fieldBox);
+ // Here we assume that fields named something with "password" are actual password inputs
+ if (std::get<0>(fieldInfo).toLower().contains("password"))
+ static_cast<QLineEdit *>(widget)->setEchoMode(QLineEdit::Password);
+ break;
+ default:
+ qWarning() << "Unsupported type for backend property" << std::get<0>(fieldInfo);
+ }
+ if (widget) {
+ widget->setObjectName(std::get<0>(fieldInfo));
+ formLayout->addRow(std::get<1>(fieldInfo) + ":", widget);
+ }
+ }
+ fieldBox->setLayout(formLayout);
+}
+
+
+template<typename FieldInfo>
+QVariantMap propertiesFromFieldWidgets(QGroupBox *fieldBox, const std::vector<FieldInfo> &fieldInfos)
+{
+ QVariantMap properties;
+ if (!fieldBox)
+ return properties;
+
+ for (auto &&fieldInfo : fieldInfos) {
+ QString key = std::get<0>(fieldInfo);
+ QVariant value;
+ switch (std::get<2>(fieldInfo).type()) {
+ case QVariant::Int: {
+ QSpinBox *spinBox = fieldBox->findChild<QSpinBox *>(key);
+ if (spinBox)
+ value = spinBox->value();
+ else
+ qWarning() << "Could not find child widget for field" << key;
+ break;
+ }
+ case QVariant::String: {
+ QLineEdit *lineEdit = fieldBox->findChild<QLineEdit *>(key);
+ if (lineEdit)
+ value = lineEdit->text();
+ else
+ qWarning() << "Could not find child widget for field" << key;
+ break;
+ }
+ default:
+ qWarning() << "Unsupported type for backend property" << key;
+ }
+ properties[key] = std::move(value);
+ }
+ return properties;
+}
+
+} // anon
+
+
+CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QVariantList &backendInfos, const QVariantList &authInfos, QWidget *parent)
: QWizard(parent),
- _connection(connection)
+ _connection{connection}
{
setModal(true);
setAttribute(Qt::WA_DeleteOnClose);
- foreach(const QVariant &v, backends)
- _backends[v.toMap()["DisplayName"].toString()] = v;
-
- foreach(const QVariant &v, authenticators)
- _authenticators[v.toMap()["BackendId"].toString()] = v;
-
setPage(IntroPage, new CoreConfigWizardPages::IntroPage(this));
setPage(AdminUserPage, new CoreConfigWizardPages::AdminUserPage(this));
- setPage(AuthenticationSelectionPage, new CoreConfigWizardPages::AuthenticationSelectionPage(_authenticators, this));
- setPage(StorageSelectionPage, new CoreConfigWizardPages::StorageSelectionPage(_backends, this));
+ setPage(AuthenticationSelectionPage, new CoreConfigWizardPages::AuthenticationSelectionPage(authInfos, this));
+ setPage(StorageSelectionPage, new CoreConfigWizardPages::StorageSelectionPage(backendInfos, this));
syncPage = new CoreConfigWizardPages::SyncPage(this);
connect(syncPage, SIGNAL(setupCore(const QString &, const QVariantMap &, const QString &, const QVariantMap &)),
SLOT(prepareCoreSetup(const QString &, const QVariantMap &, const QString &, const QVariantMap &)));
}
-QHash<QString, QVariant> CoreConfigWizard::backends() const
-{
- return _backends;
-}
-
-
-QHash<QString, QVariant> CoreConfigWizard::authenticators() const
-{
- return _authenticators;
-}
-
-
void CoreConfigWizard::prepareCoreSetup(const QString &backend, const QVariantMap &properties, const QString &authenticator, const QVariantMap &authProperties)
{
// Prevent the user from changing any settings he already specified...
{
syncPage->setStatus(tr("Your core has been successfully configured. Logging you in..."));
syncPage->setError(false);
- syncRelayPage->setMode(CoreConfigWizardPages::SyncRelayPage::Error);
+ syncRelayPage->setMode(CoreConfigWizardPages::SyncRelayPage::Success);
coreConnection()->loginToCore(field("adminUser.user").toString(), field("adminUser.password").toString(), field("adminUser.rememberPasswd").toBool());
}
registerField("adminUser.password*", ui.password);
registerField("adminUser.password2*", ui.password2);
registerField("adminUser.rememberPasswd", ui.rememberPasswd);
-
- //ui.user->setText("foo");
- //ui.password->setText("foo");
- //ui.password2->setText("foo");
}
/*** Authentication Selection Page ***/
-AuthenticationSelectionPage::AuthenticationSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent)
- : QWizardPage(parent),
- _connectionBox(0),
- _backends(backends)
+AuthenticationSelectionPage::AuthenticationSelectionPage(const QVariantList &authInfos, QWidget *parent)
+ : QWizardPage(parent)
{
ui.setupUi(this);
registerField("authentication.backend", ui.backendList);
- foreach(QString key, _backends.keys()) {
- ui.backendList->addItem(_backends[key].toMap()["DisplayName"].toString(), key);
+ for (auto &&authInfo : authInfos) {
+ auto props = authInfo.toMap();
+ // Extract field infos to avoid having to reparse the list
+ std::vector<FieldInfo> fields;
+ const auto &list = props["SetupData"].toList();
+ for (int i = 0; i + 2 < list.size(); i += 3) {
+ fields.emplace_back(std::make_tuple(list[i].toString(), list[i+1].toString(), list[i+2]));
+ }
+ props.remove("SetupData");
+
+ _authProperties.emplace_back(props);
+ _authFields.emplace_back(std::move(fields));
+
+ // Create entry in authenticator selector
+ ui.backendList->addItem(props["DisplayName"].toString(), props["BackendId"].toString());
}
- on_backendList_currentIndexChanged();
+ ui.backendList->setCurrentIndex(0);
}
}
-QString AuthenticationSelectionPage::selectedBackend() const
+QString AuthenticationSelectionPage::displayName() const
{
return ui.backendList->currentText();
}
-QVariantMap AuthenticationSelectionPage::authProperties() const
+QString AuthenticationSelectionPage::authenticator() const
{
- QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
+#if QT_VERSION >= 0x050200
+ return ui.backendList->currentData().toString();
+#else
+ return ui.backendList->itemData(ui.backendList->currentIndex()).toString();
+#endif
+}
- QVariantMap properties;
- QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
- if (!setupKeys.isEmpty()) {
- QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
- foreach(QString key, setupKeys) {
- QWidget *widget = _connectionBox->findChild<QWidget *>(key);
- QVariant def;
- if (defaults.contains(key)) {
- def = defaults[key];
- }
- switch (def.type()) {
- case QVariant::Int:
- {
- QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
- Q_ASSERT(spinbox);
- def = QVariant(spinbox->value());
- }
- break;
- default:
- {
- QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
- Q_ASSERT(lineEdit);
- def = QVariant(lineEdit->text());
- }
- }
- properties[key] = def;
- }
- }
- return properties;
+
+QVariantMap AuthenticationSelectionPage::authProperties() const
+{
+ return propertiesFromFieldWidgets(_fieldBox, _authFields[ui.backendList->currentIndex()]);
}
-void AuthenticationSelectionPage::on_backendList_currentIndexChanged()
+void AuthenticationSelectionPage::on_backendList_currentIndexChanged(int index)
{
- QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
- ui.description->setText(_backends[backend].toMap()["Description"].toString());
+ ui.description->setText(_authProperties[index]["Description"].toString());
- if (_connectionBox) {
- layout()->removeWidget(_connectionBox);
- _connectionBox->deleteLater();
- _connectionBox = 0;
+ if (_fieldBox) {
+ layout()->removeWidget(_fieldBox);
+ _fieldBox->deleteLater();
+ _fieldBox = nullptr;
}
-
- QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
- if (!setupKeys.isEmpty()) {
- QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
- QGroupBox *propertyBox = new QGroupBox(this);
- propertyBox->setTitle(tr("Connection Properties"));
- QFormLayout *formlayout = new QFormLayout;
-
- foreach(QString key, setupKeys) {
- QWidget *widget = 0;
- QVariant def;
- if (defaults.contains(key)) {
- def = defaults[key];
- }
- switch (def.type()) {
- case QVariant::Int:
- {
- QSpinBox *spinbox = new QSpinBox(propertyBox);
- spinbox->setMaximum(64000);
- spinbox->setValue(def.toInt());
- widget = spinbox;
- }
- break;
- default:
- {
- QLineEdit *lineEdit = new QLineEdit(def.toString(), propertyBox);
- if (key.toLower().contains("password")) {
- lineEdit->setEchoMode(QLineEdit::Password);
- }
- widget = lineEdit;
- }
- }
- widget->setObjectName(key);
- formlayout->addRow(key + ":", widget);
- }
- propertyBox->setLayout(formlayout);
- static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, propertyBox);
- _connectionBox = propertyBox;
+ if (!_authFields[index].empty()) {
+ _fieldBox = new QGroupBox(this);
+ _fieldBox->setTitle(tr("Authentication Settings"));
+ createFieldWidgets(_fieldBox, _authFields[index]);
+ static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, _fieldBox);
}
}
/*** Storage Selection Page ***/
-StorageSelectionPage::StorageSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent)
- : QWizardPage(parent),
- _connectionBox(0),
- _backends(backends)
+StorageSelectionPage::StorageSelectionPage(const QVariantList &backendInfos, QWidget *parent)
+ : QWizardPage(parent)
{
ui.setupUi(this);
setTitle(tr("Select Storage Backend"));
- setSubTitle(tr("Please select a database backend for the Quassel Core storage to store the backlog and other data in."));
+ setSubTitle(tr("Please select a storage backend for Quassel Core."));
setCommitPage(true);
registerField("storage.backend", ui.backendList);
- int defaultIndex = 0;
- foreach(QString key, _backends.keys()) {
- ui.backendList->addItem(_backends[key].toMap()["DisplayName"].toString(), key);
- if (_backends[key].toMap()["IsDefault"].toBool()) {
- defaultIndex = ui.backendList->count() - 1;
+ int defaultIndex {0}; // Legacy cores send backend infos in arbitrary order
+
+ for (auto &&backendInfo : backendInfos) {
+ auto props = backendInfo.toMap();
+ // Extract field infos to avoid having to reparse the list
+ std::vector<FieldInfo> fields;
+
+ // Legacy cores (prior to 0.13) didn't send SetupData for storage backends; deal with this
+ if (!props.contains("SetupData")) {
+ const auto &defaultValues = props["SetupDefaults"].toMap();
+ for (auto &&key : props["SetupKeys"].toStringList()) {
+ fields.emplace_back(std::make_tuple(key, key, defaultValues.value(key, QString{})));
+ }
+ if (props.value("IsDefault", false).toBool()) {
+ defaultIndex = ui.backendList->count();
+ }
}
+ else {
+ const auto &list = props["SetupData"].toList();
+ for (int i = 0; i + 2 < list.size(); i += 3) {
+ fields.emplace_back(std::make_tuple(list[i].toString(), list[i+1].toString(), list[i+2]));
+ }
+ props.remove("SetupData");
+ }
+ props.remove("SetupKeys");
+ props.remove("SetupDefaults");
+ // Legacy cores (prior to 0.13) don't send the BackendId property
+ if (!props.contains("BackendId"))
+ props["BackendId"] = props["DisplayName"];
+ _backendProperties.emplace_back(props);
+ _backendFields.emplace_back(std::move(fields));
+
+ // Create entry in backend selector
+ ui.backendList->addItem(props["DisplayName"].toString(), props["BackendId"].toString());
}
ui.backendList->setCurrentIndex(defaultIndex);
-
- on_backendList_currentIndexChanged();
}
}
-QString StorageSelectionPage::selectedBackend() const
+QString StorageSelectionPage::displayName() const
{
return ui.backendList->currentText();
}
-QVariantMap StorageSelectionPage::connectionProperties() const
+QString StorageSelectionPage::backend() const
{
- QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
+#if QT_VERSION >= 0x050200
+ return ui.backendList->currentData().toString();
+#else
+ return ui.backendList->itemData(ui.backendList->currentIndex()).toString();
+#endif
+}
- QVariantMap properties;
- QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
- if (!setupKeys.isEmpty()) {
- QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
- foreach(QString key, setupKeys) {
- QWidget *widget = _connectionBox->findChild<QWidget *>(key);
- QVariant def;
- if (defaults.contains(key)) {
- def = defaults[key];
- }
- switch (def.type()) {
- case QVariant::Int:
- {
- QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
- Q_ASSERT(spinbox);
- def = QVariant(spinbox->value());
- }
- break;
- default:
- {
- QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
- Q_ASSERT(lineEdit);
- def = QVariant(lineEdit->text());
- }
- }
- properties[key] = def;
- }
- }
- qDebug() << properties;
-
-// QVariantMap properties = _backends[backend].toMap()["ConnectionProperties"].toMap();
-// if(!properties.isEmpty() && _connectionBox) {
-// QVariantMap::iterator propertyIter = properties.begin();
-// while(propertyIter != properties.constEnd()) {
-// QWidget *widget = _connectionBox->findChild<QWidget *>(propertyIter.key());
-// switch(propertyIter.value().type()) {
-// case QVariant::Int:
-// {
-// QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
-// Q_ASSERT(spinbox);
-// propertyIter.value() = QVariant(spinbox->value());
-// }
-// break;
-// default:
-// {
-// QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
-// Q_ASSERT(lineEdit);
-// propertyIter.value() = QVariant(lineEdit->text());
-// }
-// }
-// propertyIter++;
-// }
-// }
- return properties;
+
+QVariantMap StorageSelectionPage::backendProperties() const
+{
+ return propertiesFromFieldWidgets(_fieldBox, _backendFields[ui.backendList->currentIndex()]);
}
-void StorageSelectionPage::on_backendList_currentIndexChanged()
+void StorageSelectionPage::on_backendList_currentIndexChanged(int index)
{
- QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
- ui.description->setText(_backends[backend].toMap()["Description"].toString());
+ ui.description->setText(_backendProperties[index]["Description"].toString());
- if (_connectionBox) {
- layout()->removeWidget(_connectionBox);
- _connectionBox->deleteLater();
- _connectionBox = 0;
+ if (_fieldBox) {
+ layout()->removeWidget(_fieldBox);
+ _fieldBox->deleteLater();
+ _fieldBox = nullptr;
}
-
- QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
- if (!setupKeys.isEmpty()) {
- QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
- QGroupBox *propertyBox = new QGroupBox(this);
- propertyBox->setTitle(tr("Connection Properties"));
- QFormLayout *formlayout = new QFormLayout;
-
- foreach(QString key, setupKeys) {
- QWidget *widget = 0;
- QVariant def;
- if (defaults.contains(key)) {
- def = defaults[key];
- }
- switch (def.type()) {
- case QVariant::Int:
- {
- QSpinBox *spinbox = new QSpinBox(propertyBox);
- spinbox->setMaximum(64000);
- spinbox->setValue(def.toInt());
- widget = spinbox;
- }
- break;
- default:
- {
- QLineEdit *lineEdit = new QLineEdit(def.toString(), propertyBox);
- if (key.toLower().contains("password")) {
- lineEdit->setEchoMode(QLineEdit::Password);
- }
- widget = lineEdit;
- }
- }
- widget->setObjectName(key);
- formlayout->addRow(key + ":", widget);
- }
- propertyBox->setLayout(formlayout);
- static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, propertyBox);
- _connectionBox = propertyBox;
+ if (!_backendFields[index].empty()) {
+ _fieldBox = new QGroupBox(this);
+ _fieldBox->setTitle(tr("Storage Settings"));
+ createFieldWidgets(_fieldBox, _backendFields[index]);
+ static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, _fieldBox);
}
}
{
ui.setupUi(this);
setTitle(tr("Storing Your Settings"));
- setSubTitle(tr("Your settings are now stored in the core, and you will be logged in automatically."));
+ setSubTitle(tr("Your settings are now being stored in the core, and you will be logged in automatically."));
}
void SyncPage::initializePage()
{
- complete = false;
- hasError = false;
+ _complete = false;
+ _hasError = false;
+ emit completeChanged();
// Fill in sync info about the storage layer.
StorageSelectionPage *storagePage = qobject_cast<StorageSelectionPage *>(wizard()->page(CoreConfigWizard::StorageSelectionPage));
- QString backend = storagePage->selectedBackend();
- QVariantMap properties = storagePage->connectionProperties();
- Q_ASSERT(!backend.isEmpty());
- ui.backend->setText(backend);
+ QString backend = storagePage->backend();
+ QVariantMap backendProperties = storagePage->backendProperties();
+ ui.backend->setText(storagePage->displayName());
// Fill in sync info about the authentication layer.
AuthenticationSelectionPage *authPage = qobject_cast<AuthenticationSelectionPage *>(wizard()->page(CoreConfigWizard::AuthenticationSelectionPage));
- QString authenticator = authPage->selectedBackend();
+ QString authenticator = authPage->authenticator();
QVariantMap authProperties = authPage->authProperties();
- Q_ASSERT(!authenticator.isEmpty());
- ui.authenticator->setText(authenticator);
+ ui.authenticator->setText(authPage->displayName());
ui.user->setText(wizard()->field("adminUser.user").toString());
- emit setupCore(backend, properties, authenticator, authProperties);
+ emit setupCore(backend, backendProperties, authenticator, authProperties);
}
int SyncPage::nextId() const
{
- if (!hasError) return -1;
+ if (!_hasError)
+ return -1;
return CoreConfigWizard::SyncRelayPage;
}
bool SyncPage::isComplete() const
{
- return complete;
+ return _complete || _hasError;
}
void SyncPage::setError(bool e)
{
- hasError = e;
+ _hasError = e;
+ setFinalPage(!e);
+ emit completeChanged();
}
void SyncPage::setComplete(bool c)
{
- complete = c;
+ _complete = c;
completeChanged();
}
mode = m;
}
-
-/*
-void SyncRelayPage::initializePage() {
- return;
- if(mode == Success) {
- wizard()->accept();
- } else {
- emit startOver();
- }
-}
-*/
-
int SyncRelayPage::nextId() const
{
emit startOver();
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
-#ifndef _CORECONFIGWIZARD_H_
-#define _CORECONFIGWIZARD_H_
+#pragma once
+
+#include <tuple>
+#include <vector>
-#include <QHash>
#include <QWizard>
#include <QVariantMap>
ConclusionPage
};
- CoreConfigWizard(CoreConnection *connection, const QList<QVariant> &backends, const QList<QVariant> &authenticators, QWidget *parent = 0);
- QHash<QString, QVariant> backends() const;
- QHash<QString, QVariant> authenticators() const;
+ CoreConfigWizard(CoreConnection *connection, const QVariantList &backendInfos, const QVariantList &authInfos, QWidget *parent = 0);
inline CoreConnection *coreConnection() const { return _connection; }
void startOver();
private:
- QHash<QString, QVariant> _backends;
- QHash<QString, QVariant> _authenticators;
-
CoreConfigWizardPages::SyncPage *syncPage;
CoreConfigWizardPages::SyncRelayPage *syncRelayPage;
class AuthenticationSelectionPage : public QWizardPage
{
Q_OBJECT
+ using FieldInfo = std::tuple<QString, QString, QVariant>;
public:
- AuthenticationSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent = 0);
+ AuthenticationSelectionPage(const QVariantList &authInfos, QWidget *parent = 0);
int nextId() const;
- QString selectedBackend() const;
+ QString displayName() const;
+ QString authenticator() const;
QVariantMap authProperties() const;
private slots:
- void on_backendList_currentIndexChanged();
+ void on_backendList_currentIndexChanged(int index);
+
private:
Ui::CoreConfigWizardAuthenticationSelectionPage ui;
- QGroupBox *_connectionBox;
- QHash<QString, QVariant> _backends;
+ QGroupBox *_fieldBox {nullptr};
+ std::vector<QVariantMap> _authProperties;
+ std::vector<std::vector<FieldInfo>> _authFields;
};
class StorageSelectionPage : public QWizardPage
{
Q_OBJECT
+ using FieldInfo = std::tuple<QString, QString, QVariant>;
public:
- StorageSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent = 0);
+ StorageSelectionPage(const QVariantList &backendInfos, QWidget *parent = 0);
int nextId() const;
- QString selectedBackend() const;
- QVariantMap connectionProperties() const;
+ QString displayName() const;
+ QString backend() const;
+ QVariantMap backendProperties() const;
private slots:
- void on_backendList_currentIndexChanged();
+ void on_backendList_currentIndexChanged(int index);
+
private:
Ui::CoreConfigWizardStorageSelectionPage ui;
- QGroupBox *_connectionBox;
- QHash<QString, QVariant> _backends;
+ QGroupBox *_fieldBox {nullptr};
+ std::vector<QVariantMap> _backendProperties;
+ std::vector<std::vector<FieldInfo>> _backendFields;
};
class SyncPage : public QWizardPage
private:
Ui::CoreConfigWizardSyncPage ui;
- bool complete;
- bool hasError;
+ bool _complete {false};
+ bool _hasError {false};
};
Mode mode;
};
}
-
-#endif
-<ui version="4.0" >
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
<class>CoreConfigWizardAuthenticationSelectionPage</class>
- <widget class="QWidget" name="CoreConfigWizardAuthenticationSelectionPage" >
- <property name="geometry" >
+ <widget class="QWidget" name="CoreConfigWizardAuthenticationSelectionPage">
+ <property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<height>168</height>
</rect>
</property>
- <property name="windowTitle" >
+ <property name="windowTitle">
<string>Form</string>
</property>
- <layout class="QVBoxLayout" >
+ <layout class="QVBoxLayout">
<item>
- <layout class="QHBoxLayout" >
+ <layout class="QHBoxLayout">
<item>
- <widget class="QLabel" name="label" >
- <property name="text" >
+ <widget class="QLabel" name="label">
+ <property name="text">
<string>Authentication Backend:</string>
</property>
</widget>
</item>
<item>
- <widget class="QComboBox" name="backendList" >
- <property name="sizePolicy" >
- <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <widget class="QComboBox" name="backendList">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="insertPolicy" >
+ <property name="insertPolicy">
<enum>QComboBox::InsertAtBottom</enum>
</property>
</widget>
</item>
<item>
<spacer>
- <property name="orientation" >
+ <property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
- <property name="sizeHint" stdset="0" >
+ <property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</layout>
</item>
<item>
- <widget class="QGroupBox" name="descriptionBox" >
- <property name="title" >
+ <widget class="QGroupBox" name="descriptionBox">
+ <property name="title">
<string>Description</string>
</property>
- <layout class="QVBoxLayout" >
+ <layout class="QVBoxLayout">
<item>
- <widget class="QLabel" name="description" >
- <property name="text" >
- <string>Foobar</string>
+ <widget class="QLabel" name="description">
+ <property name="text">
+ <string notr="true">Foobar</string>
</property>
- <property name="alignment" >
+ <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
- <property name="wordWrap" >
+ <property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
<item>
- <spacer name="verticalSpacer" >
- <property name="orientation" >
+ <spacer name="verticalSpacer">
+ <property name="orientation">
<enum>Qt::Vertical</enum>
</property>
- <property name="sizeHint" stdset="0" >
+ <property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
-<ui version="4.0" >
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
<class>CoreConfigWizardStorageSelectionPage</class>
- <widget class="QWidget" name="CoreConfigWizardStorageSelectionPage" >
- <property name="geometry" >
+ <widget class="QWidget" name="CoreConfigWizardStorageSelectionPage">
+ <property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<height>168</height>
</rect>
</property>
- <property name="windowTitle" >
+ <property name="windowTitle">
<string>Form</string>
</property>
- <layout class="QVBoxLayout" >
+ <layout class="QVBoxLayout">
<item>
- <layout class="QHBoxLayout" >
+ <layout class="QHBoxLayout">
<item>
- <widget class="QLabel" name="label" >
- <property name="text" >
+ <widget class="QLabel" name="label">
+ <property name="text">
<string>Storage Backend:</string>
</property>
</widget>
</item>
<item>
- <widget class="QComboBox" name="backendList" >
- <property name="sizePolicy" >
- <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <widget class="QComboBox" name="backendList">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="insertPolicy" >
+ <property name="insertPolicy">
<enum>QComboBox::InsertAtBottom</enum>
</property>
</widget>
</item>
<item>
<spacer>
- <property name="orientation" >
+ <property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
- <property name="sizeHint" stdset="0" >
+ <property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</layout>
</item>
<item>
- <widget class="QGroupBox" name="descriptionBox" >
- <property name="title" >
+ <widget class="QGroupBox" name="descriptionBox">
+ <property name="title">
<string>Description</string>
</property>
- <layout class="QVBoxLayout" >
+ <layout class="QVBoxLayout">
<item>
- <widget class="QLabel" name="description" >
- <property name="text" >
- <string>Foobar</string>
+ <widget class="QLabel" name="description">
+ <property name="text">
+ <string notr="true">Foobar</string>
</property>
- <property name="alignment" >
+ <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
- <property name="wordWrap" >
+ <property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
<item>
- <spacer name="verticalSpacer" >
- <property name="orientation" >
+ <spacer name="verticalSpacer">
+ <property name="orientation">
<enum>Qt::Vertical</enum>
</property>
- <property name="sizeHint" stdset="0" >
+ <property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
-<ui version="4.0" >
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
<class>CoreConfigWizardSyncPage</class>
- <widget class="QWidget" name="CoreConfigWizardSyncPage" >
- <property name="geometry" >
+ <widget class="QWidget" name="CoreConfigWizardSyncPage">
+ <property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<height>300</height>
</rect>
</property>
- <property name="windowTitle" >
+ <property name="windowTitle">
<string>Form</string>
</property>
- <layout class="QVBoxLayout" >
+ <layout class="QVBoxLayout">
<item>
- <widget class="QGroupBox" name="groupBox" >
- <property name="title" >
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
<string>Your Choices</string>
</property>
- <layout class="QVBoxLayout" >
+ <layout class="QVBoxLayout">
<item>
- <layout class="QHBoxLayout" >
+ <layout class="QHBoxLayout">
<item>
- <layout class="QGridLayout" >
- <item row="0" column="0" >
- <widget class="QLabel" name="label" >
- <property name="font" >
+ <layout class="QGridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
- <property name="text" >
+ <property name="text">
<string>Admin User:</string>
</property>
</widget>
</item>
- <item row="0" column="1" >
- <widget class="QLabel" name="user" >
- <property name="text" >
- <string>foo</string>
+ <item row="0" column="1">
+ <widget class="QLabel" name="user">
+ <property name="text">
+ <string notr="true">foo</string>
</property>
</widget>
</item>
- <item row="1" column="0" >
- <widget class="QLabel" name="label_2" >
- <property name="font" >
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
- <property name="text" >
+ <property name="text">
<string>Storage Backend:</string>
</property>
</widget>
</item>
- <item row="1" column="1" >
- <widget class="QLabel" name="backend" >
- <property name="text" >
- <string>bar</string>
+ <item row="1" column="1">
+ <widget class="QLabel" name="backend">
+ <property name="text">
+ <string notr="true">bar</string>
</property>
</widget>
</item>
- <item row="2" column="0" >
- <widget class="QLabel" name="label_3" >
- <property name="font" >
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
- <property name="text" >
+ <property name="text">
<string>Authentication Backend:</string>
</property>
</widget>
</item>
- <item row="2" column="1" >
- <widget class="QLabel" name="authenticator" >
- <property name="text" >
- <string>bar</string>
+ <item row="2" column="1">
+ <widget class="QLabel" name="authenticator">
+ <property name="text">
+ <string notr="true">bar</string>
</property>
</widget>
</item>
</item>
<item>
<spacer>
- <property name="orientation" >
+ <property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
- <property name="sizeHint" >
+ <property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</item>
<item>
<spacer>
- <property name="orientation" >
+ <property name="orientation">
<enum>Qt::Vertical</enum>
</property>
- <property name="sizeHint" >
+ <property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</spacer>
</item>
<item>
- <widget class="QLabel" name="status" >
- <property name="text" >
+ <widget class="QLabel" name="status">
+ <property name="text">
<string>Please wait while your settings are being transmitted to the core...</string>
</property>
- <property name="alignment" >
+ <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
- <property name="wordWrap" >
+ <property name="wordWrap">
<bool>true</bool>
</property>
</widget>