Compare commits

21 Commits

Author SHA1 Message Date
3887748c1a remorked sections. 2025-09-05 21:42:40 +02:00
b8f0893d59 Backup. 2025-09-05 17:12:38 +02:00
9c6f7688d7 Enable section toggle 2025-09-05 11:49:36 +02:00
8d26c32e51 cleanups, added const iterators to xqmaptor 2025-09-05 09:57:43 +02:00
c9b61c1c2b Fixed ::setData, part II 2025-09-04 20:09:21 +02:00
d6ccac1d85 Fixed ::setData, part I 2025-09-04 18:10:14 +02:00
5d2fb1b378 Added new-undo == delete 2025-09-04 17:01:01 +02:00
89c5fd21f1 Completed cmdNew implementation. 2025-09-04 14:56:18 +02:00
f8bd0886d3 Added cmdNew implementation. 2025-09-04 13:52:23 +02:00
Christoph Holzheuer
831daf898c --fy 2025-09-03 17:23:52 +02:00
Christoph Holzheuer
3e7b65dca5 add signal prototypes 2025-09-02 16:58:56 +02:00
147769bf60 added signal handler 'itemChanged' 2025-09-01 23:28:24 +02:00
Christoph Holzheuer
527de65074 -- fy 2025-09-01 17:40:08 +02:00
4d49a495fd -- fy 2025-08-31 23:18:14 +02:00
952409ab1a repaired it (a bit) 2025-08-31 14:38:11 +02:00
c6454f3106 cracket it. 2025-08-27 15:39:33 +02:00
04b0f650d6 -- pre-holiday 2025-08-27 14:06:31 +02:00
6ee677c595 looking better. 2025-08-26 19:41:28 +02:00
5057edb9ad Merge branch 'experimental/qml-widget' 2025-08-26 17:57:16 +02:00
39909ad543 Added scrollbars. 2025-08-26 17:55:39 +02:00
b217f2f9ad little breakthrought im QML Layouts 2025-08-26 17:45:06 +02:00
42 changed files with 1213 additions and 741 deletions

View File

@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: 2025 Martin Leutelt <martin.leutelt@basyskom.com>
// SPDX-FileCopyrightText: 2025 basysKom GmbH
//
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick
import QtQuick.Controls
Control {
id: container
required property int column
required property var model
property int sortOrder: Qt.AscendingOrder
signal clicked(int sortOrder)
padding: 8
background: Rectangle {
color: tapHandler.pressed ? "gray" : "lightgray"
TapHandler {
id: tapHandler
onTapped: {
if (container.sortOrder === Qt.AscendingOrder) {
container.sortOrder = Qt.DescendingOrder
} else {
container.sortOrder = Qt.AscendingOrder
}
container.clicked(container.sortOrder)
}
}
}
contentItem: Label {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
text: container.model.display
}
}

View File

@@ -0,0 +1,26 @@
import QtQuick
import QtQuick.Controls
Control {
id: container
required property int row
required property var model
padding: 8
background: Rectangle {
color: tapHandler.pressed ? "gray" : "lightgray"
TapHandler {
id: tapHandler
}
}
contentItem: Label {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
text: container.model.display
}
}

161
qml/XMain.qml Normal file
View File

@@ -0,0 +1,161 @@
// SPDX-FileCopyrightText: 2025 Martin Leutelt <martin.leutelt@basyskom.com>
// SPDX-FileCopyrightText: 2025 basysKom GmbH
//
// SPDX-License-Identifier: LGPL-3.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
ApplicationWindow {
width: 640
height: 480
visible: true
title: Application.displayName
header: ToolBar {
ColumnLayout {
RowLayout {
Label {
text: "Rows"
}
SpinBox {
id: rowSettings
from: 1
to: 20
}
ToolSeparator {}
Label {
text: "Columns"
}
SpinBox {
id: columnSettings
from: 1
to: 20
}
ToolSeparator {}
CheckBox {
id: movableColumnsSetting
text: "Movable columns"
}
ToolSeparator {}
CheckBox {
id: resizableColumnsSetting
text: "Resizable columns"
}
}
RowLayout {
Label {
text: "Selection"
}
ComboBox {
id: selectionSetting
textRole: "text"
valueRole: "value"
model: [
{ text: "disabled", value: TableView.SelectionDisabled },
{ text: "by cells", value: TableView.SelectCells },
{ text: "by rows", value: TableView.SelectRows },
{ text: "by columns", value: TableView.SelectColumns }
]
onCurrentIndexChanged: tableView.selectionModel.clear()
}
Label {
text: "Longpress to start selection, modify selection with CTRL/SHIFT of by mouse"
visible: selectionSetting.currentIndex > 0
}
}
}
}
Rectangle {
id: tableBackground
anchors.fill: parent
color: Application.styleHints.colorScheme === Qt.Light ? palette.mid : palette.midlight
HorizontalHeaderView {
id: horizontalHeader
anchors.left: tableView.left
anchors.top: parent.top
syncView: tableView
movableColumns: movableColumnsSetting.checked
resizableColumns: resizableColumnsSetting.checked
clip: true
boundsBehavior: tableView.boundsBehavior
delegate: HorizontalHeaderViewDelegate {
onClicked: (sortOrder) => tableView.model.sort(column, sortOrder)
}
}
VerticalHeaderView {
id: verticalHeader
anchors.top: tableView.top
anchors.left: parent.left
syncView: tableView
clip: true
boundsBehavior: tableView.boundsBehavior
delegate: VerticalHeaderViewDelegate {}
}
TableView {
id: tableView
anchors.left: verticalHeader.right
anchors.top: horizontalHeader.bottom
anchors.right: parent.right
anchors.bottom: parent.bottom
clip: true
columnSpacing: 1
rowSpacing: 1
rowHeightProvider: (row) => 40
boundsBehavior: TableView.StopAtBounds
selectionModel: ItemSelectionModel {}
selectionBehavior: selectionSetting.currentValue
model: SortFilterModel {
sourceModel: TableModel {
columns: columnSettings.value
rows: rowSettings.value
// when adding a new column its width isn't properly applied to the header, so we do that manually
onColumnsInserted: {
if (columns > 1) {
horizontalHeader.setColumnWidth(columns - 1, tableView.implicitColumnWidth(columns - 1))
}
}
}
}
delegate: TableViewDelegate {
implicitWidth: tableView.width / columnSettings.to
}
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
}
SelectionRectangle {
target: tableView
}
}
}

56
qml/dummyview.qml Normal file
View File

@@ -0,0 +1,56 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Window
ApplicationWindow
{
visible: true
width: 600
height: 400
TreeView
{
anchors.fill: parent
clip: true
columnSpacing: 1
rowSpacing: 1
model: myChildModel
columnWidthProvider: function(column)
{
var z= 2*(width / columns);
console.log("Firz:", z);
console.log("Berechne Spaltenbreite für column:", column);
console.log("Aktuelle TreeView-Breite:", width);
return z;
}
delegate: Rectangle
{
required property int row
required property int column
required property var model
border.width: 0
implicitWidth: 30
implicitHeight: 30
border.color: "#cccccc"
//color: index % 2 === 0 ? "#f9f9f9" : "#e0e0e0"
color: TreeView.isSelected ? "#d0eaff" : (row % 2 === 0 ? "#f9f9f9" : "#ffffff")
Text
{
anchors.centerIn: parent
text: display
font.pixelSize: 14
}
}
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
}
}

65
qml/xqtableview.qml Normal file
View File

@@ -0,0 +1,65 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Window
{
width: 640
height: 480
visible: true
title: qsTr("StringListModel")
TableView
{
id: childTableView
anchors.fill: parent
model: myChildModel // z.B. QStandardItemModel mit 9 Spalten
delegate: Rectangle
{
required property string display
//height: 5
//width: childTableView.width
color : "blue"
border.color: "#ccc"
width: childTableView.width;
RowLayout
{
anchors.fill: parent
anchors.margins: 2
TextField
{
text : display
font.pixelSize: 10
Layout.fillWidth: true
background: Rectangle
{
color : "white"
}
onEditingFinished:
{
console.log("Editing finished, new text is :"+ text + " at index :" + index)
model.names = text //The roles here are defined in model class
}
}
}
}
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
// // Optional: Spaltenbreiten setzen
// onModelChanged: {
// for (let i = 0; i < model.columns; ++i)
// table.setColumnWidth(i, 100)
// }
}
}

47
qml/xqtreeview.qml Normal file
View File

@@ -0,0 +1,47 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
TreeView
{
anchors.fill: parent
clip: true
columnSpacing: 1
rowSpacing: 1
model: xtrChildModel
columnWidthProvider: function(column)
{
var z= 1.7*(width / columns);
return z;
}
delegate: Rectangle
{
required property int row
required property int column
required property var model
border.width: 0
implicitWidth: 30
implicitHeight: 20
border.color: "#cccccc"
//color: index % 2 === 0 ? "#f9f9f9" : "#e0e0e0"
color: TreeView.isSelected ? "#d0eaff" : (row % 2 === 0 ? "#f9f9f9" : "#ffffff")
Text
{
anchors.centerIn: parent
text: display
font.pixelSize: 12
}
}
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
}

View File

@@ -1,35 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
TableView
{
id: table
anchors.fill: parent
columnSpacing: 2
rowSpacing: 2
model: meinModel // z.B. QStandardItemModel mit 9 Spalten
delegate: Rectangle
{
required property string display
width: 100
height: 20
border.color: "#ccc"
Text
{
anchors.centerIn: parent
text: display
font.pixelSize: 10
}
}
// // Optional: Spaltenbreiten setzen
// onModelChanged: {
// for (let i = 0; i < model.columns; ++i)
// table.setColumnWidth(i, 100)
// }
}

View File

@@ -38,6 +38,7 @@ 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";

View File

@@ -55,18 +55,12 @@ void XQChildModel::addModelData( const XQNodePtr& contentRoot )
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
//qDebug() << " --- add section ENTRY: " << key << " TagName: " << contentEntry->attribute("TagName");
const XQModelSection& section = _sections.sectionByKey( key );
section.setContentRootNode( contentEntry->parent() );
int newRow = _sections.lastRow(section);
XQNodePtr sheetNode = section.sheetRootNode();
XQItemList list = _itemFactory.makeRow( XQItemFactory::mData, sheetNode, contentEntry );
XQItemList list = _itemFactory.makeRow( sheetNode, contentEntry );
// als Baum?
//section.headerItem().appendRow( list );
@@ -76,24 +70,30 @@ void XQChildModel::addModelData( const XQNodePtr& contentRoot )
}
//! Erzeugt eine model-section und fügt den zugehörigen header ein.
void XQChildModel::addSectionEntry( const QString& key, const XQNodePtr& contentEntry )
{
XQModelSection& section = _sections.at( key );
const XQModelSection& section = _sections.sectionByKey( key );
if(section.isValid() )
{
section.setContentRootNode( contentEntry->parent() );
int newRow = _sections.lastRow(section);
int newRow =_sections.lastRow(section);
XQNodePtr sheetNode = section.sheetRootNode();
XQItemList list = _itemFactory.makeRow( XQItemFactory::mHeader, sheetNode, contentEntry );
XQItemList list = _itemFactory.makeRow( sheetNode, nullptr );
insertRow( newRow, list);
}
}
//! erzeugt ein adhoc-contextmenu, je nachdem welche aktionen gerade möflich sind.
//! erzeugt ein adhoc-contextmenu, je nachdem welche aktionen gerade möglich sind.
void XQChildModel::initContextMenu()
{
_sections.dump();
// __fixme! add a menu title
_contextMenu->clear();
@@ -113,7 +113,7 @@ void XQChildModel::initContextMenu()
// __fixme! set 'toggle section <name>' entry
//contextMenu.actions().first()->setText("<name>");
_contextMenu->addAction( "icn29Dummy", "Toggle Section", XQCommand::cmdToggleSection, hasSel);
_contextMenu->addAction( "icn29Dummy", "Hide Section", XQCommand::cmdToggleSection, true );
}

View File

@@ -18,8 +18,8 @@
//! erzeugt ein docukument
XQDocument::XQDocument(const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView )
: fileName{ aFileName }, friendlyName{ aFriendlyName }, treeItem{ aTreeItem }, modelView{ aModelView }
XQDocument::XQDocument(const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aViewModel )
: fileName{ aFileName }, friendlyName{ aFriendlyName }, treeItem{ aTreeItem }, viewModel{ aViewModel }
{
}
@@ -44,9 +44,9 @@ XQDocumentStore::~XQDocumentStore()
//! erzeugt ein document eintrag
void XQDocumentStore::addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView )
void XQDocumentStore::addDocument(const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aViewModel )
{
XQDocument newDocument( aFileName, aFriendlyName, aTreeItem, aModelView );
XQDocument newDocument( aFileName, aFriendlyName, aTreeItem, aViewModel );
addAtKey( aFileName, newDocument );
// attention: this assumes the presence of the 'ProjectID' value
//addAlias( aFileName, aTreeItem->attribute(c_ProjectID) );

View File

@@ -28,12 +28,10 @@ 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{};
XQViewModel* viewModel{};
};
@@ -46,11 +44,7 @@ public:
XQDocumentStore() = default;
virtual ~ XQDocumentStore();
void addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView );
protected:
XQNode _treeRootNode{ "treeRootNode" };
void addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aViewModel );
};

View File

@@ -45,57 +45,57 @@ void XQMainModel::initContextMenu()
XQItem* XQMainModel::addProjectItem( XQNodePtr contentNode )
{
// wir durchsuchen alle unsere section nach dem passenden content-type,
// hier: content-type beschreibt die
// wir durchsuchen alle unsere sections nach dem passenden content-type,
// hier: content-type beschreibt den projekt-status
const QString& sectionKey = contentNode->attribute(c_ContentType);
if( _sections.hasValidSection( sectionKey ) )
{
const XQModelSection& section = _sections.sectionByKey( sectionKey );
qDebug() << " --- add PROJECT: contentNode: " << contentNode->to_string();
// __fixme! das ist mist!
const XQNodePtr sheetNode = section.sheetRootNode()->first_child();
XQItem* newItem = _itemFactory.makeSingleItem( sheetNode, contentNode->attribute( "ProjectName") );
// den neuen eintrag in die passende section der übersicht eintragen ...
section.headerItem().appendRow( newItem );
// erzeuger sheet node speichern
newItem->setSheetNode( sheetNode );
expandNewItem(section.headerItem().index() );
return newItem;
}
/*
for(const auto& section : _sections )
{
if( contentNode->attribute( c_ContentType) == section.contentType() )
if( contentNode->attribute(c_ContentType) == section.contentType() )
{
qDebug() << " --- add PROJECT: contentNode: " << contentNode->to_string();
// __fixme! das ist mist!
const XQNodePtr sheetNode = section.sheetRootNode()->first_child();
XQItemList list = _itemFactory.makeRow( XQItemFactory::mSingle, sheetNode, contentNode, "ProjectName");
XQItem* newItem = _itemFactory.makeSingleItem( sheetNode, contentNode->attribute( "ProjectName") );
// 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 );
XQItem* newItem = dynamic_cast<XQItem*>(list[0]);
section.headerItem().appendRow( newItem );
// erzeuger sheet node speichern
newItem->setSheetNode( sheetNode );
expandNewItem(section.headerItem().index() );
return newItem;
}
}
*/
throw XQException( "addProjectItem: main model should not be empty!" );
}
void XQMainModel::addSectionItem( const XQModelSection& section, XQItem* projectItem )
{
return;
// ich brauche _meine_ section für den sheetNode!
XQNodePtr sheetNode = projectItem->sheetNode()->find_child_by_tag_name("CurrentSection");
XQItemList list = _itemFactory.makeRow( XQItemFactory::mSingle, sheetNode, nullptr, c_ContentType );
projectItem->appendRow( list );
_treeTable->expand( projectItem->index() );
XQItem* newItem = _itemFactory.makeSingleItem( sheetNode, section.contentType() );
projectItem->appendRow( newItem );
expandNewItem(projectItem->index() );
}

View File

@@ -35,6 +35,7 @@ public:
XQItem* addProjectItem( XQNodePtr contentNode );
void addSectionItem( const XQModelSection& section, XQItem* projectItem );
protected:
void initContextMenu() override;

View File

@@ -88,18 +88,26 @@ void XQMainWindow::initMainWindow()
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(onChildViewTabClicked(int)) );
//connect(&_mainModel, &QStandardItemModel::itemChanged, this, &XQMainWindow::onTreeItemChanged );
//connect( _mainTreeView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onDoubleClicked(QModelIndex)) );
//connect( _mainTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onTreeItemClicked(QModelIndex)) );
connect(&_mainModel, &XQViewModel::xqItemChanged, this, &XQMainWindow::onTreeViewItemChanged );
connect( _mainTreeView, &QTreeView::clicked, this, [&,this](const QModelIndex& index)
{
onTreeViewItemClicked( XQItem::xqItemFromIndex(index) );
});
/*
connect( &_mainModelView, &XQViewModel::itemCreated, this, [=, this](XQItem* item)
connect( &_mainModel, &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() );
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() );
@@ -109,15 +117,16 @@ void XQMainWindow::initMainWindow()
try
{
// hand over undostack
_mainModelView.setUndoStack(&_undoStack);
_mainModel.setUndoStack(&_undoStack);
// hand over left side navigation tree
_mainModelView.setTreeTable(_mainTreeView);
_mainModel.setTreeTable(_mainTreeView);
// #1. init the left side main tree view
_mainModelView.initModel( c_MainModelName );
_mainModel.initModel( c_MainModelName );
// #2. load demo data
loadDocument( c_DocumentFileName1 );
//loadDocumentQML( c_DocumentFileName2 );
loadDocument( c_DocumentFileName2 );
qDebug() << " --- all here: " << XQNode::s_Count;
@@ -232,7 +241,7 @@ void XQMainWindow::onAbout()
QMessageBox msgBox(QMessageBox::NoIcon, "About", "", QMessageBox::Ok);
QString text = "<b>xtree concept</b><br>";
text += "2024 c.holzheuer<br><br>";
text += "2024-2025 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
@@ -242,46 +251,70 @@ void XQMainWindow::onAbout()
}
//! wenn ein item im navigations-baum geklickt wird, soll die document
//! view rechts angepasst werden.
void XQMainWindow::onTreeItemClicked(const QModelIndex& index )
void XQMainWindow::onTreeViewItemClicked( const XQItem& item )
{
/*
_mainTreeView->selectionModel()->select(item.index(), QItemSelectionModel::Select);
XQItem& entry = XQItem::xqItemFromIndex(index);
qDebug() << " --- XXX mainWindow onTreeItemClicked:" << entry.text();
_mainTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
if( XQNodePtr contentNode = entry.contentNode() )
if( XQNodePtr contentNode = item.contentNode() )
{
QString key = contentNode->attribute(c_ProjectID);
qDebug() << " --- FIRZ: key: " << key;
bool isThere = _documentStore.contains(key);
if( isThere)
_tabWidget->setCurrentWidget( _documentStore[key].modelView->treeTable() );
_tabWidget->setCurrentWidget( _documentStore[key].viewModel->treeTable() );
}
*/
qDebug() << " --- Tree item CLICK:" << item.text() << " : " << item.itemType().text();
if( item.itemType().text() == "TreeChildType" )
{
setChildTabByName( item.text() );
}
}
void XQMainWindow::onTreeViewItemChanged(const XQItem& item )
{
qDebug() << " --- TREE VIEW itemChanged:" << item.text() << " : " << item.parent()->text();
// hier müssen wir erst das projekt aktivieren
XQItem* xqItem = static_cast<XQItem*>(item.parent());
onTreeViewItemClicked( *xqItem );
//if( item.itemType().text() == "TreeSectionType" )
{
int idx = _tabWidget->currentIndex();
if(_documentStore.contains(idx) )
{
qDebug() << " --- should toggle: " << item.text();
XQViewModel& childModel = *_documentStore[idx].viewModel;
childModel.onToggleSection(item.text());
}
}
}
//! beim click auf ein tab im linken fenster wird der navigationsbaum angepasst.
void XQMainWindow::onTabClicked( int index )
void XQMainWindow::onChildViewTabClicked( int idx )
{
//const QString& key = _documentStore[index].treeItem->attribute( c_ProjectID );
//qDebug() << " ---- tab clicked: " << index << " : " << _documentStore[index].friendlyName;// << ": " << key;
//_mainTreeView->setCurrentIndex( _documentStore[index].treeItem->index() );
if(_documentStore.contains(idx) )
{
QModelIndex treeIndex =_documentStore[idx].treeItem->index();
_mainModel.expandNewItem( treeIndex );
}
}
//! firz
void XQMainWindow::onSectionCreated( const XQModelSection& section )
{
qDebug() << " --- XXX section created: " << section.contentType() << ":" << section.sheetRootNode()->to_string();
if( _currentProjectItem )
{
_mainModelView.addSectionItem( section, _currentProjectItem );
_mainModel.addSectionItem( section, _currentProjectItem );
}
}
@@ -290,16 +323,16 @@ void XQMainWindow::onSectionToggled( const XQModelSection& section )
//qDebug() << " --- XXX section toggled: " << section.contentType() << ":" << section.sheetRootNode()->to_string();
}
QStandardItemModel* createModel() {
auto* model = new QStandardItemModel;
model->setHorizontalHeaderLabels({ "Name" });
QStandardItem* parent = new QStandardItem("Tiere");
parent->appendRow(new QStandardItem("Hund"));
parent->appendRow(new QStandardItem("Katze"));
model->appendRow(parent);
return model;
void XQMainWindow::setChildTabByName( const QString& key )
{
for( int i=0; i<_documentStore.size(); ++i )
{
if( key == _documentStore[i].friendlyName)
{
_tabWidget->setCurrentIndex(i);
return;
}
}
}
void XQMainWindow::loadDocumentQML( const QString& fileName )
@@ -319,8 +352,6 @@ void XQMainWindow::loadDocumentQML( const QString& fileName )
// das als Namen verwendet wird.
const QString& fName = contentRoot->friendly_name();
QStandardItemModel* model = createModel();
// Ein neues Child-Model erzeugen
XQChildModel* childModel = new XQChildModel(this);
// die Modelstruktur anlegen
@@ -331,13 +362,12 @@ void XQMainWindow::loadDocumentQML( const QString& fileName )
XQQuickWidget* quickChild = new XQQuickWidget(_tabWidget);
//quickChild->setResizeMode(QQuickWidget::SizeViewToRootObject);
quickChild->rootContext()->setContextProperty("meinModel", childModel);
quickChild->setSource(QUrl(QStringLiteral("qrc:/quickview.qml")));
_tabWidget->addTab( quickChild, "Fitze!" );
quickChild->rootContext()->setContextProperty("xtrChildModel", childModel);
quickChild->setSource(QUrl("qrc:/xqtreeview.qml"));
_tabWidget->addTab( quickChild, "QML:"+fName );
_tabWidget->setCurrentWidget( quickChild );
quickChild->setResizeMode(QQuickWidget::SizeRootObjectToView);
}
//! liest eine XML datei namens 'fileName'
@@ -369,13 +399,13 @@ void XQMainWindow::loadDocument( const QString& fileName )
// '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 );
QString pTabTitle = 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->addTab( childTreeView, pTabTitle );
_tabWidget->setCurrentWidget( childTreeView );
setWindowTitle( pTitle );
setWindowTitle( pTabTitle );
// Ein neues Child-Model erzeugen
XQChildModel* childModel = new XQChildModel(this);
@@ -390,8 +420,8 @@ void XQMainWindow::loadDocument( const QString& fileName )
childModel->setTreeTable(childTreeView);
// neuen eintrag im übsichts-baum erzeugen
_currentProjectItem = _mainModelView.addProjectItem( contentRoot );
_documentStore.addDocument( fileName, pTitle, _currentProjectItem, childModel );
_currentProjectItem = _mainModel.addProjectItem( contentRoot );
_documentStore.addDocument( fileName, fName, _currentProjectItem, childModel );
// die Modelstruktur anlegen
childModel->initModel( c_ChildModelName );
@@ -409,7 +439,9 @@ void XQMainWindow::saveDocument( const QString& fileName )
{
XQNodeWriter nodeWriter;
int curIdx = _tabWidget->currentIndex();
XQNodePtr rootNode = _documentStore[curIdx].treeItem->contentNode();
//XQNodePtr rootNode = _documentStore[curIdx].treeItem->contentNode();
XQNodePtr rootNode = _documentStore[curIdx].viewModel->contentRootNode();
Q_ASSERT(rootNode);
nodeWriter.dumpTree( rootNode, fileName );
}

View File

@@ -35,6 +35,11 @@ public:
public slots:
virtual void onMyFirz(XQItem& item)
{
qDebug() << " --- myFirz: " << item.text();
}
void onUndo();
void onRedo();
@@ -46,30 +51,32 @@ public slots:
void onAbout();
void onExit();
void onTreeItemClicked(const QModelIndex& index );
void onTabClicked( int index );
void onTreeViewItemClicked( const XQItem& item );
void onTreeViewItemChanged( const XQItem& item );
void onChildViewTabClicked( int index );
//void onItemCreated( XQItem* item );
void onSectionCreated( const XQModelSection& section);
void onSectionToggled( const XQModelSection& section );
void setChildTabByName( const QString& key );
static void setupWorkingDir();
protected:
void setupWorkingDir();
// fixme implement
void showDocumnet( const QString& key ){}
void showDocument( const QString& key ){}
void loadDocument( const QString& fileName );
void loadDocumentQML( const QString& fileName );
void saveDocument( const QString& fileName );
QUndoStack _undoStack;
XQDocumentStore _documentStore;
XQMainModel _mainModelView;
XQMainModel _mainModel;
XQItem* _currentProjectItem{};
//XQChildModel* _currentChildModel{};
};

View File

@@ -116,6 +116,8 @@ XQItem::XQPrefixExponentMap XQItem::s_PrefixExponentMap
};
//! Default konstruktor, setzt einen ungültigen (dummy)
//! itemType.
XQItem::XQItem()
: XQItem{XQItemType::staticItemType()}
@@ -123,6 +125,9 @@ XQItem::XQItem()
}
//! Default konstruktor mit einem vorhandenen itemType.
XQItem::XQItem( XQItemType* itemType )
: QStandardItem{}
{
@@ -130,12 +135,21 @@ XQItem::XQItem( XQItemType* itemType )
}
XQItem::XQItem(XQItemType* itemType, const QString *content )
//! konstruiert ein daten-item mit zeiger auf 'unser' attribut
//! im übergeordneten content-node.
XQItem::XQItem(XQItemType* itemType, const QString* content )
: XQItem{ itemType }
{
setContent(content);
// hier setzen wir direkt ohne umwege den string pointer
QStandardItem::setData( QVariant::fromValue<const QString*>(content), XQItem::ContentRole );
}
XQItem::XQItem( XQItemType* itemType, const QString& content )
: XQItem{ itemType }
{
setText(content);
}
//! ruft den copy-konstruktor auf.
XQItem* XQItem::clone() const
@@ -147,21 +161,35 @@ XQItem* XQItem::clone() const
//! false für ein ungültiges item. 'ungültig' heisst hier, dass nur ein
//! mockup-itemtype gesetzt ist.
bool XQItem::isValid() const
bool XQItem::isValidX() const
{
XQItemType* dummyType = XQItemType::staticItemType();
return QStandardItem::data( XQItem::ItemTypeRole ).value<XQItemType*>() != dummyType;
}
bool XQItem::hasContentNode() const
{
if( column() == 0)
{
QVariant value = QStandardItem::data( XQItem::ContentNodeRole );
return !value.isNull();
}
// sonst: delegieren an den node-Besitzer
QModelIndex pIndex = model()->index( row(), 0 );
if( pIndex.isValid() )
{
XQItem& firstItem = xqItemFromIndex( pIndex );
return firstItem.hasContentNode();
}
}
//! 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");
return data( ContentNodeRole ).value<XQNodePtr>();
}
@@ -319,37 +347,23 @@ QString XQItem::rawText() const
//! 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
// macht jetzt das, was 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
//! 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.
//! Setzt den den content format-string. wird im itemType gespeichert.
void XQItem::setContentFormat(const QString& contentFormat)
{
@@ -357,7 +371,7 @@ void XQItem::setContentFormat(const QString& contentFormat)
}
//! gibt das read-only auswahl-model zurück (wenn dieses item als
//! Gibt das read-only auswahl-model zurück (wenn dieses item als
//! combobox gerendert wird). wird im itemType gespeichert.
QStandardItemModel* XQItem::fixedChoices() const
@@ -413,6 +427,30 @@ QString XQItem::dataRoleName(int role) const
return XQItem::fetchItemDataRoleName(role);
}
bool XQItem::hasContentPtr() const
{
return !QStandardItem::data( XQItem::ContentRole ).isNull();
}
//! Gibt den content()-String zurück, sofern vorhanden.
//! sonst: gibt der ihnalt der Qt::DisplayRole als fallback
//! zurück.
QString XQItem::contentFallBackText() const
{
if( hasContentPtr() )
{
const QString* contentPtr = QStandardItem::data( XQItem::ContentRole ).value<const QString*>();
if(contentPtr)
return *contentPtr;
}
// wenn wir keinen contentPtr haben, benutzen wir als fallback
// die basis-text() role
return QStandardItem::data( Qt::DisplayRole ).toString();
}
//! angespasste variante von qstandarditem::setData. geteilte attribute
//! werden vom xqitemtype geholt
@@ -438,33 +476,34 @@ QVariant XQItem::data(int role ) const
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 :
case XQItem::ContentRole:
{
if( itemType().renderStyle() == XQItem::FormattedStyle)//return "display:"+content();
return itemType().formatText( *this );
[[fallthrough]];
qDebug() << " --- data(XQItem::ContentRole) should NOT be called!";
return *QStandardItem::data( XQItem::ContentRole ).value<QString*>();
}
// EditRole & ContentRole sollen den 'rohen' inhalt unseres string-pointers
// auf den original inhalt im content node zurückgeben.
case Qt::EditRole :
case XQItem::ContentRole:
case Qt::EditRole :
{
// Zugriffe auf den text-inhalt geben den inhalt des string pointer
// auf ein feld in content-node wieder. Wenn kein content-node vorhanden
// ist (single-items), wird Qt::DisplayRole zurückgeliefert.
const QString* contentPtr = QStandardItem::data( XQItem::ContentRole ).value<const QString*>();
if(contentPtr)
return *contentPtr;
return contentFallBackText();
//[[fallthrough]];
}
static const QString s_dummyContent("-");
return s_dummyContent;
// DisplayRole gibt den formatierten inhalt wieder. die formatierung übernimmt
// der item type
case Qt::DisplayRole :
{
QString plainText = contentFallBackText();
if( renderStyle() == XQItem::FormattedStyle)
return XQItemType::formatToSI( plainText, unitType() );
return plainText;
}
case Qt::ToolTipRole:
@@ -479,16 +518,30 @@ QVariant XQItem::data(int role ) const
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 );
// Das Node-Besitzer-Item wohnt in der ersten Spalte,
// wenn wir also der Node-Besitzer item sind ...
if( column() == 0)
{
QVariant value = QStandardItem::data( XQItem::ContentNodeRole );
if( !value.isNull() )
return value;
// sonst: delegieren an den node-Besitzer
QModelIndex pIndex = model()->index( row(), 0 );
// das gibt immerhin was zurück, was auf nullptr getestet werden kann,
return QVariant::fromValue<XQNodePtr>(nullptr);
// diese variante erzieht uns zur verwendung von 'hasContentNode()'
// was ist besser ?
throw XQException( "ContentNode is nullptr!");
}
// sonst: delegieren an den node-Besitzer
QModelIndex pIndex = model()->index( row(), 0 );
if( pIndex.isValid())
{
XQItem& firstItem = xqItemFromIndex( pIndex );
return firstItem.data( XQItem::ContentNodeRole );
}
throw XQException( "Item has no valid index (yet)!");
}
case Qt::StatusTipRole:
@@ -537,7 +590,6 @@ void XQItem::setData(const QVariant& value, int role )
{
switch(role)
{
case RenderStyleRole :
case EditorTypeRole :
case UnitTypeRole:
@@ -557,30 +609,31 @@ void XQItem::setData(const QVariant& value, int role )
return;
}
// set the raw, unformatted data
case ContentRole:
case Qt::DisplayRole:
case Qt::EditRole:
case XQItem::ContentRole:
{
// string ptr setzen kann die basis.
break;
}
QVariant newValue;
if( itemType().renderStyle() == XQItem::FormattedStyle)
newValue = XQItemType::unFormatFromSI( value.toString() );
else
newValue = value;
case Qt::EditRole :
{
qDebug() << " --- setting EDITrole: " << value.toString();
break;
}
// fallback: wenns keinen content node gibt, dann nehmen wir
// das standardverfahren.
if( !hasContentPtr() )
return QStandardItem::setData( newValue, Qt::DisplayRole );
case Qt::DisplayRole :
{
// what will happen? value is a string ptr ?!
qDebug() << " --- setting DISPLAYrole: " << value.toString();
break;
// wir nehmen den string pointer
const QString* constContentPtr = QStandardItem::data( XQItem::ContentRole ).value<const QString*>();
// aua, aua, muss aber sein, weil sonst alle anderen consts nicht durchgehalten werden könnten
*const_cast<QString*>(constContentPtr) = newValue.toString();
return;
}
// alles andere wie gehabt
case ContentNodeRole:
case SheetNodeRole:
//case TypeKeyRole: not used
default:
break;
@@ -694,13 +747,10 @@ 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];
}
/// ---
/// ---
/// ---

View File

@@ -15,6 +15,7 @@
#ifndef XQITEM_H
#define XQITEM_H
#include <QtQmlIntegration>
#include <QVariant>
#include <QVector>
#include <QStandardItem>
@@ -35,6 +36,8 @@ class XQItemType;
class XQItem : public QStandardItem
{
QML_ELEMENT
friend class XQItemFactory;
public:
@@ -130,6 +133,7 @@ public:
XQItem();
XQItem( XQItemType* itemType );
XQItem( XQItemType* itemType, const QString* content );
XQItem( XQItemType* itemType, const QString& content );
virtual ~XQItem() = default;
@@ -137,14 +141,16 @@ public:
//! -- not used at the moment --
XQItem* clone() const override;
//!
bool isValid() const;
//! __fix Tested, ob ein itemtype vorhanden ist.
bool isValidX() const;
//! gibt den zu diesem item gehörigen datenknoten zurück
virtual XQNodePtr contentNode() const;
bool hasContentNode() const;
//! gibt den zu diesem item gehörigen datenknoten zurück
XQNodePtr contentNode() const;
virtual XQNodePtr sheetNode() const;
virtual void setSheetNode( const XQNodePtr& sheetNode );
XQNodePtr sheetNode() const;
void setSheetNode( const XQNodePtr& sheetNode );
XQItemType& itemType() const;
void setItemType( XQItemType* itemTypePtr );
@@ -159,9 +165,8 @@ public:
QString rawText() const;
// changed: gibt jetzt den pointer zurück.
QString* content() const;
QString contentKey() const;
void setContent( const QString* content );
//QString* content() const;
//void setContent( const QString* content );
//
// Convenience-Funktionen zum Memberzugriff, die Implementierung
@@ -238,6 +243,10 @@ protected:
XQItem(const XQItem& other) = default;
XQItem& operator=(const XQItem& other) = default;
bool hasContentPtr() const;
QString contentFallBackText() const;
// das ist protected, weil damit der content()-zugriff demoliert werden kann
void setContentNode(const XQNodePtr& contentNode );
using XQItemFlagMap = QMap<QString,int>;
@@ -259,9 +268,7 @@ protected:
};
Q_DECLARE_METATYPE(XQItem);
Q_DECLARE_METATYPE(XQItem::RenderStyle);
Q_DECLARE_METATYPE(XQItem::EditorType);
Q_DECLARE_METATYPE(XQItem::UnitType);

View File

@@ -28,6 +28,8 @@
#include <xqviewmodel.h>
//! firz
class XQItemEditorFactory : public QItemEditorFactory
{
public:
@@ -60,6 +62,7 @@ public:
};
//! firz
XQItemDelegate::XQItemDelegate( XQViewModel& modelView)
: _modelView{modelView}
@@ -69,6 +72,8 @@ XQItemDelegate::XQItemDelegate( XQViewModel& modelView)
}
//! firz
XQTreeTable* XQItemDelegate::treeTable() const
{
return _modelView.treeTable();
@@ -81,40 +86,40 @@ XQItem& XQItemDelegate::xqItemFromIndex( const QModelIndex& index ) const
}
//! firz
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 );
switch( item.renderStyle() )
{
case XQItem::HeaderStyle :
return drawHeaderStyle( painter, option, index );
case XQItem::ComboBoxStyle :
return drawComboBoxStyle( painter, option, index );
case XQItem::ComboBoxStyle :
return drawComboBoxStyle( painter, option, index );
case XQItem::HiddenStyle :
return;
case XQItem::HiddenStyle :
return;
//case XQItem::ProgressBarStyle :
// return drawProgressBarStyle( painter, option, index );
//case XQItem::ProgressBarStyle :
// return drawProgressBarStyle( painter, option, index );
default:
break;
} // switch
}
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
@@ -150,7 +155,10 @@ void XQItemDelegate::drawHeaderStyle(QPainter* painter, const QStyleOptionViewIt
}
}
void XQItemDelegate::drawProgressBarStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
//! firz
void XQItemDelegate::drawProgressBarStyle(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
int progress = index.data(XQItem::ContentRole ).toInt();
@@ -168,7 +176,10 @@ void XQItemDelegate::drawProgressBarStyle(QPainter *painter, const QStyleOptionV
}
void XQItemDelegate::drawComboBoxStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
//! firz
void XQItemDelegate::drawComboBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QWidget* srcWidget = qobject_cast<QWidget*>(option.styleObject);
@@ -197,6 +208,8 @@ void XQItemDelegate::drawComboBoxStyle(QPainter *painter, const QStyleOptionView
painter->restore();
}
//! firz
void XQItemDelegate::drawSpinBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
@@ -214,58 +227,82 @@ void XQItemDelegate::drawSpinBoxStyle(QPainter* painter, const QStyleOptionViewI
}
QSize XQItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
//! firz
QSize XQItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
return QStyledItemDelegate::sizeHint(option, index);
}
//! Erzeugt ein editor-widget, sofern ein gültiger content-Ptr vorhanden und ein editor-Type gesetzt ist.
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 )
XQItem& item = xqItemFromIndex(index);
XQItem::EditorType edType = item.editorType();
if( edType == XQItem::NoEditorType )
{
return editor;
qDebug() << "---- NO Content or NO EditorType";
return nullptr;
}
qDebug() << "---- ed type:" << XQItem::fetchEditorTypeToString( edType ) << ": " << edType;
//return QStyledItemDelegate::createEditor( parent, option, index );
return itemEditorFactory()->createEditor(edType, parent);
}
//! Füttert einen editor mit den model-daten
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;
}
XQItem::EditorType edType = item.editorType();
if( edType == XQItem::NoEditorType )
return;
default:
break;
switch( edType )
{
case XQItemType::ComboBoxType :
{
QComboBox* comboBox = qobject_cast<QComboBox*>(editor);
comboBox->setModel( item.fixedChoices());
comboBox->setCurrentText( item.data().toString() );
comboBox->showPopup();
return;
}
default:
// wir benutzen hier die DisplayRole wenn der Inhalt schon formatiert ist.
int role = item.renderStyle() == XQItem::FormattedStyle ? Qt::DisplayRole : Qt::EditRole;
QVariant value = index.data(role);
QByteArray userProp = editor->metaObject()->userProperty().name();
if (!userProp.isEmpty())
{
if (!value.isValid())
value = QVariant(editor->property(userProp).metaType());
editor->setProperty(userProp, value);
}
}
QStyledItemDelegate::setEditorData(editor, index);
}
void XQItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
//! Schreibt die daten aus dem editor ins model zurück
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);
@@ -280,6 +317,9 @@ void XQItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, co
QStyledItemDelegate::setModelData(editor, model, index);
}
//! firz
void XQItemDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
//qDebug() << " --- update Editor Geometry";

View File

@@ -37,19 +37,19 @@ public:
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;
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;
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;

View File

@@ -99,6 +99,7 @@ XQItemType* XQItemFactory::makeItemType(const XQNodePtr& sheetEntry )
return itemType;
}
//! sucht einen item typ aus der map mit 'vorgefertigen' itemtypen.
XQItemType* XQItemFactory::findItemTypeTemplate(const QString& key ) const
@@ -256,10 +257,6 @@ QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const
/// ------------------------------------------------
///
/*
XQItemList XQItemFactory::makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode )
{
@@ -304,7 +301,7 @@ XQItemList XQItemFactory::createGenericRow( const XQNodePtr& contentNode, const
//! erzeugt eine item-row.
XQItemList XQItemFactory::makeRow(CreationMode mode, const XQNodePtr& sheetNode, const XQNodePtr& contentNode, const QString& captionKey )
XQItemList XQItemFactory::makeRow(const XQNodePtr& sheetNode, const XQNodePtr& contentNode )
{
XQItemList list;
@@ -320,24 +317,23 @@ XQItemList XQItemFactory::makeRow(CreationMode mode, const XQNodePtr& sheetNode,
//
for( const auto& sheetEntry : sheetNode->children() )
list.append( makeItem( mode, sheetEntry, contentNode, captionKey ) );
list.append( makeItem( sheetEntry, contentNode ) );
Q_ASSERT(!list.empty());
// wir merken uns den original content node auch, aber
// im ersten Item.
// im ersten Item. Kann null sein, macht aber erstmal nix.
dynamic_cast<XQItem*>(list[0])->setContentNode(contentNode);
return list;
}
//! 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.
//! Erzeugt ein XQItem aus einer typ-beschreibung ('sheetNode') und einem daten-knoten ('contentNode').
//! Wenn der content node nicht gesetzt ist, wird stattdess das attribut 'Caption' aus der typ-beschreibung
//! verwendet: es handelt sich dann um ein header item
XQItem* XQItemFactory::makeItem(CreationMode mode, const XQNodePtr& sheetNode, const XQNodePtr& contentNode, const QString& captionKey )
XQItem* XQItemFactory::makeItem(const XQNodePtr& sheetNode, const XQNodePtr& contentNode )
{
// den itemtype des neuen items rausfinden
XQItemType* itemType = makeItemType(sheetNode); // throws
@@ -347,19 +343,10 @@ XQItem* XQItemFactory::makeItem(CreationMode mode, const XQNodePtr& sheetNode, c
// das ist Unterschied vom HeaderItem zum normalen Item: Der Titel kommt aus der Modelbeschreibung,
// sonst wird der content indirekt über den tag-name des sheetnode geholt
switch( mode )
{
case mHeader:
contentPtr = sheetNode->attribute_ptr(captionKey);
break;
case mData:
contentPtr = contentNode->attribute_ptr( sheetNode->tag_name() );
break;
case mSingle:
contentPtr = contentNode->attribute_ptr( captionKey );
}
if( !contentNode )
contentPtr = sheetNode->attribute_ptr(c_Caption);
else
contentPtr = contentNode->attribute_ptr( sheetNode->tag_name() );
XQItem* newItem = new XQItem( itemType, contentPtr);
@@ -371,3 +358,18 @@ XQItem* XQItemFactory::makeItem(CreationMode mode, const XQNodePtr& sheetNode, c
return newItem;
}
//! Erzeugt ein Item _ohne_ internen content node, sondern
XQItem* XQItemFactory::makeSingleItem( const XQNodePtr& sheetNode, const QString& caption )
{
// den itemtype des neuen items rausfinden
XQItemType* itemType = makeItemType(sheetNode); // throws
XQItem* newItem = new XQItem( itemType, caption);
// __fixme!
if( newItem->isCheckable() )
{
newItem->setCheckState( Qt::Checked );
}
return newItem;
}

View File

@@ -28,25 +28,14 @@ class XQItemFactory : public xsingleton<XQItemFactory>
public:
enum CreationMode
{
mHeader,
mData,
mSingle
};
void initItemFactory(const QString& modelSheetFileName );
XQNodePtr findModelSheet( const QString& modelName ) const;
//XQItemList makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode );
XQItemList makeRow( const XQNodePtr& sheetNode, const XQNodePtr& contentNode );
XQItem* makeSingleItem( const XQNodePtr& sheetNode, const QString& caption );
XQItemList makeRow( CreationMode mode, const XQNodePtr& sheetNode, const XQNodePtr& contentNode, const QString& captionKey=c_Caption );
// wozu ist das gut?
//XQItemList createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode );
void setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const;
void setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const;
XQItemType* makeItemType(const XQNodePtr& sheetEntry );
XQItemType* findItemTypeTemplate(const QString& key ) const;
@@ -56,7 +45,7 @@ protected:
bool isValid();
XQItem* makeItem( CreationMode mode, const XQNodePtr& sheetNode, const XQNodePtr& contentNode, const QString& captionKey );
XQItem* makeItem(const XQNodePtr& sheetNode, const XQNodePtr& contentNode );
// shortcuts
using ItemConfigFunc = std::function<void( XQItem* item, const QString& attrValue, XQNodePtr contentNode, XQNodePtr sheetNode )>;

View File

@@ -134,22 +134,9 @@ XQItemType* XQItemType::replaceAttribute( const QVariant& newValue, int role )
}
//! 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
QString XQItemType::formatToSI( const QString& valueTxt, XQItem::UnitType unitType )
{
if( valueTxt.isEmpty() )
@@ -180,18 +167,18 @@ QString XQItemType::formatToSI( const QString& valueTxt, XQItem::UnitType unitTy
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() );
QString unitStr = XQItem::fetchUnitTypeToString( unitType);
return QString("%1 %2%3").arg( strVal, strPrefix, unitStr );
}
//! entfernt die einheit aus einem formatierten string
QString XQItemType::unFormatFromSI(const QString& formText ) const
QString XQItemType::unFormatFromSI(const QString& formText )
{
QString input = formText.simplified();
const QString input = formText.simplified();
// #1: strip numeric part
if( input.isEmpty() )
return input;

View File

@@ -40,17 +40,14 @@ public:
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();
static QString formatToSI(const QString& rawText, XQItem::UnitType unitType );
static QString unFormatFromSI(const QString& valueText );
protected:

View File

@@ -15,6 +15,13 @@
#include <QDebug>
#include <QApplication>
#include <QMetaType>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QUrl>
#include <QQmlContext>
#include <xqchildmodel.h>
#include <xqquickwidget.h>
#include <xqmainwindow.h>
@@ -49,25 +56,64 @@ who is who:
*/
XQChildModel* createChildModel()
{
XQChildModel* myModel = new XQChildModel();
myModel->initModel( c_ChildModelName );
XQNodeFactory treeLoader;
// xml daten laden
XQNodePtr rawTree = treeLoader.load_tree( qPrintable(c_DocumentFileName1) );
// versteckten root node ignorieren
XQNodePtr contentRoot = rawTree->first_child();
myModel->addModelData( contentRoot->first_child() );
return myModel;
}
using namespace Qt::Literals::StringLiterals;
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");
//app.setStyle("WindowsVista");
XQMainWindow window;
window.show();
/*
QApplication app(argc, argv);
XQMainWindow::setupWorkingDir();
XQItemFactory::instance().initItemFactory( c_ModelSheetFileName );
XQChildModel* myModel = createChildModel();
qmlRegisterType< XQChildModel>("MyApp.Models", 1, 0, "MyChildModel");
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("myChildModel", myModel);
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreationFailed,
&app,
[]() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
qDebug() << " fitz!";
engine.load( QUrl(QStringLiteral("qrc:/dummyview.qml")) );
//engine.load( QUrl(QStringLiteral("qrc:/xqtableview.qml")) );
qDebug() << " hhakl!";
*/
return app.exec();
}

View File

@@ -31,7 +31,7 @@ void XQNodeStore::dumpList( const QString& title ) const
//! kostruktor. übergibt command-type und die aufrufende modelView.
XQCommand::XQCommand(CmdType cmdType, XQViewModel* modelView )
: _cmdType{ cmdType }, _model(modelView)
: _cmdType{ cmdType }, _viewModel(modelView)
{
}
@@ -66,7 +66,7 @@ void XQCommand::setCommandType( XQCommand::CmdType cmdType )
void XQCommand::redo()
{
_model->onCommandRedo( *this );
_viewModel->onCommandRedo( *this );
}
@@ -74,7 +74,7 @@ void XQCommand::redo()
void XQCommand::undo()
{
_model->onCommandUndo( *this );
_viewModel->onCommandUndo( *this );
}
@@ -121,7 +121,7 @@ void XQCommand::saveNodes( const QModelIndexList& list )
//! erzeugt einen string aus dem command-type, fürs debuggen.
QString XQCommand::toString()
QString XQCommand::toString() const
{
static QMap<CmdType,QString> s_CmdTypeMap

View File

@@ -80,13 +80,13 @@ public:
void redo() override;
void undo() override;
QString toString();
QString toString() const;
protected:
CmdType _cmdType{cmdInvalid};
XQViewModel* _model{}; // needed for redo() / undo()
QModelIndex _originIndex;
CmdType _cmdType{cmdInvalid};
XQViewModel* _viewModel{}; // needed for redo() / undo()
QModelIndex _originIndex;
/*

View File

@@ -12,7 +12,7 @@
***************************************************************************/
#include <xqmodelsectionlist.h>
#include <xqsectionmanager.h>
//! kontstruktor. übergibt den start-index und einen model-knoten mit der beschreibung
@@ -40,9 +40,9 @@ bool XQModelSection::isValid() const
return _modelIndex.isValid() && _sectionRootNode;
}
const QModelIndex& XQModelSection::modelIndex() const
QModelIndex XQModelSection::startIndex() const
{
return _modelIndex;
return _modelIndex.operator QModelIndex();
}
XQNodePtr XQModelSection::sectionRootNode() const
@@ -72,7 +72,7 @@ XQNodePtr XQModelSection::contentRootNode() const
return _contentRootNode;
}
void XQModelSection::setContentRootNode( const XQNodePtr contentRootNode )
void XQModelSection::setContentRootNode( const XQNodePtr contentRootNode ) const
{
_contentRootNode = contentRootNode;
}
@@ -80,7 +80,7 @@ void XQModelSection::setContentRootNode( const XQNodePtr contentRootNode )
//! gibt die zeile des start-index zurück.
int XQModelSection::XQModelSection::row() const
int XQModelSection::XQModelSection::firstRow() const
{
return _modelIndex.row();
}
@@ -104,89 +104,98 @@ XQItem& XQModelSection::XQModelSection::headerItem() const
//! testet, ob die unter 'sectionKey' eine gültige section vorhanden ist.
bool XQModelSectionList::hasValidSection(const QString& sectionKey) const
bool XQSectionManager::hasValidSection(const QString& sectionKey) const
{
if (!contains(sectionKey) )
if (!_sections.contains(sectionKey) )
return false;
return at(sectionKey).isValid();
return _sections.at(sectionKey).isValid();
}
//! gibt für einen model index die 'zuständige' section zurück.
const XQModelSection& XQModelSectionList::sectionFromIndex( const QModelIndex& index ) const
const XQModelSection& XQSectionManager::sectionByKey( const QString& sectionKey ) const
{
return sectionFromRow( index.row() );
if( hasValidSection( sectionKey ) )
return _sections.at(sectionKey);
static const XQModelSection s_DummySection;
return s_DummySection;
}
//! gibt für eine zeile die 'zuständige' section zurück: der bestand an section wird
//! nach der passenden section durchsucht.
const XQModelSection& XQModelSectionList::sectionFromRow(int itemRow ) const
const XQModelSection& XQSectionManager::sectionByRow(int itemRow ) const
{
int i = size() - 1;
int i = _sections.size() - 1;
for (; i >= 0; --i)
{
if ( at(i).modelIndex().row() < itemRow )
return at(i);
if ( _sections.at(i).startIndex().row() < itemRow )
return _sections.at(i);
}
static XQModelSection s_DummySection;
return s_DummySection;
}
//! ermittelt die erste zeile einer section.
int XQModelSectionList::firstRow(const QModelIndex& idx) const
const XQModelSection& XQSectionManager::createSection(const QString& sectionKey, const QModelIndex& modelIndex, XQNodePtr sheetNode)
{
return sectionFromRow(idx.row() ).row();
// 6. jetzt können wir auch die sction erzeugen
XQModelSection section(modelIndex, sheetNode );
_sections.addAtKey( sectionKey, section);
return sectionByKey(sectionKey);
}
//! ermittelt die zeile unterhalb des gegebenen modelindex,
//! zum einfügen neuer items ebendort.
int XQModelSectionList::lastRow(const QModelIndex& idx) const
/*
int XQSectionManager::lastRow(const QModelIndex& idx) const
{
return lastRow(sectionFromRow(idx.row()));
return lastRow(sectionByRow(idx.row()));
}
//! ermittelt die zeile unterhalb der gegebenen section,
//! zum einfügen neuer items ebendort.
*/
int XQModelSectionList::lastRow(const XQModelSection& section ) const
int XQSectionManager::lastRow(const XQModelSection& section ) const
{
//qDebug() << " -- last row in section: " << section.modelIndex.data().toString() << " --> " << section.modelIndex.row();
qDebug() << " -- last row in section: " << section.startIndex().data().toString() << " --> " << section.startIndex().row();
// row() der section unterhalb dieser
// __fix? index mit speichern?
int index = indexOf(section);
int index = _sections.indexOf(section);
if (index > -1)
{
// last section? return last row of model
if (index == size() - 1)
return section.modelIndex().model()->rowCount();// - 1;
if (index == _sections.size() - 1)
return section.startIndex().model()->rowCount() - 1;
// return row above the row of the next section -> last row of given section
return at(index+1).row();
return _sections.at(index+1).firstRow() - 1;
}
return -1;
}
XQSectionRange XQSectionManager::sectionRange(const XQModelSection& section ) const
{
qDebug() << " ---- Section RANGE: " << section.startIndex().row() << " -> " << lastRow(section);
return XQSectionRange{ section.startIndex().row(), lastRow(section) };
}
//! gibt alle sections aus, zum ankucken.
void XQModelSectionList::dump() const
void XQSectionManager::dump() const
{
qDebug() << " --- sections dump(): " <<size() << " entries.";
for( int i = 0; i<size(); ++i )
qDebug() << " --- sections dump(): " <<_sections.size() << " entries.";
for( int i = 0; i<_sections.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();
QModelIndex idx = _sections.at(i).startIndex();
qDebug() << " --- sections:" << i << "row: " << idx.row() << " keyOf(i): " << _sections.keyOf(i) << " indexData: "<< idx.data().toString() << " itemData: " << XQItem::xqItemFromIndex(idx).data(Qt::DisplayRole).toString();
}
}

View File

@@ -12,17 +12,18 @@
***************************************************************************/
#ifndef XQMODELSECTIONLIST_H
#define XQMODELSECTIONLIST_H
#ifndef XQSECTIONMANAGER_H
#define XQSECTIONMANAGER_H
#include <QPersistentModelIndex>
#include <xqmaptor.h>
#include <xqitem.h>
/**
* @brief Struct containing data for a header section
*/
//! Daten zur beschreibung einer 'sektion' des models.
class XQModelSection
{
@@ -35,13 +36,13 @@ public:
bool operator==(const XQModelSection& other) const;
bool isValid() const;
int row() const;
int firstRow() const;
const QModelIndex& modelIndex() const;
QModelIndex startIndex() const;
XQNodePtr sectionRootNode() const;
XQNodePtr sheetRootNode() const;
XQNodePtr contentRootNode() const;
void setContentRootNode( const XQNodePtr dataRootNode );
void setContentRootNode( const XQNodePtr dataRootNode ) const;
const QString& contentType() const;
XQItem& headerItem() const;
@@ -50,32 +51,42 @@ protected:
QPersistentModelIndex _modelIndex;
XQNodePtr _sectionRootNode{};
XQNodePtr _contentRootNode{};
mutable XQNodePtr _sectionRootNode{};
mutable XQNodePtr _contentRootNode{};
};
Q_DECLARE_METATYPE(XQModelSection)
/**
* @brief Maptor containing all header sections.
*/
//! Erste und letzte ziele einer XQModelSection
struct XQSectionRange
{
int firstRow{-1};
int lastRow{-1};
};
class XQModelSectionList : public XQMaptor<XQModelSection>
//! struktur, die alle sections enthält
class XQSectionManager
{
public:
bool hasValidSection(const QString& sectionKey) const;
const XQModelSection& sectionFromRow( int row ) const;
const XQModelSection& sectionFromIndex( const QModelIndex& index ) const;
const XQModelSection& sectionByKey( const QString& sectionKey ) const;
const XQModelSection& sectionByRow( int row ) const;
int firstRow(const QModelIndex& idx) const;
int lastRow(const QModelIndex& idx) const;
int lastRow(const XQModelSection& section) const;
const XQModelSection& createSection(const QString& sectionKey, const QModelIndex& modelIndex, XQNodePtr sheetNode);
int lastRow(const XQModelSection& section ) const;
XQSectionRange sectionRange(const XQModelSection &section) const;
void dump()const override;
void dump()const;
protected:
XQMaptor<XQModelSection> _sections;
};
#endif // XQMODELSECTIONLIST_H
#endif // XQSECTIONMANAGER_H

View File

@@ -35,18 +35,28 @@
void showItemList( const XQItemList& list)
{
for(const auto& entry : list )
qDebug() << " --- itemList: " << ((XQItem*)entry)->content();
qDebug() << " --- itemList: " << entry->text();
qDebug();
}
//! Konstruktur mit parent.
//! Konstruktor mit parent.
XQViewModel::XQViewModel( QObject* parent )
: QStandardItemModel{ parent }, _itemFactory{ XQItemFactory::instance() }
{
invisibleRootItem()->setData( "[rootItem]", Qt::DisplayRole );
setItemPrototype( new XQItem );
// auf änderungen kann in den unterklassen reagiert werden
connect(this, &QStandardItemModel::itemChanged, this, [this](QStandardItem *item)
{
XQItem* xqItem = static_cast<XQItem*>(item);
emit xqItemChanged( *xqItem );
});
//qRegisterMetaType<XQItem>("XQItem");
}
@@ -59,7 +69,14 @@ const XQItem& XQViewModel::xqRootItem()
// dynamisch über den ItemData Mechanismus wie in QStandardItem
return *static_cast<XQItem*>(invisibleRootItem());
}
//! Gibt den daten root node des models zurück.
XQNodePtr XQViewModel::contentRootNode()
{
return _contentRoot;
}
@@ -83,6 +100,16 @@ XQItem& XQViewModel::xqFirstItem(int row) const
return *static_cast<XQItem*>( QStandardItemModel::item(row) );
}
void XQViewModel::expandNewItem(const QModelIndex& index)
{
if( _treeTable )
{
// ... ausklappen...
_treeTable->expand( index );
// ... und markieren
_treeTable->setCurrentIndex( index );
}
}
//! initialisiert dieses model über den namen. Es wird hier
//! nur die strukur erzeugt, keine inhalte.
@@ -111,7 +138,7 @@ void XQViewModel::initModel(const QString& modelName)
const XQNodePtr header = sectionNode->find_child_by_tag_name( c_Header );
if( header )
{
XQItemList list = _itemFactory.makeRow( XQItemFactory::mHeader, header, nullptr );
XQItemList list = _itemFactory.makeRow( header, nullptr );
addSection(list, sectionNode );
}
}
@@ -138,9 +165,9 @@ void XQViewModel::addSection(const XQItemList& list, const XQNodePtr& sectionNod
// 5. das erzeugt dann auch valide indices
appendRow(list);
const QString &sectionKey = sectionNode->attribute(c_ContentType);
// 6. jetzt können wir auch die sction erzeugen
XQModelSection section(list[0]->index(), sectionNode );
_sections.addAtKey(sectionNode->attribute( c_ContentType), section);
const XQModelSection& section = _sections.createSection( sectionKey, list[0]->index(), sectionNode );
// ... und es der welt mitteilen.
emit sectionCreated( section );
@@ -148,6 +175,43 @@ void XQViewModel::addSection(const XQItemList& list, const XQNodePtr& sectionNod
}
//! SLOT, toggled die section mit dem 'sectionKey' (hier: contentType)
void XQViewModel::onToggleSection(const QString& sectionKey )
{
toggleSection( _sections.sectionByKey(sectionKey) );
}
//! toggled die gegebene model section.
void XQViewModel::toggleSection( const XQModelSection& section )
{
qDebug() << " --- toggleSection: " << section.contentType();
if( section.isValid() && _treeTable )
{
XQSectionRange pos = _sections.sectionRange(section);
//int fstRow = _sections.firstRow(index);
//int lstRow = _sections.lastRow(index);
//_treeTable->toggleRowsHidden(fstRow, lstRow);
// hier nicht!?
//emit sectionToggled(section);
}
}
/*
//! SLOT als weiterleitung vom SIGNAL itemchanged
void XQViewModel::onItemChanged(XQItem* item )
{
qDebug() << " --- BASE item changed: " << item->text();
}
*/
//! SLOT, der aufgerufen wird, wenn eine edit-action getriggert wurde.
void XQViewModel::onActionTriggered(QAction* action)
@@ -195,35 +259,10 @@ void XQViewModel::onActionTriggered(QAction* action)
}
/*
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 )
void XQViewModel::onCommandRedo( const XQCommand& command )
{
static MemCallMap redoCalls
{
@@ -249,45 +288,10 @@ void XQViewModel::onCommandRedo( XQCommand& command )
}
}
/*
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 )
void XQViewModel::onCommandUndo( const XQCommand& command )
{
qDebug() << " --- onCommandUndo: count: " << XQNode::s_Count;
@@ -319,7 +323,7 @@ void XQViewModel::onCommandUndo( XQCommand& command )
//! markierte knoten entfernen, 'command' enthält die liste
void XQViewModel::cmdCut( XQCommand& command )
void XQViewModel::cmdCut( const XQCommand& command )
{
// wir gehen rückwärts über alle gemerkten knoten ...
for (auto it = command.rbegin(); it != command.rend(); ++it)
@@ -340,19 +344,19 @@ void XQViewModel::cmdCut( XQCommand& command )
//! entfernte knoten wieder einfügen , 'command' enthält die liste
void XQViewModel::cmdCutUndo( XQCommand& command )
void XQViewModel::cmdCutUndo( const XQCommand& command )
{
// die anfangsposition
int itmPos = command.first().itemPos;
// die 'zuständige' section rausfinden
const XQModelSection& section = _sections.sectionFromRow( itmPos );
const XQModelSection& section = _sections.sectionByRow( 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.makeRow( XQItemFactory::mData, section.sheetRootNode(), savedNode );
XQItemList list = _itemFactory.makeRow( section.sheetRootNode(), savedNode );
XQItem& firstItem = *((XQItem*)list[0]);
qDebug() << " --- Cut Undo: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id << " count: " << entry.contentNode.use_count();
@@ -364,7 +368,7 @@ void XQViewModel::cmdCutUndo( XQCommand& command )
//! clipboard inhalte einfügen
void XQViewModel::cmdPaste( XQCommand& command )
void XQViewModel::cmdPaste( const XQCommand& command )
{
// selection holen ...
QItemSelectionModel* selectionModel = treeTable()->selectionModel();
@@ -379,7 +383,7 @@ void XQViewModel::cmdPaste( XQCommand& command )
int nodePos = item.contentNode()->own_pos()+1;
// die zugehörige section finden
const XQModelSection& section = _sections.sectionFromRow( insRow-1 );
const XQModelSection& section = _sections.sectionByRow( insRow-1 );
// wir pasten das clipboard
for (auto& entry : _clipBoard )
{
@@ -388,7 +392,7 @@ void XQViewModel::cmdPaste( XQCommand& command )
// ... diesen einfügen ...
newNode->add_me_at( nodePos );
// ... und damit eine frische item-row erzeugen
XQItemList list = _itemFactory.makeRow( XQItemFactory::mData, section.sheetRootNode(), newNode );
XQItemList list = _itemFactory.makeRow( section.sheetRootNode(), newNode );
insertRow( insRow, list );
// die neue item-row selektieren
const QModelIndex& selIdx = list[0]->index();
@@ -399,14 +403,16 @@ void XQViewModel::cmdPaste( XQCommand& command )
}
// unsere änderungen merken fürs 'undo'
command.saveNodes( selectionModel->selectedRows() );
/// fix_xx
const_cast<XQCommand&>(command).saveNodes( selectionModel->selectedRows() );
}
//! einfügen aus dem clipboard wieder rückgängig machen
void XQViewModel::cmdPasteUndo( XQCommand& command )
void XQViewModel::cmdPasteUndo( const XQCommand& command )
{
command.dumpList("Paste UNDO");
// wir gehen rückwärts über alle markieren knoten ...
@@ -427,7 +433,7 @@ void XQViewModel::cmdPasteUndo( XQCommand& command )
//! entfernen der selection ohne copy in clipboard.
void XQViewModel::cmdDelete( XQCommand& command )
void XQViewModel::cmdDelete( const XQCommand& command )
{
// wir gehen rückwärts über alle markieren knoten ...
for (auto it = command.rbegin(); it != command.rend(); ++it)
@@ -442,9 +448,9 @@ void XQViewModel::cmdDelete( XQCommand& command )
}
}
//! macht 'delete' wirder rückgängig.
//! macht 'delete' wieder rückgängig.
void XQViewModel::cmdDeleteUndo( XQCommand& command )
void XQViewModel::cmdDeleteUndo( const XQCommand& command )
{
}
@@ -452,66 +458,55 @@ void XQViewModel::cmdDeleteUndo( XQCommand& command )
//! legt eine neue, leere zeile an.
void XQViewModel::cmdNew( XQCommand& command )
void XQViewModel::cmdNew( const XQCommand& command )
{
// __fix
/*
const QModelIndex& origin = command.originIndex();
if( !origin.isValid() )
throw XQException("cmdNewRow failed: index not valid ");
XQItem* target = xqItemFromIndex( origin );
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() );
XQNodePtr node = target.contentNode();
// we create a new data node
XQNodePtr newNode = XQNode::make_node( node->tag_name(), node->tag_value() );
// store node in node->parent()
//node->add_before_me( newNode );
// store node also in 'command' to enable undo
const XQModelSection& section = _sections.sectionFromIndex( origin );
newNode->add_me_at( node->own_pos(), node->parent() );
// create new item row
XQItemList list = _itemFactory.createGenericRow( newNode, section.sheetRootNode );
// add it to the treeview ...
//...
const XQModelSection& section = _sections.sectionByRow( origin.row() );
// neue, leere zeile erzeugen ...
XQItemList list =_itemFactory.makeRow( section.sheetRootNode(), newNode );
// ... zur treeview hinzufügen ...
insertRow( origin.row(), list );
// ... editierbar machen ...
QModelIndex newIndex = list[0]->index();
treeTable()->setCurrentIndex( newIndex );
treeTable()->edit( newIndex );
// ,,, und fürs undo speichern
const_cast<XQCommand&>(command).saveNodes( {newIndex} );
// ... and make it ...
treeTable()->setCurrentIndex( list[0]->index() );
// ... editable
treeTable()->edit( list[0]->index() );
*/
}
//! entfernt die neu angelegte zeile.
void XQViewModel::cmdNewUndo( XQCommand& command )
void XQViewModel::cmdNewUndo( const XQCommand& command )
{
cmdDelete( command );
}
//! schaltet eine section sichtbar oder unsichtbar.
void XQViewModel::cmdToggleSection( XQCommand& command )
void XQViewModel::cmdToggleSection( const 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) );
toggleSection( _sections.sectionByRow(index.row()) );
}
//! git die treetable zurück
//! gibt die treetable zurück
XQTreeTable* XQViewModel::treeTable()
{
@@ -524,7 +519,7 @@ void XQViewModel::setTreeTable(XQTreeTable* mainView )
{
// store view for direct access: the maintree
_treeTable = mainView;
// connect myself as model to the mainview
// set myself as model to the mainview
_treeTable->setModel(this);
XQItemDelegate* delegate = new XQItemDelegate( *this );
_treeTable->setItemDelegate( delegate );

View File

@@ -19,9 +19,10 @@
#include <QMenu>
#include <QStandardItemModel>
#include <QAbstractItemView>
#include <QtQmlIntegration>
#include <xqsimpleclipboard.h>
#include <xqmodelsectionlist.h>
#include <xqsectionmanager.h>
#include <xqitemfactory.h>
#include <xqcontextmenu.h>
@@ -36,12 +37,15 @@ class XQCommand;
class XQViewModel : public QStandardItemModel
{
Q_OBJECT
QML_ELEMENT
public:
XQViewModel(QObject* parent = nullptr);
virtual ~XQViewModel() = default;
QHash<int, QByteArray> roleNames() const override;
XQTreeTable* treeTable();
virtual void setTreeTable( XQTreeTable* mainView );
@@ -50,78 +54,65 @@ public:
virtual void initModel( const QString& modelName);
void expandNewItem(const QModelIndex& index);
void toggleSection( const XQModelSection& section );
//little helpers
const XQItem& xqRootItem();
XQNodePtr contentRootNode();
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 );
virtual void cmdToggleSection( const XQCommand& command );
virtual void cmdCut( const XQCommand& command );
virtual void cmdCutUndo( const XQCommand& command );
virtual void cmdPaste( const XQCommand& command );
virtual void cmdPasteUndo( const XQCommand& command );
virtual void cmdDelete( const XQCommand& command );
virtual void cmdDeleteUndo( const XQCommand& command );
virtual void cmdNew( const XQCommand& command );
virtual void cmdNewUndo( const 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'
/*!
signals:
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 );
}
*/
void xqItemChanged( const XQItem& item );
void itemCreated( XQItem* newItem );
void sectionCreated( const XQModelSection& section );
void sectionToggled( const XQModelSection& section );
public slots:
virtual void onShowContextMenu(const QPoint& point);
virtual void onActionTriggered(QAction* action);
virtual void onToggleSection(const QString& sectionKey );
// 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 );
virtual void onCommandRedo( const XQCommand& command );
virtual void onCommandUndo( const XQCommand& command );
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 MemCall = void (XQViewModel::*)(const XQCommand&);
using MemCallMap = QMap<XQCommand::CmdType,MemCall>;
// das eine reference auf ein globales singleton
XQItemFactory& _itemFactory;
XQSimpleClipBoard _clipBoard;
XQModelSectionList _sections;
XQItemFactory& _itemFactory;
XQSimpleClipBoard _clipBoard;
XQSectionManager _sections;
XQTreeTable* _treeTable{};
XQTreeTable* _treeTable{};
//QAbstractItemView* _treeTable{};
QUndoStack* _undoStack{};
XQContextMenu* _contextMenu{};

View File

@@ -78,6 +78,7 @@ namespace znode
zweak_node _parent;
znode_list _children;
// functor, der auf pointer gleichheit prüft.
struct match_node
{
match_node( zbasic_node* match )
@@ -95,9 +96,11 @@ namespace znode
public:
//! shortcut auf std::make_shared...
static zshared_node make_node( str_cref arg1, str_cref arg2 = "" , zshared_cref parent = nullptr )
//! beachte: der eltern-knoten wird hier nicht gesetzt, der neue knoten
//! wird nirgends eingefügt.
static zshared_node make_node( str_cref arg1, str_cref arg2 = "" )
{
return std::make_shared<zbasic_node>( arg1, arg2, parent );
return std::make_shared<zbasic_node>( arg1, arg2 );
}
//! leerer konstruktor
@@ -136,7 +139,7 @@ namespace znode
zbasic_node(const zbasic_node&) = delete;
zbasic_node& operator=(const zbasic_node&) = delete;
// 'move' geht (shared_from_this bleibt gültig)
//! 'move' geht (shared_from_this bleibt gültig)
zbasic_node(zbasic_node&&) noexcept = default;
zbasic_node& operator=(zbasic_node&&) noexcept = default;
@@ -178,31 +181,31 @@ namespace znode
return _parent.lock();
}
//! gibt den nachfolge-knoten oder 'end()' zurück.
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())
if( parent() )
{
znode_list& childs = _parent->_children;
auto it = std::find( childs.begin(), childs.end(), this->shared_from_this() );
return *(it);
//return zshared_node( make_node("WTF?") );
return zshared_node();
}
throw std::runtime_error("sibling(): no parent node");
}
//! gibt den vector mit kind-knoten zurück
inline const znode_list& children() const
{
return _children;
}
//! testet, ob kinder vorhanden sind.
bool has_children() const
{
return !children().empty();
}
//! gibt das erste kind zurück
zshared_node first_child()
{
if(!children().empty())
@@ -210,6 +213,7 @@ namespace znode
return nullptr;
}
//! gibt das letzte kind oder nullptr zurück
zshared_node last_child()
{
if(!children().empty())
@@ -237,7 +241,6 @@ namespace znode
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);
@@ -250,10 +253,9 @@ namespace znode
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
//! fügt einen shared_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 )
{
@@ -266,18 +268,17 @@ namespace znode
{
throw std::runtime_error("add_me_at(offset,parent): no parent node");
}
}
//! findet die eigene position im eltern-knoten
int own_pos()
{
if( parent())
return parent()->child_pos( this->shared_from_this() );
return -1;
}
//int child_pos(zbasic_node* child)
//! findet die postion eines kind-knotens
int child_pos(const zshared_node& child)
{
//auto pos = std::find_if(children().begin(), children().end(), match_node(child) );
@@ -287,7 +288,7 @@ namespace znode
return -1;
}
//zshared_node unlink_child( zbasic_node* node )
//! findet die postion eines kind-knotens
zshared_node unlink_child( const zshared_node& node )
{
auto it = std::find(_children.begin(), _children.end(), node);
@@ -315,11 +316,10 @@ namespace znode
{
for( auto child : _children )
{
qDebug() << " --#- " << child->name() << " : " << child->has_attribute( attrkey, attrvalue );
if( child->has_attribute( attrkey, attrvalue ))
return child;
}
return zshared_node();
return nullptr;
}
//
@@ -330,7 +330,7 @@ namespace znode
if( child->tag_name() == tagname )
return child;
}
return zshared_node();
return nullptr;
}
zshared_node find_child_by_id( int id )
@@ -340,46 +340,7 @@ namespace znode
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;
return nullptr;
}
// find ...
@@ -392,22 +353,6 @@ namespace znode
};
class zbasic_node_walker
{
public:
virtual void begin()
{}
template<typename str_t>
void for_each_node( zbasic_node<str_t>* node );
virtual void end()
{}
};
} //namespace znode

View File

@@ -100,7 +100,7 @@ namespace znode
//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 );
zshared_node new_node = zbasic_node<str_t>::make_node( xml_node.name(), xml_node.child_value() );
parent->add_child( new_node );
if( !xml_node.attributes().empty() )

View File

@@ -73,6 +73,16 @@ public:
return _data.end();
}
auto begin() const
{
return _data.begin();
}
auto end() const
{
return _data.end();
}
inline int size() const
{
return (int) _data.size();
@@ -94,13 +104,11 @@ public:
return mapIndex().contains(key);
}
inline const XQMapIndex& mapIndex() const
{
return _index;
}
int indexOf( const QString& key ) const
{
return mapIndex().indexOf(key);
@@ -121,7 +129,6 @@ public:
return mapIndex().key( index );
}
T& operator[]( int index )
{
if( contains(index) )
@@ -129,7 +136,6 @@ public:
throw XQException("XQMaptor operator[ int index ]: out of range");
}
const T& operator[]( int index ) const
{
if ( contains(index) )
@@ -154,7 +160,6 @@ public:
return _data[ _index[key] ];
}
const T& operator[]( const QString& key ) const
{
if (key.isEmpty() || !contains(key))
@@ -162,7 +167,6 @@ public:
return _data[_index[key]];
}
T& at( const QString& key )
{
return (*this)[key];
@@ -179,7 +183,6 @@ public:
return _data.size()-1;
}
virtual void addAtIndex( int index, const T& item )
{
if(contains(index))
@@ -187,14 +190,12 @@ public:
_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 );
@@ -209,7 +210,6 @@ public:
}
}
bool addAlias( const QString& key, const QString& alias )
{
// look for 'original' key
@@ -227,20 +227,17 @@ public:
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 );
@@ -249,7 +246,6 @@ public:
return killEntry( (int) idx );
}
virtual bool killEntry( int index )
{
if( index >= this->_data.size() )
@@ -261,19 +257,16 @@ public:
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)
@@ -283,7 +276,6 @@ public:
return "--";
}
int replaceKey( const QString& oldkey, const QString& newkey )
{
int idx = indexOf( oldkey );

View File

@@ -31,7 +31,7 @@ void XQContextMenu::addAction(const QString& text, XQCommand::CmdType commandTyp
QAction* newAction = new QAction(text, this);
newAction->setData(commandType);
_actionMap[commandType] = newAction;
QWidget::addAction(newAction);
QMenu::addAction(newAction);
setActionEnabled( commandType, enabled );
}
@@ -53,7 +53,7 @@ void XQContextMenu::addAction(const QIcon& icon, const QString& text, XQCommand:
QAction* newAction = new QAction(icon, text, this);
newAction->setData(commandType);
_actionMap[commandType] = newAction;
QWidget::addAction(newAction);
QMenu::addAction(newAction);
setActionEnabled( commandType, enabled );
}

View File

@@ -14,7 +14,7 @@
#include <xqquickwidget.h>
XQQuickWidget::XQQuickWidget(QWidget *parent)
XQQuickWidget::XQQuickWidget(QWidget* parent)
: QQuickWidget(parent)
{

View File

@@ -23,7 +23,7 @@ class XQQuickWidget : public QQuickWidget
public:
XQQuickWidget(QWidget *parent = nullptr);
XQQuickWidget(QWidget* parent = nullptr);
};
#endif // XQQUICKWIDGET_H

View File

@@ -51,6 +51,12 @@ XQItem& XQTreeTable::xqItemFromIndex(const QModelIndex& index )
return modelView()->xqItemFromIndex( index );
}
void XQTreeTable::toggleRowsHidden( int fstRow, int lstRow )
{
bool hidden = isRowHidden( fstRow, rootIndex() );
for (int row = fstRow; row < lstRow; ++row )
setRowHidden( row, rootIndex(), !hidden );
}
//! override von 'currentChanged' (noch nicht implementiert)

View File

@@ -41,6 +41,8 @@ public:
XQViewModel* modelView();
XQItem& xqItemFromIndex(const QModelIndex& index );
void toggleRowsHidden(int fstRow, int lstRow );
protected:
void currentChanged(const QModelIndex& current, const QModelIndex& previous) override;

View File

@@ -1,7 +1,10 @@
QT += core gui widgets quick quickwidgets
# widgets-private
CONFIG += c++20
CONFIG += c++20 qmltypes
QML_IMPORT_NAME = org.sourceworx.qmlcomponents
QML_IMPORT_MAJOR_VERSION = 1
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
@@ -20,9 +23,9 @@ HEADERS += \
items/xqitemtype.h \
items/xqitemdelegate.h \
model/xqcommand.h \
model/xqmodelsectionlist.h \
model/xqnode.h \
model/xqnodewriter.h \
model/xqsectionmanager.h \
model/xqselectionmodel.h \
model/xqsimpleclipboard.h \
model/xqviewmodel.h \
@@ -58,9 +61,9 @@ SOURCES += \
items/xqitemdelegate.cpp \
main.cpp \
model/xqcommand.cpp \
model/xqmodelsectionlist.cpp \
model/xqnode.cpp \
model/xqnodewriter.cpp \
model/xqsectionmanager.cpp \
model/xqselectionmodel.cpp \
model/xqsimpleclipboard.cpp \
model/xqviewmodel.cpp \

View File

@@ -1,10 +1,14 @@
<RCC>
<qresource prefix="/">
<file alias="modeldata1.xtr">../xml/modeldata1.xtr</file>
<file alias="modeldata2.xtr">../xml/modeldata2.xtr</file>
<file alias="modeldata3.xtr">../xml/modeldata3.xtr</file>
<file alias="modelsheet.xml">../xml/modelsheets.xml</file>
<file alias="quickview.qml">../quick/quickview.qml</file>
</qresource>
</RCC>
<qresource prefix="/">
<file alias="modeldata1.xtr">../xml/modeldata1.xtr</file>
<file alias="modeldata2.xtr">../xml/modeldata2.xtr</file>
<file alias="modeldata3.xtr">../xml/modeldata3.xtr</file>
<file alias="modelsheet.xml">../xml/modelsheets.xml</file>
<file alias="xqtableview.qml">../qml/xqtableview.qml</file>
<file alias="HorizontalHeaderViewDelegate.qml">../qml/HorizontalHeaderViewDelegate.qml</file>
<file alias="XMain.qml">../qml/XMain.qml</file>
<file alias="VerticalHeaderViewDelegate.qml">../qml/VerticalHeaderViewDelegate.qml</file>
<file alias="dummyview.qml">../qml/dummyview.qml</file>
<file alias="xqtreeview.qml">../qml/xqtreeview.qml</file>
</qresource>
</RCC>

View File

@@ -7,18 +7,18 @@
-->
<ItemTypes>
<TreeParentType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsDropEnabled" Icon="DirIcon" />
<TreeSectionType RenderStyle="PlainStyle" ItemFlags="IsEnabled" Icon="DesktopIcon"/>
<TreeChildType RenderStyle="PlainStyle" ItemFlags="IsUserCheckable|IsEnabled" Icon="MediaPlay"/>
<HeaderType RenderStyle="HeaderStyle" ItemFlags="IsEnabled"/>
<TreeParentType RenderStyle="PlainStyle" EditorType="LineEditType" ItemFlags="IsEnabled|IsDropEnabled" Icon="DirIcon" />
<TreeChildType RenderStyle="PlainStyle" EditorType="LineEditType" ItemFlags="IsEnabled" Icon="MediaPlay"/>
<TreeSectionType RenderStyle="PlainStyle" EditorType="LineEditType" ItemFlags="IsUserCheckable|IsEnabled" Icon="DesktopIcon"/>
<HeaderType RenderStyle="HeaderStyle" EditorType="LineEditType" 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"/>
<PlainType RenderStyle="PlainStyle" EditorType="LineEditType" ItemFlags="IsEnabled|IsEditable|IsSelectable"/>
<ValueType RenderStyle="FormattedStyle" EditorType="LineEditType" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="Coulomb"/>
<CheckableType RenderStyle="FormattedStyle" EditorType="LineEditType" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="###"/>
<PercentageType RenderStyle="ProgressBarStyle" EditorType="LineEditType" ItemFlags="IsEnabled|IsSelectable"/>
<ChoiceType RenderStyle="ComboBoxStyle" EditorType="ComboBoxType" ItemFlags="IsEnabled|IsSelectable|IsEditable" FixedChoices="la|le|lo|lu"/>
<IntValueType RenderStyle="SpinBoxStyle" EditorType="SpinBoxType" ItemFlags="IsEnabled|IsSelectable"/>
</ItemTypes>
@@ -75,7 +75,7 @@
<!-- '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"/>
<Manufacturer ItemType="PlainType"/>
<!-- '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"/>
@@ -98,20 +98,20 @@
<Weight Caption="Weight" ItemType="HeaderType" />
</Header>
<ModelSheet>
<InverterID Caption="Inverter" ItemType="ValueType" />
<InverterName Caption="Name" ItemType="ValueType" />
<Manufacturer Caption="Manufacturer" ItemType="ValueType" />
<InverterID Caption="Inverter" ItemType="PlainType" />
<InverterName Caption="Name" ItemType="PlainType" />
<Manufacturer Caption="Manufacturer" ItemType="PlainType" />
<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" />
<NumStrings Caption="Strings" ItemType="PlainType" />
<Weight Caption="Weight" ItemType="ValueType" UnitType="kg"/>
</ModelSheet>
</Section>
<Section ContentType="Battery" >
<Header>
<BatteryID Caption="Name" ItemType="HeaderType" />
<BatteryName Caption="Battery" ItemType="HeaderType" />
<BatteryID Caption="Battery" ItemType="HeaderType" />
<BatteryName Caption="Name" ItemType="HeaderType" />
<Manufacturer Caption="Manufacturer" ItemType="HeaderType" />
<Capacity Caption="Capacity" ItemType="HeaderType"/>
<Yield Caption="Yield" ItemType="HeaderType" />
@@ -119,9 +119,9 @@
<MaxVolt Caption="max. Volt" ItemType="HeaderType" />
</Header>
<ModelSheet>
<BatteryID Caption="Battery" ItemType="ValueType" />
<BatteryName Caption="Name" ItemType="ValueType" />
<Manufacturer Caption="Manufacturer" ItemType="ValueType" />
<BatteryID Caption="Battery" ItemType="PlainType" />
<BatteryName Caption="Name" ItemType="PlainType" />
<Manufacturer Caption="Manufacturer" ItemType="PlainType" />
<Capacity Caption="Capacity" ItemType="ValueType" UnitType="Wh"/>
<Yield Caption="Yield" ItemType="ValueType" ItemType="PercentageType" UnitType="%"/>
<MaxCurrent Caption="max. Current" ItemType="ValueType" UnitType="A"/>

View File

@@ -1,27 +1,24 @@
<?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>
<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="maa" 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="moo" 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>