diff --git a/cMake/FreeCAD_Helpers/SetupQt.cmake b/cMake/FreeCAD_Helpers/SetupQt.cmake index c3dc0eeedd..eba599830a 100644 --- a/cMake/FreeCAD_Helpers/SetupQt.cmake +++ b/cMake/FreeCAD_Helpers/SetupQt.cmake @@ -78,6 +78,7 @@ else() endif() configure_file(${CMAKE_SOURCE_DIR}/src/QtCore.h.cmake ${CMAKE_BINARY_DIR}/src/QtCore.h) +configure_file(${CMAKE_SOURCE_DIR}/src/QtWidgets.h.cmake ${CMAKE_BINARY_DIR}/src/QtWidgets.h) function(qt_find_and_add_translation _qm_files _tr_dir _qm_dir) file(GLOB _ts_files ${_tr_dir}) diff --git a/src/Gui/Action.cpp b/src/Gui/Action.cpp index 395095c408..c839412deb 100644 --- a/src/Gui/Action.cpp +++ b/src/Gui/Action.cpp @@ -137,16 +137,21 @@ void Action::setCheckable(bool check) } } -void Action::setChecked(bool check, bool no_signal) +void Action::setChecked(bool check) { - bool blocked = false; - if (no_signal) { - blocked = _action->blockSignals(true); - } _action->setChecked(check); - if (no_signal) { - _action->blockSignals(blocked); - } +} + +/*! + * \brief Action::setBlockedChecked + * \param check + * Does the same as \ref setChecked but additionally blocks + * any signals. + */ +void Action::setBlockedChecked(bool check) +{ + QSignalBlocker block(_action); + _action->setChecked(check); } bool Action::isChecked() const diff --git a/src/Gui/Action.h b/src/Gui/Action.h index d31c8e4563..62222990fc 100644 --- a/src/Gui/Action.h +++ b/src/Gui/Action.h @@ -57,7 +57,8 @@ public: virtual void setVisible(bool); void setCheckable(bool); - void setChecked (bool, bool no_signal=false); + void setChecked(bool); + void setBlockedChecked(bool); bool isChecked() const; bool isEnabled() const; diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 35a37e9e64..7b99d70022 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -137,6 +137,7 @@ #include "WorkbenchManipulator.h" #include "WidgetFactory.h" #include "3Dconnexion/navlib/NavlibInterface.h" +#include "QtWidgets.h" #ifdef BUILD_TRACY_FRAME_PROFILER #include diff --git a/src/Gui/Application.h b/src/Gui/Application.h index 3cece3a157..596fc32dae 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -30,10 +30,6 @@ #include -#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) && QT_VERSION < QT_VERSION_CHECK(6,8,1) -# define HAS_QTBUG_129596 -#endif - class QCloseEvent; class SoNode; class NavlibInterface; diff --git a/src/Gui/AutoSaver.cpp b/src/Gui/AutoSaver.cpp index 6228221486..62e76b1001 100644 --- a/src/Gui/AutoSaver.cpp +++ b/src/Gui/AutoSaver.cpp @@ -344,17 +344,28 @@ public: } void run() override { - prop->SaveDocFile(writer); - writer.close(); + try { + prop->SaveDocFile(writer); + writer.close(); - // We could have renamed the file in this thread. However, there is - // still chance of crash when we deleted the original and before rename - // the new file. So we ask the main thread to do it. There is still - // possibility of crash caused by thread other than the main, but - // that's the best we can do for now. - QMetaObject::invokeMethod(AutoSaver::instance(), "renameFile", - Qt::QueuedConnection, Q_ARG(QString,dirName) - ,Q_ARG(QString,fileName),Q_ARG(QString,tmpName)); + // We could have renamed the file in this thread. However, there is + // still chance of crash when we deleted the original and before rename + // the new file. So we ask the main thread to do it. There is still + // possibility of crash caused by thread other than the main, but + // that's the best we can do for now. + QMetaObject::invokeMethod(AutoSaver::instance(), "renameFile", + Qt::QueuedConnection, Q_ARG(QString,dirName) + ,Q_ARG(QString,fileName),Q_ARG(QString,tmpName)); + } + catch (const Base::Exception& e) { + Base::Console().warning("Exception in auto-saving: %s\n", e.what()); + } + catch (const std::exception& e) { + Base::Console().warning("C++ exception in auto-saving: %s\n", e.what()); + } + catch (...) { + Base::Console().warning("Unknown exception in auto-saving\n"); + } } private: diff --git a/src/Gui/Command.cpp b/src/Gui/Command.cpp index 4c01a4040c..0bc31de89c 100644 --- a/src/Gui/Command.cpp +++ b/src/Gui/Command.cpp @@ -385,7 +385,7 @@ void Command::setupCheckable(int iMsg) { action->setChecked(checked); action->blockSignals(blocked); if(action!=_pcAction->action()) - _pcAction->setChecked(checked,true); + _pcAction->setBlockedChecked(checked); } } @@ -899,8 +899,14 @@ const char* Command::keySequenceToAccel(int sk) const static StringMap strings; auto i = strings.find(sk); - if (i != strings.end()) + if (i != strings.end()) { return i->second.c_str(); + } + + // In case FreeCAD is loaded without GUI (issue 16407) + if (!QApplication::instance()) { + return ""; + } auto type = static_cast(sk); QKeySequence ks(type); @@ -1637,7 +1643,7 @@ Action * PythonGroupCommand::createAction() qtAction->blockSignals(false); }else if(qtAction->isCheckable()){ pcAction->setCheckable(true); - pcAction->setChecked(qtAction->isChecked(),true); + pcAction->setBlockedChecked(qtAction->isChecked()); } } } diff --git a/src/Gui/Command.h b/src/Gui/Command.h index cce11e8594..50809a8f45 100644 --- a/src/Gui/Command.h +++ b/src/Gui/Command.h @@ -181,7 +181,7 @@ if(__obj && __obj->isAttachedToDocument()) {\ Gui::Command::doCommand(Gui::Command::Gui,\ "Gui.ActiveDocument.setEdit(App.getDocument('%s').getObject('%s'), %i)",\ - __obj->getDocument()->getName(), __obj->getNameInDocument(), Gui::Application::Instance->getUserEditMode());\ + __obj->getDocument()->getName(), __obj->getNameInDocument(), 0);\ }\ }while(0) diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 3fc5199174..fc1fba78a3 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -1752,12 +1752,14 @@ StdCmdProperties::StdCmdProperties() void StdCmdProperties::activated(int iMsg) { Q_UNUSED(iMsg); - QWidget* propertyView = Gui::DockWindowManager::instance()->getDockWindow("Property view"); - if (propertyView) { - QWidget* parent = propertyView->parentWidget(); - if (parent && !parent->isVisible()) { - parent->show(); - } + auto dw = Gui::DockWindowManager::instance(); + if (auto propertyView = dw->getDockWindow("Property view")) { + dw->activate(propertyView); + return; + } + if (auto comboView = dw->getDockWindow("Model")) { + dw->activate(comboView); + return; } } diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index c0e5c632aa..ccf00cb137 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -3301,7 +3301,7 @@ bool StdCmdSelForward::isActive() DEF_STD_CMD_AC(StdTree##_name) \ void StdTree##_name::activated(int){ \ TreeParams::setDocumentMode(_v);\ - if(_pcAction) _pcAction->setChecked(true,true);\ + if(_pcAction) _pcAction->setBlockedChecked(true);\ }\ Action * StdTree##_name::createAction(void) {\ Action *pcAction = Command::createAction();\ @@ -3314,7 +3314,7 @@ Action * StdTree##_name::createAction(void) {\ bool StdTree##_name::isActive() {\ bool checked = TreeParams::getDocumentMode()==_v;\ if(_pcAction && _pcAction->isChecked()!=checked)\ - _pcAction->setChecked(checked,true);\ + _pcAction->setBlockedChecked(checked);\ return true;\ } @@ -3374,9 +3374,9 @@ DEF_STD_CMD_AC(StdTree##_name) \ void StdTree##_name::activated(int){ \ auto checked = !TreeParams::get##_name();\ TreeParams::set##_name(checked);\ - if(_pcAction) _pcAction->setChecked(checked,true);\ + if(_pcAction) _pcAction->setBlockedChecked(checked);\ }\ -Action * StdTree##_name::createAction(void) {\ +Action * StdTree##_name::createAction() {\ Action *pcAction = Command::createAction();\ pcAction->setCheckable(true);\ pcAction->setIcon(QIcon());\ @@ -3387,7 +3387,7 @@ Action * StdTree##_name::createAction(void) {\ bool StdTree##_name::isActive() {\ bool checked = TreeParams::get##_name();\ if(_pcAction && _pcAction->isChecked()!=checked)\ - _pcAction->setChecked(checked,true);\ + _pcAction->setBlockedChecked(checked);\ return true;\ } @@ -3576,7 +3576,7 @@ void StdCmdSelBoundingBox::activated(int iMsg) if(checked != ViewParams::instance()->getShowSelectionBoundingBox()) { ViewParams::instance()->setShowSelectionBoundingBox(checked); if(_pcAction) - _pcAction->setChecked(checked,true); + _pcAction->setBlockedChecked(checked); } } @@ -3585,7 +3585,7 @@ bool StdCmdSelBoundingBox::isActive() if(_pcAction) { bool checked = _pcAction->isChecked(); if(checked != ViewParams::instance()->getShowSelectionBoundingBox()) - _pcAction->setChecked(!checked,true); + _pcAction->setBlockedChecked(!checked); } return true; } @@ -3819,10 +3819,10 @@ void StdCmdDockOverlayMouseTransparent::activated(int iMsg) bool checked = !OverlayManager::instance()->isMouseTransparent(); OverlayManager::instance()->setMouseTransparent(checked); if(_pcAction) - _pcAction->setChecked(checked,true); + _pcAction->setBlockedChecked(checked); } -Action * StdCmdDockOverlayMouseTransparent::createAction(void) { +Action * StdCmdDockOverlayMouseTransparent::createAction() { Action *pcAction = Command::createAction(); pcAction->setCheckable(true); pcAction->setIcon(QIcon()); @@ -3834,7 +3834,7 @@ Action * StdCmdDockOverlayMouseTransparent::createAction(void) { bool StdCmdDockOverlayMouseTransparent::isActive() { bool checked = OverlayManager::instance()->isMouseTransparent(); if(_pcAction && _pcAction->isChecked()!=checked) - _pcAction->setChecked(checked,true); + _pcAction->setBlockedChecked(checked); return true; } diff --git a/src/Gui/CommandWindow.cpp b/src/Gui/CommandWindow.cpp index b4e925aee5..284299abdb 100644 --- a/src/Gui/CommandWindow.cpp +++ b/src/Gui/CommandWindow.cpp @@ -362,7 +362,7 @@ Action* StdCmdToggleToolBarLock::createAction() Action* action = Command::createAction(); action->setCheckable(true); - action->setChecked(ToolBarManager::getInstance()->areToolBarsLocked(), true); + action->setBlockedChecked(ToolBarManager::getInstance()->areToolBarsLocked()); return action; } @@ -420,7 +420,7 @@ Action * StdCmdStatusBar::createAction() { Action *pcAction = Command::createAction(); pcAction->setCheckable(true); - pcAction->setChecked(false, true); + pcAction->setBlockedChecked(false); auto fsb = new FilterStatusBar(pcAction); getMainWindow()->statusBar()->installEventFilter(fsb); diff --git a/src/Gui/Dialogs/DlgActionsImp.cpp b/src/Gui/Dialogs/DlgActionsImp.cpp index c0869fd3f7..b0b9c98895 100644 --- a/src/Gui/Dialogs/DlgActionsImp.cpp +++ b/src/Gui/Dialogs/DlgActionsImp.cpp @@ -219,8 +219,8 @@ void DlgCustomActionsImp::onActionListWidgetItemActivated(QTreeWidgetItem* item) ui->actionMenu->setText(QString::fromUtf8(pScript->getMenuText())); ui->actionToolTip->setText(QString::fromUtf8(pScript->getToolTipText())); ui->actionStatus->setText(QString::fromUtf8(pScript->getStatusTip())); - ui->actionAccel->setText( - ShortcutManager::instance()->getShortcut(actionName.constData(), pScript->getAccel())); + ui->actionAccel->setKeySequence(QKeySequence( + ShortcutManager::instance()->getShortcut(actionName.constData(), pScript->getAccel()))); ui->pixmapLabel->clear(); m_sPixmap.clear(); const char* name = pScript->getPixmap(); @@ -290,9 +290,10 @@ void DlgCustomActionsImp::onButtonAddActionClicked() ui->pixmapLabel->clear(); m_sPixmap.clear(); - if (!ui->actionAccel->text().isEmpty()) { + if (!ui->actionAccel->isEmpty()) { + QString text = ui->actionAccel->text(); ShortcutManager::instance()->setShortcut(actionName.constData(), - ui->actionAccel->text().toLatin1().constData()); + text.toLatin1().constData()); } ui->actionAccel->clear(); @@ -353,8 +354,9 @@ void DlgCustomActionsImp::onButtonReplaceActionClicked() ui->pixmapLabel->clear(); m_sPixmap.clear(); - if (!ui->actionAccel->text().isEmpty()) { - macro->setAccel(ui->actionAccel->text().toLatin1()); + if (!ui->actionAccel->isEmpty()) { + QString text = ui->actionAccel->text(); + macro->setAccel(text.toLatin1()); } ui->actionAccel->clear(); @@ -521,7 +523,6 @@ void DlgCustomActionsImp::changeEvent(QEvent* e) ui->retranslateUi(this); ui->actionListWidget->clear(); showActions(); - ui->actionAccel->setText(qApp->translate("Gui::AccelLineEdit", "none")); } QWidget::changeEvent(e); } diff --git a/src/Gui/Dialogs/DlgAddPropertyVarSet.cpp b/src/Gui/Dialogs/DlgAddPropertyVarSet.cpp index 94011897c6..3ef09b990d 100644 --- a/src/Gui/Dialogs/DlgAddPropertyVarSet.cpp +++ b/src/Gui/Dialogs/DlgAddPropertyVarSet.cpp @@ -371,8 +371,7 @@ bool DlgAddPropertyVarSet::isGroupValid() bool DlgAddPropertyVarSet::isTypeValid() { std::string type = ui->comboBoxType->currentText().toStdString(); - - return !Base::Type::fromName(type.c_str()).isBad(); + return Base::Type::fromName(type.c_str()).isDerivedFrom(App::Property::getClassTypeId()); } bool DlgAddPropertyVarSet::areFieldsValid() @@ -380,9 +379,41 @@ bool DlgAddPropertyVarSet::areFieldsValid() return isNameValid() && isGroupValid() && isTypeValid(); } -void DlgAddPropertyVarSet::onTextFieldChanged([[maybe_unused]] const QString& text) +void DlgAddPropertyVarSet::onTextFieldChanged([[maybe_unused]]const QString& text) { setOkEnabled(areFieldsValid()); + showStatusMessage(); +} + +void DlgAddPropertyVarSet::showStatusMessage() +{ + QString error; + QString text = ui->lineEditName->text(); + std::string name = text.toStdString(); + + if (!isGroupValid()) { + error = tr("Invalid group name"); + } + else if (!isTypeValid()) { + error = tr("Invalid type name"); + } + else if (name.empty()) { + error.clear(); + } + else if (name != Base::Tools::getIdentifier(name)) { + error = tr("Invalid property name '%1'").arg(text); + } + else if (propertyExists(name)) { + error = tr("Property '%1' already exists").arg(text); + } + else if (App::ExpressionParser::isTokenAConstant(name)) { + error = tr("'%1' is a constant").arg(text); + } + else if (App::ExpressionParser::isTokenAUnit(name)) { + error = tr("'%1' is a unit").arg(text); + } + + ui->labelError->setText(error); } void DlgAddPropertyVarSet::removeEditor() @@ -409,6 +440,7 @@ void DlgAddPropertyVarSet::onTypeChanged(const QString& text) } setOkEnabled(areFieldsValid()); + showStatusMessage(); } void DlgAddPropertyVarSet::changeEvent(QEvent* e) diff --git a/src/Gui/Dialogs/DlgAddPropertyVarSet.h b/src/Gui/Dialogs/DlgAddPropertyVarSet.h index d0b539ae24..8e19901f3b 100644 --- a/src/Gui/Dialogs/DlgAddPropertyVarSet.h +++ b/src/Gui/Dialogs/DlgAddPropertyVarSet.h @@ -121,6 +121,7 @@ private: bool areFieldsValid(); void onTextFieldChanged(const QString& text); + void showStatusMessage(); void removeEditor(); void onTypeChanged(const QString& text); diff --git a/src/Gui/Dialogs/DlgAddPropertyVarSet.ui b/src/Gui/Dialogs/DlgAddPropertyVarSet.ui index d46bc7ba31..651c8fc452 100644 --- a/src/Gui/Dialogs/DlgAddPropertyVarSet.ui +++ b/src/Gui/Dialogs/DlgAddPropertyVarSet.ui @@ -7,7 +7,7 @@ 0 0 418 - 223 + 234 @@ -70,6 +70,13 @@ + + + + + + + Qt::Horizontal diff --git a/src/Gui/Dialogs/DlgExpressionInput.cpp b/src/Gui/Dialogs/DlgExpressionInput.cpp index 336bbbd2e5..337cc24f02 100644 --- a/src/Gui/Dialogs/DlgExpressionInput.cpp +++ b/src/Gui/Dialogs/DlgExpressionInput.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #endif @@ -66,13 +67,16 @@ DlgExpressionInput::DlgExpressionInput(const App::ObjectIdentifier & _path, // Setup UI ui->setupUi(this); + okBtn = ui->buttonBox->button(QDialogButtonBox::Ok); + discardBtn = ui->buttonBox->button(QDialogButtonBox::Reset); + discardBtn->setToolTip(tr("Revert to last calculated value (as constant)")); initializeVarSets(); // Connect signal(s) connect(ui->expression, &ExpressionLineEdit::textChanged, this, &DlgExpressionInput::textChanged); - connect(ui->discardBtn, &QPushButton::clicked, + connect(discardBtn, &QPushButton::clicked, this, &DlgExpressionInput::setDiscarded); if (expression) { @@ -280,11 +284,11 @@ void DlgExpressionInput::checkExpression(const QString& text) std::unique_ptr result(expr->eval()); expression = expr; - ui->okBtn->setEnabled(true); + okBtn->setEnabled(true); ui->msg->clear(); //set default palette as we may have read text right now - ui->msg->setPalette(ui->okBtn->palette()); + ui->msg->setPalette(okBtn->palette()); auto * n = freecad_cast(result.get()); if (n) { @@ -325,12 +329,12 @@ static const bool NO_CHECK_EXPR = false; void DlgExpressionInput::textChanged(const QString &text) { if (text.isEmpty()) { - ui->okBtn->setDisabled(true); - ui->discardBtn->setDefault(true); + okBtn->setDisabled(true); + discardBtn->setDefault(true); return; } - ui->okBtn->setDefault(true); + okBtn->setDefault(true); try { //resize the input field according to text size @@ -357,7 +361,7 @@ void DlgExpressionInput::textChanged(const QString &text) QPalette p(ui->msg->palette()); p.setColor(QPalette::WindowText, Qt::red); ui->msg->setPalette(p); - ui->okBtn->setDisabled(true); + okBtn->setDisabled(true); } } @@ -614,7 +618,7 @@ void DlgExpressionInput::setupVarSets() ui->comboBoxVarSet->setModel(treeWidget->model()); ui->comboBoxVarSet->setView(treeWidget.get()); - ui->okBtn->setEnabled(false); + okBtn->setEnabled(false); } std::string DlgExpressionInput::getType() @@ -629,7 +633,7 @@ void DlgExpressionInput::onCheckVarSets(int state) { setupVarSets(); } else { - ui->okBtn->setEnabled(true); // normal expression + okBtn->setEnabled(true); // normal expression } } @@ -719,13 +723,13 @@ void DlgExpressionInput::updateVarSetInfo(bool checkExpr) QString nameGroup = ui->lineEditGroup->text(); if (reportGroup(nameGroup)) { // needed to report something about the group, so disable the button - ui->okBtn->setEnabled(false); + okBtn->setEnabled(false); return; } if (reportName(selected)) { // needed to report something about the name, so disable the button - ui->okBtn->setEnabled(false); + okBtn->setEnabled(false); return; } @@ -744,15 +748,15 @@ void DlgExpressionInput::updateVarSetInfo(bool checkExpr) // We have to check the text of the expression as well try { checkExpression(ui->expression->text()); - ui->okBtn->setEnabled(true); + okBtn->setEnabled(true); } catch (Base::Exception&) { - ui->okBtn->setDisabled(true); + okBtn->setDisabled(true); } } } else { - ui->okBtn->setEnabled(false); + okBtn->setEnabled(false); reportVarSetInfo("Please select a variable set."); } } diff --git a/src/Gui/Dialogs/DlgExpressionInput.h b/src/Gui/Dialogs/DlgExpressionInput.h index 7cb5c8dd92..7f6f20220a 100644 --- a/src/Gui/Dialogs/DlgExpressionInput.h +++ b/src/Gui/Dialogs/DlgExpressionInput.h @@ -120,6 +120,8 @@ private: static bool varSetsVisible; std::unique_ptr treeWidget; + QPushButton* okBtn = nullptr; + QPushButton* discardBtn = nullptr; }; } diff --git a/src/Gui/Dialogs/DlgExpressionInput.ui b/src/Gui/Dialogs/DlgExpressionInput.ui index 8b07b3812a..6b33d3cd25 100644 --- a/src/Gui/Dialogs/DlgExpressionInput.ui +++ b/src/Gui/Dialogs/DlgExpressionInput.ui @@ -249,42 +249,6 @@ - - - - 2 - - - - - Revert to last calculated value (as constant) - - - &Clear - - - true - - - false - - - - - - - &OK - - - true - - - true - - - - - @@ -298,6 +262,13 @@ + + + + QDialogButtonBox::Reset|QDialogButtonBox::Ok + + + @@ -324,15 +295,14 @@ expression - okBtn - discardBtn + buttonBox checkBoxVarSets - okBtn - clicked() + buttonBox + accepted() DlgExpressionInput accept() diff --git a/src/Gui/Dialogs/DlgKeyboardImp.cpp b/src/Gui/Dialogs/DlgKeyboardImp.cpp index 6a90b7950c..c394bff10f 100644 --- a/src/Gui/Dialogs/DlgKeyboardImp.cpp +++ b/src/Gui/Dialogs/DlgKeyboardImp.cpp @@ -139,7 +139,7 @@ void DlgCustomKeyboardImp::setupConnections() this, &DlgCustomKeyboardImp::onButtonResetClicked); connect(ui->buttonResetAll, &QPushButton::clicked, this, &DlgCustomKeyboardImp::onButtonResetAllClicked); - connect(ui->editShortcut, &AccelLineEdit::textChanged, + connect(ui->editShortcut, &AccelLineEdit::keySequenceChanged, this, &DlgCustomKeyboardImp::onEditShortcutTextChanged); // clang-format on } @@ -336,11 +336,11 @@ DlgCustomKeyboardImp::initCommandWidgets(QTreeWidget* commandTreeWidget, auto timer = new QTimer(priorityList); timer->setSingleShot(true); if (currentShortcut) { - QObject::connect(currentShortcut, &QLineEdit::textChanged, timer, [timer]() { + QObject::connect(currentShortcut, &AccelLineEdit::keySequenceChanged, timer, [timer]() { timer->start(200); }); } - QObject::connect(editShortcut, &QLineEdit::textChanged, timer, [timer]() { + QObject::connect(editShortcut, &AccelLineEdit::keySequenceChanged, timer, [timer]() { timer->start(200); }); QObject::connect(ShortcutManager::instance(), @@ -368,10 +368,10 @@ void DlgCustomKeyboardImp::populatePriorityList(QTreeWidget* priorityList, priorityList->clear(); QString sc; - if (!editor->isNone() && editor->text().size()) { + if (!editor->isEmpty()) { sc = editor->text(); } - else if (curShortcut && !curShortcut->isNone()) { + else if (curShortcut && !curShortcut->isEmpty()) { sc = curShortcut->text(); } @@ -466,10 +466,10 @@ void DlgCustomKeyboardImp::onCommandTreeWidgetCurrentItemChanged(QTreeWidgetItem QKeySequence ks2 = QString::fromLatin1(cmd->getAccel()); QKeySequence ks3 = ui->editShortcut->text(); if (ks.isEmpty()) { - ui->accelLineEditShortcut->setText(tr("none")); + ui->accelLineEditShortcut->clear(); } else { - ui->accelLineEditShortcut->setText(ks.toString(QKeySequence::NativeText)); + ui->accelLineEditShortcut->setKeySequence(ks); } ui->buttonAssign->setEnabled(!ui->editShortcut->text().isEmpty() && (ks != ks3)); @@ -500,7 +500,7 @@ void DlgCustomKeyboardImp::setShortcutOfCurrentAction(const QString& accelText) if (!accelText.isEmpty()) { QKeySequence shortcut = accelText; portableText = shortcut.toString(QKeySequence::PortableText); - ui->accelLineEditShortcut->setText(accelText); + ui->accelLineEditShortcut->setKeySequence(shortcut); ui->editShortcut->clear(); } else { @@ -538,7 +538,7 @@ void DlgCustomKeyboardImp::onButtonResetClicked() ShortcutManager::instance()->reset(name); QString txt = ShortcutManager::instance()->getShortcut(name); - ui->accelLineEditShortcut->setText((txt.isEmpty() ? tr("none") : txt)); + ui->accelLineEditShortcut->setKeySequence(QKeySequence(txt)); ui->buttonReset->setEnabled(false); } @@ -550,7 +550,7 @@ void DlgCustomKeyboardImp::onButtonResetAllClicked() } /** Checks for an already occupied shortcut. */ -void DlgCustomKeyboardImp::onEditShortcutTextChanged(const QString&) +void DlgCustomKeyboardImp::onEditShortcutTextChanged(const QKeySequence&) { QTreeWidgetItem* item = ui->commandTreeWidget->currentItem(); if (item) { @@ -560,7 +560,7 @@ void DlgCustomKeyboardImp::onEditShortcutTextChanged(const QString&) CommandManager& cCmdMgr = Application::Instance->commandManager(); Command* cmd = cCmdMgr.getCommandByName(name.constData()); - if (!ui->editShortcut->isNone()) { + if (!ui->editShortcut->isEmpty()) { ui->buttonAssign->setEnabled(true); } else { diff --git a/src/Gui/Dialogs/DlgKeyboardImp.h b/src/Gui/Dialogs/DlgKeyboardImp.h index 1cdc954439..62bae929eb 100644 --- a/src/Gui/Dialogs/DlgKeyboardImp.h +++ b/src/Gui/Dialogs/DlgKeyboardImp.h @@ -108,7 +108,7 @@ protected: void onButtonClearClicked(); void onButtonResetClicked(); void onButtonResetAllClicked(); - void onEditShortcutTextChanged(const QString&); + void onEditShortcutTextChanged(const QKeySequence&); protected Q_SLOTS: void onAddMacroAction(const QByteArray&) override; diff --git a/src/Gui/Dialogs/DlgPreferencesImp.cpp b/src/Gui/Dialogs/DlgPreferencesImp.cpp index d451d534e1..d5b539994e 100644 --- a/src/Gui/Dialogs/DlgPreferencesImp.cpp +++ b/src/Gui/Dialogs/DlgPreferencesImp.cpp @@ -365,18 +365,9 @@ int DlgPreferencesImp::minimumDialogWidth(int pageWidth) const { // this is additional safety spacing to ensure that everything fits with scrollbar etc. const auto additionalMargin = style()->pixelMetric(QStyle::PM_ScrollBarExtent) + 8; - - QSize size = ui->groupWidgetStack->sizeHint(); - int diff = pageWidth - size.width(); - int dw = width(); - - if (diff > 0) { - const int offset = 2; - dw += diff + offset; - } - - return dw + additionalMargin; + QSize tree = ui->groupsTreeView->sizeHint(); + return pageWidth + tree.width() + additionalMargin; } void DlgPreferencesImp::updatePageDependentWidgets() @@ -908,7 +899,7 @@ void DlgPreferencesImp::onStackWidgetChange(int index) ui->groupsTreeView->expand(parentItem->index()); parentItem->setExpanded(wasExpanded); } - + ui->groupsTreeView->selectionModel()->select(currentIndex, QItemSelectionModel::ClearAndSelect); } diff --git a/src/Gui/Dialogs/DlgProjectInformationImp.cpp b/src/Gui/Dialogs/DlgProjectInformationImp.cpp index 465c04106c..a242448d27 100644 --- a/src/Gui/Dialogs/DlgProjectInformationImp.cpp +++ b/src/Gui/Dialogs/DlgProjectInformationImp.cpp @@ -24,7 +24,9 @@ #ifndef _PreComp_ #include #include +#include #include +#include #include #endif @@ -71,15 +73,25 @@ DlgProjectInformationImp::DlgProjectInformationImp(App::Document* doc, , _doc(doc) , ui(new Ui_DlgProjectInformation) { + auto convertISODate = [](const char* isoDate) { + auto str = QString::fromUtf8(isoDate); + QDateTime dt = QDateTime::fromString(str, Qt::DateFormat::ISODate); + if (dt.isNull()) { + return str; + } + + QLocale loc = QLocale::system(); + return loc.toString(dt); + }; ui->setupUi(this); ui->lineEditName->setText(QString::fromUtf8(doc->Label.getValue())); ui->lineEditPath->setText(QString::fromUtf8(doc->FileName.getValue())); ui->lineEditUuid->setText(QString::fromUtf8(doc->Uid.getValueStr().c_str())); ui->lineEditProgramVersion->setText(QString::fromUtf8(doc->getProgramVersion())); ui->lineEditCreator->setText(QString::fromUtf8(doc->CreatedBy.getValue())); - ui->lineEditDate->setText(QString::fromUtf8(doc->CreationDate.getValue())); + ui->lineEditDate->setText(convertISODate(doc->CreationDate.getValue())); ui->lineEditLastMod->setText(QString::fromUtf8(doc->LastModifiedBy.getValue())); - ui->lineEditLastModDate->setText(QString::fromUtf8(doc->LastModifiedDate.getValue())); + ui->lineEditLastModDate->setText(convertISODate(doc->LastModifiedDate.getValue())); ui->lineEditCompany->setText(QString::fromUtf8(doc->Company.getValue())); // Load comboBox with unit systems diff --git a/src/Gui/DockWindowManager.cpp b/src/Gui/DockWindowManager.cpp index 69eb85409c..9a65987ec6 100644 --- a/src/Gui/DockWindowManager.cpp +++ b/src/Gui/DockWindowManager.cpp @@ -49,13 +49,13 @@ DockWindowItems::DockWindowItems() = default; DockWindowItems::~DockWindowItems() = default; -void DockWindowItems::addDockWidget(const char* name, Qt::DockWidgetArea pos, bool visibility, bool tabbed) +void DockWindowItems::addDockWidget(const char* name, Qt::DockWidgetArea pos, DockWindowOptions option) { DockWindowItem item; item.name = QString::fromUtf8(name); item.pos = pos; - item.visibility = visibility; - item.tabbed = tabbed; + item.visibility = option.testFlag(DockWindowOption::Visible); + item.tabbed = option.testFlag(DockWindowOption::HiddenTabbed); _items << item; } diff --git a/src/Gui/DockWindowManager.h b/src/Gui/DockWindowManager.h index c6ceb9440c..19cf6fe230 100644 --- a/src/Gui/DockWindowManager.h +++ b/src/Gui/DockWindowManager.h @@ -24,6 +24,7 @@ #define GUI_DOCKWINDOWMANAGER_H #include +#include #include class QDockWidget; @@ -31,6 +32,18 @@ class QWidget; namespace Gui { +enum class DockWindowOption +{ + // clang-format off + Hidden = 0, + Visible = 1, + HiddenTabbed = 2, + VisibleTabbed = 3 + // clang-format on +}; + +using DockWindowOptions = Base::Flags; + struct DockWindowItem { QString name; Qt::DockWidgetArea pos; @@ -44,7 +57,7 @@ public: DockWindowItems(); ~DockWindowItems(); - void addDockWidget(const char* name, Qt::DockWidgetArea pos, bool visibility, bool tabbed); + void addDockWidget(const char* name, Qt::DockWidgetArea pos, DockWindowOptions option); void setDockingArea(const char* name, Qt::DockWidgetArea pos); void setVisibility(const char* name, bool v); void setVisibility(bool v); @@ -122,4 +135,6 @@ private: } // namespace Gui +ENABLE_BITMASK_OPERATORS(Gui::DockWindowOption) + #endif // GUI_DOCKWINDOWMANAGER_H diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 7182eaae31..50d97b3b17 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -648,6 +648,7 @@ bool Document::trySetEdit(Gui::ViewProvider* p, int ModNum, const char *subname) Application::Instance->setEditDocument(this); if (!d->tryStartEditing(vp, obj, _subname.c_str(), ModNum)) { + d->setDocumentNameOfTaskDialog(getDocument()); return false; } @@ -2719,21 +2720,42 @@ void Document::handleChildren3D(ViewProvider* viewProvider, bool deleting) if(!deleting) { for (const auto & it : children) { - ViewProvider* ChildViewProvider = getViewProvider(it); - if (ChildViewProvider) { - auto itOld = oldChildren.find(static_cast(ChildViewProvider)); + if (auto ChildViewProvider = dynamic_cast(getViewProvider(it))) { + auto itOld = oldChildren.find(ChildViewProvider); if(itOld!=oldChildren.end()) oldChildren.erase(itOld); - SoSeparator* childRootNode = ChildViewProvider->getRoot(); - childGroup->addChild(childRootNode); + if (SoSeparator* childRootNode = ChildViewProvider->getRoot()) { + if (childRootNode == childGroup) { + Base::Console().warning("Document::handleChildren3D: Do not add " + "group of '%s' to itself\n", + it->getNameInDocument()); + } + else if (childGroup) { + childGroup->addChild(childRootNode); + } + } - SoSeparator* childFrontNode = ChildViewProvider->getFrontRoot(); - if (frontGroup && childFrontNode) - frontGroup->addChild(childFrontNode); + if (SoSeparator* childFrontNode = ChildViewProvider->getFrontRoot()) { + if (childFrontNode == frontGroup) { + Base::Console().warning("Document::handleChildren3D: Do not add " + "foreground group of '%s' to itself\n", + it->getNameInDocument()); + } + else if (frontGroup) { + frontGroup->addChild(childFrontNode); + } + } - SoSeparator* childBackNode = ChildViewProvider->getBackRoot(); - if (backGroup && childBackNode) - backGroup->addChild(childBackNode); + if (SoSeparator* childBackNode = ChildViewProvider->getBackRoot()) { + if (childBackNode == backGroup) { + Base::Console().warning("Document::handleChildren3D: Do not add " + "background group of '%s' to itself\n", + it->getNameInDocument()); + } + else if (backGroup) { + backGroup->addChild(childBackNode); + } + } // cycling to all views of the document to remove the viewprovider from the viewer itself for (Gui::BaseView* vIt : d->baseViews) { diff --git a/src/Gui/DocumentRecovery.cpp b/src/Gui/DocumentRecovery.cpp index 539cddecbe..642f730332 100644 --- a/src/Gui/DocumentRecovery.cpp +++ b/src/Gui/DocumentRecovery.cpp @@ -49,6 +49,7 @@ #include #include +#include #include #include #include @@ -164,6 +165,7 @@ public: QList recoveryInfo; Info getRecoveryInfo(const QFileInfo&) const; + bool isValidProject(const QFileInfo&) const; void writeRecoveryInfo(const Info&) const; XmlConfig readXmlFile(const QString& fn) const; }; @@ -433,7 +435,7 @@ DocumentRecoveryPrivate::Info DocumentRecoveryPrivate::getRecoveryInfo(const QFi if (info.status == DocumentRecoveryPrivate::Created) { // compare the modification dates QFileInfo fileInfo(info.fileName); - if (!info.fileName.isEmpty() && fileInfo.exists()) { + if (!info.fileName.isEmpty() && isValidProject(fileInfo)) { QDateTime dateRecv = QFileInfo(file).lastModified(); QDateTime dateProj = fileInfo.lastModified(); if (dateRecv < dateProj) { @@ -449,6 +451,16 @@ DocumentRecoveryPrivate::Info DocumentRecoveryPrivate::getRecoveryInfo(const QFi return info; } +bool DocumentRecoveryPrivate::isValidProject(const QFileInfo& fi) const +{ + if (!fi.exists()) { + return false; + } + + App::ProjectFile project(fi.absoluteFilePath().toStdString()); + return project.loadDocument(); +} + DocumentRecoveryPrivate::XmlConfig DocumentRecoveryPrivate::readXmlFile(const QString& fn) const { DocumentRecoveryPrivate::XmlConfig cfg; diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index ab2cf7184c..0a76f6dba0 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -120,6 +120,7 @@ #include "Dialogs/DlgObjectSelection.h" #include +#include "QtWidgets.h" FC_LOG_LEVEL_INIT("MainWindow",false,true,true) diff --git a/src/Gui/Navigation/NavigationStyle.cpp b/src/Gui/Navigation/NavigationStyle.cpp index 38f170877c..ca3d7c3887 100644 --- a/src/Gui/Navigation/NavigationStyle.cpp +++ b/src/Gui/Navigation/NavigationStyle.cpp @@ -319,10 +319,10 @@ NavigationStyle::~NavigationStyle() finalize(); delete this->animator; - if (pythonObject) { + if (!pythonObject.is(nullptr)) { Base::PyGILStateLocker lock; - Py_DECREF(pythonObject); - pythonObject = nullptr; + Base::PyObjectBase* obj = static_cast(pythonObject.ptr()); + obj->setInvalid(); } } @@ -1914,11 +1914,11 @@ void NavigationStyle::openPopupMenu(const SbVec2s& position) PyObject* NavigationStyle::getPyObject() { - if (!pythonObject) - pythonObject = new NavigationStylePy(this); - - Py_INCREF(pythonObject); - return pythonObject; + if (pythonObject.is(nullptr)) { + // ref counter is set to 1 + pythonObject = Py::asObject(new NavigationStylePy(this)); + } + return Py::new_reference_to(pythonObject); } // ---------------------------------------------------------------------------------- diff --git a/src/Gui/Navigation/NavigationStyle.h b/src/Gui/Navigation/NavigationStyle.h index b3000728ab..be54296471 100644 --- a/src/Gui/Navigation/NavigationStyle.h +++ b/src/Gui/Navigation/NavigationStyle.h @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -283,7 +284,7 @@ protected: SbSphereSheetProjector * spinprojector; //@} - PyObject* pythonObject; + Py::SmartPtr pythonObject; private: friend class NavigationAnimator; diff --git a/src/Gui/PythonEditor.cpp b/src/Gui/PythonEditor.cpp index a76c1eeba7..4154cc6a4d 100644 --- a/src/Gui/PythonEditor.cpp +++ b/src/Gui/PythonEditor.cpp @@ -243,27 +243,7 @@ void PythonEditor::onComment() void PythonEditor::onUncomment() { - QTextCursor cursor = textCursor(); - int selStart = cursor.selectionStart(); - int selEnd = cursor.selectionEnd(); - QTextBlock block; - cursor.beginEditBlock(); - for (block = document()->begin(); block.isValid(); block = block.next()) { - int pos = block.position(); - int off = block.length()-1; - // at least one char of the block is part of the selection - if ( pos >= selStart || pos+off >= selStart) { - if ( pos+1 > selEnd ) - break; // end of selection reached - if (block.text().startsWith(QLatin1String("#"))) { - cursor.setPosition(block.position()); - cursor.deleteChar(); - selEnd--; - } - } - } - - cursor.endEditBlock(); + remove(QStringLiteral("#")); } void PythonEditor::onExecuteInConsole() diff --git a/src/Gui/TaskTransform.cpp b/src/Gui/TaskTransform.cpp index fddb2dc46a..0fd71933d5 100644 --- a/src/Gui/TaskTransform.cpp +++ b/src/Gui/TaskTransform.cpp @@ -728,16 +728,39 @@ void TaskTransformDialog::open() Gui::TaskView::TaskDialog::open(); - Gui::Application::Instance->activeDocument()->openCommand( - QT_TRANSLATE_NOOP("Command", "Transform")); + openCommand(); +} + +void TaskTransformDialog::openCommand() +{ + if (auto document = vp->getDocument()) { + if (!document->hasPendingCommand()) { + document->openCommand(QT_TRANSLATE_NOOP("Command", "Transform")); + } + } +} + +void TaskTransformDialog::updateDraggerPlacement() +{ + const auto placement = vp->getObjectPlacement(); + vp->setDraggerPlacement(placement); +} + +void TaskTransformDialog::onUndo() +{ + updateDraggerPlacement(); + openCommand(); +} + +void TaskTransformDialog::onRedo() +{ + updateDraggerPlacement(); + openCommand(); } bool TaskTransformDialog::accept() { - if (auto documentObject = vp->getObject()) { - Gui::Document* document = - Gui::Application::Instance->getDocument(documentObject->getDocument()); - assert(document); + if (auto document = vp->getDocument()) { document->commitCommand(); document->resetEdit(); document->getDocument()->recompute(); @@ -748,10 +771,7 @@ bool TaskTransformDialog::accept() bool TaskTransformDialog::reject() { - if (auto documentObject = vp->getObject()) { - Gui::Document* document = - Gui::Application::Instance->getDocument(documentObject->getDocument()); - assert(document); + if (auto document = vp->getDocument()) { document->abortCommand(); document->resetEdit(); document->getDocument()->recompute(); diff --git a/src/Gui/TaskTransform.h b/src/Gui/TaskTransform.h index 746f12e43b..31a05c7dd9 100644 --- a/src/Gui/TaskTransform.h +++ b/src/Gui/TaskTransform.h @@ -166,6 +166,12 @@ public: void open() override; bool accept() override; bool reject() override; + void onUndo() override; + void onRedo() override; + +private: + void openCommand(); + void updateDraggerPlacement(); private: ViewProviderDragger* vp; diff --git a/src/Gui/TaskView/TaskDialog.cpp b/src/Gui/TaskView/TaskDialog.cpp index 5c5bceb088..aba148c36d 100644 --- a/src/Gui/TaskView/TaskDialog.cpp +++ b/src/Gui/TaskView/TaskDialog.cpp @@ -172,6 +172,16 @@ void TaskDialog::helpRequested() } +void TaskDialog::onUndo() +{ + +} + +void TaskDialog::onRedo() +{ + +} + diff --git a/src/Gui/TaskView/TaskDialog.h b/src/Gui/TaskView/TaskDialog.h index 41f6d6e54b..6162efa19d 100644 --- a/src/Gui/TaskView/TaskDialog.h +++ b/src/Gui/TaskView/TaskDialog.h @@ -162,8 +162,12 @@ public: virtual bool accept(); /// is called by the framework if the dialog is rejected (Cancel) virtual bool reject(); - /// is called by the framework if the user press the help button + /// is called by the framework if the user press the help button virtual void helpRequested(); + /// is called by the framework if the user press the undo button + virtual void onUndo(); + /// is called by the framework if the user press the redo button + virtual void onRedo(); void emitDestructionSignal() { Q_EMIT aboutToBeDestroyed(); diff --git a/src/Gui/TaskView/TaskView.cpp b/src/Gui/TaskView/TaskView.cpp index 25ee639aed..37cee0a18d 100644 --- a/src/Gui/TaskView/TaskView.cpp +++ b/src/Gui/TaskView/TaskView.cpp @@ -503,11 +503,15 @@ void TaskView::slotViewClosed(const Gui::MDIView* view) } } -void TaskView::transactionChangeOnDocument(const App::Document& doc) +void TaskView::transactionChangeOnDocument(const App::Document& doc, bool undo) { if (ActiveDialog) { + std::string name = ActiveDialog->getDocumentName(); + if (name == doc.getName()) { + undo ? ActiveDialog->onUndo() : ActiveDialog->onRedo(); + } + if (ActiveDialog->isAutoCloseOnTransactionChange()) { - std::string name = ActiveDialog->getDocumentName(); if (name.empty()) { Base::Console().warning(std::string("TaskView::transactionChangeOnDocument"), "No document name set\n"); @@ -527,12 +531,12 @@ void TaskView::transactionChangeOnDocument(const App::Document& doc) void TaskView::slotUndoDocument(const App::Document& doc) { - transactionChangeOnDocument(doc); + transactionChangeOnDocument(doc, true); } void TaskView::slotRedoDocument(const App::Document& doc) { - transactionChangeOnDocument(doc); + transactionChangeOnDocument(doc, false); } /// @cond DOXERR diff --git a/src/Gui/TaskView/TaskView.h b/src/Gui/TaskView/TaskView.h index f613c4d0d1..bf4537f1b7 100644 --- a/src/Gui/TaskView/TaskView.h +++ b/src/Gui/TaskView/TaskView.h @@ -187,7 +187,7 @@ private: void slotViewClosed(const Gui::MDIView*); void slotUndoDocument(const App::Document&); void slotRedoDocument(const App::Document&); - void transactionChangeOnDocument(const App::Document&); + void transactionChangeOnDocument(const App::Document&, bool undo); protected: void keyPressEvent(QKeyEvent* event) override; diff --git a/src/Gui/TextEdit.cpp b/src/Gui/TextEdit.cpp index 0ad823dce7..c11d081101 100644 --- a/src/Gui/TextEdit.cpp +++ b/src/Gui/TextEdit.cpp @@ -519,6 +519,34 @@ void PythonTextEditor::prepend(const QString& str) cursor.endEditBlock(); } +void PythonTextEditor::remove(const QString& str) +{ + QTextCursor cursor = textCursor(); + int selStart = cursor.selectionStart(); + int selEnd = cursor.selectionEnd(); + QTextBlock block; + cursor.beginEditBlock(); + for (block = document()->begin(); block.isValid(); block = block.next()) { + int pos = block.position(); + int off = block.length()-1; + // at least one char of the block is part of the selection + if ( pos >= selStart || pos+off >= selStart) { + if ( pos+1 > selEnd ) + break; // end of selection reached + QString text = block.text(); + if (text.startsWith(str)) { + cursor.setPosition(block.position()); + for (int i = 0; i < str.length(); i++) { + cursor.deleteChar(); + selEnd--; + } + } + } + } + + cursor.endEditBlock(); +} + void PythonTextEditor::keyPressEvent (QKeyEvent * e) { if ( e->key() == Qt::Key_Tab ) { @@ -547,40 +575,13 @@ void PythonTextEditor::keyPressEvent (QKeyEvent * e) // If some text is selected we remove a leading tab or // spaces from each selected block ParameterGrp::handle hPrefGrp = getWindowParameter(); + bool space = hPrefGrp->GetBool("Spaces", true); int indent = hPrefGrp->GetInt( "IndentSize", 4 ); + QString ch = space ? QString(indent, QLatin1Char(' ')) + : QStringLiteral("\t"); - int selStart = cursor.selectionStart(); - int selEnd = cursor.selectionEnd(); - QTextBlock block; - cursor.beginEditBlock(); - for (block = document()->begin(); block.isValid(); block = block.next()) { - int pos = block.position(); - int off = block.length()-1; - // at least one char of the block is part of the selection - if ( pos >= selStart || pos+off >= selStart) { - if ( pos+1 > selEnd ) - break; // end of selection reached - // if possible remove one tab or several spaces - QString text = block.text(); - if (text.startsWith(QLatin1String("\t"))) { - cursor.setPosition(block.position()); - cursor.deleteChar(); - selEnd--; - } - else { - cursor.setPosition(block.position()); - for (int i=0; i ViewProviderCoordinateSystem::claimChildren() const { - return static_cast( getObject() )->OriginFeatures.getValues(); + auto obj = getObject(); + std::vector childs = obj->OriginFeatures.getValues(); + auto it = std::find(childs.begin(), childs.end(), obj); + if (it != childs.end()) { + childs.erase(it); + } + return childs; } -std::vector ViewProviderCoordinateSystem::claimChildren3D() const { - return claimChildren (); +std::vector ViewProviderCoordinateSystem::claimChildren3D() const +{ + return claimChildren(); } void ViewProviderCoordinateSystem::attach(App::DocumentObject* pcObject) diff --git a/src/Gui/ViewProviderLink.cpp b/src/Gui/ViewProviderLink.cpp index 265d77ef56..28f8f71f6c 100644 --- a/src/Gui/ViewProviderLink.cpp +++ b/src/Gui/ViewProviderLink.cpp @@ -2793,11 +2793,13 @@ ViewProvider *ViewProviderLink::startEditing(int mode) { } if (auto result = inherited::startEditing(mode)) { - transformDragger->addStartCallback(dragStartCallback, this); - transformDragger->addFinishCallback(dragFinishCallback, this); - transformDragger->addMotionCallback(dragMotionCallback, this); + if (transformDragger.get()) { + transformDragger->addStartCallback(dragStartCallback, this); + transformDragger->addFinishCallback(dragFinishCallback, this); + transformDragger->addMotionCallback(dragMotionCallback, this); - setDraggerPlacement(dragCtx->initialPlacement); + setDraggerPlacement(dragCtx->initialPlacement); + } return result; } diff --git a/src/Gui/Widgets.cpp b/src/Gui/Widgets.cpp index a112f5ba42..0c4854d85e 100644 --- a/src/Gui/Widgets.cpp +++ b/src/Gui/Widgets.cpp @@ -358,105 +358,39 @@ void ActionSelector::onDownButtonClicked() /** * Constructs a line edit with no text. - * The \a parent argument is sent to the QLineEdit constructor. + * The \a parent argument is sent to the QKeySequenceEdit constructor. */ -AccelLineEdit::AccelLineEdit ( QWidget * parent ) - : QLineEdit(parent) +AccelLineEdit::AccelLineEdit(QWidget* parent) + : QKeySequenceEdit(parent) { - setPlaceholderText(tr("Press a keyboard shortcut")); - setClearButtonEnabled(true); - keyPressedCount = 0; + if (auto le = findChild()) { + le->setClearButtonEnabled(true); + } } -bool AccelLineEdit::isNone() const +AccelLineEdit::AccelLineEdit(const QKeySequence& keySequence, QWidget* parent) + : QKeySequenceEdit(keySequence, parent) { - return text().isEmpty(); + if (auto le = findChild()) { + le->setClearButtonEnabled(true); + } } -/** - * Checks which keys are pressed and show it as text. - */ -void AccelLineEdit::keyPressEvent (QKeyEvent * e) +void AccelLineEdit::setReadOnly(bool value) { - if (isReadOnly()) { - QLineEdit::keyPressEvent(e); - return; + if (auto le = findChild()) { + le->setReadOnly(value); } +} - QString txtLine = text(); +bool AccelLineEdit::isEmpty() const +{ + return keySequence().isEmpty(); +} - int key = e->key(); - Qt::KeyboardModifiers state = e->modifiers(); - - // Backspace clears the shortcut if text is present, else sets Backspace as shortcut. - // If a modifier is pressed without any other key, return. - // AltGr is not a modifier but doesn't have a QString representation. - switch(key) { - case Qt::Key_Backspace: - case Qt::Key_Delete: - if (state == Qt::NoModifier) { - keyPressedCount = 0; - if (isNone()) { - QKeySequence ks(key); - setText(ks.toString(QKeySequence::NativeText)); - } - else { - clear(); - } - } - case Qt::Key_Control: - case Qt::Key_Shift: - case Qt::Key_Alt: - case Qt::Key_Meta: - case Qt::Key_AltGr: - return; - default: - break; - } - - if (txtLine.isEmpty()) { - // Text maybe cleared by QLineEdit's built in clear button - keyPressedCount = 0; - } else { - // 4 keys are allowed for QShortcut - switch (keyPressedCount) { - case 4: - keyPressedCount = 0; - txtLine.clear(); - break; - case 0: - txtLine.clear(); - break; - default: - txtLine += QStringLiteral(","); - break; - } - } - - // Handles modifiers applying a mask. - if ((state & Qt::ControlModifier) == Qt::ControlModifier) { - QKeySequence ks(Qt::CTRL); - txtLine += ks.toString(QKeySequence::NativeText); - } - if ((state & Qt::AltModifier) == Qt::AltModifier) { - QKeySequence ks(Qt::ALT); - txtLine += ks.toString(QKeySequence::NativeText); - } - if ((state & Qt::ShiftModifier) == Qt::ShiftModifier) { - QKeySequence ks(Qt::SHIFT); - txtLine += ks.toString(QKeySequence::NativeText); - } - if ((state & Qt::MetaModifier) == Qt::MetaModifier) { - QKeySequence ks(Qt::META); - txtLine += ks.toString(QKeySequence::NativeText); - } - - // Handles normal keys - QKeySequence ks(key); - txtLine += ks.toString(QKeySequence::NativeText); - - setText(txtLine); - keyPressedCount++; +QString AccelLineEdit::text() const +{ + return keySequence().toString(QKeySequence::NativeText); } // ------------------------------------------------------------------------------ diff --git a/src/Gui/Widgets.h b/src/Gui/Widgets.h index 01f4ab54f9..f086c28f91 100644 --- a/src/Gui/Widgets.h +++ b/src/Gui/Widgets.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -132,19 +133,16 @@ private: * The AccelLineEdit class provides a lineedit to specify shortcuts. * \author Werner Mayer */ -class GuiExport AccelLineEdit : public QLineEdit +class GuiExport AccelLineEdit : public QKeySequenceEdit { Q_OBJECT public: - AccelLineEdit(QWidget * parent=nullptr); - bool isNone() const; - -protected: - void keyPressEvent(QKeyEvent * e) override; - -private: - int keyPressedCount; + explicit AccelLineEdit(QWidget* parent = nullptr); + explicit AccelLineEdit(const QKeySequence& keySequence, QWidget* parent = nullptr); + void setReadOnly(bool value); + bool isEmpty() const; + QString text() const; }; // ------------------------------------------------------------------------------ diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index e0c8a65f05..6aecbb3b49 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -463,6 +463,9 @@ void Workbench::removeTaskWatcher() std::list Workbench::listToolbars() const { std::unique_ptr tb(setupToolBars()); + setupCustomToolbars(tb.get(), "Toolbar"); + WorkbenchManipulator::changeToolBars(tb.get()); + std::list bars; QList items = tb->getItems(); for (const auto & item : items) { @@ -474,6 +477,8 @@ std::list Workbench::listToolbars() const std::list>> Workbench::getToolbarItems() const { std::unique_ptr tb(setupToolBars()); + setupCustomToolbars(tb.get(), "Toolbar"); + WorkbenchManipulator::changeToolBars(tb.get()); std::list>> itemsList; QList items = tb->getItems(); @@ -492,6 +497,9 @@ std::list>> Workbench::getToolbarI std::list Workbench::listMenus() const { std::unique_ptr mb(setupMenuBar()); + addPermanentMenuItems(mb.get()); + WorkbenchManipulator::changeMenuBar(mb.get()); + std::list menus; QList items = mb->getItems(); for (const auto & item : items) { @@ -852,13 +860,13 @@ ToolBarItem* StdWorkbench::setupCommandBars() const DockWindowItems* StdWorkbench::setupDockWindows() const { auto root = new DockWindowItems(); - root->addDockWidget("Std_TreeView", Qt::LeftDockWidgetArea, true, false); - root->addDockWidget("Std_PropertyView", Qt::LeftDockWidgetArea, true, false); - root->addDockWidget("Std_SelectionView", Qt::LeftDockWidgetArea, false, false); - root->addDockWidget("Std_ComboView", Qt::LeftDockWidgetArea, true, true); - root->addDockWidget("Std_TaskView", Qt::LeftDockWidgetArea, true, true); - root->addDockWidget("Std_ReportView", Qt::BottomDockWidgetArea, false, true); - root->addDockWidget("Std_PythonView", Qt::BottomDockWidgetArea, false, true); + root->addDockWidget("Std_TreeView", Qt::LeftDockWidgetArea, Gui::DockWindowOption::Visible); + root->addDockWidget("Std_PropertyView", Qt::LeftDockWidgetArea, Gui::DockWindowOption::Visible); + root->addDockWidget("Std_SelectionView", Qt::LeftDockWidgetArea, Gui::DockWindowOption::Hidden); + root->addDockWidget("Std_ComboView", Qt::LeftDockWidgetArea, Gui::DockWindowOption::VisibleTabbed); + root->addDockWidget("Std_TaskView", Qt::LeftDockWidgetArea, Gui::DockWindowOption::VisibleTabbed); + root->addDockWidget("Std_ReportView", Qt::BottomDockWidgetArea, Gui::DockWindowOption::HiddenTabbed); + root->addDockWidget("Std_PythonView", Qt::BottomDockWidgetArea, Gui::DockWindowOption::HiddenTabbed); //Dagview through parameter. ParameterGrp::handle group = App::GetApplication().GetUserParameter(). @@ -866,7 +874,7 @@ DockWindowItems* StdWorkbench::setupDockWindows() const bool enabled = group->GetBool("Enabled", false); if (enabled) { - root->addDockWidget("Std_DAGView", Qt::RightDockWidgetArea, false, false); + root->addDockWidget("Std_DAGView", Qt::RightDockWidgetArea, Gui::DockWindowOption::Hidden); } return root; @@ -987,7 +995,7 @@ ToolBarItem* NoneWorkbench::setupCommandBars() const DockWindowItems* NoneWorkbench::setupDockWindows() const { auto root = new DockWindowItems(); - root->addDockWidget("Std_ReportView", Qt::BottomDockWidgetArea, true, false); + root->addDockWidget("Std_ReportView", Qt::BottomDockWidgetArea, Gui::DockWindowOption::Visible); return root; } @@ -1049,6 +1057,7 @@ PythonBaseWorkbench::~PythonBaseWorkbench() delete _toolBar; delete _commandBar; if (_workbenchPy) { + Base::PyGILStateLocker lock; _workbenchPy->setInvalid(); _workbenchPy->DecRef(); } diff --git a/src/Gui/propertyeditor/PropertyItem.cpp b/src/Gui/propertyeditor/PropertyItem.cpp index 981bea9857..8964d29ac8 100644 --- a/src/Gui/propertyeditor/PropertyItem.cpp +++ b/src/Gui/propertyeditor/PropertyItem.cpp @@ -3752,37 +3752,33 @@ void PropertyMaterialItem::setValue(const QVariant& value) auto mat = value.value(); Base::Color dc; dc.setValue(mat.diffuseColor); + uint32_t dcp = dc.getPackedValue(); Base::Color ac; ac.setValue(mat.ambientColor); + uint32_t acp = ac.getPackedValue(); Base::Color sc; sc.setValue(mat.specularColor); + uint32_t scp = sc.getPackedValue(); Base::Color ec; ec.setValue(mat.emissiveColor); + uint32_t ecp = ec.getPackedValue(); float s = mat.shininess; float t = mat.transparency; QString data = QStringLiteral("App.Material(" - "DiffuseColor=(%1,%2,%3)," - "AmbientColor=(%4,%5,%6)," - "SpecularColor=(%7,%8,%9)," - "EmissiveColor=(%10,%11,%12)," - "Shininess=(%13)," - "Transparency=(%14)," - ")") - .arg(dc.r, 0, 'f', decimals()) - .arg(dc.g, 0, 'f', decimals()) - .arg(dc.b, 0, 'f', decimals()) - .arg(ac.r, 0, 'f', decimals()) - .arg(ac.g, 0, 'f', decimals()) - .arg(ac.b, 0, 'f', decimals()) - .arg(sc.r, 0, 'f', decimals()) - .arg(sc.g, 0, 'f', decimals()) - .arg(sc.b, 0, 'f', decimals()) - .arg(ec.r, 0, 'f', decimals()) - .arg(ec.g, 0, 'f', decimals()) - .arg(ec.b, 0, 'f', decimals()) - .arg(s, 0, 'f', decimals()) - .arg(t, 0, 'f', decimals()); + "DiffuseColor = %1," + "AmbientColor = %2," + "SpecularColor = %3," + "EmissiveColor = %4," + "Shininess = %5," + "Transparency = %6," + ")") + .arg(dcp) + .arg(acp) + .arg(scp) + .arg(ecp) + .arg(s, 0, 'f', 10) + .arg(t, 0, 'f', 10); setPropertyValue(data); } @@ -4258,37 +4254,33 @@ void PropertyMaterialListItem::setValue(const QVariant& value) auto mat = list[0].value(); Base::Color dc; dc.setValue(mat.diffuseColor); + uint32_t dcp = dc.getPackedValue(); Base::Color ac; ac.setValue(mat.ambientColor); + uint32_t acp = ac.getPackedValue(); Base::Color sc; sc.setValue(mat.specularColor); + uint32_t scp = sc.getPackedValue(); Base::Color ec; ec.setValue(mat.emissiveColor); + uint32_t ecp = ec.getPackedValue(); float s = mat.shininess; float t = mat.transparency; QString item = QStringLiteral("App.Material(" - "DiffuseColor=(%1,%2,%3)," - "AmbientColor=(%4,%5,%6)," - "SpecularColor=(%7,%8,%9)," - "EmissiveColor=(%10,%11,%12)," - "Shininess=(%13)," - "Transparency=(%14)," - ")") - .arg(dc.r, 0, 'f', decimals()) - .arg(dc.g, 0, 'f', decimals()) - .arg(dc.b, 0, 'f', decimals()) - .arg(ac.r, 0, 'f', decimals()) - .arg(ac.g, 0, 'f', decimals()) - .arg(ac.b, 0, 'f', decimals()) - .arg(sc.r, 0, 'f', decimals()) - .arg(sc.g, 0, 'f', decimals()) - .arg(sc.b, 0, 'f', decimals()) - .arg(ec.r, 0, 'f', decimals()) - .arg(ec.g, 0, 'f', decimals()) - .arg(ec.b, 0, 'f', decimals()) - .arg(s, 0, 'f', decimals()) - .arg(t, 0, 'f', decimals()); + "DiffuseColor = %1," + "AmbientColor = %2," + "SpecularColor = %3," + "EmissiveColor = %4," + "Shininess = %5," + "Transparency = %6," + ")") + .arg(dcp) + .arg(acp) + .arg(scp) + .arg(ecp) + .arg(s, 0, 'f', 10) + .arg(t, 0, 'f', 10); str << item << ")"; setPropertyValue(data); diff --git a/src/Mod/Part/Gui/ViewProvider.cpp b/src/Mod/Part/Gui/ViewProvider.cpp index d15bdf649e..81b2862b50 100644 --- a/src/Mod/Part/Gui/ViewProvider.cpp +++ b/src/Mod/Part/Gui/ViewProvider.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include "ViewProvider.h" @@ -50,7 +50,7 @@ bool ViewProviderPart::doubleClicked() try { QString text = QObject::tr("Edit %1").arg(QString::fromUtf8(getObject()->Label.getValue())); Gui::Command::openCommand(text.toUtf8()); - FCMD_SET_EDIT(pcObject); + Gui::cmdSetEdit(pcObject); return true; } catch (const Base::Exception& e) { diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index b435320fea..58ac6fce77 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -63,7 +63,7 @@ bool ViewProvider::doubleClicked() try { QString text = QObject::tr("Edit %1").arg(QString::fromUtf8(getObject()->Label.getValue())); Gui::Command::openCommand(text.toUtf8()); - FCMD_SET_EDIT(pcObject); + Gui::cmdSetEdit(pcObject); } catch (const Base::Exception&) { Gui::Command::abortCommand(); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBase.cpp b/src/Mod/PartDesign/Gui/ViewProviderBase.cpp index 58e9bad695..81b53450ce 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBase.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBase.cpp @@ -24,7 +24,7 @@ #include "PreCompiled.h" #include -#include +#include #include #include "ViewProviderBase.h" @@ -54,7 +54,7 @@ bool ViewProviderBase::doubleClicked() std::string Msg("Edit "); Msg += base->Label.getValue(); Gui::Command::openCommand(Msg.c_str()); - FCMD_SET_EDIT(base); + Gui::cmdSetEdit(base); } catch (const Base::Exception&) { Gui::Command::abortCommand(); diff --git a/src/Mod/TechDraw/Gui/CommandDecorate.cpp b/src/Mod/TechDraw/Gui/CommandDecorate.cpp index 3c7fb3bfcc..e2c0b35f72 100644 --- a/src/Mod/TechDraw/Gui/CommandDecorate.cpp +++ b/src/Mod/TechDraw/Gui/CommandDecorate.cpp @@ -340,7 +340,7 @@ void CmdTechDrawToggleFrame::activated(int iMsg) Gui::Action *action = this->getAction(); if (action) { - action->setChecked(!vpPage->getFrameState(), true); + action->setBlockedChecked(!vpPage->getFrameState()); } } @@ -358,7 +358,7 @@ bool CmdTechDrawToggleFrame::isActive() Gui::Action* action = this->getAction(); if (action) { - action->setChecked(vpp && !vpp->getFrameState(), true); + action->setBlockedChecked(vpp && !vpp->getFrameState()); } return true; diff --git a/src/QtWidgets.h.cmake b/src/QtWidgets.h.cmake new file mode 100644 index 0000000000..c7d64c59f1 --- /dev/null +++ b/src/QtWidgets.h.cmake @@ -0,0 +1,11 @@ +#ifndef FREECAD_QTWIDGETS_H +#define FREECAD_QTWIDGETS_H + +#include + + +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) && QT_VERSION < QT_VERSION_CHECK(6,8,1) +# define HAS_QTBUG_129596 +#endif + +#endif // FREECAD_QTWIDGETS_H