Download src/Gui/TaskView/TaskView.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 31.8 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Gui/TaskView/TaskView.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Gui/TaskView/TaskView.cpp
-
curl -L -o TaskView.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Gui/TaskView/TaskView.cpp
31.8 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2009 Jürgen Riegel <juergen.riegel@web.de> * | |
| * * | |
| * This file is part of the FreeCAD CAx development system. * | |
| * * | |
| * This library is free software; you can redistribute it and/or * | |
| * modify it under the terms of the GNU Library General Public * | |
| * License as published by the Free Software Foundation; either * | |
| * version 2 of the License, or (at your option) any later version. * | |
| * * | |
| * This library is distributed in the hope that it will be useful, * | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
| * GNU Library General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Library General Public * | |
| * License along with this library; see the file COPYING.LIB. If not, * | |
| * write to the Free Software Foundation, Inc., 59 Temple Place, * | |
| * Suite 330, Boston, MA 02111-1307, USA * | |
| * * | |
| ***************************************************************************/ | |
| using namespace Gui::TaskView; | |
| namespace sp = std::placeholders; | |
| //************************************************************************** | |
| //************************************************************************** | |
| // TaskWidget | |
| //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| TaskWidget::TaskWidget(QWidget* parent) | |
| : QWidget(parent) | |
| {} | |
| TaskWidget::~TaskWidget() = default; | |
| //************************************************************************** | |
| //************************************************************************** | |
| // TaskGroup | |
| //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| TaskGroup::TaskGroup(QWidget* parent) | |
| : QSint::ActionBox(parent) | |
| {} | |
| TaskGroup::TaskGroup(const QString& headerText, QWidget* parent) | |
| : QSint::ActionBox(headerText, parent) | |
| {} | |
| TaskGroup::TaskGroup(const QPixmap& icon, const QString& headerText, QWidget* parent) | |
| : QSint::ActionBox(icon, headerText, parent) | |
| {} | |
| TaskGroup::~TaskGroup() = default; | |
| void TaskGroup::actionEvent(QActionEvent* e) | |
| { | |
| QAction* action = e->action(); | |
| switch (e->type()) { | |
| case QEvent::ActionAdded: { | |
| this->createItem(action); | |
| break; | |
| } | |
| case QEvent::ActionChanged: { | |
| break; | |
| } | |
| case QEvent::ActionRemoved: { | |
| // cannot change anything | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| //************************************************************************** | |
| //************************************************************************** | |
| // TaskBox | |
| //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| TaskBox::TaskBox(QWidget* parent) | |
| : QSint::ActionGroup(parent) | |
| , wasShown(false) | |
| { | |
| // override vertical size policy because otherwise task dialogs | |
| // whose needsFullSpace() returns true won't take full space. | |
| myGroup->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); | |
| } | |
| TaskBox::TaskBox(const QString& title, bool expandable, QWidget* parent) | |
| : QSint::ActionGroup(title, expandable, parent) | |
| , wasShown(false) | |
| { | |
| // override vertical size policy because otherwise task dialogs | |
| // whose needsFullSpace() returns true won't take full space. | |
| myGroup->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); | |
| } | |
| TaskBox::TaskBox(const QPixmap& icon, const QString& title, bool expandable, QWidget* parent) | |
| : QSint::ActionGroup(icon, title, expandable, parent) | |
| , wasShown(false) | |
| { | |
| // override vertical size policy because otherwise task dialogs | |
| // whose needsFullSpace() returns true won't take full space. | |
| myGroup->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); | |
| } | |
| QSize TaskBox::minimumSizeHint() const | |
| { | |
| // ActionGroup returns a size of 200x100 which leads to problems | |
| // when there are several task groups in a panel and the first | |
| // one is collapsed. In this case the task panel doesn't expand to | |
| // the actually required size and all the remaining groups are | |
| // squeezed into the available space and thus the widgets in there | |
| // often can't be used any more. | |
| // To fix this problem minimumSizeHint() is implemented to again | |
| // respect the layout's minimum size. | |
| QSize s1 = QSint::ActionGroup::minimumSizeHint(); | |
| QSize s2 = QWidget::minimumSizeHint(); | |
| return {qMax(s1.width(), s2.width()), qMax(s1.height(), s2.height())}; | |
| } | |
| TaskBox::~TaskBox() = default; | |
| void TaskBox::showEvent(QShowEvent*) | |
| { | |
| wasShown = true; | |
| } | |
| void TaskBox::hideGroupBox() | |
| { | |
| if (!wasShown) { | |
| // get approximate height | |
| int h = 0; | |
| int ct = groupLayout()->count(); | |
| for (int i = 0; i < ct; i++) { | |
| QLayoutItem* item = groupLayout()->itemAt(i); | |
| if (item && item->widget()) { | |
| QWidget* w = item->widget(); | |
| h += w->height(); | |
| } | |
| } | |
| m_tempHeight = m_fullHeight = h; | |
| // For the very first time the group gets shown | |
| // we cannot do the animation because the layouting | |
| // is not yet fully done | |
| m_foldDelta = 0; | |
| } | |
| else { | |
| m_tempHeight = m_fullHeight = myGroup->height(); | |
| m_foldDelta = m_fullHeight / myScheme->groupFoldSteps; | |
| } | |
| m_foldStep = 0.0; | |
| m_foldDirection = -1; | |
| // make sure to have the correct icon | |
| bool block = myHeader->blockSignals(true); | |
| myHeader->fold(); | |
| myHeader->blockSignals(block); | |
| myDummy->setFixedHeight(0); | |
| myDummy->hide(); | |
| myGroup->hide(); | |
| m_foldPixmap = QPixmap(); | |
| setFixedHeight(myHeader->height()); | |
| setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); | |
| } | |
| bool TaskBox::isGroupVisible() const | |
| { | |
| return myGroup->isVisible(); | |
| } | |
| void TaskBox::actionEvent(QActionEvent* e) | |
| { | |
| QAction* action = e->action(); | |
| switch (e->type()) { | |
| case QEvent::ActionAdded: { | |
| auto label = new QSint::ActionLabel(action, this); | |
| this->addActionLabel(label, true, false); | |
| break; | |
| } | |
| case QEvent::ActionChanged: { | |
| break; | |
| } | |
| case QEvent::ActionRemoved: { | |
| // cannot change anything | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| //************************************************************************** | |
| //************************************************************************** | |
| // TaskPanel | |
| //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| TaskPanel::TaskPanel(QWidget* parent) | |
| : QSint::ActionPanel(parent) | |
| {} | |
| TaskPanel::~TaskPanel() = default; | |
| QSize TaskPanel::minimumSizeHint() const | |
| { | |
| // ActionPanel returns a size of 200x150 which leads to problems | |
| // when there are several task groups in the panel and the first | |
| // one is collapsed. In this case the task panel doesn't expand to | |
| // the actually required size and all the remaining groups are | |
| // squeezed into the available space and thus the widgets in there | |
| // often can't be used any more. | |
| // To fix this problem minimumSizeHint() is implemented to again | |
| // respect the layout's minimum size. | |
| QSize s1 = QSint::ActionPanel::minimumSizeHint(); | |
| QSize s2 = QWidget::minimumSizeHint(); | |
| return {qMax(s1.width(), s2.width()), qMax(s1.height(), s2.height())}; | |
| } | |
| //************************************************************************** | |
| //************************************************************************** | |
| // TaskView | |
| //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| TaskView::TaskView(QWidget* parent) | |
| : QWidget(parent) | |
| , ActiveDialog(nullptr) | |
| , ActiveCtrl(nullptr) | |
| , hGrp(Gui::WindowParameter::getDefaultParameter()->GetGroup("General")) | |
| { | |
| mainLayout = new QVBoxLayout(this); | |
| mainLayout->setContentsMargins(0, 0, 0, 0); | |
| this->setLayout(mainLayout); | |
| scrollArea = new QScrollArea(this); | |
| contextualPanelsLayout = new QVBoxLayout(); | |
| contextualPanelsLayout->setContentsMargins(0, 0, 0, 0); | |
| mainLayout->addLayout(contextualPanelsLayout); | |
| dialogLayout = new QVBoxLayout(); | |
| dialogLayout->setContentsMargins(0, 0, 0, 0); | |
| dialogLayout->setSpacing(0); | |
| mainLayout->addLayout(dialogLayout, 1); | |
| taskPanel = new TaskPanel(scrollArea); | |
| QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); | |
| sizePolicy.setHorizontalStretch(0); | |
| sizePolicy.setVerticalStretch(0); | |
| sizePolicy.setHeightForWidth(taskPanel->sizePolicy().hasHeightForWidth()); | |
| taskPanel->setSizePolicy(sizePolicy); | |
| taskPanel->setScheme(QSint::ActionPanelScheme::defaultScheme()); | |
| scrollArea->setWidget(taskPanel); | |
| scrollArea->setWidgetResizable(true); | |
| scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | |
| scrollArea->setMinimumWidth(200); | |
| dialogLayout->addWidget(scrollArea, 1); | |
| Gui::Selection().Attach(this); | |
| // NOLINTBEGIN | |
| connectApplicationActiveDocument = App::GetApplication().signalActiveDocument.connect( | |
| std::bind(&Gui::TaskView::TaskView::slotActiveDocument, this, sp::_1) | |
| ); | |
| connectApplicationDeleteDocument = App::GetApplication().signalDeleteDocument.connect( | |
| std::bind(&Gui::TaskView::TaskView::slotDeletedDocument, this, sp::_1) | |
| ); | |
| connectApplicationClosedView = Gui::Application::Instance->signalCloseView.connect( | |
| std::bind(&Gui::TaskView::TaskView::slotViewClosed, this, sp::_1) | |
| ); | |
| connectApplicationUndoDocument = App::GetApplication().signalUndoDocument.connect( | |
| std::bind(&Gui::TaskView::TaskView::slotUndoDocument, this, sp::_1) | |
| ); | |
| connectApplicationRedoDocument = App::GetApplication().signalRedoDocument.connect( | |
| std::bind(&Gui::TaskView::TaskView::slotRedoDocument, this, sp::_1) | |
| ); | |
| connectApplicationInEdit = Gui::Application::Instance->signalInEdit.connect( | |
| std::bind(&Gui::TaskView::TaskView::slotInEdit, this, sp::_1) | |
| ); | |
| // NOLINTEND | |
| setShowTaskWatcher(hGrp->GetBool("ShowTaskWatcher", true)); | |
| connectShowTaskWatcherSetting = hGrp->Manager()->signalParamChanged.connect( | |
| [this](ParameterGrp* Param, ParameterGrp::ParamType Type, const char* name, const char* value) { | |
| if (Param == hGrp && Type == ParameterGrp::ParamType::FCBool && name | |
| && strcmp(name, "ShowTaskWatcher") == 0) { | |
| setShowTaskWatcher(value && *value == '1'); | |
| } | |
| } | |
| ); | |
| updateWatcher(); | |
| } | |
| TaskView::~TaskView() | |
| { | |
| connectApplicationActiveDocument.disconnect(); | |
| connectApplicationDeleteDocument.disconnect(); | |
| connectApplicationClosedView.disconnect(); | |
| connectApplicationUndoDocument.disconnect(); | |
| connectApplicationRedoDocument.disconnect(); | |
| connectApplicationInEdit.disconnect(); | |
| connectShowTaskWatcherSetting.disconnect(); | |
| Gui::Selection().Detach(this); | |
| for (QWidget* panel : contextualPanels) { | |
| delete panel; | |
| } | |
| } | |
| bool TaskView::isEmpty(bool includeWatcher) const | |
| { | |
| if (ActiveCtrl || ActiveDialog) { | |
| return false; | |
| } | |
| if (includeWatcher) { | |
| for (auto* watcher : ActiveWatcher) { | |
| if (watcher->shouldShow()) { | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| bool TaskView::event(QEvent* event) | |
| { | |
| // Workaround for a limitation in Qt (#0003794) | |
| // Line edits and spin boxes don't handle the key combination | |
| // Shift+Keypad button (if NumLock is activated) | |
| if (event->type() == QEvent::ShortcutOverride) { | |
| QWidget* focusWidget = qApp->focusWidget(); | |
| bool isLineEdit = qobject_cast<QLineEdit*>(focusWidget); | |
| bool isSpinBox = qobject_cast<QAbstractSpinBox*>(focusWidget); | |
| if (isLineEdit || isSpinBox) { | |
| auto kevent = static_cast<QKeyEvent*>(event); | |
| Qt::KeyboardModifiers ShiftKeypadModifier = Qt::ShiftModifier | Qt::KeypadModifier; | |
| if (kevent->modifiers() == Qt::NoModifier || kevent->modifiers() == Qt::ShiftModifier | |
| || kevent->modifiers() == Qt::KeypadModifier | |
| || kevent->modifiers() == ShiftKeypadModifier) { | |
| switch (kevent->key()) { | |
| case Qt::Key_Delete: | |
| case Qt::Key_Home: | |
| case Qt::Key_End: | |
| case Qt::Key_Backspace: | |
| case Qt::Key_Left: | |
| case Qt::Key_Right: | |
| kevent->accept(); | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| return QWidget::event(event); | |
| } | |
| void TaskView::keyPressEvent(QKeyEvent* ke) | |
| { | |
| if (ActiveCtrl && ActiveDialog) { | |
| if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) { | |
| // get all buttons of the complete task dialog | |
| QList<QPushButton*> list = this->findChildren<QPushButton*>(); | |
| for (auto pb : list) { | |
| if (pb->isDefault() && pb->isVisible()) { | |
| if (pb->isEnabled()) { | |
| // #0001354: Crash on using Enter-Key for confirmation of chamfer or fillet | |
| // entries | |
| QPoint pos = QCursor::pos(); | |
| QCursor::setPos(pb->parentWidget()->mapToGlobal(pb->pos())); | |
| pb->click(); | |
| QCursor::setPos(pos); | |
| } | |
| return; | |
| } | |
| } | |
| } | |
| else if (ke->key() == Qt::Key_Escape && ActiveDialog->isEscapeButtonEnabled()) { | |
| // get only the buttons of the button box | |
| QDialogButtonBox* box = ActiveCtrl->standardButtons(); | |
| QList<QAbstractButton*> list = box->buttons(); | |
| for (auto pb : list) { | |
| if (box->buttonRole(pb) == QDialogButtonBox::RejectRole) { | |
| if (pb->isEnabled()) { | |
| // #0001354: Crash on using Enter-Key for confirmation of chamfer or fillet | |
| // entries | |
| QPoint pos = QCursor::pos(); | |
| QCursor::setPos(pb->parentWidget()->mapToGlobal(pb->pos())); | |
| pb->click(); | |
| QCursor::setPos(pos); | |
| } | |
| return; | |
| } | |
| } | |
| // In case a task panel has no Close or Cancel button | |
| // then invoke resetEdit() directly | |
| // See also ViewProvider::eventCallback | |
| auto func = new Gui::TimerFunction(); | |
| func->setAutoDelete(true); | |
| Gui::Document* doc = Gui::Application::Instance->getDocument( | |
| ActiveDialog->getDocumentName().c_str() | |
| ); | |
| if (doc) { | |
| func->setFunction([doc]() { doc->resetEdit(); }); | |
| func->singleShot(0); | |
| } | |
| } | |
| } | |
| else { | |
| QWidget::keyPressEvent(ke); | |
| } | |
| } | |
| void TaskView::triggerMinimumSizeHint() | |
| { | |
| // NOLINTNEXTLINE | |
| QTimer::singleShot(100, this, &TaskView::adjustMinimumSizeHint); | |
| } | |
| void TaskView::adjustMinimumSizeHint() | |
| { | |
| QSize ms = minimumSizeHint(); | |
| setMinimumWidth(ms.width()); | |
| } | |
| QSize TaskView::minimumSizeHint() const | |
| { | |
| QSize ms = QWidget::minimumSizeHint(); | |
| int spacing = 0; | |
| if (QLayout* layout = taskPanel->layout()) { | |
| spacing = 2 * layout->spacing(); | |
| } | |
| ms.setWidth(taskPanel->minimumSizeHint().width() + spacing); | |
| return ms; | |
| } | |
| void TaskView::slotActiveDocument(const App::Document& doc) | |
| { | |
| Q_UNUSED(doc); | |
| if (!ActiveDialog) { | |
| // at this point, active object of the active view returns None. | |
| // which is a problem if shouldShow of a watcher rely on the presence | |
| // of an active object (example Assembly). | |
| QTimer::singleShot(100, this, &TaskView::updateWatcher); | |
| } | |
| } | |
| void TaskView::slotInEdit(const Gui::ViewProviderDocumentObject& vp) | |
| { | |
| Q_UNUSED(vp); | |
| if (!ActiveDialog) { | |
| updateWatcher(); | |
| } | |
| } | |
| void TaskView::slotDeletedDocument(const App::Document& doc) | |
| { | |
| if (ActiveDialog) { | |
| if (ActiveDialog->isAutoCloseOnDeletedDocument()) { | |
| std::string name = ActiveDialog->getDocumentName(); | |
| if (name.empty()) { | |
| Base::Console().warning( | |
| std::string("TaskView::slotDeletedDocument"), | |
| "No document name set\n" | |
| ); | |
| } | |
| if (name == doc.getName()) { | |
| ActiveDialog->autoClosedOnDeletedDocument(); | |
| removeDialog(); | |
| } | |
| } | |
| } | |
| if (!ActiveDialog) { | |
| updateWatcher(); | |
| } | |
| } | |
| void TaskView::slotViewClosed(const Gui::MDIView* view) | |
| { | |
| // It can happen that only a view is closed an not the document | |
| if (ActiveDialog) { | |
| if (ActiveDialog->isAutoCloseOnClosedView()) { | |
| const Gui::MDIView* associatedView = ActiveDialog->getAssociatedView(); | |
| if (!associatedView) { | |
| Base::Console().warning(std::string("TaskView::slotViewClosed"), "No view associated\n"); | |
| } | |
| if (associatedView == view) { | |
| ActiveDialog->autoClosedOnClosedView(); | |
| removeDialog(); | |
| } | |
| } | |
| } | |
| if (!ActiveDialog) { | |
| updateWatcher(); | |
| } | |
| } | |
| 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()) { | |
| if (name.empty()) { | |
| Base::Console().warning( | |
| std::string("TaskView::transactionChangeOnDocument"), | |
| "No document name set\n" | |
| ); | |
| } | |
| if (name == doc.getName()) { | |
| ActiveDialog->autoClosedOnTransactionChange(); | |
| removeDialog(); | |
| } | |
| } | |
| } | |
| if (!ActiveDialog) { | |
| updateWatcher(); | |
| } | |
| } | |
| void TaskView::slotUndoDocument(const App::Document& doc) | |
| { | |
| transactionChangeOnDocument(doc, true); | |
| } | |
| void TaskView::slotRedoDocument(const App::Document& doc) | |
| { | |
| transactionChangeOnDocument(doc, false); | |
| } | |
| /// @cond DOXERR | |
| void TaskView::OnChange( | |
| Gui::SelectionSingleton::SubjectType& rCaller, | |
| Gui::SelectionSingleton::MessageType Reason | |
| ) | |
| { | |
| Q_UNUSED(rCaller); | |
| std::string temp; | |
| if (Reason.Type == SelectionChanges::AddSelection || Reason.Type == SelectionChanges::ClrSelection | |
| || Reason.Type == SelectionChanges::SetSelection | |
| || Reason.Type == SelectionChanges::RmvSelection) { | |
| if (!ActiveDialog) { | |
| updateWatcher(); | |
| } | |
| } | |
| } | |
| /// @endcond | |
| void TaskView::showDialog(TaskDialog* dlg) | |
| { | |
| // if trying to open the same dialog twice nothing needs to be done | |
| if (ActiveDialog == dlg) { | |
| return; | |
| } | |
| assert(!ActiveDialog); | |
| assert(!ActiveCtrl); | |
| // remove the TaskWatcher as long as the Dialog is up | |
| removeTaskWatcher(); | |
| // first create the control element, set it up and wire it: | |
| ActiveCtrl = new TaskEditControl(this); | |
| ActiveCtrl->buttonBox->setStandardButtons(dlg->getStandardButtons()); | |
| TaskDialogAttorney::setButtonBox(dlg, ActiveCtrl->buttonBox); | |
| // clang-format off | |
| // make connection to the needed signals | |
| connect(ActiveCtrl->buttonBox, &QDialogButtonBox::accepted, | |
| this, &TaskView::accept); | |
| connect(ActiveCtrl->buttonBox, &QDialogButtonBox::rejected, | |
| this, &TaskView::reject); | |
| connect(ActiveCtrl->buttonBox, &QDialogButtonBox::helpRequested, | |
| this, &TaskView::helpRequested); | |
| connect(ActiveCtrl->buttonBox, &QDialogButtonBox::clicked, | |
| this, &TaskView::clicked); | |
| // clang-format on | |
| const std::vector<QWidget*>& cont = dlg->getDialogContent(); | |
| // give to task dialog to customize the button box | |
| dlg->modifyStandardButtons(ActiveCtrl->buttonBox); | |
| if (dlg->buttonPosition() == TaskDialog::North) { | |
| // Add button box to the top of the main layout | |
| dialogLayout->insertWidget(0, ActiveCtrl); | |
| for (const auto& it : cont) { | |
| taskPanel->addWidget(it); | |
| } | |
| } | |
| else { | |
| for (const auto& it : cont) { | |
| taskPanel->addWidget(it); | |
| } | |
| // Add button box to the bottom of the main layout | |
| dialogLayout->addWidget(ActiveCtrl); | |
| } | |
| taskPanel->setScheme(QSint::ActionPanelScheme::defaultScheme()); | |
| if (!dlg->needsFullSpace()) { | |
| taskPanel->addStretch(); | |
| } | |
| // set as active Dialog | |
| ActiveDialog = dlg; | |
| ActiveDialog->open(); | |
| saveCurrentWidth(); | |
| getMainWindow()->updateActions(); | |
| triggerMinimumSizeHint(); | |
| Q_EMIT taskUpdate(); | |
| } | |
| void TaskView::removeDialog() | |
| { | |
| getMainWindow()->updateActions(); | |
| if (ActiveCtrl) { | |
| dialogLayout->removeWidget(ActiveCtrl); | |
| delete ActiveCtrl; | |
| ActiveCtrl = nullptr; | |
| } | |
| TaskDialog* remove = nullptr; | |
| if (ActiveDialog) { | |
| // See 'accept' and 'reject' | |
| if (ActiveDialog->property("taskview_accept_or_reject").isNull()) { | |
| const std::vector<QWidget*>& cont = ActiveDialog->getDialogContent(); | |
| for (const auto& it : cont) { | |
| taskPanel->removeWidget(it); | |
| } | |
| remove = ActiveDialog; | |
| ActiveDialog = nullptr; | |
| } | |
| else { | |
| ActiveDialog->setProperty("taskview_remove_dialog", true); | |
| } | |
| } | |
| taskPanel->removeStretch(); | |
| // put the watcher back in control | |
| addTaskWatcher(); | |
| if (remove) { | |
| remove->closed(); | |
| remove->emitDestructionSignal(); | |
| delete remove; | |
| } | |
| tryRestoreWidth(); | |
| triggerMinimumSizeHint(); | |
| } | |
| void TaskView::setShowTaskWatcher(bool show) | |
| { | |
| if (showTaskWatcher == show) { | |
| return; | |
| } | |
| showTaskWatcher = show; | |
| if (show) { | |
| addTaskWatcher(); | |
| } | |
| else { | |
| clearTaskWatcher(); | |
| } | |
| } | |
| void TaskView::updateWatcher() | |
| { | |
| if (!showTaskWatcher) { | |
| return; | |
| } | |
| if (ActiveWatcher.empty()) { | |
| auto panel = Gui::Control().taskPanel(); | |
| if (panel && panel->ActiveWatcher.size()) { | |
| takeTaskWatcher(panel); | |
| } | |
| } | |
| // In case a child of the TaskView has the focus and get hidden we have | |
| // to make sure to set the focus on a widget that won't be hidden or | |
| // deleted because otherwise Qt may forward the focus via focusNextPrevChild() | |
| // to the mdi area which may switch to another mdi view which is not an | |
| // acceptable behaviour. | |
| QWidget* fw = QApplication::focusWidget(); | |
| if (!fw) { | |
| this->setFocus(); | |
| } | |
| QPointer<QWidget> fwp = fw; | |
| while (fw && !fw->isWindow()) { | |
| if (fw == this) { | |
| this->setFocus(); | |
| break; | |
| } | |
| fw = fw->parentWidget(); | |
| } | |
| // add all widgets for all watcher to the task view | |
| for (const auto& it : ActiveWatcher) { | |
| bool match = it->shouldShow(); | |
| std::vector<QWidget*>& cont = it->getWatcherContent(); | |
| for (auto& it2 : cont) { | |
| if (match) { | |
| it2->show(); | |
| } | |
| else { | |
| it2->hide(); | |
| } | |
| } | |
| } | |
| // In case the previous widget that had the focus is still visible | |
| // give it the focus back. | |
| if (fwp && fwp->isVisible()) { | |
| fwp->setFocus(); | |
| } | |
| triggerMinimumSizeHint(); | |
| Q_EMIT taskUpdate(); | |
| } | |
| void TaskView::addTaskWatcher(const std::vector<TaskWatcher*>& Watcher) | |
| { | |
| // remove and delete the old set of TaskWatcher | |
| for (TaskWatcher* tw : ActiveWatcher) { | |
| delete tw; | |
| } | |
| ActiveWatcher = Watcher; | |
| if (!ActiveCtrl && !ActiveDialog) { | |
| addTaskWatcher(); | |
| } | |
| } | |
| void TaskView::takeTaskWatcher(TaskView* other) | |
| { | |
| clearTaskWatcher(); | |
| ActiveWatcher.swap(other->ActiveWatcher); | |
| other->clearTaskWatcher(); | |
| if (isEmpty(false)) { | |
| addTaskWatcher(); | |
| } | |
| } | |
| void TaskView::clearTaskWatcher() | |
| { | |
| std::vector<TaskWatcher*> watcher; | |
| removeTaskWatcher(); | |
| // make sure to delete the old watchers | |
| addTaskWatcher(watcher); | |
| } | |
| void TaskView::addTaskWatcher() | |
| { | |
| if (!showTaskWatcher) { | |
| return; | |
| } | |
| // add all widgets for all watcher to the task view | |
| for (TaskWatcher* tw : ActiveWatcher) { | |
| std::vector<QWidget*>& cont = tw->getWatcherContent(); | |
| for (QWidget* w : cont) { | |
| taskPanel->addWidget(w); | |
| } | |
| } | |
| if (!ActiveWatcher.empty()) { | |
| taskPanel->addStretch(); | |
| } | |
| updateWatcher(); | |
| // Workaround to avoid a crash in Qt. See also | |
| // https://forum.freecad.org/viewtopic.php?f=8&t=39187 | |
| // | |
| // Notify the button box about a style change so that it can | |
| // safely delete the style animation of its push buttons. | |
| auto box = taskPanel->findChild<QDialogButtonBox*>(); | |
| if (box) { | |
| QEvent event(QEvent::StyleChange); | |
| QApplication::sendEvent(box, &event); | |
| } | |
| taskPanel->setScheme(QSint::ActionPanelScheme::defaultScheme()); | |
| } | |
| void TaskView::saveCurrentWidth() | |
| { | |
| if (shouldRestoreWidth()) { | |
| if (auto parent = qobject_cast<QDockWidget*>(parentWidget())) { | |
| currentWidth = parent->width(); | |
| } | |
| } | |
| } | |
| void TaskView::tryRestoreWidth() | |
| { | |
| if (shouldRestoreWidth()) { | |
| if (auto parent = qobject_cast<QDockWidget*>(parentWidget())) { | |
| Gui::getMainWindow()->resizeDocks({parent}, {currentWidth}, Qt::Horizontal); | |
| } | |
| } | |
| } | |
| void TaskView::setRestoreWidth(bool on) | |
| { | |
| restoreWidth = on; | |
| } | |
| bool TaskView::shouldRestoreWidth() const | |
| { | |
| return restoreWidth; | |
| } | |
| void TaskView::removeTaskWatcher() | |
| { | |
| // In case a child of the TaskView has the focus and get hidden we have | |
| // to make sure that set the focus on a widget that won't be hidden or | |
| // deleted because otherwise Qt may forward the focus via focusNextPrevChild() | |
| // to the mdi area which may switch to another mdi view which is not an | |
| // acceptable behaviour. | |
| QWidget* fw = QApplication::focusWidget(); | |
| if (!fw) { | |
| this->setFocus(); | |
| } | |
| while (fw && !fw->isWindow()) { | |
| if (fw == this) { | |
| this->setFocus(); | |
| break; | |
| } | |
| fw = fw->parentWidget(); | |
| } | |
| // remove all widgets | |
| for (TaskWatcher* tw : ActiveWatcher) { | |
| std::vector<QWidget*>& cont = tw->getWatcherContent(); | |
| for (QWidget* w : cont) { | |
| w->hide(); | |
| taskPanel->removeWidget(w); | |
| } | |
| } | |
| taskPanel->removeStretch(); | |
| } | |
| void TaskView::accept() | |
| { | |
| if (!ActiveDialog) { // Protect against segfaults due to out-of-order deletions | |
| Base::Console().warning("ActiveDialog was null in call to TaskView::accept()\n"); | |
| return; | |
| } | |
| // Make sure that if 'accept' calls 'closeDialog' the deletion is postponed until | |
| // the dialog leaves the 'accept' method | |
| ActiveDialog->setProperty("taskview_accept_or_reject", true); | |
| bool success = ActiveDialog->accept(); | |
| ActiveDialog->setProperty("taskview_accept_or_reject", QVariant()); | |
| if (success || ActiveDialog->property("taskview_remove_dialog").isValid()) { | |
| removeDialog(); | |
| } | |
| } | |
| void TaskView::reject() | |
| { | |
| if (!ActiveDialog) { // Protect against segfaults due to out-of-order deletions | |
| Base::Console().warning("ActiveDialog was null in call to TaskView::reject()\n"); | |
| return; | |
| } | |
| // Make sure that if 'reject' calls 'closeDialog' the deletion is postponed until | |
| // the dialog leaves the 'reject' method | |
| ActiveDialog->setProperty("taskview_accept_or_reject", true); | |
| bool success = ActiveDialog->reject(); | |
| ActiveDialog->setProperty("taskview_accept_or_reject", QVariant()); | |
| if (success || ActiveDialog->property("taskview_remove_dialog").isValid()) { | |
| removeDialog(); | |
| } | |
| } | |
| void TaskView::helpRequested() | |
| { | |
| ActiveDialog->helpRequested(); | |
| } | |
| void TaskView::clicked(QAbstractButton* button) | |
| { | |
| int id = ActiveCtrl->buttonBox->standardButton(button); | |
| ActiveDialog->clicked(id); | |
| } | |
| void TaskView::clearActionStyle() | |
| { | |
| static_cast<QSint::ActionPanelScheme*>(QSint::ActionPanelScheme::defaultScheme())->clearActionStyle(); | |
| taskPanel->setScheme(QSint::ActionPanelScheme::defaultScheme()); | |
| } | |
| void TaskView::restoreActionStyle() | |
| { | |
| static_cast<QSint::ActionPanelScheme*>(QSint::ActionPanelScheme::defaultScheme()) | |
| ->restoreActionStyle(); | |
| taskPanel->setScheme(QSint::ActionPanelScheme::defaultScheme()); | |
| } | |
| void TaskView::addContextualPanel(QWidget* panel) | |
| { | |
| if (!panel || contextualPanels.contains(panel)) { | |
| return; | |
| } | |
| contextualPanelsLayout->addWidget(panel); | |
| contextualPanels.append(panel); | |
| panel->show(); | |
| triggerMinimumSizeHint(); | |
| Q_EMIT taskUpdate(); | |
| } | |
| void TaskView::removeContextualPanel(QWidget* panel) | |
| { | |
| if (!panel || !contextualPanels.contains(panel)) { | |
| return; | |
| } | |
| contextualPanelsLayout->removeWidget(panel); | |
| contextualPanels.removeOne(panel); | |
| panel->deleteLater(); | |
| triggerMinimumSizeHint(); | |
| Q_EMIT taskUpdate(); | |
| } | |