Removes Protocol and Issues widget files and references.

- Minor changes:
 - Improves comments and qCWarning  messages
 - Removes commented out code.
 - adds TODO's.

Signed-off-by: Camila San <hello@camila.codes>
This commit is contained in:
Camila San 2018-07-06 11:14:41 +02:00 committed by Roeland Jago Douma
parent ab3c6da5d7
commit 11484d5588
No known key found for this signature in database
GPG key ID: F941078878347C0C
16 changed files with 42 additions and 1436 deletions

View file

@ -22,8 +22,6 @@ set(client_UI_SRCS
generalsettings.ui
ignorelisteditor.ui
networksettings.ui
protocolwidget.ui
issueswidget.ui
activitywidget.ui
synclogdialog.ui
settingsdialog.ui
@ -70,8 +68,6 @@ set(client_SRCS
openfilemanager.cpp
owncloudgui.cpp
owncloudsetupwizard.cpp
protocolwidget.cpp
issueswidget.cpp
activitydata.cpp
activitylistmodel.cpp
activitywidget.cpp

View file

@ -131,7 +131,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
int top = option.rect.top() + margin - offset;
int buttonSize = option.rect.height()/2.5;
// Secondary will be 'Dismiss' or '...'
// Secondary will be 'Dismiss' or '...' multiple options button
secondaryButton.rect = option.rect;
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/dialog-close.png"));
if(customList.size() > 1)
@ -170,7 +170,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
int top = option.rect.top() + margin - offset;
int buttonSize = option.rect.height()/2.5;
// Secondary will be 'Dismiss' or '...'
// Secondary will be 'open file manager' with the folder icon
secondaryButton.rect = option.rect;
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/folder-grey.png"));
@ -184,7 +184,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
secondaryButton.features |= QStyleOptionButton::Flat;
secondaryButton.state |= QStyle::State_Raised;
// Primary button will be 'More Information'
// Primary button will be 'open browser'
primaryButton.rect = option.rect;
primaryButton.text = tr("Open Browser");
right = secondaryButton.rect.left() - rightMargin;
@ -251,8 +251,6 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
if (option.state & QStyle::State_Selected)
painter->setPen(option.palette.color(cg, QPalette::HighlightedText));
qDebug() << "Message text: " << messageText;
const QString elidedMessage = fm.elidedText(messageText, Qt::ElideRight, spaceLeftForText);
painter->drawText(messageTextBox, elidedMessage);
}
@ -285,11 +283,15 @@ bool ActivityItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
int x = option.rect.left() + option.rect.width() - buttonsWidth - _timeWidth;
int y = option.rect.top();
// clickable area for ...
if (mouseEventX > x && mouseEventX < x + buttonsWidth){
if(mouseEventY > y && mouseEventY < y + _buttonHeight){
// ...primary button ('more information' on notifications or 'open browser' on errors)
if (mouseEventX > x && mouseEventX < x + _primaryButtonWidth)
emit primaryButtonClickedOnItemView(index);
// ...secondary button ('dismiss' on notifications or 'open file manager' on errors)
x += _primaryButtonWidth + _spaceBetweenButtons;
if (mouseEventX > x && mouseEventX < x + _secondaryButtonWidth)
emit secondaryButtonClickedOnItemView(index);

View file

@ -120,7 +120,6 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
return a._message;
break;
case ActivityItemDelegate::LinkRole:
qDebug() << "Link Role!" << a._link;
return a._link;
break;
case ActivityItemDelegate::AccountRole:
@ -151,14 +150,11 @@ bool ActivityListModel::canFetchMore(const QModelIndex &) const
if (_activityLists.count() == 0)
return true;
//for (auto i = _activityLists.begin(); i != _activityLists.end(); ++i) {
//foreach(Activity activity, _activityLists){
if (_accountState && _accountState->isConnected()) {
if (_activityLists.count() == 0 && !_currentlyFetching) {
return true;
}
if (_accountState && _accountState->isConnected()) {
if (_activityLists.count() == 0 && !_currentlyFetching) {
return true;
}
//}
}
return false;
}

View file

@ -29,8 +29,6 @@
#include "accountstate.h"
#include "accountmanager.h"
#include "activityitemdelegate.h"
#include "protocolwidget.h"
#include "issueswidget.h"
#include "QProgressIndicator.h"
#include "notificationwidget.h"
#include "notificationconfirmjob.h"
@ -39,7 +37,7 @@
#include "ocsjob.h"
#include "configfile.h"
#include "guiutility.h"
#include "socketapi.h"
#include "ui_activitywidget.h"
#include <climits>
@ -109,6 +107,7 @@ ActivityWidget::~ActivityWidget()
delete _ui;
}
// TODO
void ActivityWidget::slotProgressInfo(const QString &folder, const ProgressInfo &progress)
{
if (progress.status() == ProgressInfo::Starting) {
@ -123,14 +122,20 @@ void ActivityWidget::slotItemCompleted(const QString &folder, const SyncFileItem
if (!folderInstance)
return;
// check if we are adding it to the right account and if it is useful information (error)
// check if we are adding it to the right account and if it is useful information (protocol errors)
if(folderInstance->accountState() == _accountState){
QString pathToFile = QString("%1/%2").arg(folderInstance->cleanPath(), item->_file);
qCWarning(lcActivity) << "Item " << pathToFile << " retrieved resulted in " << item->_errorString;
Activity activity;
activity._type = Activity::ErrorType;
activity._dateTime = QDateTime::fromString(QDateTime::currentDateTime().toString(), Qt::ISODate);
activity._subject = item->_errorString;
activity._message = item->_originalFile;
// TODO: use the full path to the file
// TODO: maybe use the full path to access the file in the browser
// folderInstance->accountState()->account()->deprecatedPrivateLinkUrl(item->_fileId).toString();
activity._link = folderInstance->accountState()->account()->url();
activity._status = item->_status;
activity._accName = folderInstance->accountState()->account()->displayName();
@ -143,8 +148,8 @@ void ActivityWidget::slotItemCompleted(const QString &folder, const SyncFileItem
al._isPrimary = true;
activity._links.append(al);
// add 'protocol error' to activity list
_model->addErrorToActivityList(activity);
// add error widget
}
}
@ -156,6 +161,8 @@ void ActivityWidget::addError(const QString &folderAlias, const QString &message
return;
if(folderInstance->accountState() == _accountState){
qCWarning(lcActivity) << "Item " << folderInstance->shortGuiLocalPath() << " retrieved resulted in " << message;
Activity activity;
activity._type = Activity::ErrorType;
activity._dateTime = QDateTime::fromString(QDateTime::currentDateTime().toString(), Qt::ISODate);
@ -174,6 +181,7 @@ void ActivityWidget::addError(const QString &folderAlias, const QString &message
activity._links.append(link);
}
// add 'other errors' to activity list
_model->addErrorToActivityList(activity);
}
}
@ -181,9 +189,10 @@ void ActivityWidget::addError(const QString &folderAlias, const QString &message
void ActivityWidget::slotPrimaryButtonClickedOnListView(const QModelIndex &index){
QUrl link = qvariant_cast<QString>(index.data(ActivityItemDelegate::LinkRole));
qDebug() << "Tyring to open link: " << link;
if(!link.isEmpty())
if(!link.isEmpty()){
qCWarning(lcActivity) << "Opening" << link.toString() << "in browser for Notification/Activity" << qvariant_cast<QString>(index.data(ActivityItemDelegate::ActionTextRole));
Utility::openBrowser(link, this);
}
}
void ActivityWidget::slotSecondaryButtonClickedOnListView(const QModelIndex &index){
@ -196,10 +205,13 @@ void ActivityWidget::slotSecondaryButtonClickedOnListView(const QModelIndex &ind
if(qvariant_cast<Activity::Type>(index.data(ActivityItemDelegate::ActionRole)) == Activity::Type::NotificationType){
const QString accountName = index.data(ActivityItemDelegate::AccountRole).toString();
if(actionLinks.size() == 1){
if(actionLinks.at(0)._verb == "DELETE")
if(actionLinks.at(0)._verb == "DELETE"){
qCWarning(lcActivity) << "Dismissing Notification/Activity" << qvariant_cast<QString>(index.data(ActivityItemDelegate::ActionTextRole));
slotSendNotificationRequest(index.data(ActivityItemDelegate::AccountRole).toString(), actionLinks.at(0)._link, actionLinks.at(0)._verb, index.row());
}
} else if(actionLinks.size() > 1){
QMenu menu;
qCWarning(lcActivity) << "Displaying menu for Notification/Activity" << qvariant_cast<QString>(index.data(ActivityItemDelegate::ActionTextRole));
foreach (ActivityLink actionLink, actionLinks) {
QAction *menuAction = new QAction(actionLink._label, &menu);
connect(menuAction, &QAction::triggered, this, [this, index, accountName, actionLink] {
@ -212,10 +224,10 @@ void ActivityWidget::slotSecondaryButtonClickedOnListView(const QModelIndex &ind
}
if(qvariant_cast<Activity::Type>(index.data(ActivityItemDelegate::ActionRole)) == Activity::Type::ErrorType){
QString fileName = index.data(ActivityItemDelegate::PathRole).toString();
// check if this is actually a folder
// check if this is actually a folder that we can open
if (FolderMan::instance()->folderForPath(actionLinks.first()._link)) {
if (QFile(actionLinks.first()._link).exists()) {
qCWarning(lcActivity) << "Opening path" << actionLinks.first()._link << "in the file manager for Notification/Activity" << qvariant_cast<QString>(index.data(ActivityItemDelegate::ActionTextRole));
showInFileManager(actionLinks.first()._link);
}
}
@ -231,8 +243,8 @@ void ActivityWidget::slotNotificationRequestFinished(int statusCode)
qCWarning(lcActivity) << "Notification Request to Server failed, leave notification visible.";
} else {
// to do use the model to rebuild the list or remove the item
qDebug() << "Notification to be removed from row" << row;
_model->removeFromActivityList(row);
qCWarning(lcActivity) << "Notification Request to Server successed, rebuilding list.";
_model->removeFromActivityList(row);
}
}
@ -358,7 +370,7 @@ void ActivityWidget::slotOpenFile(QModelIndex indx)
qCDebug(lcActivity) << indx.isValid() << indx.data(ActivityItemDelegate::PathRole).toString() << QFile::exists(indx.data(ActivityItemDelegate::PathRole).toString());
if (indx.isValid()) {
QString fullPath = indx.data(ActivityItemDelegate::PathRole).toString();
// TO DO: use full path to file
// TODO: use full path to file
if (QFile::exists(fullPath)) {
showInFileManager(fullPath);
}
@ -422,7 +434,6 @@ void ActivityWidget::slotBuildNotificationDisplay(const ActivityList &list)
void ActivityWidget::slotSendNotificationRequest(const QString &accountName, const QString &link, const QByteArray &verb, int row)
{
qCInfo(lcActivity) << "Server Notification Request " << verb << link << "on account" << accountName;
NotificationWidget *theSender = qobject_cast<NotificationWidget *>(sender());
const QStringList validVerbs = QStringList() << "GET"
<< "PUT"
@ -436,8 +447,6 @@ void ActivityWidget::slotSendNotificationRequest(const QString &accountName, con
QUrl l(link);
job->setLinkAndVerb(l, verb);
job->setProperty("activityRow", QVariant::fromValue(row));
// save the activity to be hidden or the QModelIndex
//job->setProperty();
connect(job, &AbstractNetworkJob::networkError,
this, &ActivityWidget::slotNotifyNetworkError);
connect(job, &NotificationConfirmJob::jobFinished,
@ -566,20 +575,6 @@ ActivitySettings::ActivitySettings(AccountState *accountState, QWidget *parent)
// connect a model signal to stop the animation
connect(_activityWidget, &ActivityWidget::rowsInserted, _progressIndicator, &QProgressIndicator::stopAnimation);
connect(_activityWidget, &ActivityWidget::rowsInserted, this, &ActivitySettings::slotDisplayActivities);
//_protocolWidget = new ProtocolWidget(this);
//_vbox->addWidget(_protocolWidget);
// _protocolTabId = _tab->addTab(_protocolWidget, Theme::instance()->syncStateIcon(SyncResult::Success), tr("Sync Protocol"));
// connect(_protocolWidget, &ProtocolWidget::copyToClipboard, this, &ActivitySettings::slotCopyToClipboard);
// _issuesWidget = new IssuesWidget(this);
// _vbox->addWidget(_issuesWidget);
// _syncIssueTabId = _tab->addTab(_issuesWidget, Theme::instance()->syncStateIcon(SyncResult::Problem), QString());
// slotShowIssueItemCount(0); // to display the label.
// connect(_issuesWidget, &IssuesWidget::issueCountUpdated,
// this, &ActivitySettings::slotShowIssueItemCount);
// connect(_issuesWidget, &IssuesWidget::copyToClipboard,
// this, &ActivitySettings::slotCopyToClipboard);
}
void ActivitySettings::slotDisplayActivities(){
@ -599,27 +594,16 @@ void ActivitySettings::slotShowIssueItemCount(int cnt)
//: %1 is the number of not synced files.
cntText = tr("Not Synced (%1)").arg(cnt);
}
//_tab->setTabText(_syncIssueTabId, cntText);
}
// TODO
void ActivitySettings::slotCopyToClipboard()
{
QString text;
QTextStream ts(&text);
//int idx = _tab->currentIndex();
QString message;
// if (idx == _protocolTabId) {
// // the protocol widget
// //_protocolWidget->storeSyncActivity(ts);
// message = tr("The sync activity list has been copied to the clipboard.");
// } else if (idx == _syncIssueTabId) {
// // issues Widget
// message = tr("The list of unsynced items has been copied to the clipboard.");
// //_issuesWidget->storeSyncIssues(ts);
// }
QApplication::clipboard()->setText(text);
emit guiLog(tr("Copied to clipboard"), message);

View file

@ -36,8 +36,6 @@ namespace OCC {
class Account;
class AccountStatusPtr;
class ProtocolWidget;
class IssuesWidget;
class JsonApiJob;
class NotificationWidget;
class ActivityListModel;
@ -168,8 +166,6 @@ private:
bool event(QEvent *e) Q_DECL_OVERRIDE;
ActivityWidget *_activityWidget;
ProtocolWidget *_protocolWidget;
IssuesWidget *_issuesWidget;
QProgressIndicator *_progressIndicator;
QVBoxLayout *_vbox;
QTimer _notificationCheckTimer;

View file

@ -28,12 +28,8 @@ IconJob::IconJob(const QUrl &url, QObject *parent) :
void IconJob::finished(QNetworkReply *reply)
{
if (reply->error() != QNetworkReply::NoError) {
qDebug() << reply->url() << " - " << reply->errorString();
if (reply->error() != QNetworkReply::NoError)
return;
}
qDebug() << "Icon job finished for " << reply->url();
reply->deleteLater();
emit jobFinished(reply->readAll());

View file

@ -1,540 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* 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.
*/
#include <QtGui>
#include <QtWidgets>
#include "issueswidget.h"
#include "configfile.h"
#include "syncresult.h"
#include "syncengine.h"
#include "logger.h"
#include "theme.h"
#include "folderman.h"
#include "syncfileitem.h"
#include "folder.h"
#include "openfilemanager.h"
#include "activityitemdelegate.h"
#include "protocolwidget.h"
#include "accountstate.h"
#include "account.h"
#include "accountmanager.h"
#include "common/syncjournalfilerecord.h"
#include "elidedlabel.h"
#include "ui_issueswidget.h"
#include <climits>
namespace OCC {
/**
* If more issues are reported than this they will not show up
* to avoid performance issues around sorting this many issues.
*/
static const int maxIssueCount = 50000;
static QPair<QString, QString> pathsWithIssuesKey(const ProtocolItem::ExtraData &data)
{
return qMakePair(data.folderName, data.path);
}
IssuesWidget::IssuesWidget(QWidget *parent)
: QWidget(parent)
, _ui(new Ui::IssuesWidget)
{
_ui->setupUi(this);
connect(ProgressDispatcher::instance(), &ProgressDispatcher::progressInfo,
this, &IssuesWidget::slotProgressInfo);
connect(ProgressDispatcher::instance(), &ProgressDispatcher::itemCompleted,
this, &IssuesWidget::slotItemCompleted);
connect(ProgressDispatcher::instance(), &ProgressDispatcher::syncError,
this, &IssuesWidget::addError);
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);
connect(_ui->filterAccount, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &IssuesWidget::slotUpdateFolderFilters);
connect(_ui->filterFolder, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &IssuesWidget::slotRefreshIssues);
for (auto account : AccountManager::instance()->accounts()) {
slotAccountAdded(account.data());
}
connect(AccountManager::instance(), &AccountManager::accountAdded,
this, &IssuesWidget::slotAccountAdded);
connect(AccountManager::instance(), &AccountManager::accountRemoved,
this, &IssuesWidget::slotAccountRemoved);
connect(FolderMan::instance(), &FolderMan::folderListChanged,
this, &IssuesWidget::slotUpdateFolderFilters);
// Adjust copyToClipboard() when making changes here!
QStringList header;
header << tr("Time");
header << tr("File");
header << tr("Folder");
header << tr("Issue");
int timestampColumnExtra = 0;
#ifdef Q_OS_WIN
timestampColumnExtra = 20; // font metrics are broken on Windows, see #4721
#endif
_ui->_treeWidget->setHeaderLabels(header);
int timestampColumnWidth =
ActivityItemDelegate::rowHeight() // icon
+ _ui->_treeWidget->fontMetrics().width(ProtocolItem::timeString(QDateTime::currentDateTime()))
+ timestampColumnExtra;
_ui->_treeWidget->setColumnWidth(0, timestampColumnWidth);
_ui->_treeWidget->setColumnWidth(1, 180);
_ui->_treeWidget->setColumnCount(4);
_ui->_treeWidget->setRootIsDecorated(false);
_ui->_treeWidget->setTextElideMode(Qt::ElideMiddle);
_ui->_treeWidget->header()->setObjectName("ActivityErrorListHeader");
#if defined(Q_OS_MAC)
_ui->_treeWidget->setMinimumWidth(400);
#endif
_reenableSorting.setInterval(5000);
connect(&_reenableSorting, &QTimer::timeout, this,
[this]() { _ui->_treeWidget->setSortingEnabled(true); });
_ui->_tooManyIssuesWarning->hide();
connect(this, &IssuesWidget::issueCountUpdated, this,
[this](int count) { _ui->_tooManyIssuesWarning->setVisible(count >= maxIssueCount); });
_ui->_conflictHelp->hide();
_ui->_conflictHelp->setText(
tr("There were conflicts. <a href=\"%1\">Check the documentation on how to resolve them.</a>")
.arg(Theme::instance()->conflictHelpUrl()));
}
IssuesWidget::~IssuesWidget()
{
delete _ui;
}
void IssuesWidget::showEvent(QShowEvent *ev)
{
ConfigFile cfg;
cfg.restoreGeometryHeader(_ui->_treeWidget->header());
// Sorting by section was newly enabled. But if we restore the header
// from a state where sorting was disabled, both of these flags will be
// false and sorting will be impossible!
_ui->_treeWidget->header()->setSectionsClickable(true);
_ui->_treeWidget->header()->setSortIndicatorShown(true);
// Switch back to "first important, then by time" ordering
_ui->_treeWidget->sortByColumn(0, Qt::DescendingOrder);
QWidget::showEvent(ev);
}
void IssuesWidget::hideEvent(QHideEvent *ev)
{
ConfigFile cfg;
cfg.saveGeometryHeader(_ui->_treeWidget->header());
QWidget::hideEvent(ev);
}
static bool persistsUntilLocalDiscovery(QTreeWidgetItem *item)
{
const auto data = ProtocolItem::extraData(item);
return data.status == SyncFileItem::Conflict
|| (data.status == SyncFileItem::FileIgnored && data.direction == SyncFileItem::Up);
}
void IssuesWidget::cleanItems(const std::function<bool(QTreeWidgetItem *)> &shouldDelete)
{
_ui->_treeWidget->setSortingEnabled(false);
// The issue list is a state, clear it and let the next sync fill it
// with ignored files and propagation errors.
int itemCnt = _ui->_treeWidget->topLevelItemCount();
for (int cnt = itemCnt - 1; cnt >= 0; cnt--) {
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(cnt);
if (shouldDelete(item)) {
_pathsWithIssues.remove(pathsWithIssuesKey(ProtocolItem::extraData(item)));
delete item;
}
}
_ui->_treeWidget->setSortingEnabled(true);
// update the tabtext
emit(issueCountUpdated(_ui->_treeWidget->topLevelItemCount()));
}
void IssuesWidget::addItem(QTreeWidgetItem *item)
{
if (!item)
return;
int count = _ui->_treeWidget->topLevelItemCount();
if (count >= maxIssueCount)
return;
_ui->_treeWidget->setSortingEnabled(false);
_reenableSorting.start();
// Insert item specific errors behind the others
int insertLoc = 0;
if (!item->text(1).isEmpty()) {
for (int i = 0; i < count; ++i) {
if (_ui->_treeWidget->topLevelItem(i)->text(1).isEmpty()) {
insertLoc = i + 1;
} else {
break;
}
}
}
// Wipe any existing message for the same folder and path
auto newData = ProtocolItem::extraData(item);
if (_pathsWithIssues.contains(pathsWithIssuesKey(newData))) {
for (int i = 0; i < count; ++i) {
auto otherItem = _ui->_treeWidget->topLevelItem(i);
auto otherData = ProtocolItem::extraData(otherItem);
if (otherData.path == newData.path && otherData.folderName == newData.folderName) {
delete otherItem;
break;
}
}
}
_ui->_treeWidget->insertTopLevelItem(insertLoc, item);
_pathsWithIssues.insert(pathsWithIssuesKey(newData));
item->setHidden(!shouldBeVisible(item, currentAccountFilter(), currentFolderFilter()));
emit issueCountUpdated(_ui->_treeWidget->topLevelItemCount());
}
void IssuesWidget::slotOpenFile(QTreeWidgetItem *item, int)
{
QString fileName = item->text(1);
if (Folder *folder = ProtocolItem::folder(item)) {
// folder->path() always comes back with trailing path
QString fullPath = folder->path() + fileName;
if (QFile(fullPath).exists()) {
showInFileManager(fullPath);
}
}
}
void IssuesWidget::slotProgressInfo(const QString &folder, const ProgressInfo &progress)
{
if (progress.status() == ProgressInfo::Reconcile) {
// Wipe all non-persistent entries - as well as the persistent ones
// in cases where a local discovery was done.
auto f = FolderMan::instance()->folder(folder);
if (!f)
return;
const auto &engine = f->syncEngine();
const auto style = engine.lastLocalDiscoveryStyle();
cleanItems([&](QTreeWidgetItem *item) {
if (ProtocolItem::extraData(item).folderName != folder)
return false;
if (style == LocalDiscoveryStyle::FilesystemOnly)
return true;
if (!persistsUntilLocalDiscovery(item))
return true;
// Definitely wipe the entry if the file no longer exists
if (!QFileInfo(f->path() + ProtocolItem::extraData(item).path).exists())
return true;
auto path = QFileInfo(ProtocolItem::extraData(item).path).dir().path().toUtf8();
if (path == ".")
path.clear();
return engine.shouldDiscoverLocally(path);
});
}
if (progress.status() == ProgressInfo::Done) {
// We keep track very well of pending conflicts.
// Inform other components about them.
QStringList conflicts;
auto tree = _ui->_treeWidget;
for (int i = 0; i < tree->topLevelItemCount(); ++i) {
auto item = tree->topLevelItem(i);
auto data = ProtocolItem::extraData(item);
if (data.folderName == folder
&& data.status == SyncFileItem::Conflict) {
conflicts.append(data.path);
}
}
emit ProgressDispatcher::instance()->folderConflicts(folder, conflicts);
_ui->_conflictHelp->setHidden(Theme::instance()->conflictHelpUrl().isEmpty() || conflicts.isEmpty());
}
}
void IssuesWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
{
if (!item->showInIssuesTab())
return;
QTreeWidgetItem *line = ProtocolItem::create(folder, *item);
if (!line)
return;
addItem(line);
}
void IssuesWidget::slotRefreshIssues()
{
auto tree = _ui->_treeWidget;
auto filterFolderAlias = currentFolderFilter();
auto filterAccount = currentAccountFilter();
for (int i = 0; i < tree->topLevelItemCount(); ++i) {
auto item = tree->topLevelItem(i);
item->setHidden(!shouldBeVisible(item, filterAccount, filterFolderAlias));
}
_ui->_treeWidget->setColumnHidden(2, !filterFolderAlias.isEmpty());
}
void IssuesWidget::slotAccountAdded(AccountState *account)
{
_ui->filterAccount->addItem(account->account()->displayName(), QVariant::fromValue(account));
updateAccountChoiceVisibility();
}
void IssuesWidget::slotAccountRemoved(AccountState *account)
{
for (int i = _ui->filterAccount->count() - 1; i >= 0; --i) {
if (account == _ui->filterAccount->itemData(i).value<AccountState *>())
_ui->filterAccount->removeItem(i);
}
updateAccountChoiceVisibility();
}
void IssuesWidget::slotItemContextMenu(const QPoint &pos)
{
auto item = _ui->_treeWidget->itemAt(pos);
if (!item)
return;
auto globalPos = _ui->_treeWidget->viewport()->mapToGlobal(pos);
ProtocolItem::openContextMenu(globalPos, item, this);
}
void IssuesWidget::updateAccountChoiceVisibility()
{
bool visible = _ui->filterAccount->count() > 2;
_ui->filterAccount->setVisible(visible);
_ui->accountLabel->setVisible(visible);
slotUpdateFolderFilters();
}
AccountState *IssuesWidget::currentAccountFilter() const
{
return _ui->filterAccount->currentData().value<AccountState *>();
}
QString IssuesWidget::currentFolderFilter() const
{
return _ui->filterFolder->currentData().toString();
}
bool IssuesWidget::shouldBeVisible(QTreeWidgetItem *item, AccountState *filterAccount,
const QString &filterFolderAlias) const
{
bool visible = true;
auto data = ProtocolItem::extraData(item);
auto status = data.status;
visible &= (_ui->showIgnores->isChecked() || status != SyncFileItem::FileIgnored);
visible &= (_ui->showWarnings->isChecked()
|| (status != SyncFileItem::SoftError
&& status != SyncFileItem::Restoration));
const auto &folderalias = data.folderName;
if (filterAccount) {
auto folder = FolderMan::instance()->folder(folderalias);
visible &= folder && folder->accountState() == filterAccount;
}
visible &= (filterFolderAlias.isEmpty() || filterFolderAlias == folderalias);
return visible;
}
void IssuesWidget::slotUpdateFolderFilters()
{
auto account = _ui->filterAccount->currentData().value<AccountState *>();
// If there is no account selector, show folders for the single
// available account
if (_ui->filterAccount->isHidden() && _ui->filterAccount->count() > 1) {
account = _ui->filterAccount->itemData(1).value<AccountState *>();
}
if (!account) {
_ui->filterFolder->setCurrentIndex(0);
}
_ui->filterFolder->setEnabled(account != 0);
for (int i = _ui->filterFolder->count() - 1; i >= 1; --i) {
_ui->filterFolder->removeItem(i);
}
// Find all selectable folders while figuring out if we need a folder
// selector in the first place
bool anyAccountHasMultipleFolders = false;
QSet<AccountState *> accountsWithFolders;
for (auto folder : FolderMan::instance()->map().values()) {
if (accountsWithFolders.contains(folder->accountState()))
anyAccountHasMultipleFolders = true;
accountsWithFolders.insert(folder->accountState());
if (folder->accountState() != account)
continue;
_ui->filterFolder->addItem(folder->shortGuiLocalPath(), folder->alias());
}
// If we don't need the combo box, hide it.
_ui->filterFolder->setVisible(anyAccountHasMultipleFolders);
_ui->folderLabel->setVisible(anyAccountHasMultipleFolders);
// If there's no choice, select the only folder and disable
if (_ui->filterFolder->count() == 2 && anyAccountHasMultipleFolders) {
_ui->filterFolder->setCurrentIndex(1);
_ui->filterFolder->setEnabled(false);
}
}
void IssuesWidget::storeSyncIssues(QTextStream &ts)
{
int topLevelItems = _ui->_treeWidget->topLevelItemCount();
for (int i = 0; i < topLevelItems; i++) {
QTreeWidgetItem *child = _ui->_treeWidget->topLevelItem(i);
if (child->isHidden())
continue;
ts << right
// time stamp
<< qSetFieldWidth(20)
<< child->data(0, Qt::DisplayRole).toString()
// separator
<< qSetFieldWidth(0) << ","
// file name
<< qSetFieldWidth(64)
<< child->data(1, Qt::DisplayRole).toString()
// separator
<< qSetFieldWidth(0) << ","
// folder
<< qSetFieldWidth(30)
<< child->data(2, Qt::DisplayRole).toString()
// separator
<< qSetFieldWidth(0) << ","
// action
<< qSetFieldWidth(15)
<< child->data(3, Qt::DisplayRole).toString()
<< qSetFieldWidth(0)
<< endl;
}
}
void IssuesWidget::showFolderErrors(const QString &folderAlias)
{
auto folder = FolderMan::instance()->folder(folderAlias);
if (!folder)
return;
_ui->filterAccount->setCurrentIndex(
qMax(0, _ui->filterAccount->findData(QVariant::fromValue(folder->accountState()))));
_ui->filterFolder->setCurrentIndex(
qMax(0, _ui->filterFolder->findData(folderAlias)));
_ui->showIgnores->setChecked(false);
_ui->showWarnings->setChecked(false);
}
void IssuesWidget::addError(const QString &folderAlias, const QString &message,
ErrorCategory category)
{
auto folder = FolderMan::instance()->folder(folderAlias);
if (!folder)
return;
QStringList columns;
QDateTime timestamp = QDateTime::currentDateTime();
const QString timeStr = ProtocolItem::timeString(timestamp);
const QString longTimeStr = ProtocolItem::timeString(timestamp, QLocale::LongFormat);
columns << timeStr;
columns << ""; // no "File" entry
columns << folder->shortGuiLocalPath();
columns << message;
QIcon icon = Theme::instance()->syncStateIcon(SyncResult::Error);
QTreeWidgetItem *twitem = new ProtocolItem(columns);
twitem->setData(0, Qt::SizeHintRole, QSize(0, ActivityItemDelegate::rowHeight()));
twitem->setIcon(0, icon);
twitem->setToolTip(0, longTimeStr);
twitem->setToolTip(3, message);
ProtocolItem::ExtraData data;
data.timestamp = timestamp;
data.folderName = folderAlias;
data.status = SyncFileItem::NormalError;
ProtocolItem::setExtraData(twitem, data);
addItem(twitem);
addErrorWidget(twitem, message, category);
}
void IssuesWidget::addErrorWidget(QTreeWidgetItem *item, const QString &message, ErrorCategory category)
{
QWidget *widget = 0;
if (category == ErrorCategory::InsufficientRemoteStorage) {
widget = new QWidget;
auto layout = new QHBoxLayout;
widget->setLayout(layout);
auto label = new ElidedLabel(message, widget);
label->setElideMode(Qt::ElideMiddle);
layout->addWidget(label);
auto button = new QPushButton("Retry all uploads", widget);
button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
auto folderAlias = ProtocolItem::extraData(item).folderName;
connect(button, &QPushButton::clicked,
this, [this, folderAlias]() { retryInsufficentRemoteStorageErrors(folderAlias); });
layout->addWidget(button);
}
if (widget) {
item->setText(3, QString());
}
_ui->_treeWidget->setItemWidget(item, 3, widget);
}
void IssuesWidget::retryInsufficentRemoteStorageErrors(const QString &folderAlias)
{
auto folderman = FolderMan::instance();
auto folder = folderman->folder(folderAlias);
if (!folder)
return;
folder->journalDb()->wipeErrorBlacklistCategory(SyncJournalErrorBlacklistRecord::InsufficientRemoteStorage);
folderman->scheduleFolderNext(folder);
}
}

View file

@ -1,99 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* 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.
*/
#ifndef ISSUESWIDGET_H
#define ISSUESWIDGET_H
#include <QDialog>
#include <QDateTime>
#include <QLocale>
#include <QTimer>
#include "progressdispatcher.h"
#include "owncloudgui.h"
#include "ui_issueswidget.h"
class QPushButton;
namespace OCC {
class SyncResult;
namespace Ui {
class ProtocolWidget;
}
class Application;
/**
* @brief The ProtocolWidget class
* @ingroup gui
*/
class IssuesWidget : public QWidget
{
Q_OBJECT
public:
explicit IssuesWidget(QWidget *parent = 0);
~IssuesWidget();
QSize sizeHint() const { return ownCloudGui::settingsDialogSize(); }
void storeSyncIssues(QTextStream &ts);
void showFolderErrors(const QString &folderAlias);
public slots:
void addError(const QString &folderAlias, const QString &message, ErrorCategory category);
void slotProgressInfo(const QString &folder, const ProgressInfo &progress);
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
void slotOpenFile(QTreeWidgetItem *item, int);
protected:
void showEvent(QShowEvent *);
void hideEvent(QHideEvent *);
signals:
void copyToClipboard();
void issueCountUpdated(int);
private slots:
void slotRefreshIssues();
void slotUpdateFolderFilters();
void slotAccountAdded(AccountState *account);
void slotAccountRemoved(AccountState *account);
void slotItemContextMenu(const QPoint &pos);
private:
void updateAccountChoiceVisibility();
AccountState *currentAccountFilter() const;
QString currentFolderFilter() const;
bool shouldBeVisible(QTreeWidgetItem *item, AccountState *filterAccount,
const QString &filterFolderAlias) const;
void cleanItems(const std::function<bool(QTreeWidgetItem *)> &shouldDelete);
void addItem(QTreeWidgetItem *item);
/// Add the special error widget for the category, if any
void addErrorWidget(QTreeWidgetItem *item, const QString &message, ErrorCategory category);
/// Wipes all insufficient remote storgage blacklist entries
void retryInsufficentRemoteStorageErrors(const QString &folderAlias);
/// Each insert disables sorting, this timer reenables it
QTimer _reenableSorting;
/// Optimization: keep track of all folder/paths pairs that have an associated issue
QSet<QPair<QString, QString>> _pathsWithIssues;
Ui::IssuesWidget *_ui;
};
}
#endif

View file

@ -1,198 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OCC::IssuesWidget</class>
<widget class="QWidget" name="OCC::IssuesWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>580</width>
<height>578</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="_headerLabel">
<property name="text">
<string>List of issues</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QFormLayout" name="accountFolderLayout">
<item row="0" column="0">
<widget class="QLabel" name="accountLabel">
<property name="text">
<string>Account</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="filterAccount">
<item>
<property name="text">
<string>&lt;no filter&gt;</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="folderLabel">
<property name="text">
<string>Folder</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="filterFolder">
<property name="enabled">
<bool>false</bool>
</property>
<item>
<property name="text">
<string>&lt;no filter&gt;</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="1">
<widget class="QCheckBox" name="showWarnings">
<property name="text">
<string>Show warnings</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="showIgnores">
<property name="text">
<string>Show ignored files</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QTreeWidget" name="_treeWidget">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="columnCount">
<number>4</number>
</property>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">2</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">3</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">4</string>
</property>
</column>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="_tooManyIssuesWarning">
<property name="text">
<string>There were too many issues. Not all will be visible here.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="_conflictHelp">
<property name="text">
<string>There were conflicts. Check the documentation on how to resolve them.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="copyIssuesButton">
<property name="toolTip">
<string>Copy the issues list to the clipboard.</string>
</property>
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -1,330 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* 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.
*/
#include <QtGui>
#include <QtWidgets>
#include "protocolwidget.h"
#include "configfile.h"
#include "syncresult.h"
#include "logger.h"
#include "theme.h"
#include "folderman.h"
#include "syncfileitem.h"
#include "folder.h"
#include "openfilemanager.h"
#include "activityitemdelegate.h"
#include "guiutility.h"
#include "accountstate.h"
#include "ui_protocolwidget.h"
#include <climits>
Q_DECLARE_METATYPE(OCC::ProtocolItem::ExtraData)
namespace OCC {
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::ExtraData ProtocolItem::extraData(const QTreeWidgetItem *item)
{
return item->data(0, Qt::UserRole).value<ExtraData>();
}
void ProtocolItem::setExtraData(QTreeWidgetItem *item, const ExtraData &data)
{
item->setData(0, Qt::UserRole, QVariant::fromValue(data));
}
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->setIcon(0, icon);
twitem->setToolTip(0, longTimeStr);
twitem->setToolTip(1, item._file);
twitem->setToolTip(3, message);
ProtocolItem::ExtraData data;
data.timestamp = timestamp;
data.path = item._file;
data.folderName = folder;
data.status = item._status;
data.size = item._size;
data.direction = item._direction;
ProtocolItem::setExtraData(twitem, data);
return twitem;
}
SyncJournalFileRecord ProtocolItem::syncJournalRecord(QTreeWidgetItem *item)
{
SyncJournalFileRecord rec;
auto f = folder(item);
if (!f)
return rec;
f->journalDb()->getFileRecord(extraData(item).path, &rec);
return rec;
}
Folder *ProtocolItem::folder(QTreeWidgetItem *item)
{
return FolderMan::instance()->folder(extraData(item).folderName);
}
void ProtocolItem::openContextMenu(QPoint globalPos, QTreeWidgetItem *item, QWidget *parent)
{
auto f = folder(item);
if (!f)
return;
AccountPtr account = f->accountState()->account();
auto rec = syncJournalRecord(item);
// rec might not be valid
auto menu = new QMenu(parent);
if (rec.isValid()) {
// "Open in Browser" action
auto openInBrowser = menu->addAction(ProtocolWidget::tr("Open in browser"));
QObject::connect(openInBrowser, &QAction::triggered, parent, [parent, account, rec]() {
fetchPrivateLinkUrl(account, rec._path, rec.numericFileId(), parent,
[parent](const QString &url) {
Utility::openBrowser(url, parent);
});
});
}
// More actions will be conditionally added to the context menu here later
if (menu->actions().isEmpty()) {
delete menu;
return;
}
menu->setAttribute(Qt::WA_DeleteOnClose);
menu->popup(globalPos);
}
bool ProtocolItem::operator<(const QTreeWidgetItem &other) const
{
int column = treeWidget()->sortColumn();
if (column == 0) {
// Items with empty "File" column are larger than others,
// otherwise sort by time (this uses lexicographic ordering)
return std::forward_as_tuple(text(1).isEmpty(), extraData(this).timestamp)
< std::forward_as_tuple(other.text(1).isEmpty(), extraData(&other).timestamp);
} else if (column == 4) {
return extraData(this).size < extraData(&other).size;
}
return QTreeWidgetItem::operator<(other);
}
ProtocolWidget::ProtocolWidget(QWidget *parent)
: QWidget(parent)
, _ui(new Ui::ProtocolWidget)
{
_ui->setupUi(this);
connect(ProgressDispatcher::instance(), &ProgressDispatcher::itemCompleted,
this, &ProtocolWidget::slotItemCompleted);
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");
header << tr("File");
header << tr("Folder");
header << tr("Action");
header << tr("Size");
int timestampColumnExtra = 0;
#ifdef Q_OS_WIN
timestampColumnExtra = 20; // font metrics are broken on Windows, see #4721
#endif
_ui->_treeWidget->setHeaderLabels(header);
int timestampColumnWidth =
_ui->_treeWidget->fontMetrics().width(ProtocolItem::timeString(QDateTime::currentDateTime()))
+ timestampColumnExtra;
_ui->_treeWidget->setColumnWidth(0, timestampColumnWidth);
_ui->_treeWidget->setColumnWidth(1, 180);
_ui->_treeWidget->setColumnCount(5);
_ui->_treeWidget->setRootIsDecorated(false);
_ui->_treeWidget->setTextElideMode(Qt::ElideMiddle);
_ui->_treeWidget->header()->setObjectName("ActivityListHeader");
#if defined(Q_OS_MAC)
_ui->_treeWidget->setMinimumWidth(400);
#endif
_ui->_headerLabel->setText(tr("Local sync protocol"));
QPushButton *copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
copyBtn->setToolTip(tr("Copy the activity list to the clipboard."));
copyBtn->setEnabled(true);
connect(copyBtn, &QAbstractButton::clicked, this, &ProtocolWidget::copyToClipboard);
}
ProtocolWidget::~ProtocolWidget()
{
delete _ui;
}
void ProtocolWidget::showEvent(QShowEvent *ev)
{
ConfigFile cfg;
cfg.restoreGeometryHeader(_ui->_treeWidget->header());
// Sorting by section was newly enabled. But if we restore the header
// from a state where sorting was disabled, both of these flags will be
// false and sorting will be impossible!
_ui->_treeWidget->header()->setSectionsClickable(true);
_ui->_treeWidget->header()->setSortIndicatorShown(true);
// Switch back to "by time" ordering
_ui->_treeWidget->sortByColumn(0, Qt::DescendingOrder);
QWidget::showEvent(ev);
}
void ProtocolWidget::hideEvent(QHideEvent *ev)
{
ConfigFile cfg;
cfg.saveGeometryHeader(_ui->_treeWidget->header());
QWidget::hideEvent(ev);
}
void ProtocolWidget::slotItemContextMenu(const QPoint &pos)
{
auto item = _ui->_treeWidget->itemAt(pos);
if (!item)
return;
auto globalPos = _ui->_treeWidget->viewport()->mapToGlobal(pos);
ProtocolItem::openContextMenu(globalPos, item, this);
}
void ProtocolWidget::slotOpenFile(QTreeWidgetItem *item, int)
{
QString fileName = item->text(1);
if (Folder *folder = ProtocolItem::folder(item)) {
// folder->path() always comes back with trailing path
QString fullPath = folder->path() + fileName;
if (QFile(fullPath).exists()) {
showInFileManager(fullPath);
}
}
}
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
{
if (!item->showInProtocolTab())
return;
QTreeWidgetItem *line = ProtocolItem::create(folder, *item);
if (line) {
// Limit the number of items
int itemCnt = _ui->_treeWidget->topLevelItemCount();
while (itemCnt > 2000) {
delete _ui->_treeWidget->takeTopLevelItem(itemCnt - 1);
itemCnt--;
}
_ui->_treeWidget->insertTopLevelItem(0, line);
}
}
void ProtocolWidget::storeSyncActivity(QTextStream &ts)
{
int topLevelItems = _ui->_treeWidget->topLevelItemCount();
for (int i = 0; i < topLevelItems; i++) {
QTreeWidgetItem *child = _ui->_treeWidget->topLevelItem(i);
ts << right
// time stamp
<< qSetFieldWidth(20)
<< child->data(0, Qt::DisplayRole).toString()
// separator
<< qSetFieldWidth(0) << ","
// file name
<< qSetFieldWidth(64)
<< child->data(1, Qt::DisplayRole).toString()
// separator
<< qSetFieldWidth(0) << ","
// folder
<< qSetFieldWidth(30)
<< child->data(2, Qt::DisplayRole).toString()
// separator
<< qSetFieldWidth(0) << ","
// action
<< qSetFieldWidth(15)
<< child->data(3, Qt::DisplayRole).toString()
// separator
<< qSetFieldWidth(0) << ","
// size
<< qSetFieldWidth(10)
<< child->data(4, Qt::DisplayRole).toString()
<< qSetFieldWidth(0)
<< endl;
}
}
}

View file

@ -1,112 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* 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.
*/
#ifndef PROTOCOLWIDGET_H
#define PROTOCOLWIDGET_H
#include <QDialog>
#include <QDateTime>
#include <QLocale>
#include "progressdispatcher.h"
#include "owncloudgui.h"
#include "ui_protocolwidget.h"
class QPushButton;
namespace OCC {
class SyncResult;
namespace Ui {
class ProtocolWidget;
}
class Application;
/**
* The items used in the protocol and issue QTreeWidget
*
* Special sorting: It allows items for global entries to be moved to the top if the
* sorting section is the "Time" column.
*/
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);
struct ExtraData
{
ExtraData()
: status(SyncFileItem::NoStatus)
, direction(SyncFileItem::None)
{
}
QString path;
QString folderName;
QDateTime timestamp;
quint64 size = 0;
SyncFileItem::Status status BITFIELD(4);
SyncFileItem::Direction direction BITFIELD(3);
};
static ExtraData extraData(const QTreeWidgetItem *item);
static void setExtraData(QTreeWidgetItem *item, const ExtraData &data);
static SyncJournalFileRecord syncJournalRecord(QTreeWidgetItem *item);
static Folder *folder(QTreeWidgetItem *item);
static void openContextMenu(QPoint globalPos, QTreeWidgetItem *item, QWidget *parent);
private:
bool operator<(const QTreeWidgetItem &other) const override;
};
/**
* @brief The ProtocolWidget class
* @ingroup gui
*/
class ProtocolWidget : public QWidget
{
Q_OBJECT
public:
explicit ProtocolWidget(QWidget *parent = 0);
~ProtocolWidget();
QSize sizeHint() const { return ownCloudGui::settingsDialogSize(); }
void storeSyncActivity(QTextStream &ts);
public slots:
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
void slotOpenFile(QTreeWidgetItem *item, int);
protected:
void showEvent(QShowEvent *);
void hideEvent(QHideEvent *);
private slots:
void slotItemContextMenu(const QPoint &pos);
signals:
void copyToClipboard();
private:
Ui::ProtocolWidget *_ui;
};
}
#endif // PROTOCOLWIDGET_H

View file

@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OCC::ProtocolWidget</class>
<widget class="QWidget" name="OCC::ProtocolWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>612</width>
<height>515</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="_headerLabel">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTreeWidget" name="_treeWidget">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="columnCount">
<number>4</number>
</property>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">2</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">3</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">4</string>
</property>
</column>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="_dialogButtonBox"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -80,7 +80,6 @@ void ServerNotificationHandler::slotIconDownloaded(QByteArray iconData){
QPixmap pixmap;
pixmap.loadFromData(iconData);
iconCache.insert(sender()->property("activityId").toInt(), QIcon(pixmap));
qDebug() << "Icon cached for activity " << sender()->property("activityId").toInt();
}
void ServerNotificationHandler::slotNotificationsReceived(const QJsonDocument &json, int statusCode)

View file

@ -25,7 +25,6 @@
#include "owncloudgui.h"
#include "activitywidget.h"
#include "accountmanager.h"
#include "protocolwidget.h"
#include <QLabel>
#include <QStandardItemModel>
@ -400,8 +399,6 @@ public:
btn->setDefaultAction(this);
btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
// btn->setMinimumWidth(qMax<int>(parent->sizeHint().height() * buttonSizeRatio,
// btn->sizeHint().width()));
return btn;
}
};
@ -430,10 +427,8 @@ void SettingsDialog::slotRefreshActivityAccountStateSender()
void SettingsDialog::slotRefreshActivity(AccountState *accountState)
{
if (accountState->isConnected()) {
qDebug() << "!! Fetching activities and notifications for" << accountState->account()->displayName();
if (accountState->isConnected())
_activitySettings[accountState]->slotRefresh();
}
}
} // namespace OCC

View file

@ -27,7 +27,7 @@
namespace OCC {
SyncLogDialog::SyncLogDialog(QWidget *parent, ProtocolWidget *protoWidget)
SyncLogDialog::SyncLogDialog(QWidget *parent)
: QDialog(parent)
, _ui(new Ui::SyncLogDialog)
{
@ -35,10 +35,6 @@ SyncLogDialog::SyncLogDialog(QWidget *parent, ProtocolWidget *protoWidget)
_ui->setupUi(this);
if (protoWidget) {
_ui->logWidgetLayout->addWidget(protoWidget);
}
QPushButton *closeButton = _ui->buttonBox->button(QDialogButtonBox::Close);
if (closeButton) {
connect(closeButton, &QAbstractButton::clicked, this, &QWidget::close);

View file

@ -16,8 +16,6 @@
#ifndef SyncLogDialog_H
#define SyncLogDialog_H
#include "protocolwidget.h"
#include <QDialog>
namespace OCC {
@ -37,7 +35,7 @@ class SyncLogDialog : public QDialog
Q_OBJECT
public:
explicit SyncLogDialog(QWidget *parent = 0, ProtocolWidget *protoWidget = 0);
explicit SyncLogDialog(QWidget *parent = 0);
~SyncLogDialog();
private slots: