Warning, file /graphics/glaxnimate/src/gui/item_models/property_model_base.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "property_model_private.hpp" 0008 #include "model/assets/assets.hpp" 0009 0010 using namespace glaxnimate::gui; 0011 using namespace glaxnimate; 0012 0013 0014 void item_models::PropertyModelBase::Private::begin_insert_row(item_models::PropertyModelBase::Private::Subtree* row_tree, int index) 0015 { 0016 model->beginInsertRows(subtree_index(row_tree), index, index); 0017 } 0018 0019 void item_models::PropertyModelBase::Private::end_insert_row() 0020 { 0021 model->endInsertRows(); 0022 } 0023 0024 void item_models::PropertyModelBase::Private::add_object(model::Object* object, Subtree* parent, bool insert_row, int index) 0025 { 0026 auto& container = parent ? parent->children : roots; 0027 if ( std::find_if(container.begin(), container.end(), [object](Subtree* st){ return st->object == object; }) != container.end() ) 0028 return; 0029 0030 if ( index == -1 ) 0031 index = container.size(); 0032 0033 if ( insert_row ) 0034 begin_insert_row(parent, index); 0035 0036 auto node = do_add_node(Subtree{object, parent ? parent->id : 0}, parent, index); 0037 connect_recursive(node, false); 0038 0039 if ( insert_row ) 0040 end_insert_row(); 0041 } 0042 0043 item_models::PropertyModelBase::Private::Subtree* item_models::PropertyModelBase::Private::do_add_node(Subtree st, Subtree* parent, int index) 0044 { 0045 auto it = nodes.insert({next_id, st}).first; 0046 0047 0048 auto& container = parent ? parent->children : roots; 0049 if ( index == -1 ) 0050 container.push_back(&it->second); 0051 else 0052 container.insert(container.begin() + index, &it->second); 0053 0054 it->second.id = next_id; 0055 next_id++; 0056 return &it->second; 0057 } 0058 0059 item_models::PropertyModelBase::Private::Subtree* item_models::PropertyModelBase::Private::add_node(Subtree st) 0060 { 0061 auto parent = node(st.parent); 0062 return do_add_node(std::move(st), parent, -1); 0063 } 0064 0065 void item_models::PropertyModelBase::Private::clear() 0066 { 0067 for ( const auto& p : roots ) 0068 disconnect_recursive(p); 0069 0070 roots.clear(); 0071 next_id = 1; 0072 nodes.clear(); 0073 objects.clear(); 0074 } 0075 0076 item_models::PropertyModelBase::Private::Subtree* item_models::PropertyModelBase::Private::node_from_index(const QModelIndex& index) 0077 { 0078 if ( !index.isValid() ) 0079 return nullptr; 0080 0081 auto it = nodes.find(index.internalId()); 0082 return it == nodes.end() ? nullptr : &it->second; 0083 } 0084 0085 item_models::PropertyModelBase::Private::Subtree* item_models::PropertyModelBase::Private::node(id_type id) 0086 { 0087 auto it = nodes.find(id); 0088 return it != nodes.end() ? &it->second : nullptr; 0089 } 0090 0091 QVariant item_models::PropertyModelBase::Private::data_name(Subtree* tree, int role) 0092 { 0093 if ( role == Qt::DisplayRole ) 0094 { 0095 if ( tree->object ) 0096 return tree->object->object_name(); 0097 else if ( tree->prop ) 0098 return tree->prop->localized_name(); 0099 } 0100 else if ( role == Qt::FontRole ) 0101 { 0102 QFont font; 0103 font.setBold(true); 0104 return font; 0105 } 0106 else if ( role == Qt::EditRole && tree->visual_node ) 0107 { 0108 return tree->visual_node->object_name(); 0109 } 0110 else if ( role == Qt::DecorationRole && tree->visual_node ) 0111 { 0112 return tree->visual_node->tree_icon(); 0113 } 0114 0115 0116 return {}; 0117 } 0118 0119 QVariant item_models::PropertyModelBase::Private::data_value(Subtree* tree, int role) 0120 { 0121 return data_value(tree->prop, tree->object, role); 0122 } 0123 0124 QVariant item_models::PropertyModelBase::Private::data_value(model::BaseProperty* prop, model::Object* object, int role) 0125 { 0126 if ( !prop ) 0127 { 0128 return {}; 0129 } 0130 0131 model::PropertyTraits traits = prop->traits(); 0132 0133 if ( role == Qt::ForegroundRole ) 0134 { 0135 if ( (traits.flags & (model::PropertyTraits::List|model::PropertyTraits::ReadOnly)) 0136 || traits.type == model::PropertyTraits::Object || traits.type == model::PropertyTraits::Unknown 0137 ) 0138 return QApplication::palette().color(QPalette::Disabled, QPalette::Text); 0139 } 0140 0141 if ( role == Flags ) 0142 return prop->traits().flags; 0143 0144 if ( role == ReferenceProperty && prop->traits().flags & model::PropertyTraits::OptionList ) 0145 return QVariant::fromValue(static_cast<model::OptionListPropertyBase*>(prop)); 0146 0147 if ( (traits.flags & model::PropertyTraits::Animated) ) 0148 { 0149 model::AnimatableBase* anprop = static_cast<model::AnimatableBase*>(prop); 0150 auto frame_status = anprop->keyframe_status(document->current_time()); 0151 0152 if ( role == Qt::DecorationRole ) 0153 { 0154 switch ( frame_status ) 0155 { 0156 case model::AnimatableBase::Tween: 0157 return QIcon(app::Application::instance()->data_file("images/keyframe/status/tween.svg")); 0158 case model::AnimatableBase::IsKeyframe: 0159 return QIcon(app::Application::instance()->data_file("images/keyframe/status/key.svg")); 0160 case model::AnimatableBase::Mismatch: 0161 return QIcon(app::Application::instance()->data_file("images/keyframe/status/mismatch.svg")); 0162 case model::AnimatableBase::NotAnimated: 0163 return QIcon(app::Application::instance()->data_file("images/keyframe/status/not-animated.svg")); 0164 } 0165 0166 } 0167 else if ( role == Qt::BackgroundRole ) 0168 { 0169 switch ( frame_status ) 0170 { 0171 case model::AnimatableBase::Tween: 0172 return QColor::fromHsv(100, 167, 127); 0173 case model::AnimatableBase::IsKeyframe: 0174 return QColor::fromHsv(51, 171, 133); 0175 case model::AnimatableBase::Mismatch: 0176 return QColor::fromHsv(29, 180, 149); 0177 case model::AnimatableBase::NotAnimated: 0178 return QColor::fromHsv(0, 0, 120); 0179 } 0180 } 0181 else if ( role == Qt::ForegroundRole ) 0182 { 0183 return QColor(Qt::white); 0184 } 0185 else if ( role == MinValue && traits.type == model::PropertyTraits::Float ) 0186 { 0187 return static_cast<model::AnimatedProperty<float>*>(anprop)->min(); 0188 } 0189 else if ( role == MaxValue && traits.type == model::PropertyTraits::Float ) 0190 { 0191 return static_cast<model::AnimatedProperty<float>*>(anprop)->max(); 0192 } 0193 } 0194 0195 if ( (traits.flags & model::PropertyTraits::List) || traits.type == model::PropertyTraits::Unknown ) 0196 { 0197 return {}; 0198 } 0199 else if ( traits.type == model::PropertyTraits::Object ) 0200 { 0201 if ( object && role == Qt::DisplayRole ) 0202 return object->object_name(); 0203 return {}; 0204 } 0205 else if ( traits.type == model::PropertyTraits::Bool ) 0206 { 0207 if ( role == Qt::CheckStateRole ) 0208 return QVariant::fromValue(prop->value().toBool() ? Qt::Checked : Qt::Unchecked); 0209 return {}; 0210 } 0211 else if ( traits.type == model::PropertyTraits::ObjectReference ) 0212 { 0213 if ( role == Qt::DisplayRole ) 0214 { 0215 QVariant value = prop->value(); 0216 if ( value.isNull() ) 0217 return ""; 0218 return value.value<model::DocumentNode*>()->object_name(); 0219 } 0220 0221 if ( role == Qt::DecorationRole ) 0222 { 0223 QVariant value = prop->value(); 0224 if ( value.isNull() ) 0225 return {}; 0226 return QIcon(value.value<model::DocumentNode*>()->instance_icon()); 0227 } 0228 0229 if ( role == ReferenceProperty ) 0230 return QVariant::fromValue(static_cast<model::ReferencePropertyBase*>(prop)); 0231 0232 return {}; 0233 } 0234 else if ( traits.type == model::PropertyTraits::Enum ) 0235 { 0236 if ( role == Qt::DisplayRole ) 0237 return EnumCombo::data_for(prop->value()).first; 0238 if ( role == Qt::EditRole ) 0239 return prop->value(); 0240 if ( role == Qt::DecorationRole ) 0241 return QIcon::fromTheme(EnumCombo::data_for(prop->value()).second); 0242 return {}; 0243 } 0244 else 0245 { 0246 if ( role == Qt::DisplayRole && (prop->traits().flags & model::PropertyTraits::Percent) ) 0247 return QString(i18n("%1%", prop->value().toDouble() * 100)); 0248 if ( role == Qt::DisplayRole || role == Qt::EditRole ) 0249 return prop->value(); 0250 return {}; 0251 } 0252 } 0253 0254 void item_models::PropertyModelBase::Private::connect_recursive(Subtree* this_node, bool insert_row) 0255 { 0256 auto object = this_node->object; 0257 if ( !object ) 0258 return; 0259 0260 objects[object] = this_node->id; 0261 QObject::connect(object, &model::Object::destroyed, model, &PropertyModelBase::on_delete_object); 0262 QObject::connect(object, &model::Object::removed, model, &PropertyModelBase::on_delete_object); 0263 QObject::connect(object, &model::Object::property_changed, model, &PropertyModelBase::property_changed); 0264 0265 on_connect(object, this_node, insert_row, nullptr); 0266 } 0267 0268 void item_models::PropertyModelBase::Private::connect_subobject(model::Object* object, Subtree* this_node, bool insert_row) 0269 { 0270 this_node->expand_referenced = true; 0271 0272 if ( !object ) 0273 return; 0274 0275 QObject::connect(object, &model::Object::property_changed, model, &PropertyModelBase::property_changed); 0276 0277 ReferencedPropertiesMap* referenced = nullptr; 0278 if ( this_node->prop && this_node->prop->traits().type == model::PropertyTraits::ObjectReference ) 0279 referenced = &referenced_properties[object]; 0280 0281 on_connect(object, this_node, insert_row, referenced); 0282 } 0283 0284 void item_models::PropertyModelBase::Private::disconnect_recursive(Subtree* node) 0285 { 0286 if ( node->object ) 0287 { 0288 QObject::disconnect(node->object, nullptr, model, nullptr); 0289 objects.erase(node->object); 0290 } 0291 0292 if ( node->prop ) 0293 { 0294 auto it = properties.find(node->prop); 0295 if ( it != properties.end() && it->second == node->id ) 0296 properties.erase(it); 0297 } 0298 0299 for ( Subtree* child : node->children ) 0300 { 0301 disconnect_recursive(child); 0302 nodes.erase(child->id); 0303 } 0304 0305 node->children.clear(); 0306 } 0307 0308 item_models::PropertyModelBase::Private::Subtree* item_models::PropertyModelBase::Private::object_tree(model::Object* obj) 0309 { 0310 auto it1 = objects.find(obj); 0311 if ( it1 == objects.end() ) 0312 return nullptr; 0313 0314 auto it2 = nodes.find(it1->second); 0315 if ( it2 == nodes.end() ) 0316 return nullptr; 0317 0318 return &it2->second; 0319 } 0320 0321 void item_models::PropertyModelBase::Private::on_delete_object(model::Object* obj) 0322 { 0323 auto it = objects.find(obj); 0324 if ( it == objects.end() ) 0325 return; 0326 0327 auto it2 = nodes.find(it->second); 0328 if ( it2 == nodes.end() ) 0329 return; 0330 0331 Subtree* node = &it2->second; 0332 0333 auto index = model->object_index(obj); 0334 model->beginRemoveRows(index.parent(), index.row(), index.row()); 0335 0336 disconnect_recursive(node); 0337 0338 if ( node->parent ) 0339 { 0340 auto& siblings = this->node(node->parent)->children; 0341 for ( auto itc = siblings.begin(); itc != siblings.end(); ++itc ) 0342 { 0343 if ( *itc == node ) 0344 { 0345 siblings.erase(itc); 0346 break; 0347 } 0348 } 0349 } 0350 0351 auto it_roots = std::find(roots.begin(), roots.end(), node); 0352 if ( it_roots != roots.end() ) 0353 roots.erase(it_roots); 0354 0355 nodes.erase(it2); 0356 0357 model->endRemoveRows(); 0358 } 0359 0360 item_models::PropertyModelBase::Private::Subtree* item_models::PropertyModelBase::Private::visual_node_parent(Subtree* tree) 0361 { 0362 while ( tree->parent ) 0363 { 0364 tree = node(tree->parent); 0365 if ( !tree ) 0366 return nullptr; 0367 0368 if ( tree->visual_node ) 0369 return tree; 0370 } 0371 0372 return nullptr; 0373 } 0374 0375 QModelIndex item_models::PropertyModelBase::Private::node_index(model::DocumentNode* node) 0376 { 0377 auto it = objects.find(node); 0378 if ( it == objects.end() ) 0379 return {}; 0380 0381 Subtree* tree = this->node(it->second); 0382 if ( !tree ) 0383 return {}; 0384 0385 int row = 0; 0386 if ( Subtree* parent = visual_node_parent(tree) ) 0387 { 0388 row = parent->visual_node->docnode_child_index(node); 0389 if ( row == -1 ) 0390 return {}; 0391 } 0392 else 0393 { 0394 for ( ; row < int(roots.size()); row++ ) 0395 if ( roots[row]->visual_node == node ) 0396 break; 0397 0398 if ( row == int(roots.size()) ) 0399 return {}; 0400 } 0401 0402 return model->createIndex(row, 0, tree->id); 0403 } 0404 0405 QModelIndex item_models::PropertyModelBase::Private::subtree_index(id_type id) 0406 { 0407 auto it = nodes.find(id); 0408 if ( it == nodes.end() ) 0409 return {}; 0410 return subtree_index(&it->second); 0411 } 0412 0413 QModelIndex item_models::PropertyModelBase::Private::subtree_index(Subtree* tree) 0414 { 0415 if ( !tree ) 0416 return {}; 0417 0418 int row = 0; 0419 if ( tree->parent ) 0420 { 0421 auto it = nodes.find(tree->parent); 0422 if ( it == nodes.end() ) 0423 return {}; 0424 0425 auto parent = &*it; 0426 if ( !parent ) 0427 return {}; 0428 0429 row = parent->second.child_index(tree); 0430 if ( row == -1 ) 0431 return {}; 0432 } 0433 else 0434 { 0435 for ( ; row < int(roots.size()); row++ ) 0436 if ( roots[row] == tree ) 0437 break; 0438 0439 if ( row == int(roots.size()) ) 0440 return {}; 0441 } 0442 0443 return model->createIndex(row, 0, tree->id); 0444 } 0445 0446 bool item_models::PropertyModelBase::Private::set_prop_data(Subtree* tree, const QVariant& value, int role) 0447 { 0448 return set_prop_data(tree->prop, value, role); 0449 } 0450 0451 bool item_models::PropertyModelBase::Private::set_prop_data(model::BaseProperty* prop, const QVariant& value, int role) 0452 { 0453 if ( !prop ) 0454 return false; 0455 0456 model::PropertyTraits traits = prop->traits(); 0457 0458 0459 if ( (traits.flags & (model::PropertyTraits::List|model::PropertyTraits::ReadOnly)) || 0460 traits.type == model::PropertyTraits::Object || 0461 traits.type == model::PropertyTraits::Unknown ) 0462 { 0463 return false; 0464 } 0465 else if ( traits.type == model::PropertyTraits::Bool ) 0466 { 0467 if ( role == Qt::CheckStateRole ) 0468 { 0469 return prop->set_undoable(value.value<Qt::CheckState>() == Qt::Checked); 0470 } 0471 return false; 0472 } 0473 else 0474 { 0475 if ( role == Qt::EditRole ) 0476 return prop->set_undoable(value); 0477 return false; 0478 } 0479 } 0480 0481 0482 0483 item_models::PropertyModelBase::PropertyModelBase(std::unique_ptr<Private> d) 0484 : d(std::move(d)) 0485 { 0486 } 0487 0488 item_models::PropertyModelBase::~PropertyModelBase() 0489 { 0490 } 0491 0492 QModelIndex item_models::PropertyModelBase::index(int row, int column, const QModelIndex& parent) const 0493 { 0494 Private::Subtree* tree = d->node_from_index(parent); 0495 if ( !tree ) 0496 { 0497 if ( row >= 0 && row < int(d->roots.size()) ) 0498 return createIndex(row, column, d->roots[row]->id); 0499 return {}; 0500 } 0501 0502 0503 if ( row >= 0 && row < int(tree->children.size()) ) 0504 return createIndex(row, column, tree->children[row]->id); 0505 0506 return {}; 0507 } 0508 0509 QModelIndex item_models::PropertyModelBase::parent(const QModelIndex& child) const 0510 { 0511 // tree_child is the subtree for the child index 0512 Private::Subtree* tree_child = d->node_from_index(child); 0513 0514 // child is a root node, so parent is invalid 0515 if ( !tree_child || tree_child->parent == 0 ) 0516 return {}; 0517 0518 // no parent? => error 0519 auto it = d->nodes.find(tree_child->parent); 0520 if ( it == d->nodes.end() ) 0521 return {}; 0522 0523 // tree is the subtree we want to return 0524 Private::Subtree* tree = &it->second; 0525 0526 // We have a root node 0527 if ( !tree->parent ) 0528 { 0529 // failsafe 0530 if ( !d->document ) 0531 return {}; 0532 0533 // main is 0 0534 int index = 0; 0535 // assets is 1 0536 if ( tree->object == d->document->assets() ) 0537 index = 1; 0538 0539 return createIndex(index, 0, tree->id); 0540 } 0541 0542 // no parent? => error 0543 it = d->nodes.find(tree->parent); 0544 if ( it == d->nodes.end() ) 0545 return {}; 0546 0547 // tree_parent is the parent of tree, grandparent of the model index 0548 Private::Subtree* tree_parent = &it->second; 0549 0550 // We look for the row index for the parent index 0551 for ( int i = 0; i < int(tree_parent->children.size()); i++ ) 0552 if ( tree_parent->children[i] == tree ) 0553 return createIndex(i, 0, tree->id); 0554 0555 return {}; 0556 } 0557 0558 void item_models::PropertyModelBase::set_document(model::Document* document) 0559 { 0560 beginResetModel(); 0561 d->document = document; 0562 d->clear(); 0563 on_document_reset(); 0564 endResetModel(); 0565 } 0566 0567 void item_models::PropertyModelBase::clear_document() 0568 { 0569 set_document(nullptr); 0570 } 0571 0572 item_models::PropertyModelBase::Item item_models::PropertyModelBase::item(const QModelIndex& index) const 0573 { 0574 if ( Private::Subtree* st = d->node_from_index(index) ) 0575 { 0576 Item item = st->object; 0577 if ( st->prop ) 0578 item.property = st->prop; 0579 return item; 0580 } 0581 0582 return {}; 0583 } 0584 0585 0586 QModelIndex item_models::PropertyModelBase::property_index(model::BaseProperty* prop) const 0587 { 0588 auto it = d->properties.find(prop); 0589 if ( it == d->properties.end() ) 0590 return {}; 0591 0592 return index_by_id(it->second, 1); 0593 } 0594 0595 QModelIndex item_models::PropertyModelBase::object_index(model::Object* obj) const 0596 { 0597 auto it = d->objects.find(obj); 0598 if ( it == d->objects.end() ) 0599 return {}; 0600 0601 return index_by_id(it->second); 0602 } 0603 0604 QModelIndex item_models::PropertyModelBase::index_by_id(quintptr id, int column) const 0605 { 0606 Private::Subtree* prop_node = d->node(id); 0607 if ( !prop_node ) 0608 return {}; 0609 0610 Private::Subtree* parent = d->node(prop_node->parent); 0611 0612 int i = 0; 0613 if ( !parent ) 0614 i = std::find(d->roots.begin(), d->roots.end(), prop_node) - d->roots.begin(); 0615 else 0616 i = std::find(parent->children.begin(), parent->children.end(), prop_node) - parent->children.begin(); 0617 0618 return createIndex(i, column, prop_node->id); 0619 } 0620 0621 0622 model::VisualNode* item_models::PropertyModelBase::visual_node(const QModelIndex& index) const 0623 { 0624 Private::Subtree* tree = d->node_from_index(index); 0625 if ( !tree ) 0626 return nullptr; 0627 0628 return tree->visual_node; 0629 } 0630 0631 void item_models::PropertyModelBase::on_delete_object() 0632 { 0633 d->on_delete_object(static_cast<model::Object*>(sender())); 0634 } 0635 0636 void item_models::PropertyModelBase::property_changed(const model::BaseProperty* prop, const QVariant& value) 0637 { 0638 d->property_changed(prop, value); 0639 } 0640 0641 void item_models::PropertyModelBase::Private::property_changed(const model::BaseProperty* prop, const QVariant& value) 0642 { 0643 auto it = properties.find(const_cast<model::BaseProperty*>(prop)); 0644 if ( it != properties.end() ) 0645 on_property_changed(it->second, prop, value); 0646 0647 auto itref = referenced_properties.find(prop->object()); 0648 if ( itref != referenced_properties.end() ) 0649 { 0650 auto itprop = itref->second.find(const_cast<model::BaseProperty*>(prop)); 0651 if ( itprop != itref->second.end() ) 0652 { 0653 for ( id_type id : itprop->second ) 0654 on_property_changed(id, prop, value); 0655 } 0656 } 0657 } 0658 0659 void item_models::PropertyModelBase::Private::clean_object_references(const QModelIndex& index, Private::Subtree* prop_node) 0660 { 0661 if ( prop_node->children.empty() ) 0662 return; 0663 0664 model->beginRemoveRows(index, 0, prop_node->children.size()); 0665 0666 clean_subtree(prop_node); 0667 0668 model->endRemoveRows(); 0669 } 0670 0671 void item_models::PropertyModelBase::Private::on_property_changed(id_type prop_node_id, const model::BaseProperty*, const QVariant& value) 0672 { 0673 Private::Subtree* prop_node = node(prop_node_id); 0674 if ( !prop_node ) 0675 return; 0676 0677 Private::Subtree* parent = node(prop_node->parent); 0678 0679 if ( !parent ) 0680 return; 0681 0682 int i = std::find(parent->children.begin(), parent->children.end(), prop_node) - parent->children.begin(); 0683 QModelIndex index = model->createIndex(i, 1, prop_node->id); 0684 0685 if ( !(prop_node->prop->traits().flags & model::PropertyTraits::List) ) 0686 { 0687 if ( prop_node->prop->traits().type == model::PropertyTraits::ObjectReference ) 0688 { 0689 model::Object* obj_value = value.value<model::Object*>(); 0690 0691 if ( !prop_node->children.empty() ) 0692 clean_object_references(index, prop_node); 0693 0694 if ( prop_node->expand_referenced && obj_value ) 0695 connect_subobject(obj_value, prop_node, true); 0696 } 0697 0698 Q_EMIT model->dataChanged(index, index, {}); 0699 } 0700 } 0701 0702 void item_models::PropertyModelBase::Private::clean_subtree(item_models::PropertyModelBase::Private::Subtree* node) 0703 { 0704 for ( auto& child : node->children ) 0705 { 0706 clean_subtree(child); 0707 nodes.erase(child->id); 0708 } 0709 0710 node->children.clear(); 0711 0712 auto itref = referenced_properties.find(node->object); 0713 if ( itref != referenced_properties.end() ) 0714 { 0715 auto itprop = itref->second.find(node->prop); 0716 if ( itprop != itref->second.end() ) 0717 { 0718 itprop->second.erase( 0719 std::remove_if(itprop->second.begin(), itprop->second.end(), [node, this](id_type id){ 0720 auto n = this->node(id); 0721 return !n || n->parent == node->id; 0722 }), 0723 itprop->second.end() 0724 ); 0725 } 0726 } 0727 } 0728 0729 int item_models::PropertyModelBase::rowCount(const QModelIndex& parent) const 0730 { 0731 if ( d->roots.empty() ) 0732 return 0; 0733 0734 Private::Subtree* tree = d->node_from_index(parent); 0735 if ( !tree ) 0736 return d->roots.size(); 0737 0738 return tree->children.size(); 0739 } 0740 0741 QModelIndex item_models::PropertyModelBase::node_index(model::DocumentNode* node) const 0742 { 0743 return object_index(node); 0744 } 0745 0746 model::Document * item_models::PropertyModelBase::document() const 0747 { 0748 return d->document; 0749 } 0750 0751 model::DocumentNode * item_models::PropertyModelBase::node(const QModelIndex& index) const 0752 { 0753 Private::Subtree* tree = d->node_from_index(index); 0754 if ( !tree ) 0755 return nullptr; 0756 0757 if ( tree->visual_node ) 0758 return tree->visual_node; 0759 0760 return qobject_cast<model::DocumentNode*>(tree->object); 0761 } 0762 0763 model::AnimatableBase* item_models::PropertyModelBase::Private::animatable(Subtree* tree) 0764 { 0765 if ( !tree || !tree->prop ) 0766 return nullptr; 0767 0768 model::PropertyTraits traits = tree->prop->traits(); 0769 if ( traits.flags & model::PropertyTraits::Animated ) 0770 return static_cast<model::AnimatableBase*>(tree->prop); 0771 0772 return nullptr; 0773 } 0774 0775 model::AnimatableBase* item_models::PropertyModelBase::animatable(const QModelIndex& index) const 0776 { 0777 return d->animatable(d->node_from_index(index)); 0778 } 0779 0780 0781 item_models::PropertyModelBase::Private::Subtree* 0782 item_models::PropertyModelBase::Private::add_property( 0783 model::BaseProperty* prop, id_type parent, bool insert_row, ReferencedPropertiesMap* referenced) 0784 { 0785 if ( insert_row ) 0786 { 0787 Subtree* parent_node = node(parent); 0788 begin_insert_row(parent_node, parent_node->children.size()); 0789 } 0790 0791 Subtree* prop_node = add_node(Subtree{prop, parent}); 0792 0793 if ( referenced ) 0794 (*referenced)[prop].push_back(prop_node->id); 0795 else 0796 properties[prop] = prop_node->id; 0797 0798 if ( insert_row ) 0799 end_insert_row(); 0800 0801 return prop_node; 0802 }