From 3c53950eaa710d74f75f7e85a33a1ef0436ba2d3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 Sep 2022 00:47:21 +0200 Subject: [PATCH] Rework needed for LayoutView management The application got unstable on exit under various conditions (e.g. LayoutView created in script). Reason was the ownership management of LayoutView which interfered with Qt widget lifetime management. The solution now is based on a clean widget/view hierarchy and a consistent plugin parent/child relationship. In addition, a new class is enabled which allows creating a true QWidget (rather QFrame) for a LayoutView again. --- src/img/img/imgNavigator.cc | 2 +- src/lay/lay/layApplication.cc | 6 +- src/lay/lay/layFillDialog.cc | 8 +- src/lay/lay/layFillDialog.h | 2 +- src/lay/lay/layMainWindow.cc | 4 +- src/lay/lay/layNavigator.cc | 2 +- src/laybasic/laybasic/layAbstractMenu.cc | 4 +- src/laybasic/laybasic/layLayoutViewBase.cc | 10 ++ src/laybasic/laybasic/layLayoutViewBase.h | 5 + src/laybasic/laybasic/layPlugin.cc | 4 +- src/laybasic/laybasic/layPlugin.h | 8 ++ src/layui/layui/layBrowser.cc | 1 + .../layview/gsiDeclLayLayoutView_qt.cc | 121 +++++++++++------- src/layview/layview/layLayoutView_qt.cc | 79 +++++++++--- src/layview/layview/layLayoutView_qt.h | 54 +++++++- .../lay_plugin/layBooleanOperationsPlugin.cc | 8 +- .../tools/diff/lay_plugin/layDiffPlugin.cc | 19 +-- .../tools/view_25d/lay_plugin/layD25View.cc | 2 +- .../tools/xor/lay_plugin/layXORPlugin.cc | 19 +-- testdata/klayout_main/main.rb | 8 ++ 20 files changed, 259 insertions(+), 107 deletions(-) diff --git a/src/img/img/imgNavigator.cc b/src/img/img/imgNavigator.cc index b9ce6bb92..8eb7dee63 100644 --- a/src/img/img/imgNavigator.cc +++ b/src/img/img/imgNavigator.cc @@ -51,7 +51,7 @@ Navigator::Navigator (QWidget *parent) img::Object * Navigator::setup (lay::Dispatcher *root, img::Object *img) { - mp_view = new lay::LayoutView (0, false, root, this, "img_navigator_view", lay::LayoutView::LV_Naked + lay::LayoutView::LV_NoZoom + lay::LayoutView::LV_NoServices + lay::LayoutView::LV_NoGrid); + mp_view = new lay::LayoutViewWidget (0, false, root, this, lay::LayoutView::LV_Naked + lay::LayoutView::LV_NoZoom + lay::LayoutView::LV_NoServices + lay::LayoutView::LV_NoGrid); tl_assert (mp_view->widget ()); mp_view->widget ()->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); mp_view->widget ()->setMinimumWidth (100); diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index 530ca037f..1632461e0 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -1290,7 +1290,7 @@ lay::LayoutView * ApplicationBase::create_view (db::Manager &manager) { // create a new view - lay::LayoutView *view = new lay::LayoutView (&manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), 0 /*parent*/); + lay::LayoutView *view = new lay::LayoutView (&manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher ()); // set initial attributes view->set_synchronous (m_sync_mode); @@ -1583,6 +1583,10 @@ GuiApplication::shutdown () } } + while (! (tl_widgets = topLevelWidgets ()).empty ()) { + delete tl_widgets [0]; + } + if (mp_recorder) { delete mp_recorder; mp_recorder = 0; diff --git a/src/lay/lay/layFillDialog.cc b/src/lay/lay/layFillDialog.cc index 2104b9a9b..1d8a31471 100644 --- a/src/lay/lay/layFillDialog.cc +++ b/src/lay/lay/layFillDialog.cc @@ -63,10 +63,10 @@ public: menu_entries.push_back (lay::menu_item ("fill_tool::show", "fill_tool:edit_mode", "edit_menu.utils_menu.end", tl::to_string (QObject::tr ("Fill Tool")))); } - virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const + virtual lay::Plugin *create_plugin (db::Manager *, lay::LayoutViewBase *view) const { if (lay::has_gui ()) { - return new FillDialog (root, view); + return new FillDialog (view); } else { return 0; } @@ -78,9 +78,9 @@ static tl::RegisteredClass config_decl (new FillDialogPl // ------------------------------------------------------------ -FillDialog::FillDialog (lay::Dispatcher *main, LayoutViewBase *view) +FillDialog::FillDialog (LayoutViewBase *view) : QDialog (view->widget ()), - lay::Plugin (main), + lay::Plugin (view), Ui::FillDialog (), mp_view (view) { diff --git a/src/lay/lay/layFillDialog.h b/src/lay/lay/layFillDialog.h index faa06851a..c3afebe68 100644 --- a/src/lay/lay/layFillDialog.h +++ b/src/lay/lay/layFillDialog.h @@ -76,7 +76,7 @@ class LAY_PUBLIC FillDialog Q_OBJECT public: - FillDialog (lay::Dispatcher *root, lay::LayoutViewBase *view); + FillDialog (lay::LayoutViewBase *view); ~FillDialog (); public slots: diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 914ea0066..17d9af300 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -2578,7 +2578,7 @@ MainWindow::clone_current_view () } // create a new view - view = new lay::LayoutView (current_view (), &m_manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), mp_view_stack); + view = new lay::LayoutViewWidget (current_view (), &m_manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), mp_view_stack); add_view (view); // set initial attributes @@ -3389,7 +3389,7 @@ int MainWindow::do_create_view () { // create a new view - lay::LayoutView *view = new lay::LayoutView (&m_manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), mp_view_stack); + lay::LayoutViewWidget *view = new lay::LayoutViewWidget (&m_manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), mp_view_stack); add_view (view); // set initial attributes diff --git a/src/lay/lay/layNavigator.cc b/src/lay/lay/layNavigator.cc index b55ccdec3..ea338d1ef 100644 --- a/src/lay/lay/layNavigator.cc +++ b/src/lay/lay/layNavigator.cc @@ -655,7 +655,7 @@ Navigator::attach_view (LayoutView *view) if (mp_source_view) { - mp_view = new LayoutView (0, false, mp_source_view, this, "navigator", LayoutView::LV_Naked + LayoutView::LV_NoZoom + LayoutView::LV_NoServices + LayoutView::LV_NoGrid); + mp_view = new LayoutViewWidget (0, false, mp_source_view, this, LayoutView::LV_Naked + LayoutView::LV_NoZoom + LayoutView::LV_NoServices + LayoutView::LV_NoGrid); tl_assert (mp_view->widget ()); mp_view->widget ()->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); mp_view->widget ()->setMinimumWidth (100); diff --git a/src/laybasic/laybasic/layAbstractMenu.cc b/src/laybasic/laybasic/layAbstractMenu.cc index 22d181dd7..3666b0157 100644 --- a/src/laybasic/laybasic/layAbstractMenu.cc +++ b/src/laybasic/laybasic/layAbstractMenu.cc @@ -1540,9 +1540,11 @@ AbstractMenu::insert_separator (const std::string &p, const std::string &name) void AbstractMenu::insert_menu (const std::string &p, const std::string &name, Action *action) { - if (! action->menu ()) { +#if defined(HAVE_QT) + if (! action->menu () && mp_dispatcher && mp_dispatcher->menu_parent_widget ()) { action->set_menu (new QMenu (), true); } +#endif typedef std::vector::iterator > > path_type; tl::Extractor extr (p.c_str ()); diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index 4e5b86646..89f087a31 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -514,6 +514,16 @@ LayoutViewBase::~LayoutViewBase () mp_canvas = 0; } +void LayoutViewBase::unregister_plugin (lay::Plugin *pi) +{ + for (std::vector::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) { + if (pi == *p) { + mp_plugins.erase (p); + break; + } + } +} + void LayoutViewBase::resize (unsigned int width, unsigned int height) { mp_canvas->resize (width, height); diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h index 99456135a..7ad6ba773 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.h +++ b/src/laybasic/laybasic/layLayoutViewBase.h @@ -2670,6 +2670,11 @@ public: return const_cast (this)->get_ui (); } + /** + * @brief Unregisters the given plugin + */ + void unregister_plugin (lay::Plugin *pi); + private: // event handlers used to connect to the layout object's events void signal_hier_changed (); diff --git a/src/laybasic/laybasic/layPlugin.cc b/src/laybasic/laybasic/layPlugin.cc index 3a28117d5..85efb510c 100644 --- a/src/laybasic/laybasic/layPlugin.cc +++ b/src/laybasic/laybasic/layPlugin.cc @@ -324,7 +324,9 @@ Plugin::Plugin (Plugin *parent, bool standalone) Plugin::~Plugin () { - // .. nothing yet .. + if (mp_parent) { + mp_parent->unregister_plugin (this); + } } void diff --git a/src/laybasic/laybasic/layPlugin.h b/src/laybasic/laybasic/layPlugin.h index 5ea38a6e2..7fb074a42 100644 --- a/src/laybasic/laybasic/layPlugin.h +++ b/src/laybasic/laybasic/layPlugin.h @@ -695,6 +695,14 @@ public: */ Dispatcher *dispatcher (); + /** + * @brief Notifies the plugin that a child plugin got deleted + */ + virtual void unregister_plugin (lay::Plugin * /*plugin*/) + { + // .. this implementation does nothing .. + } + /** * @brief Menu command handler * diff --git a/src/layui/layui/layBrowser.cc b/src/layui/layui/layBrowser.cc index 27a32a324..3c07bc345 100644 --- a/src/layui/layui/layBrowser.cc +++ b/src/layui/layui/layBrowser.cc @@ -23,6 +23,7 @@ #if defined(HAVE_QT) #include +#include #include "layBrowser.h" #include "layLayoutViewBase.h" diff --git a/src/layview/layview/gsiDeclLayLayoutView_qt.cc b/src/layview/layview/gsiDeclLayLayoutView_qt.cc index a5a95d6c3..d4c56aa74 100644 --- a/src/layview/layview/gsiDeclLayLayoutView_qt.cc +++ b/src/layview/layview/gsiDeclLayLayoutView_qt.cc @@ -39,31 +39,44 @@ namespace gsi { #if defined(HAVE_QTBINDINGS) -static lay::LayoutView *new_view (QWidget *parent, bool editable, db::Manager *manager, unsigned int options) +static lay::LayoutViewWidget *new_view_widget (QWidget *parent, bool editable, db::Manager *manager, unsigned int options) { - lay::LayoutView *lv = new lay::LayoutView (manager, editable, 0 /*plugin parent*/, parent, "view", options); + lay::LayoutView *lv = new lay::LayoutViewWidget (manager, editable, 0 /*plugin parent*/, parent, "view", options); if (parent) { // transfer ownership to the parent lv->keep (); } return lv; } -#endif -static lay::LayoutView *new_view2 (bool editable, db::Manager *manager, unsigned int options) +static lay::LayoutView *get_view (lay::LayoutViewWidget *lv) { - return new lay::LayoutView (manager, editable, 0 /*plugin parent*/, 0 /*parent*/, "view", options); + return lv; } -extern LAYBASIC_PUBLIC Class decl_LayoutViewBase; +static QFrame *layer_control_frame (lay::LayoutViewWidget *lv) +{ + return lv->layer_control_frame (); +} -Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView", -#if defined(HAVE_QTBINDINGS) - gsi::constructor ("new", &new_view, gsi::arg ("parent"), gsi::arg ("editable", false), gsi::arg ("manager", (db::Manager *) 0, "nil"), gsi::arg ("options", (unsigned int) 0), - "@brief Creates a standalone view\n" - "\n" - "This constructor is for special purposes only. To create a view in the context of a main window, " - "use \\MainWindow#create_view and related methods.\n" +static QFrame *hierarchy_control_frame (lay::LayoutViewWidget *lv) +{ + return lv->hierarchy_control_frame (); +} + +static QFrame *libraries_frame (lay::LayoutViewWidget *lv) +{ + return lv->libraries_frame (); +} + +static QFrame *bookmarks_frame (lay::LayoutViewWidget *lv) +{ + return lv->bookmarks_frame (); +} + +Class decl_LayoutView (QT_EXTERNAL_BASE (QFrame), "lay", "LayoutViewWidget", + gsi::constructor ("new", &new_view_widget, gsi::arg ("parent"), gsi::arg ("editable", false), gsi::arg ("manager", (db::Manager *) 0, "nil"), gsi::arg ("options", (unsigned int) 0), + "@brief Creates a standalone view widget\n" "\n" "@param parent The parent widget in which to embed the view\n" "@param editable True to make the view editable\n" @@ -73,8 +86,53 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "This constructor has been introduced in version 0.25.\n" "It has been enhanced with the arguments in version 0.27.\n" ) + + gsi::method_ext ("layer_control_frame", &layer_control_frame, + "@brief Gets the layer control side widget\n" + "A 'side widget' is a widget attached to the view. It does not have a parent, so you can " + "embed it into a different context. Please note that with embedding through 'setParent' it will be " + "destroyed when your parent widget gets destroyed. It will be lost then to the view.\n" + "\n" + "The side widget can be configured through the views configuration interface.\n" + "\n" + "This method has been introduced in version 0.27\n" + ) + + gsi::method_ext ("hierarchy_control_frame", &hierarchy_control_frame, + "@brief Gets the cell view (hierarchy view) side widget\n" + "For details about side widgets see \\layer_control_frame.\n" + "\n" + "This method has been introduced in version 0.27\n" + ) + + gsi::method_ext ("libraries_frame", &libraries_frame, + "@brief Gets the library view side widget\n" + "For details about side widgets see \\layer_control_frame.\n" + "\n" + "This method has been introduced in version 0.27\n" + ) + + gsi::method_ext ("bookmarks_frame", &bookmarks_frame, + "@brief Gets the bookmarks side widget\n" + "For details about side widgets see \\layer_control_frame.\n" + "\n" + "This method has been introduced in version 0.27\n" + ) + + gsi::method_ext ("view", &get_view, + "@brief Gets the embedded view object.\n" + ), + "This object produces a widget which embeds a LayoutView. This widget can be used inside Qt widget hierarchies.\n" + "To access the \\LayoutView object within, use \\view.\n" + "\n" + "This class has been introduced in version 0.28." +); #endif - gsi::constructor ("new", &new_view2, gsi::arg ("editable", false), gsi::arg ("manager", (db::Manager *) 0, "nil"), gsi::arg ("options", (unsigned int) 0), + +static lay::LayoutView *new_view (bool editable, db::Manager *manager, unsigned int options) +{ + return new lay::LayoutView (manager, editable, 0 /*plugin parent*/, options); +} + +extern LAYBASIC_PUBLIC Class decl_LayoutViewBase; + +Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView", + gsi::constructor ("new", &new_view, gsi::arg ("editable", false), gsi::arg ("manager", (db::Manager *) 0, "nil"), gsi::arg ("options", (unsigned int) 0), "@brief Creates a standalone view\n" "\n" "This constructor is for special purposes only. To create a view in the context of a main window, " @@ -87,41 +145,6 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "This constructor has been introduced in version 0.25.\n" "It has been enhanced with the arguments in version 0.27.\n" ) + -#if defined(HAVE_QTBINDINGS) - gsi::method ("layer_control_frame", static_cast (&lay::LayoutView::layer_control_frame), - "@brief Gets the layer control side widget\n" - "A 'side widget' is a widget attached to the view. It does not have a parent, so you can " - "embed it into a different context. Please note that with embedding through 'setParent' it will be " - "destroyed when your parent widget gets destroyed. It will be lost then to the view.\n" - "\n" - "The side widget can be configured through the views configuration interface.\n" - "\n" - "This method has been introduced in version 0.27\n" - ) + - gsi::method ("hierarchy_control_frame", static_cast (&lay::LayoutView::hierarchy_control_frame), - "@brief Gets the cell view (hierarchy view) side widget\n" - "For details about side widgets see \\layer_control_frame.\n" - "\n" - "This method has been introduced in version 0.27\n" - ) + - gsi::method ("libraries_frame", static_cast (&lay::LayoutView::libraries_frame), - "@brief Gets the library view side widget\n" - "For details about side widgets see \\layer_control_frame.\n" - "\n" - "This method has been introduced in version 0.27\n" - ) + - gsi::method ("bookmarks_frame", static_cast (&lay::LayoutView::bookmarks_frame), - "@brief Gets the bookmarks side widget\n" - "For details about side widgets see \\layer_control_frame.\n" - "\n" - "This method has been introduced in version 0.27\n" - ) + - gsi::method ("widget", &lay::LayoutView::widget, - "@brief Gets the QWidget object for the layout view\n" - "\n" - "This method has been introduced in version 0.28 where LayoutView is no longer derived from QWidget directly.\n" - ) + -#endif gsi::method ("current", &lay::LayoutView::current, "@brief Returns the current view\n" "The current view is the one that is shown in the current tab. Returns nil if no layout is loaded.\n" diff --git a/src/layview/layview/layLayoutView_qt.cc b/src/layview/layview/layLayoutView_qt.cc index ebe5cd73b..c78708fff 100644 --- a/src/layview/layview/layLayoutView_qt.cc +++ b/src/layview/layview/layLayoutView_qt.cc @@ -47,6 +47,7 @@ #include "tlLog.h" #include "tlAssert.h" #include "tlExceptions.h" +#include "tlStaticObjects.h" #include "layLayoutView.h" #include "layViewOp.h" #include "layViewObject.h" @@ -187,13 +188,18 @@ void LayoutViewSignalConnector::max_hier_changed (int i) mp_view->max_hier_changed (i); } +void LayoutViewSignalConnector::app_terminated () +{ + mp_view->close (); +} + // ------------------------------------------------------------- const int timer_interval = 10; static LayoutView *ms_current = 0; -LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, QWidget *parent, const char *name, unsigned int options) +LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : LayoutViewBase (this, manager, editable, plugin_parent, options), mp_widget (0), dm_setup_editor_option_pages (this, &LayoutView::do_setup_editor_options_pages) @@ -201,10 +207,10 @@ LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin // ensures the deferred method scheduler is present tl::DeferredMethodScheduler::instance (); - init_ui (parent, name); + init_ui (); } -LayoutView::LayoutView (lay::LayoutView *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, QWidget *parent, const char *name, unsigned int options) +LayoutView::LayoutView (lay::LayoutView *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : LayoutViewBase (this, source, manager, editable, plugin_parent, options), mp_widget (0), dm_setup_editor_option_pages (this, &LayoutView::do_setup_editor_options_pages) @@ -212,13 +218,38 @@ LayoutView::LayoutView (lay::LayoutView *source, db::Manager *manager, bool edit // ensures the deferred method scheduler is present tl::DeferredMethodScheduler::instance (); - init_ui (parent, name); + init_ui (); bookmarks (source->bookmarks ()); - set_active_cellview_index (source->active_cellview_index ()); + LayoutView::set_active_cellview_index (source->active_cellview_index ()); } -bool +LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, LayoutViewFrame *widget, unsigned int options) + : LayoutViewBase (this, manager, editable, plugin_parent, options), + mp_widget (widget), + dm_setup_editor_option_pages (this, &LayoutView::do_setup_editor_options_pages) +{ + // ensures the deferred method scheduler is present + tl::DeferredMethodScheduler::instance (); + + init_ui (); +} + +LayoutView::LayoutView (lay::LayoutView *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, LayoutViewFrame *widget, unsigned int options) + : LayoutViewBase (this, source, manager, editable, plugin_parent, options), + mp_widget (widget), + dm_setup_editor_option_pages (this, &LayoutView::do_setup_editor_options_pages) +{ + // ensures the deferred method scheduler is present + tl::DeferredMethodScheduler::instance (); + + init_ui (); + + bookmarks (source->bookmarks ()); + LayoutView::set_active_cellview_index (source->active_cellview_index ()); +} + +bool LayoutView::event_filter (QObject *obj, QEvent *event, bool &taken) { if (obj == mp_min_hier_spbx || obj == mp_max_hier_spbx) { @@ -242,14 +273,13 @@ LayoutView::event_filter (QObject *obj, QEvent *event, bool &taken) } void -LayoutView::init_ui (QWidget *parent, const char *name) +LayoutView::init_ui () { m_activated = true; m_always_show_source = false; m_always_show_ld = true; m_always_show_layout_index = false; - mp_widget = 0; mp_connector = 0; mp_timer = 0; mp_left_frame = 0; @@ -265,14 +295,13 @@ LayoutView::init_ui (QWidget *parent, const char *name) mp_min_hier_spbx = 0; mp_max_hier_spbx = 0; - if (lay::has_gui ()) { - - mp_widget = new LayoutViewFrame (parent, this); - mp_widget->setObjectName (QString::fromUtf8 (name)); + if (mp_widget) { canvas ()->init_ui (mp_widget); mp_connector = new LayoutViewSignalConnector (mp_widget, this); + QObject::connect (mp_widget, SIGNAL (destroyed ()), mp_connector, SLOT (widget_destroyed ())); + QObject::connect (qApp, SIGNAL (destroyed ()), mp_connector, SLOT (app_destroyed ())); QVBoxLayout *vbl = new QVBoxLayout (mp_widget); vbl->setContentsMargins (0, 0, 0, 0); @@ -384,14 +413,20 @@ LayoutView::init_ui (QWidget *parent, const char *name) mp_timer->start (timer_interval); } - + config_setup (); finish (); } LayoutView::~LayoutView () +{ + close (); +} + +void LayoutView::close() { close_event (); + close_event.clear (); if (ms_current == this) { ms_current = 0; @@ -428,11 +463,6 @@ LayoutView::~LayoutView () } mp_bookmarks_frame = 0; mp_bookmarks_view = 0; - - if (mp_widget) { - delete mp_widget; - mp_widget = 0; - } } void @@ -480,6 +510,19 @@ void LayoutView::side_panel_destroyed (QObject *sender) } } +void LayoutView::app_destroyed () +{ + close (); +} + +void LayoutView::widget_destroyed (QObject *sender) +{ + if (sender == mp_widget) { + mp_widget = 0; + close (); + } +} + void LayoutView::set_current () { set_current (this); diff --git a/src/layview/layview/layLayoutView_qt.h b/src/layview/layview/layLayoutView_qt.h index af49052f8..c8acc7a55 100644 --- a/src/layview/layview/layLayoutView_qt.h +++ b/src/layview/layview/layLayoutView_qt.h @@ -89,7 +89,7 @@ class EditorOptionsPages; /** * @brief A custom QFrame that acts as the central widget for the LayoutView */ -class LayoutViewFrame +class LAYVIEW_PUBLIC LayoutViewFrame : public QFrame { Q_OBJECT @@ -181,7 +181,7 @@ public: typedef lay::LayoutViewBase::cell_path_type cell_path_type; -private slots: +public slots: void active_cellview_changed (int index); void active_library_changed (int index); void side_panel_destroyed (); @@ -191,6 +191,7 @@ private slots: void select_cell_dispatch (const cell_path_type &path, int cellview_index); void min_hier_changed (int i); void max_hier_changed (int i); + void app_terminated (); void timer (); @@ -212,12 +213,12 @@ public: /** * @brief Constructor */ - LayoutView (db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, QWidget *parent = 0, const char *name = "view", unsigned int options = (unsigned int) LV_Normal); + LayoutView (db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal); /** * @brief Constructor (clone from another view) */ - LayoutView (lay::LayoutView *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, QWidget *parent = 0, const char *name = "view", unsigned int options = (unsigned int) LV_Normal); + LayoutView (lay::LayoutView *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, unsigned int options = (unsigned int) LV_Normal); /** * @brief Destructor @@ -707,6 +708,8 @@ public: void deactivate_all_browsers (); + void close (); + private: friend class LayoutViewSignalConnector; friend class LayoutViewFrame; @@ -732,6 +735,8 @@ private: void active_library_changed (int index); void side_panel_destroyed (QObject *sender); + void widget_destroyed (QObject *sender); + void app_destroyed (); void layer_tab_changed (); void layer_order_changed (); void min_hier_changed (int i); @@ -740,10 +745,20 @@ private: bool event_filter (QObject *obj, QEvent *ev, bool &taken); QSize size_hint () const; - void init_ui (QWidget *parent, const char *name); + void init_ui (); void do_setup_editor_options_pages (); protected: + /** + * @brief Constructor with widget + */ + LayoutView (db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, LayoutViewFrame *widget, unsigned int options = (unsigned int) LV_Normal); + + /** + * @brief Constructor (clone from another view) with widget + */ + LayoutView (lay::LayoutView *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, LayoutViewFrame *widget, unsigned int options = (unsigned int) LV_Normal); + void activate (); void deactivate (); @@ -775,6 +790,35 @@ private: using LayoutViewBase::ui; }; +/** + * @brief The layout view widget + * + * This is a LayoutView which actually is a widget. It can be used in a widget tree + * but only created if a QApplication is present. + */ +class LAYVIEW_PUBLIC LayoutViewWidget + : public LayoutViewFrame, public LayoutView +{ +public: + /** + * @brief Constructor + */ + LayoutViewWidget (db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, QWidget *parent = 0, unsigned int options = (unsigned int) LV_Normal) + : LayoutViewFrame (parent, this), LayoutView (mgr, editable, plugin_parent, this, options) + { + // .. nothing yet .. + } + + /** + * @brief Constructor (clone from another view) + */ + LayoutViewWidget (lay::LayoutView *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, QWidget *parent = 0, unsigned int options = (unsigned int) LV_Normal) + : LayoutViewFrame (parent, this), LayoutView (source, mgr, editable, plugin_parent, this, options) + { + // .. nothing yet .. + } +}; + } #endif diff --git a/src/plugins/tools/bool/lay_plugin/layBooleanOperationsPlugin.cc b/src/plugins/tools/bool/lay_plugin/layBooleanOperationsPlugin.cc index f8ccfd1ba..56c311fd7 100644 --- a/src/plugins/tools/bool/lay_plugin/layBooleanOperationsPlugin.cc +++ b/src/plugins/tools/bool/lay_plugin/layBooleanOperationsPlugin.cc @@ -39,8 +39,8 @@ class BooleanOperationsPlugin : public lay::Plugin { public: - BooleanOperationsPlugin (Plugin *parent, lay::LayoutViewBase *view) - : lay::Plugin (parent), mp_view (view) + BooleanOperationsPlugin (lay::LayoutViewBase *view) + : lay::Plugin (view), mp_view (view) { m_boolean_cva = -1; m_boolean_cvb = -1; @@ -494,9 +494,9 @@ public: // .. nothing yet .. } - lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const + lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *, lay::LayoutViewBase *view) const { - return new BooleanOperationsPlugin (root, view); + return new BooleanOperationsPlugin (view); } }; diff --git a/src/plugins/tools/diff/lay_plugin/layDiffPlugin.cc b/src/plugins/tools/diff/lay_plugin/layDiffPlugin.cc index 4740f8a5e..87b5738c8 100644 --- a/src/plugins/tools/diff/lay_plugin/layDiffPlugin.cc +++ b/src/plugins/tools/diff/lay_plugin/layDiffPlugin.cc @@ -27,6 +27,8 @@ #include "layLayoutViewBase.h" #include "layUtils.h" +#include + namespace lay { @@ -34,20 +36,19 @@ class DiffPlugin : public lay::Plugin { public: - DiffPlugin (Plugin *parent, lay::LayoutViewBase *view) - : lay::Plugin (parent), mp_view (view) + DiffPlugin (lay::LayoutViewBase *view) + : lay::Plugin (view), mp_view (view) { if (lay::has_gui ()) { mp_dialog = new lay::DiffToolDialog (0); - } else { - mp_dialog = 0; } } ~DiffPlugin () { - delete mp_dialog; - mp_dialog = 0; + if (mp_dialog) { + delete mp_dialog.data (); + } } void menu_activated (const std::string &symbol) @@ -65,7 +66,7 @@ public: private: lay::LayoutViewBase *mp_view; - lay::DiffToolDialog *mp_dialog; + QPointer mp_dialog; }; class DiffPluginDeclaration @@ -108,9 +109,9 @@ public: // .. nothing yet .. } - lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const + lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *, lay::LayoutViewBase *view) const { - return new DiffPlugin (root, view); + return new DiffPlugin (view); } }; diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index 529001fba..ba1b49639 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -40,7 +40,7 @@ namespace lay const double initial_elevation = 15.0; -D25View::D25View (lay::Dispatcher *root, LayoutViewBase *view) +D25View::D25View (Dispatcher *root, LayoutViewBase *view) : lay::Browser (root, view, "d25_view"), dm_rerun_macro (this, &D25View::rerun_macro), dm_fit (this, &D25View::fit) diff --git a/src/plugins/tools/xor/lay_plugin/layXORPlugin.cc b/src/plugins/tools/xor/lay_plugin/layXORPlugin.cc index 919078f59..32f066403 100644 --- a/src/plugins/tools/xor/lay_plugin/layXORPlugin.cc +++ b/src/plugins/tools/xor/lay_plugin/layXORPlugin.cc @@ -29,6 +29,8 @@ #include "layLayoutView.h" #include "layUtils.h" +#include + namespace lay { @@ -36,20 +38,19 @@ class XORPlugin : public lay::Plugin { public: - XORPlugin (Plugin *parent, lay::LayoutViewBase *view) - : lay::Plugin (parent), mp_view (view) + XORPlugin (lay::LayoutViewBase *view) + : lay::Plugin (view), mp_view (view) { if (lay::has_gui ()) { mp_dialog = new lay::XORToolDialog (0); - } else { - mp_dialog = 0; } } ~XORPlugin () { - delete mp_dialog; - mp_dialog = 0; + if (mp_dialog) { + delete mp_dialog.data (); + } } void menu_activated (const std::string &symbol) @@ -67,7 +68,7 @@ public: private: lay::LayoutViewBase *mp_view; - lay::XORToolDialog *mp_dialog; + QPointer mp_dialog; }; class XORPluginDeclaration @@ -116,9 +117,9 @@ public: // .. nothing yet .. } - lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const + lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *, lay::LayoutViewBase *view) const { - return new XORPlugin (root, view); + return new XORPlugin (view); } }; diff --git a/testdata/klayout_main/main.rb b/testdata/klayout_main/main.rb index 2f54e511a..0de2bdf55 100644 --- a/testdata/klayout_main/main.rb +++ b/testdata/klayout_main/main.rb @@ -183,6 +183,14 @@ class KLayoutMain_TestClass < TestBase end + def test_11 + + # Headless LayoutView (GUI enabled) + out = `#{self.klayout_bin} -z -rd input=#{File.join(File.dirname(__FILE__), "test1.gds")} -r #{File.join(File.dirname(__FILE__), "test10.rb")} 2>&1` + assert_equal(out, "(0,0;8,8)\n") + + end + end load("test_epilogue.rb")