Warning, file /graphics/tikzkit/src/ui/propertybrowser/PropertyBrowser.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the TikZKit project. 0002 * 0003 * Copyright (C) 2014 Dominik Haumann <dhaumann@kde.org> 0004 * 0005 * This library is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU Library General Public License as published 0007 * by the Free Software Foundation, either version 2 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, see 0017 * <http://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include "PropertyBrowser.h" 0021 #include "ValuePropertyManager.h" 0022 #include "ValueSpinBoxFactory.h" 0023 #include "OpacityEditorFactory.h" 0024 #include "OpacityPropertyManager.h" 0025 #include "UidPropertyManager.h" 0026 0027 #include <tikz/core/Uid.h> 0028 #include <tikz/core/Document.h> 0029 #include <tikz/core/Node.h> 0030 #include <tikz/core/Path.h> 0031 #include <tikz/core/Style.h> 0032 #include <tikz/core/PropertyManager.h> 0033 #include <tikz/core/UndoSetProperty.h> 0034 0035 #include <tikz/ui/View.h> 0036 #include <tikz/ui/NodeItem.h> 0037 #include <tikz/ui/PathItem.h> 0038 #include <tikz/ui/Document.h> 0039 0040 #include <QDebug> 0041 #include <QVBoxLayout> 0042 #include <QPointer> 0043 #include <QMetaProperty> 0044 0045 #include <QtTreePropertyBrowser> 0046 #include <QtDoublePropertyManager> 0047 #include <QtDoubleSpinBoxFactory> 0048 #include <QtBoolPropertyManager> 0049 #include <QtColorPropertyManager> 0050 #include <QtColorEditorFactory> 0051 0052 #include <QFile> 0053 #include <QJsonDocument> 0054 0055 tikz::core::Style * styleForItem(const tikz::core::Uid & uid) 0056 { 0057 if (! uid.isValid()) { 0058 return nullptr; 0059 } 0060 0061 auto e = uid.entity(); 0062 switch (e->entityType()) { 0063 case tikz::EntityType::Document: return qvariant_cast<tikz::core::Style*>(uid.entity()->property("style")); 0064 case tikz::EntityType::Path: return qvariant_cast<tikz::core::Uid>(uid.entity()->property("style")).entity<tikz::core::Style>(); 0065 case tikz::EntityType::Node: return qvariant_cast<tikz::core::Uid>(uid.entity()->property("style")).entity<tikz::core::Style>(); 0066 case tikz::EntityType::Style: return uid.entity<tikz::core::Style>(); 0067 } 0068 0069 return nullptr; 0070 } 0071 0072 namespace tikz { 0073 namespace ui { 0074 0075 class PropertyBrowserPrivate 0076 { 0077 public: 0078 QtTreePropertyBrowser * browser = nullptr; 0079 ValuePropertyManager * valueManager = nullptr; 0080 QtBoolPropertyManager * boolManager = nullptr; 0081 QtColorPropertyManager * colorManager = nullptr; 0082 OpacityPropertyManager * opacityManager = nullptr; 0083 QtDoublePropertyManager * doubleManager = nullptr; 0084 QtEnumPropertyManager * enumManager = nullptr; 0085 QtStringPropertyManager * stringManager = nullptr; 0086 UidPropertyManager * uidManager = nullptr; 0087 0088 QPointer<View> view = nullptr; 0089 tikz::core::Uid uid; 0090 QHash<QtProperty *, QString> propertyMap; 0091 0092 public: 0093 void addProperty(QtProperty *property, const QString & name) 0094 { 0095 Q_ASSERT(! propertyMap.contains(property)); 0096 propertyMap[property] = name; 0097 // QtBrowserItem *item = 0098 browser->addProperty(property); 0099 // browser->setExpanded(item, idToExpanded[name]); 0100 } 0101 0102 void addSubProperty(QtProperty *parent, QtProperty *property, const QString & name) 0103 { 0104 Q_ASSERT(! propertyMap.contains(property)); 0105 propertyMap[property] = name; 0106 parent->addSubProperty(property); 0107 // browser->setExpanded(item, idToExpanded[name]); 0108 } 0109 0110 void addProperty(QObject * object, const QString & name) 0111 { 0112 const auto info = tikz::core::propertyManager().info(name); 0113 0114 if (!info.isValid()) { 0115 qDebug() << "Unknown property:" << name; 0116 return; 0117 } 0118 0119 QVariant prop = object->property(name.toLatin1().data()); 0120 if (!prop.isValid()) { 0121 qDebug() << "Unknown property type:" << name; 0122 return; 0123 } 0124 0125 QtProperty *property = nullptr; 0126 0127 const QString type = info.type(); 0128 if (type == "string") { 0129 property = stringManager->addProperty(info.title()); 0130 stringManager->setValue(property, prop.toString()); 0131 } 0132 else if (type == "uid") { 0133 property = uidManager->addProperty(info.title()); 0134 uidManager->setValue(property, prop.value<tikz::core::Uid>()); 0135 } 0136 else if (type == "value") { 0137 property = valueManager->addProperty(info.title()); 0138 valueManager->setRange(property, tikz::Value(0, tikz::Unit::Millimeter), tikz::Value(10, tikz::Unit::Millimeter)); 0139 valueManager->setMinimum(property, tikz::Value::fromString(info.minimum().toString())); 0140 valueManager->setMaximum(property, tikz::Value::fromString(info.maximum().toString())); 0141 valueManager->setSingleStep(property, info.singleStep()); 0142 valueManager->setValue(property, prop.value<tikz::Value>()); 0143 } 0144 else if (type == "bool") { 0145 property = boolManager->addProperty(info.title()); 0146 boolManager->setValue(property, prop.toBool()); 0147 } 0148 else if (type == "color") { 0149 property = colorManager->addProperty(info.title()); 0150 colorManager->setValue(property, prop.value<QColor>()); 0151 } 0152 else if (type == "opacity") { 0153 property = opacityManager->addProperty(info.title()); 0154 opacityManager->setValue(property, prop.toDouble()); 0155 } 0156 else if (type == "double") { 0157 property = doubleManager->addProperty(info.title()); 0158 doubleManager->setMinimum(property, info.minimum().toDouble()); 0159 doubleManager->setMaximum(property, info.maximum().toDouble()); 0160 doubleManager->setSingleStep(property, info.singleStep()); 0161 doubleManager->setValue(property, prop.toDouble()); 0162 } 0163 else if (type == "enum") { 0164 // find out property type 0165 auto metaProp = object->metaObject()->property(object->metaObject()->indexOfProperty(name.toLatin1().data())); 0166 if (metaProp.userType() == QMetaType::UnknownType) { 0167 qDebug() << "Unknown enum type"; 0168 } 0169 0170 // remove namespace, if applicable 0171 QString typeName = metaProp.typeName(); 0172 if (typeName.startsWith("tikz::")) { 0173 typeName.remove(0, 6); 0174 } 0175 0176 const int enumIndex = tikz::staticMetaObject.indexOfEnumerator(typeName.toLatin1().data()); 0177 const QMetaEnum metaEnum = tikz::staticMetaObject.enumerator(enumIndex); 0178 QStringList enumNames; 0179 for (int i = 0; i < metaEnum.keyCount(); ++i) { 0180 enumNames << metaEnum.key(i); 0181 } 0182 property = enumManager->addProperty(info.title()); 0183 enumManager->setEnumNames(property, enumNames); 0184 enumManager->setValue(property, prop.toInt()); 0185 } 0186 else { 0187 qDebug() << "Unknown property type:" << name; 0188 } 0189 if (property) { 0190 const QString modifiedFunction = info.modifiedFunction(); 0191 if (!modifiedFunction.isEmpty()) { 0192 bool isModified = false; 0193 const bool ok = QMetaObject::invokeMethod(object, 0194 modifiedFunction.toLatin1().data(), 0195 Qt::DirectConnection, 0196 Q_RETURN_ARG(bool, isModified) 0197 ); 0198 if (ok) { 0199 property->setModified(isModified); 0200 } else { 0201 tikz::debug("properties.json: Invalid modified getter " + modifiedFunction); 0202 } 0203 } 0204 addProperty(property, name); 0205 } 0206 } 0207 0208 template <typename T> 0209 void setValue(QtProperty * property, const T & val) 0210 { 0211 // if items are inserted, the slot valueChanged() is also called. 0212 // In this case, the item is not yet registered in the map. Hence, 0213 // we just return. 0214 if (! propertyMap.contains(property)) { 0215 return; 0216 } 0217 0218 auto style = styleForItem(uid); 0219 if (style) { 0220 const QString name = propertyMap[property]; 0221 style->document()->addUndoItem(new tikz::core::UndoSetProperty(style->uid(), name, val)); 0222 } 0223 } 0224 }; 0225 0226 0227 0228 0229 0230 PropertyBrowser::PropertyBrowser(QWidget *parent) 0231 : QWidget(parent) 0232 , d(new PropertyBrowserPrivate) 0233 { 0234 d->browser = new QtTreePropertyBrowser(this); 0235 auto vboxLayout = new QVBoxLayout(this); 0236 vboxLayout->setContentsMargins(0, 0, 0, 0); 0237 vboxLayout->addWidget(d->browser); 0238 0239 // setup property managers 0240 d->valueManager = new ValuePropertyManager(this); 0241 d->boolManager = new QtBoolPropertyManager(this); 0242 d->colorManager = new QtColorPropertyManager(this); 0243 d->opacityManager = new OpacityPropertyManager(this); 0244 d->doubleManager = new QtDoublePropertyManager(this); 0245 d->enumManager = new QtEnumPropertyManager(this); 0246 d->stringManager = new QtStringPropertyManager(this); 0247 d->uidManager = new UidPropertyManager(this); 0248 0249 // setup propertybrowser 0250 d->browser->setFactoryForManager(d->valueManager, new ValueSpinBoxFactory(this)); 0251 d->browser->setFactoryForManager(d->boolManager, new QtCheckBoxFactory(this)); 0252 d->browser->setFactoryForManager(d->colorManager, new QtColorEditorFactory(this)); 0253 d->browser->setFactoryForManager(d->opacityManager, new OpacityEditorFactory(this)); 0254 d->browser->setFactoryForManager(d->doubleManager, new QtDoubleSpinBoxFactory(this)); 0255 d->browser->setFactoryForManager(d->enumManager, new QtEnumEditorFactory(this)); 0256 d->browser->setFactoryForManager(d->stringManager, new QtLineEditFactory(this)); 0257 // d->uidManager: Uids are read-only, no editor required 0258 0259 d->browser->setPropertiesWithoutValueMarked(true); 0260 d->browser->setRootIsDecorated(false); 0261 d->browser->setResizeMode(QtTreePropertyBrowser::ResizeToContents); 0262 0263 // setup connections 0264 connect(d->valueManager, SIGNAL(valueChanged(QtProperty*, const tikz::Value &)), 0265 this, SLOT(valueChanged(QtProperty*, const tikz::Value &))); 0266 connect(d->boolManager, SIGNAL(valueChanged(QtProperty*, bool)), 0267 this, SLOT(valueChanged(QtProperty*, bool))); 0268 connect(d->colorManager, SIGNAL(valueChanged(QtProperty*, const QColor &)), 0269 this, SLOT(valueChanged(QtProperty*, const QColor &))); 0270 connect(d->opacityManager, SIGNAL(valueChanged(QtProperty*, qreal)), 0271 this, SLOT(valueChanged(QtProperty*, qreal))); 0272 connect(d->doubleManager, SIGNAL(valueChanged(QtProperty*, double)), 0273 this, SLOT(doubleValueChanged(QtProperty*, double))); 0274 connect(d->enumManager, SIGNAL(valueChanged(QtProperty*, int)), 0275 this, SLOT(enumValueChanged(QtProperty*, int))); 0276 connect(d->stringManager, SIGNAL(valueChanged(QtProperty*, QString)), 0277 this, SLOT(valueChanged(QtProperty*, QString))); 0278 // d->uidManager: read-only, no connection required 0279 } 0280 0281 PropertyBrowser::~PropertyBrowser() 0282 { 0283 delete d; 0284 } 0285 0286 void PropertyBrowser::setView(tikz::ui::View * view) 0287 { 0288 if (d->view == view) { 0289 return; 0290 } 0291 0292 if (d->view) { 0293 disconnect(d->view, SIGNAL(selectionChanged(tikz::ui::View*)), this, SLOT(updateCurrentItem())); 0294 } 0295 0296 d->view = view; 0297 if (d->view) { 0298 connect(d->view, SIGNAL(selectionChanged(tikz::ui::View*)), this, SLOT(updateCurrentItem())); 0299 } 0300 0301 updateCurrentItem(); 0302 } 0303 0304 void PropertyBrowser::setItem(const tikz::core::Uid & uid) 0305 { 0306 if (d->uid == uid) { 0307 return; 0308 } 0309 0310 d->uid = uid; 0311 0312 // clear all managers and mappings 0313 d->valueManager->clear(); 0314 d->boolManager->clear(); 0315 d->colorManager->clear(); 0316 d->opacityManager->clear(); 0317 d->doubleManager->clear(); 0318 d->enumManager->clear(); 0319 d->stringManager->clear(); 0320 d->uidManager->clear(); 0321 d->propertyMap.clear(); 0322 0323 auto style = styleForItem(d->uid); 0324 if (style) { 0325 auto metaObj = style->metaObject(); 0326 while (metaObj) { 0327 for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) { 0328 d->addProperty(style, metaObj->property(i).name()); 0329 } 0330 metaObj = metaObj->superClass(); 0331 } 0332 } 0333 } 0334 0335 void PropertyBrowser::valueChanged(QtProperty *property, const tikz::Value & val) 0336 { 0337 d->setValue(property, val); 0338 } 0339 0340 void PropertyBrowser::valueChanged(QtProperty *property, bool val) 0341 { 0342 d->setValue(property, val); 0343 } 0344 0345 void PropertyBrowser::valueChanged(QtProperty *property, const QColor & val) 0346 { 0347 d->setValue(property, val); 0348 } 0349 0350 void PropertyBrowser::valueChanged(QtProperty *property, int val) 0351 { 0352 d->setValue(property, val); 0353 } 0354 0355 void PropertyBrowser::valueChanged(QtProperty *property, double val) 0356 { 0357 d->setValue(property, val); 0358 } 0359 0360 void PropertyBrowser::doubleValueChanged(QtProperty *property, double val) 0361 { 0362 d->setValue(property, val); 0363 } 0364 0365 void PropertyBrowser::enumValueChanged(QtProperty *property, int val) 0366 { 0367 d->setValue(property, val); 0368 } 0369 0370 void PropertyBrowser::valueChanged(QtProperty *property, const QString & val) 0371 { 0372 d->setValue(property, val); 0373 } 0374 0375 void PropertyBrowser::updateCurrentItem() 0376 { 0377 auto tikzItems = d->view->selectedItems(); 0378 if (tikzItems.size() != 1) { 0379 if (d->view) { 0380 setItem(d->view->document()->uid()); 0381 } else { 0382 setItem(tikz::core::Uid()); 0383 } 0384 return; 0385 } 0386 0387 auto item = tikzItems.front(); 0388 if (qobject_cast<NodeItem*>(item)) { 0389 setItem(qobject_cast<NodeItem*>(item)->uid()); 0390 } else if (qobject_cast<PathItem*>(item)) { 0391 setItem(qobject_cast<PathItem*>(item)->uid()); 0392 } 0393 } 0394 0395 } 0396 } 0397 0398 // kate: indent-width 4; replace-tabs on;