mirror of
https://github.com/nextcloud/desktop.git
synced 2024-10-26 06:15:48 +03:00
* Add a more functional error view #5516 * Allow filtering of ignores and warnings to see only important bits. * Navigate from the folder view to the error view by clicking on the error list with the red background. * Move the error list into its own ui file to allow easier extension. * Fix issue around tab id handling in ActivitySettings. * Rename "Action" column to "Issue". * Change mouse cursor to hand over button and new error list area Several OSX fixes provided by guruz.
This commit is contained in:
parent
9493e8f42e
commit
ce8341ca1f
16 changed files with 665 additions and 132 deletions
|
@ -21,6 +21,7 @@ set(client_UI
|
|||
ignorelisteditor.ui
|
||||
networksettings.ui
|
||||
protocolwidget.ui
|
||||
issueswidget.ui
|
||||
activitywidget.ui
|
||||
synclogdialog.ui
|
||||
settingsdialog.ui
|
||||
|
@ -64,6 +65,7 @@ set(client_SRCS
|
|||
owncloudgui.cpp
|
||||
owncloudsetupwizard.cpp
|
||||
protocolwidget.cpp
|
||||
issueswidget.cpp
|
||||
activitydata.cpp
|
||||
activitylistmodel.cpp
|
||||
activitywidget.cpp
|
||||
|
|
|
@ -69,6 +69,42 @@ static const char progressBarStyleC[] =
|
|||
"background-color: %1; width: 1px;"
|
||||
"}";
|
||||
|
||||
/**
|
||||
* Adjusts the mouse cursor based on the region it is on over the folder tree view.
|
||||
*
|
||||
* Used to show that one can click the red error list box by changing the cursor
|
||||
* to the pointing hand.
|
||||
*/
|
||||
class MouseCursorChanger : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MouseCursorChanger(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QTreeView *folderList;
|
||||
FolderStatusModel *model;
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override
|
||||
{
|
||||
if (event->type() == QEvent::HoverMove) {
|
||||
Qt::CursorShape shape = Qt::ArrowCursor;
|
||||
auto pos = folderList->mapFromGlobal(QCursor::pos());
|
||||
auto index = folderList->indexAt(pos);
|
||||
if (model->classify(index) == FolderStatusModel::RootFolder
|
||||
&& (FolderStatusDelegate::errorsListRect(folderList->visualRect(index)).contains(pos)
|
||||
|| FolderStatusDelegate::optionsButtonRect(folderList->visualRect(index),folderList->layoutDirection()).contains(pos))) {
|
||||
shape = Qt::PointingHandCursor;
|
||||
}
|
||||
folderList->setCursor(shape);
|
||||
}
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
};
|
||||
|
||||
AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::AccountSettings)
|
||||
|
@ -94,6 +130,13 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
|||
#endif
|
||||
new ToolTipUpdater(ui->_folderList);
|
||||
|
||||
auto mouseCursorChanger = new MouseCursorChanger(this);
|
||||
mouseCursorChanger->folderList = ui->_folderList;
|
||||
mouseCursorChanger->model = _model;
|
||||
ui->_folderList->setMouseTracking(true);
|
||||
ui->_folderList->setAttribute(Qt::WA_Hover, true);
|
||||
ui->_folderList->installEventFilter(mouseCursorChanger);
|
||||
|
||||
createAccountToolbox();
|
||||
connect(AccountManager::instance(), SIGNAL(accountAdded(AccountState *)),
|
||||
SLOT(slotAccountAdded(AccountState *)));
|
||||
|
@ -301,6 +344,10 @@ void AccountSettings::slotFolderListClicked(const QModelIndex &indx)
|
|||
slotCustomContextMenuRequested(pos);
|
||||
return;
|
||||
}
|
||||
if (FolderStatusDelegate::errorsListRect(tv->visualRect(indx)).contains(pos)) {
|
||||
emit showIssuesList(_model->data(indx, FolderStatusDelegate::FolderAliasRole).toString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand root items on single click
|
||||
if (_accountState && _accountState->state() == AccountState::Connected) {
|
||||
|
@ -808,3 +855,5 @@ bool AccountSettings::event(QEvent *e)
|
|||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
#include "accountsettings.moc"
|
||||
|
|
|
@ -60,6 +60,7 @@ public:
|
|||
signals:
|
||||
void folderChanged();
|
||||
void openFolderAlias(const QString &);
|
||||
void showIssuesList(const QString &folderAlias);
|
||||
|
||||
public slots:
|
||||
void slotOpenOC();
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "accountmanager.h"
|
||||
#include "activityitemdelegate.h"
|
||||
#include "protocolwidget.h"
|
||||
#include "issueswidget.h"
|
||||
#include "QProgressIndicator.h"
|
||||
#include "notificationwidget.h"
|
||||
#include "notificationconfirmjob.h"
|
||||
|
@ -518,33 +519,23 @@ ActivitySettings::ActivitySettings(QWidget *parent)
|
|||
_tab = new QTabWidget(this);
|
||||
hbox->addWidget(_tab);
|
||||
_activityWidget = new ActivityWidget(this);
|
||||
_activityTabId = _tab->insertTab(0, _activityWidget, Theme::instance()->applicationIcon(), tr("Server Activity"));
|
||||
_activityTabId = _tab->addTab(_activityWidget, Theme::instance()->applicationIcon(), tr("Server Activity"));
|
||||
connect(_activityWidget, SIGNAL(copyToClipboard()), this, SLOT(slotCopyToClipboard()));
|
||||
connect(_activityWidget, SIGNAL(hideActivityTab(bool)), this, SLOT(setActivityTabHidden(bool)));
|
||||
connect(_activityWidget, SIGNAL(guiLog(QString, QString)), this, SIGNAL(guiLog(QString, QString)));
|
||||
connect(_activityWidget, SIGNAL(newNotification()), SLOT(slotShowActivityTab()));
|
||||
|
||||
_protocolWidget = new ProtocolWidget(this);
|
||||
_tab->insertTab(1, _protocolWidget, Theme::instance()->syncStateIcon(SyncResult::Success), tr("Sync Protocol"));
|
||||
_protocolTabId = _tab->addTab(_protocolWidget, Theme::instance()->syncStateIcon(SyncResult::Success), tr("Sync Protocol"));
|
||||
connect(_protocolWidget, SIGNAL(copyToClipboard()), this, SLOT(slotCopyToClipboard()));
|
||||
connect(_protocolWidget, SIGNAL(issueItemCountUpdated(int)),
|
||||
this, SLOT(slotShowIssueItemCount(int)));
|
||||
|
||||
// Add the not-synced list into the tab
|
||||
QWidget *w = new QWidget;
|
||||
QVBoxLayout *vbox2 = new QVBoxLayout(w);
|
||||
vbox2->addWidget(new QLabel(tr("List of ignored or erroneous files"), this));
|
||||
vbox2->addWidget(_protocolWidget->issueWidget());
|
||||
QDialogButtonBox *dlgButtonBox = new QDialogButtonBox(this);
|
||||
vbox2->addWidget(dlgButtonBox);
|
||||
QPushButton *_copyBtn = dlgButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
|
||||
_copyBtn->setToolTip(tr("Copy the activity list to the clipboard."));
|
||||
_copyBtn->setEnabled(true);
|
||||
connect(_copyBtn, SIGNAL(clicked()), this, SLOT(slotCopyToClipboard()));
|
||||
|
||||
w->setLayout(vbox2);
|
||||
_syncIssueTabId = _tab->insertTab(2, w, Theme::instance()->syncStateIcon(SyncResult::Problem), QString());
|
||||
_issuesWidget = new IssuesWidget(this);
|
||||
_syncIssueTabId = _tab->addTab(_issuesWidget, Theme::instance()->syncStateIcon(SyncResult::Problem), QString());
|
||||
slotShowIssueItemCount(0); // to display the label.
|
||||
connect(_issuesWidget, SIGNAL(issueCountUpdated(int)),
|
||||
this, SLOT(slotShowIssueItemCount(int)));
|
||||
connect(_issuesWidget, SIGNAL(copyToClipboard()),
|
||||
this, SLOT(slotCopyToClipboard()));
|
||||
|
||||
// Add a progress indicator to spin if the acitivity list is updated.
|
||||
_progressIndicator = new QProgressIndicator(this);
|
||||
|
@ -571,10 +562,14 @@ void ActivitySettings::setActivityTabHidden(bool hidden)
|
|||
if (hidden && _activityTabId > -1) {
|
||||
_tab->removeTab(_activityTabId);
|
||||
_activityTabId = -1;
|
||||
_protocolTabId -= 1;
|
||||
_syncIssueTabId -= 1;
|
||||
}
|
||||
|
||||
if (!hidden && _activityTabId == -1) {
|
||||
_activityTabId = _tab->insertTab(0, _activityWidget, Theme::instance()->applicationIcon(), tr("Server Activity"));
|
||||
_protocolTabId += 1;
|
||||
_syncIssueTabId += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,6 +590,15 @@ void ActivitySettings::slotShowActivityTab()
|
|||
}
|
||||
}
|
||||
|
||||
void ActivitySettings::slotShowIssuesTab(const QString &folderAlias)
|
||||
{
|
||||
if (_syncIssueTabId == -1)
|
||||
return;
|
||||
_tab->setCurrentIndex(_syncIssueTabId);
|
||||
|
||||
_issuesWidget->showFolderErrors(folderAlias);
|
||||
}
|
||||
|
||||
void ActivitySettings::slotCopyToClipboard()
|
||||
{
|
||||
QString text;
|
||||
|
@ -603,18 +607,18 @@ void ActivitySettings::slotCopyToClipboard()
|
|||
int idx = _tab->currentIndex();
|
||||
QString message;
|
||||
|
||||
if (idx == 0) {
|
||||
if (idx == _activityTabId) {
|
||||
// the activity widget
|
||||
_activityWidget->storeActivityList(ts);
|
||||
message = tr("The server activity list has been copied to the clipboard.");
|
||||
} else if (idx == 1) {
|
||||
} else if (idx == _protocolTabId) {
|
||||
// the protocol widget
|
||||
_protocolWidget->storeSyncActivity(ts);
|
||||
message = tr("The sync activity list has been copied to the clipboard.");
|
||||
} else if (idx == 2) {
|
||||
} else if (idx == _syncIssueTabId) {
|
||||
// issues Widget
|
||||
message = tr("The list of unsynced items has been copied to the clipboard.");
|
||||
_protocolWidget->storeSyncIssues(ts);
|
||||
_issuesWidget->storeSyncIssues(ts);
|
||||
}
|
||||
|
||||
QApplication::clipboard()->setText(text);
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace OCC {
|
|||
class Account;
|
||||
class AccountStatusPtr;
|
||||
class ProtocolWidget;
|
||||
class IssuesWidget;
|
||||
class JsonApiJob;
|
||||
class NotificationWidget;
|
||||
class ActivityListModel;
|
||||
|
@ -138,6 +139,8 @@ public slots:
|
|||
|
||||
void setNotificationRefreshInterval(quint64 interval);
|
||||
|
||||
void slotShowIssuesTab(const QString &folderAlias);
|
||||
|
||||
private slots:
|
||||
void slotCopyToClipboard();
|
||||
void setActivityTabHidden(bool hidden);
|
||||
|
@ -153,10 +156,12 @@ private:
|
|||
|
||||
QTabWidget *_tab;
|
||||
int _activityTabId;
|
||||
int _protocolTabId;
|
||||
int _syncIssueTabId;
|
||||
|
||||
ActivityWidget *_activityWidget;
|
||||
ProtocolWidget *_protocolWidget;
|
||||
IssuesWidget *_issuesWidget;
|
||||
QProgressIndicator *_progressIndicator;
|
||||
QTimer _notificationCheckTimer;
|
||||
QHash<AccountState *, QElapsedTimer> _timeSinceLastCheck;
|
||||
|
|
|
@ -373,5 +373,15 @@ QRect FolderStatusDelegate::optionsButtonRect(QRect within, Qt::LayoutDirection
|
|||
return QStyle::visualRect(direction, within, r);
|
||||
}
|
||||
|
||||
QRect FolderStatusDelegate::errorsListRect(QRect within)
|
||||
{
|
||||
QFont font = QFont();
|
||||
QFont aliasFont = makeAliasFont(font);
|
||||
QFontMetrics fm(font);
|
||||
QFontMetrics aliasFm(aliasFont);
|
||||
within.setTop(within.top() + FolderStatusDelegate::rootFolderHeightWithoutErrors(fm, aliasFm));
|
||||
return within;
|
||||
}
|
||||
|
||||
|
||||
} // namespace OCC
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
* return the position of the option button within the item
|
||||
*/
|
||||
static QRect optionsButtonRect(QRect within, Qt::LayoutDirection direction);
|
||||
static QRect errorsListRect(QRect within);
|
||||
static int rootFolderHeightWithoutErrors(const QFontMetrics &fm, const QFontMetrics &aliasFm);
|
||||
|
||||
private:
|
||||
|
|
294
src/gui/issueswidget.cpp
Normal file
294
src/gui/issueswidget.cpp
Normal file
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* 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>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <QtWidgets>
|
||||
#endif
|
||||
|
||||
#include "issueswidget.h"
|
||||
#include "configfile.h"
|
||||
#include "syncresult.h"
|
||||
#include "logger.h"
|
||||
#include "utility.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 "ui_issueswidget.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
IssuesWidget::IssuesWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, _ui(new Ui::IssuesWidget)
|
||||
{
|
||||
_ui->setupUi(this);
|
||||
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString, ProgressInfo)),
|
||||
this, SLOT(slotProgressInfo(QString, ProgressInfo)));
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString, SyncFileItemPtr)),
|
||||
this, SLOT(slotItemCompleted(QString, SyncFileItemPtr)));
|
||||
|
||||
connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem *, int)), SLOT(slotOpenFile(QTreeWidgetItem *, int)));
|
||||
connect(_ui->copyIssuesButton, SIGNAL(clicked()), SIGNAL(copyToClipboard()));
|
||||
|
||||
connect(_ui->showIgnores, SIGNAL(toggled(bool)), SLOT(slotRefreshIssues()));
|
||||
connect(_ui->showWarnings, SIGNAL(toggled(bool)), SLOT(slotRefreshIssues()));
|
||||
connect(_ui->filterAccount, SIGNAL(currentIndexChanged(int)), SLOT(slotRefreshIssues()));
|
||||
connect(_ui->filterAccount, SIGNAL(currentIndexChanged(int)), SLOT(slotUpdateFolderFilters()));
|
||||
connect(_ui->filterFolder, SIGNAL(currentIndexChanged(int)), SLOT(slotRefreshIssues()));
|
||||
for (auto account : AccountManager::instance()->accounts()) {
|
||||
slotAccountAdded(account.data());
|
||||
}
|
||||
connect(AccountManager::instance(), SIGNAL(accountAdded(AccountState *)),
|
||||
SLOT(slotAccountAdded(AccountState *)));
|
||||
connect(AccountManager::instance(), SIGNAL(accountRemoved(AccountState *)),
|
||||
SLOT(slotAccountRemoved(AccountState *)));
|
||||
|
||||
|
||||
// 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(ProtocolWidget::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
|
||||
}
|
||||
|
||||
IssuesWidget::~IssuesWidget()
|
||||
{
|
||||
delete _ui;
|
||||
}
|
||||
|
||||
void IssuesWidget::showEvent(QShowEvent *ev)
|
||||
{
|
||||
ConfigFile cfg;
|
||||
cfg.restoreGeometryHeader(_ui->_treeWidget->header());
|
||||
QWidget::showEvent(ev);
|
||||
}
|
||||
|
||||
void IssuesWidget::hideEvent(QHideEvent *ev)
|
||||
{
|
||||
ConfigFile cfg;
|
||||
cfg.saveGeometryHeader(_ui->_treeWidget->header());
|
||||
QWidget::hideEvent(ev);
|
||||
}
|
||||
|
||||
void IssuesWidget::cleanItems(const QString &folder)
|
||||
{
|
||||
// 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);
|
||||
QString itemFolder = item->data(2, Qt::UserRole).toString();
|
||||
if (itemFolder == folder) {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
// update the tabtext
|
||||
emit(issueCountUpdated(_ui->_treeWidget->topLevelItemCount()));
|
||||
}
|
||||
|
||||
void IssuesWidget::slotOpenFile(QTreeWidgetItem *item, int)
|
||||
{
|
||||
QString folderName = item->data(2, Qt::UserRole).toString();
|
||||
QString fileName = item->text(1);
|
||||
|
||||
Folder *folder = FolderMan::instance()->folder(folderName);
|
||||
if (folder) {
|
||||
// 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.isUpdatingEstimates()) {
|
||||
// The sync is restarting, clean the old items
|
||||
cleanItems(folder);
|
||||
} else if (progress.completedFiles() >= progress.totalFiles()) {
|
||||
//Sync completed
|
||||
}
|
||||
}
|
||||
|
||||
void IssuesWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
|
||||
{
|
||||
if (!item->hasErrorStatus())
|
||||
return;
|
||||
QTreeWidgetItem *line = ProtocolWidget::createCompletedTreewidgetItem(folder, *item);
|
||||
if (!line)
|
||||
return;
|
||||
|
||||
_ui->_treeWidget->insertTopLevelItem(0, line);
|
||||
line->setHidden(!shouldBeVisible(line, currentAccountFilter(), currentFolderFilter()));
|
||||
emit issueCountUpdated(_ui->_treeWidget->topLevelItemCount());
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void IssuesWidget::slotAccountAdded(AccountState *account)
|
||||
{
|
||||
_ui->filterAccount->addItem(account->account()->displayName(), QVariant::fromValue(account));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 status = item->data(0, Qt::UserRole);
|
||||
visible &= (_ui->showIgnores->isChecked() || status != SyncFileItem::FileIgnored);
|
||||
visible &= (_ui->showWarnings->isChecked()
|
||||
|| (status != SyncFileItem::SoftError
|
||||
&& status != SyncFileItem::Conflict
|
||||
&& status != SyncFileItem::Restoration));
|
||||
|
||||
auto folderalias = item->data(2, Qt::UserRole).toString();
|
||||
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 (!account) {
|
||||
_ui->filterFolder->setCurrentIndex(0);
|
||||
}
|
||||
_ui->filterFolder->setEnabled(account != 0);
|
||||
|
||||
for (int i = _ui->filterFolder->count() - 1; i >= 1; --i) {
|
||||
_ui->filterFolder->removeItem(i);
|
||||
}
|
||||
for (auto folder : FolderMan::instance()->map().values()) {
|
||||
if (folder->accountState() != account)
|
||||
continue;
|
||||
_ui->filterFolder->addItem(folder->shortGuiLocalPath(), folder->alias());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
82
src/gui/issueswidget.h
Normal file
82
src/gui/issueswidget.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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 "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 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);
|
||||
|
||||
private:
|
||||
AccountState *currentAccountFilter() const;
|
||||
QString currentFolderFilter() const;
|
||||
bool shouldBeVisible(QTreeWidgetItem *item, AccountState *filterAccount,
|
||||
const QString &filterFolderAlias) const;
|
||||
void cleanItems(const QString &folder);
|
||||
|
||||
Ui::IssuesWidget *_ui;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
161
src/gui/issueswidget.ui
Normal file
161
src/gui/issueswidget.ui
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?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="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Account</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="filterAccount">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string><no filter></string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<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><no filter></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="uniformRowHeights">
|
||||
<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">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</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>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -37,13 +37,10 @@ namespace OCC {
|
|||
|
||||
ProtocolWidget::ProtocolWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, IgnoredIndicatorRole(Qt::UserRole + 1)
|
||||
, _ui(new Ui::ProtocolWidget)
|
||||
{
|
||||
_ui->setupUi(this);
|
||||
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString, ProgressInfo)),
|
||||
this, SLOT(slotProgressInfo(QString, ProgressInfo)));
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString, SyncFileItemPtr)),
|
||||
this, SLOT(slotItemCompleted(QString, SyncFileItemPtr)));
|
||||
|
||||
|
@ -81,25 +78,6 @@ ProtocolWidget::ProtocolWidget(QWidget *parent)
|
|||
copyBtn->setToolTip(tr("Copy the activity list to the clipboard."));
|
||||
copyBtn->setEnabled(true);
|
||||
connect(copyBtn, SIGNAL(clicked()), SIGNAL(copyToClipboard()));
|
||||
|
||||
// this view is used to display all errors such as real errors, soft errors and ignored files
|
||||
// it is instantiated here, but made accessible via the method issueWidget() so that it can
|
||||
// be embedded into another gui element.
|
||||
_issueItemView = new QTreeWidget(this);
|
||||
header.removeLast();
|
||||
_issueItemView->setHeaderLabels(header);
|
||||
timestampColumnWidth =
|
||||
ActivityItemDelegate::rowHeight() // icon
|
||||
+ _issueItemView->fontMetrics().width(timeString(QDateTime::currentDateTime()))
|
||||
+ timestampColumnExtra;
|
||||
_issueItemView->setColumnWidth(0, timestampColumnWidth);
|
||||
_issueItemView->setColumnWidth(1, 180);
|
||||
_issueItemView->setColumnCount(4);
|
||||
_issueItemView->setRootIsDecorated(false);
|
||||
_issueItemView->setTextElideMode(Qt::ElideMiddle);
|
||||
_issueItemView->header()->setObjectName("ActivityErrorListHeader");
|
||||
connect(_issueItemView, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
|
||||
SLOT(slotOpenFile(QTreeWidgetItem *, int)));
|
||||
}
|
||||
|
||||
ProtocolWidget::~ProtocolWidget()
|
||||
|
@ -121,23 +99,8 @@ void ProtocolWidget::hideEvent(QHideEvent *ev)
|
|||
QWidget::hideEvent(ev);
|
||||
}
|
||||
|
||||
void ProtocolWidget::cleanItems(const QString &folder)
|
||||
{
|
||||
// The issue list is a state, clear it and let the next sync fill it
|
||||
// with ignored files and propagation errors.
|
||||
int itemCnt = _issueItemView->topLevelItemCount();
|
||||
for (int cnt = itemCnt - 1; cnt >= 0; cnt--) {
|
||||
QTreeWidgetItem *item = _issueItemView->topLevelItem(cnt);
|
||||
QString itemFolder = item->data(2, Qt::UserRole).toString();
|
||||
if (itemFolder == folder) {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
// update the tabtext
|
||||
emit(issueItemCountUpdated(_issueItemView->topLevelItemCount()));
|
||||
}
|
||||
|
||||
QString ProtocolWidget::timeString(QDateTime dt, QLocale::FormatType format) const
|
||||
QString ProtocolWidget::timeString(QDateTime dt, QLocale::FormatType format)
|
||||
{
|
||||
const QLocale loc = QLocale::system();
|
||||
QString dtFormat = loc.dateTimeFormat(format);
|
||||
|
@ -198,50 +161,32 @@ QTreeWidgetItem *ProtocolWidget::createCompletedTreewidgetItem(const QString &fo
|
|||
}
|
||||
|
||||
QTreeWidgetItem *twitem = new QTreeWidgetItem(columns);
|
||||
if (item._status == SyncFileItem::FileIgnored) {
|
||||
// Tell that we want to remove it on the next sync.
|
||||
twitem->setData(0, IgnoredIndicatorRole, true);
|
||||
}
|
||||
|
||||
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);
|
||||
twitem->setData(0, Qt::UserRole, item._status);
|
||||
twitem->setData(2, Qt::UserRole, folder);
|
||||
return twitem;
|
||||
}
|
||||
|
||||
void ProtocolWidget::slotProgressInfo(const QString &folder, const ProgressInfo &progress)
|
||||
{
|
||||
if (!progress.isUpdatingEstimates()) {
|
||||
// The sync is restarting, clean the old items
|
||||
cleanItems(folder);
|
||||
} else if (progress.completedFiles() >= progress.totalFiles()) {
|
||||
//Sync completed
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
|
||||
{
|
||||
if (item->hasErrorStatus())
|
||||
return;
|
||||
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, *item);
|
||||
if (line) {
|
||||
if (item->hasErrorStatus()) {
|
||||
_issueItemView->insertTopLevelItem(0, line);
|
||||
emit issueItemCountUpdated(_issueItemView->topLevelItemCount());
|
||||
} else {
|
||||
// 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);
|
||||
// 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();
|
||||
|
@ -281,36 +226,4 @@ void ProtocolWidget::storeSyncActivity(QTextStream &ts)
|
|||
}
|
||||
}
|
||||
|
||||
void ProtocolWidget::storeSyncIssues(QTextStream &ts)
|
||||
{
|
||||
int topLevelItems = _issueItemView->topLevelItemCount();
|
||||
|
||||
for (int i = 0; i < topLevelItems; i++) {
|
||||
QTreeWidgetItem *child = _issueItemView->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()
|
||||
<< qSetFieldWidth(0)
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,12 +46,13 @@ public:
|
|||
~ProtocolWidget();
|
||||
QSize sizeHint() const { return ownCloudGui::settingsDialogSize(); }
|
||||
|
||||
QTreeWidget *issueWidget() { return _issueItemView; }
|
||||
void storeSyncActivity(QTextStream &ts);
|
||||
void storeSyncIssues(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 slotProgressInfo(const QString &folder, const ProgressInfo &progress);
|
||||
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
|
||||
void slotOpenFile(QTreeWidgetItem *item, int);
|
||||
|
||||
|
@ -61,19 +62,9 @@ protected:
|
|||
|
||||
signals:
|
||||
void copyToClipboard();
|
||||
void issueItemCountUpdated(int);
|
||||
|
||||
private:
|
||||
void setSyncResultStatus(const SyncResult &result);
|
||||
void cleanItems(const QString &folder);
|
||||
|
||||
QTreeWidgetItem *createCompletedTreewidgetItem(const QString &folder, const SyncFileItem &item);
|
||||
|
||||
QString timeString(QDateTime dt, QLocale::FormatType format = QLocale::NarrowFormat) const;
|
||||
|
||||
const int IgnoredIndicatorRole;
|
||||
Ui::ProtocolWidget *_ui;
|
||||
QTreeWidget *_issueItemView;
|
||||
};
|
||||
}
|
||||
#endif // PROTOCOLWIDGET_H
|
||||
|
|
|
@ -211,6 +211,14 @@ void SettingsDialog::showActivityPage()
|
|||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::showIssuesList(const QString &folderAlias)
|
||||
{
|
||||
if (!_activityAction)
|
||||
return;
|
||||
_activityAction->trigger();
|
||||
_activitySettings->slotShowIssuesTab(folderAlias);
|
||||
}
|
||||
|
||||
void SettingsDialog::accountAdded(AccountState *s)
|
||||
{
|
||||
auto height = _toolBar->sizeHint().height();
|
||||
|
@ -242,6 +250,7 @@ void SettingsDialog::accountAdded(AccountState *s)
|
|||
connect(accountSettings, SIGNAL(folderChanged()), _gui, SLOT(slotFoldersChanged()));
|
||||
connect(accountSettings, SIGNAL(openFolderAlias(const QString &)),
|
||||
_gui, SLOT(slotFolderOpenAction(QString)));
|
||||
connect(accountSettings, SIGNAL(showIssuesList(QString)), SLOT(showIssuesList(QString)));
|
||||
connect(s->account().data(), SIGNAL(accountChangedAvatar()), SLOT(slotAccountAvatarChanged()));
|
||||
|
||||
slotRefreshActivity(s);
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
public slots:
|
||||
void showFirstPage();
|
||||
void showActivityPage();
|
||||
void showIssuesList(const QString &folderAlias);
|
||||
void slotSwitchPage(QAction *action);
|
||||
void slotRefreshActivity(AccountState *accountState);
|
||||
void slotAccountAvatarChanged();
|
||||
|
|
|
@ -133,6 +133,14 @@ void SettingsDialogMac::showActivityPage()
|
|||
setCurrentPanelIndex(preferencePanelCount() - 1 - 2);
|
||||
}
|
||||
|
||||
void SettingsDialogMac::showIssuesList(const QString &folderAlias)
|
||||
{
|
||||
// Count backwards (0-based) from the last panel (multiple accounts can be on the left)
|
||||
setCurrentPanelIndex(preferencePanelCount() - 1 - 2);
|
||||
_activitySettings->slotShowIssuesTab(folderAlias);
|
||||
}
|
||||
|
||||
|
||||
void SettingsDialogMac::accountAdded(AccountState *s)
|
||||
{
|
||||
QIcon accountIcon = MacStandardIcon::icon(MacStandardIcon::UserAccounts);
|
||||
|
@ -144,6 +152,7 @@ void SettingsDialogMac::accountAdded(AccountState *s)
|
|||
|
||||
connect(accountSettings, &AccountSettings::folderChanged, _gui, &ownCloudGui::slotFoldersChanged);
|
||||
connect(accountSettings, &AccountSettings::openFolderAlias, _gui, &ownCloudGui::slotFolderOpenAction);
|
||||
connect(accountSettings, &AccountSettings::showIssuesList, this, &SettingsDialogMac::showIssuesList);
|
||||
|
||||
connect(s->account().data(), SIGNAL(accountChangedAvatar()), this, SLOT(slotAccountAvatarChanged()));
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
|
||||
public slots:
|
||||
void showActivityPage();
|
||||
void showIssuesList(const QString &folderAlias);
|
||||
void slotRefreshActivity(AccountState *accountState);
|
||||
|
||||
private slots:
|
||||
|
|
Loading…
Reference in a new issue