first commit, again.
This commit is contained in:
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
x64*
|
||||
Userschris*
|
||||
xtree.pro.user*
|
||||
.vs
|
||||
debug/
|
||||
release/
|
||||
enc_temp_folder/
|
||||
ui_*
|
||||
*autosave
|
||||
doc/~$ree_thoughts.docx
|
||||
doc/~WRL0004.tmp
|
||||
UsersC998D~1.HOLAppDataLocalTemptmpj0mbo3rd
|
||||
xml/fitzefatz.xml
|
||||
build*
|
||||
doc/
|
58
README.md
Normal file
58
README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# XTree
|
||||
|
||||
## Also, noch mal von vorn:
|
||||
|
||||
- Es geht um das Editieren von XML Daten in einer baumartigen Darstellung am Bildschirm.
|
||||
- Es handelt sich vorwiegend um technische Daten: Strom, Spannung, unterschiedliche Betriebsparameter und sowas.
|
||||
- Die Qt Viewerklassen arbeiten feldbasiert, die Datenfelder heissen 'Items', die Basisklasse zu einem Datenfeld heisst bei uns ```XQItem```
|
||||
- Unser Darstellung der Datenfelder ist im Prinzip erstmal tabellenartig, bla blu
|
||||
|
||||
- Die QtLib unterscheidet zwischen 'rendering' und 'editing'
|
||||
- bla blub
|
||||
|
||||
Also: itemtypes werden einfach beschrieben, mit properties, wie die properties intern implementiert werden, ist erstmal
|
||||
egal: ein type sheet
|
||||
|
||||
pattern: model-view-controller
|
||||
qt: model-view
|
||||
wir: modelhub _only_
|
||||
|
||||
--
|
||||
|
||||
ein ItemType aggregiert gemeinsame Eigenschaften von Items, z.b. UnitType, EditorType, RenderTypezusammen, die ein Gruppe von Items gemeinsam
|
||||
|
||||
|
||||
# Old stuff:
|
||||
|
||||
## Getting started
|
||||
|
||||
Das working directory muss aufs source directory zeigen, da liegen unter xml/
|
||||
die Testfiles.
|
||||
|
||||
## Wo ich hinwill
|
||||
|
||||
- [ ] Alle models, menus etc. sollen in XML beschrieben werden, siehe xml/modelsheet.xml
|
||||
- [ ] Es gibt nur eine Modelklasse: XQModel (ist ein QStandardItemModel)
|
||||
- [ ] Datenlogik und Anwendungslogik sollen getrennt sein
|
||||
- [ ] Dazu werden die Datenknoten (composites) in einen Wrapper verpackt und in den Items 'versteckt'
|
||||
- [ ] Für jede Editorklasse XyzEditor.cpp gibt es eine Klasse XyzHub.cpp
|
||||
- [ ] Im XyzHub wird die Anwendungslogik implementiert, d.h. die SIGNALs der UI werden mit Operationen auf das Model verbunden
|
||||
- [ ] Operationen auf Datenknoten werden für die Anwendung transparent von der Datenschicht ausgeführt
|
||||
- [ ] Die genaue Implementierung dafür ist mir noch unklar:
|
||||
- [ ] ```ZQNode::nodeManager.applyCommand( ZQCommand( ZQ::PasteNode, ZQNode& ) )``` ???
|
||||
|
||||
## Basisklassen
|
||||
|
||||
- [ ] ```znode::zbasic_node<string_type>``` Knotenabstraction, vgl. ```std::basic_string<char_t>```
|
||||
- [ ] ```ZQNode``` template-Instanziierung von zbasic_node mit QString
|
||||
- [ ] ```XQModel``` ein QStandardItemModel mit ZQItems
|
||||
- [ ] ```XQItem``` ein QStandardItem mit einem XQNodeWrapper
|
||||
- [ ] (Sauberer wäre ein eigenes Model aus einem QAbstractItemModel, aber das ist dann wirklich Arbeit ...)
|
||||
- [ ] ```XQNodeWrapper``` verpackt einen ZQNode* und vermittelt dessen Attributes an die ViewItems
|
||||
- [ ] ```XQNodeManager``` operations on nodes, gibts noch nicht.
|
||||
- [ ] Eigentlich ```znode::znode_manager<zbasic_node<string_type>...> ...``` für alle Anwendungsfälle
|
||||
- [ ] ```XQModelReader``` erzeugt QModels aus XML, siehe XML/modelsheet.xml
|
||||
- [ ] ```XQModelHub``` Datenmanager-Klasse, hier läuft alles zusammen
|
||||
- [ ] ```class XQModelHub : public XQModel, public XQModelReader```: etwas fragwürdig, spart aber leidige Verpointerungen
|
||||
|
||||
|
84
deprecated/reste.cpp
Normal file
84
deprecated/reste.cpp
Normal 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>
|
15
deprecated/xqgenericitem.cpp
Normal file
15
deprecated/xqgenericitem.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqgenericitem.h>
|
33
deprecated/xqgenericitem.h
Normal file
33
deprecated/xqgenericitem.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQGENERICITEM_H
|
||||
#define XQGENERICITEM_H
|
||||
|
||||
#include <xqitem.h>
|
||||
|
||||
//
|
||||
// Was sollte das mal werden?
|
||||
//
|
||||
template<class T, class U>
|
||||
class XQGenericItem : public XQItem, public T, public U
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
XQGenericItem() = default;
|
||||
|
||||
};
|
||||
|
||||
#endif // XQGENERICITEM_H
|
29
deprecated/xqicon.cpp
Normal file
29
deprecated/xqicon.cpp
Normal 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
35
deprecated/xqicon.h
Normal 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
|
290
deprecated/xqitemtype.cpp
Normal file
290
deprecated/xqitemtype.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
/***************************************************************************
|
||||
|
||||
source::worx xtree
|
||||
Copyright © 2024 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 <cmath>
|
||||
#include <xqitemtype.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
XQItemTypeMap XQItemType::s_ItemTypeMap;
|
||||
|
||||
|
||||
///
|
||||
/// XQItemType
|
||||
///
|
||||
|
||||
|
||||
XQItemType::XQItemType()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
XQItemType::XQItemType( const XQItemType& other)
|
||||
{
|
||||
_renderStyle = other._renderStyle;
|
||||
_editorType = other._editorType;
|
||||
_itemFlags = other._itemFlags;
|
||||
_unitType = other._unitType;
|
||||
_contentFormat = other._contentFormat;
|
||||
// wem gehören die dann? leck?
|
||||
_fixedChoices = other._fixedChoices;
|
||||
_typeIcon = other._typeIcon;
|
||||
}
|
||||
|
||||
XQItemType::~XQItemType()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
XQItemType::XQItemType( RenderStyle aRenderStyle, EditorType aEditorType, Qt::ItemFlags aItemFlags, UnitType aUnitType, const QString& aContentFormat )
|
||||
: renderStyle{aRenderStyle},
|
||||
editorType{aEditorType},
|
||||
itemFlags{aItemFlags},
|
||||
unitType{aUnitType},
|
||||
contentFormat{aContentFormat}
|
||||
{
|
||||
itemtypeKey = makeItemTypeKey(renderStyle,editorType,itemFlags,unitType,contentFormat);
|
||||
};
|
||||
*/
|
||||
|
||||
///
|
||||
/// create attributes for from factory
|
||||
///
|
||||
|
||||
void XQItemType::setAttribute(XQItem::RenderStyle renderStyle )
|
||||
{
|
||||
_renderStyle = renderStyle;
|
||||
}
|
||||
|
||||
void XQItemType::setAttribute(XQItem::EditorType editorType )
|
||||
{
|
||||
_editorType = editorType;
|
||||
}
|
||||
|
||||
void XQItemType::setAttribute(Qt::ItemFlags itemFlags )
|
||||
{
|
||||
_itemFlags = itemFlags;
|
||||
}
|
||||
|
||||
void XQItemType::setAttribute(XQItem::UnitType unitType)
|
||||
{
|
||||
_unitType = unitType;
|
||||
}
|
||||
|
||||
void XQItemType::setAttribute(const QString& contentFormat)
|
||||
{
|
||||
_contentFormat = contentFormat;
|
||||
}
|
||||
|
||||
void XQItemType::setAttribute(QStandardItemModel *fixedChoices)
|
||||
{
|
||||
_fixedChoices = fixedChoices;
|
||||
}
|
||||
|
||||
void XQItemType::setAttribute(const QIcon& typeIcon )
|
||||
{
|
||||
_typeIcon = typeIcon;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// data() access for property sytem
|
||||
///
|
||||
|
||||
XQItem::RenderStyle XQItemType::renderStyle() const
|
||||
{
|
||||
return _renderStyle;
|
||||
}
|
||||
|
||||
|
||||
XQItem::EditorType XQItemType::editorType() const
|
||||
{
|
||||
return _editorType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
XQItem::UnitType XQItemType::unitType() const
|
||||
{
|
||||
return _unitType;
|
||||
}
|
||||
|
||||
const QString& XQItemType::contentFormat() const
|
||||
{
|
||||
return _contentFormat;
|
||||
}
|
||||
|
||||
|
||||
QStandardItemModel* XQItemType::fixedChoices() const
|
||||
{
|
||||
return _fixedChoices;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString XQItemType::unitTypeStr() const
|
||||
{
|
||||
return XQItem::fetchUnitTypeStr( _unitType );
|
||||
}
|
||||
|
||||
|
||||
QString XQItemType::formatToSI( const QString& valueTxt ) const
|
||||
{
|
||||
/*
|
||||
if( valueTxt.isEmpty() )
|
||||
return valueTxt;
|
||||
|
||||
if( XQItem::ISODate == _unitType )
|
||||
{
|
||||
// format iso date
|
||||
QDateTime dateTime = QDateTime::fromString(valueTxt, Qt::ISODate);
|
||||
// fixme! make this configurable!
|
||||
QString format = "dd.MM.yyyy HH:mm:ss"; // You can customize this format
|
||||
// Format the QDateTime object into a human-readable string
|
||||
return dateTime.toString(format);
|
||||
}
|
||||
|
||||
QLocale sysLocale = QLocale::system();
|
||||
sysLocale.setNumberOptions(sysLocale.numberOptions() | QLocale::OmitGroupSeparator);
|
||||
|
||||
double dVal = sysLocale.toDouble(valueTxt);
|
||||
QString strVal, strPrefix;
|
||||
|
||||
int exp = (int)::log10f(dVal);
|
||||
exp = (exp/3)*3;
|
||||
|
||||
double nVal = dVal;
|
||||
if( !s_PrefixExponentMap.key(exp).isEmpty() )
|
||||
nVal /= ::pow( 10,exp);
|
||||
strVal = sysLocale.toString(nVal, 'f', 2);
|
||||
strPrefix = s_PrefixExponentMap.key(exp);
|
||||
//qDebug() << " convert: " << dVal << " : " << valueTxt << ": " << strVal << ":" << exp << " : " << strPrefix << ": " << nVal;
|
||||
|
||||
return QString("%1 %2%3").arg( strVal, strPrefix, unitTypeStr() );
|
||||
*/
|
||||
return "fitze!";
|
||||
}
|
||||
|
||||
|
||||
QString XQItemType::unFormatFromSI(const QString& formText ) const
|
||||
{
|
||||
/*
|
||||
QString input = formText.simplified();
|
||||
// #1: strip numeric part
|
||||
if( input.isEmpty() )
|
||||
return input;
|
||||
|
||||
int idx = 0;
|
||||
for( auto c : input )
|
||||
{
|
||||
if( c.isNumber() || c.toLower() == 'e' || c == '.' || c == ',' ||c == '-' || c == '+' )
|
||||
idx++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if(!idx)
|
||||
return QString("0");
|
||||
|
||||
QString numPart = formText.left(idx);
|
||||
QString unitPart;
|
||||
//if(idx + 1 < formText.size() )
|
||||
unitPart = formText.right(idx - 1).simplified();
|
||||
|
||||
QLocale sysLocale = QLocale::system();
|
||||
double dVal = sysLocale.toDouble(numPart);
|
||||
if( unitPart.size() > 0 )
|
||||
{
|
||||
QString prefix = QString(unitPart[0]);
|
||||
if( s_PrefixExponentMap.contains(prefix) )
|
||||
dVal *= std::pow( 10.0, s_PrefixExponentMap[prefix] );
|
||||
}
|
||||
|
||||
sysLocale.setNumberOptions(sysLocale.numberOptions() | QLocale::OmitGroupSeparator);
|
||||
QString result = sysLocale.toString(dVal, 'f', 2);
|
||||
|
||||
//qDebug() << " convert: " << numPart << " : " << unitPart << " : " << dVal << " : " << result;
|
||||
|
||||
return result;
|
||||
*/
|
||||
return "fitze!";
|
||||
}
|
||||
|
||||
///
|
||||
/// --- statics --------------------------------------------------------------------------
|
||||
///
|
||||
|
||||
QString XQItemType::makeItemTypeKey()
|
||||
{
|
||||
return makeItemTypeKey(
|
||||
_renderStyle,
|
||||
_editorType,
|
||||
_itemFlags,
|
||||
_unitType,
|
||||
_contentFormat,
|
||||
_fixedChoices,
|
||||
_typeIcon
|
||||
);
|
||||
}
|
||||
|
||||
QString XQItemType::makeItemTypeKey(
|
||||
XQItem::RenderStyle aRenderStyle,
|
||||
XQItem::EditorType aEditorType,
|
||||
Qt::ItemFlags aItemFlags,
|
||||
XQItem::UnitType aUnitType,
|
||||
const QString& aContentFormat,
|
||||
QStandardItemModel* aFixedChoices,
|
||||
const QIcon aIcon
|
||||
)
|
||||
{
|
||||
auto combinedHash = [](const QStandardItemModel* model)
|
||||
{
|
||||
const quint32 prime = 0x9e3779b1; // große Zufallszahl
|
||||
quint32 seed = 0;
|
||||
for (int row = 0; row < model->rowCount(); ++row) {
|
||||
const QString text = model->item(row)->text();
|
||||
quint32 h = qHash(text);
|
||||
// Verschmelzung nach Boost-Hash-Combine:
|
||||
seed ^= h + prime + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
return QString::number(seed);
|
||||
};
|
||||
|
||||
return QString("%1:%2:%3:%4:%5:%7:%8").arg(
|
||||
XQItem::fetchRenderStyleStr(aRenderStyle),
|
||||
XQItem::fetchEditorTypeStr(aEditorType),
|
||||
QString::number( aItemFlags.toInt() ),
|
||||
XQItem::fetchUnitTypeStr(aUnitType),
|
||||
aContentFormat,
|
||||
combinedHash(aFixedChoices),
|
||||
aIcon.name()
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
void XQItemType::setItemType( XQItem* item, RenderStyle renderStyle, UnitType unitType )
|
||||
{
|
||||
XQItemType* itemType = XQItemType::makeItemType( renderStyle, unitType );
|
||||
item->setItemType( itemType );
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
149
deprecated/xqitemtype.h
Normal file
149
deprecated/xqitemtype.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/***************************************************************************
|
||||
|
||||
source::worx xtree
|
||||
Copyright © 2024 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 XQITEMTYPE_H
|
||||
#define XQITEMTYPE_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
|
||||
#include <xqitem.h>
|
||||
|
||||
|
||||
///
|
||||
/// Ist das Unsinn!? Einfach ein QStandardItem mit data() nehmen?
|
||||
/// Ok, das erspart die die attribs, aber wo ist der fette gewinn?
|
||||
/// statt _editorType = x hast Du dann halt setData( QVariant::fromValue<>(x) );
|
||||
/// Aber: Du kannst T abbilden auf QString ... und dann
|
||||
///
|
||||
|
||||
using XQItemTypeMap = QMap<QString, XQItemType*>;
|
||||
|
||||
class XQItemType : public QObject
|
||||
{
|
||||
//?? needed?
|
||||
Q_OBJECT
|
||||
//das haut so nicht hin
|
||||
//Q_PROPERTY(XQItem::RenderStyle renderStyle renderStyle getDate WRITE setrenderStyle )
|
||||
|
||||
public:
|
||||
|
||||
|
||||
XQItemType();
|
||||
XQItemType( const XQItemType& other);
|
||||
|
||||
virtual ~XQItemType();
|
||||
|
||||
//XQItemType( RenderStyle aRenderStyle, EditorType aEditorType, Qt::ItemFlags aItemFlags, UnitType aUnitType, const QString& aContentFormat );
|
||||
|
||||
// ContentFormat als enum?? Warum, für predefined types: int, double ?
|
||||
// key for custom edit?
|
||||
// key for custom format?
|
||||
|
||||
///
|
||||
/// Setter für die XQItemFactory. Setzen das Attribute
|
||||
/// _ohne_ den itemTypeCache zu beeinflussen
|
||||
///
|
||||
|
||||
void setAttribute(XQItem::RenderStyle renderStyle );
|
||||
void setAttribute(XQItem::EditorType editorType );
|
||||
void setAttribute(Qt::ItemFlags itemFlags );
|
||||
void setAttribute(XQItem::UnitType unitType);
|
||||
void setAttribute(const QString& contentFormat);
|
||||
void setAttribute(QStandardItemModel* fixedChoices);
|
||||
void setAttribute(const QIcon& typeIcon);
|
||||
|
||||
QString unitTypeStr() const;
|
||||
|
||||
// FIX! Das gehört hier nicht her!
|
||||
QString formatToSI(const QString& rawText ) const;
|
||||
QString unFormatFromSI(const QString& valueText ) const;
|
||||
|
||||
/// data() access for property system
|
||||
XQItem::RenderStyle renderStyle() const;
|
||||
XQItem::EditorType editorType() const;
|
||||
Qt::ItemFlags itemFlags() const;
|
||||
XQItem::UnitType unitType() const;
|
||||
const QString& contentFormat() const;
|
||||
QStandardItemModel* fixedChoices() const;
|
||||
|
||||
template<typename T>
|
||||
XQItemType* replaceAttribute(T attribute)
|
||||
{
|
||||
// eine kopie meiner selbst erzeugen
|
||||
XQItemType* myClone = new XQItemType(*this);
|
||||
return myClone;
|
||||
}
|
||||
|
||||
XQItemType* replaceRenderStyle(XQItem::RenderStyle renderStyle );
|
||||
XQItemType* replaceEditorType(XQItem::EditorType editorType);
|
||||
XQItemType* replaceItemFlags(Qt::ItemFlags itemFlags);
|
||||
XQItemType* replaceUnitType(XQItem::UnitType unitType);
|
||||
XQItemType* replaceContentFormat(const QString& contentFormat);
|
||||
XQItemType* replaceFixedChoices( QStandardItemModel* fixedChoices);
|
||||
|
||||
QString makeItemTypeKey();
|
||||
|
||||
static QString makeItemTypeKey(
|
||||
XQItem::RenderStyle aRenderStyle,
|
||||
XQItem::EditorType aEditorType,
|
||||
Qt::ItemFlags aItemFlags,
|
||||
XQItem::UnitType aUnitType,
|
||||
const QString& aContentFormat,
|
||||
QStandardItemModel* aFixedChoices,
|
||||
const QIcon aIcon
|
||||
);
|
||||
|
||||
protected:
|
||||
|
||||
static XQItemTypeMap s_ItemTypeMap;
|
||||
|
||||
XQItem::RenderStyle _renderStyle{XQItem::NoRenderStyle};
|
||||
XQItem::EditorType _editorType{XQItem::NoEditorType};
|
||||
Qt::ItemFlags _itemFlags;
|
||||
XQItem::UnitType _unitType{XQItem::NoUnitType};
|
||||
QString _contentFormat;
|
||||
QStandardItemModel* _fixedChoices{};
|
||||
QIcon _typeIcon;
|
||||
|
||||
QString _itemTypeKey;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
static void setItemType( XQItem* item, RenderStyle renderStyle, Qt::ItemFlags flags, UnitType unitType, const QString& format );
|
||||
static void setStaticType( XQItem* item );
|
||||
*/
|
||||
// fix __ch
|
||||
// static void setItemType( XQItem* item, const QString& renderStyle, const QString& unitType, const QString& itemTypeID );
|
||||
|
||||
//static XQItemType* addItemType( const QString& key, RenderStyle renderStyle, UnitType unitType);
|
||||
//static XQItemType* makeItemType( RenderStyle renderStyle, UnitType unitType);
|
||||
|
||||
};
|
||||
|
||||
|
||||
Q_DECLARE_METATYPE(XQItemType*);
|
||||
|
||||
/*
|
||||
//??
|
||||
done by Q_ENUM
|
||||
Q_DECLARE_METATYPE(XQItemType::RenderStyle);
|
||||
Q_DECLARE_METATYPE(XQItemType::UnitType);
|
||||
Q_DECLARE_METATYPE(XQItemType);
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#endif // XQITEMTYPE_H
|
8
quick/xqmodelview.qml
Normal file
8
quick/xqmodelview.qml
Normal file
@@ -0,0 +1,8 @@
|
||||
Window {
|
||||
id: popup
|
||||
width: 300
|
||||
height: 200
|
||||
visible: true
|
||||
flags: Qt.Dialog | Qt.WindowStaysOnTopHint
|
||||
title: "QML-Fenster"
|
||||
}
|
189
src/application/xqappdata.cpp
Normal file
189
src/application/xqappdata.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqappdata.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QStyle>
|
||||
#include <QIcon>
|
||||
#include <QMap>
|
||||
#include <QMetaEnum>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace XQAppData
|
||||
{
|
||||
template<typename E>
|
||||
constexpr auto to_underlying(E e) noexcept
|
||||
{
|
||||
return static_cast<std::underlying_type_t<E>>(e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class XQAppIconMap : public QMap<QString,QIcon>
|
||||
{
|
||||
public:
|
||||
|
||||
XQAppIconMap()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
namedInsert( "DirIcon" , QStyle::SP_DirIcon );
|
||||
namedInsert( "FileDialogBack", QStyle::SP_FileDialogBack );
|
||||
namedInsert( "FileDialogContentsView", QStyle::SP_FileDialogContentsView );
|
||||
namedInsert( "FileDialogDetailedView", QStyle::SP_FileDialogDetailedView );
|
||||
namedInsert( "icn05Dummy", QStyle::SP_FileDialogEnd );
|
||||
namedInsert( "icn06Dummy", QStyle::SP_FileDialogInfoView );
|
||||
namedInsert( "icn07Dummy", QStyle::SP_FileDialogListView );
|
||||
namedInsert( "icn08Dummy", QStyle::SP_FileDialogNewFolder );
|
||||
namedInsert( "icn09Dummy", QStyle::SP_FileDialogStart );
|
||||
namedInsert( "icn10Dummy", QStyle::SP_FileDialogToParent );
|
||||
namedInsert( "icn11Dummy", QStyle::SP_ArrowBack );
|
||||
namedInsert( "icn12Dummy", QStyle::SP_DirIcon );
|
||||
namedInsert( "icn13Dummy", QStyle::SP_MediaSkipBackward );
|
||||
namedInsert( "icn14Dummy", QStyle::SP_ArrowDown );
|
||||
namedInsert( "icn15Dummy", QStyle::SP_DirLinkIcon );
|
||||
namedInsert( "icn16Dummy", QStyle::SP_MediaSkipForward );
|
||||
namedInsert( "icn17Dummy", QStyle::SP_ArrowForward );
|
||||
namedInsert( "icn18Dummy", QStyle::SP_DirOpenIcon );
|
||||
namedInsert( "icn19Dummy", QStyle::SP_MediaStop );
|
||||
namedInsert( "icn20Dummy", QStyle::SP_ArrowLeft );
|
||||
namedInsert( "icn21Dummy", QStyle::SP_DockWidgetCloseButton );
|
||||
namedInsert( "icn22Dummy", QStyle::SP_MediaVolume );
|
||||
namedInsert( "icn23Dummy", QStyle::SP_ArrowRight );
|
||||
namedInsert( "icn24Dummy", QStyle::SP_DriveCDIcon );
|
||||
namedInsert( "icn25Dummy", QStyle::SP_MediaVolumeMuted );
|
||||
namedInsert( "icn26Dummy", QStyle::SP_ArrowUp );
|
||||
namedInsert( "icn27Dummy", QStyle::SP_DriveDVDIcon );
|
||||
namedInsert( "icn28Dummy", QStyle::SP_MessageBoxCritical );
|
||||
namedInsert( "icn29Dummy", QStyle::SP_BrowserReload );
|
||||
namedInsert( "icn30Dummy", QStyle::SP_DriveFDIcon );
|
||||
namedInsert( "icn31Dummy", QStyle::SP_MessageBoxInformation );
|
||||
namedInsert( "BrowserStop", QStyle::SP_BrowserStop );
|
||||
namedInsert( "icn33Dummy", QStyle::SP_DriveHDIcon );
|
||||
namedInsert( "icn34Dummy", QStyle::SP_MessageBoxQuestion );
|
||||
namedInsert( "CommandLink", QStyle::SP_CommandLink );
|
||||
namedInsert( "icn36Dummy", QStyle::SP_DriveNetIcon );
|
||||
namedInsert( "MessageBoxWarning", QStyle::SP_MessageBoxWarning );
|
||||
namedInsert( "ComputerIcon", QStyle::SP_ComputerIcon );
|
||||
namedInsert( "icn39Dummy", QStyle::SP_FileDialogBack );
|
||||
namedInsert( "icn40Dummy", QStyle::SP_TitleBarCloseButton );
|
||||
namedInsert( "icn42Dummy", QStyle::SP_FileDialogContentsView );
|
||||
namedInsert( "icn43Dummy", QStyle::SP_TitleBarContextHelpButton );
|
||||
namedInsert( "DesktopIcon", QStyle::SP_DesktopIcon );
|
||||
namedInsert( "icn45Dummy", QStyle::SP_FileDialogDetailedView );
|
||||
namedInsert( "icn46Dummy", QStyle::SP_TitleBarMaxButton );
|
||||
namedInsert( "icn47Dummy", QStyle::SP_DialogApplyButton );
|
||||
namedInsert( "icn48Dummy", QStyle::SP_FileDialogEnd );
|
||||
namedInsert( "icn49Dummy", QStyle::SP_TitleBarMenuButton );
|
||||
namedInsert( "icn50Dummy", QStyle::SP_DialogCancelButton );
|
||||
namedInsert( "icn51Dummy", QStyle::SP_FileDialogInfoView );
|
||||
namedInsert( "icn52Dummy", QStyle::SP_TitleBarMinButton );
|
||||
namedInsert( "icn53Dummy", QStyle::SP_DialogCloseButton );
|
||||
namedInsert( "icn54Dummy", QStyle::SP_FileDialogListView );
|
||||
namedInsert( "icn55Dummy", QStyle::SP_TitleBarNormalButton );
|
||||
namedInsert( "icn56Dummy", QStyle::SP_DialogDiscardButton );
|
||||
namedInsert( "icn57Dummy", QStyle::SP_FileDialogNewFolder );
|
||||
namedInsert( "icn58Dummy", QStyle::SP_TitleBarShadeButton );
|
||||
namedInsert( "icn59Dummy", QStyle::SP_DialogHelpButton );
|
||||
namedInsert( "icn60Dummy", QStyle::SP_FileDialogStart );
|
||||
namedInsert( "icn61Dummy", QStyle::SP_TitleBarUnshadeButton );
|
||||
namedInsert( "icn62Dummy", QStyle::SP_DialogNoButton );
|
||||
namedInsert( "icn63Dummy", QStyle::SP_FileDialogToParent );
|
||||
namedInsert( "icn64Dummy", QStyle::SP_ToolBarHorizontalExtensionButton );
|
||||
namedInsert( "icn65Dummy", QStyle::SP_DialogOkButton );
|
||||
namedInsert( "FileIcon", QStyle::SP_FileIcon );
|
||||
namedInsert( "icn67Dummy", QStyle::SP_ToolBarVerticalExtensionButton );
|
||||
namedInsert( "icn68Dummy", QStyle::SP_DialogResetButton );
|
||||
namedInsert( "icn70Dummy", QStyle::SP_FileLinkIcon );
|
||||
namedInsert( "TrashIcon", QStyle::SP_TrashIcon );
|
||||
namedInsert( "icn72Dummy", QStyle::SP_DialogSaveButton );
|
||||
namedInsert( "icn73Dummy", QStyle::SP_MediaPause );
|
||||
namedInsert( "VistaShield", QStyle::SP_VistaShield );
|
||||
namedInsert( "icn75Dummy", QStyle::SP_DialogYesButton );
|
||||
namedInsert( "icn76Dummy", QStyle::SP_MediaPlay );
|
||||
namedInsert( "icn77Dummy", QStyle::SP_DirClosedIcon );
|
||||
namedInsert( "icn79Dummy", QStyle::SP_MediaSeekBackward );
|
||||
namedInsert( "DirHomeIcon", QStyle::SP_DirHomeIcon );
|
||||
namedInsert( "icn81Dummy", QStyle::SP_MediaSeekForward );
|
||||
/*
|
||||
auto from = to_underlying(QIcon::ThemeIcon::AddressBookNew);
|
||||
auto to = to_underlying(QIcon::ThemeIcon::NThemeIcons);
|
||||
for (auto i = from; i < to; ++i)
|
||||
{
|
||||
QIcon::ThemeIcon f = static_cast<QIcon::ThemeIcon>(i);
|
||||
QIcon icon = QIcon::fromTheme(f);
|
||||
// Nur hinzufügen, wenn das Icon existiert
|
||||
if (!icon.isNull())
|
||||
insert(icon.name(), icon);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Nein, so nicht! QApplication::style() gibts hier noch nicht -> aua!
|
||||
static XQAppIconMap s_IconMap
|
||||
{
|
||||
{ "icnFolder" , QApplication::style()->standardIcon(QStyle::SP_DirIcon) }
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
static XQAppIconMap s_IconMap;
|
||||
|
||||
|
||||
QIcon typeIcon(const QString& key )
|
||||
{
|
||||
if(s_IconMap.isEmpty())
|
||||
s_IconMap.init();
|
||||
if( s_IconMap.contains(key) )
|
||||
return s_IconMap[key];
|
||||
|
||||
return QApplication::style()->standardIcon( QStyle::SP_TrashIcon);
|
||||
}
|
||||
|
||||
QString iconName( const QIcon& icon )
|
||||
{
|
||||
if(s_IconMap.isEmpty())
|
||||
s_IconMap.init();
|
||||
return s_IconMap.iconName(icon);
|
||||
}
|
||||
|
||||
}; // namespace XQAppData
|
||||
|
||||
|
56
src/application/xqappdata.h
Normal file
56
src/application/xqappdata.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQAPPDATA_H
|
||||
#define XQAPPDATA_H
|
||||
|
||||
#include <qnamespace.h>
|
||||
#include <QVariant>
|
||||
#include <QMap>
|
||||
#include <QStringView>
|
||||
#include <QIcon>
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
const QString c_Version = "0.1.1 04.09.2024";
|
||||
|
||||
const QString c_ItemType = "ItemType";
|
||||
const QString c_Caption = "Caption";
|
||||
const QString c_Header = "Header";
|
||||
const QString c_ContentType = "ContentType";
|
||||
const QString c_ModelSheet = "ModelSheet";
|
||||
|
||||
const QString c_MainModelName = "DocumentTreeModel";
|
||||
const QString c_ChildModelName = "DocumentDetailsModel";
|
||||
const QString c_ProjectID = "ProjectID";
|
||||
|
||||
const QString c_ModelSheetFileName = "xml/modelsheets.xml";
|
||||
const QString c_ModelDummyFileName = "xml/saved_testfile.xtr";
|
||||
const QString c_DocumentDirectory = "xml/";
|
||||
const QString c_DocumentFileName1 = "xml/modeldata1.xtr";
|
||||
const QString c_DocumentFileName2 = "xml/modeldata2.xtr";
|
||||
const QString c_DocumentFileName3 = "xml/modeldata3.xtr";
|
||||
|
||||
|
||||
const QString c_FriendlyName = "FriendlyName";
|
||||
|
||||
namespace XQAppData
|
||||
{
|
||||
//class XQAppIconMap;
|
||||
|
||||
QIcon typeIcon(const QString& key );
|
||||
QString iconName( const QIcon& icon );
|
||||
}
|
||||
|
||||
#endif // XQAPPDATA_H
|
106
src/application/xqchildmodel.cpp
Normal file
106
src/application/xqchildmodel.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <znode_factory.h>
|
||||
#include <xqchildmodel.h>
|
||||
#include <xqselectionmodel.h>
|
||||
#include <xqitemdelegate.h>
|
||||
#include <xqappdata.h>
|
||||
#include <xqtreetable.h>
|
||||
#include <xqitemfactory.h>
|
||||
|
||||
|
||||
|
||||
//! default konstruktor.
|
||||
|
||||
XQChildModel::XQChildModel( QObject *parent )
|
||||
: XQViewModel{parent}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! erzegt den sichtbaren inhalt des models aus einem root-datenknoten.
|
||||
|
||||
void XQChildModel::setContent( const XQNodePtr& contentRoot )
|
||||
{
|
||||
|
||||
// __fix: set object name ??
|
||||
|
||||
qDebug() << " --- create Model Data: " << contentRoot->to_string();
|
||||
|
||||
// Die Datenbasis als shared_ptr sichern
|
||||
_contentRoot = contentRoot;
|
||||
|
||||
// Wir gehen über alle Einträge, die auch unterschiedliche Typen
|
||||
// haben können, hier: <Panel>. <Battery> ...
|
||||
for (const auto& contentEntry : _contentRoot->children())
|
||||
{
|
||||
// Das ist hier der Typ des Eintrags: Panel, Battery ...
|
||||
QString key = contentEntry->tag_name();
|
||||
|
||||
// 'silent failure' hier der Datenbaum kann auch Knoten enthalten
|
||||
// die nicht für uns gedacht sind.
|
||||
if (!_sections.hasValidSection(key))
|
||||
continue;
|
||||
|
||||
XQModelSection& section = _sections.at( key );
|
||||
// wir speichern das parent des datenknoten auch in der
|
||||
// section.
|
||||
// contentEntry->parent == _contentRoot, aber halt nur weil das model flach ist
|
||||
section.setContentRootNode( contentEntry->parent() );
|
||||
int newRow = _sections.lastRow(section);
|
||||
|
||||
XQNodePtr node = section.sheetRootNode();
|
||||
XQItemList list = _itemFactory.makeContentRow( node, contentEntry );
|
||||
//XQItemList list = _itemFactory.makeContentRow( section.sheetRootNode, contentEntry );
|
||||
|
||||
// als Baum?
|
||||
//section.headerItem().appendRow( list );
|
||||
insertRow( newRow, list);
|
||||
|
||||
} // for
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt ein adhoc-contextmenu, je nachdem welche aktionen gerade möflich sind.
|
||||
|
||||
void XQChildModel::initContextMenu()
|
||||
{
|
||||
|
||||
// __fixme! add a menu title
|
||||
_contextMenu->clear();
|
||||
|
||||
const QModelIndex& curIdx = _treeTable->currentIndex();
|
||||
bool hasSel = curIdx.isValid() && _treeTable->selectionModel()->hasSelection();
|
||||
bool canPaste = _clipBoard.canPaste( curIdx );
|
||||
|
||||
_contextMenu->addAction( "icn11Dummy", "Undo", XQCommand::cmdUndo, _undoStack->canUndo() );
|
||||
_contextMenu->addAction( "icn17Dummy", "Redo", XQCommand::cmdRedo, _undoStack->canRedo() );
|
||||
|
||||
_contextMenu->addAction( "icn58Dummy", "Cut", XQCommand::cmdCut, hasSel );
|
||||
_contextMenu->addAction( "icn61Dummy", "Paste", XQCommand::cmdPaste, canPaste );
|
||||
_contextMenu->addAction( "icn55Dummy", "Copy", XQCommand::cmdCopy, hasSel );
|
||||
//_contextMenu->addAction( "icn35Dummy", "Move", XQCommand::cmdMove, hasSel );
|
||||
_contextMenu->addAction( "icn70Dummy", "New", XQCommand::cmdNew, hasSel );
|
||||
_contextMenu->addAction( "icn50Dummy", "Delete", XQCommand::cmdDelete, hasSel );
|
||||
|
||||
// __fixme! set 'toggle section <name>' entry
|
||||
//contextMenu.actions().first()->setText("<name>");
|
||||
_contextMenu->addAction( "icn29Dummy", "Toggle Section", XQCommand::cmdToggleSection, hasSel);
|
||||
}
|
||||
|
||||
|
||||
|
41
src/application/xqchildmodel.h
Normal file
41
src/application/xqchildmodel.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQCHILDMODEL_H
|
||||
#define XQCHILDMODEL_H
|
||||
|
||||
|
||||
#include <xqviewmodel.h>
|
||||
|
||||
|
||||
|
||||
class XQChildModel : public XQViewModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit XQChildModel(QObject *parent = nullptr);
|
||||
virtual ~XQChildModel() = default;
|
||||
|
||||
void setContent(const XQNodePtr& contentRoot );
|
||||
|
||||
protected:
|
||||
|
||||
//void setupViewProperties() override;
|
||||
void initContextMenu() override;
|
||||
|
||||
};
|
||||
|
||||
#endif // XQCHILDMODEL_H
|
55
src/application/xqdocumentstore.cpp
Normal file
55
src/application/xqdocumentstore.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqdocumentstore.h>
|
||||
#include <xqitem.h>
|
||||
#include <QFile>
|
||||
|
||||
//! erzeugt ein docukument
|
||||
|
||||
XQDocument::XQDocument(const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView )
|
||||
: fileName{ aFileName }, friendlyName{ aFriendlyName }, treeItem{ aTreeItem }, modelView{ aModelView }
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// ---
|
||||
///
|
||||
|
||||
|
||||
//! destruktor
|
||||
|
||||
XQDocumentStore::~XQDocumentStore()
|
||||
{
|
||||
//for (auto entry : *this)
|
||||
// delete entry;
|
||||
//for( int i=0; i<size();++i)
|
||||
// delete at(i);
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt ein document eintrag
|
||||
|
||||
void XQDocumentStore::addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView )
|
||||
{
|
||||
XQDocument newDocument( aFileName, aFriendlyName, aTreeItem, aModelView );
|
||||
addAtKey( aFileName, newDocument );
|
||||
// attention: this assumes the presence of the 'ProjectID' value
|
||||
//addAlias( aFileName, aTreeItem->attribute(c_ProjectID) );
|
||||
//addAlias( aFileName, "fitze!" );
|
||||
}
|
||||
|
57
src/application/xqdocumentstore.h
Normal file
57
src/application/xqdocumentstore.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQDOCUMENTSTORE_H
|
||||
#define XQDOCUMENTSTORE_H
|
||||
|
||||
#include <xqmaptor.h>
|
||||
#include <xqnode.h>
|
||||
|
||||
class XQViewModel;
|
||||
class XQItem;
|
||||
|
||||
// should this be internal??
|
||||
struct XQDocument
|
||||
{
|
||||
|
||||
XQDocument() = default;
|
||||
XQDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView );
|
||||
|
||||
virtual ~XQDocument() = default;
|
||||
|
||||
QString fileName; // also used as key
|
||||
QString friendlyName;
|
||||
XQItem* treeItem{};
|
||||
XQViewModel* modelView{};
|
||||
|
||||
};
|
||||
|
||||
|
||||
class XQDocumentStore : public XQMaptor<XQDocument>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
XQDocumentStore() = default;
|
||||
virtual ~ XQDocumentStore();
|
||||
|
||||
void addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView );
|
||||
|
||||
protected:
|
||||
|
||||
XQNode _treeRootNode{ "treeRootNode" };
|
||||
|
||||
};
|
||||
|
||||
#endif // XQDOCUMENTSTORE_H
|
91
src/application/xqmainmodel.cpp
Normal file
91
src/application/xqmainmodel.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <QPersistentModelIndex>
|
||||
#include <QClipboard>
|
||||
|
||||
#include <xqmainmodel.h>
|
||||
|
||||
#include <xqexception.h>
|
||||
#include <xqtreetable.h>
|
||||
#include <xqitemdelegate.h>
|
||||
#include <xqitem.h>
|
||||
#include <xqappdata.h>
|
||||
#include <xqselectionmodel.h>
|
||||
#include <xqitemfactory.h>
|
||||
|
||||
|
||||
//! default konstruktor.
|
||||
|
||||
XQMainModel::XQMainModel(QObject *parent )
|
||||
: XQViewModel{parent}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//! leere default implementation
|
||||
|
||||
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, §ion.contentType() );
|
||||
projectItem->appendRow( newItem );
|
||||
_treeTable->expand( projectItem->index() );
|
||||
*/
|
||||
}
|
45
src/application/xqmainmodel.h
Normal file
45
src/application/xqmainmodel.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQMAINMODEL_H
|
||||
#define XQMAINMODEL_H
|
||||
|
||||
//#include <QItemSelectionModel>
|
||||
|
||||
#include <xqviewmodel.h>
|
||||
//#include <xqmodelsections.h>
|
||||
|
||||
class XQTreeTable;
|
||||
|
||||
|
||||
class XQMainModel : public XQViewModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit XQMainModel(QObject *parent = nullptr);
|
||||
virtual ~XQMainModel() = default;
|
||||
|
||||
XQItem* addProjectItem( XQNodePtr contentNode );
|
||||
void addSectionItem( const XQModelSection& section, XQItem* projectItem );
|
||||
|
||||
protected:
|
||||
|
||||
void initContextMenu() override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // XQMAINMODEL_H
|
377
src/application/xqmainwindow.cpp
Normal file
377
src/application/xqmainwindow.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <QDebug>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <xqmainwindow.h>
|
||||
#include <xqcommand.h>
|
||||
#include <xqexception.h>
|
||||
#include <xqitemfactory.h>
|
||||
#include <xqnodewriter.h>
|
||||
#include <xqquickwidget.h>
|
||||
|
||||
|
||||
//! konstruktor.
|
||||
|
||||
XQMainWindow::XQMainWindow( QWidget* parent )
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
setWindowTitle( QString("XTree %1").arg(c_Version));
|
||||
initMainWindow();
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
|
||||
void XQMainWindow::initMainWindow()
|
||||
{
|
||||
|
||||
qDebug() << " --- initMainWindow(): here we go!";
|
||||
// das working dir setzen: 'xml' muss als unterverzeichnis vorhanden sein.
|
||||
setupWorkingDir();
|
||||
|
||||
// als allererstes laden wir die Modelschreibungen
|
||||
XQItemFactory::instance().initItemFactory( c_ModelSheetFileName );
|
||||
|
||||
_undoView->setStack( &_undoStack );
|
||||
|
||||
_actionUndo->setData( XQCommand::cmdUndo);
|
||||
_actionRedo->setData( XQCommand::cmdRedo);
|
||||
_actionCut->setData( XQCommand::cmdCut);
|
||||
_actionCopy->setData( XQCommand::cmdCopy);
|
||||
_actionPaste->setData( XQCommand::cmdPaste);
|
||||
_actionNew->setData( XQCommand::cmdNew);
|
||||
_actionDelete->setData( XQCommand::cmdDelete);
|
||||
|
||||
connect( _actionUndo, &QAction::triggered, this, &XQMainWindow::onUndo );
|
||||
connect( _actionRedo, &QAction::triggered, this, &XQMainWindow::onRedo );
|
||||
|
||||
connect( _actionOpen, &QAction::triggered, this, &XQMainWindow::onOpenDocument );
|
||||
connect( _actionSave, &QAction::triggered, this, &XQMainWindow::onSaveDocument );
|
||||
connect( _actionSaveAs, &QAction::triggered, this, &XQMainWindow::onSaveDocumentAs );
|
||||
connect( _actionExit, &QAction::triggered, this, &XQMainWindow::onExit );
|
||||
connect( _actionAbout, &QAction::triggered, this, &XQMainWindow::onAbout );
|
||||
|
||||
//connect( _mainTreeView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onDoubleClicked(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)) );
|
||||
|
||||
/*
|
||||
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 ...
|
||||
QString pID = item->contentNode()->attribute(c_ProjectID);
|
||||
_mainTreeView->setCurrentIndex( item->index() );
|
||||
// ... we set the current view to this node
|
||||
if( _documentStore.contains( pID ) )
|
||||
_tabWidget->setCurrentWidget( _documentStore[pID].modelView->treeTable() );
|
||||
} );
|
||||
*/
|
||||
|
||||
try
|
||||
{
|
||||
// hand over undostack
|
||||
_mainModelView.setUndoStack(&_undoStack);
|
||||
// hand over left side navigation tree
|
||||
_mainModelView.setTreeTable(_mainTreeView);
|
||||
// #1. init the left side main tree view
|
||||
_mainModelView.initModel( c_MainModelName );
|
||||
|
||||
// #2. load demo data
|
||||
loadDocument( c_DocumentFileName1 );
|
||||
//loadDocument( c_DocumentFileName2 );
|
||||
|
||||
qDebug() << " --- all here: " << XQNode::s_Count;
|
||||
|
||||
}
|
||||
catch( XQException& exception )
|
||||
{
|
||||
qDebug() << exception.what();
|
||||
QMessageBox::critical( this, "Failure", QString("Failure: %1").arg(exception.what()) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! slot für zentrales undo
|
||||
|
||||
void XQMainWindow::onUndo()
|
||||
{
|
||||
qDebug() << " --- undo Pressed";
|
||||
if(_undoStack.canUndo())
|
||||
_undoStack.undo();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! slot für zentrales redo
|
||||
|
||||
void XQMainWindow::onRedo()
|
||||
{
|
||||
qDebug() << " --- redo Pressed";
|
||||
if(_undoStack.canRedo())
|
||||
_undoStack.redo();
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt ein document
|
||||
|
||||
void XQMainWindow::onCreateDocument()
|
||||
{
|
||||
qDebug() << " ---- create document Pressed!";
|
||||
}
|
||||
|
||||
|
||||
//! öffnet ein XML document
|
||||
|
||||
void XQMainWindow::onOpenDocument()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Project"), c_DocumentDirectory, tr("project data(*.xtr)") );
|
||||
QFile file(fileName);
|
||||
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
{
|
||||
QMessageBox::warning(this, "Warning", "Cannot load file: " + file.errorString());
|
||||
return;
|
||||
}
|
||||
// close dummy file ...
|
||||
file.close();
|
||||
|
||||
loadDocument( fileName );
|
||||
}
|
||||
|
||||
|
||||
//! speichert ein XML document
|
||||
|
||||
void XQMainWindow::onSaveDocument()
|
||||
{
|
||||
qDebug() << " ---- save Pressed!";
|
||||
saveDocument( c_ModelDummyFileName );
|
||||
}
|
||||
|
||||
|
||||
//! fragt nach einem datei-namen und speichert das akutelle XML
|
||||
//! document unter diesem
|
||||
|
||||
void XQMainWindow::onSaveDocumentAs()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this, "Save as", c_DocumentDirectory, tr("project data(*.xtr)") );
|
||||
QFile file(fileName);
|
||||
// open dummy file
|
||||
if (!file.open(QFile::WriteOnly | QFile::Text))
|
||||
{
|
||||
QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString());
|
||||
return;
|
||||
}
|
||||
// close dummy file ...
|
||||
file.close();
|
||||
// and create a xml stream
|
||||
saveDocument( fileName );
|
||||
}
|
||||
|
||||
|
||||
//! wird aufgerufen, wenn ein XML geschlossen werden soll.
|
||||
|
||||
void XQMainWindow::onCloseDocument()
|
||||
{
|
||||
qDebug() << " ---- close Pressed!";
|
||||
}
|
||||
|
||||
|
||||
//! beendet diese application
|
||||
|
||||
void XQMainWindow::onExit()
|
||||
{
|
||||
qApp->exit();
|
||||
}
|
||||
|
||||
|
||||
//! zeigt den about-dialog
|
||||
|
||||
void XQMainWindow::onAbout()
|
||||
{
|
||||
|
||||
QMessageBox msgBox(QMessageBox::NoIcon, "About", "", QMessageBox::Ok);
|
||||
|
||||
QString text = "<b>xtree concept</b><br>";
|
||||
text += "2024 c.holzheuer<br><br>";
|
||||
text += "<a href=\"https://sourceworx.org/xtree\">sourceworx.org/xtree</a>";
|
||||
|
||||
msgBox.setTextFormat(Qt::RichText); // This allows you to click the link
|
||||
msgBox.setText( text );
|
||||
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
|
||||
//! wenn ein item im navigations-baum geklickt wird, soll die document
|
||||
//! view rechts angepasst werden.
|
||||
|
||||
void XQMainWindow::onTreeItemClicked(const QModelIndex& index )
|
||||
{
|
||||
|
||||
XQItem& entry = XQItem::xqItemFromIndex(index);
|
||||
|
||||
qDebug() << " --- XXX mainWindow onTreeItemClicked:" << entry.text();
|
||||
_mainTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
|
||||
|
||||
if( XQNodePtr contentNode = entry.contentNode() )
|
||||
{
|
||||
QString key = contentNode->attribute(c_ProjectID);
|
||||
qDebug() << " --- FIRZ: key: " << key;
|
||||
|
||||
bool isThere = _documentStore.contains(key);
|
||||
if( isThere)
|
||||
_tabWidget->setCurrentWidget( _documentStore[key].modelView->treeTable() );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! beim click auf ein tab im linken fenster wird der navigationsbaum angepasst.
|
||||
|
||||
void XQMainWindow::onTabClicked( int index )
|
||||
{
|
||||
//const QString& key = _documentStore[index].treeItem->attribute( c_ProjectID );
|
||||
qDebug() << " ---- tab clicked: " << index << " : " << _documentStore[index].friendlyName;// << ": " << key;
|
||||
//_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'
|
||||
|
||||
void XQMainWindow::loadDocument( const QString& fileName )
|
||||
{
|
||||
|
||||
// gibts die Datei?
|
||||
if( !QFile::exists( fileName) )
|
||||
throw XQException( "no such file", fileName );
|
||||
|
||||
XQNodeFactory treeLoader;
|
||||
// xml daten laden
|
||||
XQNodePtr rawTree = treeLoader.load_tree( qPrintable(fileName) );
|
||||
// versteckten root node ignorieren
|
||||
XQNodePtr contentRoot = rawTree->first_child();
|
||||
// Project-ID behandeln
|
||||
const QString& pID = contentRoot->attribute(c_ProjectID);
|
||||
int idx = _documentStore.indexOf( pID );
|
||||
if( idx > -1 )
|
||||
{
|
||||
const XQDocument& document = _documentStore.at(idx);
|
||||
QMessageBox::warning( this, "Load Document", QString("File: %1 already loaded.").arg( fileName ) );
|
||||
_mainTreeView->setCurrentIndex( document.treeItem->index() );
|
||||
_tabWidget->setCurrentIndex( idx );
|
||||
return;
|
||||
}
|
||||
|
||||
// 'friendly Name' ist ein Link auf ein anderes Attribute
|
||||
// das als Namen verwendet wird.
|
||||
const QString& fName = contentRoot->friendly_name();
|
||||
QString pTitle = QString("Project %1: %2").arg( pID, fName );
|
||||
|
||||
// Eine neue TreeView erzeugn und im TabWidget parken.
|
||||
XQTreeTable* childTreeView = new XQTreeTable(_tabWidget);
|
||||
_tabWidget->addTab( childTreeView, pTitle );
|
||||
_tabWidget->setCurrentWidget( childTreeView );
|
||||
setWindowTitle( pTitle );
|
||||
|
||||
// Ein neues Child-Model erzeugen
|
||||
XQChildModel* childModel = new XQChildModel(this);
|
||||
|
||||
connect( childModel, SIGNAL(sectionCreated(XQModelSection)), this, SLOT(onSectionCreated(XQModelSection)) );
|
||||
connect( childModel, SIGNAL(sectionToggled(XQModelSection)), this, SLOT(onSectionToggled(XQModelSection)) );
|
||||
|
||||
// Den globalen undo-stack ...
|
||||
childModel->setUndoStack(&_undoStack);
|
||||
|
||||
// und die TreeView übergeben
|
||||
childModel->setTreeTable(childTreeView);
|
||||
|
||||
// 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() );
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! speichert ein XML unter dem 'filename'
|
||||
|
||||
void XQMainWindow::saveDocument( const QString& fileName )
|
||||
{
|
||||
XQNodeWriter nodeWriter;
|
||||
int curIdx = _tabWidget->currentIndex();
|
||||
XQNodePtr rootNode = _documentStore[curIdx].treeItem->contentNode();
|
||||
nodeWriter.dumpTree( rootNode, fileName );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
75
src/application/xqmainwindow.h
Normal file
75
src/application/xqmainwindow.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQMAINWINDOW_H
|
||||
#define XQMAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <ui_xqmainwindow.h>
|
||||
#include <xqdocumentstore.h>
|
||||
#include <xqmainmodel.h>
|
||||
#include <xqchildmodel.h>
|
||||
#include <xqappdata.h>
|
||||
|
||||
class XQMainWindow : public QMainWindow, public Ui_XQMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
XQMainWindow( QWidget* parent = nullptr );
|
||||
virtual ~XQMainWindow() = default;
|
||||
|
||||
void initMainWindow();
|
||||
|
||||
public slots:
|
||||
|
||||
void onUndo();
|
||||
void onRedo();
|
||||
|
||||
void onCreateDocument();
|
||||
void onOpenDocument();
|
||||
void onSaveDocument();
|
||||
void onSaveDocumentAs();
|
||||
void onCloseDocument();
|
||||
void onAbout();
|
||||
void onExit();
|
||||
|
||||
void onTreeItemClicked(const QModelIndex& index );
|
||||
void onTabClicked( int index );
|
||||
//void onItemCreated( XQItem* item );
|
||||
void onSectionCreated( const XQModelSection& section);
|
||||
void onSectionToggled( const XQModelSection& section );
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void setupWorkingDir();
|
||||
|
||||
// fixme implement
|
||||
void showDocumnet( const QString& key ){}
|
||||
void loadDocument( const QString& fileName );
|
||||
void saveDocument( const QString& fileName );
|
||||
|
||||
|
||||
QUndoStack _undoStack;
|
||||
XQDocumentStore _documentStore;
|
||||
|
||||
XQMainModel _mainModelView;
|
||||
XQItem* _currentProjectItem{};
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // XQMAINWINDOW_H
|
290
src/application/xqmainwindow.ui
Normal file
290
src/application/xqmainwindow.ui
Normal file
@@ -0,0 +1,290 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>XQMainWindow</class>
|
||||
<widget class="QMainWindow" name="XQMainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>XTree</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="_centralWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="_tabWidget"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="_menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>26</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="_fileMenu">
|
||||
<property name="title">
|
||||
<string>&File</string>
|
||||
</property>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="_actionOpen"/>
|
||||
<addaction name="_actionSave"/>
|
||||
<addaction name="_actionSaveAs"/>
|
||||
<addaction name="_actionExit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="_actionAbout"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="_menuEdit">
|
||||
<property name="title">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
<addaction name="_actionUndo"/>
|
||||
<addaction name="_actionRedo"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="_actionCut"/>
|
||||
<addaction name="_actionPaste"/>
|
||||
<addaction name="_actionCopy"/>
|
||||
</widget>
|
||||
<addaction name="_fileMenu"/>
|
||||
<addaction name="_menuEdit"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="_statusBar"/>
|
||||
<widget class="QDockWidget" name="_treeDockWidget">
|
||||
<property name="windowTitle">
|
||||
<string>MainDocument</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>1</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="_treeDockLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="XQTreeTable" name="_mainTreeView">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="_statusDock">
|
||||
<property name="toolTipDuration">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Status</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>8</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="_statusContent">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QUndoView" name="_undoView">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<action name="_actionExit">
|
||||
<property name="text">
|
||||
<string>E&xit</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionCopy">
|
||||
<property name="text">
|
||||
<string>Copy</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+C</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionCut">
|
||||
<property name="text">
|
||||
<string>Cu&t</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+X</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionNew">
|
||||
<property name="text">
|
||||
<string>New</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+N</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionPaste">
|
||||
<property name="icon">
|
||||
<iconset theme="audio-volume-high"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Paste</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+V</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionUndo">
|
||||
<property name="text">
|
||||
<string>Undo</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Z</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionRedo">
|
||||
<property name="text">
|
||||
<string>Redo</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Y</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionOpen">
|
||||
<property name="text">
|
||||
<string>Open</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopyAsText">
|
||||
<property name="text">
|
||||
<string>Copy As Text</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionDelete">
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionFind">
|
||||
<property name="text">
|
||||
<string>Find</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionSave">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionSaveAs">
|
||||
<property name="text">
|
||||
<string>Save as ...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Save as ...</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Alt+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionAbout">
|
||||
<property name="text">
|
||||
<string>About</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>XQTreeTable</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">xqtreetable.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
706
src/items/xqitem.cpp
Normal file
706
src/items/xqitem.cpp
Normal file
@@ -0,0 +1,706 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqitem.h>
|
||||
|
||||
#include <xqviewmodel.h>
|
||||
#include <xqmaptor.h>
|
||||
#include <QDateTime>
|
||||
#include <xqitemtype.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
XQItem::XQItemFlagMap XQItem::s_ItemFlagMap
|
||||
{
|
||||
{ "NoItemFlags", Qt::NoItemFlags },
|
||||
{ "IsSelectable", Qt::ItemIsSelectable },
|
||||
{ "IsEditable", Qt::ItemIsEditable },
|
||||
{ "IsDragEnabled", Qt::ItemIsDragEnabled },
|
||||
{ "IsDropEnabled", Qt::ItemIsDropEnabled },
|
||||
{ "IsUserCheckable", Qt::ItemIsUserCheckable },
|
||||
{ "IsEnabled", Qt::ItemIsEnabled },
|
||||
{ "IsAutoTristate", Qt::ItemIsAutoTristate },
|
||||
{ "ItemNeverHasChildren", Qt::ItemNeverHasChildren },
|
||||
{ "IsUserTristate", Qt::ItemIsUserTristate }
|
||||
};
|
||||
|
||||
XQItem::XQItemDataRoleMap XQItem::s_ItemDataRoleMap
|
||||
{
|
||||
{"ItemType", ItemTypeRole},
|
||||
{"Content", ContentRole},
|
||||
{"RenderStyle", RenderStyleRole},
|
||||
{"EditorType", EditorTypeRole},
|
||||
{"ItemFlags", FlagsRole},
|
||||
{"UnitType", UnitTypeRole},
|
||||
{"ContentFormat", ContentFormatRole},
|
||||
{"FlagsRole", FlagsRole},
|
||||
{"Icon", IconRole},
|
||||
{"FixedChoices", FixedChoicesRole},
|
||||
{"DataNode", ContentNodeRole},
|
||||
{"SheetNode", SheetNodeRole}
|
||||
};
|
||||
|
||||
// No bi-map needed here, qmap.key() is sufficient for the job
|
||||
XQItem::XQRenderStyleMap XQItem::s_RenderStyleMap
|
||||
{
|
||||
{ "NoRenderStyle", NoRenderStyle },
|
||||
{ "HiddenStyle", HiddenStyle },
|
||||
{ "HeaderStyle", HeaderStyle },
|
||||
{ "PlainStyle", PlainStyle },
|
||||
{ "CheckBoxStyle", CheckBoxStyle },
|
||||
{ "ComboBoxStyle", ComboBoxStyle },
|
||||
{ "TreeHeaderStyle", TreeHeaderStyle },
|
||||
{ "CustomRenderStyle", CustomRenderStyle },
|
||||
{ "PickerStyle", PickerStyle },
|
||||
{ "SpinBoxStyle", SpinBoxStyle },
|
||||
{ "ProgressBarStyle", ProgressBarStyle},
|
||||
{ "FormattedStyle", FormattedStyle},
|
||||
};
|
||||
|
||||
XQItem::XQEditorTypeMap XQItem::s_EditorTypeMap
|
||||
{
|
||||
{ "NoEditorType", NoEditorType },
|
||||
{ "LineEditType", LineEditType },
|
||||
{ "ComboBoxType", ComboBoxType },
|
||||
{ "PickerType", PickerType },
|
||||
{ "ProgressBarType", ProgressBarType },
|
||||
{ "SpinBoxType", SpinBoxType},
|
||||
{ "CustomEditorType", CustomEditorType}
|
||||
};
|
||||
|
||||
XQItem::XQUnitTypeMap XQItem::s_UnitTypeMap
|
||||
{
|
||||
{ NoUnitType, "NoUnitType" },
|
||||
{ Ampere, "A" },
|
||||
{ Volt, "V" },
|
||||
{ Ohm, "Ohm" },
|
||||
{ Farad, "C" },
|
||||
{ Watt, "W" },
|
||||
{ WattPeak, "Wp" },
|
||||
{ WattHour, "Wh" },
|
||||
{ Second, "s" },
|
||||
{ Percent, "%" },
|
||||
{ Hertz, "Hz" },
|
||||
{ Meter, "m" },
|
||||
{ Kg, "kg" },
|
||||
{ ISODate, "ISODate" }, // fixme: ISO-Date is present, but has no Unit ?!?
|
||||
};
|
||||
|
||||
XQItem::XQPrefixExponentMap XQItem::s_PrefixExponentMap
|
||||
{
|
||||
{ "p", -12 }, // pico
|
||||
{ "n", -9 }, // nano
|
||||
{ "µ", -6 }, // micro
|
||||
{ "m", -3 }, // Milli
|
||||
{ "" , 0 }, // No prefix means multiplier of 1
|
||||
//{ " ", 0 }, // No prefix means multiplier of 1
|
||||
{ "k", 3 }, // Kilo
|
||||
{ "M", 6 }, // Mega
|
||||
{ "G", 9 }, // Giga
|
||||
{ "T", 12 }, // Tera
|
||||
{ "P", 15 }, // Peta
|
||||
{ "E", 18 }, // Exa
|
||||
{ "Z", 21 }, // Zetta
|
||||
{ "Y", 24}, // Yotta
|
||||
};
|
||||
|
||||
|
||||
|
||||
XQItem::XQItem()
|
||||
: XQItem{XQItemType::staticItemType()}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
XQItem::XQItem( XQItemType* itemType )
|
||||
: QStandardItem{}
|
||||
{
|
||||
setItemType( itemType );
|
||||
}
|
||||
|
||||
|
||||
XQItem::XQItem(XQItemType* itemType, const QString *content )
|
||||
: XQItem{ itemType }
|
||||
{
|
||||
setContent(content);
|
||||
}
|
||||
|
||||
//! ruft den copy-konstruktor auf.
|
||||
|
||||
XQItem* XQItem::clone() const
|
||||
{
|
||||
return new XQItem( *this );
|
||||
}
|
||||
|
||||
|
||||
//! false für ein ungültiges item. 'ungültig' heisst hier, dass nur ein
|
||||
//! mockup-itemtype gesetzt ist.
|
||||
|
||||
bool XQItem::isValid() const
|
||||
{
|
||||
XQItemType* dummyType = XQItemType::staticItemType();
|
||||
return QStandardItem::data( XQItem::ItemTypeRole ).value<XQItemType*>() != dummyType;
|
||||
}
|
||||
|
||||
|
||||
//! gibt den content-node zurück.
|
||||
|
||||
XQNodePtr XQItem::contentNode() const
|
||||
{
|
||||
XQNodePtr node = data( ContentNodeRole ).value<XQNodePtr>();
|
||||
if( node )
|
||||
return node;
|
||||
throw XQException("XQItem::contentNode() nullptr");
|
||||
}
|
||||
|
||||
|
||||
//! setzt den content node.
|
||||
|
||||
void XQItem::setContentNode( const XQNodePtr& contentNode )
|
||||
{
|
||||
QStandardItem::setData( QVariant::fromValue(contentNode), ContentNodeRole);
|
||||
}
|
||||
|
||||
|
||||
//! gibt den sheet-node zurück.
|
||||
|
||||
XQNodePtr XQItem::sheetNode() const
|
||||
{
|
||||
return data( SheetNodeRole ).value<XQNodePtr>();
|
||||
}
|
||||
|
||||
//! setzt den sheet-node
|
||||
|
||||
void XQItem::setSheetNode(const XQNodePtr& sheetNode )
|
||||
{
|
||||
QStandardItem::setData( QVariant::fromValue(sheetNode), SheetNodeRole);
|
||||
}
|
||||
|
||||
|
||||
//! gibt eine referenz auf den itemType dieses items zurück.
|
||||
|
||||
XQItemType& XQItem::itemType() const
|
||||
{
|
||||
// __fix: wir gehen hier davon aus, das der itemType immer existiert,
|
||||
// nur weil er in jeden konstruktor gesetzt wird, das muss aber nicht
|
||||
// so sein!
|
||||
XQItemType* itemTypePtr = QStandardItem::data( XQItem::ItemTypeRole ).value<XQItemType*>();
|
||||
return *itemTypePtr;
|
||||
// should_throw
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! speichert einen neuen itemType.
|
||||
|
||||
void XQItem::setItemType( XQItemType* itemTypePtr )
|
||||
{
|
||||
// der ItemType wird direkt hier gespeichert
|
||||
QStandardItem::setData( QVariant::fromValue(itemTypePtr), XQItem::ItemTypeRole );
|
||||
}
|
||||
|
||||
|
||||
//! set ein einzelnes itemFlag.
|
||||
|
||||
void XQItem::addFlag( Qt::ItemFlag newFlag )
|
||||
{
|
||||
setFlags( flags() | newFlag );
|
||||
}
|
||||
|
||||
|
||||
//! löscht ein einzelnes itemFlag.
|
||||
|
||||
void XQItem::clearFlag( Qt::ItemFlag newFlag )
|
||||
{
|
||||
setFlags( flags() & ~newFlag);
|
||||
}
|
||||
|
||||
|
||||
//! gibt die itemFlags als string zurück.
|
||||
|
||||
QString XQItem::itemFlagsToString() const
|
||||
{
|
||||
return'(' + data(XQItem::FlagsRole).toString() +')';
|
||||
}
|
||||
|
||||
///
|
||||
/// data() access shortcuts
|
||||
///
|
||||
|
||||
//! gibt den renderStyle zurück.
|
||||
|
||||
XQItem::RenderStyle XQItem::renderStyle() const
|
||||
{
|
||||
return data( RenderStyleRole ).value<RenderStyle>();
|
||||
}
|
||||
|
||||
|
||||
//! gibt den renderStyle als string zurück.
|
||||
|
||||
QString XQItem::renderStyleToString() const
|
||||
{
|
||||
return XQItem::fetchRenderStyleToString( renderStyle() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! setzt den editorType. wird im itemType gespeichert.
|
||||
|
||||
void XQItem::setRenderStyle(RenderStyle renderStyle )
|
||||
{
|
||||
setData( QVariant::fromValue(renderStyle), XQItem::RenderStyleRole );
|
||||
}
|
||||
|
||||
|
||||
//! gibt den editorType zurück.
|
||||
|
||||
XQItem::EditorType XQItem::editorType() const
|
||||
{
|
||||
return data( EditorTypeRole ).value<EditorType>();
|
||||
}
|
||||
|
||||
|
||||
//! gibt den renderStyle als string zurück.
|
||||
|
||||
QString XQItem::editorTypeToString() const
|
||||
{
|
||||
return XQItem::fetchEditorTypeToString( editorType() );
|
||||
}
|
||||
|
||||
//! setzt den editorType. wird im itemType gespeichert.
|
||||
|
||||
void XQItem::setEditorType(EditorType editorType)
|
||||
{
|
||||
setData( QVariant::fromValue(editorType), XQItem::EditorTypeRole);
|
||||
}
|
||||
|
||||
|
||||
//! setzt den unitType.
|
||||
|
||||
XQItem::UnitType XQItem::unitType() const
|
||||
{
|
||||
return data( XQItem::UnitTypeRole ).value<UnitType>();
|
||||
}
|
||||
|
||||
|
||||
//! gibt den unitType als string zurück.
|
||||
|
||||
QString XQItem::unitTypeToString() const
|
||||
{
|
||||
return XQItem::fetchUnitTypeToString( unitType() );
|
||||
}
|
||||
|
||||
|
||||
//! setzt den editorType. wird im itemType gespeichert.
|
||||
|
||||
void XQItem::setUnitType(UnitType unitType)
|
||||
{
|
||||
setData( QVariant::fromValue(unitType), XQItem::UnitTypeRole);
|
||||
}
|
||||
|
||||
|
||||
//! Verweist auf data(Qt::EditRole). Das ist der unformatierte text.
|
||||
|
||||
QString XQItem::rawText() const
|
||||
{
|
||||
return data( Qt::EditRole ).toString();
|
||||
}
|
||||
|
||||
|
||||
//! 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*>();
|
||||
}
|
||||
|
||||
|
||||
//! set den content()-string pointer. (als leihgabe)
|
||||
|
||||
void XQItem::setContent( const QString* content )
|
||||
{
|
||||
setData( QVariant::fromValue<const QString*>(content), XQItem::ContentRole );
|
||||
}
|
||||
|
||||
|
||||
//! holt den schlüssel bzw. bezeicher des content() string aus 'unserem' content knoten.
|
||||
|
||||
QString XQItem::contentKey() const
|
||||
{
|
||||
return contentNode()->attributes().key_of( rawText() );
|
||||
}
|
||||
|
||||
//! gibt den content-format string zurück
|
||||
|
||||
QString XQItem::contentFormat() const
|
||||
{
|
||||
return data( XQItem::ContentFormatRole ).toString();
|
||||
}
|
||||
|
||||
//! setz den den content format-string. wird im itemType gespeichert.
|
||||
|
||||
void XQItem::setContentFormat(const QString& contentFormat)
|
||||
{
|
||||
setData( QVariant::fromValue(contentFormat), XQItem::ContentFormatRole);
|
||||
}
|
||||
|
||||
|
||||
//! gibt das read-only auswahl-model zurück (wenn dieses item als
|
||||
//! combobox gerendert wird). wird im itemType gespeichert.
|
||||
|
||||
QStandardItemModel* XQItem::fixedChoices() const
|
||||
{
|
||||
return data( XQItem::FixedChoicesRole ).value<QStandardItemModel*>();
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt einen string aus den werten des read-only auswahl-models
|
||||
|
||||
QString XQItem::fixedChoicesToString() const
|
||||
{
|
||||
QStandardItemModel* model = fixedChoices();
|
||||
if( !model || model->rowCount() == 0)
|
||||
return QString("()");
|
||||
|
||||
QString result = "(";
|
||||
|
||||
int rc = model->rowCount();
|
||||
for (int row = 0; row < rc; ++row)
|
||||
{
|
||||
const QString text = model->item(row)->text();
|
||||
result += text;
|
||||
if(row < rc-1)
|
||||
result += "|";
|
||||
}
|
||||
result += ")";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//! setzt das auswahl-model für read-only comboboxes
|
||||
|
||||
void XQItem::setfixedChoices( QStandardItemModel* newModel )
|
||||
{
|
||||
setData( QVariant::fromValue(newModel), XQItem::FixedChoicesRole);
|
||||
}
|
||||
|
||||
//! true, wenn 'ich' ein header item bin
|
||||
|
||||
bool XQItem::isHeaderStyle()
|
||||
{
|
||||
return renderStyle() == XQItem::HeaderStyle;
|
||||
}
|
||||
|
||||
|
||||
//! gibt den namen der datarole zurück
|
||||
|
||||
QString XQItem::dataRoleName(int role) const
|
||||
{
|
||||
if( role < XQItem::NoRole && model() )
|
||||
return model()->roleNames()[role];
|
||||
return XQItem::fetchItemDataRoleName(role);
|
||||
}
|
||||
|
||||
//! angespasste variante von qstandarditem::setData. geteilte attribute
|
||||
//! werden vom xqitemtype geholt
|
||||
|
||||
QVariant XQItem::data(int role ) const
|
||||
{
|
||||
//emitDataChanged()
|
||||
switch(role)
|
||||
{
|
||||
|
||||
//
|
||||
// Die im ItemType ausgelagerten Daten werden
|
||||
// von da geholt.
|
||||
//
|
||||
|
||||
case FlagsRole: // aka Qt::ItemDataRole(Qt::UserRole - 1),
|
||||
case IconRole: // aka Qt::DecorationRole,
|
||||
case RenderStyleRole:
|
||||
case EditorTypeRole:
|
||||
case UnitTypeRole:
|
||||
case ContentFormatRole:
|
||||
case FixedChoicesRole:
|
||||
{
|
||||
return itemType().data(role);
|
||||
}
|
||||
|
||||
// Zugriffe auf den sichtbaren inhalt geben den inhalt des string pointer
|
||||
// auf ein feld in content node wieder.
|
||||
|
||||
// DisplayRole gibt den formatieren inhalt wieder. die formatierung übernimmt
|
||||
// der item type
|
||||
// auf den original inhalt im content node zurückgeben.
|
||||
|
||||
case Qt::DisplayRole :
|
||||
{
|
||||
if( itemType().renderStyle() == XQItem::FormattedStyle)//return "display:"+content();
|
||||
return itemType().formatText( *this );
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
// EditRole & ContentRole sollen den 'rohen' inhalt unseres string-pointers
|
||||
// auf den original inhalt im content node zurückgeben.
|
||||
|
||||
case Qt::EditRole :
|
||||
case XQItem::ContentRole:
|
||||
{
|
||||
|
||||
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:
|
||||
{
|
||||
return rawText() + ":" + unitTypeToString() + ":" + renderStyleToString() + ":" + unitTypeToString() + ":" + itemFlagsToString();
|
||||
}
|
||||
|
||||
//
|
||||
// Die lokal verwalteten Resourcen werden über QStandardItem::data(role)
|
||||
// abgewickelt.
|
||||
//
|
||||
|
||||
case ContentNodeRole:
|
||||
{
|
||||
// Das Node-Besitzer-Item wohnt in der ersten Spalte,
|
||||
// wenn wir also der Node-Besitzer item sind ...
|
||||
if( column() == 0)
|
||||
return QStandardItem::data( XQItem::ContentNodeRole );
|
||||
|
||||
// sonst: delegieren an den node-Besitzer
|
||||
QModelIndex pIndex = model()->index( row(), 0 );
|
||||
XQItem& firstItem = xqItemFromIndex( pIndex );
|
||||
|
||||
return firstItem.data( XQItem::ContentNodeRole );
|
||||
}
|
||||
|
||||
case Qt::StatusTipRole:
|
||||
case Qt::WhatsThisRole:
|
||||
case Qt::SizeHintRole:
|
||||
|
||||
|
||||
case Qt::FontRole:
|
||||
case Qt::TextAlignmentRole:
|
||||
case Qt::BackgroundRole:
|
||||
case Qt::ForegroundRole:
|
||||
case Qt::CheckStateRole:
|
||||
case Qt::InitialSortOrderRole:
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return QStandardItem::data(role);
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
Überschreibt setData() vom QStandardItem. Es wird unterschieden zwischen den data roles, die von
|
||||
'unserem' itemType verwaltet und gespeichert werden und unseren eigenen. ein XQItem enthält nur folgende
|
||||
Felder:
|
||||
|
||||
// - die ItemFlags (geerbt vom QStandardItem) stimmt nicht!
|
||||
- den pointer auf den ItemType
|
||||
- den pointer auf den inhalts-string: content()
|
||||
|
||||
Die anderen werte werden vom itemType verwaltet:
|
||||
|
||||
- der EditorType
|
||||
- der RenderStyle
|
||||
- der UnitType
|
||||
- das ContentFormat
|
||||
- das Icon
|
||||
- ggf. das choiceModel, falls dieses Item als combobox gerendert wird.
|
||||
|
||||
*/
|
||||
|
||||
void XQItem::setData(const QVariant& value, int role )
|
||||
{
|
||||
switch(role)
|
||||
{
|
||||
|
||||
case RenderStyleRole :
|
||||
case EditorTypeRole :
|
||||
case UnitTypeRole:
|
||||
case ContentFormatRole:
|
||||
case FlagsRole: // Stimmt das?
|
||||
case IconRole:
|
||||
case FixedChoicesRole:
|
||||
{
|
||||
//qDebug() << " ---call type set Data: " << role << ": " << XQItem::fetchItemDataRoleName(role) << ":" << value.toString();
|
||||
XQItemType* oldType = &itemType();
|
||||
XQItemType* newType = oldType->replaceAttribute(value, role );
|
||||
if( oldType != newType )
|
||||
setItemType( newType );
|
||||
|
||||
emitDataChanged();
|
||||
// no break, return!
|
||||
return;
|
||||
}
|
||||
|
||||
// set the raw, unformatted data
|
||||
case ContentRole:
|
||||
{
|
||||
// string ptr setzen kann die basis.
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::EditRole :
|
||||
{
|
||||
qDebug() << " --- setting EDITrole: " << value.toString();
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::DisplayRole :
|
||||
{
|
||||
// what will happen? value is a string ptr ?!
|
||||
qDebug() << " --- setting DISPLAYrole: " << value.toString();
|
||||
break;
|
||||
}
|
||||
|
||||
// alles andere wie gehabt
|
||||
case ContentNodeRole:
|
||||
case SheetNodeRole:
|
||||
|
||||
//case TypeKeyRole: not used
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// hier: behandlung wie gehabt
|
||||
QStandardItem::setData( value,role);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! gibt ein statisches invalid-item zurück, anstelle von nullptr
|
||||
|
||||
XQItem& XQItem::fallBackDummyItem()
|
||||
{
|
||||
static XQItem s_fallBackDummyItem;
|
||||
return s_fallBackDummyItem;
|
||||
}
|
||||
|
||||
|
||||
//! gibt das item für den gegebenen index aus.
|
||||
|
||||
XQItem& XQItem::xqItemFromIndex(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid())
|
||||
{
|
||||
const XQViewModel* mdl = dynamic_cast<const XQViewModel*>(index.model());
|
||||
if (mdl)
|
||||
return mdl->xqItemFromIndex(index);
|
||||
}
|
||||
return fallBackDummyItem();
|
||||
}
|
||||
|
||||
|
||||
//! gibt den enum-type für den gegebenen datarole-key aus.
|
||||
|
||||
int XQItem::fetchItemDataRole( const QString& dataRoleKey )
|
||||
{
|
||||
if(!dataRoleKey.isEmpty() && s_ItemDataRoleMap.contains(dataRoleKey) )
|
||||
return s_ItemDataRoleMap[ dataRoleKey ];
|
||||
|
||||
return NoRole;
|
||||
}
|
||||
|
||||
|
||||
//! gibt die bezeichung für die gegebene datarole aus.
|
||||
|
||||
QString XQItem::fetchItemDataRoleName( int dataRole )
|
||||
{
|
||||
return s_ItemDataRoleMap.key(dataRole);
|
||||
}
|
||||
|
||||
|
||||
//! gibt das flag für den gegebenen itemflag-key aus.
|
||||
|
||||
Qt::ItemFlag XQItem::fetchItemFlag( const QString& flagKey )
|
||||
{
|
||||
if(!flagKey.isEmpty() && s_ItemFlagMap.contains(flagKey) )
|
||||
return Qt::ItemFlag( s_ItemFlagMap[ flagKey ] );
|
||||
return Qt::NoItemFlags;
|
||||
}
|
||||
|
||||
//! gibt die bezeichung für das gegebene itemFlag aus.
|
||||
|
||||
QString XQItem::fetchItemFlagName( int flag )
|
||||
{
|
||||
return s_ItemFlagMap.key(flag);
|
||||
}
|
||||
|
||||
|
||||
//! gibt den enum-type für den gegebenen renderStyle-key aus.
|
||||
|
||||
XQItem::RenderStyle XQItem::fetchRenderStyle(const QString& styleKey )
|
||||
{
|
||||
if(!styleKey.isEmpty() && s_RenderStyleMap.contains(styleKey) )
|
||||
return s_RenderStyleMap[styleKey];
|
||||
return NoRenderStyle;
|
||||
}
|
||||
|
||||
|
||||
//! gibt die bezeichung für den gegebenen renderStyle aus.
|
||||
|
||||
QString XQItem::fetchRenderStyleToString(XQItem::RenderStyle renderStyle )
|
||||
{
|
||||
return s_RenderStyleMap.key(renderStyle);
|
||||
}
|
||||
|
||||
|
||||
//! gibt den renderstyle enum-type für den gegebenen editorType-key aus.
|
||||
|
||||
XQItem::EditorType XQItem::fetchEditorType( const QString& editorTypeKey )
|
||||
{
|
||||
if(!editorTypeKey.isEmpty() && s_EditorTypeMap.contains(editorTypeKey) )
|
||||
return s_EditorTypeMap[editorTypeKey];
|
||||
return NoEditorType;
|
||||
}
|
||||
|
||||
|
||||
//! gibt die bezeichung für den gegebenen editorType aus.
|
||||
|
||||
QString XQItem::fetchEditorTypeToString( EditorType editorType )
|
||||
{
|
||||
return s_EditorTypeMap.key(editorType);
|
||||
}
|
||||
|
||||
|
||||
//! gibt den unitType für den gegebenen unitType-key aus.
|
||||
|
||||
XQItem::UnitType XQItem::fetchUnitType(const QString& unitTypeKey)
|
||||
{
|
||||
return s_UnitTypeMap.key(unitTypeKey);
|
||||
}
|
||||
|
||||
//! gibt die bezeichung für den gegebenen unitType aus.
|
||||
|
||||
QString XQItem::fetchUnitTypeToString( UnitType unitType)
|
||||
{
|
||||
return s_UnitTypeMap[unitType];
|
||||
}
|
||||
|
||||
/// ---
|
||||
/// ---
|
||||
/// ---
|
276
src/items/xqitem.h
Normal file
276
src/items/xqitem.h
Normal file
@@ -0,0 +1,276 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQITEM_H
|
||||
#define XQITEM_H
|
||||
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#include <QStandardItem>
|
||||
|
||||
#include <xqnode.h>
|
||||
|
||||
|
||||
using XQItemList = QList<QStandardItem*>;
|
||||
|
||||
class XQItemFactory;
|
||||
class XQItemType;
|
||||
|
||||
/**
|
||||
* @brief Extends QStandardItem to hold additional
|
||||
* settings.
|
||||
*/
|
||||
|
||||
class XQItem : public QStandardItem
|
||||
{
|
||||
|
||||
friend class XQItemFactory;
|
||||
|
||||
public:
|
||||
|
||||
/// Die data(enum role) Infrastruktur wird sowohl für XQItem als auch
|
||||
/// für den XQItemType verwendet, deshalb definieren wir hier _alle_
|
||||
/// notwendigen Roles
|
||||
|
||||
enum ItemDataRole
|
||||
{
|
||||
NoRole = Qt::UserRole + 1,
|
||||
// das ist ein pointer auf den original-string aus dem XML
|
||||
ContentRole,
|
||||
ItemTypeRole,
|
||||
RenderStyleRole,
|
||||
EditorTypeRole,
|
||||
UnitTypeRole,
|
||||
ContentFormatRole,
|
||||
// @see qstandarditemmodel.cpp, stolen from there
|
||||
FlagsRole = Qt::ItemDataRole(Qt::UserRole - 1),
|
||||
IconRole = Qt::DecorationRole,
|
||||
// re-start count
|
||||
FixedChoicesRole = ContentFormatRole+1,
|
||||
ContentNodeRole,
|
||||
//?? werden beide gebraucht?
|
||||
SheetNodeRole,
|
||||
// das ist der Schlüssel um den content string aus dem contentNode zu holen
|
||||
//ContentKeyRole,
|
||||
// weitere, weniger gebräuchlichen Rollen für XQItemType::data()
|
||||
|
||||
TypeKeyRole,
|
||||
//TypeNameRole, nicht so wichtig
|
||||
RoleEnd
|
||||
};
|
||||
|
||||
// wie wirds gemalt
|
||||
enum RenderStyle
|
||||
{
|
||||
NoRenderStyle,
|
||||
HiddenStyle,
|
||||
HeaderStyle,
|
||||
PlainStyle,
|
||||
CheckBoxStyle,
|
||||
ComboBoxStyle,
|
||||
PickerStyle,
|
||||
SpinBoxStyle,
|
||||
ProgressBarStyle,
|
||||
FormattedStyle,
|
||||
TreeHeaderStyle,
|
||||
CustomRenderStyle,
|
||||
RenderStyleEnd //!< Not a special editor. Keep at end of this enumeration!
|
||||
// ...
|
||||
};
|
||||
|
||||
// wie wirds editiert
|
||||
enum EditorType
|
||||
{
|
||||
NoEditorType,
|
||||
LineEditType,
|
||||
ComboBoxType,
|
||||
PickerType,
|
||||
ProgressBarType,
|
||||
SpinBoxType,
|
||||
CustomEditorType,
|
||||
EditorTypeEnd
|
||||
};
|
||||
|
||||
// typische Einheiten
|
||||
enum UnitType
|
||||
{
|
||||
NoUnitType,
|
||||
Ampere,
|
||||
Volt,
|
||||
Ohm,
|
||||
Watt,
|
||||
WattPeak,
|
||||
WattHour,
|
||||
Farad,
|
||||
Tesla,
|
||||
Henry,
|
||||
Hertz,
|
||||
Coulomb,
|
||||
Kelvin,
|
||||
Percent,
|
||||
Second,
|
||||
Meter,
|
||||
Kg,
|
||||
ISODate,
|
||||
UnitTypeEnd
|
||||
};
|
||||
|
||||
|
||||
XQItem();
|
||||
XQItem( XQItemType* itemType );
|
||||
XQItem( XQItemType* itemType, const QString* content );
|
||||
|
||||
virtual ~XQItem() = default;
|
||||
|
||||
//! creates not a clone but a new default item, \see QStandardItemModel::setItemPrototype()
|
||||
//! -- not used at the moment --
|
||||
XQItem* clone() const override;
|
||||
|
||||
//!
|
||||
bool isValid() const;
|
||||
|
||||
//! gibt den zu diesem item gehörigen datenknoten zurück
|
||||
virtual XQNodePtr contentNode() const;
|
||||
|
||||
virtual XQNodePtr sheetNode() const;
|
||||
virtual void setSheetNode( const XQNodePtr& sheetNode );
|
||||
|
||||
XQItemType& itemType() const;
|
||||
void setItemType( XQItemType* itemTypePtr );
|
||||
|
||||
// shortcuts für die itemFlags
|
||||
// __fix! das können die selber !?
|
||||
void addFlag( Qt::ItemFlag newFlag );
|
||||
void clearFlag( Qt::ItemFlag newFlag );
|
||||
QString itemFlagsToString() const;
|
||||
|
||||
// das ist die EditRole: unformatierter Text
|
||||
QString rawText() const;
|
||||
|
||||
// changed: gibt jetzt den pointer zurück.
|
||||
QString* content() const;
|
||||
QString contentKey() const;
|
||||
void setContent( const QString* content );
|
||||
|
||||
//
|
||||
// Convenience-Funktionen zum Memberzugriff, die Implementierung
|
||||
// läuft über die data()-Methode wie in den QStandardItems. So
|
||||
// ist sie für XQItem und auch für XQItemType als Deirvat von XQItem gültig.
|
||||
//
|
||||
|
||||
RenderStyle renderStyle() const;
|
||||
QString renderStyleToString() const;
|
||||
void setRenderStyle(RenderStyle renderStyle );
|
||||
|
||||
EditorType editorType() const;
|
||||
QString editorTypeToString() const;
|
||||
void setEditorType(EditorType editorType);
|
||||
|
||||
UnitType unitType() const;
|
||||
QString unitTypeToString() const;
|
||||
void setUnitType(UnitType unitType);
|
||||
|
||||
QString contentFormat() const;
|
||||
void setContentFormat(const QString& contentFormat);
|
||||
QStandardItemModel* fixedChoices() const;
|
||||
|
||||
QString fixedChoicesToString() const;
|
||||
|
||||
//! setzt das auswahl-model für read-only comboboxes
|
||||
void setfixedChoices( QStandardItemModel* newModel );
|
||||
|
||||
//
|
||||
//shortCuts
|
||||
//
|
||||
|
||||
bool isHeaderStyle();
|
||||
QString dataRoleName(int role) const;
|
||||
|
||||
QVariant data(int role = Qt::DisplayRole ) const override;
|
||||
void setData(const QVariant &value, int role ) override;
|
||||
|
||||
/*
|
||||
template<class T>
|
||||
void setToVariant(T entry, QtExtUserRoles::NTDataRoles role)
|
||||
{
|
||||
setData(QVariant::fromValue<T>(entry), role);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T getFromVariant(QtExtUserRoles::NTDataRoles role)
|
||||
{
|
||||
return data(role).value<T>();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
///
|
||||
/// Static convenience methods
|
||||
///
|
||||
|
||||
static XQItem& xqItemFromIndex( const QModelIndex& index );
|
||||
static XQItem& fallBackDummyItem();
|
||||
|
||||
static int fetchItemDataRole( const QString& dataRoleKey );
|
||||
static QString fetchItemDataRoleName( int dataRole );
|
||||
static Qt::ItemFlag fetchItemFlag( const QString& flagKey );
|
||||
static QString fetchItemFlagName( int flag );
|
||||
static RenderStyle fetchRenderStyle( const QString& styleKey );
|
||||
static QString fetchRenderStyleToString( RenderStyle renderStyle );
|
||||
static EditorType fetchEditorType( const QString& editorTypeKey );
|
||||
static QString fetchEditorTypeToString( EditorType editorType );
|
||||
static UnitType fetchUnitType( const QString& typeKey );
|
||||
static QString fetchUnitTypeToString( UnitType );
|
||||
|
||||
protected:
|
||||
|
||||
XQItem(const XQItem& other) = default;
|
||||
XQItem& operator=(const XQItem& other) = default;
|
||||
|
||||
void setContentNode(const XQNodePtr& contentNode );
|
||||
|
||||
using XQItemFlagMap = QMap<QString,int>;
|
||||
using XQItemDataRoleMap = QMap<QString,int>;
|
||||
using XQRenderStyleMap = QMap<QString,RenderStyle>;
|
||||
using XQEditorTypeMap = QMap<QString,EditorType>;
|
||||
using XQUnitTypeMap = QMap<UnitType, QString>;
|
||||
using XQPrefixExponentMap = QMap<QString, int>;
|
||||
|
||||
static XQItemFlagMap s_ItemFlagMap;
|
||||
static XQItemDataRoleMap s_ItemDataRoleMap;
|
||||
static XQRenderStyleMap s_RenderStyleMap;
|
||||
static XQEditorTypeMap s_EditorTypeMap;
|
||||
static XQUnitTypeMap s_UnitTypeMap;
|
||||
static XQPrefixExponentMap s_PrefixExponentMap;
|
||||
|
||||
//! leerer itemtype als mockup für den xqitem default constructor
|
||||
static XQItemType s_DummyItemType;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
Q_DECLARE_METATYPE(XQItem::RenderStyle);
|
||||
Q_DECLARE_METATYPE(XQItem::EditorType);
|
||||
Q_DECLARE_METATYPE(XQItem::UnitType);
|
||||
Q_DECLARE_METATYPE(const QString*);
|
||||
|
||||
#endif // XQITEM_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
287
src/items/xqitemdelegate.cpp
Normal file
287
src/items/xqitemdelegate.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <QApplication>
|
||||
#include <QItemEditorFactory>
|
||||
#include <QLineEdit>
|
||||
#include <QComboBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QProgressBar>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QHeaderView>
|
||||
#include <QCommonStyle>
|
||||
|
||||
#include <xqitemdelegate.h>
|
||||
#include <xqtreetable.h>
|
||||
#include <xqitemtype.h>
|
||||
#include <xqviewmodel.h>
|
||||
|
||||
|
||||
class XQItemEditorFactory : public QItemEditorFactory
|
||||
{
|
||||
public:
|
||||
|
||||
XQItemEditorFactory()
|
||||
{
|
||||
|
||||
registerEditor(XQItem::LineEditType, new QStandardItemEditorCreator<QLineEdit>());
|
||||
registerEditor(XQItem::ComboBoxType, new QStandardItemEditorCreator<QLineEdit>());
|
||||
registerEditor(XQItem::PickerType, new QStandardItemEditorCreator<QLineEdit>());
|
||||
registerEditor(XQItem::ProgressBarType, new QStandardItemEditorCreator<QLineEdit>());
|
||||
registerEditor(XQItem::SpinBoxType, new QStandardItemEditorCreator<QLineEdit>());
|
||||
registerEditor(XQItem::CustomEditorType, new QStandardItemEditorCreator<QLineEdit>());
|
||||
|
||||
/*
|
||||
registerEditor(XQItem::LineEditStyle, new QStandardItemEditorCreator<QLineEdit>());
|
||||
registerEditor(XQItemType::ComboBoxStyle, new QStandardItemEditorCreator<QComboBox>());
|
||||
//registerEditor(XQItemType::ProgressBarStyle, new QStandardItemEditorCreator<QProgressBar>());
|
||||
registerEditor(XQItemType::SpinBoxStyle, new QStandardItemEditorCreator<QSpinBox>());
|
||||
*/
|
||||
/*
|
||||
registerEditor(XQItem::etDoubleSpinType, new QStandardItemEditorCreator<QDoubleSpinBox>());
|
||||
registerEditor(XQItemItemTypes::etDoubleSpinType, new QStandardItemEditorCreator<QDoubleSpinBox>());
|
||||
registerEditor(XQItemItemTypes::etIPAddressType, new QStandardItemEditorCreator<NTIpAddressEdit>());
|
||||
registerEditor(XQItemItemTypes::etLineEditBrowser, new QStandardItemEditorCreator<NTFileSelectLine>());
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
XQItemDelegate::XQItemDelegate( XQViewModel& modelView)
|
||||
: _modelView{modelView}
|
||||
{
|
||||
static XQItemEditorFactory s_EditorFactory;
|
||||
setItemEditorFactory(&s_EditorFactory);
|
||||
}
|
||||
|
||||
|
||||
XQTreeTable* XQItemDelegate::treeTable() const
|
||||
{
|
||||
return _modelView.treeTable();
|
||||
}
|
||||
|
||||
|
||||
XQItem& XQItemDelegate::xqItemFromIndex( const QModelIndex& index ) const
|
||||
{
|
||||
return _modelView.xqItemFromIndex( index );
|
||||
}
|
||||
|
||||
|
||||
void XQItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
if( !index.isValid() )
|
||||
qDebug() << " index DEAD!";
|
||||
|
||||
XQItem& item = xqItemFromIndex( index );
|
||||
if( item.isValid() )
|
||||
{
|
||||
|
||||
switch( item.renderStyle() )
|
||||
{
|
||||
case XQItem::HeaderStyle :
|
||||
return drawHeaderStyle( painter, option, index );
|
||||
|
||||
case XQItem::ComboBoxStyle :
|
||||
return drawComboBoxStyle( painter, option, index );
|
||||
|
||||
case XQItem::HiddenStyle :
|
||||
return;
|
||||
|
||||
//case XQItem::ProgressBarStyle :
|
||||
// return drawProgressBarStyle( painter, option, index );
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
} // switch
|
||||
|
||||
}
|
||||
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
|
||||
}
|
||||
|
||||
//! einen section header im header-style zeichnen
|
||||
|
||||
void XQItemDelegate::drawHeaderStyle(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
QStyleOptionHeader 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)
|
||||
{
|
||||
// save painter
|
||||
painter->save();
|
||||
//value = index.data(Qt::ForegroundRole);
|
||||
//if (value.canConvert<QBrush>())
|
||||
//headerOption.palette.setBrush(QPalette::Text, Qt::red );
|
||||
//headerOption.palette.setBrush(QPalette::Window, Qt::red );
|
||||
QCommonStyle itemStyle;
|
||||
//headerOption.backgroundBrush()
|
||||
//srcWidget->style()->drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget);
|
||||
itemStyle.drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget);
|
||||
// restore painter
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
|
||||
void XQItemDelegate::drawProgressBarStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
|
||||
int progress = index.data(XQItem::ContentRole ).toInt();
|
||||
|
||||
QStyleOptionProgressBar progressBarOption;
|
||||
progressBarOption.rect = option.rect;
|
||||
progressBarOption.minimum = 0;
|
||||
progressBarOption.maximum = 100;
|
||||
progressBarOption.progress = progress;
|
||||
progressBarOption.text = QString::number(progress) + "%";
|
||||
progressBarOption.textAlignment = Qt::AlignCenter;
|
||||
progressBarOption.textVisible = true;
|
||||
|
||||
QApplication::style()->drawControl(QStyle::CE_ProgressBar,&progressBarOption, painter);
|
||||
|
||||
}
|
||||
|
||||
void XQItemDelegate::drawComboBoxStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
|
||||
QWidget* srcWidget = qobject_cast<QWidget*>(option.styleObject);
|
||||
QStyleOptionComboBox comboOption;
|
||||
QStyle* comboStyle = srcWidget->style();
|
||||
|
||||
comboOption.initFrom(srcWidget);
|
||||
|
||||
// set options
|
||||
comboOption.rect = option.rect;
|
||||
comboOption.state = option.state | QStyle::State_Selected | QStyle::State_Enabled;
|
||||
// not editable => only visual, but painter needs to know it
|
||||
comboOption.editable = false;
|
||||
comboOption.currentText = index.data(Qt::DisplayRole).toString();
|
||||
// decoration (if any)
|
||||
comboOption.currentIcon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
|
||||
comboOption.iconSize = comboOption.currentIcon.actualSize(QSize(option.rect.height() - 3, option.rect.height() - 3));
|
||||
|
||||
// save painter
|
||||
painter->save();
|
||||
// draw combo
|
||||
comboStyle->drawComplexControl(QStyle::CC_ComboBox, &comboOption, painter, srcWidget);
|
||||
// and combobox label
|
||||
comboStyle->drawControl(QStyle::CE_ComboBoxLabel, &comboOption, painter, srcWidget);
|
||||
// restore painter
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void XQItemDelegate::drawSpinBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
|
||||
// xx_fix!
|
||||
//int value = index.data(XQItem::ContentRole ).toInt();
|
||||
QStyleOptionSpinBox spinBoxOption;
|
||||
spinBoxOption.rect = option.rect;
|
||||
/*
|
||||
spinBoxOption.text = QString::number(value);
|
||||
spinBoxOption.textAlignment = Qt::AlignCenter;
|
||||
spinBoxOption.textVisible = true;
|
||||
*/
|
||||
|
||||
QApplication::style()->drawComplexControl(QStyle::CC_SpinBox,&spinBoxOption, painter);
|
||||
}
|
||||
|
||||
|
||||
QSize XQItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
return QStyledItemDelegate::sizeHint(option, index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
QWidget* XQItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
|
||||
return QStyledItemDelegate::createEditor( parent, option, index );
|
||||
|
||||
int editorType = XQItem::xqItemFromIndex(index).editorType();
|
||||
QWidget* editor = itemEditorFactory()->createEditor(editorType, parent);
|
||||
if( editor )
|
||||
{
|
||||
return editor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void XQItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||
{
|
||||
|
||||
XQItem& item = xqItemFromIndex( index );
|
||||
switch( item.editorType() )
|
||||
{
|
||||
case XQItemType::ComboBoxType :
|
||||
{
|
||||
QComboBox* comboBox = qobject_cast<QComboBox*>(editor);
|
||||
comboBox->setModel( item.fixedChoices());
|
||||
comboBox->setCurrentText( item.data().toString() );
|
||||
comboBox->showPopup();
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
|
||||
void XQItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
|
||||
{
|
||||
|
||||
XQItem& item = xqItemFromIndex( index );
|
||||
|
||||
switch( item.editorType() )
|
||||
{
|
||||
|
||||
case XQItem::ComboBoxType :
|
||||
{
|
||||
QComboBox* comboBox = qobject_cast<QComboBox*>(editor);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
|
||||
void XQItemDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
//qDebug() << " --- update Editor Geometry";
|
||||
QStyledItemDelegate::updateEditorGeometry(editor, option, index);
|
||||
}
|
58
src/items/xqitemdelegate.h
Normal file
58
src/items/xqitemdelegate.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQITEMDELEGATE_H
|
||||
#define XQITEMDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
#include <xqappdata.h>
|
||||
|
||||
class XQItem;
|
||||
class XQTreeTable;
|
||||
class XQViewModel;
|
||||
|
||||
/**
|
||||
* @brief A specialized QItemDelegate class to draw different XQItem styles.
|
||||
*/
|
||||
|
||||
class XQItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit XQItemDelegate(XQViewModel& modelView);
|
||||
|
||||
XQTreeTable* treeTable() const;
|
||||
XQItem& xqItemFromIndex( const QModelIndex& index ) const;
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
|
||||
protected:
|
||||
|
||||
void drawHeaderStyle(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 drawSpinBoxStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
XQViewModel& _modelView;
|
||||
|
||||
};
|
||||
|
||||
#endif // XQITEMDELEGATE_H
|
411
src/items/xqitemfactory.cpp
Normal file
411
src/items/xqitemfactory.cpp
Normal file
@@ -0,0 +1,411 @@
|
||||
/***************************************************************************
|
||||
|
||||
source::worx xtree
|
||||
Copyright © 2024-2025 c.holzheuer
|
||||
christoph.holzheuer@gmail.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <xqitemfactory.h>
|
||||
#include <xqexception.h>
|
||||
#include <xqdocumentstore.h>
|
||||
#include <xqviewmodel.h>
|
||||
#include <xqitemtype.h>
|
||||
|
||||
#include <znode_factory.h>
|
||||
|
||||
|
||||
void XQItemFactory::initItemFactory( const QString& modelSheetFileName )
|
||||
{
|
||||
auto configureItemType = [&, this](XQItemType* itemType, const XQNodePtr& sheetNode )
|
||||
{
|
||||
// über alle attribute
|
||||
for( const auto& [key,value] : sheetNode->attributes() )
|
||||
{
|
||||
//qDebug() << " --- conf item Type: " << key << " : " << value;
|
||||
setItemDataFromString( *itemType, key, value );
|
||||
}
|
||||
};
|
||||
|
||||
// schritt #1: modelbeschreibung laden
|
||||
XQNodeFactory treeLoader;
|
||||
_modelSheet = treeLoader.load_tree( qPrintable(modelSheetFileName) );
|
||||
|
||||
// schritt #2: model root testen
|
||||
if (!_modelSheet)
|
||||
throw XQException("modelSheet load failed. ", modelSheetFileName);
|
||||
|
||||
// schritt #3: itemtype beschreibungen laden ...
|
||||
_typesSheet = _modelSheet->find_child_by_tag_name( "ItemTypes" );
|
||||
// ... und testen
|
||||
if( !_typesSheet )
|
||||
throw XQException( "initItemFactory <ItemTypes> is null" );
|
||||
|
||||
// alle itemtype vorlagen erzeugen
|
||||
for( const XQNodePtr& typeSheetNode : _typesSheet->children())
|
||||
{
|
||||
XQItemType* itemType = new XQItemType;
|
||||
//const QString& typeName = typeSheetNode->tag_name();
|
||||
const QString& typeName = typeSheetNode->tag_name();
|
||||
configureItemType(itemType, typeSheetNode);
|
||||
|
||||
itemType->setText( typeName);
|
||||
s_ItemTypeTemplates[typeName] = itemType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool XQItemFactory::isValid()
|
||||
{
|
||||
return _modelSheet && _typesSheet;
|
||||
}
|
||||
|
||||
|
||||
//! Es reicht nicht, einen itemType aus den itemType-templates zu
|
||||
//! holen: möglicherweise muss der noch mit zusätzlichen attributen
|
||||
//! ergänzt werden.
|
||||
//! Vom aufwand ist es auch egal, ob ich daten aus dem XML in das
|
||||
//! item oder den itemtyp schreiben muss.
|
||||
|
||||
XQItemType* XQItemFactory::makeItemType(const XQNodePtr& sheetEntry )
|
||||
{
|
||||
QString typeKey = sheetEntry->attribute( c_ItemType );
|
||||
XQItemType* itemType = findItemTypeTemplate(typeKey);
|
||||
|
||||
// wir prüfen, ob im sheetEntry noch zusätzliche attribute vorhanden
|
||||
// sind, die wir in dem itemType müssen
|
||||
|
||||
//qDebug() << " --- makeItemType: " << sheetEntry->to_string();
|
||||
|
||||
// über alle attribute
|
||||
for (const auto& attrEntry : sheetEntry->attributes())
|
||||
{
|
||||
// prüfen, ob der itemType des attribute schon hat
|
||||
int role = itemType->roleForAttributeKey( attrEntry.first );
|
||||
// wenn ja, überschreiben
|
||||
if( role != XQItem::NoRole )
|
||||
{
|
||||
QVariant newValue = makeVariant(role, attrEntry.second );
|
||||
itemType = itemType->replaceAttribute( newValue, role );
|
||||
}
|
||||
|
||||
}
|
||||
return itemType;
|
||||
}
|
||||
|
||||
//! sucht einen item typ aus der map mit 'vorgefertigen' itemtypen.
|
||||
|
||||
XQItemType* XQItemFactory::findItemTypeTemplate(const QString& key ) const
|
||||
{
|
||||
if( !key.isEmpty() && s_ItemTypeTemplates.contains(key))
|
||||
return s_ItemTypeTemplates[key];
|
||||
throw XQException( "itemfactory: findItemTypeTemplate: not found:", key );
|
||||
}
|
||||
|
||||
|
||||
//! sucht eine model-beschreibung
|
||||
|
||||
XQNodePtr XQItemFactory::findModelSheet( const QString& modelName ) const
|
||||
{
|
||||
XQNodePtr modelSheet = _modelSheet->find_child_by_tag_name( modelName );
|
||||
if( !modelSheet )
|
||||
throw XQException( "model sheet not found: ", modelName );
|
||||
|
||||
return modelSheet;
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt eine QVariant aus dem gegebenen string und setzt diese dann via role im item.
|
||||
|
||||
void XQItemFactory::setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const
|
||||
{
|
||||
int dataRole = XQItem::fetchItemDataRole( roleKey );
|
||||
if( dataRole != XQItem::NoRole)
|
||||
{
|
||||
QVariant variant = makeVariant( dataRole, source );
|
||||
if( !variant.isNull() && variant.isValid() )
|
||||
item.setData( variant, dataRole );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt eine QVariant aus dem gegebenen string
|
||||
|
||||
QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const
|
||||
{
|
||||
|
||||
QVariant value;
|
||||
|
||||
switch(dataRole)
|
||||
{
|
||||
// das ist ein pointer auf den original-string aus dem XML
|
||||
case XQItem::ContentRole:
|
||||
{
|
||||
// content() -> QString*
|
||||
value = QVariant::fromValue(&source);
|
||||
break;
|
||||
}
|
||||
|
||||
case XQItem::ItemTypeRole:
|
||||
{
|
||||
// itemType() -> XQItemType*
|
||||
//qDebug() << " --- makeVariant: make ItemType: " << source;
|
||||
XQItemType* itemType = findItemTypeTemplate( source );
|
||||
value = QVariant::fromValue(itemType);
|
||||
break;
|
||||
}
|
||||
|
||||
case XQItem::RenderStyleRole:
|
||||
{
|
||||
XQItem::RenderStyle renderStyle = XQItem::fetchRenderStyle( source );
|
||||
value = QVariant::fromValue(renderStyle);
|
||||
break;
|
||||
}
|
||||
|
||||
case XQItem::EditorTypeRole:
|
||||
{
|
||||
XQItem::EditorType editorType = XQItem::fetchEditorType( source );
|
||||
value = QVariant::fromValue(editorType);
|
||||
break;
|
||||
}
|
||||
|
||||
case XQItem::UnitTypeRole:
|
||||
{
|
||||
//qDebug() << " --- make unit type: " << source;
|
||||
XQItem::UnitType unitType = XQItem::fetchUnitType( source );
|
||||
value = QVariant::fromValue(unitType);
|
||||
break;
|
||||
}
|
||||
|
||||
case XQItem::ContentFormatRole:
|
||||
{
|
||||
// contentFormat() -> QString
|
||||
value = QVariant::fromValue(source);
|
||||
break;
|
||||
}
|
||||
|
||||
case XQItem::FlagsRole:
|
||||
{
|
||||
QFlags itemFlags = Qt::NoItemFlags;
|
||||
const QStringList flagKeys = source.split( '|' );
|
||||
for( const QString& flagKey : flagKeys )
|
||||
{
|
||||
Qt::ItemFlag flag = XQItem::fetchItemFlag( flagKey );
|
||||
itemFlags.setFlag( flag );
|
||||
}
|
||||
value = QVariant::fromValue(itemFlags);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case XQItem::IconRole:
|
||||
{
|
||||
QIcon typeIcon = XQAppData::typeIcon(source);
|
||||
value = QVariant::fromValue(typeIcon);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case XQItem::FixedChoicesRole:
|
||||
{
|
||||
const QStringList choices = source.split( '|' );
|
||||
|
||||
QStandardItemModel* fixedChoices = new QStandardItemModel();
|
||||
for( const QString& entry : choices )
|
||||
fixedChoices->appendRow( new QStandardItem( entry ) );
|
||||
value = QVariant::fromValue(fixedChoices);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
case XQItem::ContentNodeRole:
|
||||
{
|
||||
value = QVariant::fromValue(&source);
|
||||
break;
|
||||
}
|
||||
|
||||
case XQItem::XQItem::SheetNodeRole:
|
||||
{
|
||||
value = QVariant::fromValue(&source);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
default:
|
||||
case XQItem::XQItem::NoRole:
|
||||
{
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
//if( !value.toString().isEmpty())
|
||||
// setData( value, dataRole);
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
/// ------------------------------------------------
|
||||
///
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
XQItemList XQItemFactory::makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode )
|
||||
{
|
||||
Q_UNUSED(contentNode)
|
||||
|
||||
XQItemList list;
|
||||
|
||||
// create a data node for each sheet entry
|
||||
size_t max = sheetNode->children().size();
|
||||
for( size_t i=0; i<max; ++i )
|
||||
{
|
||||
// __fix
|
||||
//list.append( new XQItem( "", XQItemType::EmptyStyle ) );
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
XQItemList XQItemFactory::createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode )
|
||||
{
|
||||
|
||||
// we have a new empty contentNode, so we add attributes first.
|
||||
for( const auto& sheetEntry : sheetNode->children() )
|
||||
{
|
||||
QString value = "[" + sheetEntry->tag_name() + "]";
|
||||
if( sheetEntry->has_attribute("Unit") )
|
||||
value = "0";
|
||||
contentNode->set_attribute( sheetEntry->tag_name(), value );
|
||||
}
|
||||
|
||||
if( sheetNode->has_attribute( c_FriendlyName ) )
|
||||
contentNode->set_attribute( c_FriendlyName, sheetNode->friendly_name() );
|
||||
|
||||
// now, we can create a normal entry row
|
||||
return makeContentRow(contentNode, sheetNode );
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//! 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;
|
||||
}
|
||||
|
72
src/items/xqitemfactory.h
Normal file
72
src/items/xqitemfactory.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* **************************************************************************
|
||||
|
||||
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 XQITEMFACTORY_H
|
||||
#define XQITEMFACTORY_H
|
||||
|
||||
#include <xqitem.h>
|
||||
#include <xqitemtype.h>
|
||||
#include <functional>
|
||||
|
||||
class XQViewModel;
|
||||
|
||||
// erzeugt items aus XQNodes
|
||||
|
||||
class XQItemFactory : public xsingleton<XQItemFactory>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
void initItemFactory(const QString& modelSheetFileName );
|
||||
|
||||
XQNodePtr findModelSheet( const QString& modelName ) const;
|
||||
|
||||
//XQItemList makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode );
|
||||
|
||||
XQItemList makeHeaderRow( const XQNodePtr& sheetNode, const QString& caption = c_Caption );
|
||||
XQItemList makeContentRow( const XQNodePtr& sheetNode, const XQNodePtr& contentNode );
|
||||
|
||||
// wozu ist das gut?
|
||||
//XQItemList createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode );
|
||||
|
||||
void setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const;
|
||||
|
||||
XQItemType* makeItemType(const XQNodePtr& sheetEntry );
|
||||
XQItemType* findItemTypeTemplate(const QString& key ) const;
|
||||
QVariant makeVariant(int dataRole, const QString &value ) const;
|
||||
|
||||
protected:
|
||||
|
||||
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
|
||||
using ItemConfigFunc = std::function<void( XQItem* item, const QString& attrValue, XQNodePtr contentNode, XQNodePtr sheetNode )>;
|
||||
using ItemConfigMap = QMap<QString,ItemConfigFunc>;
|
||||
|
||||
XQItemTypeMap s_ItemTypeTemplates;
|
||||
|
||||
// Beschreibung des XQModels
|
||||
XQNodePtr _modelSheet{};
|
||||
// Beschreibung der ItemTypes
|
||||
XQNodePtr _typesSheet{};
|
||||
|
||||
};
|
||||
|
||||
#endif // XQITEMFACTORY_H
|
271
src/items/xqitemtype.cpp
Normal file
271
src/items/xqitemtype.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <cmath>
|
||||
#include <xqitemtype.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
XQItemTypeMap XQItemType::s_ItemTypeMap;
|
||||
size_t XQItemType::s_ItemTypeCount = 0;
|
||||
|
||||
///
|
||||
/// XQItemType
|
||||
///
|
||||
|
||||
|
||||
XQItemType::XQItemType()
|
||||
: XQItem(nullptr) // vermeide rekursion
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
XQItemType::XQItemType( const XQItemType& other)
|
||||
: XQItem( other )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//! destruktor, räumt das fixedChoices auf, so vorhanden.
|
||||
|
||||
XQItemType::~XQItemType()
|
||||
{
|
||||
// das einzige property, was auch auf dem heap liegt.
|
||||
QStandardItemModel* choices = fixedChoices();
|
||||
if( choices )
|
||||
{
|
||||
setfixedChoices( nullptr );
|
||||
delete choices;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! ruft QStandardItem::data auf
|
||||
|
||||
QVariant XQItemType::data( int role ) const
|
||||
{
|
||||
return QStandardItem::data(role);
|
||||
}
|
||||
|
||||
|
||||
//! ruft QStandardItem::setData auf
|
||||
|
||||
void XQItemType::setData(const QVariant& value, int role )
|
||||
{
|
||||
//qDebug() << " --- itemType set Data:" << role << " : " << value.toString();
|
||||
return QStandardItem::setData(value,role);
|
||||
}
|
||||
|
||||
//! tested, ob ein attribute (z.B. unitType) hier vorhanden ist
|
||||
int XQItemType::roleForAttributeKey( const QString& attrKey )
|
||||
{
|
||||
int role = XQItem::fetchItemDataRole(attrKey);
|
||||
// gibbed überhaupt eine rolle für unser attribut?
|
||||
if( role != XQItem::NoRole)
|
||||
{
|
||||
// wenn ja, ist die role hier besetzt?
|
||||
QVariant value = data(role);
|
||||
if( !value.isValid() || value.isNull() )
|
||||
return XQItem::NoRole;
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
|
||||
//! setzt einen attributwert neu. Ggf. wird ein neuer ItemType erzeugt.
|
||||
|
||||
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?
|
||||
QVariant oldValue = data(role);
|
||||
|
||||
// nein, es hat nicht
|
||||
if( oldValue == newValue )
|
||||
return this;
|
||||
|
||||
// kopie von mir
|
||||
XQItemType* myClone = new XQItemType(*this);
|
||||
// Änderungen übernehmen
|
||||
myClone->setData( newValue, role );
|
||||
// Gibt es den geänderten ItemType schon?
|
||||
QString newKey = myClone->makeItemTypeKey();
|
||||
// jawoll
|
||||
if( s_ItemTypeMap.contains( newKey ) )
|
||||
{
|
||||
// abräumen ...
|
||||
delete myClone;
|
||||
// und die alte version zurückgegen
|
||||
return s_ItemTypeMap[newKey];
|
||||
}
|
||||
|
||||
// speichern
|
||||
s_ItemTypeMap.insert( newKey, myClone );
|
||||
|
||||
//qDebug() << " --- After: " << myClone->makeItemTypeKey();
|
||||
|
||||
/// Obacht! Der alte, geänderte itemType bleibt erhalten
|
||||
/// und verrottet ggf. ohne Daseinszweck
|
||||
|
||||
return myClone;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! formatiert den content() string eines items.
|
||||
|
||||
QVariant XQItemType::formatText( const XQItem& item ) const
|
||||
{
|
||||
XQItem::UnitType uType = unitType();
|
||||
//qDebug() << " --- formatText: " << XQItem::fetchUnitTypeToString( uType);
|
||||
const QString& cont = item.rawText();
|
||||
if( uType != XQItem::NoUnitType )
|
||||
return formatToSI( cont, uType );
|
||||
return cont;
|
||||
}
|
||||
|
||||
|
||||
//! formatiert einen zahlenwert als string mit einheit.
|
||||
|
||||
QString XQItemType::formatToSI( const QString& valueTxt, XQItem::UnitType unitType ) const
|
||||
{
|
||||
|
||||
if( valueTxt.isEmpty() )
|
||||
return valueTxt;
|
||||
|
||||
if( XQItem::ISODate == unitType )
|
||||
{
|
||||
// format iso date
|
||||
QDateTime dateTime = QDateTime::fromString(valueTxt, Qt::ISODate);
|
||||
// fixme! make this configurable!
|
||||
QString format = "dd.MM.yyyy HH:mm:ss"; // You can customize this format
|
||||
// Format the QDateTime object into a human-readable string
|
||||
return dateTime.toString(format);
|
||||
}
|
||||
|
||||
QLocale sysLocale = QLocale::system();
|
||||
sysLocale.setNumberOptions(sysLocale.numberOptions() | QLocale::OmitGroupSeparator);
|
||||
|
||||
double dVal = sysLocale.toDouble(valueTxt);
|
||||
QString strVal, strPrefix;
|
||||
|
||||
int exp = (int)::log10f(dVal);
|
||||
exp = (exp/3)*3;
|
||||
|
||||
double nVal = dVal;
|
||||
if( !s_PrefixExponentMap.key(exp).isEmpty() )
|
||||
nVal /= ::pow( 10,exp);
|
||||
strVal = sysLocale.toString(nVal, 'f', 2);
|
||||
strPrefix = s_PrefixExponentMap.key(exp);
|
||||
//qDebug() << " convert: " << dVal << " : " << valueTxt << ": " << strVal << ":" << exp << " : " << strPrefix << ": " << nVal;
|
||||
|
||||
return QString("%1 %2%3").arg( strVal, strPrefix, unitTypeToString() );
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! entfernt die einheit aus einem formatierten string
|
||||
|
||||
QString XQItemType::unFormatFromSI(const QString& formText ) const
|
||||
{
|
||||
|
||||
QString input = formText.simplified();
|
||||
// #1: strip numeric part
|
||||
if( input.isEmpty() )
|
||||
return input;
|
||||
|
||||
int idx = 0;
|
||||
for( auto c : input )
|
||||
{
|
||||
if( c.isNumber() || c.toLower() == 'e' || c == '.' || c == ',' ||c == '-' || c == '+' )
|
||||
idx++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if(!idx)
|
||||
return QString("0");
|
||||
|
||||
QString numPart = formText.left(idx);
|
||||
QString unitPart;
|
||||
//if(idx + 1 < formText.size() )
|
||||
unitPart = formText.right(idx - 1).simplified();
|
||||
|
||||
QLocale sysLocale = QLocale::system();
|
||||
double dVal = sysLocale.toDouble(numPart);
|
||||
if( unitPart.size() > 0 )
|
||||
{
|
||||
QString prefix = QString(unitPart[0]);
|
||||
if( s_PrefixExponentMap.contains(prefix) )
|
||||
dVal *= std::pow( 10.0, s_PrefixExponentMap[prefix] );
|
||||
}
|
||||
|
||||
sysLocale.setNumberOptions(sysLocale.numberOptions() | QLocale::OmitGroupSeparator);
|
||||
QString result = sysLocale.toString(dVal, 'f', 2);
|
||||
|
||||
//qDebug() << " convert: " << numPart << " : " << unitPart << " : " << dVal << " : " << result;
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
/// --- statics --------------------------------------------------------------------------
|
||||
///
|
||||
|
||||
//! gibt den dummy item type zurück (benutzt für null-items).
|
||||
|
||||
XQItemType* XQItemType::staticItemType()
|
||||
{
|
||||
static XQItemType s_DummyItemType;
|
||||
return &s_DummyItemType;
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt aus den eingenschaften des itemTypes einen eindeutigen schlüssel.
|
||||
|
||||
QString XQItemType::makeItemTypeKey()
|
||||
{
|
||||
QString key("%1:%2:%3:%4:%5:%6:%7");
|
||||
|
||||
key = key.arg( renderStyleToString() );
|
||||
key = key.arg( editorTypeToString() );
|
||||
key = key.arg( unitTypeToString() );
|
||||
key = key.arg( contentFormat() );
|
||||
key = key.arg( itemFlagsToString() );
|
||||
// icons haben leider keine namen, es sei denn, sie kommen aus einen theme
|
||||
//key = key.arg( icon().name() );
|
||||
//key = key.arg( icon().cacheKey() );
|
||||
key = key.arg( XQAppData::iconName( icon() ) );
|
||||
key = key.arg( fixedChoicesToString() );
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
68
src/items/xqitemtype.h
Normal file
68
src/items/xqitemtype.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQITEMTYPE_H
|
||||
#define XQITEMTYPE_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
|
||||
#include <xqitem.h>
|
||||
|
||||
|
||||
using XQItemTypeMap = QMap<QString, XQItemType*>;
|
||||
|
||||
|
||||
class XQItemType : public XQItem// public QObject
|
||||
{
|
||||
// Q_OBJECT
|
||||
// wäre dann auch eine möglichkeit:
|
||||
// Q_PROPERTY(XQItem::RenderStyle renderStyle renderStyle getDate WRITE setrenderStyle )
|
||||
|
||||
public:
|
||||
|
||||
XQItemType();
|
||||
XQItemType( const XQItemType& other);
|
||||
|
||||
virtual ~XQItemType();
|
||||
|
||||
QVariant data( int role ) const override;
|
||||
void setData(const QVariant& value, int role ) override;
|
||||
|
||||
QVariant formatText( const XQItem& item ) const;
|
||||
|
||||
QString formatToSI(const QString& rawText, XQItem::UnitType unitType ) const;
|
||||
QString unFormatFromSI(const QString& valueText ) const;
|
||||
|
||||
int roleForAttributeKey( const QString& attrKey );
|
||||
XQItemType* replaceAttribute(const QVariant& newValue, int role );
|
||||
|
||||
QString makeItemTypeKey();
|
||||
|
||||
static XQItemType* staticItemType();
|
||||
|
||||
protected:
|
||||
|
||||
static XQItemTypeMap s_ItemTypeMap;
|
||||
static size_t s_ItemTypeCount;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Q_DECLARE_METATYPE(XQItemType*);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // XQITEMTYPE_H
|
79
src/main.cpp
Normal file
79
src/main.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QMetaType>
|
||||
|
||||
#include <xqmainwindow.h>
|
||||
|
||||
|
||||
/*
|
||||
|
||||
TODO:
|
||||
|
||||
- kann ich die Enums auto generieren?
|
||||
- entries einfach abzählen,
|
||||
- einen enum als type
|
||||
- auf diesen type drauf-casten, siehe qtglobal.h
|
||||
|
||||
- FIX! in reality, we have nested types, also.
|
||||
- done: reference style
|
||||
- done: shared_ptr
|
||||
|
||||
- try QML
|
||||
- try 'model->readMore'
|
||||
|
||||
doc:
|
||||
- vorhandenes xnode konzept soll am qt angebunden werden
|
||||
- datensparsam: flyweight pattern & pointer auf orig
|
||||
|
||||
who is who:
|
||||
|
||||
- item
|
||||
-itemtype
|
||||
- factory
|
||||
- model
|
||||
- section
|
||||
|
||||
*/
|
||||
|
||||
int main(int argc, char *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");
|
||||
XQMainWindow window;
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
148
src/model/xqcommand.cpp
Normal file
148
src/model/xqcommand.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqcommand.h>
|
||||
#include <xqviewmodel.h>
|
||||
#include <xqtreetable.h>
|
||||
|
||||
|
||||
//! hilfsfunktion: zeigt alle position und die zugehörigen knoten an.
|
||||
|
||||
void XQNodeStore::dumpList( const QString& title ) const
|
||||
{
|
||||
if( !title.isEmpty() )
|
||||
qDebug() << " --- " << title;
|
||||
for( const auto& entry : *this )
|
||||
qDebug() << " -- dumpList: itemPos: " << entry.itemPos << " nodePos: " << entry.nodePos << " id: " << ( entry.contentNode ? entry.contentNode->_id : 0 ) << " used: " << ( entry.contentNode ? entry.contentNode.use_count() : 0 );
|
||||
}
|
||||
|
||||
|
||||
//! kostruktor. übergibt command-type und die aufrufende modelView.
|
||||
|
||||
XQCommand::XQCommand(CmdType cmdType, XQViewModel* modelView )
|
||||
: _cmdType{ cmdType }, _model(modelView)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! destruktor
|
||||
|
||||
XQCommand::~XQCommand()
|
||||
{
|
||||
qDebug() << " --- command destructor: " << toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! gibt den enum-type dieses commands zurück.
|
||||
|
||||
XQCommand::CmdType XQCommand::commandType() const
|
||||
{
|
||||
return _cmdType;
|
||||
}
|
||||
|
||||
|
||||
//! setzt den enum-type dieses commands.
|
||||
|
||||
void XQCommand::setCommandType( XQCommand::CmdType cmdType )
|
||||
{
|
||||
_cmdType = cmdType;
|
||||
}
|
||||
|
||||
|
||||
//! ruft 'onCommandRedo' 'meines' models auf.
|
||||
|
||||
void XQCommand::redo()
|
||||
{
|
||||
_model->onCommandRedo( *this );
|
||||
}
|
||||
|
||||
|
||||
//! ruft 'onCommandUndo' 'meines' models auf.
|
||||
|
||||
void XQCommand::undo()
|
||||
{
|
||||
_model->onCommandUndo( *this );
|
||||
}
|
||||
|
||||
|
||||
//! gibt den urpsrungs-index dieses commands zurück.
|
||||
|
||||
const QModelIndex& XQCommand::originIndex() const
|
||||
{
|
||||
return _originIndex;
|
||||
}
|
||||
|
||||
|
||||
//! merkt sich den ersten QModelIndex der von diesem command
|
||||
//! betroffenen items. zusätzlich wird der command-text erzeugt.
|
||||
|
||||
void XQCommand::setOriginIndex( const QModelIndex& origin )
|
||||
{
|
||||
QString cmdText("%1: %2 (%3)");
|
||||
QString name = origin.data().toString();
|
||||
QString items("%1 item%2");
|
||||
int mySize = size();
|
||||
items = items.arg(mySize).arg(mySize > 1 ? "s" : "");
|
||||
cmdText = cmdText.arg( toString(), name, items );
|
||||
_originIndex = origin;
|
||||
setText(cmdText);
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt aus den 'selected indices' eine liste mit der jewiligen knotenposition,
|
||||
//! der item-zeile und dem content-knoten.
|
||||
|
||||
void XQCommand::saveNodes( const QModelIndexList& list )
|
||||
{
|
||||
clear();
|
||||
// über jede zeil
|
||||
for( auto entry : list )
|
||||
{
|
||||
// knoten holen
|
||||
const XQNodePtr& contentNode = XQItem::xqItemFromIndex( entry ).contentNode();
|
||||
// hier speichern wir den original knoten, nicht einen clone, wie im clipboard.
|
||||
push_back( {entry.row(), contentNode->own_pos(), contentNode } );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt einen string aus dem command-type, fürs debuggen.
|
||||
|
||||
QString XQCommand::toString()
|
||||
{
|
||||
|
||||
static QMap<CmdType,QString> s_CmdTypeMap
|
||||
{
|
||||
{ cmdTextEdit, "cmdTextEdit" },
|
||||
{ cmdInvalid, "cmdInvalid" },
|
||||
{ cmdCut, "cmdCut" },
|
||||
{ cmdPaste, "cmdPaste" },
|
||||
{ cmdPasteSelf, "cmdPasteSelf" },
|
||||
{ cmdNew, "cmdNew" },
|
||||
{ cmdUndo, "cmdUndo" },
|
||||
{ cmdRedo, "cmdRedo" },
|
||||
{ cmdCopy, "cmdCopy" },
|
||||
{ cmdMove, "cmdMove" },
|
||||
{ cmdDelete, "cmdDelete" },
|
||||
{ cmdToggleSection, "cmdToggleSection" },
|
||||
{ cmdExtern, "cmdExtern" }
|
||||
};
|
||||
|
||||
if( !s_CmdTypeMap.contains( _cmdType ))
|
||||
return QString(" cmdType missmatch");
|
||||
return s_CmdTypeMap[_cmdType];
|
||||
|
||||
}
|
107
src/model/xqcommand.h
Normal file
107
src/model/xqcommand.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQCOMMAND_H
|
||||
#define XQCOMMAND_H
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include <xqitem.h>
|
||||
|
||||
class XQViewModel;
|
||||
|
||||
struct XQNodeBackup
|
||||
{
|
||||
int itemPos{-1};
|
||||
int nodePos{-1};
|
||||
XQNodePtr contentNode;
|
||||
};
|
||||
|
||||
class XQNodeStore : public QVector<XQNodeBackup>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
void dumpList( const QString& title="" ) const;
|
||||
virtual void saveNodes( const QModelIndexList& list ) = 0;
|
||||
|
||||
};
|
||||
|
||||
// Das command enthält immer auch die betroffenen items
|
||||
// ist also auch eine SavedNodeList
|
||||
class XQCommand : public QUndoCommand, public XQNodeStore
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum CmdType
|
||||
{
|
||||
cmdInvalid,
|
||||
|
||||
cmdUndo,
|
||||
cmdRedo,
|
||||
|
||||
cmdTextEdit,
|
||||
|
||||
cmdCut,
|
||||
cmdPaste,
|
||||
cmdPasteSelf,
|
||||
cmdCopy,
|
||||
cmdMove,
|
||||
cmdNew,
|
||||
cmdDelete,
|
||||
|
||||
cmdToggleSection,
|
||||
|
||||
cmdExtern //??
|
||||
};
|
||||
|
||||
XQCommand(CmdType cmdType, XQViewModel* modelView );
|
||||
virtual ~XQCommand();
|
||||
|
||||
CmdType commandType() const;
|
||||
void setCommandType( CmdType cmdType );
|
||||
|
||||
const QModelIndex& originIndex() const;
|
||||
void setOriginIndex( const QModelIndex& origin );
|
||||
|
||||
void saveNodes( const QModelIndexList& list ) override;
|
||||
|
||||
void redo() override;
|
||||
void undo() override;
|
||||
|
||||
QString toString();
|
||||
|
||||
protected:
|
||||
|
||||
CmdType _cmdType{cmdInvalid};
|
||||
XQViewModel* _model{}; // needed for redo() / undo()
|
||||
QModelIndex _originIndex;
|
||||
|
||||
/*
|
||||
|
||||
Du hast den item editor vergessen, Du Honk!
|
||||
|
||||
NTCompositeModel* m_pModel;
|
||||
QModelIndex m_index;
|
||||
QVariant m_value;
|
||||
QVariant m_oldValue;
|
||||
bool m_updateIndex;
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(XQCommand::CmdType);
|
||||
|
||||
#endif // XQCOMMAND_H
|
||||
|
206
src/model/xqmodelsectionlist.cpp
Normal file
206
src/model/xqmodelsectionlist.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqmodelsectionlist.h>
|
||||
|
||||
|
||||
//! kontstruktor. übergibt den start-index und einen model-knoten mit der beschreibung
|
||||
//! der datenknoten.
|
||||
|
||||
XQModelSection::XQModelSection(const QModelIndex& modelIndex, XQNodePtr sheetNode)
|
||||
: _modelIndex{ modelIndex }, _sectionRootNode{ sheetNode }
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! elementvergleich.
|
||||
|
||||
bool XQModelSection::operator==(const XQModelSection& other) const
|
||||
{
|
||||
return _modelIndex == other._modelIndex && _sectionRootNode == other._sectionRootNode;
|
||||
}
|
||||
|
||||
|
||||
//! true wenn der start-index valide und ein model-knoten vorhanden.
|
||||
|
||||
bool XQModelSection::isValid() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//! gibt die zeile des start-index zurück.
|
||||
|
||||
int XQModelSection::XQModelSection::row() const
|
||||
{
|
||||
return _modelIndex.row();
|
||||
}
|
||||
|
||||
|
||||
//! gibt den 'content type' zurück.
|
||||
|
||||
const QString& XQModelSection::contentType() const
|
||||
{
|
||||
return _sectionRootNode->attribute( c_ContentType );
|
||||
}
|
||||
|
||||
|
||||
//! gibt das dieser section entsprechende header-item zurück.
|
||||
|
||||
XQItem& XQModelSection::XQModelSection::headerItem() const
|
||||
{
|
||||
return XQItem::xqItemFromIndex( _modelIndex );
|
||||
}
|
||||
|
||||
|
||||
//! testet, ob die unter 'sectionKey' eine gültige section vorhanden ist.
|
||||
|
||||
bool XQModelSectionList::hasValidSection(const QString& sectionKey) const
|
||||
{
|
||||
if (!contains(sectionKey) )
|
||||
return false;
|
||||
return at(sectionKey).isValid();
|
||||
}
|
||||
|
||||
|
||||
//! gibt für einen model index die 'zuständige' section zurück.
|
||||
|
||||
const XQModelSection& XQModelSectionList::sectionFromIndex( const QModelIndex& index ) const
|
||||
{
|
||||
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
|
||||
{
|
||||
|
||||
int i = size() - 1;
|
||||
for (; i >= 0; --i)
|
||||
{
|
||||
if ( at(i).modelIndex().row() < itemRow )
|
||||
return at(i);
|
||||
}
|
||||
|
||||
static XQModelSection s_DummySection;
|
||||
|
||||
return s_DummySection;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! ermittelt die erste zeile einer section.
|
||||
|
||||
int XQModelSectionList::firstRow(const QModelIndex& idx) const
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
//qDebug() << " -- last row in section: " << section.modelIndex.data().toString() << " --> " << section.modelIndex.row();
|
||||
// row() der section unterhalb dieser
|
||||
// __fix? index mit speichern?
|
||||
int index = indexOf(section);
|
||||
if (index > -1)
|
||||
{
|
||||
// last section? return last row of model
|
||||
if (index == size() - 1)
|
||||
return section.modelIndex().model()->rowCount();// - 1;
|
||||
// return row above the row of the next section -> last row of given section
|
||||
return at(index+1).row();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//! gibt alle sections aus, zum ankucken.
|
||||
|
||||
void XQModelSectionList::dump() const
|
||||
{
|
||||
qDebug() << " --- sections dump(): " <<size() << " entries.";
|
||||
for( int i = 0; i<size(); ++i )
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
85
src/model/xqmodelsectionlist.h
Normal file
85
src/model/xqmodelsectionlist.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQMODELSECTIONLIST_H
|
||||
#define XQMODELSECTIONLIST_H
|
||||
|
||||
#include <QPersistentModelIndex>
|
||||
|
||||
#include <xqmaptor.h>
|
||||
#include <xqitem.h>
|
||||
|
||||
/**
|
||||
* @brief Struct containing data for a header section
|
||||
*/
|
||||
|
||||
class XQModelSection
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
|
||||
XQModelSection() = default;
|
||||
XQModelSection(const QModelIndex& modelIndex, XQNodePtr sheetNode );
|
||||
|
||||
bool operator==(const XQModelSection& other) const;
|
||||
bool isValid() 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;
|
||||
|
||||
protected:
|
||||
|
||||
QPersistentModelIndex _modelIndex;
|
||||
|
||||
XQNodePtr _sectionRootNode{};
|
||||
XQNodePtr _contentRootNode{};
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(XQModelSection)
|
||||
|
||||
/**
|
||||
* @brief Maptor containing all header sections.
|
||||
*/
|
||||
|
||||
class XQModelSectionList : public XQMaptor<XQModelSection>
|
||||
{
|
||||
public:
|
||||
|
||||
XQModelSectionList() = default;
|
||||
virtual ~XQModelSectionList() = default;
|
||||
|
||||
void createSectionEntry(const XQItemList& list, const XQNodePtr& sheetNode );
|
||||
bool hasValidSection(const QString& sectionKey) const;
|
||||
|
||||
const XQModelSection& sectionFromRow( int row ) const;
|
||||
const XQModelSection& sectionFromIndex( const QModelIndex& index ) const;
|
||||
|
||||
int firstRow(const QModelIndex& idx) const;
|
||||
int lastRow(const QModelIndex& idx) const;
|
||||
int lastRow(const XQModelSection& section) const;
|
||||
|
||||
void dump()const override;
|
||||
|
||||
};
|
||||
|
||||
#endif // XQMODELSECTIONLIST_H
|
92
src/model/xqnode.cpp
Normal file
92
src/model/xqnode.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqnode.h>
|
||||
#include <xqitem.h>
|
||||
|
||||
|
||||
|
||||
|
||||
//! hilfsfunktion: gibt diesen teilbaum rekursiv aus
|
||||
|
||||
void inspect( const XQNodePtr& node, int indent )
|
||||
{
|
||||
qDebug() << std::string(indent * 2, ' ').c_str() << node.use_count() << ": " << node->to_string();
|
||||
if (node->has_children())
|
||||
{
|
||||
for (const auto& child : node->children())
|
||||
{
|
||||
inspect( child, indent + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! operator<< für QString und std::ostream
|
||||
|
||||
// Overload the operator<< for MyClass and std::ostream
|
||||
std::ostream& operator<<(std::ostream& os, const QString& obj)
|
||||
{
|
||||
// Simply call the getter and insert the string into the stream
|
||||
os << obj.toStdString();
|
||||
return os; // Return the stream for chaining
|
||||
}
|
||||
|
||||
|
||||
//! 'QString' implementation von split
|
||||
|
||||
template<>
|
||||
bool znode::zpayload<QString>::xstr_split_by(const QString& entry, const QString& sep, QString& key, QString& value )
|
||||
{
|
||||
int index = entry.indexOf(sep);
|
||||
if(index < 0)
|
||||
return false;
|
||||
key = entry.left(index);
|
||||
value = entry.mid( index+sep.length() );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//! 'QString' implementation von substr
|
||||
|
||||
template<>
|
||||
QString znode::zpayload<QString>::xstr_sub_str( const QString& entry, int pos ) const
|
||||
{
|
||||
return entry.mid(pos);
|
||||
}
|
||||
|
||||
|
||||
//! 'QString' implementation vom test auf 'empty'
|
||||
|
||||
template<>
|
||||
bool znode::zpayload<QString>::xstr_is_empty(const QString& entry ) const
|
||||
{
|
||||
return entry.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
//! 'QString' varianten der keystrings.
|
||||
|
||||
template<>
|
||||
const QString znode::zpayload<QString>::cType = "Type";
|
||||
|
||||
template<>
|
||||
const QString znode::zpayload<QString>::cName = "Name";
|
||||
|
||||
template<>
|
||||
const QString znode::zpayload<QString>::cValue = "Value";
|
||||
|
||||
template<>
|
||||
const QString znode::zpayload<QString>::cFriendlyName = "FriendlyName";
|
47
src/model/xqnode.h
Normal file
47
src/model/xqnode.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQNODE_H
|
||||
#define XQNODE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include <znode.h>
|
||||
#include <xqappdata.h>
|
||||
#include <znode_factory.h>
|
||||
|
||||
//! überlädt den operator<< für QString und std::ostream
|
||||
std::ostream& operator<<(std::ostream& os, const QString& obj);
|
||||
|
||||
//! raw node
|
||||
using XQNode = znode::zbasic_node<QString>;
|
||||
//! default shared node
|
||||
using XQNodePtr = std::shared_ptr<znode::zbasic_node<QString>>;
|
||||
|
||||
//! die node factory
|
||||
using XQNodeFactory = znode::znode_factory<QString>;
|
||||
|
||||
|
||||
|
||||
//void inspect( XQNodePtr node, int offSet=0 );
|
||||
void inspect( const XQNodePtr& node, int indent=0 );
|
||||
|
||||
Q_DECLARE_METATYPE(XQNodePtr);
|
||||
|
||||
|
||||
#endif // XQNODE_H
|
65
src/model/xqnodewriter.cpp
Normal file
65
src/model/xqnodewriter.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqnodewriter.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#include <xqnode.h>
|
||||
|
||||
|
||||
|
||||
|
||||
//! schreibt einen (teil)baum in ein file
|
||||
|
||||
void XQNodeWriter::dumpTree( XQNodePtr rootNode, const QString& fileName ) const
|
||||
{
|
||||
QFile treeFile( fileName );
|
||||
if (!treeFile.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
throw XQException("can't open", fileName);
|
||||
|
||||
QXmlStreamWriter writer(&treeFile);
|
||||
writer.setAutoFormatting(true); // Makes the output more readable
|
||||
writer.writeStartDocument();
|
||||
|
||||
dumpNode( writer, rootNode );
|
||||
|
||||
writer.writeEndDocument();
|
||||
treeFile.close();
|
||||
}
|
||||
|
||||
|
||||
//! schreibt einen knoten in einen stream
|
||||
|
||||
void XQNodeWriter::dumpNode( QXmlStreamWriter& writer, XQNodePtr node ) const
|
||||
{
|
||||
//qDebug() << " --- dumpNode: id:" << node._id;
|
||||
|
||||
writer.writeStartElement(node->tag_name() );
|
||||
|
||||
if( !node->attributes().empty() )
|
||||
{
|
||||
for( const auto& attrEntry : node->attributes() )
|
||||
writer.writeAttribute( attrEntry.first , attrEntry.second );
|
||||
}
|
||||
|
||||
if( node->has_children() )
|
||||
{
|
||||
for (auto& child : node->children())
|
||||
dumpNode( writer, child );
|
||||
}
|
||||
|
||||
writer.writeEndElement();
|
||||
}
|
42
src/model/xqnodewriter.h
Normal file
42
src/model/xqnodewriter.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQNODEWRITER_H
|
||||
#define XQNODEWRITER_H
|
||||
|
||||
#include <Qt>
|
||||
|
||||
#include "qxmlstream.h"
|
||||
#include <xqnode.h>
|
||||
|
||||
|
||||
class QString;
|
||||
|
||||
class XQNodeWriter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
XQNodeWriter() = default;
|
||||
virtual ~XQNodeWriter() = default;
|
||||
|
||||
void dumpTree( XQNodePtr rootNode, const QString& fileName ) const;
|
||||
|
||||
protected:
|
||||
|
||||
void dumpNode( QXmlStreamWriter& writer, XQNodePtr node ) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // XQNODEWRITER_H
|
70
src/model/xqselectionmodel.cpp
Normal file
70
src/model/xqselectionmodel.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqselectionmodel.h>
|
||||
#include <xqitem.h>
|
||||
|
||||
|
||||
|
||||
//! konstruiert ein selectionmodel.
|
||||
|
||||
XQSelectionModel::XQSelectionModel(QAbstractItemModel* model)
|
||||
: QItemSelectionModel(model)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! konstruiert ein selectionmodel.
|
||||
|
||||
XQSelectionModel::XQSelectionModel(QAbstractItemModel* model, QObject* parent)
|
||||
: QItemSelectionModel(model, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! firz
|
||||
|
||||
void XQSelectionModel::select(const QItemSelection& selection, QItemSelectionModel::SelectionFlags command)
|
||||
{
|
||||
// step #0: fetch selected indices.
|
||||
const QModelIndexList list = selection.indexes();
|
||||
if (list.isEmpty() || selectedRows().isEmpty() )
|
||||
return QItemSelectionModel::select(selection, command);
|
||||
|
||||
// fetch first index
|
||||
QModelIndex firstValid = list.first();
|
||||
if (hasSelection() )
|
||||
firstValid = selectedRows().first();
|
||||
|
||||
//XQItem& firstItem = XQItem::xqItemFromIndex(firstValid);
|
||||
//if( firstItem.isValid() )
|
||||
{
|
||||
|
||||
XQNodePtr firstNode = XQItem::xqItemFromIndex(firstValid).contentNode();
|
||||
QItemSelection newSelection;
|
||||
// __fixme! das crasht!
|
||||
|
||||
for (const QModelIndex& idx : list)
|
||||
{
|
||||
XQNodePtr nextNode = XQItem::xqItemFromIndex(idx).contentNode();
|
||||
if (!nextNode || idx.data().toString().isEmpty() || nextNode->tag_name() != firstNode->tag_name() )
|
||||
break;
|
||||
newSelection.select(idx, idx);
|
||||
}
|
||||
return QItemSelectionModel::select(newSelection, command);
|
||||
}
|
||||
QItemSelectionModel::select(selection, command);
|
||||
}
|
41
src/model/xqselectionmodel.h
Normal file
41
src/model/xqselectionmodel.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQSELECTIONMODEL_H
|
||||
#define XQSELECTIONMODEL_H
|
||||
|
||||
#include <QItemSelectionModel>
|
||||
#include <QObject>
|
||||
|
||||
/**
|
||||
* @brief Extends QItemSelectionModel so that the selection is limited to a single section entry.
|
||||
*/
|
||||
|
||||
class XQSelectionModel : public QItemSelectionModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
XQSelectionModel(QAbstractItemModel* model = nullptr);
|
||||
XQSelectionModel(QAbstractItemModel* model, QObject* parent);
|
||||
virtual ~XQSelectionModel() = default;
|
||||
|
||||
public slots:
|
||||
|
||||
void select(const QItemSelection& selection, QItemSelectionModel::SelectionFlags command) override;
|
||||
|
||||
};
|
||||
|
||||
#endif // XQSELECTIONMODEL_H
|
55
src/model/xqsimpleclipboard.cpp
Normal file
55
src/model/xqsimpleclipboard.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqsimpleclipboard.h>
|
||||
#include <xqviewmodel.h>
|
||||
|
||||
|
||||
//! true, wenn paste an er stelle 'curIdx' möglich ist.
|
||||
|
||||
bool XQSimpleClipBoard::canPaste( const QModelIndex& curIdx ) const
|
||||
{
|
||||
bool pasteOk = false;
|
||||
if( !isEmpty() )
|
||||
{
|
||||
XQItem& item = XQItem::xqItemFromIndex(curIdx);
|
||||
// __fixme! header items haben keinen ZNode!
|
||||
qDebug() << " --- can paste: " << item.contentNode()->tag_name() << " nodelist: " << front().contentNode->tag_name();
|
||||
// paste is only allowed for the same component.type, which
|
||||
// is coded in the tag_type
|
||||
pasteOk = item.contentNode()->tag_name() == front().contentNode->tag_name();
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << " -- ClipBoard: nodelist empty!";
|
||||
}
|
||||
return pasteOk;
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt eine positions-list aus der liste selectierter indicies.
|
||||
//! Der mit seiner position zusammen gespeicherter knoten muss hier
|
||||
//! gekloned werden.
|
||||
|
||||
void XQSimpleClipBoard::saveNodes( const QModelIndexList& list )
|
||||
{
|
||||
clear();
|
||||
for( auto entry : list )
|
||||
{
|
||||
XQNodePtr contentNode = XQItem::xqItemFromIndex( entry ).contentNode();
|
||||
// im clipboard brauchen wir eine eltern-lose kopie des knotens
|
||||
push_back( {entry.row(), contentNode->own_pos(), contentNode->clone() } );
|
||||
}
|
||||
}
|
||||
|
36
src/model/xqsimpleclipboard.h
Normal file
36
src/model/xqsimpleclipboard.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQSIMPLECLIPBOARD_H
|
||||
#define XQSIMPLECLIPBOARD_H
|
||||
|
||||
#include <xqitem.h>
|
||||
#include <xqcommand.h>
|
||||
|
||||
|
||||
class XQSimpleClipBoard : public XQNodeStore
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
XQSimpleClipBoard() = default;
|
||||
virtual ~XQSimpleClipBoard() = default;
|
||||
|
||||
bool canPaste( const QModelIndex& curIdx ) const;
|
||||
|
||||
void saveNodes( const QModelIndexList& list ) override;
|
||||
|
||||
};
|
||||
|
||||
#endif // XQSIMPLECLIPBOARD_H
|
601
src/model/xqviewmodel.cpp
Normal file
601
src/model/xqviewmodel.cpp
Normal file
@@ -0,0 +1,601 @@
|
||||
/***************************************************************************
|
||||
|
||||
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& sectionNode : modelSheet->children() )
|
||||
{
|
||||
// #2: (optionalen?) header erzeugen
|
||||
const XQNodePtr header = sectionNode->find_child_by_tag_name( c_Header );
|
||||
if( header )
|
||||
{
|
||||
XQItemList list = _itemFactory.makeHeaderRow( header );
|
||||
addSection(list, sectionNode );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! Hilfsfunktion: fügt die item-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.
|
||||
|
||||
//! 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'
|
||||
|
||||
|
||||
// 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 );
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! 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 );
|
||||
|
||||
emit sectionToggled( _sections.sectionFromIndex(index) );
|
||||
}
|
||||
|
||||
|
||||
//! 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;
|
||||
|
||||
}
|
||||
|
599
src/model/xqviewmodel.cpp~RF540b760.TMP
Normal file
599
src/model/xqviewmodel.cpp~RF540b760.TMP
Normal 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( §ion );
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! 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;
|
||||
|
||||
}
|
||||
|
136
src/model/xqviewmodel.h
Normal file
136
src/model/xqviewmodel.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQVIEWMODEL_H
|
||||
#define XQVIEWMODEL_H
|
||||
|
||||
#include <QUndoStack>
|
||||
#include <QMenu>
|
||||
#include <QStandardItemModel>
|
||||
#include <QAbstractItemView>
|
||||
|
||||
#include <xqsimpleclipboard.h>
|
||||
#include <xqmodelsectionlist.h>
|
||||
#include <xqitemfactory.h>
|
||||
#include <xqcontextmenu.h>
|
||||
|
||||
|
||||
class XQTreeTable;
|
||||
class XQItem;
|
||||
class XQCommand;
|
||||
|
||||
|
||||
//! ein erweitertes QStandardItemModel welches 'seine' view bereits enthält.
|
||||
|
||||
class XQViewModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
XQViewModel(QObject* parent = nullptr);
|
||||
virtual ~XQViewModel() = default;
|
||||
|
||||
XQTreeTable* treeTable();
|
||||
virtual void setTreeTable( XQTreeTable* mainView );
|
||||
|
||||
QUndoStack* undoStack();
|
||||
void setUndoStack( QUndoStack* undoStack );
|
||||
|
||||
virtual void initModel( const QString& modelName);
|
||||
|
||||
//little helpers
|
||||
const XQItem& xqRootItem();
|
||||
|
||||
XQItem& xqItemFromIndex(const QModelIndex& index) const;
|
||||
XQItem& xqFirstItem(int row) const;
|
||||
|
||||
// undo-/redo-able stuff
|
||||
|
||||
virtual void cmdToggleSection( XQCommand& command );
|
||||
virtual void cmdCut( XQCommand& command );
|
||||
virtual void cmdCutUndo( XQCommand& command );
|
||||
virtual void cmdPaste( XQCommand& command );
|
||||
virtual void cmdPasteUndo( XQCommand& command );
|
||||
virtual void cmdDelete( XQCommand& command );
|
||||
virtual void cmdDeleteUndo( XQCommand& command );
|
||||
virtual void cmdNew( XQCommand& command );
|
||||
virtual void cmdNewUndo( XQCommand& command );
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
/*!
|
||||
|
||||
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'
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
|
||||
{
|
||||
return QStandardItemModel::data( index, role );
|
||||
}
|
||||
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override
|
||||
{
|
||||
qDebug() << " --- setData: " << value.toString();
|
||||
return QStandardItemModel::setData( index, value, role );
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void onShowContextMenu(const QPoint& point);
|
||||
virtual void onActionTriggered(QAction* action);
|
||||
|
||||
// handle XQCommands ( == UndoCommand )
|
||||
virtual void onCommandRedo( XQCommand& command );
|
||||
virtual void onCommandUndo( XQCommand& command );
|
||||
|
||||
signals:
|
||||
|
||||
void itemCreated( XQItem* newItem );
|
||||
void sectionCreated( const XQModelSection& section );
|
||||
void sectionToggled( const XQModelSection& section );
|
||||
|
||||
protected:
|
||||
|
||||
void addSection(const XQItemList& list, const XQNodePtr& sheetNode );
|
||||
virtual void initContextMenu() = 0;
|
||||
|
||||
// __fixme: should be created from xml
|
||||
virtual void setupViewProperties();
|
||||
|
||||
protected:
|
||||
|
||||
using MemCall = void (XQViewModel::*)(XQCommand&);
|
||||
using MemCallMap = QMap<XQCommand::CmdType,MemCall>;
|
||||
|
||||
// das eine reference auf ein globales singleton
|
||||
XQItemFactory& _itemFactory;
|
||||
XQSimpleClipBoard _clipBoard;
|
||||
XQModelSectionList _sections;
|
||||
|
||||
XQTreeTable* _treeTable{};
|
||||
//QAbstractItemView* _treeTable{};
|
||||
QUndoStack* _undoStack{};
|
||||
XQContextMenu* _contextMenu{};
|
||||
|
||||
//! Die Modelbeschreibung
|
||||
XQNodePtr _modelSheet{};
|
||||
//! Der eigentliche Inhalt
|
||||
XQNodePtr _contentRoot{};
|
||||
|
||||
};
|
||||
|
||||
#endif // XQVIEWMODEL_H
|
25
src/nodes/znode.cpp
Normal file
25
src/nodes/znode.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <znode.h>
|
||||
|
||||
|
||||
//! überwachungszähler
|
||||
|
||||
namespace znode
|
||||
{
|
||||
|
||||
int zid::s_Count{0};
|
||||
|
||||
} // namespace znode
|
414
src/nodes/znode.h
Normal file
414
src/nodes/znode.h
Normal file
@@ -0,0 +1,414 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 ZNODE_H
|
||||
#define ZNODE_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
//#include <typeinfo>
|
||||
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <xqmaptor.h>
|
||||
#include <xsingleton.h>
|
||||
|
||||
#include <znode_iterator.h>
|
||||
//#include <znode_vector.h>
|
||||
#include <znode_id.h>
|
||||
#include <znode_payload.h>
|
||||
|
||||
namespace znode
|
||||
{
|
||||
|
||||
/*
|
||||
|
||||
- die payload attributes wird 'drangeerbt'. sollte die nicht besser ge-templatet sein?
|
||||
- die finder sollten besser ausgelagert sein
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// forward declaration of base class zbasic_node ...
|
||||
//template<class str_t>
|
||||
//class zbasic_node;
|
||||
|
||||
// ... used here for conveniance typedef
|
||||
//template<class str_t>
|
||||
//using zshared_node = std::shared_ptr<zbasic_node<str_t>>;
|
||||
|
||||
|
||||
//! einfache tree-klasse, besonderheit: der nutzlast-string-type ist templated.
|
||||
template<class str_t>
|
||||
class zbasic_node : public zid, public zpayload<str_t>, public std::enable_shared_from_this<zbasic_node<str_t>>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
using str_cref = const str_t&;
|
||||
using str_list = std::vector<str_t>;
|
||||
|
||||
//using zshared_node = std::shared_ptr<zbasic_node>;
|
||||
//using znode_list = znode_vector<zbasic_node>;
|
||||
//using znode_list = znode_vector<zshared_node<str_t>>;
|
||||
//using znode_list = std::vector<zshared_node<str_t>>;
|
||||
|
||||
using zweak_node = std::weak_ptr<zbasic_node>;
|
||||
using zshared_node = std::shared_ptr<zbasic_node>;
|
||||
using znode_list = std::vector<zshared_node>;
|
||||
using zshared_cref = const std::shared_ptr<zbasic_node>&;
|
||||
|
||||
using ziterator = znode_iterator<zbasic_node>;
|
||||
|
||||
protected:
|
||||
|
||||
zweak_node _parent;
|
||||
znode_list _children;
|
||||
|
||||
struct match_node
|
||||
{
|
||||
match_node( zbasic_node* match )
|
||||
: _match{match}
|
||||
{}
|
||||
|
||||
bool operator()( const zshared_node& node )
|
||||
{
|
||||
return _match == node.get();
|
||||
}
|
||||
|
||||
zbasic_node* _match{};
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
//! shortcut auf std::make_shared...
|
||||
static zshared_node make_node( str_cref arg1, str_cref arg2 = "" , zshared_cref parent = nullptr )
|
||||
{
|
||||
return std::make_shared<zbasic_node>( arg1, arg2, parent );
|
||||
}
|
||||
|
||||
//! leerer konstruktor
|
||||
zbasic_node() = default;
|
||||
|
||||
//! konstruktor mit tag_name und optionalem elternknoten
|
||||
zbasic_node( str_cref tag_name, zshared_cref parent = nullptr )
|
||||
: zpayload<str_t>{tag_name}, _parent{parent}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//! konstruktor mit tag_name, value und optionalem elternknoten
|
||||
zbasic_node( str_cref tag_name, str_cref value, zshared_cref parent = nullptr )
|
||||
: zpayload<str_t>{tag_name,value}, _parent{parent}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//! konstruktor mit tag_name, attributlist und optionalem elternknoten
|
||||
zbasic_node( str_cref tag_name, const str_list& attributes, zshared_cref parent = nullptr )
|
||||
: zbasic_node{tag_name, parent}
|
||||
{
|
||||
for( str_cref entry : attributes )
|
||||
{
|
||||
str_t key_value, data_value;
|
||||
if( xstr_split_by( entry, "=", key_value, data_value) )
|
||||
set_attribute( key_value, data_value );
|
||||
}
|
||||
}
|
||||
|
||||
//! default destruktor
|
||||
virtual ~zbasic_node() = default;
|
||||
|
||||
//! kopieren ist hier nicht sinnvoll
|
||||
zbasic_node(const zbasic_node&) = delete;
|
||||
zbasic_node& operator=(const zbasic_node&) = delete;
|
||||
|
||||
// 'move' geht (shared_from_this bleibt gültig)
|
||||
zbasic_node(zbasic_node&&) noexcept = default;
|
||||
zbasic_node& operator=(zbasic_node&&) noexcept = default;
|
||||
|
||||
//! erzeugt eine deep-copy von 'mir' _mit_ allen kindknoten
|
||||
virtual zshared_node clone(const zshared_node& parent = nullptr ) const
|
||||
{
|
||||
// copy als shared ptr erzeugen
|
||||
zshared_node new_me = std::make_shared<zbasic_node>(this->_tag_name, this->_value );
|
||||
// auch die attribute kopieren ...
|
||||
new_me->_attributes = this->_attributes;
|
||||
// ... und, so vorhanden, den parent-node.
|
||||
new_me->_parent = parent;
|
||||
// kinder kopieren
|
||||
for (const zshared_node& child : _children)
|
||||
new_me->_children.push_back( child->clone( new_me ) );
|
||||
|
||||
return new_me;
|
||||
|
||||
}
|
||||
|
||||
//! stl-ish traverse iterators
|
||||
auto begin()
|
||||
{
|
||||
return ziterator(this);
|
||||
}
|
||||
|
||||
//! stl-ish traverse iterators
|
||||
auto end()
|
||||
{
|
||||
return ziterator(nullptr);
|
||||
}
|
||||
|
||||
// ... set_int
|
||||
// ... as_int
|
||||
|
||||
//! erzeugt einen shared_ptr
|
||||
zshared_node parent() const
|
||||
{
|
||||
return _parent.lock();
|
||||
}
|
||||
|
||||
zshared_node sibling()
|
||||
{
|
||||
if( !parent() )
|
||||
//return zshared_node( make_node("WTF1") );
|
||||
return zshared_node();
|
||||
|
||||
znode_list& childs = _parent->_children;
|
||||
auto it = std::find( childs.begin(), childs.end(), this->shared_from_this() );
|
||||
if( ++it != childs.end())
|
||||
return *(it);
|
||||
|
||||
//return zshared_node( make_node("WTF?") );
|
||||
return zshared_node();
|
||||
}
|
||||
|
||||
inline const znode_list& children() const
|
||||
{
|
||||
return _children;
|
||||
}
|
||||
|
||||
bool has_children() const
|
||||
{
|
||||
return !children().empty();
|
||||
}
|
||||
|
||||
zshared_node first_child()
|
||||
{
|
||||
if(!children().empty())
|
||||
return children().front();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
zshared_node last_child()
|
||||
{
|
||||
if(!children().empty())
|
||||
return children().back();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
zshared_node child( int idx )
|
||||
{
|
||||
if(idx>-1 && idx<children().size())
|
||||
return _children[idx];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//! hängt einen knoten an meine kinderliste an.
|
||||
int add_child( const zshared_node& node )
|
||||
{
|
||||
_children.push_back( node );
|
||||
node->_parent = this->shared_from_this();
|
||||
return int(children().size() - 1);
|
||||
}
|
||||
|
||||
//! fügt einen knoten in meine kinderliste ein und macht mich
|
||||
//! zu dessen elternknoten.
|
||||
int add_child_at( int idx, const zshared_node& node )
|
||||
{
|
||||
// _fixme! was ist, wenn da schon ein elternknoten ist?
|
||||
|
||||
_children.insert(children().begin() + idx, node );
|
||||
node->_parent = this->shared_from_this();
|
||||
return int(children().size() - 1);
|
||||
}
|
||||
|
||||
//! fügt einen shard_ptr von 'mir' in die kinderliste meines elternknotens ein.
|
||||
void add_me_at( int offset )
|
||||
{
|
||||
if( parent() )
|
||||
parent()->add_child_at( offset, this->shared_from_this() );
|
||||
else
|
||||
throw std::runtime_error("add_me_at(offset): no parent node");
|
||||
|
||||
}
|
||||
|
||||
//! fügt einen shard_ptr von 'mir' in die kinderliste des übergebenen knotens ein
|
||||
//! und macht diesen zu meinem elternknoten.
|
||||
void add_me_at( int offset, const zshared_node& parent_node )
|
||||
{
|
||||
if( parent_node )
|
||||
{
|
||||
_parent = parent_node;
|
||||
parent_node->add_child_at( offset, this->shared_from_this() );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("add_me_at(offset,parent): no parent node");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
int own_pos()
|
||||
{
|
||||
if( parent())
|
||||
return parent()->child_pos( this->shared_from_this() );
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
//int child_pos(zbasic_node* child)
|
||||
int child_pos(const zshared_node& child)
|
||||
{
|
||||
//auto pos = std::find_if(children().begin(), children().end(), match_node(child) );
|
||||
auto pos = std::find(children().begin(), children().end(), child );
|
||||
if ( pos != children().end() )
|
||||
return std::distance( children().begin(), pos );
|
||||
return -1;
|
||||
}
|
||||
|
||||
//zshared_node unlink_child( zbasic_node* node )
|
||||
zshared_node unlink_child( const zshared_node& node )
|
||||
{
|
||||
auto it = std::find(_children.begin(), _children.end(), node);
|
||||
if (it == _children.end())
|
||||
return nullptr;
|
||||
zshared_node removed = *it;
|
||||
// Parent-Zeiger im Kind zurücksetzen
|
||||
removed->_parent.reset();
|
||||
_children.erase(it);
|
||||
return removed;
|
||||
}
|
||||
|
||||
//! entfernt 'mich' aus der kinderliste des elternknotens.
|
||||
void unlink_self()
|
||||
{
|
||||
if(parent())
|
||||
parent()->unlink_child( this->shared_from_this() );
|
||||
else
|
||||
throw std::runtime_error("unlink_self(): no parent node");
|
||||
}
|
||||
|
||||
//! findet den ersten kind-knoten mit dem attribut 'attrkey' welches den
|
||||
//! wert 'attrvalue' hat.
|
||||
zshared_node find_child_by_attribute(str_cref attrkey, str_cref attrvalue )
|
||||
{
|
||||
for( auto child : _children )
|
||||
{
|
||||
qDebug() << " --#- " << child->name() << " : " << child->has_attribute( attrkey, attrvalue );
|
||||
if( child->has_attribute( attrkey, attrvalue ))
|
||||
return child;
|
||||
}
|
||||
return zshared_node();
|
||||
}
|
||||
|
||||
//
|
||||
zshared_node find_child_by_tag_name(str_cref tagname )
|
||||
{
|
||||
for( auto child : _children )
|
||||
{
|
||||
if( child->tag_name() == tagname )
|
||||
return child;
|
||||
}
|
||||
return zshared_node();
|
||||
}
|
||||
|
||||
zshared_node find_child_by_id( int id )
|
||||
{
|
||||
for (auto child : _children )
|
||||
{
|
||||
if (child->_id == id)
|
||||
return child;
|
||||
}
|
||||
return zshared_node();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void dump(int indent = 0) const
|
||||
{
|
||||
|
||||
// fix_me!
|
||||
qDebug() << std::string(indent * 2, ' ').c_str() << this->to_string();
|
||||
//qDebug() << to_string();
|
||||
//qDebug() << '\n';// std::endl;
|
||||
|
||||
if (!children().empty())
|
||||
{
|
||||
for (auto child : _children)
|
||||
{
|
||||
//qDebug() << " --- type: " << typeid(child).name();
|
||||
child.get()->dump( indent + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool for_each_x( T func, int depth = 0 )
|
||||
//bool for_each( auto func ) const
|
||||
{
|
||||
if( !apply( func, depth ) )
|
||||
return false;
|
||||
|
||||
if( !children().empty() )
|
||||
{
|
||||
for( auto child : _children )
|
||||
{
|
||||
if( !child->for_each( func, depth+1 ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// find ...
|
||||
// depth first ...
|
||||
// by attr
|
||||
// by child
|
||||
// by value
|
||||
// by find( auto xxx )
|
||||
// ...
|
||||
|
||||
};
|
||||
|
||||
|
||||
class zbasic_node_walker
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void begin()
|
||||
{}
|
||||
|
||||
template<class str_t>
|
||||
void for_each_node( zbasic_node<str_t>* node );
|
||||
|
||||
virtual void end()
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
} //namespace znode
|
||||
|
||||
|
||||
#endif // znode_H
|
123
src/nodes/znode_factory.h
Normal file
123
src/nodes/znode_factory.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 ZNODE_FACTORY_H
|
||||
#define ZNODE_FACTORY_H
|
||||
|
||||
#include <pugixml.hpp>
|
||||
#include <znode.h>
|
||||
|
||||
class xtree;
|
||||
|
||||
/*
|
||||
|
||||
nodes: nackt also ungekaspselt?
|
||||
-> children()
|
||||
-> attributes()
|
||||
|
||||
attributes: ja was seid ihr denn? als string gelesen, als string geschrieben, aber dazwischen?
|
||||
|
||||
-> std::variant<bool...> mit enum type{t_bool = 0 ...};
|
||||
-> conversion mit boost::lexical_cast<> bzw. std::to_string() und std::stoi(), std::stod()
|
||||
-> beim parsen konvertieren? contains '.'? is_number?
|
||||
-> betrifft tag_values und tag_attributes
|
||||
-> vorher definieren? attribute 'voltage' == double, oder gar mehr: unit V, double, range
|
||||
-> über xs:double?
|
||||
|
||||
model: muss ich wirklich jeden attibute node einzeln angeben?
|
||||
|
||||
*/
|
||||
namespace znode
|
||||
{
|
||||
template<class str_t>
|
||||
class znode_factory
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
using str_cref = const str_t&;
|
||||
|
||||
using zshared_node = std::shared_ptr<zbasic_node<str_t>>;
|
||||
|
||||
znode_factory() = default;
|
||||
virtual ~znode_factory() = default;
|
||||
|
||||
zshared_node load_tree( const std::string& filename )
|
||||
{
|
||||
|
||||
pugi::xml_document tree_document;
|
||||
// load document
|
||||
pugi::xml_parse_result result = tree_document.load_file( filename.c_str() );
|
||||
if( !result )
|
||||
{
|
||||
throw XQException( "znode_factory::load_tree: parse error: ", result.description() );
|
||||
}
|
||||
|
||||
//MemberFunc func = &znode_factory::process_node;
|
||||
//xtreewalker<znode_factory, MemberFunc> parser(this,func);
|
||||
//_current_depth = -1;
|
||||
//tree_document.traverse(parser);
|
||||
|
||||
//zbasic_node<str_t>* root_node = new zbasic_node<str_t>*("root!");
|
||||
zshared_node root_node = zbasic_node<str_t>::make_node("root!");
|
||||
//T root_node = T::make_node( "root!" );
|
||||
|
||||
// prepare root == model !?
|
||||
pugi::xml_node tmp_node = tree_document.first_child();
|
||||
while(tmp_node)
|
||||
{
|
||||
//qDebug() << " --- znode_factory building: " << tmp_node.name();
|
||||
create_node( tmp_node, root_node );
|
||||
tmp_node = tmp_node.next_sibling();
|
||||
}
|
||||
|
||||
//znode::zmeas_para<QString>* xxx = new znode::zmeas_para<QString>("mookoo!");
|
||||
//xxx->apply_command(42);
|
||||
// _root_node->apply_command(42);
|
||||
//size_t idx = _root_node->add_child( xxx);
|
||||
//qDebug() << " jo: " << _root_node->child(idx)->tag_name();
|
||||
|
||||
return root_node;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void create_node(const pugi::xml_node& xml_node, zshared_node parent)
|
||||
{
|
||||
|
||||
//T* new_node = new T( node.name(), node.child_value(), parent );
|
||||
//parent->add_child( new_node );
|
||||
|
||||
//zbasic_node<str_t>* new_node = new zbasic_node<str_t>( node.name(), node.child_value(), parent );
|
||||
zshared_node new_node = zbasic_node<str_t>::make_node( xml_node.name(), xml_node.child_value(), parent );
|
||||
parent->add_child( new_node );
|
||||
|
||||
if( !xml_node.attributes().empty() )
|
||||
{
|
||||
for (pugi::xml_attribute attr: xml_node.attributes())
|
||||
new_node->set_attribute( attr.name(), attr.value() );
|
||||
}
|
||||
|
||||
if( !xml_node.children().empty() && std::string( xml_node.child_value() ).empty() )
|
||||
{
|
||||
for (pugi::xml_node child : xml_node.children())
|
||||
create_node( child, new_node );
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ZNODE_FACTORY_H
|
33
src/nodes/znode_id.h
Normal file
33
src/nodes/znode_id.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef ZNODE_ID_H
|
||||
#define ZNODE_ID_H
|
||||
|
||||
namespace znode
|
||||
{
|
||||
|
||||
struct zid
|
||||
{
|
||||
zid()
|
||||
{
|
||||
static int s_ID{0};
|
||||
|
||||
_id = s_ID++;
|
||||
s_Count++;
|
||||
//qDebug() << " --- con ID: " << _id << " count: " << s_Count;
|
||||
}
|
||||
|
||||
virtual ~zid()
|
||||
{
|
||||
s_Count--;
|
||||
//qDebug() << " --- del ID: " << _id << " count: " << s_Count;
|
||||
}
|
||||
|
||||
static int s_Count;
|
||||
int _id{0};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ZNODE_ID_H
|
||||
|
124
src/nodes/znode_iterator.h
Normal file
124
src/nodes/znode_iterator.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 znode_iterator_H
|
||||
#define znode_iterator_H
|
||||
|
||||
#include <iterator>
|
||||
|
||||
|
||||
|
||||
namespace znode
|
||||
{
|
||||
template<class T>
|
||||
struct znode_iterator
|
||||
{
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = T;
|
||||
using pointer = T*; // or also value_type*
|
||||
using reference = T&; // or also value_type&
|
||||
|
||||
znode_iterator()
|
||||
: _root{},_node{}
|
||||
{}
|
||||
|
||||
znode_iterator(pointer node)
|
||||
: _root{node},_node{node}
|
||||
{}
|
||||
|
||||
void set_node(pointer node)
|
||||
{
|
||||
_root = node;
|
||||
_node = node;
|
||||
}
|
||||
|
||||
pointer get() // const
|
||||
{
|
||||
return _node;
|
||||
}
|
||||
|
||||
int level() // const
|
||||
{
|
||||
return _level;
|
||||
}
|
||||
|
||||
pointer operator->()
|
||||
{
|
||||
return _node;
|
||||
}
|
||||
|
||||
reference operator*()
|
||||
{
|
||||
return *(operator->());
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return _node != nullptr;
|
||||
}
|
||||
|
||||
// Prefix increment
|
||||
znode_iterator& operator++()
|
||||
{
|
||||
if( !_node )
|
||||
return *this;
|
||||
|
||||
// depth first: do we have children?
|
||||
if( _node->has_children() )
|
||||
{
|
||||
_node = _node->first_child().get();
|
||||
_level++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// no children, so we take siblings
|
||||
pointer tmp = _node->sibling().get();
|
||||
pointer nxt = _node->parent().get();
|
||||
|
||||
while( !tmp && nxt )
|
||||
{
|
||||
tmp = nxt->sibling().get();
|
||||
if( nxt == _root )
|
||||
{
|
||||
//qDebug() << " ouch ";
|
||||
_node = nullptr;
|
||||
return *this;
|
||||
}
|
||||
_level--;
|
||||
nxt = nxt->parent().get();
|
||||
}
|
||||
|
||||
_node = tmp;
|
||||
return *this;
|
||||
|
||||
}
|
||||
|
||||
// Postfix increment
|
||||
znode_iterator operator++(int) { znode_iterator tmp = *this; ++(*this); return tmp; }
|
||||
|
||||
friend bool operator== (const znode_iterator& a, const znode_iterator& b) { return a._node == b._node; };
|
||||
friend bool operator!= (const znode_iterator& a, const znode_iterator& b) { return a._node != b._node; };
|
||||
|
||||
protected:
|
||||
|
||||
pointer _root{};
|
||||
pointer _node{};
|
||||
int _level{0};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // znode_iterator_H
|
267
src/nodes/znode_payload.h
Normal file
267
src/nodes/znode_payload.h
Normal file
@@ -0,0 +1,267 @@
|
||||
#ifndef ZNODE_PAYLOAD_H
|
||||
#define ZNODE_PAYLOAD_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
//#include <znode_stringmap.h>
|
||||
//#include <znode_attributes.h>
|
||||
|
||||
namespace znode
|
||||
{
|
||||
template<class str_t>
|
||||
class zstringmap : public std::map<str_t,str_t>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
using str_cref = const str_t&;
|
||||
using str_ptr = str_t*;
|
||||
using str_list = std::vector<str_t>;
|
||||
|
||||
using zvalue = str_t; // could be any or variant
|
||||
// __fixme: should this be a vector? or a maptor?
|
||||
//using zattributes = std::map<str_t, zvalue>;
|
||||
using zattributes = zstringmap<str_t>;
|
||||
|
||||
str_cref key_of(str_cref value) const
|
||||
{
|
||||
for( const auto& pair : *this )
|
||||
{
|
||||
if (pair.second == value)
|
||||
return pair.first;
|
||||
}
|
||||
|
||||
static str_t s_dummy;
|
||||
return s_dummy;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class str_t>
|
||||
class zpayload
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
using str_cref = const str_t&;
|
||||
using str_ptr = str_t*;
|
||||
using str_list = std::vector<str_t>;
|
||||
|
||||
using zvalue = str_t; // could be any or variant
|
||||
// __fixme: should this be a vector? or a maptor?
|
||||
//using zattributes = std::map<str_t, zvalue>;
|
||||
using zattributes = zstringmap<str_t>;
|
||||
|
||||
static const str_t cType;// = "Type";
|
||||
static const str_t cName;// = "Name";
|
||||
static const str_t cValue;// = "Value";
|
||||
static const str_t cFriendlyName;
|
||||
|
||||
protected:
|
||||
|
||||
str_t _tag_name;
|
||||
str_t _value;
|
||||
zattributes _attributes;
|
||||
|
||||
static zvalue s_dummy_value;
|
||||
|
||||
public:
|
||||
|
||||
zpayload( str_cref tag_name )
|
||||
: _tag_name{tag_name}
|
||||
{}
|
||||
|
||||
// ...
|
||||
zpayload( str_cref tag_name, str_cref value )
|
||||
: _tag_name{tag_name}, _value{value}
|
||||
{}
|
||||
|
||||
zpayload( str_cref tag_name, const str_list& attriblist )
|
||||
: zpayload(tag_name)
|
||||
{
|
||||
for( str_cref entry : attriblist )
|
||||
{
|
||||
str_t key_value, data_value;
|
||||
if( xstr_split_by( entry, "=", key_value, data_value) )
|
||||
set_attribute( key_value, data_value );
|
||||
}
|
||||
}
|
||||
|
||||
str_cref tag_name() const
|
||||
{
|
||||
return _tag_name;
|
||||
}
|
||||
|
||||
str_ptr tag_name_ptr()
|
||||
{
|
||||
return &_tag_name;
|
||||
}
|
||||
|
||||
void set_tag_name( str_cref tag_name )
|
||||
{
|
||||
_tag_name = tag_name;
|
||||
}
|
||||
|
||||
str_cref tag_value() const
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
str_ptr tag_value_ptr()
|
||||
{
|
||||
return &_value;
|
||||
}
|
||||
|
||||
void set_tag_value( str_cref value )
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
str_cref friendly_name() const
|
||||
{
|
||||
return attribute(cFriendlyName);
|
||||
}
|
||||
|
||||
str_ptr friendly_name_ptr()
|
||||
{
|
||||
return &attribute(cFriendlyName);
|
||||
}
|
||||
|
||||
str_cref type() const
|
||||
{
|
||||
return attribute(cType);
|
||||
}
|
||||
|
||||
str_ptr type_ptr() const
|
||||
{
|
||||
return &attribute(cType);
|
||||
}
|
||||
|
||||
void set_type( str_cref type )
|
||||
{
|
||||
set_attribute( cType, type);
|
||||
}
|
||||
|
||||
str_cref name() const
|
||||
{
|
||||
return attribute(cName);
|
||||
}
|
||||
|
||||
str_ptr name_ptr()
|
||||
{
|
||||
return &attribute(cName);
|
||||
}
|
||||
|
||||
void set_name( str_cref name )
|
||||
{
|
||||
set_attribute( cType, name);
|
||||
}
|
||||
|
||||
const zattributes& attributes() const
|
||||
{
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
bool has_attribute(str_cref key ) const
|
||||
{
|
||||
if( xstr_is_empty( key ) )
|
||||
return false;
|
||||
typename zattributes::const_iterator pos = _attributes.find(key);
|
||||
if( pos == _attributes.end() )
|
||||
return false;
|
||||
// leer gilded nicht
|
||||
if( xstr_is_empty( pos->second ) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_attribute(str_cref key, str_cref value ) const
|
||||
{
|
||||
if( xstr_is_empty( key ) )
|
||||
return false;
|
||||
typename zattributes::const_iterator pos = _attributes.find(key);
|
||||
if( pos == _attributes.end() )
|
||||
return false;
|
||||
if( !xstr_is_empty( value ) )
|
||||
return (*pos).second == value;
|
||||
return true;
|
||||
}
|
||||
|
||||
const zvalue& attribute(str_cref key ) const
|
||||
{
|
||||
if( !xstr_is_empty( key ) )
|
||||
{
|
||||
typename zattributes::const_iterator pos = _attributes.find(key);
|
||||
if (pos != _attributes.end())
|
||||
{
|
||||
const zvalue& result = (*pos).second;
|
||||
if (!xstr_is_empty(result) && result[0] == '@')
|
||||
return attribute( xstr_sub_str(result, 1) );
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return s_dummy_value;
|
||||
}
|
||||
|
||||
const zvalue* attribute_ptr(str_cref key ) const
|
||||
{
|
||||
if( !xstr_is_empty( key ) )
|
||||
{
|
||||
typename zattributes::const_iterator pos = _attributes.find(key);
|
||||
if (pos != _attributes.end())
|
||||
{
|
||||
const zvalue& result = (*pos).second;
|
||||
if (!xstr_is_empty(result) && result[0] == '@')
|
||||
return attribute_ptr( xstr_sub_str(result, 1) );
|
||||
return &result;
|
||||
}
|
||||
}
|
||||
return &s_dummy_value;
|
||||
}
|
||||
|
||||
void set_attribute(str_cref key, zvalue value )
|
||||
{
|
||||
if( !xstr_is_empty( key ) )
|
||||
_attributes[key] = value;
|
||||
}
|
||||
|
||||
// dumper
|
||||
str_t to_string() const
|
||||
{
|
||||
str_t result = '<' +_tag_name +'>';
|
||||
if( !xstr_is_empty(_value) )
|
||||
result += ": " + _value;
|
||||
if( !_attributes.empty() )
|
||||
{
|
||||
result += " [";
|
||||
bool beg = true;
|
||||
for (const auto& entry : _attributes)
|
||||
{
|
||||
if(beg)
|
||||
{
|
||||
result += entry.first + "=" + entry.second;
|
||||
beg = false;
|
||||
continue;
|
||||
}
|
||||
result += ", " + entry.first + "=" + entry.second;
|
||||
}
|
||||
result += "]";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// forward helpers
|
||||
bool xstr_split_by(str_cref entry, str_cref sep, str_t& key, str_t& value );
|
||||
str_t xstr_sub_str(str_cref entry, int pos) const;
|
||||
bool xstr_is_empty(str_cref key ) const;
|
||||
|
||||
};
|
||||
|
||||
// init statics
|
||||
template<class str_t>
|
||||
str_t zpayload<str_t>::s_dummy_value;
|
||||
|
||||
}
|
||||
|
||||
#endif // ZNODE_PAYLOAD_H
|
50
src/nodes/znode_vector.h
Normal file
50
src/nodes/znode_vector.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef ZNODE_VECTOR_H
|
||||
#define ZNODE_VECTOR_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
//using znode_vector = std::vector<zplain_node*>;
|
||||
template<class T>
|
||||
class znode_vector : public std::vector<T*>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// FIX! implement this!
|
||||
// why delete??
|
||||
znode_vector() = default;
|
||||
znode_vector(const znode_vector&) = delete;
|
||||
znode_vector& operator=(const znode_vector&) = delete;
|
||||
|
||||
|
||||
virtual ~znode_vector()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
znode_vector* clone() const
|
||||
{
|
||||
znode_vector* new_list = new znode_vector;
|
||||
clone_into( *new_list );
|
||||
return new_list;
|
||||
}
|
||||
|
||||
void clone_into( znode_vector& new_list ) const
|
||||
{
|
||||
new_list.clear();
|
||||
for(const auto entry : *this )
|
||||
new_list.push_back( entry->clone() );
|
||||
}
|
||||
|
||||
void clone_from( const znode_vector& src_list )
|
||||
{
|
||||
this->clear();
|
||||
for(const auto entry : src_list )
|
||||
this->push_back( entry->clone() );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // ZNODE_VECTOR_H
|
77
src/pugixml/pugiconfig.hpp
Normal file
77
src/pugixml/pugiconfig.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* pugixml parser - version 1.14
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2023, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at https://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License. See notice at the end
|
||||
* of this file.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*/
|
||||
|
||||
#ifndef HEADER_PUGICONFIG_HPP
|
||||
#define HEADER_PUGICONFIG_HPP
|
||||
|
||||
// Uncomment this to enable wchar_t mode
|
||||
// #define PUGIXML_WCHAR_MODE
|
||||
|
||||
// Uncomment this to enable compact mode
|
||||
// #define PUGIXML_COMPACT
|
||||
|
||||
// Uncomment this to disable XPath
|
||||
// #define PUGIXML_NO_XPATH
|
||||
|
||||
// Uncomment this to disable STL
|
||||
// #define PUGIXML_NO_STL
|
||||
|
||||
// Uncomment this to disable exceptions
|
||||
// #define PUGIXML_NO_EXCEPTIONS
|
||||
|
||||
// Set this to control attributes for public classes/functions, i.e.:
|
||||
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||
|
||||
// Tune these constants to adjust memory-related behavior
|
||||
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||
|
||||
// Tune this constant to adjust max nesting for XPath queries
|
||||
// #define PUGIXML_XPATH_DEPTH_LIMIT 1024
|
||||
|
||||
// Uncomment this to switch to header-only version
|
||||
// #define PUGIXML_HEADER_ONLY
|
||||
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copyright (c) 2006-2023 Arseny Kapoulkine
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
13237
src/pugixml/pugixml.cpp
Normal file
13237
src/pugixml/pugixml.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1516
src/pugixml/pugixml.hpp
Normal file
1516
src/pugixml/pugixml.hpp
Normal file
File diff suppressed because it is too large
Load Diff
22
src/util/xqexception.cpp
Normal file
22
src/util/xqexception.cpp
Normal 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 <xqexception.h>
|
||||
|
||||
//! erzeugt einen std::runtime_error mit text und optionalem parameter
|
||||
|
||||
XQException::XQException(const QString& what, const QString& param )
|
||||
: std::runtime_error( param.isEmpty() ? what.toStdString() : QString( "%1: %2" ).arg(what,param).toStdString( ) )
|
||||
{}
|
||||
|
34
src/util/xqexception.h
Normal file
34
src/util/xqexception.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQEXCEPTION_H
|
||||
#define XQEXCEPTION_H
|
||||
|
||||
#include <QString>
|
||||
#include <stdexcept>
|
||||
|
||||
/**
|
||||
* @brief Simple exception class
|
||||
*/
|
||||
|
||||
class XQException : public std::runtime_error
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
XQException( const QString& what, const QString& param="" );
|
||||
|
||||
};
|
||||
|
||||
#endif // XQEXCEPTION_H
|
75
src/util/xqmapindex.h
Normal file
75
src/util/xqmapindex.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQMAPINDEX_H
|
||||
#define XQMAPINDEX_H
|
||||
|
||||
#include <QMap>
|
||||
|
||||
/**
|
||||
* @brief Holds the string to index mapping for the QXMaptor classes
|
||||
*/
|
||||
|
||||
class XQMapIndex : public QMap<QString, int>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
virtual ~XQMapIndex() = default;
|
||||
|
||||
void addKey(const QString& key, int index)
|
||||
{
|
||||
(*this)[key] = index;
|
||||
}
|
||||
|
||||
int indexOf(const QString& key) const
|
||||
{
|
||||
if (contains(key))
|
||||
return (*this)[key];
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void update(int index)
|
||||
{
|
||||
|
||||
XQMapIndex newindex;
|
||||
QMapIterator<QString, int> iter(*this);
|
||||
|
||||
while (iter.hasNext())
|
||||
{
|
||||
iter.next();
|
||||
|
||||
// item idx == kill-index: continue
|
||||
// item idx < kill-index: store item
|
||||
// item idx > kill-index: decrement & store item
|
||||
|
||||
int idx = iter.value();
|
||||
if (idx == index)
|
||||
continue;
|
||||
if (idx > index)
|
||||
idx--;
|
||||
// schlüssel auch sichern
|
||||
newindex[(iter.key())] = idx;
|
||||
|
||||
}
|
||||
|
||||
swap(newindex);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // XQMAPINDEX_H
|
305
src/util/xqmaptor.h
Normal file
305
src/util/xqmaptor.h
Normal file
@@ -0,0 +1,305 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQMAPTOR_H
|
||||
#define XQMAPTOR_H
|
||||
|
||||
#include <xqmapindex.h>
|
||||
#include <xqexception.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief map + vector = XQMaptor, a template storage class whose data
|
||||
* items can be accessed via string keys and int indices.
|
||||
*/
|
||||
|
||||
template<class T>
|
||||
class XQMaptor
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
XQMaptor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
XQMaptor( int itemsize )
|
||||
{
|
||||
if( itemsize )
|
||||
_data.resize( itemsize );
|
||||
}
|
||||
|
||||
|
||||
XQMaptor( const XQMaptor& src )
|
||||
{
|
||||
*this=src;
|
||||
}
|
||||
|
||||
|
||||
virtual ~XQMaptor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
XQMaptor& operator=( const XQMaptor& src )
|
||||
{
|
||||
if( this == &src )
|
||||
return *this;
|
||||
_data = src._data;
|
||||
_index = src._index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// STL-like iterators
|
||||
auto begin()
|
||||
{
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
auto end()
|
||||
{
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
inline int size() const
|
||||
{
|
||||
return (int) _data.size();
|
||||
}
|
||||
|
||||
|
||||
inline bool isEmpty() const
|
||||
{
|
||||
return (_data.size()==0);
|
||||
}
|
||||
|
||||
inline bool contains( int index ) const
|
||||
{
|
||||
return index < size() && index > -1;
|
||||
}
|
||||
|
||||
inline bool contains( const QString& key ) const
|
||||
{
|
||||
return mapIndex().contains(key);
|
||||
}
|
||||
|
||||
|
||||
inline const XQMapIndex& mapIndex() const
|
||||
{
|
||||
return _index;
|
||||
}
|
||||
|
||||
|
||||
int indexOf( const QString& key ) const
|
||||
{
|
||||
return mapIndex().indexOf(key);
|
||||
}
|
||||
|
||||
int indexOf(const T& entry) const
|
||||
{
|
||||
for (int i=0; i<_data.size(); ++i)
|
||||
{
|
||||
if (_data[i] == entry)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual QString keyOf( int index ) const
|
||||
{
|
||||
return mapIndex().key( index );
|
||||
}
|
||||
|
||||
|
||||
T& operator[]( int index )
|
||||
{
|
||||
if( contains(index) )
|
||||
return _data[index];
|
||||
throw XQException("XQMaptor operator[ int index ]: out of range");
|
||||
}
|
||||
|
||||
|
||||
const T& operator[]( int index ) const
|
||||
{
|
||||
if ( contains(index) )
|
||||
return _data[index];
|
||||
throw XQException("XQMaptor const operator[ int index ]: out of range");
|
||||
}
|
||||
|
||||
T& at( int index )
|
||||
{
|
||||
return (*this)[index];
|
||||
}
|
||||
|
||||
const T& at( int index ) const
|
||||
{
|
||||
return (*this)[index];
|
||||
}
|
||||
|
||||
T& operator[]( const QString& key )
|
||||
{
|
||||
if( key.isEmpty() || !contains(key) )
|
||||
throw XQException("maprow operator[]: key empty || not found: " + key);
|
||||
return _data[ _index[key] ];
|
||||
}
|
||||
|
||||
|
||||
const T& operator[]( const QString& key ) const
|
||||
{
|
||||
if (key.isEmpty() || !contains(key))
|
||||
throw XQException("maprow operator[]: key empty || not found: " + key);
|
||||
return _data[_index[key]];
|
||||
}
|
||||
|
||||
|
||||
T& at( const QString& key )
|
||||
{
|
||||
return (*this)[key];
|
||||
}
|
||||
|
||||
const T& at( const QString& key ) const
|
||||
{
|
||||
return (*this)[key];
|
||||
}
|
||||
|
||||
virtual int add( const T& item )
|
||||
{
|
||||
_data.push_back( item );
|
||||
return _data.size()-1;
|
||||
}
|
||||
|
||||
|
||||
virtual void addAtIndex( int index, const T& item )
|
||||
{
|
||||
if(contains(index))
|
||||
throw XQException( "QStringrow::add: index out of range!" );
|
||||
_data[index] = item;
|
||||
}
|
||||
|
||||
|
||||
// convenience method to mimic QMap<T,QString>
|
||||
virtual void insert( const T& item, const QString& key )
|
||||
{
|
||||
addAtKey(key, item );
|
||||
}
|
||||
|
||||
|
||||
virtual void addAtKey( const QString& key, const T& item )
|
||||
{
|
||||
XQMapIndex::iterator pos = _index.find( key );
|
||||
if( pos == _index.end() )
|
||||
{
|
||||
_data.push_back( item );
|
||||
_index[key] = _data.size()-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_data[pos.value()] = item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool addAlias( const QString& key, const QString& alias )
|
||||
{
|
||||
// look for 'original' key
|
||||
int key_idx = indexOf(key);
|
||||
// quit if not found
|
||||
if( key_idx < 0 )
|
||||
return false;
|
||||
// look for alias
|
||||
int alias_idx = indexOf(alias);
|
||||
// quit if found: don't overwrite anything
|
||||
if( alias_idx > -1 )
|
||||
return false;
|
||||
// store alias
|
||||
_index[ alias ] = key_idx;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void addKey( const QString& key, int index )
|
||||
{
|
||||
_index.addKey( key, index );
|
||||
}
|
||||
|
||||
|
||||
virtual void clear()
|
||||
{
|
||||
_data.clear();
|
||||
_index.clear();
|
||||
}
|
||||
|
||||
|
||||
virtual bool killEntry( const QString& key )
|
||||
{
|
||||
int idx = indexOf( key );
|
||||
if( idx<0 )
|
||||
return false;
|
||||
return killEntry( (int) idx );
|
||||
}
|
||||
|
||||
|
||||
virtual bool killEntry( int index )
|
||||
{
|
||||
if( index >= this->_data.size() )
|
||||
return false;
|
||||
// eintrag lschen
|
||||
this->_data.erase( this->_data.begin()+index );
|
||||
// index updaten
|
||||
_index.update( index );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
virtual QString toString() const
|
||||
{
|
||||
return join( ";" );
|
||||
}
|
||||
|
||||
|
||||
virtual void dump() const
|
||||
{
|
||||
throw XQException("XQMaptor: dump not implemented!" );
|
||||
}
|
||||
|
||||
|
||||
virtual QString join( const QString& sep, int from=0, int to=-1) const
|
||||
{
|
||||
Q_UNUSED(sep)
|
||||
Q_UNUSED(from)
|
||||
Q_UNUSED(to)
|
||||
throw XQException("XQMaptor: join not implemented!" );
|
||||
return "--";
|
||||
}
|
||||
|
||||
|
||||
int replaceKey( const QString& oldkey, const QString& newkey )
|
||||
{
|
||||
int idx = indexOf( oldkey );
|
||||
if( idx<0 || oldkey == newkey )
|
||||
return idx;
|
||||
_index.remove( oldkey );
|
||||
_index[ newkey ] = idx;
|
||||
return idx;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
QVector<T> _data;
|
||||
XQMapIndex _index;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // XQMAPTOR_H
|
128
src/util/xqptrmaptor.h
Normal file
128
src/util/xqptrmaptor.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQPTRMAPTOR_H
|
||||
#define XQPTRMAPTOR_H
|
||||
|
||||
#include <xqmaptor.h>
|
||||
|
||||
/**
|
||||
* @brief A XQMaptor implementation for pointers to to data entries.
|
||||
*/
|
||||
|
||||
template<class T>
|
||||
class XQPtrMaptor : public XQMaptor<T*>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
virtual ~XQPtrMaptor()
|
||||
{
|
||||
for (int i = 0; i < this->_data.size(); ++i)
|
||||
delete this->_data[i];
|
||||
}
|
||||
|
||||
T& entry(const QString& key)
|
||||
{
|
||||
int i = this->indexOf(key);
|
||||
if (i < 0)
|
||||
throw XQException("XQPtrMaptor: entry: not found: " + key);
|
||||
return *(this->_data[i]);
|
||||
}
|
||||
|
||||
const T& entry(const QString& key) const
|
||||
{
|
||||
int i = this->indexOf(key);
|
||||
if (i < 0)
|
||||
throw XQException("XQPtrMaptor: entry: not found: " + key);
|
||||
return *(this->_data[i]);
|
||||
}
|
||||
|
||||
T& entry(int index)
|
||||
{
|
||||
if ((int)index < this->_data.size())
|
||||
return *(this->_data[index]);
|
||||
throw XQException("ddmapptr entry( int index ): out of range");
|
||||
}
|
||||
|
||||
|
||||
const T& entry(int index) const
|
||||
{
|
||||
if (index > 0 && index < this->_data.size())
|
||||
return *(this->_data[index]);
|
||||
throw XQException("ddmapptr const entry( int index ): out of range");
|
||||
}
|
||||
|
||||
|
||||
bool killEntry(const QString& key) override
|
||||
{
|
||||
int idx = this->indexOf(key);
|
||||
// warum keine exception?
|
||||
if (idx < 0)
|
||||
return false;
|
||||
return killEntry((int)idx);
|
||||
}
|
||||
|
||||
bool killEntry(int index) override
|
||||
{
|
||||
T* item = this->_data[index];
|
||||
if (XQMaptor<T*>::killEntry(index))
|
||||
{
|
||||
delete item;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool removeEntry(const QString& key)
|
||||
{
|
||||
int idx = this->indexOf(key);
|
||||
// warum keine exception?
|
||||
if (idx < 0)
|
||||
return false;
|
||||
return removeEntry((int)idx);
|
||||
}
|
||||
|
||||
|
||||
bool removeEntry(int index)
|
||||
{
|
||||
if (index >= this->_data.size())
|
||||
return false;
|
||||
|
||||
// eintrag löschen
|
||||
this->_data.erase(this->_data.begin() + index);
|
||||
// index updaten
|
||||
this->_index.update(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void replace(int index, T* entry)
|
||||
{
|
||||
if ((int)index >= this->_data.size())
|
||||
throw XQException("ddmapptr replace( int index ): out of range");
|
||||
delete(this->_data[index]);
|
||||
this->_data[index] = entry;
|
||||
}
|
||||
|
||||
void replace(const QString& key, T* entry)
|
||||
{
|
||||
replace(this->indexOf(key), entry);
|
||||
}
|
||||
|
||||
};
|
||||
ö
|
||||
#endif // XQPTRMAPTOR_H
|
48
src/util/xsingleton.h
Normal file
48
src/util/xsingleton.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XSINGLETON_H
|
||||
#define XSINGLETON_H
|
||||
|
||||
/**
|
||||
* @brief The classic singleton template interface.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
class xsingleton
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Get the singleton instance.
|
||||
static T& instance()
|
||||
{
|
||||
static T Instance;
|
||||
return Instance;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
xsingleton() {}
|
||||
virtual ~xsingleton() {}
|
||||
|
||||
private:
|
||||
|
||||
xsingleton(xsingleton const &) = delete;
|
||||
xsingleton& operator=(xsingleton const &) = delete;
|
||||
|
||||
};
|
||||
|
||||
#endif // XSINGLETON_H
|
||||
|
47
src/util/xtreewalker.h
Normal file
47
src/util/xtreewalker.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XTREEWALKER_H
|
||||
#define XTREEWALKER_H
|
||||
|
||||
#include <pugixml.hpp>
|
||||
#include <functional>
|
||||
|
||||
/**
|
||||
* @brief A implentation of the pugi::xml treewalker class.
|
||||
*/
|
||||
|
||||
template <typename O,typename M>
|
||||
class xtreewalker : public pugi::xml_tree_walker
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
xtreewalker( O* object, M member )
|
||||
{
|
||||
_call = std::bind(member, object, std::placeholders::_1, std::placeholders::_2);
|
||||
}
|
||||
|
||||
virtual bool for_each(pugi::xml_node& node) override
|
||||
{
|
||||
return _call(node,depth());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
std::function<bool(pugi::xml_node& node,int)> _call;
|
||||
|
||||
};
|
||||
|
||||
#endif // XTREEWALKER_H
|
67
src/widgets/xqcontextmenu.cpp
Normal file
67
src/widgets/xqcontextmenu.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <xqcontextmenu.h>
|
||||
|
||||
|
||||
//! konstruktor.
|
||||
|
||||
XQContextMenu::XQContextMenu(QWidget* parent)
|
||||
: QMenu( parent )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt eine action mit text
|
||||
//! aus einem command-type und fügt sie hinzu.
|
||||
|
||||
void XQContextMenu::addAction(const QString& text, XQCommand::CmdType commandType, bool enabled)
|
||||
{
|
||||
QAction* newAction = new QAction(text, this);
|
||||
newAction->setData(commandType);
|
||||
_actionMap[commandType] = newAction;
|
||||
QWidget::addAction(newAction);
|
||||
setActionEnabled( commandType, enabled );
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt eine action mit text und icon aus
|
||||
//! einem command-type und fügt sie hinzu.
|
||||
|
||||
void XQContextMenu::addAction(const QString& iconKey, const QString& name, XQCommand::CmdType commandType, bool enabled)
|
||||
{
|
||||
addAction(XQAppData::typeIcon( iconKey), name, commandType, enabled );
|
||||
}
|
||||
|
||||
|
||||
//! erzeugt eine action mit text und icon aus
|
||||
//! einem command-type und fügt sie hinzu.
|
||||
|
||||
void XQContextMenu::addAction(const QIcon& icon, const QString& text, XQCommand::CmdType commandType, bool enabled)
|
||||
{
|
||||
QAction* newAction = new QAction(icon, text, this);
|
||||
newAction->setData(commandType);
|
||||
_actionMap[commandType] = newAction;
|
||||
QWidget::addAction(newAction);
|
||||
setActionEnabled( commandType, enabled );
|
||||
}
|
||||
|
||||
|
||||
//! schaltet die action mit 'commandType'
|
||||
|
||||
void XQContextMenu::setActionEnabled(XQCommand::CmdType commandType, bool enabled)
|
||||
{
|
||||
if( _actionMap.contains(commandType) )
|
||||
_actionMap[commandType]->setEnabled( enabled );
|
||||
}
|
50
src/widgets/xqcontextmenu.h
Normal file
50
src/widgets/xqcontextmenu.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQCONTEXTMENU_H
|
||||
#define XQCONTEXTMENU_H
|
||||
|
||||
#include <QMenu>
|
||||
#include <QMap>
|
||||
#include <xqcommand.h>
|
||||
|
||||
/**
|
||||
* @brief A specialized QMenu for @see XQCommands
|
||||
*/
|
||||
|
||||
class XQContextMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
XQContextMenu(QWidget* parent = nullptr );
|
||||
virtual ~XQContextMenu() = default;
|
||||
|
||||
void addAction(const QString& name, XQCommand::CmdType commandType, bool enabled );
|
||||
void addAction(const QString& iconKey, const QString& name, XQCommand::CmdType commandType, bool enabled );
|
||||
void addAction(const QIcon& icon, const QString& name, XQCommand::CmdType commandType, bool enabled );
|
||||
|
||||
void setActionEnabled(XQCommand::CmdType commandType, bool enabled);
|
||||
|
||||
protected:
|
||||
|
||||
QMap<int, QAction*> _actionMap;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //; XQContextMenu_H
|
22
src/widgets/xqquickwidget.cpp
Normal file
22
src/widgets/xqquickwidget.cpp
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
27
src/widgets/xqquickwidget.h
Normal file
27
src/widgets/xqquickwidget.h
Normal 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
|
195
src/widgets/xqtreetable.cpp
Normal file
195
src/widgets/xqtreetable.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 <QPainter>
|
||||
#include <QTime>
|
||||
|
||||
#include "qheaderview.h"
|
||||
#include <xqtreetable.h>
|
||||
#include <xqviewmodel.h>
|
||||
|
||||
#define DB_TIMESTAMP QTime::currentTime().toString(" -- HH:mm:ss.zzz")
|
||||
|
||||
//! standardkonstruktor
|
||||
|
||||
XQTreeTable::XQTreeTable(QWidget* parent)
|
||||
: QTreeView(parent)
|
||||
{
|
||||
/*
|
||||
setDragEnabled(true);
|
||||
setAcceptDrops(true);
|
||||
setDragDropOverwriteMode(true);
|
||||
setDropIndicatorShown(false);
|
||||
*/
|
||||
setHeaderHidden(true);
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
|
||||
//! gibt die verbundene modelview zurück, cast auf 'model()'
|
||||
|
||||
XQViewModel* XQTreeTable::modelView()
|
||||
{
|
||||
return static_cast<XQViewModel*>(model());
|
||||
}
|
||||
|
||||
|
||||
//! shortcut: gibt das item für index zurück
|
||||
|
||||
XQItem& XQTreeTable::xqItemFromIndex(const QModelIndex& index )
|
||||
{
|
||||
return modelView()->xqItemFromIndex( index );
|
||||
}
|
||||
|
||||
|
||||
//! override von 'currentChanged' (noch nicht implementiert)
|
||||
|
||||
void XQTreeTable::currentChanged(const QModelIndex& current, const QModelIndex& previous)
|
||||
{
|
||||
|
||||
QTreeView::currentChanged(current, previous);
|
||||
// edit comboboxes directly
|
||||
//XQItem& currentItem = xqItemFromIndex(current);
|
||||
// xx_fix!
|
||||
/*
|
||||
if (curreXQItem && curreXQItem->renderStyle() == XQItem::ComboBoxStyle )
|
||||
{
|
||||
QTreeView::edit(current);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
//! firz
|
||||
|
||||
void XQTreeTable::mouseResizeHeaderEntry(int xpos)
|
||||
{
|
||||
// resize colummn: minimal vertical margin in pixels
|
||||
static const int s_MinimalMargin = 50;
|
||||
|
||||
QRect itemRect = visualRect(_indexToResize);
|
||||
|
||||
// new position different to item rect outer right position
|
||||
int newPos = xpos - itemRect.right();
|
||||
|
||||
// current section size from header
|
||||
int column = _indexToResize.column();
|
||||
int sectionSize = columnWidth( column );
|
||||
int maxPos = s_MinimalMargin + xpos;
|
||||
|
||||
// resize header and update view
|
||||
if (maxPos <= width())
|
||||
{
|
||||
header()->resizeSection(column, sectionSize + newPos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! firz
|
||||
|
||||
void XQTreeTable::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
// pixel Grenzwert zur Anzeige des Splitcursors
|
||||
static const int s_CatchOffset = 5;
|
||||
|
||||
bool leftBtn = (event->buttons() & Qt::LeftButton);
|
||||
QPoint eventPos = event->pos();
|
||||
|
||||
// splitcursor ist active
|
||||
bool splitCursor = (cursor().shape() == Qt::SplitHCursor);
|
||||
|
||||
|
||||
// sind wir schon am 'draggen'?
|
||||
if (_indexToResize.isValid() && splitCursor && leftBtn)
|
||||
{
|
||||
return mouseResizeHeaderEntry(eventPos.x());
|
||||
}
|
||||
|
||||
// nein, nocht nicht
|
||||
QModelIndex idxFromPos = indexAt(eventPos);
|
||||
|
||||
// mousepointer is inside a header section
|
||||
if ( xqItemFromIndex(idxFromPos).isHeaderStyle() )
|
||||
{
|
||||
QRect itemRect = visualRect(idxFromPos);
|
||||
|
||||
int crX = itemRect.topRight().x() - s_CatchOffset;
|
||||
QRect catchRect = QRect(crX, itemRect.y(), s_CatchOffset, itemRect.height());
|
||||
if (catchRect.contains(eventPos))
|
||||
{
|
||||
return setCursor(QCursor(Qt::SplitHCursor));
|
||||
}
|
||||
}
|
||||
setCursor(QCursor(Qt::ArrowCursor));
|
||||
|
||||
QTreeView::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
|
||||
//! speichert die start-position fürs header-resizing.
|
||||
|
||||
void XQTreeTable::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
|
||||
// case #1:
|
||||
// Handle header resiszing
|
||||
|
||||
QPoint pos = event->pos();
|
||||
QModelIndex index = indexAt(pos);
|
||||
// set index for resize column if cursor for split is active
|
||||
if (cursor().shape() == Qt::SplitHCursor)
|
||||
{
|
||||
_indexToResize = index;
|
||||
}
|
||||
QTreeView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
|
||||
//! speichert die index-position fürs header-resizing.
|
||||
|
||||
void XQTreeTable::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
// reset index for resize column
|
||||
_indexToResize = QModelIndex();
|
||||
setCursor(QCursor(Qt::ArrowCursor));
|
||||
QTreeView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
|
||||
//! zoom-in / zoom-out mit mausrad & ctrl
|
||||
|
||||
void XQTreeTable::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
// Ctrl-key down?
|
||||
if (!event->modifiers().testFlag(Qt::ControlModifier))
|
||||
// default processing
|
||||
return QTreeView::wheelEvent(event);
|
||||
|
||||
// current size
|
||||
int curSize = fontInfo().pointSize();
|
||||
// increase?
|
||||
if (event->angleDelta().y() > 0)
|
||||
{
|
||||
// "zoom in"
|
||||
curSize += (curSize < 40) ? (1) : (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// "zoom out"
|
||||
curSize -= (curSize > 8) ? (1) : (0);
|
||||
}
|
||||
// adjust size via stylesheet
|
||||
setStyleSheet(QString("font: %1pt;").arg(curSize));
|
||||
|
||||
}
|
58
src/widgets/xqtreetable.h
Normal file
58
src/widgets/xqtreetable.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/***************************************************************************
|
||||
|
||||
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 XQTREETABLE_H
|
||||
#define XQTREETABLE_H
|
||||
|
||||
#include <QTreeView>
|
||||
#include <QMouseEvent>
|
||||
#include <QDebug>
|
||||
|
||||
class XQItem;
|
||||
class XQViewModel;
|
||||
|
||||
/**
|
||||
* @brief A specialized QTreeView that will handle the drawing of
|
||||
* empty or non-existing items in the future.
|
||||
*/
|
||||
|
||||
class XQTreeTable : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
// wird hier lieber ncht benutzt
|
||||
//Q_DECLARE_PRIVATE(QTreeView)
|
||||
|
||||
public:
|
||||
|
||||
XQTreeTable(QWidget* parent = nullptr );
|
||||
virtual ~XQTreeTable() = default;
|
||||
|
||||
XQViewModel* modelView();
|
||||
XQItem& xqItemFromIndex(const QModelIndex& index );
|
||||
|
||||
protected:
|
||||
|
||||
void currentChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseResizeHeaderEntry(int xpos);
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
|
||||
//! used by the mouse events
|
||||
QModelIndex _indexToResize;
|
||||
};
|
||||
|
||||
#endif // XQTREETABLE_H
|
96
src/xtree.pro
Normal file
96
src/xtree.pro
Normal file
@@ -0,0 +1,96 @@
|
||||
QT += core gui widgets quick quickwidgets
|
||||
# widgets-private
|
||||
|
||||
CONFIG += c++20
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
INCLUDEPATH += pugixml widgets nodes model application datatypes util items
|
||||
|
||||
HEADERS += \
|
||||
application/xqchildmodel.h \
|
||||
application/xqdocumentstore.h \
|
||||
application/xqmainmodel.h \
|
||||
application/xqmainwindow.h \
|
||||
application/xqappdata.h \
|
||||
items/xqitem.h \
|
||||
items/xqitemfactory.h \
|
||||
items/xqitemtype.h \
|
||||
items/xqitemdelegate.h \
|
||||
model/xqcommand.h \
|
||||
model/xqmodelsectionlist.h \
|
||||
model/xqnode.h \
|
||||
model/xqnodewriter.h \
|
||||
model/xqselectionmodel.h \
|
||||
model/xqsimpleclipboard.h \
|
||||
model/xqviewmodel.h \
|
||||
nodes/znode.h \
|
||||
nodes/znode_factory.h \
|
||||
nodes/znode_id.h \
|
||||
nodes/znode_iterator.h \
|
||||
nodes/znode_payload.h \
|
||||
#nodes/znode_stringmap.h \
|
||||
#nodes/znode_attributes.h \
|
||||
nodes/znode_vector.h \
|
||||
pugixml/pugiconfig.hpp \
|
||||
pugixml/pugixml.hpp \
|
||||
util/xqexception.h \
|
||||
util/xqmapindex.h \
|
||||
util/xqmaptor.h \
|
||||
util/xqptrmaptor.h \
|
||||
util/xsingleton.h \
|
||||
util/xtreewalker.h \
|
||||
widgets/xqcontextmenu.h \
|
||||
widgets/xqquickwidget.h \
|
||||
widgets/xqtreetable.h
|
||||
|
||||
SOURCES += \
|
||||
application/xqchildmodel.cpp \
|
||||
application/xqdocumentstore.cpp \
|
||||
application/xqmainmodel.cpp \
|
||||
application/xqmainwindow.cpp \
|
||||
application/xqappdata.cpp \
|
||||
items/xqitem.cpp \
|
||||
items/xqitemfactory.cpp \
|
||||
items/xqitemtype.cpp \
|
||||
items/xqitemdelegate.cpp \
|
||||
main.cpp \
|
||||
model/xqcommand.cpp \
|
||||
model/xqmodelsectionlist.cpp \
|
||||
model/xqnode.cpp \
|
||||
model/xqnodewriter.cpp \
|
||||
model/xqselectionmodel.cpp \
|
||||
model/xqsimpleclipboard.cpp \
|
||||
model/xqviewmodel.cpp \
|
||||
nodes/znode.cpp \
|
||||
pugixml/pugixml.cpp \
|
||||
util/xqexception.cpp \
|
||||
widgets/xqcontextmenu.cpp \
|
||||
widgets/xqquickwidget.cpp \
|
||||
widgets/xqtreetable.cpp
|
||||
|
||||
|
||||
FORMS += \
|
||||
application/xqmainwindow.ui
|
||||
|
||||
|
||||
RESOURCES = xtree.qrc
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
DISTFILES += \
|
||||
../quick/xqmodelview.qml \
|
||||
README.md \
|
||||
xml/modelsheets.xml \
|
||||
xml/modeldata1.xtr \
|
||||
xml/modeldata2.xtr \
|
||||
xml/modeldata3.xtr
|
||||
|
||||
|
||||
|
||||
|
8
src/xtree.qrc
Normal file
8
src/xtree.qrc
Normal file
@@ -0,0 +1,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>../xml/modeldata1.xtr</file>
|
||||
<file>../xml/modeldata2.xtr</file>
|
||||
<file>../xml/modeldata3.xtr</file>
|
||||
<file>../xml/modelsheets.xml</file>
|
||||
</qresource>
|
||||
</RCC>
|
25
src/xtree.sln
Normal file
25
src/xtree.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.9.34728.123
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xtree", "xtree.vcxproj", "{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Debug|x86.Build.0 = Debug|Win32
|
||||
{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Release|x86.ActiveCfg = Release|Win32
|
||||
{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {22F98E65-DA6B-44B7-989E-45B612815CD0}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
181
src/xtree.vcxproj
Normal file
181
src/xtree.vcxproj
Normal file
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}</ProjectGuid>
|
||||
<Keyword>QtVS_v304</Keyword>
|
||||
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">10.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">10.0</WindowsTargetPlatformVersion>
|
||||
<QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
|
||||
<Import Project="$(QtMsBuild)\qt_defaults.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="QtSettings">
|
||||
<QtInstall>qt691</QtInstall>
|
||||
<QtModules>core;gui;widgets</QtModules>
|
||||
<QtBuildConfig>debug</QtBuildConfig>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="QtSettings">
|
||||
<QtInstall>VS2017x86Default</QtInstall>
|
||||
<QtModules>core;gui;widgets</QtModules>
|
||||
<QtBuildConfig>release</QtBuildConfig>
|
||||
</PropertyGroup>
|
||||
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
|
||||
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
|
||||
</Target>
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="Shared" />
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(QtMsBuild)\Qt.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(QtMsBuild)\Qt.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>items;model;application;widgets;util;nodes;pugixml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration">
|
||||
<ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration">
|
||||
<ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<QtRcc Include="xtree.qrc" />
|
||||
<QtUic Include="application\xqmainwindow.ui" />
|
||||
<ClCompile Include="application\xqappdata.cpp" />
|
||||
<ClCompile Include="application\xqchildmodelview.cpp" />
|
||||
<ClCompile Include="application\xqdocumentstore.cpp" />
|
||||
<ClCompile Include="application\xqmainmodelview.cpp" />
|
||||
<ClCompile Include="application\xqmainwindow.cpp" />
|
||||
<ClCompile Include="items\xqgenericitem.cpp" />
|
||||
<ClCompile Include="items\xqitem.cpp" />
|
||||
<ClCompile Include="items\xqitemdelegate.cpp" />
|
||||
<ClCompile Include="items\xqitemfactory.cpp" />
|
||||
<ClCompile Include="items\xqitemtype.cpp" />
|
||||
<ClCompile Include="model\xqcommand.cpp" />
|
||||
<ClCompile Include="model\xqitemtype.cpp" />
|
||||
<ClCompile Include="model\xqitemtypefactory.cpp" />
|
||||
<ClCompile Include="model\xqnodewriter.cpp" />
|
||||
<ClCompile Include="model\xqselectionmodel.cpp" />
|
||||
<ClCompile Include="model\xqitem.cpp" />
|
||||
<ClCompile Include="model\xqmodelview.cpp" />
|
||||
<ClCompile Include="model\xqmodelsections.cpp" />
|
||||
<ClCompile Include="model\xqsimpleclipboard.cpp" />
|
||||
<ClCompile Include="model\xqitemfactory.cpp" />
|
||||
<ClCompile Include="model\xqnode.cpp" />
|
||||
<ClCompile Include="nodes\znode.cpp" />
|
||||
<ClCompile Include="pugixml\pugixml.cpp" />
|
||||
<ClCompile Include="util\xqexception.cpp" />
|
||||
<ClCompile Include="widgets\xqitemdelegate.cpp" />
|
||||
<ClCompile Include="widgets\xqcontextmenu.cpp" />
|
||||
<ClCompile Include="widgets\xqtreeview.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="application\xqchildmodelview.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="application\xqmainmodelview.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="application\xqmainwindow.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="application\xqdocumentstore.h" />
|
||||
<ClInclude Include="application\xqappdata.h" />
|
||||
<ClInclude Include="items\xqgenericitem.h" />
|
||||
<ClInclude Include="items\xqitem.h" />
|
||||
<ClInclude Include="items\xqitemdelegate.h" />
|
||||
<ClInclude Include="items\xqitemfactory.h" />
|
||||
<ClInclude Include="items\xqitemtype.h" />
|
||||
<ClInclude Include="model\xqcommand.h" />
|
||||
<ClInclude Include="model\xqmodelsections.h" />
|
||||
<ClInclude Include="model\xqnodewriter.h" />
|
||||
<ClInclude Include="model\xqsimpleclipboard.h" />
|
||||
<ClInclude Include="model\xqnode.h" />
|
||||
<ClInclude Include="nodes\znode.h" />
|
||||
<ClInclude Include="nodes\znode_attributes.h" />
|
||||
<ClInclude Include="nodes\znode_factory.h" />
|
||||
<ClInclude Include="nodes\znode_id.h" />
|
||||
<ClInclude Include="nodes\znode_iterator.h" />
|
||||
<ClInclude Include="nodes\znode_payload.h" />
|
||||
<ClInclude Include="nodes\znode_vector.h" />
|
||||
<ClInclude Include="pugixml\pugiconfig.hpp" />
|
||||
<ClInclude Include="pugixml\pugixml.hpp" />
|
||||
<ClInclude Include="util\xqexception.h" />
|
||||
<ClInclude Include="util\xqmapindex.h" />
|
||||
<ClInclude Include="util\xqmaptor.h" />
|
||||
<ClInclude Include="util\xqptrmaptor.h" />
|
||||
<ClInclude Include="util\xsingleton.h" />
|
||||
<ClInclude Include="util\xtreewalker.h" />
|
||||
<QtMoc Include="widgets\xqtreeview.h" />
|
||||
<QtMoc Include="widgets\xqcontextmenu.h" />
|
||||
<QtMoc Include="widgets\xqitemdelegate.h" />
|
||||
<QtMoc Include="model\xqmodelview.h" />
|
||||
<QtMoc Include="model\xqselectionmodel.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||
<Import Project="$(QtMsBuild)\qt.targets" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
272
src/xtree.vcxproj.filters
Normal file
272
src/xtree.vcxproj.filters
Normal file
@@ -0,0 +1,272 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Form Files">
|
||||
<UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
|
||||
<Extensions>ui</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Translation Files">
|
||||
<UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
|
||||
<Extensions>ts</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\pugixml">
|
||||
<UniqueIdentifier>{c1cbeda0-491a-46fe-9d15-5b21860ea498}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\widgets">
|
||||
<UniqueIdentifier>{63294d99-ad90-46cf-ba38-14f7edc6be6f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\nodes">
|
||||
<UniqueIdentifier>{298ce403-da4f-40a7-84ac-f6e9bfd730cf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\model">
|
||||
<UniqueIdentifier>{97b0d146-c114-43de-b9d7-297c147cbe29}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\application">
|
||||
<UniqueIdentifier>{8a32e1fe-2e12-47df-b2c9-792983588c4b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\util">
|
||||
<UniqueIdentifier>{b9c72284-5bbd-45c5-9494-955aa9f19e60}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\model">
|
||||
<UniqueIdentifier>{435db408-f6b8-4323-b878-1adce636c1ae}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\pugixml">
|
||||
<UniqueIdentifier>{5ce48ab8-bef4-4a72-a91d-e8c90ae21387}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\widgets">
|
||||
<UniqueIdentifier>{55c5c9bb-0d76-4941-88d7-79742698b4c7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\nodes">
|
||||
<UniqueIdentifier>{2ba2298d-4869-4816-925f-57f3f344b1c8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\application">
|
||||
<UniqueIdentifier>{c6422570-27c7-4803-b36f-fc69ce71e9a0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\util">
|
||||
<UniqueIdentifier>{59ebd050-7d3b-4c7f-a29d-e8e85c29a1f9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\items">
|
||||
<UniqueIdentifier>{8b3093d8-ce13-429c-8489-698995039f55}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Items">
|
||||
<UniqueIdentifier>{9c2a5017-1219-4efc-a661-f0d08d70dba9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtRcc Include="xtree.qrc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</QtRcc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqcommand.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqitem.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqmodelview.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqnode.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="application\xqmainmodelview.cpp">
|
||||
<Filter>Source Files\application</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="application\xqmainwindow.cpp">
|
||||
<Filter>Source Files\application</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="nodes\znode.cpp">
|
||||
<Filter>Source Files\nodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="widgets\xqitemdelegate.cpp">
|
||||
<Filter>Source Files\widgets</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="widgets\xqtreeview.cpp">
|
||||
<Filter>Source Files\widgets</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pugixml\pugixml.cpp">
|
||||
<Filter>Source Files\pugixml</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqmodelsections.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqselectionmodel.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="application\xqchildmodelview.cpp">
|
||||
<Filter>Source Files\application</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqsimpleclipboard.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="widgets\xqcontextmenu.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\xqexception.cpp">
|
||||
<Filter>Source Files\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="application\xqdocumentstore.cpp">
|
||||
<Filter>Source Files\application</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqnodewriter.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqitemfactory.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="application\xqappdata.cpp">
|
||||
<Filter>Source Files\application</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqitemtypefactory.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\xqitemtype.cpp">
|
||||
<Filter>Source Files\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="items\xqgenericitem.cpp">
|
||||
<Filter>Source Files\Items</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="items\xqitem.cpp">
|
||||
<Filter>Source Files\Items</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="items\xqitemdelegate.cpp">
|
||||
<Filter>Source Files\Items</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="items\xqitemfactory.cpp">
|
||||
<Filter>Source Files\Items</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="items\xqitemtype.cpp">
|
||||
<Filter>Source Files\Items</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="model\xqcommand.h">
|
||||
<Filter>Header Files\model</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="model\xqnode.h">
|
||||
<Filter>Header Files\model</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\xqmaptor.h">
|
||||
<Filter>Header Files\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\xsingleton.h">
|
||||
<Filter>Header Files\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\xtreewalker.h">
|
||||
<Filter>Header Files\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nodes\znode.h">
|
||||
<Filter>Header Files\nodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nodes\znode_factory.h">
|
||||
<Filter>Header Files\nodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pugixml\pugiconfig.hpp">
|
||||
<Filter>Header Files\pugixml</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pugixml\pugixml.hpp">
|
||||
<Filter>Header Files\pugixml</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="model\xqmodelsections.h">
|
||||
<Filter>Header Files\model</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\xqmapindex.h">
|
||||
<Filter>Header Files\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\xqptrmaptor.h">
|
||||
<Filter>Header Files\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="model\xqsimpleclipboard.h">
|
||||
<Filter>Header Files\model</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\xqexception.h">
|
||||
<Filter>Header Files\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="model\xqnodewriter.h">
|
||||
<Filter>Header Files\model</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="application\xqappdata.h">
|
||||
<Filter>Header Files\application</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nodes\znode_iterator.h">
|
||||
<Filter>Header Files\nodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nodes\znode_vector.h">
|
||||
<Filter>Header Files\nodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nodes\znode_id.h">
|
||||
<Filter>Header Files\nodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nodes\znode_payload.h">
|
||||
<Filter>Header Files\nodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nodes\znode_attributes.h">
|
||||
<Filter>Header Files\nodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="items\xqgenericitem.h">
|
||||
<Filter>Header Files\items</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="items\xqitem.h">
|
||||
<Filter>Header Files\items</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="items\xqitemdelegate.h">
|
||||
<Filter>Header Files\items</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="items\xqitemfactory.h">
|
||||
<Filter>Header Files\items</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="items\xqitemtype.h">
|
||||
<Filter>Header Files\items</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="model\xqmodelview.h">
|
||||
<Filter>Header Files\model</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="application\xqmainmodelview.h">
|
||||
<Filter>Header Files\application</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="application\xqmainwindow.h">
|
||||
<Filter>Header Files\application</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="widgets\xqitemdelegate.h">
|
||||
<Filter>Header Files\widgets</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="widgets\xqtreeview.h">
|
||||
<Filter>Header Files\widgets</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="widgets\xqcontextmenu.h">
|
||||
<Filter>Header Files\widgets</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="model\xqselectionmodel.h">
|
||||
<Filter>Header Files\model</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="application\xqchildmodelview.h">
|
||||
<Filter>Header Files\application</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="application\xqdocumentstore.h">
|
||||
<Filter>Header Files\application</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="application\xqmainwindow.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
</ItemGroup>
|
||||
</Project>
|
12
src/xtree.vcxproj.user
Normal file
12
src/xtree.vcxproj.user
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<QtTouchProperty>
|
||||
</QtTouchProperty>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<QtTouchProperty>
|
||||
</QtTouchProperty>
|
||||
</PropertyGroup>
|
||||
</Project>
|
35
xml/modeldata1.xtr
Normal file
35
xml/modeldata1.xtr
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<Project ProjectID="HA01" FriendlyName="@ProjectName" ProjectName="Wiebelbach West" Established="2006" WattPeak="84000" ContentType="runnning" LastFileName="modelData1.xtr">
|
||||
<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>
|
||||
<Panel PanelID="#2 JA 02" FriendlyName="@PanelName" PanelName="JA 02 Solar X58C" Manufacturer="JA Solar 2" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
|
||||
<Panel PanelID="#3 JA 03" FriendlyName="@PanelName" PanelName="JA 03 Solar T62B" Manufacturer="JA Solar 3" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"/>
|
||||
<Panel PanelID="#4 JA 04" FriendlyName="@PanelName" PanelName="JA 04 Solar X58C" Manufacturer="JA Solar 4" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
|
||||
<Panel PanelID="#5 JA 05" FriendlyName="@PanelName" PanelName="JA 05 Solar X58C" Manufacturer="JA Solar 5" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
|
||||
<Panel PanelID="#6 JA 06" FriendlyName="@PanelName" PanelName="JA 06 Solar X58C" Manufacturer="JA Solar 6" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
|
||||
<Inverter InverterID="#1 HM600 01" FriendlyName="@InverterName" InverterName="01 HM600 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="2000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
|
||||
<Inverter InverterID="#2 HM800 02" FriendlyName="@InverterName" InverterName="02 HM800 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="800" NumStrings="2" Weight="29"/>
|
||||
<Inverter InverterID="#3 HM1600 03" FriendlyName="@InverterName" InverterName="03 HM1600 S4 TMax" Manufacturer="HoyMiles" MaxPowerInput="6000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="1600" NumStrings="4" Weight="32"/>
|
||||
<Inverter InverterID="#4 D12K 04" FriendlyName="@InverterName" InverterName="04 HM600 S2 TMax" Manufacturer="Deye" MaxPowerInput="12000,33" MaxPowerInputChoice="6000;8000;12000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
|
||||
<Battery BatteryID="#1 BYD 01" FriendlyName="@BatteryName" BatteryName="01 BYD T01 Stackable" Manufacturer="BYD" Capacity="4500" Yield="90" MaxCurrent="120" MaxVolt="48">
|
||||
<AdditionalData DataItem="Image" DataValue="image.png"/>
|
||||
<AdditionalData DataItem="Manual" DataValue="manual.docx"/>
|
||||
<AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/>
|
||||
</Battery>
|
||||
<Battery BatteryID="#2 BYD 02" FriendlyName="@BatteryName" BatteryName="02 BYD T02 Stackable" Manufacturer="BYD" Capacity="9000" Yield="94" MaxCurrent="120" MaxVolt="48"/>
|
||||
<Battery BatteryID="#3 BYD 03" FriendlyName="@BatteryName" BatteryName="03 BYD T01 Stackable" Manufacturer="BYD" Capacity="4500" Yield="86" MaxCurrent="120" MaxVolt="48"/>
|
||||
<Battery BatteryID="#4 BYD 04" FriendlyName="@BatteryName" BatteryName="04 BYD T02 Stackable" Manufacturer="BYD" Capacity="9000" Yield="98" MaxCurrent="120" MaxVolt="48"/>
|
||||
<Battery BatteryID="#5 GroWatt 05 G2K" FriendlyName="@BatteryName" BatteryName="05 BYD T01 Stackable" Manufacturer="GroWatt" Capacity="4500" Yield="94" MaxCurrent="120" MaxVolt="48"/>
|
||||
<Battery BatteryID="#6 GroWatt 06 G4K" FriendlyName="@BatteryName" BatteryName="06 BYD T02 Stackable" Manufacturer="GroWatt" Capacity="9000" Yield="49" MaxCurrent="120" MaxVolt="48"/>
|
||||
<Battery BatteryID="#7 Pyne 07 G4K" FriendlyName="@BatteryName" BatteryName="07 Pyne K7 Stackable" Manufacturer="PyNe" Capacity="9000" Yield="49" MaxCurrent="120" MaxVolt="48"/>
|
||||
|
||||
</Components>
|
||||
<IrgendWasAnderes>
|
||||
</IrgendWasAnderes>
|
||||
|
||||
</Project>
|
||||
|
||||
|
31
xml/modeldata2.xtr
Normal file
31
xml/modeldata2.xtr
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
|
||||
<Project ProjectID="HA02" FriendlyName="@ProjectName" ProjectName="Gerbrunn Ost" Established="2006" WattPeak="9840" ContentType="planned">
|
||||
<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">
|
||||
<AdditionalData DataItem="Image" DataValue="image,png"/>
|
||||
<AdditionalData DataItem="Manual" DataValue="manual,docx"/>
|
||||
<AdditionalData DataItem="Certificate" DataValue="certificate,pdf"/>
|
||||
</Panel>
|
||||
<Panel PanelID="Jingli 02" FriendlyName="@PanelName" PanelName="Jingli 02 Solar X58C" Manufacturer="Jingli Solar" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
|
||||
<Panel PanelID="Jingli 03" FriendlyName="@PanelName" PanelName="Jingli 03 Solar T62B" Manufacturer="Jingli Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"/>
|
||||
|
||||
<Inverter InverterID="HM600 01" FriendlyName="@InverterName" InverterName="01 HM600 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
|
||||
<Inverter InverterID="HM800 02" FriendlyName="@InverterName" InverterName="02 HM800 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="800" NumStrings="2" Weight="29"/>
|
||||
<Inverter InverterID="HM1600 03" FriendlyName="@InverterName" InverterName="03 HM1600 S4 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="1600" NumStrings="4" Weight="32"/>
|
||||
<Inverter InverterID="D12K 04" FriendlyName="@InverterName" InverterName="04 HM600 S2 TMax" Manufacturer="Deye" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
|
||||
|
||||
<Battery BatteryID="BYD 01" FriendlyName="@BatteryName" BatteryName="01 BYD T01 Stackable" Manufacturer="BYD" Capacity="4500" Yield="88" MaxCurrent="120" MaxVolt="48">
|
||||
<AdditionalData DataItem="Image" DataValue="image.png"/>
|
||||
<AdditionalData DataItem="Manual" DataValue="manual.docx"/>
|
||||
<AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/>
|
||||
</Battery>
|
||||
<Battery BatteryID="BYD 04" FriendlyName="@BatteryName" BatteryName="04 BYD T02 Stackable" Manufacturer="BYD" Capacity="9000" Yield="32" MaxCurrent="120" MaxVolt="48"/>
|
||||
<Battery BatteryID="GroWatt 05 G2K" FriendlyName="@BatteryName" BatteryName="05 BYD T01 Stackable" Manufacturer="PylonTech" Capacity="4500" Yield="46" MaxCurrent="120" MaxVolt="48"/>
|
||||
<Battery BatteryID="GroWatt 06 G4K" FriendlyName="@BatteryName" BatteryName="06 BYD T02 Stackable" Manufacturer="PylonTech" Capacity="9000" Yield="94" MaxCurrent="120" MaxVolt="48">
|
||||
</Battery>
|
||||
|
||||
</Components>
|
||||
</Project>
|
||||
|
26
xml/modeldata3.xtr
Normal file
26
xml/modeldata3.xtr
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<Project ProjectID="HA03" FriendlyName="@ProjectName" ProjectName="Neubrunn Süd" Established="2006" WattPeak="9840" ContentType="runnning">
|
||||
<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">
|
||||
<AdditionalData DataItem="Image" DataValue="image.png"/>
|
||||
<AdditionalData DataItem="Manual" DataValue="manual.docx"/>
|
||||
<AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/>
|
||||
</Panel>
|
||||
<Panel PanelID="AIKO 02" FriendlyName="@PanelName" PanelName="AIKO 02 Solar X58C" Manufacturer="AIKO Solar" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
|
||||
<Panel PanelID="AIKO 03" FriendlyName="@PanelName" PanelName="AIKO 03 Solar T62B" Manufacturer="AIKO Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"/>
|
||||
<Panel PanelID="AIKO 04" FriendlyName="@PanelName" PanelName="AIKO 04 Solar X58C" Manufacturer="AIKO Solar" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
|
||||
<Panel PanelID="AIKO 06" FriendlyName="@PanelName" PanelName="AIKO 06 Solar X58C" Manufacturer="AIKO Solar" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
|
||||
|
||||
<Inverter InverterID="HM600 01" FriendlyName="@InverterName" InverterName="01 HM600 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
|
||||
<Inverter InverterID="HM800 02" FriendlyName="@InverterName" InverterName="02 HM800 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="800" NumStrings="2" Weight="29"/>
|
||||
<Battery BatteryID="BYD 01" FriendlyName="@BatteryName" BatteryName="01 BYD T01 Stackable" Manufacturer="BYD" Capacity="4500" Yield="94" MaxCurrent="120" MaxVolt="48">
|
||||
<AdditionalData DataItem="Image" DataValue="image.png"/>
|
||||
<AdditionalData DataItem="Manual" DataValue="manual.docx"/>
|
||||
<AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/>
|
||||
</Battery>
|
||||
<Battery BatteryID="BYD 02" FriendlyName="@BatteryName" BatteryName="02 BYD T02 Stackable" Manufacturer="BYD" Capacity="9000" Yield="94" MaxCurrent="120" MaxVolt="48"/>
|
||||
<Battery BatteryID="BYD 03" FriendlyName="@BatteryName" BatteryName="03 BYD T01 Stackable" Manufacturer="BYD" Capacity="4500" Yield="94" MaxCurrent="120" MaxVolt="48"/>
|
||||
</Components>
|
||||
</Project>
|
||||
|
135
xml/modelsheets.xml
Normal file
135
xml/modelsheets.xml
Normal file
@@ -0,0 +1,135 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<!--
|
||||
|
||||
Der ItemType beschreibt die Eigenschaften eines Items.
|
||||
|
||||
-->
|
||||
|
||||
<ItemTypes>
|
||||
<TreeParentType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsDropEnabled" Icon="DirIcon" />
|
||||
<TreeChildType RenderStyle="PlainStyle" ItemFlags="IsEnabled" Icon="DesktopIcon"/>
|
||||
<TreeSectionType RenderStyle="PlainStyle" ItemFlags="IsUserCheckable|IsEnabled" Icon="DirIcon"/>
|
||||
<HeaderType RenderStyle="HeaderStyle" ItemFlags="IsEnabled"/>
|
||||
<HiddenType RenderStyle="HiddenStyle"/>
|
||||
<StaticType RenderStyle="PlainStyle"/>
|
||||
<PlainType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable"/>
|
||||
<ValueType RenderStyle="FormattedStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="Coulomb"/>
|
||||
<CheckableType RenderStyle="FormattedStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="###"/>
|
||||
<PercentageType RenderStyle="ProgressBarStyle" ItemFlags="IsEnabled|IsSelectable"/>
|
||||
<ChoiceType RenderStyle="ComboBoxStyle" ItemFlags="IsEnabled|IsSelectable|IsEditable" FixedChoices="la|le|lo|lu"/>
|
||||
<IntValueType RenderStyle="SpinBoxStyle" ItemFlags="IsEnabled|IsSelectable"/>
|
||||
</ItemTypes>
|
||||
|
||||
|
||||
<DocumentTreeModel>
|
||||
<Section ContentType="runnning">
|
||||
<Header>
|
||||
<Entry Caption="Active Projects" ItemType="TreeParentType"/>
|
||||
</Header>
|
||||
<ModelSheet firz="running">
|
||||
<Project Caption="@ProjectName" ItemType="TreeChildType">
|
||||
<CurrentSection ItemType="TreeSectionType"/>
|
||||
</Project>
|
||||
</ModelSheet>
|
||||
</Section>
|
||||
<Section ContentType="planned">
|
||||
<Header>
|
||||
<Entry Caption="Planned Projects" ItemType="TreeParentType"/>
|
||||
</Header>
|
||||
<ModelSheet firz="planned">
|
||||
<Project Caption="@ProjectName" ItemType="TreeChildType">
|
||||
<CurrentSection ItemType="TreeSectionType"/>
|
||||
</Project>
|
||||
</ModelSheet>
|
||||
</Section>
|
||||
<Section ContentType="finished">
|
||||
<Header>
|
||||
<Entry Caption="Finished Projects" ItemType="TreeParentType"/>
|
||||
</Header>
|
||||
<ModelSheet firz="finished">
|
||||
<Project Caption="@ProjectName" ItemType="TreeChildType">
|
||||
<CurrentSection ItemType="TreeSectionType"/>
|
||||
</Project>
|
||||
</ModelSheet>
|
||||
</Section>
|
||||
</DocumentTreeModel>
|
||||
|
||||
|
||||
|
||||
<DocumentDetailsModel>
|
||||
|
||||
<Section ContentType="Panel" firz="farz">
|
||||
<Header Marker="Panel">
|
||||
<PanelID Caption="Panel" ItemType="HeaderType" />
|
||||
<PanelName Caption="Name" ItemType="HeaderType" Icon="BrowserStop" />
|
||||
<Manufacturer Caption="Manufacturer" ItemType="HeaderType" />
|
||||
<WattPeak Caption="Watt Peak" ItemType="HeaderType" />
|
||||
<Width Caption="Width" ItemType="HeaderType" />
|
||||
<Height Caption="Height" ItemType="HeaderType" />
|
||||
<Wight Caption="Weight" ItemType="HeaderType" />
|
||||
<MaxVolt Caption="max. Volt" ItemType="HeaderType" />
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
|
||||
</DocumentDetailsModel>
|
27
xml/saved_testfile.xtr
Normal file
27
xml/saved_testfile.xtr
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Project Established="2006" FriendlyName="@ProjectName" ProjectID="HA01" ProjectName="Wiebelbach West" State="runnning" WattPeak="84000">
|
||||
<Components>
|
||||
<Panel FriendlyName="@PanelName" Height="2,70" Manufacturer="JA Solar 1 XX" MaxAmpere="11" MaxVolt="67" PanelID="#1 JA 01" PanelName="JA 01 Solar T62B" WattPeak="620" Weight="12" Width="1,10"/>
|
||||
<Panel FriendlyName="@PanelName" Height="1,70" Manufacturer="JA Solar 2" MaxAmpere="11" MaxVolt="42" PanelID="#2 JA 02" PanelName="JA 02 Solar X58C" WattPeak="440" Weight="12" Width="1,10"/>
|
||||
<Panel FriendlyName="@PanelName" Height="2,70" Manufacturer="JA Solar 3" MaxAmpere="11" MaxVolt="67" PanelID="#3 JA 03" PanelName="JA 03 Solar T62B" WattPeak="620" Weight="12" Width="1,10"/>
|
||||
<Panel FriendlyName="@PanelName" Height="1,70" Manufacturer="JA Solar 4" MaxAmpere="11" MaxVolt="42" PanelID="#4 JA 04" PanelName="JA 04 Solar X58C" WattPeak="440" Weight="12" Width="1,10"/>
|
||||
<Panel FriendlyName="@PanelName" Height="1,70" Manufacturer="JA Solar 5" MaxAmpere="11" MaxVolt="42" PanelID="#5 JA 05" PanelName="JA 05 Solar X58C" WattPeak="440" Weight="12" Width="1,10"/>
|
||||
<Panel FriendlyName="@PanelName" Height="1,70" Manufacturer="JA Solar 6" MaxAmpere="11" MaxVolt="42" PanelID="#6 JA 06" PanelName="JA 06 Solar X58C" WattPeak="440" Weight="12" Width="1,10"/>
|
||||
<Inverter FriendlyName="@InverterName" InverterID="#1 HM600 01" InverterName="01 HM600 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="2000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
|
||||
<Inverter FriendlyName="@InverterName" InverterID="#2 HM800 02" InverterName="02 HM800 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="800" NumStrings="2" Weight="29"/>
|
||||
<Inverter FriendlyName="@InverterName" InverterID="#3 HM1600 03" InverterName="03 HM1600 S4 TMax" Manufacturer="HoyMiles" MaxPowerInput="6000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="1600" NumStrings="4" Weight="32"/>
|
||||
<Inverter FriendlyName="@InverterName" InverterID="#4 D12K 04" InverterName="04 HM600 S2 TMax" Manufacturer="Deye" MaxPowerInput="12000,33" MaxPowerInputChoice="6000;8000;12000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
|
||||
<Battery BatteryID="#1 BYD 01" BatteryName="01 BYD T01 Stackable" Capacity="4500" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="90">
|
||||
<AdditionalData DataItem="Image" DataValue="image.png"/>
|
||||
<AdditionalData DataItem="Manual" DataValue="manual.docx"/>
|
||||
<AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/>
|
||||
</Battery>
|
||||
<Battery BatteryID="#2 BYD 02" BatteryName="02 BYD T02 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="94"/>
|
||||
<Battery BatteryID="#3 BYD 03" BatteryName="03 BYD T01 Stackable" Capacity="4500" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="86"/>
|
||||
<Battery BatteryID="#4 BYD 04" BatteryName="04 BYD T02 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="98"/>
|
||||
<Battery BatteryID="#5 GroWatt 05 G2K" BatteryName="05 BYD T01 Stackable" Capacity="4500" FriendlyName="@BatteryName" Manufacturer="GroWatt" MaxCurrent="120" MaxVolt="48" Yield="94"/>
|
||||
<Battery BatteryID="#6 GroWatt 06 G4K" BatteryName="06 BYD T02 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="GroWatt" MaxCurrent="120" MaxVolt="48" Yield="49"/>
|
||||
<Battery BatteryID="#7 Pyne 07 G4K" BatteryName="07 Pyne K7 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="PyNe" MaxCurrent="120" MaxVolt="48" Yield="49"/>
|
||||
</Components>
|
||||
<IrgendWasAnderes/>
|
||||
</Project>
|
Reference in New Issue
Block a user