mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-05-06 07:19:58 +02:00
Merge branch 'master' into qt6_cmake_joshua
This commit is contained in:
@@ -119,8 +119,8 @@ int ElementCollectionItem::rowForInsertItem(const QString &name)
|
||||
return -1;
|
||||
|
||||
QList <ElementCollectionItem *> child;
|
||||
//The item to insert is an element we search from element child
|
||||
if (name.endsWith(".elmt"))
|
||||
//The item to insert is an element/template we search from element child
|
||||
if (name.endsWith(".elmt") || name.endsWith(".qetmak"))
|
||||
{
|
||||
child = elementsDirectChild();
|
||||
//There isn't element, we insert at last position
|
||||
|
||||
@@ -259,10 +259,12 @@ bool ElementsCollectionModel::dropMimeData(const QMimeData *data,
|
||||
@param projects : list of projects to load
|
||||
*/
|
||||
void ElementsCollectionModel::loadCollections(bool common_collection,
|
||||
bool company_collection,
|
||||
bool custom_collection,
|
||||
QList<QETProject *> projects)
|
||||
bool company_collection,
|
||||
bool custom_collection,
|
||||
QList<QETProject *> projects)
|
||||
{
|
||||
clear();
|
||||
|
||||
m_items_list_to_setUp.clear();
|
||||
|
||||
if (common_collection)
|
||||
@@ -275,17 +277,17 @@ void ElementsCollectionModel::loadCollections(bool common_collection,
|
||||
if (common_collection || company_collection || custom_collection)
|
||||
m_items_list_to_setUp.append(items());
|
||||
|
||||
|
||||
for (QETProject *project : projects)
|
||||
{
|
||||
addProject(project, false);
|
||||
m_items_list_to_setUp.append(projectItems(project));
|
||||
}
|
||||
|
||||
auto *watcher = new QFutureWatcher<void>();
|
||||
connect(watcher, &QFutureWatcher<void>::progressValueChanged,
|
||||
this, &ElementsCollectionModel::loadingProgressValueChanged);
|
||||
this, &ElementsCollectionModel::loadingProgressValueChanged);
|
||||
connect(watcher, &QFutureWatcher<void>::progressRangeChanged,
|
||||
this, &ElementsCollectionModel::loadingProgressRangeChanged);
|
||||
this, &ElementsCollectionModel::loadingProgressRangeChanged);
|
||||
connect(watcher, &QFutureWatcher<void>::finished,
|
||||
this, &ElementsCollectionModel::loadingFinished);
|
||||
connect(
|
||||
@@ -298,6 +300,41 @@ void ElementsCollectionModel::loadCollections(bool common_collection,
|
||||
watcher->setFuture(m_future);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ElementsCollectionModel::loadMacrosCollection
|
||||
* Load the macros collection synchronously to avoid thread-collisions.
|
||||
*/
|
||||
void ElementsCollectionModel::loadMacrosCollection()
|
||||
{
|
||||
m_items_list_to_setUp.clear();
|
||||
addMacrosCollection(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ElementsCollectionModel::addMacrosCollection
|
||||
* Add the user macros collection to this model
|
||||
* @param set_data
|
||||
*/
|
||||
void ElementsCollectionModel::addMacrosCollection(bool set_data)
|
||||
{
|
||||
QString macrosPath = QETApp::userMacrosDir();
|
||||
qDebug() << "=== MAKRO PFAD CHECK ===" << macrosPath;
|
||||
if (macrosPath.endsWith("/")) {
|
||||
macrosPath.remove(macrosPath.length() - 1, 1);
|
||||
}
|
||||
|
||||
FileElementCollectionItem *feci = new FileElementCollectionItem();
|
||||
if (feci->setRootPath(macrosPath,
|
||||
set_data,
|
||||
m_hide_element)) {
|
||||
invisibleRootItem()->appendRow(feci);
|
||||
if (set_data)
|
||||
feci->setUpData();
|
||||
}
|
||||
else
|
||||
delete feci;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionModel::addCommonCollection
|
||||
Add the common elements collection to this model
|
||||
@@ -356,11 +393,11 @@ void ElementsCollectionModel::addCustomCollection(bool set_data)
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionModel::addLocation
|
||||
Add the element or directory to this model.
|
||||
If the location is already managed by this model, do nothing.
|
||||
@param location
|
||||
*/
|
||||
* @brief ElementsCollectionModel::addLocation
|
||||
* Add the element or directory to this model.
|
||||
* If the location is already managed by this model, do nothing.
|
||||
* @param location
|
||||
*/
|
||||
void ElementsCollectionModel::addLocation(const ElementsLocation& location)
|
||||
{
|
||||
QModelIndex index = indexFromLocation(location);
|
||||
@@ -375,14 +412,15 @@ void ElementsCollectionModel::addLocation(const ElementsLocation& location)
|
||||
|
||||
if (project) {
|
||||
XmlProjectElementCollectionItem *xpeci =
|
||||
m_project_hash.value(project);
|
||||
m_project_hash.value(project);
|
||||
|
||||
last_item = xpeci->lastItemForPath(
|
||||
location.collectionPath(false),
|
||||
collection_name);
|
||||
location.collectionPath(false),
|
||||
collection_name);
|
||||
}
|
||||
}
|
||||
else if (location.isCustomCollection()) {
|
||||
// ANPASSUNG: Makros und Custom Collection werden hier behandelt!
|
||||
else if (location.isCustomCollection() || location.isMacrosCollection()) {
|
||||
QList <ElementCollectionItem *> child_list;
|
||||
|
||||
for (int i=0 ; i<rowCount() ; i++)
|
||||
@@ -392,15 +430,18 @@ void ElementsCollectionModel::addLocation(const ElementsLocation& location)
|
||||
|
||||
if (eci->type() == FileElementCollectionItem::Type) {
|
||||
FileElementCollectionItem *feci =
|
||||
static_cast<FileElementCollectionItem *>(eci);
|
||||
static_cast<FileElementCollectionItem *>(eci);
|
||||
|
||||
// Wir prüfen explizit, ob es Custom ODER Macros ist, und weisen es richtig zu.
|
||||
if ((location.isCustomCollection() && feci->isCustomCollection()) ||
|
||||
(location.isMacrosCollection() && feci->isMacrosCollection())) {
|
||||
|
||||
if (feci->isCustomCollection()) {
|
||||
last_item = feci->lastItemForPath(
|
||||
location.collectionPath(false),
|
||||
collection_name);
|
||||
location.collectionPath(false),
|
||||
collection_name);
|
||||
if(last_item)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -562,14 +603,14 @@ void ElementsCollectionModel::hideElement()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionModel::indexFromLocation
|
||||
Return the index who represent location.
|
||||
Index can be non valid
|
||||
@param location
|
||||
@return
|
||||
*/
|
||||
* @brief ElementsCollectionModel::indexFromLocation
|
||||
* Return the index who represent location.
|
||||
* Index can be non valid
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
QModelIndex ElementsCollectionModel::indexFromLocation(
|
||||
const ElementsLocation &location)
|
||||
const ElementsLocation &location)
|
||||
{
|
||||
QList <ElementCollectionItem *> child_list;
|
||||
|
||||
@@ -577,30 +618,34 @@ QModelIndex ElementsCollectionModel::indexFromLocation(
|
||||
child_list.append(static_cast<ElementCollectionItem *>(item(i)));
|
||||
}
|
||||
|
||||
foreach(ElementCollectionItem *eci, child_list) {
|
||||
foreach(ElementCollectionItem *eci, child_list) {
|
||||
|
||||
ElementCollectionItem *match_eci = nullptr;
|
||||
ElementCollectionItem *match_eci = nullptr;
|
||||
|
||||
if (eci->type() == FileElementCollectionItem::Type) {
|
||||
if (FileElementCollectionItem *feci = static_cast<FileElementCollectionItem *>(eci)) {
|
||||
if ( (location.isCommonCollection() && feci->isCommonCollection()) ||
|
||||
(location.isCompanyCollection() && feci->isCompanyCollection()) ||
|
||||
(location.isCustomCollection() && !feci->isCommonCollection()) ) {
|
||||
match_eci = feci->itemAtPath(location.collectionPath(false));
|
||||
if (eci->type() == FileElementCollectionItem::Type) {
|
||||
if (FileElementCollectionItem *feci = static_cast<FileElementCollectionItem *>(eci)) {
|
||||
|
||||
// ANPASSUNG: Makro-Prüfung hinzugefügt, damit das Modell den Pfad im Baum findet!
|
||||
if ( (location.isCommonCollection() && feci->isCommonCollection()) ||
|
||||
(location.isCompanyCollection() && feci->isCompanyCollection()) ||
|
||||
(location.isMacrosCollection() && feci->isMacrosCollection()) ||
|
||||
(location.isCustomCollection() && feci->isCustomCollection()) ) {
|
||||
|
||||
match_eci = feci->itemAtPath(location.collectionPath(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (eci->type() == XmlProjectElementCollectionItem::Type) {
|
||||
if (XmlProjectElementCollectionItem *xpeci = static_cast<XmlProjectElementCollectionItem *>(eci)) {
|
||||
match_eci = xpeci->itemAtPath(location.collectionPath(false));
|
||||
}
|
||||
}
|
||||
else if (eci->type() == XmlProjectElementCollectionItem::Type) {
|
||||
if (XmlProjectElementCollectionItem *xpeci = static_cast<XmlProjectElementCollectionItem *>(eci)) {
|
||||
match_eci = xpeci->itemAtPath(location.collectionPath(false));
|
||||
}
|
||||
|
||||
if (match_eci)
|
||||
return indexFromItem(match_eci);
|
||||
}
|
||||
|
||||
return QModelIndex();
|
||||
if (match_eci)
|
||||
return indexFromItem(match_eci);
|
||||
}
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,6 +47,8 @@ class ElementsCollectionModel : public QStandardItemModel
|
||||
void addCommonCollection(bool set_data = true);
|
||||
void addCompanyCollection(bool set_data = true);
|
||||
void addCustomCollection(bool set_data = true);
|
||||
void addMacrosCollection(bool set_data = true);
|
||||
void loadMacrosCollection();
|
||||
void addLocation(const ElementsLocation& location);
|
||||
|
||||
void addProject(QETProject *project, bool set_data = true);
|
||||
|
||||
@@ -93,10 +93,7 @@ void ElementsCollectionWidget::addProject(QETProject *project)
|
||||
{
|
||||
if (m_model)
|
||||
{
|
||||
m_progress_bar->show();
|
||||
m_tree_view->setDisabled(true);
|
||||
QList <QETProject *> prj; prj.append(project);
|
||||
m_model->loadCollections(false, false, false, prj);
|
||||
m_model->addProject(project, true);
|
||||
}
|
||||
else {
|
||||
m_waiting_project.append(project);
|
||||
@@ -176,16 +173,14 @@ void ElementsCollectionWidget::setUpAction()
|
||||
*/
|
||||
void ElementsCollectionWidget::setUpWidget()
|
||||
{
|
||||
//Setup the main layout
|
||||
m_main_vlayout = new QVBoxLayout(this);
|
||||
this->setLayout(m_main_vlayout);
|
||||
m_main_vlayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_main_vlayout->setSpacing(2);
|
||||
|
||||
m_search_field = new QLineEdit(this);
|
||||
m_search_field->setPlaceholderText(tr("Rechercher"));
|
||||
m_search_field->setPlaceholderText(tr("Rechercher..."));
|
||||
m_search_field->setClearButtonEnabled(true);
|
||||
m_main_vlayout->addWidget(m_search_field);
|
||||
|
||||
//Setup the tree view
|
||||
m_tree_view = new ElementsTreeView(this);
|
||||
m_tree_view->setHeaderHidden(true);
|
||||
m_tree_view->setIconSize(QSize(50, 50));
|
||||
@@ -195,12 +190,29 @@ void ElementsCollectionWidget::setUpWidget()
|
||||
m_tree_view->setAnimated(true);
|
||||
m_tree_view->setMouseTracking(true);
|
||||
m_tree_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
m_main_vlayout->addWidget(m_tree_view);
|
||||
|
||||
//Setup the progress bar
|
||||
//Setup the macros tree view
|
||||
m_macros_tree_view = new ElementsTreeView(this);
|
||||
m_macros_tree_view->setHeaderHidden(true);
|
||||
m_macros_tree_view->setIconSize(QSize(50, 50));
|
||||
m_macros_tree_view->setDragDropMode(QAbstractItemView::DragDrop);
|
||||
m_macros_tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_macros_tree_view->setAutoExpandDelay(500);
|
||||
m_macros_tree_view->setAnimated(true);
|
||||
m_macros_tree_view->setMouseTracking(true);
|
||||
m_macros_tree_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
m_tab_widget = new QTabWidget(this);
|
||||
m_tab_widget->setDocumentMode(true);
|
||||
m_tab_widget->setTabPosition(QTabWidget::North);
|
||||
m_tab_widget->addTab(m_tree_view, tr("Collections"));
|
||||
m_tab_widget->addTab(m_macros_tree_view, tr("Modèles"));
|
||||
|
||||
m_main_vlayout->addWidget(m_search_field);
|
||||
m_main_vlayout->addWidget(m_tab_widget);
|
||||
|
||||
m_progress_bar = new QProgressBar(this);
|
||||
m_progress_bar->setFormat(QObject::tr("chargement %p% (%v sur %m)"));
|
||||
|
||||
m_main_vlayout->addWidget(m_progress_bar);
|
||||
m_progress_bar->hide();
|
||||
|
||||
@@ -243,11 +255,15 @@ void ElementsCollectionWidget::setUpConnection()
|
||||
this, &ElementsCollectionWidget::dirProperties);
|
||||
|
||||
connect(m_tree_view, &QTreeView::doubleClicked,
|
||||
[this](const QModelIndex &index)
|
||||
{
|
||||
this->m_index_at_context_menu = index ;
|
||||
this->editElement();
|
||||
});
|
||||
[this](const QModelIndex &index)
|
||||
{
|
||||
this->m_index_at_context_menu = index ;
|
||||
ElementCollectionItem *eci = elementCollectionItemForIndex(index);
|
||||
if (eci && eci->collectionPath().endsWith(".qetmak")) {
|
||||
return; // Do nothing on double click for macros
|
||||
}
|
||||
this->editElement();
|
||||
});
|
||||
|
||||
connect(m_tree_view, &QTreeView::entered,
|
||||
[this] (const QModelIndex &index) {
|
||||
@@ -256,37 +272,64 @@ void ElementsCollectionWidget::setUpConnection()
|
||||
if (qde && eci)
|
||||
qde->statusBar()->showMessage(eci->localName());
|
||||
});
|
||||
|
||||
connect(m_macros_tree_view, &QTreeView::customContextMenuRequested,
|
||||
this, &ElementsCollectionWidget::customContextMenu);
|
||||
|
||||
connect(m_macros_tree_view, &QTreeView::doubleClicked,
|
||||
[this](const QModelIndex &index)
|
||||
{
|
||||
this->m_index_at_context_menu = index ;
|
||||
ElementCollectionItem *eci = elementCollectionItemForIndex(index);
|
||||
if (eci && eci->collectionPath().endsWith(".qetmak")) {
|
||||
return; // Do nothing on double click for macros
|
||||
}
|
||||
this->editElement();
|
||||
});
|
||||
|
||||
connect(m_macros_tree_view, &QTreeView::entered,
|
||||
[this] (const QModelIndex &index) {
|
||||
QETDiagramEditor *qde = QETApp::diagramEditorAncestorOf(this);
|
||||
ElementCollectionItem *eci = elementCollectionItemForIndex(index);
|
||||
if (qde && eci)
|
||||
qde->statusBar()->showMessage(eci->localName());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionWidget::customContextMenu
|
||||
Display the context menu of this widget at point
|
||||
@param point
|
||||
*/
|
||||
* @brief ElementsCollectionWidget::customContextMenu
|
||||
* Display the context menu of this widget at point
|
||||
* @param point
|
||||
*/
|
||||
void ElementsCollectionWidget::customContextMenu(const QPoint &point)
|
||||
{
|
||||
m_index_at_context_menu = m_tree_view->indexAt(point);
|
||||
QTreeView *clicked_tree = qobject_cast<QTreeView *>(sender());
|
||||
if (!clicked_tree) clicked_tree = m_tree_view; // Fallback
|
||||
|
||||
m_index_at_context_menu = clicked_tree->indexAt(point);
|
||||
if (!m_index_at_context_menu.isValid()) return;
|
||||
|
||||
m_context_menu->clear();
|
||||
|
||||
ElementCollectionItem *eci = elementCollectionItemForIndex(
|
||||
m_index_at_context_menu);
|
||||
m_index_at_context_menu);
|
||||
bool add_open_dir = false;
|
||||
|
||||
if (eci->isElement())
|
||||
if (eci->isElement() && !eci->collectionPath().endsWith(".qetmak"))
|
||||
m_context_menu->addAction(m_edit_element);
|
||||
|
||||
if (eci->type() == FileElementCollectionItem::Type)
|
||||
{
|
||||
add_open_dir = true;
|
||||
FileElementCollectionItem *feci =
|
||||
static_cast<FileElementCollectionItem*>(eci);
|
||||
static_cast<FileElementCollectionItem*>(eci);
|
||||
if (!feci->isCommonCollection())
|
||||
{
|
||||
if (feci->isDir())
|
||||
{
|
||||
m_context_menu->addAction(m_new_element);
|
||||
if (!feci->isMacrosCollection()) {
|
||||
m_context_menu->addAction(m_new_element);
|
||||
}
|
||||
m_context_menu->addAction(m_new_directory);
|
||||
if (!feci->isCollectionRoot())
|
||||
{
|
||||
@@ -301,7 +344,7 @@ void ElementsCollectionWidget::customContextMenu(const QPoint &point)
|
||||
if (eci->type() == XmlProjectElementCollectionItem::Type)
|
||||
{
|
||||
XmlProjectElementCollectionItem *xpeci =
|
||||
static_cast<XmlProjectElementCollectionItem *>(eci);
|
||||
static_cast<XmlProjectElementCollectionItem *>(eci);
|
||||
if (xpeci->isCollectionRoot())
|
||||
add_open_dir = true;
|
||||
}
|
||||
@@ -320,7 +363,7 @@ void ElementsCollectionWidget::customContextMenu(const QPoint &point)
|
||||
m_context_menu->addAction(m_open_dir);
|
||||
m_context_menu->addAction(m_reload);
|
||||
|
||||
m_context_menu->popup(mapToGlobal(m_tree_view->mapToParent(point)));
|
||||
m_context_menu->popup(mapToGlobal(clicked_tree->mapToParent(point)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -360,6 +403,9 @@ void ElementsCollectionWidget::editElement()
|
||||
|
||||
if ( !(eci && eci->isElement()) ) return;
|
||||
|
||||
// Prevent the element editor from opening for macros
|
||||
if (eci->collectionPath().endsWith(".qetmak")) return;
|
||||
|
||||
ElementsLocation location(eci->collectionPath());
|
||||
|
||||
QETApp *app = QETApp::instance();
|
||||
@@ -384,11 +430,15 @@ void ElementsCollectionWidget::deleteElement()
|
||||
if (!eci) return;
|
||||
|
||||
ElementsLocation loc(eci->collectionPath());
|
||||
if (! (loc.isElement()
|
||||
&& loc.exist()
|
||||
&& loc.isFileSystem()
|
||||
&& (loc.collectionPath().startsWith("company://")
|
||||
|| loc.collectionPath().startsWith("custom://"))) ) return;
|
||||
|
||||
bool isDeletableFile = loc.isElement() || eci->collectionPath().endsWith(".qetmak");
|
||||
|
||||
if (! (isDeletableFile
|
||||
&& loc.exist()
|
||||
&& loc.isFileSystem()
|
||||
&& (loc.collectionPath().startsWith("company://")
|
||||
|| loc.collectionPath().startsWith("custom://")
|
||||
|| loc.collectionPath().startsWith("macros://"))) ) return;
|
||||
|
||||
if (QET::QetMessageBox::question(
|
||||
this,
|
||||
@@ -400,9 +450,10 @@ void ElementsCollectionWidget::deleteElement()
|
||||
QFile file(loc.fileSystemPath());
|
||||
if (file.remove())
|
||||
{
|
||||
m_model->removeRows(m_index_at_context_menu.row(),
|
||||
1,
|
||||
m_index_at_context_menu.parent());
|
||||
QAbstractItemModel *clicked_model = const_cast<QAbstractItemModel*>(m_index_at_context_menu.model());
|
||||
if (clicked_model) {
|
||||
clicked_model->removeRows(m_index_at_context_menu.row(), 1, m_index_at_context_menu.parent());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -429,10 +480,11 @@ void ElementsCollectionWidget::deleteDirectory()
|
||||
|
||||
ElementsLocation loc (eci->collectionPath());
|
||||
if (! (loc.isDirectory()
|
||||
&& loc.exist()
|
||||
&& loc.isFileSystem()
|
||||
&& (loc.collectionPath().startsWith("company://")
|
||||
|| loc.collectionPath().startsWith("custom://"))) ) return;
|
||||
&& loc.exist()
|
||||
&& loc.isFileSystem()
|
||||
&& (loc.collectionPath().startsWith("company://")
|
||||
|| loc.collectionPath().startsWith("custom://")
|
||||
|| loc.collectionPath().startsWith("macros://"))) ) return;
|
||||
|
||||
if (QET::QetMessageBox::question(
|
||||
this,
|
||||
@@ -445,9 +497,10 @@ void ElementsCollectionWidget::deleteDirectory()
|
||||
QDir dir (loc.fileSystemPath());
|
||||
if (dir.removeRecursively())
|
||||
{
|
||||
m_model->removeRows(m_index_at_context_menu.row(),
|
||||
1,
|
||||
m_index_at_context_menu.parent());
|
||||
QAbstractItemModel *clicked_model = const_cast<QAbstractItemModel*>(m_index_at_context_menu.model());
|
||||
if (clicked_model) {
|
||||
clicked_model->removeRows(m_index_at_context_menu.row(), 1, m_index_at_context_menu.parent());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -489,19 +542,29 @@ void ElementsCollectionWidget::editDirectory()
|
||||
*/
|
||||
void ElementsCollectionWidget::newDirectory()
|
||||
{
|
||||
ElementCollectionItem *eci = elementCollectionItemForIndex(
|
||||
m_index_at_context_menu);
|
||||
ElementCollectionItem *eci = elementCollectionItemForIndex(m_index_at_context_menu);
|
||||
|
||||
if (eci->type() != FileElementCollectionItem::Type) return;
|
||||
if (!eci || eci->type() != FileElementCollectionItem::Type) return;
|
||||
|
||||
FileElementCollectionItem *feci =
|
||||
static_cast<FileElementCollectionItem*>(eci);
|
||||
FileElementCollectionItem *feci = static_cast<FileElementCollectionItem*>(eci);
|
||||
if(feci->isCommonCollection()) return;
|
||||
|
||||
ElementsLocation location(feci->collectionPath());
|
||||
ElementsCategoryEditor new_dir_editor(location, false, this);
|
||||
if (new_dir_editor.exec() == QDialog::Accepted)
|
||||
m_model->addLocation(new_dir_editor.createdLocation());
|
||||
|
||||
if (new_dir_editor.exec() == QDialog::Accepted) {
|
||||
ElementsLocation new_loc = new_dir_editor.createdLocation();
|
||||
|
||||
if (new_loc.isMacrosCollection()) {
|
||||
if (m_macros_model) {
|
||||
m_macros_model->addLocation(new_loc);
|
||||
}
|
||||
} else {
|
||||
if (m_model) {
|
||||
m_model->addLocation(new_loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -662,12 +725,19 @@ void ElementsCollectionWidget::reload()
|
||||
&ElementsCollectionWidget::loadingFinished);
|
||||
|
||||
m_new_model->loadCollections(true, true, true, project_list);
|
||||
|
||||
if (m_macros_model) {
|
||||
m_macros_model->deleteLater();
|
||||
}
|
||||
m_macros_model = new ElementsCollectionModel(m_macros_tree_view);
|
||||
m_macros_tree_view->setModel(m_macros_model);
|
||||
m_macros_model->loadMacrosCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionWidget::loadingFinished
|
||||
Process when collection finished to be loaded
|
||||
*/
|
||||
* @brief ElementsCollectionWidget::loadingFinished
|
||||
* Process when collection finished to be loaded
|
||||
*/
|
||||
void ElementsCollectionWidget::loadingFinished()
|
||||
{
|
||||
if (m_new_model)
|
||||
@@ -836,15 +906,21 @@ void ElementsCollectionWidget::showAndExpandItem(const QModelIndex &index,
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionWidget::elementCollectionItemForIndex
|
||||
@param index
|
||||
@return The internal pointer of index casted to ElementCollectionItem;
|
||||
*/
|
||||
ElementCollectionItem *ElementsCollectionWidget::elementCollectionItemForIndex(
|
||||
const QModelIndex &index) {
|
||||
if (!index.isValid())
|
||||
return nullptr;
|
||||
* @brief ElementsCollectionWidget::elementCollectionItemForIndex
|
||||
* @param index
|
||||
* @return The internal pointer of index casted to ElementCollectionItem;
|
||||
*/
|
||||
ElementCollectionItem *ElementsCollectionWidget::elementCollectionItemForIndex(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid()) return nullptr;
|
||||
|
||||
return static_cast<ElementCollectionItem*>(
|
||||
m_model->itemFromIndex(index));
|
||||
if (m_macros_model && index.model() == m_macros_model) {
|
||||
return static_cast<ElementCollectionItem *>(m_macros_model->itemFromIndex(index));
|
||||
}
|
||||
|
||||
if (m_model && index.model() == m_model) {
|
||||
return static_cast<ElementCollectionItem *>(m_model->itemFromIndex(index));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QScopedPointer>
|
||||
#include <QTabWidget>
|
||||
#include <QTreeView>
|
||||
|
||||
class ElementsCollectionModel;
|
||||
class QVBoxLayout;
|
||||
@@ -90,9 +92,12 @@ class ElementsCollectionWidget : public QWidget
|
||||
private:
|
||||
ElementsCollectionModel *m_model = nullptr;
|
||||
ElementsCollectionModel *m_new_model = nullptr;
|
||||
ElementsCollectionModel *m_macros_model = nullptr;
|
||||
QLineEdit *m_search_field;
|
||||
QTimer m_search_timer;
|
||||
ElementsTreeView *m_tree_view;
|
||||
ElementsTreeView *m_macros_tree_view = nullptr;
|
||||
QTabWidget *m_tab_widget = nullptr;
|
||||
QVBoxLayout *m_main_vlayout;
|
||||
QMenu *m_context_menu;
|
||||
QModelIndex m_index_at_context_menu;
|
||||
|
||||
@@ -181,7 +181,7 @@ QString ElementsLocation::collectionPath(bool protocol) const
|
||||
else
|
||||
{
|
||||
QString path = m_collection_path;
|
||||
return path.remove(QRegularExpression("common://|company://|custom://|embed://"));
|
||||
return path.remove(QRegularExpression("common://|company://|custom://|macros://|embed://"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,54 +232,34 @@ QString ElementsLocation::path() const
|
||||
(start by common://, company://, custom:// or embed://) or not.
|
||||
@param path
|
||||
*/
|
||||
|
||||
void ElementsLocation::setPath(const QString &path)
|
||||
{
|
||||
QString tmp_path = path;
|
||||
#ifdef Q_OS_WIN32
|
||||
//On windows, we convert backslash to slash
|
||||
#ifdef Q_OS_WIN32
|
||||
tmp_path = QDir::fromNativeSeparators(path);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
QString macrosPath = QETApp::userMacrosDir();
|
||||
if (macrosPath.endsWith("/")) macrosPath.remove(macrosPath.length() - 1, 1);
|
||||
|
||||
//There is a project, the path is for an embedded coolection.
|
||||
if (m_project)
|
||||
{
|
||||
m_collection_path = path;
|
||||
//Add the protocol to the collection path
|
||||
if (!path.startsWith("embed://"))
|
||||
m_collection_path.prepend("embed://");
|
||||
|
||||
}
|
||||
|
||||
//The path start with project, we get the project and the path from the string
|
||||
else if (tmp_path.startsWith("project"))
|
||||
{
|
||||
QRegularExpression re
|
||||
("^project(?<project_id>[0-9])\\+(?<collection_path>embed://*.*)$");
|
||||
if (!re.isValid())
|
||||
{
|
||||
qWarning() <<QObject::tr("this is an error in the code")
|
||||
<< re.errorString()
|
||||
<< re.patternErrorOffset();
|
||||
return;
|
||||
}
|
||||
QRegularExpression re ("^project(?<project_id>[0-9])\\+(?<collection_path>embed://*.*)$");
|
||||
if (!re.isValid()) return;
|
||||
QRegularExpressionMatch match = re.match(tmp_path);
|
||||
if (!match.hasMatch())
|
||||
{
|
||||
qDebug()<<"no Match => return"
|
||||
<<tmp_path;
|
||||
return;
|
||||
}
|
||||
if (!match.hasMatch()) return;
|
||||
|
||||
bool conv_ok;
|
||||
uint project_id = match.captured("project_id").toUInt(&conv_ok);
|
||||
if (!conv_ok)
|
||||
{
|
||||
qWarning()<<"toUint failed"
|
||||
<<match.captured("project_id")
|
||||
<<re
|
||||
<<tmp_path;
|
||||
return;
|
||||
}
|
||||
if (!conv_ok) return;
|
||||
|
||||
QETProject *project = QETApp::project(project_id);
|
||||
if (project)
|
||||
{
|
||||
@@ -287,10 +267,7 @@ void ElementsLocation::setPath(const QString &path)
|
||||
m_project = project;
|
||||
}
|
||||
}
|
||||
|
||||
// The path is in file system,
|
||||
// the given path is relative to common or custom collection
|
||||
else if (path.startsWith("common://") || path.startsWith("company://") || path.startsWith("custom://"))
|
||||
else if (path.startsWith("common://") || path.startsWith("company://") || path.startsWith("custom://") || path.startsWith("macros://"))
|
||||
{
|
||||
QString p;
|
||||
if (path.startsWith("common://"))
|
||||
@@ -303,6 +280,11 @@ void ElementsLocation::setPath(const QString &path)
|
||||
tmp_path.remove("company://");
|
||||
p = QETApp::companyElementsDirN() % "/" % tmp_path;
|
||||
}
|
||||
else if (path.startsWith("macros://"))
|
||||
{
|
||||
tmp_path.remove("macros://");
|
||||
p = macrosPath % "/" % tmp_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_path.remove("custom://");
|
||||
@@ -312,11 +294,10 @@ void ElementsLocation::setPath(const QString &path)
|
||||
m_file_system_path = p;
|
||||
m_collection_path = path;
|
||||
}
|
||||
//In this case, the path is supposed to be relative to the file system.
|
||||
else
|
||||
{
|
||||
QString path_ = path;
|
||||
if(path_.endsWith(".elmt"))
|
||||
if(path_.endsWith(".elmt") || path_.endsWith(".qetmak"))
|
||||
{
|
||||
m_file_system_path = path_;
|
||||
if (path_.startsWith(QETApp::commonElementsDirN()))
|
||||
@@ -331,6 +312,13 @@ void ElementsLocation::setPath(const QString &path)
|
||||
path_.prepend("company://");
|
||||
m_collection_path = path_;
|
||||
}
|
||||
else if (path_.startsWith(macrosPath))
|
||||
{
|
||||
QString matchPath = macrosPath + "/";
|
||||
path_.remove(matchPath);
|
||||
path_.prepend("macros://");
|
||||
m_collection_path = path_;
|
||||
}
|
||||
else if (path_.startsWith(QETApp::customElementsDirN()))
|
||||
{
|
||||
path_.remove(QETApp::customElementsDirN()+="/");
|
||||
@@ -353,6 +341,13 @@ void ElementsLocation::setPath(const QString &path)
|
||||
path_.prepend("company://");
|
||||
m_collection_path = path_;
|
||||
}
|
||||
else if (path_.startsWith(macrosPath))
|
||||
{
|
||||
QString matchPath = macrosPath + "/";
|
||||
path_.remove(matchPath);
|
||||
path_.prepend("macros://");
|
||||
m_collection_path = path_;
|
||||
}
|
||||
else if (path_.startsWith(QETApp::customElementsDirN()))
|
||||
{
|
||||
path_.remove(QETApp::customElementsDirN()+="/");
|
||||
@@ -371,10 +366,11 @@ void ElementsLocation::setPath(const QString &path)
|
||||
*/
|
||||
bool ElementsLocation::addToPath(const QString &string)
|
||||
{
|
||||
if (m_collection_path.endsWith(".elmt", Qt::CaseInsensitive))
|
||||
if (m_collection_path.endsWith(".elmt", Qt::CaseInsensitive) ||
|
||||
m_collection_path.endsWith(".qetmak", Qt::CaseInsensitive))
|
||||
{
|
||||
qDebug() << "ElementsLocation::addToPath :"
|
||||
" Can't add string to the path of an element";
|
||||
" Can't add string to the path of an element or template";
|
||||
return(false);
|
||||
}
|
||||
|
||||
@@ -477,7 +473,7 @@ QString ElementsLocation::toString() const
|
||||
*/
|
||||
bool ElementsLocation::isElement() const
|
||||
{
|
||||
return m_collection_path.endsWith(".elmt");
|
||||
return m_collection_path.endsWith(".elmt") || m_collection_path.endsWith(".qetmak");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -942,3 +938,14 @@ QDebug operator<< (QDebug debug, const ElementsLocation &location)
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ElementsLocation::isMacrosCollection
|
||||
* @return True if this location represent an item from the macros collection
|
||||
*/
|
||||
bool ElementsLocation::isMacrosCollection() const
|
||||
{
|
||||
QString macrosPath = QETApp::userMacrosDir();
|
||||
if (macrosPath.endsWith("/")) macrosPath.remove(macrosPath.length() - 1, 1);
|
||||
return fileSystemPath().startsWith(macrosPath);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ class ElementsLocation
|
||||
bool isCommonCollection() const;
|
||||
bool isCompanyCollection() const;
|
||||
bool isCustomCollection() const;
|
||||
bool isMacrosCollection() const;
|
||||
bool isProject() const;
|
||||
bool exist() const;
|
||||
bool isWritable() const;
|
||||
|
||||
@@ -22,7 +22,12 @@
|
||||
#include "../qeticons.h"
|
||||
#include "elementcollectionitem.h"
|
||||
#include "elementslocation.h"
|
||||
|
||||
#include "../qetproject.h"
|
||||
#include "../diagram.h"
|
||||
#include "xmlelementcollection.h"
|
||||
#include "../NameList/nameslist.h"
|
||||
#include <QPainter>
|
||||
#include <QScopedPointer>
|
||||
#include <QDrag>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
@@ -91,9 +96,107 @@ void ElementsTreeView::startElementDrag(const ElementsLocation &location)
|
||||
if (location.isDirectory())
|
||||
{
|
||||
mime_data->setData("application/x-qet-category-uri",
|
||||
location_str.toLatin1());
|
||||
location_str.toLatin1());
|
||||
drag->setPixmap(QET::Icons::Folder.pixmap(22, 22));
|
||||
}
|
||||
else if (location.fileName().endsWith(".qetmak"))
|
||||
{
|
||||
mime_data->setData("application/x-qet-element-uri", location_str.toLatin1());
|
||||
|
||||
QPixmap macro_pixmap;
|
||||
|
||||
// --- MINI-RENDERER FÜR DAS MAKRO-VORSCHAUBILD ---
|
||||
QFile file(location.fileSystemPath());
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QDomDocument macro_doc;
|
||||
if (macro_doc.setContent(&file)) {
|
||||
QDomElement root = macro_doc.documentElement();
|
||||
if (root.tagName() == "qet_macro") {
|
||||
|
||||
// 1. Unsichtbares Dummy-Projekt erstellen
|
||||
QScopedPointer<QETProject> dummy_project(new QETProject());
|
||||
|
||||
// 2. Bauteile in das Dummy-Projekt laden (wie beim echten Drop)
|
||||
QDomElement collection_node = root.firstChildElement("collection");
|
||||
if (!collection_node.isNull()) {
|
||||
QDomNodeList elements = collection_node.elementsByTagName("element");
|
||||
for (int i = 0; i < elements.count(); ++i) {
|
||||
QDomElement elmt_node = elements.at(i).toElement();
|
||||
QString path = elmt_node.attribute("path");
|
||||
QDomElement definition = elmt_node.firstChildElement("definition");
|
||||
if (!path.isEmpty() && !definition.isNull()) {
|
||||
int last_slash = path.lastIndexOf('/');
|
||||
QString dir_path = (last_slash != -1) ? path.left(last_slash) : "";
|
||||
QString file_name = (last_slash != -1) ? path.mid(last_slash + 1) : path;
|
||||
|
||||
if (!dir_path.isEmpty()) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
QStringList parts = dir_path.split('/', QString::SkipEmptyParts);
|
||||
#else
|
||||
QStringList parts = dir_path.split('/', Qt::SkipEmptyParts);
|
||||
#endif
|
||||
QString current_path = "";
|
||||
for (const QString &part : parts) {
|
||||
QString parent_path = current_path;
|
||||
if (!current_path.isEmpty()) current_path += "/";
|
||||
current_path += part;
|
||||
if (current_path == "import") continue;
|
||||
NamesList empty_names;
|
||||
dummy_project->embeddedElementCollection()->createDir(parent_path, part, empty_names);
|
||||
}
|
||||
}
|
||||
dummy_project->embeddedElementCollection()->addElementDefinition(dir_path, file_name, definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Diagram *dummy_diagram = dummy_project->addNewDiagram();
|
||||
|
||||
// 4. Makro auf dem unsichtbaren Blatt zeichnen
|
||||
QDomElement diagram_content_node = root.firstChildElement("diagram_content");
|
||||
QDomElement diagram_node = diagram_content_node.firstChildElement("diagram");
|
||||
if (!diagram_node.isNull()) {
|
||||
QDomNodeList instances = diagram_node.elementsByTagName("element");
|
||||
for (int i = 0; i < instances.count(); ++i) {
|
||||
QDomElement inst = instances.at(i).toElement();
|
||||
QString type = inst.attribute("type");
|
||||
if (type.startsWith("macro://")) {
|
||||
inst.setAttribute("type", type.replace("macro://", "embed://"));
|
||||
}
|
||||
}
|
||||
|
||||
dummy_diagram->fromXml(diagram_node, QPointF(0, 0), false, nullptr);
|
||||
dummy_diagram->clearSelection();
|
||||
|
||||
// 5. "Screenshot" (Pixmap) von den gezeichneten Elementen machen
|
||||
QRectF scene_rect = dummy_diagram->itemsBoundingRect();
|
||||
if (!scene_rect.isEmpty()) {
|
||||
scene_rect.adjust(-5, -5, 5, 5); // Kleiner Rand
|
||||
macro_pixmap = QPixmap(scene_rect.size().toSize());
|
||||
macro_pixmap.fill(Qt::transparent); // Transparenter Hintergrund
|
||||
|
||||
QPainter painter(¯o_pixmap);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
dummy_diagram->render(&painter, macro_pixmap.rect(), scene_rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (macro_pixmap.isNull()) {
|
||||
macro_pixmap = QET::Icons::Project.pixmap(32, 32);
|
||||
}
|
||||
|
||||
// Bild verkleinern, falls das Makro gigantisch groß ist
|
||||
if (macro_pixmap.width() > MAX_DND_PIXMAP_WIDTH || macro_pixmap.height() > MAX_DND_PIXMAP_HEIGHT) {
|
||||
macro_pixmap = macro_pixmap.scaled(MAX_DND_PIXMAP_WIDTH, MAX_DND_PIXMAP_HEIGHT, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
drag->setPixmap(macro_pixmap);
|
||||
// Bild zentriert an die Maus hängen
|
||||
drag->setHotSpot(QPoint(macro_pixmap.width() / 2, macro_pixmap.height() / 2));
|
||||
}
|
||||
else if (location.isElement())
|
||||
{
|
||||
mime_data->setData("application/x-qet-element-uri",
|
||||
|
||||
@@ -93,7 +93,7 @@ QString FileElementCollectionItem::dirPath() const
|
||||
*/
|
||||
bool FileElementCollectionItem::isDir() const
|
||||
{
|
||||
if (m_path.endsWith(".elmt"))
|
||||
if (m_path.endsWith(".elmt") || m_path.endsWith(".qetmak"))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
@@ -110,9 +110,9 @@ bool FileElementCollectionItem::isElement() const
|
||||
}
|
||||
|
||||
/**
|
||||
@brief FileElementCollectionItem::localName
|
||||
@return the located name of this item
|
||||
*/
|
||||
* @brief FileElementCollectionItem::localName
|
||||
* @return the located name of this item
|
||||
*/
|
||||
QString FileElementCollectionItem::localName()
|
||||
{
|
||||
if (!text().isNull())
|
||||
@@ -120,12 +120,17 @@ QString FileElementCollectionItem::localName()
|
||||
|
||||
else if (isDir()) {
|
||||
if (isCollectionRoot()) {
|
||||
QString macrosPath = QETApp::userMacrosDir();
|
||||
if (macrosPath.endsWith("/")) macrosPath.remove(macrosPath.length() - 1, 1);
|
||||
|
||||
if (m_path == QETApp::commonElementsDirN())
|
||||
setText(QObject::tr("Collection QET"));
|
||||
else if (m_path == QETApp::companyElementsDirN())
|
||||
setText(QObject::tr("Collection Company"));
|
||||
else if (m_path == QETApp::customElementsDirN())
|
||||
setText(QObject::tr("Collection utilisateur"));
|
||||
else if (m_path == macrosPath)
|
||||
setText(QObject::tr("Makros"));
|
||||
else
|
||||
setText(QObject::tr("Collection inconnue"));
|
||||
}
|
||||
@@ -136,7 +141,7 @@ QString FileElementCollectionItem::localName()
|
||||
if(docu.load_file(str.toStdString().c_str()))
|
||||
{
|
||||
if (QString(docu.document_element().name())
|
||||
== "qet-directory")
|
||||
== "qet-directory")
|
||||
{
|
||||
NamesList nl;
|
||||
nl.fromXml(docu.document_element());
|
||||
@@ -147,7 +152,11 @@ QString FileElementCollectionItem::localName()
|
||||
}
|
||||
else if (isElement()) {
|
||||
ElementsLocation loc(collectionPath());
|
||||
setText(loc.name());
|
||||
QString display_name = loc.name();
|
||||
if (display_name.endsWith(".qetmak")) {
|
||||
display_name.remove(".qetmak");
|
||||
}
|
||||
setText(display_name);
|
||||
}
|
||||
|
||||
return text();
|
||||
@@ -169,7 +178,11 @@ QString FileElementCollectionItem::localName(const ElementsLocation &location)
|
||||
localName();
|
||||
}
|
||||
else if (isElement()) {
|
||||
setText(location.name());
|
||||
QString display_name = location.name();
|
||||
if (display_name.endsWith(".qetmak")) {
|
||||
display_name.remove(".qetmak");
|
||||
}
|
||||
setText(display_name);
|
||||
}
|
||||
|
||||
return text();
|
||||
@@ -194,24 +207,29 @@ QString FileElementCollectionItem::name() const
|
||||
QString FileElementCollectionItem::collectionPath() const
|
||||
{
|
||||
if (isCollectionRoot()) {
|
||||
QString macrosPath = QETApp::userMacrosDir();
|
||||
if (macrosPath.endsWith("/")) macrosPath.remove(macrosPath.length() - 1, 1);
|
||||
|
||||
if (m_path == QETApp::commonElementsDirN())
|
||||
return "common://";
|
||||
else if (m_path == QETApp::companyElementsDirN())
|
||||
return "company://";
|
||||
else
|
||||
return "custom://";
|
||||
else if (m_path == macrosPath)
|
||||
return "macros://"; //
|
||||
else
|
||||
return "custom://";
|
||||
}
|
||||
else if (parent() && parent()->type()
|
||||
== FileElementCollectionItem::Type) {
|
||||
== FileElementCollectionItem::Type) {
|
||||
ElementCollectionItem *eci =
|
||||
static_cast<ElementCollectionItem*>(parent());
|
||||
if (eci->isCollectionRoot())
|
||||
return eci->collectionPath() + m_path;
|
||||
static_cast<ElementCollectionItem*>(parent());
|
||||
if (eci->isCollectionRoot())
|
||||
return eci->collectionPath() + m_path;
|
||||
else
|
||||
return eci->collectionPath() % "/" % m_path;
|
||||
}
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,10 +238,14 @@ QString FileElementCollectionItem::collectionPath() const
|
||||
*/
|
||||
bool FileElementCollectionItem::isCollectionRoot() const
|
||||
{
|
||||
QString macrosPath = QETApp::userMacrosDir();
|
||||
if (macrosPath.endsWith("/")) macrosPath.remove(macrosPath.length() - 1, 1);
|
||||
|
||||
if (m_path == QETApp::commonElementsDirN()
|
||||
|| m_path == QETApp::companyElementsDirN()
|
||||
|| m_path == QETApp::customElementsDirN())
|
||||
return true;
|
||||
|| m_path == QETApp::companyElementsDirN()
|
||||
|| m_path == QETApp::customElementsDirN()
|
||||
|| m_path == macrosPath)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@@ -273,55 +295,63 @@ void FileElementCollectionItem::addChildAtPath(const QString &collection_name)
|
||||
}
|
||||
|
||||
/**
|
||||
@brief FileElementCollectionItem::setUpData
|
||||
SetUp the data of this item
|
||||
*/
|
||||
* @brief FileElementCollectionItem::setUpData
|
||||
* SetUp the data of this item
|
||||
*/
|
||||
void FileElementCollectionItem::setUpData()
|
||||
{
|
||||
if (isDir())
|
||||
{
|
||||
localName();
|
||||
setFlags(Qt::ItemIsSelectable
|
||||
| Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled
|
||||
| Qt::ItemIsEnabled);
|
||||
| Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled
|
||||
| Qt::ItemIsEnabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
setFlags(Qt::ItemIsSelectable
|
||||
| Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsEnabled);
|
||||
|
||||
//Set the local name and all informations of the element
|
||||
//in the data Qt::UserRole+1, these data will be use for search.
|
||||
ElementsLocation loc(collectionPath());
|
||||
DiagramContext context = loc.elementInformations();
|
||||
QStringList search_list;
|
||||
for (QString& key : context.keys())
|
||||
{ search_list.append(context.value(key).toString()); }
|
||||
search_list.append(localName(loc));
|
||||
setData(search_list.join(" "));
|
||||
| Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsEnabled);
|
||||
|
||||
if (m_path.endsWith(".qetmak")) {
|
||||
setData(localName());
|
||||
} else {
|
||||
// Parse standard element information for search
|
||||
ElementsLocation loc(collectionPath());
|
||||
DiagramContext context = loc.elementInformations();
|
||||
QStringList search_list;
|
||||
for (QString& key : context.keys())
|
||||
{ search_list.append(context.value(key).toString()); }
|
||||
search_list.append(localName(loc));
|
||||
setData(search_list.join(" "));
|
||||
}
|
||||
}
|
||||
|
||||
setToolTip(collectionPath());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief FileElementCollectionItem::setUpIcon
|
||||
SetUp the icon of this item.
|
||||
Because icon use several memory,
|
||||
we use this method for setup icon instead setUpData.
|
||||
*/
|
||||
* @brief FileElementCollectionItem::setUpIcon
|
||||
* SetUp the icon of this item.
|
||||
* Because icon use several memory,
|
||||
* we use this method for setup icon instead setUpData.
|
||||
*/
|
||||
void FileElementCollectionItem::setUpIcon()
|
||||
{
|
||||
if (!icon().isNull())
|
||||
return;
|
||||
|
||||
if (isCollectionRoot()) {
|
||||
QString macrosPath = QETApp::userMacrosDir();
|
||||
if (macrosPath.endsWith("/")) macrosPath.remove(macrosPath.length() - 1, 1);
|
||||
|
||||
if (m_path == QETApp::commonElementsDirN())
|
||||
setIcon(QIcon(":/ico/16x16/qet.png"));
|
||||
else if (m_path == QETApp::companyElementsDirN())
|
||||
setIcon(QIcon(":/ico/16x16/go-company.png"));
|
||||
else if (m_path == macrosPath)
|
||||
setIcon(QIcon(":/ico/16x16/go-home.png"));
|
||||
else
|
||||
setIcon(QIcon(":/ico/16x16/go-home.png"));
|
||||
}
|
||||
@@ -330,8 +360,12 @@ void FileElementCollectionItem::setUpIcon()
|
||||
if (isDir()) {
|
||||
setIcon(QET::Icons::Folder);
|
||||
} else {
|
||||
ElementsLocation loc(collectionPath());
|
||||
setIcon(loc.icon());
|
||||
if (m_path.endsWith(".qetmak")) {
|
||||
setIcon(QIcon());
|
||||
} else {
|
||||
ElementsLocation loc(collectionPath());
|
||||
setIcon(loc.icon());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,13 +381,13 @@ void FileElementCollectionItem::setUpIcon()
|
||||
@param hide_element
|
||||
*/
|
||||
void FileElementCollectionItem::setPathName(const QString& path_name,
|
||||
bool set_data,
|
||||
bool hide_element)
|
||||
bool set_data,
|
||||
bool hide_element)
|
||||
{
|
||||
m_path = path_name;
|
||||
|
||||
//This isn't an element, we create the childs
|
||||
if (!path_name.endsWith(".elmt"))
|
||||
//This isn't an element or template, we create the childs
|
||||
if (!path_name.endsWith(".elmt") && !path_name.endsWith(".qetmak"))
|
||||
populate(set_data, hide_element);
|
||||
}
|
||||
|
||||
@@ -382,9 +416,9 @@ void FileElementCollectionItem::populate(bool set_data, bool hide_element)
|
||||
return;
|
||||
|
||||
//Get all elmt file in this directory
|
||||
dir.setNameFilters(QStringList() << "*.elmt");
|
||||
dir.setNameFilters(QStringList() << "*.elmt" << "*.qetmak");
|
||||
for (auto& str :
|
||||
dir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name))
|
||||
dir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name))
|
||||
{
|
||||
FileElementCollectionItem *feci = new FileElementCollectionItem();
|
||||
appendRow(feci);
|
||||
@@ -393,3 +427,15 @@ void FileElementCollectionItem::populate(bool set_data, bool hide_element)
|
||||
feci->setUpData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief FileElementCollectionItem::isMacrosCollection
|
||||
* @return True if this item represent the macros collection
|
||||
*/
|
||||
bool FileElementCollectionItem::isMacrosCollection() const
|
||||
{
|
||||
QString macrosPath = QETApp::userMacrosDir();
|
||||
if (macrosPath.endsWith("/")) macrosPath.remove(macrosPath.length() - 1, 1);
|
||||
|
||||
return fileSystemPath().startsWith(macrosPath);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ class FileElementCollectionItem : public ElementCollectionItem
|
||||
bool isCommonCollection() const;
|
||||
bool isCompanyCollection() const;
|
||||
bool isCustomCollection() const;
|
||||
bool isMacrosCollection() const;
|
||||
void addChildAtPath(const QString &collection_name) override;
|
||||
|
||||
void setUpData() override;
|
||||
|
||||
@@ -58,6 +58,10 @@ XmlElementCollection::XmlElementCollection(QETProject *project) :
|
||||
QChar(0x30A4), QChar(0x30F3), QChar(0x30D0), QChar(0x30FC),
|
||||
QChar(0x30C8), QChar(0x3055), QChar(0x308C), QChar(0x305F),
|
||||
QChar(0x8981), QChar(0x7D20)};
|
||||
const QChar korean_data[8] = {
|
||||
QChar(0xC804), QChar(0xAE30), QChar(0x0020),
|
||||
QChar(0xC2EC), QChar(0xBCFC), QChar(0x0020),
|
||||
QChar(0xC694), QChar(0xC18C)};
|
||||
const QChar russian_data[24] = {
|
||||
QChar(0x0418), QChar(0x043C), QChar(0x043F), QChar(0x043E),
|
||||
QChar(0x0440), QChar(0x0442), QChar(0x0438), QChar(0x0440),
|
||||
@@ -88,6 +92,8 @@ XmlElementCollection::XmlElementCollection(QETProject *project) :
|
||||
names.addName("it", "Elementi importati");
|
||||
names.addName("ja", QString(japanese_data, 10));
|
||||
//names.addName("ja", "インバートされた要素");
|
||||
names.addName("ko", QString(korean_data, 8));
|
||||
names.addName("ko_KR", QString(korean_data, 8));
|
||||
names.addName("nl", "Elementen geïmporteerd");
|
||||
names.addName("nl_BE", "Elementen geïmporteerd");
|
||||
names.addName("pl", "Elementy importowane");
|
||||
|
||||
257
sources/diagramevent/diagrameventaddmacro.cpp
Normal file
257
sources/diagramevent/diagrameventaddmacro.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright 2006-2026 The QElectroTech Team
|
||||
* This file is part of QElectroTech.
|
||||
*/
|
||||
#include "diagrameventaddmacro.h"
|
||||
|
||||
#include "../diagram.h"
|
||||
#include "../qetapp.h"
|
||||
#include "../qetdiagrameditor.h"
|
||||
#include "../qetproject.h"
|
||||
#include "../ElementsCollection/xmlelementcollection.h"
|
||||
#include "../NameList/nameslist.h"
|
||||
#include "../diagramcommands.h"
|
||||
#include "../diagramcontent.h"
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QStatusBar>
|
||||
#include <QPainter>
|
||||
|
||||
DiagramEventAddMacro::DiagramEventAddMacro(const ElementsLocation &location, Diagram *diagram, QPointF pos) :
|
||||
DiagramEventInterface(diagram),
|
||||
m_location(location),
|
||||
m_preview_item(nullptr)
|
||||
{
|
||||
if (loadMacro()) {
|
||||
init();
|
||||
|
||||
QScopedPointer<QETProject> dummy_project(new QETProject());
|
||||
QDomElement root = m_macro_doc.documentElement();
|
||||
|
||||
QDomElement collection_node = root.firstChildElement("collection");
|
||||
if (!collection_node.isNull()) {
|
||||
QDomNodeList elements = collection_node.elementsByTagName("element");
|
||||
for (int i = 0; i < elements.count(); ++i) {
|
||||
QDomElement elmt_node = elements.at(i).toElement();
|
||||
QString path = elmt_node.attribute("path");
|
||||
QDomElement definition = elmt_node.firstChildElement("definition");
|
||||
|
||||
if (!path.isEmpty() && !definition.isNull()) {
|
||||
int last_slash = path.lastIndexOf('/');
|
||||
QString dir_path = (last_slash != -1) ? path.left(last_slash) : "";
|
||||
QString file_name = (last_slash != -1) ? path.mid(last_slash + 1) : path;
|
||||
|
||||
if (!dir_path.isEmpty()) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
QStringList parts = dir_path.split('/', QString::SkipEmptyParts);
|
||||
#else
|
||||
QStringList parts = dir_path.split('/', Qt::SkipEmptyParts);
|
||||
#endif
|
||||
QString current_path = "";
|
||||
for (const QString &part : parts) {
|
||||
QString parent_path = current_path;
|
||||
if (!current_path.isEmpty()) current_path += "/";
|
||||
current_path += part;
|
||||
if (current_path == "import") continue;
|
||||
NamesList empty_names;
|
||||
dummy_project->embeddedElementCollection()->createDir(parent_path, part, empty_names);
|
||||
}
|
||||
}
|
||||
dummy_project->embeddedElementCollection()->addElementDefinition(dir_path, file_name, definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Diagram *dummy_diagram = dummy_project->addNewDiagram();
|
||||
QDomElement diagram_node = root.firstChildElement("diagram_content").firstChildElement("diagram");
|
||||
|
||||
if (!diagram_node.isNull()) {
|
||||
dummy_diagram->fromXml(diagram_node, QPointF(0, 0), false, nullptr);
|
||||
|
||||
QRectF scene_rect = dummy_diagram->itemsBoundingRect();
|
||||
if (!scene_rect.isEmpty()) {
|
||||
QPixmap pixmap(scene_rect.toAlignedRect().size());
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
dummy_diagram->render(&painter, QRectF(QPointF(0,0), scene_rect.size()), scene_rect);
|
||||
|
||||
m_preview_item = new QGraphicsPixmapItem(pixmap);
|
||||
m_preview_item->setOffset(scene_rect.topLeft());
|
||||
}
|
||||
}
|
||||
|
||||
if (m_preview_item) {
|
||||
m_preview_item->setPos(Diagram::snapToGrid(pos));
|
||||
m_preview_item->setOpacity(0.6);
|
||||
m_diagram->addItem(m_preview_item);
|
||||
m_running = true;
|
||||
}
|
||||
|
||||
if (!diagram->views().isEmpty()) {
|
||||
const auto qde = QETApp::diagramEditorAncestorOf(diagram->views().at(0));
|
||||
if (qde) {
|
||||
m_status_bar = qde->statusBar();
|
||||
}
|
||||
} else {
|
||||
m_status_bar.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DiagramEventAddMacro::~DiagramEventAddMacro()
|
||||
{
|
||||
if (m_preview_item) {
|
||||
m_diagram->removeItem(m_preview_item);
|
||||
delete m_preview_item;
|
||||
}
|
||||
|
||||
if (m_status_bar) {
|
||||
m_status_bar->clearMessage();
|
||||
}
|
||||
|
||||
for (auto view : m_diagram->views())
|
||||
view->setContextMenuPolicy(Qt::DefaultContextMenu);
|
||||
}
|
||||
|
||||
void DiagramEventAddMacro::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (m_preview_item) {
|
||||
const auto pos_{Diagram::snapToGrid(event->scenePos())};
|
||||
m_preview_item->setPos(pos_);
|
||||
|
||||
if (m_status_bar) {
|
||||
m_status_bar->showMessage(QString("x %1 : y %2 (Makro-Anker)").arg(QString::number(pos_.x()), QString::number(pos_.y())));
|
||||
}
|
||||
}
|
||||
event->setAccepted(true);
|
||||
}
|
||||
|
||||
void DiagramEventAddMacro::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
event->setAccepted(true);
|
||||
}
|
||||
|
||||
void DiagramEventAddMacro::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (m_preview_item) {
|
||||
if (event->button() == Qt::RightButton) {
|
||||
m_diagram->removeItem(m_preview_item);
|
||||
delete m_preview_item;
|
||||
m_preview_item = nullptr;
|
||||
m_running = false;
|
||||
emit finish();
|
||||
}
|
||||
else if (event->button() == Qt::LeftButton) {
|
||||
addMacro(Diagram::snapToGrid(event->scenePos()));
|
||||
}
|
||||
}
|
||||
event->setAccepted(true);
|
||||
}
|
||||
|
||||
void DiagramEventAddMacro::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (m_preview_item && (event->button() == Qt::LeftButton)) {
|
||||
m_diagram->removeItem(m_preview_item);
|
||||
delete m_preview_item;
|
||||
m_preview_item = nullptr;
|
||||
m_running = false;
|
||||
emit finish();
|
||||
}
|
||||
event->setAccepted(true);
|
||||
}
|
||||
|
||||
void DiagramEventAddMacro::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
DiagramEventInterface::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void DiagramEventAddMacro::init()
|
||||
{
|
||||
foreach(QGraphicsView *view, m_diagram->views())
|
||||
view->setContextMenuPolicy(Qt::NoContextMenu);
|
||||
}
|
||||
|
||||
bool DiagramEventAddMacro::loadMacro()
|
||||
{
|
||||
QFile file(m_location.fileSystemPath());
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qDebug() << "Error: Macro file could not be read:" << m_location.fileSystemPath();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_macro_doc.setContent(&file)) {
|
||||
qDebug() << "Error: Invalid XML in macro.";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDomElement root = m_macro_doc.documentElement();
|
||||
if (root.tagName() != "qet_macro") return false;
|
||||
|
||||
QDomElement collection_node = root.firstChildElement("collection");
|
||||
if (!collection_node.isNull()) {
|
||||
QDomNodeList elements = collection_node.elementsByTagName("element");
|
||||
for (int i = 0; i < elements.count(); ++i) {
|
||||
QDomElement elmt_node = elements.at(i).toElement();
|
||||
QString path = elmt_node.attribute("path");
|
||||
QDomElement definition = elmt_node.firstChildElement("definition");
|
||||
|
||||
if (!path.isEmpty() && !definition.isNull()) {
|
||||
int last_slash = path.lastIndexOf('/');
|
||||
QString dir_path = (last_slash != -1) ? path.left(last_slash) : "";
|
||||
QString file_name = (last_slash != -1) ? path.mid(last_slash + 1) : path;
|
||||
|
||||
if (!dir_path.isEmpty()) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
QStringList parts = dir_path.split('/', QString::SkipEmptyParts);
|
||||
#else
|
||||
QStringList parts = dir_path.split('/', Qt::SkipEmptyParts);
|
||||
#endif
|
||||
QString current_path = "";
|
||||
for (const QString &part : parts) {
|
||||
QString parent_path = current_path;
|
||||
if (!current_path.isEmpty()) current_path += "/";
|
||||
current_path += part;
|
||||
if (current_path == "import") continue;
|
||||
NamesList empty_names;
|
||||
m_diagram->project()->embeddedElementCollection()->createDir(parent_path, part, empty_names);
|
||||
}
|
||||
}
|
||||
m_diagram->project()->embeddedElementCollection()->addElementDefinition(dir_path, file_name, definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDomElement diagram_node = root.firstChildElement("diagram_content").firstChildElement("diagram");
|
||||
if (!diagram_node.isNull()) {
|
||||
QDomNodeList instances = diagram_node.elementsByTagName("element");
|
||||
for (int i = 0; i < instances.count(); ++i) {
|
||||
QDomElement inst = instances.at(i).toElement();
|
||||
QString type = inst.attribute("type");
|
||||
if (type.startsWith("macro://")) {
|
||||
inst.setAttribute("type", type.replace("macro://", "embed://"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiagramEventAddMacro::addMacro(QPointF final_pos)
|
||||
{
|
||||
QDomElement root = m_macro_doc.documentElement();
|
||||
QDomElement diagram_node = root.firstChildElement("diagram_content").firstChildElement("diagram");
|
||||
|
||||
if (!diagram_node.isNull()) {
|
||||
QDomElement cloned_node = diagram_node.cloneNode(true).toElement();
|
||||
|
||||
QPointF target_pos = final_pos;
|
||||
|
||||
DiagramContent pasted_content;
|
||||
|
||||
m_diagram->fromXml(cloned_node, target_pos, false, &pasted_content);
|
||||
m_diagram->refreshContents();
|
||||
|
||||
m_diagram->undoStack().push(new PasteDiagramCommand(m_diagram, pasted_content));
|
||||
}
|
||||
}
|
||||
45
sources/diagramevent/diagrameventaddmacro.h
Normal file
45
sources/diagramevent/diagrameventaddmacro.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
C opyright 2006-2026 The QEle*ctroTech Team
|
||||
This file is part of QElectroTech.
|
||||
*/
|
||||
#ifndef DIAGRAMEVENTADDMACRO_H
|
||||
#define DIAGRAMEVENTADDMACRO_H
|
||||
|
||||
#include "../ElementsCollection/elementslocation.h"
|
||||
#include "diagrameventinterface.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QGraphicsPixmapItem>
|
||||
|
||||
class QStatusBar;
|
||||
|
||||
/**
|
||||
* @brief The DiagramEventAddMacro class
|
||||
*/
|
||||
class DiagramEventAddMacro : public DiagramEventInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DiagramEventAddMacro(const ElementsLocation &location, Diagram *diagram, QPointF pos = QPointF(0,0));
|
||||
~DiagramEventAddMacro() override;
|
||||
|
||||
void mouseMoveEvent (QGraphicsSceneMouseEvent *event) override;
|
||||
void mousePressEvent (QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseReleaseEvent (QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent (QGraphicsSceneMouseEvent *event) override;
|
||||
void keyPressEvent (QKeyEvent *event) override;
|
||||
void init() override;
|
||||
|
||||
private:
|
||||
bool loadMacro();
|
||||
void addMacro(QPointF final_pos);
|
||||
|
||||
private:
|
||||
ElementsLocation m_location;
|
||||
QDomDocument m_macro_doc;
|
||||
QGraphicsPixmapItem *m_preview_item;
|
||||
QPointer<QStatusBar> m_status_bar;
|
||||
};
|
||||
|
||||
#endif // DIAGRAMEVENTADDMACRO_H
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include "diagramcommands.h"
|
||||
#include "diagramevent/diagrameventaddelement.h"
|
||||
#include "diagramevent/diagrameventaddmacro.h"
|
||||
#include "dvevent/dveventinterface.h"
|
||||
#include "projectview.h"
|
||||
#include "qetdiagrameditor.h"
|
||||
@@ -34,7 +35,9 @@
|
||||
#include "utils/conductorcreator.h"
|
||||
#include "undocommand/addgraphicsobjectcommand.h"
|
||||
#include "diagram.h"
|
||||
|
||||
#include "ElementsCollection/xmlelementcollection.h"
|
||||
#include "NameList/nameslist.h"
|
||||
#include "elementdialog.h"
|
||||
#include <QDropEvent>
|
||||
|
||||
/**
|
||||
@@ -84,6 +87,10 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) :
|
||||
d.exec();
|
||||
});
|
||||
|
||||
// Setup the action to create a template
|
||||
m_create_template = new QAction(tr("Créer un template", "context menu action"), this);
|
||||
connect(m_create_template, SIGNAL(triggered()), this, SLOT(createTemplateFromSelection()));
|
||||
|
||||
//setup three separators, to be use in context menu
|
||||
for(int i=0 ; i<3 ; ++i)
|
||||
{
|
||||
@@ -188,13 +195,13 @@ void DiagramView::dropEvent(QDropEvent *e) {
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramView::handleElementDrop
|
||||
Handle the drop of an element.
|
||||
@param event the QDropEvent describing the current drag'n drop
|
||||
*/
|
||||
* @brief DiagramView::handleElementDrop
|
||||
* Handle the drop of an element.
|
||||
* @param event the QDropEvent describing the current drag'n drop
|
||||
*/
|
||||
void DiagramView::handleElementDrop(QDropEvent *event)
|
||||
{
|
||||
//Build an element from the text of the mime data
|
||||
//Build an element from the text of the mime data
|
||||
ElementsLocation location(event->mimeData()->text());
|
||||
|
||||
if ( !(location.isElement() && location.exist()) )
|
||||
@@ -203,12 +210,13 @@ void DiagramView::handleElementDrop(QDropEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (location.path().endsWith(".qetmak")) {
|
||||
diagram()->setEventInterface(new DiagramEventAddMacro(location, diagram(), event->position()));
|
||||
} else {
|
||||
diagram()->setEventInterface(new DiagramEventAddElement(location, diagram(), event->position()));
|
||||
}
|
||||
|
||||
diagram()->setEventInterface(
|
||||
new DiagramEventAddElement(
|
||||
location, diagram(), event->position()));
|
||||
|
||||
//Set focus to the view to get event
|
||||
//Set focus to the view to get event
|
||||
this->setFocus();
|
||||
}
|
||||
|
||||
@@ -1157,6 +1165,7 @@ QList<QAction *> DiagramView::contextMenuActions() const
|
||||
list << qde->m_copy;
|
||||
list << m_multi_paste;
|
||||
list << m_separators.at(0);
|
||||
list << m_create_template; // Add the create template action
|
||||
list << qde->m_conductor_reset;
|
||||
list << m_separators.at(1);
|
||||
list << qde->m_selection_actions_group.actions();
|
||||
@@ -1220,6 +1229,100 @@ void DiagramView::contextMenuEvent(QContextMenuEvent *e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DiagramView::createTemplateFromSelection
|
||||
* Triggered from the context menu to create a new template (macro) from the current selection.
|
||||
*/
|
||||
void DiagramView::createTemplateFromSelection()
|
||||
{
|
||||
QList<QGraphicsItem *> selected_elements = m_diagram->selectedItems();
|
||||
|
||||
if (selected_elements.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Ready to create a template from" << selected_elements.size() << "elements!";
|
||||
|
||||
// Open the dialog to let the user select where to save the .qetmak file
|
||||
ElementsLocation template_location = ElementDialog::getSaveTemplateLocation(this);
|
||||
|
||||
// Check if the user clicked 'Cancel' or closed the window
|
||||
if (template_location.isNull()) {
|
||||
qDebug() << "User canceled template creation.";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Will save template to:" << template_location.path();
|
||||
|
||||
QDomDocument content_xml = m_diagram->toXml(false, true);
|
||||
|
||||
QDomDocument macro_doc;
|
||||
QDomElement root = macro_doc.createElement("qet_macro");
|
||||
macro_doc.appendChild(root);
|
||||
|
||||
QDomElement collection_node = macro_doc.createElement("collection");
|
||||
root.appendChild(collection_node);
|
||||
|
||||
QSet<QString> processed_types;
|
||||
|
||||
QDomNodeList element_nodes = content_xml.elementsByTagName("element");
|
||||
for (int i = 0; i < element_nodes.count(); ++i) {
|
||||
QDomElement elmt_node = element_nodes.at(i).toElement();
|
||||
QString old_type = elmt_node.attribute("type");
|
||||
|
||||
if (old_type.isEmpty()) continue;
|
||||
|
||||
ElementsLocation loc(old_type, m_diagram->project());
|
||||
|
||||
QString clean_path = loc.collectionPath(false);
|
||||
|
||||
QString new_type = "macro://" + clean_path;
|
||||
elmt_node.setAttribute("type", new_type);
|
||||
|
||||
if (!processed_types.contains(clean_path)) {
|
||||
processed_types.insert(clean_path);
|
||||
|
||||
QDomElement definition_node = loc.xml();
|
||||
|
||||
if (!definition_node.isNull()) {
|
||||
QDomElement collection_elmt = macro_doc.createElement("element");
|
||||
collection_elmt.setAttribute("path", clean_path);
|
||||
|
||||
QDomNode imported_def = macro_doc.importNode(definition_node, true);
|
||||
collection_elmt.appendChild(imported_def);
|
||||
|
||||
collection_node.appendChild(collection_elmt);
|
||||
} else {
|
||||
qDebug() << "Warnung: Konnte XML-Definition für" << old_type << "nicht laden.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDomElement content_container = macro_doc.createElement("diagram_content");
|
||||
root.appendChild(content_container);
|
||||
|
||||
QDomNode imported_node = macro_doc.importNode(content_xml.documentElement(), true);
|
||||
content_container.appendChild(imported_node);
|
||||
|
||||
QString full_path = template_location.fileSystemPath();
|
||||
|
||||
QDir().mkpath(QFileInfo(full_path).absolutePath());
|
||||
|
||||
QFile file(full_path);
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out << macro_doc.toString(4);
|
||||
file.close();
|
||||
qDebug() << "Template successfully saved to:" << full_path;
|
||||
|
||||
QMessageBox::information(this, tr("Modèle enregistré"),
|
||||
tr("Le modèle a été enregistré avec succès sous :\n%1").arg(full_path));
|
||||
} else {
|
||||
qDebug() << "Error: Could not open file for writing:" << full_path;
|
||||
QMessageBox::critical(this, tr("Erreur"), tr("Le fichier n'a pas pu être écrit."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return l'editeur de schemas parent ou 0
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef DIAGRAMVIEW_H
|
||||
#define DIAGRAMVIEW_H
|
||||
|
||||
#include "ElementsCollection/elementslocation.h"
|
||||
#include "../ElementsCollection/elementslocation.h"
|
||||
#include "titleblock/templatelocation.h"
|
||||
|
||||
#include <QClipboard>
|
||||
@@ -53,6 +53,7 @@ class DiagramView : public QGraphicsView
|
||||
DVEventInterface *m_event_interface = nullptr;
|
||||
QAction *m_paste_here = nullptr;
|
||||
QAction *m_multi_paste = nullptr;
|
||||
QAction *m_create_template = nullptr;
|
||||
QPoint m_paste_here_pos;
|
||||
QPointF m_drag_last_pos;
|
||||
bool m_fresh_focus_in,
|
||||
@@ -133,5 +134,6 @@ class DiagramView : public QGraphicsView
|
||||
private slots:
|
||||
void adjustGridToZoom();
|
||||
void applyReadOnly();
|
||||
void createTemplateFromSelection();
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
@@ -96,8 +96,18 @@ void ElementPropertiesEditorWidget::upDateInterface()
|
||||
}
|
||||
else if (m_data.m_type == ElementData::Master) {
|
||||
ui->m_master_type_cb->setCurrentIndex(
|
||||
ui->m_master_type_cb->findData (
|
||||
m_data.m_master_type));
|
||||
ui->m_master_type_cb->findData (
|
||||
m_data.m_master_type));
|
||||
|
||||
// NEU: Checkbox und Zahlenbox für max_slaves einstellen
|
||||
if (m_data.m_max_slaves == -1) {
|
||||
ui->max_slaves_checkbox->setChecked(false);
|
||||
ui->max_slaves_spinbox->setEnabled(false);
|
||||
} else {
|
||||
ui->max_slaves_checkbox->setChecked(true);
|
||||
ui->max_slaves_spinbox->setEnabled(true);
|
||||
ui->max_slaves_spinbox->setValue(m_data.m_max_slaves);
|
||||
}
|
||||
} else if (m_data.m_type == ElementData::Terminal) {
|
||||
ui->m_terminal_type_cb->setCurrentIndex(
|
||||
ui->m_terminal_type_cb->findData(
|
||||
@@ -151,10 +161,13 @@ void ElementPropertiesEditorWidget::setUpInterface()
|
||||
ui->m_terminal_func_cb->addItem(tr("Phase"), ElementData::TFPhase);
|
||||
ui->m_terminal_func_cb->addItem(tr("Neutre"), ElementData::TFNeutral);
|
||||
|
||||
//Disable the edition of the first column of the information tree
|
||||
//by this little workaround
|
||||
//Disable the edition of the first column of the information tree
|
||||
//by this little workaround
|
||||
ui->m_tree->setItemDelegate(new EditorDelegate(this));
|
||||
ui->m_tree->header()->resizeSection(0, 150);
|
||||
|
||||
// NEU: Checkbox mit der Zahlenbox verbinden (Aktivieren/Deaktivieren)
|
||||
connect(ui->max_slaves_checkbox, SIGNAL(toggled(bool)), ui->max_slaves_spinbox, SLOT(setEnabled(bool)));
|
||||
|
||||
populateTree();
|
||||
}
|
||||
|
||||
@@ -226,6 +239,13 @@ void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
|
||||
}
|
||||
else if (m_data.m_type == ElementData::Master) {
|
||||
m_data.m_master_type = ui->m_master_type_cb->currentData().value<ElementData::MasterType>();
|
||||
|
||||
//If the checkbox is checked, save the number; otherwise, -1 (infinity)
|
||||
if (ui->max_slaves_checkbox->isChecked()) {
|
||||
m_data.m_max_slaves = ui->max_slaves_spinbox->value();
|
||||
} else {
|
||||
m_data.m_max_slaves = -1;
|
||||
}
|
||||
}
|
||||
else if (m_data.m_type == ElementData::Terminal)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>527</width>
|
||||
<height>442</height>
|
||||
<height>492</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -104,6 +104,23 @@
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="m_master_type_cb"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="max_slaves_checkbox">
|
||||
<property name="text">
|
||||
<string>Définir le nombre maximal d'esclaves</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="max_slaves_spinbox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -74,6 +74,10 @@ void ElementDialog::setUpWidget()
|
||||
title_ = tr("Enregistrer une catégorie", "dialog title");
|
||||
label_ = tr("Choisissez une catégorie.", "dialog content");
|
||||
break;
|
||||
case SaveTemplate:
|
||||
title_ = tr("Enregistrer un template", "dialog title");
|
||||
label_ = tr("Choisissez l'emplacement dans lequel vous souhaitez enregistrer votre template.", "dialog content");
|
||||
break;
|
||||
default:
|
||||
title_ = tr("Titre");
|
||||
label_ = tr("Label");
|
||||
@@ -92,10 +96,14 @@ void ElementDialog::setUpWidget()
|
||||
foreach(QETProject *prj, QETApp::registeredProjects())
|
||||
prjs.append(prj);
|
||||
|
||||
if (m_mode == OpenElement)
|
||||
if (m_mode == OpenElement) {
|
||||
m_model->loadCollections(true, true, true, prjs);
|
||||
else
|
||||
} else if (m_mode == SaveTemplate) {
|
||||
// Load only the templates/macros collection for the template save dialog
|
||||
m_model->loadMacrosCollection();
|
||||
} else {
|
||||
m_model->loadCollections(false, true, true, prjs);
|
||||
}
|
||||
|
||||
m_tree_view->setModel(m_model);
|
||||
m_tree_view->setHeaderHidden(true);
|
||||
@@ -103,14 +111,21 @@ void ElementDialog::setUpWidget()
|
||||
|
||||
m_buttons_box = new QDialogButtonBox(this);
|
||||
|
||||
if (m_mode == SaveCategory || m_mode == SaveElement)
|
||||
if (m_mode == SaveCategory || m_mode == SaveElement || m_mode == SaveTemplate)
|
||||
{
|
||||
m_buttons_box->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
m_buttons_box->button(QDialogButtonBox::Save)->setDisabled(true);
|
||||
|
||||
m_text_field = new QFileNameEdit();
|
||||
m_text_field->setDisabled(true);
|
||||
m_text_field->setPlaceholderText(m_mode == SaveCategory? tr("Nom du nouveau dossier") : tr("Nom du nouvel élément"));
|
||||
|
||||
if (m_mode == SaveCategory) {
|
||||
m_text_field->setPlaceholderText(tr("Nom du nouveau dossier"));
|
||||
} else if (m_mode == SaveTemplate) {
|
||||
m_text_field->setPlaceholderText(tr("Nom du nouveau template"));
|
||||
} else {
|
||||
m_text_field->setPlaceholderText(tr("Nom du nouvel élément"));
|
||||
}
|
||||
|
||||
layout->addWidget(m_text_field);
|
||||
}
|
||||
@@ -156,14 +171,17 @@ void ElementDialog::checkCurrentLocation()
|
||||
if (m_mode == OpenElement) {
|
||||
m_buttons_box->button(QDialogButtonBox::Open)->setEnabled(m_location.isElement() && m_location.exist());
|
||||
}
|
||||
else if (m_mode == SaveElement)
|
||||
else if (m_mode == SaveElement || m_mode == SaveTemplate)
|
||||
{
|
||||
m_buttons_box->button(QDialogButtonBox::Save)->setDisabled(true);
|
||||
|
||||
//Location doesn't exist
|
||||
//Location doesn't exist
|
||||
if (!m_location.exist()) { return; }
|
||||
|
||||
if (m_location.isElement())
|
||||
// Accept .elmt for elements, and .qetmak for templates
|
||||
bool is_valid_file = m_location.isElement() || (m_mode == SaveTemplate && m_location.path().endsWith(".qetmak"));
|
||||
|
||||
if (is_valid_file)
|
||||
{
|
||||
m_text_field->setDisabled(true);
|
||||
m_buttons_box->button(QDialogButtonBox::Save)->setEnabled(true);
|
||||
@@ -174,10 +192,10 @@ void ElementDialog::checkCurrentLocation()
|
||||
|
||||
if (m_text_field->text().isEmpty()) { return; }
|
||||
|
||||
//Only enable save button if the location at path :
|
||||
//m_location.collectionPath + m_text_filed.text doesn't exist.
|
||||
//Only enable save button if the location at path doesn't exist.
|
||||
QString new_path = m_text_field->text();
|
||||
if (!new_path.endsWith(".elmt")) new_path += ".elmt";
|
||||
QString extension = (m_mode == SaveTemplate) ? ".qetmak" : ".elmt";
|
||||
if (!new_path.endsWith(extension)) new_path += extension;
|
||||
|
||||
ElementsLocation loc = m_location;
|
||||
loc.addToPath(new_path);
|
||||
@@ -209,15 +227,19 @@ void ElementDialog::checkAccept()
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (m_mode == SaveElement)
|
||||
else if (m_mode == SaveElement || m_mode == SaveTemplate)
|
||||
{
|
||||
if (loc.isElement())
|
||||
bool is_valid_file = loc.isElement() || (m_mode == SaveTemplate && loc.path().endsWith(".qetmak"));
|
||||
|
||||
if (is_valid_file)
|
||||
{
|
||||
if (loc.exist())
|
||||
{
|
||||
QString msgTitle = (m_mode == SaveTemplate) ? tr("Écraser le template ?", "message box title") : tr("Écraser l'élément ?", "message box title");
|
||||
QString msgContent = (m_mode == SaveTemplate) ? tr("Le template existe déjà. Voulez-vous l'écraser ?", "message box content") : tr("L'élément existe déjà. Voulez-vous l'écraser ?", "message box content");
|
||||
QMessageBox::StandardButton answer = QET::QetMessageBox::question(this,
|
||||
tr("Écraser l'élément ?", "message box title"),
|
||||
tr("L'élément existe déjà. Voulez-vous l'écraser ?", "message box content"),
|
||||
msgTitle,
|
||||
msgContent,
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No);
|
||||
if (answer == QMessageBox::Yes) {accept();}
|
||||
@@ -248,19 +270,21 @@ ElementsLocation ElementDialog::location() const
|
||||
else {return ElementsLocation(); }
|
||||
}
|
||||
|
||||
else if (m_mode == SaveElement)
|
||||
else if (m_mode == SaveElement || m_mode == SaveTemplate)
|
||||
{
|
||||
//Current selected location is element, we return this location
|
||||
if (m_location.isElement()) { return m_location; }
|
||||
//Current selected location is element or template, we return this location
|
||||
bool is_valid_file = m_location.isElement() || (m_mode == SaveTemplate && m_location.path().endsWith(".qetmak"));
|
||||
if (is_valid_file) { return m_location; }
|
||||
|
||||
//Current selected location is directory, we return a location at path :
|
||||
//m_location->collectionPath + m_text_field->text
|
||||
//Current selected location is directory, we return a location at path :
|
||||
//m_location->collectionPath + m_text_field->text
|
||||
else if (m_location.isDirectory())
|
||||
{
|
||||
QString new_path = m_text_field->text();
|
||||
if (new_path.isEmpty()) { return ElementsLocation(); }
|
||||
|
||||
if (!new_path.endsWith(".elmt")) { new_path += ".elmt"; }
|
||||
QString extension = (m_mode == SaveTemplate) ? ".qetmak" : ".elmt";
|
||||
if (!new_path.endsWith(extension)) { new_path += extension; }
|
||||
|
||||
ElementsLocation loc = m_location;
|
||||
loc.addToPath(new_path);
|
||||
@@ -291,6 +315,16 @@ ElementsLocation ElementDialog::getSaveElementLocation(QWidget *parentWidget) {
|
||||
return(ElementDialog::execConfiguredDialog(ElementDialog::SaveElement, parentWidget));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ElementDialog::getSaveTemplateLocation
|
||||
* Display a dialog that allow to user to select a location for saving a template
|
||||
* @param parentWidget
|
||||
* @return The location where the template must be save
|
||||
*/
|
||||
ElementsLocation ElementDialog::getSaveTemplateLocation(QWidget *parentWidget) {
|
||||
return(ElementDialog::execConfiguredDialog(ElementDialog::SaveTemplate, parentWidget));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementDialog::execConfiguredDialog
|
||||
launch a dialog with the chosen mode
|
||||
|
||||
@@ -42,7 +42,8 @@ class ElementDialog : public QDialog
|
||||
OpenElement = 0, ///< The dialog should open an element
|
||||
SaveElement = 1, ///< The dialog should select an element for saving
|
||||
OpenCategory = 2, ///< The dialog should open a category
|
||||
SaveCategory = 3 ///< The dialog should select a category for saving
|
||||
SaveCategory = 3, ///< The dialog should select a category for saving
|
||||
SaveTemplate = 4 ///< The dialog should select a template for saving
|
||||
};
|
||||
|
||||
// constructors, destructor
|
||||
@@ -74,6 +75,7 @@ class ElementDialog : public QDialog
|
||||
public:
|
||||
static ElementsLocation getOpenElementLocation(QWidget *parent = nullptr);
|
||||
static ElementsLocation getSaveElementLocation(QWidget *parent = nullptr);
|
||||
static ElementsLocation getSaveTemplateLocation(QWidget *parent = nullptr);
|
||||
private:
|
||||
static ElementsLocation execConfiguredDialog(int, QWidget *parent = nullptr);
|
||||
|
||||
|
||||
@@ -67,7 +67,10 @@ ElementsPanel::ElementsPanel(QWidget *parent) :
|
||||
connect(this, &ElementsPanel::itemDoubleClicked, this, &ElementsPanel::slot_doubleClick);
|
||||
connect(this, &GenericPanel::firstActivated, [this]() {QTimer::singleShot(250, this, SLOT(reload()));});
|
||||
connect(this, &ElementsPanel::panelContentChanged, this, &ElementsPanel::panelContentChange);
|
||||
|
||||
|
||||
// manage signal itemClicked
|
||||
connect(this, &ElementsPanel::itemClicked, this, &ElementsPanel::slot_clicked);
|
||||
|
||||
//Emit a signal instead au manage is own context menu
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
}
|
||||
@@ -132,31 +135,69 @@ void ElementsPanel::panelContentChange()
|
||||
Le QTreeWidgetItem insere le plus haut
|
||||
*/
|
||||
QTreeWidgetItem *ElementsPanel::addProject(QETProject *project,
|
||||
QTreeWidgetItem *parent_item,
|
||||
PanelOptions options)
|
||||
QTreeWidgetItem *parent_item,
|
||||
PanelOptions options)
|
||||
{
|
||||
Q_UNUSED(parent_item)
|
||||
Q_UNUSED(options)
|
||||
|
||||
|
||||
// 1. Save the current chart before clearing the selection
|
||||
Diagram *current_diagram = nullptr;
|
||||
if (QTreeWidgetItem *current_qtwi = currentItem()) {
|
||||
if (current_qtwi->type() == QET::Diagram) {
|
||||
current_diagram = valueForItem<Diagram *>(current_qtwi);
|
||||
}
|
||||
}
|
||||
|
||||
bool first_add = (first_reload_ || !projects_to_display_.contains(project));
|
||||
|
||||
clearSelection();
|
||||
|
||||
// create the QTreeWidgetItem representing the project
|
||||
QTreeWidgetItem *qtwi_project = GenericPanel::addProject(project, nullptr, GenericPanel::All);
|
||||
// the project will be inserted right before the common tb templates collection
|
||||
invisibleRootItem() -> insertChild(
|
||||
indexOfTopLevelItem(common_tbt_collection_item_),
|
||||
qtwi_project
|
||||
qtwi_project
|
||||
);
|
||||
if (first_add) qtwi_project -> setExpanded(true);
|
||||
|
||||
|
||||
if (first_add){
|
||||
qtwi_project -> setExpanded(true);
|
||||
// on adding an project select first diagram
|
||||
setCurrentItem(qtwi_project -> child(0));
|
||||
qtwi_project -> child(0)->setSelected(true);
|
||||
}
|
||||
else {
|
||||
// 2. Check whether we can restore the previous selection
|
||||
bool restored = false;
|
||||
if (current_diagram) {
|
||||
// Browse the children of the project node to find our diagram
|
||||
for (int i = 0; i < qtwi_project->childCount(); ++i) {
|
||||
QTreeWidgetItem *child = qtwi_project->child(i);
|
||||
if (child->type() == QET::Diagram && valueForItem<Diagram *>(child) == current_diagram) {
|
||||
setCurrentItem(child);
|
||||
child->setSelected(true);
|
||||
restored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fallback: Only if NOTHING could be restored (e.g., actually adding a new page)
|
||||
if (!restored && qtwi_project->childCount() >= 2) {
|
||||
// on adding an diagram to project select the last diagram
|
||||
setCurrentItem(qtwi_project->child(qtwi_project->childCount()-2));
|
||||
qtwi_project->child(qtwi_project->childCount()-2)->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (TitleBlockTemplatesCollection *tbt_collection = project -> embeddedTitleBlockTemplatesCollection()) {
|
||||
if (QTreeWidgetItem *tbt_collection_qtwi = itemForTemplatesCollection(tbt_collection)) {
|
||||
if (first_add) tbt_collection_qtwi -> setExpanded(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qtwi_project -> setStatusTip(0, tr("Double-cliquez pour réduire ou développer ce projet", "Status tip"));
|
||||
|
||||
|
||||
return(qtwi_project);
|
||||
}
|
||||
|
||||
@@ -258,21 +299,28 @@ void ElementsPanel::reload()
|
||||
}
|
||||
|
||||
/**
|
||||
Gere le double-clic sur un element.
|
||||
Si un double-clic sur un projet est effectue, le signal requestForProject
|
||||
est emis.
|
||||
Si un double-clic sur un schema est effectue, le signal requestForDiagram
|
||||
est emis.
|
||||
@brief ElementsPanel::slot_clicked
|
||||
handle click on qtwi
|
||||
@param qtwi item that was clickerd on
|
||||
*/
|
||||
void ElementsPanel::slot_clicked(QTreeWidgetItem *clickedItem, int) {
|
||||
|
||||
requestForItem(clickedItem);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsPanel::slot_doubleClick
|
||||
handle double click on qtwi
|
||||
@param qtwi
|
||||
*/
|
||||
void ElementsPanel::slot_doubleClick(QTreeWidgetItem *qtwi, int) {
|
||||
int qtwi_type = qtwi -> type();
|
||||
if (qtwi_type == QET::Project) {
|
||||
QETProject *project = valueForItem<QETProject *>(qtwi);
|
||||
emit(requestForProject(project));
|
||||
// open project properties
|
||||
emit(requestForProjectPropertiesEdition());
|
||||
} else if (qtwi_type == QET::Diagram) {
|
||||
Diagram *diagram = valueForItem<Diagram *>(qtwi);
|
||||
diagram->showMe();
|
||||
// open diagram properties
|
||||
emit(requestForDiagramPropertiesEdition());
|
||||
} else if (qtwi_type == QET::TitleBlockTemplate) {
|
||||
TitleBlockTemplateLocation tbt = valueForItem<TitleBlockTemplateLocation>(qtwi);
|
||||
emit(requestForTitleBlockTemplate(tbt));
|
||||
@@ -444,3 +492,64 @@ void ElementsPanel::ensureHierarchyIsVisible(const QList<QTreeWidgetItem *> &ite
|
||||
if (parent_qtwi -> isHidden()) parent_qtwi -> setHidden(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ElementsPanel::syncTabBars
|
||||
* set the project- or diagram Tab corresponding to
|
||||
* the selection in the treeView
|
||||
*/
|
||||
void ElementsPanel::requestForItem(QTreeWidgetItem *clickedItem)
|
||||
{
|
||||
// activate diagram
|
||||
if(clickedItem->type() == QET::Diagram){
|
||||
Diagram *diagram = valueForItem<Diagram *>(clickedItem);
|
||||
// if we click on diagramItem in annother project we need the other project
|
||||
emit(requestForProject(projectForItem(clickedItem->parent())));
|
||||
// required for keyPressEvent
|
||||
// after emit the focus is on the diagram editor, we put it back to elementsPanel
|
||||
this->setFocus();
|
||||
// activate diagram
|
||||
diagram->showMe();
|
||||
}
|
||||
// activate project
|
||||
else if(clickedItem->type() == QET::Project) {
|
||||
QETProject *project = projectForItem(clickedItem);
|
||||
emit(requestForProject(project));
|
||||
this->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ElementsPanel::keyPressEvent
|
||||
* @param event
|
||||
*/
|
||||
void ElementsPanel::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_Up:{
|
||||
// check if there is another item abbove
|
||||
if(!itemAbove(currentItem()))
|
||||
break;
|
||||
|
||||
setCurrentItem(itemAbove(currentItem()));
|
||||
if (currentItem()->type()==QET::Diagram || currentItem()->type()==QET::Project){
|
||||
requestForItem(currentItem());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Down:{
|
||||
// check if there is another item below
|
||||
if(!itemBelow(currentItem()))
|
||||
break;
|
||||
|
||||
setCurrentItem(itemBelow(currentItem()));
|
||||
if (currentItem()->type()==QET::Diagram || currentItem()->type()==QET::Project){
|
||||
requestForItem(currentItem());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
QTreeView::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,13 @@ class ElementsPanel : public GenericPanel {
|
||||
signals:
|
||||
void requestForProject(QETProject *);
|
||||
void requestForTitleBlockTemplate(const TitleBlockTemplateLocation &);
|
||||
|
||||
// Signal to open the project properties
|
||||
void requestForProjectPropertiesEdition();
|
||||
// Signal to open the diagram properties
|
||||
void requestForDiagramPropertiesEdition();
|
||||
|
||||
public slots:
|
||||
void slot_clicked(QTreeWidgetItem *, int);
|
||||
void slot_doubleClick(QTreeWidgetItem *, int);
|
||||
void reload();
|
||||
void filter(const QString &, QET::Filtering = QET::RegularFilter);
|
||||
@@ -63,7 +68,9 @@ class ElementsPanel : public GenericPanel {
|
||||
void buildFilterList();
|
||||
void applyCurrentFilter(const QList<QTreeWidgetItem *> &);
|
||||
void ensureHierarchyIsVisible(const QList<QTreeWidgetItem *> &);
|
||||
|
||||
void requestForItem(QTreeWidgetItem *);
|
||||
void keyPressEvent(QKeyEvent *event)override;
|
||||
|
||||
protected:
|
||||
void startDrag(Qt::DropActions) override;
|
||||
void startTitleBlockTemplateDrag(const TitleBlockTemplateLocation &);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "qeticons.h"
|
||||
#include "qetproject.h"
|
||||
#include "titleblock/templatedeleter.h"
|
||||
#include <QFileInfo>
|
||||
|
||||
/*
|
||||
When the ENABLE_PANEL_WIDGET_DND_CHECKS flag is set, the panel
|
||||
@@ -120,6 +121,12 @@ ElementsPanelWidget::ElementsPanelWidget(QWidget *parent) : QWidget(parent) {
|
||||
SLOT(openTitleBlockTemplate(const TitleBlockTemplateLocation &))
|
||||
);
|
||||
|
||||
// manage double click on TreeWidgetItem
|
||||
connect(elements_panel, SIGNAL(requestForProjectPropertiesEdition()), this, SLOT(editProjectProperties()) );
|
||||
connect(elements_panel, SIGNAL(requestForDiagramPropertiesEdition()), this, SLOT(editDiagramProperties()) );
|
||||
// manage project activation
|
||||
connect(elements_panel, SIGNAL(requestForProject(QETProject*)), this, SIGNAL(requestForProject(QETProject*)));
|
||||
|
||||
// disposition verticale
|
||||
QVBoxLayout *vlayout = new QVBoxLayout(this);
|
||||
vlayout -> setContentsMargins(0,0,0,0);
|
||||
@@ -146,6 +153,11 @@ void ElementsPanelWidget::openDirectoryForSelectedItem()
|
||||
if (QTreeWidgetItem *qtwi = elements_panel -> currentItem()) {
|
||||
QString dir_path = elements_panel -> dirPathForItem(qtwi);
|
||||
if (!dir_path.isEmpty()) {
|
||||
QFileInfo fileInfo(dir_path);
|
||||
// Wenn der Pfad auf eine Datei (z.B. Makro) zeigt, isoliere den Ordnerpfad
|
||||
if (fileInfo.isFile()) {
|
||||
dir_path = fileInfo.absolutePath();
|
||||
}
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(dir_path));
|
||||
}
|
||||
}
|
||||
@@ -236,6 +248,7 @@ void ElementsPanelWidget::deleteDiagram()
|
||||
{
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
emit(requestForDiagramDeletion(selected_diagram));
|
||||
elements_panel->reload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,28 +486,33 @@ void ElementsPanelWidget::keyPressEvent (QKeyEvent *e) {
|
||||
break;
|
||||
case Qt::Key_F3:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUp(selected_diagram));
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F4:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveDown(selected_diagram));
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F5:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUpTop(selected_diagram));
|
||||
}
|
||||
|
||||
break;
|
||||
case Qt::Key_F6:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveDownx10(selected_diagram));
|
||||
}
|
||||
|
||||
break;
|
||||
case Qt::Key_F7:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveDownx100(selected_diagram));
|
||||
}
|
||||
|
||||
@@ -502,12 +520,14 @@ void ElementsPanelWidget::keyPressEvent (QKeyEvent *e) {
|
||||
break;
|
||||
case Qt::Key_F8:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUpx10(selected_diagram));
|
||||
}
|
||||
|
||||
break;
|
||||
case Qt::Key_F9:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUpx100(selected_diagram));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -418,7 +418,8 @@ void ExportDialog::generateSvg(
|
||||
|
||||
// "joue" la QPicture sur un QSvgGenerator
|
||||
QSvgGenerator svg_engine;
|
||||
svg_engine.setSize(QSize((width*9/16), (height*9/16)));
|
||||
svg_engine.setSize(QSize(width, height));
|
||||
svg_engine.setViewBox(QRect(0, 0, width*0.75, height*0.75));
|
||||
svg_engine.setOutputDevice(&io_device);
|
||||
QPainter svg_painter(&svg_engine);
|
||||
picture.play(&svg_painter);
|
||||
|
||||
@@ -766,7 +766,6 @@ void GenericPanel::projectDiagramsOrderChanged(QETProject *project,
|
||||
if (!moved_qtwi_diagram) return;
|
||||
|
||||
// remove the QTWI then insert it back at the adequate location
|
||||
bool was_selected = moved_qtwi_diagram -> isSelected();
|
||||
qtwi_project -> removeChild (moved_qtwi_diagram);
|
||||
qtwi_project -> insertChild (to, moved_qtwi_diagram);
|
||||
|
||||
@@ -781,8 +780,14 @@ void GenericPanel::projectDiagramsOrderChanged(QETProject *project,
|
||||
updateDiagramItem(qtwi_diagram, diagram);
|
||||
}
|
||||
|
||||
if (was_selected)
|
||||
// select the moved diagram
|
||||
if(m_selected_item){
|
||||
setCurrentItem(moved_qtwi_diagram);
|
||||
}
|
||||
else{
|
||||
setCurrentItem(qtwi_project -> child(from));
|
||||
}
|
||||
m_selected_item = nullptr;
|
||||
|
||||
emit(panelContentChanged());
|
||||
}
|
||||
@@ -1041,3 +1046,12 @@ void GenericPanel::emitFirstActivated()
|
||||
{
|
||||
emit(firstActivated());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GenericPanel::setSelectedItem
|
||||
@param selectedItem
|
||||
*/
|
||||
void GenericPanel::setSelectedItem(QTreeWidgetItem *selectedItem)
|
||||
{
|
||||
m_selected_item = selectedItem;
|
||||
}
|
||||
|
||||
@@ -95,8 +95,8 @@ class GenericPanel : public QTreeWidget {
|
||||
virtual QTreeWidgetItem *addDiagram(Diagram *,
|
||||
QTreeWidgetItem * = nullptr,
|
||||
PanelOptions = AddAllChild);
|
||||
protected:
|
||||
virtual QTreeWidgetItem *getItemForDiagram(Diagram *, bool * = nullptr);
|
||||
protected:
|
||||
virtual QTreeWidgetItem *updateDiagramItem(QTreeWidgetItem *,
|
||||
Diagram *,
|
||||
PanelOptions = AddAllChild,
|
||||
@@ -171,6 +171,9 @@ class GenericPanel : public QTreeWidget {
|
||||
const QString &);
|
||||
|
||||
// various other methods
|
||||
public:
|
||||
void setSelectedItem(QTreeWidgetItem *selectedItem);
|
||||
|
||||
protected:
|
||||
virtual QString defaultText(QET::ItemType);
|
||||
virtual QIcon defaultIcon(QET::ItemType);
|
||||
@@ -222,5 +225,7 @@ class GenericPanel : public QTreeWidget {
|
||||
representing a title block template
|
||||
*/
|
||||
QHash<TitleBlockTemplateLocation, QTreeWidgetItem *> tb_templates_;
|
||||
|
||||
QTreeWidgetItem *m_selected_item = nullptr;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -721,6 +721,14 @@ void ProjectView::initActions()
|
||||
|
||||
m_end_view = new QAction(QET::Icons::ArrowRightDouble, tr("Aller à la fin du projet"),this);
|
||||
connect(m_end_view, &QAction::triggered, [this](){this->m_tab->setCurrentWidget(lastDiagram());});
|
||||
|
||||
// button to scroll one page left
|
||||
m_next_view_left = new QAction(QET::Icons::ArrowLeft, tr("go one page left"),this);
|
||||
connect(m_next_view_left, &QAction::triggered, [this](){this->m_tab->setCurrentWidget(previousDiagram());});
|
||||
|
||||
// button to scroll one page right
|
||||
m_next_view_right = new QAction(QET::Icons::ArrowRight, tr("go one page right"),this);
|
||||
connect(m_next_view_right, &QAction::triggered, [this](){this->m_tab->setCurrentWidget(nextDiagram());});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -748,34 +756,65 @@ void ProjectView::initWidgets()
|
||||
m_tab = new QTabWidget(this);
|
||||
#endif
|
||||
m_tab -> setMovable(true);
|
||||
// setting UsesScrollButton ensures that when the tab bar is full, the tabs are scrolled.
|
||||
m_tab -> setUsesScrollButtons(true);
|
||||
// disable the internal scroll buttons of the TabWidget, we will use our own buttons.
|
||||
m_tab->setStyleSheet("QTabBar QToolButton {border-image: ;border-width: 0px}");
|
||||
m_tab->setStyleSheet("QTabBar::scroller {width: 0px;}");
|
||||
|
||||
// add layouts
|
||||
QHBoxLayout *TopRightCorner_Layout = new QHBoxLayout();
|
||||
TopRightCorner_Layout->setContentsMargins(0,0,0,0);
|
||||
// some place left to the 'next_right_view_button' button
|
||||
TopRightCorner_Layout->insertSpacing(1,10);
|
||||
|
||||
QToolButton *add_new_diagram_button = new QToolButton;
|
||||
add_new_diagram_button -> setDefaultAction(m_add_new_diagram);
|
||||
add_new_diagram_button -> setAutoRaise(true);
|
||||
TopRightCorner_Layout->addWidget(add_new_diagram_button);
|
||||
QHBoxLayout *TopLeftCorner_Layout = new QHBoxLayout();
|
||||
TopLeftCorner_Layout->setContentsMargins(0,0,0,0);
|
||||
|
||||
// add buttons
|
||||
QToolButton *m_next_right_view_button =new QToolButton;
|
||||
m_next_right_view_button->setDefaultAction(m_next_view_right);
|
||||
m_next_right_view_button->setAutoRaise(true);
|
||||
TopRightCorner_Layout->addWidget(m_next_right_view_button);
|
||||
|
||||
connect(m_tab, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
|
||||
connect(m_tab, SIGNAL(tabBarDoubleClicked(int)), this, SLOT(tabDoubleClicked(int)));
|
||||
connect(m_tab->tabBar(), SIGNAL(tabMoved(int, int)), this, SLOT(tabMoved(int, int)), Qt::QueuedConnection);
|
||||
|
||||
//arrows button to return on first view
|
||||
QToolButton *m_first_view_button =new QToolButton;
|
||||
m_first_view_button->setDefaultAction(m_first_view);
|
||||
m_first_view_button->setAutoRaise(true);
|
||||
m_tab->setCornerWidget(m_first_view_button, Qt::TopLeftCorner);
|
||||
|
||||
//arrows button to go on last view
|
||||
QToolButton *m_end_view_button =new QToolButton;
|
||||
m_end_view_button->setDefaultAction(m_end_view);
|
||||
m_end_view_button->setAutoRaise(true);
|
||||
TopRightCorner_Layout->addWidget(m_end_view_button);
|
||||
|
||||
QWidget *tabwidget=new QWidget(this);
|
||||
tabwidget->setLayout(TopRightCorner_Layout);
|
||||
m_tab -> setCornerWidget(tabwidget, Qt::TopRightCorner);
|
||||
QToolButton *add_new_diagram_button = new QToolButton;
|
||||
add_new_diagram_button -> setDefaultAction(m_add_new_diagram);
|
||||
add_new_diagram_button -> setAutoRaise(true);
|
||||
TopRightCorner_Layout->addWidget(add_new_diagram_button);
|
||||
// some place right to the 'add_new_diagram_button' button
|
||||
TopRightCorner_Layout->addSpacing(5);
|
||||
|
||||
QToolButton *m_first_view_button =new QToolButton;
|
||||
m_first_view_button->setDefaultAction(m_first_view);
|
||||
m_first_view_button->setAutoRaise(true);
|
||||
TopLeftCorner_Layout->addWidget(m_first_view_button);
|
||||
|
||||
QToolButton *m_next_left_view_button =new QToolButton;
|
||||
m_next_left_view_button->setDefaultAction(m_next_view_left);
|
||||
m_next_left_view_button->setAutoRaise(true);
|
||||
TopLeftCorner_Layout->addWidget(m_next_left_view_button);
|
||||
|
||||
// some place right to the 'first_view_button' button
|
||||
TopLeftCorner_Layout->addSpacing(10);
|
||||
|
||||
// add widgets to tabbar
|
||||
QWidget *tabwidgetRight=new QWidget(this);
|
||||
tabwidgetRight->setLayout(TopRightCorner_Layout);
|
||||
m_tab -> setCornerWidget(tabwidgetRight, Qt::TopRightCorner);
|
||||
|
||||
QWidget *tabwidgetLeft=new QWidget(this);
|
||||
tabwidgetLeft->setLayout(TopLeftCorner_Layout);
|
||||
m_tab -> setCornerWidget(tabwidgetLeft, Qt::TopLeftCorner);
|
||||
|
||||
// manage signals
|
||||
connect(m_tab, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
|
||||
connect(m_tab, SIGNAL(tabBarDoubleClicked(int)), this, SLOT(tabDoubleClicked(int)));
|
||||
connect(m_tab->tabBar(), SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int,int)), Qt::QueuedConnection);
|
||||
|
||||
fallback_widget_ -> setVisible(false);
|
||||
m_tab -> setVisible(false);
|
||||
|
||||
@@ -168,8 +168,10 @@ class ProjectView : public QWidget
|
||||
// attributes
|
||||
private:
|
||||
QAction *m_add_new_diagram,
|
||||
*m_first_view,
|
||||
*m_end_view;
|
||||
*m_first_view,
|
||||
*m_end_view,
|
||||
*m_next_view_left,
|
||||
*m_next_view_right;
|
||||
QETProject *m_project;
|
||||
QVBoxLayout *layout_;
|
||||
QWidget *fallback_widget_;
|
||||
|
||||
@@ -76,6 +76,16 @@ QDomElement ElementData::kindInfoToXml(QDomDocument &document)
|
||||
xml_type.appendChild(type_txt);
|
||||
|
||||
returned_elmt.appendChild(xml_type);
|
||||
|
||||
// Save max_slaves only if a specific limit is set (not default -1)
|
||||
if (m_max_slaves != -1) {
|
||||
auto xml_max_slaves = document.createElement(QStringLiteral("kindInformation"));
|
||||
xml_max_slaves.setAttribute(QStringLiteral("name"), QStringLiteral("max_slaves"));
|
||||
auto max_slaves_txt = document.createTextNode(QString::number(m_max_slaves));
|
||||
xml_max_slaves.appendChild(max_slaves_txt);
|
||||
|
||||
returned_elmt.appendChild(xml_max_slaves);
|
||||
}
|
||||
}
|
||||
else if (m_type == ElementData::Slave)
|
||||
{
|
||||
@@ -558,9 +568,12 @@ void ElementData::kindInfoFromXml(const QDomElement &xml_element)
|
||||
}
|
||||
auto name = dom_elmt.attribute(QStringLiteral("name"));
|
||||
|
||||
if (m_type == ElementData::Master &&
|
||||
name == QLatin1String("type")) {
|
||||
m_master_type = masterTypeFromString(dom_elmt.text());
|
||||
if (m_type == ElementData::Master) {
|
||||
if (name == QLatin1String("type")) {
|
||||
m_master_type = masterTypeFromString(dom_elmt.text());
|
||||
} else if (name == QLatin1String("max_slaves")) {
|
||||
m_max_slaves = dom_elmt.text().toInt();
|
||||
}
|
||||
}
|
||||
else if (m_type == ElementData::Slave ) {
|
||||
if (name == QLatin1String("type")) {
|
||||
|
||||
@@ -134,6 +134,7 @@ class ElementData : public PropertiesInterface
|
||||
ElementData::Type m_type = ElementData::Simple;
|
||||
|
||||
ElementData::MasterType m_master_type = ElementData::Coil;
|
||||
int m_max_slaves{-1};
|
||||
|
||||
ElementData::SlaveType m_slave_type = ElementData::SSimple;
|
||||
ElementData::SlaveState m_slave_state = ElementData::NO;
|
||||
@@ -141,7 +142,7 @@ class ElementData : public PropertiesInterface
|
||||
ElementData::TerminalType m_terminal_type = ElementData::TTGeneric;
|
||||
ElementData::TerminalFunction m_terminal_function = ElementData::TFGeneric;
|
||||
|
||||
int m_contact_count = 1;
|
||||
int m_contact_count{1};
|
||||
DiagramContext m_informations;
|
||||
NamesList m_names_list;
|
||||
QString m_drawing_information;
|
||||
|
||||
@@ -91,6 +91,8 @@ QString QETApp::m_user_company_tbt_dir = QString();
|
||||
|
||||
QString QETApp::m_user_custom_tbt_dir = QString();
|
||||
|
||||
QString QETApp::m_user_macros_dir = QString();
|
||||
|
||||
QETApp *QETApp::m_qetapp = nullptr;
|
||||
|
||||
bool lang_is_set = false;
|
||||
@@ -717,6 +719,8 @@ void QETApp::resetCollectionsPath()
|
||||
m_user_company_tbt_dir.clear();
|
||||
|
||||
m_user_custom_tbt_dir.clear();
|
||||
|
||||
m_user_macros_dir.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -815,6 +819,38 @@ QString QETApp::customTitleBlockTemplatesDir()
|
||||
return(dataDir() + "/titleblocks/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QETApp::userMacrosDir
|
||||
* @return the path of the directory containing the user macros collection.
|
||||
*/
|
||||
QString QETApp::userMacrosDir()
|
||||
{
|
||||
if (m_user_macros_dir.isEmpty())
|
||||
{
|
||||
QSettings settings;
|
||||
QString path = settings.value(
|
||||
"elements-collections/macros-path",
|
||||
"default").toString();
|
||||
if (path != "default" && !path.isEmpty())
|
||||
{
|
||||
QDir dir(path);
|
||||
if (dir.exists())
|
||||
{
|
||||
m_user_macros_dir = path;
|
||||
return m_user_macros_dir;
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_user_macros_dir = "default";
|
||||
}
|
||||
}
|
||||
else if (m_user_macros_dir != "default") {
|
||||
return m_user_macros_dir;
|
||||
}
|
||||
|
||||
return(dataDir() + "/macros/");
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETApp::configDir
|
||||
Return the QET configuration folder, i.e. the path to the folder in
|
||||
@@ -931,6 +967,8 @@ QString QETApp::realPath(const QString &sym_path) {
|
||||
directory = commonElementsDir();
|
||||
} else if (sym_path.startsWith("company://")) {
|
||||
directory = companyElementsDir();
|
||||
} else if (sym_path.startsWith("macros://")) {
|
||||
directory = userMacrosDir();
|
||||
} else if (sym_path.startsWith("company://")) {
|
||||
directory = companyElementsDir();
|
||||
} else if (sym_path.startsWith("custom://")) {
|
||||
@@ -969,6 +1007,7 @@ QString QETApp::symbolicPath(const QString &real_path) {
|
||||
QString commond = commonElementsDir();
|
||||
QString companyd = companyElementsDir();
|
||||
QString customd = customElementsDir();
|
||||
QString macrosd = userMacrosDir();
|
||||
QString chemin;
|
||||
// analyzes the file path passed in parameter
|
||||
// analyse le chemin de fichier passe en parametre
|
||||
@@ -980,6 +1019,10 @@ QString QETApp::symbolicPath(const QString &real_path) {
|
||||
chemin = "company://"
|
||||
+ real_path.right(
|
||||
real_path.length() - companyd.length());
|
||||
} else if (real_path.startsWith(macrosd)) {
|
||||
chemin = "macros://"
|
||||
+ real_path.right(
|
||||
real_path.length() - macrosd.length());
|
||||
} else if (real_path.startsWith(customd)) {
|
||||
chemin = "custom://"
|
||||
+ real_path.right(
|
||||
@@ -2205,6 +2248,10 @@ void QETApp::initConfiguration()
|
||||
if (!custom_tbt_dir.exists())
|
||||
custom_tbt_dir.mkpath(QETApp::customTitleBlockTemplatesDir());
|
||||
|
||||
QDir macros_dir(QETApp::userMacrosDir());
|
||||
if (!macros_dir.exists())
|
||||
macros_dir.mkpath(QETApp::userMacrosDir());
|
||||
|
||||
/* recent files
|
||||
* note:
|
||||
* icons must be initialized before these instructions
|
||||
|
||||
@@ -91,6 +91,7 @@ class QETApp : public QObject
|
||||
static QString commonTitleBlockTemplatesDir();
|
||||
static QString companyTitleBlockTemplatesDir();
|
||||
static QString customTitleBlockTemplatesDir();
|
||||
static QString userMacrosDir();
|
||||
static bool registerProject(QETProject *);
|
||||
static bool unregisterProject(QETProject *);
|
||||
static QMap<uint, QETProject *> registeredProjects();
|
||||
@@ -242,7 +243,7 @@ class QETApp : public QObject
|
||||
|
||||
static QString m_user_company_tbt_dir;
|
||||
static QString m_user_custom_tbt_dir;
|
||||
|
||||
static QString m_user_macros_dir;
|
||||
|
||||
public slots:
|
||||
void systray(QSystemTrayIcon::ActivationReason);
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
#include "TerminalStrip/ui/terminalstripeditorwindow.h"
|
||||
#include "ui/diagrameditorhandlersizewidget.h"
|
||||
#include "TerminalStrip/ui/addterminalstripitemdialog.h"
|
||||
#include "wiringlistexport.h"
|
||||
#include "ui/terminalnumberingdialog.h"
|
||||
|
||||
#ifdef BUILD_WITHOUT_KF5
|
||||
#else
|
||||
@@ -465,13 +467,27 @@ void QETDiagramEditor::setUpActions()
|
||||
wne.toCsv();
|
||||
}
|
||||
});
|
||||
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
m_export_project_db = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter la base de donnée interne du projet"), this);
|
||||
connect(m_export_project_db, &QAction::triggered, [this]() {
|
||||
projectDataBase::exportDb(this->currentProject()->dataBase(), this);
|
||||
// Export wiring list to CSV
|
||||
m_project_export_wiring_list = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter le plan de câblage"), this);
|
||||
connect(m_project_export_wiring_list, &QAction::triggered, [this]() {
|
||||
QETProject *project = this->currentProject();
|
||||
if (project)
|
||||
{
|
||||
WiringListExport wle(project, this);
|
||||
wle.toCsv();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
// Terminal Numbering
|
||||
m_terminal_numbering = new QAction(QET::Icons::TerminalStrip, tr("Numérotation automatique des bornes"), this);
|
||||
connect(m_terminal_numbering, &QAction::triggered, this, &QETDiagramEditor::slot_terminalNumbering);
|
||||
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
m_export_project_db = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter la base de donnée interne du projet"), this);
|
||||
connect(m_export_project_db, &QAction::triggered, [this]() {
|
||||
projectDataBase::exportDb(this->currentProject()->dataBase(), this);
|
||||
});
|
||||
#endif
|
||||
|
||||
//MDI view style
|
||||
m_tabbed_view_mode = new QAction(tr("en utilisant des onglets"), this);
|
||||
@@ -835,6 +851,8 @@ void QETDiagramEditor::setUpMenu()
|
||||
menu_project -> addAction(m_project_export_conductor_num);
|
||||
menu_project -> addAction(m_terminal_strip_dialog);
|
||||
menu_project -> addAction(m_project_terminalBloc);
|
||||
menu_project -> addAction(m_project_export_wiring_list);
|
||||
menu_project -> addAction(m_terminal_numbering);
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
menu_project -> addSeparator();
|
||||
menu_project -> addAction(m_export_project_db);
|
||||
@@ -1567,6 +1585,8 @@ void QETDiagramEditor::slot_updateActions()
|
||||
m_csv_export -> setEnabled(editable_project);
|
||||
m_project_export_conductor_num-> setEnabled(opened_project);
|
||||
m_terminal_strip_dialog -> setEnabled(editable_project);
|
||||
m_project_export_wiring_list -> setEnabled(opened_project);
|
||||
m_terminal_numbering -> setEnabled(editable_project);
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
m_export_project_db -> setEnabled(editable_project);
|
||||
#endif
|
||||
@@ -1828,6 +1848,31 @@ void QETDiagramEditor::addProjectView(ProjectView *project_view)
|
||||
connect(project_view, SIGNAL(errorEncountered(QString)),
|
||||
this, SLOT(showError(const QString &)));
|
||||
|
||||
//Highlight the current page
|
||||
connect(project_view, &ProjectView::diagramActivated, this, [this](DiagramView *dv) {
|
||||
if (dv && dv->diagram() && pa) {
|
||||
// 1. Find the item in the tree that corresponds to this diagram
|
||||
QTreeWidgetItem *item = pa->elementsPanel().getItemForDiagram(dv->diagram());
|
||||
|
||||
// 2. If you find it, select it
|
||||
if (item) {
|
||||
pa->elementsPanel().setCurrentItem(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//Highlight the current page in projectView on project activation
|
||||
connect(this, &QETDiagramEditor::syncElementsPanel, this, [this]() {
|
||||
if (pa && currentDiagramView()) {
|
||||
// In the tree, find the element that corresponds to the diagram of the selected project.
|
||||
QTreeWidgetItem *item = pa->elementsPanel().getItemForDiagram(currentDiagramView()->diagram());
|
||||
if (item) {
|
||||
// select the diagram
|
||||
pa->elementsPanel().setCurrentItem(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//We maximise the new window if the current window is inexistent or maximized
|
||||
QWidget *current_window = m_workspace.activeSubWindow();
|
||||
bool maximise = ((!current_window)
|
||||
@@ -2336,6 +2381,7 @@ void QETDiagramEditor::subWindowActivated(QMdiSubWindow *subWindows)
|
||||
|
||||
slot_updateActions();
|
||||
slot_updateWindowsMenu();
|
||||
emit syncElementsPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2471,7 +2517,27 @@ void QETDiagramEditor::generateTerminalBlock()
|
||||
#endif
|
||||
if ( !success ) {
|
||||
QMessageBox::warning(nullptr,
|
||||
QObject::tr("Error launching qet_tb_generator plugin"),
|
||||
message);
|
||||
QObject::tr("Error launching qet_tb_generator plugin"),
|
||||
message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QETDiagramEditor::slot_terminalNumbering
|
||||
* Opens the dialog for automatic terminal numbering and applies the generated undo command.
|
||||
*/
|
||||
void QETDiagramEditor::slot_terminalNumbering() {
|
||||
TerminalNumberingDialog dialog(this);
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
QETProject *project = currentProject();
|
||||
if (!project) return;
|
||||
|
||||
// Fetch the generated undo command from the dialog logic
|
||||
QUndoCommand *macro = dialog.getUndoCommand(project);
|
||||
|
||||
// If changes were made, push them to the global undo stack
|
||||
if (macro) {
|
||||
undo_group.activeStack()->push(macro);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ class RecentFiles;
|
||||
class DiagramPropertiesEditorDockWidget;
|
||||
class ElementsCollectionWidget;
|
||||
class AutoNumberingDockWidget;
|
||||
class TerminalNumberingDialog;
|
||||
|
||||
#ifdef BUILD_WITHOUT_KF5
|
||||
#else
|
||||
@@ -98,6 +99,9 @@ class QETDiagramEditor : public QETMainWindow
|
||||
ProjectView *findProject(const QString &) const;
|
||||
QMdiSubWindow *subWindowForWidget(QWidget *) const;
|
||||
|
||||
signals:
|
||||
void syncElementsPanel();
|
||||
|
||||
public slots:
|
||||
void save();
|
||||
void saveAs();
|
||||
@@ -129,6 +133,7 @@ class QETDiagramEditor : public QETMainWindow
|
||||
void projectWasClosed(ProjectView *);
|
||||
void editProjectProperties(ProjectView *);
|
||||
void editProjectProperties(QETProject *);
|
||||
void slot_terminalNumbering();
|
||||
void editDiagramProperties(DiagramView *);
|
||||
void editDiagramProperties(Diagram *);
|
||||
void addDiagramToProject(QETProject *);
|
||||
@@ -197,6 +202,8 @@ class QETDiagramEditor : public QETMainWindow
|
||||
*m_terminal_strip_dialog = nullptr, ///<Launch terminal strip dialog
|
||||
*m_project_terminalBloc, ///< generate terminal block
|
||||
*m_project_export_conductor_num,///<Export the wire num to csv
|
||||
*m_project_export_wiring_list, ///< Action to export the wiring list
|
||||
*m_terminal_numbering, ///< Action to launch terminal numbering
|
||||
*m_export_project_db, ///Export to file the internal database of the current project
|
||||
*m_tile_window, ///< Show MDI subwindows as tile
|
||||
*m_cascade_window, ///< Show MDI subwindows as cascade
|
||||
|
||||
@@ -1351,6 +1351,7 @@ void DynamicElementTextItem::updateXref()
|
||||
{
|
||||
m_slave_Xref_item = new QGraphicsTextItem(xref_label, this);
|
||||
m_slave_Xref_item->setFont(QETApp::diagramTextsFont(5));
|
||||
m_slave_Xref_item->setDefaultTextColor(Qt::black);
|
||||
m_slave_Xref_item->installSceneEventFilter(this);
|
||||
|
||||
m_update_slave_Xref_connection << connect(m_master_element.data(), &Element::xChanged, this, &DynamicElementTextItem::updateXref);
|
||||
|
||||
@@ -183,3 +183,27 @@ void MasterElement::aboutDeleteXref()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MasterElement::isFull
|
||||
* @return true if the master has reached its maximum number of slaves
|
||||
*/
|
||||
bool MasterElement::isFull() const
|
||||
{
|
||||
// Set default value to -1 (unlimited slaves)
|
||||
int max_slaves = -1;
|
||||
QVariant max_slaves_variant = kindInformations().value("max_slaves");
|
||||
|
||||
// Overwrite default if a valid limit is defined in the element's XML
|
||||
if (max_slaves_variant.isValid() && !max_slaves_variant.toString().isEmpty()) {
|
||||
max_slaves = max_slaves_variant.toInt();
|
||||
}
|
||||
|
||||
// If no limit is set (-1), the master is never full
|
||||
if (max_slaves == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if current connected elements reached or exceeded the limit
|
||||
return connected_elements.size() >= max_slaves;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ class MasterElement : public Element
|
||||
void unlinkElement (Element *elmt) override;
|
||||
void initLink (QETProject *project) override;
|
||||
QRectF XrefBoundingRect() const;
|
||||
|
||||
bool isFull() const; // Check Slave-Limit
|
||||
|
||||
protected:
|
||||
QVariant itemChange(
|
||||
|
||||
@@ -198,6 +198,7 @@ namespace QET {
|
||||
QIcon hu;
|
||||
QIcon it;
|
||||
QIcon jp;
|
||||
QIcon ko;
|
||||
QIcon pl;
|
||||
QIcon pt;
|
||||
QIcon ro;
|
||||
@@ -672,6 +673,7 @@ void QET::Icons::initIcons()
|
||||
hu .addFile(":/ico/24x16/hu.png");
|
||||
it .addFile(":/ico/24x16/it.png");
|
||||
jp .addFile(":/ico/24x16/jp.png");
|
||||
ko .addFile(":/ico/24x16/kr.png");
|
||||
pl .addFile(":/ico/24x16/pl.png");
|
||||
pt .addFile(":/ico/24x16/pt.png");
|
||||
ro .addFile(":/ico/24x16/ro.png");
|
||||
|
||||
@@ -206,6 +206,7 @@ namespace QET {
|
||||
extern QIcon hu;
|
||||
extern QIcon it;
|
||||
extern QIcon jp;
|
||||
extern QIcon ko;
|
||||
extern QIcon pl;
|
||||
extern QIcon pt;
|
||||
extern QIcon ro;
|
||||
|
||||
@@ -131,6 +131,7 @@ void AboutQETDialog::setTranslators()
|
||||
addAuthor(ui->m_translators_label, "Yaroslav", "", tr("Traduction en ukrainien"));
|
||||
addAuthor(ui->m_translators_label, "JoelAs", "", tr("Traduction en norvégien"));
|
||||
addAuthor(ui->m_translators_label, "Yuki", "yuki.atoh@gmail.com", tr("Traduction en japonais"));
|
||||
addAuthor(ui->m_translators_label, "Jung Kwang-Ho", "jkh2rokmc@daum.net", tr("Traduction en coréen"));
|
||||
addAuthor(ui->m_translators_label, "Nathalie", "nathalie.roussier@giz.de", tr("Traduction en mongol"));
|
||||
addAuthor(ui->m_translators_label, "Uroš Platiše", "uros.platise@energycon.eu", tr("Traduction en slovène"));
|
||||
}
|
||||
|
||||
@@ -173,6 +173,15 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
||||
ui->m_custom_tbt_path_cb->blockSignals(false);
|
||||
}
|
||||
|
||||
path = settings.value("elements-collections/macros-path", "default").toString();
|
||||
if (path != "default")
|
||||
{
|
||||
ui->m_user_macros_path_cb->blockSignals(true);
|
||||
ui->m_user_macros_path_cb->setCurrentIndex(1);
|
||||
ui->m_user_macros_path_cb->setItemData(1, path, Qt::DisplayRole);
|
||||
ui->m_user_macros_path_cb->blockSignals(false);
|
||||
}
|
||||
|
||||
fillLang();
|
||||
}
|
||||
|
||||
@@ -315,6 +324,21 @@ void GeneralConfigurationPage::applyConf()
|
||||
if (path != settings.value("elements-collections/custom-tbt-path").toString()) {
|
||||
QETApp::resetCollectionsPath();
|
||||
}
|
||||
|
||||
path = settings.value("elements-collections/macros-path").toString();
|
||||
if (ui->m_user_macros_path_cb->currentIndex() == 1)
|
||||
{
|
||||
QString path = ui->m_user_macros_path_cb->currentText();
|
||||
QDir dir(path);
|
||||
settings.setValue("elements-collections/macros-path",
|
||||
dir.exists() ? path : "default");
|
||||
}
|
||||
else {
|
||||
settings.setValue("elements-collections/macros-path", "default");
|
||||
}
|
||||
if (path != settings.value("elements-collections/macros-path").toString()) {
|
||||
QETApp::resetCollectionsPath();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,6 +382,7 @@ void GeneralConfigurationPage::fillLang()
|
||||
ui->m_lang_cb->addItem(QET::Icons::hr, tr("Croate"), "hr");
|
||||
ui->m_lang_cb->addItem(QET::Icons::it, tr("Italien"), "it");
|
||||
ui->m_lang_cb->addItem(QET::Icons::jp, tr("Japonais"), "ja");
|
||||
ui->m_lang_cb->addItem(QET::Icons::ko, tr("Coréen"), "ko");
|
||||
ui->m_lang_cb->addItem(QET::Icons::pl, tr("Polonais"), "pl");
|
||||
ui->m_lang_cb->addItem(QET::Icons::pt, tr("Portugais"), "pt");
|
||||
ui->m_lang_cb->addItem(QET::Icons::ro, tr("Roumains"), "ro");
|
||||
@@ -505,6 +530,19 @@ void GeneralConfigurationPage::on_m_custom_tbt_path_cb_currentIndexChanged(int i
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralConfigurationPage::on_m_user_macros_path_cb_currentIndexChanged(int index)
|
||||
{
|
||||
if (index == 1)
|
||||
{
|
||||
QString path = QFileDialog::getExistingDirectory(this, tr("Chemin des macros utilisateur"), QETApp::documentDir());
|
||||
if (!path.isEmpty()) {
|
||||
ui->m_user_macros_path_cb->setItemData(1, path, Qt::DisplayRole);
|
||||
}
|
||||
else {
|
||||
ui->m_user_macros_path_cb->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralConfigurationPage::on_m_indi_text_font_pb_clicked()
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ class GeneralConfigurationPage : public ConfigPage
|
||||
void on_m_custom_elmt_path_cb_currentIndexChanged(int index);
|
||||
void on_m_company_tbt_path_cb_currentIndexChanged(int index);
|
||||
void on_m_custom_tbt_path_cb_currentIndexChanged(int index);
|
||||
void on_m_user_macros_path_cb_currentIndexChanged(int index);
|
||||
void on_m_indi_text_font_pb_clicked();
|
||||
void on_MaxPartsElementEditorList_sb_valueChanged(int value);
|
||||
void on_DiagramEditor_Grid_PointSize_min_sb_valueChanged(int value);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
@@ -349,6 +349,27 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Répertoire des Macros utilisateur</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QComboBox" name="m_user_macros_path_cb">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Par defaut</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Parcourir...</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -160,6 +160,7 @@ void ElementInfoWidget::enableLiveEdit()
|
||||
{
|
||||
for (ElementInfoPartWidget *eipw : m_eipw_list)
|
||||
connect(eipw, &ElementInfoPartWidget::textChanged, this, &ElementInfoWidget::apply);
|
||||
connect(ui->m_auto_num_locked_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,6 +171,7 @@ void ElementInfoWidget::disableLiveEdit()
|
||||
{
|
||||
for (ElementInfoPartWidget *eipw : m_eipw_list)
|
||||
disconnect(eipw, &ElementInfoPartWidget::textChanged, this, &ElementInfoWidget::apply);
|
||||
disconnect(ui->m_auto_num_locked_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,6 +195,12 @@ void ElementInfoWidget::buildInterface()
|
||||
}
|
||||
|
||||
ui->scroll_vlayout->addStretch();
|
||||
// Show checkbox only if the element is a terminal
|
||||
if (m_element.data()->elementData().m_type == ElementData::Terminal) {
|
||||
ui->m_auto_num_locked_cb->setVisible(true);
|
||||
} else {
|
||||
ui->m_auto_num_locked_cb->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,6 +239,11 @@ void ElementInfoWidget::updateUi()
|
||||
for (ElementInfoPartWidget *eipw : m_eipw_list) {
|
||||
eipw -> setText (element_info[eipw->key()].toString());
|
||||
}
|
||||
// Load the lock status for auto numbering
|
||||
if (m_element->elementData().m_type == ElementData::Terminal) {
|
||||
QString lock_value = element_info.value(QStringLiteral("auto_num_locked")).toString();
|
||||
ui->m_auto_num_locked_cb->setChecked(lock_value == QLatin1String("true"));
|
||||
}
|
||||
|
||||
if (m_live_edit) {
|
||||
enableLiveEdit();
|
||||
@@ -259,6 +272,10 @@ DiagramContext ElementInfoWidget::currentInfo() const
|
||||
}
|
||||
}
|
||||
|
||||
// Save the auto numbering lock status
|
||||
if (m_element->elementData().m_type == ElementData::Terminal) {
|
||||
info_.addValue(QStringLiteral("auto_num_locked"), ui->m_auto_num_locked_cb->isChecked() ? QStringLiteral("true") : QStringLiteral("false"));
|
||||
}
|
||||
return info_;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,19 @@
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_auto_num_locked_cb">
|
||||
<property name="text">
|
||||
<string>Exclure de la numérotation auto</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">margin: 5px; font-weight: bold;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="sizePolicy">
|
||||
|
||||
@@ -372,6 +372,10 @@ QWidget *ElementPropertiesWidget::generalWidget()
|
||||
description_string += QString(tr("Rotation : %1°\n")).arg(m_element.data()->rotation());
|
||||
description_string += QString(tr("Dimensions : %1*%2\n")).arg(m_element -> size().width()).arg(m_element -> size().height());
|
||||
description_string += QString(tr("Bornes : %1\n")).arg(m_element -> terminals().count());
|
||||
if (m_element->linkType() == Element::Master){
|
||||
description_string += QString(tr("Nombre maximum de contacts esclaves définis : %1\n")).arg(m_element -> elementData().m_max_slaves);
|
||||
description_string += QString(tr("Nombre de contacts esclaves utilisés : %1\n")).arg(m_element ->linkedElements().count());
|
||||
}
|
||||
description_string += QString(tr("Emplacement : %1\n")).arg(m_element.data()->location().toString());
|
||||
|
||||
// widget himself
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "linksingleelementwidget.h"
|
||||
|
||||
#include "../qetgraphicsitem/masterelement.h"
|
||||
#include "../qetgraphicsitem/conductor.h"
|
||||
#include "../diagram.h"
|
||||
#include "../diagramposition.h"
|
||||
@@ -386,7 +386,22 @@ QVector <QPointer<Element>> LinkSingleElementWidget::availableElements()
|
||||
|
||||
//If element is linked, remove is parent from the list
|
||||
if(!m_element->isFree()) elmt_vector.removeAll(m_element->linkedElements().first());
|
||||
|
||||
// Filter out all master elements from the list
|
||||
for (int i = elmt_vector.size() - 1; i >= 0; --i) {
|
||||
Element *elmt = elmt_vector.at(i);
|
||||
|
||||
// If the item in the list is a master
|
||||
if (elmt->linkType() == Element::Master) {
|
||||
|
||||
// We convert the generic element pointer into a MasterElement pointer
|
||||
MasterElement *master = static_cast<MasterElement*>(elmt);
|
||||
|
||||
// If the master is full, we'll remove it from the list!
|
||||
if (master->isFull()) {
|
||||
elmt_vector.removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return elmt_vector;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>389</width>
|
||||
<height>442</height>
|
||||
<height>460</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -64,6 +64,23 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="4" column="0" colspan="3">
|
||||
<widget class="QLabel" name="m_hidden_masters_label">
|
||||
<property name="text">
|
||||
<string>Remarque : les éléments maîtres ayant atteint leur nombre maximal d'esclaves sont masqués.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech 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.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
* Copyright 2006-2026 The QElectroTech Team
|
||||
* This file is part of QElectroTech.
|
||||
*
|
||||
* QElectroTech 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.
|
||||
*
|
||||
* QElectroTech is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "masterpropertieswidget.h"
|
||||
|
||||
#include "../diagram.h"
|
||||
@@ -25,64 +25,65 @@
|
||||
#include "ui_masterpropertieswidget.h"
|
||||
|
||||
#include <QListWidgetItem>
|
||||
#include <QMessageBox>
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::MasterPropertiesWidget
|
||||
Default constructor
|
||||
@param elmt
|
||||
@param parent
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::MasterPropertiesWidget
|
||||
* Default constructor
|
||||
* @param elmt
|
||||
* @param parent
|
||||
*/
|
||||
MasterPropertiesWidget::MasterPropertiesWidget(Element *elmt, QWidget *parent) :
|
||||
AbstractElementPropertiesEditorWidget(parent),
|
||||
ui(new Ui::MasterPropertiesWidget),
|
||||
m_project(nullptr)
|
||||
AbstractElementPropertiesEditorWidget(parent),
|
||||
ui(new Ui::MasterPropertiesWidget),
|
||||
m_project(nullptr)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
||||
ui->m_free_tree_widget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
ui->m_link_tree_widget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
|
||||
QStringList list;
|
||||
QSettings settings;
|
||||
if (settings.value("genericpanel/folio", false).toBool()) {
|
||||
list << tr("Vignette")
|
||||
<< tr("Label de folio")
|
||||
<< tr("Titre de folio")
|
||||
<< tr("Position");
|
||||
<< tr("Label de folio")
|
||||
<< tr("Titre de folio")
|
||||
<< tr("Position");
|
||||
}
|
||||
else {
|
||||
list << tr("Vignette")
|
||||
<< tr("N° de folio")
|
||||
<< tr("Titre de folio")
|
||||
<< tr("Position");
|
||||
<< tr("N° de folio")
|
||||
<< tr("Titre de folio")
|
||||
<< tr("Position");
|
||||
}
|
||||
ui->m_free_tree_widget->setHeaderLabels(list);
|
||||
ui->m_link_tree_widget->setHeaderLabels(list);
|
||||
|
||||
|
||||
m_context_menu = new QMenu(this);
|
||||
m_link_action = new QAction(tr("Lier l'élément"), this);
|
||||
m_unlink_action = new QAction(tr("Délier l'élément"), this);
|
||||
m_show_qtwi = new QAction(tr("Montrer l'élément"), this);
|
||||
m_show_element = new QAction(tr("Montrer l'élément maître"), this);
|
||||
m_save_header_state = new QAction(tr("Enregistrer la disposition"), this);
|
||||
|
||||
|
||||
connect(ui->m_free_tree_widget, &QTreeWidget::itemDoubleClicked,
|
||||
this, &MasterPropertiesWidget::showElementFromTWI);
|
||||
this, &MasterPropertiesWidget::showElementFromTWI);
|
||||
connect(ui->m_link_tree_widget, &QTreeWidget::itemDoubleClicked,
|
||||
this, &MasterPropertiesWidget::showElementFromTWI);
|
||||
|
||||
this, &MasterPropertiesWidget::showElementFromTWI);
|
||||
|
||||
connect(ui->m_free_tree_widget, &QTreeWidget::customContextMenuRequested,
|
||||
[this](QPoint point) {this->customContextMenu(point, 1);});
|
||||
[this](QPoint point) {this->customContextMenu(point, 1);});
|
||||
connect(ui->m_link_tree_widget, &QTreeWidget::customContextMenuRequested,
|
||||
[this](QPoint point) {this->customContextMenu(point, 2);});
|
||||
|
||||
[this](QPoint point) {this->customContextMenu(point, 2);});
|
||||
|
||||
connect(m_link_action, &QAction::triggered,
|
||||
this, &MasterPropertiesWidget::on_link_button_clicked);
|
||||
this, &MasterPropertiesWidget::on_link_button_clicked);
|
||||
connect(m_unlink_action, &QAction::triggered,
|
||||
this, &MasterPropertiesWidget::on_unlink_button_clicked);
|
||||
this, &MasterPropertiesWidget::on_unlink_button_clicked);
|
||||
connect(m_show_qtwi, &QAction::triggered,
|
||||
[this]() {this->showElementFromTWI(this->m_qtwi_at_context_menu,0);});
|
||||
|
||||
[this]() {this->showElementFromTWI(this->m_qtwi_at_context_menu,0);});
|
||||
|
||||
connect(m_show_element, &QAction::triggered, [this]()
|
||||
{
|
||||
this->m_element->diagram()->showMe();
|
||||
@@ -90,46 +91,46 @@ MasterPropertiesWidget::MasterPropertiesWidget(Element *elmt, QWidget *parent) :
|
||||
if(this->m_showed_element)
|
||||
m_showed_element->setHighlighted(false);
|
||||
});
|
||||
|
||||
|
||||
QHeaderView *qhv = ui->m_free_tree_widget->header();
|
||||
qhv->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(qhv, &QHeaderView::customContextMenuRequested,
|
||||
this, &MasterPropertiesWidget::headerCustomContextMenuRequested);
|
||||
this, &MasterPropertiesWidget::headerCustomContextMenuRequested);
|
||||
connect(m_save_header_state, &QAction::triggered, [qhv]()
|
||||
{
|
||||
QByteArray qba = qhv->saveState();
|
||||
QSettings settings;
|
||||
settings.setValue("link-element-widget/master-state", qba);
|
||||
});
|
||||
|
||||
|
||||
setElement(elmt);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::~MasterPropertiesWidget
|
||||
Destructor
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::~MasterPropertiesWidget
|
||||
* Destructor
|
||||
*/
|
||||
MasterPropertiesWidget::~MasterPropertiesWidget()
|
||||
{
|
||||
if (m_showed_element)
|
||||
m_showed_element->setHighlighted(false);
|
||||
|
||||
|
||||
if(m_element)
|
||||
m_element->setHighlighted(false);
|
||||
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::setElement
|
||||
Set the element to be edited
|
||||
@param element
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::setElement
|
||||
* Set the element to be edited
|
||||
* @param element
|
||||
*/
|
||||
void MasterPropertiesWidget::setElement(Element *element)
|
||||
{
|
||||
if (m_element == element)
|
||||
return;
|
||||
|
||||
|
||||
if (m_showed_element)
|
||||
{
|
||||
m_showed_element->setHighlighted(false);
|
||||
@@ -137,40 +138,40 @@ void MasterPropertiesWidget::setElement(Element *element)
|
||||
}
|
||||
if (m_element)
|
||||
m_element->setHighlighted(false);
|
||||
|
||||
|
||||
if (m_project)
|
||||
disconnect(m_project, SIGNAL(diagramRemoved(QETProject*,Diagram*)),
|
||||
this, SLOT(diagramWasdeletedFromProject()));
|
||||
this, SLOT(diagramWasdeletedFromProject()));
|
||||
|
||||
if(Q_LIKELY(element->diagram() && element->diagram()->project()))
|
||||
{
|
||||
m_project = element->diagram()->project();
|
||||
connect(m_project, SIGNAL(diagramRemoved(QETProject*,Diagram*)),
|
||||
this, SLOT(diagramWasdeletedFromProject()));
|
||||
}
|
||||
else
|
||||
m_project = nullptr;
|
||||
if(Q_LIKELY(element->diagram() && element->diagram()->project()))
|
||||
{
|
||||
m_project = element->diagram()->project();
|
||||
connect(m_project, SIGNAL(diagramRemoved(QETProject*,Diagram*)),
|
||||
this, SLOT(diagramWasdeletedFromProject()));
|
||||
}
|
||||
else
|
||||
m_project = nullptr;
|
||||
|
||||
//Keep up to date this widget when the linked elements of m_element change
|
||||
if (m_element)
|
||||
disconnect(m_element.data(), &Element::linkedElementChanged,
|
||||
this, &MasterPropertiesWidget::updateUi);
|
||||
|
||||
m_element = element;
|
||||
this, &MasterPropertiesWidget::updateUi);
|
||||
|
||||
m_element = element;
|
||||
connect(m_element.data(), &Element::linkedElementChanged,
|
||||
this, &MasterPropertiesWidget::updateUi);
|
||||
this, &MasterPropertiesWidget::updateUi);
|
||||
|
||||
updateUi();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::apply
|
||||
If link between edited element and other change,
|
||||
apply the change with a QUndoCommand (got with method associatedUndo)
|
||||
pushed to the stack of element project.
|
||||
Return true if link change, else false
|
||||
@note is void no Return ???
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::apply
|
||||
* If link between edited element and other change,
|
||||
* apply the change with a QUndoCommand (got with method associatedUndo)
|
||||
* pushed to the stack of element project.
|
||||
* Return true if link change, else false
|
||||
* @note is void no Return ???
|
||||
*/
|
||||
void MasterPropertiesWidget::apply()
|
||||
{
|
||||
if (QUndoCommand *undo = associatedUndo())
|
||||
@@ -178,25 +179,25 @@ void MasterPropertiesWidget::apply()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::reset
|
||||
Reset current widget, clear eveything and rebuild widget.
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::reset
|
||||
* Reset current widget, clear eveything and rebuild widget.
|
||||
*/
|
||||
void MasterPropertiesWidget::reset()
|
||||
{
|
||||
foreach (QTreeWidgetItem *qtwi, m_qtwi_hash.keys())
|
||||
delete qtwi;
|
||||
|
||||
|
||||
m_qtwi_hash.clear();
|
||||
updateUi();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::associatedUndo
|
||||
If link between the edited element and other change,
|
||||
return a QUndoCommand with this change.
|
||||
If no change return nullptr.
|
||||
@return
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::associatedUndo
|
||||
* If link between the edited element and other change,
|
||||
* return a QUndoCommand with this change.
|
||||
* If no change return nullptr.
|
||||
* @return
|
||||
*/
|
||||
QUndoCommand* MasterPropertiesWidget::associatedUndo() const
|
||||
{
|
||||
QList <Element *> to_link;
|
||||
@@ -205,7 +206,7 @@ QUndoCommand* MasterPropertiesWidget::associatedUndo() const
|
||||
for (int i=0; i<ui->m_link_tree_widget->topLevelItemCount(); i++)
|
||||
to_link << m_qtwi_hash[ui->m_link_tree_widget->topLevelItem(i)];
|
||||
|
||||
//The two list contain the same element, there is no change
|
||||
//The two list contain the same element, there is no change
|
||||
if (to_link.size() == linked_.size())
|
||||
{
|
||||
bool equal = true;
|
||||
@@ -229,11 +230,11 @@ QUndoCommand* MasterPropertiesWidget::associatedUndo() const
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::setLiveEdit
|
||||
@param live_edit = true : live edit is enable
|
||||
else false : live edit is disable.
|
||||
@return always true because live edit is handled by this editor widget
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::setLiveEdit
|
||||
* @param live_edit = true : live edit is enable
|
||||
* else false : live edit is disable.
|
||||
* @return always true because live edit is handled by this editor widget
|
||||
*/
|
||||
bool MasterPropertiesWidget::setLiveEdit(bool live_edit)
|
||||
{
|
||||
m_live_edit = live_edit;
|
||||
@@ -241,9 +242,9 @@ bool MasterPropertiesWidget::setLiveEdit(bool live_edit)
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::updateUi
|
||||
Build the interface of the widget
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::updateUi
|
||||
* Build the interface of the widget
|
||||
*/
|
||||
void MasterPropertiesWidget::updateUi()
|
||||
{
|
||||
ui->m_free_tree_widget->clear();
|
||||
@@ -256,75 +257,75 @@ void MasterPropertiesWidget::updateUi()
|
||||
ElementProvider elmt_prov(m_project);
|
||||
QSettings settings;
|
||||
|
||||
//Build the list of free available element
|
||||
//Build the list of free available element
|
||||
QList <QTreeWidgetItem *> items_list;
|
||||
for(const auto &elmt : elmt_prov.freeElement(ElementData::Slave))
|
||||
{
|
||||
QTreeWidgetItem *qtwi = new QTreeWidgetItem(ui->m_free_tree_widget);
|
||||
qtwi->setIcon(0, elmt->pixmap());
|
||||
|
||||
|
||||
if(settings.value("genericpanel/folio", false).toBool())
|
||||
{
|
||||
autonum::sequentialNumbers seq;
|
||||
QString F =autonum::AssignVariables::formulaToLabel(
|
||||
elmt->diagram()->border_and_titleblock.folio(),
|
||||
seq,
|
||||
elmt->diagram(),
|
||||
elmt);
|
||||
elmt->diagram()->border_and_titleblock.folio(),
|
||||
seq,
|
||||
elmt->diagram(),
|
||||
elmt);
|
||||
qtwi->setText(1, F);
|
||||
}
|
||||
else
|
||||
{
|
||||
qtwi->setText(1, QString::number(
|
||||
elmt->diagram()->folioIndex()
|
||||
+ 1));
|
||||
elmt->diagram()->folioIndex()
|
||||
+ 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
qtwi->setText(2, elmt->diagram()->title());
|
||||
qtwi->setText(4, elmt->diagram()->convertPosition(
|
||||
elmt->scenePos()).toString());
|
||||
elmt->scenePos()).toString());
|
||||
items_list.append(qtwi);
|
||||
m_qtwi_hash.insert(qtwi, elmt);
|
||||
}
|
||||
|
||||
|
||||
ui->m_free_tree_widget->addTopLevelItems(items_list);
|
||||
items_list.clear();
|
||||
|
||||
//Build the list of already linked element
|
||||
//Build the list of already linked element
|
||||
const QList<Element *> link_list = m_element->linkedElements();
|
||||
for(Element *elmt : link_list)
|
||||
{
|
||||
QTreeWidgetItem *qtwi = new QTreeWidgetItem(ui->m_link_tree_widget);
|
||||
qtwi->setIcon(0, elmt->pixmap());
|
||||
|
||||
|
||||
if(settings.value("genericpanel/folio", false).toBool())
|
||||
{
|
||||
autonum::sequentialNumbers seq;
|
||||
QString F =autonum::AssignVariables::formulaToLabel(
|
||||
elmt->diagram()->border_and_titleblock.folio(),
|
||||
seq,
|
||||
elmt->diagram(),
|
||||
elmt);
|
||||
elmt->diagram()->border_and_titleblock.folio(),
|
||||
seq,
|
||||
elmt->diagram(),
|
||||
elmt);
|
||||
qtwi->setText(1, F);
|
||||
}
|
||||
else
|
||||
{
|
||||
qtwi->setText(1, QString::number(
|
||||
elmt->diagram()->folioIndex()
|
||||
+ 1));
|
||||
elmt->diagram()->folioIndex()
|
||||
+ 1));
|
||||
}
|
||||
|
||||
qtwi->setText(2, elmt->diagram()->title());
|
||||
qtwi->setText(3, elmt->diagram()->convertPosition(
|
||||
elmt->scenePos()).toString());
|
||||
elmt->scenePos()).toString());
|
||||
items_list.append(qtwi);
|
||||
m_qtwi_hash.insert(qtwi, elmt);
|
||||
}
|
||||
|
||||
|
||||
if(items_list.count())
|
||||
ui->m_link_tree_widget->addTopLevelItems(items_list);
|
||||
|
||||
|
||||
QVariant v = settings.value("link-element-widget/master-state");
|
||||
if(!v.isNull())
|
||||
{
|
||||
@@ -334,9 +335,9 @@ void MasterPropertiesWidget::updateUi()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::headerCustomContextMenuRequested
|
||||
@param pos
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::headerCustomContextMenuRequested
|
||||
* @param pos
|
||||
*/
|
||||
void MasterPropertiesWidget::headerCustomContextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
m_context_menu->clear();
|
||||
@@ -345,36 +346,57 @@ void MasterPropertiesWidget::headerCustomContextMenuRequested(const QPoint &pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::on_link_button_clicked
|
||||
move current item in the free_list to linked_list
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::on_link_button_clicked
|
||||
* Moves the current item from the free_list to the linked_list,
|
||||
* provided the master's slave limit has not been reached.
|
||||
*/
|
||||
void MasterPropertiesWidget::on_link_button_clicked()
|
||||
{
|
||||
//take the current item from free_list and push it to linked_list
|
||||
// Get the maximum number of allowed slaves from the element's information
|
||||
QVariant max_slaves_variant = m_element->kindInformations().value("max_slaves");
|
||||
|
||||
if (max_slaves_variant.isValid() && !max_slaves_variant.toString().isEmpty()) {
|
||||
int max_slaves = max_slaves_variant.toInt();
|
||||
int current_slaves = ui->m_link_tree_widget->topLevelItemCount();
|
||||
|
||||
// If a limit is set and reached
|
||||
if (max_slaves != -1 && current_slaves >= max_slaves) {
|
||||
|
||||
|
||||
// Show a message box with the actual window as parent to ensure it's on top
|
||||
QMessageBox::warning(this->window(),
|
||||
tr("Nombre maximal d'esclaves atteint."),
|
||||
tr("Cet élément maître ne peut plus accepter aucun nouveau contact esclave, la limite fixée a été atteinte (Limite: %1).").arg(max_slaves));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Move current item from free_list to linked_list
|
||||
QTreeWidgetItem *qtwi = ui->m_free_tree_widget->currentItem();
|
||||
if (qtwi)
|
||||
{
|
||||
ui->m_free_tree_widget->takeTopLevelItem(
|
||||
ui->m_free_tree_widget->indexOfTopLevelItem(qtwi));
|
||||
ui->m_free_tree_widget->indexOfTopLevelItem(qtwi));
|
||||
ui->m_link_tree_widget->insertTopLevelItem(0, qtwi);
|
||||
|
||||
|
||||
if(m_live_edit)
|
||||
apply();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::on_unlink_button_clicked
|
||||
move current item in linked_list to free_list
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::on_unlink_button_clicked
|
||||
* move current item in linked_list to free_list
|
||||
*/
|
||||
void MasterPropertiesWidget::on_unlink_button_clicked()
|
||||
{
|
||||
//take the current item from linked_list and push it to free_list
|
||||
//take the current item from linked_list and push it to free_list
|
||||
QTreeWidgetItem *qtwi = ui->m_link_tree_widget->currentItem();
|
||||
if(qtwi)
|
||||
{
|
||||
ui->m_link_tree_widget->takeTopLevelItem(
|
||||
ui->m_link_tree_widget->indexOfTopLevelItem(qtwi));
|
||||
ui->m_link_tree_widget->indexOfTopLevelItem(qtwi));
|
||||
ui->m_free_tree_widget->insertTopLevelItem(0, qtwi);
|
||||
|
||||
if(m_live_edit)
|
||||
@@ -383,18 +405,18 @@ void MasterPropertiesWidget::on_unlink_button_clicked()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::showElementFromTWI
|
||||
Show the element corresponding to the given QTreeWidgetItem
|
||||
@param qtwi
|
||||
@param column
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::showElementFromTWI
|
||||
* Show the element corresponding to the given QTreeWidgetItem
|
||||
* @param qtwi
|
||||
* @param column
|
||||
*/
|
||||
void MasterPropertiesWidget::showElementFromTWI(QTreeWidgetItem *qtwi, int column)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
if (m_showed_element)
|
||||
{
|
||||
disconnect(m_showed_element, SIGNAL(destroyed()),
|
||||
this, SLOT(showedElementWasDeleted()));
|
||||
this, SLOT(showedElementWasDeleted()));
|
||||
m_showed_element -> setHighlighted(false);
|
||||
}
|
||||
if (m_element)
|
||||
@@ -404,23 +426,23 @@ void MasterPropertiesWidget::showElementFromTWI(QTreeWidgetItem *qtwi, int colum
|
||||
m_showed_element->diagram()->showMe();
|
||||
m_showed_element->setHighlighted(true);
|
||||
connect(m_showed_element, SIGNAL(destroyed()),
|
||||
this, SLOT(showedElementWasDeleted()));
|
||||
this, SLOT(showedElementWasDeleted()));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::showedElementWasDeleted
|
||||
Set to nullptr the current showed element when he was deleted
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::showedElementWasDeleted
|
||||
* Set to nullptr the current showed element when he was deleted
|
||||
*/
|
||||
void MasterPropertiesWidget::showedElementWasDeleted()
|
||||
{
|
||||
m_showed_element = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::diagramWasdeletedFromProject
|
||||
This slot is called when a diagram is removed from the parent project
|
||||
of edited element to update the content of this widget
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::diagramWasdeletedFromProject
|
||||
* This slot is called when a diagram is removed from the parent project
|
||||
* of edited element to update the content of this widget
|
||||
*/
|
||||
void MasterPropertiesWidget::diagramWasdeletedFromProject()
|
||||
{
|
||||
// We use a timer because if the removed diagram
|
||||
@@ -431,11 +453,11 @@ void MasterPropertiesWidget::diagramWasdeletedFromProject()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::customContextMenu
|
||||
Display a context menu
|
||||
@param pos
|
||||
@param i : the tree widget where the context menu was requested.
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::customContextMenu
|
||||
* Display a context menu
|
||||
* @param pos
|
||||
* @param i : the tree widget where the context menu was requested.
|
||||
*/
|
||||
void MasterPropertiesWidget::customContextMenu(const QPoint &pos, int i)
|
||||
{
|
||||
// add the size of the header to display the topleft of the QMenu
|
||||
@@ -444,14 +466,14 @@ void MasterPropertiesWidget::customContextMenu(const QPoint &pos, int i)
|
||||
// section related to QAbstractScrollArea
|
||||
QPoint point = pos;
|
||||
point.ry()+=ui->m_free_tree_widget->header()->height();
|
||||
|
||||
|
||||
m_context_menu->clear();
|
||||
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
point = ui->m_free_tree_widget->mapToGlobal(point);
|
||||
|
||||
//Context at for free tree widget
|
||||
|
||||
//Context at for free tree widget
|
||||
if (ui->m_free_tree_widget->currentItem())
|
||||
{
|
||||
m_qtwi_at_context_menu = ui->m_free_tree_widget->currentItem();
|
||||
@@ -462,8 +484,8 @@ void MasterPropertiesWidget::customContextMenu(const QPoint &pos, int i)
|
||||
else
|
||||
{
|
||||
point = ui->m_link_tree_widget->mapToGlobal(point);
|
||||
|
||||
//context at for link tre widget
|
||||
|
||||
//context at for link tre widget
|
||||
if (ui->m_link_tree_widget->currentItem())
|
||||
{
|
||||
m_qtwi_at_context_menu = ui->m_link_tree_widget->currentItem();
|
||||
@@ -471,7 +493,7 @@ void MasterPropertiesWidget::customContextMenu(const QPoint &pos, int i)
|
||||
m_context_menu->addAction(m_show_qtwi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_context_menu->addAction(m_show_element);
|
||||
m_context_menu->popup(point);
|
||||
}
|
||||
|
||||
178
sources/ui/terminalnumberingdialog.cpp
Normal file
178
sources/ui/terminalnumberingdialog.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#include "terminalnumberingdialog.h"
|
||||
#include "ui_terminalnumberingdialog.h"
|
||||
#include "../qetproject.h"
|
||||
#include "../diagram.h"
|
||||
#include "../qetgraphicsitem/element.h"
|
||||
#include "../undocommand/changeelementinformationcommand.h"
|
||||
#include <QUndoCommand>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::TerminalNumberingDialog
|
||||
* Constructor
|
||||
* @param parent
|
||||
*/
|
||||
TerminalNumberingDialog::TerminalNumberingDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::TerminalNumberingDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::~TerminalNumberingDialog
|
||||
* Destructor
|
||||
*/
|
||||
TerminalNumberingDialog::~TerminalNumberingDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::isXAxisPriority
|
||||
* @return true if X axis has priority, false if Y axis has priority
|
||||
*/
|
||||
bool TerminalNumberingDialog::isXAxisPriority() const
|
||||
{
|
||||
return ui->rb_priority_x->isChecked();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::isAlphanumeric
|
||||
* @return true if alphanumeric sorting is enabled, false if numeric only
|
||||
*/
|
||||
bool TerminalNumberingDialog::isAlphanumeric() const
|
||||
{
|
||||
return ui->rb_type_alpha->isChecked();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::getUndoCommand
|
||||
* Scans the given project for terminals, sorts them according to user preferences
|
||||
* (X/Y axis, alphanumeric rules), and generates an undo command containing all label changes.
|
||||
* * @param project Pointer to the current QETProject
|
||||
* @return QUndoCommand* containing the modifications, or nullptr if no changes are needed.
|
||||
*/
|
||||
QUndoCommand* TerminalNumberingDialog::getUndoCommand(QETProject *project) const {
|
||||
if (!project) return nullptr;
|
||||
|
||||
bool axisX = isXAxisPriority();
|
||||
bool alpha = isAlphanumeric();
|
||||
|
||||
// 1. Helper structure to store and sort terminal data
|
||||
struct TermInfo {
|
||||
Element *elmt;
|
||||
QString prefix;
|
||||
QString suffix;
|
||||
int folioIndex;
|
||||
qreal x;
|
||||
qreal y;
|
||||
};
|
||||
QList<TermInfo> termList;
|
||||
|
||||
// 2. Collect all terminals from all folios in the project
|
||||
foreach (Diagram *diagram, project->diagrams()) {
|
||||
int fIndex = diagram->folioIndex();
|
||||
foreach (QGraphicsItem *qgi, diagram->items()) {
|
||||
if (Element *elmt = qgraphicsitem_cast<Element *>(qgi)) {
|
||||
|
||||
// Check if the element is actually a terminal
|
||||
if (elmt->elementData().m_type == ElementData::Terminal) {
|
||||
DiagramContext info = elmt->elementInformations();
|
||||
|
||||
// Ignore locked terminals (if the user checked a 'lock' property)
|
||||
if (info.value(QStringLiteral("auto_num_locked")).toString() == QLatin1String("true")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString label = elmt->actualLabel();
|
||||
if (label.isEmpty()) continue;
|
||||
|
||||
// Split prefix (e.g., "-X1") and suffix (e.g., "1" or "A")
|
||||
QString prefix = label;
|
||||
QString suffix = "";
|
||||
int colonIndex = label.lastIndexOf(':');
|
||||
if (colonIndex != -1) {
|
||||
prefix = label.left(colonIndex);
|
||||
suffix = label.mid(colonIndex + 1);
|
||||
}
|
||||
|
||||
// If user chose purely numeric, skip terminals with alphabetical suffixes
|
||||
if (!alpha && !suffix.isEmpty()) {
|
||||
bool isNum;
|
||||
suffix.toInt(&isNum);
|
||||
if (!isNum) continue;
|
||||
}
|
||||
|
||||
TermInfo ti;
|
||||
ti.elmt = elmt;
|
||||
ti.prefix = prefix;
|
||||
ti.suffix = suffix;
|
||||
ti.folioIndex = fIndex;
|
||||
ti.x = elmt->pos().x();
|
||||
ti.y = elmt->pos().y();
|
||||
termList.append(ti);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Sort terminals based on user selection (X or Y axis priority)
|
||||
std::sort(termList.begin(), termList.end(), [axisX](const TermInfo &a, const TermInfo &b) {
|
||||
// First sort by BMK Prefix alphabetically (case insensitive)
|
||||
int prefixCmp = a.prefix.compare(b.prefix, Qt::CaseInsensitive);
|
||||
if (prefixCmp != 0) return prefixCmp < 0;
|
||||
|
||||
// Then sort by folio (page) index
|
||||
if (a.folioIndex != b.folioIndex) return a.folioIndex < b.folioIndex;
|
||||
|
||||
// Finally sort by coordinates (with a 1.0px tolerance to handle slight misalignments)
|
||||
if (axisX) {
|
||||
if (qAbs(a.x - b.x) > 1.0) return a.x < b.x;
|
||||
return a.y < b.y;
|
||||
} else {
|
||||
if (qAbs(a.y - b.y) > 1.0) return a.y < b.y;
|
||||
return a.x < b.x;
|
||||
}
|
||||
});
|
||||
|
||||
// 4. Generate new numbering and create the undo command macro
|
||||
QUndoCommand *macro = new QUndoCommand(QObject::tr("Automatic terminal numbering"));
|
||||
QMap<QString, int> counters;
|
||||
|
||||
foreach (const TermInfo &ti, termList) {
|
||||
// Increment the counter for this terminal block (e.g., "-X3")
|
||||
counters[ti.prefix]++;
|
||||
int newNum = counters[ti.prefix];
|
||||
|
||||
// Determine if the original suffix was a pure number
|
||||
QString newLabel;
|
||||
bool isNum;
|
||||
ti.suffix.toInt(&isNum);
|
||||
|
||||
if (isNum || ti.suffix.isEmpty()) {
|
||||
// If it was a number (e.g., "1") or empty, update it with the new counter
|
||||
newLabel = ti.prefix + ":" + QString::number(newNum);
|
||||
} else {
|
||||
// If it was alphabetical (e.g., "N", "PE"), keep the original text but consume the count!
|
||||
newLabel = ti.prefix + ":" + ti.suffix;
|
||||
}
|
||||
|
||||
DiagramContext oldInfo = ti.elmt->elementInformations();
|
||||
DiagramContext newInfo = oldInfo;
|
||||
newInfo.addValue(QStringLiteral("label"), newLabel);
|
||||
|
||||
// Create an undo command only if the label actually changes
|
||||
if (oldInfo != newInfo) {
|
||||
new ChangeElementInformationCommand(ti.elmt, oldInfo, newInfo, macro);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Return the macro if it contains changes, otherwise delete and return null
|
||||
if (macro->childCount() > 0) {
|
||||
return macro;
|
||||
} else {
|
||||
delete macro;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
35
sources/ui/terminalnumberingdialog.h
Normal file
35
sources/ui/terminalnumberingdialog.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef TERMINALNUMBERINGDIALOG_H
|
||||
#define TERMINALNUMBERINGDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QETProject;
|
||||
class QUndoCommand;
|
||||
|
||||
namespace Ui {
|
||||
class TerminalNumberingDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The TerminalNumberingDialog class
|
||||
* Dialog to configure the automatic numbering of terminals.
|
||||
*/
|
||||
class TerminalNumberingDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TerminalNumberingDialog(QWidget *parent = nullptr);
|
||||
~TerminalNumberingDialog();
|
||||
|
||||
// Getters for the user's choices
|
||||
bool isXAxisPriority() const;
|
||||
bool isAlphanumeric() const;
|
||||
|
||||
QUndoCommand* getUndoCommand(QETProject *project) const;
|
||||
|
||||
private:
|
||||
Ui::TerminalNumberingDialog *ui;
|
||||
};
|
||||
|
||||
#endif // TERMINALNUMBERINGDIALOG_H
|
||||
139
sources/ui/terminalnumberingdialog.ui
Normal file
139
sources/ui/terminalnumberingdialog.ui
Normal file
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TerminalNumberingDialog</class>
|
||||
<widget class="QDialog" name="TerminalNumberingDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Numérotation automatique des bornes</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_description">
|
||||
<property name="text">
|
||||
<string>Cette fonction numérote les bornes du projet selon leur position. Les bornes vides ou verrouillées sont ignorées.Le marquage des bornes doit être configuré au préalable comme suit : '-X:AB'. La partie avant les deux-points (le bornier) peut être nommée au choix. 'AB' peut être composé de chiffres ou de lettres."</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_axis">
|
||||
<property name="title">
|
||||
<string>Priorité des axes</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_priority_x">
|
||||
<property name="text">
|
||||
<string>Priorité à l'axe X (horizontal)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_priority_y">
|
||||
<property name="text">
|
||||
<string>Priorité à l'axe Y (vertical)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_type">
|
||||
<property name="title">
|
||||
<string>Type de numérotation</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_type_num">
|
||||
<property name="text">
|
||||
<string>Numérique uniquement (1, 2, 3...)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_type_alpha">
|
||||
<property name="text">
|
||||
<string>Alphanumérique (A, B, C... 1, 2...)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>TerminalNumberingDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>TerminalNumberingDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
290
sources/wiringlistexport.cpp
Normal file
290
sources/wiringlistexport.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
#include "wiringlistexport.h"
|
||||
#include "qetproject.h"
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QTextStream>
|
||||
#include <QDomDocument>
|
||||
#include <QFile>
|
||||
#include <QRegularExpression>
|
||||
#include <QQueue>
|
||||
#include <QSet>
|
||||
|
||||
WiringListExport::WiringListExport(QETProject *project, QWidget *parent) :
|
||||
QObject(parent),
|
||||
m_project(project),
|
||||
m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QString WiringListExport::normalizeUuid(const QString &u) const
|
||||
{
|
||||
QString res = u;
|
||||
res.remove('{').remove('}');
|
||||
return res.trimmed().toLower();
|
||||
}
|
||||
|
||||
QString WiringListExport::findDiagramFolio(const QDomElement &diagramElem) const
|
||||
{
|
||||
if (diagramElem.isNull()) return "";
|
||||
if (diagramElem.hasAttribute("folio")) return diagramElem.attribute("folio");
|
||||
if (diagramElem.hasAttribute("title")) return diagramElem.attribute("title");
|
||||
return "";
|
||||
}
|
||||
|
||||
QDomElement WiringListExport::climbToDiagram(QDomNode node) const
|
||||
{
|
||||
while (!node.isNull()) {
|
||||
if (node.isElement() && node.toElement().tagName().toLower() == "diagram") {
|
||||
return node.toElement();
|
||||
}
|
||||
node = node.parentNode();
|
||||
}
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
QMap<QString, ElementInfo> WiringListExport::collectElementsInfo(const QDomElement &root) const
|
||||
{
|
||||
QMap<QString, ElementInfo> infoMap;
|
||||
QDomNodeList elements = root.elementsByTagName("element");
|
||||
|
||||
for (int i = 0; i < elements.size(); ++i) {
|
||||
QDomElement el = elements.at(i).toElement();
|
||||
QString uuid = normalizeUuid(el.attribute("uuid", el.attribute("id", "")));
|
||||
if (uuid.isEmpty()) continue;
|
||||
|
||||
ElementInfo info;
|
||||
info.folio = findDiagramFolio(climbToDiagram(el));
|
||||
|
||||
QDomElement linksNode = el.firstChildElement("links_uuids");
|
||||
if (!linksNode.isNull()) {
|
||||
QDomNodeList linkUuids = linksNode.elementsByTagName("link_uuid");
|
||||
for (int j = 0; j < linkUuids.size(); ++j) {
|
||||
QString luuid = normalizeUuid(linkUuids.at(j).toElement().attribute("uuid"));
|
||||
if (!luuid.isEmpty()) info.links.append(luuid);
|
||||
}
|
||||
}
|
||||
|
||||
QDomElement elInfoNode = el.firstChildElement("elementInformations");
|
||||
if (!elInfoNode.isNull()) {
|
||||
QDomNodeList eics = elInfoNode.elementsByTagName("elementInformation");
|
||||
for (int j = 0; j < eics.size(); ++j) {
|
||||
QDomElement eic = eics.at(j).toElement();
|
||||
QString nameAttr = eic.attribute("name").toLower();
|
||||
if (nameAttr == "label") info.label = eic.text().trimmed();
|
||||
if (nameAttr == "name") info.name = eic.text().trimmed();
|
||||
}
|
||||
}
|
||||
|
||||
QString typeVal = el.attribute("type").toLower();
|
||||
if (typeVal.contains("naechste") || typeVal.contains("vorherige") ||
|
||||
typeVal.contains("next") || typeVal.contains("previous")) {
|
||||
info.isPlaceholder = true;
|
||||
}
|
||||
|
||||
infoMap.insert(uuid, info);
|
||||
}
|
||||
return infoMap;
|
||||
}
|
||||
|
||||
QList<ConductorData> WiringListExport::collectConductors(const QDomElement &root) const
|
||||
{
|
||||
QList<ConductorData> conductors;
|
||||
QDomNodeList conductorNodes = root.elementsByTagName("conductor");
|
||||
|
||||
for (int i = 0; i < conductorNodes.size(); ++i) {
|
||||
QDomElement cond = conductorNodes.at(i).toElement();
|
||||
|
||||
if (cond.attribute("num") == "Brücke") continue;
|
||||
|
||||
ConductorData data;
|
||||
data.index = i;
|
||||
data.el1_uuid = normalizeUuid(cond.attribute("element1", cond.attribute("element1id", "")));
|
||||
data.el2_uuid = normalizeUuid(cond.attribute("element2", cond.attribute("element2id", "")));
|
||||
|
||||
data.element1_label = cond.attribute("element1_label");
|
||||
data.element2_label = cond.attribute("element2_label");
|
||||
data.terminalname1 = cond.attribute("terminalname1");
|
||||
data.terminalname2 = cond.attribute("terminalname2");
|
||||
data.tension_protocol = cond.attribute("tension_protocol");
|
||||
data.conductor_color = cond.attribute("conductor_color");
|
||||
data.conductor_section = cond.attribute("conductor_section");
|
||||
data.function = cond.attribute("function");
|
||||
|
||||
QDomElement diag = climbToDiagram(cond);
|
||||
data.folio = findDiagramFolio(diag);
|
||||
if (data.folio.isEmpty()) data.folio = cond.attribute("folio", cond.attribute("page", ""));
|
||||
|
||||
conductors.append(data);
|
||||
}
|
||||
return conductors;
|
||||
}
|
||||
|
||||
void WiringListExport::resolveEndpoints(QList<ConductorData> &conductors, const QMap<QString, ElementInfo> &elementsInfo) const
|
||||
{
|
||||
QRegularExpression numericLabelRe("^\\d+(\\.\\d+)?$");
|
||||
|
||||
QMap<QString, QList<ConductorData>> el_to_cons;
|
||||
for (const ConductorData &c : conductors) {
|
||||
if (!c.el1_uuid.isEmpty()) el_to_cons[c.el1_uuid].append(c);
|
||||
if (!c.el2_uuid.isEmpty()) el_to_cons[c.el2_uuid].append(c);
|
||||
}
|
||||
|
||||
for (int i = 0; i < conductors.size(); ++i) {
|
||||
ConductorData &c = conductors[i];
|
||||
|
||||
auto resolveSide = [&](const QString &startUuid, QString &outLabel, QString &outTerminal) {
|
||||
if (startUuid.isEmpty() || !elementsInfo.contains(startUuid)) return;
|
||||
|
||||
const ElementInfo &startInfo = elementsInfo[startUuid];
|
||||
if (!startInfo.links.isEmpty() || startInfo.isPlaceholder) {
|
||||
QQueue<QString> q;
|
||||
QSet<QString> visited;
|
||||
q.enqueue(startUuid);
|
||||
visited.insert(startUuid);
|
||||
|
||||
int depth = 0;
|
||||
while (!q.isEmpty() && depth < 3) {
|
||||
int levelSize = q.size();
|
||||
for (int k = 0; k < levelSize; ++k) {
|
||||
QString curr = q.dequeue();
|
||||
|
||||
if (elementsInfo.contains(curr)) {
|
||||
const ElementInfo &currInfo = elementsInfo[curr];
|
||||
|
||||
if (!currInfo.isPlaceholder && !currInfo.label.isEmpty() && !numericLabelRe.match(currInfo.label).hasMatch()) {
|
||||
outLabel = currInfo.label;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const QString &lnk : currInfo.links) {
|
||||
if (!visited.contains(lnk)) {
|
||||
visited.insert(lnk);
|
||||
q.enqueue(lnk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const ConductorData &cond : el_to_cons.value(curr)) {
|
||||
if (cond.index == c.index) continue;
|
||||
|
||||
QString other;
|
||||
QString terminalHint;
|
||||
if (cond.el1_uuid == curr) {
|
||||
other = cond.el2_uuid;
|
||||
terminalHint = cond.terminalname2;
|
||||
} else {
|
||||
other = cond.el1_uuid;
|
||||
terminalHint = cond.terminalname1;
|
||||
}
|
||||
|
||||
if (!other.isEmpty() && !visited.contains(other)) {
|
||||
if (elementsInfo.contains(other)) {
|
||||
const ElementInfo &oInfo = elementsInfo[other];
|
||||
if (!oInfo.isPlaceholder && !oInfo.label.isEmpty() && !numericLabelRe.match(oInfo.label).hasMatch()) {
|
||||
outLabel = oInfo.label;
|
||||
if (outTerminal.isEmpty()) outTerminal = terminalHint;
|
||||
return;
|
||||
}
|
||||
}
|
||||
visited.insert(other);
|
||||
q.enqueue(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
depth++;
|
||||
}
|
||||
} else {
|
||||
if (outLabel.isEmpty()) {
|
||||
outLabel = startInfo.label.isEmpty() ? startInfo.name : startInfo.label;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool p1 = elementsInfo.value(c.el1_uuid).isPlaceholder;
|
||||
bool p2 = elementsInfo.value(c.el2_uuid).isPlaceholder;
|
||||
|
||||
if (c.element1_label.isEmpty() || p1) {
|
||||
if (p1) c.element1_label = "";
|
||||
resolveSide(c.el1_uuid, c.element1_label, c.terminalname1);
|
||||
}
|
||||
if (c.element2_label.isEmpty() || p2) {
|
||||
if (p2) c.element2_label = "";
|
||||
resolveSide(c.el2_uuid, c.element2_label, c.terminalname2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WiringListExport::toCsv()
|
||||
{
|
||||
if (!m_project) return;
|
||||
|
||||
QDomDocument doc = m_project->toXml();
|
||||
|
||||
if (doc.isNull()) {
|
||||
QMessageBox::warning(m_parent, tr("Erreur"), tr("Impossible de lire la structure en mémoire du projet."));
|
||||
return;
|
||||
}
|
||||
|
||||
QFileDialog dialog(m_parent);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog.setWindowTitle(tr("Exporter le plan de câblage"));
|
||||
dialog.setDefaultSuffix("csv");
|
||||
dialog.setNameFilter(tr("Fichiers CSV (*.csv)"));
|
||||
|
||||
if (dialog.exec() != QDialog::Accepted) return;
|
||||
QString fileName = dialog.selectedFiles().first();
|
||||
|
||||
QFile file(fileName);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QMessageBox::warning(m_parent, tr("Erreur"), tr("Impossible d'ouvrir le fichier pour l'écriture."));
|
||||
return;
|
||||
}
|
||||
|
||||
QMap<QString, ElementInfo> elementsInfo = collectElementsInfo(doc.documentElement());
|
||||
QList<ConductorData> conductors = collectConductors(doc.documentElement());
|
||||
|
||||
resolveEndpoints(conductors, elementsInfo);
|
||||
|
||||
QList<ConductorData> uniqueConductors;
|
||||
QSet<QString> seenConnections;
|
||||
|
||||
for (const ConductorData &c : conductors) {
|
||||
if (c.element1_label.isEmpty() && c.element2_label.isEmpty()) continue;
|
||||
|
||||
QString sideA = c.element1_label + ":" + c.terminalname1;
|
||||
QString sideB = c.element2_label + ":" + c.terminalname2;
|
||||
|
||||
QString key = (sideA < sideB) ? (sideA + "||" + sideB) : (sideB + "||" + sideA);
|
||||
|
||||
if (!seenConnections.contains(key)) {
|
||||
seenConnections.insert(key);
|
||||
uniqueConductors.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
QTextStream out(&file);
|
||||
out << tr("Page", "Wiring list CSV header") << ";"
|
||||
<< tr("Composant 1", "Wiring list CSV header") << ";"
|
||||
<< tr("Borne 1", "Wiring list CSV header") << ";"
|
||||
<< tr("Composant 2", "Wiring list CSV header") << ";"
|
||||
<< tr("Borne 2", "Wiring list CSV header") << ";"
|
||||
<< tr("Tension / Protocole", "Wiring list CSV header") << ";"
|
||||
<< tr("Couleur du fil", "Wiring list CSV header") << ";"
|
||||
<< tr("Section du fil", "Wiring list CSV header") << ";"
|
||||
<< tr("Fonction", "Wiring list CSV header") << "\n";
|
||||
|
||||
for (const ConductorData &c : uniqueConductors) {
|
||||
out << c.folio << ";"
|
||||
<< c.element1_label << ";"
|
||||
<< c.terminalname1 << ";"
|
||||
<< c.element2_label << ";"
|
||||
<< c.terminalname2 << ";"
|
||||
<< c.tension_protocol << ";"
|
||||
<< c.conductor_color << ";"
|
||||
<< c.conductor_section << ";"
|
||||
<< c.function << "\n";
|
||||
}
|
||||
|
||||
file.close();
|
||||
QMessageBox::information(m_parent, tr("Export réussi"), tr("Le plan de câblage a été exporté avec succès !"));
|
||||
}
|
||||
71
sources/wiringlistexport.h
Normal file
71
sources/wiringlistexport.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef WIRINGLISTEXPORT_H
|
||||
#define WIRINGLISTEXPORT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
|
||||
class QETProject;
|
||||
class QWidget;
|
||||
class QDomElement;
|
||||
class QDomNode;
|
||||
|
||||
// Internal data structures for parsing the XML graph
|
||||
struct ElementInfo {
|
||||
QString folio;
|
||||
QStringList links;
|
||||
QString label;
|
||||
QString name;
|
||||
bool isPlaceholder = false;
|
||||
};
|
||||
|
||||
struct ConductorData {
|
||||
int index = 0;
|
||||
QString el1_uuid;
|
||||
QString el2_uuid;
|
||||
QString element1_label;
|
||||
QString element2_label;
|
||||
QString terminalname1;
|
||||
QString terminalname2;
|
||||
QString tension_protocol;
|
||||
QString conductor_color;
|
||||
QString conductor_section;
|
||||
QString function;
|
||||
QString folio;
|
||||
|
||||
// Resolved endpoints
|
||||
QString chosen_a_uuid;
|
||||
QString chosen_a_label;
|
||||
QString chosen_b_uuid;
|
||||
QString chosen_b_label;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The WiringListExport class
|
||||
* Handles the export of the wiring list (Verdrahtungsplan) to a CSV file.
|
||||
* Automatically resolves links and placeholders to find physical endpoints.
|
||||
*/
|
||||
class WiringListExport : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WiringListExport(QETProject *project, QWidget *parent = nullptr);
|
||||
void toCsv();
|
||||
|
||||
private:
|
||||
QETProject *m_project;
|
||||
QWidget *m_parent;
|
||||
|
||||
QString normalizeUuid(const QString &u) const;
|
||||
QString findDiagramFolio(const QDomElement &diagramElem) const;
|
||||
QDomElement climbToDiagram(QDomNode node) const;
|
||||
|
||||
QMap<QString, ElementInfo> collectElementsInfo(const QDomElement &root) const;
|
||||
QList<ConductorData> collectConductors(const QDomElement &root) const;
|
||||
|
||||
void resolveEndpoints(QList<ConductorData> &conductors, const QMap<QString, ElementInfo> &elementsInfo) const;
|
||||
};
|
||||
|
||||
#endif // WIRINGLISTEXPORT_H
|
||||
Reference in New Issue
Block a user