Skip to content

Commit

Permalink
Protocol: Introduce context menu with "open in browser" #6121
Browse files Browse the repository at this point in the history
To do this conveniently a bunch of functionality that's common to
IssueWidget and ProtocolWidget is moved to ProtocolItem.

Also the convenience function to asynchronously retrieve the private
link url is moved from the socket api to the network jobs.
  • Loading branch information
ckamm committed Nov 8, 2017
1 parent d903afc commit b757eff
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 98 deletions.
22 changes: 17 additions & 5 deletions src/gui/issueswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "common/syncjournalfilerecord.h"
#include "elidedlabel.h"


#include "ui_issueswidget.h"

#include <climits>
Expand All @@ -54,6 +55,9 @@ IssuesWidget::IssuesWidget(QWidget *parent)
connect(_ui->_treeWidget, &QTreeWidget::itemActivated, this, &IssuesWidget::slotOpenFile);
connect(_ui->copyIssuesButton, &QAbstractButton::clicked, this, &IssuesWidget::copyToClipboard);

_ui->_treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(_ui->_treeWidget, &QTreeWidget::customContextMenuRequested, this, &IssuesWidget::slotItemContextMenu);

connect(_ui->showIgnores, &QAbstractButton::toggled, this, &IssuesWidget::slotRefreshIssues);
connect(_ui->showWarnings, &QAbstractButton::toggled, this, &IssuesWidget::slotRefreshIssues);
connect(_ui->filterAccount, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &IssuesWidget::slotRefreshIssues);
Expand Down Expand Up @@ -85,7 +89,7 @@ IssuesWidget::IssuesWidget(QWidget *parent)
_ui->_treeWidget->setHeaderLabels(header);
int timestampColumnWidth =
ActivityItemDelegate::rowHeight() // icon
+ _ui->_treeWidget->fontMetrics().width(ProtocolWidget::timeString(QDateTime::currentDateTime()))
+ _ui->_treeWidget->fontMetrics().width(ProtocolItem::timeString(QDateTime::currentDateTime()))
+ timestampColumnExtra;
_ui->_treeWidget->setColumnWidth(0, timestampColumnWidth);
_ui->_treeWidget->setColumnWidth(1, 180);
Expand Down Expand Up @@ -198,7 +202,7 @@ void IssuesWidget::slotItemCompleted(const QString &folder, const SyncFileItemPt
{
if (!item->hasErrorStatus())
return;
QTreeWidgetItem *line = ProtocolWidget::createCompletedTreewidgetItem(folder, *item);
QTreeWidgetItem *line = ProtocolItem::create(folder, *item);
if (!line)
return;
addItem(line);
Expand Down Expand Up @@ -233,6 +237,14 @@ void IssuesWidget::slotAccountRemoved(AccountState *account)
updateAccountChoiceVisibility();
}

void IssuesWidget::slotItemContextMenu(const QPoint &pos)
{
auto item = _ui->_treeWidget->itemAt(pos);
if (!item)
return;
ProtocolItem::openContextMenu(item, this);
}

void IssuesWidget::updateAccountChoiceVisibility()
{
bool visible = _ui->filterAccount->count() > 2;
Expand Down Expand Up @@ -373,8 +385,8 @@ void IssuesWidget::addError(const QString &folderAlias, const QString &message,

QStringList columns;
QDateTime timestamp = QDateTime::currentDateTime();
const QString timeStr = ProtocolWidget::timeString(timestamp);
const QString longTimeStr = ProtocolWidget::timeString(timestamp, QLocale::LongFormat);
const QString timeStr = ProtocolItem::timeString(timestamp);
const QString longTimeStr = ProtocolItem::timeString(timestamp, QLocale::LongFormat);

columns << timeStr;
columns << ""; // no "File" entry
Expand All @@ -383,7 +395,7 @@ void IssuesWidget::addError(const QString &folderAlias, const QString &message,

QIcon icon = Theme::instance()->syncStateIcon(SyncResult::Error);

QTreeWidgetItem *twitem = new SortedTreeWidgetItem(columns);
QTreeWidgetItem *twitem = new ProtocolItem(columns);
twitem->setData(0, Qt::SizeHintRole, QSize(0, ActivityItemDelegate::rowHeight()));
twitem->setData(0, Qt::UserRole, timestamp);
twitem->setIcon(0, icon);
Expand Down
1 change: 1 addition & 0 deletions src/gui/issueswidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ private slots:
void slotUpdateFolderFilters();
void slotAccountAdded(AccountState *account);
void slotAccountRemoved(AccountState *account);
void slotItemContextMenu(const QPoint &pos);

private:
void updateAccountChoiceVisibility();
Expand Down
171 changes: 112 additions & 59 deletions src/gui/protocolwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,115 @@
#include "folder.h"
#include "openfilemanager.h"
#include "activityitemdelegate.h"
#include "guiutility.h"
#include "accountstate.h"

#include "ui_protocolwidget.h"

#include <climits>

namespace OCC {

bool SortedTreeWidgetItem::operator<(const QTreeWidgetItem &other) const
QString ProtocolItem::timeString(QDateTime dt, QLocale::FormatType format)
{
const QLocale loc = QLocale::system();
QString dtFormat = loc.dateTimeFormat(format);
static const QRegExp re("(HH|H|hh|h):mm(?!:s)");
dtFormat.replace(re, "\\1:mm:ss");
return loc.toString(dt, dtFormat);
}

ProtocolItem *ProtocolItem::create(const QString &folder, const SyncFileItem &item)
{
auto f = FolderMan::instance()->folder(folder);
if (!f) {
return 0;
}

QStringList columns;
QDateTime timestamp = QDateTime::currentDateTime();
const QString timeStr = timeString(timestamp);
const QString longTimeStr = timeString(timestamp, QLocale::LongFormat);

columns << timeStr;
columns << Utility::fileNameForGuiUse(item._originalFile);
columns << f->shortGuiLocalPath();

// If the error string is set, it's prefered because it is a useful user message.
QString message = item._errorString;
if (message.isEmpty()) {
message = Progress::asResultString(item);
}
columns << message;

QIcon icon;
if (item._status == SyncFileItem::NormalError
|| item._status == SyncFileItem::FatalError
|| item._status == SyncFileItem::DetailError
|| item._status == SyncFileItem::BlacklistedError) {
icon = Theme::instance()->syncStateIcon(SyncResult::Error);
} else if (Progress::isWarningKind(item._status)) {
icon = Theme::instance()->syncStateIcon(SyncResult::Problem);
}

if (ProgressInfo::isSizeDependent(item)) {
columns << Utility::octetsToString(item._size);
}

ProtocolItem *twitem = new ProtocolItem(columns);
// Warning: The data and tooltips on the columns define an implicit
// interface and can only be changed with care.
twitem->setData(0, Qt::SizeHintRole, QSize(0, ActivityItemDelegate::rowHeight()));
twitem->setData(0, Qt::UserRole, timestamp);
twitem->setIcon(0, icon);
twitem->setToolTip(0, longTimeStr);
twitem->setToolTip(1, item._file);
twitem->setData(2, Qt::UserRole, folder);
twitem->setToolTip(3, message);
twitem->setData(3, Qt::UserRole, item._status);
return twitem;
}

SyncJournalFileRecord ProtocolItem::syncJournalRecord(QTreeWidgetItem *item)
{
SyncJournalFileRecord rec;
auto f = folder(item);
if (!f)
return rec;
f->journalDb()->getFileRecord(item->toolTip(1), &rec);
return rec;
}

Folder *ProtocolItem::folder(QTreeWidgetItem *item)
{
return FolderMan::instance()->folder(item->data(2, Qt::UserRole).toString());
}

void ProtocolItem::openContextMenu(QTreeWidgetItem *item, QWidget *parent)
{
auto f = ProtocolItem::folder(item);
if (!f)
return;
auto rec = ProtocolItem::syncJournalRecord(item);
// rec might not be valid

QObject *noParent = nullptr;
QAction openInBrowser(ProtocolWidget::tr("Open in browser"), noParent);
QObject::connect(&openInBrowser, &QAction::triggered, parent, [&]() {
fetchPrivateLinkUrl(f->accountState()->account(), rec._path,
rec.numericFileId(), parent, [parent](const QString &url) {
Utility::openBrowser(url, parent);
});
});

QMenu menu;
if (rec.isValid())
menu.addAction(&openInBrowser);

menu.exec(QCursor::pos());
}

bool ProtocolItem::operator<(const QTreeWidgetItem &other) const
{
int column = treeWidget()->sortColumn();
if (column != 0) {
Expand All @@ -56,6 +157,9 @@ ProtocolWidget::ProtocolWidget(QWidget *parent)

connect(_ui->_treeWidget, &QTreeWidget::itemActivated, this, &ProtocolWidget::slotOpenFile);

_ui->_treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(_ui->_treeWidget, &QTreeWidget::customContextMenuRequested, this, &ProtocolWidget::slotItemContextMenu);

// Adjust copyToClipboard() when making changes here!
QStringList header;
header << tr("Time");
Expand All @@ -71,7 +175,7 @@ ProtocolWidget::ProtocolWidget(QWidget *parent)

_ui->_treeWidget->setHeaderLabels(header);
int timestampColumnWidth =
_ui->_treeWidget->fontMetrics().width(timeString(QDateTime::currentDateTime()))
_ui->_treeWidget->fontMetrics().width(ProtocolItem::timeString(QDateTime::currentDateTime()))
+ timestampColumnExtra;
_ui->_treeWidget->setColumnWidth(0, timestampColumnWidth);
_ui->_treeWidget->setColumnWidth(1, 180);
Expand Down Expand Up @@ -119,14 +223,12 @@ void ProtocolWidget::hideEvent(QHideEvent *ev)
QWidget::hideEvent(ev);
}


QString ProtocolWidget::timeString(QDateTime dt, QLocale::FormatType format)
void ProtocolWidget::slotItemContextMenu(const QPoint &pos)
{
const QLocale loc = QLocale::system();
QString dtFormat = loc.dateTimeFormat(format);
static const QRegExp re("(HH|H|hh|h):mm(?!:s)");
dtFormat.replace(re, "\\1:mm:ss");
return loc.toString(dt, dtFormat);
auto item = _ui->_treeWidget->itemAt(pos);
if (!item)
return;
ProtocolItem::openContextMenu(item, this);
}

void ProtocolWidget::slotOpenFile(QTreeWidgetItem *item, int)
Expand All @@ -144,60 +246,11 @@ void ProtocolWidget::slotOpenFile(QTreeWidgetItem *item, int)
}
}

QTreeWidgetItem *ProtocolWidget::createCompletedTreewidgetItem(const QString &folder, const SyncFileItem &item)
{
auto f = FolderMan::instance()->folder(folder);
if (!f) {
return 0;
}

QStringList columns;
QDateTime timestamp = QDateTime::currentDateTime();
const QString timeStr = timeString(timestamp);
const QString longTimeStr = timeString(timestamp, QLocale::LongFormat);

columns << timeStr;
columns << Utility::fileNameForGuiUse(item._originalFile);
columns << f->shortGuiLocalPath();

// If the error string is set, it's prefered because it is a useful user message.
QString message = item._errorString;
if (message.isEmpty()) {
message = Progress::asResultString(item);
}
columns << message;

QIcon icon;
if (item._status == SyncFileItem::NormalError
|| item._status == SyncFileItem::FatalError
|| item._status == SyncFileItem::DetailError
|| item._status == SyncFileItem::BlacklistedError) {
icon = Theme::instance()->syncStateIcon(SyncResult::Error);
} else if (Progress::isWarningKind(item._status)) {
icon = Theme::instance()->syncStateIcon(SyncResult::Problem);
}

if (ProgressInfo::isSizeDependent(item)) {
columns << Utility::octetsToString(item._size);
}

QTreeWidgetItem *twitem = new SortedTreeWidgetItem(columns);
twitem->setData(0, Qt::SizeHintRole, QSize(0, ActivityItemDelegate::rowHeight()));
twitem->setData(0, Qt::UserRole, timestamp);
twitem->setIcon(0, icon);
twitem->setToolTip(0, longTimeStr);
twitem->setToolTip(1, item._file);
twitem->setData(2, Qt::UserRole, folder);
twitem->setToolTip(3, message);
twitem->setData(3, Qt::UserRole, item._status);
return twitem;
}

void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
{
if (item->hasErrorStatus())
return;
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, *item);
QTreeWidgetItem *line = ProtocolItem::create(folder, *item);
if (line) {
// Limit the number of items
int itemCnt = _ui->_treeWidget->topLevelItemCount();
Expand Down
22 changes: 15 additions & 7 deletions src/gui/protocolwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,25 @@ namespace Ui {
class Application;

/**
* A QTreeWidgetItem with special sorting.
* The items used in the protocol and issue QTreeWidget
*
* It allows items for global entries to be moved to the top if the
* Special sorting: It allows items for global entries to be moved to the top if the
* sorting section is the "Time" column.
*/
class SortedTreeWidgetItem : public QTreeWidgetItem
class ProtocolItem : public QTreeWidgetItem
{
public:
using QTreeWidgetItem::QTreeWidgetItem;

// Shared with IssueWidget
static ProtocolItem *create(const QString &folder, const SyncFileItem &item);
static QString timeString(QDateTime dt, QLocale::FormatType format = QLocale::NarrowFormat);

static SyncJournalFileRecord syncJournalRecord(QTreeWidgetItem *item);
static Folder *folder(QTreeWidgetItem *item);

static void openContextMenu(QTreeWidgetItem *item, QWidget *parent);

private:
bool operator<(const QTreeWidgetItem &other) const override;
};
Expand All @@ -63,10 +72,6 @@ class ProtocolWidget : public QWidget

void storeSyncActivity(QTextStream &ts);

// Shared with IssueWidget
static QTreeWidgetItem *createCompletedTreewidgetItem(const QString &folder, const SyncFileItem &item);
static QString timeString(QDateTime dt, QLocale::FormatType format = QLocale::NarrowFormat);

public slots:
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
void slotOpenFile(QTreeWidgetItem *item, int);
Expand All @@ -75,6 +80,9 @@ public slots:
void showEvent(QShowEvent *);
void hideEvent(QHideEvent *);

private slots:
void slotItemContextMenu(const QPoint &pos);

signals:
void copyToClipboard();

Expand Down
Loading

0 comments on commit b757eff

Please sign in to comment.