From b8238a85f96046924d110b70e2647a38496d4f7e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 18 Mar 2017 00:22:45 +0100 Subject: [PATCH] WIP: first steps towards package browser --- src/lay/SaltManagerDialog.ui | 199 ++++++++++++++++++--------- src/lay/laySaltManagerDialog.cc | 151 ++++++++++++++++++++ src/laybasic/rdbMarkerBrowserPage.cc | 26 +--- src/tl/tlString.cc | 26 ++++ src/tl/tlString.h | 12 ++ src/unit_tests/tlString.cc | 17 +++ 6 files changed, 346 insertions(+), 85 deletions(-) diff --git a/src/lay/SaltManagerDialog.ui b/src/lay/SaltManagerDialog.ui index 0a97e8cda..4ad0a109b 100644 --- a/src/lay/SaltManagerDialog.ui +++ b/src/lay/SaltManagerDialog.ui @@ -21,6 +21,9 @@ + + 4 + @@ -56,6 +59,9 @@ Qt::NoFocus + + Install Package + ... @@ -76,7 +82,7 @@ 50 - 20 + 0 @@ -86,6 +92,9 @@ Qt::NoFocus + + Create New Package + ... @@ -103,6 +112,9 @@ Qt::NoFocus + + Uninstall Package + ... @@ -115,47 +127,13 @@ - - - - Qt::NoFocus - - - ... - - - - :/new_folder.png:/new_folder.png - - - true - - - - - - - Qt::NoFocus - - - ... - - - - :/rename.png:/rename.png - - - true - - - - + 0 0 @@ -178,15 +156,13 @@ 0 - - - false - - - - 1 - - + + + true + + + true + @@ -214,23 +190,69 @@ QFrame::Raised + + 0 + + + 0 + + + 0 + + + 0 + - - - <html><body><center>No packages are installed currently.<br><br>You can use:<br> + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 218 + 138 + + + + + + + + 0 + 0 + + + + + 200 + 0 + + + + <html><body><center>No packages are installed currently.<br><br>You can use:<br> </center> <table> <tr><td width="30"><a href=":import"><img src=":/import.png"></a></td><td>to import a package from an external source</td></tr> <tr><td><a href=":add"><img src=":/add.png"></a></td><td>to create a new package</td></tr> </table> </body></html> - - - Qt::AlignHCenter|Qt::AlignTop - - - true - + + + Qt::AlignHCenter|Qt::AlignTop + + + true + + + + + @@ -250,13 +272,25 @@ - QFrame::StyledPanel + QFrame::NoFrame QFrame::Raised - - + + + 4 + + + 0 + + + 0 + + + 0 + + @@ -269,13 +303,37 @@ - + + + + Edit Package Details + + + Edit + + + + :/edit.png:/edit.png + + + true + + + + + + + + QDialogButtonBox::Close + + + @@ -336,16 +394,31 @@ - treeWidget + salt_view toolButton_4 toolButton_2 toolButton_3 - toolButton - toolButton_5 textBrowser - + + + buttonBox + clicked(QAbstractButton*) + SaltManagerDialog + accept() + + + 635 + 421 + + + 653 + 432 + + + + diff --git a/src/lay/laySaltManagerDialog.cc b/src/lay/laySaltManagerDialog.cc index f63a236cc..5876a1c7a 100644 --- a/src/lay/laySaltManagerDialog.cc +++ b/src/lay/laySaltManagerDialog.cc @@ -21,15 +21,166 @@ */ #include "laySaltManagerDialog.h" +#include "laySalt.h" +#include "tlString.h" + +#include +#include +#include +#include +#include +#include namespace lay { +class SaltModel + : public QAbstractItemModel +{ +public: + SaltModel (QObject *parent, lay::Salt *salt) + : QAbstractItemModel (parent), mp_salt (salt) + { + // .. nothing yet .. + } + + QVariant data (const QModelIndex &index, int role) const + { + if (role == Qt::DisplayRole) { + + const lay::SaltGrain *g = mp_salt->begin_flat ()[index.row ()]; + + std::string text = ""; + text += "

"; + text += tl::escaped_to_html (g->name ()); + if (!g->version ().empty ()) { + text += " "; + text += tl::escaped_to_html (g->version ()); + } + if (!g->title ().empty ()) { + text += " - "; + text += tl::escaped_to_html (g->title ()); + } + text += "

"; + if (!g->doc ().empty ()) { + text += "

"; + text += tl::escaped_to_html (g->doc ()); + text += "

"; + } + text += ""; + + return tl::to_qstring (text); + + } else { + return QVariant (); + } + } + + QModelIndex index (int row, int column, const QModelIndex &parent) const + { + if (parent.isValid ()) { + return QModelIndex (); + } else { + return createIndex (row, column); + } + } + + QModelIndex parent (const QModelIndex & /*index*/) const + { + return QModelIndex (); + } + + int columnCount(const QModelIndex & /*parent*/) const + { + return 1; + } + + int rowCount (const QModelIndex &parent) const + { + if (parent.isValid ()) { + return 0; + } else { + return mp_salt->end_flat () - mp_salt->begin_flat (); + } + } + +public: + lay::Salt *mp_salt; +}; + +class SaltItemDelegate + : public QStyledItemDelegate +{ +public: + SaltItemDelegate (QObject *parent) + : QStyledItemDelegate (parent) + { + // .. nothing yet .. + } + + void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const + { + QStyleOptionViewItemV4 optionV4 = option; + initStyleOption (&optionV4, index); + + QStyle *style = optionV4.widget ? optionV4.widget->style () : QApplication::style (); + + QTextDocument doc; + doc.setHtml (optionV4.text); + + optionV4.text = QString (); + style->drawControl (QStyle::CE_ItemViewItem, &optionV4, painter); + + QAbstractTextDocumentLayout::PaintContext ctx; + + if (optionV4.state & QStyle::State_Selected) { + ctx.palette.setColor (QPalette::Text, optionV4.palette.color (QPalette::Active, QPalette::HighlightedText)); + } + + QRect textRect = style->subElementRect (QStyle::SE_ItemViewItemText, &optionV4); + painter->save (); + painter->translate (textRect.topLeft ()); + painter->setClipRect (textRect.translated (-textRect.topLeft ())); + doc.documentLayout()->draw (painter, ctx); + painter->restore (); + } + + QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const + { + const int textWidth = 500; + + QStyleOptionViewItemV4 optionV4 = option; + initStyleOption (&optionV4, index); + + QTextDocument doc; + doc.setHtml (optionV4.text); + doc.setTextWidth (textWidth); + return QSize (textWidth, doc.size ().height ()); + } +}; + +// @@@ +lay::Salt salt; +static bool salt_initialized = false; +void make_salt () +{ + if (!salt_initialized) { + salt_initialized = true; + salt.add_location (tl::to_string (QDir::homePath () + QString::fromUtf8("/.klayout/salt"))); + } +} +// @@@ + SaltManagerDialog::SaltManagerDialog (QWidget *parent) : QDialog (parent) { Ui::SaltManagerDialog::setupUi (this); + salt = lay::Salt (); salt_initialized = false; // @@@ + make_salt (); // @@@ + salt_view->setModel (new SaltModel (this, &salt)); + salt_view->setItemDelegate (new SaltItemDelegate (this)); + // ... } diff --git a/src/laybasic/rdbMarkerBrowserPage.cc b/src/laybasic/rdbMarkerBrowserPage.cc index e31087072..f14e57338 100644 --- a/src/laybasic/rdbMarkerBrowserPage.cc +++ b/src/laybasic/rdbMarkerBrowserPage.cc @@ -1820,24 +1820,6 @@ MarkerBrowserPage::set_max_marker_count (size_t max_marker_count) } } -static void -escape_to_html (std::string &out, const std::string &in) -{ - for (const char *cp = in.c_str (); *cp; ++cp) { - if (*cp == '<') { - out += "<"; - } else if (*cp == '>') { - out += ">"; - } else if (*cp == '&') { - out += "&"; - } else if (*cp == '\n') { - out += "
"; - } else { - out += *cp; - } - } -} - void MarkerBrowserPage::enable_updates (bool f) { @@ -1955,13 +1937,13 @@ MarkerBrowserPage::update_info_text () if (category && n_category == 1 && ! category->description ().empty ()) { info += "

"; - escape_to_html (info, category->description ()); + tl::escape_to_html (info, category->description ()); info += "

"; } if (! m_error_text.empty ()) { info += "

"; - escape_to_html (info, m_error_text); + tl::escape_to_html (info, m_error_text); info += "

"; } @@ -1978,7 +1960,7 @@ MarkerBrowserPage::update_info_text () if (v->tag_id () != 0) { const rdb::Tag &tag = mp_database->tags ().tag (v->tag_id ()); info += ""; - escape_to_html (info, tag.name ()); + tl::escape_to_html (info, tag.name ()); info += ":
"; } @@ -1989,7 +1971,7 @@ MarkerBrowserPage::update_info_text () value_string = std::string (value_string.begin (), value_string.begin () + max_length) + "..."; } - escape_to_html (info, value_string); + tl::escape_to_html (info, value_string); info += "
"; diff --git a/src/tl/tlString.cc b/src/tl/tlString.cc index 15aa9d5ef..22d05402f 100644 --- a/src/tl/tlString.cc +++ b/src/tl/tlString.cc @@ -413,6 +413,32 @@ tl::to_word_or_quoted_string (const std::string &s, const char *non_term) } } +void +tl::escape_to_html (std::string &out, const std::string &in, bool replace_newlines) +{ + for (const char *cp = in.c_str (); *cp; ++cp) { + if (*cp == '<') { + out += "<"; + } else if (*cp == '>') { + out += ">"; + } else if (*cp == '&') { + out += "&"; + } else if (replace_newlines && *cp == '\n') { + out += "
"; + } else { + out += *cp; + } + } +} + +std::string +tl::escaped_to_html (const std::string &in, bool replace_newlines) +{ + std::string s; + escape_to_html (s, in, replace_newlines); + return s; +} + void tl::from_string (const std::string &s, const char * &result) { diff --git a/src/tl/tlString.h b/src/tl/tlString.h index 5c9aaf630..6840a7fba 100644 --- a/src/tl/tlString.h +++ b/src/tl/tlString.h @@ -326,6 +326,18 @@ TL_PUBLIC int edit_distance (const std::string &a, const std::string &b); */ TL_PUBLIC std::string to_word_or_quoted_string (const std::string &s, const char *non_term = "_.$"); +/** + * @brief Escapes HTML (or XML) characters from in and adds the result to out + * If "replace_newlines" is true, "\n" will be replaced by "
". + */ +TL_PUBLIC void escape_to_html (std::string &out, const std::string &in, bool replace_newlines = true); + +/** + * @brief Escapes HTML (or XML) characters from in and returns the resulting string + * If "replace_newlines" is true, "\n" will be replaced by "
". + */ +TL_PUBLIC std::string escaped_to_html (const std::string &in, bool replace_newlines = true); + /** * @brief Set the number of digits resolution for a micron display */ diff --git a/src/unit_tests/tlString.cc b/src/unit_tests/tlString.cc index 72a910cda..c4a111a22 100644 --- a/src/unit_tests/tlString.cc +++ b/src/unit_tests/tlString.cc @@ -423,3 +423,20 @@ TEST(10) EXPECT_EQ (unescape_string (escape_string ("'a\n\003")), "'a\n\003"); } +TEST(11) +{ + std::string s; + tl::escape_to_html (s, "x"); + EXPECT_EQ (s, "x"); + tl::escape_to_html (s, "<&>"); + EXPECT_EQ (s, "x<&>"); + s = std::string (); + tl::escape_to_html (s, "a\nb"); + EXPECT_EQ (s, "a
b"); + s = std::string (); + tl::escape_to_html (s, "a\nb", false); + EXPECT_EQ (s, "a\nb"); + EXPECT_EQ (tl::escaped_to_html ("x<&>"), "x<&>"); + EXPECT_EQ (tl::escaped_to_html ("a\nb"), "a
b"); + EXPECT_EQ (tl::escaped_to_html ("a\nb", false), "a\nb"); +}