+
+namespace lay
+{
+
+SaltGrainDetailsTextWidget::SaltGrainDetailsTextWidget (QWidget *w)
+ : QTextBrowser (w), mp_grain (0)
+{
+ // .. nothing yet ..
+}
+
+void SaltGrainDetailsTextWidget::set_grain (SaltGrain *g)
+{
+ if (mp_grain != g) {
+ mp_grain = g;
+ setHtml (details_text ());
+ }
+}
+
+QVariant
+SaltGrainDetailsTextWidget::loadResource (int type, const QUrl &url)
+{
+ if (url.path () == QString::fromUtf8 ("/icon")) {
+ // @@@
+ return QImage (":/salt_icon.png");
+ // @@@
+ } else {
+ return QTextBrowser::loadResource (type, url);
+ }
+}
+
+QString
+SaltGrainDetailsTextWidget::details_text ()
+{
+ SaltGrain *g = mp_grain;
+ if (! g) {
+ return QString ();
+ }
+
+ QBuffer buffer;
+ buffer.open (QIODevice::WriteOnly);
+ QTextStream stream (&buffer);
+ stream.setCodec ("UTF-8");
+
+ stream << "";
+
+ stream << "";
+ stream << " | ";
+ stream << "";
+ stream << "";
+ stream << tl::to_qstring (tl::escaped_to_html (g->name ())) << " " << tl::to_qstring (tl::escaped_to_html (g->version ()));
+ stream << "";
+ if (! g->title ().empty()) {
+ stream << "" << tl::to_qstring (tl::escaped_to_html (g->title ())) << "";
+ }
+
+ if (g->version ().empty ()) {
+ stream << "";
+ stream << QObject::tr ("This package does not have a version. "
+ "Use the <version> element of the specification file or edit the package properties to provide a version.");
+ stream << " ";
+ }
+
+ if (g->title ().empty ()) {
+ stream << "";
+ stream << QObject::tr ("This package does not have a title. "
+ "Use the <title> element of the specification file or edit the package properties to provide a title.");
+ stream << " ";
+ }
+
+ stream << " |
";
+
+ stream << "
";
+ if (! g->doc ().empty ()) {
+ stream << tl::to_qstring (tl::escaped_to_html (g->doc ()));
+ } else {
+ stream << "";
+ stream << QObject::tr ("This package does not have a description. "
+ "Use the <doc> element of the specification file or edit the package properties to provide a description.");
+ stream << "";
+ }
+ stream << "
";
+
+ stream << "";
+ if (! g->author ().empty ()) {
+ stream << "" << QObject::tr ("Author") << ": " << tl::to_qstring (tl::escaped_to_html (g->author ())) << " ";
+ if (! g->author_contact ().empty ()) {
+ stream << "(" << tl::to_qstring (tl::escaped_to_html (g->author_contact ())) << ")";
+ }
+ if (!g->authored_time ().isNull ()) {
+ stream << "
";
+ stream << "" << QObject::tr ("Released") << ": " << g->authored_time ().date ().toString (Qt::ISODate);
+ }
+ } else {
+ stream << "";
+ stream << QObject::tr ("This package does not have a author information. "
+ "Use the <author>, <authored-time> and <author-contact> elements of the specification file or edit the package properties to provide authoring information.");
+ stream << "";
+ }
+ stream << "
";
+
+ stream << "";
+ if (! g->url ().empty ()) {
+ stream << "" << QObject::tr ("Documentation link") << ": url ()) << "\">" << tl::to_qstring (tl::escaped_to_html (g->url ())) << "";
+ } else {
+ stream << "";
+ stream << QObject::tr ("This package does not have a documentation link. "
+ "Use the <url> element of the specification file or edit the package properties to provide a link.");
+ stream << "";
+ }
+ stream << "
";
+
+ stream << "";
+
+ stream.flush ();
+
+ return QString::fromUtf8 (buffer.buffer());
+}
+
+}
diff --git a/src/lay/laySaltGrainDetailsTextWidget.h b/src/lay/laySaltGrainDetailsTextWidget.h
new file mode 100644
index 000000000..bb25a0e48
--- /dev/null
+++ b/src/lay/laySaltGrainDetailsTextWidget.h
@@ -0,0 +1,61 @@
+
+/*
+
+ KLayout Layout Viewer
+ Copyright (C) 2006-2017 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
+
+*/
+
+#ifndef HDR_laySaltGrainDetailsTextWidget
+#define HDR_laySaltGrainDetailsTextWidget
+
+#include
+
+namespace lay
+{
+
+class SaltGrain;
+
+/**
+ * @brief A specialisation of QTextBrowser that displays the details of the salt grain
+ */
+class SaltGrainDetailsTextWidget
+ : public QTextBrowser
+{
+public:
+ /**
+ * @brief Constructor
+ */
+ SaltGrainDetailsTextWidget (QWidget *w);
+
+ /**
+ * @brief Sets the grain whose details are to be shown
+ */
+ void set_grain (SaltGrain *g);
+
+protected:
+ virtual QVariant loadResource (int type, const QUrl &url);
+
+private:
+ lay::SaltGrain *mp_grain;
+
+ QString details_text ();
+};
+
+}
+
+#endif
diff --git a/src/lay/laySaltGrains.cc b/src/lay/laySaltGrains.cc
index a40bcea64..9c17944c6 100644
--- a/src/lay/laySaltGrains.cc
+++ b/src/lay/laySaltGrains.cc
@@ -112,7 +112,15 @@ SaltGrains::remove_grain (grain_iterator iter, bool with_files)
bool
SaltGrains::is_empty () const
{
- return m_collections.empty () && m_grains.empty ();
+ if (! m_grains.empty ()) {
+ return false;
+ }
+ for (collections_type::const_iterator i = m_collections.begin (); i != m_collections.end (); ++i) {
+ if (!i->is_empty ()) {
+ return false;
+ }
+ }
+ return true;
}
bool
diff --git a/src/lay/laySaltManagerDialog.cc b/src/lay/laySaltManagerDialog.cc
index 5876a1c7a..9606164f3 100644
--- a/src/lay/laySaltManagerDialog.cc
+++ b/src/lay/laySaltManagerDialog.cc
@@ -30,10 +30,17 @@
#include
#include
#include
+#include
+#include
namespace lay
{
+// --------------------------------------------------------------------------------------
+
+/**
+ * @brief A model representing the salt grains for a QListView
+ */
class SaltModel
: public QAbstractItemModel
{
@@ -71,6 +78,12 @@ public:
return tl::to_qstring (text);
+ } else if (role == Qt::DecorationRole) {
+
+ // @@@
+ return QIcon (":/salt_icon.png");
+ // @@@
+
} else {
return QVariant ();
}
@@ -81,7 +94,7 @@ public:
if (parent.isValid ()) {
return QModelIndex ();
} else {
- return createIndex (row, column);
+ return createIndex (row, column, mp_salt->begin_flat () [row]);
}
}
@@ -104,10 +117,29 @@ public:
}
}
+ SaltGrain *grain_from_index (const QModelIndex &index) const
+ {
+ if (index.isValid ()) {
+ return static_cast (index.internalPointer ());
+ } else {
+ return 0;
+ }
+ }
+
+ void update ()
+ {
+ // @@@
+ }
+
public:
lay::Salt *mp_salt;
};
+// --------------------------------------------------------------------------------------
+
+/**
+ * @brief A delegate displaying the summary of a grain
+ */
class SaltItemDelegate
: public QStyledItemDelegate
{
@@ -152,13 +184,22 @@ public:
QStyleOptionViewItemV4 optionV4 = option;
initStyleOption (&optionV4, index);
+ const QListView *view = dynamic_cast (optionV4.widget);
+ QSize icon_size (0, 0);
+ if (view) {
+ icon_size = view->iconSize ();
+ }
+
QTextDocument doc;
doc.setHtml (optionV4.text);
doc.setTextWidth (textWidth);
- return QSize (textWidth, doc.size ().height ());
+ return QSize (textWidth + icon_size.width () + 6, std::max (icon_size.height () + 12, int (doc.size ().height ())));
}
};
+// --------------------------------------------------------------------------------------
+// SaltManager implementation
+
// @@@
lay::Salt salt;
static bool salt_initialized = false;
@@ -172,16 +213,76 @@ void make_salt ()
// @@@
SaltManagerDialog::SaltManagerDialog (QWidget *parent)
- : QDialog (parent)
+ : QDialog (parent),
+ m_current_changed_enabled (true)
{
Ui::SaltManagerDialog::setupUi (this);
- salt = lay::Salt (); salt_initialized = false; // @@@
- make_salt (); // @@@
- salt_view->setModel (new SaltModel (this, &salt));
+// @@@
+ salt = lay::Salt (); salt_initialized = false;
+ make_salt ();
+ mp_salt = &salt;
+// @@@
+
+ SaltModel *model = new SaltModel (this, mp_salt);
+ salt_view->setModel (model);
salt_view->setItemDelegate (new SaltItemDelegate (this));
+ connect (mp_salt, SIGNAL (collections_changed ()), this, SLOT (salt_changed ()));
+
+ // select the first grain
+ if (model->rowCount (QModelIndex ()) > 0) {
+ salt_view->setCurrentIndex (model->index (0, 0, QModelIndex ()));
+ }
+
+ salt_changed ();
+
+ connect (salt_view->selectionModel (), SIGNAL (currentChanged (const QModelIndex &, const QModelIndex &)), this, SLOT (current_changed ()));
+
+
// ...
}
+void
+SaltManagerDialog::salt_changed ()
+{
+ SaltModel *model = dynamic_cast (salt_view->model ());
+ if (! model) {
+ return;
+ }
+
+ m_current_changed_enabled = false;
+ model->update ();
+ m_current_changed_enabled = true;
+
+ if (mp_salt->is_empty ()) {
+ list_stack->setCurrentIndex (1);
+ details_frame->hide ();
+ } else {
+ list_stack->setCurrentIndex (0);
+ details_frame->show ();
+ }
+
+ current_changed ();
+}
+
+void
+SaltManagerDialog::current_changed ()
+{
+ SaltModel *model = dynamic_cast (salt_view->model ());
+ if (! model) {
+ return;
+ }
+
+ SaltGrain *g = model->grain_from_index (salt_view->currentIndex ());
+ details_text->set_grain (g);
+ if (!g) {
+ details_frame->setEnabled (false);
+ delete_button->setEnabled (false);
+ } else {
+ details_frame->setEnabled (true);
+ delete_button->setEnabled (true);
+ }
+}
+
}
diff --git a/src/lay/laySaltManagerDialog.h b/src/lay/laySaltManagerDialog.h
index 42e59a993..24b55a62e 100644
--- a/src/lay/laySaltManagerDialog.h
+++ b/src/lay/laySaltManagerDialog.h
@@ -30,18 +30,37 @@
namespace lay
{
+class Salt;
+class SaltGrain;
+
/**
* @brief The dialog for managing the Salt ("Packages")
*/
class SaltManagerDialog
: public QDialog, private Ui::SaltManagerDialog
{
+Q_OBJECT
+
public:
/**
* @brief Constructor
*/
SaltManagerDialog (QWidget *parent);
+private slots:
+ /**
+ * @brief Called when the list of packages (grains) has changed
+ */
+ void salt_changed ();
+
+ /**
+ * @brief Called when the currently selected package (grain) has changed
+ */
+ void current_changed ();
+
+private:
+ lay::Salt *mp_salt;
+ bool m_current_changed_enabled;
};
}
diff --git a/src/unit_tests/laySalt.cc b/src/unit_tests/laySalt.cc
index 2d761ed62..75d7986ca 100644
--- a/src/unit_tests/laySalt.cc
+++ b/src/unit_tests/laySalt.cc
@@ -72,7 +72,20 @@ static std::string salt_to_string (lay::Salt &salt)
TEST (1)
{
+ std::string tmp0 = tmp_file ("tmp0");
+
lay::SaltGrain g;
+ g.save (tmp0);
+ EXPECT_EQ (g.authored_time ().isNull (), true);
+ EXPECT_EQ (g.installed_time ().isNull (), true);
+
+ lay::SaltGrain g0;
+ g0.load (tmp0);
+ EXPECT_EQ (g0.authored_time ().isNull (), true);
+ EXPECT_EQ (g0.installed_time ().isNull (), true);
+ EXPECT_EQ (g == g0, true);
+
+ std::string tmp = tmp_file ();
g.set_name ("abc");
EXPECT_EQ (g.name (), "abc");
@@ -86,6 +99,20 @@ TEST (1)
EXPECT_EQ (g.title (), "title");
g.set_doc ("doc");
EXPECT_EQ (g.doc (), "doc");
+ g.set_author ("me");
+ EXPECT_EQ (g.author (), "me");
+ g.set_author_contact ("ac");
+ EXPECT_EQ (g.author_contact (), "ac");
+ g.set_license ("free");
+ EXPECT_EQ (g.license (), "free");
+ g.set_authored_time (QDateTime ());
+ EXPECT_EQ (g.authored_time ().isNull (), true);
+ g.set_authored_time (QDateTime::fromMSecsSinceEpoch (1000000000));
+ EXPECT_EQ (QDateTime::fromMSecsSinceEpoch (0).msecsTo (g.authored_time ()), 1000000000);
+ g.set_installed_time (QDateTime ());
+ EXPECT_EQ (g.installed_time ().isNull (), true);
+ g.set_installed_time (QDateTime::fromMSecsSinceEpoch (2000000000));
+ EXPECT_EQ (QDateTime::fromMSecsSinceEpoch (0).msecsTo (g.installed_time ()), 2000000000);
g.add_dependency (lay::SaltGrain::Dependency ());
g.dependencies ().back ().name = "depname";
@@ -105,8 +132,6 @@ TEST (1)
gg.set_doc ("blabla");
EXPECT_EQ (g == gg, false);
- std::string tmp = tmp_file ();
-
EXPECT_EQ (g == gg, false);
g.save (tmp);
@@ -269,11 +294,14 @@ TEST (4)
// That's the main test part
lay::Salt salt;
+ EXPECT_EQ (salt.is_empty (), true);
+
QSignalSpy spy (&salt, SIGNAL (collections_changed ()));
EXPECT_EQ (salt_to_string (salt), "[]");
spy.clear ();
salt.add_location (tl::to_string (tmp_dir.path ()));
+ EXPECT_EQ (salt.is_empty (), false);
EXPECT_EQ (spy.count (), 1);
EXPECT_EQ (salt_to_string (salt), "[a,b,c/c/v,c/u]");