2015-10-19 15:41:53 +03:00
|
|
|
/*
|
|
|
|
* 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
|
2016-10-25 12:00:07 +03:00
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
2015-10-19 15:41:53 +03:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
|
2016-03-11 13:37:45 +03:00
|
|
|
#include "activitylistmodel.h"
|
2015-10-19 15:41:53 +03:00
|
|
|
#include "activitywidget.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 "owncloudpropagator.h"
|
2015-11-02 00:27:33 +03:00
|
|
|
#include "account.h"
|
|
|
|
#include "accountstate.h"
|
|
|
|
#include "accountmanager.h"
|
2015-11-03 19:54:37 +03:00
|
|
|
#include "activityitemdelegate.h"
|
2015-11-10 17:12:35 +03:00
|
|
|
#include "protocolwidget.h"
|
2015-11-10 20:10:58 +03:00
|
|
|
#include "QProgressIndicator.h"
|
2016-03-04 19:41:57 +03:00
|
|
|
#include "notificationwidget.h"
|
|
|
|
#include "notificationconfirmjob.h"
|
2016-03-10 19:09:36 +03:00
|
|
|
#include "servernotificationhandler.h"
|
2016-03-11 14:48:31 +03:00
|
|
|
#include "theme.h"
|
2016-03-18 13:25:14 +03:00
|
|
|
#include "ocsjob.h"
|
2015-10-19 15:41:53 +03:00
|
|
|
|
|
|
|
#include "ui_activitywidget.h"
|
|
|
|
|
|
|
|
#include <climits>
|
|
|
|
|
2016-03-18 18:23:21 +03:00
|
|
|
// time span in milliseconds which has to be between two
|
|
|
|
// refreshes of the notifications
|
|
|
|
#define NOTIFICATION_REQUEST_FREE_PERIOD 15000
|
2015-11-19 18:00:22 +03:00
|
|
|
|
2015-10-19 15:41:53 +03:00
|
|
|
namespace OCC {
|
2015-11-12 17:39:07 +03:00
|
|
|
|
2015-11-02 17:44:13 +03:00
|
|
|
/* ==================================================================== */
|
|
|
|
|
|
|
|
ActivityWidget::ActivityWidget(QWidget *parent) :
|
|
|
|
QWidget(parent),
|
2016-03-10 19:09:36 +03:00
|
|
|
_ui(new Ui::ActivityWidget),
|
2016-03-16 18:31:52 +03:00
|
|
|
_notificationRequestsRunning(0)
|
2015-11-02 00:27:33 +03:00
|
|
|
{
|
2015-11-02 17:44:13 +03:00
|
|
|
_ui->setupUi(this);
|
2015-11-02 00:27:33 +03:00
|
|
|
|
2015-11-02 17:44:13 +03:00
|
|
|
// Adjust copyToClipboard() when making changes here!
|
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
_ui->_activityList->setMinimumWidth(400);
|
|
|
|
#endif
|
2015-11-02 00:27:33 +03:00
|
|
|
|
2015-11-02 17:44:13 +03:00
|
|
|
_model = new ActivityListModel(this);
|
2015-11-03 19:54:37 +03:00
|
|
|
ActivityItemDelegate *delegate = new ActivityItemDelegate;
|
|
|
|
delegate->setParent(this);
|
|
|
|
_ui->_activityList->setItemDelegate(delegate);
|
2015-11-04 15:22:03 +03:00
|
|
|
_ui->_activityList->setAlternatingRowColors(true);
|
2015-11-02 17:44:13 +03:00
|
|
|
_ui->_activityList->setModel(_model);
|
2015-11-02 00:27:33 +03:00
|
|
|
|
2016-03-04 19:41:57 +03:00
|
|
|
_ui->_notifyLabel->hide();
|
|
|
|
_ui->_notifyScroll->hide();
|
|
|
|
|
|
|
|
// Create a widget container for the notifications. The ui file defines
|
|
|
|
// a scroll area that get a widget with a layout as children
|
2016-04-11 16:38:25 +03:00
|
|
|
QWidget *w = new QWidget;
|
|
|
|
_notificationsLayout = new QVBoxLayout;
|
2016-03-04 19:41:57 +03:00
|
|
|
w->setLayout(_notificationsLayout);
|
2016-04-11 16:38:25 +03:00
|
|
|
_notificationsLayout->setAlignment(Qt::AlignTop);
|
|
|
|
_ui->_notifyScroll->setAlignment(Qt::AlignTop);
|
2016-03-04 19:41:57 +03:00
|
|
|
_ui->_notifyScroll->setWidget(w);
|
|
|
|
|
2015-11-19 18:00:22 +03:00
|
|
|
showLabels();
|
|
|
|
|
2016-03-08 20:01:42 +03:00
|
|
|
connect(_model, SIGNAL(activityJobStatusCode(AccountState*,int)),
|
|
|
|
this, SLOT(slotAccountActivityStatus(AccountState*,int)));
|
2015-11-10 17:12:35 +03:00
|
|
|
|
2015-11-02 17:44:13 +03:00
|
|
|
_copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
|
|
|
|
_copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
|
2015-11-10 17:12:35 +03:00
|
|
|
connect(_copyBtn, SIGNAL(clicked()), SIGNAL(copyToClipboard()));
|
2015-11-10 20:10:58 +03:00
|
|
|
|
|
|
|
connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(rowsInserted()));
|
2015-11-16 17:31:24 +03:00
|
|
|
|
|
|
|
connect( _ui->_activityList, SIGNAL(activated(QModelIndex)), this,
|
|
|
|
SLOT(slotOpenFile(QModelIndex)));
|
2016-03-23 18:59:03 +03:00
|
|
|
|
|
|
|
connect( &_removeTimer, SIGNAL(timeout()), this, SLOT(slotCheckToCleanWidgets()) );
|
|
|
|
_removeTimer.setInterval(1000);
|
2015-11-02 00:27:33 +03:00
|
|
|
}
|
|
|
|
|
2015-10-19 15:41:53 +03:00
|
|
|
ActivityWidget::~ActivityWidget()
|
|
|
|
{
|
|
|
|
delete _ui;
|
|
|
|
}
|
|
|
|
|
2016-03-18 18:23:21 +03:00
|
|
|
void ActivityWidget::slotRefreshActivities(AccountState *ptr)
|
2015-11-04 18:40:22 +03:00
|
|
|
{
|
|
|
|
_model->slotRefreshActivity(ptr);
|
|
|
|
}
|
|
|
|
|
2016-03-18 18:23:21 +03:00
|
|
|
void ActivityWidget::slotRefreshNotifications(AccountState *ptr)
|
|
|
|
{
|
2016-03-10 19:09:36 +03:00
|
|
|
// start a server notification handler if no notification requests
|
|
|
|
// are running
|
2016-03-16 18:31:52 +03:00
|
|
|
if( _notificationRequestsRunning == 0 ) {
|
2016-03-10 19:09:36 +03:00
|
|
|
ServerNotificationHandler *snh = new ServerNotificationHandler;
|
|
|
|
connect(snh, SIGNAL(newNotificationList(ActivityList)), this,
|
|
|
|
SLOT(slotBuildNotificationDisplay(ActivityList)));
|
|
|
|
|
|
|
|
snh->slotFetchNotifications(ptr);
|
|
|
|
} else {
|
2016-03-14 17:40:39 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << "========> notification request counter not zero.";
|
2016-03-10 19:09:36 +03:00
|
|
|
}
|
2015-11-04 18:40:22 +03:00
|
|
|
}
|
|
|
|
|
2015-11-12 17:39:07 +03:00
|
|
|
void ActivityWidget::slotRemoveAccount( AccountState *ptr )
|
|
|
|
{
|
|
|
|
_model->slotRemoveAccount(ptr);
|
|
|
|
}
|
|
|
|
|
2015-11-19 18:00:22 +03:00
|
|
|
void ActivityWidget::showLabels()
|
|
|
|
{
|
|
|
|
QString t = tr("Server Activities");
|
|
|
|
_ui->_headerLabel->setTextFormat(Qt::RichText);
|
|
|
|
_ui->_headerLabel->setText(t);
|
|
|
|
|
2016-03-04 19:41:57 +03:00
|
|
|
_ui->_notifyLabel->setText(tr("Action Required: Notifications"));
|
|
|
|
|
2015-11-19 18:00:22 +03:00
|
|
|
t.clear();
|
|
|
|
QSetIterator<QString> i(_accountsWithoutActivities);
|
|
|
|
while (i.hasNext() ) {
|
|
|
|
t.append( tr("<br/>Account %1 does not have activities enabled.").arg(i.next()));
|
|
|
|
}
|
|
|
|
_ui->_bottomLabel->setTextFormat(Qt::RichText);
|
|
|
|
_ui->_bottomLabel->setText(t);
|
|
|
|
}
|
|
|
|
|
2016-03-08 20:01:42 +03:00
|
|
|
void ActivityWidget::slotAccountActivityStatus(AccountState *ast, int statusCode)
|
2015-11-19 18:00:22 +03:00
|
|
|
{
|
2016-03-08 20:01:42 +03:00
|
|
|
if( !(ast && ast->account()) ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( statusCode == 999 ) {
|
2015-11-19 18:00:22 +03:00
|
|
|
_accountsWithoutActivities.insert(ast->account()->displayName());
|
2016-03-08 20:01:42 +03:00
|
|
|
} else {
|
|
|
|
_accountsWithoutActivities.remove(ast->account()->displayName());
|
2015-11-19 18:00:22 +03:00
|
|
|
}
|
|
|
|
|
2016-04-14 12:35:16 +03:00
|
|
|
checkActivityTabVisibility();
|
2015-11-19 18:00:22 +03:00
|
|
|
showLabels();
|
|
|
|
}
|
|
|
|
|
2015-10-19 15:41:53 +03:00
|
|
|
// FIXME: Reused from protocol widget. Move over to utilities.
|
|
|
|
QString ActivityWidget::timeString(QDateTime dt, QLocale::FormatType format) const
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-11-10 17:12:35 +03:00
|
|
|
void ActivityWidget::storeActivityList( QTextStream& ts )
|
|
|
|
{
|
|
|
|
ActivityList activities = _model->activityList();
|
|
|
|
|
|
|
|
foreach( Activity activity, activities ) {
|
2015-12-09 17:49:30 +03:00
|
|
|
ts << right
|
2015-11-10 17:12:35 +03:00
|
|
|
// account name
|
|
|
|
<< qSetFieldWidth(30)
|
|
|
|
<< activity._accName
|
2015-12-09 17:49:30 +03:00
|
|
|
// separator
|
|
|
|
<< qSetFieldWidth(0) << ","
|
|
|
|
|
2015-11-10 17:12:35 +03:00
|
|
|
// date and time
|
|
|
|
<< qSetFieldWidth(34)
|
|
|
|
<< activity._dateTime.toString()
|
2015-12-09 17:49:30 +03:00
|
|
|
// separator
|
|
|
|
<< qSetFieldWidth(0) << ","
|
|
|
|
|
2015-11-10 17:12:35 +03:00
|
|
|
// file
|
|
|
|
<< qSetFieldWidth(30)
|
|
|
|
<< activity._file
|
2015-12-09 17:49:30 +03:00
|
|
|
// separator
|
|
|
|
<< qSetFieldWidth(0) << ","
|
|
|
|
|
|
|
|
// subject
|
|
|
|
<< qSetFieldWidth(100)
|
|
|
|
<< activity._subject
|
|
|
|
// separator
|
|
|
|
<< qSetFieldWidth(0) << ","
|
|
|
|
|
2015-11-10 17:12:35 +03:00
|
|
|
// message (mostly empty)
|
|
|
|
<< qSetFieldWidth(55)
|
|
|
|
<< activity._message
|
|
|
|
//
|
|
|
|
<< qSetFieldWidth(0)
|
|
|
|
<< endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-14 12:35:16 +03:00
|
|
|
void ActivityWidget::checkActivityTabVisibility()
|
|
|
|
{
|
|
|
|
int accountCount = AccountManager::instance()->accounts().count();
|
|
|
|
bool hasAccountsWithActivity =
|
|
|
|
_accountsWithoutActivities.count() != accountCount;
|
|
|
|
bool hasNotifications = !_widgetForNotifId.isEmpty();
|
|
|
|
|
|
|
|
_ui->_headerLabel->setVisible( hasAccountsWithActivity );
|
|
|
|
_ui->_activityList->setVisible( hasAccountsWithActivity );
|
|
|
|
|
|
|
|
_ui->_notifyLabel->setVisible( hasNotifications );
|
|
|
|
_ui->_notifyScroll->setVisible( hasNotifications );
|
|
|
|
|
|
|
|
emit hideActivityTab(!hasAccountsWithActivity && !hasNotifications);
|
|
|
|
}
|
|
|
|
|
2015-11-16 17:31:24 +03:00
|
|
|
void ActivityWidget::slotOpenFile(QModelIndex indx)
|
2015-10-19 15:41:53 +03:00
|
|
|
{
|
2016-03-14 17:40:39 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << indx.isValid() << indx.data(ActivityItemDelegate::PathRole).toString() << QFile::exists(indx.data(ActivityItemDelegate::PathRole).toString());
|
2015-11-16 17:31:24 +03:00
|
|
|
if( indx.isValid() ) {
|
|
|
|
QString fullPath = indx.data(ActivityItemDelegate::PathRole).toString();
|
|
|
|
|
|
|
|
if (QFile::exists(fullPath)) {
|
2015-10-19 15:41:53 +03:00
|
|
|
showInFileManager(fullPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-22 12:35:24 +03:00
|
|
|
// GUI: Display the notifications.
|
|
|
|
// All notifications in list are coming from the same account
|
|
|
|
// but in the _widgetForNotifId hash widgets for all accounts are
|
|
|
|
// collected.
|
2016-03-10 19:09:36 +03:00
|
|
|
void ActivityWidget::slotBuildNotificationDisplay(const ActivityList& list)
|
2016-03-04 19:41:57 +03:00
|
|
|
{
|
2016-03-11 14:48:31 +03:00
|
|
|
QHash<QString, int> accNotified;
|
2016-03-22 12:35:24 +03:00
|
|
|
QString listAccountName;
|
2016-03-11 14:48:31 +03:00
|
|
|
|
2016-05-12 12:47:42 +03:00
|
|
|
// Whether a new notification widget was added to the notificationLayout.
|
|
|
|
bool newNotificationShown = false;
|
|
|
|
|
2016-03-10 19:09:36 +03:00
|
|
|
foreach( auto activity, list ) {
|
2016-03-29 17:50:58 +03:00
|
|
|
if( _blacklistedNotifications.contains(activity)) {
|
2016-03-23 18:59:03 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << "Activity in blacklist, skip";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-03-10 19:09:36 +03:00
|
|
|
NotificationWidget *widget = 0;
|
2016-03-04 19:41:57 +03:00
|
|
|
|
2016-03-23 18:59:03 +03:00
|
|
|
if( _widgetForNotifId.contains( activity.ident()) ) {
|
|
|
|
widget = _widgetForNotifId[activity.ident()];
|
2016-03-10 19:09:36 +03:00
|
|
|
} else {
|
|
|
|
widget = new NotificationWidget(this);
|
2016-03-29 18:18:02 +03:00
|
|
|
connect(widget, SIGNAL(sendNotificationRequest(QString, QString, QByteArray)),
|
|
|
|
this, SLOT(slotSendNotificationRequest(QString, QString, QByteArray)));
|
2016-03-23 18:59:03 +03:00
|
|
|
connect(widget, SIGNAL(requestCleanupAndBlacklist(Activity)),
|
|
|
|
this, SLOT(slotRequestCleanupAndBlacklist(Activity)));
|
|
|
|
|
2016-03-10 19:09:36 +03:00
|
|
|
_notificationsLayout->addWidget(widget);
|
|
|
|
// _ui->_notifyScroll->setMinimumHeight( widget->height());
|
2016-04-11 16:26:57 +03:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
|
2016-03-10 19:09:36 +03:00
|
|
|
_ui->_notifyScroll->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
|
2016-04-11 16:26:57 +03:00
|
|
|
#endif
|
2016-03-23 18:59:03 +03:00
|
|
|
_widgetForNotifId[activity.ident()] = widget;
|
2016-05-12 12:47:42 +03:00
|
|
|
newNotificationShown = true;
|
2016-03-04 19:41:57 +03:00
|
|
|
}
|
|
|
|
|
2016-03-10 19:09:36 +03:00
|
|
|
widget->setActivity( activity );
|
|
|
|
|
2016-03-22 12:35:24 +03:00
|
|
|
// remember the list account name for the strayCat handling below.
|
|
|
|
listAccountName = activity._accName;
|
|
|
|
|
2016-03-10 16:49:31 +03:00
|
|
|
// handle gui logs. In order to NOT annoy the user with every fetching of the
|
|
|
|
// notifications the notification id is stored in a Set. Only if an id
|
|
|
|
// is not in the set, it qualifies for guiLog.
|
|
|
|
// Important: The _guiLoggedNotifications set must be wiped regularly which
|
|
|
|
// will repeat the gui log.
|
|
|
|
|
|
|
|
// after one hour, clear the gui log notification store
|
2016-03-10 19:09:36 +03:00
|
|
|
if( _guiLogTimer.elapsed() > 60*60*1000 ) {
|
2016-03-10 16:49:31 +03:00
|
|
|
_guiLoggedNotifications.clear();
|
|
|
|
}
|
2016-03-10 19:09:36 +03:00
|
|
|
if( !_guiLoggedNotifications.contains(activity._id)) {
|
2016-03-11 14:48:31 +03:00
|
|
|
QString host = activity._accName;
|
|
|
|
// store the name of the account that sends the notification to be
|
|
|
|
// able to add it to the tray notification
|
|
|
|
// remove the user name from the account as that is not accurate here.
|
|
|
|
int indx = host.indexOf(QChar('@'));
|
|
|
|
if( indx>-1 ) {
|
|
|
|
host.remove(0, 1+indx);
|
|
|
|
}
|
|
|
|
if( !host.isEmpty() ) {
|
|
|
|
if( accNotified.contains(host)) {
|
|
|
|
accNotified[host] = accNotified[host]+1;
|
|
|
|
} else {
|
|
|
|
accNotified[host] = 1;
|
|
|
|
}
|
|
|
|
}
|
2016-03-10 19:09:36 +03:00
|
|
|
_guiLoggedNotifications.insert(activity._id);
|
2016-03-10 16:49:31 +03:00
|
|
|
}
|
2016-03-04 19:41:57 +03:00
|
|
|
}
|
2016-03-10 19:09:36 +03:00
|
|
|
|
2016-03-23 18:59:03 +03:00
|
|
|
// check if there are widgets that have no corresponding activity from
|
2016-03-21 18:26:37 +03:00
|
|
|
// the server any more. Collect them in a list
|
2016-03-23 18:59:03 +03:00
|
|
|
QList< Activity::Identifier > strayCats;
|
2016-03-21 18:26:37 +03:00
|
|
|
foreach( auto id, _widgetForNotifId.keys() ) {
|
2016-03-22 12:35:24 +03:00
|
|
|
NotificationWidget *widget = _widgetForNotifId[id];
|
|
|
|
|
2016-03-23 18:59:03 +03:00
|
|
|
bool found = false;
|
2016-03-22 12:35:24 +03:00
|
|
|
// do not mark widgets of other accounts to delete.
|
2016-03-23 18:59:03 +03:00
|
|
|
if( widget->activity()._accName != listAccountName ) {
|
2016-03-22 12:35:24 +03:00
|
|
|
continue;
|
|
|
|
}
|
2016-03-23 18:59:03 +03:00
|
|
|
|
2016-03-21 18:26:37 +03:00
|
|
|
foreach( auto activity, list ) {
|
2016-03-23 18:59:03 +03:00
|
|
|
if( activity.ident() == id ) {
|
2016-03-21 18:26:37 +03:00
|
|
|
// found an activity
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( ! found ) {
|
|
|
|
// the activity does not exist any more.
|
|
|
|
strayCats.append(id);
|
|
|
|
}
|
|
|
|
}
|
2016-03-22 12:35:24 +03:00
|
|
|
|
2016-03-21 18:26:37 +03:00
|
|
|
// .. and now delete all these stray cat widgets.
|
|
|
|
foreach( auto strayCatId, strayCats ) {
|
|
|
|
NotificationWidget *widgetToGo = _widgetForNotifId[strayCatId];
|
2016-03-23 18:59:03 +03:00
|
|
|
scheduleWidgetToRemove(widgetToGo, 0);
|
2016-03-21 18:26:37 +03:00
|
|
|
}
|
|
|
|
|
2016-04-14 12:35:16 +03:00
|
|
|
checkActivityTabVisibility();
|
2016-03-09 19:22:19 +03:00
|
|
|
|
2016-03-14 16:41:21 +03:00
|
|
|
int newGuiLogCount = accNotified.count();
|
|
|
|
|
|
|
|
if( newGuiLogCount > 0 ) {
|
2016-03-10 16:49:31 +03:00
|
|
|
// restart the gui log timer now that we show a notification
|
|
|
|
_guiLogTimer.restart();
|
|
|
|
|
2016-03-11 14:48:31 +03:00
|
|
|
// Assemble a tray notification
|
2016-03-14 18:21:04 +03:00
|
|
|
QString msg = tr("You received %n new notification(s) from %2.", "", accNotified[accNotified.keys().at(0)]).
|
2016-03-14 16:41:21 +03:00
|
|
|
arg(accNotified.keys().at(0));
|
|
|
|
|
|
|
|
if( newGuiLogCount >= 2 ) {
|
|
|
|
QString acc1 = accNotified.keys().at(0);
|
|
|
|
QString acc2 = accNotified.keys().at(1);
|
|
|
|
if( newGuiLogCount == 2 ) {
|
|
|
|
int notiCount = accNotified[ acc1 ] + accNotified[ acc2 ];
|
2016-03-29 18:18:53 +03:00
|
|
|
msg = tr("You received %n new notification(s) from %1 and %2.", "", notiCount).arg(acc1, acc2);
|
2016-03-11 14:48:31 +03:00
|
|
|
} else {
|
2016-03-29 18:18:53 +03:00
|
|
|
msg = tr("You received new notifications from %1, %2 and other accounts.").arg(acc1, acc2);
|
2016-03-11 14:48:31 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-29 18:18:53 +03:00
|
|
|
const QString log = tr("%1 Notifications - Action Required").arg(Theme::instance()->appNameGUI());
|
|
|
|
emit guiLog( log, msg);
|
2016-03-10 16:49:31 +03:00
|
|
|
}
|
2016-05-12 12:47:42 +03:00
|
|
|
|
|
|
|
if (newNotificationShown) {
|
|
|
|
emit newNotification();
|
|
|
|
}
|
2016-03-04 19:41:57 +03:00
|
|
|
}
|
|
|
|
|
2016-03-29 18:18:53 +03:00
|
|
|
void ActivityWidget::slotSendNotificationRequest(const QString& accountName, const QString& link, const QByteArray& verb)
|
2016-03-04 19:41:57 +03:00
|
|
|
{
|
2016-03-14 17:40:39 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << "Server Notification Request " << verb << link << "on account" << accountName;
|
2016-03-09 17:21:52 +03:00
|
|
|
NotificationWidget *theSender = qobject_cast<NotificationWidget*>(sender());
|
2016-03-04 19:41:57 +03:00
|
|
|
|
|
|
|
const QStringList validVerbs = QStringList() << "GET" << "PUT" << "POST" << "DELETE";
|
|
|
|
|
|
|
|
if( validVerbs.contains(verb)) {
|
|
|
|
AccountStatePtr acc = AccountManager::instance()->account(accountName);
|
|
|
|
if( acc ) {
|
|
|
|
NotificationConfirmJob *job = new NotificationConfirmJob(acc->account());
|
2016-03-09 17:21:52 +03:00
|
|
|
QUrl l(link);
|
2016-03-04 19:41:57 +03:00
|
|
|
job->setLinkAndVerb(l, verb);
|
2016-03-09 17:21:52 +03:00
|
|
|
job->setWidget(theSender);
|
2016-03-04 19:41:57 +03:00
|
|
|
connect( job, SIGNAL( networkError(QNetworkReply*)),
|
|
|
|
this, SLOT(slotNotifyNetworkError(QNetworkReply*)));
|
|
|
|
connect( job, SIGNAL( jobFinished(QString, int)),
|
|
|
|
this, SLOT(slotNotifyServerFinished(QString, int)) );
|
|
|
|
job->start();
|
2016-03-10 19:09:36 +03:00
|
|
|
|
|
|
|
// count the number of running notification requests. If this member var
|
|
|
|
// is larger than zero, no new fetching of notifications is started
|
2016-03-16 18:31:52 +03:00
|
|
|
_notificationRequestsRunning++;
|
2016-03-04 19:41:57 +03:00
|
|
|
}
|
|
|
|
} else {
|
2016-03-14 17:40:39 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << "Notification Links: Invalid verb:" << verb;
|
2016-03-04 19:41:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-09 17:21:52 +03:00
|
|
|
void ActivityWidget::endNotificationRequest( NotificationWidget *widget, int replyCode )
|
|
|
|
{
|
2016-03-16 18:31:52 +03:00
|
|
|
_notificationRequestsRunning--;
|
2016-03-09 17:21:52 +03:00
|
|
|
if( widget ) {
|
|
|
|
widget->slotNotificationRequestFinished(replyCode);
|
|
|
|
}
|
|
|
|
}
|
2016-03-04 19:41:57 +03:00
|
|
|
|
2016-03-09 17:21:52 +03:00
|
|
|
void ActivityWidget::slotNotifyNetworkError( QNetworkReply *reply)
|
2016-03-04 19:41:57 +03:00
|
|
|
{
|
2016-03-09 17:21:52 +03:00
|
|
|
NotificationConfirmJob *job = qobject_cast<NotificationConfirmJob*>(sender());
|
|
|
|
if( !job ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int resultCode =0;
|
|
|
|
if( reply ) {
|
|
|
|
resultCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
endNotificationRequest(job->widget(), resultCode);
|
2016-03-14 17:40:39 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << "Server notify job failed with code " << resultCode;
|
2016-03-09 17:21:52 +03:00
|
|
|
|
2016-03-04 19:41:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ActivityWidget::slotNotifyServerFinished( const QString& reply, int replyCode )
|
|
|
|
{
|
2016-03-09 17:21:52 +03:00
|
|
|
NotificationConfirmJob *job = qobject_cast<NotificationConfirmJob*>(sender());
|
|
|
|
if( !job ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
endNotificationRequest(job->widget(), replyCode);
|
2016-03-04 19:41:57 +03:00
|
|
|
// FIXME: remove the widget after a couple of seconds
|
2016-03-14 17:40:39 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << "Server Notification reply code"<< replyCode << reply;
|
2016-03-18 13:25:14 +03:00
|
|
|
|
|
|
|
// if the notification was successful start a timer that triggers
|
|
|
|
// removal of the done widgets in a few seconds
|
|
|
|
// Add 200 millisecs to the predefined value to make sure that the timer in
|
|
|
|
// widget's method readyToClose() has elapsed.
|
|
|
|
if( replyCode == OCS_SUCCESS_STATUS_CODE ) {
|
2016-03-23 18:59:03 +03:00
|
|
|
scheduleWidgetToRemove( job->widget() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// blacklist the activity coming in here.
|
|
|
|
void ActivityWidget::slotRequestCleanupAndBlacklist(const Activity& blacklistActivity)
|
|
|
|
{
|
2016-03-29 17:50:58 +03:00
|
|
|
if ( ! _blacklistedNotifications.contains(blacklistActivity) ) {
|
|
|
|
_blacklistedNotifications.append(blacklistActivity);
|
2016-03-18 13:25:14 +03:00
|
|
|
}
|
2016-03-23 18:59:03 +03:00
|
|
|
|
|
|
|
NotificationWidget *widget = _widgetForNotifId[ blacklistActivity.ident() ];
|
|
|
|
scheduleWidgetToRemove(widget);
|
2016-03-18 13:25:14 +03:00
|
|
|
}
|
|
|
|
|
2016-03-23 18:59:03 +03:00
|
|
|
void ActivityWidget::scheduleWidgetToRemove(NotificationWidget *widget, int milliseconds)
|
2016-03-18 13:25:14 +03:00
|
|
|
{
|
2016-03-23 18:59:03 +03:00
|
|
|
if( !widget ) {
|
|
|
|
return;
|
|
|
|
}
|
2016-04-11 16:27:29 +03:00
|
|
|
// in five seconds from now, remove the widget.
|
|
|
|
QDateTime removeTime = QDateTime::currentDateTimeUtc().addMSecs(milliseconds);
|
|
|
|
QDateTime &it = _widgetsToRemove[widget];
|
|
|
|
if (!it.isValid() || it > removeTime) {
|
|
|
|
it = removeTime;
|
|
|
|
}
|
|
|
|
if( !_removeTimer.isActive() ) {
|
|
|
|
_removeTimer.start();
|
2016-03-23 18:59:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Called every second to see if widgets need to be removed.
|
|
|
|
void ActivityWidget::slotCheckToCleanWidgets()
|
|
|
|
{
|
2016-04-11 16:27:29 +03:00
|
|
|
auto currentTime = QDateTime::currentDateTimeUtc();
|
|
|
|
auto it = _widgetsToRemove.begin();
|
|
|
|
while (it != _widgetsToRemove.end()) {
|
|
|
|
// loop over all widgets in the to-remove queue
|
|
|
|
QDateTime t = it.value();
|
|
|
|
NotificationWidget *widget = it.key();
|
|
|
|
|
|
|
|
if( currentTime > t ) {
|
2016-03-23 18:59:03 +03:00
|
|
|
// found one to remove!
|
|
|
|
Activity::Identifier id = widget->activity().ident();
|
2016-03-18 13:25:14 +03:00
|
|
|
_widgetForNotifId.remove(id);
|
2016-03-23 18:59:03 +03:00
|
|
|
widget->deleteLater();
|
2016-04-11 16:27:29 +03:00
|
|
|
it = _widgetsToRemove.erase(it);
|
|
|
|
} else {
|
|
|
|
++it;
|
2016-03-18 13:25:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-23 18:59:03 +03:00
|
|
|
if( _widgetsToRemove.isEmpty() ) {
|
|
|
|
_removeTimer.stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
// check to see if the whole notification pane should be hidden
|
2016-03-18 13:25:14 +03:00
|
|
|
if( _widgetForNotifId.isEmpty() ) {
|
|
|
|
_ui->_notifyLabel->setHidden(true);
|
|
|
|
_ui->_notifyScroll->setHidden(true);
|
|
|
|
}
|
2016-03-04 19:41:57 +03:00
|
|
|
}
|
|
|
|
|
2016-03-18 13:25:14 +03:00
|
|
|
|
2015-11-16 17:38:08 +03:00
|
|
|
/* ==================================================================== */
|
2015-11-10 17:12:35 +03:00
|
|
|
|
|
|
|
ActivitySettings::ActivitySettings(QWidget *parent)
|
|
|
|
:QWidget(parent)
|
|
|
|
{
|
|
|
|
QHBoxLayout *hbox = new QHBoxLayout(this);
|
|
|
|
setLayout(hbox);
|
|
|
|
|
|
|
|
// create a tab widget for the three activity views
|
|
|
|
_tab = new QTabWidget(this);
|
|
|
|
hbox->addWidget(_tab);
|
|
|
|
_activityWidget = new ActivityWidget(this);
|
2016-03-08 20:01:42 +03:00
|
|
|
_activityTabId = _tab->insertTab(0, _activityWidget, Theme::instance()->applicationIcon(), tr("Server Activity"));
|
2015-11-10 17:12:35 +03:00
|
|
|
connect(_activityWidget, SIGNAL(copyToClipboard()), this, SLOT(slotCopyToClipboard()));
|
2016-04-14 11:59:40 +03:00
|
|
|
connect(_activityWidget, SIGNAL(hideActivityTab(bool)), this, SLOT(setActivityTabHidden(bool)));
|
2016-03-10 16:49:31 +03:00
|
|
|
connect(_activityWidget, SIGNAL(guiLog(QString,QString)), this, SIGNAL(guiLog(QString,QString)));
|
2016-05-12 12:47:42 +03:00
|
|
|
connect(_activityWidget, SIGNAL(newNotification()), SLOT(slotShowActivityTab()));
|
2015-11-10 20:10:58 +03:00
|
|
|
|
2015-11-10 17:12:35 +03:00
|
|
|
_protocolWidget = new ProtocolWidget(this);
|
2016-03-08 20:01:42 +03:00
|
|
|
_tab->insertTab(1, _protocolWidget, Theme::instance()->syncStateIcon(SyncResult::Success), tr("Sync Protocol"));
|
2015-11-10 17:12:35 +03:00
|
|
|
connect(_protocolWidget, SIGNAL(copyToClipboard()), this, SLOT(slotCopyToClipboard()));
|
2016-04-05 14:57:38 +03:00
|
|
|
connect(_protocolWidget, SIGNAL(issueItemCountUpdated(int)),
|
|
|
|
this, SLOT(slotShowIssueItemCount(int)));
|
2015-11-10 17:12:35 +03:00
|
|
|
|
|
|
|
// Add the not-synced list into the tab
|
|
|
|
QWidget *w = new QWidget;
|
2015-11-18 17:29:16 +03:00
|
|
|
QVBoxLayout *vbox2 = new QVBoxLayout(w);
|
2015-11-26 23:40:46 +03:00
|
|
|
vbox2->addWidget(new QLabel(tr("List of ignored or erroneous files"), this));
|
2015-11-10 20:10:58 +03:00
|
|
|
vbox2->addWidget(_protocolWidget->issueWidget());
|
2015-11-10 17:12:35 +03:00
|
|
|
QDialogButtonBox *dlgButtonBox = new QDialogButtonBox(this);
|
2015-11-10 20:10:58 +03:00
|
|
|
vbox2->addWidget(dlgButtonBox);
|
2015-11-10 17:12:35 +03:00
|
|
|
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()));
|
|
|
|
|
2015-11-10 20:10:58 +03:00
|
|
|
w->setLayout(vbox2);
|
2016-04-05 14:57:38 +03:00
|
|
|
_syncIssueTabId = _tab->insertTab(2, w, Theme::instance()->syncStateIcon(SyncResult::Problem), QString());
|
|
|
|
slotShowIssueItemCount(0); // to display the label.
|
2015-11-10 20:10:58 +03:00
|
|
|
|
|
|
|
// Add a progress indicator to spin if the acitivity list is updated.
|
|
|
|
_progressIndicator = new QProgressIndicator(this);
|
|
|
|
_tab->setCornerWidget(_progressIndicator);
|
|
|
|
|
2016-03-18 18:23:21 +03:00
|
|
|
connect(&_notificationCheckTimer, SIGNAL(timeout()),
|
|
|
|
this, SLOT(slotRegularNotificationCheck()));
|
|
|
|
|
2015-11-10 20:10:58 +03:00
|
|
|
// connect a model signal to stop the animation.
|
|
|
|
connect(_activityWidget, SIGNAL(rowsInserted()), _progressIndicator, SLOT(stopAnimation()));
|
2016-03-11 18:08:15 +03:00
|
|
|
|
|
|
|
// We want the protocol be the default
|
|
|
|
_tab->setCurrentIndex(1);
|
2015-11-10 17:12:35 +03:00
|
|
|
}
|
|
|
|
|
2016-03-18 18:23:21 +03:00
|
|
|
void ActivitySettings::setNotificationRefreshInterval( quint64 interval )
|
|
|
|
{
|
|
|
|
qDebug() << "Starting Notification refresh timer with " << interval/1000 << " sec interval";
|
|
|
|
_notificationCheckTimer.start(interval);
|
|
|
|
}
|
|
|
|
|
2016-03-08 20:01:42 +03:00
|
|
|
void ActivitySettings::setActivityTabHidden(bool hidden)
|
|
|
|
{
|
|
|
|
if( hidden && _activityTabId > -1 ) {
|
|
|
|
_tab->removeTab(_activityTabId);
|
|
|
|
_activityTabId = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !hidden && _activityTabId == -1 ) {
|
|
|
|
_activityTabId = _tab->insertTab(0, _activityWidget, Theme::instance()->applicationIcon(), tr("Server Activity"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-05 14:57:38 +03:00
|
|
|
void ActivitySettings::slotShowIssueItemCount(int cnt)
|
|
|
|
{
|
|
|
|
QString cntText = tr("Not Synced");
|
|
|
|
if( cnt ) {
|
2016-04-07 10:18:51 +03:00
|
|
|
//: %1 is the number of not synced files.
|
|
|
|
cntText = tr("Not Synced (%1)").arg(cnt);
|
2016-04-05 14:57:38 +03:00
|
|
|
}
|
2016-04-11 16:26:57 +03:00
|
|
|
_tab->setTabText(_syncIssueTabId, cntText);
|
2016-04-05 14:57:38 +03:00
|
|
|
}
|
|
|
|
|
2016-05-12 12:47:42 +03:00
|
|
|
void ActivitySettings::slotShowActivityTab()
|
|
|
|
{
|
|
|
|
if (_activityTabId != -1) {
|
|
|
|
_tab->setCurrentIndex(_activityTabId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-10 17:12:35 +03:00
|
|
|
void ActivitySettings::slotCopyToClipboard()
|
|
|
|
{
|
|
|
|
QString text;
|
|
|
|
QTextStream ts(&text);
|
|
|
|
|
|
|
|
int idx = _tab->currentIndex();
|
2016-01-06 18:50:59 +03:00
|
|
|
QString message;
|
2015-11-10 17:12:35 +03:00
|
|
|
|
|
|
|
if( idx == 0 ) {
|
|
|
|
// the activity widget
|
|
|
|
_activityWidget->storeActivityList(ts);
|
2016-01-06 18:50:59 +03:00
|
|
|
message = tr("The server activity list has been copied to the clipboard.");
|
2015-11-10 17:12:35 +03:00
|
|
|
} else if(idx == 1 ) {
|
|
|
|
// the protocol widget
|
|
|
|
_protocolWidget->storeSyncActivity(ts);
|
2016-01-06 18:50:59 +03:00
|
|
|
message = tr("The sync activity list has been copied to the clipboard.");
|
2015-11-10 17:12:35 +03:00
|
|
|
} else if(idx == 2 ) {
|
|
|
|
// issues Widget
|
2016-11-22 12:15:21 +03:00
|
|
|
message = tr("The list of unsynced items has been copied to the clipboard.");
|
2015-11-10 17:12:35 +03:00
|
|
|
_protocolWidget->storeSyncIssues(ts);
|
|
|
|
}
|
|
|
|
|
|
|
|
QApplication::clipboard()->setText(text);
|
2016-01-06 18:50:59 +03:00
|
|
|
emit guiLog(tr("Copied to clipboard"), message);
|
2015-11-10 17:12:35 +03:00
|
|
|
}
|
|
|
|
|
2015-11-12 17:39:07 +03:00
|
|
|
void ActivitySettings::slotRemoveAccount( AccountState *ptr )
|
|
|
|
{
|
|
|
|
_activityWidget->slotRemoveAccount(ptr);
|
|
|
|
}
|
|
|
|
|
2015-11-10 17:12:35 +03:00
|
|
|
void ActivitySettings::slotRefresh( AccountState* ptr )
|
|
|
|
{
|
2016-04-14 12:35:16 +03:00
|
|
|
// QElapsedTimer isn't actually constructed as invalid.
|
|
|
|
if ( !_timeSinceLastCheck.contains(ptr) ) {
|
|
|
|
_timeSinceLastCheck[ptr].invalidate();
|
|
|
|
}
|
|
|
|
QElapsedTimer & timer = _timeSinceLastCheck[ptr];
|
2016-03-22 11:58:30 +03:00
|
|
|
|
2016-03-18 18:23:21 +03:00
|
|
|
// Fetch Activities only if visible and if last check is longer than 15 secs ago
|
2016-03-22 11:58:30 +03:00
|
|
|
if( timer.isValid() && timer.elapsed() < NOTIFICATION_REQUEST_FREE_PERIOD ) {
|
|
|
|
qDebug() << Q_FUNC_INFO << "do not check as last check is only secs ago: " << timer.elapsed() / 1000;
|
2016-03-18 18:23:21 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( ptr && ptr->isConnected() ) {
|
2016-04-14 12:35:16 +03:00
|
|
|
if( isVisible() || !timer.isValid() ) {
|
2016-03-18 18:23:21 +03:00
|
|
|
_progressIndicator->startAnimation();
|
|
|
|
_activityWidget->slotRefreshActivities( ptr);
|
|
|
|
}
|
|
|
|
_activityWidget->slotRefreshNotifications(ptr);
|
2016-04-14 12:35:16 +03:00
|
|
|
timer.start();
|
2016-03-18 18:23:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActivitySettings::slotRegularNotificationCheck()
|
|
|
|
{
|
|
|
|
AccountManager *am = AccountManager::instance();
|
|
|
|
foreach (AccountStatePtr a, am->accounts()) {
|
|
|
|
slotRefresh(a.data());
|
2015-11-17 17:05:54 +03:00
|
|
|
}
|
2015-11-10 17:12:35 +03:00
|
|
|
}
|
|
|
|
|
2015-11-18 17:25:29 +03:00
|
|
|
bool ActivitySettings::event(QEvent* e)
|
|
|
|
{
|
|
|
|
if (e->type() == QEvent::Show) {
|
|
|
|
AccountManager *am = AccountManager::instance();
|
|
|
|
foreach (AccountStatePtr a, am->accounts()) {
|
|
|
|
slotRefresh(a.data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return QWidget::event(e);
|
|
|
|
}
|
|
|
|
|
2015-11-10 17:12:35 +03:00
|
|
|
ActivitySettings::~ActivitySettings()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-19 15:41:53 +03:00
|
|
|
}
|