syncthingtray/model/syncthingrecentchangesmodel.cpp
Martchus 19bede39a2 Simplify coloring of common ForkAwesome icons
The normal QPalette can be used to determine the icon color so it is
unnecessary to use the flag for custom bright colors here (which is only
intended for colors which are not on the standard QPalette).
2021-10-16 21:20:12 +02:00

239 lines
6.8 KiB
C++

#include "./syncthingrecentchangesmodel.h"
#include "./colors.h"
#include "./syncthingicons.h"
#include <syncthingconnector/syncthingconnection.h>
#include <syncthingconnector/utils.h>
#include <c++utilities/conversion/stringconversion.h>
#include <QStringBuilder>
#include <limits>
using namespace std;
using namespace CppUtilities;
namespace Data {
SyncthingRecentChangesModel::SyncthingRecentChangesModel(SyncthingConnection &connection, int maxRows, QObject *parent)
: SyncthingModel(connection, parent)
, m_maxRows(maxRows)
{
connect(&m_connection, &SyncthingConnection::fileChanged, this, &SyncthingRecentChangesModel::fileChanged);
connect(&m_connection, &SyncthingConnection::statusChanged, this, &SyncthingRecentChangesModel::handleStatusChanged);
}
QHash<int, QByteArray> SyncthingRecentChangesModel::roleNames() const
{
const static QHash<int, QByteArray> roles{
{ Action, "action" },
{ ActionIcon, "actionIcon" },
{ ModifiedBy, "modifiedBy" },
{ DirectoryId, "directoryId" },
{ DirectoryName, "directoryName" },
{ Path, "path" },
{ EventTime, "eventTime" },
{ ExtendedAction, "extendedAction" },
{ ItemType, "itemType" },
};
return roles;
}
const QVector<int> &SyncthingRecentChangesModel::colorRoles() const
{
static const QVector<int> colorRoles({ Qt::DecorationRole, Qt::ForegroundRole, ActionIcon });
return colorRoles;
}
QModelIndex SyncthingRecentChangesModel::index(int row, int column, const QModelIndex &parent) const
{
if (static_cast<size_t>(row) >= m_changes.size() || parent.isValid()) {
return QModelIndex();
}
return createIndex(row, column, static_cast<quintptr>(-1));
}
QModelIndex SyncthingRecentChangesModel::parent(const QModelIndex &child) const
{
Q_UNUSED(child)
return QModelIndex();
}
QVariant SyncthingRecentChangesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
switch (orientation) {
case Qt::Horizontal:
switch (role) {
case Qt::DisplayRole:
switch (section) {
case 0:
return tr("Action");
case 1:
return tr("Device");
case 2:
return tr("Directory");
case 3:
return tr("Path");
}
break;
default:;
}
break;
default:;
}
return QVariant();
}
QVariant SyncthingRecentChangesModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.parent().isValid() || static_cast<size_t>(index.row()) >= m_changes.size()) {
return QVariant();
}
const SyncthingRecentChange &change = m_changes[static_cast<size_t>(index.row())];
switch (role) {
case Qt::DisplayRole:
case Qt::EditRole:
switch (index.column()) {
case 0:
return change.fileChange.action;
case 1:
return change.fileChange.modifiedBy;
case 2:
return change.directoryId;
case 3:
return change.fileChange.path;
}
break;
case Qt::DecorationRole:
case ActionIcon:
switch (index.column()) {
case 0:
return change.fileChange.local ? commonForkAwesomeIcons().home : commonForkAwesomeIcons().globe;
}
break;
case Qt::ToolTipRole:
switch (index.column()) {
case 0:
return QString((change.fileChange.local ? tr("Locally") : tr("Remotely")) % QChar(' ') % change.fileChange.action % QStringLiteral(", ")
% QString::fromStdString(change.fileChange.eventTime.toString(DateTimeOutputFormat::DateAndTime, true)));
case 3:
return change.fileChange.path; // usually too long so add a tooltip
}
break;
case Action:
return change.fileChange.action;
case ModifiedBy:
return change.fileChange.modifiedBy;
case DirectoryId:
return change.directoryId;
case DirectoryName:
return change.directoryName;
case Path:
return change.fileChange.path;
case EventTime:
return QString::fromStdString(change.fileChange.eventTime.toString(DateTimeOutputFormat::DateAndTime, true));
case ExtendedAction: {
auto extendedAction = change.fileChange.action;
extendedAction[0] = extendedAction[0].toUpper();
return QVariant(move(extendedAction));
}
case ItemType:
return change.fileChange.type;
default:;
}
return QVariant();
}
bool SyncthingRecentChangesModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
Q_UNUSED(index)
Q_UNUSED(value)
Q_UNUSED(role)
return false;
}
int SyncthingRecentChangesModel::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid()) {
return static_cast<int>(m_changes.size());
} else {
return 0;
}
}
int SyncthingRecentChangesModel::columnCount(const QModelIndex &parent) const
{
if (!parent.isValid()) {
return 4; // action, device, folder, path
} else {
return 0;
}
}
void SyncthingRecentChangesModel::fileChanged(const SyncthingDir &dir, int index, const SyncthingFileChange &change)
{
Q_UNUSED(index)
if (index >= 0) {
beginInsertRows(QModelIndex(), 0, 0);
}
m_changes.emplace_front(SyncthingRecentChange{
.directoryId = dir.id,
.directoryName = dir.displayName(),
.fileChange = change,
});
if (index >= 0) {
endInsertRows();
}
ensureWithinLimit();
}
void SyncthingRecentChangesModel::handleConfigInvalidated()
{
}
void SyncthingRecentChangesModel::handleNewConfigAvailable()
{
}
void SyncthingRecentChangesModel::handleStatusChanged(SyncthingStatus status)
{
// clear history when re-connecting
// note: This model is independent of changes to the current configuration (it is about the past and not
// the current state) so the re-connect event is used here instead of handleConfigInvalidated()
// and handleNewConfigAvailable() as usual.
if (status != SyncthingStatus::Reconnecting) {
return;
}
beginResetModel();
m_changes.clear();
endResetModel();
}
void SyncthingRecentChangesModel::handleForkAwesomeIconsChanged()
{
invalidateTopLevelIndicies(QVector<int>({ Qt::DecorationRole, ActionIcon }));
}
void SyncthingRecentChangesModel::setMaxRows(int maxRows)
{
m_maxRows = maxRows < 0 ? std::numeric_limits<int>::max() : maxRows;
}
void SyncthingRecentChangesModel::ensureWithinLimit()
{
const auto rowsToDelete = static_cast<int>(m_changes.size()) - m_maxRows;
if (rowsToDelete <= 0) {
return;
}
beginRemoveRows(QModelIndex(), m_maxRows, static_cast<int>(m_changes.size()) - 1);
m_changes.erase(m_changes.begin() + m_maxRows, m_changes.end());
endRemoveRows();
}
} // namespace Data