Files
xtree.old.ng/src/items/xqitemfactory.cpp

395 lines
10 KiB
C++
Raw Normal View History

2025-08-05 22:39:41 +02:00
/***************************************************************************
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 <xqitemfactory.h>
#include <xqexception.h>
#include <xqdocumentstore.h>
2025-08-07 03:11:56 +02:00
#include <xqviewmodel.h>
2025-08-05 22:39:41 +02:00
#include <xqitemtype.h>
#include <znode_factory.h>
void XQItemFactory::initItemFactory( const QString& modelSheetFileName )
{
auto configureItemType = [&, this](XQItemType* itemType, const XQNodePtr& sheetNode )
{
// über alle attribute
for( const auto& [key,value] : sheetNode->attributes() )
{
2025-08-09 11:56:11 +02:00
qDebug() << " --- conf item Type: " << key << " : " << value;
2025-08-05 22:39:41 +02:00
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 )
2025-08-09 11:56:11 +02:00
throw XQException( "initItemFactory <ItemTypes> is null" );
2025-08-05 22:39:41 +02:00
// 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);
2025-08-09 11:56:11 +02:00
s_ItemTypeTemplates[typeName] = itemType;
2025-08-05 22:39:41 +02:00
}
2025-08-09 11:56:11 +02:00
2025-08-05 22:39:41 +02:00
}
bool XQItemFactory::isValid()
{
return _modelSheet && _typesSheet;
}
2025-08-09 11:56:11 +02:00
//! es reicht nicht, einen itemType aus den itemType-templates zu
//! holen: möglicherweise muss der noch mit zusätzlichen attributen
2025-08-09 12:15:37 +02:00
//! ergänzt werden, (hier 'UnitType' ).
2025-08-09 11:56:11 +02:00
XQItemType* XQItemFactory::makeItemType(const XQNodePtr& sheetEntry )
2025-08-05 22:39:41 +02:00
{
2025-08-09 11:56:11 +02:00
QString typeKey = sheetEntry->attribute("ItemType");
2025-08-09 12:15:37 +02:00
2025-08-09 11:56:11 +02:00
XQItemType* itemType = findItemTypeTemplate(typeKey);
// wir prüfen, ob im sheetEntry noch zusätzliche attribute vorhanden
// sind, die wir in dem itemType müssen
2025-08-09 12:15:37 +02:00
// ü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 );
}
2025-08-09 11:56:11 +02:00
2025-08-09 12:15:37 +02:00
}
2025-08-09 11:56:11 +02:00
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 );
2025-08-05 22:39:41 +02:00
}
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;
}
2025-08-09 21:33:03 +02:00
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 );
}
2025-08-09 11:56:11 +02:00
XQItem* XQItemFactory::makeContentItem( const XQNodePtr& contentNode, const XQNodePtr& sheetEntry )
2025-08-05 22:39:41 +02:00
{
// den itemtype des neuen items rausfinden
QString typeKey = sheetEntry->attribute("ItemType");
2025-08-09 11:56:11 +02:00
//XQItemType* itemType = findItemTypeTemplate(typeKey); // throws
XQItemType* itemType = makeItemType(sheetEntry); // throws
2025-08-05 22:39:41 +02:00
const QString* contentPtr = contentNode->attribute_ptr( sheetEntry->tag_name() );
2025-08-09 21:33:03 +02:00
return new XQItem( itemType, contentPtr );
2025-08-05 22:39:41 +02:00
}
2025-08-09 21:33:03 +02:00
XQItem* XQItemFactory::makeTreeChildItem( const XQNodePtr& contentNode, const XQNodePtr& sheetEntry )
2025-08-05 22:39:41 +02:00
{
// den itemtype des neuen items rausfinden
2025-08-09 21:33:03 +02:00
QString typeKey = sheetEntry->attribute("ItemType");
2025-08-09 11:56:11 +02:00
XQItemType* itemType = findItemTypeTemplate(typeKey); // throws
2025-08-09 21:33:03 +02:00
//XQItemType* itemType = makeItemType(sheetEntry); // throws
2025-08-05 22:39:41 +02:00
2025-08-09 21:33:03 +02:00
const QString* contentPtr = contentNode->attribute_ptr( "ProjectName" );
2025-08-05 22:39:41 +02:00
2025-08-09 21:33:03 +02:00
XQItem* newItem = new XQItem( itemType, contentPtr );
2025-08-05 22:39:41 +02:00
2025-08-09 21:33:03 +02:00
return newItem;
}
2025-08-05 22:39:41 +02:00
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*
2025-08-09 11:56:11 +02:00
XQItemType* itemType = findItemTypeTemplate( source );
2025-08-05 22:39:41 +02:00
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:
{
2025-08-09 07:45:32 +02:00
qDebug() << " --- make unit type: " << source;
2025-08-05 22:39:41 +02:00
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;
}
///
/// ------------------------------------------------
///
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<XQItem*>(list[0])->setContentNode(sheetNode);
// brauchen wir den noch?
dynamic_cast<XQItem*>(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:
//
// <Battery>
// <Voltage .../>
// -> <Capacity ../>
//
// - 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<XQItem*>(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; i<max; ++i )
{
// __fix
//list.append( new XQItem( "", XQItemType::EmptyStyle ) );
}
return list;
}
XQItemList XQItemFactory::createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode )
{
// we have a new empty contentNode, so we add attributes first.
for( const auto& sheetEntry : sheetNode->children() )
{
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 );
}