/*************************************************************************** * 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() { }