1 /***************************************************************************
2  *   This file is part of the Lime Report project                          *
3  *   Copyright (C) 2015 by Alexander Arin                                  *
4  *   arin_a@bk.ru                                                          *
5  *                                                                         *
6  **                   GNU General Public License Usage                    **
7  *                                                                         *
8  *   This library is free software: you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation, either version 3 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *   You should have received a copy of the GNU General Public License     *
13  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
14  *                                                                         *
15  **                  GNU Lesser General Public License                    **
16  *                                                                         *
17  *   This library is free software: you can redistribute it and/or modify  *
18  *   it under the terms of the GNU Lesser General Public License as        *
19  *   published by the Free Software Foundation, either version 3 of the    *
20  *   License, or (at your option) any later version.                       *
21  *   You should have received a copy of the GNU Lesser General Public      *
22  *   License along with this library.                                      *
23  *   If not, see <http://www.gnu.org/licenses/>.                           *
24  *                                                                         *
25  *   This library is distributed in the hope that it will be useful,       *
26  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
27  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
28  *   GNU General Public License for more details.                          *
29  ****************************************************************************/
30 #include "lrobjectitemmodel.h"
31 #include <QMetaProperty>
32 #include <QPainter>
33 #include <QDebug>
34 #include <QMessageBox>
35 
36 namespace LimeReport {
37 
translatePropertyName()38 void QObjectPropertyModel::translatePropertyName()
39 {
40     tr("leftMargin");
41     tr("rightMargin");
42     tr("topMargin");
43     tr("bottomMargin");
44     tr("objectName");
45     tr("borders");
46     tr("geometry");
47     tr("itemAlign");
48     tr("pageOrientation");
49     tr("pageSize");
50     tr("TopLine");
51     tr("BottomLine");
52     tr("LeftLine");
53     tr("RightLine");
54     tr("reprintOnEachPage");
55     tr("borderLineSize");
56     tr("autoHeight");
57     tr("backgroundColor");
58     tr("columnCount");
59     tr("columnsFillDirection");
60     tr("datasource");
61     tr("keepBottomSpace");
62     tr("keepFooterTogether");
63     tr("keepSubdetailTogether");
64     tr("printIfEmpty");
65     tr("sliceLastRow");
66     tr("splittable");
67     tr("alignment");
68     tr("angle");
69     tr("autoWidth");
70     tr("backgroundMode");
71     tr("backgroundOpacity");
72     tr("content");
73     tr("font");
74     tr("fontColor");
75     tr("foregroundOpacity");
76     tr("itemLocation");
77     tr("margin");
78     tr("stretchToMaxHeight");
79     tr("trimValue");
80     tr("lineWidth");
81     tr("opacity");
82     tr("penStyle");
83     tr("shape");
84     tr("shapeBrush");
85     tr("shapeBrushColor");
86     tr("gridStep");
87     tr("fullPage");
88     tr("oldPrintMode");
89     tr("borderColor");
90     tr("resetPageNumber");
91     tr("alternateBackgroundColor");
92     tr("backgroundBrushStyle");
93     tr("columnCount");
94     tr("startFromNewPage");
95     tr("startNewPage");
96     tr("adaptFontToSize");
97     tr("allowHTML");
98     tr("allowHTMLInFields");
99     tr("backgroundBrushStyle");
100     tr("followTo");
101     tr("format");
102     tr("lineSpacing");
103     tr("textIndent");
104     tr("textLayoutDirection");
105     tr("underlineLineSize");
106     tr("underlines");
107     tr("valueType");
108     tr("securityLevel");
109     tr("testValue");
110     tr("whitespace");
111     tr("resourcePath");
112     tr("scale");
113     tr("cornerRadius");
114     tr("shapeColor");
115     tr("layoutType");
116     tr("barcodeType");
117     tr("barcodeHeight");
118     tr("foregroundColor");
119     tr("inputMode");
120     tr("pdf417CodeWords");
121     tr("autoSize");
122     tr("center");
123     tr("field");
124     tr("image");
125     tr("keepAspectRatio");
126     tr("columnsCount");
127     tr("useAlternateBackgroundColor");
128     tr("printBeforePageHeader");
129     tr("maxScalePercent");
130     tr("printOnFirstPage");
131     tr("printOnLastPage");
132     tr("printAlways");
133     tr("repeatOnEachRow");
134     tr("condition");
135     tr("groupFieldName");
136     tr("keepGroupTogether");
137     tr("endlessHeight");
138     tr("extendedHeight");
139     tr("isExtendedInDesignMode");
140     tr("pageIsTOC");
141     tr("setPageSizeToPrinter");
142     tr("fillInSecondPass");
143     tr("chartTitle");
144     tr("chartType");
145     tr("drawLegendBorder");
146     tr("labelsField");
147     tr("legendAlign");
148     tr("series");
149     tr("titleAlign");
150     tr("watermark");
151     tr("keepTopSpace");
152     tr("printable");
153     tr("variable");
154     tr("replaceCRwithBR");
155     tr("hideIfEmpty");
156     tr("hideEmptyItems");
157 	tr("useExternalPainter");
158     tr("layoutSpacing");
159     tr("printerName");
160     tr("fontLetterSpacing");
161     tr("hideText");
162     tr("option3");
163     tr("units");
164     tr("geometryLocked");
165     tr("printBehavior");
166     tr("shiftItems");
167 }
168 
clearObjectsList()169 void QObjectPropertyModel::clearObjectsList()
170 {
171     m_objects.clear();
172 }
173 
QObjectPropertyModel(QObject * parent)174 QObjectPropertyModel::QObjectPropertyModel(QObject *parent/*=0*/)
175     :QAbstractItemModel(parent),m_rootNode(0), m_object(0), m_dataChanging(false),
176      m_subclassesAsLevel(true), m_validator(0), m_translateProperties(true)
177 {}
178 
~QObjectPropertyModel()179 QObjectPropertyModel::~QObjectPropertyModel()
180 {
181     delete m_rootNode;
182 }
183 
initModel()184 void QObjectPropertyModel::initModel()
185 {
186     beginResetModel();
187     delete m_rootNode;
188     m_rootNode=0;
189     if (m_object) {
190         connect(m_object,SIGNAL(destroyed(QObject*)),this,SLOT(slotObjectDestroyed(QObject*)));
191         m_rootNode=new ObjectPropItem(0,0,"root","root",QVariant(),0);
192         m_rootNode->setModel(this);
193         foreach(QObject* item, m_objects)
194             connect(item,SIGNAL(destroyed(QObject*)),this,SLOT(slotObjectDestroyed(QObject*)));
195         addObjectProperties(m_object->metaObject(), m_object, &m_objects);
196     }
197     endResetModel();
198 }
199 
setObject(QObject * object)200 void QObjectPropertyModel::setObject(QObject *object)
201 {
202     m_objects.clear();
203     if (m_object!=object){
204         submit();
205         m_object=object;
206         initModel();
207     }
208 }
209 
setMultiObjects(QList<QObject * > * list)210 void QObjectPropertyModel::setMultiObjects(QList<QObject *>* list)
211 {
212     m_objects.clear();
213     submit();
214 
215     if (!list->contains(m_object)){
216         m_object=list->at(0);
217         list->removeAt(0);
218     } else {
219         list->removeOne(m_object);
220     }
221 
222     foreach(QObject* item, *list)
223         m_objects.append(item);
224     //initModel();
225 }
226 
slotObjectDestroyed(QObject * obj)227 void QObjectPropertyModel::slotObjectDestroyed(QObject *obj)
228 {
229     m_objects.removeOne(obj);
230     if (m_object == obj){
231        m_object=0;
232        initModel();
233     }
234 }
235 
slotPropertyChanged(const QString & propertyName,const QVariant & oldValue,const QVariant & newValue)236 void QObjectPropertyModel::slotPropertyChanged(const QString &propertyName, const QVariant& oldValue, const QVariant& newValue)
237 {
238     Q_UNUSED(oldValue);
239     Q_UNUSED(newValue);
240     if (m_object)
241         updateProperty(propertyName);
242 }
243 
slotPropertyObjectNameChanged(const QString & oldName,const QString & newName)244 void QObjectPropertyModel::slotPropertyObjectNameChanged(const QString &oldName, const QString &newName)
245 {
246     Q_UNUSED(oldName)
247     Q_UNUSED(newName)
248     if (m_object)
249         updateProperty("objectName");
250 }
251 
252 
columnCount(const QModelIndex &) const253 int QObjectPropertyModel::columnCount(const QModelIndex &/*parent*/) const
254 {
255     return 2;
256 }
257 
headerData(int section,Qt::Orientation orientation,int role) const258 QVariant QObjectPropertyModel::headerData(int section, Qt::Orientation orientation, int role) const
259 {
260     if(orientation==Qt::Horizontal&&role==Qt::DisplayRole){
261         if (section==0) return tr("Property Name");
262         else return tr("Property value");
263     } else return QVariant();
264 }
265 
nodeFromIndex(const QModelIndex & index) const266 ObjectPropItem * QObjectPropertyModel::nodeFromIndex(const QModelIndex &index) const
267 {
268     if(index.isValid()){
269         return static_cast<ObjectPropItem*>(index.internalPointer());
270     } else return m_rootNode;
271 }
272 
updateProperty(const QString & propertyName)273 void QObjectPropertyModel::updateProperty(const QString &propertyName)
274 {
275     if (!m_dataChanging&&m_rootNode){
276         ObjectPropItem* propItem = m_rootNode->findPropertyItem(propertyName);
277         if (propItem)
278            propItem->updatePropertyValue();
279     }
280 }
281 
setSubclassesAsLevel(bool value)282 void QObjectPropertyModel::setSubclassesAsLevel(bool value)
283 {
284     m_subclassesAsLevel = value;
285 }
286 
rowCount(const QModelIndex & parent) const287 int QObjectPropertyModel::rowCount(const QModelIndex &parent) const
288 {
289     if (!m_rootNode) return 0;
290     ObjectPropItem *parentNode;
291     if (parent.isValid())
292         parentNode = nodeFromIndex(parent);
293     else
294         parentNode = m_rootNode;
295     return parentNode->childCount();
296 }
297 
data(const QModelIndex & index,int role) const298 QVariant QObjectPropertyModel::data(const QModelIndex &index, int role) const
299 {
300     ObjectPropItem *node = nodeFromIndex(index);
301     switch (role) {
302     case Qt::DisplayRole:
303         if (!node) return QVariant();
304         node->setTranslateProperty(isTranslateProperties());
305         if (index.column()==0){
306             return node->displayName();
307         } else {
308             return node->displayValue();
309         }
310     case Qt::DecorationRole :
311         if (!node) return QIcon();
312         if (index.column()==1){
313             return node->iconValue();
314         } else return QIcon();
315     case Qt::UserRole:
316         return QVariant::fromValue(node);
317     default:
318         return QVariant();
319     }
320 }
321 
index(int row,int column,const QModelIndex & parent) const322 QModelIndex QObjectPropertyModel::index(int row, int column, const QModelIndex &parent) const
323 {
324     if(!m_rootNode)
325         return QModelIndex();
326 
327     if (!hasIndex(row, column, parent))
328         return QModelIndex();
329 
330     ObjectPropItem *parentNode;
331     if (parent.isValid())
332         parentNode = nodeFromIndex(parent);
333     else
334         parentNode = m_rootNode;
335 
336     ObjectPropItem *childItem=parentNode->child(row);
337 
338     if (childItem){
339         QModelIndex modelIndex=createIndex(row,column,childItem);
340         if (column==1){
341             if (childItem->modelIndex()!=modelIndex){
342                 childItem->setModelIndex(modelIndex);
343             }
344         }
345         return modelIndex;
346     }
347     else return QModelIndex();
348 }
349 
parent(const QModelIndex & child) const350 QModelIndex QObjectPropertyModel::parent(const QModelIndex &child) const
351 {
352     if (!child.isValid()) return QModelIndex();
353 
354     ObjectPropItem *childNode = nodeFromIndex(child);
355     if (!childNode) return QModelIndex();
356 
357     ObjectPropItem *parentNode = childNode->parent();
358     if ((parentNode == m_rootNode) || (!parentNode)) return QModelIndex();
359 
360     return createIndex(parentNode->row(),0,parentNode);
361 }
362 
363 
flags(const QModelIndex & index) const364 Qt::ItemFlags QObjectPropertyModel::flags(const QModelIndex &index) const
365 {
366     if ((index.column() == 1) && (!nodeFromIndex(index)->isValueReadonly())) return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
367     else return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
368 }
369 
propertyItemCreator(QMetaProperty prop)370 CreatePropItem QObjectPropertyModel::propertyItemCreator(QMetaProperty prop)
371 {
372     CreatePropItem creator = 0;
373     creator = ObjectPropFactory::instance().objectCreator(APropIdent(prop.name(),prop.enclosingMetaObject()->className()));
374     if (!creator){
375         if (prop.isFlagType()){
376             creator=ObjectPropFactory::instance().objectCreator(APropIdent("flags",""));
377             if (creator){
378               return creator;
379             } else {
380                 qDebug()<<"flags prop editor not found";
381                 return 0;
382             }
383         }
384         if (prop.isEnumType()){
385             creator=ObjectPropFactory::instance().objectCreator(APropIdent("enum",""));
386             if (creator){
387                 return creator;
388             } else {
389                 qDebug()<<"enum prop editor not found";
390                 return 0;
391             }
392         }
393         creator = ObjectPropFactory::instance().objectCreator(APropIdent(prop.typeName(),""));
394         if (!creator) {qDebug()<<"Editor for propperty name = \""<<prop.name()<<"\" & property type =\""<<prop.typeName()<<"\" not found!";}
395     }
396     return creator;
397 }
398 
createPropertyItem(QMetaProperty prop,QObject * object,ObjectPropItem::ObjectsList * objects,ObjectPropItem * parent)399 ObjectPropItem * QObjectPropertyModel::createPropertyItem(QMetaProperty prop, QObject *object, ObjectPropItem::ObjectsList *objects, ObjectPropItem *parent)
400 {
401     ObjectPropItem* propertyItem=0;
402     CreatePropItem creator=propertyItemCreator(prop);
403 
404     if (creator) {
405         propertyItem=creator(
406                 object,
407                 objects,
408                 QString(prop.name()),
409                 QString(tr(prop.name())),
410                 object->property(prop.name()),
411                 parent,
412                 !(prop.isWritable() && prop.isDesignable())
413              );
414     } else {
415         propertyItem=new ObjectPropItem(
416                     0,
417                     0,
418                     QString(prop.name()),
419                     QString(tr(prop.name())),
420                     object->property(prop.name()),
421                     parent
422                  );
423     }
424     return propertyItem;
425 }
426 
isTranslateProperties() const427 bool QObjectPropertyModel::isTranslateProperties() const
428 {
429     return m_translateProperties;
430 }
431 
setTranslateProperties(bool translateProperties)432 void QObjectPropertyModel::setTranslateProperties(bool translateProperties)
433 {
434     m_translateProperties = translateProperties;
435 }
validator() const436 ValidatorIntf *QObjectPropertyModel::validator() const
437 {
438     return m_validator;
439 }
440 
setValidator(ValidatorIntf * validator)441 void QObjectPropertyModel::setValidator(ValidatorIntf *validator)
442 {
443     m_validator = validator;
444 }
445 
addObjectProperties(const QMetaObject * metaObject,QObject * object,ObjectPropItem::ObjectsList * objects,int level)446 void QObjectPropertyModel::addObjectProperties(const QMetaObject *metaObject, QObject *object, ObjectPropItem::ObjectsList *objects, int level)
447 {
448     if (metaObject->propertyCount()>metaObject->propertyOffset()){
449         ObjectPropItem* objectNode;
450         if (m_subclassesAsLevel){
451             objectNode=new ObjectPropItem(0,0,metaObject->className(),metaObject->className(),m_rootNode,true);
452             m_rootNode->appendItem(objectNode);
453         } else {
454             objectNode = m_rootNode;
455         }
456 
457         for (int i=metaObject->propertyOffset();i<metaObject->propertyCount();i++){
458             if (metaObject->property(i).isDesignable()){
459                 ObjectPropItem* prop=createPropertyItem(metaObject->property(i),object,objects,objectNode);
460                 objectNode->appendItem(prop);
461             }
462         }
463         if (m_subclassesAsLevel){
464             objectNode->setColorIndex(level);
465             objectNode->sortItem();
466             level++;
467         }
468     }
469 
470     if (metaObject->superClass()) addObjectProperties(metaObject->superClass(),object,objects,level);
471     m_rootNode->sortItem();
472 }
473 
setData(const QModelIndex & index,const QVariant & value,int role)474 bool QObjectPropertyModel::setData(const QModelIndex &index, const QVariant &value, int role)
475 {
476     if (index.isValid()&&role==Qt::EditRole){
477         m_dataChanging=true;
478         ObjectPropItem * propItem = nodeFromIndex(index);
479         if (propItem->propertyValue()!=value){
480             QString msg;
481             if (validator() && !validator()->validate(propItem->propertyName(),value.toString(),m_object,msg)){
482                 QMessageBox::information(0,tr("Warning"),msg);
483                 return true;
484             }
485             QVariant oldValue=propItem->propertyValue();
486             propItem->setPropertyValue(value);
487             emit dataChanged(index,index);
488             emit objectPropetyChanged(propItem->propertyName(),oldValue,propItem->propertyValue());
489         }
490         m_dataChanging=false;
491         return true;
492     }
493     return false;
494 }
495 
itemDataChanged(const QModelIndex & index)496 void QObjectPropertyModel::itemDataChanged(const QModelIndex &index)
497 {
498     emit dataChanged(index,index);
499 }
500 
501 }
502 
503