diff --git a/src/db/db/dbPCellDeclaration.h b/src/db/db/dbPCellDeclaration.h index 5c40adc38..cf0ec2881 100644 --- a/src/db/db/dbPCellDeclaration.h +++ b/src/db/db/dbPCellDeclaration.h @@ -37,7 +37,21 @@ namespace db { typedef std::vector pcell_parameters_type; - + +/** + * @brief A base class for PCell parameters pages + * + * Currently, the implementations of PCell parameter pages + * live in the "edt" namespace. This base class is the + * abstract one used inside "db". + */ +class DB_PUBLIC PCellParametersPageBase +{ +public: + PCellParametersPageBase () { } + virtual ~PCellParametersPageBase () { } +}; + /** * @brief A declaration for one PCell parameter * @@ -847,6 +861,14 @@ public: */ std::map named_parameters (const pcell_parameters_type &pv) const; + /** + * @brief Creates the PCell parameters page or returns nil if there is no specific one + */ + virtual db::PCellParametersPageBase *create_parameter_page () const + { + return 0; + } + protected: /** * @brief Gets a value indicating whether the PCell wants caching of the parameter declarations diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index 2deb658e4..dfcaa1ceb 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -880,10 +880,26 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector pcell_declaration (pc.second) && view ()->cellview (m_cv_index).is_valid ()) { + const db::PCellDeclaration *pcell_decl = 0; + + if (pc.first && (pcell_decl = layout->pcell_declaration (pc.second)) != 0 && view ()->cellview (m_cv_index).is_valid ()) { + + db::PCellParametersPageBase *pp = pcell_decl->create_parameter_page (); + + mp_pcell_parameters = dynamic_cast (pp); + if (! mp_pcell_parameters) { + if (pp) { + // not useful. + delete pp; + } + mp_pcell_parameters = new PCellParametersPage (); + } + + // NOTE: these functions must be called in that order + mp_pcell_parameters->set_dense (true); + mp_pcell_parameters->set_parent (this); + mp_pcell_parameters->setup (view (), dispatcher (), m_cv_index, pcell_decl, parameters); - mp_pcell_parameters = new PCellParametersPage (this, dispatcher (), true /*dense*/); - mp_pcell_parameters->setup (view (), m_cv_index, layout->pcell_declaration (pc.second), parameters); this->layout ()->addWidget (mp_pcell_parameters); mp_pcell_parameters->set_state (pcp_state); diff --git a/src/edt/edt/edtEditorOptionsPages.h b/src/edt/edt/edtEditorOptionsPages.h index 80d86deda..c5b7d1bff 100644 --- a/src/edt/edt/edtEditorOptionsPages.h +++ b/src/edt/edt/edtEditorOptionsPages.h @@ -61,7 +61,7 @@ namespace lay namespace edt { -class PCellParametersPage; +class PCellParametersPageBase; /** * @brief The generic properties page @@ -156,7 +156,7 @@ private slots: private: Ui::EditorOptionsInst *mp_ui; - edt::PCellParametersPage *mp_pcell_parameters; + edt::PCellParametersPageBase *mp_pcell_parameters; int m_cv_index; virtual void technology_changed (const std::string &); @@ -185,7 +185,7 @@ private slots: private: Ui::EditorOptionsInstPCellParam *mp_ui; - edt::PCellParametersPage *mp_pcell_parameters; + edt::PCellParametersPageBase *mp_pcell_parameters; QLabel *mp_placeholder_label; int m_cv_index; std::string m_lib_name, m_cell_name; diff --git a/src/edt/edt/edtInstPropertiesPage.cc b/src/edt/edt/edtInstPropertiesPage.cc index b5f87c0b5..13de6f716 100644 --- a/src/edt/edt/edtInstPropertiesPage.cc +++ b/src/edt/edt/edtInstPropertiesPage.cc @@ -1038,9 +1038,22 @@ InstPropertiesPage::update_pcell_parameters () mp_pcell_parameters->delete_later (); } - mp_pcell_parameters = new PCellParametersPage (pcell_tab, mp_service->view ()->dispatcher ()); + db::PCellParametersPageBase *pp = pcell_decl->create_parameter_page (); + + mp_pcell_parameters = dynamic_cast (pp); + if (! mp_pcell_parameters) { + if (pp) { + // not useful. + delete pp; + } + mp_pcell_parameters = new PCellParametersPage (); + } + + // NOTE: these functions must be called in that order + mp_pcell_parameters->set_parent (pcell_tab); + mp_pcell_parameters->setup (mp_service->view (), mp_service->view ()->dispatcher (), pos->cv_index (), pcell_decl, parameters); + connect (mp_pcell_parameters, SIGNAL (edited ()), this, SIGNAL (edited ())); - mp_pcell_parameters->setup (mp_service->view (), pos->cv_index (), layout->pcell_declaration (pc.second), parameters); pcell_tab->layout ()->addWidget (mp_pcell_parameters); } diff --git a/src/edt/edt/edtInstPropertiesPage.h b/src/edt/edt/edtInstPropertiesPage.h index 8856885cb..3d9ce4c9c 100644 --- a/src/edt/edt/edtInstPropertiesPage.h +++ b/src/edt/edt/edtInstPropertiesPage.h @@ -34,7 +34,7 @@ namespace edt { -class PCellParametersPage; +class PCellParametersPageBase; class ChangeApplicator; class InstPropertiesPage @@ -64,7 +64,7 @@ protected: edt::Service *mp_service; bool m_enable_cb_callback; db::properties_id_type m_prop_id; - edt::PCellParametersPage *mp_pcell_parameters; + edt::PCellParametersPageBase *mp_pcell_parameters; virtual bool readonly (); virtual void apply (bool commit); diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index 391741ec2..87ed634fa 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -209,8 +209,8 @@ static void set_value (const db::PCellParameterDeclaration &p, QWidget *widget, } } -PCellParametersPage::PCellParametersPage (QWidget *parent, lay::Dispatcher *dispatcher, bool dense) - : PCellParametersPageBase (parent, dispatcher, dense) +PCellParametersPage::PCellParametersPage () + : PCellParametersPageBase () { // .. nothing yet .. } diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h index 38f724e77..cf26da0a5 100644 --- a/src/edt/edt/edtPCellParametersPage.h +++ b/src/edt/edt/edtPCellParametersPage.h @@ -42,7 +42,7 @@ public: /** * @brief Constructor */ - PCellParametersPage (QWidget *parent, lay::Dispatcher *dispatcher, bool dense = false); + PCellParametersPage (); protected: virtual void build_widgets (QFrame *container); diff --git a/src/edt/edt/edtPCellParametersPageBase.cc b/src/edt/edt/edtPCellParametersPageBase.cc index b5f0d6936..abf17fdab 100644 --- a/src/edt/edt/edtPCellParametersPageBase.cc +++ b/src/edt/edt/edtPCellParametersPageBase.cc @@ -39,17 +39,34 @@ namespace edt { -PCellParametersPageBase::PCellParametersPageBase (QWidget *parent, lay::Dispatcher *dispatcher, bool dense) - : QFrame (parent), m_dense (dense), mp_dispatcher (dispatcher), m_show_parameter_names (false), m_lazy_evaluation (-1), dm_parameter_changed (this, &PCellParametersPageBase::do_parameter_changed) +PCellParametersPageBase::PCellParametersPageBase () + : QFrame (0), + m_parameter_changed_enabled (false), + m_dense (false), + mp_dispatcher (0), + m_show_parameter_names (false), + m_lazy_evaluation (-1), + dm_parameter_changed (this, &PCellParametersPageBase::do_parameter_changed) { - if (mp_dispatcher) { - mp_dispatcher->config_get (cfg_edit_pcell_show_parameter_names, m_show_parameter_names); - mp_dispatcher->config_get (cfg_edit_pcell_lazy_eval_mode, m_lazy_evaluation); - } + // .. nothing yet .. +} +void +PCellParametersPageBase::set_parent (QWidget *p) +{ + tl_assert (parent () == 0); + tl_assert (p != 0); + setParent (p); init (); } +void +PCellParametersPageBase::set_dense (bool d) +{ + tl_assert (parent () == 0); + m_dense = d; +} + tl::Variant PCellParametersPageBase::get_user_state () { @@ -233,7 +250,7 @@ PCellParametersPageBase::lazy_eval_mode (int mode) mp_dispatcher->config_set (cfg_edit_pcell_lazy_eval_mode, m_lazy_evaluation); } - setup (mp_view, m_cv_index, mp_pcell_decl.get (), get_parameters ()); + setup (mp_view, mp_dispatcher, m_cv_index, mp_pcell_decl.get (), get_parameters ()); } void @@ -250,12 +267,20 @@ PCellParametersPageBase::show_parameter_names (bool f) mp_dispatcher->config_set (cfg_edit_pcell_show_parameter_names, m_show_parameter_names); } - setup (mp_view, m_cv_index, mp_pcell_decl.get (), get_parameters ()); + setup (mp_view, mp_dispatcher, m_cv_index, mp_pcell_decl.get (), get_parameters ()); } void -PCellParametersPageBase::setup (lay::LayoutViewBase *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) +PCellParametersPageBase::setup (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) { + tl_assert (parent () != 0); + + if (mp_dispatcher != dispatcher) { + mp_dispatcher = dispatcher; + mp_dispatcher->config_get (cfg_edit_pcell_show_parameter_names, m_show_parameter_names); + mp_dispatcher->config_get (cfg_edit_pcell_lazy_eval_mode, m_lazy_evaluation); + } + mp_pcell_decl.reset (const_cast (pcell_decl)); // no const weak_ptr ... mp_view = view; m_cv_index = cv_index; @@ -315,15 +340,20 @@ PCellParametersPageBase::setup (lay::LayoutViewBase *view, int cv_index, const d } - // populate the main frame with widgets - build_widgets (mp_main_frame); - - // initial callback + // block parameter change events during setup + m_parameter_changed_enabled = false; try { + + // populate the main frame with widgets + build_widgets (mp_main_frame); + + // initial callback + if (mp_pcell_decl->layout ()) { mp_pcell_decl->callback (*mp_pcell_decl->layout (), std::string (), m_states); } + } catch (tl::Exception &ex) { // potentially caused by script errors in callback implementation tl::error << ex.msg (); @@ -333,6 +363,8 @@ PCellParametersPageBase::setup (lay::LayoutViewBase *view, int cv_index, const d // ignore other errors } + m_parameter_changed_enabled = true; + m_initial_states = m_states; mp_error_frame->hide (); @@ -396,6 +428,12 @@ PCellParametersPageBase::parameter_changed (const std::string &name) return; } + if (! m_parameter_changed_enabled) { + return; + } + // prevent recursive calls + m_parameter_changed_enabled = false; + db::ParameterStates states = m_states; bool edit_error = true; @@ -429,6 +467,8 @@ PCellParametersPageBase::parameter_changed (const std::string &name) } + m_parameter_changed_enabled = true; + dm_parameter_changed (); } @@ -583,7 +623,20 @@ PCellParametersPageBase::update_widgets_from_states (const db::ParameterStates & } set_parameters_internal (states, tentatively); - apply_states (states); + + bool en = m_parameter_changed_enabled; + m_parameter_changed_enabled = false; + try { + apply_states (states); + } catch (tl::Exception &ex) { + // potentially caused by script errors in callback implementation + tl::error << ex.msg (); + } catch (std::runtime_error &ex) { + tl::error << ex.what (); + } catch (...) { + // ignore other errors + } + m_parameter_changed_enabled = en; } void @@ -605,7 +658,19 @@ PCellParametersPageBase::set_parameters_internal (const db::ParameterStates &sta return; } - apply_values (states); + bool en = m_parameter_changed_enabled; + m_parameter_changed_enabled = false; + try { + apply_values (states); + } catch (tl::Exception &ex) { + // potentially caused by script errors in callback implementation + tl::error << ex.msg (); + } catch (std::runtime_error &ex) { + tl::error << ex.what (); + } catch (...) { + // ignore other errors + } + m_parameter_changed_enabled = en; bool update_needed = false; diff --git a/src/edt/edt/edtPCellParametersPageBase.h b/src/edt/edt/edtPCellParametersPageBase.h index 4fe6a40fe..e0a50978d 100644 --- a/src/edt/edt/edtPCellParametersPageBase.h +++ b/src/edt/edt/edtPCellParametersPageBase.h @@ -51,7 +51,7 @@ namespace edt * @brief A QScrollArea that displays and allows editing PCell parameters */ class PCellParametersPageBase - : public QFrame, public tl::Object + : public QFrame, public tl::Object, public db::PCellParametersPageBase { Q_OBJECT @@ -70,11 +70,32 @@ public: /** * @brief Constructor * - * @param parent The parent widgets - * @param dispatcher The dispatcher object for configuration - * @param dense A flag indicating that a dense layout shall be used (for embedded pages) + * After the page has been constructed, the following methods need to be called in this order: + * 1.) "set_dense" if required + * 2.) "set_parent" + * 3.) "setup" */ - PCellParametersPageBase (QWidget *parent, lay::Dispatcher *dispatcher, bool dense = false); + PCellParametersPageBase (); + + /** + * @brief Sets the parent widget + */ + void set_parent (QWidget *parent); + + /** + * @brief Gets a value indicating that a dense layout shall be created + * + * Dense layouts are used for embedded parameter pages. + */ + bool dense () const + { + return m_dense; + } + + /** + * @brief Sets a value indicating that a dense layout shall be created + */ + void set_dense (bool d); /** * @brief initialization @@ -87,7 +108,7 @@ public: * @param pcell_decl The PCell declaration * @param parameters The parameter values to show (if empty, the default values are used) */ - void setup (lay::LayoutViewBase *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters); + void setup (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters); /** * @brief Gets the pages current state @@ -99,16 +120,6 @@ public: */ void set_state (const State &s); - /** - * @brief Gets a value indicating that a dense layout shall be created - * - * Dense layouts are used for embedded parameter pages. - */ - bool dense () const - { - return m_dense; - } - /** * @brief Gets a value indicating whether parameter names shall be shown * @@ -249,6 +260,7 @@ private slots: void lazy_eval_mode_slot (); private: + bool m_parameter_changed_enabled; bool m_dense; lay::Dispatcher *mp_dispatcher; QScrollArea *mp_parameters_area;