mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-27 12:34:14 +02:00
Merge branch 'master' into master-feature-renum-elements-rebased
This commit is contained in:
@@ -24,6 +24,8 @@
|
||||
#include "../qetgraphicsitem/element.h"
|
||||
#include "../qetxml.h"
|
||||
#include "../qetproject.h"
|
||||
#include <QDir>
|
||||
#include <QDomDocument>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
#include <utility>
|
||||
@@ -703,6 +705,74 @@ namespace autonum
|
||||
return formula;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief prefixFromLabelFile
|
||||
Look up a prefix for @a path (path[dirLevel] outermost, path[1] the
|
||||
deepest directory; path[0], the element's own file name, is never
|
||||
matched) in the qet_labels.xml at @a filepath.
|
||||
|
||||
Descends through nested \<category name="..."\> elements matching
|
||||
path[dirLevel], path[dirLevel-1], ..., path[1] in turn, considering
|
||||
only *direct* children at each step -- unlike a flat token scan,
|
||||
this cannot be fooled by a same-named category living elsewhere in
|
||||
the document at the wrong nesting depth (bugtracker #671 item 5).
|
||||
|
||||
At each matched level, that category's own \<prefix\> child -- even
|
||||
an empty one -- overrides whatever a shallower ancestor already
|
||||
provided, so an explicit empty \<prefix/\> cancels inheritance
|
||||
rather than silently falling back to it (the behaviour requested in
|
||||
PR #686 review). A category with no \<prefix\> child at all leaves
|
||||
the inherited value untouched, which is how a directory with no
|
||||
prefix of its own comes to inherit its parent's, as the file's own
|
||||
header comment documents.
|
||||
|
||||
@return the prefix that applies, or a null QString if the file
|
||||
cannot be read, is not well-formed, or does not describe this
|
||||
path at all (as opposed to describing it with no prefix
|
||||
anywhere along it, which is a non-null empty string).
|
||||
*/
|
||||
static QString prefixFromLabelFile(const QString &filepath, const QStringList &path, int dirLevel)
|
||||
{
|
||||
QFile file(filepath);
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
return QString();
|
||||
|
||||
QDomDocument document;
|
||||
if (!document.setContent(&file))
|
||||
return QString();
|
||||
|
||||
QDomElement node = document.documentElement();
|
||||
if (node.isNull())
|
||||
return QString();
|
||||
|
||||
QString prefix;
|
||||
for (int i = dirLevel ; i >= 1 ; --i) {
|
||||
QDomElement child = node.firstChildElement(QStringLiteral("category"));
|
||||
while (!child.isNull()
|
||||
&& child.attribute(QStringLiteral("name")) != path[i]) {
|
||||
child = child.nextSiblingElement(QStringLiteral("category"));
|
||||
}
|
||||
if (child.isNull())
|
||||
return QString();
|
||||
node = child;
|
||||
|
||||
const QDomElement own = node.firstChildElement(QStringLiteral("prefix"));
|
||||
if (!own.isNull()) {
|
||||
//readElementText()'s null-vs-empty distinction that PR
|
||||
//#686 needed for the old QXmlStreamReader-based lookup
|
||||
//has a QDomElement equivalent: text() on an empty
|
||||
//element can itself come back null depending on how the
|
||||
//XML was written, so the same explicit fallback applies
|
||||
//-- an empty QString here means "found, deliberately
|
||||
//blank", not "not found".
|
||||
prefix = own.text();
|
||||
if (prefix.isNull())
|
||||
prefix = QString("");
|
||||
}
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief elementPrefixForLocation
|
||||
@param location
|
||||
@@ -716,114 +786,85 @@ namespace autonum
|
||||
if (!location.isProject())
|
||||
return QString();
|
||||
|
||||
QXmlStreamReader rxml;
|
||||
QString path[10];
|
||||
int i = -1;
|
||||
//Directory names from the element up to (not including) the
|
||||
//collection root, outermost last -- path[dirLevel] is the
|
||||
//top-level category, path[1] the element's immediate parent
|
||||
//directory, path[0] the element's own file name (never matched
|
||||
//against a category: the search stops descending once it has
|
||||
//matched path[1], the deepest real directory). An unbounded
|
||||
//QStringList rather than a fixed-size array, because a custom
|
||||
//collection can nest deeper than the shipped one -- see
|
||||
//bugtracker #671 item 3.
|
||||
QStringList path;
|
||||
ElementsLocation current_location = location;
|
||||
int dirLevel = -1;
|
||||
|
||||
//Add location name to path array
|
||||
while((current_location.parent() != current_location) && (current_location.parent().fileName() != "import"))
|
||||
while ((current_location.parent() != current_location)
|
||||
&& (current_location.parent().fileName() != "import"))
|
||||
{
|
||||
i++;
|
||||
path[i]=current_location.fileName();
|
||||
path << current_location.fileName();
|
||||
current_location = current_location.parent();
|
||||
dirLevel++;
|
||||
}
|
||||
//User Element without folder treatment
|
||||
if (i == -1)
|
||||
{
|
||||
i = 0;
|
||||
path[i]=current_location.fileName();
|
||||
//User element without folder treatment
|
||||
if (path.isEmpty()) {
|
||||
path << current_location.fileName();
|
||||
current_location = current_location.parent();
|
||||
dirLevel = 0;
|
||||
}
|
||||
const int dirLevel = path.size() - 1;
|
||||
//Name of the top-level tree the element's path was found
|
||||
//under, e.g. "10_electric" -- or, for a custom/company
|
||||
//collection not organised that way, whatever its top-level
|
||||
//folder happens to be called.
|
||||
const QString collection_root = current_location.fileName();
|
||||
|
||||
//Every top-level common-collection tree (10_electric,
|
||||
//20_logic, 30_hydraulic, ...) may carry its own
|
||||
//qet_labels.xml, with categories relative to that tree, the
|
||||
//same way 10_electric/qet_labels.xml already does -- not just
|
||||
//10_electric, which is all the hardcoded check this replaces
|
||||
//used to allow (bugtracker #671 item 2). commonElementsDir()
|
||||
//-- unlike customElementsDir(), which normalises this itself
|
||||
//-- returns whatever path the user configured verbatim, with
|
||||
//no guaranteed trailing separator; concatenating a suffix onto
|
||||
//it directly used to silently mangle the path (and so the
|
||||
//prefix lookup) for any install relocated to a directory
|
||||
//without a trailing slash (#671 item 1). QDir::filePath()
|
||||
//joins correctly either way.
|
||||
{
|
||||
const QString common_file = QDir(QETApp::commonElementsDir())
|
||||
.filePath(collection_root + QStringLiteral("/qet_labels.xml"));
|
||||
const QString prefix = prefixFromLabelFile(common_file, path, dirLevel);
|
||||
if (!prefix.isNull()) {
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
|
||||
// Create Custom labels if qet_labels.xml exits in customElementsDir
|
||||
if (current_location.fileName() != "10_electric"){
|
||||
QString custom_labels = "qet_labels.xml";
|
||||
QString customfilepath = QETApp::customElementsDir().append(custom_labels);
|
||||
|
||||
QFile file(customfilepath);
|
||||
file.isReadable();
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
return QString();
|
||||
rxml.setDevice(&file);
|
||||
rxml.readNext();
|
||||
/* Which collection an element actually came from is not
|
||||
* recoverable post-import (addElement() strips the protocol),
|
||||
* so custom and company labels files are tried against two
|
||||
* possible layouts: with the collection's top-level tree name
|
||||
* folded into the path (a custom/company file organised as a
|
||||
* mirror of the common collection, tree name included) and
|
||||
* without it (a file scoped to just this one tree, matching
|
||||
* how the common collection's own files are written). Custom
|
||||
* is tried before company, so a user override wins over a
|
||||
* shared one.
|
||||
*/
|
||||
QStringList path_from_root = path;
|
||||
path_from_root << collection_root;
|
||||
|
||||
while(!rxml.atEnd())
|
||||
{
|
||||
if (rxml.attributes().value("name").toString() == path[i])
|
||||
{
|
||||
rxml.readNext();
|
||||
i=i-1;
|
||||
//reached element directory
|
||||
if (i==0)
|
||||
{
|
||||
for (int j=i; j<= dirLevel; j = j +1)
|
||||
{
|
||||
//if there is a prefix available apply prefix
|
||||
if(rxml.name().toString()=="prefix")
|
||||
{
|
||||
return rxml.readElementText();
|
||||
}
|
||||
//if there isn't a prefix available, find parent prefix in parent folder
|
||||
else
|
||||
{
|
||||
while (rxml.readNextStartElement() && rxml.name().toString()!="prefix")
|
||||
{
|
||||
rxml.skipCurrentElement();
|
||||
rxml.readNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
const QStringList candidate_dirs = {
|
||||
QETApp::customElementsDir(),
|
||||
QETApp::companyElementsDir()
|
||||
};
|
||||
for (const QString &dir : candidate_dirs) {
|
||||
const QString candidate =
|
||||
QDir(dir).filePath(QStringLiteral("qet_labels.xml"));
|
||||
for (const QStringList &segments : {path_from_root, path}) {
|
||||
const QString prefix = prefixFromLabelFile(
|
||||
candidate, segments, segments.size() - 1);
|
||||
if (!prefix.isNull()) {
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
rxml.readNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QString qet_labels = "10_electric/qet_labels.xml";
|
||||
QString filepath = QETApp::commonElementsDir().append(qet_labels);
|
||||
QFile file(filepath);
|
||||
file.isReadable();
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
return QString();
|
||||
|
||||
rxml.setDevice(&file);
|
||||
rxml.readNext();
|
||||
|
||||
while(!rxml.atEnd())
|
||||
{
|
||||
if (rxml.attributes().value("name").toString() == path[i])
|
||||
{
|
||||
rxml.readNext();
|
||||
i=i-1;
|
||||
//reached element directory
|
||||
if (i==0)
|
||||
{
|
||||
for (int j=i; j<= dirLevel; j = j +1)
|
||||
{
|
||||
//if there is a prefix available apply prefix
|
||||
if(rxml.name().toString()=="prefix")
|
||||
{
|
||||
return rxml.readElementText();
|
||||
}
|
||||
//if there isn't a prefix available, find parent prefix in parent folder
|
||||
else
|
||||
{
|
||||
while (rxml.readNextStartElement() && rxml.name().toString()!="prefix")
|
||||
{
|
||||
rxml.skipCurrentElement();
|
||||
rxml.readNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rxml.readNext();
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
@@ -275,3 +275,80 @@ QString NumerotationContext::formatValue(const QStringList &item)
|
||||
return QString("%1").arg(value.toInt(), 3, 10, QChar('0'));
|
||||
return QString::number(value.toInt());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NumerotationContext::saveToSettings
|
||||
Save a hash of named NumerotationContexts to QSettings.
|
||||
@param contexts : the named rules to save
|
||||
@param currentRule : the name of the currently active rule
|
||||
@param settings : QSettings instance
|
||||
@param prefix : settings key prefix (e.g. "autonum/conductor")
|
||||
*/
|
||||
void NumerotationContext::saveToSettings(
|
||||
const QHash<QString, NumerotationContext> &contexts,
|
||||
const QString ¤tRule,
|
||||
QSettings &settings,
|
||||
const QString &prefix)
|
||||
{
|
||||
settings.setValue(prefix + "/current", currentRule);
|
||||
|
||||
// Clear stale array entries before writing (beginWriteArray does not
|
||||
// remove entries beyond the new size).
|
||||
settings.remove(prefix + "/rules");
|
||||
|
||||
QStringList names = contexts.keys();
|
||||
settings.beginWriteArray(prefix + "/rules", names.size());
|
||||
for (int i = 0; i < names.size(); ++i) {
|
||||
settings.setArrayIndex(i);
|
||||
const QString &name = names.at(i);
|
||||
const NumerotationContext &nc = contexts.value(name);
|
||||
|
||||
settings.setValue("name", name);
|
||||
|
||||
// Serialize context to XML string
|
||||
QDomDocument doc;
|
||||
NumerotationContext nc_copy = nc;
|
||||
QDomElement root = nc_copy.toXml(doc, "context");
|
||||
doc.appendChild(root);
|
||||
settings.setValue("xml", doc.toString());
|
||||
}
|
||||
settings.endArray();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NumerotationContext::loadFromSettings
|
||||
Load named NumerotationContexts from QSettings.
|
||||
@param settings : QSettings instance
|
||||
@param prefix : settings key prefix (e.g. "autonum/conductor")
|
||||
@return pair of (hash of named rules, name of current rule)
|
||||
*/
|
||||
QPair<QHash<QString, NumerotationContext>, QString> NumerotationContext::loadFromSettings(
|
||||
QSettings &settings,
|
||||
const QString &prefix)
|
||||
{
|
||||
QPair<QHash<QString, NumerotationContext>, QString> result;
|
||||
QHash<QString, NumerotationContext> &contexts = result.first;
|
||||
QString ¤tRule = result.second;
|
||||
|
||||
currentRule = settings.value(prefix + "/current").toString();
|
||||
|
||||
int size = settings.beginReadArray(prefix + "/rules");
|
||||
for (int i = 0; i < size; ++i) {
|
||||
settings.setArrayIndex(i);
|
||||
QString name = settings.value("name").toString();
|
||||
QString xmlStr = settings.value("xml").toString();
|
||||
|
||||
if (name.isEmpty() || xmlStr.isEmpty()) continue;
|
||||
|
||||
QDomDocument doc;
|
||||
if (!doc.setContent(xmlStr)) continue;
|
||||
|
||||
QDomElement root = doc.documentElement();
|
||||
NumerotationContext nc;
|
||||
nc.fromXml(root);
|
||||
contexts.insert(name, nc);
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
#include <QDomElement>
|
||||
#include <QHash>
|
||||
#include <QSettings>
|
||||
|
||||
/**
|
||||
This class represents a numerotation context, i.e. the data (type, value, increase)
|
||||
@@ -60,6 +62,14 @@ class NumerotationContext
|
||||
/// UI preview of a part's value matches what actually gets rendered.
|
||||
static QString formatValue(const QStringList &item);
|
||||
|
||||
static void saveToSettings(const QHash<QString, NumerotationContext> &contexts,
|
||||
const QString ¤tRule,
|
||||
QSettings &settings,
|
||||
const QString &prefix);
|
||||
static QPair<QHash<QString, NumerotationContext>, QString> loadFromSettings(
|
||||
QSettings &settings,
|
||||
const QString &prefix);
|
||||
|
||||
private:
|
||||
QStringList content_;
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<iconset theme="view-refresh" resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/view-refresh.png</normaloff>:/ico/16x16/view-refresh.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -161,7 +161,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<iconset theme="view-refresh" resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/view-refresh.png</normaloff>:/ico/16x16/view-refresh.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -238,7 +238,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<iconset theme="view-refresh" resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/view-refresh.png</normaloff>:/ico/16x16/view-refresh.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -319,7 +319,7 @@
|
||||
<string>Configurer</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<iconset theme="configure" resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/configure.png</normaloff>:/ico/16x16/configure.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
||||
@@ -141,7 +141,6 @@
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
@@ -163,7 +162,6 @@
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
@@ -238,7 +236,6 @@
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
@@ -335,7 +332,6 @@
|
||||
<widget class="QWidget" name="folioWidget" native="true">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
@@ -345,7 +341,6 @@
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
|
||||
@@ -54,6 +54,10 @@ FolioAutonumberingW::~FolioAutonumberingW()
|
||||
*/
|
||||
void FolioAutonumberingW::setContext(QList <QString> autonums)
|
||||
{
|
||||
// Replace the list rather than append to it: this is called again
|
||||
// whenever the project's numberings change (import, for instance),
|
||||
// and appending gave a second copy of every name.
|
||||
ui->m_autonums_cb->clear();
|
||||
foreach (QString str, autonums) { ui->m_autonums_cb->addItem(str);}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<iconset theme="edit-delete" resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-delete.png</normaloff>:/ico/16x16/edit-delete.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -136,7 +136,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<iconset theme="list-remove" resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/list-remove.png</normaloff>:/ico/22x22/list-remove.png</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
@@ -153,7 +153,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<iconset theme="list-add" resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/list-add.png</normaloff>:/ico/22x22/list-add.png</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
@@ -170,7 +170,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<iconset theme="arrow-left" resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/arrow-left.png</normaloff>:/ico/16x16/arrow-left.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -184,7 +184,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<iconset theme="arrow-right" resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/arrow-right.png</normaloff>:/ico/16x16/arrow-right.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
||||
Reference in New Issue
Block a user