RetroShare/retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.cpp

365 lines
11 KiB
C++

/*******************************************************************************
* retroshare-gui/src/gui/NetworkDialog/pgpid_item_model.cpp *
* *
* Copyright (C) 2018 by Retroshare Team <retroshare.project@gmail.com> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "pgpid_item_model.h"
#include <time.h>
#include <retroshare/rspeers.h>
#include <QIcon>
#include <QBrush>
/*TODO:
* using list here for internal data storage is not best option
*/
pgpid_item_model::pgpid_item_model(std::list<RsPgpId> &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 the trust level you indicated 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("Connections"));
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();
}
int pgpid_item_model::rowCount(const QModelIndex &/*parent*/) const
{
return neighs.size();
}
int pgpid_item_model::columnCount(const QModelIndex &/*parent*/) const
{
return COLUMN_COUNT;
}
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<RsPgpId>::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::EditRole) //some columns return raw data for editrole, used for proper filtering and sorting
{
switch(index.column())
{
case COLUMN_LAST_USED:
return detail.lastUsed;
break;
case COLUMN_I_AUTH_PEER:
{
if (detail.ownsign)
return RS_TRUST_LVL_ULTIMATE;
return detail.trustLvl;
}
break;
case COLUMN_PEER_AUTH_ME:
return detail.hasSignedMe;
break;
case COLUMN_CHECK:
return detail.accept_connection;
break;
default:
break;
}
}
//we using editrole only where it is useful, for other data we use display, so no "else if" here
if(role == Qt::DisplayRole || role == Qt::EditRole)
{
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 )) ;
return lst_used_str;
}
break;
case COLUMN_CHECK:
{
if (detail.accept_connection || rsPeers->getGPGOwnId() == detail.gpg_id)
return tr("Accepted");
else
return tr("Denied");
}
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)
{
if (detail.accept_connection)
{
if (detail.ownsign)
{
return QBrush(mBackgroundColorOwnSign);
}
else
{
return QBrush(mBackgroundColorAcceptConnection);
}
}
else
{
if (detail.hasSignedMe)
{
return QBrush(mBackgroundColorHasSignedMe);
}
else
{
return QBrush(mBackgroundColorDenied);
}
}
}
return QVariant();
}
//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<RsPgpId> &new_neighs)
{
//shit code follow (rewrite this please)
size_t old_size = neighs.size(), new_size = 0;
std::list<RsPgpId> old_neighs = neighs;
new_size = new_neighs.size();
//set model data to new cleaned up data
neighs = new_neighs;
neighs.sort();
neighs.unique(); //remove possible dups
//reflect actual row count in model
if(old_size < new_size)
{
beginInsertRows(QModelIndex(), old_size, new_size);
insertRows(old_size, new_size - old_size);
endInsertRows();
}
else if(new_size < old_size)
{
beginRemoveRows(QModelIndex(), new_size, old_size);
removeRows(old_size, old_size - new_size);
endRemoveRows();
}
//update data in ui, to avoid unnecessary redraw and ui updates, updating only changed elements
//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
}