WIP: first steps towards package browser

This commit is contained in:
Matthias Koefferlein 2017-03-18 00:22:45 +01:00
parent 695a5d3169
commit b8238a85f9
6 changed files with 346 additions and 85 deletions

View File

@ -21,6 +21,9 @@
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="rightMargin">
<number>4</number>
</property>
<item>
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
@ -56,6 +59,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Install Package</string>
</property>
<property name="text">
<string>...</string>
</property>
@ -76,7 +82,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>50</width>
<height>20</height>
<height>0</height>
</size>
</property>
</spacer>
@ -86,6 +92,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Create New Package</string>
</property>
<property name="text">
<string>...</string>
</property>
@ -103,6 +112,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Uninstall Package</string>
</property>
<property name="text">
<string>...</string>
</property>
@ -115,47 +127,13 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="layResources.qrc">
<normaloff>:/new_folder.png</normaloff>:/new_folder.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton_5">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="layResources.qrc">
<normaloff>:/rename.png</normaloff>:/rename.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -178,15 +156,13 @@
<number>0</number>
</property>
<item>
<widget class="QTreeWidget" name="treeWidget">
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
<widget class="QListView" name="salt_view">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionRectVisible">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
@ -214,23 +190,69 @@
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;body&gt;&lt;center&gt;No packages are installed currently.&lt;br&gt;&lt;br&gt;You can use:&lt;br&gt;
<widget class="QScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>218</width>
<height>138</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>&lt;html&gt;&lt;body&gt;&lt;center&gt;No packages are installed currently.&lt;br&gt;&lt;br&gt;You can use:&lt;br&gt;
&lt;/center&gt;
&lt;table&gt;
&lt;tr&gt;&lt;td width=&quot;30&quot;&gt;&lt;a href=&quot;:import&quot;&gt;&lt;img src=&quot;:/import.png&quot;&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;to import a package from an external source&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;:add&quot;&gt;&lt;img src=&quot;:/add.png&quot;&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;to create a new package&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
@ -250,13 +272,25 @@
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
@ -269,13 +303,37 @@
</property>
</widget>
</item>
<item>
<item row="0" column="1">
<widget class="QToolButton" name="edit_button">
<property name="toolTip">
<string>Edit Package Details</string>
</property>
<property name="text">
<string>Edit</string>
</property>
<property name="icon">
<iconset resource="layResources.qrc">
<normaloff>:/edit.png</normaloff>:/edit.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTextBrowser" name="textBrowser"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
<action name="actionNewFolder">
<property name="icon">
@ -336,16 +394,31 @@
</action>
</widget>
<tabstops>
<tabstop>treeWidget</tabstop>
<tabstop>salt_view</tabstop>
<tabstop>toolButton_4</tabstop>
<tabstop>toolButton_2</tabstop>
<tabstop>toolButton_3</tabstop>
<tabstop>toolButton</tabstop>
<tabstop>toolButton_5</tabstop>
<tabstop>textBrowser</tabstop>
</tabstops>
<resources>
<include location="layResources.qrc"/>
</resources>
<connections/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>clicked(QAbstractButton*)</signal>
<receiver>SaltManagerDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>635</x>
<y>421</y>
</hint>
<hint type="destinationlabel">
<x>653</x>
<y>432</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -21,15 +21,166 @@
*/
#include "laySaltManagerDialog.h"
#include "laySalt.h"
#include "tlString.h"
#include <QAbstractItemModel>
#include <QAbstractTextDocumentLayout>
#include <QStyledItemDelegate>
#include <QTextDocument>
#include <QPainter>
#include <QDir>
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 = "<html><body>";
text += "<h4>";
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 += "</h4>";
if (!g->doc ().empty ()) {
text += "<p>";
text += tl::escaped_to_html (g->doc ());
text += "</p>";
}
text += "</body></html>";
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));
// ...
}

View File

@ -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 += "&lt;";
} else if (*cp == '>') {
out += "&gt;";
} else if (*cp == '&') {
out += "&amp;";
} else if (*cp == '\n') {
out += "<br/>";
} 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 += "<p style=\"color:blue; font-weight: bold\">";
escape_to_html (info, category->description ());
tl::escape_to_html (info, category->description ());
info += "</p>";
}
if (! m_error_text.empty ()) {
info += "<p style=\"color:red; font-weight: bold\">";
escape_to_html (info, m_error_text);
tl::escape_to_html (info, m_error_text);
info += "</p>";
}
@ -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 += "<b>";
escape_to_html (info, tag.name ());
tl::escape_to_html (info, tag.name ());
info += ":</br> ";
}
@ -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 += "<br/>";

View File

@ -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 += "&lt;";
} else if (*cp == '>') {
out += "&gt;";
} else if (*cp == '&') {
out += "&amp;";
} else if (replace_newlines && *cp == '\n') {
out += "<br/>";
} 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)
{

View File

@ -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 "<br/>".
*/
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 "<br/>".
*/
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
*/

View File

@ -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&lt;&amp;&gt;");
s = std::string ();
tl::escape_to_html (s, "a\nb");
EXPECT_EQ (s, "a<br/>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&lt;&amp;&gt;");
EXPECT_EQ (tl::escaped_to_html ("a\nb"), "a<br/>b");
EXPECT_EQ (tl::escaped_to_html ("a\nb", false), "a\nb");
}