first reCommit

This commit is contained in:
2025-08-13 18:30:47 +02:00
commit a946c7dd58
73 changed files with 23368 additions and 0 deletions

153
application/xqappdata.cpp Normal file
View File

@@ -0,0 +1,153 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#include <xqappdata.h>
#include <QDebug>
#include <QApplication>
#include <QStyle>
#include <QIcon>
#include <QMap>
#include <QMetaEnum>
#include <QPushButton>
namespace XQAppData
{
template<typename E>
constexpr auto to_underlying(E e) noexcept
{
return static_cast<std::underlying_type_t<E>>(e);
}
class XQAppIconMap : public QMap<QString,QIcon>
{
public:
void init()
{
auto from = to_underlying(QIcon::ThemeIcon::AddressBookNew);
auto to = to_underlying(QIcon::ThemeIcon::NThemeIcons);
for (auto i = from; i < to; ++i)
{
QIcon::ThemeIcon f = static_cast<QIcon::ThemeIcon>(i);
QIcon icon = QIcon::fromTheme(f);
// Nur hinzufügen, wenn das Icon existiert
if (!icon.isNull())
insert(icon.name(), icon);
}
}
};
static XQAppIconMap s_IconMap;
bool hasTypeIcon(const QString& key )
{
if(s_IconMap.isEmpty())
s_IconMap.init();
return !key.isEmpty() && s_IconMap.contains(key);
}
QIcon typeIcon(const QString& key )
{
if( hasTypeIcon(key) )
return s_IconMap[key];
return QApplication::style()->standardIcon(QStyle::SP_TrashIcon);
}
/*
{ "icnFolder" , QApplication::style()->standardIcon(QStyle::SP_DirIcon) },
{ "icnFolder" , QApplication::style()->standardIcon(QStyle::SP_DirIcon)},
{ "icn02Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogBack)},
{ "icn03Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogContentsView)},
{ "icn04Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogDetailedView)},
{ "icn05Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogEnd)},
{ "icn06Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogInfoView)},
{ "icn07Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogListView)},
{ "icn08Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogNewFolder)},
{ "icn09Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogStart)},
{ "icn10Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogToParent)},
{ "icn11Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowBack)},
{ "icn12Dummy", QApplication::style()->standardIcon(QStyle::SP_DirIcon)},
{ "icn13Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSkipBackward)},
{ "icn14Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowDown)},
{ "icn15Dummy", QApplication::style()->standardIcon(QStyle::SP_DirLinkIcon)},
{ "icn16Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSkipForward)},
{ "icn17Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowForward)},
{ "icn18Dummy", QApplication::style()->standardIcon(QStyle::SP_DirOpenIcon)},
{ "icn19Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaStop)},
{ "icn20Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowLeft)},
{ "icn21Dummy", QApplication::style()->standardIcon(QStyle::SP_DockWidgetCloseButton)},
{ "icn22Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaVolume)},
{ "icn23Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowRight)},
{ "icn24Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveCDIcon)},
{ "icn25Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaVolumeMuted)},
{ "icn26Dummy", QApplication::style()->standardIcon(QStyle::SP_ArrowUp)},
{ "icn27Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveDVDIcon)},
{ "icn28Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical)},
{ "icn29Dummy", QApplication::style()->standardIcon(QStyle::SP_BrowserReload)},
{ "icn30Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveFDIcon)},
{ "icn31Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation)},
{ "icn32Dummy", QApplication::style()->standardIcon(QStyle::SP_BrowserStop)},
{ "icn33Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveHDIcon)},
{ "icn34Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion)},
{ "icn35Dummy", QApplication::style()->standardIcon(QStyle::SP_CommandLink)},
{ "icn36Dummy", QApplication::style()->standardIcon(QStyle::SP_DriveNetIcon)},
{ "icn37Dummy", QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning)},
{ "icn38Dummy", QApplication::style()->standardIcon(QStyle::SP_ComputerIcon)},
{ "icn39Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogBack)},
{ "icn40Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarCloseButton)},
{ "icn41Dummy", QApplication::style()->standardIcon(QStyle::SP_CustomBase)},
{ "icn42Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogContentsView)},
{ "icn43Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarContextHelpButton)},
{ "icn44Dummy", QApplication::style()->standardIcon(QStyle::SP_DesktopIcon)},
{ "icn45Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogDetailedView)},
{ "icn46Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarMaxButton)},
{ "icn47Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogApplyButton)},
{ "icn48Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogEnd)},
{ "icn49Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarMenuButton)},
{ "icn50Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogCancelButton)},
{ "icn51Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogInfoView)},
{ "icn52Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarMinButton)},
{ "icn53Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogCloseButton)},
{ "icn54Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogListView)},
{ "icn55Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarNormalButton)},
{ "icn56Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogDiscardButton)},
{ "icn57Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogNewFolder)},
{ "icn58Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarShadeButton)},
{ "icn59Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogHelpButton)},
{ "icn60Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogStart)},
{ "icn61Dummy", QApplication::style()->standardIcon(QStyle::SP_TitleBarUnshadeButton)},
{ "icn62Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogNoButton)},
{ "icn63Dummy", QApplication::style()->standardIcon(QStyle::SP_FileDialogToParent)},
{ "icn64Dummy", QApplication::style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton)},
{ "icn65Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogOkButton)},
{ "icn66Dummy", QApplication::style()->standardIcon(QStyle::SP_FileIcon)},
{ "icn67Dummy", QApplication::style()->standardIcon(QStyle::SP_ToolBarVerticalExtensionButton)},
{ "icn68Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogResetButton)},
{ "icn70Dummy", QApplication::style()->standardIcon(QStyle::SP_FileLinkIcon)},
{ "icn71Dummy", QApplication::style()->standardIcon(QStyle::SP_TrashIcon)},
{ "icn72Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogSaveButton)},
{ "icn73Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaPause)},
{ "icn74Dummy", QApplication::style()->standardIcon(QStyle::SP_VistaShield)},
{ "icn75Dummy", QApplication::style()->standardIcon(QStyle::SP_DialogYesButton)},
{ "icn76Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaPlay)},
{ "icn77Dummy", QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon)},
{ "icn79Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSeekBackward)},
{ "icn80Dummy", QApplication::style()->standardIcon(QStyle::SP_DirHomeIcon)},
{ "icn81Dummy", QApplication::style()->standardIcon(QStyle::SP_MediaSeekForward)}
}
*/
}; // namespace XQAppData

49
application/xqappdata.h Normal file
View File

@@ -0,0 +1,49 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#ifndef XQAPPDATA_H
#define XQAPPDATA_H
#include <qnamespace.h>
#include <QVariant>
#include <QMap>
#include <QStringView>
#include <QIcon>
#include <pugixml.hpp>
const QString c_Version = "0.1.1 04.09.2024";
const QString c_MainModelName = "DocumentTreeModel";
const QString c_ChildModelName = "DocumentDetailsModel";
const QString c_ProjectID = "ProjectID";
const QString c_ModelSheetFileName = "xml/modelsheets.xml";
const QString c_ModelDummyFileName = "xml/saved_testfile.xtr";
const QString c_DocumentDirectory = "xml/";
const QString c_DocumentFileName1 = "xml/modeldata1.xtr";
const QString c_DocumentFileName2 = "xml/modeldata2.xtr";
const QString c_DocumentFileName3 = "xml/modeldata3.xtr";
const QString c_FriendlyName = "FriendlyName";
namespace XQAppData
{
class XQAppIconMap;
bool hasTypeIcon(const QString& key );
QIcon typeIcon(const QString& key );
}
#endif // XQAPPDATA_H

View File

@@ -0,0 +1,155 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#include <znode_factory.h>
#include <xqchildmodel.h>
#include <xqselectionmodel.h>
#include <xqitemdelegate.h>
#include <xqappdata.h>
#include <xqtreeview.h>
#include <xqitemfactory.h>
XQChildModel::XQChildModel( QObject *parent )
: XQModel{parent}
{
}
XQChildModel::~XQChildModel()
{
}
/**
* @brief XQChildModel::initModel: Create the own modelstructure
* using subtree 'Components'
*/
void XQChildModel::initModel(const QString& modelName)
{
// #0: Wir suchen die Model-Beschreibung
XQNodePtr modelSheet = _itemFactory.findModelSheet( modelName ); // throws
// #1: Wie erzeugen die Model-Struktur: Jedes Kind beschreibt einen
// XML-Datentyp, z.B. <Panel atr1="..." />, <Battery .../>
// Jeder XML-Knoten entspricht einer Zeile im späteren Model, jedes
// Attribut wird einem eigenen Feld (XQItem) abgebildet.
for( auto& sheetNode : modelSheet->children() )
{
XQItemList list;
// Die Kinder des Knotens beschreiben die einzelnen
// Attribute des XML-Datenknotens
for( const auto& attrNode : sheetNode->children() )
{
// ??
//if(attrNode->has_children() )
// continue;
XQItem* headerItem = _itemFactory.makeHeaderItem( attrNode );
list.append( headerItem );
}
// für jeden XML-Knotentyp erzeugen wir eine section
addSection(list, sheetNode );
/*
// empty row
XQNodePtr contentNode = XQNode::make_node( sheetNode->tag_name() );
XQItemList emptyRow = _itemFactory.createEmptyRow( contentNode, sheetNode );
appendRow( emptyRow );
*/
} // for
}
void XQChildModel::setContent( const XQNodePtr& contentRoot )
{
// __fix: set object name ??
qDebug() << " --- create Model Data: " << contentRoot->to_string();
// Die Datenbasis als shared_ptr sichern
_contentRoot = contentRoot;
// Wir gehen über alle Einträge, die verschiedenen Typen
// haben, hier: <Panel>. <Battery> ...
for (const auto& contentEntry : _contentRoot->children())
{
// Das ist hier der Typ des Eintrags: Panel, Battery ...
QString key = contentEntry->tag_name();
// 'silent failure' hier der Datenbaum kann auch Knoten enthalten
// die nicht für uns gedacht sind.
if (!_sections.hasValidSection(key))
continue;
const XQModelSection& section = _sections.at( key );
int newRow = _sections.lastRow(section);
qDebug() << " --- AHJA: " << key << " -- last Row dazu: " << newRow;
XQItemList list = _itemFactory.createDataRow( contentEntry, section.sheetRootNode );
//section.headerItem().appendRow( list );
insertRow( newRow, list);
} // for
}
void XQChildModel::createModelContentChildRow( QStandardItem* parent, XQNodePtr contentNode )
{
/*
parent->appendRow( { new XQItem("Optionals", XQItemType::HeaderStyle ), new XQItem( "Value", XQItemType::HeaderStyle )} );
for( auto& child : contentNode->children() )
{
XQItemList list;
list.append( new XQItem( child->attribute("DataItem"), XQItemType::StaticStyle ) );
list.append( new XQItem( child->attribute("DataValue"), XQItemType::StaticStyle ) );
parent->appendRow( list );
}
*/
}
void XQChildModel::initContextMenu()
{
// __fixme! add a menu title
_contextMenu->clear();
const QModelIndex& curIdx = _treeView->currentIndex();
bool hasSel = curIdx.isValid() && _treeView->selectionModel()->hasSelection();
bool canPaste = _clipBoard.canPaste( curIdx );
_contextMenu->addAction( "icn11Dummy", "Undo", XQCommand::cmdUndo, _undoStack->canUndo() );
_contextMenu->addAction( "icn17Dummy", "Redo", XQCommand::cmdRedo, _undoStack->canRedo() );
_contextMenu->addAction( "icn58Dummy", "Cut", XQCommand::cmdCut, hasSel );
_contextMenu->addAction( "icn61Dummy", "Paste", XQCommand::cmdPaste, canPaste );
_contextMenu->addAction( "icn55Dummy", "Copy", XQCommand::cmdCopy, hasSel );
//_contextMenu->addAction( "icn35Dummy", "Move", XQCommand::cmdMove, hasSel );
_contextMenu->addAction( "icn70Dummy", "New", XQCommand::cmdNew, hasSel );
_contextMenu->addAction( "icn50Dummy", "Delete", XQCommand::cmdDelete, hasSel );
// __fixme! set 'toggle section <name>' entry
//contextMenu.actions().first()->setText("<name>");
_contextMenu->addAction( "icn29Dummy", "Toggle Section", XQCommand::cmdToggleSection, hasSel);
}

View File

@@ -0,0 +1,44 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#ifndef XQCHILDMODEL_H
#define XQCHILDMODEL_H
#include <xqmodel.h>
class XQChildModel : public XQModel
{
Q_OBJECT
public:
explicit XQChildModel(QObject *parent = nullptr);
virtual ~XQChildModel();
void initModel(const QString& modelName) override;
void setContent(const XQNodePtr& contentRoot );
protected:
virtual void createModelContentChildRow(QStandardItem* parent, XQNodePtr contentNode );
//void setupViewProperties() override;
void initContextMenu() override;
};
#endif // XQCHILDMODEL_H

View File

@@ -0,0 +1,58 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#include <xqdocumentstore.h>
#include <xqitem.h>
#include <QFile>
XQDocument::XQDocument(const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQModel* aModelView )
: fileName{ aFileName }, friendlyName{ aFriendlyName }, treeItem{ aTreeItem }, modelView{ aModelView }
{
}
XQDocument::~XQDocument()
{
//delete _documentRoot;
}
///
/// ---
///
XQDocumentStore::~XQDocumentStore()
{
//for (auto entry : *this)
// delete entry;
//for( int i=0; i<size();++i)
// delete at(i);
}
void XQDocumentStore::addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQModel* aModelView )
{
//qDebug() << " --- addDoc: " << aDocumentRoot->friendly_name() << " : " << aDocumentRoot->attribute(c_ProjectID);
XQDocument newDocument( aFileName, aFriendlyName, aTreeItem,aModelView );
addAtKey( aFileName, newDocument );
// attention: this assumes the presence of the 'ProjectID' value
addAlias( aFileName, aTreeItem->attribute(c_ProjectID) );
}

View File

@@ -0,0 +1,59 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#ifndef XQDOCUMENTSTORE_H
#define XQDOCUMENTSTORE_H
#include <xqmaptor.h>
#include <xqnode.h>
class XQModel;
class XQItem;
// should this be internal??
struct XQDocument
{
XQDocument() = default;
XQDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQModel* aModelView );
virtual ~XQDocument();
QString fileName; // also used as key
QString friendlyName;
XQItem* treeItem{};
XQModel* modelView{};
};
class XQDocumentStore : public XQMaptor<XQDocument>
{
public:
XQDocumentStore() = default;
virtual ~ XQDocumentStore();
void addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQModel* aModelView );
protected:
//?? needed?
//XQNodePtr _treeRootNode;//{ "treeRootNode" };
XQNode _treeRootNode{ "treeRootNode" };
};
#endif // XQDOCUMENTSTORE_H

View File

@@ -0,0 +1,87 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#include <QPersistentModelIndex>
#include <QClipboard>
#include <xqmainmodel.h>
#include <xqexception.h>
#include <xqtreeview.h>
#include <xqitemdelegate.h>
#include <xqitem.h>
#include <xqappdata.h>
#include <xqselectionmodel.h>
#include <xqitemfactory.h>
XQMainModel::XQMainModel(QObject *parent )
: XQModel{parent}
{
}
XQMainModel::~XQMainModel()
{
// delete
}
void XQMainModel::initModel(const QString& modelName)
{
XQNodePtr modelSheet = _itemFactory.findModelSheet( modelName );
// #1: create structure: create static sections for this model
for( auto& sheetNode : modelSheet->children() )
{
qDebug() << " create main model: " << sheetNode->tag_name();
XQItemList list = { _itemFactory.makeHeaderItem( sheetNode ) };
/*
Q_ASSERT(!list.isEmpty());
//addSection(list, sheetNode );
*/
appendRow( list );
}
}
XQItem* XQMainModel::createTreeEntry( XQNodePtr contentNode )
{
/*
for(const auto& section : _sections )
{
if( contentNode->attribute("State") == section.sheetRootNode->attribute("State") )
{
XQItem* entry = _itemFactory.createTreeItem( contentNode, section.sheetRootNode );
section.headerItem().appendRow( entry );
_treeView->expand( section.modelIndex );
// ??
_treeView->setCurrentIndex( section.modelIndex );
//emit xqItemCreated( entry );
return entry;
}
}
*/
return nullptr;
}
void XQMainModel::initContextMenu()
{
}

47
application/xqmainmodel.h Normal file
View File

@@ -0,0 +1,47 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#ifndef XQMAINMODEL_H
#define XQMAINMODEL_H
//#include <QItemSelectionModel>
#include <xqmodel.h>
//#include <xqmodelsections.h>
class XQTreeView;
class XQMainModel : public XQModel
{
Q_OBJECT
public:
explicit XQMainModel(QObject *parent = nullptr);
virtual ~XQMainModel();
void initModel(const QString& modelName) override;
XQItem* createTreeEntry( XQNodePtr contentNode );
public slots:
protected:
void initContextMenu() override;
};
#endif // XQMAINMODEL_H

View File

@@ -0,0 +1,266 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#include <QDebug>
#include <QFileDialog>
#include <QMessageBox>
#include <xqmainwindow.h>
#include <xqcommand.h>
#include <xqexception.h>
#include <xqitemfactory.h>
#include <xqnodewriter.h>
XQMainWindow::XQMainWindow( QWidget* parent )
: QMainWindow(parent)
{
setupUi(this);
setWindowTitle( QString("XTree %1").arg(c_Version));
initMainWindow();
}
void XQMainWindow::initMainWindow()
{
qDebug() << " --- initMainWindow(): here we go!";
// als allererstes laden wir die Modelschreibungen
XQItemFactory::instance().initItemFactory( c_ModelSheetFileName );
_undoView->setStack( &_undoStack );
_actionUndo->setData( XQCommand::cmdUndo);
_actionRedo->setData( XQCommand::cmdRedo);
_actionCut->setData( XQCommand::cmdCut);
_actionCopy->setData( XQCommand::cmdCopy);
_actionPaste->setData( XQCommand::cmdPaste);
_actionNew->setData( XQCommand::cmdNew);
_actionDelete->setData( XQCommand::cmdDelete);
connect( _actionOpen, &QAction::triggered, this, &XQMainWindow::onOpenDocument );
connect( _actionSave, &QAction::triggered, this, &XQMainWindow::onSaveDocument );
connect( _actionSaveAs, &QAction::triggered, this, &XQMainWindow::onSaveDocumentAs );
connect( _actionExit, &QAction::triggered, this, &XQMainWindow::onExit );
connect( _actionAbout, &QAction::triggered, this, &XQMainWindow::onAbout );
//connect( _mainTreeView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onDoubleClicked(QModelIndex)) );
connect( _mainTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onTreeItemClicked(QModelIndex)) );
connect( _tabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(onTabClicked(int)) );
connect( &_mainModelView, &XQModel::xqItemCreated, this, [=, this](XQItem* item)
{
// when a new main tree item has been created ...
QString pID = item->contentNode()->attribute(c_ProjectID);
_mainTreeView->setCurrentIndex( item->index() );
// ... we set the current view to this node
if( _documentStore.contains( pID ) )
_tabWidget->setCurrentWidget( _documentStore[pID].modelView->treeView() );
} );
try
{
// hand over undostack
_mainModelView.setUndoStack(&_undoStack);
// hand over left side navigation tree
_mainModelView.setTreeView(_mainTreeView);
// #1. init the left side main tree view
_mainModelView.initModel( c_MainModelName );
// #2. load demo data
loadDocument( c_DocumentFileName1 );
//loadDocument( c_DocumentFileName2 );
qDebug() << " --- all here: " << XQNode::s_Count;
}
catch( XQException& exception )
{
qDebug() << exception.what();
QMessageBox::critical( this, "Failure", QString("Failure: %1").arg(exception.what()) );
}
}
void XQMainWindow::onCreateDocument()
{
qDebug() << " ---- create document Pressed!";
}
void XQMainWindow::onOpenDocument()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Project"), c_DocumentDirectory, tr("project data(*.xtr)") );
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::warning(this, "Warning", "Cannot load file: " + file.errorString());
return;
}
// close dummy file ...
file.close();
loadDocument( fileName );
}
void XQMainWindow::onSaveDocument()
{
qDebug() << " ---- save Pressed!";
saveDocument( c_ModelDummyFileName );
}
void XQMainWindow::onSaveDocumentAs()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save as", c_DocumentDirectory, tr("project data(*.xtr)") );
QFile file(fileName);
// open dummy file
if (!file.open(QFile::WriteOnly | QFile::Text))
{
QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString());
return;
}
// close dummy file ...
file.close();
// and create a xml stream
saveDocument( fileName );
}
void XQMainWindow::onCloseDocument()
{
qDebug() << " ---- close Pressed!";
}
void XQMainWindow::onExit()
{
qApp->exit();
}
void XQMainWindow::onAbout()
{
QMessageBox msgBox(QMessageBox::NoIcon, "About", "", QMessageBox::Ok);
QString text = "<b>xtree concept</b><br>";
text += "2024 c.holzheuer<br><br>";
text += "<a href=\"https://sourceworx.org/xtree\">sourceworx.org/xtree</a>";
msgBox.setTextFormat(Qt::RichText); // This allows you to click the link
msgBox.setText( text );
msgBox.exec();
}
// when item in the left tree is clicked, switch view on the right side
void XQMainWindow::onTreeItemClicked(const QModelIndex& index )
{
XQItem& entry = XQItem::xqItemFromIndex(index);
qDebug() << " --- mainWindow onTreeItemClicked:" << entry.text();
return;
//_mainTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
//entry->setBackground( QBrush( Qt::green ) );
QString key = entry.attribute(c_ProjectID);
if( _documentStore.contains(key) )
_tabWidget->setCurrentWidget( _documentStore[key].modelView->treeView() );
}
// when item in the left tree is clicked, switch view on the right side
void XQMainWindow::onTabClicked( int index )
{
const QString& key = _documentStore[index].treeItem->attribute( c_ProjectID );
qDebug() << " ---- tab clicked: " << index << " : " << _documentStore[index].friendlyName << ": " << key;
_mainTreeView->setCurrentIndex( _documentStore[index].treeItem->index() );
}
void XQMainWindow::loadDocument( const QString& fileName )
{
//ntThrowIfNullPtr
// gibts die Datei?
if( !QFile::exists( fileName) )
throw XQException( "no such file", fileName );
// load data tree from xml file
XQNodeFactory treeLoader;
XQNodePtr rawTree = treeLoader.load_tree( qPrintable(fileName) );
// versteckten root node ignorieren
XQNodePtr contentRoot = rawTree->first_child();
// Project-ID behandeln
const QString& pID = contentRoot->attribute(c_ProjectID);
int idx = _documentStore.indexOf( pID );
if( idx > -1 )
{
const XQDocument& doc = _documentStore.at(idx);
QMessageBox::warning( this, "Load Document", QString("File: %1 already loaded.").arg( fileName ) );
_mainTreeView->setCurrentIndex( doc.treeItem->index() );
_tabWidget->setCurrentIndex( idx );
return;
}
// 'friendly Name' ist ein Link auf ein anderes Attribute
// das als Namen verwendet wird.
const QString& fName = contentRoot->friendly_name();
QString pTitle = QString("Project %1: %2").arg( pID, fName );
// Eine neue TreeView erzeugn und im TabWidget parken.
XQTreeView* childTreeView = new XQTreeView(_tabWidget);
_tabWidget->addTab( childTreeView, pTitle );
_tabWidget->setCurrentWidget( childTreeView );
setWindowTitle( pTitle );
// Ein neues Child-Model erzeugen
XQChildModel* childModel = new XQChildModel(this);
// die Modelstruktur anlegen
childModel->initModel( c_ChildModelName );
// Den globalen undo-stack ...
childModel->setUndoStack(&_undoStack);
// und die TreeView übergeben
childModel->setTreeView(childTreeView);
// read the model data
childModel->setContent( contentRoot->first_child() );
// create new entry in the left side main tree view
//XQItem* newEntry = _mainModelView.createTreeEntry( contentRoot );
//_mainTreeView->setCurrentIndex( newEntry->index() );
//_documentStore.addDocument( fileName, pTitle, newEntry, childModelView );
}
void XQMainWindow::saveDocument( const QString& fileName )
{
XQNodeWriter nodeWriter;
int curIdx = _tabWidget->currentIndex();
XQNodePtr rootNode = _documentStore[curIdx].treeItem->contentNode();
nodeWriter.dumpTree( rootNode, fileName );
}

View File

@@ -0,0 +1,65 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#ifndef XQMAINWINDOW_H
#define XQMAINWINDOW_H
#include <QMainWindow>
#include <ui_xqmainwindow.h>
#include <xqdocumentstore.h>
#include <xqmainmodel.h>
#include <xqchildmodel.h>
#include <xqappdata.h>
class XQMainWindow : public QMainWindow, public Ui_XQMainWindow
{
Q_OBJECT
public:
XQMainWindow( QWidget* parent = nullptr );
virtual ~XQMainWindow() = default;
void initMainWindow();
public slots:
void onCreateDocument();
void onOpenDocument();
void onSaveDocument();
void onSaveDocumentAs();
void onCloseDocument();
void onAbout();
void onExit();
void onTreeItemClicked(const QModelIndex& index );
void onTabClicked( int index );
protected:
// showDocumentTab( XQItem* item)
// fixme implement
void showDocumnet( const QString& key ){}
void loadDocument( const QString& fileName );
void saveDocument( const QString& fileName );
QUndoStack _undoStack;
XQDocumentStore _documentStore;
XQMainModel _mainModelView;
};
#endif // XQMAINWINDOW_H

290
application/xqmainwindow.ui Normal file
View File

@@ -0,0 +1,290 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>XQMainWindow</class>
<widget class="QMainWindow" name="XQMainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>XTree</string>
</property>
<widget class="QWidget" name="_centralWidget">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="_tabWidget"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="_menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>26</height>
</rect>
</property>
<widget class="QMenu" name="_fileMenu">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="separator"/>
<addaction name="_actionOpen"/>
<addaction name="_actionSave"/>
<addaction name="_actionSaveAs"/>
<addaction name="_actionExit"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="_actionAbout"/>
</widget>
<widget class="QMenu" name="_menuEdit">
<property name="title">
<string>Edit</string>
</property>
<addaction name="_actionUndo"/>
<addaction name="_actionRedo"/>
<addaction name="separator"/>
<addaction name="_actionCut"/>
<addaction name="_actionPaste"/>
<addaction name="_actionCopy"/>
</widget>
<addaction name="_fileMenu"/>
<addaction name="_menuEdit"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="_statusBar"/>
<widget class="QDockWidget" name="_treeDockWidget">
<property name="windowTitle">
<string>MainDocument</string>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="_treeDockLayout">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="XQTreeView" name="_mainTreeView">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="frameShape">
<enum>QFrame::Shape::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="_statusDock">
<property name="toolTipDuration">
<number>7</number>
</property>
<property name="windowTitle">
<string>Status</string>
</property>
<attribute name="dockWidgetArea">
<number>8</number>
</attribute>
<widget class="QWidget" name="_statusContent">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QUndoView" name="_undoView">
<property name="frameShape">
<enum>QFrame::Shape::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="_actionExit">
<property name="text">
<string>E&amp;xit</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
<action name="_actionCopy">
<property name="text">
<string>Copy</string>
</property>
<property name="shortcut">
<string>Ctrl+C</string>
</property>
</action>
<action name="_actionCut">
<property name="text">
<string>Cu&amp;t</string>
</property>
<property name="shortcut">
<string>Ctrl+X</string>
</property>
</action>
<action name="_actionNew">
<property name="text">
<string>New</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
<action name="_actionPaste">
<property name="icon">
<iconset theme="audio-volume-high"/>
</property>
<property name="text">
<string>Paste</string>
</property>
<property name="shortcut">
<string>Ctrl+V</string>
</property>
</action>
<action name="_actionUndo">
<property name="text">
<string>Undo</string>
</property>
<property name="shortcut">
<string>Ctrl+Z</string>
</property>
</action>
<action name="_actionRedo">
<property name="text">
<string>Redo</string>
</property>
<property name="shortcut">
<string>Ctrl+Y</string>
</property>
</action>
<action name="_actionOpen">
<property name="text">
<string>Open</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="actionCopyAsText">
<property name="text">
<string>Copy As Text</string>
</property>
<property name="menuRole">
<enum>QAction::MenuRole::NoRole</enum>
</property>
</action>
<action name="_actionDelete">
<property name="text">
<string>Delete</string>
</property>
<property name="menuRole">
<enum>QAction::MenuRole::NoRole</enum>
</property>
</action>
<action name="_actionFind">
<property name="text">
<string>Find</string>
</property>
<property name="menuRole">
<enum>QAction::MenuRole::NoRole</enum>
</property>
</action>
<action name="_actionSave">
<property name="text">
<string>Save</string>
</property>
<property name="toolTip">
<string>Save</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="_actionSaveAs">
<property name="text">
<string>Save as ...</string>
</property>
<property name="toolTip">
<string>Save as ...</string>
</property>
<property name="shortcut">
<string>Ctrl+Alt+S</string>
</property>
</action>
<action name="_actionAbout">
<property name="text">
<string>About</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>XQTreeView</class>
<extends>QTreeView</extends>
<header location="global">xqtreeview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>