Merge pull request #24446 from pieterhijma/fix-add-prop-dialog-py-console
Gui: Fix Python Console messages Add Property dialog
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
# include <QString>
|
||||
# include <QCompleter>
|
||||
# include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
@@ -37,6 +38,8 @@
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include "Dialogs/DlgAddProperty.h"
|
||||
#include "Application.h"
|
||||
#include "Macro.h"
|
||||
#include "ui_DlgAddProperty.h"
|
||||
#include "ViewProviderVarSet.h"
|
||||
#include "propertyeditor/PropertyItem.h"
|
||||
@@ -58,7 +61,8 @@ const std::string DlgAddProperty::GroupBase = "Base";
|
||||
* - keep the value if the name of the property is changed,
|
||||
* - support units (see #15557),
|
||||
* - support enumerations (see #15553),
|
||||
* - make OK available as soon as there is a valid property (see #17474), and
|
||||
* - make OK available as soon as there is a valid property (see #17474),
|
||||
* - useful Python console commands (see #23760),
|
||||
* - support expressions (see #19716).
|
||||
*
|
||||
* Especially supporting expressions in the value field makes the logic
|
||||
@@ -145,21 +149,29 @@ DlgAddProperty::DlgAddProperty(QWidget* parent,
|
||||
DlgAddProperty::DlgAddProperty(QWidget* parent,
|
||||
App::PropertyContainer* container,
|
||||
ViewProviderVarSet* viewProvider)
|
||||
: QDialog(parent),
|
||||
container(container),
|
||||
ui(new Ui_DlgAddProperty),
|
||||
comboBoxGroup(this),
|
||||
completerType(this),
|
||||
editor(nullptr),
|
||||
transactionID(0)
|
||||
: QDialog(parent)
|
||||
, container(container)
|
||||
, ui(new Ui_DlgAddProperty)
|
||||
, comboBoxGroup(this)
|
||||
, completerType(this)
|
||||
, editor(nullptr)
|
||||
, transactionID(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setupMacroRedirector();
|
||||
initializeWidgets(viewProvider);
|
||||
}
|
||||
|
||||
DlgAddProperty::~DlgAddProperty() = default;
|
||||
|
||||
void DlgAddProperty::setupMacroRedirector()
|
||||
{
|
||||
setValueRedirector = std::make_unique<MacroManager::MacroRedirector>([this](MacroManager::LineType /*type*/,
|
||||
const char* line) {
|
||||
this->setValueCommand = line;
|
||||
});
|
||||
}
|
||||
|
||||
int DlgAddProperty::findLabelRow(const char* labelName, QFormLayout* layout)
|
||||
{
|
||||
for (int row = 0; row < layout->rowCount(); ++row) {
|
||||
@@ -337,9 +349,8 @@ void DlgAddProperty::addEnumEditor(PropertyItem* propertyItem)
|
||||
|
||||
void DlgAddProperty::addNormalEditor(PropertyItem* propertyItem)
|
||||
{
|
||||
editor.reset(propertyItem->createEditor(this, [this]() {
|
||||
this->valueChanged();
|
||||
}, FrameOption::WithFrame));
|
||||
editor.reset(propertyItem->createEditor(this, []() {},
|
||||
FrameOption::WithFrame));
|
||||
}
|
||||
|
||||
void DlgAddProperty::addEditor(PropertyItem* propertyItem)
|
||||
@@ -652,11 +663,6 @@ void DlgAddProperty::setEditor(bool valueNeedsReset)
|
||||
else {
|
||||
initializeValue();
|
||||
}
|
||||
|
||||
if (editor) {
|
||||
QVariant data = propertyItem->editorData(editor.get());
|
||||
propertyItem->setData(data);
|
||||
}
|
||||
}
|
||||
|
||||
void DlgAddProperty::setPropertyItem(App::Property* prop, bool supportsExpressions)
|
||||
@@ -801,12 +807,6 @@ void DlgAddProperty::valueChangedEnum()
|
||||
propEnum->setEnums(enumValuesVec);
|
||||
}
|
||||
|
||||
void DlgAddProperty::valueChanged()
|
||||
{
|
||||
QVariant data = propertyItem->editorData(editor.get());
|
||||
propertyItem->setData(data);
|
||||
}
|
||||
|
||||
/* We use these functions rather than the functions provided by App::Document
|
||||
* because this dialog may be opened when another transaction is in progress.
|
||||
* An example is opening a sketch. If this dialog uses the functions provided
|
||||
@@ -827,6 +827,29 @@ void DlgAddProperty::critical(const QString& title, const QString& text) {
|
||||
}
|
||||
}
|
||||
|
||||
void DlgAddProperty::recordMacroAdd(const App::PropertyContainer* container,
|
||||
const std::string& type, const std::string& name,
|
||||
const std::string& group, const std::string& doc) const
|
||||
{
|
||||
std::ostringstream command;
|
||||
command << "App.getDocument('";
|
||||
const App::Document* document = freecad_cast<App::Document*>(container);
|
||||
const App::DocumentObject* object = freecad_cast<App::DocumentObject*>(container);
|
||||
if (document) {
|
||||
command << document->getName() << "')";
|
||||
}
|
||||
else if (object) {
|
||||
command << object->getDocument()->getName() << "')." << object->getNameInDocument();
|
||||
}
|
||||
else {
|
||||
FC_ERR("Cannot record macro for container of type " << container->getTypeId().getName());
|
||||
return;
|
||||
}
|
||||
command << ".addProperty('" << type << "', '" << name << "', '" <<
|
||||
group << "', '" << doc + "')";
|
||||
Application::Instance->macroManager()->addLine(Gui::MacroManager::App, command.str().c_str());
|
||||
}
|
||||
|
||||
App::Property* DlgAddProperty::createProperty()
|
||||
{
|
||||
std::string name = ui->lineEditName->text().toStdString();
|
||||
@@ -834,9 +857,16 @@ App::Property* DlgAddProperty::createProperty()
|
||||
std::string type = ui->comboBoxType->currentText().toStdString();
|
||||
std::string doc = ui->lineEditToolTip->text().toStdString();
|
||||
|
||||
auto recordAddCommand = [this](MacroManager::LineType, const char* line) {
|
||||
this->addCommand = line;
|
||||
};
|
||||
|
||||
try {
|
||||
return container->addDynamicProperty(type.c_str(), name.c_str(),
|
||||
group.c_str(), doc.c_str());
|
||||
App::Property* prop = container->addDynamicProperty(type.c_str(), name.c_str(),
|
||||
group.c_str(), doc.c_str());
|
||||
MacroManager::MacroRedirector redirector(recordAddCommand);
|
||||
recordMacroAdd(container, type, name, group, doc);
|
||||
return prop;
|
||||
}
|
||||
catch (Base::Exception& e) {
|
||||
e.reportException();
|
||||
@@ -894,12 +924,23 @@ void DlgAddProperty::addDocumentation() {
|
||||
|
||||
void DlgAddProperty::accept()
|
||||
{
|
||||
if (editor) {
|
||||
QVariant data = propertyItem->editorData(editor.get());
|
||||
propertyItem->setData(data);
|
||||
}
|
||||
addDocumentation();
|
||||
auto* object = freecad_cast<App::DocumentObject*>(container);
|
||||
if (object) {
|
||||
object->ExpressionEngine.execute();
|
||||
}
|
||||
closeTransaction(TransactionOption::Commit);
|
||||
|
||||
setValueRedirector = nullptr;
|
||||
Application::Instance->macroManager()->addLine(MacroManager::LineType::App, addCommand.c_str());
|
||||
Application::Instance->macroManager()->addLine(MacroManager::LineType::App,
|
||||
setValueCommand.c_str());
|
||||
setupMacroRedirector();
|
||||
|
||||
std::string group = comboBoxGroup.currentText().toStdString();
|
||||
std::string type = ui->comboBoxType->currentText().toStdString();
|
||||
auto paramGroup = App::GetApplication().GetParameterGroupByPath(
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <App/PropertyContainer.h>
|
||||
|
||||
#include "propertyeditor/PropertyItem.h"
|
||||
#include "Macro.h"
|
||||
|
||||
namespace Gui {
|
||||
|
||||
@@ -94,7 +95,6 @@ public:
|
||||
QLayout* layout);
|
||||
|
||||
public Q_SLOTS:
|
||||
void valueChanged();
|
||||
void valueChangedEnum();
|
||||
|
||||
private:
|
||||
@@ -108,8 +108,11 @@ private:
|
||||
Type
|
||||
};
|
||||
|
||||
DlgAddProperty(QWidget* parent, App::PropertyContainer* container,
|
||||
ViewProviderVarSet* viewProvider);
|
||||
DlgAddProperty(QWidget* parent,
|
||||
App::PropertyContainer* container,
|
||||
ViewProviderVarSet* viewProvider);
|
||||
|
||||
void setupMacroRedirector();
|
||||
|
||||
void initializeGroup();
|
||||
|
||||
@@ -156,6 +159,9 @@ private:
|
||||
|
||||
void openTransaction();
|
||||
void critical(const QString& title, const QString& text);
|
||||
void recordMacroAdd(const App::PropertyContainer* container,
|
||||
const std::string& type, const std::string& name,
|
||||
const std::string& group, const std::string& doc) const;
|
||||
App::Property* createProperty();
|
||||
void closeTransaction(TransactionOption option);
|
||||
void clearFields();
|
||||
@@ -181,6 +187,10 @@ private:
|
||||
QMetaObject::Connection connComboBoxGroup;
|
||||
QMetaObject::Connection connComboBoxType;
|
||||
QMetaObject::Connection connLineEditNameTextChanged;
|
||||
|
||||
std::unique_ptr<MacroManager::MacroRedirector> setValueRedirector;
|
||||
std::string addCommand;
|
||||
std::string setValueCommand;
|
||||
};
|
||||
|
||||
} // namespace Dialog
|
||||
|
||||
@@ -218,6 +218,8 @@ MacroManager::~MacroManager()
|
||||
this->params->Detach(this);
|
||||
}
|
||||
|
||||
std::stack<std::function<void(MacroManager::LineType, const char*)>> MacroManager::redirectFuncs;
|
||||
|
||||
void MacroManager::OnChange(Base::Subject<const char*> &rCaller, const char * sReason)
|
||||
{
|
||||
(void)rCaller;
|
||||
@@ -268,8 +270,16 @@ void MacroManager::addPendingLine(LineType type, const char* line)
|
||||
|
||||
void MacroManager::addLine(LineType Type, const char* sLine)
|
||||
{
|
||||
if (!sLine)
|
||||
if (!sLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::function<void(LineType, const char*)> redirectFunc =
|
||||
redirectFuncs.empty() ? nullptr : redirectFuncs.top();
|
||||
if (redirectFunc) {
|
||||
redirectFunc(Type, sLine);
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.hasPendingLines()) {
|
||||
if (buffer.addPendingLineIfComment(Type, sLine)) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#ifndef GUI_MACRO_H
|
||||
#define GUI_MACRO_H
|
||||
|
||||
#include <stack>
|
||||
#include <tuple>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
@@ -121,6 +122,46 @@ public:
|
||||
Cmt, /**< The line is handled as a comment */
|
||||
};
|
||||
|
||||
/** Redirect the macro output temporarily.
|
||||
*
|
||||
* This is a RAII class to redirect the macro output to a function.
|
||||
* Initializing an instance with a redirect function, ensures that
|
||||
* MacroManager::addLine() calls are redirected by means of the redirect
|
||||
* function. More than one instances can be used, overriding earlier
|
||||
* instances and their redirect functions.
|
||||
*
|
||||
* @code
|
||||
* void myRedirectFunc1(MacroManager::LineType type, const char* line)
|
||||
* { // do something with the line }
|
||||
*
|
||||
* void myRedirectFunc2(MacroManager::LineType type, const char* line)
|
||||
* { // do something else with the line }
|
||||
*
|
||||
* {
|
||||
* MacroRedirector redirect(myRedirectFunc1);
|
||||
* // all macro output will go to myRedirectFunc1
|
||||
* {
|
||||
* MacroRedirector redirect2(myRedirectFunc2);
|
||||
* // all macro output will go to myRedirectFunc2
|
||||
* }
|
||||
* // all macro output will go to myRedirectFunc1
|
||||
* }
|
||||
* // normal macro output is restored
|
||||
* @endcode
|
||||
*/
|
||||
class MacroRedirector
|
||||
{
|
||||
public:
|
||||
explicit MacroRedirector(const std::function<void(LineType, const char*)>& func)
|
||||
{
|
||||
MacroManager::redirectFuncs.push(func);
|
||||
}
|
||||
|
||||
~MacroRedirector() {
|
||||
MacroManager::redirectFuncs.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/** Opens a new Macro recording session
|
||||
* Starts a session with the type and the name of the macro.
|
||||
* All user interactions will be recorded as long as the commit() or cancel() isn't called.
|
||||
@@ -139,7 +180,15 @@ public:
|
||||
bool isOpen() const {
|
||||
return macroFile.isOpen();
|
||||
}
|
||||
/// insert a new line in the macro
|
||||
|
||||
/** Insert a new line in the macro.
|
||||
*
|
||||
* The line is added to the macro unless the output is redirected.
|
||||
* @see MacroRedirector.
|
||||
*
|
||||
* @param Type The type of the line
|
||||
* @param sLine The line to add
|
||||
*/
|
||||
void addLine(LineType Type, const char* sLine);
|
||||
/// insert a new pending line in the macro
|
||||
void addPendingLine(LineType type, const char* line);
|
||||
@@ -174,6 +223,7 @@ private:
|
||||
mutable PythonConsole* pyConsole{nullptr}; // link to the python console
|
||||
PythonDebugger* pyDebugger;
|
||||
Base::Reference<ParameterGrp> params; // link to the Macro parameter group
|
||||
static std::stack<std::function<void(LineType, const char*)>> redirectFuncs;
|
||||
|
||||
friend struct ApplicationP;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user