/*************************************************************************** source::worx xtree Copyright © 2024-2025 c.holzheuer christoph.holzheuer@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. ***************************************************************************/ #include #include #include #include #include #include void XQItemFactory::initItemFactory( const QString& modelSheetFileName ) { auto configureItemType = [&, this](XQItemType* itemType, const XQNodePtr& sheetNode ) { // über alle attribute for( const auto& [key,value] : sheetNode->attributes() ) { qDebug() << " --- conf item Type: " << key << " : " << value; setItemDataFromString( *itemType, key, value ); } }; // schritt #1: modelbeschreibung laden XQNodeFactory treeLoader; _modelSheet = treeLoader.load_tree( qPrintable(modelSheetFileName) ); // schritt #2: model root testen if (!_modelSheet) throw XQException("modelSheet load failed. ", modelSheetFileName); // schritt #3: itemtype beschreibungen laden ... _typesSheet = _modelSheet->find_child_by_tag_name( "ItemTypes" ); // ... und testen if( !_typesSheet ) throw XQException( "initItemFactory is null" ); // alle itemtype vorlagen erzeugen for( const XQNodePtr& typeSheetNode : _typesSheet->children()) { XQItemType* itemType = new XQItemType; //const QString& typeName = typeSheetNode->tag_name(); const QString& typeName = typeSheetNode->tag_name(); configureItemType(itemType, typeSheetNode); itemType->setText( typeName); s_ItemTypeTemplates[typeName] = itemType; } } bool XQItemFactory::isValid() { return _modelSheet && _typesSheet; } //! es reicht nicht, einen itemType aus den itemType-templates zu //! holen: möglicherweise muss der noch mit zusätzlichen attributen //! ergänzt werden, (hier 'UnitType' ). XQItemType* XQItemFactory::makeItemType(const XQNodePtr& sheetEntry ) { QString typeKey = sheetEntry->attribute("ItemType"); XQItemType* itemType = findItemTypeTemplate(typeKey); // wir prüfen, ob im sheetEntry noch zusätzliche attribute vorhanden // sind, die wir in dem itemType müssen // über alle attribute for (const auto& attr : sheetEntry->attributes()) { // prüfen, ob der itemType des attribute schon hat int role = itemType->hasAttribute( attr.first); // wenn ja, überschreiben if( role != XQItem::NoRole ) { QVariant newValue = makeVariant(role,attr.second); itemType = itemType->replaceAttribute( newValue, role ); } } return itemType; } XQItemType* XQItemFactory::findItemTypeTemplate(const QString& key ) const { if( !key.isEmpty() && s_ItemTypeTemplates.contains(key)) return s_ItemTypeTemplates[key]; throw XQException( "itemfactory: findItemTypeTemplate: not found:", key ); } XQNodePtr XQItemFactory::findModelSheet( const QString& modelName ) const { XQNodePtr modelSheet = _modelSheet->find_child_by_tag_name( modelName ); if( !modelSheet ) throw XQException( "model sheet not found: ", modelName ); return modelSheet; } XQItem* XQItemFactory::makeHeaderItem( const XQNodePtr& sheetEntry ) { // header items are all non-data items: // - section header row items // - main tree header items // - main tree child items // - also: static items, hidden items // den itemtype des neuen items rausfinden QString typeKey = sheetEntry->attribute("HeaderItemType"); //XQItemType* itemType = makeItemType(sheetEntry); // throws XQItemType* itemType = findItemTypeTemplate(typeKey); // das ist Unterschied zum normalen Item: Der Titel kommt aus der Modelbeschreibung const QString* contentPtr = sheetEntry->attribute_ptr("HeaderCaption"); return new XQItem( itemType, contentPtr ); } XQItem* XQItemFactory::makeTreeChildItem( const XQNodePtr& contentNode, const XQNodePtr& sheetEntry ) { // den itemtype des neuen items rausfinden QString typeKey = sheetEntry->attribute("ItemType"); XQItemType* itemType = findItemTypeTemplate(typeKey); // throws //XQItemType* itemType = makeItemType(sheetEntry); // throws const QString* contentPtr = contentNode->attribute_ptr( "ProjectName" ); XQItem* newItem = new XQItem( itemType, contentPtr ); return newItem; } void XQItemFactory::setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const { int dataRole = XQItem::fetchItemDataRole( roleKey ); if( dataRole != XQItem::NoRole) { QVariant variant = makeVariant( dataRole, source ); if( !variant.isNull() && variant.isValid() ) item.setData( variant, dataRole ); } } QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const { QVariant value; switch(dataRole) { // das ist ein pointer auf den original-string aus dem XML case XQItem::ContentRole: { // content() -> QString* value = QVariant::fromValue(&source); break; } case XQItem::ItemTypeRole: { // itemType() -> XQItemType* XQItemType* itemType = findItemTypeTemplate( source ); value = QVariant::fromValue(itemType); break; } case XQItem::RenderStyleRole: { XQItem::RenderStyle renderStyle = XQItem::fetchRenderStyle( source ); value = QVariant::fromValue(renderStyle); break; } case XQItem::EditorTypeRole: { XQItem::EditorType editorType = XQItem::fetchEditorType( source ); value = QVariant::fromValue(editorType); break; } case XQItem::UnitTypeRole: { qDebug() << " --- make unit type: " << source; XQItem::UnitType unitType = XQItem::fetchUnitType( source ); value = QVariant::fromValue(unitType); break; } case XQItem::ContentFormatRole: { // contentFormat() -> QString value = QVariant::fromValue(source); break; } case XQItem::FlagsRole: { QFlags itemFlags = Qt::NoItemFlags; const QStringList flagKeys = source.split( '|' ); for( const QString& flagKey : flagKeys ) { Qt::ItemFlag flag = XQItem::fetchItemFlag( flagKey ); itemFlags.setFlag( flag ); } value = QVariant::fromValue(itemFlags); break; } case XQItem::IconRole: { QIcon typeIcon; if(XQAppData::hasTypeIcon(source)) typeIcon = XQAppData::typeIcon(source); value = QVariant::fromValue(typeIcon); break; } case XQItem::FixedChoicesRole: { const QStringList choices = source.split( '|' ); QStandardItemModel* fixedChoices = new QStandardItemModel(); for( const QString& entry : choices ) fixedChoices->appendRow( new QStandardItem( entry ) ); value = QVariant::fromValue(fixedChoices); break; } /* case XQItem::ContentNodeRole: { value = QVariant::fromValue(&source); break; } case XQItem::XQItem::SheetNodeRole: { value = QVariant::fromValue(&source); break; } */ default: case XQItem::XQItem::NoRole: { break; } }; //if( !value.toString().isEmpty()) // setData( value, dataRole); return value; } /// /// ------------------------------------------------ /// XQItem* XQItemFactory::makeContentItem( const XQNodePtr& contentNode, const XQNodePtr& sheetEntry ) { // den itemtype des neuen items rausfinden QString typeKey = sheetEntry->attribute(c_ItemType); //XQItemType* itemType = findItemTypeTemplate(typeKey); // throws XQItemType* itemType = makeItemType(sheetEntry); // throws // das ist Unterschied zum normalen Item: Der Titel kommt aus der Modelbeschreibung const QString* contentPtr = contentNode->attribute_ptr( sheetEntry->tag_name() ); return new XQItem( itemType, contentPtr ); } XQItem* XQItemFactory::makeItem( const XQNodePtr& sheetNode, const XQNodePtr& contentNode ) { // den itemtype des neuen items rausfinden QString typeKey = sheetNode->attribute(c_ItemType); //XQItemType* itemType = makeItemType(sheetEntry); // throws XQItemType* itemType = findItemTypeTemplate(typeKey); // fallunterscheidung beim inhalt: const QString* contentPtr{}; // das ist Unterschied zum normalen Item: Der Titel kommt aus der Modelbeschreibung if(!contentNode) contentPtr = sheetNode->attribute_ptr(c_Caption); else // der content wird indirect über den tag-name des sheetnode geholt contentPtr = contentNode->attribute_ptr( sheetNode->tag_name() ); return new XQItem( itemType, contentPtr ); } XQItemList XQItemFactory::makeHeader( const XQNodePtr& headerNode ) { XQItemList list; // über alle kinder der
sektion for( const auto& headerEntry : headerNode->children() ) { qDebug() << " --- headerEntry: " << headerEntry->tag_name() << ": " << headerEntry->attribute( "ItemType") << headerEntry->attribute( "Caption"); XQItem* headerItem = makeItem( headerEntry ); list.append( headerItem ); } return list; } XQItemList XQItemFactory::makeHeaderRow( const XQNodePtr& sheetNode ) { XQItemList list; // Die Kinder des Knotens beschreiben die einzelnen // Attribute des XML-Datenknotens for( const auto& attrNode : sheetNode->children() ) { // ?? //if(attrNode->has_children() ) // continue; XQItem* headerItem = makeHeaderItem( attrNode ); list.append( headerItem ); } if( !list.empty() ) { // wir merken uns den original content node auch, aber // im ersten Item. dynamic_cast(list[0])->setContentNode(sheetNode); // brauchen wir den noch? dynamic_cast(list[0])->setSheetNode(sheetNode); } return list; } // no clone here ! XQItemList XQItemFactory::makeContentRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode ) { XQItemList list; // - Gehe über alle Einträge der Typbeschreibung: // // // // -> // // - Nimm das dazugehörige Attribut aus dem contentNode // value = contentNode->attributes["Capacity"]; // for( const auto& sheetEntry : sheetNode->children() ) { list.append( makeContentItem( contentNode, sheetEntry ) ); } if( !list.empty() ) { // wir merken uns den original content node auch, aber // im ersten Item. dynamic_cast(list[0])->setContentNode(contentNode); } return list; } XQItemList XQItemFactory::makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode ) { Q_UNUSED(contentNode) XQItemList list; // create a data node for each sheet entry size_t max = sheetNode->children().size(); for( size_t i=0; ichildren() ) { QString value = "[" + sheetEntry->tag_name() + "]"; if( sheetEntry->has_attribute("Unit") ) value = "0"; contentNode->set_attribute( sheetEntry->tag_name(), value ); } if( sheetNode->has_attribute( c_FriendlyName ) ) contentNode->set_attribute( c_FriendlyName, sheetNode->friendly_name() ); // now, we can create a normal entry row return makeContentRow(contentNode, sheetNode ); }