More sophisticated progress, add Recent Changes Menu to tray.

ProgressDispatcher now stores a queue of events as well as sync
problems, better known as soft errors. The tray menu displays a
sub menu with 5 recent changes and adds a more... button that
shows a warning icon if soft errors had happend.
More to implement.
This commit is contained in:
Klaas Freitag 2013-07-30 22:22:43 +02:00
parent a0d9d41455
commit a64724be0e
8 changed files with 154 additions and 34 deletions

View file

@ -492,7 +492,7 @@ QString AccountSettings::shortenFilename( const QString& folder, const QString&
return shortFile;
}
void AccountSettings::slotSetProgress( const QString& folder, Progress::Info progress )
void AccountSettings::slotSetProgress(const QString& folder, const Progress::Info &progress )
{
// qDebug() << "================================> Progress for folder " << folder << " file " << file << ": "<< p1;
QStandardItem *item = itemForFolder( folder );

View file

@ -99,6 +99,7 @@ Application::Application(int &argc, char **argv) :
_networkMgr(new QNetworkConfigurationManager(this)),
_sslErrorDialog(0),
_contextMenu(0),
_recentActionsMenu(0),
_theme(Theme::instance()),
_logBrowser(0),
_logExpire(0),
@ -125,6 +126,9 @@ Application::Application(int &argc, char **argv) :
connect( pd, SIGNAL(progressInfo(QString,Progress::Info)), this,
SLOT(slotUpdateProgress(QString,Progress::Info)) );
connect( pd, SIGNAL(progressSyncProblem(QString,Progress::SyncProblem)),
SLOT(slotProgressSyncProblem(QString,Progress::SyncProblem)));
// create folder manager for sync folder management
FolderMan *folderMan = FolderMan::instance();
connect( folderMan, SIGNAL(folderSyncStateChange(QString)),
@ -285,6 +289,10 @@ void Application::setupActions()
_actionStatus = new QAction(tr("Unknown status"), this);
_actionStatus->setEnabled( false );
_actionSettings = new QAction(tr("Settings..."), this);
_actionRecent = new QAction(tr("more..."), this);
_actionRecent->setEnabled( true );
QObject::connect(_actionRecent, SIGNAL(triggered(bool)), SLOT(slotShowRecentChanges()));
QObject::connect(_actionSettings, SIGNAL(triggered(bool)), SLOT(slotSettings()));
_actionHelp = new QAction(tr("Help"), this);
QObject::connect(_actionHelp, SIGNAL(triggered(bool)), SLOT(slotHelp()));
@ -316,8 +324,11 @@ void Application::setupContextMenu()
if( _contextMenu ) {
_contextMenu->clear();
_recentActionsMenu->clear();
_recentActionsMenu->addAction(tr("None."));
} else {
_contextMenu = new QMenu();
_recentActionsMenu = _contextMenu->addMenu(tr("Recent Changes..."));
// this must be called only once after creating the context menu, or
// it will trigger a bug in Ubuntu's SNI bridge patch (11.10, 12.04).
_tray->setContextMenu(_contextMenu);
@ -359,6 +370,7 @@ void Application::setupContextMenu()
_contextMenu->addAction(_actionQuota);
_contextMenu->addSeparator();
_contextMenu->addAction(_actionStatus);
_contextMenu->addMenu(_recentActionsMenu);
_contextMenu->addSeparator();
_contextMenu->addAction(_actionSettings);
_contextMenu->addAction(_actionHelp);
@ -484,23 +496,71 @@ void Application::slotUseMonoIconsChanged(bool)
computeOverallSyncStatus();
}
void Application::slotUpdateProgress(const QString &folder, Progress::Info progress)
void Application::slotProgressSyncProblem(const QString& folder, const Progress::SyncProblem& problem)
{
Q_UNUSED(folder);
Q_UNUSED(problem);
// display a warn icon if warnings happend.
QIcon warnIcon(":/mirall/resources/warning-16");
_actionRecent->setIcon(warnIcon);
rebuildRecentMenus();
}
void Application::rebuildRecentMenus()
{
_recentActionsMenu->clear();
QList<Progress::Info> progressInfoList;
progressInfoList = ProgressDispatcher::instance()->recentChangedItems(5);
if( progressInfoList.size() == 0 ) {
_recentActionsMenu->addAction(tr("No items synced recently"));
} else {
foreach( Progress::Info info, progressInfoList ) {
QString kindStr = tr("Upload");
if( info.kind == Progress::EndDownload ) {
kindStr = tr("Download");
}
QString timeStr = info.timestamp.toString("hh:mm");
QString actionText = tr("%1 (%2, %3)").arg(info.current_file).arg(kindStr).arg(timeStr);
_recentActionsMenu->addAction( actionText );
}
}
// add a more... entry.
_recentActionsMenu->addAction(_actionRecent);
}
void Application::slotUpdateProgress(const QString &folder, const Progress::Info& progress)
{
Q_UNUSED(folder);
// shows an entry in the context menu.
QString curAmount = Utility::octetsToString(progress.overall_current_bytes);
QString totalAmount = Utility::octetsToString(progress.overall_transmission_size);
_actionStatus->setText(tr("Syncing %1 of %2 (%3 of %4) ").arg(progress.current_file_no)
.arg(progress.overall_file_count).arg(curAmount, totalAmount));
// wipe the problem list at start of sync.
if( progress.kind == Progress::StartSync ) {
_actionRecent->setIcon( QIcon() ); // Fixme: Set a "in-progress"-item eventually.
}
// If there was a change in the file list, redo the progress menu.
if( progress.kind == Progress::EndDownload || progress.kind == Progress::EndUpload ) {
rebuildRecentMenus();
}
if (progress.kind == Progress::EndSync) {
rebuildRecentMenus(); // show errors.
QTimer::singleShot(2000, this, SLOT(slotDisplayIdle()));
}
}
void Application::slotDisplayIdle()
{
_actionStatus->setText(tr("Idle"));
_actionStatus->setText(tr("In Sync"));
}
void Application::slotHelp()
@ -577,6 +637,11 @@ void Application::slotFoldersChanged()
setupContextMenu();
}
void Application::slotShowRecentChanges()
{
// not yet here.
}
void Application::slotSettings()
{
if (_settingsDialog.isNull()) {

View file

@ -19,6 +19,7 @@
#include <QNetworkReply>
#include <QSslError>
#include <QPointer>
#include <QQueue>
#include "qtsingleapplication.h"
@ -98,18 +99,22 @@ protected slots:
void slotSetupProxy();
void slotRefreshQuotaDisplay( qint64 total, qint64 used );
void slotUseMonoIconsChanged( bool );
void slotUpdateProgress(const QString&,Progress::Info);
void slotUpdateProgress(const QString&, const Progress::Info&);
void slotProgressSyncProblem(const QString& folder, const Progress::SyncProblem &problem);
void slotDisplayIdle();
void slotHelp();
void slotShowRecentChanges();
private:
void setHelp();
void raiseDialog( QWidget* );
void rebuildRecentMenus();
Systray *_tray;
QAction *_actionOpenoC;
QAction *_actionSettings;
QAction *_actionQuota;
QAction *_actionStatus;
QAction *_actionRecent;
QAction *_actionHelp;
QAction *_actionQuit;
@ -121,6 +126,7 @@ private:
// tray's menu
QMenu *_contextMenu;
QMenu *_recentActionsMenu;
Theme *_theme;
QSignalMapper *_folderOpenActionMapper;
@ -128,6 +134,7 @@ private:
QPointer<SettingsDialog> _settingsDialog;
QString _logFile;
QString _logDirectory;
int _logExpire;
bool _showLogWindow;
bool _logFlush;

View file

@ -395,7 +395,7 @@ void CSyncThread::startSync()
if( walkOk ) {
if( csync_walk_local_tree(_csync_ctx, &walkFinalize, 0) < 0 ||
csync_walk_remote_tree( _csync_ctx, &walkFinalize, 0 ) < 0 ) {
csync_walk_remote_tree(_csync_ctx, &walkFinalize, 0 ) < 0 ) {
qDebug() << "Error in finalize treewalk.";
} else {
// emit the treewalk results.
@ -466,6 +466,7 @@ void CSyncThread::cb_progress( CSYNC_PROGRESS *progress, void *userdata )
pInfo.current_file_no = progress->current_file_no;
pInfo.overall_transmission_size = progress->overall_transmission_size;
pInfo.overall_current_bytes = progress->current_overall_bytes;
pInfo.timestamp = QTime::currentTime();
// Connect to something in folder!
thread->transmissionProgress( pInfo );

View file

@ -630,7 +630,19 @@ void Folder::slotCSyncFinished()
void Folder::slotTransmissionProgress(const Progress::Info& progress)
{
ProgressDispatcher::instance()->setProgressInfo(alias(), progress);
Progress::Info newInfo = progress;
newInfo.folder = alias();
if(newInfo.current_file.startsWith(QLatin1String("ownclouds://")) ||
newInfo.current_file.startsWith(QLatin1String("owncloud://")) ) {
// rip off the whole ownCloud URL.
QString regexp = QString("^owncloud[s]*://.*/remote.php/webdav/%1/").arg(secondPath());
QRegExp re( regexp );
re.setMinimal(true);
newInfo.current_file.remove(re);
}
ProgressDispatcher::instance()->setProgressInfo(alias(), newInfo);
}
ServerActionNotifier::ServerActionNotifier(QObject *parent)
@ -667,7 +679,10 @@ void ServerActionNotifier::slotSyncFinished(const SyncResult &result)
updatedItems++;
if (firstItemUpdated.isEmpty())
firstItemUpdated = item;
break;
break;
case CSYNC_INSTRUCTION_ERROR:
qDebug() << "Got Instruction ERROR. " << result.errorString();
break;
default:
// nothing.
break;

View file

@ -62,7 +62,7 @@ public slots:
void slotSyncFinished(const SyncResult &result);
signals:
void guiLog(const QString&, const QString&);
void sendResults();
private:
};

View file

@ -71,7 +71,8 @@ ProgressDispatcher* ProgressDispatcher::instance() {
}
ProgressDispatcher::ProgressDispatcher(QObject *parent) :
QObject(parent)
QObject(parent),
_problemQueueSize(50)
{
}
@ -81,27 +82,45 @@ ProgressDispatcher::~ProgressDispatcher()
}
void ProgressDispatcher::setProgressInfo(const QString& folder, Progress::Info newProgress)
QList<Progress::Info> ProgressDispatcher::recentChangedItems(int count)
{
return _recentChanges.mid(0, count);
}
QList<Progress::SyncProblem> ProgressDispatcher::recentProblems(int count)
{
return _recentProblems.mid(0, count);
}
void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::Info& progress)
{
if( folder.isEmpty() ) {
return;
}
Progress::Info newProgress = progress;
if( newProgress.kind == Progress::Error ) {
const char *msg = (const char*)newProgress.file_size;
qDebug() << "Progress-Error:" << QString::fromLocal8Bit(msg);
Progress::SyncProblem err;
err.folder = folder;
err.current_file = newProgress.current_file;
err.error_message = QString::fromLocal8Bit( (const char*)newProgress.file_size );
err.error_code = newProgress.file_size;
_recentProblems.enqueue( err );
if( _recentProblems.size() > _problemQueueSize ) {
_recentProblems.dequeue();
}
emit progressSyncProblem( folder, err );
} else {
if( newProgress.kind == Progress::EndSync ) {
newProgress.overall_current_bytes = newProgress.overall_transmission_size;
newProgress.current_file_no = newProgress.overall_file_count;
}
if( newProgress.kind == Progress::EndDownload || newProgress.kind == Progress::EndUpload ) {
_recentChanges.enqueue(newProgress);
}
emit progressInfo( folder, newProgress );
}
if( newProgress.kind == Progress::EndSync ) {
newProgress.overall_current_bytes = newProgress.overall_transmission_size;
newProgress.current_file_no = newProgress.overall_file_count;
}
_lastProgressHash[folder] = newProgress;
emit progressInfo( folder, newProgress );
}
Progress::Info ProgressDispatcher::lastProgressInfo(const QString& folder) {
return _lastProgressHash[folder];
}
}

View file

@ -16,6 +16,8 @@
#include <QObject>
#include <QHash>
#include <QTime>
#include <QQueue>
namespace Mirall {
@ -26,7 +28,7 @@ namespace Mirall {
class Progress
{
public:
enum ProgressKind_s {
typedef enum {
Invalid,
StartSync,
Download,
@ -39,11 +41,11 @@ public:
EndUpload,
EndSync,
Error
};
typedef ProgressKind_s Kind;
} Kind;
struct ProgressInfo_s {
typedef struct {
Kind kind;
QString folder;
QString current_file;
qint64 file_size;
qint64 current_file_bytes;
@ -53,8 +55,16 @@ public:
qint64 overall_transmission_size;
qint64 overall_current_bytes;
};
typedef ProgressInfo_s Info;
QTime timestamp;
} Info;
typedef struct {
QString folder;
QString current_file;
QString error_message;
int error_code;
} SyncProblem;
static QString asString( Kind );
};
@ -77,7 +87,8 @@ public:
static ProgressDispatcher* instance();
~ProgressDispatcher();
Progress::Info lastProgressInfo(const QString& folder);
QList<Progress::Info> recentChangedItems(int count);
QList<Progress::SyncProblem> recentProblems(int count);
signals:
/**
@brief Signals the progress of data transmission.
@ -87,17 +98,19 @@ signals:
*/
void progressInfo( const QString& folder, Progress::Info progress );
void progressInfo( const QString& folder, const Progress::Info& progress );
void progressSyncProblem( const QString& folder, const Progress::SyncProblem& problem );
protected:
void setProgressInfo(const QString &folder, Progress::Info newProgress);
void setProgressInfo(const QString &folder, const Progress::Info& progress);
private:
ProgressDispatcher(QObject* parent = 0);
const int _problemQueueSize;
QQueue<Progress::Info> _recentChanges;
QQueue<Progress::SyncProblem> _recentProblems;
static ProgressDispatcher* _instance;
QHash<QString, Progress::Info> _lastProgressHash;
};
}