From d764adb1016f74d3e9cc8059cb183f5fc29b2a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Tue, 8 Feb 2022 19:07:04 +0100 Subject: [PATCH] Issue 984 (#987) * WIP: first attempt to fix issue-983 * WIP: bugfixes * Fixed a problem with displaying empty cell dimensions, one warning * Another fix: don't allow proxy cells to be selected in the instance properties dialog. This creates a confusing behaviour * Fixed a few flaws in the cell selection scheme on the instance properties dialog. * Early warning when trying to build a recursive hierarchy. * Another fix: avoid too much undo in case of errors thrown during 'apply' followed by 'cancel' * First attempt to fix issue 984 * Fixed issue-983 solution * Fixed the modification status of PCell parameters for 'apply to all' --- src/lay/lay/layApplication.cc | 26 ++++-- src/lay/lay/layApplication.h | 16 +++- src/lay/lay/layMacroEditorDialog.cc | 16 ++-- src/lay/lay/layMacroEditorDialog.h | 1 - src/laybasic/laybasic/layBusy.cc | 82 +++++++++++++++++++ src/laybasic/laybasic/layBusy.h | 65 +++++++++++++++ .../laybasic/layHierarchyControlPanel.cc | 3 + src/laybasic/laybasic/layLibrariesView.cc | 3 + src/laybasic/laybasic/laybasic.pro | 2 + 9 files changed, 197 insertions(+), 17 deletions(-) create mode 100644 src/laybasic/laybasic/layBusy.cc create mode 100644 src/laybasic/laybasic/layBusy.h diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index 29507c87f..f5d4dd505 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -1317,6 +1317,20 @@ GuiApplication::notify (QObject *receiver, QEvent *e) return ret; } +void +GuiApplication::enter_busy_mode (bool bm) +{ + if (mp_mw) { + mp_mw->enter_busy_mode (bm); + } +} + +bool +GuiApplication::is_busy () const +{ + return mp_mw && mp_mw->is_busy (); +} + void GuiApplication::force_update_app_menu () { @@ -1484,18 +1498,19 @@ GuiApplication::setup () void GuiApplication::process_events_impl (QEventLoop::ProcessEventsFlags flags, bool silent) { + // prevent recursive process_events + if (is_busy ()) { + return; + } + if (mp_mw) { - // prevent recursive process_events - if (mp_mw->is_busy ()) { - return; - } + lay::BusySection busy; if (silent) { tl::DeferredMethodScheduler::enable (false); } - mp_mw->enter_busy_mode (true); try { #if QT_VERSION < 0x050000 QApplication::syncX (); @@ -1507,7 +1522,6 @@ GuiApplication::process_events_impl (QEventLoop::ProcessEventsFlags flags, bool } catch (...) { // ignore exceptions } - mp_mw->enter_busy_mode (false); if (silent) { tl::DeferredMethodScheduler::enable (true); diff --git a/src/lay/lay/layApplication.h b/src/lay/lay/layApplication.h index 2e31f120d..85eb65267 100644 --- a/src/lay/lay/layApplication.h +++ b/src/lay/lay/layApplication.h @@ -25,6 +25,7 @@ #define HDR_layApplication #include "layCommon.h" +#include "layBusy.h" #include #include @@ -366,7 +367,7 @@ private: * @brief The GUI-enabled application class */ class LAY_PUBLIC GuiApplication - : public QApplication, public ApplicationBase + : public QApplication, public ApplicationBase, public lay::BusyMode { public: GuiApplication (int &argc, char **argv); @@ -408,6 +409,19 @@ public: return mp_mw; } + /** + * @brief Enters busy mode (true) or leaves it (false) + * + * Use lay::BusySection to declare a section in "busy" mode. In busy mode, some features are disabled to + * prevent recursion in processing of events. + */ + virtual void enter_busy_mode (bool bm); + + /** + * @brief Gets a value indicating whether busy mode is enabled + */ + virtual bool is_busy () const; + /** * @brief Forces update of the application menu * This function is used for work around a MacOS issue. diff --git a/src/lay/lay/layMacroEditorDialog.cc b/src/lay/lay/layMacroEditorDialog.cc index 30bdd7667..49da27914 100644 --- a/src/lay/lay/layMacroEditorDialog.cc +++ b/src/lay/lay/layMacroEditorDialog.cc @@ -234,7 +234,7 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection lay::Plugin (pr, true), mp_plugin_root (pr), mp_root (root), - m_first_show (true), m_in_processing (false), m_debugging_on (true), + m_first_show (true), m_debugging_on (true), mp_run_macro (0), md_update_console_text (this, &MacroEditorDialog::update_console_text), md_search_edited (this, &MacroEditorDialog::do_search_edited), @@ -1075,12 +1075,10 @@ void MacroEditorDialog::process_events (QEventLoop::ProcessEventsFlags flags) { if (lay::ApplicationBase::instance ()) { - // disable execution of deferred methods to avoid undesired execution of + // NOTE: we disable execution of deferred methods to avoid undesired execution of // code while we are inside a Ruby callback through the silent mode - bool last_processing = m_in_processing; - m_in_processing = true; + // NOTE: process_events will set BusySection::is_busy lay::ApplicationBase::instance ()->process_events (flags, true /*silent*/); - m_in_processing = last_processing; } } @@ -1430,7 +1428,7 @@ MacroEditorDialog::eventFilter (QObject *obj, QEvent *event) return false; } - if (m_in_processing && (m_in_breakpoint || m_in_exec) && (dynamic_cast (event) != 0 || dynamic_cast (event) != 0)) { + if (lay::BusySection::is_busy () && (m_in_breakpoint || m_in_exec) && (dynamic_cast (event) != 0 || dynamic_cast (event) != 0)) { // In breakpoint or execution mode and while processing the events from the debugger, // ignore all input or paint events targeted to widgets which are not children of this or the assistant dialog. @@ -1447,7 +1445,7 @@ MacroEditorDialog::eventFilter (QObject *obj, QEvent *event) return true; } - } else if (! m_in_processing && m_in_exec) { + } else if (! lay::BusySection::is_busy () && m_in_exec) { // While no explicit event processing is in progress and we are executing, this is an indication that // "real" events are processed. In that case, we can postpone excplit processing. This avoids interference @@ -3032,7 +3030,7 @@ MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_ } // avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop - if (m_in_processing) { + if (lay::BusySection::is_busy ()) { return; } @@ -3126,7 +3124,7 @@ MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int lin } // avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop - if (m_in_processing) { + if (lay::BusySection::is_busy ()) { return; } diff --git a/src/lay/lay/layMacroEditorDialog.h b/src/lay/lay/layMacroEditorDialog.h index dc234822f..7e6e363e0 100644 --- a/src/lay/lay/layMacroEditorDialog.h +++ b/src/lay/lay/layMacroEditorDialog.h @@ -301,7 +301,6 @@ private: lay::Dispatcher *mp_plugin_root; lym::MacroCollection *mp_root; bool m_first_show; - bool m_in_processing; bool m_debugging_on; lym::Macro *mp_run_macro; std::vector m_macro_templates; diff --git a/src/laybasic/laybasic/layBusy.cc b/src/laybasic/laybasic/layBusy.cc new file mode 100644 index 000000000..bfd7cda31 --- /dev/null +++ b/src/laybasic/laybasic/layBusy.cc @@ -0,0 +1,82 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "layBusy.h" +#include "tlThreads.h" + +namespace lay +{ + +tl::Mutex s_lock; + +BusyMode *sp_busy_mode = 0; + +// ---------------------------------------------------------------------------------------------------------- + +BusyMode::BusyMode () +{ + tl::MutexLocker locker (&s_lock); + if (sp_busy_mode == 0) { + sp_busy_mode = this; + } +} + +BusyMode::~BusyMode () +{ + tl::MutexLocker locker (&s_lock); + if (sp_busy_mode == this) { + sp_busy_mode = 0; + } +} + +// ---------------------------------------------------------------------------------------------------------- + +BusySection::BusySection () +{ + tl::MutexLocker locker (&s_lock); + mp_busy_mode = sp_busy_mode; + m_previous_mode = false; + if (mp_busy_mode) { + m_previous_mode = mp_busy_mode->is_busy (); + mp_busy_mode->enter_busy_mode (true); + } +} + +BusySection::~BusySection () +{ + tl::MutexLocker locker (&s_lock); + if (sp_busy_mode == mp_busy_mode && mp_busy_mode) { + mp_busy_mode->enter_busy_mode (m_previous_mode); + } + mp_busy_mode = 0; +} + +bool +BusySection::is_busy () +{ + tl::MutexLocker locker (&s_lock); + return sp_busy_mode && sp_busy_mode->is_busy (); +} + +// ---------------------------------------------------------------------------------------------------------- + +} diff --git a/src/laybasic/laybasic/layBusy.h b/src/laybasic/laybasic/layBusy.h new file mode 100644 index 000000000..ed9597c33 --- /dev/null +++ b/src/laybasic/laybasic/layBusy.h @@ -0,0 +1,65 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_layBusy +#define HDR_layBusy + +#include "laybasicCommon.h" + +namespace lay +{ + +/** + * @brief An interface providing the "busy" methods + * + * There must be one provider implementing this interface. + */ +class LAYBASIC_PUBLIC BusyMode +{ +public: + BusyMode (); + virtual ~BusyMode (); + + virtual bool is_busy () const = 0; + virtual void enter_busy_mode (bool bm) = 0; +}; + +/** + * @brief A RAII implementation of the busy mode setter + */ +class LAYBASIC_PUBLIC BusySection +{ +public: + BusySection (); + ~BusySection (); + + static bool is_busy (); + +private: + bool m_previous_mode; + BusyMode *mp_busy_mode; +}; + +} + +#endif diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.cc b/src/laybasic/laybasic/layHierarchyControlPanel.cc index d531365bd..1f21ae24c 100644 --- a/src/laybasic/laybasic/layHierarchyControlPanel.cc +++ b/src/laybasic/laybasic/layHierarchyControlPanel.cc @@ -42,6 +42,7 @@ #include "dbClipboard.h" #include "dbClipboardData.h" +#include "layBusy.h" #include "layHierarchyControlPanel.h" #include "layCellTreeModel.h" #include "layLayoutView.h" @@ -146,6 +147,8 @@ HCPCellTreeWidget::startDrag (Qt::DropActions supportedActions) return; } + lay::BusySection busy_section; // issue 984 + QDrag *drag = new QDrag (this); drag->setMimeData(data); QPixmap px (1, 1); diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc index fc911a83c..4b1246666 100644 --- a/src/laybasic/laybasic/layLibrariesView.cc +++ b/src/laybasic/laybasic/layLibrariesView.cc @@ -44,6 +44,7 @@ #include "dbClipboardData.h" #include "dbLibraryManager.h" #include "dbLibrary.h" +#include "layBusy.h" #include "layLibrariesView.h" #include "layCellTreeModel.h" #include "layLayoutView.h" @@ -136,6 +137,8 @@ LibraryTreeWidget::startDrag (Qt::DropActions supportedActions) return; } + lay::BusySection busy_section; // issue 984 + QDrag *drag = new QDrag (this); drag->setMimeData(data); QPixmap px (1, 1); diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index 309e33a20..a9cd72e78 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -102,6 +102,7 @@ SOURCES = \ layBrowserDialog.cc \ layBrowserPanel.cc \ layBrowseShapesForm.cc \ + layBusy.cc \ layCanvasPlane.cc \ layCellSelectionForm.cc \ layCellTreeModel.cc \ @@ -208,6 +209,7 @@ HEADERS = \ layBrowser.h \ layBrowserPanel.h \ layBrowseShapesForm.h \ + layBusy.h \ layCanvasPlane.h \ layCellSelectionForm.h \ layCellTreeModel.h \