221 lines
6.4 KiB
C++
221 lines
6.4 KiB
C++
/***************************************************************************
|
|
|
|
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>
|
|
#include <xqviewmodel.h>
|
|
#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() )
|
|
{
|
|
//qDebug() << " --- conf item Type: " << key << " : " << value;
|
|
setItemTypeDataFromString( *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 <ItemTypes> is null" );
|
|
|
|
// alle itemtype vorlagen erzeugen
|
|
for( const XQNodePtr& typeSheetNode : _typesSheet->children())
|
|
{
|
|
XQItemType* itemType = new XQItemType;
|
|
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.
|
|
//! Vom aufwand ist es auch egal, ob ich daten aus dem XML in das
|
|
//! item oder den itemtyp schreiben muss.
|
|
|
|
XQItemType* XQItemFactory::makeItemType(const XQNodePtr& sheetEntry )
|
|
{
|
|
QString typeKey = sheetEntry->attribute( c_ItemType );
|
|
XQItemType* itemType = findItemTypeTemplate(typeKey);
|
|
|
|
// wir prüfen, ob im sheetEntry noch zusätzliche attribute vorhanden
|
|
// sind, die wir in dem itemType müssen
|
|
|
|
//qDebug() << " --- makeItemType: " << sheetEntry->to_string();
|
|
|
|
// über alle attribute
|
|
for (const auto& attrEntry : sheetEntry->attributes())
|
|
{
|
|
// prüfen, ob der itemType des attribute schon hat
|
|
int role = itemType->roleForAttributeKey( attrEntry.first );
|
|
// wenn ja, überschreiben
|
|
if( role != XQItem::NoRole )
|
|
{
|
|
QVariant newValue = XQItem::makeVariant( itemType, role, attrEntry.second );
|
|
itemType = itemType->replaceAttribute( newValue, role );
|
|
}
|
|
|
|
}
|
|
return itemType;
|
|
}
|
|
|
|
|
|
//! sucht einen item typ aus der map mit 'vorgefertigen' itemtypen.
|
|
|
|
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 );
|
|
}
|
|
|
|
|
|
//! sucht eine model-beschreibung
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
//! erzeugt eine QVariant aus dem gegebenen string und setzt diese dann via role im item.
|
|
|
|
void XQItemFactory::setItemTypeDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const
|
|
{
|
|
int dataRole = XQItem::fetchItemDataRole( roleKey );
|
|
if( dataRole != XQItem::NoRole)
|
|
{
|
|
QVariant variant = XQItem::makeVariant( &item, dataRole, source );
|
|
if( !variant.isNull() && variant.isValid() )
|
|
item.setData( variant, dataRole );
|
|
}
|
|
}
|
|
|
|
|
|
//! erzeugt eine item-row.
|
|
|
|
XQItemList XQItemFactory::makeRow(const XQNodePtr& sheetNode, const XQNodePtr& contentNode )
|
|
{
|
|
|
|
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( makeItem( sheetEntry, contentNode ) );
|
|
|
|
Q_ASSERT(!list.empty());
|
|
|
|
// wir merken uns den original content node auch, aber
|
|
// im ersten Item. Kann null sein, macht aber erstmal nix.
|
|
dynamic_cast<XQItem*>(list[0])->setContentNode(contentNode);
|
|
|
|
return list;
|
|
}
|
|
|
|
XQItemList XQItemFactory::makeChildRow( XQItem* parent, const XQNodePtr& sheetNode, const XQNodePtr& contentNode )
|
|
{
|
|
Q_UNUSED(parent);
|
|
Q_UNUSED(sheetNode);
|
|
Q_UNUSED(contentNode);
|
|
|
|
return XQItemList();
|
|
}
|
|
|
|
//! Erzeugt ein XQItem aus einer typ-beschreibung ('sheetNode') und einem daten-knoten ('contentNode').
|
|
//! Wenn der content node nicht gesetzt ist, wird stattdess das attribut 'Caption' aus der typ-beschreibung
|
|
//! verwendet: es handelt sich dann um ein header item
|
|
|
|
XQItem* XQItemFactory::makeItem(const XQNodePtr& sheetNode, const XQNodePtr& contentNode )
|
|
{
|
|
// den itemtype des neuen items rausfinden
|
|
XQItemType* itemType = makeItemType(sheetNode); // throws
|
|
|
|
const QString* contentPtr{};
|
|
|
|
// das ist Unterschied vom HeaderItem zum normalen Item: Der Titel kommt aus der Modelbeschreibung,
|
|
// sonst wird der content indirekt über den tag-name des sheetnode geholt
|
|
|
|
if( !contentNode )
|
|
contentPtr = sheetNode->attribute_ptr(c_Caption);
|
|
else
|
|
contentPtr = contentNode->attribute_ptr( sheetNode->tag_name() );
|
|
|
|
XQItem* newItem = new XQItem( itemType, contentPtr);
|
|
|
|
// __fixme!
|
|
if( newItem->isCheckable() )
|
|
{
|
|
newItem->setCheckState( Qt::Checked );
|
|
}
|
|
|
|
return newItem;
|
|
}
|
|
|
|
//! Erzeugt ein Item _ohne_ internen content node, sondern
|
|
XQItem* XQItemFactory::makeSingleItem( const XQNodePtr& sheetNode, const QString& caption )
|
|
{
|
|
// den itemtype des neuen items rausfinden
|
|
XQItemType* itemType = makeItemType(sheetNode); // throws
|
|
XQItem* newItem = new XQItem( itemType, caption);
|
|
// __fixme!
|
|
if( newItem->isCheckable() )
|
|
{
|
|
newItem->setCheckState( Qt::Checked );
|
|
}
|
|
|
|
return newItem;
|
|
}
|