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