From cd1da4495e535c8d4272f1b0a85548e31d1bfa2f Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 12 Oct 2017 21:33:39 +0200 Subject: [PATCH] added latest patch from sss --- RetroShare.pro | 6 - retroshare-gui/src/gui/NetworkDialog.cpp | 150 +------ retroshare-gui/src/gui/NetworkDialog.h | 4 +- .../gui/NetworkDialog/pgpid_item_model.cpp | 375 ++++++++++++++++++ .../src/gui/NetworkDialog/pgpid_item_model.h | 48 +++ .../gui/NetworkDialog/pgpid_item_proxy.cpp | 50 +++ .../src/gui/NetworkDialog/pgpid_item_proxy.h | 23 ++ 7 files changed, 505 insertions(+), 151 deletions(-) create mode 100644 retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.cpp create mode 100644 retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.h create mode 100644 retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.cpp create mode 100644 retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.h diff --git a/RetroShare.pro b/RetroShare.pro index 833173029..d22af1418 100644 --- a/RetroShare.pro +++ b/RetroShare.pro @@ -56,12 +56,6 @@ retroshare_qml_app { } } -retroshare_plugins { - SUBDIRS += plugins - plugins.file = plugins/plugins.pro - plugins.depends = retroshare_gui - plugins.target = plugins -} wikipoos { SUBDIRS += pegmarkdown diff --git a/retroshare-gui/src/gui/NetworkDialog.cpp b/retroshare-gui/src/gui/NetworkDialog.cpp index 76dc61aa4..bc5ea3e06 100644 --- a/retroshare-gui/src/gui/NetworkDialog.cpp +++ b/retroshare-gui/src/gui/NetworkDialog.cpp @@ -71,7 +71,7 @@ #define COLUMN_LAST_USED 5 #define COLUMN_COUNT 6 -RsPeerId getNeighRsCertId(QTreeWidgetItem *i); +//RsPeerId getNeighRsCertId(QTreeWidgetItem *i); /****** * #define NET_DEBUG 1 @@ -88,19 +88,16 @@ NetworkDialog::NetworkDialog(QWidget *parent) connect( ui.filterLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(filterItems(QString))); connect( ui.filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterColumnChanged(int))); - connect( ui.onlyTrustedKeys, SIGNAL(clicked()), this, SLOT(securedUpdateDisplay())); - - -/* compareNetworkRole = new RSTreeWidgetItemCompareRole; - compareNetworkRole->setRole(COLUMN_LAST_USED, ROLE_SORT); */ //list data model float f = QFontMetricsF(font()).height()/14.0 ; PGPIdItemModel = new pgpid_item_model(neighs, f, this); PGPIdItemProxy = new pgpid_item_proxy(this); + connect(ui.onlyTrustedKeys, SIGNAL(toggled(bool)), PGPIdItemProxy, SLOT(use_only_trusted_keys(bool))); PGPIdItemProxy->setSourceModel(PGPIdItemModel); PGPIdItemProxy->setFilterKeyColumn(COLUMN_PEERNAME); PGPIdItemProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); + PGPIdItemProxy->setSortRole(Qt::EditRole); //use edit role to get raw data since we do not have edit for this model. ui.connectTreeWidget->setModel(PGPIdItemProxy); ui.connectTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); ui.connectTreeWidget->verticalHeader()->hide(); @@ -253,7 +250,8 @@ void NetworkDialog::removeUnusedKeys() } QMessageBox::warning(NULL,tr("Keyring info"),tr("Key removal has failed. Your keyring remains intact.\n\nReported error:")+" "+error_string ) ; } - insertConnect() ; + updateDisplay(); +// insertConnect() ; } void NetworkDialog::denyFriend() @@ -346,113 +344,14 @@ void NetworkDialog::copyLink() // /* window will destroy itself! */ //} -/* get the list of Neighbours from the RsIface. */ -void NetworkDialog::insertConnect() -{ -// static time_t last_time = 0 ; - -// if (!rsPeers) -// return; - - //these are GPG ids -// std::list::iterator it; -// rsPeers->getGPGAllList(neighs); - - /* get a link to the table */ -// QTreeView *connectWidget = ui.connectTreeWidget; - /* disable sorting while editing the table */ -// connectWidget->setSortingEnabled(false); - - //remove items -// int index = 0; - -/* for(it = neighs.begin(); it != neighs.end(); ++it) - { -#ifdef NET_DEBUG - std::cerr << "NetworkDialog::insertConnect() inserting gpg key : " << *it << std::endl; -#endif */ - - /** - * Determinated the Background Color - */ -/* QColor backgrndcolor; - - if (detail.accept_connection) - { - if (detail.ownsign) - { - backgrndcolor = backgroundColorOwnSign(); - } - else - { - backgrndcolor = backgroundColorAcceptConnection(); - } - } - else - { - - if (detail.hasSignedMe) - { - backgrndcolor = backgroundColorHasSignedMe(); - } - else - { - backgrndcolor = backgroundColorDenied(); - } - } - - // Color each Background column in the Network Tab except the first one => 1-9 - // whith the determinated color - for(int i = 0; i setBackground(i,QBrush(backgrndcolor)); - - if( (detail.accept_connection || detail.validLvl >= RS_TRUST_LVL_MARGINAL) || !ui.onlyTrustedKeys->isChecked()) - connectWidget->addTopLevelItem(item); */ -// } - - // add self to network. -// RsPeerDetails ownGPGDetails; -// rsPeers->getGPGDetails(rsPeers->getGPGOwnId(), ownGPGDetails); - /* make a widget per friend */ -/* QTreeWidgetItem *self_item; - QList list = connectWidget->findItems(QString::fromStdString(ownGPGDetails.gpg_id.toStdString()), Qt::MatchExactly, COLUMN_PEERID); - if (list.size() == 1) { - self_item = list.front(); - } else { - self_item = new RSTreeWidgetItem(compareNetworkRole, 0); - self_item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); - } - self_item -> setText(COLUMN_CHECK, "0"); - self_item->setIcon(COLUMN_CHECK,(QIcon(IMAGE_AUTHED))); - self_item->setText(COLUMN_PEERNAME, QString::fromUtf8(ownGPGDetails.name.c_str()) + " (" + tr("yourself") + ")"); - self_item->setText(COLUMN_I_AUTH_PEER,"N/A"); - self_item->setText(COLUMN_PEERID, QString::fromStdString(ownGPGDetails.gpg_id.toStdString())); - - // Color each Background column in the Network Tab except the first one => 1-9 - for(int i=0;isetBackground(i,backgroundColorSelf()) ; - } - connectWidget->addTopLevelItem(self_item); */ - - /* enable sorting */ -// connectWidget->setSortingEnabled(true); - /* update display */ -// connectWidget->update(); - -// if (ui.filterLineEdit->text().isEmpty() == false) { -// filterItems(ui.filterLineEdit->text()); -// } - -} /* Utility Fns */ -RsPeerId getNeighRsCertId(QTreeWidgetItem *i) +/*RsPeerId getNeighRsCertId(QTreeWidgetItem *i) { RsPeerId id ( (i -> text(COLUMN_PEERID)).toStdString() ); return id; -} +} */ void NetworkDialog::on_actionAddFriend_activated() { // /* Create a new input dialog, which allows users to create files, too */ @@ -585,42 +484,7 @@ void NetworkDialog::filterColumnChanged(int col) //filterItems(ui.filterLineEdit->text()); } -/*void NetworkDialog::filterItems(const QString &text) -{ - int filterColumn = ui.filterLineEdit->currentFilter(); - int count = ui.connectTreeWidget->topLevelItemCount (); - for (int index = 0; index < count; ++index) { - filterItem(ui.connectTreeWidget->topLevelItem(index), text, filterColumn); - } -}*/ - -bool NetworkDialog::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn) -{ - bool visible = true; - - if (text.isEmpty() == false) { - if (item->text(filterColumn).contains(text, Qt::CaseInsensitive) == false) { - visible = false; - } - } - - int visibleChildCount = 0; - int count = item->childCount(); - for (int index = 0; index < count; ++index) { - if (filterItem(item->child(index), text, filterColumn)) { - ++visibleChildCount; - } - } - - if (visible || visibleChildCount) { - item->setHidden(false); - } else { - item->setHidden(true); - } - - return (visible || visibleChildCount); -} void NetworkDialog::updateDisplay() { diff --git a/retroshare-gui/src/gui/NetworkDialog.h b/retroshare-gui/src/gui/NetworkDialog.h index 084b04126..5c73c0a51 100644 --- a/retroshare-gui/src/gui/NetworkDialog.h +++ b/retroshare-gui/src/gui/NetworkDialog.h @@ -62,7 +62,7 @@ public: void setBackgroundColorDenied(QColor color) { mBackgroundColorDenied = color; } private: - void insertConnect(); +// void insertConnect(); // std::string loadneighbour(); /* void loadneighbour(); */ //void updateNewDiscoveryInfo() ; @@ -116,7 +116,7 @@ private: // class NetworkView *networkview; - bool filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn); +// bool filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn); /* Color definitions (for standard see qss.default) */ QColor mBackgroundColorSelf; diff --git a/retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.cpp b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.cpp new file mode 100644 index 000000000..e6f9eaa90 --- /dev/null +++ b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.cpp @@ -0,0 +1,375 @@ +#include "pgpid_item_model.h" +#include +#include + +#define IMAGE_AUTHED ":/images/accepted16.png" +#define IMAGE_DENIED ":/images/denied16.png" +#define IMAGE_TRUSTED ":/images/rs-2.png" + +/*TODO: + * using list here for internal data storage is not best options +*/ +pgpid_item_model::pgpid_item_model(std::list &neighs_, float &_font_height, QObject *parent) + : QAbstractTableModel(parent), neighs(neighs_), font_height(_font_height) +{ +} + +QVariant pgpid_item_model::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(orientation == Qt::Horizontal) + { + if(role == Qt::ToolTipRole) + { + switch(section) + { + case COLUMN_CHECK: + return QString(tr(" Do you accept connections signed by this profile?")); + break; + case COLUMN_PEERNAME: + return QString(tr("Name of the profile")); + break; + case COLUMN_I_AUTH_PEER: + return QString(tr("This column indicates trust level and whether you signed the profile PGP key")); + break; + case COLUMN_PEER_AUTH_ME: + return QString(tr("Did that peer sign your own profile PGP key")); + break; + case COLUMN_PEERID: + return QString(tr("PGP Key Id of that profile")); + break; + case COLUMN_LAST_USED: + return QString(tr("Last time this key was used (received time, or to check connection)")); + break; + } + } + else if(role == Qt::DisplayRole) + { + switch(section) + { + case COLUMN_CHECK: + return QString(tr("")); + break; + case COLUMN_PEERNAME: + return QString(tr("Profile")); + break; + case COLUMN_I_AUTH_PEER: + return QString(tr("Trust level")); + break; + case COLUMN_PEER_AUTH_ME: + return QString(tr("Has signed your key?")); + break; + case COLUMN_PEERID: + return QString(tr("Id")); + break; + case COLUMN_LAST_USED: + return QString(tr("Last used")); + break; + } + } + else if (role == Qt::TextAlignmentRole) + { + switch(section) + { + default: + return (uint32_t)(Qt::AlignHCenter | Qt::AlignVCenter); + break; + } + } + else if(role == Qt::SizeHintRole) + { + switch(section) + { + case COLUMN_CHECK: + return 25*font_height; + break; + case COLUMN_PEERNAME: case COLUMN_I_AUTH_PEER: case COLUMN_PEER_AUTH_ME: + return 200*font_height; + break; + case COLUMN_LAST_USED: + return 75*font_height; + break; + } + + } + } + return QVariant(); +} + +/*QModelIndex pgpid_item_model::index(int row, int column, const QModelIndex &parent) const +{ + return createIndex(row, column); +}*/ + +/*QModelIndex pgpid_item_model::parent(const QModelIndex &index) const +{ + if(index.row() > -1 && index.column() > -1) + return createIndex(-1, -1); + if (!index.isValid()) + return QModelIndex(); + return QModelIndex(); +}*/ + +/*bool pgpid_item_model::hasChildren(const QModelIndex &parent) const +{ + if(parent.column() == -1 && parent.row() == -1) + return true; + return false; +} */ + +int pgpid_item_model::rowCount(const QModelIndex &/*parent*/) const +{ + return neighs.size(); +} + +int pgpid_item_model::columnCount(const QModelIndex &/*parent*/) const +{ + return COLUMN_COUNT; +} + +//bool pgpid_item_model::insertRows(int position, int rows, const QModelIndex &/*index*/) +//{ +// beginInsertRows(QModelIndex(), position, position+rows-1); +// endInsertRows(); +// return true; +//} + +//bool pgpid_item_model::removeRows(int position, int rows, const QModelIndex &/*index*/) +//{ +// beginRemoveRows(QModelIndex(), position, position+rows-1); +// endRemoveRows(); +// return true; +//} + + +QVariant pgpid_item_model::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if((unsigned)index.row() >= neighs.size()) + return QVariant(); + + + //shit code (please rewrite it) + + std::list::iterator it = neighs.begin(); + for(int i = 0; i < index.row(); i++) + it++; + RsPeerDetails detail; + if (!rsPeers->getGPGDetails(*it, detail)) + return QVariant(); + //shit code end + if(role == Qt::DisplayRole) + { + switch(index.column()) + { + case COLUMN_PEERNAME: + return QString::fromUtf8(detail.name.c_str()); + break; + case COLUMN_PEERID: + return QString::fromStdString(detail.gpg_id.toStdString()); + break; + case COLUMN_I_AUTH_PEER: + { + if (detail.ownsign) + return tr("Personal signature"); + else + { + switch(detail.trustLvl) + { + case RS_TRUST_LVL_MARGINAL: return tr("Marginally trusted peer") ; break; + case RS_TRUST_LVL_FULL: + case RS_TRUST_LVL_ULTIMATE: return tr("Fully trusted peer") ; break ; + case RS_TRUST_LVL_UNKNOWN: + case RS_TRUST_LVL_UNDEFINED: + case RS_TRUST_LVL_NEVER: + default: return tr("Untrusted peer") ; break ; + } + } + } + break; + case COLUMN_PEER_AUTH_ME: + { + if (detail.hasSignedMe) + return tr("Yes"); + else + return tr("No"); + } + break; + case COLUMN_LAST_USED: + { + time_t now = time(NULL); + uint64_t last_time_used = now - detail.lastUsed ; + QString lst_used_str ; + + if(last_time_used < 3600) + lst_used_str = tr("Last hour") ; + else if(last_time_used < 86400) + lst_used_str = tr("Today") ; + else if(last_time_used > 86400 * 15000) + lst_used_str = tr("Never"); + else + lst_used_str = tr("%1 days ago").arg((int)( last_time_used / 86400 )) ; + +// QString lst_used_sort_str = QString::number(detail.lastUsed,'f',10); + + return lst_used_str; +// item->setData(COLUMN_LAST_USED,ROLE_SORT,lst_used_sort_str) ; + } + break; + case COLUMN_CHECK: + { + if (detail.accept_connection) + { + return QString("0"); + } + else + { + return QString("1"); + } + } + break; + + + } + } + else if(role == Qt::ToolTipRole) + { + switch(index.column()) + { + case COLUMN_I_AUTH_PEER: + { + if (detail.ownsign) + return tr("PGP key signed by you"); + } + break; + default: + { + if (!detail.accept_connection && detail.hasSignedMe) + { + return QString::fromUtf8(detail.name.c_str()) + tr(" has authenticated you. \nRight-click and select 'make friend' to be able to connect."); + } + } + break; + + } + } + else if(role == Qt::DecorationRole) + { + switch(index.column()) + { + case COLUMN_CHECK: + { + if (detail.accept_connection) + return QIcon(IMAGE_AUTHED); + else + return QIcon(IMAGE_DENIED); + + } + break; + } + } + else if(role == Qt::BackgroundRole) + { + switch(index.column()) + { + default: + { + //TODO: add access to bckground colors from networkdialog + if (detail.accept_connection) + { + if (detail.ownsign) + ; + } + } + break; + + } + } + + + return QVariant(); +} + +/*void pgpid_item_model::sort(int column, Qt::SortOrder order) +{ + +} */ + + +//following code is just a poc, it's still suboptimal, unefficient, but much better then existing rs code + +void pgpid_item_model::data_updated(std::list &new_neighs) +{ + + //shit code follow (rewrite this please) + size_t old_size = neighs.size(), new_size = 0; + std::list old_neighs = neighs; + + //find all bad elements in list + std::list bad_elements; + for(std::list::iterator it = new_neighs.begin(); it != new_neighs.end(); ++it) + { + if (*it == rsPeers->getGPGOwnId()) + bad_elements.push_back(*it); + RsPeerDetails detail; + if (!rsPeers->getGPGDetails(*it, detail)) + bad_elements.push_back(*it); + + } + //remove all bad elements from list + for(std::list::iterator it = bad_elements.begin(); it != bad_elements.end(); ++it) + { + std::list::iterator it2 = std::find(new_neighs.begin(), new_neighs.end(), *it); + if(it2 != new_neighs.end()) + new_neighs.remove(*it2); + } + new_size = new_neighs.size(); + //set model data to new cleaned up data + neighs = new_neighs; + + //reflect actual row count in model + if(old_size < new_size) + { + beginInsertRows(QModelIndex(), old_size - 1, old_size - 1 + new_size - old_size); + insertRows(old_size - 1 , new_size - old_size); + endInsertRows(); + } + else if(new_size < old_size) + { + beginRemoveRows(QModelIndex(), new_size - 1, new_size - 1 + old_size - new_size); + removeRows(old_size - 1, old_size - new_size); + endRemoveRows(); + } + //update data in ui, to avoid unnecessary redraw and ui updates, updating only changed elements + //i guessing what order is unchanged between rsPeers->getGPGAllList() calls + //TODO: libretroshare should implement a way to obtain only changed elements via some signalling non-blocking api. + { + size_t ii1 = 0; + for(auto i1 = neighs.begin(), end1 = neighs.end(), i2 = old_neighs.begin(), end2 = old_neighs.end(); i1 != end1; ++i1, ++i2, ii1++) + { + if(i2 == end2) + break; + if(*i1 != *i2) + { + QModelIndex topLeft = createIndex(ii1,0), bottomRight = createIndex(ii1, COLUMN_COUNT-1); + emit dataChanged(topLeft, bottomRight); + } + } + } + if(new_size > old_size) + { + QModelIndex topLeft = createIndex(old_size ? old_size -1 : 0 ,0), bottomRight = createIndex(new_size -1, COLUMN_COUNT-1); + emit dataChanged(topLeft, bottomRight); + } + //dirty solution for initial data fetch + //TODO: do it properly! + if(!old_size) + { + beginResetModel(); + endResetModel(); + } + + //shit code end +} + diff --git a/retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.h b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.h new file mode 100644 index 000000000..84bae523b --- /dev/null +++ b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.h @@ -0,0 +1,48 @@ +#ifndef KEY_ITEM_MODEL_H +#define KEY_ITEM_MODEL_H + +#include +#include + +#define COLUMN_CHECK 0 +#define COLUMN_PEERNAME 1 +#define COLUMN_I_AUTH_PEER 2 +#define COLUMN_PEER_AUTH_ME 3 +#define COLUMN_PEERID 4 +#define COLUMN_LAST_USED 5 +#define COLUMN_COUNT 6 + + +class pgpid_item_model : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit pgpid_item_model(std::list &neighs, float &font_height, QObject *parent = nullptr); + + // Header: + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + // Basic functionality: +// QModelIndex index(int row, int column, +// const QModelIndex &parent = QModelIndex()) const override; +// QModelIndex parent(const QModelIndex &index) const override; +// bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; +// bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; +// bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +// void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; +public slots: + void data_updated(std::list &new_neighs); + +private: + std::list &neighs; + float &font_height; +}; + +#endif // KEY_ITEM_MODEL_H diff --git a/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.cpp b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.cpp new file mode 100644 index 000000000..da42db568 --- /dev/null +++ b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.cpp @@ -0,0 +1,50 @@ +#include "pgpid_item_proxy.h" + +pgpid_item_proxy::pgpid_item_proxy(QObject *parent) : + //QAbstractProxyModel(parent) + QSortFilterProxyModel(parent) +{ + +} + + +/*QModelIndex pgpid_item_proxy::mapFromSource(const QModelIndex &sourceIndex) const +{ + if(sourceIndex.isValid()) + return createIndex(sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer()); + else + return QModelIndex(); +} + + +QModelIndex pgpid_item_proxy::mapToSource(const QModelIndex &proxyIndex) const +{ + if(proxyIndex.isValid()) + return sourceModel()->index(proxyIndex.row(), proxyIndex.column()); + else + return QModelIndex();} + + +QModelIndex pgpid_item_proxy::index(int row, int column, const QModelIndex &parent) const +{ + const QModelIndex sourceParent = mapToSource(parent); + const QModelIndex sourceIndex = sourceModel()->index(row, column, sourceParent); + return mapFromSource(sourceIndex); +} + +QModelIndex pgpid_item_proxy::parent(const QModelIndex &child) const +{ + const QModelIndex sourceIndex = mapToSource(child); + const QModelIndex sourceParent = sourceIndex.parent(); + return mapFromSource(sourceParent); +} +int pgpid_item_proxy::rowCount(const QModelIndex &parent) const +{ + //TODO: + return sourceModel()->rowCount(parent); +} +int pgpid_item_proxy::columnCount(const QModelIndex &parent) const +{ + return sourceModel()->columnCount(parent); +} +*/ diff --git a/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.h b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.h new file mode 100644 index 000000000..d33bc9666 --- /dev/null +++ b/retroshare-gui/src/gui/NetworkDialog/pgpid_item_proxy.h @@ -0,0 +1,23 @@ +#ifndef PGPID_ITEM_PROXY_H +#define PGPID_ITEM_PROXY_H + +#include + +class pgpid_item_proxy : + //public QAbstractProxyModel + public QSortFilterProxyModel +{ + Q_OBJECT + +public: + pgpid_item_proxy(QObject *parent = nullptr); +/* virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; + QModelIndex mapToSource(const QModelIndex &proxyIndex) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; +*/ +}; + +#endif // PGPID_ITEM_PROXY_H