WIP: netlist browser

This commit is contained in:
Matthias Koefferlein 2019-04-25 01:23:36 +02:00
parent 5500ca45d8
commit 9ee58b161f
9 changed files with 734 additions and 193 deletions

View File

@ -26,6 +26,7 @@
#include "laySaltDownloadManager.h"
#include "laySalt.h"
#include "layVersion.h"
#include "layItemDelegates.h"
#include "ui_SaltGrainTemplateSelectionDialog.h"
#include "tlString.h"
#include "tlExceptions.h"
@ -59,7 +60,7 @@ public:
m_salt_templates.add_location (":/salt_templates");
salt_view->setModel (new SaltModel (this, &m_salt_templates));
salt_view->setItemDelegate (new SaltItemDelegate (this));
salt_view->setItemDelegate (new lay::HTMLItemDelegate (this));
salt_view->setCurrentIndex (salt_view->model ()->index (0, 0, QModelIndex ()));
}
@ -130,7 +131,7 @@ SaltManagerDialog::SaltManagerDialog (QWidget *parent, lay::Salt *salt, const st
SaltModel *model = new SaltModel (this, mp_salt);
model->set_empty_explanation (tr ("No packages are present on this system"));
salt_view->setModel (model);
salt_view->setItemDelegate (new SaltItemDelegate (this));
salt_view->setItemDelegate (new lay::HTMLItemDelegate (this));
SaltModel *mine_model;
@ -138,13 +139,13 @@ SaltManagerDialog::SaltManagerDialog (QWidget *parent, lay::Salt *salt, const st
mine_model = new SaltModel (this, &m_salt_mine, mp_salt, true);
mine_model->set_empty_explanation (tr ("All available packages are installed"));
salt_mine_view_new->setModel (mine_model);
salt_mine_view_new->setItemDelegate (new SaltItemDelegate (this));
salt_mine_view_new->setItemDelegate (new lay::HTMLItemDelegate (this));
// This model will show only the grains of mp_salt_mine which are present in mp_salt already.
mine_model = new SaltModel (this, &m_salt_mine, mp_salt, false);
mine_model->set_empty_explanation (tr ("No packages are installed"));
salt_mine_view_update->setModel (mine_model);
salt_mine_view_update->setItemDelegate (new SaltItemDelegate (this));
salt_mine_view_update->setItemDelegate (new lay::HTMLItemDelegate (this));
mode_tab->setCurrentIndex (0);

View File

@ -25,84 +25,13 @@
#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);
// let the text take all the available space (fixes #144)
optionV4.showDecorationSelected = true;
bool is_enabled = (optionV4.state & QStyle::State_Enabled);
if ((index.flags () & 0x10000) != 0) {
// the item wants to be drawn "disabled"
is_enabled = false;
}
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),

View File

@ -196,21 +196,6 @@ public:
void create_ordered_list ();
};
// --------------------------------------------------------------------------------------
/**
* @brief A delegate displaying the summary of a grain
*/
class SaltItemDelegate
: public QStyledItemDelegate
{
public:
SaltItemDelegate (QObject *parent);
void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
}
#endif

View File

@ -63,93 +63,15 @@
<property name="spacing">
<number>6</number>
</property>
<item row="2" column="1">
<widget class="QToolButton" name="dir_down_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/down.png</normaloff>:/down.png</iconset>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QToolButton" name="dir_up_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/up.png</normaloff>:/up.png</iconset>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QTreeView" name="directory_tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>4</height>
</size>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>true</bool>
</attribute>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QLabel" name="label">
<property name="text">
<string>Netlist</string>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<item row="3" column="0" colspan="9">
<widget class="QFrame" name="frame_3">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
@ -162,6 +84,28 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="dir_down_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/down.png</normaloff>:/down.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="dir_up_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/up.png</normaloff>:/up.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
@ -210,6 +154,138 @@
</layout>
</widget>
</item>
<item row="2" column="0" colspan="9">
<widget class="QTreeView" name="directory_tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>4</height>
</size>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="4" column="5" colspan="4">
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<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>
</layout>
</widget>
</item>
<item row="1" column="0" colspan="9">
<widget class="QFrame" name="frame_4">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<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="QToolButton" name="backward">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/back_16.png</normaloff>:/back_16.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="forward">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/forward_16.png</normaloff>:/forward_16.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Netlist</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
@ -218,9 +294,6 @@
</widget>
<tabstops>
<tabstop>directory_tree</tabstop>
<tabstop>dir_up_pb</tabstop>
<tabstop>dir_down_pb</tabstop>
<tabstop>filter</tabstop>
</tabstops>
<resources>
<include location="../../lay/lay/layResources.qrc"/>

View File

@ -0,0 +1,193 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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 "layItemDelegates.h"
#include <QApplication>
#include <QTextDocument>
#include <QPainter>
#include <QAbstractTextDocumentLayout>
#include <QAbstractItemView>
namespace lay
{
// --------------------------------------------------------------------------------------
HTMLItemDelegate::HTMLItemDelegate (QObject *parent)
: QStyledItemDelegate (parent)
{
m_icon_margin = 6;
m_icon_spacing = 6;
m_text_margin = 4;
m_text_height = -1;
m_text_width = 500;
m_plain_text = false;
m_anchors_clickable = false;
}
void
HTMLItemDelegate::set_anchors_clickable (bool a)
{
m_anchors_clickable = a;
}
void
HTMLItemDelegate::set_plain_text (bool pt)
{
m_plain_text = pt;
}
void
HTMLItemDelegate::set_icon_margin (int m)
{
m_icon_margin = m;
}
void
HTMLItemDelegate::set_icon_spacing (int s)
{
m_icon_spacing = s;
}
void
HTMLItemDelegate::set_text_margin (int m)
{
m_text_margin = m;
}
void
HTMLItemDelegate::set_text_height (int h)
{
m_text_height = h;
}
void
HTMLItemDelegate::set_text_width (int w)
{
m_text_width = w;
}
void
HTMLItemDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItemV4 option_v4 = option;
initStyleOption (&option_v4, index);
// let the text take all the available space (fixes #144)
option_v4.showDecorationSelected = true;
bool is_enabled = (option_v4.state & QStyle::State_Enabled);
if ((index.flags () & 0x10000) != 0) {
// the item wants to be drawn "disabled"
is_enabled = false;
}
option_v4.state |= QStyle::State_Enabled;
QStyle *style = option_v4.widget ? option_v4.widget->style () : QApplication::style ();
QTextDocument doc;
if (m_plain_text) {
doc.setPlainText (option_v4.text);
} else {
doc.setHtml (option_v4.text);
}
doc.setTextWidth (m_text_width);
doc.setDocumentMargin (m_text_margin);
option_v4.text = QString ();
style->drawControl (QStyle::CE_ItemViewItem, &option_v4, painter);
QAbstractTextDocumentLayout::PaintContext ctx;
if (option_v4.state & QStyle::State_Selected) {
ctx.palette.setColor (QPalette::Text, option_v4.palette.color (QPalette::Active, QPalette::HighlightedText));
} else if (! is_enabled) {
ctx.palette.setColor (QPalette::Text, option_v4.palette.color (QPalette::Disabled, QPalette::Text));
}
QRect text_rect = style->subElementRect (QStyle::SE_ItemViewItemText, &option_v4);
painter->save ();
QPoint tr = text_rect.topLeft ();
painter->translate (tr);
painter->setClipRect (text_rect.translated (-tr));
doc.documentLayout ()->draw (painter, ctx);
painter->restore ();
}
QSize
HTMLItemDelegate::sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItemV4 option_v4 = option;
initStyleOption (&option_v4, index);
const QAbstractItemView *view = dynamic_cast<const QAbstractItemView *> (option_v4.widget);
QSize icon_size (0, 0);
if (view) {
icon_size = view->iconSize ();
}
QTextDocument doc;
if (m_plain_text) {
doc.setPlainText (option_v4.text);
} else {
doc.setHtml (option_v4.text);
}
doc.setTextWidth (m_text_width);
doc.setDocumentMargin (m_text_margin);
bool has_icon = ! option_v4.icon.isNull ();
int th = m_text_height < 0 ? int (doc.size ().height ()) : m_text_height;
return QSize (m_text_width + (has_icon ? icon_size.width () + m_icon_spacing : 0), std::max (has_icon ? icon_size.height () + 2 * m_icon_margin : 0, th));
}
bool
HTMLItemDelegate::editorEvent (QEvent *event, QAbstractItemModel * /*model*/, const QStyleOptionViewItem &option, const QModelIndex &index)
{
if ((event->type () == QEvent::MouseButtonRelease || event->type () == QEvent::MouseButtonPress) && ! m_plain_text && m_anchors_clickable) {
QMouseEvent *mouse_event = static_cast<QMouseEvent *> (event);
QStyleOptionViewItemV4 option_v4 = option;
initStyleOption (&option_v4, index);
QTextDocument doc;
doc.setHtml (option_v4.text);
doc.setTextWidth (m_text_width);
doc.setDocumentMargin (m_text_margin);
QStyle *style = option_v4.widget ? option_v4.widget->style () : QApplication::style ();
QRect text_rect = style->subElementRect (QStyle::SE_ItemViewItemText, &option_v4);
QString a = doc.documentLayout ()->anchorAt (mouse_event->pos () - text_rect.topLeft ());
if (! a.isNull ()) {
if (event->type () == QEvent::MouseButtonRelease) {
emit anchor_clicked (a);
}
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,103 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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_layItemDelegates
#define HDR_layItemDelegates
#include <QStyledItemDelegate>
namespace lay
{
// --------------------------------------------------------------------------------------
/**
* @brief A delegate displaying the display text as HTML formatted text
*/
class HTMLItemDelegate
: public QStyledItemDelegate
{
Q_OBJECT
public:
HTMLItemDelegate (QObject *parent);
virtual void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
virtual QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const;
virtual bool editorEvent (QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
void set_anchors_clickable (bool a);
bool anchors_clickable () const
{
return m_anchors_clickable;
}
void set_icon_margin (int m);
int icon_margin () const
{
return m_icon_margin;
}
void set_icon_spacing (int s);
int icon_spacing () const
{
return m_icon_spacing;
}
void set_text_margin (int m);
int text_margin () const
{
return m_text_margin;
}
void set_text_height (int h);
int text_height () const
{
return m_text_height;
}
void set_text_width (int w);
int text_width () const
{
return m_text_width;
}
void set_plain_text (bool pt);
bool plain_text () const
{
return m_plain_text;
}
signals:
void anchor_clicked (const QString &url);
private:
int m_icon_margin, m_icon_spacing, m_text_margin;
int m_text_width, m_text_height;
bool m_plain_text;
bool m_anchors_clickable;
};
}
#endif

View File

@ -22,9 +22,12 @@
#include "layNetlistBrowserPage.h"
#include "layItemDelegates.h"
#include "dbLayoutToNetlist.h"
#include "dbNetlistDeviceClasses.h"
#include <QUrl>
namespace lay
{
@ -429,6 +432,45 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const
}
}
QString
NetlistBrowserModel::make_link_to (const db::Net *net) const
{
if (! net) {
return QString ();
} else {
void *id = make_id_circuit_net (circuit_index (net->circuit ()), net_index (net));
return tl::to_qstring (tl::sprintf ("<a href='int:net?id=%s'>%s</a>", tl::to_string (reinterpret_cast<size_t> (id)), net->expanded_name ()));
}
}
static
std::string device_string (const db::Device *device)
{
if (! device || ! device->device_class ()) {
return std::string ();
}
std::string s = device->device_class ()->name ();
bool first = true;
const std::vector<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
if (p->is_primary ()) {
if (first) {
s += " [";
first = false;
} else {
s += ", ";
}
s += p->name ();
s += "=";
double v = device->parameter_value (p->id ());
s += tl::to_string (v);
}
}
s += "]";
return s;
}
QString
NetlistBrowserModel::text (const QModelIndex &index) const
{
@ -436,99 +478,152 @@ NetlistBrowserModel::text (const QModelIndex &index) const
if (is_id_circuit (id)) {
db::Circuit *circuit = circuit_from_id (id);
if (circuit) {
return tl::to_qstring (circuit->name ());
// circuit: header column = name, other columns empty
if (index.column () == 0) {
db::Circuit *circuit = circuit_from_id (id);
if (circuit) {
return tl::to_qstring (circuit->name ());
}
}
} else if (is_id_circuit_pin (id) || is_id_circuit_subcircuit_pin (id)) {
db::Pin *pin = pin_from_id (id);
if (pin) {
return tl::to_qstring (pin->expanded_name ());
// circuit/pin: header column = name, other columns empty
if (index.column () == 0) {
db::Pin *pin = pin_from_id (id);
if (pin) {
return tl::to_qstring (pin->expanded_name ());
}
}
} else if (is_id_circuit_pin_net (id)) {
// circuit/pin/net: header column = name, second column link to net
db::Circuit *circuit = circuit_from_id (id);
db::Pin *pin = pin_from_id (id);
if (pin) {
db::Net *net = circuit->net_for_pin (pin->id ());
if (net) {
return tl::to_qstring (net->expanded_name ());
if (index.column () == 0) {
return tl::to_qstring (net->expanded_name ());
} else {
return make_link_to (net);
}
}
}
} else if (is_id_circuit_device (id)) {
// circuit/device: header column = class + parameters, second column device name
db::Device *device = device_from_id (id);
if (device) {
return tl::to_qstring (device->expanded_name ());
if (device && device->device_class ()) {
if (index.column () == 0) {
return tl::to_qstring (device_string (device));
} else {
return tl::to_qstring (device->expanded_name ());
}
}
} else if (is_id_circuit_device_terminal (id)) {
// circuit/device/terminal: header column = terminal name, second column link to net
db::Device *device = device_from_id (id);
if (device && device->device_class ()) {
size_t terminal = circuit_device_terminal_index_from_id (id);
if (device->device_class ()->terminal_definitions ().size () > terminal) {
return tl::to_qstring (device->device_class ()->terminal_definitions () [terminal].name ());
const db::DeviceTerminalDefinition &td = device->device_class ()->terminal_definitions () [terminal];
if (index.column () == 0) {
return tl::to_qstring (td.name ());
} else {
return make_link_to (device->net_for_terminal (td.id ()));
}
}
}
} else if (is_id_circuit_subcircuit (id)) {
// circuit/subcircuit: header column = circuit name, second column subcircuit name
db::SubCircuit *subcircuit = subcircuit_from_id (id);
if (subcircuit) {
return tl::to_qstring (subcircuit->expanded_name ());
if (index.column () == 0) {
return tl::to_qstring (subcircuit->circuit_ref ()->name ());
} else {
return tl::to_qstring (subcircuit->expanded_name ());
}
}
} else if (is_id_circuit_net (id)) {
// circuit/net: header column = node count, second column net name
db::Net *net = net_from_id (id);
if (net) {
return tl::to_qstring (net->expanded_name ());
if (index.column () == 0) {
return tl::to_qstring ("(" + tl::to_string (net->pin_count () + net->terminal_count () + net->subcircuit_pin_count ()) + ")");
} else {
return tl::to_qstring (net->expanded_name ());
}
}
} else if (is_id_circuit_net_pin (id)) {
// circuit/net/pin: header column = pin name, second column empty (for now)
const db::NetPinRef *ref = net_pinref_from_id (id);
if (ref && ref->pin ()) {
return tl::to_qstring (ref->pin ()->expanded_name ());
if (index.column () == 0) {
// TODO: make link to pin
return tl::to_qstring (ref->pin ()->expanded_name ());
}
// TODO: in case of compare use second and third column
}
} else if (is_id_circuit_net_subcircuit_pin (id)) {
// TODO: enhance
const db::NetSubcircuitPinRef *ref = net_subcircuit_pinref_from_id (id);
if (ref && ref->pin ()) {
// TODO: make link to circuit
return tl::to_qstring (ref->pin ()->expanded_name ());
}
} else if (is_id_circuit_net_subcircuit_pin_others (id)) {
// TODO: enhance
const db::NetSubcircuitPinRef *ref = net_subcircuit_pinref_from_id (id);
size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id);
if (ref && ref->pin () && ref->subcircuit () && ref->subcircuit ()->circuit_ref () && ref->subcircuit ()->circuit_ref ()->pin_by_id (other_index)) {
const db::Pin *pin = ref->subcircuit ()->circuit_ref ()->pin_by_id (other_index);
// TODO: make link to pin inside circuit
return tl::to_qstring (pin->expanded_name ());
}
} else if (is_id_circuit_net_device_terminal (id)) {
// circuit/net/device terminal: header column = terminal and device string, second column = device name
const db::NetTerminalRef *ref = net_terminalref_from_id (id);
if (ref && ref->terminal_def ()) {
return tl::to_qstring (ref->terminal_def ()->name ());
if (index.column () == 0) {
return tl::to_qstring (ref->terminal_def ()->name () + " - " + device_string (ref->device ()));
} else {
return tl::to_qstring (ref->device ()->expanded_name ());
}
}
} else if (is_id_circuit_net_device_terminal_others (id)) {
// circuit/net/device terminal/more: header column = terminal name, second column = net link
const db::NetTerminalRef *ref = net_terminalref_from_id (id);
size_t other_index = circuit_net_device_terminal_other_index_from_id (id);
if (ref && ref->device_class () && ref->device_class ()->terminal_definitions ().size () > other_index) {
const db::DeviceTerminalDefinition &def = ref->device_class ()->terminal_definitions ()[other_index];
return tl::to_qstring (def.name ());
if (index.column () == 0) {
return tl::to_qstring (def.name ());
} else {
return make_link_to (ref->device ()->net_for_terminal (def.id ()));
}
}
}
@ -762,6 +857,20 @@ NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) cons
return createIndex (row, column, new_id);
}
QModelIndex
NetlistBrowserModel::index_from_id (void *id, int column) const
{
if (is_id_circuit_net (id)) {
db::Circuit *circuit = circuit_from_id (id);
return createIndex (int (circuit->pin_count () + circuit_net_index_from_id (id)), column, make_id_circuit_net (circuit_index_from_id (id), circuit_net_index_from_id (id)));
}
// TODO: more ...
return QModelIndex ();
}
QModelIndex
NetlistBrowserModel::parent (const QModelIndex &index) const
{
@ -979,6 +1088,38 @@ NetlistBrowserModel::subcircuit_from_id (void *id) const
return attr_by_object_and_index (circuit, index, circuit->begin_subcircuits (), circuit->end_subcircuits (), m_subcircuit_by_circuit_and_index);
}
template <class Attr, class Iter>
static size_t index_from_attr (const Attr *attr, const Iter &begin, const Iter &end, std::map<const Attr *, size_t> &cache)
{
typename std::map<const Attr *, size_t>::iterator cc = cache.find (attr);
if (cc != cache.end ()) {
return cc->second;
}
size_t index = 0;
for (Iter i = begin; i != end; ++i, ++index) {
if (i.operator-> () == attr) {
cache.insert (std::make_pair (i.operator-> (), index));
return index;
}
}
tl_assert (false);
}
size_t
NetlistBrowserModel::circuit_index (const db::Circuit *circuit) const
{
return index_from_attr (circuit, netlist ()->begin_circuits (), netlist ()->end_circuits (), m_circuit_index_by_object);
}
size_t
NetlistBrowserModel::net_index (const db::Net *net) const
{
const db::Circuit *circuit = net->circuit ();
return index_from_attr (net, circuit->begin_nets (), circuit->end_nets (), m_net_index_by_object);
}
// ----------------------------------------------------------------------------------
// NetlistBrowserPage implementation
@ -994,7 +1135,8 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
m_marker_dither_pattern (-1),
mp_view (0),
m_cv_index (0),
mp_plugin_root (0)
mp_plugin_root (0),
m_history_ptr (0)
{
Ui::NetlistBrowserPage::setupUi (this);
@ -1002,8 +1144,26 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
m_show_all_action->setCheckable (true);
m_show_all_action->setChecked (m_show_all);
lay::HTMLItemDelegate *delegate;
delegate = new lay::HTMLItemDelegate (this);
delegate->set_text_margin (2);
delegate->set_anchors_clickable (true);
connect (delegate, SIGNAL (anchor_clicked (const QString &)), this, SLOT (anchor_clicked (const QString &)));
directory_tree->setItemDelegateForColumn (1, delegate);
delegate = new lay::HTMLItemDelegate (this);
delegate->set_text_margin (2);
delegate->set_plain_text (true);
directory_tree->setItemDelegateForColumn (0, delegate);
connect (m_show_all_action, SIGNAL (triggered ()), this, SLOT (show_all_clicked ()));
connect (filter, SIGNAL (textEdited (const QString &)), this, SLOT (filter_changed ()));
connect (forward, SIGNAL (clicked ()), this, SLOT (navigate_forward ()));
connect (backward, SIGNAL (clicked ()), this, SLOT (navigate_back ()));
forward->setEnabled (false);
backward->setEnabled (false);
}
NetlistBrowserPage::~NetlistBrowserPage ()
@ -1057,6 +1217,85 @@ NetlistBrowserPage::set_max_shape_count (size_t max_shape_count)
}
}
void
NetlistBrowserPage::anchor_clicked (const QString &a)
{
QUrl url (a);
QString ids = url.queryItemValue (QString::fromUtf8 ("id"));
if (ids.isEmpty ()) {
return;
}
void *id = reinterpret_cast<void *> (ids.toULongLong ());
navigate_to (id, true);
}
void
NetlistBrowserPage::navigate_to (void *id, bool fwd)
{
NetlistBrowserModel *model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
if (! model) {
return;
}
QModelIndex index = model->index_from_id (id, 0);
if (! index.isValid ()) {
return;
}
directory_tree->setCurrentIndex (index);
add_to_history (id, fwd);
}
void
NetlistBrowserPage::current_index_changed (const QModelIndex &index)
{
if (index.isValid ()) {
printf("@@@1\n"); fflush(stdout);
add_to_history (index.internalPointer (), true);
}
}
void
NetlistBrowserPage::add_to_history (void *id, bool fwd)
{
if (! fwd) {
if (m_history_ptr > 1) {
--m_history_ptr;
m_history [m_history_ptr - 1] = id;
}
} else if (m_history_ptr >= m_history.size ()) {
m_history.push_back (id);
m_history_ptr = m_history.size ();
} else {
if (m_history [m_history_ptr] != id) {
m_history.erase (m_history.begin () + m_history_ptr + 1, m_history.end ());
}
m_history [m_history_ptr] = id;
++m_history_ptr;
}
backward->setEnabled (m_history_ptr > 1);
forward->setEnabled (m_history_ptr < m_history.size ());
}
void
NetlistBrowserPage::navigate_back ()
{
if (m_history_ptr > 1) {
navigate_to (m_history [m_history_ptr - 2], false);
}
}
void
NetlistBrowserPage::navigate_forward ()
{
if (m_history_ptr < m_history.size ()) {
navigate_to (m_history [m_history_ptr]);
}
}
void
NetlistBrowserPage::filter_changed ()
{
@ -1137,6 +1376,7 @@ NetlistBrowserPage::set_l2ndb (db::LayoutToNetlist *database)
NetlistBrowserModel *new_model = new NetlistBrowserModel (directory_tree, database);
directory_tree->setModel (new_model);
connect (directory_tree->selectionModel (), SIGNAL (currentChanged (const QModelIndex &, const QModelIndex &)), this, SLOT (current_index_changed (const QModelIndex &)));
// @@@ connect (directory_tree->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (directory_selection_changed (const QItemSelection &, const QItemSelection &)));
directory_tree->header ()->setSortIndicatorShown (true);

View File

@ -78,8 +78,9 @@ public:
virtual QModelIndex parent (const QModelIndex &index) const;
virtual int rowCount (const QModelIndex &parent) const;
private:
QModelIndex index_from_id (void *id, int column) const;
private:
void *make_id_circuit (size_t circuit_index) const;
void *make_id_circuit_pin (size_t circuit_index, size_t pin_index) const;
void *make_id_circuit_pin_net (size_t circuit_index, size_t pin_index, size_t net_index) const;
@ -128,6 +129,9 @@ private:
db::SubCircuit *subcircuit_from_id (void *id) const;
QString text (const QModelIndex &index) const;
QIcon icon (const QModelIndex &index) const;
size_t circuit_index (const db::Circuit *attr) const;
size_t net_index (const db::Net *attr) const;
QString make_link_to (const db::Net *net) const;
db::Netlist *netlist () const
{
@ -143,6 +147,8 @@ private:
mutable std::map<db::Circuit *, std::map<size_t, db::Device *> > m_device_by_circuit_and_index;
mutable std::map<db::Circuit *, std::map<size_t, db::Pin *> > m_pin_by_circuit_and_index;
mutable std::map<db::Circuit *, std::map<size_t, db::SubCircuit *> > m_subcircuit_by_circuit_and_index;
mutable std::map<const db::Circuit *, size_t> m_circuit_index_by_object;
mutable std::map<const db::Net *, size_t> m_net_index_by_object;
};
/**
@ -239,6 +245,10 @@ public:
private slots:
void show_all_clicked ();
void filter_changed ();
void anchor_clicked (const QString &url);
void navigate_back ();
void navigate_forward ();
void current_index_changed (const QModelIndex &index);
private:
bool m_show_all;
@ -256,6 +266,11 @@ private:
unsigned int m_cv_index;
lay::PluginRoot *mp_plugin_root;
tl::weak_ptr<db::LayoutToNetlist> mp_database;
std::vector<void *> m_history;
size_t m_history_ptr;
void add_to_history (void *id, bool fwd);
void navigate_to (void *id, bool forward = true);
};
} // namespace lay

View File

@ -166,7 +166,8 @@ SOURCES = \
layBackgroundAwareTreeStyle.cc \
layNetlistBrowser.cc \
layNetlistBrowserDialog.cc \
layNetlistBrowserPage.cc
layNetlistBrowserPage.cc \
layItemDelegates.cc
HEADERS = \
gtf.h \
@ -255,7 +256,8 @@ HEADERS = \
layBackgroundAwareTreeStyle.h \
layNetlistBrowser.h \
layNetlistBrowserDialog.h \
layNetlistBrowserPage.h
layNetlistBrowserPage.h \
layItemDelegates.h
INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC