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