Merge branch 'newactivity'

This commit is contained in:
Klaas Freitag 2015-11-16 17:02:05 +01:00
commit 87aa1de67a
26 changed files with 1362 additions and 140 deletions

View file

@ -21,6 +21,8 @@ set(client_UI
ignorelisteditor.ui
networksettings.ui
protocolwidget.ui
activitywidget.ui
synclogdialog.ui
settingsdialog.ui
sharedialog.ui
sharelinkwidget.ui
@ -60,6 +62,8 @@ set(client_SRCS
owncloudgui.cpp
owncloudsetupwizard.cpp
protocolwidget.cpp
activitywidget.cpp
activityitemdelegate.cpp
selectivesyncdialog.cpp
settingsdialog.cpp
share.cpp
@ -79,6 +83,7 @@ set(client_SRCS
authenticationdialog.cpp
proxyauthhandler.cpp
proxyauthdialog.cpp
synclogdialog.cpp
creds/credentialsfactory.cpp
creds/httpcredentialsgui.cpp
creds/shibbolethcredentials.cpp

View file

@ -215,6 +215,16 @@ AccountPtr AccountManager::load(QSettings& settings)
return acc;
}
AccountStatePtr AccountManager::account(const QString& name)
{
foreach (const auto& acc, _accounts) {
if (acc->account()->displayName() == name) {
return acc;
}
}
return AccountStatePtr();
}
AccountState *AccountManager::addAccount(const AccountPtr& newAccount)
{
auto id = newAccount->id();

View file

@ -58,6 +58,11 @@ public:
*/
QList<AccountStatePtr> accounts() { return _accounts; }
/**
* Return the account state pointer for an account identified by its display name
*/
AccountStatePtr account(const QString& name);
/**
* Delete the AccountState
*/

View file

@ -0,0 +1,153 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
* Copyright (C) by Olivier Goffart <ogoffart@woboq.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 "activityitemdelegate.h"
#include "folderstatusmodel.h"
#include "folderman.h"
#include "accountstate.h"
#include "utility.h"
#include <theme.h>
#include <account.h>
#include <QFileIconProvider>
#include <QPainter>
#include <QApplication>
namespace OCC {
int ActivityItemDelegate::_iconHeight = 0;
int ActivityItemDelegate::_margin = 0;
int ActivityItemDelegate::iconHeight()
{
if( _iconHeight == 0 ) {
QStyleOptionViewItem option;
QFont font = option.font;
QFontMetrics fm(font);
_iconHeight = qRound(fm.height() / 5.0 * 8.0);
}
return _iconHeight;
}
int ActivityItemDelegate::rowHeight()
{
if( _margin == 0 ) {
QStyleOptionViewItem opt;
QFont f = opt.font;
QFontMetrics fm(f);
_margin = fm.height()/4;
}
return iconHeight() + 2 * _margin;
}
QSize ActivityItemDelegate::sizeHint(const QStyleOptionViewItem & option ,
const QModelIndex & /* index */) const
{
QFont font = option.font;
return QSize( 0, rowHeight() );
}
void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter,option,index);
QFont font = option.font;
QFontMetrics fm( font );
int margin = fm.height()/4;
painter->save();
QIcon actionIcon = qvariant_cast<QIcon>(index.data(ActionIconRole));
QIcon userIcon = qvariant_cast<QIcon>(index.data(UserIconRole));
QString actionText = qvariant_cast<QString>(index.data(ActionTextRole));
QString pathText = qvariant_cast<QString>(index.data(PathRole));
QString remoteLink = qvariant_cast<QString>(index.data(LinkRole));
QString timeText = qvariant_cast<QString>(index.data(PointInTimeRole));
QString accountRole = qvariant_cast<QString>(index.data(AccountRole));
bool accountOnline = qvariant_cast<bool> (index.data(AccountConnectedRole));
QRect actionIconRect = option.rect;
QRect userIconRect = option.rect;
int iconHeight = qRound(fm.height() / 5.0 * 8.0);
int iconWidth = iconHeight;
actionIconRect.setLeft( option.rect.left() + margin );
actionIconRect.setWidth( iconWidth );
actionIconRect.setHeight( iconHeight );
actionIconRect.setTop( actionIconRect.top() + margin );
userIconRect.setLeft( actionIconRect.right() + margin );
userIconRect.setWidth( iconWidth );
userIconRect.setHeight( iconHeight );
userIconRect.setTop( actionIconRect.top() );
int textTopOffset = qRound( (iconHeight - fm.height())/ 2.0 );
// time rect
QRect timeBox;
int timeBoxWidth = fm.boundingRect(QLatin1String("4 hour(s) ago on longlongdomain.org")).width(); // FIXME.
timeBox.setTop( actionIconRect.top()+textTopOffset);
timeBox.setLeft( option.rect.right() - timeBoxWidth- margin );
timeBox.setWidth( timeBoxWidth);
timeBox.setHeight( fm.height() );
QRect actionTextBox = timeBox;
actionTextBox.setLeft( userIconRect.right()+margin );
actionTextBox.setRight( timeBox.left()-margin );
/* === start drawing === */
QPixmap pm = actionIcon.pixmap(iconWidth, iconHeight, QIcon::Normal);
painter->drawPixmap(QPoint(actionIconRect.left(), actionIconRect.top()), pm);
pm = userIcon.pixmap(iconWidth, iconHeight, QIcon::Normal);
painter->drawPixmap(QPoint(userIconRect.left(), userIconRect.top()), pm);
const QString elidedAction = fm.elidedText(actionText, Qt::ElideRight, actionTextBox.width());
painter->drawText(actionTextBox, elidedAction);
int atPos = accountRole.indexOf(QLatin1Char('@'));
if( atPos > -1 ) {
accountRole.remove(0, atPos+1);
}
QString timeStr = tr("%1 on %2").arg(timeText).arg(accountRole);
if( !accountOnline ) {
QPalette p = option.palette;
painter->setPen(p.color(QPalette::Disabled, QPalette::Text));
timeStr.append(" ");
timeStr.append(tr("(disconnected)"));
}
const QString elidedTime = fm.elidedText(timeStr, Qt::ElideRight, timeBox.width());
painter->drawText(timeBox, elidedTime);
painter->restore();
}
bool ActivityItemDelegate::editorEvent ( QEvent * event, QAbstractItemModel * model,
const QStyleOptionViewItem & option, const QModelIndex & index )
{
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
} // namespace OCC

View file

@ -0,0 +1,53 @@
/*
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Olivier Goffart <ogoffart@woboq.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.
*/
#pragma once
#include <QStyledItemDelegate>
namespace OCC {
/**
* @brief The ActivityItemDelegate class
* @ingroup gui
*/
class ActivityItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
enum datarole { ActionIconRole = Qt::UserRole + 1,
UserIconRole,
AccountRole,
ActionTextRole,
PathRole,
LinkRole,
PointInTimeRole,
AccountConnectedRole };
void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const Q_DECL_OVERRIDE;
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const Q_DECL_OVERRIDE;
bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
const QModelIndex& index ) Q_DECL_OVERRIDE;
static int rowHeight();
static int iconHeight();
private:
static int _margin;
static int _iconHeight;
};
} // namespace OCC

462
src/gui/activitywidget.cpp Normal file
View file

@ -0,0 +1,462 @@
/*
* 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>
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QtWidgets>
#endif
#include "activitywidget.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 "owncloudpropagator.h"
#include "account.h"
#include "accountstate.h"
#include "accountmanager.h"
#include "activityitemdelegate.h"
#include "protocolwidget.h"
#include "QProgressIndicator.h"
#include "ui_activitywidget.h"
#include <climits>
namespace OCC {
void ActivityList::setAccountName( const QString& name )
{
_accountName = name;
}
QString ActivityList::accountName() const
{
return _accountName;
}
/* ==================================================================== */
ActivityListModel::ActivityListModel(QWidget *parent)
:QAbstractListModel(parent)
{
}
QVariant ActivityListModel::data(const QModelIndex &index, int role) const
{
Activity a;
if (!index.isValid())
return QVariant();
a = _finalList.at(index.row());
AccountStatePtr ast = AccountManager::instance()->account(a._accName);
QStringList list;
if (role == Qt::EditRole)
return QVariant();
switch (role) {
case ActivityItemDelegate::PathRole:
list = FolderMan::instance()->findFileInLocalFolders(a._file);
if( list.count() > 0 ) {
return QVariant(list.at(0));
}
return QVariant();
break;
case ActivityItemDelegate::ActionIconRole:
return QVariant(); // FIXME once the action can be quantified, display on Icon
break;
case ActivityItemDelegate::UserIconRole:
return QIcon(QLatin1String(":/client/resources/account.png"));
break;
case Qt::ToolTipRole:
case ActivityItemDelegate::ActionTextRole:
return a._subject;
break;
case ActivityItemDelegate::LinkRole:
return a._link;
break;
case ActivityItemDelegate::AccountRole:
return a._accName;
break;
case ActivityItemDelegate::PointInTimeRole:
return timeSpanFromNow(a._dateTime);
break;
case ActivityItemDelegate::AccountConnectedRole:
return (ast && ast->isConnected());
break;
default:
return QVariant();
}
return QVariant();
}
QString ActivityListModel::timeSpanFromNow(const QDateTime& dt) const
{
QDateTime now = QDateTime::currentDateTime();
if( dt.daysTo(now)>0 ) {
return tr("%1 day(s) ago").arg(dt.daysTo(now));
} else {
qint64 secs = dt.secsTo(now);
if( floor(secs / 3600.0) > 0 ) {
int hours = floor(secs/3600.0);
return( tr("%1 hour(s) ago").arg(hours));
} else {
int minutes = qRound(secs/60.0);
return( tr("%1 minute(s) ago").arg(minutes));
}
}
return tr("Some time ago");
}
int ActivityListModel::rowCount(const QModelIndex&) const
{
return _finalList.count();
}
// current strategy: Fetch 100 items per Account
bool ActivityListModel::canFetchMore(const QModelIndex& ) const
{
if( _activityLists.count() == 0 ) return true;
QMap<AccountState*, ActivityList>::const_iterator i = _activityLists.begin();
while (i != _activityLists.end()) {
AccountState *ast = i.key();
if( !ast->isConnected() ) {
return false;
}
ActivityList activities = i.value();
if( activities.count() == 0 &&
! _currentlyFetching.contains(ast) ) {
return true;
}
++i;
}
return false;
}
void ActivityListModel::startFetchJob(AccountState* s)
{
if( !s->isConnected() ) {
return;
}
JsonApiJob *job = new JsonApiJob(s->account(), QLatin1String("ocs/v1.php/cloud/activity"), this);
QObject::connect(job, SIGNAL(jsonRecieved(QVariantMap)), this, SLOT(slotActivitiesReceived(QVariantMap)));
job->setProperty("AccountStatePtr", QVariant::fromValue<AccountState*>(s));
QList< QPair<QString,QString> > params;
params.append(qMakePair(QLatin1String("page"), QLatin1String("0")));
params.append(qMakePair(QLatin1String("pagesize"), QLatin1String("100")));
job->addQueryParams(params);
_currentlyFetching.insert(s);
job->start();
}
void ActivityListModel::slotActivitiesReceived(const QVariantMap& json)
{
auto activities = json.value("ocs").toMap().value("data").toList();
qDebug() << "*** activities" << activities;
ActivityList list;
AccountState* ai = qvariant_cast<AccountState*>(sender()->property("AccountStatePtr"));
_currentlyFetching.remove(ai);
list.setAccountName( ai->account()->displayName());
foreach( auto activ, activities ) {
auto json = activ.toMap();
Activity a;
a._accName = ai->account()->displayName();
a._id = json.value("id").toLongLong();
a._subject = json.value("subject").toString();
a._message = json.value("message").toString();
a._file = json.value("file").toString();
a._link = json.value("link").toUrl();
a._dateTime = json.value("date").toDateTime();
list.append(a);
}
_activityLists[ai] = list;
// if all activity lists were received, assemble the whole list
// otherwise wait until the others are finished
bool allAreHere = true;
foreach( ActivityList list, _activityLists.values() ) {
if( list.count() == 0 ) {
allAreHere = false;
break;
}
}
// FIXME: Be more efficient,
if( allAreHere ) {
combineActivityLists();
}
}
void ActivityListModel::combineActivityLists()
{
ActivityList resultList;
foreach( ActivityList list, _activityLists.values() ) {
resultList.append(list);
}
std::sort( resultList.begin(), resultList.end() );
beginInsertRows(QModelIndex(), 0, resultList.count()-1);
_finalList = resultList;
endInsertRows();
}
void ActivityListModel::fetchMore(const QModelIndex &)
{
QList<AccountStatePtr> accounts = AccountManager::instance()->accounts();
foreach (AccountStatePtr asp, accounts) {
// if the account is not yet managed, add an empty list.
if( !_activityLists.contains(asp.data()) ) {
_activityLists[asp.data()] = ActivityList();
}
ActivityList activities = _activityLists[asp.data()];
if( activities.count() == 0 ) {
startFetchJob(asp.data());
}
}
}
void ActivityListModel::slotRefreshActivity(AccountState *ast)
{
if(ast && _activityLists.contains(ast)) {
qDebug() << "**** Refreshing Activity list for" << ast->account()->displayName();
_activityLists[ast].clear();
}
startFetchJob(ast);
}
void ActivityListModel::slotRemoveAccount(AccountState *ast )
{
if( _activityLists.contains(ast) ) {
int i = 0;
const QString accountToRemove = ast->account()->displayName();
QMutableListIterator<Activity> it(_finalList);
while (it.hasNext()) {
Activity activity = it.next();
if( activity._accName == accountToRemove ) {
beginRemoveRows(QModelIndex(), i, i+1);
it.remove();
endRemoveRows();
}
}
_activityLists.remove(ast);
_currentlyFetching.remove(ast);
}
}
/* ==================================================================== */
ActivityWidget::ActivityWidget(QWidget *parent) :
QWidget(parent),
_ui(new Ui::ActivityWidget)
{
_ui->setupUi(this);
// Adjust copyToClipboard() when making changes here!
#if defined(Q_OS_MAC)
_ui->_activityList->setMinimumWidth(400);
#endif
_model = new ActivityListModel(this);
ActivityItemDelegate *delegate = new ActivityItemDelegate;
delegate->setParent(this);
_ui->_activityList->setItemDelegate(delegate);
_ui->_activityList->setAlternatingRowColors(true);
_ui->_activityList->setModel(_model);
_ui->_headerLabel->setText(tr("Server Activities"));
_copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
_copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
connect(_copyBtn, SIGNAL(clicked()), SIGNAL(copyToClipboard()));
connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(rowsInserted()));
connect( _ui->_activityList, SIGNAL(activated(QModelIndex)), this,
SLOT(slotOpenFile(QModelIndex)));
}
ActivityWidget::~ActivityWidget()
{
delete _ui;
}
void ActivityWidget::slotRefresh(AccountState *ptr)
{
_model->slotRefreshActivity(ptr);
}
void ActivityWidget::slotRemoveAccount( AccountState *ptr )
{
_model->slotRemoveAccount(ptr);
}
// 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);
}
void ActivityWidget::storeActivityList( QTextStream& ts )
{
ActivityList activities = _model->activityList();
foreach( Activity activity, activities ) {
ts << left
// account name
<< qSetFieldWidth(30)
<< activity._accName
// date and time
<< qSetFieldWidth(34)
<< activity._dateTime.toString()
// subject
<< qSetFieldWidth(10)
<< activity._subject
// file
<< qSetFieldWidth(30)
<< activity._file
// message (mostly empty)
<< qSetFieldWidth(55)
<< activity._message
//
<< qSetFieldWidth(0)
<< endl;
}
}
void ActivityWidget::slotOpenFile(QModelIndex indx)
{
if( indx.isValid() ) {
QString fullPath = indx.data(ActivityItemDelegate::PathRole).toString();
if (QFile::exists(fullPath)) {
showInFileManager(fullPath);
}
}
}
/* ==================================================================== */
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);
_tab->addTab(_activityWidget, Theme::instance()->applicationIcon(), tr("Server Activity"));
connect(_activityWidget, SIGNAL(copyToClipboard()), this, SLOT(slotCopyToClipboard()));
_protocolWidget = new ProtocolWidget(this);
_tab->addTab(_protocolWidget, Theme::instance()->syncStateIcon(SyncResult::Success), tr("Sync Protocol"));
connect(_protocolWidget, SIGNAL(copyToClipboard()), this, SLOT(slotCopyToClipboard()));
// Add the not-synced list into the tab
QWidget *w = new QWidget;
QVBoxLayout *vbox2 = new QVBoxLayout(this);
vbox2->addWidget(new QLabel(tr("List of ignored or errornous 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);
_tab->addTab(w, Theme::instance()->syncStateIcon(SyncResult::Problem), tr("Not Synced"));
// Add a progress indicator to spin if the acitivity list is updated.
_progressIndicator = new QProgressIndicator(this);
_tab->setCornerWidget(_progressIndicator);
// connect a model signal to stop the animation.
connect(_activityWidget, SIGNAL(rowsInserted()), _progressIndicator, SLOT(stopAnimation()));
}
void ActivitySettings::slotCopyToClipboard()
{
QString text;
QTextStream ts(&text);
int idx = _tab->currentIndex();
QString theSubject;
if( idx == 0 ) {
// the activity widget
_activityWidget->storeActivityList(ts);
theSubject = tr("server activity list");
} else if(idx == 1 ) {
// the protocol widget
_protocolWidget->storeSyncActivity(ts);
theSubject = tr("sync activity list");
} else if(idx == 2 ) {
// issues Widget
theSubject = tr("not syned items list");
_protocolWidget->storeSyncIssues(ts);
}
QApplication::clipboard()->setText(text);
emit guiLog(tr("Copied to clipboard"), tr("The %1 has been copied to the clipboard.").arg(theSubject));
}
void ActivitySettings::slotRemoveAccount( AccountState *ptr )
{
_activityWidget->slotRemoveAccount(ptr);
}
void ActivitySettings::slotRefresh( AccountState* ptr )
{
_progressIndicator->startAnimation();
_activityWidget->slotRefresh(ptr);
}
ActivitySettings::~ActivitySettings()
{
}
}

195
src/gui/activitywidget.h Normal file
View file

@ -0,0 +1,195 @@
/*
* 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 ACTIVITYWIDGET_H
#define ACTIVITYWIDGET_H
#include <QDialog>
#include <QDateTime>
#include <QLocale>
#include <QAbstractListModel>
#include "progressdispatcher.h"
#include "owncloudgui.h"
#include "account.h"
#include "ui_activitywidget.h"
class QPushButton;
class QProgressIndicator;
namespace OCC {
class Account;
class AccountStatusPtr;
class ProtocolWidget;
namespace Ui {
class ActivityWidget;
}
class Application;
/**
* @brief Activity Structure
* @ingroup gui
*
* contains all the information describing a single activity.
*/
class Activity
{
public:
qlonglong _id;
QString _subject;
QString _message;
QString _file;
QUrl _link;
QDateTime _dateTime;
QString _accName;
/**
* @brief Sort operator to sort the list youngest first.
* @param val
* @return
*/
bool operator<( const Activity& val ) const {
return _dateTime.toMSecsSinceEpoch() > val._dateTime.toMSecsSinceEpoch();
}
};
/**
* @brief The ActivityList
* @ingroup gui
*
* A QList based list of Activities
*/
class ActivityList:public QList<Activity>
{
// explicit ActivityList();
public:
void setAccountName( const QString& name );
QString accountName() const;
private:
QString _accountName;
};
/**
* @brief The ActivityListModel
* @ingroup gui
*
* Simple list model to provide the list view with data.
*/
class ActivityListModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ActivityListModel(QWidget *parent=0);
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
bool canFetchMore(const QModelIndex& ) const;
void fetchMore(const QModelIndex&);
ActivityList activityList() { return _finalList; }
public slots:
void slotRefreshActivity(AccountState* ast);
void slotRemoveAccount( AccountState *ast );
private slots:
void slotActivitiesReceived(const QVariantMap& json);
private:
void startFetchJob(AccountState* s);
void combineActivityLists();
QString timeSpanFromNow(const QDateTime& dt) const;
QMap<AccountState*, ActivityList> _activityLists;
ActivityList _finalList;
QSet<AccountState*> _currentlyFetching;
};
/**
* @brief The ActivityWidget class
* @ingroup gui
*
* The list widget to display the activities, contained in the
* subsequent ActivitySettings widget.
*/
class ActivityWidget : public QWidget
{
Q_OBJECT
public:
explicit ActivityWidget(QWidget *parent = 0);
~ActivityWidget();
QSize sizeHint() const { return ownCloudGui::settingsDialogSize(); }
void storeActivityList(QTextStream &ts);
public slots:
void slotOpenFile(QModelIndex indx);
void slotRefresh(AccountState* ptr);
void slotRemoveAccount( AccountState *ptr );
signals:
void guiLog(const QString&, const QString&);
void copyToClipboard();
void rowsInserted();
private:
QString timeString(QDateTime dt, QLocale::FormatType format) const;
Ui::ActivityWidget *_ui;
QPushButton *_copyBtn;
ActivityListModel *_model;
};
/**
* @brief The ActivitySettings class
* @ingroup gui
*
* Implements a tab for the settings dialog, displaying the three activity
* lists.
*/
class ActivitySettings : public QWidget
{
Q_OBJECT
public:
explicit ActivitySettings(QWidget *parent = 0);
~ActivitySettings();
QSize sizeHint() const { return ownCloudGui::settingsDialogSize(); }
public slots:
void slotRefresh( AccountState* ptr );
void slotRemoveAccount( AccountState *ptr );
void slotCopyToClipboard();
signals:
void guiLog(const QString&, const QString&);
private:
QTabWidget *_tab;
ActivityWidget *_activityWidget;
ProtocolWidget *_protocolWidget;
QProgressIndicator *_progressIndicator;
};
}
#endif // ActivityWIDGET_H

38
src/gui/activitywidget.ui Normal file
View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OCC::ActivityWidget</class>
<widget class="QWidget" name="OCC::ActivityWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>693</width>
<height>556</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="_headerLabel">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QListView" name="_activityList"/>
</item>
<item row="2" column="0">
<widget class="QDialogButtonBox" name="_dialogButtonBox"/>
</item>
</layout>
</widget>
<tabstops>
<tabstop>_activityList</tabstop>
<tabstop>_dialogButtonBox</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View file

@ -824,6 +824,24 @@ Folder *FolderMan::folderForPath(const QString &path)
return 0;
}
QStringList FolderMan::findFileInLocalFolders( const QString& relPath )
{
QStringList re;
foreach(Folder* folder, this->map().values()) {
QString path = folder->cleanPath();
QString remRelPath;
// cut off the remote path from the server path.
remRelPath = relPath.mid(folder->remotePath().length());
path += remRelPath;
if( QFile::exists(path) ) {
re.append( path );
}
}
return re;
}
void FolderMan::slotRemoveFolder( Folder *f )
{
if( !f ) {

View file

@ -57,6 +57,13 @@ public:
/** Returns the folder which the file or directory stored in path is in */
Folder* folderForPath(const QString& path);
/**
* returns a list of local files that exist on the local harddisk for an
* incoming relative server path. The method checks with all existing sync
* folders.
*/
QStringList findFileInLocalFolders( const QString& relPath );
/** Returns the folder by alias or NULL if no folder with the alias exists. */
Folder *folder( const QString& );

View file

@ -21,6 +21,7 @@
#include "configfile.h"
#include "owncloudsetupwizard.h"
#include "accountmanager.h"
#include "synclogdialog.h"
#include "updater/updater.h"
#include "updater/ocupdater.h"
@ -88,6 +89,7 @@ GeneralSettings::GeneralSettings(QWidget *parent) :
GeneralSettings::~GeneralSettings()
{
delete _ui;
delete _syncLogDialog;
}
QSize GeneralSettings::sizeHint() const {

View file

@ -19,6 +19,7 @@
namespace OCC {
class IgnoreListEditor;
class SyncLogDialog;
namespace Ui {
class GeneralSettings;
@ -50,6 +51,7 @@ private:
Ui::GeneralSettings *_ui;
QPointer<IgnoreListEditor> _ignoreEditor;
QPointer<SyncLogDialog> _syncLogDialog;
};

View file

@ -23,14 +23,14 @@
<item row="0" column="0">
<widget class="QCheckBox" name="autostartCheckBox">
<property name="text">
<string>Launch on System Startup</string>
<string>&amp;Launch on System Startup</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="desktopNotificationsCheckBox">
<property name="text">
<string>Show Desktop Notifications</string>
<string>Show &amp;Desktop Notifications</string>
</property>
</widget>
</item>
@ -40,7 +40,7 @@
<string>For System Tray</string>
</property>
<property name="text">
<string>Use Monochrome Icons</string>
<string>Use &amp;Monochrome Icons</string>
</property>
</widget>
</item>
@ -58,7 +58,7 @@
<item>
<widget class="QPushButton" name="ignoredFilesButton">
<property name="text">
<string>Edit Ignored Files</string>
<string>Edit &amp;Ignored Files</string>
</property>
</widget>
</item>
@ -77,12 +77,36 @@
</item>
</layout>
</item>
<item row="1" column="0">
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="addAccountButton">
<property name="text">
<string>&amp;Add an Account</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="newFolderLimitCheckBox">
<property name="text">
<string>Ask confirmation before downloading folders larger than</string>
<string>Ask &amp;confirmation before downloading folders larger than</string>
</property>
<property name="checked">
<bool>true</bool>
@ -122,19 +146,32 @@
</layout>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="crashreporterCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>S&amp;how crash reporter</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QCheckBox" name="crashreporterCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="text">
<string>Show crash reporter</string>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</widget>
</spacer>
</item>
</layout>
</item>

View file

@ -204,6 +204,10 @@ void ownCloudGui::slotSyncStateChange( Folder* folder )
if (result.status() == SyncResult::Success || result.status() == SyncResult::Error) {
Logger::instance()->enterNextLogFile();
}
if (result.status() == SyncResult::NotYetStarted) {
_settingsDialog->slotRefreshActivity( folder->accountState() );
}
}
void ownCloudGui::slotFoldersChanged()

View file

@ -27,6 +27,7 @@
#include "folder.h"
#include "openfilemanager.h"
#include "owncloudpropagator.h"
#include "activityitemdelegate.h"
#include "ui_protocolwidget.h"
@ -65,17 +66,24 @@ ProtocolWidget::ProtocolWidget(QWidget *parent) :
#if defined(Q_OS_MAC)
_ui->_treeWidget->setMinimumWidth(400);
#endif
_ui->_headerLabel->setText(tr("Local sync protocol"));
connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
QPushButton *copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
copyBtn->setEnabled(true);
connect(copyBtn, SIGNAL(clicked()), SIGNAL(copyToClipboard()));
_retrySyncBtn = _ui->_dialogButtonBox->addButton(tr("Retry Sync"), QDialogButtonBox::ActionRole);
_retrySyncBtn->setEnabled(false);
connect(_retrySyncBtn, SIGNAL(clicked()), SLOT(slotRetrySync()));
_copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
_copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
_copyBtn->setEnabled(false);
connect(_copyBtn, SIGNAL(clicked()), SLOT(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 );
_issueItemView->setColumnWidth(1, 180);
_issueItemView->setColumnCount(4);
_issueItemView->setRootIsDecorated(false);
_issueItemView->setTextElideMode(Qt::ElideMiddle);
_issueItemView->header()->setObjectName("ActivityErrorListHeader");
}
ProtocolWidget::~ProtocolWidget()
@ -83,38 +91,7 @@ ProtocolWidget::~ProtocolWidget()
delete _ui;
}
void ProtocolWidget::copyToClipboard()
{
QString text;
QTextStream ts(&text);
int topLevelItems = _ui->_treeWidget->topLevelItemCount();
for (int i = 0; i < topLevelItems; i++) {
QTreeWidgetItem *child = _ui->_treeWidget->topLevelItem(i);
ts << left
// time stamp
<< qSetFieldWidth(10)
<< child->data(0,Qt::DisplayRole).toString()
// file name
<< qSetFieldWidth(64)
<< child->data(1,Qt::DisplayRole).toString()
// folder
<< qSetFieldWidth(30)
<< child->data(2, Qt::DisplayRole).toString()
// action
<< qSetFieldWidth(15)
<< child->data(3, Qt::DisplayRole).toString()
// size
<< qSetFieldWidth(10)
<< child->data(4, Qt::DisplayRole).toString()
<< qSetFieldWidth(0)
<< endl;
}
QApplication::clipboard()->setText(text);
emit guiLog(tr("Copied to clipboard"), tr("The sync status has been copied to the clipboard."));
}
#if 0
void ProtocolWidget::slotRetrySync()
{
FolderMan *folderMan = FolderMan::instance();
@ -133,6 +110,7 @@ void ProtocolWidget::slotRetrySync()
folderMan->slotScheduleAllFolders();
}
#endif
void ProtocolWidget::showEvent(QShowEvent *ev)
{
@ -158,8 +136,18 @@ void ProtocolWidget::cleanIgnoreItems(const QString& folder)
itemCnt--;
}
// limit also in the protocol widget
itemCnt = _issueItemView->topLevelItemCount();
// Limit the number of items in the issue view
while(itemCnt > 2000) {
delete _issueItemView->takeTopLevelItem(itemCnt - 1);
itemCnt--;
}
// clean up the issue list
for( int cnt = itemCnt-1; cnt >=0 ; cnt-- ) {
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(cnt);
QTreeWidgetItem *item = _issueItemView->topLevelItem(cnt);
bool isErrorItem = item->data(0, IgnoredIndicatorRole).toBool();
QString itemFolder = item->data(2, Qt::UserRole).toString();
if( isErrorItem && itemFolder == folder ) {
@ -192,15 +180,6 @@ void ProtocolWidget::slotOpenFile( QTreeWidgetItem *item, int )
}
}
QString ProtocolWidget::fixupFilename( const QString& name )
{
if( Utility::isMac() ) {
QString n(name);
return n.replace(QChar(':'), QChar('/'));
}
return name;
}
QTreeWidgetItem* ProtocolWidget::createCompletedTreewidgetItem(const QString& folder, const SyncFileItem& item)
{
auto f = FolderMan::instance()->folder(folder);
@ -214,7 +193,7 @@ QTreeWidgetItem* ProtocolWidget::createCompletedTreewidgetItem(const QString& fo
const QString longTimeStr = timeString(timestamp, QLocale::LongFormat);
columns << timeStr;
columns << fixupFilename(item._originalFile);
columns << Utility::fileNameForGuiUse(item._originalFile);
columns << f->shortGuiPath();
// If the error string is set, it's prefered because it is a useful user message.
@ -242,6 +221,7 @@ QTreeWidgetItem* ProtocolWidget::createCompletedTreewidgetItem(const QString& fo
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);
@ -252,6 +232,7 @@ QTreeWidgetItem* ProtocolWidget::createCompletedTreewidgetItem(const QString& fo
void ProtocolWidget::computeResyncButtonEnabled()
{
#if 0
FolderMan *folderMan = FolderMan::instance();
Folder::Map folders = folderMan->map();
@ -272,6 +253,7 @@ void ProtocolWidget::computeResyncButtonEnabled()
_retrySyncBtn->setEnabled(enabled);
_retrySyncBtn->setToolTip(t);
#endif
}
@ -295,11 +277,65 @@ void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItem
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, item);
if(line) {
_ui->_treeWidget->insertTopLevelItem(0, line);
if (!_copyBtn->isEnabled()) {
_copyBtn->setEnabled(true);
if( item.hasErrorStatus() ) {
_issueItemView->insertTopLevelItem(0, line);
} else {
_ui->_treeWidget->insertTopLevelItem(0, line);
}
}
}
void ProtocolWidget::storeSyncActivity(QTextStream& ts)
{
int topLevelItems = _ui->_treeWidget->topLevelItemCount();
for (int i = 0; i < topLevelItems; i++) {
QTreeWidgetItem *child = _ui->_treeWidget->topLevelItem(i);
ts << left
// time stamp
<< qSetFieldWidth(10)
<< child->data(0,Qt::DisplayRole).toString()
// file name
<< qSetFieldWidth(64)
<< child->data(1,Qt::DisplayRole).toString()
// folder
<< qSetFieldWidth(30)
<< child->data(2, Qt::DisplayRole).toString()
// action
<< qSetFieldWidth(15)
<< child->data(3, Qt::DisplayRole).toString()
// size
<< qSetFieldWidth(10)
<< child->data(4, Qt::DisplayRole).toString()
<< qSetFieldWidth(0)
<< endl;
}
}
void ProtocolWidget::storeSyncIssues(QTextStream& ts)
{
int topLevelItems = _issueItemView->topLevelItemCount();
for (int i = 0; i < topLevelItems; i++) {
QTreeWidgetItem *child = _issueItemView->topLevelItem(i);
ts << left
// time stamp
<< qSetFieldWidth(10)
<< child->data(0,Qt::DisplayRole).toString()
// file name
<< qSetFieldWidth(64)
<< child->data(1,Qt::DisplayRole).toString()
// folder
<< qSetFieldWidth(30)
<< child->data(2, Qt::DisplayRole).toString()
// action
<< qSetFieldWidth(15)
<< child->data(3, Qt::DisplayRole).toString()
<< qSetFieldWidth(0)
<< endl;
}
}
}

View file

@ -45,28 +45,26 @@ public:
~ProtocolWidget();
QSize sizeHint() const { return ownCloudGui::settingsDialogSize(); }
QTreeWidget *issueWidget() { return _issueItemView; }
void storeSyncActivity(QTextStream& ts);
void storeSyncIssues(QTextStream& ts);
public slots:
void slotProgressInfo( const QString& folder, const ProgressInfo& progress );
void slotItemCompleted( const QString& folder, const SyncFileItem& item, const PropagatorJob& job);
void slotOpenFile( QTreeWidgetItem* item, int );
protected slots:
void copyToClipboard();
void slotRetrySync();
protected:
void showEvent(QShowEvent *);
void hideEvent(QHideEvent *);
signals:
void guiLog(const QString&, const QString&);
void copyToClipboard();
private:
void setSyncResultStatus(const SyncResult& result );
void cleanIgnoreItems( const QString& folder );
void computeResyncButtonEnabled();
QString fixupFilename( const QString& name );
QTreeWidgetItem* createCompletedTreewidgetItem(const QString &folder, const SyncFileItem &item );
@ -74,8 +72,7 @@ private:
const int IgnoredIndicatorRole;
Ui::ProtocolWidget *_ui;
QPushButton *_retrySyncBtn;
QPushButton *_copyBtn;
QTreeWidget *_issueItemView;
};
}

View file

@ -13,59 +13,53 @@
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Sync Activity</string>
<widget class="QLabel" name="_headerLabel">
<property name="text">
<string>TextLabel</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<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 row="1" column="0">
<widget class="QDialogButtonBox" name="_dialogButtonBox">
<property name="standardButtons">
<set>QDialogButtonBox::NoButton</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTreeWidget" name="_treeWidget">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="columnCount">
<number>4</number>
</property>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">2</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">3</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">4</string>
</property>
</column>
</widget>
</item>
<item row="2" column="1">
<widget class="QDialogButtonBox" name="_dialogButtonBox"/>
</item>
</layout>
</widget>
<resources/>

View file

@ -22,8 +22,9 @@
#include "configfile.h"
#include "progressdispatcher.h"
#include "owncloudgui.h"
#include "protocolwidget.h"
#include "activitywidget.h"
#include "accountmanager.h"
#include "protocolwidget.h"
#include <QLabel>
#include <QStandardItemModel>
@ -81,11 +82,13 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) :
// Note: all the actions have a '\n' because the account name is in two lines and
// all buttons must have the same size in order to keep a good layout
_protocolAction = createColorAwareAction(QLatin1String(":/client/resources/activity.png"), tr("Activity"));
_actionGroup->addAction(_protocolAction);
_toolBar->addAction(_protocolAction);
ProtocolWidget *protocolWidget = new ProtocolWidget;
_ui->stack->addWidget(protocolWidget);
_activityAction = createColorAwareAction(QLatin1String(":/client/resources/activity.png"), tr("Activity"));
_actionGroup->addAction(_activityAction);
addActionToToolBar(_activityAction);
_activitySettings = new ActivitySettings;
_ui->stack->addWidget(_activitySettings);
connect( _activitySettings, SIGNAL(guiLog(QString,QString)), _gui,
SLOT(slotShowOptionalTrayMessage(QString,QString)) );
QAction *generalAction = createColorAwareAction(QLatin1String(":/client/resources/settings.png"), tr("General"));
_actionGroup->addAction(generalAction);
@ -99,7 +102,7 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) :
NetworkSettings *networkSettings = new NetworkSettings;
_ui->stack->addWidget(networkSettings);
_actionGroupWidgets.insert(_protocolAction, protocolWidget);
_actionGroupWidgets.insert(_activityAction, _activitySettings);
_actionGroupWidgets.insert(generalAction, generalSettings);
_actionGroupWidgets.insert(networkAction, networkSettings);
@ -179,8 +182,8 @@ void SettingsDialog::showFirstPage()
void SettingsDialog::showActivityPage()
{
if (_protocolAction) {
slotSwitchPage(_protocolAction);
if (_activityAction) {
slotSwitchPage(_activityAction);
}
}
@ -200,6 +203,8 @@ void SettingsDialog::accountAdded(AccountState *s)
connect( accountSettings, SIGNAL(folderChanged()), _gui, SLOT(slotFoldersChanged()));
connect( accountSettings, SIGNAL(openFolderAlias(const QString&)),
_gui, SLOT(slotFolderOpenAction(QString)));
slotRefreshActivity(s);
}
void SettingsDialog::accountRemoved(AccountState *s)
@ -218,11 +223,13 @@ void SettingsDialog::accountRemoved(AccountState *s)
break;
}
}
_activitySettings->slotRemoveAccount(s);
}
void SettingsDialog::customizeStyle()
{
QString highlightColor(palette().highlight().color().name());
QString highlightColor(palette().highlight().color().name());
QString altBase(palette().alternateBase().color().name());
QString dark(palette().dark().color().name());
QString background(palette().base().color().name());
@ -290,4 +297,21 @@ QAction *SettingsDialog::createColorAwareAction(const QString &iconPath, const Q
return action;
}
void SettingsDialog::addActionToToolBar(QAction *action) {
QToolButton* btn = new QToolButton;
btn->setDefaultAction(action);
btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
_toolBar->addWidget(btn);
btn->setMinimumWidth(_toolBar->sizeHint().height() * 1.3);
}
void SettingsDialog::slotRefreshActivity( AccountState* accountState )
{
if (accountState) {
qDebug() << "Refreshing Activity list for " << accountState->account()->displayName();
_activitySettings->slotRefresh(accountState);
}
}
} // namespace OCC

View file

@ -18,6 +18,7 @@
#include <QStyledItemDelegate>
#include "progressdispatcher.h"
#include "owncloudgui.h"
class QAction;
class QActionGroup;
@ -35,6 +36,7 @@ class AccountSettings;
class Application;
class FolderMan;
class ownCloudGui;
class ActivitySettings;
/**
* @brief The SettingsDialog class
@ -54,6 +56,7 @@ public slots:
void showFirstPage();
void showActivityPage();
void slotSwitchPage(QAction *action);
void slotRefreshActivity(AccountState *accountState );
protected:
void reject() Q_DECL_OVERRIDE;
@ -66,6 +69,8 @@ private slots:
private:
void customizeStyle();
void addActionToToolBar(QAction* action);
QIcon createColorAwareIcon(const QString &name);
QAction *createColorAwareAction(const QString &iconName, const QString &fileName);
Ui::SettingsDialog * const _ui;
@ -76,7 +81,9 @@ private:
QToolBar* _toolBar;
QAction * _protocolAction;
ActivitySettings *_activitySettings;
QAction * _activityAction;
ownCloudGui *_gui;
};

52
src/gui/synclogdialog.cpp Normal file
View file

@ -0,0 +1,52 @@
/*
* Copyright (C) by Roeland Jago Douma <roeland@famdouma.nl>
* Copyright (C) 2015 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 "synclogdialog.h"
#include "ui_synclogdialog.h"
#include "theme.h"
#include "syncresult.h"
#include "configfile.h"
#include "capabilities.h"
#include "QProgressIndicator.h"
#include <QPushButton>
namespace OCC {
SyncLogDialog::SyncLogDialog(QWidget *parent, ProtocolWidget *protoWidget) :
QDialog(parent),
_ui(new Ui::SyncLogDialog)
{
setObjectName("SyncLogDialog"); // required as group for saveGeometry call
_ui->setupUi(this);
if( protoWidget) {
_ui->logWidgetLayout->addWidget(protoWidget);
}
QPushButton *closeButton = _ui->buttonBox->button(QDialogButtonBox::Close);
if( closeButton ) {
connect( closeButton, SIGNAL(clicked()), this, SLOT(close()) );
}
}
SyncLogDialog::~SyncLogDialog()
{
}
}

51
src/gui/synclogdialog.h Normal file
View file

@ -0,0 +1,51 @@
/*
* Copyright (C) by Roeland Jago Douma <roeland@famdouma.nl>
* Copyright (C) 2015 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 SyncLogDialog_H
#define SyncLogDialog_H
#include "protocolwidget.h"
#include <QDialog>
namespace OCC {
namespace Ui {
class SyncLogDialog;
}
/**
* @brief The SyncLogDialog class
* @ingroup gui
*/
class SyncLogDialog : public QDialog
{
Q_OBJECT
public:
explicit SyncLogDialog(QWidget *parent = 0, ProtocolWidget *protoWidget = 0);
~SyncLogDialog();
private slots:
private:
Ui::SyncLogDialog *_ui;
};
}
#endif // SyncLogDialog_H

38
src/gui/synclogdialog.ui Normal file
View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OCC::SyncLogDialog</class>
<widget class="QDialog" name="OCC::SyncLogDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>372</width>
<height>247</height>
</rect>
</property>
<property name="windowTitle">
<string>Synchronisation Log</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="logWidgetLayout"/>
</item>
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View file

@ -588,12 +588,19 @@ bool EntityExistsJob::finished()
JsonApiJob::JsonApiJob(const AccountPtr &account, const QString& path, QObject* parent): AbstractNetworkJob(account, path, parent)
{ }
void JsonApiJob::addQueryParams(QList< QPair<QString,QString> > params)
{
_additionalParams = params;
}
void JsonApiJob::start()
{
QNetworkRequest req;
req.setRawHeader("OCS-APIREQUEST", "true");
QUrl url = Account::concatUrlPath(account()->url(), path());
url.setQueryItems(QList<QPair<QString, QString> >() << qMakePair(QString::fromLatin1("format"), QString::fromLatin1("json")));
QList<QPair<QString, QString> > params = _additionalParams;
params << qMakePair(QString::fromLatin1("format"), QString::fromLatin1("json"));
url.setQueryItems(params);
setReply(davRequest("GET", url, req));
setupConnections(reply());
AbstractNetworkJob::start();

View file

@ -209,12 +209,26 @@ class OWNCLOUDSYNC_EXPORT JsonApiJob : public AbstractNetworkJob {
Q_OBJECT
public:
explicit JsonApiJob(const AccountPtr &account, const QString &path, QObject *parent = 0);
/**
* @brief addQueryParams - add more parameters to the ocs call
* @param params: list pairs of strings containing the parameter name and the value.
*
* All parameters from the passed list are appended to the query. Note
* that the format=json parameter is added automatically and does not
* need to be set this way.
*
* This function needs to be called before start() obviously.
*/
void addQueryParams(QList< QPair<QString,QString> > params);
public slots:
void start() Q_DECL_OVERRIDE;
protected:
bool finished() Q_DECL_OVERRIDE;
signals:
void jsonRecieved(const QVariantMap &json);
private:
QList< QPair<QString,QString> > _additionalParams;
};
} // namespace OCC

View file

@ -334,6 +334,15 @@ QString Utility::durationToDescriptiveString(quint64 msecs)
QCoreApplication::translate("Utility", periods[p+1].name, 0, QCoreApplication::UnicodeUTF8, secondPartNum));
}
QString Utility::fileNameForGuiUse(const QString& fName)
{
if( isMac() ) {
QString n(fName);
return n.replace(QChar(':'), QChar('/'));
}
return fName;
}
bool Utility::hasDarkSystray()
{
return hasDarkSystray_private();

View file

@ -105,6 +105,8 @@ namespace Utility
// For Mac and Windows, it returns QString()
OWNCLOUDSYNC_EXPORT QByteArray versionOfInstalledBinary(const QString& command = QString() );
OWNCLOUDSYNC_EXPORT QString fileNameForGuiUse(const QString& fName);
class OWNCLOUDSYNC_EXPORT StopWatch {
private:
QHash<QString, quint64> _lapTimes;