Added itemprogressdialog class to show the sync progress and problems.

This commit is contained in:
Klaas Freitag 2013-08-01 14:34:31 +02:00
parent 43ae3dfce5
commit a25d9fd3b4
8 changed files with 436 additions and 8 deletions

View file

@ -25,6 +25,7 @@ mirall/networksettings.ui
mirall/accountsettings.ui mirall/accountsettings.ui
mirall/ignorelisteditor.ui mirall/ignorelisteditor.ui
mirall/fileitemdialog.ui mirall/fileitemdialog.ui
mirall/itemprogressdialog.ui
) )
set(3rdparty_SRC set(3rdparty_SRC
@ -164,6 +165,7 @@ set(mirall_SRCS
mirall/networksettings.cpp mirall/networksettings.cpp
mirall/accountsettings.cpp mirall/accountsettings.cpp
mirall/ignorelisteditor.cpp mirall/ignorelisteditor.cpp
mirall/itemprogressdialog.cpp
) )
set(mirall_HEADERS set(mirall_HEADERS
@ -182,6 +184,7 @@ set(mirall_HEADERS
mirall/networksettings.h mirall/networksettings.h
mirall/accountsettings.h mirall/accountsettings.h
mirall/ignorelisteditor.h mirall/ignorelisteditor.h
mirall/itemprogressdialog.h
) )
if( UNIX AND NOT APPLE) if( UNIX AND NOT APPLE)

View file

@ -27,6 +27,7 @@
#include "mirall/owncloudsetupwizard.h" #include "mirall/owncloudsetupwizard.h"
#include "mirall/mirallconfigfile.h" #include "mirall/mirallconfigfile.h"
#include "mirall/ignorelisteditor.h" #include "mirall/ignorelisteditor.h"
#include "mirall/itemprogressdialog.h"
#include <math.h> #include <math.h>
@ -386,11 +387,11 @@ void AccountSettings::slotUpdateFolderState( Folder *folder )
item = _model->item( ++row ); item = _model->item( ++row );
} }
#if 0
if( !_fileItemDialog.isNull() && _fileItemDialog->isVisible() ) { if( !_fileItemDialog.isNull() && _fileItemDialog->isVisible() ) {
_fileItemDialog->setSyncResult( FolderMan::instance()->syncResult(folder) ); _fileItemDialog->setSyncResult( FolderMan::instance()->syncResult(folder) );
} }
#endif
if( item ) { if( item ) {
folderToModelItem( item, folder ); folderToModelItem( item, folder );
} else { } else {
@ -641,13 +642,14 @@ void AccountSettings::slotInfoAboutCurrentFolder()
qDebug() << "details of folder with alias " << alias; qDebug() << "details of folder with alias " << alias;
if( _fileItemDialog.isNull() ) { if( _fileItemDialog.isNull() ) {
_fileItemDialog = new FileItemDialog(this); _fileItemDialog = new ItemProgressDialog(this);
_fileItemDialog->open(); _fileItemDialog->open();
_fileItemDialog->setupList();
} else { } else {
Utility::raiseDialog( _fileItemDialog ); Utility::raiseDialog( _fileItemDialog );
} }
_fileItemDialog->setSyncResult( FolderMan::instance()->syncResult( alias ) ); // _fileItemDialog->setSyncResult( FolderMan::instance()->syncResult( alias ) );
} }
} }
} }

View file

@ -23,6 +23,7 @@
#include "mirall/folder.h" #include "mirall/folder.h"
#include "mirall/progressdispatcher.h" #include "mirall/progressdispatcher.h"
#include "mirall/itemprogressdialog.h"
class QStandardItemModel; class QStandardItemModel;
class QModelIndex; class QModelIndex;
@ -37,7 +38,7 @@ class AccountSettings;
} }
class FolderMan; class FolderMan;
class FileItemDialog; class ItemProgressDialog;
class IgnoreListEditor; class IgnoreListEditor;
class AccountSettings : public QWidget class AccountSettings : public QWidget
@ -89,7 +90,7 @@ private:
QStandardItem* itemForFolder(const QString& ); QStandardItem* itemForFolder(const QString& );
Ui::AccountSettings *ui; Ui::AccountSettings *ui;
QPointer<FileItemDialog> _fileItemDialog; QPointer<ItemProgressDialog> _fileItemDialog;
QPointer<IgnoreListEditor> _ignoreEditor; QPointer<IgnoreListEditor> _ignoreEditor;
QStandardItemModel *_model; QStandardItemModel *_model;
QListWidgetItem *_item; QListWidgetItem *_item;

View file

@ -0,0 +1,251 @@
/*
* 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; version 2 of the License.
*
* 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 "mirall/itemprogressdialog.h"
#include "mirall/syncresult.h"
#include "mirall/logger.h"
#include "mirall/utility.h"
#include "mirall/theme.h"
#include "ui_itemprogressdialog.h"
#define TYPE_SUCCESS 1
#define TYPE_CONFLICT 2
#define TYPE_NEW 3
#define TYPE_DELETED 4
#define TYPE_ERROR 5
#define TYPE_RENAME 6
#define TYPE_IGNORE 7
#define FILE_TYPE 100
namespace Mirall {
ItemProgressDialog::ItemProgressDialog(QWidget *parent) :
QDialog(parent),
_ui(new Ui::ItemProgressDialog),
ErrorIndicatorRole( Qt::UserRole +1 )
{
_ui->setupUi(this);
connect(_ui->_dialogButtonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
this, SLOT(accept()));
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString,Progress::Info)),
this, SLOT(slotProgressInfo(QString,Progress::Info)));
connect(ProgressDispatcher::instance(), SIGNAL(progressSyncProblem(const QString&,const Progress::SyncProblem&)),
this, SLOT(slotProgressErrors(const QString&, const Progress::SyncProblem&)));
QStringList header;
header << tr("Folder/Time");
header << tr("File");
header << tr("Action");
header << tr("Size");
_ui->_treeWidget->setHeaderLabels( header );
_ui->_treeWidget->setColumnWidth(1, 180);
connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
QPushButton *copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
connect(copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard()));
setWindowTitle(tr("Sync Protocol"));
}
void ItemProgressDialog::setupList()
{
QList<Progress::Info> progressList = ProgressDispatcher::instance()->recentChangedItems(0); // All.
QHash <QString, int> folderHash;
foreach( Progress::Info info, progressList ) {
slotProgressInfo( info.folder, info );
folderHash[info.folder] = 1;
}
QList<Progress::SyncProblem> problemList = ProgressDispatcher::instance()->recentProblems(0);
foreach( Progress::SyncProblem prob, problemList ) {
slotProgressErrors(prob.folder, prob);
folderHash[prob.folder] = 1;
}
foreach( const QString& folder, folderHash.keys() ) {
decorateFolderItem(folder);
}
}
ItemProgressDialog::~ItemProgressDialog()
{
delete _ui;
}
void ItemProgressDialog::copyToClipboard()
{
QString text;
QTextStream ts(&text);
int topLevelItems = _ui->_treeWidget->topLevelItemCount();
for (int i = 0; i < topLevelItems; i++) {
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(i);
ts << left << qSetFieldWidth(50)
<< item->data(0, Qt::DisplayRole).toString()
<< right << qSetFieldWidth(6)
<< item->data(1, Qt::DisplayRole).toString()
<< endl;
int childItems = item->childCount();
for (int j = 0; j < childItems; j++) {
QTreeWidgetItem *child =item->child(j);
ts << left << qSetFieldWidth(0) << QLatin1String(" ")
<< child->data(0,Qt::DisplayRole).toString()
<< QString::fromLatin1(" (%1)").arg(
child->data(1, Qt::DisplayRole).toString()
)
<< endl;
}
}
QApplication::clipboard()->setText(text);
emit guiLog(tr("Copied to clipboard"), tr("The sync protocol has been copied to the clipboard."));
}
void ItemProgressDialog::accept()
{
QDialog::accept();
}
void ItemProgressDialog::decorateFolderItem( const QString& folder )
{
QTreeWidgetItem *folderItem = findFolderItem(folder);
if( ! folderItem ) return;
int errorCnt = 0;
int childCnt = folderItem->childCount();
for( int cnt = 0; cnt < childCnt; cnt++ ) {
bool isErrorItem = folderItem->child(cnt)->data(0, ErrorIndicatorRole).toBool();
if( isErrorItem ) {
errorCnt++;
}
}
if( errorCnt == 0 ) {
folderItem->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::Success));
} else {
// FIXME: Set a soft error icon here.
folderItem->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::Error));
}
}
QTreeWidgetItem *ItemProgressDialog::createFolderItem(const QString& folder)
{
QStringList strings;
strings.append(folder);
QTreeWidgetItem *item = new QTreeWidgetItem( _ui->_treeWidget, strings );
item->setFirstColumnSpanned(true);
return item;
}
QTreeWidgetItem *ItemProgressDialog::findFolderItem( const QString& folder )
{
QTreeWidgetItem *folderItem;
if( folder.isEmpty() ) return NULL;
if( !_folderItems.contains(folder)) {
_folderItems[folder] = createFolderItem(folder);
_ui->_treeWidget->addTopLevelItem(_folderItems[folder]);
}
folderItem = _folderItems[folder];
return folderItem;
}
void ItemProgressDialog::cleanErrors( const QString& folder )
{
_problemCounter = 0;
QList<QTreeWidgetItem*> wipeList;
QTreeWidgetItem *folderItem = findFolderItem(folder);
if( ! folderItem ) return;
int childCnt = folderItem->childCount();
for( int cnt = 0; cnt < childCnt; cnt++ ) {
bool isErrorItem = folderItem->child(cnt)->data(0, ErrorIndicatorRole).toBool();
if( isErrorItem ) {
wipeList.append(folderItem->child(cnt));
}
}
qDeleteAll(wipeList.begin(), wipeList.end());
}
void ItemProgressDialog::slotProgressErrors( const QString& folder, const Progress::SyncProblem& problem )
{
QTreeWidgetItem *folderItem;
folderItem = findFolderItem(folder);
if( !folderItem ) return;
QStringList columns;
QString timeStr = problem.timestamp.toString("hh:mm");
columns << timeStr;
columns << problem.current_file;
QString errMsg = tr("Problem: %1").arg(problem.error_message);
columns << errMsg;
// FIXME: Show the error code if available.
QTreeWidgetItem *item = new QTreeWidgetItem(folderItem, columns);
item->setData(0, ErrorIndicatorRole, QVariant(true) );
_problemCounter++;
Q_UNUSED(item);
}
void ItemProgressDialog::slotProgressInfo( const QString& folder, const Progress::Info& progress )
{
QTreeWidgetItem *folderItem;
folderItem = findFolderItem(folder);
if( !folderItem ) return;
if( progress.kind == Progress::StartSync ) {
cleanErrors( folder );
folderItem->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::SyncRunning));
}
if( progress.kind == Progress::EndSync ) {
decorateFolderItem( folder );
}
// Ingore other events than finishing an individual up- or download.
if( !(progress.kind == Progress::EndDownload || progress.kind == Progress::EndUpload)) {
return;
}
QStringList columns;
QString timeStr = progress.timestamp.toString("hh:mm");
columns << timeStr;
columns << progress.current_file;
columns << Progress::asString(progress.kind);
columns << Utility::octetsToString( progress.file_size );
QTreeWidgetItem *item = new QTreeWidgetItem(folderItem, columns);
Q_UNUSED(item);
}
}

View file

@ -0,0 +1,66 @@
/*
* 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; version 2 of the License.
*
* 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 FILEITEMDIALOG_H
#define FILEITEMDIALOG_H
#include <QDialog>
#include <QDateTime>
#include "mirall/progressdispatcher.h"
#include "ui_fileitemdialog.h"
namespace Mirall {
class SyncResult;
namespace Ui {
class ItemProgressDialog;
}
class ItemProgressDialog : public QDialog
{
Q_OBJECT
public:
explicit ItemProgressDialog(QWidget *parent = 0);
~ItemProgressDialog();
void setupList();
signals:
public slots:
void accept();
void slotProgressInfo( const QString& folder, const Progress::Info& progress );
void slotProgressErrors( const QString& folder, const Progress::SyncProblem& problem );
protected slots:
void copyToClipboard();
signals:
void guiLog(const QString&, const QString&);
private:
QTreeWidgetItem *createFolderItem(const QString& folder);
QTreeWidgetItem *findFolderItem( const QString& folder );
void cleanErrors( const QString& folder );
void decorateFolderItem( const QString& folder );
QHash<QString, QTreeWidgetItem*> _folderItems;
const int ErrorIndicatorRole;
Ui::ItemProgressDialog *_ui;
int _problemCounter;
};
}
#endif // FILEITEMDIALOG_H

View file

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mirall::ItemProgressDialog</class>
<widget class="QWidget" name="Mirall::ItemProgressDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>612</width>
<height>543</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>Detailed Sync Protocol</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="_treeWidget">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="rootIsDecorated">
<bool>true</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>3</string>
</property>
</column>
<column>
<property name="text">
<string>4</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QLabel" name="_timelabel">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="_errorLabel">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="_dialogButtonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -84,13 +84,19 @@ ProgressDispatcher::~ProgressDispatcher()
QList<Progress::Info> ProgressDispatcher::recentChangedItems(int count) QList<Progress::Info> ProgressDispatcher::recentChangedItems(int count)
{ {
if( count > 0 ) {
return _recentChanges.mid(0, count); return _recentChanges.mid(0, count);
} }
return _recentChanges;
}
QList<Progress::SyncProblem> ProgressDispatcher::recentProblems(int count) QList<Progress::SyncProblem> ProgressDispatcher::recentProblems(int count)
{ {
if( count > 0 ) {
return _recentProblems.mid(0, count); return _recentProblems.mid(0, count);
} }
return _recentProblems;
}
void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::Info& progress) void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::Info& progress)
{ {
@ -105,6 +111,7 @@ void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::
err.current_file = newProgress.current_file; err.current_file = newProgress.current_file;
err.error_message = QString::fromLocal8Bit( (const char*)newProgress.file_size ); err.error_message = QString::fromLocal8Bit( (const char*)newProgress.file_size );
err.error_code = newProgress.file_size; err.error_code = newProgress.file_size;
err.timestamp = QTime::currentTime();
_recentProblems.enqueue( err ); _recentProblems.enqueue( err );
if( _recentProblems.size() > _problemQueueSize ) { if( _recentProblems.size() > _problemQueueSize ) {

View file

@ -64,6 +64,7 @@ public:
QString current_file; QString current_file;
QString error_message; QString error_message;
int error_code; int error_code;
QTime timestamp;
} SyncProblem; } SyncProblem;
static QString asString( Kind ); static QString asString( Kind );