23 Commits

Author SHA1 Message Date
3c4893f308 -- tree missmatch 2025-08-22 18:06:11 +02:00
e3be14c27b -- backup 2025-08-22 17:52:08 +02:00
b6299be24b wrecked it on purpose. 2025-08-21 22:40:33 +02:00
306a68f6c9 trashed it. 2025-08-20 23:04:09 +02:00
Christoph Holzheuer
0ec1f7a7c0 -- fy 2025-08-20 17:37:14 +02:00
6393096072 happy crashing 2025-08-19 22:41:00 +02:00
123dc695d9 added XQStaticItem 2025-08-19 22:26:38 +02:00
c870ef8801 sections in treeview. 2025-08-18 21:09:57 +02:00
Christoph Holzheuer
429c939cdf some fixes 2025-08-18 16:09:47 +02:00
0f7299a74a added missing widgets 2025-08-17 22:54:50 +02:00
1433e393f7 changed icon 2025-08-17 16:11:39 +02:00
372873717e adding projects to project tree works again. 2025-08-17 11:50:26 +02:00
a13a1de8fe reworked section handling (a bit) 2025-08-16 22:03:41 +02:00
8756793039 added section signals 2025-08-16 16:39:23 +02:00
d249c9c631 simplified model commands. 2025-08-16 15:28:18 +02:00
062b935a7c Merge branch 'experimental/remork-childmodel' 2025-08-15 20:57:42 +02:00
eac668d297 removed XQIcon 2025-08-15 20:55:53 +02:00
c87da2802a backup 2025-08-15 20:31:40 +02:00
6865e6aaaa cleanups. 2025-08-14 22:03:31 +02:00
0d7ab33c74 reworked model sections. 2025-08-14 21:36:39 +02:00
Christoph Holzheuer
a6fb7e82bd works again 2025-08-14 19:13:53 +02:00
d3f2cbeaec Still works... 2025-08-13 22:25:01 +02:00
7ade8ef1c8 Merge branch 'experimental/cleanup' 2025-08-13 21:02:21 +02:00
36 changed files with 1641 additions and 789 deletions

84
deprecated/reste.cpp Normal file
View File

@@ -0,0 +1,84 @@
XQItem* createTreeEntry( XQNodePtr contentNode );
//! erzeugt einen eintrag in der baum-übersicht.
XQItem* XQMainModel::createTreeEntry( XQNodePtr contentNode )
{
/*
for(const auto& section : _sections )
{
qDebug() << " --- wtf1: " << contentNode->to_string();
qDebug() << " --- wtf2: " << section.sheetRootNode->to_string();
if( contentNode->attribute("State") == section.sheetRootNode->attribute("State") )
{
//XQItem* newTreeentry = _itemFactory.makeTreeChildItem( contentNode, section.sheetRootNode );
makeTreeChildItem:
// 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;
section.headerItem().appendRow( newTreeentry );
_treeTable->expand( section.modelIndex );
// ??
_treeTable->setCurrentIndex( section.modelIndex );
newTreeentry->setContentNode(contentNode);
emit xqItemCreated( newTreeentry );
return newTreeentry;
}
}
*/
throw XQException( "createTreeEntry: main model should not be empty!" );
}
<Section ContentType="Inverter">
<Header Marker="Inverter">
<InverterID Caption="Inverter" ItemType="HeaderType" />
<InverterName Caption="Name" ItemType="HeaderType" />
<Manufacturer Caption="Manufacturer" ItemType="HeaderType" />
<MaxPowerInput Caption="max. Input" ItemType="HeaderType" />
<MaxPowerOutput Caption="max Output" ItemType="HeaderType" />
<NumStrings Caption="Strings" ItemType="HeaderType" />
<Weight Caption="Weight" ItemType="HeaderType" />
</Header>
<Data>
<InverterID Caption="Inverter" ItemType="ValueType" />
<InverterName Caption="Name" ItemType="ValueType" />
<Manufacturer Caption="Manufacturer" ItemType="ValueType" />
<MaxPowerInput Caption="max. Input" ItemType="ValueType" ItemType="ChoiceType" ChoiceDataSource="MaxPowerInputChoice" UnitType="W"/>
<MaxPowerOutput Caption="max Output" ItemType="ValueType" UnitType="W"/>
<NumStrings Caption="Strings" ItemType="ValueType" />
<Weight Caption="Weight" ItemType="ValueType" UnitType="kg"/>
</Data>
</Section>
<Section ContentType="Battery">
<Header Marker="Battery">
<BatteryID Caption="Name" ItemType="HeaderType" />
<BatteryName Caption="Battery" ItemType="HeaderType" />
<Manufacturer Caption="Manufacturer" ItemType="HeaderType" />
<Capacity Caption="Capacity" ItemType="HeaderType"/>
<Yield Caption="Yield" ItemType="HeaderType" />
<MaxCurrent Caption="max. Current" ItemType="HeaderType" />
<MaxVolt Caption="max. Volt" ItemType="HeaderType" />
</Header>
<Data>
<BatteryID Caption="Battery" ItemType="ValueType" />
<BatteryName Caption="Name" ItemType="ValueType" />
<Manufacturer Caption="Manufacturer" ItemType="ValueType" />
<Capacity Caption="Capacity" ItemType="ValueType" UnitType="Wh"/>
<Yield Caption="Yield" ItemType="ValueType" ItemType="PercentageType" UnitType="%"/>
<MaxCurrent Caption="max. Current" ItemType="ValueType" UnitType="A"/>
<MaxVolt Caption="max. Volt" ItemType="ValueType" UnitType="V"/>
</Data>
</Section>

29
deprecated/xqicon.cpp Normal file
View File

@@ -0,0 +1,29 @@
/***************************************************************************
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 <xqicon.h>
XQIcon::XQIcon()
{}
XQIcon::XQIcon( const QIcon& icon, const QString& iconKey )
: QIcon{icon}, _iconKey{iconKey}
{
}
const QString& XQIcon::iconKey()
{
return _iconKey;
}

35
deprecated/xqicon.h Normal file
View File

@@ -0,0 +1,35 @@
/***************************************************************************
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.
***************************************************************************/
#ifndef XQICON_H
#define XQICON_H
#include <QIcon>
class XQIcon : public QIcon
{
public:
XQIcon();
XQIcon( const QIcon& icon, const QString& iconKey );
const QString& iconKey();
protected:
QString _iconKey;
};
#endif // XQICON_H

View File

@@ -36,89 +36,91 @@ namespace XQAppData
{ {
public: public:
XQAppIconMap() = default; XQAppIconMap()
{
}
void init() void init()
{ {
insert( "DirIcon" , QApplication::style()->standardIcon(QStyle::SP_DirIcon)); namedInsert( "DirIcon" , QStyle::SP_DirIcon );
insert( "FileDialogBack", QApplication::style()->standardIcon(QStyle::SP_FileDialogBack)); namedInsert( "FileDialogBack", QStyle::SP_FileDialogBack );
insert( "FileDialogContentsView", QApplication::style()->standardIcon(QStyle::SP_FileDialogContentsView)); namedInsert( "FileDialogContentsView", QStyle::SP_FileDialogContentsView );
insert( "FileDialogDetailedView", QApplication::style()->standardIcon(QStyle::SP_FileDialogDetailedView)); namedInsert( "FileDialogDetailedView", QStyle::SP_FileDialogDetailedView );
insert( "icn05Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogEnd)); namedInsert( "icn05Dummy", QStyle::SP_FileDialogEnd );
insert( "icn06Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogInfoView)); namedInsert( "icn06Dummy", QStyle::SP_FileDialogInfoView );
insert( "icn07Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogListView)); namedInsert( "icn07Dummy", QStyle::SP_FileDialogListView );
insert( "icn08Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogNewFolder)); namedInsert( "icn08Dummy", QStyle::SP_FileDialogNewFolder );
insert( "icn09Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogStart)); namedInsert( "icn09Dummy", QStyle::SP_FileDialogStart );
insert( "icn10Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogToParent)); namedInsert( "icn10Dummy", QStyle::SP_FileDialogToParent );
insert( "icn11Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowBack)); namedInsert( "icn11Dummy", QStyle::SP_ArrowBack );
insert( "icn12Dummy", QApplication::style()->standardIcon(QStyle::SP_DirIcon)); namedInsert( "icn12Dummy", QStyle::SP_DirIcon );
insert( "icn13Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSkipBackward)); namedInsert( "icn13Dummy", QStyle::SP_MediaSkipBackward );
insert( "icn14Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowDown)); namedInsert( "icn14Dummy", QStyle::SP_ArrowDown );
insert( "icn15Dummy", QApplication::style()->standardIcon(QStyle::SP_DirLinkIcon)); namedInsert( "icn15Dummy", QStyle::SP_DirLinkIcon );
insert( "icn16Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSkipForward)); namedInsert( "icn16Dummy", QStyle::SP_MediaSkipForward );
insert( "icn17Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowForward)); namedInsert( "icn17Dummy", QStyle::SP_ArrowForward );
insert( "icn18Dummy", QApplication::style()->standardIcon(QStyle::SP_DirOpenIcon)); namedInsert( "icn18Dummy", QStyle::SP_DirOpenIcon );
insert( "icn19Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaStop)); namedInsert( "icn19Dummy", QStyle::SP_MediaStop );
insert( "icn20Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowLeft)); namedInsert( "icn20Dummy", QStyle::SP_ArrowLeft );
insert( "icn21Dummy", QApplication::style()->standardIcon(QStyle::SP_DockWidgetCloseButton)); namedInsert( "icn21Dummy", QStyle::SP_DockWidgetCloseButton );
insert( "icn22Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaVolume)); namedInsert( "icn22Dummy", QStyle::SP_MediaVolume );
insert( "icn23Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowRight)); namedInsert( "icn23Dummy", QStyle::SP_ArrowRight );
insert( "icn24Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveCDIcon)); namedInsert( "icn24Dummy", QStyle::SP_DriveCDIcon );
insert( "icn25Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaVolumeMuted)); namedInsert( "icn25Dummy", QStyle::SP_MediaVolumeMuted );
insert( "icn26Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowUp)); namedInsert( "icn26Dummy", QStyle::SP_ArrowUp );
insert( "icn27Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveDVDIcon)); namedInsert( "icn27Dummy", QStyle::SP_DriveDVDIcon );
insert( "icn28Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical)); namedInsert( "icn28Dummy", QStyle::SP_MessageBoxCritical );
insert( "icn29Dummy", QApplication::style()->standardIcon(QStyle::SP_BrowserReload)); namedInsert( "icn29Dummy", QStyle::SP_BrowserReload );
insert( "icn30Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveFDIcon)); namedInsert( "icn30Dummy", QStyle::SP_DriveFDIcon );
insert( "icn31Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation)); namedInsert( "icn31Dummy", QStyle::SP_MessageBoxInformation );
insert( "icn32Dummy", QApplication::style()->standardIcon(QStyle::SP_BrowserStop)); namedInsert( "BrowserStop", QStyle::SP_BrowserStop );
insert( "icn33Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveHDIcon)); namedInsert( "icn33Dummy", QStyle::SP_DriveHDIcon );
insert( "icn34Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion)); namedInsert( "icn34Dummy", QStyle::SP_MessageBoxQuestion );
insert( "icn35Dummy", QApplication::style()->standardIcon(QStyle::SP_CommandLink)); namedInsert( "CommandLink", QStyle::SP_CommandLink );
insert( "icn36Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveNetIcon)); namedInsert( "icn36Dummy", QStyle::SP_DriveNetIcon );
insert( "icn37Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning)); namedInsert( "MessageBoxWarning", QStyle::SP_MessageBoxWarning );
insert( "icn38Dummy", QApplication::style()->standardIcon(QStyle::SP_ComputerIcon)); namedInsert( "ComputerIcon", QStyle::SP_ComputerIcon );
insert( "icn39Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogBack)); namedInsert( "icn39Dummy", QStyle::SP_FileDialogBack );
insert( "icn40Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarCloseButton)); namedInsert( "icn40Dummy", QStyle::SP_TitleBarCloseButton );
insert( "icn41Dummy", QApplication::style()->standardIcon(QStyle::SP_CustomBase)); namedInsert( "icn42Dummy", QStyle::SP_FileDialogContentsView );
insert( "icn42Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogContentsView)); namedInsert( "icn43Dummy", QStyle::SP_TitleBarContextHelpButton );
insert( "icn43Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarContextHelpButton)); namedInsert( "DesktopIcon", QStyle::SP_DesktopIcon );
insert( "icn44Dummy", QApplication::style()->standardIcon(QStyle::SP_DesktopIcon)); namedInsert( "icn45Dummy", QStyle::SP_FileDialogDetailedView );
insert( "icn45Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogDetailedView)); namedInsert( "icn46Dummy", QStyle::SP_TitleBarMaxButton );
insert( "icn46Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarMaxButton)); namedInsert( "icn47Dummy", QStyle::SP_DialogApplyButton );
insert( "icn47Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogApplyButton)); namedInsert( "icn48Dummy", QStyle::SP_FileDialogEnd );
insert( "icn48Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogEnd)); namedInsert( "icn49Dummy", QStyle::SP_TitleBarMenuButton );
insert( "icn49Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarMenuButton)); namedInsert( "icn50Dummy", QStyle::SP_DialogCancelButton );
insert( "icn50Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogCancelButton)); namedInsert( "icn51Dummy", QStyle::SP_FileDialogInfoView );
insert( "icn51Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogInfoView)); namedInsert( "icn52Dummy", QStyle::SP_TitleBarMinButton );
insert( "icn52Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarMinButton)); namedInsert( "icn53Dummy", QStyle::SP_DialogCloseButton );
insert( "icn53Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogCloseButton)); namedInsert( "icn54Dummy", QStyle::SP_FileDialogListView );
insert( "icn54Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogListView)); namedInsert( "icn55Dummy", QStyle::SP_TitleBarNormalButton );
insert( "icn55Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarNormalButton)); namedInsert( "icn56Dummy", QStyle::SP_DialogDiscardButton );
insert( "icn56Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogDiscardButton)); namedInsert( "icn57Dummy", QStyle::SP_FileDialogNewFolder );
insert( "icn57Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogNewFolder)); namedInsert( "icn58Dummy", QStyle::SP_TitleBarShadeButton );
insert( "icn58Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarShadeButton)); namedInsert( "icn59Dummy", QStyle::SP_DialogHelpButton );
insert( "icn59Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogHelpButton)); namedInsert( "icn60Dummy", QStyle::SP_FileDialogStart );
insert( "icn60Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogStart)); namedInsert( "icn61Dummy", QStyle::SP_TitleBarUnshadeButton );
insert( "icn61Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarUnshadeButton)); namedInsert( "icn62Dummy", QStyle::SP_DialogNoButton );
insert( "icn62Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogNoButton)); namedInsert( "icn63Dummy", QStyle::SP_FileDialogToParent );
insert( "icn63Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogToParent)); namedInsert( "icn64Dummy", QStyle::SP_ToolBarHorizontalExtensionButton );
insert( "icn64Dummy", QApplication::style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton)); namedInsert( "icn65Dummy", QStyle::SP_DialogOkButton );
insert( "icn65Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogOkButton)); namedInsert( "FileIcon", QStyle::SP_FileIcon );
insert( "FileIcon", QApplication::style()->standardIcon(QStyle::SP_FileIcon)); namedInsert( "icn67Dummy", QStyle::SP_ToolBarVerticalExtensionButton );
insert( "icn67Dummy", QApplication::style()->standardIcon(QStyle::SP_ToolBarVerticalExtensionButton)); namedInsert( "icn68Dummy", QStyle::SP_DialogResetButton );
insert( "icn68Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogResetButton)); namedInsert( "icn70Dummy", QStyle::SP_FileLinkIcon );
insert( "icn70Dummy", QApplication::style()->standardIcon(QStyle::SP_FileLinkIcon)); namedInsert( "TrashIcon", QStyle::SP_TrashIcon );
insert( "TrashIcon", QApplication::style()->standardIcon(QStyle::SP_TrashIcon)); namedInsert( "icn72Dummy", QStyle::SP_DialogSaveButton );
insert( "icn72Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogSaveButton)); namedInsert( "icn73Dummy", QStyle::SP_MediaPause );
insert( "icn73Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaPause)); namedInsert( "VistaShield", QStyle::SP_VistaShield );
insert( "icn74Dummy", QApplication::style()->standardIcon(QStyle::SP_VistaShield)); namedInsert( "icn75Dummy", QStyle::SP_DialogYesButton );
insert( "icn75Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogYesButton)); namedInsert( "icn76Dummy", QStyle::SP_MediaPlay );
insert( "icn76Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaPlay)); namedInsert( "icn77Dummy", QStyle::SP_DirClosedIcon );
insert( "icn77Dummy", QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon)); namedInsert( "icn79Dummy", QStyle::SP_MediaSeekBackward );
insert( "icn79Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSeekBackward)); namedInsert( "DirHomeIcon", QStyle::SP_DirHomeIcon );
insert( "DirHomeIcon", QApplication::style()->standardIcon(QStyle::SP_DirHomeIcon)); namedInsert( "icn81Dummy", QStyle::SP_MediaSeekForward );
insert( "icn81Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSeekForward));
/* /*
auto from = to_underlying(QIcon::ThemeIcon::AddressBookNew); auto from = to_underlying(QIcon::ThemeIcon::AddressBookNew);
auto to = to_underlying(QIcon::ThemeIcon::NThemeIcons); auto to = to_underlying(QIcon::ThemeIcon::NThemeIcons);
@@ -134,8 +136,22 @@ namespace XQAppData
} }
}; void namedInsert( const QString& key, QStyle::StandardPixmap pixmapID )
{
QIcon icon = QApplication::style()->standardIcon( pixmapID );
insert( key, icon );
_keysToNames.insert( icon.cacheKey(), key );
}
QString iconName( const QIcon& icon )
{
return _keysToNames[icon.cacheKey()];
}
protected:
QMap<qint64,QString> _keysToNames;
};
@@ -150,102 +166,24 @@ namespace XQAppData
static XQAppIconMap s_IconMap; static XQAppIconMap s_IconMap;
bool hasTypeIcon(const QString& key )
{
if(s_IconMap.isEmpty())
s_IconMap.init();
return !key.isEmpty() && s_IconMap.contains(key);
}
QIcon typeIcon(const QString& key ) QIcon typeIcon(const QString& key )
{ {
if( hasTypeIcon(key) ) if(s_IconMap.isEmpty())
s_IconMap.init();
if( s_IconMap.contains(key) )
return s_IconMap[key]; return s_IconMap[key];
return QApplication::style()->standardIcon(QStyle::SP_TrashIcon);
return QApplication::style()->standardIcon( QStyle::SP_TrashIcon);
} }
QString iconName( const QIcon& icon )
/* {
{ "icnFolder" , QApplication::style()->standardIcon(QStyle::SP_DirIcon) }, if(s_IconMap.isEmpty())
{ "icnFolder" , QApplication::style()->standardIcon(QStyle::SP_DirIcon"); s_IconMap.init();
{ "icn02Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogBack"); return s_IconMap.iconName(icon);
{ "icn03Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogContentsView");
{ "icn04Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogDetailedView");
{ "icn05Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogEnd");
{ "icn06Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogInfoView");
{ "icn07Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogListView");
{ "icn08Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogNewFolder");
{ "icn09Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogStart");
{ "icn10Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogToParent");
{ "icn11Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowBack");
{ "icn12Dummy", QApplication::style()->standardIcon(QStyle::SP_DirIcon");
{ "icn13Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSkipBackward");
{ "icn14Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowDown");
{ "icn15Dummy", QApplication::style()->standardIcon(QStyle::SP_DirLinkIcon");
{ "icn16Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSkipForward");
{ "icn17Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowForward");
{ "icn18Dummy", QApplication::style()->standardIcon(QStyle::SP_DirOpenIcon");
{ "icn19Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaStop");
{ "icn20Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowLeft");
{ "icn21Dummy", QApplication::style()->standardIcon(QStyle::SP_DockWidgetCloseButton");
{ "icn22Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaVolume");
{ "icn23Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowRight");
{ "icn24Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveCDIcon");
{ "icn25Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaVolumeMuted");
{ "icn26Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowUp");
{ "icn27Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveDVDIcon");
{ "icn28Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical");
{ "icn29Dummy", QApplication::style()->standardIcon(QStyle::SP_BrowserReload");
{ "icn30Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveFDIcon");
{ "icn31Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation");
{ "icn32Dummy", QApplication::style()->standardIcon(QStyle::SP_BrowserStop");
{ "icn33Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveHDIcon");
{ "icn34Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion");
{ "icn35Dummy", QApplication::style()->standardIcon(QStyle::SP_CommandLink");
{ "icn36Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveNetIcon");
{ "icn37Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning");
{ "icn38Dummy", QApplication::style()->standardIcon(QStyle::SP_ComputerIcon");
{ "icn39Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogBack");
{ "icn40Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarCloseButton");
{ "icn41Dummy", QApplication::style()->standardIcon(QStyle::SP_CustomBase");
{ "icn42Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogContentsView");
{ "icn43Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarContextHelpButton");
{ "icn44Dummy", QApplication::style()->standardIcon(QStyle::SP_DesktopIcon");
{ "icn45Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogDetailedView");
{ "icn46Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarMaxButton");
{ "icn47Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogApplyButton");
{ "icn48Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogEnd");
{ "icn49Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarMenuButton");
{ "icn50Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogCancelButton");
{ "icn51Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogInfoView");
{ "icn52Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarMinButton");
{ "icn53Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogCloseButton");
{ "icn54Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogListView");
{ "icn55Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarNormalButton");
{ "icn56Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogDiscardButton");
{ "icn57Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogNewFolder");
{ "icn58Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarShadeButton");
{ "icn59Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogHelpButton");
{ "icn60Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogStart");
{ "icn61Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarUnshadeButton");
{ "icn62Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogNoButton");
{ "icn63Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogToParent");
{ "icn64Dummy", QApplication::style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton");
{ "icn65Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogOkButton");
{ "icn66Dummy", QApplication::style()->standardIcon(QStyle::SP_FileIcon");
{ "icn67Dummy", QApplication::style()->standardIcon(QStyle::SP_ToolBarVerticalExtensionButton");
{ "icn68Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogResetButton");
{ "icn70Dummy", QApplication::style()->standardIcon(QStyle::SP_FileLinkIcon");
{ "icn71Dummy", QApplication::style()->standardIcon(QStyle::SP_TrashIcon");
{ "icn72Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogSaveButton");
{ "icn73Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaPause");
{ "icn74Dummy", QApplication::style()->standardIcon(QStyle::SP_VistaShield");
{ "icn75Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogYesButton");
{ "icn76Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaPlay");
{ "icn77Dummy", QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon");
{ "icn79Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSeekBackward");
{ "icn80Dummy", QApplication::style()->standardIcon(QStyle::SP_DirHomeIcon");
{ "icn81Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSeekForward)}
} }
*/
}; // namespace XQAppData }; // namespace XQAppData

View File

@@ -20,6 +20,7 @@
#include <QMap> #include <QMap>
#include <QStringView> #include <QStringView>
#include <QIcon> #include <QIcon>
#include <pugixml.hpp> #include <pugixml.hpp>
const QString c_Version = "0.1.1 04.09.2024"; const QString c_Version = "0.1.1 04.09.2024";
@@ -27,6 +28,8 @@ const QString c_Version = "0.1.1 04.09.2024";
const QString c_ItemType = "ItemType"; const QString c_ItemType = "ItemType";
const QString c_Caption = "Caption"; const QString c_Caption = "Caption";
const QString c_Header = "Header"; const QString c_Header = "Header";
const QString c_ContentType = "ContentType";
const QString c_ModelSheet = "ModelSheet";
const QString c_MainModelName = "DocumentTreeModel"; const QString c_MainModelName = "DocumentTreeModel";
const QString c_ChildModelName = "DocumentDetailsModel"; const QString c_ChildModelName = "DocumentDetailsModel";
@@ -46,8 +49,8 @@ namespace XQAppData
{ {
//class XQAppIconMap; //class XQAppIconMap;
bool hasTypeIcon(const QString& key );
QIcon typeIcon(const QString& key ); QIcon typeIcon(const QString& key );
QString iconName( const QIcon& icon );
} }
#endif // XQAPPDATA_H #endif // XQAPPDATA_H

View File

@@ -31,72 +31,7 @@ XQChildModel::XQChildModel( QObject *parent )
} }
//! erzeugt die basisstruktur des models. //! erzegt den sichtbaren inhalt des models aus einem root-datenknoten.
void XQChildModel::initModel(const QString& modelName)
{
auto extendItemType = [=,this](const XQNodePtr& entry)
{
const QString& typeName = entry->attribute("ItemType");
XQItemType* itemType = _itemFactory.findItemTypeTemplate( typeName); // throws
// über alle attribute
for (const auto& attr : entry->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 = _itemFactory.makeVariant(role,attr.second);
itemType->replaceAttribute( newValue, role );
}
}
};
// #0: Wir suchen die Model-Beschreibung
XQNodePtr modelSheet = _itemFactory.findModelSheet( modelName ); // throws
// #1: Wir erzeugen die Model-Struktur: Jedes Kind beschreibt einen
// XML-Datentyp, z.B. <Panel atr1="..." />, <Battery .../>
// Jeder XML-Knoten entspricht einer Zeile im späteren Model, jedes
// Attribut wird einem eigenen Feld (XQItem) abgebildet.
for( const auto& sheetNode : modelSheet->children() )
{
XQItemList list = _itemFactory.makeHeaderRow( sheetNode );
// für jeden XML-Knotentyp in der Modelbeschreibung erzeugen wir eine section
addSection(list, sheetNode );
// jedes kind kann enthält einen itemType und einen headerItemType. Für
// diese sind eventuell weitere attribute vorhanden, die die im type
// enthaltenen defualt-werte überschreiben.
for( const auto& sheetChild : sheetNode->children() )
{
//qDebug() << "---- kloppo: " << sheetChild->tag_name() << ": " << sheetChild->to_string();
extendItemType( sheetChild );
}
/*
// empty row:
XQNodePtr contentNode = XQNode::make_node( sheetNode->tag_name() );
XQItemList emptyRow = _itemFactory.makeEmptyRow( contentNode, sheetNode );
appendRow( emptyRow );
*/
} // for
}
//! erzegut den sichtbaren inhalt des models aus einem root-datenknoten.
void XQChildModel::setContent( const XQNodePtr& contentRoot ) void XQChildModel::setContent( const XQNodePtr& contentRoot )
{ {
@@ -108,8 +43,8 @@ void XQChildModel::setContent( const XQNodePtr& contentRoot )
// Die Datenbasis als shared_ptr sichern // Die Datenbasis als shared_ptr sichern
_contentRoot = contentRoot; _contentRoot = contentRoot;
// Wir gehen über alle Einträge, die verschiedenen Typen // Wir gehen über alle Einträge, die auch unterschiedliche Typen
// haben, hier: <Panel>. <Battery> ... // haben können, hier: <Panel>. <Battery> ...
for (const auto& contentEntry : _contentRoot->children()) for (const auto& contentEntry : _contentRoot->children())
{ {
// Das ist hier der Typ des Eintrags: Panel, Battery ... // Das ist hier der Typ des Eintrags: Panel, Battery ...
@@ -124,11 +59,13 @@ void XQChildModel::setContent( const XQNodePtr& contentRoot )
// wir speichern das parent des datenknoten auch in der // wir speichern das parent des datenknoten auch in der
// section. // section.
// contentEntry->parent == _contentRoot, aber halt nur weil das model flach ist // contentEntry->parent == _contentRoot, aber halt nur weil das model flach ist
section.contentRootNode = contentEntry->parent(); section.setContentRootNode( contentEntry->parent() );
int newRow = _sections.lastRow(section); int newRow = _sections.lastRow(section);
//qDebug() << " --- AHJA: " << key << " -- last Row dazu: " << newRow; XQNodePtr node = section.sheetRootNode();
XQItemList list = _itemFactory.makeContentRow( contentEntry, section.sheetRootNode ); XQItemList list = _itemFactory.makeContentRow( node, contentEntry );
//XQItemList list = _itemFactory.makeContentRow( section.sheetRootNode, contentEntry );
// als Baum? // als Baum?
//section.headerItem().appendRow( list ); //section.headerItem().appendRow( list );
insertRow( newRow, list); insertRow( newRow, list);

View File

@@ -29,13 +29,10 @@ public:
explicit XQChildModel(QObject *parent = nullptr); explicit XQChildModel(QObject *parent = nullptr);
virtual ~XQChildModel() = default; virtual ~XQChildModel() = default;
void initModel(const QString& modelName) override;
void setContent(const XQNodePtr& contentRoot ); void setContent(const XQNodePtr& contentRoot );
protected: protected:
//void setupViewProperties() override; //void setupViewProperties() override;
void initContextMenu() override; void initContextMenu() override;

View File

@@ -34,54 +34,6 @@ XQMainModel::XQMainModel(QObject *parent )
} }
//! initialisiert dieses model über den namen.
void XQMainModel::initModel(const QString& modelName)
{
// model rootnode finden -> <DocumentTreeModel>
XQNodePtr modelSheet = _itemFactory.findModelSheet( modelName ); // throws
// #1: über alle sections
for( auto& section : modelSheet->children() )
{
// #2: (optionalen) header erzeugen
const XQNodePtr header = section->find_child_by_tag_name( "Header");
if( header )
{
XQItemList list = _itemFactory.makeHeader( header );
Q_ASSERT(!list.isEmpty());
addSection(list, section );
}
}
}
//! erzeugt einen eintrag in der baum-übersicht.
XQItem* XQMainModel::createTreeEntry( XQNodePtr contentNode )
{
for(const auto& section : _sections )
{
qDebug() << " --- wtf1: " << contentNode->to_string();
qDebug() << " --- wtf2: " << section.sheetRootNode->to_string();
if( contentNode->attribute("State") == section.sheetRootNode->attribute("State") )
{
XQItem* newTreeentry = _itemFactory.makeTreeChildItem( contentNode, section.sheetRootNode );
section.headerItem().appendRow( newTreeentry );
_treeTable->expand( section.modelIndex );
// ??
_treeTable->setCurrentIndex( section.modelIndex );
newTreeentry->setContentNode(contentNode);
emit xqItemCreated( newTreeentry );
return newTreeentry;
}
}
throw XQException( "createTreeEntry: main model should not be emtpy!" );
}
//! leere default implementation //! leere default implementation
void XQMainModel::initContextMenu() void XQMainModel::initContextMenu()
@@ -89,3 +41,55 @@ void XQMainModel::initContextMenu()
} }
//! erzeugt einen eintrag in der baum-übersicht.
XQItem* XQMainModel::addProjectItem( XQNodePtr contentNode )
{
// wir durchsuchen alle unsere section nach dem passenden content-type,
// hier: content-type beschreibt die
/*
for(const auto& section : _sections )
{
if( contentNode->attribute( c_ContentType) == section.contentType() )
{
const QString* contentPtr = contentNode->attribute_ptr( "ProjectName" );
// __fixme! das ist mist!
const XQNodePtr sheetNode = section.sheetRootNode()->first_child();
XQItemList list = _itemFactory.makeHeaderRow( sheetNode, contentPtr );
// erzeuger sheet node speichern
//newItem->setSheetNode( sheetNode );
// den neuen eintrag in die passende section der übersicht eintragen ...
section.headerItem().appendRow( list );
// ... ausklappen...
const QModelIndex index = section.headerItem().index();
_treeTable->expand( index );
// ... und markieren
_treeTable->setCurrentIndex( index );
// quellknoten auch speichern
//newItem->setContentNode( contentNode );
//emit itemCreated( newItem );
return list[0];
}
}
. */
throw XQException( "addProjectItem: main model should not be empty!" );
}
void XQMainModel::addSectionItem( const XQModelSection& section, XQItem* projectItem )
{
/*
XQNodePtr sheetNode = projectItem->sheetNode()->find_child_by_tag_name("CurrentSection");
XQItem* newItem = _itemFactory.makeItem(sheetNode, &section.contentType() );
projectItem->appendRow( newItem );
_treeTable->expand( projectItem->index() );
*/
}

View File

@@ -32,10 +32,8 @@ public:
explicit XQMainModel(QObject *parent = nullptr); explicit XQMainModel(QObject *parent = nullptr);
virtual ~XQMainModel() = default; virtual ~XQMainModel() = default;
void initModel(const QString& modelName) override; XQItem* addProjectItem( XQNodePtr contentNode );
XQItem* createTreeEntry( XQNodePtr contentNode ); void addSectionItem( const XQModelSection& section, XQItem* projectItem );
public slots:
protected: protected:

View File

@@ -15,12 +15,14 @@
#include <QDebug> #include <QDebug>
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton>
#include <xqmainwindow.h> #include <xqmainwindow.h>
#include <xqcommand.h> #include <xqcommand.h>
#include <xqexception.h> #include <xqexception.h>
#include <xqitemfactory.h> #include <xqitemfactory.h>
#include <xqnodewriter.h> #include <xqnodewriter.h>
#include <xqquickwidget.h>
//! konstruktor. //! konstruktor.
@@ -34,12 +36,34 @@ XQMainWindow::XQMainWindow( QWidget* parent )
} }
// setzt das working directory: dieses muss das 'xml' datenverzeichnis enthalten.
void XQMainWindow::setupWorkingDir()
{
QDir dir = QDir::current();
while (dir.exists())
{
QString xmlPath = dir.absoluteFilePath("xml");
if (QDir(xmlPath).exists())
{
qDebug() << " --- CD TO: " << dir.absolutePath();
QDir::setCurrent( dir.absolutePath() );
}
if (!dir.cdUp())
return;
}
}
//! actions & document struktur einrichten. //! actions & document struktur einrichten.
void XQMainWindow::initMainWindow() void XQMainWindow::initMainWindow()
{ {
qDebug() << " --- initMainWindow(): here we go!"; qDebug() << " --- initMainWindow(): here we go!";
// das working dir setzen: 'xml' muss als unterverzeichnis vorhanden sein.
setupWorkingDir();
// als allererstes laden wir die Modelschreibungen // als allererstes laden wir die Modelschreibungen
XQItemFactory::instance().initItemFactory( c_ModelSheetFileName ); XQItemFactory::instance().initItemFactory( c_ModelSheetFileName );
@@ -67,8 +91,18 @@ void XQMainWindow::initMainWindow()
connect( _mainTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onTreeItemClicked(QModelIndex)) ); connect( _mainTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onTreeItemClicked(QModelIndex)) );
connect( _tabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(onTabClicked(int)) ); connect( _tabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(onTabClicked(int)) );
connect( _tabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(onTabClicked(int)) );
connect( &_mainModelView, &XQViewModel::xqItemCreated, this, [=, this](XQItem* item) /*
XQQuickWidget* butt = new XQQuickWidget;
butt->resize(800,600);
butt->setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint);
butt->move( 1200,300);
butt->show();
*/
/*
connect( &_mainModelView, &XQViewModel::itemCreated, this, [=, this](XQItem* item)
{ {
// when a new main tree item has been created ... // when a new main tree item has been created ...
QString pID = item->contentNode()->attribute(c_ProjectID); QString pID = item->contentNode()->attribute(c_ProjectID);
@@ -77,6 +111,7 @@ void XQMainWindow::initMainWindow()
if( _documentStore.contains( pID ) ) if( _documentStore.contains( pID ) )
_tabWidget->setCurrentWidget( _documentStore[pID].modelView->treeTable() ); _tabWidget->setCurrentWidget( _documentStore[pID].modelView->treeTable() );
} ); } );
*/
try try
{ {
@@ -222,15 +257,19 @@ void XQMainWindow::onTreeItemClicked(const QModelIndex& index )
XQItem& entry = XQItem::xqItemFromIndex(index); XQItem& entry = XQItem::xqItemFromIndex(index);
qDebug() << " --- mainWindow onTreeItemClicked:" << entry.text(); qDebug() << " --- XXX mainWindow onTreeItemClicked:" << entry.text();
_mainTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
return; if( XQNodePtr contentNode = entry.contentNode() )
//_mainTreeView->selectionModel()->select(index, QItemSelectionModel::Select); {
//entry->setBackground( QBrush( Qt::green ) ); QString key = contentNode->attribute(c_ProjectID);
qDebug() << " --- FIRZ: key: " << key;
QString key = entry.attribute(c_ProjectID); bool isThere = _documentStore.contains(key);
if( _documentStore.contains(key) ) if( isThere)
_tabWidget->setCurrentWidget( _documentStore[key].modelView->treeTable() ); _tabWidget->setCurrentWidget( _documentStore[key].modelView->treeTable() );
}
} }
@@ -239,35 +278,46 @@ void XQMainWindow::onTreeItemClicked(const QModelIndex& index )
void XQMainWindow::onTabClicked( int index ) void XQMainWindow::onTabClicked( int index )
{ {
const QString& key = _documentStore[index].treeItem->attribute( c_ProjectID ); //const QString& key = _documentStore[index].treeItem->attribute( c_ProjectID );
qDebug() << " ---- tab clicked: " << index << " : " << _documentStore[index].friendlyName << ": " << key; qDebug() << " ---- tab clicked: " << index << " : " << _documentStore[index].friendlyName;// << ": " << key;
_mainTreeView->setCurrentIndex( _documentStore[index].treeItem->index() ); //_mainTreeView->setCurrentIndex( _documentStore[index].treeItem->index() );
} }
void XQMainWindow::onSectionCreated( const XQModelSection& section )
{
if( _currentProjectItem )
{
_mainModelView.addSectionItem( section, _currentProjectItem );
}
}
void XQMainWindow::onSectionToggled( const XQModelSection& section )
{
//qDebug() << " --- XXX section toggled: " << section.contentType() << ":" << section.sheetRootNode()->to_string();
}
//! liest eine XML datei namens 'fileName' //! liest eine XML datei namens 'fileName'
void XQMainWindow::loadDocument( const QString& fileName ) void XQMainWindow::loadDocument( const QString& fileName )
{ {
// gibts die Datei? // gibts die Datei?
if( !QFile::exists( fileName) ) if( !QFile::exists( fileName) )
throw XQException( "no such file", fileName ); throw XQException( "no such file", fileName );
// load data tree from xml file
XQNodeFactory treeLoader; XQNodeFactory treeLoader;
// xml daten laden
XQNodePtr rawTree = treeLoader.load_tree( qPrintable(fileName) ); XQNodePtr rawTree = treeLoader.load_tree( qPrintable(fileName) );
// versteckten root node ignorieren // versteckten root node ignorieren
XQNodePtr contentRoot = rawTree->first_child(); XQNodePtr contentRoot = rawTree->first_child();
// Project-ID behandeln // Project-ID behandeln
const QString& pID = contentRoot->attribute(c_ProjectID); const QString& pID = contentRoot->attribute(c_ProjectID);
int idx = _documentStore.indexOf( pID ); int idx = _documentStore.indexOf( pID );
if( idx > -1 ) if( idx > -1 )
{ {
const XQDocument& doc = _documentStore.at(idx); const XQDocument& document = _documentStore.at(idx);
QMessageBox::warning( this, "Load Document", QString("File: %1 already loaded.").arg( fileName ) ); QMessageBox::warning( this, "Load Document", QString("File: %1 already loaded.").arg( fileName ) );
_mainTreeView->setCurrentIndex( doc.treeItem->index() ); _mainTreeView->setCurrentIndex( document.treeItem->index() );
_tabWidget->setCurrentIndex( idx ); _tabWidget->setCurrentIndex( idx );
return; return;
} }
@@ -285,21 +335,28 @@ void XQMainWindow::loadDocument( const QString& fileName )
// Ein neues Child-Model erzeugen // Ein neues Child-Model erzeugen
XQChildModel* childModel = new XQChildModel(this); XQChildModel* childModel = new XQChildModel(this);
// die Modelstruktur anlegen
childModel->initModel( c_ChildModelName ); connect( childModel, SIGNAL(sectionCreated(XQModelSection)), this, SLOT(onSectionCreated(XQModelSection)) );
connect( childModel, SIGNAL(sectionToggled(XQModelSection)), this, SLOT(onSectionToggled(XQModelSection)) );
// Den globalen undo-stack ... // Den globalen undo-stack ...
childModel->setUndoStack(&_undoStack); childModel->setUndoStack(&_undoStack);
// und die TreeView übergeben // und die TreeView übergeben
childModel->setTreeTable(childTreeView); childModel->setTreeTable(childTreeView);
// read the model data // neuen eintrag im übsichts-baum erzeugen
//_currentProjectItem = _mainModelView.addProjectItem( contentRoot );
//_documentStore.addDocument( fileName, pTitle, _currentProjectItem, childModel );
qDebug() << " --- ZZZ und jetzt:";
// die Modelstruktur anlegen
childModel->initModel( c_ChildModelName );
// model inhalte laden
childModel->setContent( contentRoot->first_child() ); childModel->setContent( contentRoot->first_child() );
// create new entry in the left side main tree view
XQItem* newEntry = _mainModelView.createTreeEntry( contentRoot );
_mainTreeView->setCurrentIndex( newEntry->index() );
_documentStore.addDocument( fileName, pTitle, newEntry, childModel );
} }

View File

@@ -48,18 +48,26 @@ public slots:
void onTreeItemClicked(const QModelIndex& index ); void onTreeItemClicked(const QModelIndex& index );
void onTabClicked( int index ); void onTabClicked( int index );
//void onItemCreated( XQItem* item );
void onSectionCreated( const XQModelSection& section);
void onSectionToggled( const XQModelSection& section );
protected: protected:
void setupWorkingDir();
// fixme implement // fixme implement
void showDocumnet( const QString& key ){} void showDocumnet( const QString& key ){}
void loadDocument( const QString& fileName ); void loadDocument( const QString& fileName );
void saveDocument( const QString& fileName ); void saveDocument( const QString& fileName );
QUndoStack _undoStack; QUndoStack _undoStack;
XQDocumentStore _documentStore; XQDocumentStore _documentStore;
XQMainModel _mainModelView; XQMainModel _mainModelView;
XQItem* _currentProjectItem{};
}; };

View File

@@ -136,14 +136,6 @@ XQItem::XQItem(XQItemType* itemType, const QString *content )
setContent(content); setContent(content);
} }
// Warum beides?
XQItem::XQItem(XQItemType* itemType, const QString *content, const XQNodePtr& contentNode )
: XQItem{ itemType, content }
{
setContentNode(contentNode);
}
//! ruft den copy-konstruktor auf. //! ruft den copy-konstruktor auf.
XQItem* XQItem::clone() const XQItem* XQItem::clone() const
@@ -166,7 +158,10 @@ bool XQItem::isValid() const
XQNodePtr XQItem::contentNode() const XQNodePtr XQItem::contentNode() const
{ {
return data( ContentNodeRole ).value<XQNodePtr>(); XQNodePtr node = data( ContentNodeRole ).value<XQNodePtr>();
if( node )
return node;
throw XQException("XQItem::contentNode() nullptr");
} }
@@ -193,32 +188,6 @@ void XQItem::setSheetNode(const XQNodePtr& sheetNode )
} }
//! tested, ob ein attribut mit dem namen 'attribKey' vorhanden ist.
bool XQItem::hasAttribute( const QString& attribKey ) const
{
return contentNode()->has_attribute( attribKey );
}
//! gibt das attribut namens 'attribKey' zurück, sofern vorhanden, sonst 'defaultValue'
const QString& XQItem::attribute( const QString& attribKey, const QString& defaultValue ) const
{
if( !hasAttribute(attribKey ) )
return defaultValue;
return contentNode()->attribute( attribKey );
}
//! tested, ob das attribut namens 'attribKey' dem wert 'attribValue' entspricht.
bool XQItem::testAttribute( const QString& attribKey, const QString& attribValue ) const
{
return contentNode()->test_attribute( attribKey, attribValue );
}
//! gibt eine referenz auf den itemType dieses items zurück. //! gibt eine referenz auf den itemType dieses items zurück.
XQItemType& XQItem::itemType() const XQItemType& XQItem::itemType() const
@@ -257,6 +226,14 @@ void XQItem::clearFlag( Qt::ItemFlag newFlag )
setFlags( flags() & ~newFlag); setFlags( flags() & ~newFlag);
} }
//! gibt die itemFlags als string zurück.
QString XQItem::itemFlagsToString() const
{
return'(' + data(XQItem::FlagsRole).toString() +')';
}
/// ///
/// data() access shortcuts /// data() access shortcuts
/// ///
@@ -277,6 +254,7 @@ QString XQItem::renderStyleToString() const
} }
//! setzt den editorType. wird im itemType gespeichert. //! setzt den editorType. wird im itemType gespeichert.
void XQItem::setRenderStyle(RenderStyle renderStyle ) void XQItem::setRenderStyle(RenderStyle renderStyle )
@@ -332,18 +310,20 @@ void XQItem::setUnitType(UnitType unitType)
} }
//! gibt den content-string zurück. das ist ein derefenzierter pointer //! Verweist auf data(Qt::EditRole). Das ist der unformatierte text.
//! auf das zu diesem item gehörige daten-attribut 'useres' datenknotens.
const QString& XQItem::content() const QString XQItem::rawText() const
{ {
const QString* contentPtr = QStandardItem::data( XQItem::ContentRole ).value<const QString*>(); return data( Qt::EditRole ).toString();
if(contentPtr) }
return *contentPtr;
static const QString s_dummyContent("-");
return s_dummyContent; //! Gibt den string-zeiger auf das attribut aus unseren XQNodePtr zurück.
QString* XQItem::content() const
{
// macht jetzt das, ws draufsteht: gibt einen string* zurück
return data( XQItem::ContentRole ).value<QString*>();
} }
@@ -357,9 +337,9 @@ void XQItem::setContent( const QString* content )
//! holt den schlüssel bzw. bezeicher des content() string aus 'unserem' content knoten. //! holt den schlüssel bzw. bezeicher des content() string aus 'unserem' content knoten.
const QString& XQItem::contentKey() const QString XQItem::contentKey() const
{ {
return contentNode()->attributes().key_of( content() ); return contentNode()->attributes().key_of( rawText() );
} }
//! gibt den content-format string zurück //! gibt den content-format string zurück
@@ -478,12 +458,18 @@ QVariant XQItem::data(int role ) const
case Qt::EditRole : case Qt::EditRole :
case XQItem::ContentRole: case XQItem::ContentRole:
{ {
return content();
const QString* contentPtr = QStandardItem::data( XQItem::ContentRole ).value<const QString*>();
if(contentPtr)
return *contentPtr;
static const QString s_dummyContent("-");
return s_dummyContent;
} }
case Qt::ToolTipRole: case Qt::ToolTipRole:
{ {
return content() + ":" + itemType().text() + ":" + renderStyleToString() + ":" + unitTypeToString(); return rawText() + ":" + unitTypeToString() + ":" + renderStyleToString() + ":" + unitTypeToString() + ":" + itemFlagsToString();
} }
// //
@@ -571,30 +557,24 @@ void XQItem::setData(const QVariant& value, int role )
return; return;
} }
// DAS PASSIERT NIE, AUSSER
// set the raw, unformatted data // set the raw, unformatted data
case ContentRole: case ContentRole:
{ {
// what will happen? value is a string ptr ?!
//qDebug() << " --- setting content: " << value.toString();
// string ptr setzen kann die basis. // string ptr setzen kann die basis.
break; break;
return;
} }
case Qt::EditRole : case Qt::EditRole :
{ {
// what will happen? value is a string ptr ?! qDebug() << " --- setting EDITrole: " << value.toString();
qDebug() << " --- setting editrole: " << value.toString(); break;
return;
} }
case Qt::DisplayRole : case Qt::DisplayRole :
{ {
// what will happen? value is a string ptr ?! // what will happen? value is a string ptr ?!
qDebug() << " --- setting DISPLAYrole: " << value.toString(); qDebug() << " --- setting DISPLAYrole: " << value.toString();
// ignore this break;
return;
} }
// alles andere wie gehabt // alles andere wie gehabt
@@ -721,5 +701,6 @@ QString XQItem::fetchUnitTypeToString( UnitType unitType)
return s_UnitTypeMap[unitType]; return s_UnitTypeMap[unitType];
} }
/// ---
/// ---
/// ---

View File

@@ -35,6 +35,8 @@ class XQItemType;
class XQItem : public QStandardItem class XQItem : public QStandardItem
{ {
friend class XQItemFactory;
public: public:
/// Die data(enum role) Infrastruktur wird sowohl für XQItem als auch /// Die data(enum role) Infrastruktur wird sowohl für XQItem als auch
@@ -126,10 +128,8 @@ public:
XQItem(); XQItem();
XQItem( XQItemType* itemType ); XQItem( XQItemType* itemType );
XQItem( XQItemType* itemType, const QString* content ); XQItem( XQItemType* itemType, const QString* content );
XQItem( XQItemType* itemType, const QString* content, const XQNodePtr& contentNode );
virtual ~XQItem() = default; virtual ~XQItem() = default;
@@ -140,20 +140,12 @@ public:
//! //!
bool isValid() const; bool isValid() const;
// shortcuts auf XQNodePtr //! gibt den zu diesem item gehörigen datenknoten zurück
//! gibt den zu diesem item gehörigen datenknoten
virtual XQNodePtr contentNode() const; virtual XQNodePtr contentNode() const;
virtual void setContentNode(const XQNodePtr& contentNode );
virtual XQNodePtr sheetNode() const; virtual XQNodePtr sheetNode() const;
virtual void setSheetNode( const XQNodePtr& sheetNode ); virtual void setSheetNode( const XQNodePtr& sheetNode );
bool hasAttribute( const QString& attribKey ) const;
const QString& attribute( const QString& attribKey, const QString& defaultValue="" ) const;
bool testAttribute( const QString& attribKey, const QString& attribValue ) const;
XQItemType& itemType() const; XQItemType& itemType() const;
void setItemType( XQItemType* itemTypePtr ); void setItemType( XQItemType* itemTypePtr );
@@ -161,13 +153,14 @@ public:
// __fix! das können die selber !? // __fix! das können die selber !?
void addFlag( Qt::ItemFlag newFlag ); void addFlag( Qt::ItemFlag newFlag );
void clearFlag( Qt::ItemFlag newFlag ); void clearFlag( Qt::ItemFlag newFlag );
QString itemFlagsToString() const;
//das ist ein Sonderfall: Ein ist ein dereferenzierter Zeiger auf 'unser' Atrribut in // das ist die EditRole: unformatierter Text
// XQNodePtr, also unserem contentNode(). Das wird hier direkt aufgelöst und nicht auf QString rawText() const;
// data() umgeleitet.
const QString& content() const; // changed: gibt jetzt den pointer zurück.
const QString& contentKey() const; QString* content() const;
QString contentKey() const;
void setContent( const QString* content ); void setContent( const QString* content );
// //
@@ -245,6 +238,8 @@ protected:
XQItem(const XQItem& other) = default; XQItem(const XQItem& other) = default;
XQItem& operator=(const XQItem& other) = default; XQItem& operator=(const XQItem& other) = default;
void setContentNode(const XQNodePtr& contentNode );
using XQItemFlagMap = QMap<QString,int>; using XQItemFlagMap = QMap<QString,int>;
using XQItemDataRoleMap = QMap<QString,int>; using XQItemDataRoleMap = QMap<QString,int>;
using XQRenderStyleMap = QMap<QString,RenderStyle>; using XQRenderStyleMap = QMap<QString,RenderStyle>;
@@ -264,6 +259,9 @@ protected:
}; };
Q_DECLARE_METATYPE(XQItem::RenderStyle); Q_DECLARE_METATYPE(XQItem::RenderStyle);
Q_DECLARE_METATYPE(XQItem::EditorType); Q_DECLARE_METATYPE(XQItem::EditorType);
Q_DECLARE_METATYPE(XQItem::UnitType); Q_DECLARE_METATYPE(XQItem::UnitType);

View File

@@ -81,22 +81,6 @@ XQItem& XQItemDelegate::xqItemFromIndex( const QModelIndex& index ) const
} }
QWidget* XQItemDelegate::prepareHeaderOption(const QStyleOptionViewItem& option, const QModelIndex& index, QStyleOptionHeader& headerOption) const
{
// use the header as "parent" for style init
QWidget* srcWidget = treeTable()->header();
headerOption.initFrom(srcWidget);
headerOption.text = index.data(Qt::DisplayRole).toString();
headerOption.rect = option.rect;
headerOption.styleObject = option.styleObject;
// __ch: reduce inner offset when painting
headerOption.textAlignment |= Qt::AlignVCenter;
return srcWidget;
}
void XQItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const void XQItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{ {
if( !index.isValid() ) if( !index.isValid() )
@@ -131,11 +115,24 @@ void XQItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option
} }
//! einen section header im header-style zeichnen
void XQItemDelegate::drawHeaderStyle(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const void XQItemDelegate::drawHeaderStyle(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{ {
QStyleOptionHeader headerOption; QStyleOptionHeader headerOption;
QWidget* srcWidget = prepareHeaderOption(option, index, headerOption);
XQItem& item = xqItemFromIndex( index );
// use the header as "parent" for style init
QWidget* srcWidget = treeTable();//->header();
headerOption.initFrom(srcWidget);
headerOption.text = index.data(Qt::DisplayRole).toString();
headerOption.rect = option.rect.adjusted(0,0,0,3);
headerOption.styleObject = option.styleObject;
// __ch: reduce inner offset when painting
headerOption.textAlignment |= Qt::AlignVCenter;
headerOption.icon = item.icon();
if (srcWidget != nullptr) if (srcWidget != nullptr)
{ {
// save painter // save painter

View File

@@ -46,8 +46,6 @@ public:
protected: protected:
QWidget* prepareHeaderOption(const QStyleOptionViewItem& option, const QModelIndex& index, QStyleOptionHeader& headerOption) const;
void drawHeaderStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawHeaderStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void drawProgressBarStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawProgressBarStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void drawComboBoxStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawComboBoxStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;

View File

@@ -28,7 +28,7 @@ void XQItemFactory::initItemFactory( const QString& modelSheetFileName )
// über alle attribute // über alle attribute
for( const auto& [key,value] : sheetNode->attributes() ) for( const auto& [key,value] : sheetNode->attributes() )
{ {
qDebug() << " --- conf item Type: " << key << " : " << value; //qDebug() << " --- conf item Type: " << key << " : " << value;
setItemDataFromString( *itemType, key, value ); setItemDataFromString( *itemType, key, value );
} }
}; };
@@ -68,28 +68,31 @@ bool XQItemFactory::isValid()
} }
//! es reicht nicht, einen itemType aus den itemType-templates zu //! Es reicht nicht, einen itemType aus den itemType-templates zu
//! holen: möglicherweise muss der noch mit zusätzlichen attributen //! holen: möglicherweise muss der noch mit zusätzlichen attributen
//! ergänzt werden, (hier 'UnitType' ). //! 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 ) XQItemType* XQItemFactory::makeItemType(const XQNodePtr& sheetEntry )
{ {
QString typeKey = sheetEntry->attribute("ItemType"); QString typeKey = sheetEntry->attribute( c_ItemType );
XQItemType* itemType = findItemTypeTemplate(typeKey); XQItemType* itemType = findItemTypeTemplate(typeKey);
// wir prüfen, ob im sheetEntry noch zusätzliche attribute vorhanden // wir prüfen, ob im sheetEntry noch zusätzliche attribute vorhanden
// sind, die wir in dem itemType müssen // sind, die wir in dem itemType müssen
//qDebug() << " --- makeItemType: " << sheetEntry->to_string();
// über alle attribute // über alle attribute
for (const auto& attr : sheetEntry->attributes()) for (const auto& attrEntry : sheetEntry->attributes())
{ {
// prüfen, ob der itemType des attribute schon hat // prüfen, ob der itemType des attribute schon hat
int role = itemType->hasAttribute( attr.first); int role = itemType->roleForAttributeKey( attrEntry.first );
// wenn ja, überschreiben // wenn ja, überschreiben
if( role != XQItem::NoRole ) if( role != XQItem::NoRole )
{ {
QVariant newValue = makeVariant(role,attr.second); QVariant newValue = makeVariant(role, attrEntry.second );
itemType = itemType->replaceAttribute( newValue, role ); itemType = itemType->replaceAttribute( newValue, role );
} }
@@ -97,6 +100,8 @@ XQItemType* XQItemFactory::makeItemType(const XQNodePtr& sheetEntry )
return itemType; return itemType;
} }
//! sucht einen item typ aus der map mit 'vorgefertigen' itemtypen.
XQItemType* XQItemFactory::findItemTypeTemplate(const QString& key ) const XQItemType* XQItemFactory::findItemTypeTemplate(const QString& key ) const
{ {
if( !key.isEmpty() && s_ItemTypeTemplates.contains(key)) if( !key.isEmpty() && s_ItemTypeTemplates.contains(key))
@@ -105,6 +110,8 @@ XQItemType* XQItemFactory::findItemTypeTemplate(const QString& key ) const
} }
//! sucht eine model-beschreibung
XQNodePtr XQItemFactory::findModelSheet( const QString& modelName ) const XQNodePtr XQItemFactory::findModelSheet( const QString& modelName ) const
{ {
XQNodePtr modelSheet = _modelSheet->find_child_by_tag_name( modelName ); XQNodePtr modelSheet = _modelSheet->find_child_by_tag_name( modelName );
@@ -115,40 +122,7 @@ XQNodePtr XQItemFactory::findModelSheet( const QString& modelName ) const
} }
//! erzeugt eine QVariant aus dem gegebenen string und setzt diese dann via role im item.
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 void XQItemFactory::setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const
{ {
@@ -162,6 +136,8 @@ void XQItemFactory::setItemDataFromString( XQItem& item, const QString& roleKey,
} }
//! erzeugt eine QVariant aus dem gegebenen string
QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const
{ {
@@ -180,6 +156,7 @@ QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const
case XQItem::ItemTypeRole: case XQItem::ItemTypeRole:
{ {
// itemType() -> XQItemType* // itemType() -> XQItemType*
//qDebug() << " --- makeVariant: make ItemType: " << source;
XQItemType* itemType = findItemTypeTemplate( source ); XQItemType* itemType = findItemTypeTemplate( source );
value = QVariant::fromValue(itemType); value = QVariant::fromValue(itemType);
break; break;
@@ -201,7 +178,7 @@ QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const
case XQItem::UnitTypeRole: case XQItem::UnitTypeRole:
{ {
qDebug() << " --- make unit type: " << source; //qDebug() << " --- make unit type: " << source;
XQItem::UnitType unitType = XQItem::fetchUnitType( source ); XQItem::UnitType unitType = XQItem::fetchUnitType( source );
value = QVariant::fromValue(unitType); value = QVariant::fromValue(unitType);
break; break;
@@ -230,9 +207,7 @@ QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const
case XQItem::IconRole: case XQItem::IconRole:
{ {
QIcon typeIcon; QIcon typeIcon = XQAppData::typeIcon(source);
if(XQAppData::hasTypeIcon(source))
typeIcon = XQAppData::typeIcon(source);
value = QVariant::fromValue(typeIcon); value = QVariant::fromValue(typeIcon);
break; break;
} }
@@ -283,115 +258,10 @@ QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const
/// ///
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;
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<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 ) XQItemList XQItemFactory::makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode )
{ {
Q_UNUSED(contentNode) Q_UNUSED(contentNode)
@@ -408,8 +278,9 @@ XQItemList XQItemFactory::makeEmptyRow( const XQNodePtr& contentNode, const XQNo
return list; return list;
} }
*/
/*
XQItemList XQItemFactory::createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode ) XQItemList XQItemFactory::createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode )
{ {
@@ -429,3 +300,112 @@ XQItemList XQItemFactory::createGenericRow( const XQNodePtr& contentNode, const
return makeContentRow(contentNode, sheetNode ); return makeContentRow(contentNode, sheetNode );
} }
*/
//! erzeugt eine header-item row.
XQItemList XQItemFactory::makeHeaderRow( const XQNodePtr& sheetNode, const QString& caption )
{
XQItemList list;
for( const auto& sheetEntry : sheetNode->children() )
{
list.append( makeHeaderItem( sheetEntry, caption ) );
}
Q_ASSERT(!list.empty());
return list;
}
//! erzeugt eine item-row.
XQItemList XQItemFactory::makeContentRow( 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( makeContentItem( sheetEntry, contentNode ) );
}
Q_ASSERT(!list.empty());
// wir merken uns den original content node auch, aber
// im ersten Item.
dynamic_cast<XQItem*>(list[0])->setContentNode(contentNode);
return list;
}
XQItem* XQItemFactory::makeHeaderItem( const XQNodePtr& sheetNode, const QString& caption )
{
// den itemtype des neuen items rausfinden
XQItemType* itemType = makeItemType(sheetNode); // throws
// das ist Unterschied zum normalen Item: Der Titel kommt aus der Modelbeschreibung
// der content wird indirect über den tag-name des sheetnode geholt
XQItem* newItem = new XQItem( itemType, sheetNode->attribute_ptr(caption) );
// __fixme!
if( newItem->isCheckable() )
newItem->setCheckState( Qt::Checked );
return newItem;
}
//! fixme! unsinn!
//! 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, das erzeugt wurde.
XQItem* XQItemFactory::makeContentItem( const XQNodePtr& sheetNode, const XQNodePtr& contentNode )
{
// den itemtype des neuen items rausfinden
XQItemType* itemType = makeItemType(sheetNode); // throws
// das ist Unterschied zum normalen Item: Der Titel kommt aus der Modelbeschreibung
// der content wird indirect über den tag-name des sheetnode geholt
// das ist Unterschied vom HeaderItem zum normalen Item: Der Titel kommt aus der Modelbeschreibung
if(!contentNode)
return makeItem( sheetNode, sheetNode->attribute_ptr(c_Caption) );
// der content wird indirect über den tag-name des sheetnode geholt
const QString* contentPtr = contentNode->attribute_ptr( sheetNode->tag_name() );
return makeItem( sheetNode, contentPtr );
}
XQItem* XQItemFactory::makeItem( const XQNodePtr& sheetNode, const QString* contentPtr )
{
// den itemtype des neuen items rausfinden
XQItemType* itemType = makeItemType(sheetNode); // throws
XQItem* newItem = new XQItem( itemType, contentPtr );
// __fixme!
if( newItem->isCheckable() )
{
newItem->setCheckState( Qt::Checked );
}
return newItem;
}

View File

@@ -32,20 +32,13 @@ public:
XQNodePtr findModelSheet( const QString& modelName ) const; XQNodePtr findModelSheet( const QString& modelName ) const;
XQItem* makeHeaderItem(const XQNodePtr& typeSheetNode ); //XQItemList makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode );
XQItem* makeContentItem( const XQNodePtr& contentNode, const XQNodePtr& sheetEntry );
XQItem* makeTreeChildItem( const XQNodePtr& contentNode, const XQNodePtr& sheetEntry );
XQItem* makeItem( const XQNodePtr& sheetNode, const XQNodePtr& contentNode=nullptr); XQItemList makeHeaderRow( const XQNodePtr& sheetNode, const QString& caption = c_Caption );
XQItemList makeHeader( const XQNodePtr& sheetNode ); XQItemList makeContentRow( const XQNodePtr& sheetNode, const XQNodePtr& contentNode );
XQItemList makeHeaderRow( const XQNodePtr& sheetNode );
XQItemList makeContentRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode );
XQItemList makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode );
// wozu ist das gut? // wozu ist das gut?
XQItemList createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode ); //XQItemList createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode );
void setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const; void setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const;
@@ -57,6 +50,12 @@ protected:
bool isValid(); bool isValid();
XQItem* makeHeaderItem( const XQNodePtr& sheetNode, const QString& caption );
XQItem* makeContentItem( const XQNodePtr& sheetNode, const XQNodePtr& contentNode );
XQItem* makeItem( const XQNodePtr& sheetNode, const XQNodePtr& contentNode );
XQItem* makeItem( const XQNodePtr& sheetNode, const QString* contentPtr );
// shortcuts // shortcuts
using ItemConfigFunc = std::function<void( XQItem* item, const QString& attrValue, XQNodePtr contentNode, XQNodePtr sheetNode )>; using ItemConfigFunc = std::function<void( XQItem* item, const QString& attrValue, XQNodePtr contentNode, XQNodePtr sheetNode )>;
using ItemConfigMap = QMap<QString,ItemConfigFunc>; using ItemConfigMap = QMap<QString,ItemConfigFunc>;

View File

@@ -65,23 +65,22 @@ QVariant XQItemType::data( int role ) const
void XQItemType::setData(const QVariant& value, int role ) void XQItemType::setData(const QVariant& value, int role )
{ {
qDebug() << " --- itemType set Data:" << role << " : " << value.toString(); //qDebug() << " --- itemType set Data:" << role << " : " << value.toString();
return QStandardItem::setData(value,role); return QStandardItem::setData(value,role);
} }
//! tested, ob ein attribute (z.B. unitType) hier vorhanden ist //! tested, ob ein attribute (z.B. unitType) hier vorhanden ist
int XQItemType::hasAttribute( const QString& attrKey ) int XQItemType::roleForAttributeKey( const QString& attrKey )
{ {
int role = XQItem::fetchItemDataRole(attrKey); int role = XQItem::fetchItemDataRole(attrKey);
// gibbed überhaupt eine rolle für unser attribut? // gibbed überhaupt eine rolle für unser attribut?
if( role == XQItem::NoRole) if( role != XQItem::NoRole)
return XQItem::NoRole; {
// wenn ja, ist die role hier besetzt? // wenn ja, ist die role hier besetzt?
QVariant value = data(role); QVariant value = data(role);
if( !value.isValid() || value.isNull() ) if( !value.isValid() || value.isNull() )
return XQItem::NoRole; return XQItem::NoRole;
}
return role; return role;
} }
@@ -91,6 +90,15 @@ int XQItemType::hasAttribute( const QString& attrKey )
XQItemType* XQItemType::replaceAttribute( const QVariant& newValue, int role ) XQItemType* XQItemType::replaceAttribute( const QVariant& newValue, int role )
{ {
QString msg = newValue.toString();
if( role == XQItem::IconRole )
{
QIcon icn = newValue.value<QIcon>();
msg = XQAppData::iconName( icn );
}
//qDebug() << " --- Before: " << makeItemTypeKey() << " role:" << XQItem::fetchItemDataRoleName(role) << " value:" << msg;
// hat sich überhaupt was geändert? // hat sich überhaupt was geändert?
QVariant oldValue = data(role); QVariant oldValue = data(role);
@@ -115,8 +123,8 @@ XQItemType* XQItemType::replaceAttribute( const QVariant& newValue, int role )
// speichern // speichern
s_ItemTypeMap.insert( newKey, myClone ); s_ItemTypeMap.insert( newKey, myClone );
// und ins item übernehmen
//item.setItemType( myClone ); //qDebug() << " --- After: " << myClone->makeItemTypeKey();
/// Obacht! Der alte, geänderte itemType bleibt erhalten /// Obacht! Der alte, geänderte itemType bleibt erhalten
/// und verrottet ggf. ohne Daseinszweck /// und verrottet ggf. ohne Daseinszweck
@@ -131,7 +139,8 @@ XQItemType* XQItemType::replaceAttribute( const QVariant& newValue, int role )
QVariant XQItemType::formatText( const XQItem& item ) const QVariant XQItemType::formatText( const XQItem& item ) const
{ {
XQItem::UnitType uType = unitType(); XQItem::UnitType uType = unitType();
const QString& cont = item.content(); //qDebug() << " --- formatText: " << XQItem::fetchUnitTypeToString( uType);
const QString& cont = item.rawText();
if( uType != XQItem::NoUnitType ) if( uType != XQItem::NoUnitType )
return formatToSI( cont, uType ); return formatToSI( cont, uType );
return cont; return cont;
@@ -245,9 +254,11 @@ QString XQItemType::makeItemTypeKey()
key = key.arg( editorTypeToString() ); key = key.arg( editorTypeToString() );
key = key.arg( unitTypeToString() ); key = key.arg( unitTypeToString() );
key = key.arg( contentFormat() ); key = key.arg( contentFormat() );
key = key.arg( itemFlagsToString() );
key = key.arg( data(XQItem::FlagsRole).toString() ); // icons haben leider keine namen, es sei denn, sie kommen aus einen theme
key = key.arg( icon().name() ); //key = key.arg( icon().name() );
//key = key.arg( icon().cacheKey() );
key = key.arg( XQAppData::iconName( icon() ) );
key = key.arg( fixedChoicesToString() ); key = key.arg( fixedChoicesToString() );
return key; return key;

View File

@@ -40,12 +40,12 @@ public:
QVariant data( int role ) const override; QVariant data( int role ) const override;
void setData(const QVariant& value, int role ) override; void setData(const QVariant& value, int role ) override;
virtual QVariant formatText( const XQItem& item ) const; QVariant formatText( const XQItem& item ) const;
QString formatToSI(const QString& rawText, XQItem::UnitType unitType ) const; QString formatToSI(const QString& rawText, XQItem::UnitType unitType ) const;
QString unFormatFromSI(const QString& valueText ) const; QString unFormatFromSI(const QString& valueText ) const;
int hasAttribute( const QString& attrKey ); int roleForAttributeKey( const QString& attrKey );
XQItemType* replaceAttribute(const QVariant& newValue, int role ); XQItemType* replaceAttribute(const QVariant& newValue, int role );
QString makeItemTypeKey(); QString makeItemTypeKey();

View File

@@ -14,6 +14,7 @@
#include <QDebug> #include <QDebug>
#include <QApplication> #include <QApplication>
#include <QMetaType>
#include <xqmainwindow.h> #include <xqmainwindow.h>
@@ -48,12 +49,21 @@ who is who:
*/ */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication app(argc, argv); QApplication app(argc, argv);
/*
// Signal für einzelne QStandardItem-Änderungen
connect(model, &QStandardItemModel::itemChanged,
this, [](QStandardItem *changedItem){
QVariant state = changedItem->data(Qt::CheckStateRole);
qDebug() << "Neuer Check-State:" << state.toInt();
});
*/
//app.setStyle("fusion"); //app.setStyle("fusion");
XQMainWindow window; XQMainWindow window;
window.show(); window.show();

View File

@@ -13,14 +13,13 @@
#include <xqmodelsectionlist.h> #include <xqmodelsectionlist.h>
#include <xqitem.h>
//! kontstruktor. übergibt den start-index und einen model-knoten mit der beschreibung //! kontstruktor. übergibt den start-index und einen model-knoten mit der beschreibung
//! der datenknoten. //! der datenknoten.
XQModelSection::XQModelSection(const QModelIndex& aModelIndex, XQNodePtr aSheetNode) XQModelSection::XQModelSection(const QModelIndex& modelIndex, XQNodePtr sheetNode)
: modelIndex{ aModelIndex }, sheetRootNode{ aSheetNode } : _modelIndex{ modelIndex }, _sectionRootNode{ sheetNode }
{ {
} }
@@ -30,7 +29,7 @@ XQModelSection::XQModelSection(const QModelIndex& aModelIndex, XQNodePtr aSheetN
bool XQModelSection::operator==(const XQModelSection& other) const bool XQModelSection::operator==(const XQModelSection& other) const
{ {
return modelIndex == other.modelIndex && sheetRootNode == other.sheetRootNode; return _modelIndex == other._modelIndex && _sectionRootNode == other._sectionRootNode;
} }
@@ -38,7 +37,44 @@ bool XQModelSection::operator==(const XQModelSection& other) const
bool XQModelSection::isValid() const bool XQModelSection::isValid() const
{ {
return modelIndex.isValid() && sheetRootNode; return _modelIndex.isValid() && _sectionRootNode;
}
const QModelIndex& XQModelSection::modelIndex() const
{
return _modelIndex;
}
XQNodePtr XQModelSection::sectionRootNode() const
{
return _sectionRootNode;
}
//! Gibt den sheet-node zurück, das ist die model-beschreibung,
//! siehe modelsheet.xml:
//! <section>
//! <header>
//! <data> <- dort
//! __fix! das versteht doch kein mensch!
XQNodePtr XQModelSection::sheetRootNode() const
{
return _sectionRootNode->find_child_by_tag_name( c_ModelSheet );
}
//! Gibt den content root node zurück, das ist der
//! zeiger auf die realen inhalte.
XQNodePtr XQModelSection::contentRootNode() const
{
return _contentRootNode;
}
void XQModelSection::setContentRootNode( const XQNodePtr contentRootNode )
{
_contentRootNode = contentRootNode;
} }
@@ -46,7 +82,15 @@ bool XQModelSection::isValid() const
int XQModelSection::XQModelSection::row() const int XQModelSection::XQModelSection::row() const
{ {
return modelIndex.row(); return _modelIndex.row();
}
//! gibt den 'content type' zurück.
const QString& XQModelSection::contentType() const
{
return _sectionRootNode->attribute( c_ContentType );
} }
@@ -54,16 +98,11 @@ int XQModelSection::XQModelSection::row() const
XQItem& XQModelSection::XQModelSection::headerItem() const XQItem& XQModelSection::XQModelSection::headerItem() const
{ {
return XQItem::xqItemFromIndex( modelIndex ); return XQItem::xqItemFromIndex( _modelIndex );
} }
//! testet, ob die unter 'sectionKey' eine gültige section vorhanden ist.
void XQModelSectionList::addSectionEntry(const QModelIndex& idx, XQNodePtr sheetNode)
{
XQModelSection section(idx, sheetNode);
addAtKey(sheetNode->tag_name(), section);
}
bool XQModelSectionList::hasValidSection(const QString& sectionKey) const bool XQModelSectionList::hasValidSection(const QString& sectionKey) const
{ {
@@ -73,40 +112,54 @@ bool XQModelSectionList::hasValidSection(const QString& sectionKey) const
} }
const XQModelSection& XQModelSectionList::sectionxqItemFromIndex( const QModelIndex& index ) const //! gibt für einen model index die 'zuständige' section zurück.
const XQModelSection& XQModelSectionList::sectionFromIndex( const QModelIndex& index ) const
{ {
return sectionFromRow( index.row() ); return sectionFromRow( index.row() );
} }
//! gibt für eine zeile die 'zuständige' section zurück: der bestand an section wird
//! nach der passenden section durchsucht.
const XQModelSection& XQModelSectionList::sectionFromRow(int itemRow ) const const XQModelSection& XQModelSectionList::sectionFromRow(int itemRow ) const
{ {
int i = size() - 1; int i = size() - 1;
for (; i >= 0; --i) for (; i >= 0; --i)
{ {
if ( at(i).modelIndex.row() < itemRow ) if ( at(i).modelIndex().row() < itemRow )
return at(i); return at(i);
} }
static XQModelSection s_DummySection; static XQModelSection s_DummySection;
return s_DummySection; return s_DummySection;
} }
//! ermittelt die erste zeile einer section.
int XQModelSectionList::firstRow(const QModelIndex& idx) const int XQModelSectionList::firstRow(const QModelIndex& idx) const
{ {
return sectionFromRow(idx.row() ).row(); return sectionFromRow(idx.row() ).row();
} }
//! ermittelt die zeile unterhalb des gegebenen modelindex,
//! zum einfügen neuer items ebendort.
int XQModelSectionList::lastRow(const QModelIndex& idx) const int XQModelSectionList::lastRow(const QModelIndex& idx) const
{ {
return lastRow(sectionFromRow(idx.row())); return lastRow(sectionFromRow(idx.row()));
} }
//! ermittelt die zeile unterhalb der gegebenen section,
//! zum einfügen neuer items ebendort.
int XQModelSectionList::lastRow(const XQModelSection& section ) const int XQModelSectionList::lastRow(const XQModelSection& section ) const
{ {
//qDebug() << " -- last row in section: " << section.modelIndex.data().toString() << " --> " << section.modelIndex.row(); //qDebug() << " -- last row in section: " << section.modelIndex.data().toString() << " --> " << section.modelIndex.row();
@@ -117,7 +170,7 @@ int XQModelSectionList::lastRow(const XQModelSection& section ) const
{ {
// last section? return last row of model // last section? return last row of model
if (index == size() - 1) if (index == size() - 1)
return section.modelIndex.model()->rowCount();// - 1; return section.modelIndex().model()->rowCount();// - 1;
// return row above the row of the next section -> last row of given section // return row above the row of the next section -> last row of given section
return at(index+1).row(); return at(index+1).row();
} }
@@ -125,12 +178,14 @@ int XQModelSectionList::lastRow(const XQModelSection& section ) const
} }
//! gibt alle sections aus, zum ankucken.
void XQModelSectionList::dump() const void XQModelSectionList::dump() const
{ {
qDebug() << " --- sections dump(): " <<size() << " entries."; qDebug() << " --- sections dump(): " <<size() << " entries.";
for( int i = 0; i<size(); ++i ) for( int i = 0; i<size(); ++i )
{ {
QModelIndex idx = at(i).modelIndex; QModelIndex idx = at(i).modelIndex();
qDebug() << " --- sections:" << i << "row: " << idx.row() << " keyOf(i): " << keyOf(i) << " indexData: "<< idx.data().toString() << " itemData: " << XQItem::xqItemFromIndex(idx).data(Qt::DisplayRole).toString(); qDebug() << " --- sections:" << i << "row: " << idx.row() << " keyOf(i): " << keyOf(i) << " indexData: "<< idx.data().toString() << " itemData: " << XQItem::xqItemFromIndex(idx).data(Qt::DisplayRole).toString();
} }

View File

@@ -16,32 +16,46 @@
#define XQMODELSECTIONLIST_H #define XQMODELSECTIONLIST_H
#include <QPersistentModelIndex> #include <QPersistentModelIndex>
#include <xqnode.h>
#include <xqmaptor.h>
class XQItem; #include <xqmaptor.h>
#include <xqitem.h>
/** /**
* @brief Struct containing data for a header section * @brief Struct containing data for a header section
*/ */
struct XQModelSection class XQModelSection
{ {
QPersistentModelIndex modelIndex;
XQNodePtr sheetRootNode{}; public:
XQNodePtr contentRootNode{};
XQModelSection() = default; XQModelSection() = default;
XQModelSection(const QModelIndex& aModelIndex, XQNodePtr aSheetNode); XQModelSection(const QModelIndex& modelIndex, XQNodePtr sheetNode );
bool operator==(const XQModelSection& other) const; bool operator==(const XQModelSection& other) const;
bool isValid() const; bool isValid() const;
int row() const; int row() const;
const QModelIndex& modelIndex() const;
XQNodePtr sectionRootNode() const;
XQNodePtr sheetRootNode() const;
XQNodePtr contentRootNode() const;
void setContentRootNode( const XQNodePtr dataRootNode );
const QString& contentType() const;
XQItem& headerItem() const; XQItem& headerItem() const;
protected:
QPersistentModelIndex _modelIndex;
XQNodePtr _sectionRootNode{};
XQNodePtr _contentRootNode{};
}; };
Q_DECLARE_METATYPE(XQModelSection)
/** /**
* @brief Maptor containing all header sections. * @brief Maptor containing all header sections.
@@ -54,11 +68,11 @@ public:
XQModelSectionList() = default; XQModelSectionList() = default;
virtual ~XQModelSectionList() = default; virtual ~XQModelSectionList() = default;
void addSectionEntry(const QModelIndex& idx, XQNodePtr sheetNode ); void createSectionEntry(const XQItemList& list, const XQNodePtr& sheetNode );
bool hasValidSection(const QString& sectionKey) const; bool hasValidSection(const QString& sectionKey) const;
const XQModelSection& sectionFromRow( int row ) const; const XQModelSection& sectionFromRow( int row ) const;
const XQModelSection& sectionxqItemFromIndex( const QModelIndex& index ) const; const XQModelSection& sectionFromIndex( const QModelIndex& index ) const;
int firstRow(const QModelIndex& idx) const; int firstRow(const QModelIndex& idx) const;
int lastRow(const QModelIndex& idx) const; int lastRow(const QModelIndex& idx) const;

View File

@@ -83,56 +83,68 @@ XQItem& XQViewModel::xqFirstItem(int row) const
return *static_cast<XQItem*>( QStandardItemModel::item(row) ); return *static_cast<XQItem*>( QStandardItemModel::item(row) );
} }
//! create the own model structure
void XQViewModel::initModel( const QString& modelName) //! initialisiert dieses model über den namen. Es wird hier
//! nur die strukur erzeugt, keine inhalte.
void XQViewModel::initModel(const QString& modelName)
{ {
/* /*
model model
section section
header header
data
section section
... ...
*/ */
// model rootnode finden -> <DocumentTreeModel>
/*
// #0: Wir suchen die Model-Beschreibung
XQNodePtr modelSheet = _itemFactory.findModelSheet( modelName ); // throws XQNodePtr modelSheet = _itemFactory.findModelSheet( modelName ); // throws
// #1: Wir erzeugen die Model-Struktur: Jedes Kind beschreibt einen // #1: über alle sections
// XML-Datentyp, z.B. <Panel atr1="..." />, <Battery .../> for( auto& sectionNode : modelSheet->children() )
// Jeder XML-Knoten entspricht einer Zeile im späteren Model, jedes
// Attribut wird einem eigenen Feld (XQItem) abgebildet.
for( const auto& sheetNode : modelSheet->children() )
{ {
// #2: (optionalen?) header erzeugen
const XQNodePtr header = sectionNode->find_child_by_tag_name( c_Header );
XQItemList list = _itemFactory.makeHeaderRow( sheetNode ); if( header )
// für jeden XML-Knotentyp in der Modelbeschreibung erzeugen wir eine section
addSection(list, sheetNode );
// jedes kind kann enthält einen itemType und einen headerItemType. Für
// diese sind eventuell weitere attribute vorhanden, die die im type
// enthaltenen defualt-werte überschreiben.
for( const auto& sheetChild : sheetNode->children() )
{ {
//qDebug() << "---- kloppo: " << sheetChild->tag_name() << ": " << sheetChild->to_string(); XQItemList list = _itemFactory.makeHeaderRow( header );
extendItemType( sheetChild ); addSection(list, sectionNode );
} }
}
}
// empty row: //! Hilfsfunktion: fügt die item-liste unserem model hinzu und erzeugt eine 'section'.
//XQNodePtr contentNode = XQNode::make_node( sheetNode->tag_name() ); //! die section kann erst gültig sein, wenn die items im model gelandet sind,
//XQItemList emptyRow = _itemFactory.makeEmptyRow( contentNode, sheetNode ); //! deswegen ist das hier zusammengefasst.
//appendRow( emptyRow );
//! Wrzeugt dann eine section aus einer frisch erzeugten itemlist. Der erste modelindex
//! der liste und der root knoten der model-beschreibung werden gespeichert.
void XQViewModel::addSection(const XQItemList& list, const XQNodePtr& sectionNode )
{
// 1. die liste darf nicht leer sein
Q_ASSERT(!list.isEmpty());
// 2. sectionNode muss da sein
Q_ASSERT(sectionNode);
// 3. 'ContenType' muss vorhanden sein
if( !sectionNode->has_attribute( c_ContentType) )
throw XQException( "section list: Section node needs attribute 'ContentType'!");
// 5. das erzeugt dann auch valide indices
appendRow(list);
// 6. die beschreibung der daten liegt im unterknoten 'Data'
} // for // 6. jetzt können wir auch die sction erzeugen
*/ XQModelSection section(list[0]->index(), sectionNode );
_sections.addAtKey(sectionNode->attribute( c_ContentType), section);
// ... und es der welt mitteilen.
emit sectionCreated( section );
} }
@@ -184,14 +196,7 @@ void XQViewModel::onActionTriggered(QAction* action)
} }
/*
//! führt die 'redo' action des gegebenen commnds aus.
void XQViewModel::onCommandRedo( XQCommand& command )
{
try
{
switch (command.commandType()) switch (command.commandType())
{ {
case XQCommand::cmdToggleSection: case XQCommand::cmdToggleSection:
@@ -215,6 +220,28 @@ void XQViewModel::onCommandRedo( XQCommand& command )
default: default:
qDebug() << " --- onCommandRedo: default: not handled: " << command.toString(); qDebug() << " --- onCommandRedo: default: not handled: " << command.toString();
} }
*/
//! führt die 'redo' action des gegebenen commnds aus.
void XQViewModel::onCommandRedo( XQCommand& command )
{
static MemCallMap redoCalls
{
{ XQCommand::cmdToggleSection, &XQViewModel::cmdToggleSection },
{ XQCommand::cmdCut, &XQViewModel::cmdCut },
{ XQCommand::cmdPaste, &XQViewModel::cmdPaste },
{ XQCommand::cmdNew, &XQViewModel::cmdNew },
{ XQCommand::cmdDelete, &XQViewModel::cmdDelete }
};
try
{
MemCall memCall = redoCalls[command.commandType()];
if( memCall )
(this->*memCall)( command );
else
qDebug() << " --- onCommandRedo: default: not handled: " << command.toString();
} }
catch( XQException& exception ) catch( XQException& exception )
{ {
@@ -223,12 +250,7 @@ void XQViewModel::onCommandRedo( XQCommand& command )
} }
} }
/*
//! führt die 'undo' action des gegebenen commnds aus.
void XQViewModel::onCommandUndo( XQCommand& command )
{
qDebug() << " --- onCommandUndo: count: " << XQNode::s_Count;
try try
{ {
switch (command.commandType()) switch (command.commandType())
@@ -263,13 +285,35 @@ void XQViewModel::onCommandUndo( XQCommand& command )
default: default:
qDebug() << " --- onCommandUndo: default: not handled: " << command.toString(); qDebug() << " --- onCommandUndo: default: not handled: " << command.toString();
} }
*/
//! führt die 'undo' action des gegebenen commnds aus.
void XQViewModel::onCommandUndo( XQCommand& command )
{
qDebug() << " --- onCommandUndo: count: " << XQNode::s_Count;
static MemCallMap undoCalls
{
{ XQCommand::cmdToggleSection, &XQViewModel::cmdToggleSection },
{ XQCommand::cmdCut, &XQViewModel::cmdCutUndo },
{ XQCommand::cmdPaste, &XQViewModel::cmdPasteUndo },
{ XQCommand::cmdNew, &XQViewModel::cmdNewUndo },
{ XQCommand::cmdDelete, &XQViewModel::cmdDeleteUndo },
};
try
{
MemCall memCall = undoCalls[command.commandType()];
if( memCall )
(this->*memCall)( command );
else
qDebug() << " --- onCommandUndo: default: not handled: " << command.toString();
} }
catch( XQException& exception ) catch( XQException& exception )
{ {
qDebug() << exception.what(); qDebug() << exception.what();
QMessageBox::critical( nullptr, "Failure", QString("Failure: %1").arg(exception.what()) ); QMessageBox::critical( nullptr, "Failure", QString("Failure: %1").arg(exception.what()) );
} }
} }
// undo-/redo-able stuff // undo-/redo-able stuff
@@ -283,15 +327,18 @@ void XQViewModel::cmdCut( XQCommand& command )
{ {
// ... holen das erste item, das auch den content node enthält // ... holen das erste item, das auch den content node enthält
//const XQNodeBackup& entry = *it; //const XQNodeBackup& entry = *it;
//XQItem& firstItem = xqFirstItem( (*it).itemPos );
//qDebug() << " --- Cut: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id;
// jetzt löschen, dabei wird die parent-verbindung entfernt // jetzt löschen, dabei wird die parent-verbindung entfernt
const XQNodeBackup& entry = *it; const XQNodeBackup& entry = *it;
XQItem& firstItem = xqFirstItem( (*it).itemPos );
qDebug() << " --- Cut: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id;
entry.contentNode->unlink_self(); entry.contentNode->unlink_self();
removeRow(entry.itemPos ); removeRow(entry.itemPos );
} }
} }
//! entfernte knoten wieder einfügen , 'command' enthält die liste //! entfernte knoten wieder einfügen , 'command' enthält die liste
void XQViewModel::cmdCutUndo( XQCommand& command ) void XQViewModel::cmdCutUndo( XQCommand& command )
@@ -306,7 +353,7 @@ void XQViewModel::cmdCutUndo( XQCommand& command )
const XQNodePtr& savedNode = entry.contentNode; const XQNodePtr& savedNode = entry.contentNode;
// __fix! should not be _contentRoot! // __fix! should not be _contentRoot!
savedNode->add_me_at( entry.nodePos, _contentRoot ); savedNode->add_me_at( entry.nodePos, _contentRoot );
XQItemList list = _itemFactory.makeContentRow( savedNode, section.sheetRootNode ); XQItemList list = _itemFactory.makeContentRow( section.sheetRootNode(), savedNode );
XQItem& firstItem = *((XQItem*)list[0]); XQItem& firstItem = *((XQItem*)list[0]);
qDebug() << " --- Cut Undo: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id << " count: " << entry.contentNode.use_count(); qDebug() << " --- Cut Undo: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id << " count: " << entry.contentNode.use_count();
@@ -338,10 +385,10 @@ void XQViewModel::cmdPaste( XQCommand& command )
for (auto& entry : _clipBoard ) for (auto& entry : _clipBoard )
{ {
// noch ein clone vom clone erzeugen ... // noch ein clone vom clone erzeugen ...
XQNodePtr newNode = entry.contentNode->clone(section.contentRootNode ); XQNodePtr newNode = entry.contentNode->clone(section.contentRootNode() );
newNode->clone(section.contentRootNode )->add_me_at( nodePos ); newNode->clone(section.contentRootNode() )->add_me_at( nodePos );
// ... und damit eine frische item-row erzeugen // ... und damit eine frische item-row erzeugen
XQItemList list = _itemFactory.makeContentRow( newNode, section.sheetRootNode ); XQItemList list = _itemFactory.makeContentRow( section.sheetRootNode(), newNode );
insertRow( insRow, list ); insertRow( insRow, list );
// die neue item-row selektieren // die neue item-row selektieren
const QModelIndex& selIdx = list[0]->index(); const QModelIndex& selIdx = list[0]->index();
@@ -424,7 +471,7 @@ void XQViewModel::cmdNew( XQCommand& command )
// store node in node->parent() // store node in node->parent()
//node->add_before_me( newNode ); //node->add_before_me( newNode );
// store node also in 'command' to enable undo // store node also in 'command' to enable undo
const XQModelSection& section = _sections.sectionxqItemFromIndex( origin ); const XQModelSection& section = _sections.sectionFromIndex( origin );
// create new item row // create new item row
XQItemList list = _itemFactory.createGenericRow( newNode, section.sheetRootNode ); XQItemList list = _itemFactory.createGenericRow( newNode, section.sheetRootNode );
@@ -448,8 +495,9 @@ void XQViewModel::cmdNewUndo( XQCommand& command )
//! schaltet eine section sichtbar oder unsichtbar. //! schaltet eine section sichtbar oder unsichtbar.
void XQViewModel::cmdToggleSection( const QModelIndex& index ) void XQViewModel::cmdToggleSection( XQCommand& command )
{ {
const QModelIndex& index = command.originIndex();
Q_ASSERT(index.isValid()); Q_ASSERT(index.isValid());
int fstRow = _sections.firstRow( index ); int fstRow = _sections.firstRow( index );
@@ -459,6 +507,7 @@ void XQViewModel::cmdToggleSection( const QModelIndex& index )
for (int row = fstRow; row < lstRow; ++row ) for (int row = fstRow; row < lstRow; ++row )
_treeTable->setRowHidden( row, _treeTable->rootIndex(), !hidden ); _treeTable->setRowHidden( row, _treeTable->rootIndex(), !hidden );
emit sectionToggled( _sections.sectionFromIndex(index) );
} }
@@ -504,15 +553,6 @@ void XQViewModel::setupViewProperties()
} }
//! füg eine section mit header hinzu.
void XQViewModel::addSection( const XQItemList& list, const XQNodePtr& sheetNode )
{
appendRow(list);
_sections.addSectionEntry( list[0]->index(), sheetNode );
}
//! gibt den undo-stack zurück. //! gibt den undo-stack zurück.
QUndoStack* XQViewModel::undoStack() QUndoStack* XQViewModel::undoStack()

View File

@@ -0,0 +1,599 @@
/***************************************************************************
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 <QMessageBox>
#include <QUndoStack>
#include <xqexception.h>
#include <xqviewmodel.h>
#include <xqselectionmodel.h>
#include <xqtreetable.h>
#include <xqcommand.h>
#include <xqitemdelegate.h>
#include <xqitemfactory.h>
#include <znode_factory.h>
// create global dummy item as
// fallback return value (klappt nicht)
//Q_GLOBAL_STATIC(XQItem,s_dummyItem)
//! hilfsfunkion, zeigt den string-content() für alle elemente der liste
void showItemList( const XQItemList& list)
{
for(const auto& entry : list )
qDebug() << " --- itemList: " << ((XQItem*)entry)->content();
qDebug();
}
//! Konstruktur mit parent.
XQViewModel::XQViewModel( QObject* parent )
: QStandardItemModel{ parent }, _itemFactory{ XQItemFactory::instance() }
{
invisibleRootItem()->setData( "[rootItem]", Qt::DisplayRole );
setItemPrototype( new XQItem );
}
//! gibt einen static-cast<QXItem*> auf 'invisibleRootItem()' zurück
const XQItem& XQViewModel::xqRootItem()
{
// das ist ein hack, denn 'invisibleRootItem()' ist und bleibt ein
// QStandardItem. Trick: keine eigenen members in XQItem, alles
// dynamisch über den ItemData Mechanismus wie in QStandardItem
return *static_cast<XQItem*>(invisibleRootItem());
}
//! hifsfunktion, die das item zu einen index zurückgibt
XQItem& XQViewModel::xqItemFromIndex(const QModelIndex& index) const
{
if( index.isValid() )
{
QStandardItem* xqItem = QStandardItemModel::itemFromIndex(index);
if( xqItem )
return *static_cast<XQItem*>(xqItem);
}
return XQItem::fallBackDummyItem();
}
//! hilfsfunktiom, die das erste xqitem einer zeile zurückgibt.
XQItem& XQViewModel::xqFirstItem(int row) const
{
return *static_cast<XQItem*>( QStandardItemModel::item(row) );
}
//! initialisiert dieses model über den namen. Es wird hier
//! nur die strukur erzeugt, keine inhalte.
void XQViewModel::initModel(const QString& modelName)
{
/*
model
section
header
data
section
...
*/
// model rootnode finden -> <DocumentTreeModel>
XQNodePtr modelSheet = _itemFactory.findModelSheet( modelName ); // throws
// #1: über alle sections
for( auto& section : modelSheet->children() )
{
// #2: (optionalen?) header erzeugen
const XQNodePtr header = section->find_child_by_tag_name( "Header");
if( header )
{
XQItemList list = _itemFactory.makeContentRow( header, nullptr );
addSection(list, section );
}
}
}
//! hilfsfunktion: fügt die liste unserem model hinzu und erzeugt eine 'section'.
//! die section kann erst gültig sein, wenn die items im model gelandet sind,
//! deswegen ist das hier zusammengefasst.
//! erzeugt dann eine section aus einer frisch erzeugten itemlist. der erste modelindex
//! der liste und der unterknoten 'Data' werden gespeichert.
void XQViewModel::addSection(const XQItemList& list, const XQNodePtr& sheetNode )
{
// 1. die liste darf nicht leer sein
Q_ASSERT(!list.isEmpty());
// 2. sheetNode muss da sein
Q_ASSERT(sheetNode);
// 3. 'ContenType' muss vorhanden sein
if( !sheetNode->has_attribute( c_ContentType) )
throw XQException( "section list: Section node needs attribute 'ContentType'!");
// 4. Data child muss auch da sein
XQNodePtr dataNode = sheetNode->find_child_by_tag_name( c_Data );
if( !dataNode )
throw XQException( "section list: 'Data' child is missing!");
// 5. das erzeugt dann auch valide indices
appendRow(list);
XQModelSection section(list[0]->index(), dataNode );
_sections.addAtKey(sheetNode->attribute( c_ContentType), section);
emit sectionCreated( &section );
}
//! SLOT, der aufgerufen wird, wenn eine edit-action getriggert wurde.
void XQViewModel::onActionTriggered(QAction* action)
{
qDebug() << " --- onActionTriggered: count:" << XQNode::s_Count;
// all selected indices
QModelIndexList selectionList = treeTable()->selectionModel()->selectedRows();
// extract command type
XQCommand::CmdType cmdType = action->data().value<XQCommand::CmdType>();
switch( cmdType )
{
// just handle undo ...
case XQCommand::cmdUndo :
return _undoStack->undo();
// ... or do/redo
case XQCommand::cmdRedo :
return _undoStack->redo();
// for copy & cut, we create a clone of the dataNodes in the clipboard
case XQCommand::cmdCopy :
case XQCommand::cmdCut :
// don't 'copy' empty selections
if( !selectionList.isEmpty() )
_clipBoard.saveNodes( selectionList );
// for copy, we are done, since copy cannot be undone
if( cmdType == XQCommand::cmdCopy )
return;
default:
break;
}
// we create a command
XQCommand* command = new XQCommand( cmdType, this );
// store the row positions of the selected indices
command->saveNodes( selectionList );
command->setOriginIndex( treeTable()->currentIndex() );
// execute command
_undoStack->push( command );
}
/*
switch (command.commandType())
{
case XQCommand::cmdToggleSection:
return cmdToggleSection( command.originIndex() );
case XQCommand::cmdCut:
return cmdCut( command );
case XQCommand::cmdPaste:
return cmdPaste( command );
case XQCommand::cmdNew:
return cmdNew( command );
case XQCommand::cmdDelete:
return cmdDelete( command );
case XQCommand::cmdMove:
break;
default:
qDebug() << " --- onCommandRedo: default: not handled: " << command.toString();
}
*/
//! führt die 'redo' action des gegebenen commnds aus.
void XQViewModel::onCommandRedo( XQCommand& command )
{
static MemCallMap redoCalls
{
{ XQCommand::cmdToggleSection, &XQViewModel::cmdToggleSection },
{ XQCommand::cmdCut, &XQViewModel::cmdCut },
{ XQCommand::cmdPaste, &XQViewModel::cmdPaste },
{ XQCommand::cmdNew, &XQViewModel::cmdNew },
{ XQCommand::cmdDelete, &XQViewModel::cmdDelete }
};
try
{
MemCall memCall = redoCalls[command.commandType()];
if( memCall )
(this->*memCall)( command );
else
qDebug() << " --- onCommandRedo: default: not handled: " << command.toString();
}
catch( XQException& exception )
{
qDebug() << exception.what();
QMessageBox::critical( nullptr, "Failure", QString("Failure: %1").arg(exception.what()) );
}
}
/*
try
{
switch (command.commandType())
{
case XQCommand::cmdToggleSection:
return cmdToggleSection( command.originIndex() );
break;
// undo Cut -> perform undoCut
case XQCommand::cmdCut:
return cmdCutUndo( command );
// undo Paste -> perform Cut
case XQCommand::cmdPaste:
return cmdPasteUndo( command );
// undo Move -> perform move back
case XQCommand::cmdMove:
// not yet implemented
break;
// undo New -> perform Delete
case XQCommand::cmdNew:
cmdNewUndo( command );
break;
// undo Delete -> perform New
case XQCommand::cmdDelete:
qDebug() << " --- onCommandUndo: delete: " << command.toString();
return cmdDeleteUndo( command );
default:
qDebug() << " --- onCommandUndo: default: not handled: " << command.toString();
}
*/
//! führt die 'undo' action des gegebenen commnds aus.
void XQViewModel::onCommandUndo( XQCommand& command )
{
qDebug() << " --- onCommandUndo: count: " << XQNode::s_Count;
static MemCallMap undoCalls
{
{ XQCommand::cmdToggleSection, &XQViewModel::cmdToggleSection },
{ XQCommand::cmdCut, &XQViewModel::cmdCutUndo },
{ XQCommand::cmdPaste, &XQViewModel::cmdPasteUndo },
{ XQCommand::cmdNew, &XQViewModel::cmdNewUndo },
{ XQCommand::cmdDelete, &XQViewModel::cmdDeleteUndo },
};
try
{
MemCall memCall = undoCalls[command.commandType()];
if( memCall )
(this->*memCall)( command );
else
qDebug() << " --- onCommandUndo: default: not handled: " << command.toString();
}
catch( XQException& exception )
{
qDebug() << exception.what();
QMessageBox::critical( nullptr, "Failure", QString("Failure: %1").arg(exception.what()) );
}
}
// undo-/redo-able stuff
//! markierte knoten entfernen, 'command' enthält die liste
void XQViewModel::cmdCut( XQCommand& command )
{
// wir gehen rückwärts über alle gemerkten knoten ...
for (auto it = command.rbegin(); it != command.rend(); ++it)
{
// ... holen das erste item, das auch den content node enthält
//const XQNodeBackup& entry = *it;
// jetzt löschen, dabei wird die parent-verbindung entfernt
const XQNodeBackup& entry = *it;
XQItem& firstItem = xqFirstItem( (*it).itemPos );
qDebug() << " --- Cut: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id;
entry.contentNode->unlink_self();
removeRow(entry.itemPos );
}
}
//! entfernte knoten wieder einfügen , 'command' enthält die liste
void XQViewModel::cmdCutUndo( XQCommand& command )
{
// die anfangsposition
int itmPos = command.first().itemPos;
// die 'zuständige' section rausfinden
const XQModelSection& section = _sections.sectionFromRow( itmPos );
// über alle einträge ...
for (auto& entry : command )
{
const XQNodePtr& savedNode = entry.contentNode;
// __fix! should not be _contentRoot!
savedNode->add_me_at( entry.nodePos, _contentRoot );
XQItemList list = _itemFactory.makeContentRow( section.sheetRootNode, savedNode );
XQItem& firstItem = *((XQItem*)list[0]);
qDebug() << " --- Cut Undo: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id << " count: " << entry.contentNode.use_count();
insertRow( entry.itemPos, list );
}
}
//! clipboard inhalte einfügen
void XQViewModel::cmdPaste( XQCommand& command )
{
// selection holen ...
QItemSelectionModel* selectionModel = treeTable()->selectionModel();
// ... und löschen
selectionModel->clearSelection();
// aktuelles item finden
const XQItem& item = xqItemFromIndex( command.originIndex() );
// die neue item position ist unter dem akutellen item
int insRow = item.row()+1;
int nodePos = item.contentNode()->own_pos()+1;
// die zugehörige section finden
const XQModelSection& section = _sections.sectionFromRow( insRow-1 );
// wir pasten das clipboard
for (auto& entry : _clipBoard )
{
// noch ein clone vom clone erzeugen ...
XQNodePtr newNode = entry.contentNode->clone(section.contentRootNode );
newNode->clone(section.contentRootNode )->add_me_at( nodePos );
// ... und damit eine frische item-row erzeugen
XQItemList list = _itemFactory.makeContentRow( section.sheetRootNode, newNode );
insertRow( insRow, list );
// die neue item-row selektieren
const QModelIndex& selIdx = list[0]->index();
_treeTable->selectionModel()->select(selIdx, QItemSelectionModel::Select | QItemSelectionModel::Rows);
// zur nächsten zeile
insRow++;
nodePos++;
}
// unsere änderungen merken fürs 'undo'
command.saveNodes( selectionModel->selectedRows() );
}
//! einfügen aus dem clipboard wieder rückgängig machen
void XQViewModel::cmdPasteUndo( XQCommand& command )
{
command.dumpList("Paste UNDO");
// wir gehen rückwärts über alle markieren knoten ...
for (auto it = command.rbegin(); it != command.rend(); ++it)
{
// ... holen das erste item, das auch den content node enthält
const XQNodeBackup& entry = *it;
XQItem& firstItem = xqFirstItem( (*it).itemPos );
qDebug() << " --- Cut: " << firstItem.text() << " " << firstItem.row();
// jetzt löschen
entry.contentNode->unlink_self();
removeRow(entry.itemPos );
}
}
// don't clone into clipboard, remove items
//! entfernen der selection ohne copy in clipboard.
void XQViewModel::cmdDelete( XQCommand& command )
{
// wir gehen rückwärts über alle markieren knoten ...
for (auto it = command.rbegin(); it != command.rend(); ++it)
{
// ... holen das erste item, das auch den content node enthält
const XQNodeBackup& entry = *it;
XQItem& firstItem = xqFirstItem( (*it).itemPos );
qDebug() << " --- Cut: " << firstItem.text() << " " << firstItem.row();
// jetzt löschen
entry.contentNode->unlink_self();
removeRow(entry.itemPos );
}
}
//! macht 'delete' wirder rückgängig.
void XQViewModel::cmdDeleteUndo( XQCommand& command )
{
}
//! legt eine neue, leere zeile an.
void XQViewModel::cmdNew( XQCommand& command )
{
// __fix
/*
const QModelIndex& origin = command.originIndex();
if( !origin.isValid() )
throw XQException("cmdNewRow failed: index not valid ");
XQItem* target = xqItemFromIndex( origin );
// current data node
XQNodePtr node = target->contentNode();
// we create a new data node
//XQNodePtr newNode = new XQNodePtr( node->tag_name(), node->parent() );
XQNodePtr newNode = XQNode::make_node( node->tag_name(), node->tag_value(), node->parent() );
// store node in node->parent()
//node->add_before_me( newNode );
// store node also in 'command' to enable undo
const XQModelSection& section = _sections.sectionFromIndex( origin );
// create new item row
XQItemList list = _itemFactory.createGenericRow( newNode, section.sheetRootNode );
// add it to the treeview ...
insertRow( origin.row(), list );
// ... and make it ...
treeTable()->setCurrentIndex( list[0]->index() );
// ... editable
treeTable()->edit( list[0]->index() );
*/
}
//! entfernt die neu angelegte zeile.
void XQViewModel::cmdNewUndo( XQCommand& command )
{
}
//! schaltet eine section sichtbar oder unsichtbar.
void XQViewModel::cmdToggleSection( XQCommand& command )
{
const QModelIndex& index = command.originIndex();
Q_ASSERT(index.isValid());
int fstRow = _sections.firstRow( index );
int lstRow = _sections.lastRow( index );
bool hidden =_treeTable->isRowHidden( fstRow, _treeTable->rootIndex() );
for (int row = fstRow; row < lstRow; ++row )
_treeTable->setRowHidden( row, _treeTable->rootIndex(), !hidden );
}
//! git die treetable zurück
XQTreeTable* XQViewModel::treeTable()
{
return _treeTable;
}
//! setzt die treetable als member.
void XQViewModel::setTreeTable(XQTreeTable* mainView )
{
// store view for direct access: the maintree
_treeTable = mainView;
// connect myself as model to the mainview
_treeTable->setModel(this);
XQItemDelegate* delegate = new XQItemDelegate( *this );
_treeTable->setItemDelegate( delegate );
_contextMenu = new XQContextMenu( mainView );
connect( _treeTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onShowContextMenu(QPoint)));
//connect( _treeTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onDoubleClicked(QModelIndex)) );
connect(_contextMenu, SIGNAL(triggered(QAction*)), this, SLOT(onActionTriggered(QAction*)));
// __fixme, die view soll über das modelsheet konfiguriert werden!
setupViewProperties();
}
//! setzt die eigenschaften der TreeTable.
void XQViewModel::setupViewProperties()
{
_treeTable->setContextMenuPolicy(Qt::CustomContextMenu);
_treeTable->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
_treeTable->setSelectionBehavior(QAbstractItemView::SelectRows);
_treeTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
//_treeTable->setSelectionMode(QAbstractItemView::ContiguousSelection);
_treeTable->setSelectionModel( new XQSelectionModel(this) );
}
//! gibt den undo-stack zurück.
QUndoStack* XQViewModel::undoStack()
{
return _undoStack;
}
//! setzt den undo-stack.
void XQViewModel::setUndoStack( QUndoStack* undoStack )
{
_undoStack = undoStack;
}
//! SLOT, der die erstellung & anzeige es context-menues triggert.
void XQViewModel::onShowContextMenu(const QPoint& point)
{
initContextMenu();
_contextMenu->popup(_treeTable->mapToGlobal(point));
}
//! gibt die namen der neuen data-roles zurück.
//! __fix: die alten roles fehlen hier!
QHash<int, QByteArray> XQViewModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[XQItem::ContentRole] = "content";
roles[XQItem::ItemTypeRole] = "itemType";
roles[XQItem::RenderStyleRole] = "renderStyle";
roles[XQItem::EditorTypeRole] = "editorType";
roles[XQItem::UnitTypeRole] = "unitType";
roles[XQItem::FixedChoicesRole] = "fixedChoices";
roles[XQItem::ContentNodeRole] = "contentNode";
roles[XQItem::SheetNodeRole] = "sheetNode";
roles[XQItem::TypeKeyRole] = "typeKey";
return roles;
}

View File

@@ -48,7 +48,6 @@ public:
QUndoStack* undoStack(); QUndoStack* undoStack();
void setUndoStack( QUndoStack* undoStack ); void setUndoStack( QUndoStack* undoStack );
//! create the own model structure
virtual void initModel( const QString& modelName); virtual void initModel( const QString& modelName);
//little helpers //little helpers
@@ -59,7 +58,7 @@ public:
// undo-/redo-able stuff // undo-/redo-able stuff
virtual void cmdToggleSection( const QModelIndex& index ); virtual void cmdToggleSection( XQCommand& command );
virtual void cmdCut( XQCommand& command ); virtual void cmdCut( XQCommand& command );
virtual void cmdCutUndo( XQCommand& command ); virtual void cmdCutUndo( XQCommand& command );
virtual void cmdPaste( XQCommand& command ); virtual void cmdPaste( XQCommand& command );
@@ -73,7 +72,7 @@ public:
/*! /*!
Derzeit wir die default-implementierung von data/setData genutzt. hier wäre dann die Derzeit wird die default-implementierung von data/setData genutzt. hier wäre dann die
Stelle um setData & data an externe 'handler' umzubiegen, siehe giovannies 'model-injection' Stelle um setData & data an externe 'handler' umzubiegen, siehe giovannies 'model-injection'
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
@@ -100,14 +99,13 @@ public slots:
signals: signals:
void xqItemCreated( XQItem* newItem ); void itemCreated( XQItem* newItem );
void sectionCreated( const XQModelSection& section );
void sectionToggled( const XQModelSection& section );
protected: protected:
void addSection(const XQItemList& list, const XQNodePtr& sheetNode ); void addSection(const XQItemList& list, const XQNodePtr& sheetNode );
protected:
virtual void initContextMenu() = 0; virtual void initContextMenu() = 0;
// __fixme: should be created from xml // __fixme: should be created from xml
@@ -115,6 +113,9 @@ protected:
protected: protected:
using MemCall = void (XQViewModel::*)(XQCommand&);
using MemCallMap = QMap<XQCommand::CmdType,MemCall>;
// das eine reference auf ein globales singleton // das eine reference auf ein globales singleton
XQItemFactory& _itemFactory; XQItemFactory& _itemFactory;
XQSimpleClipBoard _clipBoard; XQSimpleClipBoard _clipBoard;

View File

@@ -170,6 +170,9 @@ namespace znode
typename zattributes::const_iterator pos = _attributes.find(key); typename zattributes::const_iterator pos = _attributes.find(key);
if( pos == _attributes.end() ) if( pos == _attributes.end() )
return false; return false;
// leer gilded nicht
if( xstr_is_empty( pos->second ) )
return false;
return true; return true;
} }

View File

@@ -33,7 +33,6 @@ public:
(*this)[key] = index; (*this)[key] = index;
} }
int indexOf(const QString& key) const int indexOf(const QString& key) const
{ {
if (contains(key)) if (contains(key))

View File

@@ -0,0 +1,22 @@
/***************************************************************************
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 <xqquickwidget.h>
XQQuickWidget::XQQuickWidget()
{
}

View File

@@ -0,0 +1,27 @@
/***************************************************************************
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.
***************************************************************************/
#ifndef XQQUICKWIDGET_H
#define XQQUICKWIDGET_H
#include <QQuickWidget>
class XQQuickWidget : public QQuickWidget
{
Q_OBJECT
public:
XQQuickWidget();
};
#endif // XQQUICKWIDGET_H

View File

@@ -1,4 +1,4 @@
QT += core gui widgets QT += core gui widgets quick quickwidgets
# widgets-private # widgets-private
CONFIG += c++20 CONFIG += c++20
@@ -15,7 +15,6 @@ HEADERS += \
application/xqmainmodel.h \ application/xqmainmodel.h \
application/xqmainwindow.h \ application/xqmainwindow.h \
application/xqappdata.h \ application/xqappdata.h \
items/xqgenericitem.h \
items/xqitem.h \ items/xqitem.h \
items/xqitemfactory.h \ items/xqitemfactory.h \
items/xqitemtype.h \ items/xqitemtype.h \
@@ -44,6 +43,7 @@ HEADERS += \
util/xsingleton.h \ util/xsingleton.h \
util/xtreewalker.h \ util/xtreewalker.h \
widgets/xqcontextmenu.h \ widgets/xqcontextmenu.h \
widgets/xqquickwidget.h \
widgets/xqtreetable.h widgets/xqtreetable.h
SOURCES += \ SOURCES += \
@@ -52,7 +52,6 @@ SOURCES += \
application/xqmainmodel.cpp \ application/xqmainmodel.cpp \
application/xqmainwindow.cpp \ application/xqmainwindow.cpp \
application/xqappdata.cpp \ application/xqappdata.cpp \
items/xqgenericitem.cpp \
items/xqitem.cpp \ items/xqitem.cpp \
items/xqitemfactory.cpp \ items/xqitemfactory.cpp \
items/xqitemtype.cpp \ items/xqitemtype.cpp \
@@ -69,6 +68,7 @@ SOURCES += \
pugixml/pugixml.cpp \ pugixml/pugixml.cpp \
util/xqexception.cpp \ util/xqexception.cpp \
widgets/xqcontextmenu.cpp \ widgets/xqcontextmenu.cpp \
widgets/xqquickwidget.cpp \
widgets/xqtreetable.cpp widgets/xqtreetable.cpp
@@ -84,6 +84,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target !isEmpty(target.path): INSTALLS += target
DISTFILES += \ DISTFILES += \
../quick/xqmodelview.qml \
README.md \ README.md \
xml/modelsheets.xml \ xml/modelsheets.xml \
xml/modeldata1.xtr \ xml/modeldata1.xtr \

View File

@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<Project ProjectID="HA01" FriendlyName="@ProjectName" ProjectName="Wiebelbach West" Established="2006" WattPeak="84000" State="runnning" LastFileName="modelData1.xtr"> <Project ProjectID="HA01" FriendlyName="@ProjectName" ProjectName="Wiebelbach West" Established="2006" WattPeak="84000" ContentType="runnning" LastFileName="modelData1.xtr">
<Components> <Components>
<Panel PanelID="#1 JA 01" FriendlyName="@PanelName" PanelName="JA 01 Solar T62B" Manufacturer="JA Solar 1 XX" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"> <Panel PanelID="#1 JA 01" FriendlyName="@PanelName" PanelName="JA 01 Solar T62B" Manufacturer="JA Solar 1 XX" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11">

View File

@@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<Project ProjectID="HA02" FriendlyName="@ProjectName" ProjectName="Gerbrunn Ost" Established="2006" WattPeak="9840" State="planned"> <Project ProjectID="HA02" FriendlyName="@ProjectName" ProjectName="Gerbrunn Ost" Established="2006" WattPeak="9840" ContentType="planned">
<Components> <Components>
<Panel PanelID="Jingli 01" FriendlyName="@PanelName" PanelName="Jingli 01 Solar T62B" Manufacturer="Jingli Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"> <Panel PanelID="Jingli 01" FriendlyName="@PanelName" PanelName="Jingli 01 Solar T62B" Manufacturer="Jingli Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11">
<AdditionalData DataItem="Image" DataValue="image,png"/> <AdditionalData DataItem="Image" DataValue="image,png"/>

View File

@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<Project ProjectID="HA03" FriendlyName="@ProjectName" ProjectName="Neubrunn Süd" Established="2006" WattPeak="9840" State="runnning"> <Project ProjectID="HA03" FriendlyName="@ProjectName" ProjectName="Neubrunn Süd" Established="2006" WattPeak="9840" ContentType="runnning">
<Components> <Components>
<Panel PanelID="AIKO 01" FriendlyName="@PanelName" PanelName="AIKO 01 Solar T62B" Manufacturer="AIKO Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"> <Panel PanelID="AIKO 01" FriendlyName="@PanelName" PanelName="AIKO 01 Solar T62B" Manufacturer="AIKO Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11">
<AdditionalData DataItem="Image" DataValue="image.png"/> <AdditionalData DataItem="Image" DataValue="image.png"/>

View File

@@ -8,101 +8,128 @@
<ItemTypes> <ItemTypes>
<TreeParentType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsDropEnabled" Icon="DirIcon" /> <TreeParentType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsDropEnabled" Icon="DirIcon" />
<TreeChildType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsDragEnabled|IsSelectable|IsDropEnabled"/> <TreeChildType RenderStyle="PlainStyle" ItemFlags="IsEnabled" Icon="DesktopIcon"/>
<HeaderType RenderStyle="HeaderStyle" ItemFlags="IsEnabled" Icon="battery"/> <TreeSectionType RenderStyle="PlainStyle" ItemFlags="IsUserCheckable|IsEnabled" Icon="DirIcon"/>
<HeaderType RenderStyle="HeaderStyle" ItemFlags="IsEnabled"/>
<HiddenType RenderStyle="HiddenStyle"/> <HiddenType RenderStyle="HiddenStyle"/>
<StaticType RenderStyle="PlainStyle"/> <StaticType RenderStyle="PlainStyle"/>
<PlainType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable"/> <PlainType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable"/>
<ValueType RenderStyle="FormattedStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="Coulomb"/> <ValueType RenderStyle="FormattedStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="Coulomb"/>
<CheckableType RenderStyle="FormattedStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="###"/>
<PercentageType RenderStyle="ProgressBarStyle" ItemFlags="IsEnabled|IsSelectable"/> <PercentageType RenderStyle="ProgressBarStyle" ItemFlags="IsEnabled|IsSelectable"/>
<ChoiceType RenderStyle="ComboBoxStyle" ItemFlags="IsEnabled|IsSelectable|IsEditable" FixedChoices="la|le|lo|lu"/> <ChoiceType RenderStyle="ComboBoxStyle" ItemFlags="IsEnabled|IsSelectable|IsEditable" FixedChoices="la|le|lo|lu"/>
<IntValueType RenderStyle="SpinBoxStyle" ItemFlags="IsEnabled|IsSelectable"/> <IntValueType RenderStyle="SpinBoxStyle" ItemFlags="IsEnabled|IsSelectable"/>
</ItemTypes> </ItemTypes>
<!--
DocumentTreeModel
-->
<!--
<DocumentTreeModel> <DocumentTreeModel>
<ActiveProjects ItemType="PlainType" HeaderItemType="TreeParentType" HeaderCaption="Active Projects" State="runnning"> <Section ContentType="runnning">
<Project ItemType="TreeChildType" Icon="list-add"/>
</ActiveProjects>
<PlannedProjects HeaderItemType="TreeParentType" HeaderCaption="Planned Projects" State="planned">
<Project ItemType="TreeChildType" Icon="list-add"/>
</PlannedProjects>
<FinishedProjects HeaderItemType="TreeParentType" HeaderCaption="Finished Projects" State="finished">
<Project ItemType="TreeChildType" Icon="list-remove"/>
</FinishedProjects>
</DocumentTreeModel>
-->
<!--
DocumentDetailsModel:
-->
<DocumentTreeModel>
<Section State="runnning">
<Header> <Header>
<Entry Caption="Active Projects" ItemType="TreeParentType"/> <Entry Caption="Active Projects" ItemType="TreeParentType"/>
</Header> </Header>
<Data> <ModelSheet firz="running">
<Project Caption="@ProjectName" ItemType="TreeParentType"/> <Project Caption="@ProjectName" ItemType="TreeChildType">
</Data> <CurrentSection ItemType="TreeSectionType"/>
</Project>
</ModelSheet>
</Section> </Section>
<Section State="planned"> <Section ContentType="planned">
<Header> <Header>
<Entry Caption="Planned Projects" ItemType="TreeParentType"/> <Entry Caption="Planned Projects" ItemType="TreeParentType"/>
</Header> </Header>
<Data> <ModelSheet firz="planned">
<Project Caption="@ProjectName" ItemType="TreeParentType"/> <Project Caption="@ProjectName" ItemType="TreeChildType">
</Data> <CurrentSection ItemType="TreeSectionType"/>
</Project>
</ModelSheet>
</Section> </Section>
<Section State="finished"> <Section ContentType="finished">
<Header> <Header>
<Entry Caption="Finished Projects" ItemType="TreeParentType"/> <Entry Caption="Finished Projects" ItemType="TreeParentType"/>
</Header> </Header>
<Data> <ModelSheet firz="finished">
<Project Caption="@ProjectName" ItemType="TreeParentType"/> <Project Caption="@ProjectName" ItemType="TreeChildType">
</Data> <CurrentSection ItemType="TreeSectionType"/>
</Project>
</ModelSheet>
</Section> </Section>
</DocumentTreeModel> </DocumentTreeModel>
<DocumentDetailsModel> <DocumentDetailsModel>
<Panel FriendlyName="@PanelName"> <Section ContentType="Panel" firz="farz">
<PanelID HeaderCaption="Panel" HeaderItemType="HeaderType" ItemType="PlainType" Icon="icn74Dummy"/> <Header Marker="Panel">
<PanelName HeaderCaption="Name" HeaderItemType="HeaderType" ItemType="PlainType"/> <PanelID Caption="Panel" ItemType="HeaderType" />
<Manufacturer HeaderCaption="Manufacturer" HeaderItemType="HeaderType" ItemType="ValueType"/> <PanelName Caption="Name" ItemType="HeaderType" Icon="BrowserStop" />
<WattPeak HeaderCaption="Watt Peak" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="Wp"/> <Manufacturer Caption="Manufacturer" ItemType="HeaderType" />
<Width HeaderCaption="Width" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="m"/> <WattPeak Caption="Watt Peak" ItemType="HeaderType" />
<Height HeaderCaption="Height" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="m"/> <Width Caption="Width" ItemType="HeaderType" />
<Weight HeaderCaption="Weight" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="kg"/> <Height Caption="Height" ItemType="HeaderType" />
<MaxVolt HeaderCaption="max. Volt" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="V"/> <Wight Caption="Weight" ItemType="HeaderType" />
<MaxAmpere HeaderCaption="max. Ampere" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="A"/> <MaxVolt Caption="max. Volt" ItemType="HeaderType" />
</Panel> <MaxAmpere Caption="max. Ampere" ItemType="HeaderType" />
</Header>
<ModelSheet Marker="Panel">
<!-- 'Icon' überschreibt den default wert im ItemType und erzeugt damit einen neuen ItemType-->
<PanelID ItemType="PlainType" Icon="DesktopIcon"/>
<PanelName ItemType="PlainType" Icon="BrowserStop"/>
<Manufacturer ItemType="ValueType"/>
<!-- 'UnitType' überschreibt den default wert im ItemType und erzeugt damit einen neuen ItemType-->
<WattPeak ItemType="ValueType" UnitType="Wp"/>
<Width ItemType="CheckableType" Icon="VistaShield" UnitType="m"/>
<Height ItemType="ValueType" UnitType="m"/>
<Weight ItemType="ValueType" UnitType="kg"/>
<MaxVolt ItemType="ValueType" UnitType="V"/>
<MaxAmpere ItemType="ValueType" UnitType="A"/>
</ModelSheet>
</Section>
<Section ContentType="Inverter" firz="farz">
<Header Marker="Inverter">
<InverterID Caption="Inverter" ItemType="HeaderType" />
<InverterName Caption="Name" ItemType="HeaderType" />
<Manufacturer Caption="Manufacturer" ItemType="HeaderType" />
<MaxPowerInput Caption="max. Input" ItemType="HeaderType" />
<MaxPowerOutput Caption="max Output" ItemType="HeaderType" />
<NumStrings Caption="Strings" ItemType="HeaderType" />
<Weight Caption="Weight" ItemType="HeaderType" />
</Header>
<ModelSheet Marker="Inverter">
<InverterID Caption="Inverter" ItemType="ValueType" />
<InverterName Caption="Name" ItemType="ValueType" />
<Manufacturer Caption="Manufacturer" ItemType="ValueType" />
<MaxPowerInput Caption="max. Input" ItemType="ValueType" ItemType="ChoiceType" ChoiceModelSheetSource="MaxPowerInputChoice" UnitType="W"/>
<MaxPowerOutput Caption="max Output" ItemType="ValueType" UnitType="W"/>
<NumStrings Caption="Strings" ItemType="ValueType" />
<Weight Caption="Weight" ItemType="ValueType" UnitType="kg"/>
</ModelSheet>
</Section>
<Section ContentType="Battery" firz="farz">
<Header Marker="Battery">
<BatteryID Caption="Name" ItemType="HeaderType" />
<BatteryName Caption="Battery" ItemType="HeaderType" />
<Manufacturer Caption="Manufacturer" ItemType="HeaderType" />
<Capacity Caption="Capacity" ItemType="HeaderType"/>
<Yield Caption="Yield" ItemType="HeaderType" />
<MaxCurrent Caption="max. Current" ItemType="HeaderType" />
<MaxVolt Caption="max. Volt" ItemType="HeaderType" />
</Header>
<ModelSheet Marker="Bettery">
<BatteryID Caption="Battery" ItemType="ValueType" />
<BatteryName Caption="Name" ItemType="ValueType" />
<Manufacturer Caption="Manufacturer" ItemType="ValueType" />
<Capacity Caption="Capacity" ItemType="ValueType" UnitType="Wh"/>
<Yield Caption="Yield" ItemType="ValueType" ItemType="PercentageType" UnitType="%"/>
<MaxCurrent Caption="max. Current" ItemType="ValueType" UnitType="A"/>
<MaxVolt Caption="max. Volt" ItemType="ValueType" UnitType="V"/>
</ModelSheet>
</Section>
<Inverter FriendlyName="@InverterName">
<InverterID HeaderCaption="Inverter" HeaderItemType="HeaderType" ItemType="ValueType"/>
<InverterName HeaderCaption="Name" HeaderItemType="HeaderType" ItemType="ValueType"/>
<Manufacturer HeaderCaption="Manufacturer" HeaderItemType="HeaderType" ItemType="ValueType"/>
<MaxPowerInput HeaderCaption="max. Input" HeaderItemType="HeaderType" ItemType="ChoiceType" ChoiceDataSource="MaxPowerInputChoice" UnitType="W"/>
<MaxPowerOutput HeaderCaption="max Output" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="W"/>
<NumStrings HeaderCaption="Strings" HeaderItemType="HeaderType" ItemType="ValueType"/>
<Weight HeaderCaption="Weight" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="kg"/>
</Inverter>
<Battery FriendlyName="@BatteryName">
<BatteryID HeaderCaption="Battery" HeaderItemType="HeaderType" ItemType="ValueType"/>
<BatteryName HeaderCaption="Name" HeaderItemType="HeaderType" ItemType="ValueType"/>
<Manufacturer HeaderCaption="Manufacturer" HeaderItemType="HeaderType" ItemType="ValueType"/>
<Capacity HeaderCaption="Capacity" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="Wh"/>
<Yield HeaderCaption="Yield" HeaderItemType="HeaderType" ItemType="PercentageType" UnitType="%"/>
<MaxCurrent HeaderCaption="max. Current" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="A"/>
<MaxVolt HeaderCaption="max. Volt" HeaderItemType="HeaderType" ItemType="ValueType" UnitType="V"/>
</Battery>
</DocumentDetailsModel> </DocumentDetailsModel>