Merge pull request #2232 from KLayout/bugfix/issue-2221

Bugfix/issue 2221
This commit is contained in:
Matthias Köfferlein 2025-12-07 22:27:37 +01:00 committed by GitHub
commit 9fbaf8fb14
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 125 additions and 131 deletions

View File

@ -2277,6 +2277,29 @@ MainWindow::cm_save_as ()
do_save (true); do_save (true);
} }
static db::SaveLayoutOptions
get_save_options_from_cv (const lay::CellView &cv)
{
db::SaveLayoutOptions options = cv->save_options ();
if (!cv->save_options_valid () && cv->technology ()) {
options = cv->technology ()->save_layout_options ();
options.set_format (cv->save_options ().format ());
}
// preconfigure options with current values
options.set_dbu (cv->layout ().dbu ());
if (cv->layout ().has_meta_info ("libname")) {
tl::Variant libname = cv->layout ().meta_info ("libname").value;
if (libname.is_a_string ()) {
options.set_libname (libname.to_stdstring ());
}
}
return options;
}
void void
MainWindow::do_save (bool as) MainWindow::do_save (bool as)
{ {
@ -2309,22 +2332,7 @@ MainWindow::do_save (bool as)
// - if the layout's save options are valid we take the options from there, otherwise we take the options from the technology // - if the layout's save options are valid we take the options from there, otherwise we take the options from the technology
// - on "save as" we let the user edit the options // - on "save as" we let the user edit the options
db::SaveLayoutOptions options = cv->save_options (); db::SaveLayoutOptions options = get_save_options_from_cv (cv);
if (!cv->save_options_valid () && cv->technology ()) {
options = cv->technology ()->save_layout_options ();
options.set_format (cv->save_options ().format ());
}
// preconfigure options with current values
options.set_dbu (cv->layout ().dbu ());
if (cv->layout ().has_meta_info ("libname")) {
tl::Variant libname = cv->layout ().meta_info ("libname").value;
if (libname.is_a_string ()) {
options.set_libname (libname.to_stdstring ());
}
}
if (as || options.format ().empty ()) { if (as || options.format ().empty ()) {
options.set_format_from_filename (fn); options.set_format_from_filename (fn);
@ -2337,7 +2345,18 @@ MainWindow::do_save (bool as)
} }
current_view ()->save_as ((unsigned int) cv_index, fn, om, options, true, m_keep_backups); current_view ()->save_as ((unsigned int) cv_index, fn, om, options, true, m_keep_backups);
add_mru (fn, current_view ()->cellview (cv_index)->tech_name ()); add_mru (fn, cv->tech_name ());
if (as) {
lay::LayoutViewNotification n ("reload", tl::to_string (tr ("The next 'save' operations will use the writer options you have picked, instead of the application-wide ones.")));
current_view ()->add_notification (n);
// freeze writer options in the 'save_as' case, so we can do another "save" and get the
// selected options again
cv->set_save_options (options, true);
}
} }
@ -2362,8 +2381,7 @@ MainWindow::cm_save_all ()
if (! fn.empty () || mp_layout_fdia->get_save (fn, tl::to_string (tr ("Save Layout '%1'").arg (tl::to_qstring (cv->name ()))))) { if (! fn.empty () || mp_layout_fdia->get_save (fn, tl::to_string (tr ("Save Layout '%1'").arg (tl::to_qstring (cv->name ()))))) {
db::SaveLayoutOptions options (cv->save_options ()); db::SaveLayoutOptions options = get_save_options_from_cv (cv);
options.set_dbu (cv->layout ().dbu ());
if (options.format ().empty ()) { if (options.format ().empty ()) {
options.set_format_from_filename (fn); options.set_format_from_filename (fn);
@ -2371,14 +2389,6 @@ MainWindow::cm_save_all ()
tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto; tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto;
// initialize the specific options from the configuration if required
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
const StreamWriterPluginDeclaration *decl = dynamic_cast <const StreamWriterPluginDeclaration *> (&*cls);
if (decl) {
options.set_options (decl->create_specific_options ());
}
}
view (view_index)->save_as (cv_index, fn, om, options, true, m_keep_backups); view (view_index)->save_as (cv_index, fn, om, options, true, m_keep_backups);
add_mru (fn, cv->tech_name ()); add_mru (fn, cv->tech_name ());

View File

@ -300,39 +300,11 @@ LayoutHandle::set_save_options (const db::SaveLayoutOptions &options, bool valid
m_save_options_valid = valid; m_save_options_valid = valid;
} }
void
LayoutHandle::update_save_options (db::SaveLayoutOptions &options)
{
#if defined(HAVE_QT)
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
const lay::StreamWriterPluginDeclaration *decl = dynamic_cast <const lay::StreamWriterPluginDeclaration *> (&*cls);
if (! decl || decl->options_alias ()) {
continue;
}
std::unique_ptr<db::FormatSpecificWriterOptions> specific_options;
if (options.get_options (decl->format_name ())) {
specific_options.reset (options.get_options (decl->format_name ())->clone ());
} else {
specific_options.reset (decl->create_specific_options ());
}
if (specific_options.get ()) {
options.set_options (specific_options.release ());
}
}
#endif
}
void void
LayoutHandle::save_as (const std::string &fn, tl::OutputStream::OutputStreamMode om, const db::SaveLayoutOptions &options, bool update, int keep_backups) LayoutHandle::save_as (const std::string &fn, tl::OutputStream::OutputStreamMode om, const db::SaveLayoutOptions &options, bool update, int keep_backups)
{ {
if (update) { if (update) {
m_save_options = options;
m_save_options_valid = true;
// We must not load with the original options after we have saved the file - hence we reset the // We must not load with the original options after we have saved the file - hence we reset the
// reader options. // reader options.
m_load_options = db::LoadLayoutOptions (); m_load_options = db::LoadLayoutOptions ();

View File

@ -242,15 +242,6 @@ public:
return m_save_options; return m_save_options;
} }
/**
* @brief Updates the given save options with attributes from this cell view
*
* Some formats will initialize attributes from the cell view and the layout's
* metadata (example: libname of GDS2). This method will update the options
* if the layout provides attributes for initializing the latter.
*/
void update_save_options (db::SaveLayoutOptions &options);
/** /**
* @brief Gets a flag indicating whether the save options are valid * @brief Gets a flag indicating whether the save options are valid
* *

View File

@ -149,6 +149,70 @@ struct LAYBASIC_PUBLIC LayerDisplayProperties
std::string name; std::string name;
}; };
/**
* @brief Descriptor for a notification inside the layout view
*
* Notifications are popups added at the top of the view to indicate need for reloading for example.
* Notifications have a name, a title, optional actions (id, title) and a parameter (e.g. file path to reload).
* Actions are mapped to QPushButtons.
*/
class LAYBASIC_PUBLIC LayoutViewNotification
{
public:
LayoutViewNotification (const std::string &name, const std::string &title, const tl::Variant &parameter = tl::Variant ())
: m_name (name), m_title (title), m_parameter (parameter)
{
// .. nothing yet ..
}
void add_action (const std::string &name, const std::string &title)
{
m_actions.push_back (std::make_pair (name, title));
}
const std::vector<std::pair<std::string, std::string> > &actions () const
{
return m_actions;
}
const std::string &name () const
{
return m_name;
}
const std::string &title () const
{
return m_title;
}
const tl::Variant &parameter () const
{
return m_parameter;
}
bool operator<(const LayoutViewNotification &other) const
{
if (m_name != other.name ()) {
return m_name < other.name ();
}
return m_parameter < other.parameter ();
}
bool operator==(const LayoutViewNotification &other) const
{
if (m_name != other.name ()) {
return false;
}
return m_parameter == other.parameter ();
}
private:
std::string m_name;
std::string m_title;
tl::Variant m_parameter;
std::vector<std::pair<std::string, std::string> > m_actions;
};
/** /**
* @brief The layout view object * @brief The layout view object
* *
@ -279,6 +343,14 @@ public:
*/ */
virtual void cut (); virtual void cut ();
/**
* @brief Adds a notification
*/
virtual void add_notification (const LayoutViewNotification & /*notification*/)
{
// the base implementation does nothing
}
/** /**
* @brief Gets the explicit title string of the view * @brief Gets the explicit title string of the view
* *

View File

@ -453,6 +453,14 @@ LayoutView::LayoutView (lay::LayoutView *source, db::Manager *manager, bool edit
LayoutView::set_active_cellview_index (source->active_cellview_index ()); LayoutView::set_active_cellview_index (source->active_cellview_index ());
} }
void
LayoutView::add_notification (const LayoutViewNotification &notification)
{
if (mp_widget) {
mp_widget->add_notification (notification);
}
}
bool bool
LayoutView::event_filter (QObject *obj, QEvent *event, bool &taken) LayoutView::event_filter (QObject *obj, QEvent *event, bool &taken)
{ {

View File

@ -1,4 +1,4 @@
#
/* /*
KLayout Layout Viewer KLayout Layout Viewer
@ -149,6 +149,11 @@ public:
*/ */
~LayoutView (); ~LayoutView ();
/**
* @brief Adds a notification
*/
virtual void add_notification (const LayoutViewNotification &notification);
/** /**
* @brief Gets the widget object that view is embedded in * @brief Gets the widget object that view is embedded in
*/ */
@ -695,70 +700,6 @@ private:
void activate_editor_option_pages (); void activate_editor_option_pages ();
}; };
/**
* @brief Descriptor for a notification inside the layout view
*
* Notifications are popups added at the top of the view to indicate need for reloading for example.
* Notifications have a name, a title, optional actions (id, title) and a parameter (e.g. file path to reload).
* Actions are mapped to QPushButtons.
*/
class LAYVIEW_PUBLIC LayoutViewNotification
{
public:
LayoutViewNotification (const std::string &name, const std::string &title, const tl::Variant &parameter = tl::Variant ())
: m_name (name), m_title (title), m_parameter (parameter)
{
// .. nothing yet ..
}
void add_action (const std::string &name, const std::string &title)
{
m_actions.push_back (std::make_pair (name, title));
}
const std::vector<std::pair<std::string, std::string> > &actions () const
{
return m_actions;
}
const std::string &name () const
{
return m_name;
}
const std::string &title () const
{
return m_title;
}
const tl::Variant &parameter () const
{
return m_parameter;
}
bool operator<(const LayoutViewNotification &other) const
{
if (m_name != other.name ()) {
return m_name < other.name ();
}
return m_parameter < other.parameter ();
}
bool operator==(const LayoutViewNotification &other) const
{
if (m_name != other.name ()) {
return false;
}
return m_parameter == other.parameter ();
}
private:
std::string m_name;
std::string m_title;
tl::Variant m_parameter;
std::vector<std::pair<std::string, std::string> > m_actions;
};
/** /**
* @brief A widget representing a notification * @brief A widget representing a notification
*/ */
@ -810,12 +751,12 @@ public:
/** /**
* @brief Adds a notification * @brief Adds a notification
*/ */
void add_notification (const LayoutViewNotification &notificaton); void add_notification (const LayoutViewNotification &notification);
/** /**
* @brief Removes a notification * @brief Removes a notification
*/ */
void remove_notification (const LayoutViewNotification &notificaton); void remove_notification (const LayoutViewNotification &notification);
/** /**
* @brief Gets the LayoutView embedded into this widget * @brief Gets the LayoutView embedded into this widget