1 /* Copyright (c) 2015 Gerald Knizia 2 * 3 * This file is part of the IboView program (see: http://www.iboview.org) 4 * 5 * IboView is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, version 3. 8 * 9 * IboView is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with bfint (LICENSE). If not, see http://www.gnu.org/licenses/ 16 * 17 * Please see IboView documentation in README.txt for: 18 * -- A list of included external software and their licenses. The included 19 * external software's copyright is not touched by this agreement. 20 * -- Notes on re-distribution and contributions to/further development of 21 * the IboView software 22 */ 23 24 // QPropertyModel 25 // - a class for easily turning any QObject-derived subclass with properties into a one-row model 26 // 27 // Copyright 2013 - Harvey Chapman <hchapman@3gfp.com> 28 // Source: https://gist.github.com/sr105/7955969 29 // License: 30 // This work is licensed under the Creative Commons Attribution-ShareAlike 31 // 4.0 International License. To view a copy of this license, visit 32 // http://creativecommons.org/licenses/by-sa/4.0/deed.en_US. 33 // 34 // It's not required, but I'd appreciate it if any improvements were e-mailed 35 // back to me so I can share them with others. This code is specifically not 36 // GPL-like so you can use it commercially without worrying about it tainting 37 // the rest of your proprietary code. 38 // -- Harvey 39 40 // Notes by cgk: 41 // - Taken from https://gist.github.com/sr105/7955969 42 // - See also: http://stackoverflow.com/questions/18793735/connect-a-signal-to-the-slot-of-a-qmetaproperty 43 // (which is what I originally wanted to do, but failed to find a viable way, just as the 44 // author of that question) 45 // - Various slight changes (in particular, un-staticify the property name list/map) 46 47 #ifndef QPROPERTYMODEL_H 48 #define QPROPERTYMODEL_H 49 50 #include <QAbstractItemModel> 51 #include <QStringList> 52 #include <QDataWidgetMapper> 53 #include <QMap> 54 #include <QMetaProperty> 55 56 void LinkPropertyWidgets(QObject *pTarget, QWidget *pWidgetContainer, char const *pPropertyKeyName); 57 58 class QPropertyModel; 59 60 // Convenience class that exposes the public methods of QPropertyModel 61 // without requiring casting. 62 class QPropertyDataWidgetMapper : public QDataWidgetMapper 63 { 64 Q_OBJECT 65 public: QDataWidgetMapper(parent)66 QPropertyDataWidgetMapper(QObject *parent = 0) : QDataWidgetMapper(parent) {} 67 68 // QDataWidgetMapper::model() re-written to return QPropertyDataWidgetMapper 69 QPropertyModel *model() const; 70 // For convenience, these automatically convert "property" into column numbers 71 void addMapping(QWidget *widget, QString property); 72 void addMapping(QWidget *widget, QString property, const QByteArray &propertyName); 73 // Pass-thru methods to QDataWidgetMapper 74 void addMapping(QWidget *widget, int section); 75 void addMapping(QWidget *widget, int section, const QByteArray &propertyName); 76 }; 77 78 // QPropertyModel creates a single row data model consisting of columns mapping 79 // to properties in a QObject. The column list can be retrieved as a QStringList, 80 // and a method exists to convert the property names to column numbers. 81 class QPropertyModel : public QAbstractItemModel 82 { 83 Q_OBJECT 84 public: 85 explicit QPropertyModel(QObject *source, QObject *parent = 0); 86 ~QPropertyModel(); 87 88 // Return a QPropertyDataWidgetMapper wrapping a new instance of this class. 89 static QPropertyDataWidgetMapper *newMapper(QObject *source, QObject *parent = 0); 90 // Return a QPropertyDataWidgetMapper wrapping this existing instance 91 QPropertyDataWidgetMapper *newMapper(); 92 93 QStringList propertyNames() const; 94 int columnForProperty(QString name) const; 95 QMap<int, QMetaProperty> properties() const; 96 97 protected: 98 void connectToPropertyNotifySignals(); 99 100 // Pointer to our data source 101 QObject *_source; 102 103 mutable QStringList _names; 104 mutable QMap<int, QMetaProperty> _properties; 105 protected slots: 106 void columnChanged(int column); 107 108 // Required virtual function implementations. They mostly map 109 // directly to the (getItem/setItem/itemChanged) methods above. 110 public: 111 // read & write data 112 virtual QVariant data(const QModelIndex &index, int role) const; 113 virtual bool setData(const QModelIndex &index, const QVariant &value, int role); 114 115 // returns the number of properties in _source 116 virtual int columnCount(const QModelIndex &parent) const; 117 118 // all hard-coded simple implementations 119 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 120 virtual Qt::ItemFlags flags(const QModelIndex &index) const; 121 virtual QModelIndex parent(const QModelIndex &child) const; 122 virtual QModelIndex index(int row, int column, const QModelIndex &) const; 123 124 // Helper method to make virtual methods easier to code 125 virtual bool hasIndex(const QModelIndex &index) const; 126 }; 127 128 129 // Until we can come up with something more clever, this little class allows 130 // us to connect each signal in a single QObject to a single slot using 131 // QSignalMapper to pass information to us about which signal was sent. 132 // QSignalMapper maps Objects to data. All of our signals come from the same 133 // object, so that won't work. However, if we create a SignalObject as a 134 // forwareder for each signal, now we have a unique object for each signal 135 // that QSignalMapper can work with. 136 class SignalForwarder: public QObject 137 { 138 Q_OBJECT 139 public: QObject(parent)140 SignalForwarder(QObject *parent = 0) : QObject(parent) {} 141 signals: 142 void forward(); 143 }; 144 145 #endif // QPROPERTYMODEL_H 146