blob: bc9154d75953b847c28476730a3af38315fd4d52 [file] [log] [blame]
/***************************************************************************
* Copyright (C) 2015-2016 by Savoir-faire Linux *
* Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#include "accountserializationadapter.h"
#include <QtWidgets/QWidget>
#include <QtWidgets/QLayout>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QSpinBox>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QAbstractButton>
#include <QtWidgets/QLabel>
#include <account.h>
#include <accountmodel.h>
constexpr static const char LRC_CFG[] = "lrcfg_";
constexpr static const int LRC_CFG_LEN = 6 ;
struct ConnHolder {
QMetaObject::Connection c;
~ConnHolder();
};
Q_DECLARE_METATYPE(ConnHolder*);
ConnHolder::~ConnHolder()
{
QObject::disconnect(c);
}
static void avoidDuplicate(QWidget* w)
{
if (qvariant_cast<ConnHolder*>(w->property("lrcfgConn")))
delete qvariant_cast<ConnHolder*>(w->property("lrcfgConn"));
}
/**
* This check for some supported widgets and bind the widgets and property
*/
static void setupWidget(QWidget* w, Account* a, const QHash<QByteArray, int>& roles)
{
if (w->objectName().left(LRC_CFG_LEN) == LRC_CFG) {
const QByteArray prop = w->objectName().mid(LRC_CFG_LEN, 999).toLatin1();
if (roles.contains(prop)) {
const int role = roles[prop];
if (qobject_cast<QLineEdit*>(w)) {
QLineEdit* le = qobject_cast<QLineEdit*>(w);
avoidDuplicate(le);
le->setText(a->roleData(role).toString());
ConnHolder* c = new ConnHolder {
QObject::connect(le, &QLineEdit::textChanged, [a,role](const QString& text) {
if (a->roleData(role) != text)
a->setRoleData(role, text);
})
};
le->setProperty("lrcfgConn",QVariant::fromValue(c));
}
else if (qobject_cast<QSpinBox*>(w)) {
QSpinBox* sb = qobject_cast<QSpinBox*>(w);
avoidDuplicate(sb);
sb->setValue(a->roleData(role).toInt());
ConnHolder* c = new ConnHolder {
QObject::connect(sb, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [a,role](int value) {
if (a->roleData(role).toInt() != value)
a->setRoleData(role, value);
})
};
sb->setProperty("lrcfgConn",QVariant::fromValue(c));
}
else if (qobject_cast<QAbstractButton*>(w)) {
//QCheckBox, QRadioButton, QToolButton, QPushButton
QAbstractButton* b = qobject_cast<QAbstractButton*>(w);
avoidDuplicate(b);
b->setChecked(a->roleData(role).toBool());
ConnHolder* c = new ConnHolder {
QObject::connect(b, &QAbstractButton::toggled,[a,role](bool c) {
if (a->roleData(role).toBool() != c)
a->setRoleData(role, c);
})
};
b->setProperty("lrcfgConn",QVariant::fromValue(c));
}
else if (qobject_cast<QGroupBox*>(w)) {
QGroupBox* b = qobject_cast<QGroupBox*>(w);
avoidDuplicate(b);
b->setChecked(a->roleData(role).toBool());
ConnHolder* c = new ConnHolder {
QObject::connect(b, &QGroupBox::toggled,[a,role](bool c) {
if (a->roleData(role).toBool() != c)
a->setRoleData(role, c);
})
};
b->setProperty("lrcfgConn",QVariant::fromValue(c));
}
else {
qDebug() << "Unsupported widget type" << w;
}
//Check if the field is required for this account type
if (a->roleState((Account::Role)role) == Account::RoleState::UNAVAILABLE) {
w->setProperty("lrcfgVisible", w->isVisible() ? 2 : 1);
w->setVisible(false);
QFormLayout* fm = qobject_cast<QFormLayout*>(w->parentWidget()->layout());
//There is many of corner case here, this only handle the one that's
//created by Qt Designer
if (!fm) {
QLayoutItem* il = w->parentWidget()->layout()->itemAt(0);
if (il && il->layout())
fm = qobject_cast<QFormLayout*>(il->layout());
}
if (fm) {
QWidget* buddy = fm->labelForField(w);
qDebug() << "BUDDY " << buddy;
if (buddy)
buddy->setVisible(false);
}
}
else {
//0 = unset, 1=invisible, 2=visible
const int oldVisibleState = w->property("lrcfgVisible").toInt();
if (oldVisibleState)
w->setVisible(oldVisibleState-1);
}
}
else {
qWarning() << "Unknown config properties" << w->objectName();
}
}
}
static void clearConnections(QWidget* w)
{
if (w->objectName().left(LRC_CFG_LEN) == LRC_CFG) {
avoidDuplicate(w);
}
}
static void drill(QWidget* w, Account* a, const QHash<QByteArray, int>& roles, bool clear = false)
{
for (QObject *object : w->children()) {
if (!object->isWidgetType())
continue;
QWidget* w2 = static_cast<QWidget*>(object);
if (clear)
clearConnections(w2);
else
setupWidget(w2, a, roles);
drill(w2, a, roles);
}
}
static void hideLabel(QWidget* w) {
for (QObject *object : w->children()) {
if (!object->isWidgetType())
continue;
QWidget* w2 = qobject_cast<QWidget*>(object);
if (w2) {
QLabel* l = qobject_cast<QLabel*>(w2);
if (l && l->buddy()) {
l->setVisible(!l->buddy()->isHidden());
}
}
hideLabel(w2);
}
}
AccountSerializationAdapter::AccountSerializationAdapter(Account* a, QWidget* w) : QObject(w)
{
static QHash<QByteArray, int> reverse;
if (reverse.isEmpty()) {
const QHash<int, QByteArray> a = AccountModel::instance().roleNames();
for (QHash<int, QByteArray>::const_iterator i = a.begin(); i != a.end(); ++i) {
reverse[i.value()] = i.key();
}
}
drill(w, a, reverse);
hideLabel(w);
}
AccountSerializationAdapter::~AccountSerializationAdapter()
{
}