325 lines
8.0 KiB
C++
325 lines
8.0 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 <xqmodel.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() )
|
|
{
|
|
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 typeSheetRoot 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_ItemTypeCache[typeName] = itemType;
|
|
}
|
|
}
|
|
|
|
|
|
bool XQItemFactory::isValid()
|
|
{
|
|
return _modelSheet && _typesSheet;
|
|
}
|
|
|
|
|
|
XQItemType* XQItemFactory::findItemType(const QString& key ) const
|
|
{
|
|
if( !key.isEmpty() && s_ItemTypeCache.contains(key))
|
|
return s_ItemTypeCache[key];
|
|
throw XQException( "findItemType: 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::makeItem( const XQNodePtr& contentNode, const XQNodePtr& sheetEntry ) const
|
|
{
|
|
// den itemtype des neuen items rausfinden
|
|
QString typeKey = sheetEntry->attribute("ItemType");
|
|
XQItemType* itemType = findItemType(typeKey); // throws
|
|
const QString* contentPtr = contentNode->attribute_ptr( sheetEntry->tag_name() );
|
|
|
|
XQItem* newItem = new XQItem( itemType, contentPtr );
|
|
|
|
return newItem;
|
|
}
|
|
|
|
|
|
XQItem* XQItemFactory::makeHeaderItem( const XQNodePtr& sheetEntry ) const
|
|
{
|
|
// 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 = findItemType(typeKey); // throws
|
|
// das ist Unterschied zum normalen Item: Der Titel kommt aus der Modelbeschreibung
|
|
const QString* contentPtr = sheetEntry->attribute_ptr("HeaderCaption");
|
|
|
|
XQItem* newItem = new XQItem( itemType, contentPtr );
|
|
|
|
// brauchen wir den noch?
|
|
//newHeaderItem->setSheetNode( sheetNode );
|
|
|
|
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 = findItemType( 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:
|
|
{
|
|
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;
|
|
|
|
}
|
|
|
|
///
|
|
/// ------------------------------------------------
|
|
///
|
|
|
|
|
|
// no clone here !
|
|
XQItemList XQItemFactory::createDataRow( 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( makeItem( 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::createEmptyRow( 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 createDataRow(contentNode, sheetNode );
|
|
|
|
}
|