improve UpToFace option of pad/pocket for datum planes

This commit is contained in:
wmayer
2018-01-06 17:36:14 +01:00
parent 762140d9ab
commit e68021029d
5 changed files with 238 additions and 100 deletions

View File

@@ -27,6 +27,7 @@
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/MainWindow.h>
#include <Gui/BitmapFactory.h>
#include <Mod/PartDesign/App/Feature.h>
#include <Mod/PartDesign/App/Body.h>
@@ -131,7 +132,7 @@ bool TaskDlgFeatureParameters::accept() {
Gui::Command::commitCommand();
} catch (const Base::Exception& e) {
// Generally the only thing that should fail is feature->isValid() others should be fine
QMessageBox::warning( 0, tr("Input error"), QString::fromLatin1(e.what()));
QMessageBox::warning(Gui::getMainWindow(), tr("Input error"), QString::fromLatin1(e.what()));
return false;
}

View File

@@ -59,6 +59,9 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView, QWidget *parent,
proxy = new QWidget(this);
ui = new Ui_TaskPadParameters();
ui->setupUi(proxy);
#if QT_VERSION >= 0x040700
ui->lineFaceName->setPlaceholderText(tr("No face selected"));
#endif
this->groupLayout()->addWidget(proxy);
@@ -97,14 +100,26 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView, QWidget *parent,
// According to bug #0000521 the reversed option
// shouldn't be de-activated if the pad has a support face
ui->checkBoxReversed->setChecked(reversed);
if ((obj != NULL) && PartDesign::Feature::isDatum(obj))
ui->lineFaceName->setText(QString::fromLatin1(obj->getNameInDocument()));
else if (faceId >= 0)
ui->lineFaceName->setText(QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + tr("Face") +
QString::number(faceId));
else
ui->lineFaceName->setText(tr("No face selected"));
// Set object labels
if (obj && PartDesign::Feature::isDatum(obj)) {
ui->lineFaceName->setText(QString::fromUtf8(obj->Label.getValue()));
ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument()));
}
else if (obj && faceId >= 0) {
ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3")
.arg(QString::fromUtf8(obj->Label.getValue()))
.arg(tr("Face"))
.arg(faceId));
ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument()));
}
else {
ui->lineFaceName->clear();
ui->lineFaceName->setProperty("FeatureName", QVariant());
}
ui->lineFaceName->setProperty("FaceName", QByteArray(upToFace.c_str()));
ui->changeMode->clear();
ui->changeMode->insertItem(0, tr("Dimension"));
ui->changeMode->insertItem(1, tr("To last"));
@@ -159,7 +174,8 @@ void TaskPadParameters::updateUI(int index)
bool isReversedEnabled = false;
bool isFaceEditEnabled = false;
if (index == 0) { // dimension
// dimension
if (index == 0) {
isLengthEditVisable = true;
ui->lengthEdit->selectNumber();
// Make sure that the spin box has the focus to get key events
@@ -169,17 +185,23 @@ void TaskPadParameters::updateUI(int index)
isMidplateEnabled = true;
// Reverse only makes sense if Midplane is not true
isReversedEnabled = !ui->checkBoxMidplane->isChecked();
} else if (index == 1 || index == 2) { // up to first/last
}
// up to first/last
else if (index == 1 || index == 2) {
isOffsetEditVisable = true;
isReversedEnabled = true;
} else if (index == 3) { // up to face
}
// up to face
else if (index == 3) {
isOffsetEditVisable = true;
isFaceEditEnabled = true;
QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection);
// Go into reference selection mode if no face has been selected yet
if (ui->lineFaceName->text().isEmpty() || (ui->lineFaceName->text() == tr("No face selected")))
if (ui->lineFaceName->property("FeatureName").isNull())
onButtonFace(true);
} else { // two dimensions
}
// two dimensions
else {
isLengthEditVisable = true;
isLengthEdit2Visable = true;
}
@@ -214,20 +236,23 @@ void TaskPadParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
if (refText.length() > 0) {
ui->lineFaceName->blockSignals(true);
ui->lineFaceName->setText(refText);
ui->lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName));
ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName));
ui->lineFaceName->blockSignals(false);
// Turn off reference selection mode
onButtonFace(false);
} else {
ui->lineFaceName->blockSignals(true);
ui->lineFaceName->setText(tr("No face selected"));
ui->lineFaceName->setProperty("FaceName", QByteArray());
ui->lineFaceName->clear();
ui->lineFaceName->setProperty("FeatureName", QVariant());
ui->lineFaceName->setProperty("FaceName", QVariant());
ui->lineFaceName->blockSignals(false);
}
} else if (msg.Type == Gui::SelectionChanges::ClrSelection) {
ui->lineFaceName->blockSignals(true);
ui->lineFaceName->setText(tr("No face selected"));
ui->lineFaceName->setProperty("FaceName", QByteArray());
ui->lineFaceName->clear();
ui->lineFaceName->setProperty("FeatureName", QVariant());
ui->lineFaceName->setProperty("FaceName", QVariant());
ui->lineFaceName->blockSignals(false);
}
}
@@ -289,7 +314,10 @@ void TaskPadParameters::onModeChanged(int index)
recomputeFeature();
}
void TaskPadParameters::onButtonFace(const bool pressed) {
void TaskPadParameters::onButtonFace(const bool pressed)
{
this->blockConnection(!pressed);
TaskSketchBasedParameters::onSelectReference(pressed, false, true, false);
// Update button if onButtonFace() is called explicitly
@@ -298,7 +326,27 @@ void TaskPadParameters::onButtonFace(const bool pressed) {
void TaskPadParameters::onFaceName(const QString& text)
{
ui->lineFaceName->setProperty("FaceName", TaskSketchBasedParameters::onFaceName(text));
if (text.isEmpty()) {
// if user cleared the text field then also clear the properties
ui->lineFaceName->setProperty("FeatureName", QVariant());
ui->lineFaceName->setProperty("FaceName", QVariant());
}
else {
// expect that the label of an object is used
QStringList parts = text.split(QChar::fromLatin1(':'));
QString label = parts[0];
QVariant name = objectNameByLabel(label, ui->lineFaceName->property("FeatureName"));
if (name.isValid()) {
parts[0] = name.toString();
QString uptoface = parts.join(QString::fromLatin1(":"));
ui->lineFaceName->setProperty("FeatureName", name);
ui->lineFaceName->setProperty("FaceName", setUpToFace(uptoface));
}
else {
ui->lineFaceName->setProperty("FeatureName", QVariant());
ui->lineFaceName->setProperty("FaceName", QVariant());
}
}
}
double TaskPadParameters::getLength(void) const
@@ -333,13 +381,15 @@ int TaskPadParameters::getMode(void) const
QString TaskPadParameters::getFaceName(void) const
{
// 'Up to face' mode
if (getMode() == 3) {
QString faceName = ui->lineFaceName->property("FaceName").toString();
if (!faceName.isEmpty()) {
return getFaceReference(ui->lineFaceName->text(), faceName);
QVariant featureName = ui->lineFaceName->property("FeatureName");
if (featureName.isValid()) {
QString faceName = ui->lineFaceName->property("FaceName").toString();
return getFaceReference(featureName.toString(), faceName);
}
}
return QString();
return QString::fromLatin1("None");
}
TaskPadParameters::~TaskPadParameters()
@@ -366,19 +416,30 @@ void TaskPadParameters::changeEvent(QEvent *e)
ui->changeMode->addItem(tr("Two dimensions"));
ui->changeMode->setCurrentIndex(index);
QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':'));
QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray();
int faceId = -1;
bool ok = false;
if (upToFace.indexOf("Face") == 0) {
faceId = upToFace.remove(0,4).toInt(&ok);
}
#if QT_VERSION >= 0x040700
ui->lineFaceName->setPlaceholderText(tr("No face selected"));
#endif
ui->lineFaceName->setText(ok ?
parts[0] + QString::fromLatin1(":") + tr("Face") + QString::number(faceId) :
tr(""));
QVariant featureName = ui->lineFaceName->property("FeatureName");
if (featureName.isValid()) {
QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':'));
QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray();
int faceId = -1;
bool ok = false;
if (upToFace.indexOf("Face") == 0) {
faceId = upToFace.remove(0,4).toInt(&ok);
}
if (ok) {
ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3")
.arg(parts[0])
.arg(tr("Face"))
.arg(faceId));
}
else {
ui->lineFaceName->setText(parts[0]);
}
}
ui->lengthEdit->blockSignals(false);
ui->lengthEdit2->blockSignals(false);
ui->offsetEdit->blockSignals(false);
@@ -405,14 +466,8 @@ void TaskPadParameters::apply()
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u", cname, getMode());
QString facename = getFaceName();
// TODO get rid of this if (2015-12-05, Fat-Zer)
if (!facename.isEmpty()) {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s",
cname, facename.toLatin1().data());
} else {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", cname);
}
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s",
cname, facename.toLatin1().data());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i", cname, getReversed()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i", cname, getMidplane()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f", name.c_str(), getOffset());

View File

@@ -60,6 +60,9 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
proxy = new QWidget(this);
ui = new Ui_TaskPocketParameters();
ui->setupUi(proxy);
#if QT_VERSION >= 0x040700
ui->lineFaceName->setPlaceholderText(tr("No face selected"));
#endif
this->groupLayout()->addWidget(proxy);
@@ -89,14 +92,26 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
ui->offsetEdit->setValue(off);
ui->checkBoxMidplane->setChecked(midplane);
ui->checkBoxReversed->setChecked(reversed);
if ((obj != NULL) && PartDesign::Feature::isDatum(obj))
ui->lineFaceName->setText(QString::fromLatin1(obj->getNameInDocument()));
else if (faceId >= 0)
ui->lineFaceName->setText(QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + tr("Face") +
QString::number(faceId));
else
ui->lineFaceName->setText(tr("No face selected"));
// Set object labels
if (obj && PartDesign::Feature::isDatum(obj)) {
ui->lineFaceName->setText(QString::fromUtf8(obj->Label.getValue()));
ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument()));
}
else if (obj && faceId >= 0) {
ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3")
.arg(QString::fromUtf8(obj->Label.getValue()))
.arg(tr("Face"))
.arg(faceId));
ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument()));
}
else {
ui->lineFaceName->clear();
ui->lineFaceName->setProperty("FeatureName", QVariant());
}
ui->lineFaceName->setProperty("FaceName", QByteArray(upToFace.c_str()));
ui->changeMode->clear();
ui->changeMode->insertItem(0, tr("Dimension"));
ui->changeMode->insertItem(1, tr("Through all"));
@@ -149,7 +164,8 @@ void TaskPocketParameters::updateUI(int index)
bool isReversedEnabled = false;
bool isFaceEditEnabled = false;
if (index == 0) { // dimension
// dimension
if (index == 0) {
isLengthEditVisable = true;
ui->lengthEdit->selectNumber();
// Make sure that the spin box has the focus to get key events
@@ -159,23 +175,29 @@ void TaskPocketParameters::updateUI(int index)
isMidplateEnabled = true;
// Reverse only makes sense if Midplane is not true
isReversedEnabled = !ui->checkBoxMidplane->isChecked();
} else if (index == 1) { // through all
}
// through all
else if (index == 1) {
isOffsetEditVisable = true;
isOffsetEditEnabled = false; // offset may have some meaning for through all but it doesn't work
isMidplateEnabled = true;
isReversedEnabled = !ui->checkBoxMidplane->isChecked();
} else if (index == 2) { // up to first
}
// up to first
else if (index == 2) {
isOffsetEditVisable = true;
isReversedEnabled = true; // Will change the direction it seeks for its first face?
// It may work not quite as expected but useful if sketch oriented upside-down.
// (may happen in bodies)
// FIXME: Fix probably lies somewhere in IF block on line 125 of FeaturePocket.cpp
} else if (index == 3) { // up to face
}
// up to face
else if (index == 3) {
isOffsetEditVisable = true;
isFaceEditEnabled = true;
QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection);
// Go into reference selection mode if no face has been selected yet
if (ui->lineFaceName->text().isEmpty() || (ui->lineFaceName->text() == tr("No face selected")))
if (ui->lineFaceName->property("FeatureName").isNull())
onButtonFace(true);
}
@@ -205,20 +227,23 @@ void TaskPocketParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
if (refText.length() > 0) {
ui->lineFaceName->blockSignals(true);
ui->lineFaceName->setText(refText);
ui->lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName));
ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName));
ui->lineFaceName->blockSignals(false);
// Turn off reference selection mode
onButtonFace(false);
} else {
ui->lineFaceName->blockSignals(true);
ui->lineFaceName->setText(tr("No face selected"));
ui->lineFaceName->setProperty("FaceName", QByteArray());
ui->lineFaceName->clear();
ui->lineFaceName->setProperty("FeatureName", QVariant());
ui->lineFaceName->setProperty("FaceName", QVariant());
ui->lineFaceName->blockSignals(false);
}
} else if (msg.Type == Gui::SelectionChanges::ClrSelection) {
ui->lineFaceName->blockSignals(true);
ui->lineFaceName->setText(tr("No face selected"));
ui->lineFaceName->setProperty("FaceName", QByteArray());
ui->lineFaceName->clear();
ui->lineFaceName->setProperty("FeatureName", QVariant());
ui->lineFaceName->setProperty("FaceName", QVariant());
ui->lineFaceName->blockSignals(false);
}
}
@@ -287,7 +312,10 @@ void TaskPocketParameters::onModeChanged(int index)
recomputeFeature();
}
void TaskPocketParameters::onButtonFace(const bool pressed) {
void TaskPocketParameters::onButtonFace(const bool pressed)
{
this->blockConnection(!pressed);
TaskSketchBasedParameters::onSelectReference(pressed, false, true, false);
// Update button if onButtonFace() is called explicitly
@@ -296,7 +324,27 @@ void TaskPocketParameters::onButtonFace(const bool pressed) {
void TaskPocketParameters::onFaceName(const QString& text)
{
ui->lineFaceName->setProperty("FaceName", TaskSketchBasedParameters::onFaceName(text));
if (text.isEmpty()) {
// if user cleared the text field then also clear the properties
ui->lineFaceName->setProperty("FeatureName", QVariant());
ui->lineFaceName->setProperty("FaceName", QVariant());
}
else {
// expect that the label of an object is used
QStringList parts = text.split(QChar::fromLatin1(':'));
QString label = parts[0];
QVariant name = objectNameByLabel(label, ui->lineFaceName->property("FeatureName"));
if (name.isValid()) {
parts[0] = name.toString();
QString uptoface = parts.join(QString::fromLatin1(":"));
ui->lineFaceName->setProperty("FeatureName", name);
ui->lineFaceName->setProperty("FaceName", setUpToFace(uptoface));
}
else {
ui->lineFaceName->setProperty("FeatureName", QVariant());
ui->lineFaceName->setProperty("FaceName", QVariant());
}
}
}
double TaskPocketParameters::getLength(void) const
@@ -326,14 +374,15 @@ int TaskPocketParameters::getMode(void) const
QString TaskPocketParameters::getFaceName(void) const
{
// TODO Make it return None rather than empty string (2015-11-03, Fat-Zer)
// 'Up to face' mode
if (getMode() == 3) {
QString faceName = ui->lineFaceName->property("FaceName").toString();
if (!faceName.isEmpty()) {
return getFaceReference(ui->lineFaceName->text(), faceName);
QVariant featureName = ui->lineFaceName->property("FeatureName");
if (featureName.isValid()) {
QString faceName = ui->lineFaceName->property("FaceName").toString();
return getFaceReference(featureName.toString(), faceName);
}
}
return QString ();
return QString::fromLatin1("None");
}
TaskPocketParameters::~TaskPocketParameters()
@@ -358,19 +407,30 @@ void TaskPocketParameters::changeEvent(QEvent *e)
ui->changeMode->addItem(tr("Up to face"));
ui->changeMode->setCurrentIndex(index);
QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':'));
QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray();
int faceId = -1;
bool ok = false;
if (upToFace.indexOf("Face") == 0) {
faceId = upToFace.remove(0,4).toInt(&ok);
}
#if QT_VERSION >= 0x040700
ui->lineFaceName->setPlaceholderText(tr("No face selected"));
#endif
ui->lineFaceName->setText(ok ?
parts[0] + QString::fromLatin1(":") + tr("Face") + QString::number(faceId) :
tr(""));
QVariant featureName = ui->lineFaceName->property("FeatureName");
if (featureName.isValid()) {
QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':'));
QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray();
int faceId = -1;
bool ok = false;
if (upToFace.indexOf("Face") == 0) {
faceId = upToFace.remove(0,4).toInt(&ok);
}
if (ok) {
ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3")
.arg(parts[0])
.arg(tr("Face"))
.arg(faceId));
}
else {
ui->lineFaceName->setText(parts[0]);
}
}
ui->lengthEdit->blockSignals(false);
ui->offsetEdit->blockSignals(false);
ui->lineFaceName->blockSignals(false);
@@ -394,13 +454,8 @@ void TaskPocketParameters::apply()
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u", cname, getMode());
QString facename = getFaceName();
if (!facename.isEmpty()) {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s",
cname, facename.toLatin1().data());
} else {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", cname);
}
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s",
cname, facename.toLatin1().data());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i", cname, getReversed()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i", cname, getMidplane()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f", name.c_str(), getOffset());

View File

@@ -126,38 +126,36 @@ void TaskSketchBasedParameters::exitSelectionMode()
onSelectReference(false, false, false, false);
}
const QByteArray TaskSketchBasedParameters::onFaceName(const QString& text)
QVariant TaskSketchBasedParameters::setUpToFace(const QString& text)
{
if (text.isEmpty())
return QByteArray();
return QVariant();
QStringList parts = text.split(QChar::fromLatin1(':'));
if (parts.length() < 2)
parts.push_back(QString::fromLatin1(""));
// Check whether this is the name of an App::Plane or Part::Datum feature
App::DocumentObject* obj = vp->getObject()->getDocument()->getObject(parts[0].toLatin1());
if (obj == NULL)
return QByteArray();
PartDesign::Body* activeBody = Gui::Application::Instance->activeView()->getActiveObject<PartDesign::Body*>(PDBODYKEY);
if (!activeBody)
return QByteArray();
return QVariant();
if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) {
// everything is OK (we assume a Part can only have exactly 3 App::Plane objects located at the base of the feature tree)
return QByteArray();
} else if (obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) {
if (!activeBody->hasObject(obj))
return QByteArray();
return QByteArray();
} else {
// We must expect that "text" is the translation of "Face" followed by an ID.
return QVariant();
}
else if (obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) {
// it's up to the document to check that the datum plane is in the same body
return QVariant();
}
else {
// We must expect that "parts[1]" is the translation of "Face" followed by an ID.
QString name;
QTextStream str(&name);
str << "^" << tr("Face") << "(\\d+)$";
QRegExp rx(name);
if (text.indexOf(rx) < 0) {
return QByteArray();
if (parts[1].indexOf(rx) < 0) {
return QVariant();
}
int faceId = rx.cap(1).toInt();
@@ -173,11 +171,36 @@ const QByteArray TaskSketchBasedParameters::onFaceName(const QString& text)
}
}
QVariant TaskSketchBasedParameters::objectNameByLabel(const QString& label,
const QVariant& suggest) const
{
// search for an object with the given label
App::Document* doc = this->vp->getObject()->getDocument();
// for faster access try the suggestion
if (suggest.isValid()) {
App::DocumentObject* obj = doc->getObject(suggest.toByteArray());
if (obj && QString::fromUtf8(obj->Label.getValue()) == label) {
return QVariant(QByteArray(obj->getNameInDocument()));
}
}
// go through all objects and check the labels
std::string name = label.toUtf8().data();
std::vector<App::DocumentObject*> objs = doc->getObjects();
for (std::vector<App::DocumentObject*>::iterator it = objs.begin(); it != objs.end(); ++it) {
if (name == (*it)->Label.getValue()) {
return QVariant(QByteArray((*it)->getNameInDocument()));
}
}
return QVariant(); // no such feature found
}
QString TaskSketchBasedParameters::getFaceReference(const QString& obj, const QString& sub)
{
QString o = obj.left(obj.indexOf(QString::fromLatin1(":")));
if (o == tr("No face selected"))
if (o.isEmpty())
return QString();
else
return QString::fromLatin1("(App.activeDocument().") + o +

View File

@@ -37,7 +37,8 @@ namespace PartDesignGui {
/// Convenience class to collect common methods for all SketchBased features
class TaskSketchBasedParameters : public PartDesignGui::TaskFeatureParameters, public Gui::SelectionObserver
class TaskSketchBasedParameters : public PartDesignGui::TaskFeatureParameters,
public Gui::SelectionObserver
{
Q_OBJECT
@@ -51,7 +52,10 @@ protected:
const QString onAddSelection(const Gui::SelectionChanges& msg);
void onSelectReference(const bool pressed, const bool edge, const bool face, const bool planar);
void exitSelectionMode();
const QByteArray onFaceName(const QString& text);
QVariant setUpToFace(const QString& text);
/// Try to find the name of a feature with the given label.
/// For faster access a suggeted name can be tested, first.
QVariant objectNameByLabel(const QString& label, const QVariant& suggest) const;
static QString getFaceReference(const QString& obj, const QString& sub);
};