Merge branch 'master' into qt6_cmake_joshua

This commit is contained in:
joshua
2026-07-31 21:15:21 +02:00
parent f16cf7dac8
commit e6d29cf345
297 changed files with 82691 additions and 27463 deletions
@@ -143,8 +143,12 @@ ElementsLocation ECHSFileToFile::copyElement(ElementsLocation &source, ElementsL
//On windows when user drag and drop an element from the common elements collection
//to the custom elements collection, the element file stay in read only mode, and so
//user can't save the element
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
QNtfsPermissionCheckGuard ntfs_guard;
#else
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
qt_ntfs_permission_lookup++;
#endif
QFile file(destination.fileSystemPath() % "/" % new_elmt_name);
if (!file.isWritable()) {
if (!file.setPermissions(file.permissions() | QFileDevice::WriteUser)) {
@@ -152,7 +156,9 @@ ElementsLocation ECHSFileToFile::copyElement(ElementsLocation &source, ElementsL
<< " in ECHSFileToFile::copyElement";
}
}
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
qt_ntfs_permission_lookup--;
#endif
#endif
return ElementsLocation (destination.fileSystemPath() % "/" % new_elmt_name);
}
@@ -469,7 +475,7 @@ bool ElementCollectionHandler::setNames(ElementsLocation &location,
root.appendChild(name_list.toXml(document));
QString filepath = location.fileSystemPath()
+ "/qet_directory";
% "/qet_directory";
if (!QET::writeXmlFile(document, filepath)) {
qDebug() << "ElementCollectionHandler::setNames : write qet-directory file failed";
return false;
@@ -533,6 +533,16 @@ QList<QETProject *> ElementsCollectionModel::project() const
*/
void ElementsCollectionModel::highlightUnusedElement()
{
//Reset only the items currently highlighted in red, so elements that
//are no longer unused lose the highlight. Scoping to the red
//Dense4Pattern avoids touching other backgrounds (e.g. the amber
//"show this dir" highlight) and avoids needless updates on big
//collections (issue #159).
for (ElementCollectionItem *eci : items())
if (eci->background().style() == Qt::Dense4Pattern &&
eci->background().color() == Qt::red)
eci->setBackground(QBrush());
QList <ElementsLocation> unused;
foreach (QETProject *project, m_project_list)
@@ -19,6 +19,7 @@
#include "../editor/ui/qetelementeditor.h"
#include "../elementscategoryeditor.h"
#include "../import/edz/edzimporter.h"
#include "../newelementwizard.h"
#include "../qetapp.h"
#include "../qetdiagrameditor.h"
@@ -32,8 +33,14 @@
#include "fileelementcollectionitem.h"
#include "xmlprojectelementcollectionitem.h"
#include <QCheckBox>
#include <QDesktopServices>
#include <QDialog>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QLabel>
#include <QMenu>
#include <QPushButton>
#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
@@ -158,6 +165,8 @@ void ElementsCollectionWidget::setUpAction()
tr("Nouveau dossier"), this);
m_new_element = new QAction(QET::Icons::ElementNew,
tr("Nouvel élément"), this);
m_import_edz = new QAction(QET::Icons::ElementNew,
tr("Importer une pièce EPLAN (.edz)…"), this);
m_show_this_dir = new QAction(QET::Icons::FolderOnlyThis,
tr("Afficher uniquement ce dossier"),
this);
@@ -247,6 +256,8 @@ void ElementsCollectionWidget::setUpConnection()
this, &ElementsCollectionWidget::newDirectory);
connect(m_new_element, &QAction::triggered,
this, &ElementsCollectionWidget::newElement);
connect(m_import_edz, &QAction::triggered,
this, &ElementsCollectionWidget::importEdz);
connect(m_show_this_dir, &QAction::triggered,
this, &ElementsCollectionWidget::showThisDir);
connect(m_show_all_dir, &QAction::triggered,
@@ -329,6 +340,7 @@ void ElementsCollectionWidget::customContextMenu(const QPoint &point)
{
if (!feci->isMacrosCollection()) {
m_context_menu->addAction(m_new_element);
m_context_menu->addAction(m_import_edz);
}
m_context_menu->addAction(m_new_directory);
if (!feci->isCollectionRoot())
@@ -599,6 +611,108 @@ void ElementsCollectionWidget::newElement()
&ElementsCollectionWidget::locationWasSaved);
}
/**
@brief ElementsCollectionWidget::confirmEdzImportTerms
Show the EPLAN (.edz) import warning dialog. The user must tick the
acknowledgement checkbox before the Import button is enabled.
@return true if the user accepted the terms, false otherwise.
*/
bool ElementsCollectionWidget::confirmEdzImportTerms()
{
QDialog dialog(this);
dialog.setWindowTitle(tr("Avertissement — Importation d'un fichier EPLAN (.edz)"));
QLabel *text = new QLabel(
tr("Le format .edz peut provenir de deux sources différentes :\n"
"\n"
"• Le portail EPLAN Data Portal (dataportal.eplan.com), soumis "
"aux conditions d'utilisation de l'environnement EPLAN Cloud ;\n"
"• Le site d'un fabricant de composants (ou d'un distributeur) "
"qui met ses fichiers .edz à disposition directement, selon ses "
"propres conditions.\n"
"\n"
"QElectroTech ne peut pas déterminer automatiquement l'origine "
"du fichier que vous importez, ni les conditions qui s'y "
"appliquent.\n"
"\n"
"En important ce fichier, vous confirmez que :\n"
"\n"
"• vous connaissez son origine et êtes autorisé à l'utiliser "
"dans ce contexte, au regard des conditions applicables à cette "
"source ;\n"
"• cette importation est effectuée à vos propres risques et "
"responsabilité ;\n"
"• ni QElectroTech, ni ses mainteneurs, ni ses contributeurs ne "
"peuvent être tenus responsables d'une utilisation non conforme "
"de ces données."),
&dialog);
text->setWordWrap(true);
QCheckBox *accept_box = new QCheckBox(
tr("J'ai lu et j'accepte ces conditions."), &dialog);
QDialogButtonBox *buttons = new QDialogButtonBox(
QDialogButtonBox::Cancel, &dialog);
QPushButton *import_button = buttons->addButton(
tr("Importer"), QDialogButtonBox::AcceptRole);
import_button->setDefault(true);
import_button->setEnabled(false);
connect(accept_box, &QCheckBox::toggled,
import_button, &QPushButton::setEnabled);
connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
QVBoxLayout *layout = new QVBoxLayout(&dialog);
layout->addWidget(text);
layout->addWidget(accept_box);
layout->addWidget(buttons);
return dialog.exec() == QDialog::Accepted;
}
/**
@brief ElementsCollectionWidget::importEdz
Import an EPLAN Data Portal part (.edz) as a QET element into the directory
pointed at by the context menu.
*/
void ElementsCollectionWidget::importEdz()
{
ElementCollectionItem *eci = elementCollectionItemForIndex(
m_index_at_context_menu);
if (!eci || eci->type() != FileElementCollectionItem::Type) {
return;
}
FileElementCollectionItem *feci =
static_cast<FileElementCollectionItem*>(eci);
if (feci->isCommonCollection() || !feci->isDir()) {
return;
}
if (!confirmEdzImportTerms()) {
return;
}
const QString edz_path = QFileDialog::getOpenFileName(
this, tr("Importer une pièce EPLAN"), QString(),
tr("Pièces EPLAN (*.edz)"));
if (edz_path.isEmpty()) {
return;
}
EdzImporter importer;
if (!importer.importToDirectory(edz_path, feci->fileSystemPath())) {
QET::QetMessageBox::critical(
this, tr("Import EPLAN"),
tr("Impossible d'importer cette pièce :\n%1")
.arg(importer.errorString()));
return;
}
reload();
}
/**
@brief ElementsCollectionWidget::showThisDir
Hide all directories except the pointed dir;
@@ -830,7 +944,7 @@ void ElementsCollectionWidget::search()
}
//start the search when text have at least 3 letters.
if (text.count() < 3) {
if (text.size() < 3) {
return;
}
@@ -72,6 +72,8 @@ class ElementsCollectionWidget : public QWidget
void editDirectory();
void newDirectory();
void newElement();
bool confirmEdzImportTerms();
void importEdz();
void showThisDir();
void resetShowThisDir();
void dirProperties();
@@ -112,6 +114,7 @@ class ElementsCollectionWidget : public QWidget
*m_edit_dir,
*m_new_directory,
*m_new_element,
*m_import_edz,
*m_show_this_dir,
*m_show_all_dir,
*m_dir_propertie;
@@ -523,7 +523,9 @@ bool ElementsLocation::isCompanyCollection() const
*/
bool ElementsLocation::isCustomCollection() const
{
return fileSystemPath().startsWith(QETApp::customElementsDirN());
const QString dir = QETApp::customElementsDirN();
const QString path = fileSystemPath();
return path == dir || path.startsWith(dir + QLatin1Char('/'));
}
/**
@@ -701,11 +703,11 @@ pugi::xml_document ElementsLocation::pugiXml() const
if (!m_project)
{
#ifndef Q_OS_LINUX
if (docu.load_file(m_file_system_path.toStdString().c_str())) {
if (docu.load_file(m_file_system_path.toStdWString().c_str())) {
docu.save(m_string_stream);
}
#else
docu.load_file(m_file_system_path.toStdString().c_str());
docu.load_file(m_file_system_path.toStdWString().c_str());
#endif
}
else
@@ -802,6 +804,7 @@ bool ElementsLocation::setXml(const QDomDocument &xml_document) const
QString path_ = collectionPath(false);
QRegularExpression rx("^(.*)/(.*\\.elmt)$");
QRegularExpressionMatch match = rx.match(path_);
if (auto regex_match = rx.match(path_); regex_match.hasMatch())
{
@@ -138,7 +138,7 @@ QString FileElementCollectionItem::localName()
{
QString str(fileSystemPath() % "/qet_directory");
pugi::xml_document docu;
if(docu.load_file(str.toStdString().c_str()))
if(docu.load_file(str.toStdWString().c_str()))
{
if (QString(docu.document_element().name())
== "qet-directory")
@@ -274,7 +274,9 @@ bool FileElementCollectionItem::isCompanyCollection() const
*/
bool FileElementCollectionItem::isCustomCollection() const
{
return fileSystemPath().startsWith(QETApp::customElementsDirN());
const QString dir = QETApp::customElementsDirN();
const QString path = fileSystemPath();
return path == dir || path.startsWith(dir + QLatin1Char('/'));
}
/**
@@ -325,6 +327,26 @@ void FileElementCollectionItem::setUpData()
{ search_list.append(context.value(key).toString()); }
search_list.append(localName(loc));
setData(search_list.join(" "));
// Tooltip: show what a truncated tree label can't - the full
// localized name and the descriptive element information.
// Reuses the location/context already parsed for the search
// index above; the collection path stays as the last line
// (it used to be the whole tooltip).
QStringList tip;
tip << localName(loc);
for (const auto &key : { QStringLiteral("description"),
QStringLiteral("manufacturer"),
QStringLiteral("manufacturer_reference") })
{
const QString value = context.value(key).toString();
if (!value.isEmpty())
tip << value;
}
tip << collectionPath();
tip.removeDuplicates();
setToolTip(tip.join(QLatin1Char('\n')));
return;
}
}
@@ -186,23 +186,22 @@ QDomElement XmlElementCollection::child(const QDomElement &parent_element,
if (parent_element.ownerDocument() != m_dom_document)
return QDomElement();
//Get all childs element of parent_element
QDomNodeList child_list = parent_element.childNodes();
QString tag_name(child_name.endsWith(".elmt")? "element" : "category");
QList <QDomElement> found_dom_element;
for (int i=0 ; i<child_list.length() ; i++)
/* Walk the siblings directly instead of the previous
* childNodes()+item(i) double pass: QDomNodeList::item(i) restarts
* from the first child every call, which made this loop quadratic
* in the number of children. This lookup runs several times per
* element instance while loading a project, on the "import"
* category that holds every embedded definition. */
const QString tag_name = child_name.endsWith(QLatin1String(".elmt"))
? QStringLiteral("element") : QStringLiteral("category");
for (QDomElement child_element = parent_element.firstChildElement(tag_name) ;
!child_element.isNull() ;
child_element = child_element.nextSiblingElement(tag_name))
{
QDomElement child_element = child_list.item(i).toElement();
if (child_element.tagName() == tag_name)
found_dom_element << child_element;
if (child_element.attribute(QStringLiteral("name")) == child_name)
return child_element;
}
if (found_dom_element.isEmpty()) return QDomElement();
foreach (QDomElement elmt, found_dom_element)
if (elmt.attribute("name") == child_name)
return elmt;
return QDomElement();
}