klayout/src/lay/lay/laySaltModel.cc

476 lines
12 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#include "laySaltModel.h"
#include "laySalt.h"
#include <QIcon>
#include <QPainter>
#include <QAbstractTextDocumentLayout>
#include <QApplication>
#include <QListView>
namespace lay
{
// --------------------------------------------------------------------------------------
SaltItemDelegate::SaltItemDelegate (QObject *parent)
: QStyledItemDelegate (parent)
{
// .. nothing yet ..
}
const int textWidth = 500;
void
SaltItemDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItemV4 optionV4 = option;
initStyleOption (&optionV4, index);
bool is_enabled = (optionV4.state & QStyle::State_Enabled);
optionV4.state |= QStyle::State_Enabled;
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));
} else if (! is_enabled) {
ctx.palette.setColor (QPalette::Text, optionV4.palette.color (QPalette::Disabled, QPalette::Text));
}
QRect textRect = style->subElementRect (QStyle::SE_ItemViewItemText, &optionV4);
painter->save ();
painter->translate (textRect.topLeft ());
painter->setClipRect (textRect.translated (-textRect.topLeft ()));
doc.setTextWidth (textWidth);
doc.documentLayout ()->draw (painter, ctx);
painter->restore ();
}
QSize
SaltItemDelegate::sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItemV4 optionV4 = option;
initStyleOption (&optionV4, index);
const QListView *view = dynamic_cast<const QListView *> (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 + icon_size.width () + 6, std::max (icon_size.height () + 12, int (doc.size ().height ())));
}
// --------------------------------------------------------------------------------------
SaltModel::SaltModel (QObject *parent, lay::Salt *salt, lay::Salt *salt_filtered, bool salt_exclude)
: QAbstractItemModel (parent), mp_salt (salt),
mp_salt_filtered (salt_filtered), m_salt_exclude (salt_exclude),
m_in_update (false)
{
create_ordered_list ();
}
void
SaltModel::set_empty_explanation (const QString &text)
{
m_empty_explanation = text;
}
Qt::ItemFlags
SaltModel::flags (const QModelIndex &index) const
{
Qt::ItemFlags f = QAbstractItemModel::flags (index);
const lay::SaltGrain *g = grain_from_index (index);
if (! g /*|| ! is_enabled (g->name ())*/) {
f &= ~Qt::ItemIsSelectable;
f &= ~Qt::ItemIsEnabled;
}
return f;
}
QVariant
SaltModel::data (const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
const lay::SaltGrain *g = grain_from_index (index);
if (!g) {
return QVariant (tr ("<html><body><h4>There are no items to show in this list</h4><p>%1</p></body></html>").arg (m_empty_explanation));
}
bool en = is_enabled (g->name ());
bool hidden = g->is_hidden ();
std::string text = "<html><body>";
if (! en || hidden) {
text += "<font color=\"#c0c0c0\">";
} else {
text += "<font color=\"#303030\">";
}
if (hidden) {
text += "<i>";
}
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>";
}
std::map<std::string, std::pair<Severity, std::string> >::const_iterator m = m_messages.find (g->name ());
if (m != m_messages.end ()) {
if (m->second.first == Warning || m->second.first == Error) {
text += "<p><font color=\"#ff0000\"><b>" + tl::escaped_to_html (m->second.second) + "</b></font></p>";
} else if (m->second.first == Info) {
text += "<p><font color=\"#c0c0c0\">" + tl::escaped_to_html (m->second.second) + "</font></p>";
} else {
text += "<p>" + tl::escaped_to_html (m->second.second) + "</p>";
}
}
if (hidden) {
text += "<p>";
text += tl::to_string (tr ("This package is an auxiliary package for use with other packages."));
text += "</p></i>";
}
text += "</font>";
text += "</body></html>";
return tl::to_qstring (text);
} else if (role == Qt::DecorationRole) {
int icon_dim = 64;
const lay::SaltGrain *g = grain_from_index (index);
if (!g) {
return QVariant ();
}
QImage img;
if (g->icon ().isNull ()) {
img = QImage (":/salt_icon.png");
} else {
img = g->icon ();
}
if (img.format () != QImage::Format_ARGB32) {
img = img.convertToFormat (QImage::Format_ARGB32);
}
if (img.width () != icon_dim || img.height () != icon_dim) {
QImage scaled = img.scaled (QSize (icon_dim, icon_dim), Qt::KeepAspectRatio, Qt::SmoothTransformation);
img = QImage (icon_dim, icon_dim, QImage::Format_ARGB32);
#if QT_VERSION >= 0x40700
img.fill (QColor (0, 0, 0, 0));
#else
img.fill (0);
#endif
QPainter painter (&img);
painter.drawImage ((icon_dim - scaled.width ()) / 2, (icon_dim - scaled.height ()) / 2, scaled);
}
if (m_marked.find (g->name ()) != m_marked.end ()) {
QPainter painter (&img);
QImage warn (":/marked_64.png");
painter.drawImage (0, 0, warn);
}
std::map<std::string, std::pair<Severity, std::string> >::const_iterator m = m_messages.find (g->name ());
if (m != m_messages.end ()) {
if (m->second.first == Warning) {
QPainter painter (&img);
QImage warn (":/warn_16.png");
painter.drawImage (0, 0, warn);
} else if (m->second.first == Error) {
QPainter painter (&img);
QImage warn (":/error_16.png");
painter.drawImage (0, 0, warn);
} else if (m->second.first == Info) {
QPainter painter (&img);
QImage warn (":/info_16.png");
painter.drawImage (0, 0, warn);
}
}
return QPixmap::fromImage (img);
} else {
return QVariant ();
}
}
QModelIndex
SaltModel::index (int row, int column, const QModelIndex &parent) const
{
if (parent.isValid ()) {
return QModelIndex ();
} else {
return createIndex (row, column);
}
}
QModelIndex
SaltModel::parent (const QModelIndex & /*index*/) const
{
return QModelIndex ();
}
int
SaltModel::columnCount(const QModelIndex & /*parent*/) const
{
return 1;
}
int
SaltModel::rowCount (const QModelIndex &parent) const
{
if (parent.isValid ()) {
return 0;
} else {
return std::max (1, int (m_ordered_grains.size ()));
}
}
SaltGrain *
SaltModel::grain_from_index (const QModelIndex &index) const
{
if (index.isValid () && index.row () >= 0 && index.row () < int (m_ordered_grains.size ())) {
return m_ordered_grains [index.row ()];
} else {
return 0;
}
}
bool
SaltModel::is_marked (const std::string &name) const
{
return m_marked.find (name) != m_marked.end ();
}
bool
SaltModel::is_enabled (const std::string &name) const
{
return m_disabled.find (name) == m_disabled.end ();
}
void
SaltModel::set_marked (const std::string &name, bool marked)
{
if (marked != is_marked (name)) {
if (! marked) {
m_marked.erase (name);
} else {
m_marked.insert (name);
}
emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
}
void
SaltModel::clear_marked ()
{
if (! m_marked.empty ()) {
m_marked.clear ();
emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
}
void
SaltModel::mark_all ()
{
m_marked.clear ();
for (std::vector<SaltGrain *>::const_iterator g = m_ordered_grains.begin (); g != m_ordered_grains.end (); ++g) {
m_marked.insert ((*g)->name ());
}
emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
void
SaltModel::set_enabled (const std::string &name, bool enabled)
{
if (enabled != is_enabled (name)) {
if (enabled) {
m_disabled.erase (name);
} else {
m_disabled.insert (name);
}
emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
}
void
SaltModel::enable_all ()
{
if (! m_disabled.empty ()) {
m_disabled.clear ();
emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
}
void
SaltModel::clear_order ()
{
m_display_order.clear ();
}
void
SaltModel::reset_order (const std::string &name)
{
m_display_order.erase (name);
}
void
SaltModel::set_order (const std::string &name, int order)
{
m_display_order[name] = order;
}
void
SaltModel::set_message (const std::string &name, Severity severity, const std::string &message)
{
bool needs_update = false;
if (message.empty ()) {
if (m_messages.find (name) != m_messages.end ()) {
m_messages.erase (name);
needs_update = true;
}
} else {
std::map<std::string, std::pair<Severity, std::string> >::iterator m = m_messages.find (name);
if (m == m_messages.end () || m->second.second != message || m->second.first != severity) {
m_messages.insert (std::make_pair (name, std::make_pair (severity, message)));
needs_update = true;
}
}
if (needs_update) {
emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
}
void
SaltModel::clear_messages ()
{
if (! m_messages.empty ()) {
m_messages.clear ();
emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
}
void
SaltModel::begin_update ()
{
if (! m_in_update) {
m_ordered_grains.clear ();
beginResetModel ();
m_in_update = true;
}
}
void
SaltModel::update ()
{
begin_update ();
create_ordered_list ();
endResetModel ();
m_in_update = false;
}
void
SaltModel::create_ordered_list ()
{
m_ordered_grains.clear ();
if (m_display_order.empty ()) {
for (Salt::flat_iterator i = mp_salt->begin_flat (); i != mp_salt->end_flat (); ++i) {
// filter the grains by looking them up in the reference salt
if (mp_salt_filtered && (mp_salt_filtered->grain_by_name ((*i)->name ()) != 0) == m_salt_exclude) {
continue;
}
m_ordered_grains.push_back (*i);
}
} else {
int min_order = m_display_order.begin ()->second;
int max_order = min_order;
min_order = std::min (min_order, 0);
max_order = std::max (max_order, 0);
for (std::map<std::string, int>::const_iterator i = m_display_order.begin (); i != m_display_order.end (); ++i) {
min_order = std::min (min_order, i->second);
max_order = std::max (max_order, i->second);
}
for (int o = min_order; o <= max_order; ++o) {
for (Salt::flat_iterator i = mp_salt->begin_flat (); i != mp_salt->end_flat (); ++i) {
// filter the grains by looking them up in the reference salt
if (mp_salt_filtered && (mp_salt_filtered->grain_by_name ((*i)->name ()) != 0) == m_salt_exclude) {
continue;
}
std::map<std::string, int>::const_iterator d = m_display_order.find ((*i)->name ());
int oi = 0;
if (d != m_display_order.end ()) {
oi = d->second;
}
if (oi == o) {
m_ordered_grains.push_back (*i);
}
}
}
}
}
}