From cb199a489c1e01bb76f5af8bacd84191e52ffce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Fri, 5 Jun 2020 10:58:53 +0200 Subject: [PATCH] Implemented #560 (multiple technologies on libraries) (#576) * First implementation. * PORT BACK: fixed a few flaws (fixed-width side panel ..) 1. On "save as" the filename displayed in the cell view selection box was not updated 2. The width of the library and cellview panel could not be reduced below the width of the combo boxes in the headers. So the panels might have become pretty wide without being able to reduce them. * Implemented #560 (multiple techs on libraries) --- src/db/db/dbLibrary.cc | 33 ++++++++ src/db/db/dbLibrary.h | 37 +++++++-- src/db/db/gsiDeclDbLibrary.cc | 45 ++++++++++- src/lay/lay/layLibraryController.cc | 2 +- src/lay/lay/layTechSetupDialog.cc | 2 +- src/laybasic/laybasic/layLibrariesView.cc | 5 +- src/laybasic/laybasic/layWidgets.cc | 7 +- src/rba/unit_tests/rba.cc | 1 + testdata/ruby/dbLibrary.rb | 93 +++++++++++++++++++++++ 9 files changed, 207 insertions(+), 18 deletions(-) create mode 100644 testdata/ruby/dbLibrary.rb diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index fec55c29b..6c0ca490c 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -46,6 +46,39 @@ Library::~Library () // .. nothing yet .. } +bool +Library::is_for_technology (const std::string &name) const +{ + return m_technologies.find (name) != m_technologies.end (); +} + +bool +Library::for_technologies () const +{ + return ! m_technologies.empty (); +} + +void +Library::set_technology (const std::string &t) +{ + m_technologies.clear (); + if (! t.empty ()) { + m_technologies.insert (t); + } +} + +void +Library::clear_technologies () +{ + m_technologies.clear (); +} + +void +Library::add_technology (const std::string &tech) +{ + m_technologies.insert (tech); +} + void Library::register_proxy (db::LibraryProxy *lib_proxy, db::Layout *ly) { diff --git a/src/db/db/dbLibrary.h b/src/db/db/dbLibrary.h index 422eec281..21cd70061 100644 --- a/src/db/db/dbLibrary.h +++ b/src/db/db/dbLibrary.h @@ -31,6 +31,7 @@ #include "tlObject.h" #include +#include namespace db { @@ -108,18 +109,38 @@ public: * If this attribute is non-empty, the library is selected only when the given technology is * used for the layout. */ - const std::string &get_technology () const + const std::set &get_technologies () const { - return m_technology; + return m_technologies; } /** - * @brief Sets the technology name this library is associated with + * @brief Gets a value indicating whether this library is associated with the given technology */ - void set_technology (const std::string &t) - { - m_technology = t; - } + bool is_for_technology (const std::string &name) const; + + /** + * @brief Gets a value indicating whether the library is associated with any technology + */ + bool for_technologies () const; + + /** + * @brief Sets the technology name this library is associated with + * + * This will reset the list of technologies to this one. + * If the given technology string is empty, the list of technologies will be cleared. + */ + void set_technology (const std::string &t); + + /** + * @brief Clears the list of technologies this library is associated with + */ + void clear_technologies (); + + /** + * @brief Additionally associate the library with the given technology + */ + void add_technology (const std::string &tech); /** * @brief Getter for the description property @@ -198,7 +219,7 @@ public: private: std::string m_name; std::string m_description; - std::string m_technology; + std::set m_technologies; lib_id_type m_id; db::Layout m_layout; std::map m_referrers; diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index ff4f406a1..cfd1f5f2f 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -68,6 +68,16 @@ static void delete_lib (db::Library *lib) db::LibraryManager::instance ().delete_lib (lib); } +static std::string get_technology (db::Library *lib) +{ + const std::set &techs = lib->get_technologies (); + if (techs.empty ()) { + return std::string (); + } else { + return *techs.begin (); + } +} + Class decl_Library ("db", "Library", gsi::constructor ("new", &new_lib, "@brief Creates a new, empty library" @@ -114,19 +124,48 @@ Class decl_Library ("db", "Library", "@brief Sets the libraries' description text\n" "@args description\n" ) + - gsi::method ("technology", &db::Library::get_technology, + gsi::method_ext ("#technology", &get_technology, "@brief Returns name of the technology the library is associated with\n" "If this attribute is a non-empty string, this library is only offered for " "selection if the current layout uses this technology.\n" "\n" - "This attribute has been introduced in version 0.25." + "This attribute has been introduced in version 0.25. In version 0.27 this attribute is deprecated as " + "a library can now be associated with multiple technologies." ) + gsi::method ("technology=", &db::Library::set_technology, "@brief sets the name of the technology the library is associated with\n" "@args technology\n" "\n" "See \\technology for details. " - "This attribute has been introduced in version 0.25." + "This attribute has been introduced in version 0.25. In version 0.27, a library can be associated with " + "multiple technologies and this method will revert the selection to a single one. Passing an empty string " + "is equivalent to \\clear_technologies." + ) + + gsi::method ("clear_technologies", &db::Library::clear_technologies, + "@brief Clears the list of technologies the library is associated with.\n" + "See also \\add_technology.\n" + "\n" + "This method has been introduced in version 0.27" + ) + + gsi::method ("add_technology", &db::Library::add_technology, gsi::arg ("tech"), + "@brief Additionally associates the library with the given technology.\n" + "See also \\clear_technologies.\n" + "\n" + "This method has been introduced in version 0.27" + ) + + gsi::method ("is_for_technology", &db::Library::is_for_technology, gsi::arg ("tech"), + "@brief Returns a value indicating whether the library is associated with the given technology.\n" + "This method has been introduced in version 0.27" + ) + + gsi::method ("for_technologies", &db::Library::for_technologies, + "@brief Returns a value indicating whether the library is associated with any technology.\n" + "The method is equivalent to checking whether the \\technologies list is empty.\n" + "\n" + "This method has been introduced in version 0.27" + ) + + gsi::method ("technologies", &db::Library::get_technologies, + "@brief Gets the list of technologies this library is associated with.\n" + "This method has been introduced in version 0.27" ) + gsi::method ("layout_const", (const db::Layout &(db::Library::*)() const) &db::Library::layout, "@brief The layout object where the cells reside that this library defines (const version)\n" diff --git a/src/lay/lay/layLibraryController.cc b/src/lay/lay/layLibraryController.cc index 2636a4ede..36556b05a 100644 --- a/src/lay/lay/layLibraryController.cc +++ b/src/lay/lay/layLibraryController.cc @@ -205,7 +205,7 @@ LibraryController::sync_files () } } - tl::log << "Registering as '" << lib->get_name () << "' for tech '" << lib->get_technology () << "'"; + tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'"; new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ()))); db::LibraryManager::instance ().register_lib (lib.release ()); diff --git a/src/lay/lay/layTechSetupDialog.cc b/src/lay/lay/layTechSetupDialog.cc index e89396411..266c42cf6 100644 --- a/src/lay/lay/layTechSetupDialog.cc +++ b/src/lay/lay/layTechSetupDialog.cc @@ -135,7 +135,7 @@ TechBaseEditorPage::setup () for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) { const db::Library *lib = db::LibraryManager::instance ().lib (l->second); - if (lib->get_technology () == tech ()->name ()) { + if (lib->is_for_technology (tech ()->name ())) { std::string text = lib->get_name (); if (! lib->get_description ().empty ()) { text += " - " + lib->get_description (); diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc index fd9aced34..fa63e5ba0 100644 --- a/src/laybasic/laybasic/layLibrariesView.cc +++ b/src/laybasic/laybasic/layLibrariesView.cc @@ -794,9 +794,10 @@ LibrariesView::display_string (int n) const if (! lib->get_description ().empty ()) { text += " - " + lib->get_description (); } - if (! lib->get_technology ().empty ()) { + if (lib->for_technologies ()) { text += " "; - text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (lib->get_technology ()))); + std::string tn = tl::join (std::vector (lib->get_technologies ().begin (), lib->get_technologies ().end ()), ","); + text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (tn))); } return text; } diff --git a/src/laybasic/laybasic/layWidgets.cc b/src/laybasic/laybasic/layWidgets.cc index ca9da9088..bfa616bb0 100644 --- a/src/laybasic/laybasic/layWidgets.cc +++ b/src/laybasic/laybasic/layWidgets.cc @@ -600,15 +600,16 @@ LibrarySelectionComboBox::update_list () for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) { db::Library *lib = db::LibraryManager::instance ().lib (l->second); - if (! m_tech_set || lib->get_technology ().empty () || m_tech == lib->get_technology ()) { + if (! m_tech_set || !lib->for_technologies ()|| lib->is_for_technology (m_tech)) { std::string item_text = lib->get_name (); if (! lib->get_description ().empty ()) { item_text += " - " + lib->get_description (); } - if (m_tech_set && !lib->get_technology ().empty ()) { + if (m_tech_set && lib->for_technologies ()) { item_text += " "; - item_text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (lib->get_technology ()))); + std::string tn = tl::join (std::vector (lib->get_technologies ().begin (), lib->get_technologies ().end ()), ","); + item_text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (tn))); } addItem (tl::to_qstring (item_text), QVariant ((unsigned int) lib->get_id ())); diff --git a/src/rba/unit_tests/rba.cc b/src/rba/unit_tests/rba.cc index c7ac735e6..75f79c5cd 100644 --- a/src/rba/unit_tests/rba.cc +++ b/src/rba/unit_tests/rba.cc @@ -104,6 +104,7 @@ RUBYTEST (dbGlyphs, "dbGlyphs.rb") RUBYTEST (dbInstanceTest, "dbInstanceTest.rb") RUBYTEST (dbInstElementTest, "dbInstElementTest.rb") RUBYTEST (dbLayerMapping, "dbLayerMapping.rb") +RUBYTEST (dbLibrary, "dbLibrary.rb") RUBYTEST (dbLayout, "dbLayout.rb") RUBYTEST (dbLayoutTest, "dbLayoutTest.rb") RUBYTEST (dbLayoutDiff, "dbLayoutDiff.rb") diff --git a/testdata/ruby/dbLibrary.rb b/testdata/ruby/dbLibrary.rb new file mode 100644 index 000000000..cd73007a5 --- /dev/null +++ b/testdata/ruby/dbLibrary.rb @@ -0,0 +1,93 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2020 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 + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + +class DBLibrary_TestClass < TestBase + + def test_1_registration + + lib = RBA::Library::new + + assert_equal(lib.name, "") + assert_equal(lib.id, 0) + + lib.register("RBA-unit-test") + + assert_equal(lib.name, "RBA-unit-test") + assert_equal(lib.id != 0, true) + + assert_equal(RBA::Library::library_names.member?("RBA-unit-test"), true) + assert_equal(RBA::Library::library_by_name("RBA-unit-test").id, lib.id) + + lib.delete + assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil) + + end + + def test_2_attributes + + lib = RBA::Library::new + + lib.description = "42 is the answer" + assert_equal(lib.description, "42 is the answer") + + assert_equal(lib.is_for_technology("X"), false) + assert_equal(lib.technologies, []) + assert_equal(lib.for_technologies, false) + + lib.technology = "X" + assert_equal(lib.is_for_technology("X"), true) + assert_equal(lib.technologies, ["X"]) + assert_equal(lib.for_technologies, true) + + lib.technology = "" + assert_equal(lib.is_for_technology("X"), false) + assert_equal(lib.technologies, []) + assert_equal(lib.for_technologies, false) + + lib.add_technology("Y") + assert_equal(lib.is_for_technology("X"), false) + assert_equal(lib.is_for_technology("Y"), true) + assert_equal(lib.technologies, ["Y"]) + assert_equal(lib.for_technologies, true) + + lib.clear_technologies + assert_equal(lib.is_for_technology("Y"), false) + assert_equal(lib.technologies, []) + assert_equal(lib.for_technologies, false) + + end + + def test_3_layout + + lib = RBA::Library::new + lib.layout.create_cell("X") + assert_equal(lib.layout.top_cell.name, "X") + + end + +end + +load("test_epilogue.rb") +