2013-07-04 21:59:40 +04:00
/*
* Copyright ( C ) by Klaas Freitag < freitag @ kde . org >
*
* 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 .
*/
2014-07-11 02:31:24 +04:00
# include "folderstatusmodel.h"
2015-03-27 13:46:03 +03:00
# include "folderman.h"
2015-04-27 20:09:48 +03:00
# include "accountstate.h"
2017-09-01 19:11:43 +03:00
# include "common/asserts.h"
2015-03-27 13:46:03 +03:00
# include <theme.h>
# include <account.h>
2015-06-15 15:16:21 +03:00
# include "folderstatusdelegate.h"
2013-07-04 21:59:40 +04:00
2015-06-02 21:01:13 +03:00
# include <QFileIconProvider>
2015-08-06 14:54:43 +03:00
# include <QVarLengthArray>
2015-10-26 17:46:11 +03:00
# include <set>
2013-07-04 21:59:40 +04:00
2015-03-27 13:46:03 +03:00
Q_DECLARE_METATYPE ( QPersistentModelIndex )
2014-11-10 00:34:07 +03:00
namespace OCC {
2013-07-04 21:59:40 +04:00
2017-12-28 22:33:10 +03:00
Q_LOGGING_CATEGORY ( lcFolderStatus , " nextcloud.gui.folder.model " , QtInfoMsg )
2017-05-09 15:24:11 +03:00
2015-03-27 13:46:03 +03:00
static const char propertyParentIndexC [ ] = " oc_parentIndex " ;
2017-01-24 17:39:08 +03:00
static const char propertyPermissionMap [ ] = " oc_permissionMap " ;
2020-12-07 21:12:21 +03:00
static const char propertyEncryptionMap [ ] = " nc_encryptionMap " ;
2017-01-24 17:39:08 +03:00
2017-05-17 11:55:42 +03:00
static QString removeTrailingSlash ( const QString & s )
{
2017-01-24 17:39:08 +03:00
if ( s . endsWith ( ' / ' ) ) {
return s . left ( s . size ( ) - 1 ) ;
}
return s ;
}
2015-03-27 13:46:03 +03:00
FolderStatusModel : : FolderStatusModel ( QObject * parent )
2017-05-17 11:55:42 +03:00
: QAbstractItemModel ( parent )
2013-07-04 21:59:40 +04:00
{
2017-11-23 18:55:12 +03:00
2015-03-27 13:46:03 +03:00
}
2020-05-25 22:33:24 +03:00
FolderStatusModel : : ~ FolderStatusModel ( ) = default ;
2015-03-27 13:46:03 +03:00
2017-05-17 11:55:42 +03:00
static bool sortByFolderHeader ( const FolderStatusModel : : SubFolderInfo & lhs , const FolderStatusModel : : SubFolderInfo & rhs )
2016-11-08 15:30:18 +03:00
{
return QString : : compare ( lhs . _folder - > shortGuiRemotePathOrAppName ( ) ,
2017-05-17 11:55:42 +03:00
rhs . _folder - > shortGuiRemotePathOrAppName ( ) ,
Qt : : CaseInsensitive )
< 0 ;
2016-11-08 15:30:18 +03:00
}
2013-07-04 21:59:40 +04:00
2017-05-17 11:55:42 +03:00
void FolderStatusModel : : setAccountState ( const AccountState * accountState )
2015-03-27 13:46:03 +03:00
{
2022-12-07 21:43:27 +03:00
connect ( accountState - > account ( ) - > e2e ( ) , & OCC : : ClientSideEncryption : : initializationFinished , this , & FolderStatusModel : : e2eInitializationFinished ) ;
2015-03-27 13:46:03 +03:00
beginResetModel ( ) ;
_dirty = false ;
_folders . clear ( ) ;
2015-07-03 16:03:18 +03:00
_accountState = accountState ;
2015-04-27 20:09:48 +03:00
2017-09-20 11:14:48 +03:00
connect ( FolderMan : : instance ( ) , & FolderMan : : folderSyncStateChange ,
this , & FolderStatusModel : : slotFolderSyncStateChange , Qt : : UniqueConnection ) ;
connect ( FolderMan : : instance ( ) , & FolderMan : : scheduleQueueChanged ,
this , & FolderStatusModel : : slotFolderScheduleQueueChanged , Qt : : UniqueConnection ) ;
2015-09-04 11:33:48 +03:00
2015-04-27 20:09:48 +03:00
auto folders = FolderMan : : instance ( ) - > map ( ) ;
foreach ( auto f , folders ) {
2017-05-17 11:55:42 +03:00
if ( ! accountState )
break ;
2015-07-03 16:03:18 +03:00
if ( f - > accountState ( ) ! = accountState )
2015-04-27 20:09:48 +03:00
continue ;
SubFolderInfo info ;
info . _name = f - > alias ( ) ;
info . _path = " / " ;
info . _folder = f ;
2015-06-10 18:00:08 +03:00
info . _checked = Qt : : PartiallyChecked ;
2015-04-27 20:09:48 +03:00
_folders < < info ;
2015-06-02 20:45:23 +03:00
2017-09-20 11:14:48 +03:00
connect ( f , & Folder : : progressInfo , this , & FolderStatusModel : : slotSetProgress , Qt : : UniqueConnection ) ;
connect ( f , & Folder : : newBigFolderDiscovered , this , & FolderStatusModel : : slotNewBigFolder , Qt : : UniqueConnection ) ;
2015-04-27 20:09:48 +03:00
}
2016-11-08 15:30:18 +03:00
// Sort by header text
2017-12-08 13:07:46 +03:00
std : : sort ( _folders . begin ( ) , _folders . end ( ) , sortByFolderHeader ) ;
2016-11-08 15:30:18 +03:00
// Set the root _pathIdx after the sorting
for ( int i = 0 ; i < _folders . size ( ) ; + + i ) {
_folders [ i ] . _pathIdx < < i ;
}
2015-03-27 13:46:03 +03:00
endResetModel ( ) ;
2015-06-12 12:28:56 +03:00
emit dirtyChanged ( ) ;
2013-07-04 21:59:40 +04:00
}
2015-03-27 13:46:03 +03:00
2017-05-17 11:55:42 +03:00
Qt : : ItemFlags FolderStatusModel : : flags ( const QModelIndex & index ) const
2013-07-04 21:59:40 +04:00
{
2017-05-17 11:55:42 +03:00
if ( ! _accountState ) {
2020-10-09 23:56:45 +03:00
return { } ;
2017-05-17 11:55:42 +03:00
}
2020-12-09 18:54:49 +03:00
const auto info = infoForIndex ( index ) ;
const auto supportsSelectiveSync = info & & info - > _folder & & info - > _folder - > supportsSelectiveSync ( ) ;
2015-03-27 13:46:03 +03:00
switch ( classify ( index ) ) {
2017-05-17 11:55:42 +03:00
case AddButton : {
Qt : : ItemFlags ret ;
ret = Qt : : ItemNeverHasChildren ;
if ( ! _accountState - > isConnected ( ) ) {
return ret ;
2015-07-14 12:03:25 +03:00
}
2017-05-17 11:55:42 +03:00
return Qt : : ItemIsEnabled | ret ;
}
case FetchLabel :
2017-09-13 07:26:56 +03:00
return Qt : : ItemIsEnabled | Qt : : ItemNeverHasChildren ;
2017-05-17 11:55:42 +03:00
case RootFolder :
return Qt : : ItemIsEnabled ;
case SubFolder :
2020-12-09 18:54:49 +03:00
if ( supportsSelectiveSync ) {
return Qt : : ItemIsEnabled | Qt : : ItemIsUserCheckable | Qt : : ItemIsSelectable ;
} else {
return Qt : : ItemIsEnabled | Qt : : ItemIsSelectable ;
}
2015-03-27 13:46:03 +03:00
}
2020-10-09 23:56:45 +03:00
return { } ;
2013-07-04 21:59:40 +04:00
}
QVariant FolderStatusModel : : data ( const QModelIndex & index , int role ) const
{
if ( ! index . isValid ( ) )
return QVariant ( ) ;
if ( role = = Qt : : EditRole )
return QVariant ( ) ;
2015-03-27 13:46:03 +03:00
2017-05-17 11:55:42 +03:00
switch ( classify ( index ) ) {
2015-07-14 12:03:25 +03:00
case AddButton : {
if ( role = = FolderStatusDelegate : : AddButton ) {
2015-03-27 13:46:03 +03:00
return QVariant ( true ) ;
2015-07-14 12:03:25 +03:00
} else if ( role = = Qt : : ToolTipRole ) {
if ( ! _accountState - > isConnected ( ) ) {
return tr ( " You need to be connected to add a folder " ) ;
2017-05-17 11:55:42 +03:00
}
2015-07-14 12:03:25 +03:00
return tr ( " Click this button to add a folder to synchronize. " ) ;
}
2015-03-27 13:46:03 +03:00
return QVariant ( ) ;
2015-07-14 12:03:25 +03:00
}
2017-05-17 11:55:42 +03:00
case SubFolder : {
2022-12-07 21:43:27 +03:00
const auto & subfolderInfo = static_cast < SubFolderInfo * > ( index . internalPointer ( ) ) - > _subs . at ( index . row ( ) ) ;
const auto supportsSelectiveSync = subfolderInfo . _folder & & subfolderInfo . _folder - > supportsSelectiveSync ( ) ;
2020-12-09 18:54:49 +03:00
2015-03-27 13:46:03 +03:00
switch ( role ) {
2022-12-07 21:43:27 +03:00
case Qt : : DisplayRole : {
2015-11-18 17:40:07 +03:00
//: Example text: "File.txt (23KB)"
2022-12-07 21:43:27 +03:00
const auto & xParent = static_cast < SubFolderInfo * > ( index . internalPointer ( ) ) ;
const auto suffix = ( subfolderInfo . _isNonDecryptable & & subfolderInfo . _checked & & ( ! xParent | | ! xParent - > _isEncrypted ) )
? tr ( " - %1 " ) . arg ( " Could not decrypt! " )
: QString { } ;
return subfolderInfo . _size < 0 ? QString ( subfolderInfo . _name + suffix ) : QString ( tr ( " %1 (%2) " ) . arg ( subfolderInfo . _name , Utility : : octetsToString ( subfolderInfo . _size ) ) + suffix ) ;
}
2017-02-23 16:54:17 +03:00
case Qt : : ToolTipRole :
2022-12-07 21:43:27 +03:00
return QString ( QLatin1String ( " <qt> " ) + Utility : : escape ( subfolderInfo . _size < 0 ? subfolderInfo . _name : tr ( " %1 (%2) " ) . arg ( subfolderInfo . _name , Utility : : octetsToString ( subfolderInfo . _size ) ) ) + QLatin1String ( " </qt> " ) ) ;
2015-03-27 13:46:03 +03:00
case Qt : : CheckStateRole :
2020-12-09 18:54:49 +03:00
if ( supportsSelectiveSync ) {
2022-12-07 21:43:27 +03:00
return subfolderInfo . _checked ;
2020-12-09 18:54:49 +03:00
} else {
return QVariant ( ) ;
}
2020-06-30 18:47:10 +03:00
case Qt : : DecorationRole : {
2022-12-07 21:43:27 +03:00
if ( subfolderInfo . _isNonDecryptable & & subfolderInfo . _checked ) {
return QIcon ( QLatin1String ( " :/client/theme/lock-broken.svg " ) ) ;
}
if ( subfolderInfo . _isEncrypted ) {
2020-01-18 19:47:17 +03:00
return QIcon ( QLatin1String ( " :/client/theme/lock-https.svg " ) ) ;
2022-12-07 21:43:27 +03:00
} else if ( subfolderInfo . _size > 0 & & isAnyAncestorEncrypted ( index ) ) {
2020-05-28 21:23:55 +03:00
return QIcon ( QLatin1String ( " :/client/theme/lock-broken.svg " ) ) ;
2018-06-22 12:21:30 +03:00
}
2022-12-07 21:43:27 +03:00
return QFileIconProvider ( ) . icon ( subfolderInfo . _isExternal ? QFileIconProvider : : Network : QFileIconProvider : : Folder ) ;
2020-06-30 18:47:10 +03:00
}
2015-06-11 16:46:01 +03:00
case Qt : : ForegroundRole :
2022-12-07 21:43:27 +03:00
if ( subfolderInfo . _isUndecided | | ( subfolderInfo . _isNonDecryptable & & subfolderInfo . _checked ) ) {
2015-06-11 16:46:01 +03:00
return QColor ( Qt : : red ) ;
}
break ;
2017-08-25 15:12:27 +03:00
case FileIdRole :
2022-12-07 21:43:27 +03:00
return subfolderInfo . _fileId ;
2017-04-26 21:03:55 +03:00
case FolderStatusDelegate : : FolderPathRole : {
2022-12-07 21:43:27 +03:00
auto f = subfolderInfo . _folder ;
2017-04-26 21:03:55 +03:00
if ( ! f )
return QVariant ( ) ;
2022-12-07 21:43:27 +03:00
return QVariant ( f - > path ( ) + subfolderInfo . _path ) ;
2017-05-17 11:55:42 +03:00
}
2015-03-27 13:46:03 +03:00
}
}
return QVariant ( ) ;
2017-05-17 11:55:42 +03:00
case FetchLabel : {
2015-10-13 15:10:52 +03:00
const auto x = static_cast < SubFolderInfo * > ( index . internalPointer ( ) ) ;
2017-05-17 11:55:42 +03:00
switch ( role ) {
case Qt : : DisplayRole :
if ( x - > _hasError ) {
return QVariant ( tr ( " Error while loading the list of folders from the server. " )
+ QString ( " \n " ) + x - > _lastErrorString ) ;
} else {
2019-11-15 01:23:43 +03:00
return tr ( " Fetching folder list from server … " ) ;
2017-05-17 11:55:42 +03:00
}
break ;
default :
return QVariant ( ) ;
2015-08-18 14:21:02 +03:00
}
2015-10-13 15:10:52 +03:00
}
2015-03-27 13:46:03 +03:00
case RootFolder :
break ;
}
2017-05-17 11:55:42 +03:00
const SubFolderInfo & folderInfo = _folders . at ( index . row ( ) ) ;
2015-07-03 15:28:04 +03:00
auto f = folderInfo . _folder ;
2015-03-27 13:46:03 +03:00
if ( ! f )
return QVariant ( ) ;
2017-05-17 11:55:42 +03:00
const SubFolderInfo : : Progress & progress = folderInfo . _progress ;
2015-07-03 16:03:18 +03:00
const bool accountConnected = _accountState - > isConnected ( ) ;
2015-03-27 13:46:03 +03:00
switch ( role ) {
2017-05-17 11:55:42 +03:00
case FolderStatusDelegate : : FolderPathRole :
return f - > shortGuiLocalPath ( ) ;
case FolderStatusDelegate : : FolderSecondPathRole :
return f - > remotePath ( ) ;
2017-07-12 15:50:51 +03:00
case FolderStatusDelegate : : FolderConflictMsg :
2018-01-23 16:11:20 +03:00
return ( f - > syncResult ( ) . hasUnresolvedConflicts ( ) )
2017-07-12 15:50:51 +03:00
? QStringList ( tr ( " There are unresolved conflicts. Click for details. " ) )
: QStringList ( ) ;
2017-05-17 11:55:42 +03:00
case FolderStatusDelegate : : FolderErrorMsg :
return f - > syncResult ( ) . errorStrings ( ) ;
2018-08-18 10:37:00 +03:00
case FolderStatusDelegate : : FolderInfoMsg :
2020-10-21 13:31:21 +03:00
return f - > virtualFilesEnabled ( ) & & f - > vfs ( ) . mode ( ) ! = Vfs : : Mode : : WindowsCfApi
2019-01-08 15:10:20 +03:00
? QStringList ( tr ( " Virtual file support is enabled. " ) )
2018-08-18 10:37:00 +03:00
: QStringList ( ) ;
2017-05-17 11:55:42 +03:00
case FolderStatusDelegate : : SyncRunning :
return f - > syncResult ( ) . status ( ) = = SyncResult : : SyncRunning ;
2019-01-23 01:16:57 +03:00
case FolderStatusDelegate : : SyncDate :
return f - > syncResult ( ) . syncTime ( ) ;
2017-05-17 11:55:42 +03:00
case FolderStatusDelegate : : HeaderRole :
return f - > shortGuiRemotePathOrAppName ( ) ;
case FolderStatusDelegate : : FolderAliasRole :
return f - > alias ( ) ;
case FolderStatusDelegate : : FolderSyncPaused :
return f - > syncPaused ( ) ;
case FolderStatusDelegate : : FolderAccountConnected :
return accountConnected ;
2015-11-09 18:38:48 +03:00
case Qt : : ToolTipRole : {
QString toolTip ;
2016-01-21 11:56:01 +03:00
if ( ! progress . isNull ( ) ) {
return progress . _progressString ;
}
2017-05-17 11:55:42 +03:00
if ( accountConnected )
2015-11-09 18:38:48 +03:00
toolTip = Theme : : instance ( ) - > statusHeaderText ( f - > syncResult ( ) . status ( ) ) ;
2015-08-29 14:04:10 +03:00
else
2015-11-09 18:38:48 +03:00
toolTip = tr ( " Signed out " ) ;
toolTip + = " \n " ;
toolTip + = folderInfo . _folder - > path ( ) ;
return toolTip ;
}
2015-03-27 13:46:03 +03:00
case FolderStatusDelegate : : FolderStatusIconRole :
2017-05-17 11:55:42 +03:00
if ( accountConnected ) {
2015-03-27 13:46:03 +03:00
auto theme = Theme : : instance ( ) ;
auto status = f - > syncResult ( ) . status ( ) ;
2017-05-17 11:55:42 +03:00
if ( f - > syncPaused ( ) ) {
return theme - > folderDisabledIcon ( ) ;
2015-03-27 13:46:03 +03:00
} else {
2020-08-18 18:41:02 +03:00
if ( status = = SyncResult : : SyncPrepare | | status = = SyncResult : : Undefined ) {
2015-03-27 13:46:03 +03:00
return theme - > syncStateIcon ( SyncResult : : SyncRunning ) ;
} else {
2018-04-09 12:02:29 +03:00
// The "Problem" *result* just means some files weren't
// synced, so we show "Success" in these cases. But we
// do use the "Problem" *icon* for unresolved conflicts.
if ( status = = SyncResult : : Success | | status = = SyncResult : : Problem ) {
if ( f - > syncResult ( ) . hasUnresolvedConflicts ( ) ) {
return theme - > syncStateIcon ( SyncResult : : Problem ) ;
} else {
return theme - > syncStateIcon ( SyncResult : : Success ) ;
}
2015-03-27 13:46:03 +03:00
} else {
2017-05-17 11:55:42 +03:00
return theme - > syncStateIcon ( status ) ;
2015-03-27 13:46:03 +03:00
}
}
}
} else {
return Theme : : instance ( ) - > folderOfflineIcon ( ) ;
}
2015-04-09 13:06:47 +03:00
case FolderStatusDelegate : : SyncProgressItemString :
2015-07-03 15:28:04 +03:00
return progress . _progressString ;
2015-04-09 13:06:47 +03:00
case FolderStatusDelegate : : WarningCount :
2015-07-03 15:28:04 +03:00
return progress . _warningCount ;
2015-04-09 13:06:47 +03:00
case FolderStatusDelegate : : SyncProgressOverallPercent :
2015-07-03 15:28:04 +03:00
return progress . _overallPercent ;
2015-04-09 13:06:47 +03:00
case FolderStatusDelegate : : SyncProgressOverallString :
2015-07-03 15:28:04 +03:00
return progress . _overallSyncString ;
2020-10-05 18:05:58 +03:00
case FolderStatusDelegate : : FolderSyncText :
2020-10-21 13:31:21 +03:00
if ( f - > virtualFilesEnabled ( ) ) {
2020-10-05 18:05:58 +03:00
return tr ( " Synchronizing VirtualFiles with local folder " ) ;
} else {
return tr ( " Synchronizing with local folder " ) ;
}
2015-03-27 13:46:03 +03:00
}
return QVariant ( ) ;
}
2017-05-17 11:55:42 +03:00
bool FolderStatusModel : : setData ( const QModelIndex & index , const QVariant & value , int role )
2015-03-27 13:46:03 +03:00
{
2017-05-17 11:55:42 +03:00
if ( role = = Qt : : CheckStateRole ) {
2015-03-27 13:46:03 +03:00
auto info = infoForIndex ( index ) ;
2020-12-09 18:54:49 +03:00
Q_ASSERT ( info - > _folder & & info - > _folder - > supportsSelectiveSync ( ) ) ;
2020-05-18 21:54:23 +03:00
auto checked = static_cast < Qt : : CheckState > ( value . toInt ( ) ) ;
2015-03-27 13:46:03 +03:00
if ( info & & info - > _checked ! = checked ) {
info - > _checked = checked ;
if ( checked = = Qt : : Checked ) {
// If we are checked, check that we may need to check the parent as well if
2015-10-05 07:21:19 +03:00
// all the siblings are also checked
2015-03-27 13:46:03 +03:00
QModelIndex parent = index . parent ( ) ;
auto parentInfo = infoForIndex ( parent ) ;
if ( parentInfo & & parentInfo - > _checked ! = Qt : : Checked ) {
bool hasUnchecked = false ;
2017-05-17 11:55:42 +03:00
foreach ( const auto & sub , parentInfo - > _subs ) {
2015-03-27 13:46:03 +03:00
if ( sub . _checked ! = Qt : : Checked ) {
hasUnchecked = true ;
break ;
}
}
if ( ! hasUnchecked ) {
setData ( parent , Qt : : Checked , Qt : : CheckStateRole ) ;
} else if ( parentInfo - > _checked = = Qt : : Unchecked ) {
setData ( parent , Qt : : PartiallyChecked , Qt : : CheckStateRole ) ;
}
}
// also check all the children
for ( int i = 0 ; i < info - > _subs . count ( ) ; + + i ) {
2020-07-22 22:02:09 +03:00
if ( info - > _subs . at ( i ) . _checked ! = Qt : : Checked ) {
2018-01-24 12:19:54 +03:00
setData ( this - > index ( i , 0 , index ) , Qt : : Checked , Qt : : CheckStateRole ) ;
2015-03-27 13:46:03 +03:00
}
}
}
if ( checked = = Qt : : Unchecked ) {
QModelIndex parent = index . parent ( ) ;
auto parentInfo = infoForIndex ( parent ) ;
if ( parentInfo & & parentInfo - > _checked = = Qt : : Checked ) {
setData ( parent , Qt : : PartiallyChecked , Qt : : CheckStateRole ) ;
}
// Uncheck all the children
for ( int i = 0 ; i < info - > _subs . count ( ) ; + + i ) {
2020-07-22 22:02:09 +03:00
if ( info - > _subs . at ( i ) . _checked ! = Qt : : Unchecked ) {
2018-01-24 12:19:54 +03:00
setData ( this - > index ( i , 0 , index ) , Qt : : Unchecked , Qt : : CheckStateRole ) ;
2015-03-27 13:46:03 +03:00
}
}
}
if ( checked = = Qt : : PartiallyChecked ) {
QModelIndex parent = index . parent ( ) ;
auto parentInfo = infoForIndex ( parent ) ;
if ( parentInfo & & parentInfo - > _checked ! = Qt : : PartiallyChecked ) {
setData ( parent , Qt : : PartiallyChecked , Qt : : CheckStateRole ) ;
}
}
}
_dirty = true ;
emit dirtyChanged ( ) ;
2015-06-02 20:57:41 +03:00
emit dataChanged ( index , index , QVector < int > ( ) < < role ) ;
2015-03-27 13:46:03 +03:00
return true ;
}
return QAbstractItemModel : : setData ( index , value , role ) ;
}
2017-05-17 11:55:42 +03:00
int FolderStatusModel : : columnCount ( const QModelIndex & ) const
2015-03-27 13:46:03 +03:00
{
return 1 ;
}
2017-05-17 11:55:42 +03:00
int FolderStatusModel : : rowCount ( const QModelIndex & parent ) const
2015-03-27 13:46:03 +03:00
{
if ( ! parent . isValid ( ) ) {
2017-05-17 11:55:42 +03:00
if ( Theme : : instance ( ) - > singleSyncFolder ( ) & & _folders . count ( ) ! = 0 ) {
2015-08-19 18:59:39 +03:00
// "Add folder" button not visible in the singleSyncFolder configuration.
return _folders . count ( ) ;
}
return _folders . count ( ) + 1 ; // +1 for the "add folder" button
2015-03-27 13:46:03 +03:00
}
auto info = infoForIndex ( parent ) ;
if ( ! info )
return 0 ;
2015-10-13 15:10:52 +03:00
if ( info - > hasLabel ( ) )
2015-08-18 14:21:02 +03:00
return 1 ;
2015-03-27 13:46:03 +03:00
return info - > _subs . count ( ) ;
}
2017-05-17 11:55:42 +03:00
FolderStatusModel : : ItemType FolderStatusModel : : classify ( const QModelIndex & index ) const
2015-03-27 13:46:03 +03:00
{
2017-05-17 11:55:42 +03:00
if ( auto sub = static_cast < SubFolderInfo * > ( index . internalPointer ( ) ) ) {
2015-10-13 15:10:52 +03:00
if ( sub - > hasLabel ( ) ) {
return FetchLabel ;
} else {
return SubFolder ;
}
2015-03-27 13:46:03 +03:00
}
2015-04-27 20:09:48 +03:00
if ( index . row ( ) < _folders . count ( ) ) {
2015-03-27 13:46:03 +03:00
return RootFolder ;
}
return AddButton ;
2013-07-04 21:59:40 +04:00
}
2017-05-17 11:55:42 +03:00
FolderStatusModel : : SubFolderInfo * FolderStatusModel : : infoForIndex ( const QModelIndex & index ) const
2015-03-27 13:46:03 +03:00
{
if ( ! index . isValid ( ) )
2018-11-11 12:56:22 +03:00
return nullptr ;
2017-05-17 11:55:42 +03:00
if ( auto parentInfo = static_cast < SubFolderInfo * > ( index . internalPointer ( ) ) ) {
2015-10-13 15:10:52 +03:00
if ( parentInfo - > hasLabel ( ) ) {
2018-11-11 12:56:22 +03:00
return nullptr ;
2015-08-18 14:21:02 +03:00
}
2017-01-24 17:39:08 +03:00
if ( index . row ( ) > = parentInfo - > _subs . size ( ) ) {
2018-11-11 12:56:22 +03:00
return nullptr ;
2017-01-24 17:39:08 +03:00
}
2015-08-18 14:21:02 +03:00
return & parentInfo - > _subs [ index . row ( ) ] ;
2015-03-27 13:46:03 +03:00
} else {
2015-04-27 20:09:48 +03:00
if ( index . row ( ) > = _folders . count ( ) ) {
2015-03-27 13:46:03 +03:00
// AddButton
2018-11-11 12:56:22 +03:00
return nullptr ;
2015-03-27 13:46:03 +03:00
}
2015-04-27 20:09:48 +03:00
return const_cast < SubFolderInfo * > ( & _folders [ index . row ( ) ] ) ;
2015-03-27 13:46:03 +03:00
}
}
2020-12-07 21:37:21 +03:00
bool FolderStatusModel : : isAnyAncestorEncrypted ( const QModelIndex & index ) const
{
auto parentIndex = parent ( index ) ;
while ( parentIndex . isValid ( ) ) {
const auto info = infoForIndex ( parentIndex ) ;
if ( info - > _isEncrypted ) {
return true ;
}
parentIndex = parent ( parentIndex ) ;
}
return false ;
}
2017-05-17 11:55:42 +03:00
QModelIndex FolderStatusModel : : indexForPath ( Folder * f , const QString & path ) const
2015-08-31 11:12:45 +03:00
{
2017-05-17 11:55:42 +03:00
if ( ! f ) {
2020-05-27 15:36:07 +03:00
return { } ;
2015-10-07 18:59:33 +03:00
}
2015-08-31 11:12:45 +03:00
int slashPos = path . lastIndexOf ( ' / ' ) ;
if ( slashPos = = - 1 ) {
// first level folder
for ( int i = 0 ; i < _folders . size ( ) ; + + i ) {
2017-05-17 11:55:42 +03:00
auto & info = _folders . at ( i ) ;
2016-11-08 15:57:03 +03:00
if ( info . _folder = = f ) {
2017-05-17 11:55:42 +03:00
if ( path . isEmpty ( ) ) { // the folder object
2015-10-07 18:59:33 +03:00
return index ( i , 0 ) ;
}
2016-11-08 15:57:03 +03:00
for ( int j = 0 ; j < info . _subs . size ( ) ; + + j ) {
const QString subName = info . _subs . at ( j ) . _name ;
2015-10-07 18:59:33 +03:00
if ( subName = = path ) {
2015-08-31 11:12:45 +03:00
return index ( j , 0 , index ( i ) ) ;
}
}
2020-05-27 15:36:07 +03:00
return { } ;
2015-08-31 11:12:45 +03:00
}
}
2020-05-27 15:36:07 +03:00
return { } ;
2015-08-31 11:12:45 +03:00
}
auto parent = indexForPath ( f , path . left ( slashPos ) ) ;
if ( ! parent . isValid ( ) )
return parent ;
if ( slashPos = = path . size ( ) - 1 ) {
// The slash is the last part, we found our index
return parent ;
}
auto parentInfo = infoForIndex ( parent ) ;
if ( ! parentInfo ) {
2020-05-27 15:36:07 +03:00
return { } ;
2015-08-31 11:12:45 +03:00
}
for ( int i = 0 ; i < parentInfo - > _subs . size ( ) ; + + i ) {
2017-05-17 11:55:42 +03:00
if ( parentInfo - > _subs . at ( i ) . _name = = path . mid ( slashPos + 1 ) ) {
2015-08-31 11:12:45 +03:00
return index ( i , 0 , parent ) ;
}
}
2020-05-27 15:36:07 +03:00
return { } ;
2015-08-31 11:12:45 +03:00
}
2015-03-27 13:46:03 +03:00
2017-05-17 11:55:42 +03:00
QModelIndex FolderStatusModel : : index ( int row , int column , const QModelIndex & parent ) const
2015-03-27 13:46:03 +03:00
{
if ( ! parent . isValid ( ) ) {
2017-05-17 11:55:42 +03:00
return createIndex ( row , column /*, nullptr*/ ) ;
}
switch ( classify ( parent ) ) {
case AddButton :
case FetchLabel :
2020-05-27 15:36:07 +03:00
return { } ;
2017-05-17 11:55:42 +03:00
case RootFolder :
if ( _folders . count ( ) < = parent . row ( ) )
2020-05-27 21:19:15 +03:00
return { } ; // should not happen
2017-05-17 11:55:42 +03:00
return createIndex ( row , column , const_cast < SubFolderInfo * > ( & _folders [ parent . row ( ) ] ) ) ;
case SubFolder : {
auto pinfo = static_cast < SubFolderInfo * > ( parent . internalPointer ( ) ) ;
if ( pinfo - > _subs . count ( ) < = parent . row ( ) )
2020-05-27 15:36:07 +03:00
return { } ; // should not happen
2017-05-17 11:55:42 +03:00
auto & info = pinfo - > _subs [ parent . row ( ) ] ;
if ( ! info . hasLabel ( )
& & info . _subs . count ( ) < = row )
2020-05-27 15:36:07 +03:00
return { } ; // should not happen
2017-05-17 11:55:42 +03:00
return createIndex ( row , column , & info ) ;
}
2015-03-27 13:46:03 +03:00
}
2020-05-27 15:36:07 +03:00
return { } ;
2015-03-27 13:46:03 +03:00
}
2017-05-17 11:55:42 +03:00
QModelIndex FolderStatusModel : : parent ( const QModelIndex & child ) const
2015-03-27 13:46:03 +03:00
{
if ( ! child . isValid ( ) ) {
2020-05-27 15:36:07 +03:00
return { } ;
2015-03-27 13:46:03 +03:00
}
2017-05-17 11:55:42 +03:00
switch ( classify ( child ) ) {
case RootFolder :
case AddButton :
2020-05-27 15:36:07 +03:00
return { } ;
2017-05-17 11:55:42 +03:00
case SubFolder :
case FetchLabel :
break ;
2015-03-27 13:46:03 +03:00
}
2017-05-17 11:55:42 +03:00
auto pathIdx = static_cast < SubFolderInfo * > ( child . internalPointer ( ) ) - > _pathIdx ;
2015-03-27 13:46:03 +03:00
int i = 1 ;
2017-02-07 15:52:15 +03:00
ASSERT ( pathIdx . at ( 0 ) < _folders . count ( ) ) ;
2015-08-18 14:21:02 +03:00
if ( pathIdx . count ( ) = = 1 ) {
2017-05-17 11:55:42 +03:00
return createIndex ( pathIdx . at ( 0 ) , 0 /*, nullptr*/ ) ;
2015-03-27 13:46:03 +03:00
}
const SubFolderInfo * info = & _folders [ pathIdx . at ( 0 ) ] ;
2015-08-18 14:21:02 +03:00
while ( i < pathIdx . count ( ) - 1 ) {
2017-02-07 15:52:15 +03:00
ASSERT ( pathIdx . at ( i ) < info - > _subs . count ( ) ) ;
2020-07-22 22:02:09 +03:00
info = & info - > _subs . at ( pathIdx . at ( i ) ) ;
2015-03-27 13:46:03 +03:00
+ + i ;
}
return createIndex ( pathIdx . at ( i ) , 0 , const_cast < SubFolderInfo * > ( info ) ) ;
}
2017-05-17 11:55:42 +03:00
bool FolderStatusModel : : hasChildren ( const QModelIndex & parent ) const
2015-03-27 13:46:03 +03:00
{
if ( ! parent . isValid ( ) )
return true ;
auto info = infoForIndex ( parent ) ;
if ( ! info )
return false ;
if ( ! info - > _fetched )
return true ;
if ( info - > _subs . isEmpty ( ) )
return false ;
return true ;
}
2017-05-17 11:55:42 +03:00
bool FolderStatusModel : : canFetchMore ( const QModelIndex & parent ) const
2015-03-27 13:46:03 +03:00
{
2015-12-01 21:21:52 +03:00
if ( ! _accountState ) {
2017-05-17 11:55:42 +03:00
return false ;
}
2015-10-19 19:32:34 +03:00
if ( _accountState - > state ( ) ! = AccountState : : Connected ) {
return false ;
}
2015-03-27 13:46:03 +03:00
auto info = infoForIndex ( parent ) ;
2018-03-27 13:17:29 +03:00
if ( ! info | | info - > _fetched | | info - > _fetchingJob )
2015-03-27 13:46:03 +03:00
return false ;
2016-09-06 12:11:03 +03:00
if ( info - > _hasError ) {
// Keep showing the error to the user, it will be hidden when the account reconnects
return false ;
}
2015-03-27 13:46:03 +03:00
return true ;
}
2017-05-17 11:55:42 +03:00
void FolderStatusModel : : fetchMore ( const QModelIndex & parent )
2015-03-27 13:46:03 +03:00
{
auto info = infoForIndex ( parent ) ;
2015-06-02 21:15:16 +03:00
2018-03-27 13:17:29 +03:00
if ( ! info | | info - > _fetched | | info - > _fetchingJob )
2015-03-27 13:46:03 +03:00
return ;
2016-11-29 19:17:06 +03:00
info - > resetSubs ( this , parent ) ;
2019-01-25 09:46:16 +03:00
QString path = info - > _folder - > remotePathTrailingSlash ( ) ;
2021-01-29 21:00:21 +03:00
// info->_path always contains non-mangled name, so we need to use mangled when requesting nested folders for encrypted subfolders as required by LsColJob
const QString infoPath = ( info - > _isEncrypted & & ! info - > _e2eMangledName . isEmpty ( ) ) ? info - > _e2eMangledName : info - > _path ;
if ( infoPath ! = QLatin1String ( " / " ) ) {
path + = infoPath ;
2015-06-02 21:41:59 +03:00
}
2017-11-23 18:55:12 +03:00
2020-05-18 21:54:23 +03:00
auto * job = new LsColJob ( _accountState - > account ( ) , path , this ) ;
2018-03-27 13:17:29 +03:00
info - > _fetchingJob = job ;
2020-12-07 21:12:21 +03:00
auto props = QList < QByteArray > ( ) < < " resourcetype "
< < " http://owncloud.org/ns:size "
< < " http://owncloud.org/ns:permissions "
< < " http://owncloud.org/ns:fileid " ;
if ( _accountState - > account ( ) - > capabilities ( ) . clientSideEncryptionAvailable ( ) ) {
props < < " http://nextcloud.org/ns:is-encrypted " ;
}
job - > setProperties ( props ) ;
2017-08-25 14:56:13 +03:00
2015-10-13 15:10:52 +03:00
job - > setTimeout ( 60 * 1000 ) ;
2017-09-20 11:14:48 +03:00
connect ( job , & LsColJob : : directoryListingSubfolders ,
this , & FolderStatusModel : : slotUpdateDirectories ) ;
connect ( job , & LsColJob : : finishedWithError ,
this , & FolderStatusModel : : slotLscolFinishedWithError ) ;
connect ( job , & LsColJob : : directoryListingIterated ,
this , & FolderStatusModel : : slotGatherPermissions ) ;
2020-12-07 21:12:21 +03:00
connect ( job , & LsColJob : : directoryListingIterated ,
this , & FolderStatusModel : : slotGatherEncryptionStatus ) ;
2017-01-24 17:39:08 +03:00
2015-03-27 13:46:03 +03:00
job - > start ( ) ;
2015-10-07 18:59:33 +03:00
2015-10-13 15:10:52 +03:00
QPersistentModelIndex persistentIndex ( parent ) ;
2017-05-17 11:55:42 +03:00
job - > setProperty ( propertyParentIndexC , QVariant : : fromValue ( persistentIndex ) ) ;
2015-10-13 15:10:52 +03:00
// Show 'fetching data...' hint after a while.
_fetchingItems [ persistentIndex ] . start ( ) ;
2017-09-20 11:14:48 +03:00
QTimer : : singleShot ( 1000 , this , & FolderStatusModel : : slotShowFetchProgress ) ;
2015-03-27 13:46:03 +03:00
}
2020-02-04 17:35:14 +03:00
void FolderStatusModel : : resetAndFetch ( const QModelIndex & parent )
{
auto info = infoForIndex ( parent ) ;
info - > resetSubs ( this , parent ) ;
fetchMore ( parent ) ;
}
2017-05-17 11:55:42 +03:00
void FolderStatusModel : : slotGatherPermissions ( const QString & href , const QMap < QString , QString > & map )
2017-01-24 17:39:08 +03:00
{
auto it = map . find ( " permissions " ) ;
if ( it = = map . end ( ) )
return ;
auto job = sender ( ) ;
auto permissionMap = job - > property ( propertyPermissionMap ) . toMap ( ) ;
job - > setProperty ( propertyPermissionMap , QVariant ( ) ) ; // avoid a detach of the map while it is modified
2017-02-07 15:52:15 +03:00
ASSERT ( ! href . endsWith ( QLatin1Char ( ' / ' ) ) , " LsColXMLParser::parse should remove the trailing slash before calling us. " ) ;
2017-01-24 17:39:08 +03:00
permissionMap [ href ] = * it ;
job - > setProperty ( propertyPermissionMap , permissionMap ) ;
}
2020-12-07 21:12:21 +03:00
void FolderStatusModel : : slotGatherEncryptionStatus ( const QString & href , const QMap < QString , QString > & properties )
{
auto it = properties . find ( " is-encrypted " ) ;
if ( it = = properties . end ( ) )
return ;
auto job = sender ( ) ;
auto encryptionMap = job - > property ( propertyEncryptionMap ) . toMap ( ) ;
job - > setProperty ( propertyEncryptionMap , QVariant ( ) ) ; // avoid a detach of the map while it is modified
ASSERT ( ! href . endsWith ( QLatin1Char ( ' / ' ) ) , " LsColXMLParser::parse should remove the trailing slash before calling us. " ) ;
encryptionMap [ href ] = * it ;
job - > setProperty ( propertyEncryptionMap , encryptionMap ) ;
}
2015-10-23 16:13:15 +03:00
void FolderStatusModel : : slotUpdateDirectories ( const QStringList & list )
2015-03-27 13:46:03 +03:00
{
auto job = qobject_cast < LsColJob * > ( sender ( ) ) ;
2017-02-07 15:52:15 +03:00
ASSERT ( job ) ;
2015-03-27 13:46:03 +03:00
QModelIndex idx = qvariant_cast < QPersistentModelIndex > ( job - > property ( propertyParentIndexC ) ) ;
2015-06-16 14:26:39 +03:00
auto parentInfo = infoForIndex ( idx ) ;
if ( ! parentInfo ) {
2015-03-27 13:46:03 +03:00
return ;
}
2018-03-27 13:17:29 +03:00
ASSERT ( parentInfo - > _fetchingJob = = job ) ;
2017-05-29 14:00:43 +03:00
ASSERT ( parentInfo - > _subs . isEmpty ( ) ) ;
2015-03-27 13:46:03 +03:00
2015-10-13 15:10:52 +03:00
if ( parentInfo - > hasLabel ( ) ) {
2017-05-17 11:55:42 +03:00
beginRemoveRows ( idx , 0 , 0 ) ;
2015-08-18 14:21:02 +03:00
parentInfo - > _hasError = false ;
2015-10-13 15:10:52 +03:00
parentInfo - > _fetchingLabel = false ;
2015-08-18 14:21:02 +03:00
endRemoveRows ( ) ;
}
2018-03-27 13:17:29 +03:00
parentInfo - > _lastErrorString . clear ( ) ;
parentInfo - > _fetchingJob = nullptr ;
2015-10-13 15:10:52 +03:00
parentInfo - > _fetched = true ;
2015-03-27 13:46:03 +03:00
QUrl url = parentInfo - > _folder - > remoteUrl ( ) ;
QString pathToRemove = url . path ( ) ;
if ( ! pathToRemove . endsWith ( ' / ' ) )
pathToRemove + = ' / ' ;
2015-06-11 16:46:01 +03:00
QStringList selectiveSyncBlackList ;
2016-04-06 16:01:28 +03:00
bool ok1 = true ;
bool ok2 = true ;
2015-06-11 16:46:01 +03:00
if ( parentInfo - > _checked = = Qt : : PartiallyChecked ) {
2016-04-06 16:01:28 +03:00
selectiveSyncBlackList = parentInfo - > _folder - > journalDb ( ) - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncBlackList , & ok1 ) ;
2015-06-11 16:46:01 +03:00
}
2016-04-06 16:01:28 +03:00
auto selectiveSyncUndecidedList = parentInfo - > _folder - > journalDb ( ) - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , & ok2 ) ;
2017-05-17 11:55:42 +03:00
if ( ! ( ok1 & & ok2 ) ) {
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolderStatus ) < < " Could not retrieve selective sync info from journal " ;
2016-04-06 16:01:28 +03:00
return ;
}
2015-10-26 17:46:11 +03:00
std : : set < QString > selectiveSyncUndecidedSet ; // not QSet because it's not sorted
foreach ( const QString & str , selectiveSyncUndecidedList ) {
if ( str . startsWith ( parentInfo - > _path ) | | parentInfo - > _path = = QLatin1String ( " / " ) ) {
selectiveSyncUndecidedSet . insert ( str ) ;
}
}
2017-01-24 17:39:08 +03:00
const auto permissionMap = job - > property ( propertyPermissionMap ) . toMap ( ) ;
2020-12-07 21:12:21 +03:00
const auto encryptionMap = job - > property ( propertyEncryptionMap ) . toMap ( ) ;
2015-10-26 17:46:11 +03:00
2016-04-28 10:18:38 +03:00
QStringList sortedSubfolders = list ;
2017-03-15 19:17:33 +03:00
if ( ! sortedSubfolders . isEmpty ( ) )
sortedSubfolders . removeFirst ( ) ; // skip the parent item (first in the list)
2016-05-19 16:36:46 +03:00
Utility : : sortFilenames ( sortedSubfolders ) ;
2016-04-28 10:18:38 +03:00
QVarLengthArray < int , 10 > undecidedIndexes ;
QVector < SubFolderInfo > newSubs ;
newSubs . reserve ( sortedSubfolders . size ( ) ) ;
2017-05-17 11:55:42 +03:00
foreach ( const QString & path , sortedSubfolders ) {
2015-10-23 16:13:15 +03:00
auto relativePath = path . mid ( pathToRemove . size ( ) ) ;
if ( parentInfo - > _folder - > isFileExcludedRelative ( relativePath ) ) {
continue ;
}
2015-08-05 13:51:49 +03:00
2015-03-27 13:46:03 +03:00
SubFolderInfo newInfo ;
newInfo . _folder = parentInfo - > _folder ;
newInfo . _pathIdx = parentInfo - > _pathIdx ;
2015-10-23 16:13:15 +03:00
newInfo . _pathIdx < < newSubs . size ( ) ;
2017-01-24 17:39:08 +03:00
newInfo . _isExternal = permissionMap . value ( removeTrailingSlash ( path ) ) . toString ( ) . contains ( " M " ) ;
2020-12-07 21:12:21 +03:00
newInfo . _isEncrypted = encryptionMap . value ( removeTrailingSlash ( path ) ) . toString ( ) = = QStringLiteral ( " 1 " ) ;
2015-10-23 16:13:15 +03:00
newInfo . _path = relativePath ;
2020-06-23 20:24:56 +03:00
2022-12-07 21:43:27 +03:00
newInfo . _isNonDecryptable = newInfo . _isEncrypted
& & _accountState - > account ( ) - > e2e ( ) & & ! _accountState - > account ( ) - > e2e ( ) - > _publicKey . isNull ( )
& & _accountState - > account ( ) - > e2e ( ) - > _privateKey . isNull ( ) ;
2020-06-23 20:24:56 +03:00
SyncJournalFileRecord rec ;
2022-08-04 17:29:02 +03:00
if ( ! parentInfo - > _folder - > journalDb ( ) - > getFileRecordByE2eMangledName ( removeTrailingSlash ( relativePath ) , & rec ) ) {
qCWarning ( lcFolderStatus ) < < " Could not get file record by E2E Mangled Name from local DB " < < removeTrailingSlash ( relativePath ) ;
}
2020-06-23 20:24:56 +03:00
if ( rec . isValid ( ) ) {
newInfo . _name = removeTrailingSlash ( rec . _path ) . split ( ' / ' ) . last ( ) ;
2021-01-29 21:00:21 +03:00
if ( rec . _isE2eEncrypted & & ! rec . _e2eMangledName . isEmpty ( ) ) {
// we must use local path for Settings Dialog's filesystem tree, otherwise open and create new folder actions won't work
// hence, we are storing _e2eMangledName separately so it can be use later for LsColJob
newInfo . _e2eMangledName = relativePath ;
newInfo . _path = rec . _path ;
}
if ( ! newInfo . _path . endsWith ( ' / ' ) ) {
newInfo . _path + = ' / ' ;
}
2020-06-23 20:24:56 +03:00
} else {
newInfo . _name = removeTrailingSlash ( relativePath ) . split ( ' / ' ) . last ( ) ;
}
2015-03-27 13:46:03 +03:00
2017-08-25 14:56:13 +03:00
const auto & folderInfo = job - > _folderInfos . value ( path ) ;
newInfo . _size = folderInfo . size ;
newInfo . _fileId = folderInfo . fileId ;
2015-10-23 16:13:15 +03:00
if ( relativePath . isEmpty ( ) )
2015-03-27 13:46:03 +03:00
continue ;
if ( parentInfo - > _checked = = Qt : : Unchecked ) {
newInfo . _checked = Qt : : Unchecked ;
2015-06-11 16:46:01 +03:00
} else if ( parentInfo - > _checked = = Qt : : Checked ) {
newInfo . _checked = Qt : : Checked ;
2015-03-27 13:46:03 +03:00
} else {
2017-05-17 11:55:42 +03:00
foreach ( const QString & str , selectiveSyncBlackList ) {
2015-10-23 16:13:15 +03:00
if ( str = = relativePath | | str = = QLatin1String ( " / " ) ) {
2015-03-27 13:46:03 +03:00
newInfo . _checked = Qt : : Unchecked ;
break ;
2015-10-23 16:13:15 +03:00
} else if ( str . startsWith ( relativePath ) ) {
2015-03-27 13:46:03 +03:00
newInfo . _checked = Qt : : PartiallyChecked ;
}
}
}
2015-08-05 13:51:49 +03:00
2015-10-26 17:46:11 +03:00
auto it = selectiveSyncUndecidedSet . lower_bound ( relativePath ) ;
if ( it ! = selectiveSyncUndecidedSet . end ( ) ) {
if ( * it = = relativePath ) {
2015-08-05 16:00:21 +03:00
newInfo . _isUndecided = true ;
2015-10-26 17:46:11 +03:00
selectiveSyncUndecidedSet . erase ( it ) ;
} else if ( ( * it ) . startsWith ( relativePath ) ) {
2015-08-05 13:51:49 +03:00
undecidedIndexes . append ( newInfo . _pathIdx . last ( ) ) ;
2015-10-26 17:46:11 +03:00
// Remove all the items from the selectiveSyncUndecidedSet that starts with this path
QString relativePathNext = relativePath ;
2017-05-17 11:55:42 +03:00
relativePathNext [ relativePathNext . length ( ) - 1 ] . unicode ( ) + + ;
2015-10-26 17:46:11 +03:00
auto it2 = selectiveSyncUndecidedSet . lower_bound ( relativePathNext ) ;
selectiveSyncUndecidedSet . erase ( it , it2 ) ;
2015-08-05 13:51:49 +03:00
}
}
2015-10-23 16:13:15 +03:00
newSubs . append ( newInfo ) ;
2015-03-27 13:46:03 +03:00
}
2017-05-29 14:00:43 +03:00
if ( ! newSubs . isEmpty ( ) ) {
beginInsertRows ( idx , 0 , newSubs . size ( ) - 1 ) ;
parentInfo - > _subs = std : : move ( newSubs ) ;
endInsertRows ( ) ;
}
2015-08-05 13:51:49 +03:00
2020-08-13 13:23:02 +03:00
for ( int undecidedIndex : qAsConst ( undecidedIndexes ) ) {
suggestExpand ( index ( undecidedIndex , 0 , idx ) ) ;
2015-08-05 13:51:49 +03:00
}
2015-10-26 17:46:11 +03:00
/* Try to remove the the undecided lists the items that are not on the server. */
auto it = std : : remove_if ( selectiveSyncUndecidedList . begin ( ) , selectiveSyncUndecidedList . end ( ) ,
2017-05-17 11:55:42 +03:00
[ & ] ( const QString & s ) { return selectiveSyncUndecidedSet . count ( s ) ; } ) ;
2015-10-26 17:46:11 +03:00
if ( it ! = selectiveSyncUndecidedList . end ( ) ) {
selectiveSyncUndecidedList . erase ( it , selectiveSyncUndecidedList . end ( ) ) ;
parentInfo - > _folder - > journalDb ( ) - > setSelectiveSyncList (
2017-05-17 11:55:42 +03:00
SyncJournalDb : : SelectiveSyncUndecidedList , selectiveSyncUndecidedList ) ;
2015-10-26 17:46:11 +03:00
emit dirtyChanged ( ) ;
}
2015-03-27 13:46:03 +03:00
}
2017-05-17 11:55:42 +03:00
void FolderStatusModel : : slotLscolFinishedWithError ( QNetworkReply * r )
2015-03-27 13:46:03 +03:00
{
2015-06-02 21:15:16 +03:00
auto job = qobject_cast < LsColJob * > ( sender ( ) ) ;
2017-02-07 15:52:15 +03:00
ASSERT ( job ) ;
2015-06-02 21:15:16 +03:00
QModelIndex idx = qvariant_cast < QPersistentModelIndex > ( job - > property ( propertyParentIndexC ) ) ;
if ( ! idx . isValid ( ) ) {
return ;
}
auto parentInfo = infoForIndex ( idx ) ;
if ( parentInfo ) {
2017-05-09 15:24:11 +03:00
qCDebug ( lcFolderStatus ) < < r - > errorString ( ) ;
2016-09-06 12:11:03 +03:00
parentInfo - > _lastErrorString = r - > errorString ( ) ;
2018-05-31 12:00:11 +03:00
auto error = r - > error ( ) ;
2016-09-06 12:11:03 +03:00
2016-11-29 19:17:06 +03:00
parentInfo - > resetSubs ( this , idx ) ;
2018-05-31 12:00:11 +03:00
if ( error = = QNetworkReply : : ContentNotFoundError ) {
2015-06-02 21:15:16 +03:00
parentInfo - > _fetched = true ;
2015-10-13 15:10:52 +03:00
} else {
2017-02-07 15:52:15 +03:00
ASSERT ( ! parentInfo - > hasLabel ( ) ) ;
2016-11-29 19:17:06 +03:00
beginInsertRows ( idx , 0 , 0 ) ;
2015-08-18 14:21:02 +03:00
parentInfo - > _hasError = true ;
2016-11-29 19:17:06 +03:00
endInsertRows ( ) ;
2015-06-02 21:15:16 +03:00
}
}
}
2015-03-27 13:46:03 +03:00
2020-07-22 22:02:09 +03:00
QStringList FolderStatusModel : : createBlackList ( const FolderStatusModel : : SubFolderInfo & root ,
2017-05-17 11:55:42 +03:00
const QStringList & oldBlackList ) const
2015-03-27 13:46:03 +03:00
{
2020-07-22 22:02:09 +03:00
switch ( root . _checked ) {
2017-05-17 11:55:42 +03:00
case Qt : : Unchecked :
2020-07-22 22:02:09 +03:00
return QStringList ( root . _path ) ;
2017-05-17 11:55:42 +03:00
case Qt : : Checked :
return QStringList ( ) ;
case Qt : : PartiallyChecked :
break ;
2015-03-27 13:46:03 +03:00
}
QStringList result ;
2020-07-22 22:02:09 +03:00
if ( root . _fetched ) {
for ( int i = 0 ; i < root . _subs . count ( ) ; + + i ) {
result + = createBlackList ( root . _subs . at ( i ) , oldBlackList ) ;
2015-03-27 13:46:03 +03:00
}
} else {
// We did not load from the server so we re-use the one from the old black list
2020-07-22 22:02:09 +03:00
const QString path = root . _path ;
2017-05-17 11:55:42 +03:00
foreach ( const QString & it , oldBlackList ) {
2015-03-27 13:46:03 +03:00
if ( it . startsWith ( path ) )
result + = it ;
}
}
return result ;
}
2015-06-02 20:45:23 +03:00
void FolderStatusModel : : slotUpdateFolderState ( Folder * folder )
{
2017-05-17 11:55:42 +03:00
if ( ! folder )
return ;
2015-06-02 20:45:23 +03:00
for ( int i = 0 ; i < _folders . count ( ) ; + + i ) {
if ( _folders . at ( i ) . _folder = = folder ) {
2016-01-06 12:56:07 +03:00
emit dataChanged ( index ( i ) , index ( i ) ) ;
2015-06-02 20:45:23 +03:00
}
}
}
2015-03-27 13:46:03 +03:00
void FolderStatusModel : : slotApplySelectiveSync ( )
{
2020-07-23 13:40:58 +03:00
for ( const auto & folderInfo : qAsConst ( _folders ) ) {
if ( ! folderInfo . _fetched ) {
folderInfo . _folder - > journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , QStringList ( ) ) ;
2015-06-12 12:28:56 +03:00
continue ;
}
2020-07-23 13:40:58 +03:00
const auto folder = folderInfo . _folder ;
2015-03-27 13:46:03 +03:00
2020-05-29 16:07:05 +03:00
bool ok = false ;
2016-04-06 16:01:28 +03:00
auto oldBlackList = folder - > journalDb ( ) - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncBlackList , & ok ) ;
2017-05-17 11:55:42 +03:00
if ( ! ok ) {
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolderStatus ) < < " Could not read selective sync list from db. " ;
2018-08-01 12:10:38 +03:00
continue ;
2016-04-06 16:01:28 +03:00
}
2020-07-23 13:40:58 +03:00
QStringList blackList = createBlackList ( folderInfo , oldBlackList ) ;
2015-06-10 17:22:14 +03:00
folder - > journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncBlackList , blackList ) ;
2015-03-27 13:46:03 +03:00
2015-08-07 14:36:10 +03:00
auto blackListSet = blackList . toSet ( ) ;
auto oldBlackListSet = oldBlackList . toSet ( ) ;
// The folders that were undecided or blacklisted and that are now checked should go on the white list.
// The user confirmed them already just now.
2021-09-03 23:15:23 +03:00
QStringList toAddToWhiteList = ( ( oldBlackListSet + folder - > journalDb ( ) - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , & ok ) . toSet ( ) ) - blackListSet ) . values ( ) ;
2015-08-07 14:36:10 +03:00
2015-06-11 16:46:01 +03:00
if ( ! toAddToWhiteList . isEmpty ( ) ) {
2016-04-06 16:01:28 +03:00
auto whiteList = folder - > journalDb ( ) - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncWhiteList , & ok ) ;
if ( ok ) {
whiteList + = toAddToWhiteList ;
folder - > journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncWhiteList , whiteList ) ;
}
2015-06-11 16:46:01 +03:00
}
// clear the undecided list
folder - > journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , QStringList ( ) ) ;
2015-10-05 07:21:19 +03:00
// do the sync if there were changes
2015-03-27 13:46:03 +03:00
auto changes = ( oldBlackListSet - blackListSet ) + ( blackListSet - oldBlackListSet ) ;
if ( ! changes . isEmpty ( ) ) {
if ( folder - > isBusy ( ) ) {
folder - > slotTerminateSync ( ) ;
}
//The part that changed should not be read from the DB on next sync because there might be new folders
// (the ones that are no longer in the blacklist)
2017-05-17 11:55:42 +03:00
foreach ( const auto & it , changes ) {
2019-02-13 16:18:54 +03:00
folder - > journalDb ( ) - > schedulePathForRemoteDiscovery ( it ) ;
folder - > schedulePathForLocalDiscovery ( it ) ;
2015-03-27 13:46:03 +03:00
}
2022-09-06 18:03:31 +03:00
FolderMan : : instance ( ) - > scheduleFolderForImmediateSync ( folder ) ;
2015-03-27 13:46:03 +03:00
}
}
resetFolders ( ) ;
}
2015-06-02 20:45:23 +03:00
void FolderStatusModel : : slotSetProgress ( const ProgressInfo & progress )
{
2017-05-17 11:55:42 +03:00
auto par = qobject_cast < QWidget * > ( QObject : : parent ( ) ) ;
2015-06-02 20:45:23 +03:00
if ( ! par - > isVisible ( ) ) {
return ; // for https://github.com/owncloud/client/issues/2648#issuecomment-71377909
}
2020-05-18 21:54:23 +03:00
auto * f = qobject_cast < Folder * > ( sender ( ) ) ;
2017-05-17 11:55:42 +03:00
if ( ! f ) {
return ;
}
2015-06-02 20:45:23 +03:00
int folderIndex = - 1 ;
for ( int i = 0 ; i < _folders . count ( ) ; + + i ) {
if ( _folders . at ( i ) . _folder = = f ) {
folderIndex = i ;
break ;
}
}
2017-05-17 11:55:42 +03:00
if ( folderIndex < 0 ) {
return ;
}
2015-06-02 20:45:23 +03:00
auto * pi = & _folders [ folderIndex ] . _progress ;
2022-09-06 14:36:29 +03:00
if ( progress . status ( ) = = ProgressInfo : : Starting ) {
_isSyncRunningForAwhile = false ;
}
2015-06-02 20:45:23 +03:00
QVector < int > roles ;
2016-01-21 11:56:01 +03:00
roles < < FolderStatusDelegate : : SyncProgressItemString
< < FolderStatusDelegate : : WarningCount
< < Qt : : ToolTipRole ;
2015-06-02 20:45:23 +03:00
2018-02-21 11:39:55 +03:00
if ( progress . status ( ) = = ProgressInfo : : Discovery ) {
if ( ! progress . _currentDiscoveredRemoteFolder . isEmpty ( ) ) {
2021-07-28 22:35:13 +03:00
pi - > _overallSyncString = tr ( " Checking for changes in remote \" %1 \" " ) . arg ( progress . _currentDiscoveredRemoteFolder ) ;
2018-02-21 11:39:55 +03:00
emit dataChanged ( index ( folderIndex ) , index ( folderIndex ) , roles ) ;
return ;
} else if ( ! progress . _currentDiscoveredLocalFolder . isEmpty ( ) ) {
2021-07-28 22:35:13 +03:00
pi - > _overallSyncString = tr ( " Checking for changes in local \" %1 \" " ) . arg ( progress . _currentDiscoveredLocalFolder ) ;
2018-02-21 11:39:55 +03:00
emit dataChanged ( index ( folderIndex ) , index ( folderIndex ) , roles ) ;
return ;
}
2015-06-02 20:45:23 +03:00
}
2017-07-11 13:52:40 +03:00
if ( progress . status ( ) = = ProgressInfo : : Reconcile ) {
pi - > _overallSyncString = tr ( " Reconciling changes " ) ;
emit dataChanged ( index ( folderIndex ) , index ( folderIndex ) , roles ) ;
return ;
}
// Status is Starting, Propagation or Done
2017-05-17 11:55:42 +03:00
if ( ! progress . _lastCompletedItem . isEmpty ( )
& & Progress : : isWarningKind ( progress . _lastCompletedItem . _status ) ) {
2015-06-02 20:45:23 +03:00
pi - > _warningCount + + ;
}
// find the single item to display: This is going to be the bigger item, or the last completed
// item if no items are in progress.
SyncFileItem curItem = progress . _lastCompletedItem ;
qint64 curItemProgress = - 1 ; // -1 means finished
2019-02-13 12:15:33 +03:00
qint64 biggerItemSize = 0 ;
2015-08-06 15:05:08 +03:00
quint64 estimatedUpBw = 0 ;
quint64 estimatedDownBw = 0 ;
QString allFilenames ;
2017-05-17 11:55:42 +03:00
foreach ( const ProgressInfo : : ProgressItem & citm , progress . _currentItems ) {
2015-06-02 20:45:23 +03:00
if ( curItemProgress = = - 1 | | ( ProgressInfo : : isSizeDependent ( citm . _item )
2017-05-17 11:55:42 +03:00
& & biggerItemSize < citm . _item . _size ) ) {
2015-06-02 20:45:23 +03:00
curItemProgress = citm . _progress . completed ( ) ;
curItem = citm . _item ;
biggerItemSize = citm . _item . _size ;
}
2017-05-17 11:55:42 +03:00
if ( citm . _item . _direction ! = SyncFileItem : : Up ) {
2015-08-06 15:05:08 +03:00
estimatedDownBw + = progress . fileProgress ( citm . _item ) . estimatedBandwidth ;
} else {
estimatedUpBw + = progress . fileProgress ( citm . _item ) . estimatedBandwidth ;
}
2015-11-18 17:40:07 +03:00
auto fileName = QFileInfo ( citm . _item . _file ) . fileName ( ) ;
2015-08-06 15:05:08 +03:00
if ( allFilenames . length ( ) > 0 ) {
2015-11-18 17:40:07 +03:00
//: Build a list of file names
2021-05-12 13:45:33 +03:00
allFilenames . append ( QStringLiteral ( " , \" %1 \" " ) . arg ( fileName ) ) ;
2015-11-18 17:40:07 +03:00
} else {
//: Argument is a file name
2021-05-12 13:45:33 +03:00
allFilenames . append ( QStringLiteral ( " \" %1 \" " ) . arg ( fileName ) ) ;
2015-08-06 15:05:08 +03:00
}
2015-06-02 20:45:23 +03:00
}
if ( curItemProgress = = - 1 ) {
curItemProgress = curItem . _size ;
}
2016-11-15 20:47:04 +03:00
QString itemFileName = curItem . _file ;
2015-06-02 20:45:23 +03:00
QString kindString = Progress : : asActionString ( curItem ) ;
QString fileProgressString ;
if ( ProgressInfo : : isSizeDependent ( curItem ) ) {
2017-05-17 11:55:42 +03:00
QString s1 = Utility : : octetsToString ( curItemProgress ) ;
QString s2 = Utility : : octetsToString ( curItem . _size ) ;
2015-08-06 15:05:08 +03:00
//quint64 estimatedBw = progress.fileProgress(curItem).estimatedBandwidth;
if ( estimatedUpBw | | estimatedDownBw ) {
/*
2015-06-02 20:45:23 +03:00
//: Example text: "uploading foobar.png (1MB of 2MB) time left 2 minutes at a rate of 24Kb/s"
fileProgressString = tr ( " %1 %2 (%3 of %4) %5 left at a rate of %6/s " )
. arg ( kindString , itemFileName , s1 , s2 ,
2015-06-29 15:53:37 +03:00
Utility : : durationToDescriptiveString ( progress . fileProgress ( curItem ) . estimatedEta ) ,
2015-06-02 20:45:23 +03:00
Utility : : octetsToString ( estimatedBw ) ) ;
2015-08-06 15:05:08 +03:00
*/
2015-11-18 17:40:07 +03:00
//: Example text: "Syncing 'foo.txt', 'bar.txt'"
2015-08-06 15:05:08 +03:00
fileProgressString = tr ( " Syncing %1 " ) . arg ( allFilenames ) ;
if ( estimatedDownBw > 0 ) {
2015-11-18 17:40:07 +03:00
fileProgressString . append ( tr ( " , " ) ) ;
2015-08-06 19:08:05 +03:00
// ifdefs: https://github.com/owncloud/client/issues/3095#issuecomment-128409294
# ifdef Q_OS_WIN
2015-11-18 17:40:07 +03:00
//: Example text: "download 24Kb/s" (%1 is replaced by 24Kb (translated))
2015-08-06 19:08:05 +03:00
fileProgressString . append ( tr ( " download %1/s " ) . arg ( Utility : : octetsToString ( estimatedDownBw ) ) ) ;
# else
2017-12-08 13:03:14 +03:00
fileProgressString . append ( tr ( " \u2193 %1/s " )
2017-05-17 11:55:42 +03:00
. arg ( Utility : : octetsToString ( estimatedDownBw ) ) ) ;
2015-08-06 19:08:05 +03:00
# endif
2015-08-06 15:05:08 +03:00
}
if ( estimatedUpBw > 0 ) {
2015-11-18 17:40:07 +03:00
fileProgressString . append ( tr ( " , " ) ) ;
2017-05-17 11:55:42 +03:00
# ifdef Q_OS_WIN
2015-11-18 17:40:07 +03:00
//: Example text: "upload 24Kb/s" (%1 is replaced by 24Kb (translated))
2015-08-06 19:08:05 +03:00
fileProgressString . append ( tr ( " upload %1/s " ) . arg ( Utility : : octetsToString ( estimatedUpBw ) ) ) ;
# else
2017-12-08 13:03:14 +03:00
fileProgressString . append ( tr ( " \u2191 %1/s " )
2017-05-17 11:55:42 +03:00
. arg ( Utility : : octetsToString ( estimatedUpBw ) ) ) ;
2015-08-06 19:08:05 +03:00
# endif
2015-08-06 15:05:08 +03:00
}
2015-06-02 20:45:23 +03:00
} else {
//: Example text: "uploading foobar.png (2MB of 2MB)"
2017-05-17 11:55:42 +03:00
fileProgressString = tr ( " %1 %2 (%3 of %4) " ) . arg ( kindString , itemFileName , s1 , s2 ) ;
2015-06-02 20:45:23 +03:00
}
} else if ( ! kindString . isEmpty ( ) ) {
//: Example text: "uploading foobar.png"
fileProgressString = tr ( " %1 %2 " ) . arg ( kindString , itemFileName ) ;
}
pi - > _progressString = fileProgressString ;
// overall progress
2019-02-13 12:15:33 +03:00
qint64 completedSize = progress . completedSize ( ) ;
qint64 completedFile = progress . completedFiles ( ) ;
qint64 currentFile = progress . currentFile ( ) ;
qint64 totalSize = qMax ( completedSize , progress . totalSize ( ) ) ;
qint64 totalFileCount = qMax ( currentFile , progress . totalFiles ( ) ) ;
2015-06-02 20:45:23 +03:00
QString overallSyncString ;
if ( totalSize > 0 ) {
2017-05-17 11:55:42 +03:00
QString s1 = Utility : : octetsToString ( completedSize ) ;
QString s2 = Utility : : octetsToString ( totalSize ) ;
2016-08-15 14:36:53 +03:00
2022-09-06 14:36:29 +03:00
const auto estimatedEta = progress . totalProgress ( ) . estimatedEta ;
if ( progress . trustEta ( ) & & ( estimatedEta > 0 | | _isSyncRunningForAwhile ) ) {
_isSyncRunningForAwhile = true ;
2016-08-15 14:36:53 +03:00
//: Example text: "5 minutes left, 12 MB of 345 MB, file 6 of 7"
2022-09-06 14:36:29 +03:00
if ( estimatedEta = = 0 ) {
overallSyncString = tr ( " A few seconds left, %1 of %2, file %3 of %4 " )
. arg ( s1 , s2 )
. arg ( currentFile )
. arg ( totalFileCount ) ;
} else {
overallSyncString = tr ( " %5 left, %1 of %2, file %3 of %4 " )
. arg ( s1 , s2 )
. arg ( currentFile )
. arg ( totalFileCount )
. arg ( Utility : : durationToDescriptiveString1 ( estimatedEta ) ) ;
}
2016-08-15 14:36:53 +03:00
} else {
//: Example text: "12 MB of 345 MB, file 6 of 7"
overallSyncString = tr ( " %1 of %2, file %3 of %4 " )
2017-05-17 11:55:42 +03:00
. arg ( s1 , s2 )
. arg ( currentFile )
. arg ( totalFileCount ) ;
2016-08-15 14:36:53 +03:00
}
2015-06-02 20:45:23 +03:00
} else if ( totalFileCount > 0 ) {
2015-10-05 07:21:19 +03:00
// Don't attempt to estimate the time left if there is no kb to transfer.
2017-05-17 11:55:42 +03:00
overallSyncString = tr ( " file %1 of %2 " ) . arg ( currentFile ) . arg ( totalFileCount ) ;
2015-06-02 20:45:23 +03:00
}
2017-05-17 11:55:42 +03:00
pi - > _overallSyncString = overallSyncString ;
2015-06-02 20:45:23 +03:00
int overallPercent = 0 ;
2017-05-17 11:55:42 +03:00
if ( totalFileCount > 0 ) {
2015-10-05 07:21:19 +03:00
// Add one 'byte' for each file so the percentage is moving when deleting or renaming files
2017-05-17 11:55:42 +03:00
overallPercent = qRound ( double ( completedSize + completedFile ) / double ( totalSize + totalFileCount ) * 100.0 ) ;
2015-06-02 20:45:23 +03:00
}
pi - > _overallPercent = qBound ( 0 , overallPercent , 100 ) ;
emit dataChanged ( index ( folderIndex ) , index ( folderIndex ) , roles ) ;
}
2022-12-07 21:43:27 +03:00
void FolderStatusModel : : e2eInitializationFinished ( bool isNewMnemonicGenerated )
{
Q_UNUSED ( isNewMnemonicGenerated ) ;
for ( int i = 0 ; i < _folders . count ( ) ; + + i ) {
resetAndFetch ( index ( i ) ) ;
}
}
2015-09-04 11:33:48 +03:00
void FolderStatusModel : : slotFolderSyncStateChange ( Folder * f )
2015-06-02 20:45:23 +03:00
{
2017-05-17 11:55:42 +03:00
if ( ! f ) {
return ;
}
2015-07-02 14:50:13 +03:00
2015-06-02 20:45:23 +03:00
int folderIndex = - 1 ;
for ( int i = 0 ; i < _folders . count ( ) ; + + i ) {
if ( _folders . at ( i ) . _folder = = f ) {
folderIndex = i ;
break ;
}
}
2017-05-17 11:55:42 +03:00
if ( folderIndex < 0 ) {
return ;
}
2015-06-02 20:45:23 +03:00
2017-05-17 11:55:42 +03:00
auto & pi = _folders [ folderIndex ] . _progress ;
2016-11-08 15:57:03 +03:00
2015-06-02 20:45:23 +03:00
SyncResult : : Status state = f - > syncResult ( ) . status ( ) ;
2020-08-18 18:41:02 +03:00
if ( ! f - > canSync ( ) | | state = = SyncResult : : Problem | | state = = SyncResult : : Success | | state = = SyncResult : : Error ) {
2015-11-11 12:56:19 +03:00
// Reset progress info.
2016-11-08 15:57:03 +03:00
pi = SubFolderInfo : : Progress ( ) ;
2015-11-11 12:56:19 +03:00
} else if ( state = = SyncResult : : NotYetStarted ) {
2017-05-17 11:55:42 +03:00
FolderMan * folderMan = FolderMan : : instance ( ) ;
2015-09-04 11:33:48 +03:00
int pos = folderMan - > scheduleQueue ( ) . indexOf ( f ) ;
2020-11-26 19:19:20 +03:00
for ( auto other : folderMan - > map ( ) ) {
if ( other ! = f & & other - > isSyncRunning ( ) )
pos + = 1 ;
2015-09-04 11:33:48 +03:00
}
QString message ;
if ( pos < = 0 ) {
2019-11-15 01:23:43 +03:00
message = tr ( " Waiting … " ) ;
2015-09-04 11:33:48 +03:00
} else {
2019-11-15 01:23:43 +03:00
message = tr ( " Waiting for %n other folder(s) … " , " " , pos ) ;
2015-09-04 11:33:48 +03:00
}
2016-11-08 15:57:03 +03:00
pi = SubFolderInfo : : Progress ( ) ;
pi . _overallSyncString = message ;
2015-09-04 11:33:48 +03:00
} else if ( state = = SyncResult : : SyncPrepare ) {
2016-11-08 15:57:03 +03:00
pi = SubFolderInfo : : Progress ( ) ;
2019-11-15 01:23:43 +03:00
pi . _overallSyncString = tr ( " Preparing to sync … " ) ;
2015-06-02 20:45:23 +03:00
}
2015-07-02 14:50:13 +03:00
// update the icon etc. now
slotUpdateFolderState ( f ) ;
2015-08-17 13:46:24 +03:00
2018-01-29 11:36:35 +03:00
if ( f - > syncResult ( ) . folderStructureWasChanged ( )
& & ( state = = SyncResult : : Success | | state = = SyncResult : : Problem ) ) {
2017-01-25 13:28:18 +03:00
// There is a new or a removed folder. reset all data
2020-02-04 17:35:14 +03:00
resetAndFetch ( index ( folderIndex ) ) ;
2015-08-17 13:46:24 +03:00
}
2015-06-02 20:45:23 +03:00
}
2015-09-04 11:33:48 +03:00
void FolderStatusModel : : slotFolderScheduleQueueChanged ( )
{
// Update messages on waiting folders.
2017-05-17 11:55:42 +03:00
foreach ( Folder * f , FolderMan : : instance ( ) - > map ( ) ) {
2015-09-04 11:33:48 +03:00
slotFolderSyncStateChange ( f ) ;
}
}
2015-03-27 13:46:03 +03:00
void FolderStatusModel : : resetFolders ( )
{
2015-07-03 16:03:18 +03:00
setAccountState ( _accountState ) ;
2015-03-27 13:46:03 +03:00
}
2016-09-23 14:47:57 +03:00
void FolderStatusModel : : slotSyncAllPendingBigFolders ( )
{
for ( int i = 0 ; i < _folders . count ( ) ; + + i ) {
if ( ! _folders [ i ] . _fetched ) {
_folders [ i ] . _folder - > journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , QStringList ( ) ) ;
continue ;
}
auto folder = _folders . at ( i ) . _folder ;
2020-05-29 16:07:05 +03:00
bool ok = false ;
2016-09-23 14:47:57 +03:00
auto undecidedList = folder - > journalDb ( ) - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , & ok ) ;
2017-05-17 11:55:42 +03:00
if ( ! ok ) {
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolderStatus ) < < " Could not read selective sync list from db. " ;
2016-09-23 14:47:57 +03:00
return ;
}
// If this folder had no undecided entries, skip it.
if ( undecidedList . isEmpty ( ) ) {
continue ;
}
// Remove all undecided folders from the blacklist
auto blackList = folder - > journalDb ( ) - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncBlackList , & ok ) ;
2017-05-17 11:55:42 +03:00
if ( ! ok ) {
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolderStatus ) < < " Could not read selective sync list from db. " ;
2016-09-23 14:47:57 +03:00
return ;
}
2017-05-17 11:55:42 +03:00
foreach ( const auto & undecidedFolder , undecidedList ) {
2016-09-23 14:47:57 +03:00
blackList . removeAll ( undecidedFolder ) ;
}
folder - > journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncBlackList , blackList ) ;
// Add all undecided folders to the white list
auto whiteList = folder - > journalDb ( ) - > getSelectiveSyncList ( SyncJournalDb : : SelectiveSyncWhiteList , & ok ) ;
2017-05-17 11:55:42 +03:00
if ( ! ok ) {
2017-03-30 14:46:20 +03:00
qCWarning ( lcFolderStatus ) < < " Could not read selective sync list from db. " ;
2016-09-23 14:47:57 +03:00
return ;
}
whiteList + = undecidedList ;
folder - > journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncWhiteList , whiteList ) ;
// Clear the undecided list
folder - > journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , QStringList ( ) ) ;
// Trigger a sync
if ( folder - > isBusy ( ) ) {
folder - > slotTerminateSync ( ) ;
}
// The part that changed should not be read from the DB on next sync because there might be new folders
// (the ones that are no longer in the blacklist)
foreach ( const auto & it , undecidedList ) {
2019-02-13 16:18:54 +03:00
folder - > journalDb ( ) - > schedulePathForRemoteDiscovery ( it ) ;
folder - > schedulePathForLocalDiscovery ( it ) ;
2016-09-23 14:47:57 +03:00
}
2016-10-19 12:03:13 +03:00
FolderMan : : instance ( ) - > scheduleFolder ( folder ) ;
2016-09-23 14:47:57 +03:00
}
resetFolders ( ) ;
}
void FolderStatusModel : : slotSyncNoPendingBigFolders ( )
{
for ( int i = 0 ; i < _folders . count ( ) ; + + i ) {
auto folder = _folders . at ( i ) . _folder ;
// clear the undecided list
folder - > journalDb ( ) - > setSelectiveSyncList ( SyncJournalDb : : SelectiveSyncUndecidedList , QStringList ( ) ) ;
}
resetFolders ( ) ;
}
2015-08-05 13:51:49 +03:00
void FolderStatusModel : : slotNewBigFolder ( )
{
auto f = qobject_cast < Folder * > ( sender ( ) ) ;
2017-02-07 15:52:15 +03:00
ASSERT ( f ) ;
2015-08-05 13:51:49 +03:00
int folderIndex = - 1 ;
for ( int i = 0 ; i < _folders . count ( ) ; + + i ) {
if ( _folders . at ( i ) . _folder = = f ) {
folderIndex = i ;
break ;
}
}
2017-05-17 11:55:42 +03:00
if ( folderIndex < 0 ) {
return ;
}
2015-08-05 13:51:49 +03:00
2020-02-04 17:35:14 +03:00
resetAndFetch ( index ( folderIndex ) ) ;
2015-08-05 13:51:49 +03:00
emit suggestExpand ( index ( folderIndex ) ) ;
emit dirtyChanged ( ) ;
}
2015-10-13 15:10:52 +03:00
void FolderStatusModel : : slotShowFetchProgress ( )
{
QMutableMapIterator < QPersistentModelIndex , QElapsedTimer > it ( _fetchingItems ) ;
while ( it . hasNext ( ) ) {
it . next ( ) ;
2017-05-17 11:55:42 +03:00
if ( it . value ( ) . elapsed ( ) > 800 ) {
2015-10-13 15:10:52 +03:00
auto idx = it . key ( ) ;
2017-05-17 11:55:42 +03:00
auto * info = infoForIndex ( idx ) ;
2018-03-27 13:17:29 +03:00
if ( info & & info - > _fetchingJob ) {
2016-08-31 11:16:25 +03:00
bool add = ! info - > hasLabel ( ) ;
if ( add ) {
2015-10-13 15:10:52 +03:00
beginInsertRows ( idx , 0 , 0 ) ;
}
info - > _fetchingLabel = true ;
2016-08-31 11:16:25 +03:00
if ( add ) {
endInsertRows ( ) ;
}
2015-10-13 15:10:52 +03:00
}
it . remove ( ) ;
}
}
}
bool FolderStatusModel : : SubFolderInfo : : hasLabel ( ) const
{
return _hasError | | _fetchingLabel ;
}
2017-05-17 11:55:42 +03:00
void FolderStatusModel : : SubFolderInfo : : resetSubs ( FolderStatusModel * model , QModelIndex index )
2015-10-13 15:10:52 +03:00
{
_fetched = false ;
2018-05-31 12:00:11 +03:00
if ( _fetchingJob ) {
disconnect ( _fetchingJob , nullptr , model , nullptr ) ;
_fetchingJob - > deleteLater ( ) ;
_fetchingJob . clear ( ) ;
}
2015-10-13 15:10:52 +03:00
if ( hasLabel ( ) ) {
2017-05-17 11:55:42 +03:00
model - > beginRemoveRows ( index , 0 , 0 ) ;
2015-10-13 15:10:52 +03:00
_fetchingLabel = false ;
_hasError = false ;
model - > endRemoveRows ( ) ;
} else if ( ! _subs . isEmpty ( ) ) {
model - > beginRemoveRows ( index , 0 , _subs . count ( ) - 1 ) ;
_subs . clear ( ) ;
model - > endRemoveRows ( ) ;
}
}
2015-08-05 13:51:49 +03:00
2014-11-10 00:34:07 +03:00
} // namespace OCC