first commit, again.
This commit is contained in:
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
|
Reference in New Issue
Block a user